XKBMisc.c revision 818534a1
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) || ((groups & XkbAllGroupsMask) == 0) ||
686        (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        return Success;
698    }
699
700    nOldGroups = XkbKeyNumGroups(xkb, key);
701    oldWidth = XkbKeyGroupsWidth(xkb, key);
702    for (width = i = 0; i < nGroups; i++) {
703        if (groups & (1 << i))
704            newTypes[i] = newTypesIn[i];
705        else if (i < nOldGroups)
706            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
707        else if (nOldGroups > 0)
708            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
709        else
710            newTypes[i] = XkbTwoLevelIndex;
711        if (newTypes[i] > xkb->map->num_types)
712            return BadMatch;
713        pNewType = &xkb->map->types[newTypes[i]];
714        if (pNewType->num_levels > width)
715            width = pNewType->num_levels;
716    }
717    if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
718        xkb->ctrls->num_groups = nGroups;
719    if ((width != oldWidth) || (nGroups != nOldGroups)) {
720        KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
721        int nCopy;
722
723        if (nOldGroups == 0) {
724            pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
725            if (pSyms != NULL) {
726                i = xkb->map->key_sym_map[key].group_info;
727                i = XkbSetNumGroups(i, nGroups);
728                xkb->map->key_sym_map[key].group_info = i;
729                xkb->map->key_sym_map[key].width = width;
730                for (i = 0; i < nGroups; i++) {
731                    xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
732                }
733                return Success;
734            }
735            return BadAlloc;
736        }
737        pSyms = XkbKeySymsPtr(xkb, key);
738        memcpy(oldSyms, pSyms, XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
739        pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
740        if (pSyms == NULL)
741            return BadAlloc;
742        bzero(pSyms, width * nGroups * sizeof(KeySym));
743        for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
744            pOldType = XkbKeyKeyType(xkb, key, i);
745            pNewType = &xkb->map->types[newTypes[i]];
746            if (pNewType->num_levels > pOldType->num_levels)
747                nCopy = pOldType->num_levels;
748            else
749                nCopy = pNewType->num_levels;
750            memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
751                   nCopy * sizeof(KeySym));
752        }
753        if (XkbKeyHasActions(xkb, key)) {
754            XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
755
756            pActs = XkbKeyActionsPtr(xkb, key);
757            memcpy(oldActs, pActs, XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
758            pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
759            if (pActs == NULL)
760                return BadAlloc;
761            bzero(pActs, width * nGroups * sizeof(XkbAction));
762            for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
763                pOldType = XkbKeyKeyType(xkb, key, i);
764                pNewType = &xkb->map->types[newTypes[i]];
765                if (pNewType->num_levels > pOldType->num_levels)
766                    nCopy = pOldType->num_levels;
767                else
768                    nCopy = pNewType->num_levels;
769                memcpy(&pActs[i * width], &oldActs[i * oldWidth],
770                       nCopy * sizeof(XkbAction));
771            }
772        }
773        i = xkb->map->key_sym_map[key].group_info;
774        i = XkbSetNumGroups(i, nGroups);
775        xkb->map->key_sym_map[key].group_info = i;
776        xkb->map->key_sym_map[key].width = width;
777    }
778    width = 0;
779    for (i = 0; i < nGroups; i++) {
780        xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
781        if (xkb->map->types[newTypes[i]].num_levels > width)
782            width = xkb->map->types[newTypes[i]].num_levels;
783    }
784    xkb->map->key_sym_map[key].width = width;
785    if (changes != NULL) {
786        if (changes->changed & XkbKeySymsMask) {
787            _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
788                             key);
789        }
790        else {
791            changes->changed |= XkbKeySymsMask;
792            changes->first_key_sym = key;
793            changes->num_key_syms = 1;
794        }
795    }
796    return Success;
797}
798
799/***====================================================================***/
800
801Bool
802XkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
803{
804    register int i, bit;
805    register unsigned mask;
806
807    if (xkb == NULL)
808        return False;
809    if (virtual_mask == 0) {
810        *mask_rtrn = 0;
811        return True;
812    }
813    if (xkb->server == NULL)
814        return False;
815    for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
816        if (virtual_mask & bit)
817            mask |= xkb->server->vmods[i];
818    }
819    *mask_rtrn = mask;
820    return True;
821}
822
823/***====================================================================***/
824
825Bool
826XkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
827{
828    unsigned int tmp;
829
830    switch (act->type) {
831    case XkbSA_SetMods:
832    case XkbSA_LatchMods:
833    case XkbSA_LockMods:
834        if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
835            XkbVirtualModsToReal(xkb, tmp, &tmp);
836            act->mods.mask = act->mods.real_mods;
837            act->mods.mask |= tmp;
838            return True;
839        }
840        break;
841    case XkbSA_ISOLock:
842        if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
843            XkbVirtualModsToReal(xkb, tmp, &tmp);
844            act->iso.mask = act->iso.real_mods;
845            act->iso.mask |= tmp;
846            return True;
847        }
848        break;
849    }
850    return False;
851}
852
853void
854XkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
855                            XkbKeyTypePtr type,
856                            unsigned int changed,
857                            XkbChangesPtr changes)
858{
859    register unsigned int i;
860    unsigned int mask;
861
862    XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
863    type->mods.mask = type->mods.real_mods | mask;
864    if ((type->map_count > 0) && (type->mods.vmods != 0)) {
865        XkbKTMapEntryPtr entry;
866
867        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
868            if (entry->mods.vmods != 0) {
869                XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
870                entry->mods.mask = entry->mods.real_mods | mask;
871                /* entry is active if vmods are bound */
872                entry->active = (mask != 0);
873            }
874            else
875                entry->active = 1;
876        }
877    }
878    if (changes) {
879        int type_ndx;
880
881        type_ndx = type - xkb->map->types;
882        if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
883            return;
884        if (changes->map.changed & XkbKeyTypesMask) {
885            int last;
886
887            last = changes->map.first_type + changes->map.num_types - 1;
888            if (type_ndx < changes->map.first_type) {
889                changes->map.first_type = type_ndx;
890                changes->map.num_types = (last - type_ndx) + 1;
891            }
892            else if (type_ndx > last) {
893                changes->map.num_types =
894                    (type_ndx - changes->map.first_type) + 1;
895            }
896        }
897        else {
898            changes->map.changed |= XkbKeyTypesMask;
899            changes->map.first_type = type_ndx;
900            changes->map.num_types = 1;
901        }
902    }
903    return;
904}
905
906Bool
907XkbApplyVirtualModChanges(XkbDescPtr xkb,
908                          unsigned changed,
909                          XkbChangesPtr changes)
910{
911    register int i;
912    unsigned int checkState = 0;
913
914    if ((!xkb) || (!xkb->map) || (changed == 0))
915        return False;
916    for (i = 0; i < xkb->map->num_types; i++) {
917        if (xkb->map->types[i].mods.vmods & changed)
918            XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
919                                        changes);
920    }
921    if (changed & xkb->ctrls->internal.vmods) {
922        unsigned int newMask;
923
924        XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
925        newMask |= xkb->ctrls->internal.real_mods;
926        if (xkb->ctrls->internal.mask != newMask) {
927            xkb->ctrls->internal.mask = newMask;
928            if (changes) {
929                changes->ctrls.changed_ctrls |= XkbInternalModsMask;
930                checkState = True;
931            }
932        }
933    }
934    if (changed & xkb->ctrls->ignore_lock.vmods) {
935        unsigned int newMask;
936
937        XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
938        newMask |= xkb->ctrls->ignore_lock.real_mods;
939        if (xkb->ctrls->ignore_lock.mask != newMask) {
940            xkb->ctrls->ignore_lock.mask = newMask;
941            if (changes) {
942                changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
943                checkState = True;
944            }
945        }
946    }
947    if (xkb->indicators != NULL) {
948        XkbIndicatorMapPtr map;
949
950        map = &xkb->indicators->maps[0];
951        for (i = 0; i < XkbNumIndicators; i++, map++) {
952            if (map->mods.vmods & changed) {
953                unsigned int newMask;
954
955                XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
956                newMask |= map->mods.real_mods;
957                if (newMask != map->mods.mask) {
958                    map->mods.mask = newMask;
959                    if (changes) {
960                        changes->indicators.map_changes |= (1 << i);
961                        checkState = True;
962                    }
963                }
964            }
965        }
966    }
967    if (xkb->compat != NULL) {
968        XkbCompatMapPtr compat;
969
970        compat = xkb->compat;
971        for (i = 0; i < XkbNumKbdGroups; i++) {
972            unsigned int newMask;
973
974            XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
975            newMask |= compat->groups[i].real_mods;
976            if (compat->groups[i].mask != newMask) {
977                compat->groups[i].mask = newMask;
978                if (changes) {
979                    changes->compat.changed_groups |= (1 << i);
980                    checkState = True;
981                }
982            }
983        }
984    }
985    if (xkb->map && xkb->server) {
986        int highChange = 0, lowChange = -1;
987
988        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
989            if (XkbKeyHasActions(xkb, i)) {
990                register XkbAction *pAct;
991                register int n;
992
993                pAct = XkbKeyActionsPtr(xkb, i);
994                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
995                    if ((pAct->type != XkbSA_NoAction) &&
996                        XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
997                        if (lowChange < 0)
998                            lowChange = i;
999                        highChange = i;
1000                    }
1001                }
1002            }
1003        }
1004        if (changes && (lowChange > 0)) {       /* something changed */
1005            if (changes->map.changed & XkbKeyActionsMask) {
1006                int last;
1007
1008                if (changes->map.first_key_act < lowChange)
1009                    lowChange = changes->map.first_key_act;
1010                last =
1011                    changes->map.first_key_act + changes->map.num_key_acts - 1;
1012                if (last > highChange)
1013                    highChange = last;
1014            }
1015            changes->map.changed |= XkbKeyActionsMask;
1016            changes->map.first_key_act = lowChange;
1017            changes->map.num_key_acts = (highChange - lowChange) + 1;
1018        }
1019    }
1020    return checkState;
1021}
1022