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