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