XKBMisc.c revision 9c019ec5
11ab64890Smrg/************************************************************
21ab64890SmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
31ab64890Smrg
41ab64890SmrgPermission to use, copy, modify, and distribute this
51ab64890Smrgsoftware and its documentation for any purpose and without
61ab64890Smrgfee is hereby granted, provided that the above copyright
71ab64890Smrgnotice appear in all copies and that both that copyright
81ab64890Smrgnotice and this permission notice appear in supporting
961b2299dSmrgdocumentation, and that the name of Silicon Graphics not be
1061b2299dSmrgused in advertising or publicity pertaining to distribution
111ab64890Smrgof the software without specific prior written permission.
1261b2299dSmrgSilicon Graphics makes no representation about the suitability
131ab64890Smrgof this software for any purpose. It is provided "as is"
141ab64890Smrgwithout any express or implied warranty.
151ab64890Smrg
1661b2299dSmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1761b2299dSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
181ab64890SmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
1961b2299dSmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2061b2299dSmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2161b2299dSmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
221ab64890SmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
231ab64890SmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
241ab64890Smrg
251ab64890Smrg********************************************************/
261ab64890Smrg
27818534a1Smrg#ifdef HAVE_CONFIG_H
281ab64890Smrg#include <config.h>
291ab64890Smrg#endif
301ab64890Smrg
311ab64890Smrg
321ab64890Smrg#include <stdio.h>
331ab64890Smrg#include "Xlibint.h"
341ab64890Smrg#include <X11/extensions/XKBproto.h>
351ab64890Smrg#include <X11/keysym.h>
361ab64890Smrg#include "XKBlibint.h"
371ab64890Smrg
381ab64890Smrg
391ab64890Smrg/***====================================================================***/
401ab64890Smrg
411ab64890Smrg#define	mapSize(m)	(sizeof(m)/sizeof(XkbKTMapEntryRec))
42818534a1Smrgstatic XkbKTMapEntryRec map2Level[] = {
43818534a1Smrg    { True, ShiftMask, {1, ShiftMask, 0} }
441ab64890Smrg};
451ab64890Smrg
46818534a1Smrgstatic XkbKTMapEntryRec mapAlpha[] = {
47818534a1Smrg    { True, ShiftMask, {1, ShiftMask, 0} },
48818534a1Smrg    { True, LockMask, {0, LockMask, 0} }
491ab64890Smrg};
501ab64890Smrg
51818534a1Smrgstatic XkbModsRec preAlpha[] = {
52818534a1Smrg    {        0,        0, 0 },
53818534a1Smrg    { LockMask, LockMask, 0 }
541ab64890Smrg};
551ab64890Smrg
561ab64890Smrg#define	NL_VMOD_MASK	0
57818534a1Smrgstatic XkbKTMapEntryRec mapKeypad[] = {
58818534a1Smrg    { True, ShiftMask, { 1, ShiftMask,            0 } },
59818534a1Smrg    { False,        0, { 1,         0, NL_VMOD_MASK } }
601ab64890Smrg};
611ab64890Smrg
62818534a1Smrgstatic XkbKeyTypeRec canonicalTypes[XkbNumRequiredTypes] = {
63818534a1Smrg    { { 0, 0, 0 },
64818534a1Smrg      1,                             /* num_levels */
65818534a1Smrg      0,                             /* map_count */
66818534a1Smrg      NULL,         NULL,
67818534a1Smrg      None,         NULL
68818534a1Smrg    },
69818534a1Smrg    { { ShiftMask, ShiftMask, 0 },
70818534a1Smrg      2,                             /* num_levels */
71818534a1Smrg      mapSize(map2Level),            /* map_count */
72818534a1Smrg      map2Level,    NULL,
73818534a1Smrg      None,         NULL
74818534a1Smrg    },
75818534a1Smrg    { { ShiftMask|LockMask, ShiftMask|LockMask, 0 },
76818534a1Smrg      2,                            /* num_levels */
77818534a1Smrg      mapSize(mapAlpha),            /* map_count */
78818534a1Smrg      mapAlpha,     preAlpha,
79818534a1Smrg      None,         NULL
80818534a1Smrg    },
81818534a1Smrg    { { ShiftMask, ShiftMask, NL_VMOD_MASK },
82818534a1Smrg      2,                            /* num_levels */
83818534a1Smrg      mapSize(mapKeypad),           /* map_count */
84818534a1Smrg      mapKeypad,    NULL,
85818534a1Smrg      None,         NULL
86818534a1Smrg    }
871ab64890Smrg};
881ab64890Smrg
891ab64890SmrgStatus
90818534a1SmrgXkbInitCanonicalKeyTypes(XkbDescPtr xkb, unsigned which, int keypadVMod)
911ab64890Smrg{
92818534a1Smrg    XkbClientMapPtr map;
93818534a1Smrg    XkbKeyTypePtr from, to;
94818534a1Smrg    Status rtrn;
951ab64890Smrg
961ab64890Smrg    if (!xkb)
97818534a1Smrg        return BadMatch;
98818534a1Smrg    rtrn = XkbAllocClientMap(xkb, XkbKeyTypesMask, XkbNumRequiredTypes);
99818534a1Smrg    if (rtrn != Success)
100818534a1Smrg        return rtrn;
101818534a1Smrg    map = xkb->map;
102818534a1Smrg    if ((which & XkbAllRequiredTypes) == 0)
103818534a1Smrg        return Success;
104818534a1Smrg    rtrn = Success;
105818534a1Smrg    from = canonicalTypes;
106818534a1Smrg    to = map->types;
107818534a1Smrg    if (which & XkbOneLevelMask)
108818534a1Smrg        rtrn = XkbCopyKeyType(&from[XkbOneLevelIndex], &to[XkbOneLevelIndex]);
109818534a1Smrg    if ((which & XkbTwoLevelMask) && (rtrn == Success))
110818534a1Smrg        rtrn = XkbCopyKeyType(&from[XkbTwoLevelIndex], &to[XkbTwoLevelIndex]);
111818534a1Smrg    if ((which & XkbAlphabeticMask) && (rtrn == Success))
112818534a1Smrg        rtrn =
113818534a1Smrg            XkbCopyKeyType(&from[XkbAlphabeticIndex], &to[XkbAlphabeticIndex]);
114818534a1Smrg    if ((which & XkbKeypadMask) && (rtrn == Success)) {
115818534a1Smrg        XkbKeyTypePtr type;
116818534a1Smrg
117818534a1Smrg        rtrn = XkbCopyKeyType(&from[XkbKeypadIndex], &to[XkbKeypadIndex]);
118818534a1Smrg        type = &to[XkbKeypadIndex];
119818534a1Smrg        if ((keypadVMod >= 0) && (keypadVMod < XkbNumVirtualMods) &&
120818534a1Smrg            (rtrn == Success)) {
121818534a1Smrg            type->mods.vmods = (1 << keypadVMod);
122818534a1Smrg            type->map[0].active = True;
123818534a1Smrg            type->map[0].mods.mask = ShiftMask;
124818534a1Smrg            type->map[0].mods.real_mods = ShiftMask;
125818534a1Smrg            type->map[0].mods.vmods = 0;
126818534a1Smrg            type->map[0].level = 1;
127818534a1Smrg            type->map[1].active = False;
128818534a1Smrg            type->map[1].mods.mask = 0;
129818534a1Smrg            type->map[1].mods.real_mods = 0;
130818534a1Smrg            type->map[1].mods.vmods = (1 << keypadVMod);
131818534a1Smrg            type->map[1].level = 1;
132818534a1Smrg        }
1331ab64890Smrg    }
1341ab64890Smrg    return Success;
1351ab64890Smrg}
1361ab64890Smrg
1371ab64890Smrg/***====================================================================***/
1381ab64890Smrg
1391ab64890Smrg#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
1401ab64890Smrg#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
1411ab64890Smrg
1421ab64890Smrgint
143818534a1SmrgXkbKeyTypesForCoreSymbols(XkbDescPtr xkb,
144818534a1Smrg                          int map_width,
145818534a1Smrg                          KeySym *core_syms,
146818534a1Smrg                          unsigned int protected,
147818534a1Smrg                          int *types_inout,
148818534a1Smrg                          KeySym *xkb_syms_rtrn)
1491ab64890Smrg{
150818534a1Smrg    register int i;
151818534a1Smrg    unsigned int empty;
152818534a1Smrg    int nSyms[XkbNumKbdGroups];
153818534a1Smrg    int nGroups, tmp, groupsWidth;
1541ab64890Smrg
1551ab64890Smrg    /* Section 12.2 of the protocol describes this process in more detail */
1561ab64890Smrg    /* Step 1:  find the # of symbols in the core mapping per group */
157818534a1Smrg    groupsWidth = 2;
158818534a1Smrg    for (i = 0; i < XkbNumKbdGroups; i++) {
159818534a1Smrg        if ((protected & (1 << i)) && (types_inout[i] < xkb->map->num_types)) {
160818534a1Smrg            nSyms[i] = xkb->map->types[types_inout[i]].num_levels;
161818534a1Smrg            if (nSyms[i] > groupsWidth)
162818534a1Smrg                groupsWidth = nSyms[i];
163818534a1Smrg        }
164818534a1Smrg        else {
165818534a1Smrg            types_inout[i] = XkbTwoLevelIndex;  /* don't really know, yet */
166818534a1Smrg            nSyms[i] = 2;
167818534a1Smrg        }
168818534a1Smrg    }
169818534a1Smrg    if (nSyms[XkbGroup1Index] < 2)
170818534a1Smrg        nSyms[XkbGroup1Index] = 2;
171818534a1Smrg    if (nSyms[XkbGroup2Index] < 2)
172818534a1Smrg        nSyms[XkbGroup2Index] = 2;
173818534a1Smrg    /* Step 2:  Copy the symbols from the core ordering to XKB ordering */
174818534a1Smrg    /*          symbols in the core are in the order:                   */
175818534a1Smrg    /*          G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */
176818534a1Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 0)] = CORE_SYM(0);
177818534a1Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 1)] = CORE_SYM(1);
178818534a1Smrg    for (i = 2; i < nSyms[XkbGroup1Index]; i++) {
179818534a1Smrg        xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, i)] = CORE_SYM(2 + i);
180818534a1Smrg    }
181818534a1Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 0)] = CORE_SYM(2);
182818534a1Smrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 1)] = CORE_SYM(3);
183818534a1Smrg    tmp = 2 + (nSyms[XkbGroup1Index] - 2);      /* offset to extra group2 syms */
184818534a1Smrg    for (i = 2; i < nSyms[XkbGroup2Index]; i++) {
185818534a1Smrg        xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, i)] = CORE_SYM(tmp + i);
186818534a1Smrg    }
187818534a1Smrg    tmp = nSyms[XkbGroup1Index] + nSyms[XkbGroup2Index];
188818534a1Smrg    if ((tmp >= map_width) &&
189818534a1Smrg        ((protected & (XkbExplicitKeyType3Mask | XkbExplicitKeyType4Mask)) ==
190818534a1Smrg         0)) {
191818534a1Smrg        nSyms[XkbGroup3Index] = 0;
192818534a1Smrg        nSyms[XkbGroup4Index] = 0;
193818534a1Smrg        nGroups = 2;
1941ab64890Smrg    }
1951ab64890Smrg    else {
196818534a1Smrg        nGroups = 3;
197818534a1Smrg        for (i = 0; i < nSyms[XkbGroup3Index]; i++, tmp++) {
198818534a1Smrg            xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index, i)] = CORE_SYM(tmp);
199818534a1Smrg        }
200818534a1Smrg        if ((tmp < map_width) || (protected & XkbExplicitKeyType4Mask)) {
201818534a1Smrg            nGroups = 4;
202818534a1Smrg            for (i = 0; i < nSyms[XkbGroup4Index]; i++, tmp++) {
203818534a1Smrg                xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index, i)] = CORE_SYM(tmp);
204818534a1Smrg            }
205818534a1Smrg        }
206818534a1Smrg        else {
207818534a1Smrg            nSyms[XkbGroup4Index] = 0;
208818534a1Smrg        }
2091ab64890Smrg    }
2101ab64890Smrg    /* steps 3&4: alphanumeric expansion,  assign canonical types */
211818534a1Smrg    empty = 0;
212818534a1Smrg    for (i = 0; i < nGroups; i++) {
213818534a1Smrg        KeySym *syms;
214818534a1Smrg
215818534a1Smrg        syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
216818534a1Smrg        if ((nSyms[i] > 1) && (syms[1] == NoSymbol) && (syms[0] != NoSymbol)) {
217818534a1Smrg            KeySym upper, lower;
218818534a1Smrg
219818534a1Smrg            XConvertCase(syms[0], &lower, &upper);
220818534a1Smrg            if (upper != lower) {
221818534a1Smrg                xkb_syms_rtrn[XKB_OFFSET(i, 0)] = lower;
222818534a1Smrg                xkb_syms_rtrn[XKB_OFFSET(i, 1)] = upper;
223818534a1Smrg                if ((protected & (1 << i)) == 0)
224818534a1Smrg                    types_inout[i] = XkbAlphabeticIndex;
225818534a1Smrg            }
226818534a1Smrg            else if ((protected & (1 << i)) == 0) {
227818534a1Smrg                types_inout[i] = XkbOneLevelIndex;
228818534a1Smrg                /*      nSyms[i]=       1; */
229818534a1Smrg            }
230818534a1Smrg        }
231818534a1Smrg        if (((protected & (1 << i)) == 0) &&
232818534a1Smrg            (types_inout[i] == XkbTwoLevelIndex)) {
233818534a1Smrg            if (IsKeypadKey(syms[0]) || IsKeypadKey(syms[1]))
234818534a1Smrg                types_inout[i] = XkbKeypadIndex;
235818534a1Smrg            else {
236818534a1Smrg                KeySym upper, lower;
237818534a1Smrg
238818534a1Smrg                XConvertCase(syms[0], &lower, &upper);
239818534a1Smrg                if ((syms[0] == lower) && (syms[1] == upper))
240818534a1Smrg                    types_inout[i] = XkbAlphabeticIndex;
241818534a1Smrg            }
242818534a1Smrg        }
243818534a1Smrg        if (syms[0] == NoSymbol) {
244818534a1Smrg            register int n;
245818534a1Smrg            Bool found;
246818534a1Smrg
247818534a1Smrg            for (n = 1, found = False; (!found) && (n < nSyms[i]); n++) {
248818534a1Smrg                found = (syms[n] != NoSymbol);
249818534a1Smrg            }
250818534a1Smrg            if (!found)
251818534a1Smrg                empty |= (1 << i);
252818534a1Smrg        }
2531ab64890Smrg    }
2541ab64890Smrg    /* step 5: squoosh out empty groups */
2551ab64890Smrg    if (empty) {
256818534a1Smrg        for (i = nGroups - 1; i >= 0; i--) {
257818534a1Smrg            if (((empty & (1 << i)) == 0) || (protected & (1 << i)))
258818534a1Smrg                break;
259818534a1Smrg            nGroups--;
260818534a1Smrg        }
2611ab64890Smrg    }
262818534a1Smrg    if (nGroups < 1)
263818534a1Smrg        return 0;
2641ab64890Smrg
2651ab64890Smrg    /* step 6: replicate group 1 into group two, if necessary */
266818534a1Smrg    if ((nGroups > 1) &&
267818534a1Smrg        ((empty & (XkbGroup1Mask | XkbGroup2Mask)) == XkbGroup2Mask)) {
268818534a1Smrg        if ((protected & (XkbExplicitKeyType1Mask | XkbExplicitKeyType2Mask)) ==
269818534a1Smrg            0) {
270818534a1Smrg            nSyms[XkbGroup2Index] = nSyms[XkbGroup1Index];
271818534a1Smrg            types_inout[XkbGroup2Index] = types_inout[XkbGroup1Index];
272818534a1Smrg            memcpy((char *) &xkb_syms_rtrn[2], (char *) xkb_syms_rtrn,
273818534a1Smrg                   2 * sizeof(KeySym));
274818534a1Smrg        }
275818534a1Smrg        else if (types_inout[XkbGroup1Index] == types_inout[XkbGroup2Index]) {
276818534a1Smrg            memcpy((char *) &xkb_syms_rtrn[nSyms[XkbGroup1Index]],
277818534a1Smrg                   (char *) xkb_syms_rtrn,
278818534a1Smrg                   nSyms[XkbGroup1Index] * sizeof(KeySym));
279818534a1Smrg        }
2801ab64890Smrg    }
2811ab64890Smrg
2821ab64890Smrg    /* step 7: check for all groups identical or all width 1 */
283818534a1Smrg    if (nGroups > 1) {
284818534a1Smrg        Bool sameType, allOneLevel;
285818534a1Smrg
286818534a1Smrg        allOneLevel = (xkb->map->types[types_inout[0]].num_levels == 1);
287818534a1Smrg        for (i = 1, sameType = True; (allOneLevel || sameType) && (i < nGroups);
288818534a1Smrg             i++) {
289818534a1Smrg            sameType = (sameType &&
290818534a1Smrg                        (types_inout[i] == types_inout[XkbGroup1Index]));
291818534a1Smrg            if (allOneLevel)
292818534a1Smrg                allOneLevel = (xkb->map->types[types_inout[i]].num_levels == 1);
293818534a1Smrg        }
294818534a1Smrg        if ((sameType) &&
295818534a1Smrg            (!(protected &
296818534a1Smrg               (XkbExplicitKeyTypesMask & ~XkbExplicitKeyType1Mask)))) {
297818534a1Smrg            register int s;
298818534a1Smrg            Bool identical;
299818534a1Smrg
300818534a1Smrg            for (i = 1, identical = True; identical && (i < nGroups); i++) {
301818534a1Smrg                KeySym *syms;
302818534a1Smrg
303818534a1Smrg                syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
304818534a1Smrg                for (s = 0; identical && (s < nSyms[i]); s++) {
305818534a1Smrg                    if (syms[s] != xkb_syms_rtrn[s])
306818534a1Smrg                        identical = False;
307818534a1Smrg                }
308818534a1Smrg            }
309818534a1Smrg            if (identical)
310818534a1Smrg                nGroups = 1;
311818534a1Smrg        }
312818534a1Smrg        if (allOneLevel && (nGroups > 1)) {
313818534a1Smrg            KeySym *syms;
314818534a1Smrg
315818534a1Smrg            syms = &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
316818534a1Smrg            nSyms[XkbGroup1Index] = 1;
317818534a1Smrg            for (i = 1; i < nGroups; i++) {
318818534a1Smrg                xkb_syms_rtrn[i] = syms[0];
319818534a1Smrg                syms += nSyms[i];
320818534a1Smrg                nSyms[i] = 1;
321818534a1Smrg            }
322818534a1Smrg        }
3231ab64890Smrg    }
3241ab64890Smrg    return nGroups;
3251ab64890Smrg}
3261ab64890Smrg
3271ab64890Smrgstatic XkbSymInterpretPtr
328818534a1Smrg_XkbFindMatchingInterp(XkbDescPtr xkb,
329818534a1Smrg                       KeySym sym,
330818534a1Smrg                       unsigned int real_mods,
331818534a1Smrg                       unsigned int level)
3321ab64890Smrg{
333818534a1Smrg    register unsigned i;
334818534a1Smrg    XkbSymInterpretPtr interp, rtrn;
335818534a1Smrg    CARD8 mods;
336818534a1Smrg
337818534a1Smrg    rtrn = NULL;
338818534a1Smrg    interp = xkb->compat->sym_interpret;
339818534a1Smrg    for (i = 0; i < xkb->compat->num_si; i++, interp++) {
340818534a1Smrg        if ((interp->sym == NoSymbol) || (sym == interp->sym)) {
341818534a1Smrg            int match;
342818534a1Smrg
343818534a1Smrg            if ((level == 0) || ((interp->match & XkbSI_LevelOneOnly) == 0))
344818534a1Smrg                mods = real_mods;
345818534a1Smrg            else
346818534a1Smrg                mods = 0;
347818534a1Smrg            switch (interp->match & XkbSI_OpMask) {
348818534a1Smrg            case XkbSI_NoneOf:
349818534a1Smrg                match = ((interp->mods & mods) == 0);
350818534a1Smrg                break;
351818534a1Smrg            case XkbSI_AnyOfOrNone:
352818534a1Smrg                match = ((mods == 0) || ((interp->mods & mods) != 0));
353818534a1Smrg                break;
354818534a1Smrg            case XkbSI_AnyOf:
355818534a1Smrg                match = ((interp->mods & mods) != 0);
356818534a1Smrg                break;
357818534a1Smrg            case XkbSI_AllOf:
358818534a1Smrg                match = ((interp->mods & mods) == interp->mods);
359818534a1Smrg                break;
360818534a1Smrg            case XkbSI_Exactly:
361818534a1Smrg                match = (interp->mods == mods);
362818534a1Smrg                break;
363818534a1Smrg            default:
364818534a1Smrg                match = 0;
365818534a1Smrg                break;
366818534a1Smrg            }
367818534a1Smrg            if (match) {
368818534a1Smrg                if (interp->sym != NoSymbol) {
369818534a1Smrg                    return interp;
370818534a1Smrg                }
371818534a1Smrg                else if (rtrn == NULL) {
372818534a1Smrg                    rtrn = interp;
373818534a1Smrg                }
374818534a1Smrg            }
375818534a1Smrg        }
3761ab64890Smrg    }
3771ab64890Smrg    return rtrn;
3781ab64890Smrg}
3791ab64890Smrg
3801ab64890Smrgstatic void
381818534a1Smrg_XkbAddKeyChange(KeyCode *pFirst, unsigned char *pNum, KeyCode newKey)
3821ab64890Smrg{
383818534a1Smrg    KeyCode last;
3841ab64890Smrg
385818534a1Smrg    last = (*pFirst) + (*pNum);
386818534a1Smrg    if (newKey < *pFirst) {
387818534a1Smrg        *pFirst = newKey;
388818534a1Smrg        *pNum = (last - newKey) + 1;
3891ab64890Smrg    }
390818534a1Smrg    else if (newKey > last) {
391818534a1Smrg        *pNum = (last - *pFirst) + 1;
3921ab64890Smrg    }
3931ab64890Smrg    return;
3941ab64890Smrg}
3951ab64890Smrg
3961ab64890Smrgstatic void
397818534a1Smrg_XkbSetActionKeyMods(XkbDescPtr xkb, XkbAction *act, unsigned mods)
3981ab64890Smrg{
399818534a1Smrg    unsigned tmp;
4001ab64890Smrg
4011ab64890Smrg    switch (act->type) {
402818534a1Smrg    case XkbSA_SetMods:
403818534a1Smrg    case XkbSA_LatchMods:
404818534a1Smrg    case XkbSA_LockMods:
405818534a1Smrg        if (act->mods.flags & XkbSA_UseModMapMods)
406818534a1Smrg            act->mods.real_mods = act->mods.mask = mods;
407818534a1Smrg        if ((tmp = XkbModActionVMods(&act->mods)) != 0) {
408818534a1Smrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
409818534a1Smrg            act->mods.mask |= tmp;
410818534a1Smrg        }
411818534a1Smrg        break;
412818534a1Smrg    case XkbSA_ISOLock:
413818534a1Smrg        if (act->iso.flags & XkbSA_UseModMapMods)
414818534a1Smrg            act->iso.real_mods = act->iso.mask = mods;
415818534a1Smrg        if ((tmp = XkbModActionVMods(&act->iso)) != 0) {
416818534a1Smrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
417818534a1Smrg            act->iso.mask |= tmp;
418818534a1Smrg        }
419818534a1Smrg        break;
4201ab64890Smrg    }
4211ab64890Smrg    return;
4221ab64890Smrg}
4231ab64890Smrg
4241ab64890Smrg#define	IBUF_SIZE	8
4251ab64890Smrg
4261ab64890SmrgBool
427818534a1SmrgXkbApplyCompatMapToKey(XkbDescPtr xkb, KeyCode key, XkbChangesPtr changes)
4281ab64890Smrg{
429818534a1Smrg    KeySym *syms;
430818534a1Smrg    unsigned char explicit, mods;
431818534a1Smrg    XkbSymInterpretPtr *interps, ibuf[IBUF_SIZE];
432818534a1Smrg    int n, nSyms, found;
433818534a1Smrg    unsigned changed, tmp;
434818534a1Smrg
435818534a1Smrg    if ((!xkb) || (!xkb->map) || (!xkb->map->key_sym_map) ||
436818534a1Smrg        (!xkb->compat) || (!xkb->compat->sym_interpret) ||
437818534a1Smrg        (key < xkb->min_key_code) || (key > xkb->max_key_code)) {
438818534a1Smrg        return False;
439818534a1Smrg    }
440818534a1Smrg    if (((!xkb->server) || (!xkb->server->key_acts)) &&
441818534a1Smrg        (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 0) != Success)) {
442818534a1Smrg        return False;
443818534a1Smrg    }
444818534a1Smrg    changed = 0;                /* keeps track of what has changed in _this_ call */
445818534a1Smrg    explicit = xkb->server->explicit[key];
446818534a1Smrg    if (explicit & XkbExplicitInterpretMask)    /* nothing to do */
447818534a1Smrg        return True;
448818534a1Smrg    mods = (xkb->map->modmap ? xkb->map->modmap[key] : 0);
449818534a1Smrg    nSyms = XkbKeyNumSyms(xkb, key);
450818534a1Smrg    syms = XkbKeySymsPtr(xkb, key);
451818534a1Smrg    if (nSyms > IBUF_SIZE) {
452818534a1Smrg        interps = _XkbTypedCalloc(nSyms, XkbSymInterpretPtr);
453818534a1Smrg        if (interps == NULL) {
454818534a1Smrg            interps = ibuf;
455818534a1Smrg            nSyms = IBUF_SIZE;
456818534a1Smrg        }
4571ab64890Smrg    }
4581ab64890Smrg    else {
459818534a1Smrg        interps = ibuf;
460818534a1Smrg    }
461818534a1Smrg    found = 0;
462818534a1Smrg    for (n = 0; n < nSyms; n++) {
463818534a1Smrg        unsigned level = (n % XkbKeyGroupsWidth(xkb, key));
464818534a1Smrg
465818534a1Smrg        interps[n] = NULL;
466818534a1Smrg        if (syms[n] != NoSymbol) {
467818534a1Smrg            interps[n] = _XkbFindMatchingInterp(xkb, syms[n], mods, level);
468818534a1Smrg            if (interps[n] && interps[n]->act.type != XkbSA_NoAction)
469818534a1Smrg                found++;
470818534a1Smrg            else
471818534a1Smrg                interps[n] = NULL;
472818534a1Smrg        }
4731ab64890Smrg    }
4741ab64890Smrg    /* 1/28/96 (ef) -- XXX! WORKING HERE */
4751ab64890Smrg    if (!found) {
476818534a1Smrg        if (xkb->server->key_acts[key] != 0) {
477818534a1Smrg            xkb->server->key_acts[key] = 0;
478818534a1Smrg            changed |= XkbKeyActionsMask;
479818534a1Smrg        }
4801ab64890Smrg    }
4811ab64890Smrg    else {
482818534a1Smrg        XkbAction *pActs;
483818534a1Smrg        unsigned int new_vmodmask;
484818534a1Smrg
485818534a1Smrg        changed |= XkbKeyActionsMask;
486818534a1Smrg        pActs = XkbResizeKeyActions(xkb, key, nSyms);
487818534a1Smrg        if (!pActs) {
4881ab64890Smrg            if (nSyms > IBUF_SIZE)
4891ab64890Smrg                Xfree(interps);
490818534a1Smrg            return False;
491818534a1Smrg        }
492818534a1Smrg        new_vmodmask = 0;
493818534a1Smrg        for (n = 0; n < nSyms; n++) {
494818534a1Smrg            if (interps[n]) {
495818534a1Smrg                unsigned effMods;
496818534a1Smrg
497818534a1Smrg                pActs[n] = *((XkbAction *) &interps[n]->act);
498818534a1Smrg                if ((n == 0) || ((interps[n]->match & XkbSI_LevelOneOnly) == 0)) {
499818534a1Smrg                    effMods = mods;
500818534a1Smrg                    if (interps[n]->virtual_mod != XkbNoModifier)
501818534a1Smrg                        new_vmodmask |= (1 << interps[n]->virtual_mod);
502818534a1Smrg                }
503818534a1Smrg                else
504818534a1Smrg                    effMods = 0;
505818534a1Smrg                _XkbSetActionKeyMods(xkb, &pActs[n], effMods);
506818534a1Smrg            }
507818534a1Smrg            else
508818534a1Smrg                pActs[n].type = XkbSA_NoAction;
509818534a1Smrg        }
510818534a1Smrg        if (((explicit & XkbExplicitVModMapMask) == 0) &&
511818534a1Smrg            (xkb->server->vmodmap[key] != new_vmodmask)) {
512818534a1Smrg            changed |= XkbVirtualModMapMask;
513818534a1Smrg            xkb->server->vmodmap[key] = new_vmodmask;
514818534a1Smrg        }
515818534a1Smrg        if (interps[0]) {
516818534a1Smrg            if ((interps[0]->flags & XkbSI_LockingKey) &&
517818534a1Smrg                ((explicit & XkbExplicitBehaviorMask) == 0)) {
518818534a1Smrg                xkb->server->behaviors[key].type = XkbKB_Lock;
519818534a1Smrg                changed |= XkbKeyBehaviorsMask;
520818534a1Smrg            }
521818534a1Smrg            if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
522818534a1Smrg                CARD8 old;
523818534a1Smrg
524818534a1Smrg                old = xkb->ctrls->per_key_repeat[key / 8];
525818534a1Smrg                if (interps[0]->flags & XkbSI_AutoRepeat)
526818534a1Smrg                    xkb->ctrls->per_key_repeat[key / 8] |= (1 << (key % 8));
527818534a1Smrg                else
528818534a1Smrg                    xkb->ctrls->per_key_repeat[key / 8] &= ~(1 << (key % 8));
529818534a1Smrg                if (changes && (old != xkb->ctrls->per_key_repeat[key / 8]))
530818534a1Smrg                    changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
531818534a1Smrg            }
532818534a1Smrg        }
533818534a1Smrg    }
534818534a1Smrg    if ((!found) || (interps[0] == NULL)) {
535818534a1Smrg        if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
536818534a1Smrg            CARD8 old;
537818534a1Smrg
538818534a1Smrg            old = xkb->ctrls->per_key_repeat[key / 8];
5391ab64890Smrg#ifdef RETURN_SHOULD_REPEAT
540818534a1Smrg            if (*XkbKeySymsPtr(xkb, key) != XK_Return)
5411ab64890Smrg#endif
542818534a1Smrg                xkb->ctrls->per_key_repeat[key / 8] |= (1 << (key % 8));
543818534a1Smrg            if (changes && (old != xkb->ctrls->per_key_repeat[key / 8]))
544818534a1Smrg                changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
545818534a1Smrg        }
546818534a1Smrg        if (((explicit & XkbExplicitBehaviorMask) == 0) &&
547818534a1Smrg            (xkb->server->behaviors[key].type == XkbKB_Lock)) {
548818534a1Smrg            xkb->server->behaviors[key].type = XkbKB_Default;
549818534a1Smrg            changed |= XkbKeyBehaviorsMask;
550818534a1Smrg        }
5511ab64890Smrg    }
5521ab64890Smrg    if (changes) {
553818534a1Smrg        XkbMapChangesPtr mc;
554818534a1Smrg
555818534a1Smrg        mc = &changes->map;
556818534a1Smrg        tmp = (changed & mc->changed);
557818534a1Smrg        if (tmp & XkbKeyActionsMask)
558818534a1Smrg            _XkbAddKeyChange(&mc->first_key_act, &mc->num_key_acts, key);
559818534a1Smrg        else if (changed & XkbKeyActionsMask) {
560818534a1Smrg            mc->changed |= XkbKeyActionsMask;
561818534a1Smrg            mc->first_key_act = key;
562818534a1Smrg            mc->num_key_acts = 1;
563818534a1Smrg        }
564818534a1Smrg        if (tmp & XkbKeyBehaviorsMask) {
565818534a1Smrg            _XkbAddKeyChange(&mc->first_key_behavior, &mc->num_key_behaviors,
566818534a1Smrg                             key);
567818534a1Smrg        }
568818534a1Smrg        else if (changed & XkbKeyBehaviorsMask) {
569818534a1Smrg            mc->changed |= XkbKeyBehaviorsMask;
570818534a1Smrg            mc->first_key_behavior = key;
571818534a1Smrg            mc->num_key_behaviors = 1;
572818534a1Smrg        }
573818534a1Smrg        if (tmp & XkbVirtualModMapMask)
574818534a1Smrg            _XkbAddKeyChange(&mc->first_vmodmap_key, &mc->num_vmodmap_keys,
575818534a1Smrg                             key);
576818534a1Smrg        else if (changed & XkbVirtualModMapMask) {
577818534a1Smrg            mc->changed |= XkbVirtualModMapMask;
578818534a1Smrg            mc->first_vmodmap_key = key;
579818534a1Smrg            mc->num_vmodmap_keys = 1;
580818534a1Smrg        }
581818534a1Smrg        mc->changed |= changed;
582818534a1Smrg    }
583818534a1Smrg    if (interps != ibuf)
584818534a1Smrg        _XkbFree(interps);
5851ab64890Smrg    return True;
5861ab64890Smrg}
5871ab64890Smrg
5881ab64890SmrgBool
589818534a1SmrgXkbUpdateMapFromCore(XkbDescPtr xkb,
590818534a1Smrg                     KeyCode first_key,
591818534a1Smrg                     int num_keys,
592818534a1Smrg                     int map_width,
593818534a1Smrg                     KeySym *core_keysyms,
594818534a1Smrg                     XkbChangesPtr changes)
5951ab64890Smrg{
596818534a1Smrg    register int key, last_key;
597818534a1Smrg    KeySym *syms;
5981ab64890Smrg
599818534a1Smrg    syms = &core_keysyms[(first_key - xkb->min_key_code) * map_width];
6001ab64890Smrg    if (changes) {
601818534a1Smrg        if (changes->map.changed & XkbKeySymsMask) {
602818534a1Smrg            _XkbAddKeyChange(&changes->map.first_key_sym,
603818534a1Smrg                             &changes->map.num_key_syms, first_key);
604818534a1Smrg            if (num_keys > 1) {
605818534a1Smrg                _XkbAddKeyChange(&changes->map.first_key_sym,
606818534a1Smrg                                 &changes->map.num_key_syms,
607818534a1Smrg                                 first_key + num_keys - 1);
608818534a1Smrg            }
609818534a1Smrg        }
610818534a1Smrg        else {
611818534a1Smrg            changes->map.changed |= XkbKeySymsMask;
612818534a1Smrg            changes->map.first_key_sym = first_key;
613818534a1Smrg            changes->map.num_key_syms = num_keys;
614818534a1Smrg        }
615818534a1Smrg    }
616818534a1Smrg    last_key = first_key + num_keys - 1;
617818534a1Smrg    for (key = first_key; key <= last_key; key++, syms += map_width) {
618818534a1Smrg        XkbMapChangesPtr mc;
619818534a1Smrg        unsigned explicit;
620818534a1Smrg        KeySym tsyms[XkbMaxSymsPerKey];
621818534a1Smrg        int types[XkbNumKbdGroups];
622818534a1Smrg        int nG;
623818534a1Smrg
624818534a1Smrg        explicit = xkb->server->explicit[key] & XkbExplicitKeyTypesMask;
625818534a1Smrg        types[XkbGroup1Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
626818534a1Smrg        types[XkbGroup2Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup2Index);
627818534a1Smrg        types[XkbGroup3Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup3Index);
628818534a1Smrg        types[XkbGroup4Index] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup4Index);
629818534a1Smrg        nG = XkbKeyTypesForCoreSymbols(xkb, map_width, syms, explicit, types,
630818534a1Smrg                                       tsyms);
631818534a1Smrg        if (changes)
632818534a1Smrg            mc = &changes->map;
633818534a1Smrg        else
634818534a1Smrg            mc = NULL;
635818534a1Smrg        XkbChangeTypesOfKey(xkb, key, nG, XkbAllGroupsMask, types, mc);
636818534a1Smrg        memcpy((char *) XkbKeySymsPtr(xkb, key), (char *) tsyms,
637818534a1Smrg               XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
638818534a1Smrg        XkbApplyCompatMapToKey(xkb, key, changes);
639818534a1Smrg    }
640818534a1Smrg
641818534a1Smrg    if ((xkb->map->modmap != NULL) && (changes) &&
642818534a1Smrg        (changes->map.changed & (XkbVirtualModMapMask | XkbModifierMapMask))) {
643818534a1Smrg        unsigned char newVMods[XkbNumVirtualMods];
644818534a1Smrg        register unsigned bit, i;
645818534a1Smrg        unsigned present;
646818534a1Smrg
647818534a1Smrg        bzero(newVMods, XkbNumVirtualMods);
648818534a1Smrg        present = 0;
649818534a1Smrg        for (key = xkb->min_key_code; key <= xkb->max_key_code; key++) {
650818534a1Smrg            if (xkb->server->vmodmap[key] == 0)
651818534a1Smrg                continue;
652818534a1Smrg            for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
653818534a1Smrg                if (bit & xkb->server->vmodmap[key]) {
654818534a1Smrg                    present |= bit;
655818534a1Smrg                    newVMods[i] |= xkb->map->modmap[key];
656818534a1Smrg                }
657818534a1Smrg            }
658818534a1Smrg        }
659818534a1Smrg        for (i = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
660818534a1Smrg            if ((bit & present) && (newVMods[i] != xkb->server->vmods[i])) {
661818534a1Smrg                changes->map.changed |= XkbVirtualModsMask;
662818534a1Smrg                changes->map.vmods |= bit;
663818534a1Smrg                xkb->server->vmods[i] = newVMods[i];
664818534a1Smrg            }
665818534a1Smrg        }
666818534a1Smrg    }
667818534a1Smrg    if (changes && (changes->map.changed & XkbVirtualModsMask))
668818534a1Smrg        XkbApplyVirtualModChanges(xkb, changes->map.vmods, changes);
6691ab64890Smrg    return True;
6701ab64890Smrg}
6711ab64890Smrg
6721ab64890SmrgStatus
673818534a1SmrgXkbChangeTypesOfKey(XkbDescPtr xkb,
674818534a1Smrg                    int key,
675818534a1Smrg                    int nGroups,
676818534a1Smrg                    unsigned groups,
677818534a1Smrg                    int *newTypesIn,
678818534a1Smrg                    XkbMapChangesPtr changes)
6791ab64890Smrg{
680818534a1Smrg    XkbKeyTypePtr pOldType, pNewType;
681818534a1Smrg    register int i;
682818534a1Smrg    int width, nOldGroups, oldWidth, newTypes[XkbNumKbdGroups];
683818534a1Smrg
684818534a1Smrg    if ((!xkb) || (!XkbKeycodeInRange(xkb, key)) || (!xkb->map) ||
685818534a1Smrg        (!xkb->map->types) || ((groups & XkbAllGroupsMask) == 0) ||
686818534a1Smrg        (nGroups > XkbNumKbdGroups)) {
687818534a1Smrg        return BadMatch;
688818534a1Smrg    }
689818534a1Smrg    if (nGroups == 0) {
690818534a1Smrg        for (i = 0; i < XkbNumKbdGroups; i++) {
691818534a1Smrg            xkb->map->key_sym_map[key].kt_index[i] = XkbOneLevelIndex;
692818534a1Smrg        }
693818534a1Smrg        i = xkb->map->key_sym_map[key].group_info;
694818534a1Smrg        i = XkbSetNumGroups(i, 0);
695818534a1Smrg        xkb->map->key_sym_map[key].group_info = i;
696818534a1Smrg        XkbResizeKeySyms(xkb, key, 0);
697818534a1Smrg        return Success;
698818534a1Smrg    }
699818534a1Smrg
700818534a1Smrg    nOldGroups = XkbKeyNumGroups(xkb, key);
701818534a1Smrg    oldWidth = XkbKeyGroupsWidth(xkb, key);
702818534a1Smrg    for (width = i = 0; i < nGroups; i++) {
703818534a1Smrg        if (groups & (1 << i))
704818534a1Smrg            newTypes[i] = newTypesIn[i];
705818534a1Smrg        else if (i < nOldGroups)
706818534a1Smrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
707818534a1Smrg        else if (nOldGroups > 0)
708818534a1Smrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
709818534a1Smrg        else
710818534a1Smrg            newTypes[i] = XkbTwoLevelIndex;
711818534a1Smrg        if (newTypes[i] > xkb->map->num_types)
712818534a1Smrg            return BadMatch;
713818534a1Smrg        pNewType = &xkb->map->types[newTypes[i]];
714818534a1Smrg        if (pNewType->num_levels > width)
715818534a1Smrg            width = pNewType->num_levels;
716818534a1Smrg    }
717818534a1Smrg    if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
718818534a1Smrg        xkb->ctrls->num_groups = nGroups;
719818534a1Smrg    if ((width != oldWidth) || (nGroups != nOldGroups)) {
720818534a1Smrg        KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
721818534a1Smrg        int nCopy;
722818534a1Smrg
723818534a1Smrg        if (nOldGroups == 0) {
724818534a1Smrg            pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
725818534a1Smrg            if (pSyms != NULL) {
726818534a1Smrg                i = xkb->map->key_sym_map[key].group_info;
727818534a1Smrg                i = XkbSetNumGroups(i, nGroups);
728818534a1Smrg                xkb->map->key_sym_map[key].group_info = i;
729818534a1Smrg                xkb->map->key_sym_map[key].width = width;
730818534a1Smrg                for (i = 0; i < nGroups; i++) {
731818534a1Smrg                    xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
732818534a1Smrg                }
733818534a1Smrg                return Success;
734818534a1Smrg            }
735818534a1Smrg            return BadAlloc;
736818534a1Smrg        }
737818534a1Smrg        pSyms = XkbKeySymsPtr(xkb, key);
7389c019ec5Smaya        memcpy(oldSyms, pSyms, (size_t) XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
739818534a1Smrg        pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
740818534a1Smrg        if (pSyms == NULL)
741818534a1Smrg            return BadAlloc;
742818534a1Smrg        bzero(pSyms, width * nGroups * sizeof(KeySym));
743818534a1Smrg        for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
744818534a1Smrg            pOldType = XkbKeyKeyType(xkb, key, i);
745818534a1Smrg            pNewType = &xkb->map->types[newTypes[i]];
746818534a1Smrg            if (pNewType->num_levels > pOldType->num_levels)
747818534a1Smrg                nCopy = pOldType->num_levels;
748818534a1Smrg            else
749818534a1Smrg                nCopy = pNewType->num_levels;
750818534a1Smrg            memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
751818534a1Smrg                   nCopy * sizeof(KeySym));
752818534a1Smrg        }
753818534a1Smrg        if (XkbKeyHasActions(xkb, key)) {
754818534a1Smrg            XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
755818534a1Smrg
756818534a1Smrg            pActs = XkbKeyActionsPtr(xkb, key);
7579c019ec5Smaya            memcpy(oldActs, pActs, (size_t) XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
758818534a1Smrg            pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
759818534a1Smrg            if (pActs == NULL)
760818534a1Smrg                return BadAlloc;
761818534a1Smrg            bzero(pActs, width * nGroups * sizeof(XkbAction));
762818534a1Smrg            for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
763818534a1Smrg                pOldType = XkbKeyKeyType(xkb, key, i);
764818534a1Smrg                pNewType = &xkb->map->types[newTypes[i]];
765818534a1Smrg                if (pNewType->num_levels > pOldType->num_levels)
766818534a1Smrg                    nCopy = pOldType->num_levels;
767818534a1Smrg                else
768818534a1Smrg                    nCopy = pNewType->num_levels;
769818534a1Smrg                memcpy(&pActs[i * width], &oldActs[i * oldWidth],
770818534a1Smrg                       nCopy * sizeof(XkbAction));
771818534a1Smrg            }
772818534a1Smrg        }
773818534a1Smrg        i = xkb->map->key_sym_map[key].group_info;
774818534a1Smrg        i = XkbSetNumGroups(i, nGroups);
775818534a1Smrg        xkb->map->key_sym_map[key].group_info = i;
776818534a1Smrg        xkb->map->key_sym_map[key].width = width;
777818534a1Smrg    }
778818534a1Smrg    width = 0;
779818534a1Smrg    for (i = 0; i < nGroups; i++) {
780818534a1Smrg        xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
781818534a1Smrg        if (xkb->map->types[newTypes[i]].num_levels > width)
782818534a1Smrg            width = xkb->map->types[newTypes[i]].num_levels;
783818534a1Smrg    }
784818534a1Smrg    xkb->map->key_sym_map[key].width = width;
785818534a1Smrg    if (changes != NULL) {
786818534a1Smrg        if (changes->changed & XkbKeySymsMask) {
787818534a1Smrg            _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
788818534a1Smrg                             key);
789818534a1Smrg        }
790818534a1Smrg        else {
791818534a1Smrg            changes->changed |= XkbKeySymsMask;
792818534a1Smrg            changes->first_key_sym = key;
793818534a1Smrg            changes->num_key_syms = 1;
794818534a1Smrg        }
7951ab64890Smrg    }
7961ab64890Smrg    return Success;
7971ab64890Smrg}
7981ab64890Smrg
7991ab64890Smrg/***====================================================================***/
8001ab64890Smrg
8011ab64890SmrgBool
802818534a1SmrgXkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
8031ab64890Smrg{
804818534a1Smrg    register int i, bit;
805818534a1Smrg    register unsigned mask;
806818534a1Smrg
807818534a1Smrg    if (xkb == NULL)
808818534a1Smrg        return False;
809818534a1Smrg    if (virtual_mask == 0) {
810818534a1Smrg        *mask_rtrn = 0;
811818534a1Smrg        return True;
812818534a1Smrg    }
813818534a1Smrg    if (xkb->server == NULL)
814818534a1Smrg        return False;
815818534a1Smrg    for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
816818534a1Smrg        if (virtual_mask & bit)
817818534a1Smrg            mask |= xkb->server->vmods[i];
818818534a1Smrg    }
819818534a1Smrg    *mask_rtrn = mask;
8201ab64890Smrg    return True;
8211ab64890Smrg}
8221ab64890Smrg
8231ab64890Smrg/***====================================================================***/
8241ab64890Smrg
8251ab64890SmrgBool
826818534a1SmrgXkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
8271ab64890Smrg{
828818534a1Smrg    unsigned int tmp;
8291ab64890Smrg
8301ab64890Smrg    switch (act->type) {
831818534a1Smrg    case XkbSA_SetMods:
832818534a1Smrg    case XkbSA_LatchMods:
833818534a1Smrg    case XkbSA_LockMods:
834818534a1Smrg        if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
835818534a1Smrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
836818534a1Smrg            act->mods.mask = act->mods.real_mods;
837818534a1Smrg            act->mods.mask |= tmp;
838818534a1Smrg            return True;
839818534a1Smrg        }
840818534a1Smrg        break;
841818534a1Smrg    case XkbSA_ISOLock:
842818534a1Smrg        if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
843818534a1Smrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
844818534a1Smrg            act->iso.mask = act->iso.real_mods;
845818534a1Smrg            act->iso.mask |= tmp;
846818534a1Smrg            return True;
847818534a1Smrg        }
848818534a1Smrg        break;
8491ab64890Smrg    }
8501ab64890Smrg    return False;
8511ab64890Smrg}
8521ab64890Smrg
8531ab64890Smrgvoid
854818534a1SmrgXkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
855818534a1Smrg                            XkbKeyTypePtr type,
856818534a1Smrg                            unsigned int changed,
857818534a1Smrg                            XkbChangesPtr changes)
8581ab64890Smrg{
859818534a1Smrg    register unsigned int i;
860818534a1Smrg    unsigned int mask;
861818534a1Smrg
862818534a1Smrg    XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
863818534a1Smrg    type->mods.mask = type->mods.real_mods | mask;
864818534a1Smrg    if ((type->map_count > 0) && (type->mods.vmods != 0)) {
865818534a1Smrg        XkbKTMapEntryPtr entry;
866818534a1Smrg
867818534a1Smrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
868818534a1Smrg            if (entry->mods.vmods != 0) {
869818534a1Smrg                XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
870818534a1Smrg                entry->mods.mask = entry->mods.real_mods | mask;
871818534a1Smrg                /* entry is active if vmods are bound */
872818534a1Smrg                entry->active = (mask != 0);
873818534a1Smrg            }
874818534a1Smrg            else
875818534a1Smrg                entry->active = 1;
876818534a1Smrg        }
8771ab64890Smrg    }
8781ab64890Smrg    if (changes) {
879818534a1Smrg        int type_ndx;
880818534a1Smrg
881818534a1Smrg        type_ndx = type - xkb->map->types;
882818534a1Smrg        if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
883818534a1Smrg            return;
884818534a1Smrg        if (changes->map.changed & XkbKeyTypesMask) {
885818534a1Smrg            int last;
886818534a1Smrg
887818534a1Smrg            last = changes->map.first_type + changes->map.num_types - 1;
888818534a1Smrg            if (type_ndx < changes->map.first_type) {
889818534a1Smrg                changes->map.first_type = type_ndx;
890818534a1Smrg                changes->map.num_types = (last - type_ndx) + 1;
891818534a1Smrg            }
892818534a1Smrg            else if (type_ndx > last) {
893818534a1Smrg                changes->map.num_types =
894818534a1Smrg                    (type_ndx - changes->map.first_type) + 1;
895818534a1Smrg            }
896818534a1Smrg        }
897818534a1Smrg        else {
898818534a1Smrg            changes->map.changed |= XkbKeyTypesMask;
899818534a1Smrg            changes->map.first_type = type_ndx;
900818534a1Smrg            changes->map.num_types = 1;
901818534a1Smrg        }
9021ab64890Smrg    }
9031ab64890Smrg    return;
9041ab64890Smrg}
9051ab64890Smrg
9061ab64890SmrgBool
907818534a1SmrgXkbApplyVirtualModChanges(XkbDescPtr xkb,
908818534a1Smrg                          unsigned changed,
909818534a1Smrg                          XkbChangesPtr changes)
9101ab64890Smrg{
911818534a1Smrg    register int i;
912818534a1Smrg    unsigned int checkState = 0;
913818534a1Smrg
914818534a1Smrg    if ((!xkb) || (!xkb->map) || (changed == 0))
915818534a1Smrg        return False;
916818534a1Smrg    for (i = 0; i < xkb->map->num_types; i++) {
917818534a1Smrg        if (xkb->map->types[i].mods.vmods & changed)
918818534a1Smrg            XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
919818534a1Smrg                                        changes);
920818534a1Smrg    }
921818534a1Smrg    if (changed & xkb->ctrls->internal.vmods) {
922818534a1Smrg        unsigned int newMask;
923818534a1Smrg
924818534a1Smrg        XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
925818534a1Smrg        newMask |= xkb->ctrls->internal.real_mods;
926818534a1Smrg        if (xkb->ctrls->internal.mask != newMask) {
927818534a1Smrg            xkb->ctrls->internal.mask = newMask;
928818534a1Smrg            if (changes) {
929818534a1Smrg                changes->ctrls.changed_ctrls |= XkbInternalModsMask;
930818534a1Smrg                checkState = True;
931818534a1Smrg            }
932818534a1Smrg        }
933818534a1Smrg    }
934818534a1Smrg    if (changed & xkb->ctrls->ignore_lock.vmods) {
935818534a1Smrg        unsigned int newMask;
936818534a1Smrg
937818534a1Smrg        XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
938818534a1Smrg        newMask |= xkb->ctrls->ignore_lock.real_mods;
939818534a1Smrg        if (xkb->ctrls->ignore_lock.mask != newMask) {
940818534a1Smrg            xkb->ctrls->ignore_lock.mask = newMask;
941818534a1Smrg            if (changes) {
942818534a1Smrg                changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
943818534a1Smrg                checkState = True;
944818534a1Smrg            }
945818534a1Smrg        }
946818534a1Smrg    }
947818534a1Smrg    if (xkb->indicators != NULL) {
948818534a1Smrg        XkbIndicatorMapPtr map;
949818534a1Smrg
950818534a1Smrg        map = &xkb->indicators->maps[0];
951818534a1Smrg        for (i = 0; i < XkbNumIndicators; i++, map++) {
952818534a1Smrg            if (map->mods.vmods & changed) {
953818534a1Smrg                unsigned int newMask;
954818534a1Smrg
955818534a1Smrg                XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
956818534a1Smrg                newMask |= map->mods.real_mods;
957818534a1Smrg                if (newMask != map->mods.mask) {
958818534a1Smrg                    map->mods.mask = newMask;
959818534a1Smrg                    if (changes) {
960818534a1Smrg                        changes->indicators.map_changes |= (1 << i);
961818534a1Smrg                        checkState = True;
962818534a1Smrg                    }
963818534a1Smrg                }
964818534a1Smrg            }
965818534a1Smrg        }
966818534a1Smrg    }
967818534a1Smrg    if (xkb->compat != NULL) {
968818534a1Smrg        XkbCompatMapPtr compat;
969818534a1Smrg
970818534a1Smrg        compat = xkb->compat;
971818534a1Smrg        for (i = 0; i < XkbNumKbdGroups; i++) {
972818534a1Smrg            unsigned int newMask;
973818534a1Smrg
974818534a1Smrg            XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
975818534a1Smrg            newMask |= compat->groups[i].real_mods;
976818534a1Smrg            if (compat->groups[i].mask != newMask) {
977818534a1Smrg                compat->groups[i].mask = newMask;
978818534a1Smrg                if (changes) {
979818534a1Smrg                    changes->compat.changed_groups |= (1 << i);
980818534a1Smrg                    checkState = True;
981818534a1Smrg                }
982818534a1Smrg            }
983818534a1Smrg        }
9841ab64890Smrg    }
9851ab64890Smrg    if (xkb->map && xkb->server) {
986818534a1Smrg        int highChange = 0, lowChange = -1;
987818534a1Smrg
988818534a1Smrg        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
989818534a1Smrg            if (XkbKeyHasActions(xkb, i)) {
990818534a1Smrg                register XkbAction *pAct;
991818534a1Smrg                register int n;
992818534a1Smrg
993818534a1Smrg                pAct = XkbKeyActionsPtr(xkb, i);
994818534a1Smrg                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
995818534a1Smrg                    if ((pAct->type != XkbSA_NoAction) &&
996818534a1Smrg                        XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
997818534a1Smrg                        if (lowChange < 0)
998818534a1Smrg                            lowChange = i;
999818534a1Smrg                        highChange = i;
1000818534a1Smrg                    }
1001818534a1Smrg                }
1002818534a1Smrg            }
1003818534a1Smrg        }
1004818534a1Smrg        if (changes && (lowChange > 0)) {       /* something changed */
1005818534a1Smrg            if (changes->map.changed & XkbKeyActionsMask) {
1006818534a1Smrg                int last;
1007818534a1Smrg
1008818534a1Smrg                if (changes->map.first_key_act < lowChange)
1009818534a1Smrg                    lowChange = changes->map.first_key_act;
1010818534a1Smrg                last =
1011818534a1Smrg                    changes->map.first_key_act + changes->map.num_key_acts - 1;
1012818534a1Smrg                if (last > highChange)
1013818534a1Smrg                    highChange = last;
1014818534a1Smrg            }
1015818534a1Smrg            changes->map.changed |= XkbKeyActionsMask;
1016818534a1Smrg            changes->map.first_key_act = lowChange;
1017818534a1Smrg            changes->map.num_key_acts = (highChange - lowChange) + 1;
1018818534a1Smrg        }
10191ab64890Smrg    }
10201ab64890Smrg    return checkState;
10211ab64890Smrg}
1022