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