XKBMisc.c revision 6747b715
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#include <X11/Xproto.h>
3605b261ecSmrg#include "misc.h"
3705b261ecSmrg#include "inputstr.h"
3805b261ecSmrg#include <X11/keysym.h>
3905b261ecSmrg#define	XKBSRV_NEED_FILE_FUNCS
4005b261ecSmrg#include <xkbsrv.h>
4105b261ecSmrg
4205b261ecSmrg/***====================================================================***/
4305b261ecSmrg
4405b261ecSmrg#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
4505b261ecSmrg#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
4605b261ecSmrg
4705b261ecSmrgint
4805b261ecSmrgXkbKeyTypesForCoreSymbols(	XkbDescPtr	xkb,
4905b261ecSmrg				int		map_width,
5005b261ecSmrg				KeySym *	core_syms,
5105b261ecSmrg				unsigned int 	protected,
5205b261ecSmrg    				int *		types_inout,
5305b261ecSmrg				KeySym *	xkb_syms_rtrn)
5405b261ecSmrg{
5505b261ecSmrgregister int	i;
5605b261ecSmrgunsigned int	empty;
5705b261ecSmrgint		nSyms[XkbNumKbdGroups];
5805b261ecSmrgint		nGroups,tmp,groupsWidth;
596747b715SmrgBOOL		replicated = FALSE;
6005b261ecSmrg
6105b261ecSmrg    /* Section 12.2 of the protocol describes this process in more detail */
6205b261ecSmrg    /* Step 1:  find the # of symbols in the core mapping per group */
6305b261ecSmrg    groupsWidth= 2;
6405b261ecSmrg    for (i=0;i<XkbNumKbdGroups;i++) {
6505b261ecSmrg	if ((protected&(1<<i))&&(types_inout[i]<xkb->map->num_types)) {
6605b261ecSmrg	    nSyms[i]= xkb->map->types[types_inout[i]].num_levels;
6705b261ecSmrg	    if (nSyms[i]>groupsWidth)
6805b261ecSmrg		groupsWidth= nSyms[i];
6905b261ecSmrg	}
7005b261ecSmrg	else {
7105b261ecSmrg	    types_inout[i]= XkbTwoLevelIndex;	/* don't really know, yet */
7205b261ecSmrg	    nSyms[i]= 2;
7305b261ecSmrg	}
7405b261ecSmrg    }
7505b261ecSmrg    if (nSyms[XkbGroup1Index]<2)
7605b261ecSmrg	nSyms[XkbGroup1Index]= 2;
7705b261ecSmrg    if (nSyms[XkbGroup2Index]<2)
7805b261ecSmrg	nSyms[XkbGroup2Index]= 2;
7905b261ecSmrg    /* Step 2:	Copy the symbols from the core ordering to XKB ordering	*/
8005b261ecSmrg    /*		symbols in the core are in the order:			*/
8105b261ecSmrg    /*		G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*]	*/
8205b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0);
8305b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1);
8405b261ecSmrg    for (i=2;i<nSyms[XkbGroup1Index];i++) {
8505b261ecSmrg	xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,i)]= CORE_SYM(2+i);
8605b261ecSmrg    }
8705b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,0)]= CORE_SYM(2);
8805b261ecSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,1)]= CORE_SYM(3);
8905b261ecSmrg    tmp= 2+(nSyms[XkbGroup1Index]-2); /* offset to extra group2 syms */
9005b261ecSmrg    for (i=2;i<nSyms[XkbGroup2Index];i++) {
9105b261ecSmrg	xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,i)]= CORE_SYM(tmp+i);
9205b261ecSmrg    }
936747b715Smrg
946747b715Smrg    /* Special case: if only the first group is explicit, and the symbols
956747b715Smrg     * replicate across all groups, then we have a Section 12.4 replication */
966747b715Smrg    if ((protected & ~XkbExplicitKeyType1Mask) == 0)
976747b715Smrg    {
986747b715Smrg        int j, width = nSyms[XkbGroup1Index];
996747b715Smrg
1006747b715Smrg        replicated = TRUE;
1016747b715Smrg
1026747b715Smrg        /* Check ABAB in ABABCDECDEABCDE */
1036747b715Smrg        if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) ||
1046747b715Smrg            (width > 1 && CORE_SYM(1) != CORE_SYM(3)))
1056747b715Smrg            replicated = FALSE;
1066747b715Smrg
1076747b715Smrg        /* Check CDECDE in ABABCDECDEABCDE */
1086747b715Smrg        for (i = 2; i < width && replicated; i++)
1096747b715Smrg        {
1106747b715Smrg            if (CORE_SYM(2 + i) != CORE_SYM(i + width))
1116747b715Smrg                replicated = FALSE;
1126747b715Smrg        }
1136747b715Smrg
1146747b715Smrg        /* Check ABCDE in ABABCDECDEABCDE */
1156747b715Smrg        for (j = 2; replicated &&
1166747b715Smrg                    j < XkbNumKbdGroups &&
1176747b715Smrg                    map_width >= width * (j + 1); j++)
1186747b715Smrg        {
1196747b715Smrg            for (i = 0; i < width && replicated; i++)
1206747b715Smrg            {
1216747b715Smrg                if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j))
1226747b715Smrg                    replicated = FALSE;
1236747b715Smrg            }
1246747b715Smrg        }
1256747b715Smrg    }
1266747b715Smrg
1276747b715Smrg    if (replicated)
1286747b715Smrg    {
1296747b715Smrg	nSyms[XkbGroup2Index]= 0;
13005b261ecSmrg	nSyms[XkbGroup3Index]= 0;
13105b261ecSmrg	nSyms[XkbGroup4Index]= 0;
1326747b715Smrg	nGroups= 1;
1336747b715Smrg    } else
1346747b715Smrg    {
1356747b715Smrg        tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index];
1366747b715Smrg        if ((tmp>=map_width)&&
1376747b715Smrg                ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) {
1386747b715Smrg            nSyms[XkbGroup3Index]= 0;
1396747b715Smrg            nSyms[XkbGroup4Index]= 0;
1406747b715Smrg            nGroups= 2;
1416747b715Smrg        } else
1426747b715Smrg        {
1436747b715Smrg            nGroups= 3;
1446747b715Smrg            for (i=0;i<nSyms[XkbGroup3Index];i++,tmp++) {
1456747b715Smrg                xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index,i)]= CORE_SYM(tmp);
1466747b715Smrg            }
1476747b715Smrg            if ((tmp<map_width)||(protected&XkbExplicitKeyType4Mask)) {
1486747b715Smrg                nGroups= 4;
1496747b715Smrg                for (i=0;i<nSyms[XkbGroup4Index];i++,tmp++) {
1506747b715Smrg                    xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index,i)]= CORE_SYM(tmp);
1516747b715Smrg                }
1526747b715Smrg            }
1536747b715Smrg            else {
1546747b715Smrg                nSyms[XkbGroup4Index]= 0;
1556747b715Smrg            }
1566747b715Smrg        }
15705b261ecSmrg    }
15805b261ecSmrg    /* steps 3&4: alphanumeric expansion,  assign canonical types */
15905b261ecSmrg    empty= 0;
16005b261ecSmrg    for (i=0;i<nGroups;i++) {
16105b261ecSmrg	KeySym *syms;
16205b261ecSmrg	syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
16305b261ecSmrg	if ((nSyms[i]>1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) {
16405b261ecSmrg	    KeySym upper,lower;
1656747b715Smrg	    XkbConvertCase(syms[0],&lower,&upper);
16605b261ecSmrg	    if (upper!=lower) {
16705b261ecSmrg		xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower;
16805b261ecSmrg		xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper;
16905b261ecSmrg		if ((protected&(1<<i))==0)
17005b261ecSmrg		    types_inout[i]= XkbAlphabeticIndex;
17105b261ecSmrg	    }
17205b261ecSmrg	    else if ((protected&(1<<i))==0) {
17305b261ecSmrg		types_inout[i]= XkbOneLevelIndex;
17405b261ecSmrg	/*	nSyms[i]=	1;*/
17505b261ecSmrg	    }
17605b261ecSmrg	}
17705b261ecSmrg	if (((protected&(1<<i))==0)&&(types_inout[i]==XkbTwoLevelIndex)) {
1786747b715Smrg	    if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1]))
17905b261ecSmrg		types_inout[i]= XkbKeypadIndex;
18005b261ecSmrg	    else {
18105b261ecSmrg		KeySym upper,lower;
1826747b715Smrg		XkbConvertCase(syms[0],&lower,&upper);
18305b261ecSmrg		if ((syms[0]==lower)&&(syms[1]==upper))
18405b261ecSmrg		    types_inout[i]= XkbAlphabeticIndex;
18505b261ecSmrg	    }
18605b261ecSmrg	}
18705b261ecSmrg	if (syms[0]==NoSymbol) {
18805b261ecSmrg	    register int n;
18905b261ecSmrg	    Bool	found;
1906747b715Smrg	    for (n=1,found=FALSE;(!found)&&(n<nSyms[i]);n++) {
19105b261ecSmrg		found= (syms[n]!=NoSymbol);
19205b261ecSmrg	    }
19305b261ecSmrg	    if (!found)
19405b261ecSmrg		empty|= (1<<i);
19505b261ecSmrg	}
19605b261ecSmrg    }
19705b261ecSmrg    /* step 5: squoosh out empty groups */
19805b261ecSmrg    if (empty) {
19905b261ecSmrg	for (i=nGroups-1;i>=0;i--) {
20005b261ecSmrg	    if (((empty&(1<<i))==0)||(protected&(1<<i)))
20105b261ecSmrg		break;
20205b261ecSmrg	    nGroups--;
20305b261ecSmrg	}
20405b261ecSmrg    }
20505b261ecSmrg    if (nGroups<1)
20605b261ecSmrg	return 0;
20705b261ecSmrg
20805b261ecSmrg    /* step 6: replicate group 1 into group two, if necessary */
20905b261ecSmrg    if ((nGroups>1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) {
21005b261ecSmrg	if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) {
21105b261ecSmrg	    nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index];
21205b261ecSmrg	    types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index];
21305b261ecSmrg	    memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn,
21405b261ecSmrg							2*sizeof(KeySym));
21505b261ecSmrg	}
21605b261ecSmrg	else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) {
21705b261ecSmrg	    memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]],
21805b261ecSmrg	    				(char *)xkb_syms_rtrn,
21905b261ecSmrg					nSyms[XkbGroup1Index]*sizeof(KeySym));
22005b261ecSmrg	}
22105b261ecSmrg    }
22205b261ecSmrg
2234642e01fSmrg    /* step 7: check for all groups identical or all width 1
2244642e01fSmrg     *
2254642e01fSmrg     * Special feature: if group 1 has an explicit type and all other groups
2264642e01fSmrg     * have canonical types with same symbols, we assume it's info lost from
2274642e01fSmrg     * the core replication.
2284642e01fSmrg     */
22905b261ecSmrg    if (nGroups>1) {
2306747b715Smrg	Bool sameType,allOneLevel, canonical = TRUE;
23105b261ecSmrg	allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1);
2326747b715Smrg	for (i=1,sameType=TRUE;(allOneLevel||sameType)&&(i<nGroups);i++) {
23305b261ecSmrg	    sameType=(sameType&&(types_inout[i]==types_inout[XkbGroup1Index]));
23405b261ecSmrg	    if (allOneLevel)
23505b261ecSmrg		allOneLevel= (xkb->map->types[types_inout[i]].num_levels==1);
2364642e01fSmrg	    if (types_inout[i] > XkbLastRequiredType)
2376747b715Smrg		canonical = FALSE;
23805b261ecSmrg	}
2394642e01fSmrg	if (((sameType) || canonical)&&
24005b261ecSmrg	    (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){
24105b261ecSmrg	    register int s;
24205b261ecSmrg	    Bool	identical;
2436747b715Smrg	    for (i=1,identical=TRUE;identical&&(i<nGroups);i++) {
24405b261ecSmrg		KeySym *syms;
2456747b715Smrg                if (nSyms[i] != nSyms[XkbGroup1Index])
2466747b715Smrg                    identical = FALSE;
24705b261ecSmrg		syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
24805b261ecSmrg		for (s=0;identical&&(s<nSyms[i]);s++) {
24905b261ecSmrg		    if (syms[s]!=xkb_syms_rtrn[s])
2506747b715Smrg			identical= FALSE;
25105b261ecSmrg		}
25205b261ecSmrg	    }
25305b261ecSmrg	    if (identical)
25405b261ecSmrg		nGroups= 1;
25505b261ecSmrg	}
25605b261ecSmrg	if (allOneLevel && (nGroups>1)) {
25705b261ecSmrg	    KeySym *syms;
25805b261ecSmrg	    syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
25905b261ecSmrg	    nSyms[XkbGroup1Index]= 1;
26005b261ecSmrg	    for (i=1;i<nGroups;i++) {
26105b261ecSmrg		xkb_syms_rtrn[i]= syms[0];
26205b261ecSmrg		syms+= nSyms[i];
26305b261ecSmrg		nSyms[i]= 1;
26405b261ecSmrg	    }
26505b261ecSmrg	}
26605b261ecSmrg    }
26705b261ecSmrg    return nGroups;
26805b261ecSmrg}
26905b261ecSmrg
27005b261ecSmrgstatic XkbSymInterpretPtr
27105b261ecSmrg_XkbFindMatchingInterp(	XkbDescPtr	xkb,
27205b261ecSmrg			KeySym 		sym,
27305b261ecSmrg			unsigned int	real_mods,
27405b261ecSmrg			unsigned int	level)
27505b261ecSmrg{
27605b261ecSmrgregister unsigned	 i;
27705b261ecSmrgXkbSymInterpretPtr	 interp,rtrn;
27805b261ecSmrgCARD8			 mods;
27905b261ecSmrg
28005b261ecSmrg    rtrn= NULL;
28105b261ecSmrg    interp= xkb->compat->sym_interpret;
28205b261ecSmrg    for (i=0;i<xkb->compat->num_si;i++,interp++) {
28305b261ecSmrg	if ((interp->sym==NoSymbol)||(sym==interp->sym)) {
28405b261ecSmrg	    int match;
28505b261ecSmrg	    if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0))
28605b261ecSmrg		 mods= real_mods;
28705b261ecSmrg	    else mods= 0;
28805b261ecSmrg	    switch (interp->match&XkbSI_OpMask) {
28905b261ecSmrg		case XkbSI_NoneOf:
29005b261ecSmrg		    match= ((interp->mods&mods)==0);
29105b261ecSmrg		    break;
29205b261ecSmrg		case XkbSI_AnyOfOrNone:
29305b261ecSmrg		    match= ((mods==0)||((interp->mods&mods)!=0));
29405b261ecSmrg		    break;
29505b261ecSmrg		case XkbSI_AnyOf:
29605b261ecSmrg		    match= ((interp->mods&mods)!=0);
29705b261ecSmrg		    break;
29805b261ecSmrg		case XkbSI_AllOf:
29905b261ecSmrg		    match= ((interp->mods&mods)==interp->mods);
30005b261ecSmrg		    break;
30105b261ecSmrg		case XkbSI_Exactly:
30205b261ecSmrg		    match= (interp->mods==mods);
30305b261ecSmrg		    break;
30405b261ecSmrg		default:
30505b261ecSmrg		    match= 0;
30605b261ecSmrg		    break;
30705b261ecSmrg	    }
30805b261ecSmrg	    if (match) {
30905b261ecSmrg		if (interp->sym!=NoSymbol) {
31005b261ecSmrg		    return interp;
31105b261ecSmrg		}
31205b261ecSmrg		else if (rtrn==NULL) {
31305b261ecSmrg		    rtrn= interp;
31405b261ecSmrg		}
31505b261ecSmrg	    }
31605b261ecSmrg	}
31705b261ecSmrg    }
31805b261ecSmrg    return rtrn;
31905b261ecSmrg}
32005b261ecSmrg
32105b261ecSmrgstatic void
32205b261ecSmrg_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey)
32305b261ecSmrg{
32405b261ecSmrgKeyCode	last;
32505b261ecSmrg
32605b261ecSmrg    last= (*pFirst)+(*pNum);
32705b261ecSmrg    if (newKey<*pFirst) {
32805b261ecSmrg	*pFirst= newKey;
32905b261ecSmrg	*pNum= (last-newKey)+1;
33005b261ecSmrg    }
33105b261ecSmrg    else if (newKey>last) {
33205b261ecSmrg	*pNum= (last-*pFirst)+1;
33305b261ecSmrg    }
33405b261ecSmrg    return;
33505b261ecSmrg}
33605b261ecSmrg
33705b261ecSmrgstatic void
33805b261ecSmrg_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods)
33905b261ecSmrg{
34005b261ecSmrgunsigned	tmp;
34105b261ecSmrg
34205b261ecSmrg    switch (act->type) {
34305b261ecSmrg	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
34405b261ecSmrg	    if (act->mods.flags&XkbSA_UseModMapMods)
34505b261ecSmrg		act->mods.real_mods= act->mods.mask= mods;
34605b261ecSmrg	    if ((tmp= XkbModActionVMods(&act->mods))!=0) {
34705b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
34805b261ecSmrg		act->mods.mask|= tmp;
34905b261ecSmrg	    }
35005b261ecSmrg	    break;
35105b261ecSmrg	case XkbSA_ISOLock:
35205b261ecSmrg	    if (act->iso.flags&XkbSA_UseModMapMods)
35305b261ecSmrg		act->iso.real_mods= act->iso.mask= mods;
35405b261ecSmrg	    if ((tmp= XkbModActionVMods(&act->iso))!=0) {
35505b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
35605b261ecSmrg		act->iso.mask|= tmp;
35705b261ecSmrg	    }
35805b261ecSmrg	    break;
35905b261ecSmrg    }
36005b261ecSmrg    return;
36105b261ecSmrg}
36205b261ecSmrg
36305b261ecSmrg#define	IBUF_SIZE	8
36405b261ecSmrg
36505b261ecSmrgBool
36605b261ecSmrgXkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes)
36705b261ecSmrg{
36805b261ecSmrgKeySym *		syms;
36905b261ecSmrgunsigned char 		explicit,mods;
37005b261ecSmrgXkbSymInterpretPtr	*interps,ibuf[IBUF_SIZE];
37105b261ecSmrgint			n,nSyms,found;
37205b261ecSmrgunsigned		changed,tmp;
37305b261ecSmrg
37405b261ecSmrg    if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)||
37505b261ecSmrg    			(!xkb->compat)||(!xkb->compat->sym_interpret)||
37605b261ecSmrg			(key<xkb->min_key_code)||(key>xkb->max_key_code)) {
3776747b715Smrg	return FALSE;
37805b261ecSmrg    }
37905b261ecSmrg    if (((!xkb->server)||(!xkb->server->key_acts))&&
38005b261ecSmrg		(XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) {
3816747b715Smrg	return FALSE;
38205b261ecSmrg    }
38305b261ecSmrg    changed= 0;	/* keeps track of what has changed in _this_ call */
38405b261ecSmrg    explicit= xkb->server->explicit[key];
38505b261ecSmrg    if (explicit&XkbExplicitInterpretMask) /* nothing to do */
3866747b715Smrg	return TRUE;
38705b261ecSmrg    mods= (xkb->map->modmap?xkb->map->modmap[key]:0);
38805b261ecSmrg    nSyms= XkbKeyNumSyms(xkb,key);
38905b261ecSmrg    syms= XkbKeySymsPtr(xkb,key);
39005b261ecSmrg    if (nSyms>IBUF_SIZE) {
3916747b715Smrg	interps= calloc(nSyms, sizeof(XkbSymInterpretPtr));
39205b261ecSmrg	if (interps==NULL) {
39305b261ecSmrg	    interps= ibuf;
39405b261ecSmrg	    nSyms= IBUF_SIZE;
39505b261ecSmrg	}
39605b261ecSmrg    }
39705b261ecSmrg    else {
39805b261ecSmrg	interps= ibuf;
39905b261ecSmrg    }
40005b261ecSmrg    found= 0;
40105b261ecSmrg    for (n=0;n<nSyms;n++) {
40205b261ecSmrg	unsigned level= (n%XkbKeyGroupsWidth(xkb,key));
40305b261ecSmrg	interps[n]= NULL;
40405b261ecSmrg	if (syms[n]!=NoSymbol) {
40505b261ecSmrg	    interps[n]= _XkbFindMatchingInterp(xkb,syms[n],mods,level);
40605b261ecSmrg	    if (interps[n]&&interps[n]->act.type!=XkbSA_NoAction)
40705b261ecSmrg		found++;
40805b261ecSmrg	    else interps[n]= NULL;
40905b261ecSmrg	}
41005b261ecSmrg    }
41105b261ecSmrg    /* 1/28/96 (ef) -- XXX! WORKING HERE */
41205b261ecSmrg    if (!found) {
41305b261ecSmrg	if (xkb->server->key_acts[key]!=0) {
41405b261ecSmrg	    xkb->server->key_acts[key]= 0;
41505b261ecSmrg	    changed|= XkbKeyActionsMask;
41605b261ecSmrg	}
41705b261ecSmrg    }
41805b261ecSmrg    else {
41905b261ecSmrg	XkbAction *pActs;
42005b261ecSmrg	unsigned int	new_vmodmask;
42105b261ecSmrg	changed|= XkbKeyActionsMask;
42205b261ecSmrg	pActs= XkbResizeKeyActions(xkb,key,nSyms);
42305b261ecSmrg	if (!pActs) {
42405b261ecSmrg            if (nSyms > IBUF_SIZE)
4256747b715Smrg                free(interps);
4266747b715Smrg	    return FALSE;
42705b261ecSmrg        }
42805b261ecSmrg	new_vmodmask= 0;
42905b261ecSmrg	for (n=0;n<nSyms;n++) {
43005b261ecSmrg	    if (interps[n]) {
43105b261ecSmrg		unsigned effMods;
43205b261ecSmrg
43305b261ecSmrg		pActs[n]= *((XkbAction *)&interps[n]->act);
43405b261ecSmrg		if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) {
43505b261ecSmrg		     effMods= mods;
43605b261ecSmrg		     if (interps[n]->virtual_mod!=XkbNoModifier)
43705b261ecSmrg			new_vmodmask|= (1<<interps[n]->virtual_mod);
43805b261ecSmrg		}
43905b261ecSmrg		else effMods= 0;
44005b261ecSmrg		_XkbSetActionKeyMods(xkb,&pActs[n],effMods);
44105b261ecSmrg	    }
44205b261ecSmrg	    else pActs[n].type= XkbSA_NoAction;
44305b261ecSmrg	}
44405b261ecSmrg	if (((explicit&XkbExplicitVModMapMask)==0)&&
44505b261ecSmrg				(xkb->server->vmodmap[key]!=new_vmodmask)) {
44605b261ecSmrg	    changed|= XkbVirtualModMapMask;
44705b261ecSmrg	    xkb->server->vmodmap[key]= new_vmodmask;
44805b261ecSmrg	}
44905b261ecSmrg	if (interps[0]) {
45005b261ecSmrg	    if ((interps[0]->flags&XkbSI_LockingKey)&&
45105b261ecSmrg				((explicit&XkbExplicitBehaviorMask)==0)) {
45205b261ecSmrg		xkb->server->behaviors[key].type= XkbKB_Lock;
45305b261ecSmrg		changed|= XkbKeyBehaviorsMask;
45405b261ecSmrg	    }
45505b261ecSmrg	    if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
45605b261ecSmrg		CARD8 old;
45705b261ecSmrg		old= xkb->ctrls->per_key_repeat[key/8];
45805b261ecSmrg		if (interps[0]->flags&XkbSI_AutoRepeat)
45905b261ecSmrg		     xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
46005b261ecSmrg		else xkb->ctrls->per_key_repeat[key/8]&= ~(1<<(key%8));
46105b261ecSmrg		if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
46205b261ecSmrg		    changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
46305b261ecSmrg	    }
46405b261ecSmrg	}
46505b261ecSmrg    }
46605b261ecSmrg    if ((!found)||(interps[0]==NULL)) {
46705b261ecSmrg	if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
46805b261ecSmrg	    CARD8 old;
46905b261ecSmrg	    old= xkb->ctrls->per_key_repeat[key/8];
4704642e01fSmrg            xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
47105b261ecSmrg	    if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
47205b261ecSmrg		changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
47305b261ecSmrg	}
47405b261ecSmrg	if (((explicit&XkbExplicitBehaviorMask)==0)&&
47505b261ecSmrg		(xkb->server->behaviors[key].type==XkbKB_Lock)) {
47605b261ecSmrg		xkb->server->behaviors[key].type= XkbKB_Default;
47705b261ecSmrg		changed|= XkbKeyBehaviorsMask;
47805b261ecSmrg	}
47905b261ecSmrg    }
48005b261ecSmrg    if (changes) {
48105b261ecSmrg	XkbMapChangesPtr	mc;
48205b261ecSmrg	mc= &changes->map;
48305b261ecSmrg	tmp= (changed&mc->changed);
48405b261ecSmrg	if (tmp&XkbKeyActionsMask)
48505b261ecSmrg	    _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key);
48605b261ecSmrg	else if (changed&XkbKeyActionsMask) {
48705b261ecSmrg	    mc->changed|= XkbKeyActionsMask;
48805b261ecSmrg	    mc->first_key_act= key;
48905b261ecSmrg	    mc->num_key_acts= 1;
49005b261ecSmrg	}
49105b261ecSmrg	if (tmp&XkbKeyBehaviorsMask) {
49205b261ecSmrg	    _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors,
49305b261ecSmrg	    								key);
49405b261ecSmrg	}
49505b261ecSmrg	else if (changed&XkbKeyBehaviorsMask) {
49605b261ecSmrg	    mc->changed|= XkbKeyBehaviorsMask;
49705b261ecSmrg	    mc->first_key_behavior= key;
49805b261ecSmrg	    mc->num_key_behaviors= 1;
49905b261ecSmrg	}
50005b261ecSmrg	if (tmp&XkbVirtualModMapMask)
50105b261ecSmrg	    _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key);
50205b261ecSmrg	else if (changed&XkbVirtualModMapMask) {
50305b261ecSmrg	    mc->changed|= XkbVirtualModMapMask;
50405b261ecSmrg	    mc->first_vmodmap_key= key;
50505b261ecSmrg	    mc->num_vmodmap_keys= 1;
50605b261ecSmrg	}
50705b261ecSmrg	mc->changed|= changed;
50805b261ecSmrg    }
50905b261ecSmrg    if (interps!=ibuf)
5106747b715Smrg	free(interps);
5116747b715Smrg    return TRUE;
51205b261ecSmrg}
51305b261ecSmrg
51405b261ecSmrgStatus
51505b261ecSmrgXkbChangeTypesOfKey(	XkbDescPtr		 xkb,
51605b261ecSmrg			int		 	 key,
51705b261ecSmrg			int			 nGroups,
51805b261ecSmrg			unsigned	 	 groups,
51905b261ecSmrg			int	* 	 	 newTypesIn,
52005b261ecSmrg			XkbMapChangesPtr	 changes)
52105b261ecSmrg{
52205b261ecSmrgXkbKeyTypePtr	pOldType,pNewType;
52305b261ecSmrgregister int	i;
52405b261ecSmrgint		width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups];
52505b261ecSmrg
52605b261ecSmrg    if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) ||
5274642e01fSmrg	(!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)||
52805b261ecSmrg	(nGroups>XkbNumKbdGroups)) {
52905b261ecSmrg	return BadMatch;
53005b261ecSmrg    }
53105b261ecSmrg    if (nGroups==0) {
53205b261ecSmrg	for (i=0;i<XkbNumKbdGroups;i++) {
53305b261ecSmrg	    xkb->map->key_sym_map[key].kt_index[i]= XkbOneLevelIndex;
53405b261ecSmrg	}
53505b261ecSmrg	i= xkb->map->key_sym_map[key].group_info;
53605b261ecSmrg	i= XkbSetNumGroups(i,0);
53705b261ecSmrg	xkb->map->key_sym_map[key].group_info= i;
53805b261ecSmrg	XkbResizeKeySyms(xkb,key,0);
53905b261ecSmrg	return Success;
54005b261ecSmrg    }
54105b261ecSmrg
54205b261ecSmrg    nOldGroups= XkbKeyNumGroups(xkb,key);
54305b261ecSmrg    oldWidth= XkbKeyGroupsWidth(xkb,key);
54405b261ecSmrg    for (width=i=0;i<nGroups;i++) {
54505b261ecSmrg	if (groups&(1<<i))
54605b261ecSmrg	     newTypes[i]=  newTypesIn[i];
54705b261ecSmrg	else if (i<nOldGroups)
54805b261ecSmrg	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,i);
54905b261ecSmrg	else if (nOldGroups>0)
55005b261ecSmrg	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
55105b261ecSmrg	else newTypes[i]= XkbTwoLevelIndex;
55205b261ecSmrg	if (newTypes[i]>xkb->map->num_types)
55305b261ecSmrg	    return BadMatch;
55405b261ecSmrg	pNewType= &xkb->map->types[newTypes[i]];
55505b261ecSmrg	if (pNewType->num_levels>width)
55605b261ecSmrg	    width= pNewType->num_levels;
55705b261ecSmrg    }
55805b261ecSmrg    if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups))
55905b261ecSmrg	xkb->ctrls->num_groups= nGroups;
56005b261ecSmrg    if ((width!=oldWidth)||(nGroups!=nOldGroups)) {
56105b261ecSmrg	KeySym		oldSyms[XkbMaxSymsPerKey],*pSyms;
56205b261ecSmrg	int		nCopy;
56305b261ecSmrg
56405b261ecSmrg	if (nOldGroups==0) {
56505b261ecSmrg	    pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
56605b261ecSmrg	    if (pSyms!=NULL) {
56705b261ecSmrg		i= xkb->map->key_sym_map[key].group_info;
56805b261ecSmrg		i= XkbSetNumGroups(i,nGroups);
56905b261ecSmrg		xkb->map->key_sym_map[key].group_info= i;
57005b261ecSmrg		xkb->map->key_sym_map[key].width= width;
57105b261ecSmrg		for (i=0;i<nGroups;i++) {
57205b261ecSmrg		    xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
57305b261ecSmrg		}
57405b261ecSmrg		return Success;
57505b261ecSmrg	    }
57605b261ecSmrg	    return BadAlloc;
57705b261ecSmrg	}
57805b261ecSmrg	pSyms= XkbKeySymsPtr(xkb,key);
57905b261ecSmrg	memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
58005b261ecSmrg	pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
58105b261ecSmrg	if (pSyms==NULL)
58205b261ecSmrg	    return BadAlloc;
5836747b715Smrg	memset(pSyms, 0, width*nGroups*sizeof(KeySym));
58405b261ecSmrg	for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
58505b261ecSmrg	    pOldType= XkbKeyKeyType(xkb,key,i);
58605b261ecSmrg	    pNewType= &xkb->map->types[newTypes[i]];
58705b261ecSmrg	    if (pNewType->num_levels>pOldType->num_levels)
58805b261ecSmrg		 nCopy= pOldType->num_levels;
58905b261ecSmrg	    else nCopy= pNewType->num_levels;
59005b261ecSmrg	    memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym));
59105b261ecSmrg	}
59205b261ecSmrg	if (XkbKeyHasActions(xkb,key)) {
59305b261ecSmrg	    XkbAction	oldActs[XkbMaxSymsPerKey],*pActs;
59405b261ecSmrg	    pActs= XkbKeyActionsPtr(xkb,key);
59505b261ecSmrg	    memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction));
59605b261ecSmrg	    pActs= XkbResizeKeyActions(xkb,key,width*nGroups);
59705b261ecSmrg	    if (pActs==NULL)
59805b261ecSmrg		return BadAlloc;
5996747b715Smrg	    memset(pActs, 0, width*nGroups*sizeof(XkbAction));
60005b261ecSmrg	    for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
60105b261ecSmrg		pOldType= XkbKeyKeyType(xkb,key,i);
60205b261ecSmrg		pNewType= &xkb->map->types[newTypes[i]];
60305b261ecSmrg		if (pNewType->num_levels>pOldType->num_levels)
60405b261ecSmrg		     nCopy= pOldType->num_levels;
60505b261ecSmrg		else nCopy= pNewType->num_levels;
60605b261ecSmrg		memcpy(&pActs[i*width],&oldActs[i*oldWidth],
60705b261ecSmrg						nCopy*sizeof(XkbAction));
60805b261ecSmrg	    }
60905b261ecSmrg	}
61005b261ecSmrg	i= xkb->map->key_sym_map[key].group_info;
61105b261ecSmrg	i= XkbSetNumGroups(i,nGroups);
61205b261ecSmrg	xkb->map->key_sym_map[key].group_info= i;
61305b261ecSmrg	xkb->map->key_sym_map[key].width= width;
61405b261ecSmrg    }
61505b261ecSmrg    width= 0;
61605b261ecSmrg    for (i=0;i<nGroups;i++) {
61705b261ecSmrg	xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
61805b261ecSmrg	if (xkb->map->types[newTypes[i]].num_levels>width)
61905b261ecSmrg	    width= xkb->map->types[newTypes[i]].num_levels;
62005b261ecSmrg    }
62105b261ecSmrg    xkb->map->key_sym_map[key].width= width;
62205b261ecSmrg    if (changes!=NULL) {
62305b261ecSmrg	if (changes->changed&XkbKeySymsMask) {
62405b261ecSmrg	    _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms,
62505b261ecSmrg	    								key);
62605b261ecSmrg	}
62705b261ecSmrg	else {
62805b261ecSmrg	    changes->changed|= XkbKeySymsMask;
62905b261ecSmrg	    changes->first_key_sym= key;
63005b261ecSmrg	    changes->num_key_syms= 1;
63105b261ecSmrg	}
63205b261ecSmrg    }
63305b261ecSmrg    return Success;
63405b261ecSmrg}
63505b261ecSmrg
63605b261ecSmrg/***====================================================================***/
63705b261ecSmrg
63805b261ecSmrgBool
63905b261ecSmrgXkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn)
64005b261ecSmrg{
64105b261ecSmrgregister int i,bit;
64205b261ecSmrgregister unsigned mask;
64305b261ecSmrg
64405b261ecSmrg    if (xkb==NULL)
6456747b715Smrg	return FALSE;
64605b261ecSmrg    if (virtual_mask==0) {
64705b261ecSmrg	*mask_rtrn= 0;
6486747b715Smrg	return TRUE;
64905b261ecSmrg    }
65005b261ecSmrg    if (xkb->server==NULL)
6516747b715Smrg	return FALSE;
65205b261ecSmrg    for (i=mask=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
65305b261ecSmrg	if (virtual_mask&bit)
65405b261ecSmrg	    mask|= xkb->server->vmods[i];
65505b261ecSmrg    }
65605b261ecSmrg    *mask_rtrn= mask;
6576747b715Smrg    return TRUE;
65805b261ecSmrg}
65905b261ecSmrg
66005b261ecSmrg/***====================================================================***/
66105b261ecSmrg
66205b261ecSmrgstatic Bool
66305b261ecSmrgXkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed)
66405b261ecSmrg{
66505b261ecSmrgunsigned int	tmp;
66605b261ecSmrg
66705b261ecSmrg    switch (act->type) {
66805b261ecSmrg	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
66905b261ecSmrg	    if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) {
67005b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
67105b261ecSmrg		act->mods.mask= act->mods.real_mods;
67205b261ecSmrg		act->mods.mask|= tmp;
6736747b715Smrg		return TRUE;
67405b261ecSmrg	    }
67505b261ecSmrg	    break;
67605b261ecSmrg	case XkbSA_ISOLock:
67705b261ecSmrg	    if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) {
67805b261ecSmrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
67905b261ecSmrg		act->iso.mask= act->iso.real_mods;
68005b261ecSmrg		act->iso.mask|= tmp;
6816747b715Smrg		return TRUE;
68205b261ecSmrg	    }
68305b261ecSmrg	    break;
68405b261ecSmrg    }
6856747b715Smrg    return FALSE;
68605b261ecSmrg}
68705b261ecSmrg
68805b261ecSmrgstatic void
68905b261ecSmrgXkbUpdateKeyTypeVirtualMods(	XkbDescPtr	xkb,
69005b261ecSmrg				XkbKeyTypePtr	type,
69105b261ecSmrg				unsigned int	changed,
69205b261ecSmrg				XkbChangesPtr 	changes)
69305b261ecSmrg{
69405b261ecSmrgregister unsigned int	i;
69505b261ecSmrgunsigned int		mask;
69605b261ecSmrg
69705b261ecSmrg    XkbVirtualModsToReal(xkb,type->mods.vmods,&mask);
69805b261ecSmrg    type->mods.mask= type->mods.real_mods|mask;
69905b261ecSmrg    if ((type->map_count>0)&&(type->mods.vmods!=0)) {
70005b261ecSmrg	XkbKTMapEntryPtr entry;
70105b261ecSmrg	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
70205b261ecSmrg	    if (entry->mods.vmods!=0) {
70305b261ecSmrg		XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask);
70405b261ecSmrg		entry->mods.mask=entry->mods.real_mods|mask;
70505b261ecSmrg		/* entry is active if vmods are bound*/
70605b261ecSmrg	    	entry->active= (mask!=0);
70705b261ecSmrg	    }
70805b261ecSmrg	    else entry->active= 1;
70905b261ecSmrg	}
71005b261ecSmrg    }
71105b261ecSmrg    if (changes) {
71205b261ecSmrg	int	type_ndx;
71305b261ecSmrg	type_ndx= type-xkb->map->types;
71405b261ecSmrg	if ((type_ndx<0)||(type_ndx>xkb->map->num_types))
71505b261ecSmrg	    return;
71605b261ecSmrg	if (changes->map.changed&XkbKeyTypesMask) {
71705b261ecSmrg	    int last;
71805b261ecSmrg	    last= changes->map.first_type+changes->map.num_types-1;
71905b261ecSmrg	    if (type_ndx<changes->map.first_type) {
72005b261ecSmrg		changes->map.first_type= type_ndx;
72105b261ecSmrg		changes->map.num_types= (last-type_ndx)+1;
72205b261ecSmrg	    }
72305b261ecSmrg	    else if (type_ndx>last) {
72405b261ecSmrg		changes->map.num_types= (type_ndx-changes->map.first_type)+1;
72505b261ecSmrg	    }
72605b261ecSmrg	}
72705b261ecSmrg	else {
72805b261ecSmrg	    changes->map.changed|= XkbKeyTypesMask;
72905b261ecSmrg	    changes->map.first_type= type_ndx;
73005b261ecSmrg	    changes->map.num_types= 1;
73105b261ecSmrg	}
73205b261ecSmrg    }
73305b261ecSmrg    return;
73405b261ecSmrg}
73505b261ecSmrg
73605b261ecSmrgBool
73705b261ecSmrgXkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes)
73805b261ecSmrg{
73905b261ecSmrgregister int	i;
74005b261ecSmrgunsigned int	checkState = 0;
74105b261ecSmrg
74205b261ecSmrg    if ((!xkb) || (!xkb->map) || (changed==0))
7436747b715Smrg	return FALSE;
74405b261ecSmrg    for (i=0;i<xkb->map->num_types;i++) {
74505b261ecSmrg	if (xkb->map->types[i].mods.vmods & changed)
74605b261ecSmrg	XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes);
74705b261ecSmrg    }
74805b261ecSmrg    if (changed&xkb->ctrls->internal.vmods) {
74905b261ecSmrg	unsigned int	newMask;
75005b261ecSmrg	XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask);
75105b261ecSmrg	newMask|= xkb->ctrls->internal.real_mods;
75205b261ecSmrg	if (xkb->ctrls->internal.mask!=newMask) {
75305b261ecSmrg	    xkb->ctrls->internal.mask= newMask;
75405b261ecSmrg	    if (changes) {
75505b261ecSmrg		changes->ctrls.changed_ctrls|= XkbInternalModsMask;
7566747b715Smrg		checkState= TRUE;
75705b261ecSmrg	    }
75805b261ecSmrg	}
75905b261ecSmrg    }
76005b261ecSmrg    if (changed&xkb->ctrls->ignore_lock.vmods) {
76105b261ecSmrg	unsigned int	newMask;
76205b261ecSmrg	XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask);
76305b261ecSmrg	newMask|= xkb->ctrls->ignore_lock.real_mods;
76405b261ecSmrg	if (xkb->ctrls->ignore_lock.mask!=newMask) {
76505b261ecSmrg	    xkb->ctrls->ignore_lock.mask= newMask;
76605b261ecSmrg	    if (changes) {
76705b261ecSmrg		changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask;
7686747b715Smrg		checkState= TRUE;
76905b261ecSmrg	    }
77005b261ecSmrg	}
77105b261ecSmrg    }
77205b261ecSmrg    if (xkb->indicators!=NULL) {
77305b261ecSmrg	XkbIndicatorMapPtr map;
77405b261ecSmrg	map= &xkb->indicators->maps[0];
77505b261ecSmrg	for (i=0;i<XkbNumIndicators;i++,map++) {
77605b261ecSmrg	    if (map->mods.vmods&changed) {
77705b261ecSmrg		unsigned int newMask;
77805b261ecSmrg		XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask);
77905b261ecSmrg		newMask|= map->mods.real_mods;
78005b261ecSmrg		if (newMask!=map->mods.mask) {
78105b261ecSmrg		    map->mods.mask= newMask;
78205b261ecSmrg		    if (changes) {
78305b261ecSmrg			changes->indicators.map_changes|= (1<<i);
7846747b715Smrg			checkState= TRUE;
78505b261ecSmrg		    }
78605b261ecSmrg		}
78705b261ecSmrg	    }
78805b261ecSmrg	}
78905b261ecSmrg    }
79005b261ecSmrg    if (xkb->compat!=NULL) {
79105b261ecSmrg	XkbCompatMapPtr	compat;
79205b261ecSmrg	compat= xkb->compat;
79305b261ecSmrg	for (i=0;i<XkbNumKbdGroups;i++) {
79405b261ecSmrg	    unsigned int newMask;
79505b261ecSmrg	    XkbVirtualModsToReal(xkb,compat->groups[i].vmods,&newMask);
79605b261ecSmrg	    newMask|= compat->groups[i].real_mods;
79705b261ecSmrg	    if (compat->groups[i].mask!=newMask) {
79805b261ecSmrg		compat->groups[i].mask= newMask;
79905b261ecSmrg		if (changes) {
80005b261ecSmrg		    changes->compat.changed_groups|= (1<<i);
8016747b715Smrg		    checkState= TRUE;
80205b261ecSmrg		}
80305b261ecSmrg	    }
80405b261ecSmrg	}
80505b261ecSmrg    }
80605b261ecSmrg    if (xkb->map && xkb->server) {
80705b261ecSmrg	int highChange = 0, lowChange = -1;
80805b261ecSmrg	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
80905b261ecSmrg	    if (XkbKeyHasActions(xkb,i)) {
81005b261ecSmrg		register XkbAction *pAct;
81105b261ecSmrg		register int n;
81205b261ecSmrg
81305b261ecSmrg		pAct= XkbKeyActionsPtr(xkb,i);
81405b261ecSmrg		for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) {
81505b261ecSmrg		    if ((pAct->type!=XkbSA_NoAction)&&
81605b261ecSmrg			XkbUpdateActionVirtualMods(xkb,pAct,changed)) {
81705b261ecSmrg			if (lowChange<0)
81805b261ecSmrg			    lowChange= i;
81905b261ecSmrg			highChange= i;
82005b261ecSmrg		    }
82105b261ecSmrg		}
82205b261ecSmrg	    }
82305b261ecSmrg	}
82405b261ecSmrg	if (changes && (lowChange>0)) { /* something changed */
82505b261ecSmrg	    if (changes->map.changed&XkbKeyActionsMask) {
82605b261ecSmrg		int last;
82705b261ecSmrg		if (changes->map.first_key_act<lowChange)
82805b261ecSmrg		    lowChange= changes->map.first_key_act;
82905b261ecSmrg		last= changes->map.first_key_act+changes->map.num_key_acts-1;
83005b261ecSmrg		if (last>highChange)
83105b261ecSmrg		    highChange= last;
83205b261ecSmrg	    }
83305b261ecSmrg	    changes->map.changed|= 	XkbKeyActionsMask;
83405b261ecSmrg	    changes->map.first_key_act=	lowChange;
83505b261ecSmrg	    changes->map.num_key_acts=	(highChange-lowChange)+1;
83605b261ecSmrg	}
83705b261ecSmrg    }
83805b261ecSmrg    return checkState;
83905b261ecSmrg}
840