105b261ecSmrg/************************************************************
205b261ecSmrgCopyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
305b261ecSmrg
405b261ecSmrgPermission to use, copy, modify, and distribute this
505b261ecSmrgsoftware and its documentation for any purpose and without
605b261ecSmrgfee is hereby granted, provided that the above copyright
705b261ecSmrgnotice appear in all copies and that both that copyright
805b261ecSmrgnotice and this permission notice appear in supporting
935c4bbdfSmrgdocumentation, and that the name of Silicon Graphics not be
1035c4bbdfSmrgused in advertising or publicity pertaining to distribution
1105b261ecSmrgof the software without specific prior written permission.
1235c4bbdfSmrgSilicon Graphics makes no representation about the suitability
1305b261ecSmrgof this software for any purpose. It is provided "as is"
1405b261ecSmrgwithout any express or implied warranty.
1505b261ecSmrg
1635c4bbdfSmrgSILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
1735c4bbdfSmrgSOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1805b261ecSmrgAND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
1935c4bbdfSmrgGRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
2035c4bbdfSmrgDAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
2135c4bbdfSmrgDATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
2205b261ecSmrgOR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
2305b261ecSmrgTHE USE OR PERFORMANCE OF THIS SOFTWARE.
2405b261ecSmrg
2505b261ecSmrg********************************************************/
2605b261ecSmrg
2705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2805b261ecSmrg#include <dix-config.h>
2905b261ecSmrg#endif
3005b261ecSmrg
3105b261ecSmrg#include <stdio.h>
3205b261ecSmrg#include <X11/X.h>
3305b261ecSmrg#include <X11/Xproto.h>
3405b261ecSmrg#include "misc.h"
3505b261ecSmrg#include "inputstr.h"
3605b261ecSmrg#include <X11/keysym.h>
3705b261ecSmrg#define	XKBSRV_NEED_FILE_FUNCS
3805b261ecSmrg#include <xkbsrv.h>
3905b261ecSmrg
4005b261ecSmrg/***====================================================================***/
4105b261ecSmrg
4205b261ecSmrg#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
4305b261ecSmrg#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
4405b261ecSmrg
4505b261ecSmrgint
4635c4bbdfSmrgXkbKeyTypesForCoreSymbols(XkbDescPtr xkb,
4735c4bbdfSmrg                          int map_width,
4835c4bbdfSmrg                          KeySym * core_syms,
4935c4bbdfSmrg                          unsigned int protected,
5035c4bbdfSmrg                          int *types_inout, KeySym * xkb_syms_rtrn)
5105b261ecSmrg{
5235c4bbdfSmrg    register int i;
5335c4bbdfSmrg    unsigned int empty;
5435c4bbdfSmrg    int nSyms[XkbNumKbdGroups];
5535c4bbdfSmrg    int nGroups, tmp, groupsWidth;
5635c4bbdfSmrg    BOOL replicated = FALSE;
5705b261ecSmrg
5805b261ecSmrg    /* Section 12.2 of the protocol describes this process in more detail */
5905b261ecSmrg    /* Step 1:  find the # of symbols in the core mapping per group */
6035c4bbdfSmrg    groupsWidth = 2;
6135c4bbdfSmrg    for (i = 0; i < XkbNumKbdGroups; i++) {
6235c4bbdfSmrg        if ((protected & (1 << i)) && (types_inout[i] < xkb->map->num_types)) {
6335c4bbdfSmrg            nSyms[i] = xkb->map->types[types_inout[i]].num_levels;
6435c4bbdfSmrg            if (nSyms[i] > groupsWidth)
6535c4bbdfSmrg                groupsWidth = nSyms[i];
6635c4bbdfSmrg        }
6735c4bbdfSmrg        else {
6835c4bbdfSmrg            types_inout[i] = XkbTwoLevelIndex;  /* don't really know, yet */
6935c4bbdfSmrg            nSyms[i] = 2;
7035c4bbdfSmrg        }
7135c4bbdfSmrg    }
7235c4bbdfSmrg    if (nSyms[XkbGroup1Index] < 2)
7335c4bbdfSmrg        nSyms[XkbGroup1Index] = 2;
7435c4bbdfSmrg    if (nSyms[XkbGroup2Index] < 2)
7535c4bbdfSmrg        nSyms[XkbGroup2Index] = 2;
7635c4bbdfSmrg    /* Step 2:  Copy the symbols from the core ordering to XKB ordering */
7735c4bbdfSmrg    /*          symbols in the core are in the order:                   */
7835c4bbdfSmrg    /*          G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */
7935c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 0)] = CORE_SYM(0);
8035c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 1)] = CORE_SYM(1);
8135c4bbdfSmrg    for (i = 2; i < nSyms[XkbGroup1Index]; i++) {
8235c4bbdfSmrg        xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, i)] = CORE_SYM(2 + i);
8335c4bbdfSmrg    }
8435c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 0)] = CORE_SYM(2);
8535c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 1)] = CORE_SYM(3);
8635c4bbdfSmrg    tmp = 2 + (nSyms[XkbGroup1Index] - 2);      /* offset to extra group2 syms */
8735c4bbdfSmrg    for (i = 2; i < nSyms[XkbGroup2Index]; i++) {
8835c4bbdfSmrg        xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, i)] = CORE_SYM(tmp + i);
8905b261ecSmrg    }
906747b715Smrg
916747b715Smrg    /* Special case: if only the first group is explicit, and the symbols
926747b715Smrg     * replicate across all groups, then we have a Section 12.4 replication */
9335c4bbdfSmrg    if ((protected & ~XkbExplicitKeyType1Mask) == 0) {
946747b715Smrg        int j, width = nSyms[XkbGroup1Index];
956747b715Smrg
966747b715Smrg        replicated = TRUE;
976747b715Smrg
986747b715Smrg        /* Check ABAB in ABABCDECDEABCDE */
996747b715Smrg        if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) ||
1006747b715Smrg            (width > 1 && CORE_SYM(1) != CORE_SYM(3)))
1016747b715Smrg            replicated = FALSE;
1026747b715Smrg
1036747b715Smrg        /* Check CDECDE in ABABCDECDEABCDE */
10435c4bbdfSmrg        for (i = 2; i < width && replicated; i++) {
1056747b715Smrg            if (CORE_SYM(2 + i) != CORE_SYM(i + width))
1066747b715Smrg                replicated = FALSE;
1076747b715Smrg        }
1086747b715Smrg
1096747b715Smrg        /* Check ABCDE in ABABCDECDEABCDE */
1106747b715Smrg        for (j = 2; replicated &&
11135c4bbdfSmrg             j < XkbNumKbdGroups && map_width >= width * (j + 1); j++) {
11235c4bbdfSmrg            for (i = 0; i < width && replicated; i++) {
1136747b715Smrg                if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j))
1146747b715Smrg                    replicated = FALSE;
1156747b715Smrg            }
1166747b715Smrg        }
1176747b715Smrg    }
1186747b715Smrg
11935c4bbdfSmrg    if (replicated) {
12035c4bbdfSmrg        nSyms[XkbGroup2Index] = 0;
12135c4bbdfSmrg        nSyms[XkbGroup3Index] = 0;
12235c4bbdfSmrg        nSyms[XkbGroup4Index] = 0;
12335c4bbdfSmrg        nGroups = 1;
12435c4bbdfSmrg    }
12535c4bbdfSmrg    else {
12635c4bbdfSmrg        tmp = nSyms[XkbGroup1Index] + nSyms[XkbGroup2Index];
12735c4bbdfSmrg        if ((tmp >= map_width) &&
12835c4bbdfSmrg            ((protected & (XkbExplicitKeyType3Mask | XkbExplicitKeyType4Mask))
12935c4bbdfSmrg             == 0)) {
13035c4bbdfSmrg            nSyms[XkbGroup3Index] = 0;
13135c4bbdfSmrg            nSyms[XkbGroup4Index] = 0;
13235c4bbdfSmrg            nGroups = 2;
13335c4bbdfSmrg        }
13435c4bbdfSmrg        else {
13535c4bbdfSmrg            nGroups = 3;
13635c4bbdfSmrg            for (i = 0; i < nSyms[XkbGroup3Index]; i++, tmp++) {
13735c4bbdfSmrg                xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index, i)] = CORE_SYM(tmp);
1386747b715Smrg            }
13935c4bbdfSmrg            if ((tmp < map_width) || (protected & XkbExplicitKeyType4Mask)) {
14035c4bbdfSmrg                nGroups = 4;
14135c4bbdfSmrg                for (i = 0; i < nSyms[XkbGroup4Index]; i++, tmp++) {
14235c4bbdfSmrg                    xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index, i)] =
14335c4bbdfSmrg                        CORE_SYM(tmp);
1446747b715Smrg                }
1456747b715Smrg            }
1466747b715Smrg            else {
14735c4bbdfSmrg                nSyms[XkbGroup4Index] = 0;
1486747b715Smrg            }
1496747b715Smrg        }
15005b261ecSmrg    }
15105b261ecSmrg    /* steps 3&4: alphanumeric expansion,  assign canonical types */
15235c4bbdfSmrg    empty = 0;
15335c4bbdfSmrg    for (i = 0; i < nGroups; i++) {
15435c4bbdfSmrg        KeySym *syms;
15535c4bbdfSmrg
15635c4bbdfSmrg        syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
15735c4bbdfSmrg        if ((nSyms[i] > 1) && (syms[1] == NoSymbol) && (syms[0] != NoSymbol)) {
15835c4bbdfSmrg            KeySym upper, lower;
15935c4bbdfSmrg
16035c4bbdfSmrg            XkbConvertCase(syms[0], &lower, &upper);
16135c4bbdfSmrg            if (upper != lower) {
16235c4bbdfSmrg                xkb_syms_rtrn[XKB_OFFSET(i, 0)] = lower;
16335c4bbdfSmrg                xkb_syms_rtrn[XKB_OFFSET(i, 1)] = upper;
16435c4bbdfSmrg                if ((protected & (1 << i)) == 0)
16535c4bbdfSmrg                    types_inout[i] = XkbAlphabeticIndex;
16635c4bbdfSmrg            }
16735c4bbdfSmrg            else if ((protected & (1 << i)) == 0) {
16835c4bbdfSmrg                types_inout[i] = XkbOneLevelIndex;
16935c4bbdfSmrg                /*      nSyms[i]=       1; */
17035c4bbdfSmrg            }
17135c4bbdfSmrg        }
17235c4bbdfSmrg        if (((protected & (1 << i)) == 0) &&
17335c4bbdfSmrg            (types_inout[i] == XkbTwoLevelIndex)) {
17435c4bbdfSmrg            if (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1]))
17535c4bbdfSmrg                types_inout[i] = XkbKeypadIndex;
17635c4bbdfSmrg            else {
17735c4bbdfSmrg                KeySym upper, lower;
17835c4bbdfSmrg
17935c4bbdfSmrg                XkbConvertCase(syms[0], &lower, &upper);
18035c4bbdfSmrg                if ((syms[0] == lower) && (syms[1] == upper))
18135c4bbdfSmrg                    types_inout[i] = XkbAlphabeticIndex;
18235c4bbdfSmrg            }
18335c4bbdfSmrg        }
18435c4bbdfSmrg        if (syms[0] == NoSymbol) {
18535c4bbdfSmrg            register int n;
18635c4bbdfSmrg            Bool found;
18735c4bbdfSmrg
18835c4bbdfSmrg            for (n = 1, found = FALSE; (!found) && (n < nSyms[i]); n++) {
18935c4bbdfSmrg                found = (syms[n] != NoSymbol);
19035c4bbdfSmrg            }
19135c4bbdfSmrg            if (!found)
19235c4bbdfSmrg                empty |= (1 << i);
19335c4bbdfSmrg        }
19405b261ecSmrg    }
19505b261ecSmrg    /* step 5: squoosh out empty groups */
19605b261ecSmrg    if (empty) {
19735c4bbdfSmrg        for (i = nGroups - 1; i >= 0; i--) {
19835c4bbdfSmrg            if (((empty & (1 << i)) == 0) || (protected & (1 << i)))
19935c4bbdfSmrg                break;
20035c4bbdfSmrg            nGroups--;
20135c4bbdfSmrg        }
20205b261ecSmrg    }
20335c4bbdfSmrg    if (nGroups < 1)
20435c4bbdfSmrg        return 0;
20505b261ecSmrg
20605b261ecSmrg    /* step 6: replicate group 1 into group two, if necessary */
20735c4bbdfSmrg    if ((nGroups > 1) &&
20835c4bbdfSmrg        ((empty & (XkbGroup1Mask | XkbGroup2Mask)) == XkbGroup2Mask)) {
20935c4bbdfSmrg        if ((protected & (XkbExplicitKeyType1Mask | XkbExplicitKeyType2Mask)) ==
21035c4bbdfSmrg            0) {
21135c4bbdfSmrg            nSyms[XkbGroup2Index] = nSyms[XkbGroup1Index];
21235c4bbdfSmrg            types_inout[XkbGroup2Index] = types_inout[XkbGroup1Index];
21335c4bbdfSmrg            memcpy((char *) &xkb_syms_rtrn[2], (char *) xkb_syms_rtrn,
21435c4bbdfSmrg                   2 * sizeof(KeySym));
21535c4bbdfSmrg        }
21635c4bbdfSmrg        else if (types_inout[XkbGroup1Index] == types_inout[XkbGroup2Index]) {
21735c4bbdfSmrg            memcpy((char *) &xkb_syms_rtrn[nSyms[XkbGroup1Index]],
21835c4bbdfSmrg                   (char *) xkb_syms_rtrn,
21935c4bbdfSmrg                   nSyms[XkbGroup1Index] * sizeof(KeySym));
22035c4bbdfSmrg        }
22105b261ecSmrg    }
22205b261ecSmrg
2234642e01fSmrg    /* step 7: check for all groups identical or all width 1
2244642e01fSmrg     *
2254642e01fSmrg     * Special feature: if group 1 has an explicit type and all other groups
2264642e01fSmrg     * have canonical types with same symbols, we assume it's info lost from
2274642e01fSmrg     * the core replication.
2284642e01fSmrg     */
22935c4bbdfSmrg    if (nGroups > 1) {
23035c4bbdfSmrg        Bool sameType, allOneLevel, canonical = TRUE;
23135c4bbdfSmrg
23235c4bbdfSmrg        allOneLevel = (xkb->map->types[types_inout[0]].num_levels == 1);
23335c4bbdfSmrg        for (i = 1, sameType = TRUE; (allOneLevel || sameType) && (i < nGroups);
23435c4bbdfSmrg             i++) {
23535c4bbdfSmrg            sameType = (sameType &&
23635c4bbdfSmrg                        (types_inout[i] == types_inout[XkbGroup1Index]));
23735c4bbdfSmrg            if (allOneLevel)
23835c4bbdfSmrg                allOneLevel = (xkb->map->types[types_inout[i]].num_levels == 1);
23935c4bbdfSmrg            if (types_inout[i] > XkbLastRequiredType)
24035c4bbdfSmrg                canonical = FALSE;
24135c4bbdfSmrg        }
24235c4bbdfSmrg        if (((sameType) || canonical) &&
24335c4bbdfSmrg            (!(protected &
24435c4bbdfSmrg               (XkbExplicitKeyTypesMask & ~XkbExplicitKeyType1Mask)))) {
24535c4bbdfSmrg            register int s;
24635c4bbdfSmrg            Bool identical;
24735c4bbdfSmrg
24835c4bbdfSmrg            for (i = 1, identical = TRUE; identical && (i < nGroups); i++) {
24935c4bbdfSmrg                KeySym *syms;
25035c4bbdfSmrg
2516747b715Smrg                if (nSyms[i] != nSyms[XkbGroup1Index])
2526747b715Smrg                    identical = FALSE;
25335c4bbdfSmrg                syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
25435c4bbdfSmrg                for (s = 0; identical && (s < nSyms[i]); s++) {
25535c4bbdfSmrg                    if (syms[s] != xkb_syms_rtrn[s])
25635c4bbdfSmrg                        identical = FALSE;
25735c4bbdfSmrg                }
25835c4bbdfSmrg            }
25935c4bbdfSmrg            if (identical)
26035c4bbdfSmrg                nGroups = 1;
26135c4bbdfSmrg        }
26235c4bbdfSmrg        if (allOneLevel && (nGroups > 1)) {
26335c4bbdfSmrg            KeySym *syms;
26435c4bbdfSmrg
26535c4bbdfSmrg            syms = &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
26635c4bbdfSmrg            nSyms[XkbGroup1Index] = 1;
26735c4bbdfSmrg            for (i = 1; i < nGroups; i++) {
26835c4bbdfSmrg                xkb_syms_rtrn[i] = syms[0];
26935c4bbdfSmrg                syms += nSyms[i];
27035c4bbdfSmrg                nSyms[i] = 1;
27135c4bbdfSmrg            }
27235c4bbdfSmrg        }
27305b261ecSmrg    }
27405b261ecSmrg    return nGroups;
27505b261ecSmrg}
27605b261ecSmrg
27705b261ecSmrgstatic XkbSymInterpretPtr
27835c4bbdfSmrg_XkbFindMatchingInterp(XkbDescPtr xkb,
27935c4bbdfSmrg                       KeySym sym, unsigned int real_mods, unsigned int level)
28005b261ecSmrg{
28135c4bbdfSmrg    register unsigned i;
28235c4bbdfSmrg    XkbSymInterpretPtr interp, rtrn;
28335c4bbdfSmrg    CARD8 mods;
28435c4bbdfSmrg
28535c4bbdfSmrg    rtrn = NULL;
28635c4bbdfSmrg    interp = xkb->compat->sym_interpret;
28735c4bbdfSmrg    for (i = 0; i < xkb->compat->num_si; i++, interp++) {
28835c4bbdfSmrg        if ((interp->sym == NoSymbol) || (sym == interp->sym)) {
28935c4bbdfSmrg            int match;
29035c4bbdfSmrg
29135c4bbdfSmrg            if ((level == 0) || ((interp->match & XkbSI_LevelOneOnly) == 0))
29235c4bbdfSmrg                mods = real_mods;
29335c4bbdfSmrg            else
29435c4bbdfSmrg                mods = 0;
29535c4bbdfSmrg            switch (interp->match & XkbSI_OpMask) {
29635c4bbdfSmrg            case XkbSI_NoneOf:
29735c4bbdfSmrg                match = ((interp->mods & mods) == 0);
29835c4bbdfSmrg                break;
29935c4bbdfSmrg            case XkbSI_AnyOfOrNone:
30035c4bbdfSmrg                match = ((mods == 0) || ((interp->mods & mods) != 0));
30135c4bbdfSmrg                break;
30235c4bbdfSmrg            case XkbSI_AnyOf:
30335c4bbdfSmrg                match = ((interp->mods & mods) != 0);
30435c4bbdfSmrg                break;
30535c4bbdfSmrg            case XkbSI_AllOf:
30635c4bbdfSmrg                match = ((interp->mods & mods) == interp->mods);
30735c4bbdfSmrg                break;
30835c4bbdfSmrg            case XkbSI_Exactly:
30935c4bbdfSmrg                match = (interp->mods == mods);
31035c4bbdfSmrg                break;
31135c4bbdfSmrg            default:
31235c4bbdfSmrg                match = 0;
31335c4bbdfSmrg                break;
31435c4bbdfSmrg            }
31535c4bbdfSmrg            if (match) {
31635c4bbdfSmrg                if (interp->sym != NoSymbol) {
31735c4bbdfSmrg                    return interp;
31835c4bbdfSmrg                }
31935c4bbdfSmrg                else if (rtrn == NULL) {
32035c4bbdfSmrg                    rtrn = interp;
32135c4bbdfSmrg                }
32235c4bbdfSmrg            }
32335c4bbdfSmrg        }
32405b261ecSmrg    }
32505b261ecSmrg    return rtrn;
32605b261ecSmrg}
32705b261ecSmrg
32805b261ecSmrgstatic void
32935c4bbdfSmrg_XkbAddKeyChange(KeyCode *pFirst, unsigned char *pNum, KeyCode newKey)
33005b261ecSmrg{
33135c4bbdfSmrg    KeyCode last;
33205b261ecSmrg
33335c4bbdfSmrg    last = (*pFirst) + (*pNum);
33435c4bbdfSmrg    if (newKey < *pFirst) {
33535c4bbdfSmrg        *pFirst = newKey;
33635c4bbdfSmrg        *pNum = (last - newKey) + 1;
33705b261ecSmrg    }
33835c4bbdfSmrg    else if (newKey > last) {
33935c4bbdfSmrg        *pNum = (last - *pFirst) + 1;
34005b261ecSmrg    }
34105b261ecSmrg    return;
34205b261ecSmrg}
34305b261ecSmrg
34405b261ecSmrgstatic void
34535c4bbdfSmrg_XkbSetActionKeyMods(XkbDescPtr xkb, XkbAction *act, unsigned mods)
34605b261ecSmrg{
34735c4bbdfSmrg    unsigned tmp;
34805b261ecSmrg
34905b261ecSmrg    switch (act->type) {
35035c4bbdfSmrg    case XkbSA_SetMods:
35135c4bbdfSmrg    case XkbSA_LatchMods:
35235c4bbdfSmrg    case XkbSA_LockMods:
35335c4bbdfSmrg        if (act->mods.flags & XkbSA_UseModMapMods)
35435c4bbdfSmrg            act->mods.real_mods = act->mods.mask = mods;
35535c4bbdfSmrg        if ((tmp = XkbModActionVMods(&act->mods)) != 0) {
35635c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
35735c4bbdfSmrg            act->mods.mask |= tmp;
35835c4bbdfSmrg        }
35935c4bbdfSmrg        break;
36035c4bbdfSmrg    case XkbSA_ISOLock:
36135c4bbdfSmrg        if (act->iso.flags & XkbSA_UseModMapMods)
36235c4bbdfSmrg            act->iso.real_mods = act->iso.mask = mods;
36335c4bbdfSmrg        if ((tmp = XkbModActionVMods(&act->iso)) != 0) {
36435c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
36535c4bbdfSmrg            act->iso.mask |= tmp;
36635c4bbdfSmrg        }
36735c4bbdfSmrg        break;
36805b261ecSmrg    }
36905b261ecSmrg    return;
37005b261ecSmrg}
37105b261ecSmrg
37205b261ecSmrg#define	IBUF_SIZE	8
37305b261ecSmrg
37405b261ecSmrgBool
37535c4bbdfSmrgXkbApplyCompatMapToKey(XkbDescPtr xkb, KeyCode key, XkbChangesPtr changes)
37605b261ecSmrg{
37735c4bbdfSmrg    KeySym *syms;
37835c4bbdfSmrg    unsigned char explicit, mods;
37935c4bbdfSmrg    XkbSymInterpretPtr *interps, ibuf[IBUF_SIZE];
38035c4bbdfSmrg    int n, nSyms, found;
38135c4bbdfSmrg    unsigned changed, tmp;
38235c4bbdfSmrg
38335c4bbdfSmrg    if ((!xkb) || (!xkb->map) || (!xkb->map->key_sym_map) ||
38435c4bbdfSmrg        (!xkb->compat) || (!xkb->compat->sym_interpret) ||
38535c4bbdfSmrg        (key < xkb->min_key_code) || (key > xkb->max_key_code)) {
38635c4bbdfSmrg        return FALSE;
38735c4bbdfSmrg    }
38835c4bbdfSmrg    if (((!xkb->server) || (!xkb->server->key_acts)) &&
38935c4bbdfSmrg        (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 0) != Success)) {
39035c4bbdfSmrg        return FALSE;
39135c4bbdfSmrg    }
39235c4bbdfSmrg    changed = 0;                /* keeps track of what has changed in _this_ call */
39335c4bbdfSmrg    explicit = xkb->server->explicit[key];
39435c4bbdfSmrg    if (explicit & XkbExplicitInterpretMask)    /* nothing to do */
39535c4bbdfSmrg        return TRUE;
39635c4bbdfSmrg    mods = (xkb->map->modmap ? xkb->map->modmap[key] : 0);
39735c4bbdfSmrg    nSyms = XkbKeyNumSyms(xkb, key);
39835c4bbdfSmrg    syms = XkbKeySymsPtr(xkb, key);
39935c4bbdfSmrg    if (nSyms > IBUF_SIZE) {
40035c4bbdfSmrg        interps = calloc(nSyms, sizeof(XkbSymInterpretPtr));
40135c4bbdfSmrg        if (interps == NULL) {
40235c4bbdfSmrg            interps = ibuf;
40335c4bbdfSmrg            nSyms = IBUF_SIZE;
40435c4bbdfSmrg        }
40505b261ecSmrg    }
40605b261ecSmrg    else {
40735c4bbdfSmrg        interps = ibuf;
40835c4bbdfSmrg    }
40935c4bbdfSmrg    found = 0;
41035c4bbdfSmrg    for (n = 0; n < nSyms; n++) {
41135c4bbdfSmrg        unsigned level = (n % XkbKeyGroupsWidth(xkb, key));
41235c4bbdfSmrg
41335c4bbdfSmrg        interps[n] = NULL;
41435c4bbdfSmrg        if (syms[n] != NoSymbol) {
41535c4bbdfSmrg            interps[n] = _XkbFindMatchingInterp(xkb, syms[n], mods, level);
41635c4bbdfSmrg            if (interps[n] && interps[n]->act.type != XkbSA_NoAction)
41735c4bbdfSmrg                found++;
41835c4bbdfSmrg            else
41935c4bbdfSmrg                interps[n] = NULL;
42035c4bbdfSmrg        }
42105b261ecSmrg    }
42205b261ecSmrg    /* 1/28/96 (ef) -- XXX! WORKING HERE */
42305b261ecSmrg    if (!found) {
42435c4bbdfSmrg        if (xkb->server->key_acts[key] != 0) {
42535c4bbdfSmrg            xkb->server->key_acts[key] = 0;
42635c4bbdfSmrg            changed |= XkbKeyActionsMask;
42735c4bbdfSmrg        }
42805b261ecSmrg    }
42905b261ecSmrg    else {
43035c4bbdfSmrg        XkbAction *pActs;
43135c4bbdfSmrg        unsigned int new_vmodmask;
43235c4bbdfSmrg
43335c4bbdfSmrg        changed |= XkbKeyActionsMask;
43435c4bbdfSmrg        pActs = XkbResizeKeyActions(xkb, key, nSyms);
43535c4bbdfSmrg        if (!pActs) {
43605b261ecSmrg            if (nSyms > IBUF_SIZE)
4376747b715Smrg                free(interps);
43835c4bbdfSmrg            return FALSE;
43935c4bbdfSmrg        }
44035c4bbdfSmrg        new_vmodmask = 0;
44135c4bbdfSmrg        for (n = 0; n < nSyms; n++) {
44235c4bbdfSmrg            if (interps[n]) {
44335c4bbdfSmrg                unsigned effMods;
44435c4bbdfSmrg
44535c4bbdfSmrg                pActs[n] = *((XkbAction *) &interps[n]->act);
44635c4bbdfSmrg                if ((n == 0) || ((interps[n]->match & XkbSI_LevelOneOnly) == 0)) {
44735c4bbdfSmrg                    effMods = mods;
44835c4bbdfSmrg                    if (interps[n]->virtual_mod != XkbNoModifier)
44935c4bbdfSmrg                        new_vmodmask |= (1 << interps[n]->virtual_mod);
45035c4bbdfSmrg                }
45135c4bbdfSmrg                else
45235c4bbdfSmrg                    effMods = 0;
45335c4bbdfSmrg                _XkbSetActionKeyMods(xkb, &pActs[n], effMods);
45435c4bbdfSmrg            }
45535c4bbdfSmrg            else
45635c4bbdfSmrg                pActs[n].type = XkbSA_NoAction;
45735c4bbdfSmrg        }
45835c4bbdfSmrg        if (((explicit & XkbExplicitVModMapMask) == 0) &&
45935c4bbdfSmrg            (xkb->server->vmodmap[key] != new_vmodmask)) {
46035c4bbdfSmrg            changed |= XkbVirtualModMapMask;
46135c4bbdfSmrg            xkb->server->vmodmap[key] = new_vmodmask;
46235c4bbdfSmrg        }
46335c4bbdfSmrg        if (interps[0]) {
46435c4bbdfSmrg            if ((interps[0]->flags & XkbSI_LockingKey) &&
46535c4bbdfSmrg                ((explicit & XkbExplicitBehaviorMask) == 0)) {
46635c4bbdfSmrg                xkb->server->behaviors[key].type = XkbKB_Lock;
46735c4bbdfSmrg                changed |= XkbKeyBehaviorsMask;
46835c4bbdfSmrg            }
46935c4bbdfSmrg            if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
47035c4bbdfSmrg                CARD8 old;
47135c4bbdfSmrg
47235c4bbdfSmrg                old = BitIsOn(xkb->ctrls->per_key_repeat, key);
47335c4bbdfSmrg                if (interps[0]->flags & XkbSI_AutoRepeat)
47435c4bbdfSmrg                    SetBit(xkb->ctrls->per_key_repeat, key);
47535c4bbdfSmrg                else
47635c4bbdfSmrg                    ClearBit(xkb->ctrls->per_key_repeat, key);
47735c4bbdfSmrg                if (changes && old != BitIsOn(xkb->ctrls->per_key_repeat, key))
47835c4bbdfSmrg                    changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
47935c4bbdfSmrg            }
48035c4bbdfSmrg        }
48135c4bbdfSmrg    }
48235c4bbdfSmrg    if ((!found) || (interps[0] == NULL)) {
48335c4bbdfSmrg        if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
48435c4bbdfSmrg            CARD8 old;
48535c4bbdfSmrg
48635c4bbdfSmrg            old = BitIsOn(xkb->ctrls->per_key_repeat, key);
48735c4bbdfSmrg            SetBit(xkb->ctrls->per_key_repeat, key);
48835c4bbdfSmrg            if (changes && (old != BitIsOn(xkb->ctrls->per_key_repeat, key)))
48935c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
49035c4bbdfSmrg        }
49135c4bbdfSmrg        if (((explicit & XkbExplicitBehaviorMask) == 0) &&
49235c4bbdfSmrg            (xkb->server->behaviors[key].type == XkbKB_Lock)) {
49335c4bbdfSmrg            xkb->server->behaviors[key].type = XkbKB_Default;
49435c4bbdfSmrg            changed |= XkbKeyBehaviorsMask;
49535c4bbdfSmrg        }
49605b261ecSmrg    }
49705b261ecSmrg    if (changes) {
49835c4bbdfSmrg        XkbMapChangesPtr mc;
49935c4bbdfSmrg
50035c4bbdfSmrg        mc = &changes->map;
50135c4bbdfSmrg        tmp = (changed & mc->changed);
50235c4bbdfSmrg        if (tmp & XkbKeyActionsMask)
50335c4bbdfSmrg            _XkbAddKeyChange(&mc->first_key_act, &mc->num_key_acts, key);
50435c4bbdfSmrg        else if (changed & XkbKeyActionsMask) {
50535c4bbdfSmrg            mc->changed |= XkbKeyActionsMask;
50635c4bbdfSmrg            mc->first_key_act = key;
50735c4bbdfSmrg            mc->num_key_acts = 1;
50835c4bbdfSmrg        }
50935c4bbdfSmrg        if (tmp & XkbKeyBehaviorsMask) {
51035c4bbdfSmrg            _XkbAddKeyChange(&mc->first_key_behavior, &mc->num_key_behaviors,
51135c4bbdfSmrg                             key);
51235c4bbdfSmrg        }
51335c4bbdfSmrg        else if (changed & XkbKeyBehaviorsMask) {
51435c4bbdfSmrg            mc->changed |= XkbKeyBehaviorsMask;
51535c4bbdfSmrg            mc->first_key_behavior = key;
51635c4bbdfSmrg            mc->num_key_behaviors = 1;
51735c4bbdfSmrg        }
51835c4bbdfSmrg        if (tmp & XkbVirtualModMapMask)
51935c4bbdfSmrg            _XkbAddKeyChange(&mc->first_vmodmap_key, &mc->num_vmodmap_keys,
52035c4bbdfSmrg                             key);
52135c4bbdfSmrg        else if (changed & XkbVirtualModMapMask) {
52235c4bbdfSmrg            mc->changed |= XkbVirtualModMapMask;
52335c4bbdfSmrg            mc->first_vmodmap_key = key;
52435c4bbdfSmrg            mc->num_vmodmap_keys = 1;
52535c4bbdfSmrg        }
52635c4bbdfSmrg        mc->changed |= changed;
52735c4bbdfSmrg    }
52835c4bbdfSmrg    if (interps != ibuf)
52935c4bbdfSmrg        free(interps);
5306747b715Smrg    return TRUE;
53105b261ecSmrg}
53205b261ecSmrg
53305b261ecSmrgStatus
53435c4bbdfSmrgXkbChangeTypesOfKey(XkbDescPtr xkb,
53535c4bbdfSmrg                    int key,
53635c4bbdfSmrg                    int nGroups,
53735c4bbdfSmrg                    unsigned groups, int *newTypesIn, XkbMapChangesPtr changes)
53805b261ecSmrg{
53935c4bbdfSmrg    XkbKeyTypePtr pOldType, pNewType;
54035c4bbdfSmrg    register int i;
54135c4bbdfSmrg    int width, nOldGroups, oldWidth, newTypes[XkbNumKbdGroups];
54235c4bbdfSmrg
54335c4bbdfSmrg    if ((!xkb) || (!XkbKeycodeInRange(xkb, key)) || (!xkb->map) ||
54435c4bbdfSmrg        (!xkb->map->types) || (!newTypesIn) ||
54535c4bbdfSmrg        ((groups & XkbAllGroupsMask) == 0) || (nGroups > XkbNumKbdGroups)) {
54635c4bbdfSmrg        return BadMatch;
54735c4bbdfSmrg    }
54835c4bbdfSmrg    if (nGroups == 0) {
54935c4bbdfSmrg        for (i = 0; i < XkbNumKbdGroups; i++) {
55035c4bbdfSmrg            xkb->map->key_sym_map[key].kt_index[i] = XkbOneLevelIndex;
55135c4bbdfSmrg        }
55235c4bbdfSmrg        i = xkb->map->key_sym_map[key].group_info;
55335c4bbdfSmrg        i = XkbSetNumGroups(i, 0);
55435c4bbdfSmrg        xkb->map->key_sym_map[key].group_info = i;
55535c4bbdfSmrg        XkbResizeKeySyms(xkb, key, 0);
556f2346221Smrg        XkbResizeKeyActions(xkb, key, 0);
55735c4bbdfSmrg        return Success;
55835c4bbdfSmrg    }
55935c4bbdfSmrg
56035c4bbdfSmrg    nOldGroups = XkbKeyNumGroups(xkb, key);
56135c4bbdfSmrg    oldWidth = XkbKeyGroupsWidth(xkb, key);
56235c4bbdfSmrg    for (width = i = 0; i < nGroups; i++) {
56335c4bbdfSmrg        if (groups & (1 << i))
56435c4bbdfSmrg            newTypes[i] = newTypesIn[i];
56535c4bbdfSmrg        else if (i < nOldGroups)
56635c4bbdfSmrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
56735c4bbdfSmrg        else if (nOldGroups > 0)
56835c4bbdfSmrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
56935c4bbdfSmrg        else
57035c4bbdfSmrg            newTypes[i] = XkbTwoLevelIndex;
57135c4bbdfSmrg        if (newTypes[i] > xkb->map->num_types)
57235c4bbdfSmrg            return BadMatch;
57335c4bbdfSmrg        pNewType = &xkb->map->types[newTypes[i]];
57435c4bbdfSmrg        if (pNewType->num_levels > width)
57535c4bbdfSmrg            width = pNewType->num_levels;
57635c4bbdfSmrg    }
57735c4bbdfSmrg    if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
57835c4bbdfSmrg        xkb->ctrls->num_groups = nGroups;
57935c4bbdfSmrg    if ((width != oldWidth) || (nGroups != nOldGroups)) {
58035c4bbdfSmrg        KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
58135c4bbdfSmrg        int nCopy;
58235c4bbdfSmrg
58335c4bbdfSmrg        if (nOldGroups == 0) {
58435c4bbdfSmrg            pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
58535c4bbdfSmrg            if (pSyms != NULL) {
58635c4bbdfSmrg                i = xkb->map->key_sym_map[key].group_info;
58735c4bbdfSmrg                i = XkbSetNumGroups(i, nGroups);
58835c4bbdfSmrg                xkb->map->key_sym_map[key].group_info = i;
58935c4bbdfSmrg                xkb->map->key_sym_map[key].width = width;
59035c4bbdfSmrg                for (i = 0; i < nGroups; i++) {
59135c4bbdfSmrg                    xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
59235c4bbdfSmrg                }
59335c4bbdfSmrg                return Success;
59435c4bbdfSmrg            }
59535c4bbdfSmrg            return BadAlloc;
59635c4bbdfSmrg        }
59735c4bbdfSmrg        pSyms = XkbKeySymsPtr(xkb, key);
59835c4bbdfSmrg        memcpy(oldSyms, pSyms, XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
59935c4bbdfSmrg        pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
60035c4bbdfSmrg        if (pSyms == NULL)
60135c4bbdfSmrg            return BadAlloc;
60235c4bbdfSmrg        memset(pSyms, 0, width * nGroups * sizeof(KeySym));
60335c4bbdfSmrg        for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
60435c4bbdfSmrg            pOldType = XkbKeyKeyType(xkb, key, i);
60535c4bbdfSmrg            pNewType = &xkb->map->types[newTypes[i]];
60635c4bbdfSmrg            if (pNewType->num_levels > pOldType->num_levels)
60735c4bbdfSmrg                nCopy = pOldType->num_levels;
60835c4bbdfSmrg            else
60935c4bbdfSmrg                nCopy = pNewType->num_levels;
61035c4bbdfSmrg            memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
61135c4bbdfSmrg                   nCopy * sizeof(KeySym));
61235c4bbdfSmrg        }
61335c4bbdfSmrg        if (XkbKeyHasActions(xkb, key)) {
61435c4bbdfSmrg            XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
61535c4bbdfSmrg
61635c4bbdfSmrg            pActs = XkbKeyActionsPtr(xkb, key);
61735c4bbdfSmrg            memcpy(oldActs, pActs, XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
61835c4bbdfSmrg            pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
61935c4bbdfSmrg            if (pActs == NULL)
62035c4bbdfSmrg                return BadAlloc;
62135c4bbdfSmrg            memset(pActs, 0, width * nGroups * sizeof(XkbAction));
62235c4bbdfSmrg            for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
62335c4bbdfSmrg                pOldType = XkbKeyKeyType(xkb, key, i);
62435c4bbdfSmrg                pNewType = &xkb->map->types[newTypes[i]];
62535c4bbdfSmrg                if (pNewType->num_levels > pOldType->num_levels)
62635c4bbdfSmrg                    nCopy = pOldType->num_levels;
62735c4bbdfSmrg                else
62835c4bbdfSmrg                    nCopy = pNewType->num_levels;
62935c4bbdfSmrg                memcpy(&pActs[i * width], &oldActs[i * oldWidth],
63035c4bbdfSmrg                       nCopy * sizeof(XkbAction));
63135c4bbdfSmrg            }
63235c4bbdfSmrg        }
63335c4bbdfSmrg        i = xkb->map->key_sym_map[key].group_info;
63435c4bbdfSmrg        i = XkbSetNumGroups(i, nGroups);
63535c4bbdfSmrg        xkb->map->key_sym_map[key].group_info = i;
63635c4bbdfSmrg        xkb->map->key_sym_map[key].width = width;
63735c4bbdfSmrg    }
63835c4bbdfSmrg    width = 0;
63935c4bbdfSmrg    for (i = 0; i < nGroups; i++) {
64035c4bbdfSmrg        xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
64135c4bbdfSmrg        if (xkb->map->types[newTypes[i]].num_levels > width)
64235c4bbdfSmrg            width = xkb->map->types[newTypes[i]].num_levels;
64335c4bbdfSmrg    }
64435c4bbdfSmrg    xkb->map->key_sym_map[key].width = width;
64535c4bbdfSmrg    if (changes != NULL) {
64635c4bbdfSmrg        if (changes->changed & XkbKeySymsMask) {
64735c4bbdfSmrg            _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
64835c4bbdfSmrg                             key);
64935c4bbdfSmrg        }
65035c4bbdfSmrg        else {
65135c4bbdfSmrg            changes->changed |= XkbKeySymsMask;
65235c4bbdfSmrg            changes->first_key_sym = key;
65335c4bbdfSmrg            changes->num_key_syms = 1;
65435c4bbdfSmrg        }
65505b261ecSmrg    }
65605b261ecSmrg    return Success;
65705b261ecSmrg}
65805b261ecSmrg
65905b261ecSmrg/***====================================================================***/
66005b261ecSmrg
66105b261ecSmrgBool
66235c4bbdfSmrgXkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
66305b261ecSmrg{
66435c4bbdfSmrg    register int i, bit;
66535c4bbdfSmrg    register unsigned mask;
66635c4bbdfSmrg
667ed6184dfSmrg    if ((xkb == NULL) || (xkb->server == NULL)) {
668ed6184dfSmrg        *mask_rtrn = 0;
66935c4bbdfSmrg        return FALSE;
670ed6184dfSmrg    }
67135c4bbdfSmrg    if (virtual_mask == 0) {
67235c4bbdfSmrg        *mask_rtrn = 0;
67335c4bbdfSmrg        return TRUE;
67435c4bbdfSmrg    }
67535c4bbdfSmrg    for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
67635c4bbdfSmrg        if (virtual_mask & bit)
67735c4bbdfSmrg            mask |= xkb->server->vmods[i];
67835c4bbdfSmrg    }
67935c4bbdfSmrg    *mask_rtrn = mask;
6806747b715Smrg    return TRUE;
68105b261ecSmrg}
68205b261ecSmrg
68305b261ecSmrg/***====================================================================***/
68405b261ecSmrg
68505b261ecSmrgstatic Bool
68635c4bbdfSmrgXkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
68705b261ecSmrg{
68835c4bbdfSmrg    unsigned int tmp;
68905b261ecSmrg
69005b261ecSmrg    switch (act->type) {
69135c4bbdfSmrg    case XkbSA_SetMods:
69235c4bbdfSmrg    case XkbSA_LatchMods:
69335c4bbdfSmrg    case XkbSA_LockMods:
69435c4bbdfSmrg        if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
69535c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
69635c4bbdfSmrg            act->mods.mask = act->mods.real_mods;
69735c4bbdfSmrg            act->mods.mask |= tmp;
69835c4bbdfSmrg            return TRUE;
69935c4bbdfSmrg        }
70035c4bbdfSmrg        break;
70135c4bbdfSmrg    case XkbSA_ISOLock:
70235c4bbdfSmrg        if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
70335c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
70435c4bbdfSmrg            act->iso.mask = act->iso.real_mods;
70535c4bbdfSmrg            act->iso.mask |= tmp;
70635c4bbdfSmrg            return TRUE;
70735c4bbdfSmrg        }
70835c4bbdfSmrg        break;
70905b261ecSmrg    }
7106747b715Smrg    return FALSE;
71105b261ecSmrg}
71205b261ecSmrg
71305b261ecSmrgstatic void
71435c4bbdfSmrgXkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
71535c4bbdfSmrg                            XkbKeyTypePtr type,
71635c4bbdfSmrg                            unsigned int changed, XkbChangesPtr changes)
71705b261ecSmrg{
71835c4bbdfSmrg    register unsigned int i;
71935c4bbdfSmrg    unsigned int mask;
72035c4bbdfSmrg
72135c4bbdfSmrg    XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
72235c4bbdfSmrg    type->mods.mask = type->mods.real_mods | mask;
72335c4bbdfSmrg    if ((type->map_count > 0) && (type->mods.vmods != 0)) {
72435c4bbdfSmrg        XkbKTMapEntryPtr entry;
72535c4bbdfSmrg
72635c4bbdfSmrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
72735c4bbdfSmrg            if (entry->mods.vmods != 0) {
72835c4bbdfSmrg                XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
72935c4bbdfSmrg                entry->mods.mask = entry->mods.real_mods | mask;
73035c4bbdfSmrg                /* entry is active if vmods are bound */
73135c4bbdfSmrg                entry->active = (mask != 0);
73235c4bbdfSmrg            }
73335c4bbdfSmrg            else
73435c4bbdfSmrg                entry->active = 1;
73535c4bbdfSmrg        }
73605b261ecSmrg    }
73705b261ecSmrg    if (changes) {
73835c4bbdfSmrg        int type_ndx;
73935c4bbdfSmrg
74035c4bbdfSmrg        type_ndx = type - xkb->map->types;
74135c4bbdfSmrg        if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
74235c4bbdfSmrg            return;
74335c4bbdfSmrg        if (changes->map.changed & XkbKeyTypesMask) {
74435c4bbdfSmrg            int last;
74535c4bbdfSmrg
74635c4bbdfSmrg            last = changes->map.first_type + changes->map.num_types - 1;
74735c4bbdfSmrg            if (type_ndx < changes->map.first_type) {
74835c4bbdfSmrg                changes->map.first_type = type_ndx;
74935c4bbdfSmrg                changes->map.num_types = (last - type_ndx) + 1;
75035c4bbdfSmrg            }
75135c4bbdfSmrg            else if (type_ndx > last) {
75235c4bbdfSmrg                changes->map.num_types =
75335c4bbdfSmrg                    (type_ndx - changes->map.first_type) + 1;
75435c4bbdfSmrg            }
75535c4bbdfSmrg        }
75635c4bbdfSmrg        else {
75735c4bbdfSmrg            changes->map.changed |= XkbKeyTypesMask;
75835c4bbdfSmrg            changes->map.first_type = type_ndx;
75935c4bbdfSmrg            changes->map.num_types = 1;
76035c4bbdfSmrg        }
76105b261ecSmrg    }
76205b261ecSmrg    return;
76305b261ecSmrg}
76405b261ecSmrg
76505b261ecSmrgBool
76635c4bbdfSmrgXkbApplyVirtualModChanges(XkbDescPtr xkb, unsigned changed,
76735c4bbdfSmrg                          XkbChangesPtr changes)
76805b261ecSmrg{
76935c4bbdfSmrg    register int i;
77035c4bbdfSmrg    unsigned int checkState = 0;
77135c4bbdfSmrg
77235c4bbdfSmrg    if ((!xkb) || (!xkb->map) || (changed == 0))
77335c4bbdfSmrg        return FALSE;
77435c4bbdfSmrg    for (i = 0; i < xkb->map->num_types; i++) {
77535c4bbdfSmrg        if (xkb->map->types[i].mods.vmods & changed)
77635c4bbdfSmrg            XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
77735c4bbdfSmrg                                        changes);
77835c4bbdfSmrg    }
77935c4bbdfSmrg    if (changed & xkb->ctrls->internal.vmods) {
78035c4bbdfSmrg        unsigned int newMask;
78135c4bbdfSmrg
78235c4bbdfSmrg        XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
78335c4bbdfSmrg        newMask |= xkb->ctrls->internal.real_mods;
78435c4bbdfSmrg        if (xkb->ctrls->internal.mask != newMask) {
78535c4bbdfSmrg            xkb->ctrls->internal.mask = newMask;
78635c4bbdfSmrg            if (changes) {
78735c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbInternalModsMask;
78835c4bbdfSmrg                checkState = TRUE;
78935c4bbdfSmrg            }
79035c4bbdfSmrg        }
79135c4bbdfSmrg    }
79235c4bbdfSmrg    if (changed & xkb->ctrls->ignore_lock.vmods) {
79335c4bbdfSmrg        unsigned int newMask;
79435c4bbdfSmrg
79535c4bbdfSmrg        XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
79635c4bbdfSmrg        newMask |= xkb->ctrls->ignore_lock.real_mods;
79735c4bbdfSmrg        if (xkb->ctrls->ignore_lock.mask != newMask) {
79835c4bbdfSmrg            xkb->ctrls->ignore_lock.mask = newMask;
79935c4bbdfSmrg            if (changes) {
80035c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
80135c4bbdfSmrg                checkState = TRUE;
80235c4bbdfSmrg            }
80335c4bbdfSmrg        }
80435c4bbdfSmrg    }
80535c4bbdfSmrg    if (xkb->indicators != NULL) {
80635c4bbdfSmrg        XkbIndicatorMapPtr map;
80735c4bbdfSmrg
80835c4bbdfSmrg        map = &xkb->indicators->maps[0];
80935c4bbdfSmrg        for (i = 0; i < XkbNumIndicators; i++, map++) {
81035c4bbdfSmrg            if (map->mods.vmods & changed) {
81135c4bbdfSmrg                unsigned int newMask;
81235c4bbdfSmrg
81335c4bbdfSmrg                XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
81435c4bbdfSmrg                newMask |= map->mods.real_mods;
81535c4bbdfSmrg                if (newMask != map->mods.mask) {
81635c4bbdfSmrg                    map->mods.mask = newMask;
81735c4bbdfSmrg                    if (changes) {
81835c4bbdfSmrg                        changes->indicators.map_changes |= (1 << i);
81935c4bbdfSmrg                        checkState = TRUE;
82035c4bbdfSmrg                    }
82135c4bbdfSmrg                }
82235c4bbdfSmrg            }
82335c4bbdfSmrg        }
82435c4bbdfSmrg    }
82535c4bbdfSmrg    if (xkb->compat != NULL) {
82635c4bbdfSmrg        XkbCompatMapPtr compat;
82735c4bbdfSmrg
82835c4bbdfSmrg        compat = xkb->compat;
82935c4bbdfSmrg        for (i = 0; i < XkbNumKbdGroups; i++) {
83035c4bbdfSmrg            unsigned int newMask;
83135c4bbdfSmrg
83235c4bbdfSmrg            XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
83335c4bbdfSmrg            newMask |= compat->groups[i].real_mods;
83435c4bbdfSmrg            if (compat->groups[i].mask != newMask) {
83535c4bbdfSmrg                compat->groups[i].mask = newMask;
83635c4bbdfSmrg                if (changes) {
83735c4bbdfSmrg                    changes->compat.changed_groups |= (1 << i);
83835c4bbdfSmrg                    checkState = TRUE;
83935c4bbdfSmrg                }
84035c4bbdfSmrg            }
84135c4bbdfSmrg        }
84205b261ecSmrg    }
84305b261ecSmrg    if (xkb->map && xkb->server) {
84435c4bbdfSmrg        int highChange = 0, lowChange = -1;
84535c4bbdfSmrg
84635c4bbdfSmrg        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
84735c4bbdfSmrg            if (XkbKeyHasActions(xkb, i)) {
84835c4bbdfSmrg                register XkbAction *pAct;
84935c4bbdfSmrg                register int n;
85035c4bbdfSmrg
85135c4bbdfSmrg                pAct = XkbKeyActionsPtr(xkb, i);
85235c4bbdfSmrg                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
85335c4bbdfSmrg                    if ((pAct->type != XkbSA_NoAction) &&
85435c4bbdfSmrg                        XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
85535c4bbdfSmrg                        if (lowChange < 0)
85635c4bbdfSmrg                            lowChange = i;
85735c4bbdfSmrg                        highChange = i;
85835c4bbdfSmrg                    }
85935c4bbdfSmrg                }
86035c4bbdfSmrg            }
86135c4bbdfSmrg        }
86235c4bbdfSmrg        if (changes && (lowChange > 0)) {       /* something changed */
86335c4bbdfSmrg            if (changes->map.changed & XkbKeyActionsMask) {
86435c4bbdfSmrg                int last;
86535c4bbdfSmrg
86635c4bbdfSmrg                if (changes->map.first_key_act < lowChange)
86735c4bbdfSmrg                    lowChange = changes->map.first_key_act;
86835c4bbdfSmrg                last =
86935c4bbdfSmrg                    changes->map.first_key_act + changes->map.num_key_acts - 1;
87035c4bbdfSmrg                if (last > highChange)
87135c4bbdfSmrg                    highChange = last;
87235c4bbdfSmrg            }
87335c4bbdfSmrg            changes->map.changed |= XkbKeyActionsMask;
87435c4bbdfSmrg            changes->map.first_key_act = lowChange;
87535c4bbdfSmrg            changes->map.num_key_acts = (highChange - lowChange) + 1;
87635c4bbdfSmrg        }
87705b261ecSmrg    }
87805b261ecSmrg    return checkState;
87905b261ecSmrg}
880