XKBMisc.c revision 4642e01f
105b261ecSmrg/************************************************************
205b261ecSmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
305b261ecSmrg
405b261ecSmrgPermission to use, copy, modify, and distribute this
505b261ecSmrgsoftware and its documentation for any purpose and without
605b261ecSmrgfee is hereby granted, provided that the above copyright
705b261ecSmrgnotice appear in all copies and that both that copyright
805b261ecSmrgnotice and this permission notice appear in supporting
905b261ecSmrgdocumentation, and that the name of Silicon Graphics not be
1005b261ecSmrgused in advertising or publicity pertaining to distribution
1105b261ecSmrgof the software without specific prior written permission.
1205b261ecSmrgSilicon Graphics makes no representation about the suitability
1305b261ecSmrgof this software for any purpose. It is provided "as is"
1405b261ecSmrgwithout any express or implied warranty.
1505b261ecSmrg
1605b261ecSmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1705b261ecSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1805b261ecSmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
1905b261ecSmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2005b261ecSmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2105b261ecSmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2205b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
2305b261ecSmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
2405b261ecSmrg
2505b261ecSmrg********************************************************/
2605b261ecSmrg
2705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2805b261ecSmrg#include <dix-config.h>
2905b261ecSmrg#elif defined(HAVE_CONFIG_H)
3005b261ecSmrg#include <config.h>
3105b261ecSmrg#endif
3205b261ecSmrg
3305b261ecSmrg#include <stdio.h>
3405b261ecSmrg#include <X11/X.h>
3505b261ecSmrg#define	NEED_EVENTS
3605b261ecSmrg#define	NEED_REPLIES
3705b261ecSmrg#include <X11/Xproto.h>
3805b261ecSmrg#include "misc.h"
3905b261ecSmrg#include "inputstr.h"
4005b261ecSmrg#include <X11/keysym.h>
4105b261ecSmrg#define	XKBSRV_NEED_FILE_FUNCS
4205b261ecSmrg#include <xkbsrv.h>
4305b261ecSmrg
4405b261ecSmrg/***====================================================================***/
4505b261ecSmrg
4605b261ecSmrg#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
4705b261ecSmrg#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
4805b261ecSmrg
4905b261ecSmrgint
5005b261ecSmrgXkbKeyTypesForCoreSymbols(	XkbDescPtr	xkb,
5105b261ecSmrg				int		map_width,
5205b261ecSmrg				KeySym *	core_syms,
5305b261ecSmrg				unsigned int 	protected,
5405b261ecSmrg    				int *		types_inout,
5505b261ecSmrg				KeySym *	xkb_syms_rtrn)
5605b261ecSmrg{
5705b261ecSmrgregister int	i;
5805b261ecSmrgunsigned int	empty;
5905b261ecSmrgint		nSyms[XkbNumKbdGroups];
6005b261ecSmrgint		nGroups,tmp,groupsWidth;
6105b261ecSmrg
6205b261ecSmrg    /* Section 12.2 of the protocol describes this process in more detail */
6305b261ecSmrg    /* Step 1:  find the # of symbols in the core mapping per group */
6405b261ecSmrg    groupsWidth= 2;
6505b261ecSmrg    for (i=0;i<XkbNumKbdGroups;i++) {
6605b261ecSmrg	if ((protected&(1<<i))&&(types_inout[i]<xkb->map->num_types)) {
6705b261ecSmrg	    nSyms[i]= xkb->map->types[types_inout[i]].num_levels;
6805b261ecSmrg	    if (nSyms[i]>groupsWidth)
6905b261ecSmrg		groupsWidth= nSyms[i];
7005b261ecSmrg	}
7105b261ecSmrg	else {
7205b261ecSmrg	    types_inout[i]= XkbTwoLevelIndex;	/* don't really know, yet */
7305b261ecSmrg	    nSyms[i]= 2;
7405b261ecSmrg	}
7505b261ecSmrg    }
7605b261ecSmrg    if (nSyms[XkbGroup1Index]<2)
7705b261ecSmrg	nSyms[XkbGroup1Index]= 2;
7805b261ecSmrg    if (nSyms[XkbGroup2Index]<2)
7905b261ecSmrg	nSyms[XkbGroup2Index]= 2;
8005b261ecSmrg    /* Step 2:	Copy the symbols from the core ordering to XKB ordering	*/
8105b261ecSmrg    /*		symbols in the core are in the order:			*/
8205b261ecSmrg    /*		G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*]	*/
8305b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0);
8405b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1);
8505b261ecSmrg    for (i=2;i<nSyms[XkbGroup1Index];i++) {
8605b261ecSmrg	xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,i)]= CORE_SYM(2+i);
8705b261ecSmrg    }
8805b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,0)]= CORE_SYM(2);
8905b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,1)]= CORE_SYM(3);
9005b261ecSmrg    tmp= 2+(nSyms[XkbGroup1Index]-2); /* offset to extra group2 syms */
9105b261ecSmrg    for (i=2;i<nSyms[XkbGroup2Index];i++) {
9205b261ecSmrg	xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,i)]= CORE_SYM(tmp+i);
9305b261ecSmrg    }
9405b261ecSmrg    tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index];
9505b261ecSmrg    if ((tmp>=map_width)&&
9605b261ecSmrg	 ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) {
9705b261ecSmrg	nSyms[XkbGroup3Index]= 0;
9805b261ecSmrg	nSyms[XkbGroup4Index]= 0;
9905b261ecSmrg	nGroups= 2;
10005b261ecSmrg    }
10105b261ecSmrg    else {
10205b261ecSmrg    	nGroups= 3;
10305b261ecSmrg	for (i=0;i<nSyms[XkbGroup3Index];i++,tmp++) {
10405b261ecSmrg	    xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index,i)]= CORE_SYM(tmp);
10505b261ecSmrg	}
10605b261ecSmrg	if ((tmp<map_width)||(protected&XkbExplicitKeyType4Mask)) {
10705b261ecSmrg	    nGroups= 4;
10805b261ecSmrg	    for (i=0;i<nSyms[XkbGroup4Index];i++,tmp++) {
10905b261ecSmrg		xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index,i)]= CORE_SYM(tmp);
11005b261ecSmrg	    }
11105b261ecSmrg	}
11205b261ecSmrg	else {
11305b261ecSmrg	    nSyms[XkbGroup4Index]= 0;
11405b261ecSmrg	}
11505b261ecSmrg    }
11605b261ecSmrg    /* steps 3&4: alphanumeric expansion,  assign canonical types */
11705b261ecSmrg    empty= 0;
11805b261ecSmrg    for (i=0;i<nGroups;i++) {
11905b261ecSmrg	KeySym *syms;
12005b261ecSmrg	syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
12105b261ecSmrg	if ((nSyms[i]>1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) {
12205b261ecSmrg	    KeySym upper,lower;
12305b261ecSmrg	    XConvertCase(syms[0],&lower,&upper);
12405b261ecSmrg	    if (upper!=lower) {
12505b261ecSmrg		xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower;
12605b261ecSmrg		xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper;
12705b261ecSmrg		if ((protected&(1<<i))==0)
12805b261ecSmrg		    types_inout[i]= XkbAlphabeticIndex;
12905b261ecSmrg	    }
13005b261ecSmrg	    else if ((protected&(1<<i))==0) {
13105b261ecSmrg		types_inout[i]= XkbOneLevelIndex;
13205b261ecSmrg	/*	nSyms[i]=	1;*/
13305b261ecSmrg	    }
13405b261ecSmrg	}
13505b261ecSmrg	if (((protected&(1<<i))==0)&&(types_inout[i]==XkbTwoLevelIndex)) {
13605b261ecSmrg	    if (IsKeypadKey(syms[0])||IsKeypadKey(syms[1]))
13705b261ecSmrg		types_inout[i]= XkbKeypadIndex;
13805b261ecSmrg	    else {
13905b261ecSmrg		KeySym upper,lower;
14005b261ecSmrg		XConvertCase(syms[0],&lower,&upper);
14105b261ecSmrg		if ((syms[0]==lower)&&(syms[1]==upper))
14205b261ecSmrg		    types_inout[i]= XkbAlphabeticIndex;
14305b261ecSmrg	    }
14405b261ecSmrg	}
14505b261ecSmrg	if (syms[0]==NoSymbol) {
14605b261ecSmrg	    register int n;
14705b261ecSmrg	    Bool	found;
14805b261ecSmrg	    for (n=1,found=False;(!found)&&(n<nSyms[i]);n++) {
14905b261ecSmrg		found= (syms[n]!=NoSymbol);
15005b261ecSmrg	    }
15105b261ecSmrg	    if (!found)
15205b261ecSmrg		empty|= (1<<i);
15305b261ecSmrg	}
15405b261ecSmrg    }
15505b261ecSmrg    /* step 5: squoosh out empty groups */
15605b261ecSmrg    if (empty) {
15705b261ecSmrg	for (i=nGroups-1;i>=0;i--) {
15805b261ecSmrg	    if (((empty&(1<<i))==0)||(protected&(1<<i)))
15905b261ecSmrg		break;
16005b261ecSmrg	    nGroups--;
16105b261ecSmrg	}
16205b261ecSmrg    }
16305b261ecSmrg    if (nGroups<1)
16405b261ecSmrg	return 0;
16505b261ecSmrg
16605b261ecSmrg    /* step 6: replicate group 1 into group two, if necessary */
16705b261ecSmrg    if ((nGroups>1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) {
16805b261ecSmrg	if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) {
16905b261ecSmrg	    nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index];
17005b261ecSmrg	    types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index];
17105b261ecSmrg	    memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn,
17205b261ecSmrg							2*sizeof(KeySym));
17305b261ecSmrg	}
17405b261ecSmrg	else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) {
17505b261ecSmrg	    memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]],
17605b261ecSmrg	    				(char *)xkb_syms_rtrn,
17705b261ecSmrg					nSyms[XkbGroup1Index]*sizeof(KeySym));
17805b261ecSmrg	}
17905b261ecSmrg    }
18005b261ecSmrg
1814642e01fSmrg    /* step 7: check for all groups identical or all width 1
1824642e01fSmrg     *
1834642e01fSmrg     * Special feature: if group 1 has an explicit type and all other groups
1844642e01fSmrg     * have canonical types with same symbols, we assume it's info lost from
1854642e01fSmrg     * the core replication.
1864642e01fSmrg     */
18705b261ecSmrg    if (nGroups>1) {
1884642e01fSmrg	Bool sameType,allOneLevel, canonical = True;
18905b261ecSmrg	allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1);
19005b261ecSmrg	for (i=1,sameType=True;(allOneLevel||sameType)&&(i<nGroups);i++) {
19105b261ecSmrg	    sameType=(sameType&&(types_inout[i]==types_inout[XkbGroup1Index]));
19205b261ecSmrg	    if (allOneLevel)
19305b261ecSmrg		allOneLevel= (xkb->map->types[types_inout[i]].num_levels==1);
1944642e01fSmrg	    if (types_inout[i] > XkbLastRequiredType)
1954642e01fSmrg		canonical = False;
19605b261ecSmrg	}
1974642e01fSmrg	if (((sameType) || canonical)&&
19805b261ecSmrg	    (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){
19905b261ecSmrg	    register int s;
20005b261ecSmrg	    Bool	identical;
20105b261ecSmrg	    for (i=1,identical=True;identical&&(i<nGroups);i++) {
20205b261ecSmrg		KeySym *syms;
20305b261ecSmrg		syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
20405b261ecSmrg		for (s=0;identical&&(s<nSyms[i]);s++) {
20505b261ecSmrg		    if (syms[s]!=xkb_syms_rtrn[s])
20605b261ecSmrg			identical= False;
20705b261ecSmrg		}
20805b261ecSmrg	    }
20905b261ecSmrg	    if (identical)
21005b261ecSmrg		nGroups= 1;
21105b261ecSmrg	}
21205b261ecSmrg	if (allOneLevel && (nGroups>1)) {
21305b261ecSmrg	    KeySym *syms;
21405b261ecSmrg	    syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
21505b261ecSmrg	    nSyms[XkbGroup1Index]= 1;
21605b261ecSmrg	    for (i=1;i<nGroups;i++) {
21705b261ecSmrg		xkb_syms_rtrn[i]= syms[0];
21805b261ecSmrg		syms+= nSyms[i];
21905b261ecSmrg		nSyms[i]= 1;
22005b261ecSmrg	    }
22105b261ecSmrg	}
22205b261ecSmrg    }
22305b261ecSmrg    return nGroups;
22405b261ecSmrg}
22505b261ecSmrg
22605b261ecSmrgstatic XkbSymInterpretPtr
22705b261ecSmrg_XkbFindMatchingInterp(	XkbDescPtr	xkb,
22805b261ecSmrg			KeySym 		sym,
22905b261ecSmrg			unsigned int	real_mods,
23005b261ecSmrg			unsigned int	level)
23105b261ecSmrg{
23205b261ecSmrgregister unsigned	 i;
23305b261ecSmrgXkbSymInterpretPtr	 interp,rtrn;
23405b261ecSmrgCARD8			 mods;
23505b261ecSmrg
23605b261ecSmrg    rtrn= NULL;
23705b261ecSmrg    interp= xkb->compat->sym_interpret;
23805b261ecSmrg    for (i=0;i<xkb->compat->num_si;i++,interp++) {
23905b261ecSmrg	if ((interp->sym==NoSymbol)||(sym==interp->sym)) {
24005b261ecSmrg	    int match;
24105b261ecSmrg	    if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0))
24205b261ecSmrg		 mods= real_mods;
24305b261ecSmrg	    else mods= 0;
24405b261ecSmrg	    switch (interp->match&XkbSI_OpMask) {
24505b261ecSmrg		case XkbSI_NoneOf:
24605b261ecSmrg		    match= ((interp->mods&mods)==0);
24705b261ecSmrg		    break;
24805b261ecSmrg		case XkbSI_AnyOfOrNone:
24905b261ecSmrg		    match= ((mods==0)||((interp->mods&mods)!=0));
25005b261ecSmrg		    break;
25105b261ecSmrg		case XkbSI_AnyOf:
25205b261ecSmrg		    match= ((interp->mods&mods)!=0);
25305b261ecSmrg		    break;
25405b261ecSmrg		case XkbSI_AllOf:
25505b261ecSmrg		    match= ((interp->mods&mods)==interp->mods);
25605b261ecSmrg		    break;
25705b261ecSmrg		case XkbSI_Exactly:
25805b261ecSmrg		    match= (interp->mods==mods);
25905b261ecSmrg		    break;
26005b261ecSmrg		default:
26105b261ecSmrg		    match= 0;
26205b261ecSmrg		    break;
26305b261ecSmrg	    }
26405b261ecSmrg	    if (match) {
26505b261ecSmrg		if (interp->sym!=NoSymbol) {
26605b261ecSmrg		    return interp;
26705b261ecSmrg		}
26805b261ecSmrg		else if (rtrn==NULL) {
26905b261ecSmrg		    rtrn= interp;
27005b261ecSmrg		}
27105b261ecSmrg	    }
27205b261ecSmrg	}
27305b261ecSmrg    }
27405b261ecSmrg    return rtrn;
27505b261ecSmrg}
27605b261ecSmrg
27705b261ecSmrgstatic void
27805b261ecSmrg_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey)
27905b261ecSmrg{
28005b261ecSmrgKeyCode	last;
28105b261ecSmrg
28205b261ecSmrg    last= (*pFirst)+(*pNum);
28305b261ecSmrg    if (newKey<*pFirst) {
28405b261ecSmrg	*pFirst= newKey;
28505b261ecSmrg	*pNum= (last-newKey)+1;
28605b261ecSmrg    }
28705b261ecSmrg    else if (newKey>last) {
28805b261ecSmrg	*pNum= (last-*pFirst)+1;
28905b261ecSmrg    }
29005b261ecSmrg    return;
29105b261ecSmrg}
29205b261ecSmrg
29305b261ecSmrgstatic void
29405b261ecSmrg_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods)
29505b261ecSmrg{
29605b261ecSmrgunsigned	tmp;
29705b261ecSmrg
29805b261ecSmrg    switch (act->type) {
29905b261ecSmrg	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
30005b261ecSmrg	    if (act->mods.flags&XkbSA_UseModMapMods)
30105b261ecSmrg		act->mods.real_mods= act->mods.mask= mods;
30205b261ecSmrg	    if ((tmp= XkbModActionVMods(&act->mods))!=0) {
30305b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
30405b261ecSmrg		act->mods.mask|= tmp;
30505b261ecSmrg	    }
30605b261ecSmrg	    break;
30705b261ecSmrg	case XkbSA_ISOLock:
30805b261ecSmrg	    if (act->iso.flags&XkbSA_UseModMapMods)
30905b261ecSmrg		act->iso.real_mods= act->iso.mask= mods;
31005b261ecSmrg	    if ((tmp= XkbModActionVMods(&act->iso))!=0) {
31105b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
31205b261ecSmrg		act->iso.mask|= tmp;
31305b261ecSmrg	    }
31405b261ecSmrg	    break;
31505b261ecSmrg    }
31605b261ecSmrg    return;
31705b261ecSmrg}
31805b261ecSmrg
31905b261ecSmrg#define	IBUF_SIZE	8
32005b261ecSmrg
32105b261ecSmrgBool
32205b261ecSmrgXkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes)
32305b261ecSmrg{
32405b261ecSmrgKeySym *		syms;
32505b261ecSmrgunsigned char 		explicit,mods;
32605b261ecSmrgXkbSymInterpretPtr	*interps,ibuf[IBUF_SIZE];
32705b261ecSmrgint			n,nSyms,found;
32805b261ecSmrgunsigned		changed,tmp;
32905b261ecSmrg
33005b261ecSmrg    if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)||
33105b261ecSmrg    			(!xkb->compat)||(!xkb->compat->sym_interpret)||
33205b261ecSmrg			(key<xkb->min_key_code)||(key>xkb->max_key_code)) {
33305b261ecSmrg	return False;
33405b261ecSmrg    }
33505b261ecSmrg    if (((!xkb->server)||(!xkb->server->key_acts))&&
33605b261ecSmrg		(XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) {
33705b261ecSmrg	return False;
33805b261ecSmrg    }
33905b261ecSmrg    changed= 0;	/* keeps track of what has changed in _this_ call */
34005b261ecSmrg    explicit= xkb->server->explicit[key];
34105b261ecSmrg    if (explicit&XkbExplicitInterpretMask) /* nothing to do */
34205b261ecSmrg	return True;
34305b261ecSmrg    mods= (xkb->map->modmap?xkb->map->modmap[key]:0);
34405b261ecSmrg    nSyms= XkbKeyNumSyms(xkb,key);
34505b261ecSmrg    syms= XkbKeySymsPtr(xkb,key);
34605b261ecSmrg    if (nSyms>IBUF_SIZE) {
34705b261ecSmrg	interps= _XkbTypedCalloc(nSyms,XkbSymInterpretPtr);
34805b261ecSmrg	if (interps==NULL) {
34905b261ecSmrg	    interps= ibuf;
35005b261ecSmrg	    nSyms= IBUF_SIZE;
35105b261ecSmrg	}
35205b261ecSmrg    }
35305b261ecSmrg    else {
35405b261ecSmrg	interps= ibuf;
35505b261ecSmrg    }
35605b261ecSmrg    found= 0;
35705b261ecSmrg    for (n=0;n<nSyms;n++) {
35805b261ecSmrg	unsigned level= (n%XkbKeyGroupsWidth(xkb,key));
35905b261ecSmrg	interps[n]= NULL;
36005b261ecSmrg	if (syms[n]!=NoSymbol) {
36105b261ecSmrg	    interps[n]= _XkbFindMatchingInterp(xkb,syms[n],mods,level);
36205b261ecSmrg	    if (interps[n]&&interps[n]->act.type!=XkbSA_NoAction)
36305b261ecSmrg		found++;
36405b261ecSmrg	    else interps[n]= NULL;
36505b261ecSmrg	}
36605b261ecSmrg    }
36705b261ecSmrg    /* 1/28/96 (ef) -- XXX! WORKING HERE */
36805b261ecSmrg    if (!found) {
36905b261ecSmrg	if (xkb->server->key_acts[key]!=0) {
37005b261ecSmrg	    xkb->server->key_acts[key]= 0;
37105b261ecSmrg	    changed|= XkbKeyActionsMask;
37205b261ecSmrg	}
37305b261ecSmrg    }
37405b261ecSmrg    else {
37505b261ecSmrg	XkbAction *pActs;
37605b261ecSmrg	unsigned int	new_vmodmask;
37705b261ecSmrg	changed|= XkbKeyActionsMask;
37805b261ecSmrg	pActs= XkbResizeKeyActions(xkb,key,nSyms);
37905b261ecSmrg	if (!pActs) {
38005b261ecSmrg            if (nSyms > IBUF_SIZE)
38105b261ecSmrg                xfree(interps);
38205b261ecSmrg	    return False;
38305b261ecSmrg        }
38405b261ecSmrg	new_vmodmask= 0;
38505b261ecSmrg	for (n=0;n<nSyms;n++) {
38605b261ecSmrg	    if (interps[n]) {
38705b261ecSmrg		unsigned effMods;
38805b261ecSmrg
38905b261ecSmrg		pActs[n]= *((XkbAction *)&interps[n]->act);
39005b261ecSmrg		if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) {
39105b261ecSmrg		     effMods= mods;
39205b261ecSmrg		     if (interps[n]->virtual_mod!=XkbNoModifier)
39305b261ecSmrg			new_vmodmask|= (1<<interps[n]->virtual_mod);
39405b261ecSmrg		}
39505b261ecSmrg		else effMods= 0;
39605b261ecSmrg		_XkbSetActionKeyMods(xkb,&pActs[n],effMods);
39705b261ecSmrg	    }
39805b261ecSmrg	    else pActs[n].type= XkbSA_NoAction;
39905b261ecSmrg	}
40005b261ecSmrg	if (((explicit&XkbExplicitVModMapMask)==0)&&
40105b261ecSmrg				(xkb->server->vmodmap[key]!=new_vmodmask)) {
40205b261ecSmrg	    changed|= XkbVirtualModMapMask;
40305b261ecSmrg	    xkb->server->vmodmap[key]= new_vmodmask;
40405b261ecSmrg	}
40505b261ecSmrg	if (interps[0]) {
40605b261ecSmrg	    if ((interps[0]->flags&XkbSI_LockingKey)&&
40705b261ecSmrg				((explicit&XkbExplicitBehaviorMask)==0)) {
40805b261ecSmrg		xkb->server->behaviors[key].type= XkbKB_Lock;
40905b261ecSmrg		changed|= XkbKeyBehaviorsMask;
41005b261ecSmrg	    }
41105b261ecSmrg	    if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
41205b261ecSmrg		CARD8 old;
41305b261ecSmrg		old= xkb->ctrls->per_key_repeat[key/8];
41405b261ecSmrg		if (interps[0]->flags&XkbSI_AutoRepeat)
41505b261ecSmrg		     xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
41605b261ecSmrg		else xkb->ctrls->per_key_repeat[key/8]&= ~(1<<(key%8));
41705b261ecSmrg		if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
41805b261ecSmrg		    changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
41905b261ecSmrg	    }
42005b261ecSmrg	}
42105b261ecSmrg    }
42205b261ecSmrg    if ((!found)||(interps[0]==NULL)) {
42305b261ecSmrg	if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
42405b261ecSmrg	    CARD8 old;
42505b261ecSmrg	    old= xkb->ctrls->per_key_repeat[key/8];
4264642e01fSmrg            xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
42705b261ecSmrg	    if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
42805b261ecSmrg		changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
42905b261ecSmrg	}
43005b261ecSmrg	if (((explicit&XkbExplicitBehaviorMask)==0)&&
43105b261ecSmrg		(xkb->server->behaviors[key].type==XkbKB_Lock)) {
43205b261ecSmrg		xkb->server->behaviors[key].type= XkbKB_Default;
43305b261ecSmrg		changed|= XkbKeyBehaviorsMask;
43405b261ecSmrg	}
43505b261ecSmrg    }
43605b261ecSmrg    if (changes) {
43705b261ecSmrg	XkbMapChangesPtr	mc;
43805b261ecSmrg	mc= &changes->map;
43905b261ecSmrg	tmp= (changed&mc->changed);
44005b261ecSmrg	if (tmp&XkbKeyActionsMask)
44105b261ecSmrg	    _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key);
44205b261ecSmrg	else if (changed&XkbKeyActionsMask) {
44305b261ecSmrg	    mc->changed|= XkbKeyActionsMask;
44405b261ecSmrg	    mc->first_key_act= key;
44505b261ecSmrg	    mc->num_key_acts= 1;
44605b261ecSmrg	}
44705b261ecSmrg	if (tmp&XkbKeyBehaviorsMask) {
44805b261ecSmrg	    _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors,
44905b261ecSmrg	    								key);
45005b261ecSmrg	}
45105b261ecSmrg	else if (changed&XkbKeyBehaviorsMask) {
45205b261ecSmrg	    mc->changed|= XkbKeyBehaviorsMask;
45305b261ecSmrg	    mc->first_key_behavior= key;
45405b261ecSmrg	    mc->num_key_behaviors= 1;
45505b261ecSmrg	}
45605b261ecSmrg	if (tmp&XkbVirtualModMapMask)
45705b261ecSmrg	    _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key);
45805b261ecSmrg	else if (changed&XkbVirtualModMapMask) {
45905b261ecSmrg	    mc->changed|= XkbVirtualModMapMask;
46005b261ecSmrg	    mc->first_vmodmap_key= key;
46105b261ecSmrg	    mc->num_vmodmap_keys= 1;
46205b261ecSmrg	}
46305b261ecSmrg	mc->changed|= changed;
46405b261ecSmrg    }
46505b261ecSmrg    if (interps!=ibuf)
46605b261ecSmrg	_XkbFree(interps);
46705b261ecSmrg    return True;
46805b261ecSmrg}
46905b261ecSmrg
47005b261ecSmrgStatus
47105b261ecSmrgXkbChangeTypesOfKey(	XkbDescPtr		 xkb,
47205b261ecSmrg			int		 	 key,
47305b261ecSmrg			int			 nGroups,
47405b261ecSmrg			unsigned	 	 groups,
47505b261ecSmrg			int	* 	 	 newTypesIn,
47605b261ecSmrg			XkbMapChangesPtr	 changes)
47705b261ecSmrg{
47805b261ecSmrgXkbKeyTypePtr	pOldType,pNewType;
47905b261ecSmrgregister int	i;
48005b261ecSmrgint		width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups];
48105b261ecSmrg
48205b261ecSmrg    if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) ||
4834642e01fSmrg	(!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)||
48405b261ecSmrg	(nGroups>XkbNumKbdGroups)) {
48505b261ecSmrg	return BadMatch;
48605b261ecSmrg    }
48705b261ecSmrg    if (nGroups==0) {
48805b261ecSmrg	for (i=0;i<XkbNumKbdGroups;i++) {
48905b261ecSmrg	    xkb->map->key_sym_map[key].kt_index[i]= XkbOneLevelIndex;
49005b261ecSmrg	}
49105b261ecSmrg	i= xkb->map->key_sym_map[key].group_info;
49205b261ecSmrg	i= XkbSetNumGroups(i,0);
49305b261ecSmrg	xkb->map->key_sym_map[key].group_info= i;
49405b261ecSmrg	XkbResizeKeySyms(xkb,key,0);
49505b261ecSmrg	return Success;
49605b261ecSmrg    }
49705b261ecSmrg
49805b261ecSmrg    nOldGroups= XkbKeyNumGroups(xkb,key);
49905b261ecSmrg    oldWidth= XkbKeyGroupsWidth(xkb,key);
50005b261ecSmrg    for (width=i=0;i<nGroups;i++) {
50105b261ecSmrg	if (groups&(1<<i))
50205b261ecSmrg	     newTypes[i]=  newTypesIn[i];
50305b261ecSmrg	else if (i<nOldGroups)
50405b261ecSmrg	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,i);
50505b261ecSmrg	else if (nOldGroups>0)
50605b261ecSmrg	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
50705b261ecSmrg	else newTypes[i]= XkbTwoLevelIndex;
50805b261ecSmrg	if (newTypes[i]>xkb->map->num_types)
50905b261ecSmrg	    return BadMatch;
51005b261ecSmrg	pNewType= &xkb->map->types[newTypes[i]];
51105b261ecSmrg	if (pNewType->num_levels>width)
51205b261ecSmrg	    width= pNewType->num_levels;
51305b261ecSmrg    }
51405b261ecSmrg    if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups))
51505b261ecSmrg	xkb->ctrls->num_groups= nGroups;
51605b261ecSmrg    if ((width!=oldWidth)||(nGroups!=nOldGroups)) {
51705b261ecSmrg	KeySym		oldSyms[XkbMaxSymsPerKey],*pSyms;
51805b261ecSmrg	int		nCopy;
51905b261ecSmrg
52005b261ecSmrg	if (nOldGroups==0) {
52105b261ecSmrg	    pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
52205b261ecSmrg	    if (pSyms!=NULL) {
52305b261ecSmrg		i= xkb->map->key_sym_map[key].group_info;
52405b261ecSmrg		i= XkbSetNumGroups(i,nGroups);
52505b261ecSmrg		xkb->map->key_sym_map[key].group_info= i;
52605b261ecSmrg		xkb->map->key_sym_map[key].width= width;
52705b261ecSmrg		for (i=0;i<nGroups;i++) {
52805b261ecSmrg		    xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
52905b261ecSmrg		}
53005b261ecSmrg		return Success;
53105b261ecSmrg	    }
53205b261ecSmrg	    return BadAlloc;
53305b261ecSmrg	}
53405b261ecSmrg	pSyms= XkbKeySymsPtr(xkb,key);
53505b261ecSmrg	memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
53605b261ecSmrg	pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
53705b261ecSmrg	if (pSyms==NULL)
53805b261ecSmrg	    return BadAlloc;
53905b261ecSmrg	bzero(pSyms,width*nGroups*sizeof(KeySym));
54005b261ecSmrg	for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
54105b261ecSmrg	    pOldType= XkbKeyKeyType(xkb,key,i);
54205b261ecSmrg	    pNewType= &xkb->map->types[newTypes[i]];
54305b261ecSmrg	    if (pNewType->num_levels>pOldType->num_levels)
54405b261ecSmrg		 nCopy= pOldType->num_levels;
54505b261ecSmrg	    else nCopy= pNewType->num_levels;
54605b261ecSmrg	    memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym));
54705b261ecSmrg	}
54805b261ecSmrg	if (XkbKeyHasActions(xkb,key)) {
54905b261ecSmrg	    XkbAction	oldActs[XkbMaxSymsPerKey],*pActs;
55005b261ecSmrg	    pActs= XkbKeyActionsPtr(xkb,key);
55105b261ecSmrg	    memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction));
55205b261ecSmrg	    pActs= XkbResizeKeyActions(xkb,key,width*nGroups);
55305b261ecSmrg	    if (pActs==NULL)
55405b261ecSmrg		return BadAlloc;
55505b261ecSmrg	    bzero(pActs,width*nGroups*sizeof(XkbAction));
55605b261ecSmrg	    for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
55705b261ecSmrg		pOldType= XkbKeyKeyType(xkb,key,i);
55805b261ecSmrg		pNewType= &xkb->map->types[newTypes[i]];
55905b261ecSmrg		if (pNewType->num_levels>pOldType->num_levels)
56005b261ecSmrg		     nCopy= pOldType->num_levels;
56105b261ecSmrg		else nCopy= pNewType->num_levels;
56205b261ecSmrg		memcpy(&pActs[i*width],&oldActs[i*oldWidth],
56305b261ecSmrg						nCopy*sizeof(XkbAction));
56405b261ecSmrg	    }
56505b261ecSmrg	}
56605b261ecSmrg	i= xkb->map->key_sym_map[key].group_info;
56705b261ecSmrg	i= XkbSetNumGroups(i,nGroups);
56805b261ecSmrg	xkb->map->key_sym_map[key].group_info= i;
56905b261ecSmrg	xkb->map->key_sym_map[key].width= width;
57005b261ecSmrg    }
57105b261ecSmrg    width= 0;
57205b261ecSmrg    for (i=0;i<nGroups;i++) {
57305b261ecSmrg	xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
57405b261ecSmrg	if (xkb->map->types[newTypes[i]].num_levels>width)
57505b261ecSmrg	    width= xkb->map->types[newTypes[i]].num_levels;
57605b261ecSmrg    }
57705b261ecSmrg    xkb->map->key_sym_map[key].width= width;
57805b261ecSmrg    if (changes!=NULL) {
57905b261ecSmrg	if (changes->changed&XkbKeySymsMask) {
58005b261ecSmrg	    _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms,
58105b261ecSmrg	    								key);
58205b261ecSmrg	}
58305b261ecSmrg	else {
58405b261ecSmrg	    changes->changed|= XkbKeySymsMask;
58505b261ecSmrg	    changes->first_key_sym= key;
58605b261ecSmrg	    changes->num_key_syms= 1;
58705b261ecSmrg	}
58805b261ecSmrg    }
58905b261ecSmrg    return Success;
59005b261ecSmrg}
59105b261ecSmrg
59205b261ecSmrg/***====================================================================***/
59305b261ecSmrg
59405b261ecSmrgBool
59505b261ecSmrgXkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn)
59605b261ecSmrg{
59705b261ecSmrgregister int i,bit;
59805b261ecSmrgregister unsigned mask;
59905b261ecSmrg
60005b261ecSmrg    if (xkb==NULL)
60105b261ecSmrg	return False;
60205b261ecSmrg    if (virtual_mask==0) {
60305b261ecSmrg	*mask_rtrn= 0;
60405b261ecSmrg	return True;
60505b261ecSmrg    }
60605b261ecSmrg    if (xkb->server==NULL)
60705b261ecSmrg	return False;
60805b261ecSmrg    for (i=mask=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
60905b261ecSmrg	if (virtual_mask&bit)
61005b261ecSmrg	    mask|= xkb->server->vmods[i];
61105b261ecSmrg    }
61205b261ecSmrg    *mask_rtrn= mask;
61305b261ecSmrg    return True;
61405b261ecSmrg}
61505b261ecSmrg
61605b261ecSmrg/***====================================================================***/
61705b261ecSmrg
61805b261ecSmrgstatic Bool
61905b261ecSmrgXkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed)
62005b261ecSmrg{
62105b261ecSmrgunsigned int	tmp;
62205b261ecSmrg
62305b261ecSmrg    switch (act->type) {
62405b261ecSmrg	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
62505b261ecSmrg	    if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) {
62605b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
62705b261ecSmrg		act->mods.mask= act->mods.real_mods;
62805b261ecSmrg		act->mods.mask|= tmp;
62905b261ecSmrg		return True;
63005b261ecSmrg	    }
63105b261ecSmrg	    break;
63205b261ecSmrg	case XkbSA_ISOLock:
63305b261ecSmrg	    if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) {
63405b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
63505b261ecSmrg		act->iso.mask= act->iso.real_mods;
63605b261ecSmrg		act->iso.mask|= tmp;
63705b261ecSmrg		return True;
63805b261ecSmrg	    }
63905b261ecSmrg	    break;
64005b261ecSmrg    }
64105b261ecSmrg    return False;
64205b261ecSmrg}
64305b261ecSmrg
64405b261ecSmrgstatic void
64505b261ecSmrgXkbUpdateKeyTypeVirtualMods(	XkbDescPtr	xkb,
64605b261ecSmrg				XkbKeyTypePtr	type,
64705b261ecSmrg				unsigned int	changed,
64805b261ecSmrg				XkbChangesPtr 	changes)
64905b261ecSmrg{
65005b261ecSmrgregister unsigned int	i;
65105b261ecSmrgunsigned int		mask;
65205b261ecSmrg
65305b261ecSmrg    XkbVirtualModsToReal(xkb,type->mods.vmods,&mask);
65405b261ecSmrg    type->mods.mask= type->mods.real_mods|mask;
65505b261ecSmrg    if ((type->map_count>0)&&(type->mods.vmods!=0)) {
65605b261ecSmrg	XkbKTMapEntryPtr entry;
65705b261ecSmrg	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
65805b261ecSmrg	    if (entry->mods.vmods!=0) {
65905b261ecSmrg		XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask);
66005b261ecSmrg		entry->mods.mask=entry->mods.real_mods|mask;
66105b261ecSmrg		/* entry is active if vmods are bound*/
66205b261ecSmrg	    	entry->active= (mask!=0);
66305b261ecSmrg	    }
66405b261ecSmrg	    else entry->active= 1;
66505b261ecSmrg	}
66605b261ecSmrg    }
66705b261ecSmrg    if (changes) {
66805b261ecSmrg	int	type_ndx;
66905b261ecSmrg	type_ndx= type-xkb->map->types;
67005b261ecSmrg	if ((type_ndx<0)||(type_ndx>xkb->map->num_types))
67105b261ecSmrg	    return;
67205b261ecSmrg	if (changes->map.changed&XkbKeyTypesMask) {
67305b261ecSmrg	    int last;
67405b261ecSmrg	    last= changes->map.first_type+changes->map.num_types-1;
67505b261ecSmrg	    if (type_ndx<changes->map.first_type) {
67605b261ecSmrg		changes->map.first_type= type_ndx;
67705b261ecSmrg		changes->map.num_types= (last-type_ndx)+1;
67805b261ecSmrg	    }
67905b261ecSmrg	    else if (type_ndx>last) {
68005b261ecSmrg		changes->map.num_types= (type_ndx-changes->map.first_type)+1;
68105b261ecSmrg	    }
68205b261ecSmrg	}
68305b261ecSmrg	else {
68405b261ecSmrg	    changes->map.changed|= XkbKeyTypesMask;
68505b261ecSmrg	    changes->map.first_type= type_ndx;
68605b261ecSmrg	    changes->map.num_types= 1;
68705b261ecSmrg	}
68805b261ecSmrg    }
68905b261ecSmrg    return;
69005b261ecSmrg}
69105b261ecSmrg
69205b261ecSmrgBool
69305b261ecSmrgXkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes)
69405b261ecSmrg{
69505b261ecSmrgregister int	i;
69605b261ecSmrgunsigned int	checkState = 0;
69705b261ecSmrg
69805b261ecSmrg    if ((!xkb) || (!xkb->map) || (changed==0))
69905b261ecSmrg	return False;
70005b261ecSmrg    for (i=0;i<xkb->map->num_types;i++) {
70105b261ecSmrg	if (xkb->map->types[i].mods.vmods & changed)
70205b261ecSmrg	XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes);
70305b261ecSmrg    }
70405b261ecSmrg    if (changed&xkb->ctrls->internal.vmods) {
70505b261ecSmrg	unsigned int	newMask;
70605b261ecSmrg	XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask);
70705b261ecSmrg	newMask|= xkb->ctrls->internal.real_mods;
70805b261ecSmrg	if (xkb->ctrls->internal.mask!=newMask) {
70905b261ecSmrg	    xkb->ctrls->internal.mask= newMask;
71005b261ecSmrg	    if (changes) {
71105b261ecSmrg		changes->ctrls.changed_ctrls|= XkbInternalModsMask;
71205b261ecSmrg		checkState= True;
71305b261ecSmrg	    }
71405b261ecSmrg	}
71505b261ecSmrg    }
71605b261ecSmrg    if (changed&xkb->ctrls->ignore_lock.vmods) {
71705b261ecSmrg	unsigned int	newMask;
71805b261ecSmrg	XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask);
71905b261ecSmrg	newMask|= xkb->ctrls->ignore_lock.real_mods;
72005b261ecSmrg	if (xkb->ctrls->ignore_lock.mask!=newMask) {
72105b261ecSmrg	    xkb->ctrls->ignore_lock.mask= newMask;
72205b261ecSmrg	    if (changes) {
72305b261ecSmrg		changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask;
72405b261ecSmrg		checkState= True;
72505b261ecSmrg	    }
72605b261ecSmrg	}
72705b261ecSmrg    }
72805b261ecSmrg    if (xkb->indicators!=NULL) {
72905b261ecSmrg	XkbIndicatorMapPtr map;
73005b261ecSmrg	map= &xkb->indicators->maps[0];
73105b261ecSmrg	for (i=0;i<XkbNumIndicators;i++,map++) {
73205b261ecSmrg	    if (map->mods.vmods&changed) {
73305b261ecSmrg		unsigned int newMask;
73405b261ecSmrg		XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask);
73505b261ecSmrg		newMask|= map->mods.real_mods;
73605b261ecSmrg		if (newMask!=map->mods.mask) {
73705b261ecSmrg		    map->mods.mask= newMask;
73805b261ecSmrg		    if (changes) {
73905b261ecSmrg			changes->indicators.map_changes|= (1<<i);
74005b261ecSmrg			checkState= True;
74105b261ecSmrg		    }
74205b261ecSmrg		}
74305b261ecSmrg	    }
74405b261ecSmrg	}
74505b261ecSmrg    }
74605b261ecSmrg    if (xkb->compat!=NULL) {
74705b261ecSmrg	XkbCompatMapPtr	compat;
74805b261ecSmrg	compat= xkb->compat;
74905b261ecSmrg	for (i=0;i<XkbNumKbdGroups;i++) {
75005b261ecSmrg	    unsigned int newMask;
75105b261ecSmrg	    XkbVirtualModsToReal(xkb,compat->groups[i].vmods,&newMask);
75205b261ecSmrg	    newMask|= compat->groups[i].real_mods;
75305b261ecSmrg	    if (compat->groups[i].mask!=newMask) {
75405b261ecSmrg		compat->groups[i].mask= newMask;
75505b261ecSmrg		if (changes) {
75605b261ecSmrg		    changes->compat.changed_groups|= (1<<i);
75705b261ecSmrg		    checkState= True;
75805b261ecSmrg		}
75905b261ecSmrg	    }
76005b261ecSmrg	}
76105b261ecSmrg    }
76205b261ecSmrg    if (xkb->map && xkb->server) {
76305b261ecSmrg	int highChange = 0, lowChange = -1;
76405b261ecSmrg	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
76505b261ecSmrg	    if (XkbKeyHasActions(xkb,i)) {
76605b261ecSmrg		register XkbAction *pAct;
76705b261ecSmrg		register int n;
76805b261ecSmrg
76905b261ecSmrg		pAct= XkbKeyActionsPtr(xkb,i);
77005b261ecSmrg		for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) {
77105b261ecSmrg		    if ((pAct->type!=XkbSA_NoAction)&&
77205b261ecSmrg			XkbUpdateActionVirtualMods(xkb,pAct,changed)) {
77305b261ecSmrg			if (lowChange<0)
77405b261ecSmrg			    lowChange= i;
77505b261ecSmrg			highChange= i;
77605b261ecSmrg		    }
77705b261ecSmrg		}
77805b261ecSmrg	    }
77905b261ecSmrg	}
78005b261ecSmrg	if (changes && (lowChange>0)) { /* something changed */
78105b261ecSmrg	    if (changes->map.changed&XkbKeyActionsMask) {
78205b261ecSmrg		int last;
78305b261ecSmrg		if (changes->map.first_key_act<lowChange)
78405b261ecSmrg		    lowChange= changes->map.first_key_act;
78505b261ecSmrg		last= changes->map.first_key_act+changes->map.num_key_acts-1;
78605b261ecSmrg		if (last>highChange)
78705b261ecSmrg		    highChange= last;
78805b261ecSmrg	    }
78905b261ecSmrg	    changes->map.changed|= 	XkbKeyActionsMask;
79005b261ecSmrg	    changes->map.first_key_act=	lowChange;
79105b261ecSmrg	    changes->map.num_key_acts=	(highChange-lowChange)+1;
79205b261ecSmrg	}
79305b261ecSmrg    }
79405b261ecSmrg    return checkState;
79505b261ecSmrg}
796