XKBMisc.c revision ed6184df
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        return Success;
557    }
558
559    nOldGroups = XkbKeyNumGroups(xkb, key);
560    oldWidth = XkbKeyGroupsWidth(xkb, key);
561    for (width = i = 0; i < nGroups; i++) {
562        if (groups & (1 << i))
563            newTypes[i] = newTypesIn[i];
564        else if (i < nOldGroups)
565            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
566        else if (nOldGroups > 0)
567            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
568        else
569            newTypes[i] = XkbTwoLevelIndex;
570        if (newTypes[i] > xkb->map->num_types)
571            return BadMatch;
572        pNewType = &xkb->map->types[newTypes[i]];
573        if (pNewType->num_levels > width)
574            width = pNewType->num_levels;
575    }
576    if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
577        xkb->ctrls->num_groups = nGroups;
578    if ((width != oldWidth) || (nGroups != nOldGroups)) {
579        KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
580        int nCopy;
581
582        if (nOldGroups == 0) {
583            pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
584            if (pSyms != NULL) {
585                i = xkb->map->key_sym_map[key].group_info;
586                i = XkbSetNumGroups(i, nGroups);
587                xkb->map->key_sym_map[key].group_info = i;
588                xkb->map->key_sym_map[key].width = width;
589                for (i = 0; i < nGroups; i++) {
590                    xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
591                }
592                return Success;
593            }
594            return BadAlloc;
595        }
596        pSyms = XkbKeySymsPtr(xkb, key);
597        memcpy(oldSyms, pSyms, XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
598        pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
599        if (pSyms == NULL)
600            return BadAlloc;
601        memset(pSyms, 0, width * nGroups * sizeof(KeySym));
602        for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
603            pOldType = XkbKeyKeyType(xkb, key, i);
604            pNewType = &xkb->map->types[newTypes[i]];
605            if (pNewType->num_levels > pOldType->num_levels)
606                nCopy = pOldType->num_levels;
607            else
608                nCopy = pNewType->num_levels;
609            memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
610                   nCopy * sizeof(KeySym));
611        }
612        if (XkbKeyHasActions(xkb, key)) {
613            XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
614
615            pActs = XkbKeyActionsPtr(xkb, key);
616            memcpy(oldActs, pActs, XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
617            pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
618            if (pActs == NULL)
619                return BadAlloc;
620            memset(pActs, 0, width * nGroups * sizeof(XkbAction));
621            for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
622                pOldType = XkbKeyKeyType(xkb, key, i);
623                pNewType = &xkb->map->types[newTypes[i]];
624                if (pNewType->num_levels > pOldType->num_levels)
625                    nCopy = pOldType->num_levels;
626                else
627                    nCopy = pNewType->num_levels;
628                memcpy(&pActs[i * width], &oldActs[i * oldWidth],
629                       nCopy * sizeof(XkbAction));
630            }
631        }
632        i = xkb->map->key_sym_map[key].group_info;
633        i = XkbSetNumGroups(i, nGroups);
634        xkb->map->key_sym_map[key].group_info = i;
635        xkb->map->key_sym_map[key].width = width;
636    }
637    width = 0;
638    for (i = 0; i < nGroups; i++) {
639        xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
640        if (xkb->map->types[newTypes[i]].num_levels > width)
641            width = xkb->map->types[newTypes[i]].num_levels;
642    }
643    xkb->map->key_sym_map[key].width = width;
644    if (changes != NULL) {
645        if (changes->changed & XkbKeySymsMask) {
646            _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
647                             key);
648        }
649        else {
650            changes->changed |= XkbKeySymsMask;
651            changes->first_key_sym = key;
652            changes->num_key_syms = 1;
653        }
654    }
655    return Success;
656}
657
658/***====================================================================***/
659
660Bool
661XkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
662{
663    register int i, bit;
664    register unsigned mask;
665
666    if ((xkb == NULL) || (xkb->server == NULL)) {
667        *mask_rtrn = 0;
668        return FALSE;
669    }
670    if (virtual_mask == 0) {
671        *mask_rtrn = 0;
672        return TRUE;
673    }
674    for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
675        if (virtual_mask & bit)
676            mask |= xkb->server->vmods[i];
677    }
678    *mask_rtrn = mask;
679    return TRUE;
680}
681
682/***====================================================================***/
683
684static Bool
685XkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
686{
687    unsigned int tmp;
688
689    switch (act->type) {
690    case XkbSA_SetMods:
691    case XkbSA_LatchMods:
692    case XkbSA_LockMods:
693        if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
694            XkbVirtualModsToReal(xkb, tmp, &tmp);
695            act->mods.mask = act->mods.real_mods;
696            act->mods.mask |= tmp;
697            return TRUE;
698        }
699        break;
700    case XkbSA_ISOLock:
701        if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
702            XkbVirtualModsToReal(xkb, tmp, &tmp);
703            act->iso.mask = act->iso.real_mods;
704            act->iso.mask |= tmp;
705            return TRUE;
706        }
707        break;
708    }
709    return FALSE;
710}
711
712static void
713XkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
714                            XkbKeyTypePtr type,
715                            unsigned int changed, XkbChangesPtr changes)
716{
717    register unsigned int i;
718    unsigned int mask;
719
720    XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
721    type->mods.mask = type->mods.real_mods | mask;
722    if ((type->map_count > 0) && (type->mods.vmods != 0)) {
723        XkbKTMapEntryPtr entry;
724
725        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
726            if (entry->mods.vmods != 0) {
727                XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
728                entry->mods.mask = entry->mods.real_mods | mask;
729                /* entry is active if vmods are bound */
730                entry->active = (mask != 0);
731            }
732            else
733                entry->active = 1;
734        }
735    }
736    if (changes) {
737        int type_ndx;
738
739        type_ndx = type - xkb->map->types;
740        if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
741            return;
742        if (changes->map.changed & XkbKeyTypesMask) {
743            int last;
744
745            last = changes->map.first_type + changes->map.num_types - 1;
746            if (type_ndx < changes->map.first_type) {
747                changes->map.first_type = type_ndx;
748                changes->map.num_types = (last - type_ndx) + 1;
749            }
750            else if (type_ndx > last) {
751                changes->map.num_types =
752                    (type_ndx - changes->map.first_type) + 1;
753            }
754        }
755        else {
756            changes->map.changed |= XkbKeyTypesMask;
757            changes->map.first_type = type_ndx;
758            changes->map.num_types = 1;
759        }
760    }
761    return;
762}
763
764Bool
765XkbApplyVirtualModChanges(XkbDescPtr xkb, unsigned changed,
766                          XkbChangesPtr changes)
767{
768    register int i;
769    unsigned int checkState = 0;
770
771    if ((!xkb) || (!xkb->map) || (changed == 0))
772        return FALSE;
773    for (i = 0; i < xkb->map->num_types; i++) {
774        if (xkb->map->types[i].mods.vmods & changed)
775            XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
776                                        changes);
777    }
778    if (changed & xkb->ctrls->internal.vmods) {
779        unsigned int newMask;
780
781        XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
782        newMask |= xkb->ctrls->internal.real_mods;
783        if (xkb->ctrls->internal.mask != newMask) {
784            xkb->ctrls->internal.mask = newMask;
785            if (changes) {
786                changes->ctrls.changed_ctrls |= XkbInternalModsMask;
787                checkState = TRUE;
788            }
789        }
790    }
791    if (changed & xkb->ctrls->ignore_lock.vmods) {
792        unsigned int newMask;
793
794        XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
795        newMask |= xkb->ctrls->ignore_lock.real_mods;
796        if (xkb->ctrls->ignore_lock.mask != newMask) {
797            xkb->ctrls->ignore_lock.mask = newMask;
798            if (changes) {
799                changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
800                checkState = TRUE;
801            }
802        }
803    }
804    if (xkb->indicators != NULL) {
805        XkbIndicatorMapPtr map;
806
807        map = &xkb->indicators->maps[0];
808        for (i = 0; i < XkbNumIndicators; i++, map++) {
809            if (map->mods.vmods & changed) {
810                unsigned int newMask;
811
812                XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
813                newMask |= map->mods.real_mods;
814                if (newMask != map->mods.mask) {
815                    map->mods.mask = newMask;
816                    if (changes) {
817                        changes->indicators.map_changes |= (1 << i);
818                        checkState = TRUE;
819                    }
820                }
821            }
822        }
823    }
824    if (xkb->compat != NULL) {
825        XkbCompatMapPtr compat;
826
827        compat = xkb->compat;
828        for (i = 0; i < XkbNumKbdGroups; i++) {
829            unsigned int newMask;
830
831            XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
832            newMask |= compat->groups[i].real_mods;
833            if (compat->groups[i].mask != newMask) {
834                compat->groups[i].mask = newMask;
835                if (changes) {
836                    changes->compat.changed_groups |= (1 << i);
837                    checkState = TRUE;
838                }
839            }
840        }
841    }
842    if (xkb->map && xkb->server) {
843        int highChange = 0, lowChange = -1;
844
845        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
846            if (XkbKeyHasActions(xkb, i)) {
847                register XkbAction *pAct;
848                register int n;
849
850                pAct = XkbKeyActionsPtr(xkb, i);
851                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
852                    if ((pAct->type != XkbSA_NoAction) &&
853                        XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
854                        if (lowChange < 0)
855                            lowChange = i;
856                        highChange = i;
857                    }
858                }
859            }
860        }
861        if (changes && (lowChange > 0)) {       /* something changed */
862            if (changes->map.changed & XkbKeyActionsMask) {
863                int last;
864
865                if (changes->map.first_key_act < lowChange)
866                    lowChange = changes->map.first_key_act;
867                last =
868                    changes->map.first_key_act + changes->map.num_key_acts - 1;
869                if (last > highChange)
870                    highChange = last;
871            }
872            changes->map.changed |= XkbKeyActionsMask;
873            changes->map.first_key_act = lowChange;
874            changes->map.num_key_acts = (highChange - lowChange) + 1;
875        }
876    }
877    return checkState;
878}
879