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