XKBMisc.c revision 9ace9065
1/************************************************************
2Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
3
4Permission to use, copy, modify, and distribute this
5software and its documentation for any purpose and without
6fee is hereby granted, provided that the above copyright
7notice appear in all copies and that both that copyright
8notice and this permission notice appear in supporting
9documentation, and that the name of Silicon Graphics not be
10used in advertising or publicity pertaining to distribution
11of the software without specific prior written permission.
12Silicon Graphics makes no representation about the suitability
13of this software for any purpose. It is provided "as is"
14without any express or implied warranty.
15
16SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
17SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
19GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
20DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
22OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
23THE USE OR PERFORMANCE OF THIS SOFTWARE.
24
25********************************************************/
26
27#ifdef HAVE_DIX_CONFIG_H
28#include <dix-config.h>
29#elif defined(HAVE_CONFIG_H)
30#include <config.h>
31#endif
32
33#include <stdio.h>
34#include <X11/X.h>
35#include <X11/Xproto.h>
36#include "misc.h"
37#include "inputstr.h"
38#include <X11/keysym.h>
39#define	XKBSRV_NEED_FILE_FUNCS
40#include <xkbsrv.h>
41
42/***====================================================================***/
43
44#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
45#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
46
47int
48XkbKeyTypesForCoreSymbols(	XkbDescPtr	xkb,
49				int		map_width,
50				KeySym *	core_syms,
51				unsigned int 	protected,
52    				int *		types_inout,
53				KeySym *	xkb_syms_rtrn)
54{
55register int	i;
56unsigned int	empty;
57int		nSyms[XkbNumKbdGroups];
58int		nGroups,tmp,groupsWidth;
59BOOL		replicated = FALSE;
60
61    /* Section 12.2 of the protocol describes this process in more detail */
62    /* Step 1:  find the # of symbols in the core mapping per group */
63    groupsWidth= 2;
64    for (i=0;i<XkbNumKbdGroups;i++) {
65	if ((protected&(1<<i))&&(types_inout[i]<xkb->map->num_types)) {
66	    nSyms[i]= xkb->map->types[types_inout[i]].num_levels;
67	    if (nSyms[i]>groupsWidth)
68		groupsWidth= nSyms[i];
69	}
70	else {
71	    types_inout[i]= XkbTwoLevelIndex;	/* don't really know, yet */
72	    nSyms[i]= 2;
73	}
74    }
75    if (nSyms[XkbGroup1Index]<2)
76	nSyms[XkbGroup1Index]= 2;
77    if (nSyms[XkbGroup2Index]<2)
78	nSyms[XkbGroup2Index]= 2;
79    /* Step 2:	Copy the symbols from the core ordering to XKB ordering	*/
80    /*		symbols in the core are in the order:			*/
81    /*		G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*]	*/
82    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,0)]= CORE_SYM(0);
83    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,1)]= CORE_SYM(1);
84    for (i=2;i<nSyms[XkbGroup1Index];i++) {
85	xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index,i)]= CORE_SYM(2+i);
86    }
87    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,0)]= CORE_SYM(2);
88    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,1)]= CORE_SYM(3);
89    tmp= 2+(nSyms[XkbGroup1Index]-2); /* offset to extra group2 syms */
90    for (i=2;i<nSyms[XkbGroup2Index];i++) {
91	xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index,i)]= CORE_SYM(tmp+i);
92    }
93
94    /* Special case: if only the first group is explicit, and the symbols
95     * replicate across all groups, then we have a Section 12.4 replication */
96    if ((protected & ~XkbExplicitKeyType1Mask) == 0)
97    {
98        int j, width = nSyms[XkbGroup1Index];
99
100        replicated = TRUE;
101
102        /* Check ABAB in ABABCDECDEABCDE */
103        if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) ||
104            (width > 1 && CORE_SYM(1) != CORE_SYM(3)))
105            replicated = FALSE;
106
107        /* Check CDECDE in ABABCDECDEABCDE */
108        for (i = 2; i < width && replicated; i++)
109        {
110            if (CORE_SYM(2 + i) != CORE_SYM(i + width))
111                replicated = FALSE;
112        }
113
114        /* Check ABCDE in ABABCDECDEABCDE */
115        for (j = 2; replicated &&
116                    j < XkbNumKbdGroups &&
117                    map_width >= width * (j + 1); j++)
118        {
119            for (i = 0; i < width && replicated; i++)
120            {
121                if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j))
122                    replicated = FALSE;
123            }
124        }
125    }
126
127    if (replicated)
128    {
129	nSyms[XkbGroup2Index]= 0;
130	nSyms[XkbGroup3Index]= 0;
131	nSyms[XkbGroup4Index]= 0;
132	nGroups= 1;
133    } else
134    {
135        tmp= nSyms[XkbGroup1Index]+nSyms[XkbGroup2Index];
136        if ((tmp>=map_width)&&
137                ((protected&(XkbExplicitKeyType3Mask|XkbExplicitKeyType4Mask))==0)) {
138            nSyms[XkbGroup3Index]= 0;
139            nSyms[XkbGroup4Index]= 0;
140            nGroups= 2;
141        } else
142        {
143            nGroups= 3;
144            for (i=0;i<nSyms[XkbGroup3Index];i++,tmp++) {
145                xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index,i)]= CORE_SYM(tmp);
146            }
147            if ((tmp<map_width)||(protected&XkbExplicitKeyType4Mask)) {
148                nGroups= 4;
149                for (i=0;i<nSyms[XkbGroup4Index];i++,tmp++) {
150                    xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index,i)]= CORE_SYM(tmp);
151                }
152            }
153            else {
154                nSyms[XkbGroup4Index]= 0;
155            }
156        }
157    }
158    /* steps 3&4: alphanumeric expansion,  assign canonical types */
159    empty= 0;
160    for (i=0;i<nGroups;i++) {
161	KeySym *syms;
162	syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
163	if ((nSyms[i]>1)&&(syms[1]==NoSymbol)&&(syms[0]!=NoSymbol)) {
164	    KeySym upper,lower;
165	    XkbConvertCase(syms[0],&lower,&upper);
166	    if (upper!=lower) {
167		xkb_syms_rtrn[XKB_OFFSET(i,0)]= lower;
168		xkb_syms_rtrn[XKB_OFFSET(i,1)]= upper;
169		if ((protected&(1<<i))==0)
170		    types_inout[i]= XkbAlphabeticIndex;
171	    }
172	    else if ((protected&(1<<i))==0) {
173		types_inout[i]= XkbOneLevelIndex;
174	/*	nSyms[i]=	1;*/
175	    }
176	}
177	if (((protected&(1<<i))==0)&&(types_inout[i]==XkbTwoLevelIndex)) {
178	    if (XkbKSIsKeypad(syms[0])||XkbKSIsKeypad(syms[1]))
179		types_inout[i]= XkbKeypadIndex;
180	    else {
181		KeySym upper,lower;
182		XkbConvertCase(syms[0],&lower,&upper);
183		if ((syms[0]==lower)&&(syms[1]==upper))
184		    types_inout[i]= XkbAlphabeticIndex;
185	    }
186	}
187	if (syms[0]==NoSymbol) {
188	    register int n;
189	    Bool	found;
190	    for (n=1,found=FALSE;(!found)&&(n<nSyms[i]);n++) {
191		found= (syms[n]!=NoSymbol);
192	    }
193	    if (!found)
194		empty|= (1<<i);
195	}
196    }
197    /* step 5: squoosh out empty groups */
198    if (empty) {
199	for (i=nGroups-1;i>=0;i--) {
200	    if (((empty&(1<<i))==0)||(protected&(1<<i)))
201		break;
202	    nGroups--;
203	}
204    }
205    if (nGroups<1)
206	return 0;
207
208    /* step 6: replicate group 1 into group two, if necessary */
209    if ((nGroups>1)&&((empty&(XkbGroup1Mask|XkbGroup2Mask))==XkbGroup2Mask)) {
210	if ((protected&(XkbExplicitKeyType1Mask|XkbExplicitKeyType2Mask))==0) {
211	    nSyms[XkbGroup2Index]= nSyms[XkbGroup1Index];
212	    types_inout[XkbGroup2Index]= types_inout[XkbGroup1Index];
213	    memcpy((char *)&xkb_syms_rtrn[2],(char *)xkb_syms_rtrn,
214							2*sizeof(KeySym));
215	}
216	else if (types_inout[XkbGroup1Index]==types_inout[XkbGroup2Index]) {
217	    memcpy((char *)&xkb_syms_rtrn[nSyms[XkbGroup1Index]],
218	    				(char *)xkb_syms_rtrn,
219					nSyms[XkbGroup1Index]*sizeof(KeySym));
220	}
221    }
222
223    /* step 7: check for all groups identical or all width 1
224     *
225     * Special feature: if group 1 has an explicit type and all other groups
226     * have canonical types with same symbols, we assume it's info lost from
227     * the core replication.
228     */
229    if (nGroups>1) {
230	Bool sameType,allOneLevel, canonical = TRUE;
231	allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1);
232	for (i=1,sameType=TRUE;(allOneLevel||sameType)&&(i<nGroups);i++) {
233	    sameType=(sameType&&(types_inout[i]==types_inout[XkbGroup1Index]));
234	    if (allOneLevel)
235		allOneLevel= (xkb->map->types[types_inout[i]].num_levels==1);
236	    if (types_inout[i] > XkbLastRequiredType)
237		canonical = FALSE;
238	}
239	if (((sameType) || canonical)&&
240	    (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){
241	    register int s;
242	    Bool	identical;
243	    for (i=1,identical=TRUE;identical&&(i<nGroups);i++) {
244		KeySym *syms;
245                if (nSyms[i] != nSyms[XkbGroup1Index])
246                    identical = FALSE;
247		syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
248		for (s=0;identical&&(s<nSyms[i]);s++) {
249		    if (syms[s]!=xkb_syms_rtrn[s])
250			identical= FALSE;
251		}
252	    }
253	    if (identical)
254		nGroups= 1;
255	}
256	if (allOneLevel && (nGroups>1)) {
257	    KeySym *syms;
258	    syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
259	    nSyms[XkbGroup1Index]= 1;
260	    for (i=1;i<nGroups;i++) {
261		xkb_syms_rtrn[i]= syms[0];
262		syms+= nSyms[i];
263		nSyms[i]= 1;
264	    }
265	}
266    }
267    return nGroups;
268}
269
270static XkbSymInterpretPtr
271_XkbFindMatchingInterp(	XkbDescPtr	xkb,
272			KeySym 		sym,
273			unsigned int	real_mods,
274			unsigned int	level)
275{
276register unsigned	 i;
277XkbSymInterpretPtr	 interp,rtrn;
278CARD8			 mods;
279
280    rtrn= NULL;
281    interp= xkb->compat->sym_interpret;
282    for (i=0;i<xkb->compat->num_si;i++,interp++) {
283	if ((interp->sym==NoSymbol)||(sym==interp->sym)) {
284	    int match;
285	    if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0))
286		 mods= real_mods;
287	    else mods= 0;
288	    switch (interp->match&XkbSI_OpMask) {
289		case XkbSI_NoneOf:
290		    match= ((interp->mods&mods)==0);
291		    break;
292		case XkbSI_AnyOfOrNone:
293		    match= ((mods==0)||((interp->mods&mods)!=0));
294		    break;
295		case XkbSI_AnyOf:
296		    match= ((interp->mods&mods)!=0);
297		    break;
298		case XkbSI_AllOf:
299		    match= ((interp->mods&mods)==interp->mods);
300		    break;
301		case XkbSI_Exactly:
302		    match= (interp->mods==mods);
303		    break;
304		default:
305		    match= 0;
306		    break;
307	    }
308	    if (match) {
309		if (interp->sym!=NoSymbol) {
310		    return interp;
311		}
312		else if (rtrn==NULL) {
313		    rtrn= interp;
314		}
315	    }
316	}
317    }
318    return rtrn;
319}
320
321static void
322_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey)
323{
324KeyCode	last;
325
326    last= (*pFirst)+(*pNum);
327    if (newKey<*pFirst) {
328	*pFirst= newKey;
329	*pNum= (last-newKey)+1;
330    }
331    else if (newKey>last) {
332	*pNum= (last-*pFirst)+1;
333    }
334    return;
335}
336
337static void
338_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods)
339{
340unsigned	tmp;
341
342    switch (act->type) {
343	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
344	    if (act->mods.flags&XkbSA_UseModMapMods)
345		act->mods.real_mods= act->mods.mask= mods;
346	    if ((tmp= XkbModActionVMods(&act->mods))!=0) {
347		XkbVirtualModsToReal(xkb,tmp,&tmp);
348		act->mods.mask|= tmp;
349	    }
350	    break;
351	case XkbSA_ISOLock:
352	    if (act->iso.flags&XkbSA_UseModMapMods)
353		act->iso.real_mods= act->iso.mask= mods;
354	    if ((tmp= XkbModActionVMods(&act->iso))!=0) {
355		XkbVirtualModsToReal(xkb,tmp,&tmp);
356		act->iso.mask|= tmp;
357	    }
358	    break;
359    }
360    return;
361}
362
363#define	IBUF_SIZE	8
364
365Bool
366XkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes)
367{
368KeySym *		syms;
369unsigned char 		explicit,mods;
370XkbSymInterpretPtr	*interps,ibuf[IBUF_SIZE];
371int			n,nSyms,found;
372unsigned		changed,tmp;
373
374    if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)||
375    			(!xkb->compat)||(!xkb->compat->sym_interpret)||
376			(key<xkb->min_key_code)||(key>xkb->max_key_code)) {
377	return FALSE;
378    }
379    if (((!xkb->server)||(!xkb->server->key_acts))&&
380		(XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) {
381	return FALSE;
382    }
383    changed= 0;	/* keeps track of what has changed in _this_ call */
384    explicit= xkb->server->explicit[key];
385    if (explicit&XkbExplicitInterpretMask) /* nothing to do */
386	return TRUE;
387    mods= (xkb->map->modmap?xkb->map->modmap[key]:0);
388    nSyms= XkbKeyNumSyms(xkb,key);
389    syms= XkbKeySymsPtr(xkb,key);
390    if (nSyms>IBUF_SIZE) {
391	interps= calloc(nSyms, sizeof(XkbSymInterpretPtr));
392	if (interps==NULL) {
393	    interps= ibuf;
394	    nSyms= IBUF_SIZE;
395	}
396    }
397    else {
398	interps= ibuf;
399    }
400    found= 0;
401    for (n=0;n<nSyms;n++) {
402	unsigned level= (n%XkbKeyGroupsWidth(xkb,key));
403	interps[n]= NULL;
404	if (syms[n]!=NoSymbol) {
405	    interps[n]= _XkbFindMatchingInterp(xkb,syms[n],mods,level);
406	    if (interps[n]&&interps[n]->act.type!=XkbSA_NoAction)
407		found++;
408	    else interps[n]= NULL;
409	}
410    }
411    /* 1/28/96 (ef) -- XXX! WORKING HERE */
412    if (!found) {
413	if (xkb->server->key_acts[key]!=0) {
414	    xkb->server->key_acts[key]= 0;
415	    changed|= XkbKeyActionsMask;
416	}
417    }
418    else {
419	XkbAction *pActs;
420	unsigned int	new_vmodmask;
421	changed|= XkbKeyActionsMask;
422	pActs= XkbResizeKeyActions(xkb,key,nSyms);
423	if (!pActs) {
424            if (nSyms > IBUF_SIZE)
425                free(interps);
426	    return FALSE;
427        }
428	new_vmodmask= 0;
429	for (n=0;n<nSyms;n++) {
430	    if (interps[n]) {
431		unsigned effMods;
432
433		pActs[n]= *((XkbAction *)&interps[n]->act);
434		if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) {
435		     effMods= mods;
436		     if (interps[n]->virtual_mod!=XkbNoModifier)
437			new_vmodmask|= (1<<interps[n]->virtual_mod);
438		}
439		else effMods= 0;
440		_XkbSetActionKeyMods(xkb,&pActs[n],effMods);
441	    }
442	    else pActs[n].type= XkbSA_NoAction;
443	}
444	if (((explicit&XkbExplicitVModMapMask)==0)&&
445				(xkb->server->vmodmap[key]!=new_vmodmask)) {
446	    changed|= XkbVirtualModMapMask;
447	    xkb->server->vmodmap[key]= new_vmodmask;
448	}
449	if (interps[0]) {
450	    if ((interps[0]->flags&XkbSI_LockingKey)&&
451				((explicit&XkbExplicitBehaviorMask)==0)) {
452		xkb->server->behaviors[key].type= XkbKB_Lock;
453		changed|= XkbKeyBehaviorsMask;
454	    }
455	    if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
456		CARD8 old;
457		old= BitIsOn(xkb->ctrls->per_key_repeat, key);
458		if (interps[0]->flags&XkbSI_AutoRepeat)
459		    SetBit(xkb->ctrls->per_key_repeat, key);
460		else
461		    ClearBit(xkb->ctrls->per_key_repeat, key);
462		if (changes && old != BitIsOn(xkb->ctrls->per_key_repeat, key))
463		    changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
464	    }
465	}
466    }
467    if ((!found)||(interps[0]==NULL)) {
468	if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
469	    CARD8 old;
470	    old = BitIsOn(xkb->ctrls->per_key_repeat, key);
471	    SetBit(xkb->ctrls->per_key_repeat, key);
472	    if (changes && (old != BitIsOn(xkb->ctrls->per_key_repeat, key)))
473		changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
474	}
475	if (((explicit&XkbExplicitBehaviorMask)==0)&&
476		(xkb->server->behaviors[key].type==XkbKB_Lock)) {
477		xkb->server->behaviors[key].type= XkbKB_Default;
478		changed|= XkbKeyBehaviorsMask;
479	}
480    }
481    if (changes) {
482	XkbMapChangesPtr	mc;
483	mc= &changes->map;
484	tmp= (changed&mc->changed);
485	if (tmp&XkbKeyActionsMask)
486	    _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key);
487	else if (changed&XkbKeyActionsMask) {
488	    mc->changed|= XkbKeyActionsMask;
489	    mc->first_key_act= key;
490	    mc->num_key_acts= 1;
491	}
492	if (tmp&XkbKeyBehaviorsMask) {
493	    _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors,
494	    								key);
495	}
496	else if (changed&XkbKeyBehaviorsMask) {
497	    mc->changed|= XkbKeyBehaviorsMask;
498	    mc->first_key_behavior= key;
499	    mc->num_key_behaviors= 1;
500	}
501	if (tmp&XkbVirtualModMapMask)
502	    _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key);
503	else if (changed&XkbVirtualModMapMask) {
504	    mc->changed|= XkbVirtualModMapMask;
505	    mc->first_vmodmap_key= key;
506	    mc->num_vmodmap_keys= 1;
507	}
508	mc->changed|= changed;
509    }
510    if (interps!=ibuf)
511	free(interps);
512    return TRUE;
513}
514
515Status
516XkbChangeTypesOfKey(	XkbDescPtr		 xkb,
517			int		 	 key,
518			int			 nGroups,
519			unsigned	 	 groups,
520			int	* 	 	 newTypesIn,
521			XkbMapChangesPtr	 changes)
522{
523XkbKeyTypePtr	pOldType,pNewType;
524register int	i;
525int		width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups];
526
527    if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) ||
528	(!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)||
529	(nGroups>XkbNumKbdGroups)) {
530	return BadMatch;
531    }
532    if (nGroups==0) {
533	for (i=0;i<XkbNumKbdGroups;i++) {
534	    xkb->map->key_sym_map[key].kt_index[i]= XkbOneLevelIndex;
535	}
536	i= xkb->map->key_sym_map[key].group_info;
537	i= XkbSetNumGroups(i,0);
538	xkb->map->key_sym_map[key].group_info= i;
539	XkbResizeKeySyms(xkb,key,0);
540	return Success;
541    }
542
543    nOldGroups= XkbKeyNumGroups(xkb,key);
544    oldWidth= XkbKeyGroupsWidth(xkb,key);
545    for (width=i=0;i<nGroups;i++) {
546	if (groups&(1<<i))
547	     newTypes[i]=  newTypesIn[i];
548	else if (i<nOldGroups)
549	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,i);
550	else if (nOldGroups>0)
551	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
552	else newTypes[i]= XkbTwoLevelIndex;
553	if (newTypes[i]>xkb->map->num_types)
554	    return BadMatch;
555	pNewType= &xkb->map->types[newTypes[i]];
556	if (pNewType->num_levels>width)
557	    width= pNewType->num_levels;
558    }
559    if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups))
560	xkb->ctrls->num_groups= nGroups;
561    if ((width!=oldWidth)||(nGroups!=nOldGroups)) {
562	KeySym		oldSyms[XkbMaxSymsPerKey],*pSyms;
563	int		nCopy;
564
565	if (nOldGroups==0) {
566	    pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
567	    if (pSyms!=NULL) {
568		i= xkb->map->key_sym_map[key].group_info;
569		i= XkbSetNumGroups(i,nGroups);
570		xkb->map->key_sym_map[key].group_info= i;
571		xkb->map->key_sym_map[key].width= width;
572		for (i=0;i<nGroups;i++) {
573		    xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
574		}
575		return Success;
576	    }
577	    return BadAlloc;
578	}
579	pSyms= XkbKeySymsPtr(xkb,key);
580	memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
581	pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
582	if (pSyms==NULL)
583	    return BadAlloc;
584	memset(pSyms, 0, width*nGroups*sizeof(KeySym));
585	for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
586	    pOldType= XkbKeyKeyType(xkb,key,i);
587	    pNewType= &xkb->map->types[newTypes[i]];
588	    if (pNewType->num_levels>pOldType->num_levels)
589		 nCopy= pOldType->num_levels;
590	    else nCopy= pNewType->num_levels;
591	    memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym));
592	}
593	if (XkbKeyHasActions(xkb,key)) {
594	    XkbAction	oldActs[XkbMaxSymsPerKey],*pActs;
595	    pActs= XkbKeyActionsPtr(xkb,key);
596	    memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction));
597	    pActs= XkbResizeKeyActions(xkb,key,width*nGroups);
598	    if (pActs==NULL)
599		return BadAlloc;
600	    memset(pActs, 0, width*nGroups*sizeof(XkbAction));
601	    for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
602		pOldType= XkbKeyKeyType(xkb,key,i);
603		pNewType= &xkb->map->types[newTypes[i]];
604		if (pNewType->num_levels>pOldType->num_levels)
605		     nCopy= pOldType->num_levels;
606		else nCopy= pNewType->num_levels;
607		memcpy(&pActs[i*width],&oldActs[i*oldWidth],
608						nCopy*sizeof(XkbAction));
609	    }
610	}
611	i= xkb->map->key_sym_map[key].group_info;
612	i= XkbSetNumGroups(i,nGroups);
613	xkb->map->key_sym_map[key].group_info= i;
614	xkb->map->key_sym_map[key].width= width;
615    }
616    width= 0;
617    for (i=0;i<nGroups;i++) {
618	xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
619	if (xkb->map->types[newTypes[i]].num_levels>width)
620	    width= xkb->map->types[newTypes[i]].num_levels;
621    }
622    xkb->map->key_sym_map[key].width= width;
623    if (changes!=NULL) {
624	if (changes->changed&XkbKeySymsMask) {
625	    _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms,
626	    								key);
627	}
628	else {
629	    changes->changed|= XkbKeySymsMask;
630	    changes->first_key_sym= key;
631	    changes->num_key_syms= 1;
632	}
633    }
634    return Success;
635}
636
637/***====================================================================***/
638
639Bool
640XkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn)
641{
642register int i,bit;
643register unsigned mask;
644
645    if (xkb==NULL)
646	return FALSE;
647    if (virtual_mask==0) {
648	*mask_rtrn= 0;
649	return TRUE;
650    }
651    if (xkb->server==NULL)
652	return FALSE;
653    for (i=mask=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
654	if (virtual_mask&bit)
655	    mask|= xkb->server->vmods[i];
656    }
657    *mask_rtrn= mask;
658    return TRUE;
659}
660
661/***====================================================================***/
662
663static Bool
664XkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed)
665{
666unsigned int	tmp;
667
668    switch (act->type) {
669	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
670	    if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) {
671		XkbVirtualModsToReal(xkb,tmp,&tmp);
672		act->mods.mask= act->mods.real_mods;
673		act->mods.mask|= tmp;
674		return TRUE;
675	    }
676	    break;
677	case XkbSA_ISOLock:
678	    if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) {
679		XkbVirtualModsToReal(xkb,tmp,&tmp);
680		act->iso.mask= act->iso.real_mods;
681		act->iso.mask|= tmp;
682		return TRUE;
683	    }
684	    break;
685    }
686    return FALSE;
687}
688
689static void
690XkbUpdateKeyTypeVirtualMods(	XkbDescPtr	xkb,
691				XkbKeyTypePtr	type,
692				unsigned int	changed,
693				XkbChangesPtr 	changes)
694{
695register unsigned int	i;
696unsigned int		mask;
697
698    XkbVirtualModsToReal(xkb,type->mods.vmods,&mask);
699    type->mods.mask= type->mods.real_mods|mask;
700    if ((type->map_count>0)&&(type->mods.vmods!=0)) {
701	XkbKTMapEntryPtr entry;
702	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
703	    if (entry->mods.vmods!=0) {
704		XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask);
705		entry->mods.mask=entry->mods.real_mods|mask;
706		/* entry is active if vmods are bound*/
707	    	entry->active= (mask!=0);
708	    }
709	    else entry->active= 1;
710	}
711    }
712    if (changes) {
713	int	type_ndx;
714	type_ndx= type-xkb->map->types;
715	if ((type_ndx<0)||(type_ndx>xkb->map->num_types))
716	    return;
717	if (changes->map.changed&XkbKeyTypesMask) {
718	    int last;
719	    last= changes->map.first_type+changes->map.num_types-1;
720	    if (type_ndx<changes->map.first_type) {
721		changes->map.first_type= type_ndx;
722		changes->map.num_types= (last-type_ndx)+1;
723	    }
724	    else if (type_ndx>last) {
725		changes->map.num_types= (type_ndx-changes->map.first_type)+1;
726	    }
727	}
728	else {
729	    changes->map.changed|= XkbKeyTypesMask;
730	    changes->map.first_type= type_ndx;
731	    changes->map.num_types= 1;
732	}
733    }
734    return;
735}
736
737Bool
738XkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes)
739{
740register int	i;
741unsigned int	checkState = 0;
742
743    if ((!xkb) || (!xkb->map) || (changed==0))
744	return FALSE;
745    for (i=0;i<xkb->map->num_types;i++) {
746	if (xkb->map->types[i].mods.vmods & changed)
747	XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes);
748    }
749    if (changed&xkb->ctrls->internal.vmods) {
750	unsigned int	newMask;
751	XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask);
752	newMask|= xkb->ctrls->internal.real_mods;
753	if (xkb->ctrls->internal.mask!=newMask) {
754	    xkb->ctrls->internal.mask= newMask;
755	    if (changes) {
756		changes->ctrls.changed_ctrls|= XkbInternalModsMask;
757		checkState= TRUE;
758	    }
759	}
760    }
761    if (changed&xkb->ctrls->ignore_lock.vmods) {
762	unsigned int	newMask;
763	XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask);
764	newMask|= xkb->ctrls->ignore_lock.real_mods;
765	if (xkb->ctrls->ignore_lock.mask!=newMask) {
766	    xkb->ctrls->ignore_lock.mask= newMask;
767	    if (changes) {
768		changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask;
769		checkState= TRUE;
770	    }
771	}
772    }
773    if (xkb->indicators!=NULL) {
774	XkbIndicatorMapPtr map;
775	map= &xkb->indicators->maps[0];
776	for (i=0;i<XkbNumIndicators;i++,map++) {
777	    if (map->mods.vmods&changed) {
778		unsigned int newMask;
779		XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask);
780		newMask|= map->mods.real_mods;
781		if (newMask!=map->mods.mask) {
782		    map->mods.mask= newMask;
783		    if (changes) {
784			changes->indicators.map_changes|= (1<<i);
785			checkState= TRUE;
786		    }
787		}
788	    }
789	}
790    }
791    if (xkb->compat!=NULL) {
792	XkbCompatMapPtr	compat;
793	compat= xkb->compat;
794	for (i=0;i<XkbNumKbdGroups;i++) {
795	    unsigned int newMask;
796	    XkbVirtualModsToReal(xkb,compat->groups[i].vmods,&newMask);
797	    newMask|= compat->groups[i].real_mods;
798	    if (compat->groups[i].mask!=newMask) {
799		compat->groups[i].mask= newMask;
800		if (changes) {
801		    changes->compat.changed_groups|= (1<<i);
802		    checkState= TRUE;
803		}
804	    }
805	}
806    }
807    if (xkb->map && xkb->server) {
808	int highChange = 0, lowChange = -1;
809	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
810	    if (XkbKeyHasActions(xkb,i)) {
811		register XkbAction *pAct;
812		register int n;
813
814		pAct= XkbKeyActionsPtr(xkb,i);
815		for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) {
816		    if ((pAct->type!=XkbSA_NoAction)&&
817			XkbUpdateActionVirtualMods(xkb,pAct,changed)) {
818			if (lowChange<0)
819			    lowChange= i;
820			highChange= i;
821		    }
822		}
823	    }
824	}
825	if (changes && (lowChange>0)) { /* something changed */
826	    if (changes->map.changed&XkbKeyActionsMask) {
827		int last;
828		if (changes->map.first_key_act<lowChange)
829		    lowChange= changes->map.first_key_act;
830		last= changes->map.first_key_act+changes->map.num_key_acts-1;
831		if (last>highChange)
832		    highChange= last;
833	    }
834	    changes->map.changed|= 	XkbKeyActionsMask;
835	    changes->map.first_key_act=	lowChange;
836	    changes->map.num_key_acts=	(highChange-lowChange)+1;
837	}
838    }
839    return checkState;
840}
841