XKBMisc.c revision ed6184df
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);
55635c4bbdfSmrg        return Success;
55735c4bbdfSmrg    }
55835c4bbdfSmrg
55935c4bbdfSmrg    nOldGroups = XkbKeyNumGroups(xkb, key);
56035c4bbdfSmrg    oldWidth = XkbKeyGroupsWidth(xkb, key);
56135c4bbdfSmrg    for (width = i = 0; i < nGroups; i++) {
56235c4bbdfSmrg        if (groups & (1 << i))
56335c4bbdfSmrg            newTypes[i] = newTypesIn[i];
56435c4bbdfSmrg        else if (i < nOldGroups)
56535c4bbdfSmrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
56635c4bbdfSmrg        else if (nOldGroups > 0)
56735c4bbdfSmrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
56835c4bbdfSmrg        else
56935c4bbdfSmrg            newTypes[i] = XkbTwoLevelIndex;
57035c4bbdfSmrg        if (newTypes[i] > xkb->map->num_types)
57135c4bbdfSmrg            return BadMatch;
57235c4bbdfSmrg        pNewType = &xkb->map->types[newTypes[i]];
57335c4bbdfSmrg        if (pNewType->num_levels > width)
57435c4bbdfSmrg            width = pNewType->num_levels;
57535c4bbdfSmrg    }
57635c4bbdfSmrg    if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
57735c4bbdfSmrg        xkb->ctrls->num_groups = nGroups;
57835c4bbdfSmrg    if ((width != oldWidth) || (nGroups != nOldGroups)) {
57935c4bbdfSmrg        KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
58035c4bbdfSmrg        int nCopy;
58135c4bbdfSmrg
58235c4bbdfSmrg        if (nOldGroups == 0) {
58335c4bbdfSmrg            pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
58435c4bbdfSmrg            if (pSyms != NULL) {
58535c4bbdfSmrg                i = xkb->map->key_sym_map[key].group_info;
58635c4bbdfSmrg                i = XkbSetNumGroups(i, nGroups);
58735c4bbdfSmrg                xkb->map->key_sym_map[key].group_info = i;
58835c4bbdfSmrg                xkb->map->key_sym_map[key].width = width;
58935c4bbdfSmrg                for (i = 0; i < nGroups; i++) {
59035c4bbdfSmrg                    xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
59135c4bbdfSmrg                }
59235c4bbdfSmrg                return Success;
59335c4bbdfSmrg            }
59435c4bbdfSmrg            return BadAlloc;
59535c4bbdfSmrg        }
59635c4bbdfSmrg        pSyms = XkbKeySymsPtr(xkb, key);
59735c4bbdfSmrg        memcpy(oldSyms, pSyms, XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
59835c4bbdfSmrg        pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
59935c4bbdfSmrg        if (pSyms == NULL)
60035c4bbdfSmrg            return BadAlloc;
60135c4bbdfSmrg        memset(pSyms, 0, width * nGroups * sizeof(KeySym));
60235c4bbdfSmrg        for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
60335c4bbdfSmrg            pOldType = XkbKeyKeyType(xkb, key, i);
60435c4bbdfSmrg            pNewType = &xkb->map->types[newTypes[i]];
60535c4bbdfSmrg            if (pNewType->num_levels > pOldType->num_levels)
60635c4bbdfSmrg                nCopy = pOldType->num_levels;
60735c4bbdfSmrg            else
60835c4bbdfSmrg                nCopy = pNewType->num_levels;
60935c4bbdfSmrg            memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
61035c4bbdfSmrg                   nCopy * sizeof(KeySym));
61135c4bbdfSmrg        }
61235c4bbdfSmrg        if (XkbKeyHasActions(xkb, key)) {
61335c4bbdfSmrg            XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
61435c4bbdfSmrg
61535c4bbdfSmrg            pActs = XkbKeyActionsPtr(xkb, key);
61635c4bbdfSmrg            memcpy(oldActs, pActs, XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
61735c4bbdfSmrg            pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
61835c4bbdfSmrg            if (pActs == NULL)
61935c4bbdfSmrg                return BadAlloc;
62035c4bbdfSmrg            memset(pActs, 0, width * nGroups * sizeof(XkbAction));
62135c4bbdfSmrg            for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
62235c4bbdfSmrg                pOldType = XkbKeyKeyType(xkb, key, i);
62335c4bbdfSmrg                pNewType = &xkb->map->types[newTypes[i]];
62435c4bbdfSmrg                if (pNewType->num_levels > pOldType->num_levels)
62535c4bbdfSmrg                    nCopy = pOldType->num_levels;
62635c4bbdfSmrg                else
62735c4bbdfSmrg                    nCopy = pNewType->num_levels;
62835c4bbdfSmrg                memcpy(&pActs[i * width], &oldActs[i * oldWidth],
62935c4bbdfSmrg                       nCopy * sizeof(XkbAction));
63035c4bbdfSmrg            }
63135c4bbdfSmrg        }
63235c4bbdfSmrg        i = xkb->map->key_sym_map[key].group_info;
63335c4bbdfSmrg        i = XkbSetNumGroups(i, nGroups);
63435c4bbdfSmrg        xkb->map->key_sym_map[key].group_info = i;
63535c4bbdfSmrg        xkb->map->key_sym_map[key].width = width;
63635c4bbdfSmrg    }
63735c4bbdfSmrg    width = 0;
63835c4bbdfSmrg    for (i = 0; i < nGroups; i++) {
63935c4bbdfSmrg        xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
64035c4bbdfSmrg        if (xkb->map->types[newTypes[i]].num_levels > width)
64135c4bbdfSmrg            width = xkb->map->types[newTypes[i]].num_levels;
64235c4bbdfSmrg    }
64335c4bbdfSmrg    xkb->map->key_sym_map[key].width = width;
64435c4bbdfSmrg    if (changes != NULL) {
64535c4bbdfSmrg        if (changes->changed & XkbKeySymsMask) {
64635c4bbdfSmrg            _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
64735c4bbdfSmrg                             key);
64835c4bbdfSmrg        }
64935c4bbdfSmrg        else {
65035c4bbdfSmrg            changes->changed |= XkbKeySymsMask;
65135c4bbdfSmrg            changes->first_key_sym = key;
65235c4bbdfSmrg            changes->num_key_syms = 1;
65335c4bbdfSmrg        }
65405b261ecSmrg    }
65505b261ecSmrg    return Success;
65605b261ecSmrg}
65705b261ecSmrg
65805b261ecSmrg/***====================================================================***/
65905b261ecSmrg
66005b261ecSmrgBool
66135c4bbdfSmrgXkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
66205b261ecSmrg{
66335c4bbdfSmrg    register int i, bit;
66435c4bbdfSmrg    register unsigned mask;
66535c4bbdfSmrg
666ed6184dfSmrg    if ((xkb == NULL) || (xkb->server == NULL)) {
667ed6184dfSmrg        *mask_rtrn = 0;
66835c4bbdfSmrg        return FALSE;
669ed6184dfSmrg    }
67035c4bbdfSmrg    if (virtual_mask == 0) {
67135c4bbdfSmrg        *mask_rtrn = 0;
67235c4bbdfSmrg        return TRUE;
67335c4bbdfSmrg    }
67435c4bbdfSmrg    for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
67535c4bbdfSmrg        if (virtual_mask & bit)
67635c4bbdfSmrg            mask |= xkb->server->vmods[i];
67735c4bbdfSmrg    }
67835c4bbdfSmrg    *mask_rtrn = mask;
6796747b715Smrg    return TRUE;
68005b261ecSmrg}
68105b261ecSmrg
68205b261ecSmrg/***====================================================================***/
68305b261ecSmrg
68405b261ecSmrgstatic Bool
68535c4bbdfSmrgXkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
68605b261ecSmrg{
68735c4bbdfSmrg    unsigned int tmp;
68805b261ecSmrg
68905b261ecSmrg    switch (act->type) {
69035c4bbdfSmrg    case XkbSA_SetMods:
69135c4bbdfSmrg    case XkbSA_LatchMods:
69235c4bbdfSmrg    case XkbSA_LockMods:
69335c4bbdfSmrg        if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
69435c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
69535c4bbdfSmrg            act->mods.mask = act->mods.real_mods;
69635c4bbdfSmrg            act->mods.mask |= tmp;
69735c4bbdfSmrg            return TRUE;
69835c4bbdfSmrg        }
69935c4bbdfSmrg        break;
70035c4bbdfSmrg    case XkbSA_ISOLock:
70135c4bbdfSmrg        if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
70235c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
70335c4bbdfSmrg            act->iso.mask = act->iso.real_mods;
70435c4bbdfSmrg            act->iso.mask |= tmp;
70535c4bbdfSmrg            return TRUE;
70635c4bbdfSmrg        }
70735c4bbdfSmrg        break;
70805b261ecSmrg    }
7096747b715Smrg    return FALSE;
71005b261ecSmrg}
71105b261ecSmrg
71205b261ecSmrgstatic void
71335c4bbdfSmrgXkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
71435c4bbdfSmrg                            XkbKeyTypePtr type,
71535c4bbdfSmrg                            unsigned int changed, XkbChangesPtr changes)
71605b261ecSmrg{
71735c4bbdfSmrg    register unsigned int i;
71835c4bbdfSmrg    unsigned int mask;
71935c4bbdfSmrg
72035c4bbdfSmrg    XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
72135c4bbdfSmrg    type->mods.mask = type->mods.real_mods | mask;
72235c4bbdfSmrg    if ((type->map_count > 0) && (type->mods.vmods != 0)) {
72335c4bbdfSmrg        XkbKTMapEntryPtr entry;
72435c4bbdfSmrg
72535c4bbdfSmrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
72635c4bbdfSmrg            if (entry->mods.vmods != 0) {
72735c4bbdfSmrg                XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
72835c4bbdfSmrg                entry->mods.mask = entry->mods.real_mods | mask;
72935c4bbdfSmrg                /* entry is active if vmods are bound */
73035c4bbdfSmrg                entry->active = (mask != 0);
73135c4bbdfSmrg            }
73235c4bbdfSmrg            else
73335c4bbdfSmrg                entry->active = 1;
73435c4bbdfSmrg        }
73505b261ecSmrg    }
73605b261ecSmrg    if (changes) {
73735c4bbdfSmrg        int type_ndx;
73835c4bbdfSmrg
73935c4bbdfSmrg        type_ndx = type - xkb->map->types;
74035c4bbdfSmrg        if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
74135c4bbdfSmrg            return;
74235c4bbdfSmrg        if (changes->map.changed & XkbKeyTypesMask) {
74335c4bbdfSmrg            int last;
74435c4bbdfSmrg
74535c4bbdfSmrg            last = changes->map.first_type + changes->map.num_types - 1;
74635c4bbdfSmrg            if (type_ndx < changes->map.first_type) {
74735c4bbdfSmrg                changes->map.first_type = type_ndx;
74835c4bbdfSmrg                changes->map.num_types = (last - type_ndx) + 1;
74935c4bbdfSmrg            }
75035c4bbdfSmrg            else if (type_ndx > last) {
75135c4bbdfSmrg                changes->map.num_types =
75235c4bbdfSmrg                    (type_ndx - changes->map.first_type) + 1;
75335c4bbdfSmrg            }
75435c4bbdfSmrg        }
75535c4bbdfSmrg        else {
75635c4bbdfSmrg            changes->map.changed |= XkbKeyTypesMask;
75735c4bbdfSmrg            changes->map.first_type = type_ndx;
75835c4bbdfSmrg            changes->map.num_types = 1;
75935c4bbdfSmrg        }
76005b261ecSmrg    }
76105b261ecSmrg    return;
76205b261ecSmrg}
76305b261ecSmrg
76405b261ecSmrgBool
76535c4bbdfSmrgXkbApplyVirtualModChanges(XkbDescPtr xkb, unsigned changed,
76635c4bbdfSmrg                          XkbChangesPtr changes)
76705b261ecSmrg{
76835c4bbdfSmrg    register int i;
76935c4bbdfSmrg    unsigned int checkState = 0;
77035c4bbdfSmrg
77135c4bbdfSmrg    if ((!xkb) || (!xkb->map) || (changed == 0))
77235c4bbdfSmrg        return FALSE;
77335c4bbdfSmrg    for (i = 0; i < xkb->map->num_types; i++) {
77435c4bbdfSmrg        if (xkb->map->types[i].mods.vmods & changed)
77535c4bbdfSmrg            XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
77635c4bbdfSmrg                                        changes);
77735c4bbdfSmrg    }
77835c4bbdfSmrg    if (changed & xkb->ctrls->internal.vmods) {
77935c4bbdfSmrg        unsigned int newMask;
78035c4bbdfSmrg
78135c4bbdfSmrg        XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
78235c4bbdfSmrg        newMask |= xkb->ctrls->internal.real_mods;
78335c4bbdfSmrg        if (xkb->ctrls->internal.mask != newMask) {
78435c4bbdfSmrg            xkb->ctrls->internal.mask = newMask;
78535c4bbdfSmrg            if (changes) {
78635c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbInternalModsMask;
78735c4bbdfSmrg                checkState = TRUE;
78835c4bbdfSmrg            }
78935c4bbdfSmrg        }
79035c4bbdfSmrg    }
79135c4bbdfSmrg    if (changed & xkb->ctrls->ignore_lock.vmods) {
79235c4bbdfSmrg        unsigned int newMask;
79335c4bbdfSmrg
79435c4bbdfSmrg        XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
79535c4bbdfSmrg        newMask |= xkb->ctrls->ignore_lock.real_mods;
79635c4bbdfSmrg        if (xkb->ctrls->ignore_lock.mask != newMask) {
79735c4bbdfSmrg            xkb->ctrls->ignore_lock.mask = newMask;
79835c4bbdfSmrg            if (changes) {
79935c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
80035c4bbdfSmrg                checkState = TRUE;
80135c4bbdfSmrg            }
80235c4bbdfSmrg        }
80335c4bbdfSmrg    }
80435c4bbdfSmrg    if (xkb->indicators != NULL) {
80535c4bbdfSmrg        XkbIndicatorMapPtr map;
80635c4bbdfSmrg
80735c4bbdfSmrg        map = &xkb->indicators->maps[0];
80835c4bbdfSmrg        for (i = 0; i < XkbNumIndicators; i++, map++) {
80935c4bbdfSmrg            if (map->mods.vmods & changed) {
81035c4bbdfSmrg                unsigned int newMask;
81135c4bbdfSmrg
81235c4bbdfSmrg                XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
81335c4bbdfSmrg                newMask |= map->mods.real_mods;
81435c4bbdfSmrg                if (newMask != map->mods.mask) {
81535c4bbdfSmrg                    map->mods.mask = newMask;
81635c4bbdfSmrg                    if (changes) {
81735c4bbdfSmrg                        changes->indicators.map_changes |= (1 << i);
81835c4bbdfSmrg                        checkState = TRUE;
81935c4bbdfSmrg                    }
82035c4bbdfSmrg                }
82135c4bbdfSmrg            }
82235c4bbdfSmrg        }
82335c4bbdfSmrg    }
82435c4bbdfSmrg    if (xkb->compat != NULL) {
82535c4bbdfSmrg        XkbCompatMapPtr compat;
82635c4bbdfSmrg
82735c4bbdfSmrg        compat = xkb->compat;
82835c4bbdfSmrg        for (i = 0; i < XkbNumKbdGroups; i++) {
82935c4bbdfSmrg            unsigned int newMask;
83035c4bbdfSmrg
83135c4bbdfSmrg            XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
83235c4bbdfSmrg            newMask |= compat->groups[i].real_mods;
83335c4bbdfSmrg            if (compat->groups[i].mask != newMask) {
83435c4bbdfSmrg                compat->groups[i].mask = newMask;
83535c4bbdfSmrg                if (changes) {
83635c4bbdfSmrg                    changes->compat.changed_groups |= (1 << i);
83735c4bbdfSmrg                    checkState = TRUE;
83835c4bbdfSmrg                }
83935c4bbdfSmrg            }
84035c4bbdfSmrg        }
84105b261ecSmrg    }
84205b261ecSmrg    if (xkb->map && xkb->server) {
84335c4bbdfSmrg        int highChange = 0, lowChange = -1;
84435c4bbdfSmrg
84535c4bbdfSmrg        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
84635c4bbdfSmrg            if (XkbKeyHasActions(xkb, i)) {
84735c4bbdfSmrg                register XkbAction *pAct;
84835c4bbdfSmrg                register int n;
84935c4bbdfSmrg
85035c4bbdfSmrg                pAct = XkbKeyActionsPtr(xkb, i);
85135c4bbdfSmrg                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
85235c4bbdfSmrg                    if ((pAct->type != XkbSA_NoAction) &&
85335c4bbdfSmrg                        XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
85435c4bbdfSmrg                        if (lowChange < 0)
85535c4bbdfSmrg                            lowChange = i;
85635c4bbdfSmrg                        highChange = i;
85735c4bbdfSmrg                    }
85835c4bbdfSmrg                }
85935c4bbdfSmrg            }
86035c4bbdfSmrg        }
86135c4bbdfSmrg        if (changes && (lowChange > 0)) {       /* something changed */
86235c4bbdfSmrg            if (changes->map.changed & XkbKeyActionsMask) {
86335c4bbdfSmrg                int last;
86435c4bbdfSmrg
86535c4bbdfSmrg                if (changes->map.first_key_act < lowChange)
86635c4bbdfSmrg                    lowChange = changes->map.first_key_act;
86735c4bbdfSmrg                last =
86835c4bbdfSmrg                    changes->map.first_key_act + changes->map.num_key_acts - 1;
86935c4bbdfSmrg                if (last > highChange)
87035c4bbdfSmrg                    highChange = last;
87135c4bbdfSmrg            }
87235c4bbdfSmrg            changes->map.changed |= XkbKeyActionsMask;
87335c4bbdfSmrg            changes->map.first_key_act = lowChange;
87435c4bbdfSmrg            changes->map.num_key_acts = (highChange - lowChange) + 1;
87535c4bbdfSmrg        }
87605b261ecSmrg    }
87705b261ecSmrg    return checkState;
87805b261ecSmrg}
879