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