XKBMisc.c revision 4642e01f
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     *
183     * Special feature: if group 1 has an explicit type and all other groups
184     * have canonical types with same symbols, we assume it's info lost from
185     * the core replication.
186     */
187    if (nGroups>1) {
188	Bool sameType,allOneLevel, canonical = True;
189	allOneLevel= (xkb->map->types[types_inout[0]].num_levels==1);
190	for (i=1,sameType=True;(allOneLevel||sameType)&&(i<nGroups);i++) {
191	    sameType=(sameType&&(types_inout[i]==types_inout[XkbGroup1Index]));
192	    if (allOneLevel)
193		allOneLevel= (xkb->map->types[types_inout[i]].num_levels==1);
194	    if (types_inout[i] > XkbLastRequiredType)
195		canonical = False;
196	}
197	if (((sameType) || canonical)&&
198	    (!(protected&(XkbExplicitKeyTypesMask&~XkbExplicitKeyType1Mask)))){
199	    register int s;
200	    Bool	identical;
201	    for (i=1,identical=True;identical&&(i<nGroups);i++) {
202		KeySym *syms;
203		syms= &xkb_syms_rtrn[XKB_OFFSET(i,0)];
204		for (s=0;identical&&(s<nSyms[i]);s++) {
205		    if (syms[s]!=xkb_syms_rtrn[s])
206			identical= False;
207		}
208	    }
209	    if (identical)
210		nGroups= 1;
211	}
212	if (allOneLevel && (nGroups>1)) {
213	    KeySym *syms;
214	    syms= &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
215	    nSyms[XkbGroup1Index]= 1;
216	    for (i=1;i<nGroups;i++) {
217		xkb_syms_rtrn[i]= syms[0];
218		syms+= nSyms[i];
219		nSyms[i]= 1;
220	    }
221	}
222    }
223    return nGroups;
224}
225
226static XkbSymInterpretPtr
227_XkbFindMatchingInterp(	XkbDescPtr	xkb,
228			KeySym 		sym,
229			unsigned int	real_mods,
230			unsigned int	level)
231{
232register unsigned	 i;
233XkbSymInterpretPtr	 interp,rtrn;
234CARD8			 mods;
235
236    rtrn= NULL;
237    interp= xkb->compat->sym_interpret;
238    for (i=0;i<xkb->compat->num_si;i++,interp++) {
239	if ((interp->sym==NoSymbol)||(sym==interp->sym)) {
240	    int match;
241	    if ((level==0)||((interp->match&XkbSI_LevelOneOnly)==0))
242		 mods= real_mods;
243	    else mods= 0;
244	    switch (interp->match&XkbSI_OpMask) {
245		case XkbSI_NoneOf:
246		    match= ((interp->mods&mods)==0);
247		    break;
248		case XkbSI_AnyOfOrNone:
249		    match= ((mods==0)||((interp->mods&mods)!=0));
250		    break;
251		case XkbSI_AnyOf:
252		    match= ((interp->mods&mods)!=0);
253		    break;
254		case XkbSI_AllOf:
255		    match= ((interp->mods&mods)==interp->mods);
256		    break;
257		case XkbSI_Exactly:
258		    match= (interp->mods==mods);
259		    break;
260		default:
261		    match= 0;
262		    break;
263	    }
264	    if (match) {
265		if (interp->sym!=NoSymbol) {
266		    return interp;
267		}
268		else if (rtrn==NULL) {
269		    rtrn= interp;
270		}
271	    }
272	}
273    }
274    return rtrn;
275}
276
277static void
278_XkbAddKeyChange(KeyCode *pFirst,unsigned char *pNum,KeyCode newKey)
279{
280KeyCode	last;
281
282    last= (*pFirst)+(*pNum);
283    if (newKey<*pFirst) {
284	*pFirst= newKey;
285	*pNum= (last-newKey)+1;
286    }
287    else if (newKey>last) {
288	*pNum= (last-*pFirst)+1;
289    }
290    return;
291}
292
293static void
294_XkbSetActionKeyMods(XkbDescPtr xkb,XkbAction *act,unsigned mods)
295{
296unsigned	tmp;
297
298    switch (act->type) {
299	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
300	    if (act->mods.flags&XkbSA_UseModMapMods)
301		act->mods.real_mods= act->mods.mask= mods;
302	    if ((tmp= XkbModActionVMods(&act->mods))!=0) {
303		XkbVirtualModsToReal(xkb,tmp,&tmp);
304		act->mods.mask|= tmp;
305	    }
306	    break;
307	case XkbSA_ISOLock:
308	    if (act->iso.flags&XkbSA_UseModMapMods)
309		act->iso.real_mods= act->iso.mask= mods;
310	    if ((tmp= XkbModActionVMods(&act->iso))!=0) {
311		XkbVirtualModsToReal(xkb,tmp,&tmp);
312		act->iso.mask|= tmp;
313	    }
314	    break;
315    }
316    return;
317}
318
319#define	IBUF_SIZE	8
320
321Bool
322XkbApplyCompatMapToKey(XkbDescPtr xkb,KeyCode key,XkbChangesPtr changes)
323{
324KeySym *		syms;
325unsigned char 		explicit,mods;
326XkbSymInterpretPtr	*interps,ibuf[IBUF_SIZE];
327int			n,nSyms,found;
328unsigned		changed,tmp;
329
330    if ((!xkb)||(!xkb->map)||(!xkb->map->key_sym_map)||
331    			(!xkb->compat)||(!xkb->compat->sym_interpret)||
332			(key<xkb->min_key_code)||(key>xkb->max_key_code)) {
333	return False;
334    }
335    if (((!xkb->server)||(!xkb->server->key_acts))&&
336		(XkbAllocServerMap(xkb,XkbAllServerInfoMask,0)!=Success)) {
337	return False;
338    }
339    changed= 0;	/* keeps track of what has changed in _this_ call */
340    explicit= xkb->server->explicit[key];
341    if (explicit&XkbExplicitInterpretMask) /* nothing to do */
342	return True;
343    mods= (xkb->map->modmap?xkb->map->modmap[key]:0);
344    nSyms= XkbKeyNumSyms(xkb,key);
345    syms= XkbKeySymsPtr(xkb,key);
346    if (nSyms>IBUF_SIZE) {
347	interps= _XkbTypedCalloc(nSyms,XkbSymInterpretPtr);
348	if (interps==NULL) {
349	    interps= ibuf;
350	    nSyms= IBUF_SIZE;
351	}
352    }
353    else {
354	interps= ibuf;
355    }
356    found= 0;
357    for (n=0;n<nSyms;n++) {
358	unsigned level= (n%XkbKeyGroupsWidth(xkb,key));
359	interps[n]= NULL;
360	if (syms[n]!=NoSymbol) {
361	    interps[n]= _XkbFindMatchingInterp(xkb,syms[n],mods,level);
362	    if (interps[n]&&interps[n]->act.type!=XkbSA_NoAction)
363		found++;
364	    else interps[n]= NULL;
365	}
366    }
367    /* 1/28/96 (ef) -- XXX! WORKING HERE */
368    if (!found) {
369	if (xkb->server->key_acts[key]!=0) {
370	    xkb->server->key_acts[key]= 0;
371	    changed|= XkbKeyActionsMask;
372	}
373    }
374    else {
375	XkbAction *pActs;
376	unsigned int	new_vmodmask;
377	changed|= XkbKeyActionsMask;
378	pActs= XkbResizeKeyActions(xkb,key,nSyms);
379	if (!pActs) {
380            if (nSyms > IBUF_SIZE)
381                xfree(interps);
382	    return False;
383        }
384	new_vmodmask= 0;
385	for (n=0;n<nSyms;n++) {
386	    if (interps[n]) {
387		unsigned effMods;
388
389		pActs[n]= *((XkbAction *)&interps[n]->act);
390		if ((n==0)||((interps[n]->match&XkbSI_LevelOneOnly)==0)) {
391		     effMods= mods;
392		     if (interps[n]->virtual_mod!=XkbNoModifier)
393			new_vmodmask|= (1<<interps[n]->virtual_mod);
394		}
395		else effMods= 0;
396		_XkbSetActionKeyMods(xkb,&pActs[n],effMods);
397	    }
398	    else pActs[n].type= XkbSA_NoAction;
399	}
400	if (((explicit&XkbExplicitVModMapMask)==0)&&
401				(xkb->server->vmodmap[key]!=new_vmodmask)) {
402	    changed|= XkbVirtualModMapMask;
403	    xkb->server->vmodmap[key]= new_vmodmask;
404	}
405	if (interps[0]) {
406	    if ((interps[0]->flags&XkbSI_LockingKey)&&
407				((explicit&XkbExplicitBehaviorMask)==0)) {
408		xkb->server->behaviors[key].type= XkbKB_Lock;
409		changed|= XkbKeyBehaviorsMask;
410	    }
411	    if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
412		CARD8 old;
413		old= xkb->ctrls->per_key_repeat[key/8];
414		if (interps[0]->flags&XkbSI_AutoRepeat)
415		     xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
416		else xkb->ctrls->per_key_repeat[key/8]&= ~(1<<(key%8));
417		if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
418		    changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
419	    }
420	}
421    }
422    if ((!found)||(interps[0]==NULL)) {
423	if (((explicit&XkbExplicitAutoRepeatMask)==0)&&(xkb->ctrls)) {
424	    CARD8 old;
425	    old= xkb->ctrls->per_key_repeat[key/8];
426            xkb->ctrls->per_key_repeat[key/8]|= (1<<(key%8));
427	    if (changes && (old!=xkb->ctrls->per_key_repeat[key/8]))
428		changes->ctrls.changed_ctrls|= XkbPerKeyRepeatMask;
429	}
430	if (((explicit&XkbExplicitBehaviorMask)==0)&&
431		(xkb->server->behaviors[key].type==XkbKB_Lock)) {
432		xkb->server->behaviors[key].type= XkbKB_Default;
433		changed|= XkbKeyBehaviorsMask;
434	}
435    }
436    if (changes) {
437	XkbMapChangesPtr	mc;
438	mc= &changes->map;
439	tmp= (changed&mc->changed);
440	if (tmp&XkbKeyActionsMask)
441	    _XkbAddKeyChange(&mc->first_key_act,&mc->num_key_acts,key);
442	else if (changed&XkbKeyActionsMask) {
443	    mc->changed|= XkbKeyActionsMask;
444	    mc->first_key_act= key;
445	    mc->num_key_acts= 1;
446	}
447	if (tmp&XkbKeyBehaviorsMask) {
448	    _XkbAddKeyChange(&mc->first_key_behavior,&mc->num_key_behaviors,
449	    								key);
450	}
451	else if (changed&XkbKeyBehaviorsMask) {
452	    mc->changed|= XkbKeyBehaviorsMask;
453	    mc->first_key_behavior= key;
454	    mc->num_key_behaviors= 1;
455	}
456	if (tmp&XkbVirtualModMapMask)
457	    _XkbAddKeyChange(&mc->first_vmodmap_key,&mc->num_vmodmap_keys,key);
458	else if (changed&XkbVirtualModMapMask) {
459	    mc->changed|= XkbVirtualModMapMask;
460	    mc->first_vmodmap_key= key;
461	    mc->num_vmodmap_keys= 1;
462	}
463	mc->changed|= changed;
464    }
465    if (interps!=ibuf)
466	_XkbFree(interps);
467    return True;
468}
469
470Status
471XkbChangeTypesOfKey(	XkbDescPtr		 xkb,
472			int		 	 key,
473			int			 nGroups,
474			unsigned	 	 groups,
475			int	* 	 	 newTypesIn,
476			XkbMapChangesPtr	 changes)
477{
478XkbKeyTypePtr	pOldType,pNewType;
479register int	i;
480int		width,nOldGroups,oldWidth,newTypes[XkbNumKbdGroups];
481
482    if ((!xkb) || (!XkbKeycodeInRange(xkb,key)) || (!xkb->map) ||
483	(!xkb->map->types)||(!newTypesIn)||((groups&XkbAllGroupsMask)==0)||
484	(nGroups>XkbNumKbdGroups)) {
485	return BadMatch;
486    }
487    if (nGroups==0) {
488	for (i=0;i<XkbNumKbdGroups;i++) {
489	    xkb->map->key_sym_map[key].kt_index[i]= XkbOneLevelIndex;
490	}
491	i= xkb->map->key_sym_map[key].group_info;
492	i= XkbSetNumGroups(i,0);
493	xkb->map->key_sym_map[key].group_info= i;
494	XkbResizeKeySyms(xkb,key,0);
495	return Success;
496    }
497
498    nOldGroups= XkbKeyNumGroups(xkb,key);
499    oldWidth= XkbKeyGroupsWidth(xkb,key);
500    for (width=i=0;i<nGroups;i++) {
501	if (groups&(1<<i))
502	     newTypes[i]=  newTypesIn[i];
503	else if (i<nOldGroups)
504	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,i);
505	else if (nOldGroups>0)
506	     newTypes[i]= XkbKeyKeyTypeIndex(xkb,key,XkbGroup1Index);
507	else newTypes[i]= XkbTwoLevelIndex;
508	if (newTypes[i]>xkb->map->num_types)
509	    return BadMatch;
510	pNewType= &xkb->map->types[newTypes[i]];
511	if (pNewType->num_levels>width)
512	    width= pNewType->num_levels;
513    }
514    if ((xkb->ctrls)&&(nGroups>xkb->ctrls->num_groups))
515	xkb->ctrls->num_groups= nGroups;
516    if ((width!=oldWidth)||(nGroups!=nOldGroups)) {
517	KeySym		oldSyms[XkbMaxSymsPerKey],*pSyms;
518	int		nCopy;
519
520	if (nOldGroups==0) {
521	    pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
522	    if (pSyms!=NULL) {
523		i= xkb->map->key_sym_map[key].group_info;
524		i= XkbSetNumGroups(i,nGroups);
525		xkb->map->key_sym_map[key].group_info= i;
526		xkb->map->key_sym_map[key].width= width;
527		for (i=0;i<nGroups;i++) {
528		    xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
529		}
530		return Success;
531	    }
532	    return BadAlloc;
533	}
534	pSyms= XkbKeySymsPtr(xkb,key);
535	memcpy(oldSyms,pSyms,XkbKeyNumSyms(xkb,key)*sizeof(KeySym));
536	pSyms= XkbResizeKeySyms(xkb,key,width*nGroups);
537	if (pSyms==NULL)
538	    return BadAlloc;
539	bzero(pSyms,width*nGroups*sizeof(KeySym));
540	for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
541	    pOldType= XkbKeyKeyType(xkb,key,i);
542	    pNewType= &xkb->map->types[newTypes[i]];
543	    if (pNewType->num_levels>pOldType->num_levels)
544		 nCopy= pOldType->num_levels;
545	    else nCopy= pNewType->num_levels;
546	    memcpy(&pSyms[i*width],&oldSyms[i*oldWidth],nCopy*sizeof(KeySym));
547	}
548	if (XkbKeyHasActions(xkb,key)) {
549	    XkbAction	oldActs[XkbMaxSymsPerKey],*pActs;
550	    pActs= XkbKeyActionsPtr(xkb,key);
551	    memcpy(oldActs,pActs,XkbKeyNumSyms(xkb,key)*sizeof(XkbAction));
552	    pActs= XkbResizeKeyActions(xkb,key,width*nGroups);
553	    if (pActs==NULL)
554		return BadAlloc;
555	    bzero(pActs,width*nGroups*sizeof(XkbAction));
556	    for (i=0;(i<nGroups)&&(i<nOldGroups);i++) {
557		pOldType= XkbKeyKeyType(xkb,key,i);
558		pNewType= &xkb->map->types[newTypes[i]];
559		if (pNewType->num_levels>pOldType->num_levels)
560		     nCopy= pOldType->num_levels;
561		else nCopy= pNewType->num_levels;
562		memcpy(&pActs[i*width],&oldActs[i*oldWidth],
563						nCopy*sizeof(XkbAction));
564	    }
565	}
566	i= xkb->map->key_sym_map[key].group_info;
567	i= XkbSetNumGroups(i,nGroups);
568	xkb->map->key_sym_map[key].group_info= i;
569	xkb->map->key_sym_map[key].width= width;
570    }
571    width= 0;
572    for (i=0;i<nGroups;i++) {
573	xkb->map->key_sym_map[key].kt_index[i]= newTypes[i];
574	if (xkb->map->types[newTypes[i]].num_levels>width)
575	    width= xkb->map->types[newTypes[i]].num_levels;
576    }
577    xkb->map->key_sym_map[key].width= width;
578    if (changes!=NULL) {
579	if (changes->changed&XkbKeySymsMask) {
580	    _XkbAddKeyChange(&changes->first_key_sym,&changes->num_key_syms,
581	    								key);
582	}
583	else {
584	    changes->changed|= XkbKeySymsMask;
585	    changes->first_key_sym= key;
586	    changes->num_key_syms= 1;
587	}
588    }
589    return Success;
590}
591
592/***====================================================================***/
593
594Bool
595XkbVirtualModsToReal(XkbDescPtr xkb,unsigned virtual_mask,unsigned *mask_rtrn)
596{
597register int i,bit;
598register unsigned mask;
599
600    if (xkb==NULL)
601	return False;
602    if (virtual_mask==0) {
603	*mask_rtrn= 0;
604	return True;
605    }
606    if (xkb->server==NULL)
607	return False;
608    for (i=mask=0,bit=1;i<XkbNumVirtualMods;i++,bit<<=1) {
609	if (virtual_mask&bit)
610	    mask|= xkb->server->vmods[i];
611    }
612    *mask_rtrn= mask;
613    return True;
614}
615
616/***====================================================================***/
617
618static Bool
619XkbUpdateActionVirtualMods(XkbDescPtr xkb,XkbAction *act,unsigned changed)
620{
621unsigned int	tmp;
622
623    switch (act->type) {
624	case XkbSA_SetMods: case XkbSA_LatchMods: case XkbSA_LockMods:
625	    if (((tmp= XkbModActionVMods(&act->mods))&changed)!=0) {
626		XkbVirtualModsToReal(xkb,tmp,&tmp);
627		act->mods.mask= act->mods.real_mods;
628		act->mods.mask|= tmp;
629		return True;
630	    }
631	    break;
632	case XkbSA_ISOLock:
633	    if ((((tmp= XkbModActionVMods(&act->iso))!=0)&changed)!=0) {
634		XkbVirtualModsToReal(xkb,tmp,&tmp);
635		act->iso.mask= act->iso.real_mods;
636		act->iso.mask|= tmp;
637		return True;
638	    }
639	    break;
640    }
641    return False;
642}
643
644static void
645XkbUpdateKeyTypeVirtualMods(	XkbDescPtr	xkb,
646				XkbKeyTypePtr	type,
647				unsigned int	changed,
648				XkbChangesPtr 	changes)
649{
650register unsigned int	i;
651unsigned int		mask;
652
653    XkbVirtualModsToReal(xkb,type->mods.vmods,&mask);
654    type->mods.mask= type->mods.real_mods|mask;
655    if ((type->map_count>0)&&(type->mods.vmods!=0)) {
656	XkbKTMapEntryPtr entry;
657	for (i=0,entry=type->map;i<type->map_count;i++,entry++) {
658	    if (entry->mods.vmods!=0) {
659		XkbVirtualModsToReal(xkb,entry->mods.vmods,&mask);
660		entry->mods.mask=entry->mods.real_mods|mask;
661		/* entry is active if vmods are bound*/
662	    	entry->active= (mask!=0);
663	    }
664	    else entry->active= 1;
665	}
666    }
667    if (changes) {
668	int	type_ndx;
669	type_ndx= type-xkb->map->types;
670	if ((type_ndx<0)||(type_ndx>xkb->map->num_types))
671	    return;
672	if (changes->map.changed&XkbKeyTypesMask) {
673	    int last;
674	    last= changes->map.first_type+changes->map.num_types-1;
675	    if (type_ndx<changes->map.first_type) {
676		changes->map.first_type= type_ndx;
677		changes->map.num_types= (last-type_ndx)+1;
678	    }
679	    else if (type_ndx>last) {
680		changes->map.num_types= (type_ndx-changes->map.first_type)+1;
681	    }
682	}
683	else {
684	    changes->map.changed|= XkbKeyTypesMask;
685	    changes->map.first_type= type_ndx;
686	    changes->map.num_types= 1;
687	}
688    }
689    return;
690}
691
692Bool
693XkbApplyVirtualModChanges(XkbDescPtr xkb,unsigned changed,XkbChangesPtr changes)
694{
695register int	i;
696unsigned int	checkState = 0;
697
698    if ((!xkb) || (!xkb->map) || (changed==0))
699	return False;
700    for (i=0;i<xkb->map->num_types;i++) {
701	if (xkb->map->types[i].mods.vmods & changed)
702	XkbUpdateKeyTypeVirtualMods(xkb,&xkb->map->types[i],changed,changes);
703    }
704    if (changed&xkb->ctrls->internal.vmods) {
705	unsigned int	newMask;
706	XkbVirtualModsToReal(xkb,xkb->ctrls->internal.vmods,&newMask);
707	newMask|= xkb->ctrls->internal.real_mods;
708	if (xkb->ctrls->internal.mask!=newMask) {
709	    xkb->ctrls->internal.mask= newMask;
710	    if (changes) {
711		changes->ctrls.changed_ctrls|= XkbInternalModsMask;
712		checkState= True;
713	    }
714	}
715    }
716    if (changed&xkb->ctrls->ignore_lock.vmods) {
717	unsigned int	newMask;
718	XkbVirtualModsToReal(xkb,xkb->ctrls->ignore_lock.vmods,&newMask);
719	newMask|= xkb->ctrls->ignore_lock.real_mods;
720	if (xkb->ctrls->ignore_lock.mask!=newMask) {
721	    xkb->ctrls->ignore_lock.mask= newMask;
722	    if (changes) {
723		changes->ctrls.changed_ctrls|= XkbIgnoreLockModsMask;
724		checkState= True;
725	    }
726	}
727    }
728    if (xkb->indicators!=NULL) {
729	XkbIndicatorMapPtr map;
730	map= &xkb->indicators->maps[0];
731	for (i=0;i<XkbNumIndicators;i++,map++) {
732	    if (map->mods.vmods&changed) {
733		unsigned int newMask;
734		XkbVirtualModsToReal(xkb,map->mods.vmods,&newMask);
735		newMask|= map->mods.real_mods;
736		if (newMask!=map->mods.mask) {
737		    map->mods.mask= newMask;
738		    if (changes) {
739			changes->indicators.map_changes|= (1<<i);
740			checkState= True;
741		    }
742		}
743	    }
744	}
745    }
746    if (xkb->compat!=NULL) {
747	XkbCompatMapPtr	compat;
748	compat= xkb->compat;
749	for (i=0;i<XkbNumKbdGroups;i++) {
750	    unsigned int newMask;
751	    XkbVirtualModsToReal(xkb,compat->groups[i].vmods,&newMask);
752	    newMask|= compat->groups[i].real_mods;
753	    if (compat->groups[i].mask!=newMask) {
754		compat->groups[i].mask= newMask;
755		if (changes) {
756		    changes->compat.changed_groups|= (1<<i);
757		    checkState= True;
758		}
759	    }
760	}
761    }
762    if (xkb->map && xkb->server) {
763	int highChange = 0, lowChange = -1;
764	for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
765	    if (XkbKeyHasActions(xkb,i)) {
766		register XkbAction *pAct;
767		register int n;
768
769		pAct= XkbKeyActionsPtr(xkb,i);
770		for (n=XkbKeyNumActions(xkb,i);n>0;n--,pAct++) {
771		    if ((pAct->type!=XkbSA_NoAction)&&
772			XkbUpdateActionVirtualMods(xkb,pAct,changed)) {
773			if (lowChange<0)
774			    lowChange= i;
775			highChange= i;
776		    }
777		}
778	    }
779	}
780	if (changes && (lowChange>0)) { /* something changed */
781	    if (changes->map.changed&XkbKeyActionsMask) {
782		int last;
783		if (changes->map.first_key_act<lowChange)
784		    lowChange= changes->map.first_key_act;
785		last= changes->map.first_key_act+changes->map.num_key_acts-1;
786		if (last>highChange)
787		    highChange= last;
788	    }
789	    changes->map.changed|= 	XkbKeyActionsMask;
790	    changes->map.first_key_act=	lowChange;
791	    changes->map.num_key_acts=	(highChange-lowChange)+1;
792	}
793    }
794    return checkState;
795}
796