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