XKBMisc.c revision 61b2299d
11ab64890Smrg/* $Xorg: XKBMisc.c,v 1.4 2000/08/17 19:45:02 cpqbld Exp $ */
21ab64890Smrg/************************************************************
31ab64890SmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
41ab64890Smrg
51ab64890SmrgPermission to use, copy, modify, and distribute this
61ab64890Smrgsoftware and its documentation for any purpose and without
71ab64890Smrgfee is hereby granted, provided that the above copyright
81ab64890Smrgnotice appear in all copies and that both that copyright
91ab64890Smrgnotice and this permission notice appear in supporting
1061b2299dSmrgdocumentation, and that the name of Silicon Graphics not be
1161b2299dSmrgused in advertising or publicity pertaining to distribution
121ab64890Smrgof the software without specific prior written permission.
1361b2299dSmrgSilicon Graphics makes no representation about the suitability
141ab64890Smrgof this software for any purpose. It is provided "as is"
151ab64890Smrgwithout any express or implied warranty.
161ab64890Smrg
1761b2299dSmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1861b2299dSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
191ab64890SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
2061b2299dSmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2161b2299dSmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2261b2299dSmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
231ab64890SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
241ab64890SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
251ab64890Smrg
261ab64890Smrg********************************************************/
271ab64890Smrg/* $XFree86: xc/lib/X11/XKBMisc.c,v 3.5 2001/10/28 03:32:33 tsi Exp $ */
281ab64890Smrg
291ab64890Smrg#ifdef HAVE_DIX_CONFIG_H
301ab64890Smrg#include <dix-config.h>
311ab64890Smrg#elif defined(HAVE_CONFIG_H)
321ab64890Smrg#include <config.h>
331ab64890Smrg#endif
341ab64890Smrg
351ab64890Smrg#ifndef XKB_IN_SERVER
361ab64890Smrg
371ab64890Smrg#include <stdio.h>
381ab64890Smrg#define NEED_REPLIES
391ab64890Smrg#define NEED_EVENTS
401ab64890Smrg#include "Xlibint.h"
411ab64890Smrg#include <X11/extensions/XKBproto.h>
421ab64890Smrg#include <X11/keysym.h>
431ab64890Smrg#include "XKBlibint.h"
441ab64890Smrg
4561b2299dSmrg#else
461ab64890Smrg
471ab64890Smrg#include <stdio.h>
481ab64890Smrg#include <X11/X.h>
491ab64890Smrg#define	NEED_EVENTS
501ab64890Smrg#define	NEED_REPLIES
511ab64890Smrg#include <X11/Xproto.h>
521ab64890Smrg#include "misc.h"
531ab64890Smrg#include "inputstr.h"
541ab64890Smrg#include <X11/keysym.h>
551ab64890Smrg#define	XKBSRV_NEED_FILE_FUNCS
561ab64890Smrg#include <X11/extensions/XKBsrv.h>
571ab64890Smrg
581ab64890Smrg#endif /* XKB_IN_SERVER */
591ab64890Smrg
601ab64890Smrg/***====================================================================***/
611ab64890Smrg
621ab64890Smrg#define	mapSize(m)	(sizeof(m)/sizeof(XkbKTMapEntryRec))
6361b2299dSmrgstatic  XkbKTMapEntryRec map2Level[]= {
641ab64890Smrg  { True, ShiftMask, {1, ShiftMask, 0} }
651ab64890Smrg};
661ab64890Smrg
6761b2299dSmrgstatic  XkbKTMapEntryRec mapAlpha[]= {
681ab64890Smrg  { True, ShiftMask, { 1, ShiftMask, 0 } },
691ab64890Smrg  { True, LockMask,  { 0,  LockMask, 0 } }
701ab64890Smrg};
711ab64890Smrg
721ab64890Smrgstatic	XkbModsRec preAlpha[]= {
731ab64890Smrg	{        0,        0, 0 },
741ab64890Smrg	{ LockMask, LockMask, 0 }
751ab64890Smrg};
761ab64890Smrg
771ab64890Smrg#define	NL_VMOD_MASK	0
7861b2299dSmrgstatic  XkbKTMapEntryRec mapKeypad[]= {
791ab64890Smrg	{ True,	ShiftMask, { 1, ShiftMask,            0 } },
801ab64890Smrg	{ False,        0, { 1,         0, NL_VMOD_MASK } }
811ab64890Smrg};
821ab64890Smrg
831ab64890Smrgstatic	XkbKeyTypeRec	canonicalTypes[XkbNumRequiredTypes] = {
8461b2299dSmrg	{ { 0, 0, 0 },
851ab64890Smrg	  1,	/* num_levels */
861ab64890Smrg	  0,	/* map_count */
871ab64890Smrg	  NULL,		NULL,
881ab64890Smrg	  None,		NULL
891ab64890Smrg	},
9061b2299dSmrg	{ { ShiftMask, ShiftMask, 0 },
911ab64890Smrg	  2,	/* num_levels */
921ab64890Smrg	  mapSize(map2Level),	/* map_count */
931ab64890Smrg	  map2Level,	NULL,
941ab64890Smrg	  None,		NULL
951ab64890Smrg	},
9661b2299dSmrg	{ { ShiftMask|LockMask, ShiftMask|LockMask, 0 },
971ab64890Smrg	  2,				/* num_levels */
981ab64890Smrg	  mapSize(mapAlpha),		/* map_count */
991ab64890Smrg	  mapAlpha,	preAlpha,
1001ab64890Smrg	  None,		NULL
1011ab64890Smrg	},
1021ab64890Smrg	{ { ShiftMask, ShiftMask, NL_VMOD_MASK },
1031ab64890Smrg	  2,				/* num_levels */
1041ab64890Smrg	  mapSize(mapKeypad),		/* map_count */
1051ab64890Smrg	  mapKeypad,	NULL,
1061ab64890Smrg	  None,		NULL
1071ab64890Smrg	}
1081ab64890Smrg};
1091ab64890Smrg
1101ab64890SmrgStatus
1111ab64890SmrgXkbInitCanonicalKeyTypes(XkbDescPtr xkb,unsigned which,int keypadVMod)
1121ab64890Smrg{
1131ab64890SmrgXkbClientMapPtr	map;
1141ab64890SmrgXkbKeyTypePtr	from,to;
1151ab64890SmrgStatus		rtrn;
1161ab64890Smrg
1171ab64890Smrg    if (!xkb)
1181ab64890Smrg	return BadMatch;
1191ab64890Smrg    rtrn= XkbAllocClientMap(xkb,XkbKeyTypesMask,XkbNumRequiredTypes);
1201ab64890Smrg    if (rtrn!=Success)
1211ab64890Smrg	return rtrn;
1221ab64890Smrg    map= xkb->map;
1231ab64890Smrg    if ((which&XkbAllRequiredTypes)==0)
1241ab64890Smrg	return Success;
1251ab64890Smrg    rtrn= Success;
1261ab64890Smrg    from= canonicalTypes;
1271ab64890Smrg    to= map->types;
1281ab64890Smrg    if (which&XkbOneLevelMask)
1291ab64890Smrg	rtrn= XkbCopyKeyType(&from[XkbOneLevelIndex],&to[XkbOneLevelIndex]);
1301ab64890Smrg    if ((which&XkbTwoLevelMask)&&(rtrn==Success))
1311ab64890Smrg	rtrn= XkbCopyKeyType(&from[XkbTwoLevelIndex],&to[XkbTwoLevelIndex]);
1321ab64890Smrg    if ((which&XkbAlphabeticMask)&&(rtrn==Success))
1331ab64890Smrg	rtrn= XkbCopyKeyType(&from[XkbAlphabeticIndex],&to[XkbAlphabeticIndex]);
1341ab64890Smrg    if ((which&XkbKeypadMask)&&(rtrn==Success)) {
1351ab64890Smrg	XkbKeyTypePtr type;
1361ab64890Smrg	rtrn= XkbCopyKeyType(&from[XkbKeypadIndex],&to[XkbKeypadIndex]);
1371ab64890Smrg	type= &to[XkbKeypadIndex];
1381ab64890Smrg	if ((keypadVMod>=0)&&(keypadVMod<XkbNumVirtualMods)&&(rtrn==Success)) {
1391ab64890Smrg	    type->mods.vmods= (1<<keypadVMod);
1401ab64890Smrg	    type->map[0].active= True;
1411ab64890Smrg	    type->map[0].mods.mask= ShiftMask;
1421ab64890Smrg	    type->map[0].mods.real_mods= ShiftMask;
1431ab64890Smrg	    type->map[0].mods.vmods= 0;
1441ab64890Smrg	    type->map[0].level= 1;
1451ab64890Smrg	    type->map[1].active= False;
1461ab64890Smrg	    type->map[1].mods.mask= 0;
1471ab64890Smrg	    type->map[1].mods.real_mods= 0;
1481ab64890Smrg	    type->map[1].mods.vmods= (1<<keypadVMod);
1491ab64890Smrg	    type->map[1].level= 1;
1501ab64890Smrg	}
1511ab64890Smrg    }
1521ab64890Smrg    return Success;
1531ab64890Smrg}
1541ab64890Smrg
1551ab64890Smrg/***====================================================================***/
1561ab64890Smrg
1571ab64890Smrg#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
1581ab64890Smrg#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
1591ab64890Smrg
1601ab64890Smrgint
1611ab64890SmrgXkbKeyTypesForCoreSymbols(	XkbDescPtr	xkb,
1621ab64890Smrg				int		map_width,
1631ab64890Smrg				KeySym *	core_syms,
1641ab64890Smrg				unsigned int 	protected,
1651ab64890Smrg    				int *		types_inout,
1661ab64890Smrg				KeySym *	xkb_syms_rtrn)
1671ab64890Smrg{
1681ab64890Smrgregister int	i;
1691ab64890Smrgunsigned int	empty;
1701ab64890Smrgint		nSyms[XkbNumKbdGroups];
1711ab64890Smrgint		nGroups,tmp,groupsWidth;
1721ab64890Smrg
1731ab64890Smrg    /* Section 12.2 of the protocol describes this process in more detail */
1741ab64890Smrg    /* Step 1:  find the # of symbols in the core mapping per group */
1751ab64890Smrg    groupsWidth= 2;
1761ab64890Smrg    for (i=0;i<XkbNumKbdGroups;i++) {
1771ab64890Smrg	if ((protected&(1<<i))&&(types_inout[i]<xkb->map->num_types)) {
1781ab64890Smrg	    nSyms[i]= xkb->map->types[types_inout[i]].num_levels;
1791ab64890Smrg	    if (nSyms[i]>groupsWidth)
1801ab64890Smrg		groupsWidth= nSyms[i];
1811ab64890Smrg	}
1821ab64890Smrg	else {
1831ab64890Smrg	    types_inout[i]= XkbTwoLevelIndex;	/* don't really know, yet */
1841ab64890Smrg	    nSyms[i]= 2;
1851ab64890Smrg	}
1861ab64890Smrg    }
1871ab64890Smrg    if (nSyms[XkbGroup1Index]<2)
1881ab64890Smrg	nSyms[XkbGroup1Index]= 2;
1891ab64890Smrg    if (nSyms[XkbGroup2Index]<2)
1901ab64890Smrg	nSyms[XkbGroup2Index]= 2;
1911ab64890Smrg    /* Step 2:	Copy the symbols from the core ordering to XKB ordering	*/
1921ab64890Smrg    /*		symbols in the core are in the order:			*/
1931ab64890Smrg    /*		G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*]	*/
1941ab64890Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0);
1951ab64890Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1);
1961ab64890Smrg    for (i=2;i<nSyms[XkbGroup1Index];i++) {
1971ab64890Smrg	xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,i)]= CORE_SYM(2+i);
1981ab64890Smrg    }
1991ab64890Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,0)]= CORE_SYM(2);
2001ab64890Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,1)]= CORE_SYM(3);
2011ab64890Smrg    tmp= 2+(nSyms[XkbGroup1Index]-2); /* offset to extra group2 syms */
2021ab64890Smrg    for (i=2;i<nSyms[XkbGroup2Index];i++) {
2031ab64890Smrg	xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,i)]= CORE_SYM(tmp+i);
2041ab64890Smrg    }
2051ab64890Smrg    tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index];
2061ab64890Smrg    if ((tmp>=map_width)&&
2071ab64890Smrg	 ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) {
2081ab64890Smrg	nSyms[XkbGroup3Index]= 0;
2091ab64890Smrg	nSyms[XkbGroup4Index]= 0;
2101ab64890Smrg	nGroups= 2;
2111ab64890Smrg    }
2121ab64890Smrg    else {
2131ab64890Smrg    	nGroups= 3;
2141ab64890Smrg	for (i=0;i<nSyms[XkbGroup3Index];i++,tmp++) {
2151ab64890Smrg	    xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index,i)]= CORE_SYM(tmp);
2161ab64890Smrg	}
2171ab64890Smrg	if ((tmp<map_width)||(protected&XkbExplicitKeyType4Mask)) {
2181ab64890Smrg	    nGroups= 4;
2191ab64890Smrg	    for (i=0;i<nSyms[XkbGroup4Index];i++,tmp++) {
2201ab64890Smrg		xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index,i)]= CORE_SYM(tmp);
2211ab64890Smrg	    }
2221ab64890Smrg	}
2231ab64890Smrg	else {
2241ab64890Smrg	    nSyms[XkbGroup4Index]= 0;
2251ab64890Smrg	}
2261ab64890Smrg    }
2271ab64890Smrg    /* steps 3&4: alphanumeric expansion,  assign canonical types */
2281ab64890Smrg    empty= 0;
2291ab64890Smrg    for (i=0;i<nGroups;i++) {
2301ab64890Smrg	KeySym *syms;
2311ab64890Smrg	syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
2321ab64890Smrg	if ((nSyms[i]>1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) {
2331ab64890Smrg	    KeySym upper,lower;
2341ab64890Smrg	    XConvertCase(syms[0],&lower,&upper);
2351ab64890Smrg	    if (upper!=lower) {
2361ab64890Smrg		xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower;
2371ab64890Smrg		xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper;
2381ab64890Smrg		if ((protected&(1<<i))==0)
2391ab64890Smrg		    types_inout[i]= XkbAlphabeticIndex;
2401ab64890Smrg	    }
2411ab64890Smrg	    else if ((protected&(1<<i))==0) {
2421ab64890Smrg		types_inout[i]= XkbOneLevelIndex;
2431ab64890Smrg	/*	nSyms[i]=	1;*/
2441ab64890Smrg	    }
2451ab64890Smrg	}
2461ab64890Smrg	if (((protected&(1<<i))==0)&&(types_inout[i]==XkbTwoLevelIndex)) {
2471ab64890Smrg	    if (IsKeypadKey(syms[0])||IsKeypadKey(syms[1]))
2481ab64890Smrg		types_inout[i]= XkbKeypadIndex;
2491ab64890Smrg	    else {
2501ab64890Smrg		KeySym upper,lower;
2511ab64890Smrg		XConvertCase(syms[0],&lower,&upper);
2521ab64890Smrg		if ((syms[0]==lower)&&(syms[1]==upper))
2531ab64890Smrg		    types_inout[i]= XkbAlphabeticIndex;
2541ab64890Smrg	    }
2551ab64890Smrg	}
2561ab64890Smrg	if (syms[0]==NoSymbol) {
2571ab64890Smrg	    register int n;
2581ab64890Smrg	    Bool	found;
2591ab64890Smrg	    for (n=1,found=False;(!found)&&(n<nSyms[i]);n++) {
2601ab64890Smrg		found= (syms[n]!=NoSymbol);
2611ab64890Smrg	    }
2621ab64890Smrg	    if (!found)
2631ab64890Smrg		empty|= (1<<i);
2641ab64890Smrg	}
2651ab64890Smrg    }
2661ab64890Smrg    /* step 5: squoosh out empty groups */
2671ab64890Smrg    if (empty) {
2681ab64890Smrg	for (i=nGroups-1;i>=0;i--) {
2691ab64890Smrg	    if (((empty&(1<<i))==0)||(protected&(1<<i)))
2701ab64890Smrg		break;
2711ab64890Smrg	    nGroups--;
2721ab64890Smrg	}
2731ab64890Smrg    }
2741ab64890Smrg    if (nGroups<1)
2751ab64890Smrg	return 0;
2761ab64890Smrg
2771ab64890Smrg    /* step 6: replicate group 1 into group two, if necessary */
2781ab64890Smrg    if ((nGroups>1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) {
2791ab64890Smrg	if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) {
2801ab64890Smrg	    nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index];
2811ab64890Smrg	    types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index];
2821ab64890Smrg	    memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn,
2831ab64890Smrg							2*sizeof(KeySym));
2841ab64890Smrg	}
2851ab64890Smrg	else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) {
2861ab64890Smrg	    memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]],
2871ab64890Smrg	    				(char *)xkb_syms_rtrn,
2881ab64890Smrg					nSyms[XkbGroup1Index]*sizeof(KeySym));
2891ab64890Smrg	}
2901ab64890Smrg    }
2911ab64890Smrg
2921ab64890Smrg    /* step 7: check for all groups identical or all width 1 */
2931ab64890Smrg    if (nGroups>1) {
2941ab64890Smrg	Bool sameType,allOneLevel;
2951ab64890Smrg	allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1);
2961ab64890Smrg	for (i=1,sameType=True;(allOneLevel||sameType)&&(i<nGroups);i++) {
2971ab64890Smrg	    sameType=(sameType&&(types_inout[i]==types_inout[XkbGroup1Index]));
2981ab64890Smrg	    if (allOneLevel)
2991ab64890Smrg		allOneLevel= (xkb->map->types[types_inout[i]].num_levels==1);
3001ab64890Smrg	}
3011ab64890Smrg	if ((sameType)&&
3021ab64890Smrg	    (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){
3031ab64890Smrg	    register int s;
3041ab64890Smrg	    Bool	identical;
3051ab64890Smrg	    for (i=1,identical=True;identical&&(i<nGroups);i++) {
3061ab64890Smrg		KeySym *syms;
3071ab64890Smrg		syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
3081ab64890Smrg		for (s=0;identical&&(s<nSyms[i]);s++) {
3091ab64890Smrg		    if (syms[s]!=xkb_syms_rtrn[s])
3101ab64890Smrg			identical= False;
3111ab64890Smrg		}
3121ab64890Smrg	    }
3131ab64890Smrg	    if (identical)
3141ab64890Smrg		nGroups= 1;
3151ab64890Smrg	}
3161ab64890Smrg	if (allOneLevel && (nGroups>1)) {
3171ab64890Smrg	    KeySym *syms;
3181ab64890Smrg	    syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
3191ab64890Smrg	    nSyms[XkbGroup1Index]= 1;
3201ab64890Smrg	    for (i=1;i<nGroups;i++) {
3211ab64890Smrg		xkb_syms_rtrn[i]= syms[0];
3221ab64890Smrg		syms+= nSyms[i];
3231ab64890Smrg		nSyms[i]= 1;
3241ab64890Smrg	    }
3251ab64890Smrg	}
3261ab64890Smrg    }
3271ab64890Smrg    return nGroups;
3281ab64890Smrg}
3291ab64890Smrg
3301ab64890Smrgstatic XkbSymInterpretPtr
3311ab64890Smrg_XkbFindMatchingInterp(	XkbDescPtr	xkb,
3321ab64890Smrg			KeySym 		sym,
3331ab64890Smrg			unsigned int	real_mods,
3341ab64890Smrg			unsigned int	level)
3351ab64890Smrg{
3361ab64890Smrgregister unsigned	 i;
3371ab64890SmrgXkbSymInterpretPtr	 interp,rtrn;
3381ab64890SmrgCARD8			 mods;
3391ab64890Smrg
3401ab64890Smrg    rtrn= NULL;
3411ab64890Smrg    interp= xkb->compat->sym_interpret;
3421ab64890Smrg    for (i=0;i<xkb->compat->num_si;i++,interp++) {
3431ab64890Smrg	if ((interp->sym==NoSymbol)||(sym==interp->sym)) {
3441ab64890Smrg	    int match;
3451ab64890Smrg	    if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0))
3461ab64890Smrg		 mods= real_mods;
3471ab64890Smrg	    else mods= 0;
3481ab64890Smrg	    switch (interp->match&XkbSI_OpMask) {
3491ab64890Smrg		case XkbSI_NoneOf:
3501ab64890Smrg		    match= ((interp->mods&mods)==0);
3511ab64890Smrg		    break;
3521ab64890Smrg		case XkbSI_AnyOfOrNone:
3531ab64890Smrg		    match= ((mods==0)||((interp->mods&mods)!=0));
3541ab64890Smrg		    break;
3551ab64890Smrg		case XkbSI_AnyOf:
3561ab64890Smrg		    match= ((interp->mods&mods)!=0);
3571ab64890Smrg		    break;
3581ab64890Smrg		case XkbSI_AllOf:
3591ab64890Smrg		    match= ((interp->mods&mods)==interp->mods);
3601ab64890Smrg		    break;
3611ab64890Smrg		case XkbSI_Exactly:
3621ab64890Smrg		    match= (interp->mods==mods);
3631ab64890Smrg		    break;
3641ab64890Smrg		default:
3651ab64890Smrg		    match= 0;
3661ab64890Smrg		    break;
3671ab64890Smrg	    }
3681ab64890Smrg	    if (match) {
3691ab64890Smrg		if (interp->sym!=NoSymbol) {
3701ab64890Smrg		    return interp;
3711ab64890Smrg		}
3721ab64890Smrg		else if (rtrn==NULL) {
3731ab64890Smrg		    rtrn= interp;
3741ab64890Smrg		}
3751ab64890Smrg	    }
3761ab64890Smrg	}
3771ab64890Smrg    }
3781ab64890Smrg    return rtrn;
3791ab64890Smrg}
3801ab64890Smrg
3811ab64890Smrgstatic void
3821ab64890Smrg_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey)
3831ab64890Smrg{
3841ab64890SmrgKeyCode	last;
3851ab64890Smrg
3861ab64890Smrg    last= (*pFirst)+(*pNum);
3871ab64890Smrg    if (newKey<*pFirst) {
3881ab64890Smrg	*pFirst= newKey;
3891ab64890Smrg	*pNum= (last-newKey)+1;
3901ab64890Smrg    }
3911ab64890Smrg    else if (newKey>last) {
3921ab64890Smrg	*pNum= (last-*pFirst)+1;
3931ab64890Smrg    }
3941ab64890Smrg    return;
3951ab64890Smrg}
3961ab64890Smrg
3971ab64890Smrgstatic void
3981ab64890Smrg_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods)
3991ab64890Smrg{
4001ab64890Smrgunsigned	tmp;
4011ab64890Smrg
4021ab64890Smrg    switch (act->type) {
4031ab64890Smrg	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
4041ab64890Smrg	    if (act->mods.flags&XkbSA_UseModMapMods)
4051ab64890Smrg		act->mods.real_mods= act->mods.mask= mods;
4061ab64890Smrg	    if ((tmp= XkbModActionVMods(&act->mods))!=0) {
4071ab64890Smrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
4081ab64890Smrg		act->mods.mask|= tmp;
4091ab64890Smrg	    }
4101ab64890Smrg	    break;
4111ab64890Smrg	case XkbSA_ISOLock:
4121ab64890Smrg	    if (act->iso.flags&XkbSA_UseModMapMods)
4131ab64890Smrg		act->iso.real_mods= act->iso.mask= mods;
4141ab64890Smrg	    if ((tmp= XkbModActionVMods(&act->iso))!=0) {
4151ab64890Smrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
4161ab64890Smrg		act->iso.mask|= tmp;
4171ab64890Smrg	    }
4181ab64890Smrg	    break;
4191ab64890Smrg    }
4201ab64890Smrg    return;
4211ab64890Smrg}
4221ab64890Smrg
4231ab64890Smrg#define	IBUF_SIZE	8
4241ab64890Smrg
4251ab64890SmrgBool
4261ab64890SmrgXkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes)
4271ab64890Smrg{
4281ab64890SmrgKeySym *		syms;
4291ab64890Smrgunsigned char 		explicit,mods;
43061b2299dSmrgXkbSymInterpretPtr	*interps,ibuf[IBUF_SIZE];
4311ab64890Smrgint			n,nSyms,found;
4321ab64890Smrgunsigned		changed,tmp;
4331ab64890Smrg
4341ab64890Smrg    if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)||
4351ab64890Smrg    			(!xkb->compat)||(!xkb->compat->sym_interpret)||
4361ab64890Smrg			(key<xkb->min_key_code)||(key>xkb->max_key_code)) {
4371ab64890Smrg	return False;
4381ab64890Smrg    }
4391ab64890Smrg    if (((!xkb->server)||(!xkb->server->key_acts))&&
4401ab64890Smrg		(XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) {
4411ab64890Smrg	return False;
4421ab64890Smrg    }
4431ab64890Smrg    changed= 0;	/* keeps track of what has changed in _this_ call */
4441ab64890Smrg    explicit= xkb->server->explicit[key];
4451ab64890Smrg    if (explicit&XkbExplicitInterpretMask) /* nothing to do */
4461ab64890Smrg	return True;
4471ab64890Smrg    mods= (xkb->map->modmap?xkb->map->modmap[key]:0);
4481ab64890Smrg    nSyms= XkbKeyNumSyms(xkb,key);
4491ab64890Smrg    syms= XkbKeySymsPtr(xkb,key);
4501ab64890Smrg    if (nSyms>IBUF_SIZE) {
4511ab64890Smrg	interps= _XkbTypedCalloc(nSyms,XkbSymInterpretPtr);
4521ab64890Smrg	if (interps==NULL) {
4531ab64890Smrg	    interps= ibuf;
4541ab64890Smrg	    nSyms= IBUF_SIZE;
4551ab64890Smrg	}
4561ab64890Smrg    }
4571ab64890Smrg    else {
4581ab64890Smrg	interps= ibuf;
4591ab64890Smrg    }
4601ab64890Smrg    found= 0;
4611ab64890Smrg    for (n=0;n<nSyms;n++) {
4621ab64890Smrg	unsigned level= (n%XkbKeyGroupsWidth(xkb,key));
4631ab64890Smrg	interps[n]= NULL;
4641ab64890Smrg	if (syms[n]!=NoSymbol) {
4651ab64890Smrg	    interps[n]= _XkbFindMatchingInterp(xkb,syms[n],mods,level);
4661ab64890Smrg	    if (interps[n]&&interps[n]->act.type!=XkbSA_NoAction)
4671ab64890Smrg		found++;
4681ab64890Smrg	    else interps[n]= NULL;
4691ab64890Smrg	}
4701ab64890Smrg    }
4711ab64890Smrg    /* 1/28/96 (ef) -- XXX! WORKING HERE */
4721ab64890Smrg    if (!found) {
4731ab64890Smrg	if (xkb->server->key_acts[key]!=0) {
4741ab64890Smrg	    xkb->server->key_acts[key]= 0;
4751ab64890Smrg	    changed|= XkbKeyActionsMask;
4761ab64890Smrg	}
4771ab64890Smrg    }
4781ab64890Smrg    else {
4791ab64890Smrg	XkbAction *pActs;
4801ab64890Smrg	unsigned int	new_vmodmask;
4811ab64890Smrg	changed|= XkbKeyActionsMask;
4821ab64890Smrg	pActs= XkbResizeKeyActions(xkb,key,nSyms);
4831ab64890Smrg	if (!pActs) {
4841ab64890Smrg            if (nSyms > IBUF_SIZE)
4851ab64890Smrg                Xfree(interps);
4861ab64890Smrg	    return False;
4871ab64890Smrg        }
4881ab64890Smrg	new_vmodmask= 0;
4891ab64890Smrg	for (n=0;n<nSyms;n++) {
4901ab64890Smrg	    if (interps[n]) {
4911ab64890Smrg		unsigned effMods;
4921ab64890Smrg
4931ab64890Smrg		pActs[n]= *((XkbAction *)&interps[n]->act);
4941ab64890Smrg		if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) {
4951ab64890Smrg		     effMods= mods;
4961ab64890Smrg		     if (interps[n]->virtual_mod!=XkbNoModifier)
4971ab64890Smrg			new_vmodmask|= (1<<interps[n]->virtual_mod);
4981ab64890Smrg		}
4991ab64890Smrg		else effMods= 0;
5001ab64890Smrg		_XkbSetActionKeyMods(xkb,&pActs[n],effMods);
5011ab64890Smrg	    }
5021ab64890Smrg	    else pActs[n].type= XkbSA_NoAction;
5031ab64890Smrg	}
5041ab64890Smrg	if (((explicit&XkbExplicitVModMapMask)==0)&&
5051ab64890Smrg				(xkb->server->vmodmap[key]!=new_vmodmask)) {
5061ab64890Smrg	    changed|= XkbVirtualModMapMask;
5071ab64890Smrg	    xkb->server->vmodmap[key]= new_vmodmask;
5081ab64890Smrg	}
5091ab64890Smrg	if (interps[0]) {
5101ab64890Smrg	    if ((interps[0]->flags&XkbSI_LockingKey)&&
5111ab64890Smrg				((explicit&XkbExplicitBehaviorMask)==0)) {
5121ab64890Smrg		xkb->server->behaviors[key].type= XkbKB_Lock;
5131ab64890Smrg		changed|= XkbKeyBehaviorsMask;
5141ab64890Smrg	    }
5151ab64890Smrg	    if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
5161ab64890Smrg		CARD8 old;
5171ab64890Smrg		old= xkb->ctrls->per_key_repeat[key/8];
5181ab64890Smrg		if (interps[0]->flags&XkbSI_AutoRepeat)
5191ab64890Smrg		     xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
5201ab64890Smrg		else xkb->ctrls->per_key_repeat[key/8]&= ~(1<<(key%8));
5211ab64890Smrg		if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
5221ab64890Smrg		    changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
5231ab64890Smrg	    }
5241ab64890Smrg	}
5251ab64890Smrg    }
5261ab64890Smrg    if ((!found)||(interps[0]==NULL)) {
5271ab64890Smrg	if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
5281ab64890Smrg	    CARD8 old;
5291ab64890Smrg	    old= xkb->ctrls->per_key_repeat[key/8];
5301ab64890Smrg#ifdef RETURN_SHOULD_REPEAT
5311ab64890Smrg	    if (*XkbKeySymsPtr(xkb,key) != XK_Return)
5321ab64890Smrg#endif
5331ab64890Smrg		xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
5341ab64890Smrg	    if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
5351ab64890Smrg		changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
5361ab64890Smrg	}
5371ab64890Smrg	if (((explicit&XkbExplicitBehaviorMask)==0)&&
5381ab64890Smrg		(xkb->server->behaviors[key].type==XkbKB_Lock)) {
5391ab64890Smrg		xkb->server->behaviors[key].type= XkbKB_Default;
5401ab64890Smrg		changed|= XkbKeyBehaviorsMask;
5411ab64890Smrg	}
5421ab64890Smrg    }
5431ab64890Smrg    if (changes) {
5441ab64890Smrg	XkbMapChangesPtr	mc;
5451ab64890Smrg	mc= &changes->map;
5461ab64890Smrg	tmp= (changed&mc->changed);
5471ab64890Smrg	if (tmp&XkbKeyActionsMask)
5481ab64890Smrg	    _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key);
5491ab64890Smrg	else if (changed&XkbKeyActionsMask) {
5501ab64890Smrg	    mc->changed|= XkbKeyActionsMask;
5511ab64890Smrg	    mc->first_key_act= key;
5521ab64890Smrg	    mc->num_key_acts= 1;
5531ab64890Smrg	}
5541ab64890Smrg	if (tmp&XkbKeyBehaviorsMask) {
5551ab64890Smrg	    _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors,
5561ab64890Smrg	    								key);
5571ab64890Smrg	}
5581ab64890Smrg	else if (changed&XkbKeyBehaviorsMask) {
5591ab64890Smrg	    mc->changed|= XkbKeyBehaviorsMask;
5601ab64890Smrg	    mc->first_key_behavior= key;
5611ab64890Smrg	    mc->num_key_behaviors= 1;
5621ab64890Smrg	}
5631ab64890Smrg	if (tmp&XkbVirtualModMapMask)
5641ab64890Smrg	    _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key);
5651ab64890Smrg	else if (changed&XkbVirtualModMapMask) {
5661ab64890Smrg	    mc->changed|= XkbVirtualModMapMask;
5671ab64890Smrg	    mc->first_vmodmap_key= key;
5681ab64890Smrg	    mc->num_vmodmap_keys= 1;
5691ab64890Smrg	}
5701ab64890Smrg	mc->changed|= changed;
5711ab64890Smrg    }
5721ab64890Smrg    if (interps!=ibuf)
5731ab64890Smrg	_XkbFree(interps);
5741ab64890Smrg    return True;
5751ab64890Smrg}
5761ab64890Smrg
5771ab64890SmrgBool
5781ab64890SmrgXkbUpdateMapFromCore(	XkbDescPtr	xkb,
5791ab64890Smrg			KeyCode		first_key,
5801ab64890Smrg			int		num_keys,
5811ab64890Smrg			int		map_width,
5821ab64890Smrg			KeySym *	core_keysyms,
5831ab64890Smrg			XkbChangesPtr	changes)
5841ab64890Smrg{
5851ab64890Smrgregister int	key,last_key;
5861ab64890SmrgKeySym *	syms;
5871ab64890Smrg
5881ab64890Smrg    syms= &core_keysyms[(first_key-xkb->min_key_code)*map_width];
5891ab64890Smrg    if (changes) {
5901ab64890Smrg	if (changes->map.changed&XkbKeySymsMask) {
5911ab64890Smrg	    _XkbAddKeyChange(&changes->map.first_key_sym,
5921ab64890Smrg	    			&changes->map.num_key_syms,first_key);
5931ab64890Smrg	    if (num_keys>1) {
5941ab64890Smrg		_XkbAddKeyChange(&changes->map.first_key_sym,
5951ab64890Smrg						&changes->map.num_key_syms,
5961ab64890Smrg						first_key+num_keys-1);
5971ab64890Smrg	    }
5981ab64890Smrg	}
5991ab64890Smrg	else {
6001ab64890Smrg	    changes->map.changed|= XkbKeySymsMask;
6011ab64890Smrg	    changes->map.first_key_sym= first_key;
6021ab64890Smrg	    changes->map.num_key_syms= num_keys;
6031ab64890Smrg	}
6041ab64890Smrg    }
6051ab64890Smrg    last_key= first_key+num_keys-1;
6061ab64890Smrg    for (key=first_key;key<=last_key;key++,syms+= map_width) {
6071ab64890Smrg	XkbMapChangesPtr	mc;
6081ab64890Smrg	unsigned		explicit;
6091ab64890Smrg	KeySym			tsyms[XkbMaxSymsPerKey];
6101ab64890Smrg	int	 		types[XkbNumKbdGroups];
6111ab64890Smrg	int			nG;
6121ab64890Smrg
6131ab64890Smrg	explicit= xkb->server->explicit[key]&XkbExplicitKeyTypesMask;
6141ab64890Smrg	types[XkbGroup1Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
6151ab64890Smrg	types[XkbGroup2Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup2Index);
6161ab64890Smrg	types[XkbGroup3Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup3Index);
6171ab64890Smrg	types[XkbGroup4Index]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup4Index);
6181ab64890Smrg	nG= XkbKeyTypesForCoreSymbols(xkb,map_width,syms,explicit,types,tsyms);
6191ab64890Smrg	if (changes)
6201ab64890Smrg	     mc= &changes->map;
6211ab64890Smrg	else mc= NULL;
6221ab64890Smrg	XkbChangeTypesOfKey(xkb,key,nG,XkbAllGroupsMask,types,mc);
6231ab64890Smrg	memcpy((char *)XkbKeySymsPtr(xkb,key),(char *)tsyms,
6241ab64890Smrg					XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
6251ab64890Smrg	XkbApplyCompatMapToKey(xkb,key,changes);
6261ab64890Smrg    }
6271ab64890Smrg
6281ab64890Smrg    if ((xkb->server->vmods!=NULL)&&(xkb->map->modmap!=NULL)&&(changes)&&
6291ab64890Smrg	(changes->map.changed&(XkbVirtualModMapMask|XkbModifierMapMask))) {
6301ab64890Smrg	unsigned char		newVMods[XkbNumVirtualMods];
6311ab64890Smrg	register  unsigned 	bit,i;
6321ab64890Smrg	unsigned		present;
6331ab64890Smrg
6341ab64890Smrg	bzero(newVMods,XkbNumVirtualMods);
6351ab64890Smrg	present= 0;
6361ab64890Smrg	for (key=xkb->min_key_code;key<=xkb->max_key_code;key++) {
6371ab64890Smrg	    if (xkb->server->vmodmap[key]==0)
6381ab64890Smrg		continue;
6391ab64890Smrg	    for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
6401ab64890Smrg		if (bit&xkb->server->vmodmap[key]) {
6411ab64890Smrg		    present|= bit;
6421ab64890Smrg		    newVMods[i]|= xkb->map->modmap[key];
6431ab64890Smrg		}
6441ab64890Smrg	    }
6451ab64890Smrg	}
6461ab64890Smrg	for (i=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
6471ab64890Smrg	    if ((bit&present)&&(newVMods[i]!=xkb->server->vmods[i])) {
6481ab64890Smrg		changes->map.changed|= XkbVirtualModsMask;
6491ab64890Smrg		changes->map.vmods|= bit;
6501ab64890Smrg		xkb->server->vmods[i]= newVMods[i];
6511ab64890Smrg	    }
6521ab64890Smrg	}
6531ab64890Smrg    }
6541ab64890Smrg    if (changes && (changes->map.changed&XkbVirtualModsMask))
6551ab64890Smrg	XkbApplyVirtualModChanges(xkb,changes->map.vmods,changes);
6561ab64890Smrg    return True;
6571ab64890Smrg}
6581ab64890Smrg
6591ab64890SmrgStatus
6601ab64890SmrgXkbChangeTypesOfKey(	XkbDescPtr		 xkb,
6611ab64890Smrg			int		 	 key,
6621ab64890Smrg			int			 nGroups,
6631ab64890Smrg			unsigned	 	 groups,
6641ab64890Smrg			int	* 	 	 newTypesIn,
6651ab64890Smrg			XkbMapChangesPtr	 changes)
6661ab64890Smrg{
6671ab64890SmrgXkbKeyTypePtr	pOldType,pNewType;
6681ab64890Smrgregister int	i;
6691ab64890Smrgint		width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups];
6701ab64890Smrg
6711ab64890Smrg    if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) ||
67261b2299dSmrg	(!xkb->map->types)||((groups&XkbAllGroupsMask)==0)||
6731ab64890Smrg	(nGroups>XkbNumKbdGroups)) {
6741ab64890Smrg	return BadMatch;
6751ab64890Smrg    }
6761ab64890Smrg    if (nGroups==0) {
6771ab64890Smrg	for (i=0;i<XkbNumKbdGroups;i++) {
6781ab64890Smrg	    xkb->map->key_sym_map[key].kt_index[i]= XkbOneLevelIndex;
6791ab64890Smrg	}
6801ab64890Smrg	i= xkb->map->key_sym_map[key].group_info;
6811ab64890Smrg	i= XkbSetNumGroups(i,0);
6821ab64890Smrg	xkb->map->key_sym_map[key].group_info= i;
6831ab64890Smrg	XkbResizeKeySyms(xkb,key,0);
6841ab64890Smrg	return Success;
6851ab64890Smrg    }
6861ab64890Smrg
6871ab64890Smrg    nOldGroups= XkbKeyNumGroups(xkb,key);
6881ab64890Smrg    oldWidth= XkbKeyGroupsWidth(xkb,key);
6891ab64890Smrg    for (width=i=0;i<nGroups;i++) {
6901ab64890Smrg	if (groups&(1<<i))
6911ab64890Smrg	     newTypes[i]=  newTypesIn[i];
6921ab64890Smrg	else if (i<nOldGroups)
6931ab64890Smrg	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,i);
6941ab64890Smrg	else if (nOldGroups>0)
6951ab64890Smrg	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
6961ab64890Smrg	else newTypes[i]= XkbTwoLevelIndex;
6971ab64890Smrg	if (newTypes[i]>xkb->map->num_types)
6981ab64890Smrg	    return BadMatch;
6991ab64890Smrg	pNewType= &xkb->map->types[newTypes[i]];
7001ab64890Smrg	if (pNewType->num_levels>width)
7011ab64890Smrg	    width= pNewType->num_levels;
7021ab64890Smrg    }
7031ab64890Smrg    if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups))
7041ab64890Smrg	xkb->ctrls->num_groups= nGroups;
7051ab64890Smrg    if ((width!=oldWidth)||(nGroups!=nOldGroups)) {
7061ab64890Smrg	KeySym		oldSyms[XkbMaxSymsPerKey],*pSyms;
7071ab64890Smrg	int		nCopy;
7081ab64890Smrg
7091ab64890Smrg	if (nOldGroups==0) {
7101ab64890Smrg	    pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
7111ab64890Smrg	    if (pSyms!=NULL) {
7121ab64890Smrg		i= xkb->map->key_sym_map[key].group_info;
7131ab64890Smrg		i= XkbSetNumGroups(i,nGroups);
7141ab64890Smrg		xkb->map->key_sym_map[key].group_info= i;
7151ab64890Smrg		xkb->map->key_sym_map[key].width= width;
7161ab64890Smrg		for (i=0;i<nGroups;i++) {
7171ab64890Smrg		    xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
7181ab64890Smrg		}
7191ab64890Smrg		return Success;
7201ab64890Smrg	    }
7211ab64890Smrg	    return BadAlloc;
7221ab64890Smrg	}
7231ab64890Smrg	pSyms= XkbKeySymsPtr(xkb,key);
7241ab64890Smrg	memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
7251ab64890Smrg	pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
7261ab64890Smrg	if (pSyms==NULL)
7271ab64890Smrg	    return BadAlloc;
7281ab64890Smrg	bzero(pSyms,width*nGroups*sizeof(KeySym));
7291ab64890Smrg	for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
7301ab64890Smrg	    pOldType= XkbKeyKeyType(xkb,key,i);
7311ab64890Smrg	    pNewType= &xkb->map->types[newTypes[i]];
7321ab64890Smrg	    if (pNewType->num_levels>pOldType->num_levels)
7331ab64890Smrg		 nCopy= pOldType->num_levels;
7341ab64890Smrg	    else nCopy= pNewType->num_levels;
7351ab64890Smrg	    memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym));
7361ab64890Smrg	}
7371ab64890Smrg	if (XkbKeyHasActions(xkb,key)) {
7381ab64890Smrg	    XkbAction	oldActs[XkbMaxSymsPerKey],*pActs;
7391ab64890Smrg	    pActs= XkbKeyActionsPtr(xkb,key);
7401ab64890Smrg	    memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction));
7411ab64890Smrg	    pActs= XkbResizeKeyActions(xkb,key,width*nGroups);
7421ab64890Smrg	    if (pActs==NULL)
7431ab64890Smrg		return BadAlloc;
7441ab64890Smrg	    bzero(pActs,width*nGroups*sizeof(XkbAction));
7451ab64890Smrg	    for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
7461ab64890Smrg		pOldType= XkbKeyKeyType(xkb,key,i);
7471ab64890Smrg		pNewType= &xkb->map->types[newTypes[i]];
7481ab64890Smrg		if (pNewType->num_levels>pOldType->num_levels)
7491ab64890Smrg		     nCopy= pOldType->num_levels;
7501ab64890Smrg		else nCopy= pNewType->num_levels;
7511ab64890Smrg		memcpy(&pActs[i*width],&oldActs[i*oldWidth],
7521ab64890Smrg						nCopy*sizeof(XkbAction));
7531ab64890Smrg	    }
7541ab64890Smrg	}
7551ab64890Smrg	i= xkb->map->key_sym_map[key].group_info;
7561ab64890Smrg	i= XkbSetNumGroups(i,nGroups);
7571ab64890Smrg	xkb->map->key_sym_map[key].group_info= i;
7581ab64890Smrg	xkb->map->key_sym_map[key].width= width;
7591ab64890Smrg    }
7601ab64890Smrg    width= 0;
7611ab64890Smrg    for (i=0;i<nGroups;i++) {
7621ab64890Smrg	xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
7631ab64890Smrg	if (xkb->map->types[newTypes[i]].num_levels>width)
7641ab64890Smrg	    width= xkb->map->types[newTypes[i]].num_levels;
7651ab64890Smrg    }
7661ab64890Smrg    xkb->map->key_sym_map[key].width= width;
7671ab64890Smrg    if (changes!=NULL) {
7681ab64890Smrg	if (changes->changed&XkbKeySymsMask) {
7691ab64890Smrg	    _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms,
7701ab64890Smrg	    								key);
7711ab64890Smrg	}
7721ab64890Smrg	else {
7731ab64890Smrg	    changes->changed|= XkbKeySymsMask;
7741ab64890Smrg	    changes->first_key_sym= key;
7751ab64890Smrg	    changes->num_key_syms= 1;
7761ab64890Smrg	}
7771ab64890Smrg    }
7781ab64890Smrg    return Success;
7791ab64890Smrg}
7801ab64890Smrg
7811ab64890Smrg/***====================================================================***/
7821ab64890Smrg
7831ab64890SmrgBool
7841ab64890SmrgXkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn)
7851ab64890Smrg{
7861ab64890Smrgregister int i,bit;
7871ab64890Smrgregister unsigned mask;
7881ab64890Smrg
7891ab64890Smrg    if (xkb==NULL)
7901ab64890Smrg	return False;
7911ab64890Smrg    if (virtual_mask==0) {
7921ab64890Smrg	*mask_rtrn= 0;
7931ab64890Smrg	return True;
7941ab64890Smrg    }
7951ab64890Smrg    if (xkb->server==NULL)
7961ab64890Smrg	return False;
7971ab64890Smrg    for (i=mask=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
7981ab64890Smrg	if (virtual_mask&bit)
7991ab64890Smrg	    mask|= xkb->server->vmods[i];
8001ab64890Smrg    }
8011ab64890Smrg    *mask_rtrn= mask;
8021ab64890Smrg    return True;
8031ab64890Smrg}
8041ab64890Smrg
8051ab64890Smrg/***====================================================================***/
8061ab64890Smrg
8071ab64890SmrgBool
8081ab64890SmrgXkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed)
8091ab64890Smrg{
8101ab64890Smrgunsigned int	tmp;
8111ab64890Smrg
8121ab64890Smrg    switch (act->type) {
8131ab64890Smrg	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
8141ab64890Smrg	    if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) {
8151ab64890Smrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
8161ab64890Smrg		act->mods.mask= act->mods.real_mods;
8171ab64890Smrg		act->mods.mask|= tmp;
8181ab64890Smrg		return True;
8191ab64890Smrg	    }
8201ab64890Smrg	    break;
8211ab64890Smrg	case XkbSA_ISOLock:
8221ab64890Smrg	    if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) {
8231ab64890Smrg		XkbVirtualModsToReal(xkb,tmp,&tmp);
8241ab64890Smrg		act->iso.mask= act->iso.real_mods;
8251ab64890Smrg		act->iso.mask|= tmp;
8261ab64890Smrg		return True;
8271ab64890Smrg	    }
8281ab64890Smrg	    break;
8291ab64890Smrg    }
8301ab64890Smrg    return False;
8311ab64890Smrg}
8321ab64890Smrg
8331ab64890Smrgvoid
8341ab64890SmrgXkbUpdateKeyTypeVirtualMods(	XkbDescPtr	xkb,
8351ab64890Smrg				XkbKeyTypePtr	type,
8361ab64890Smrg				unsigned int	changed,
8371ab64890Smrg				XkbChangesPtr 	changes)
8381ab64890Smrg{
8391ab64890Smrgregister unsigned int	i;
8401ab64890Smrgunsigned int		mask;
8411ab64890Smrg
8421ab64890Smrg    XkbVirtualModsToReal(xkb,type->mods.vmods,&mask);
8431ab64890Smrg    type->mods.mask= type->mods.real_mods|mask;
8441ab64890Smrg    if ((type->map_count>0)&&(type->mods.vmods!=0)) {
8451ab64890Smrg	XkbKTMapEntryPtr entry;
8461ab64890Smrg	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
8471ab64890Smrg	    if (entry->mods.vmods!=0) {
8481ab64890Smrg		XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask);
8491ab64890Smrg		entry->mods.mask=entry->mods.real_mods|mask;
8501ab64890Smrg		/* entry is active if vmods are bound*/
8511ab64890Smrg	    	entry->active= (mask!=0);
8521ab64890Smrg	    }
8531ab64890Smrg	    else entry->active= 1;
8541ab64890Smrg	}
8551ab64890Smrg    }
8561ab64890Smrg    if (changes) {
8571ab64890Smrg	int	type_ndx;
8581ab64890Smrg	type_ndx= type-xkb->map->types;
8591ab64890Smrg	if ((type_ndx<0)||(type_ndx>xkb->map->num_types))
8601ab64890Smrg	    return;
8611ab64890Smrg	if (changes->map.changed&XkbKeyTypesMask) {
8621ab64890Smrg	    int last;
8631ab64890Smrg	    last= changes->map.first_type+changes->map.num_types-1;
8641ab64890Smrg	    if (type_ndx<changes->map.first_type) {
8651ab64890Smrg		changes->map.first_type= type_ndx;
8661ab64890Smrg		changes->map.num_types= (last-type_ndx)+1;
8671ab64890Smrg	    }
8681ab64890Smrg	    else if (type_ndx>last) {
8691ab64890Smrg		changes->map.num_types= (type_ndx-changes->map.first_type)+1;
8701ab64890Smrg	    }
8711ab64890Smrg	}
8721ab64890Smrg	else {
8731ab64890Smrg	    changes->map.changed|= XkbKeyTypesMask;
8741ab64890Smrg	    changes->map.first_type= type_ndx;
8751ab64890Smrg	    changes->map.num_types= 1;
8761ab64890Smrg	}
8771ab64890Smrg    }
8781ab64890Smrg    return;
8791ab64890Smrg}
8801ab64890Smrg
8811ab64890SmrgBool
8821ab64890SmrgXkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes)
8831ab64890Smrg{
8841ab64890Smrgregister int	i;
8851ab64890Smrgunsigned int	checkState = 0;
8861ab64890Smrg
8871ab64890Smrg    if ((!xkb) || (!xkb->map) || (changed==0))
8881ab64890Smrg	return False;
8891ab64890Smrg    for (i=0;i<xkb->map->num_types;i++) {
8901ab64890Smrg	if (xkb->map->types[i].mods.vmods & changed)
8911ab64890Smrg	XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes);
8921ab64890Smrg    }
8931ab64890Smrg    if (changed&xkb->ctrls->internal.vmods) {
8941ab64890Smrg	unsigned int	newMask;
8951ab64890Smrg	XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask);
8961ab64890Smrg	newMask|= xkb->ctrls->internal.real_mods;
8971ab64890Smrg	if (xkb->ctrls->internal.mask!=newMask) {
8981ab64890Smrg	    xkb->ctrls->internal.mask= newMask;
8991ab64890Smrg	    if (changes) {
9001ab64890Smrg		changes->ctrls.changed_ctrls|= XkbInternalModsMask;
9011ab64890Smrg		checkState= True;
9021ab64890Smrg	    }
9031ab64890Smrg	}
9041ab64890Smrg    }
9051ab64890Smrg    if (changed&xkb->ctrls->ignore_lock.vmods) {
9061ab64890Smrg	unsigned int	newMask;
9071ab64890Smrg	XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask);
9081ab64890Smrg	newMask|= xkb->ctrls->ignore_lock.real_mods;
9091ab64890Smrg	if (xkb->ctrls->ignore_lock.mask!=newMask) {
9101ab64890Smrg	    xkb->ctrls->ignore_lock.mask= newMask;
9111ab64890Smrg	    if (changes) {
9121ab64890Smrg		changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask;
9131ab64890Smrg		checkState= True;
9141ab64890Smrg	    }
9151ab64890Smrg	}
9161ab64890Smrg    }
9171ab64890Smrg    if (xkb->indicators!=NULL) {
9181ab64890Smrg	XkbIndicatorMapPtr map;
9191ab64890Smrg	map= &xkb->indicators->maps[0];
9201ab64890Smrg	for (i=0;i<XkbNumIndicators;i++,map++) {
9211ab64890Smrg	    if (map->mods.vmods&changed) {
9221ab64890Smrg		unsigned int newMask;
9231ab64890Smrg		XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask);
9241ab64890Smrg		newMask|= map->mods.real_mods;
9251ab64890Smrg		if (newMask!=map->mods.mask) {
9261ab64890Smrg		    map->mods.mask= newMask;
9271ab64890Smrg		    if (changes) {
9281ab64890Smrg			changes->indicators.map_changes|= (1<<i);
9291ab64890Smrg			checkState= True;
9301ab64890Smrg		    }
9311ab64890Smrg		}
9321ab64890Smrg	    }
9331ab64890Smrg	}
9341ab64890Smrg    }
9351ab64890Smrg    if (xkb->compat!=NULL) {
9361ab64890Smrg	XkbCompatMapPtr	compat;
9371ab64890Smrg	compat= xkb->compat;
9381ab64890Smrg	for (i=0;i<XkbNumKbdGroups;i++) {
9391ab64890Smrg	    unsigned int newMask;
9401ab64890Smrg	    XkbVirtualModsToReal(xkb,compat->groups[i].vmods,&newMask);
9411ab64890Smrg	    newMask|= compat->groups[i].real_mods;
9421ab64890Smrg	    if (compat->groups[i].mask!=newMask) {
9431ab64890Smrg		compat->groups[i].mask= newMask;
9441ab64890Smrg		if (changes) {
9451ab64890Smrg		    changes->compat.changed_groups|= (1<<i);
9461ab64890Smrg		    checkState= True;
9471ab64890Smrg		}
9481ab64890Smrg	    }
9491ab64890Smrg	}
9501ab64890Smrg    }
9511ab64890Smrg    if (xkb->map && xkb->server) {
9521ab64890Smrg	int highChange = 0, lowChange = -1;
9531ab64890Smrg	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
9541ab64890Smrg	    if (XkbKeyHasActions(xkb,i)) {
9551ab64890Smrg		register XkbAction *pAct;
9561ab64890Smrg		register int n;
9571ab64890Smrg
9581ab64890Smrg		pAct= XkbKeyActionsPtr(xkb,i);
9591ab64890Smrg		for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) {
9601ab64890Smrg		    if ((pAct->type!=XkbSA_NoAction)&&
9611ab64890Smrg			XkbUpdateActionVirtualMods(xkb,pAct,changed)) {
9621ab64890Smrg			if (lowChange<0)
9631ab64890Smrg			    lowChange= i;
9641ab64890Smrg			highChange= i;
9651ab64890Smrg		    }
9661ab64890Smrg		}
9671ab64890Smrg	    }
9681ab64890Smrg	}
9691ab64890Smrg	if (changes && (lowChange>0)) { /* something changed */
9701ab64890Smrg	    if (changes->map.changed&XkbKeyActionsMask) {
9711ab64890Smrg		int last;
9721ab64890Smrg		if (changes->map.first_key_act<lowChange)
9731ab64890Smrg		    lowChange= changes->map.first_key_act;
9741ab64890Smrg		last= changes->map.first_key_act+changes->map.num_key_acts-1;
9751ab64890Smrg		if (last>highChange)
9761ab64890Smrg		    highChange= last;
9771ab64890Smrg	    }
9781ab64890Smrg	    changes->map.changed|= 	XkbKeyActionsMask;
9791ab64890Smrg	    changes->map.first_key_act=	lowChange;
9801ab64890Smrg	    changes->map.num_key_acts=	(highChange-lowChange)+1;
9811ab64890Smrg	}
9821ab64890Smrg    }
9831ab64890Smrg    return checkState;
9841ab64890Smrg}
985