XKBMisc.c revision 35c4bbdf
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#elif defined(HAVE_CONFIG_H)
3005b261ecSmrg#include <config.h>
3105b261ecSmrg#endif
3205b261ecSmrg
3305b261ecSmrg#include <stdio.h>
3405b261ecSmrg#include <X11/X.h>
3505b261ecSmrg#include <X11/Xproto.h>
3605b261ecSmrg#include "misc.h"
3705b261ecSmrg#include "inputstr.h"
3805b261ecSmrg#include <X11/keysym.h>
3905b261ecSmrg#define	XKBSRV_NEED_FILE_FUNCS
4005b261ecSmrg#include <xkbsrv.h>
4105b261ecSmrg
4205b261ecSmrg/***====================================================================***/
4305b261ecSmrg
4405b261ecSmrg#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
4505b261ecSmrg#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
4605b261ecSmrg
4705b261ecSmrgint
4835c4bbdfSmrgXkbKeyTypesForCoreSymbols(XkbDescPtr xkb,
4935c4bbdfSmrg                          int map_width,
5035c4bbdfSmrg                          KeySym * core_syms,
5135c4bbdfSmrg                          unsigned int protected,
5235c4bbdfSmrg                          int *types_inout, KeySym * xkb_syms_rtrn)
5305b261ecSmrg{
5435c4bbdfSmrg    register int i;
5535c4bbdfSmrg    unsigned int empty;
5635c4bbdfSmrg    int nSyms[XkbNumKbdGroups];
5735c4bbdfSmrg    int nGroups, tmp, groupsWidth;
5835c4bbdfSmrg    BOOL replicated = FALSE;
5905b261ecSmrg
6005b261ecSmrg    /* Section 12.2 of the protocol describes this process in more detail */
6105b261ecSmrg    /* Step 1:  find the # of symbols in the core mapping per group */
6235c4bbdfSmrg    groupsWidth = 2;
6335c4bbdfSmrg    for (i = 0; i < XkbNumKbdGroups; i++) {
6435c4bbdfSmrg        if ((protected & (1 << i)) && (types_inout[i] < xkb->map->num_types)) {
6535c4bbdfSmrg            nSyms[i] = xkb->map->types[types_inout[i]].num_levels;
6635c4bbdfSmrg            if (nSyms[i] > groupsWidth)
6735c4bbdfSmrg                groupsWidth = nSyms[i];
6835c4bbdfSmrg        }
6935c4bbdfSmrg        else {
7035c4bbdfSmrg            types_inout[i] = XkbTwoLevelIndex;  /* don't really know, yet */
7135c4bbdfSmrg            nSyms[i] = 2;
7235c4bbdfSmrg        }
7335c4bbdfSmrg    }
7435c4bbdfSmrg    if (nSyms[XkbGroup1Index] < 2)
7535c4bbdfSmrg        nSyms[XkbGroup1Index] = 2;
7635c4bbdfSmrg    if (nSyms[XkbGroup2Index] < 2)
7735c4bbdfSmrg        nSyms[XkbGroup2Index] = 2;
7835c4bbdfSmrg    /* Step 2:  Copy the symbols from the core ordering to XKB ordering */
7935c4bbdfSmrg    /*          symbols in the core are in the order:                   */
8035c4bbdfSmrg    /*          G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */
8135c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 0)] = CORE_SYM(0);
8235c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 1)] = CORE_SYM(1);
8335c4bbdfSmrg    for (i = 2; i < nSyms[XkbGroup1Index]; i++) {
8435c4bbdfSmrg        xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, i)] = CORE_SYM(2 + i);
8535c4bbdfSmrg    }
8635c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 0)] = CORE_SYM(2);
8735c4bbdfSmrg    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 1)] = CORE_SYM(3);
8835c4bbdfSmrg    tmp = 2 + (nSyms[XkbGroup1Index] - 2);      /* offset to extra group2 syms */
8935c4bbdfSmrg    for (i = 2; i < nSyms[XkbGroup2Index]; i++) {
9035c4bbdfSmrg        xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, i)] = CORE_SYM(tmp + i);
9105b261ecSmrg    }
926747b715Smrg
936747b715Smrg    /* Special case: if only the first group is explicit, and the symbols
946747b715Smrg     * replicate across all groups, then we have a Section 12.4 replication */
9535c4bbdfSmrg    if ((protected & ~XkbExplicitKeyType1Mask) == 0) {
966747b715Smrg        int j, width = nSyms[XkbGroup1Index];
976747b715Smrg
986747b715Smrg        replicated = TRUE;
996747b715Smrg
1006747b715Smrg        /* Check ABAB in ABABCDECDEABCDE */
1016747b715Smrg        if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) ||
1026747b715Smrg            (width > 1 && CORE_SYM(1) != CORE_SYM(3)))
1036747b715Smrg            replicated = FALSE;
1046747b715Smrg
1056747b715Smrg        /* Check CDECDE in ABABCDECDEABCDE */
10635c4bbdfSmrg        for (i = 2; i < width && replicated; i++) {
1076747b715Smrg            if (CORE_SYM(2 + i) != CORE_SYM(i + width))
1086747b715Smrg                replicated = FALSE;
1096747b715Smrg        }
1106747b715Smrg
1116747b715Smrg        /* Check ABCDE in ABABCDECDEABCDE */
1126747b715Smrg        for (j = 2; replicated &&
11335c4bbdfSmrg             j < XkbNumKbdGroups && map_width >= width * (j + 1); j++) {
11435c4bbdfSmrg            for (i = 0; i < width && replicated; i++) {
1156747b715Smrg                if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j))
1166747b715Smrg                    replicated = FALSE;
1176747b715Smrg            }
1186747b715Smrg        }
1196747b715Smrg    }
1206747b715Smrg
12135c4bbdfSmrg    if (replicated) {
12235c4bbdfSmrg        nSyms[XkbGroup2Index] = 0;
12335c4bbdfSmrg        nSyms[XkbGroup3Index] = 0;
12435c4bbdfSmrg        nSyms[XkbGroup4Index] = 0;
12535c4bbdfSmrg        nGroups = 1;
12635c4bbdfSmrg    }
12735c4bbdfSmrg    else {
12835c4bbdfSmrg        tmp = nSyms[XkbGroup1Index] + nSyms[XkbGroup2Index];
12935c4bbdfSmrg        if ((tmp >= map_width) &&
13035c4bbdfSmrg            ((protected & (XkbExplicitKeyType3Mask | XkbExplicitKeyType4Mask))
13135c4bbdfSmrg             == 0)) {
13235c4bbdfSmrg            nSyms[XkbGroup3Index] = 0;
13335c4bbdfSmrg            nSyms[XkbGroup4Index] = 0;
13435c4bbdfSmrg            nGroups = 2;
13535c4bbdfSmrg        }
13635c4bbdfSmrg        else {
13735c4bbdfSmrg            nGroups = 3;
13835c4bbdfSmrg            for (i = 0; i < nSyms[XkbGroup3Index]; i++, tmp++) {
13935c4bbdfSmrg                xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index, i)] = CORE_SYM(tmp);
1406747b715Smrg            }
14135c4bbdfSmrg            if ((tmp < map_width) || (protected & XkbExplicitKeyType4Mask)) {
14235c4bbdfSmrg                nGroups = 4;
14335c4bbdfSmrg                for (i = 0; i < nSyms[XkbGroup4Index]; i++, tmp++) {
14435c4bbdfSmrg                    xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index, i)] =
14535c4bbdfSmrg                        CORE_SYM(tmp);
1466747b715Smrg                }
1476747b715Smrg            }
1486747b715Smrg            else {
14935c4bbdfSmrg                nSyms[XkbGroup4Index] = 0;
1506747b715Smrg            }
1516747b715Smrg        }
15205b261ecSmrg    }
15305b261ecSmrg    /* steps 3&4: alphanumeric expansion,  assign canonical types */
15435c4bbdfSmrg    empty = 0;
15535c4bbdfSmrg    for (i = 0; i < nGroups; i++) {
15635c4bbdfSmrg        KeySym *syms;
15735c4bbdfSmrg
15835c4bbdfSmrg        syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
15935c4bbdfSmrg        if ((nSyms[i] > 1) && (syms[1] == NoSymbol) && (syms[0] != NoSymbol)) {
16035c4bbdfSmrg            KeySym upper, lower;
16135c4bbdfSmrg
16235c4bbdfSmrg            XkbConvertCase(syms[0], &lower, &upper);
16335c4bbdfSmrg            if (upper != lower) {
16435c4bbdfSmrg                xkb_syms_rtrn[XKB_OFFSET(i, 0)] = lower;
16535c4bbdfSmrg                xkb_syms_rtrn[XKB_OFFSET(i, 1)] = upper;
16635c4bbdfSmrg                if ((protected & (1 << i)) == 0)
16735c4bbdfSmrg                    types_inout[i] = XkbAlphabeticIndex;
16835c4bbdfSmrg            }
16935c4bbdfSmrg            else if ((protected & (1 << i)) == 0) {
17035c4bbdfSmrg                types_inout[i] = XkbOneLevelIndex;
17135c4bbdfSmrg                /*      nSyms[i]=       1; */
17235c4bbdfSmrg            }
17335c4bbdfSmrg        }
17435c4bbdfSmrg        if (((protected & (1 << i)) == 0) &&
17535c4bbdfSmrg            (types_inout[i] == XkbTwoLevelIndex)) {
17635c4bbdfSmrg            if (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1]))
17735c4bbdfSmrg                types_inout[i] = XkbKeypadIndex;
17835c4bbdfSmrg            else {
17935c4bbdfSmrg                KeySym upper, lower;
18035c4bbdfSmrg
18135c4bbdfSmrg                XkbConvertCase(syms[0], &lower, &upper);
18235c4bbdfSmrg                if ((syms[0] == lower) && (syms[1] == upper))
18335c4bbdfSmrg                    types_inout[i] = XkbAlphabeticIndex;
18435c4bbdfSmrg            }
18535c4bbdfSmrg        }
18635c4bbdfSmrg        if (syms[0] == NoSymbol) {
18735c4bbdfSmrg            register int n;
18835c4bbdfSmrg            Bool found;
18935c4bbdfSmrg
19035c4bbdfSmrg            for (n = 1, found = FALSE; (!found) && (n < nSyms[i]); n++) {
19135c4bbdfSmrg                found = (syms[n] != NoSymbol);
19235c4bbdfSmrg            }
19335c4bbdfSmrg            if (!found)
19435c4bbdfSmrg                empty |= (1 << i);
19535c4bbdfSmrg        }
19605b261ecSmrg    }
19705b261ecSmrg    /* step 5: squoosh out empty groups */
19805b261ecSmrg    if (empty) {
19935c4bbdfSmrg        for (i = nGroups - 1; i >= 0; i--) {
20035c4bbdfSmrg            if (((empty & (1 << i)) == 0) || (protected & (1 << i)))
20135c4bbdfSmrg                break;
20235c4bbdfSmrg            nGroups--;
20335c4bbdfSmrg        }
20405b261ecSmrg    }
20535c4bbdfSmrg    if (nGroups < 1)
20635c4bbdfSmrg        return 0;
20705b261ecSmrg
20805b261ecSmrg    /* step 6: replicate group 1 into group two, if necessary */
20935c4bbdfSmrg    if ((nGroups > 1) &&
21035c4bbdfSmrg        ((empty & (XkbGroup1Mask | XkbGroup2Mask)) == XkbGroup2Mask)) {
21135c4bbdfSmrg        if ((protected & (XkbExplicitKeyType1Mask | XkbExplicitKeyType2Mask)) ==
21235c4bbdfSmrg            0) {
21335c4bbdfSmrg            nSyms[XkbGroup2Index] = nSyms[XkbGroup1Index];
21435c4bbdfSmrg            types_inout[XkbGroup2Index] = types_inout[XkbGroup1Index];
21535c4bbdfSmrg            memcpy((char *) &xkb_syms_rtrn[2], (char *) xkb_syms_rtrn,
21635c4bbdfSmrg                   2 * sizeof(KeySym));
21735c4bbdfSmrg        }
21835c4bbdfSmrg        else if (types_inout[XkbGroup1Index] == types_inout[XkbGroup2Index]) {
21935c4bbdfSmrg            memcpy((char *) &xkb_syms_rtrn[nSyms[XkbGroup1Index]],
22035c4bbdfSmrg                   (char *) xkb_syms_rtrn,
22135c4bbdfSmrg                   nSyms[XkbGroup1Index] * sizeof(KeySym));
22235c4bbdfSmrg        }
22305b261ecSmrg    }
22405b261ecSmrg
2254642e01fSmrg    /* step 7: check for all groups identical or all width 1
2264642e01fSmrg     *
2274642e01fSmrg     * Special feature: if group 1 has an explicit type and all other groups
2284642e01fSmrg     * have canonical types with same symbols, we assume it's info lost from
2294642e01fSmrg     * the core replication.
2304642e01fSmrg     */
23135c4bbdfSmrg    if (nGroups > 1) {
23235c4bbdfSmrg        Bool sameType, allOneLevel, canonical = TRUE;
23335c4bbdfSmrg
23435c4bbdfSmrg        allOneLevel = (xkb->map->types[types_inout[0]].num_levels == 1);
23535c4bbdfSmrg        for (i = 1, sameType = TRUE; (allOneLevel || sameType) && (i < nGroups);
23635c4bbdfSmrg             i++) {
23735c4bbdfSmrg            sameType = (sameType &&
23835c4bbdfSmrg                        (types_inout[i] == types_inout[XkbGroup1Index]));
23935c4bbdfSmrg            if (allOneLevel)
24035c4bbdfSmrg                allOneLevel = (xkb->map->types[types_inout[i]].num_levels == 1);
24135c4bbdfSmrg            if (types_inout[i] > XkbLastRequiredType)
24235c4bbdfSmrg                canonical = FALSE;
24335c4bbdfSmrg        }
24435c4bbdfSmrg        if (((sameType) || canonical) &&
24535c4bbdfSmrg            (!(protected &
24635c4bbdfSmrg               (XkbExplicitKeyTypesMask & ~XkbExplicitKeyType1Mask)))) {
24735c4bbdfSmrg            register int s;
24835c4bbdfSmrg            Bool identical;
24935c4bbdfSmrg
25035c4bbdfSmrg            for (i = 1, identical = TRUE; identical && (i < nGroups); i++) {
25135c4bbdfSmrg                KeySym *syms;
25235c4bbdfSmrg
2536747b715Smrg                if (nSyms[i] != nSyms[XkbGroup1Index])
2546747b715Smrg                    identical = FALSE;
25535c4bbdfSmrg                syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
25635c4bbdfSmrg                for (s = 0; identical && (s < nSyms[i]); s++) {
25735c4bbdfSmrg                    if (syms[s] != xkb_syms_rtrn[s])
25835c4bbdfSmrg                        identical = FALSE;
25935c4bbdfSmrg                }
26035c4bbdfSmrg            }
26135c4bbdfSmrg            if (identical)
26235c4bbdfSmrg                nGroups = 1;
26335c4bbdfSmrg        }
26435c4bbdfSmrg        if (allOneLevel && (nGroups > 1)) {
26535c4bbdfSmrg            KeySym *syms;
26635c4bbdfSmrg
26735c4bbdfSmrg            syms = &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
26835c4bbdfSmrg            nSyms[XkbGroup1Index] = 1;
26935c4bbdfSmrg            for (i = 1; i < nGroups; i++) {
27035c4bbdfSmrg                xkb_syms_rtrn[i] = syms[0];
27135c4bbdfSmrg                syms += nSyms[i];
27235c4bbdfSmrg                nSyms[i] = 1;
27335c4bbdfSmrg            }
27435c4bbdfSmrg        }
27505b261ecSmrg    }
27605b261ecSmrg    return nGroups;
27705b261ecSmrg}
27805b261ecSmrg
27905b261ecSmrgstatic XkbSymInterpretPtr
28035c4bbdfSmrg_XkbFindMatchingInterp(XkbDescPtr xkb,
28135c4bbdfSmrg                       KeySym sym, unsigned int real_mods, unsigned int level)
28205b261ecSmrg{
28335c4bbdfSmrg    register unsigned i;
28435c4bbdfSmrg    XkbSymInterpretPtr interp, rtrn;
28535c4bbdfSmrg    CARD8 mods;
28635c4bbdfSmrg
28735c4bbdfSmrg    rtrn = NULL;
28835c4bbdfSmrg    interp = xkb->compat->sym_interpret;
28935c4bbdfSmrg    for (i = 0; i < xkb->compat->num_si; i++, interp++) {
29035c4bbdfSmrg        if ((interp->sym == NoSymbol) || (sym == interp->sym)) {
29135c4bbdfSmrg            int match;
29235c4bbdfSmrg
29335c4bbdfSmrg            if ((level == 0) || ((interp->match & XkbSI_LevelOneOnly) == 0))
29435c4bbdfSmrg                mods = real_mods;
29535c4bbdfSmrg            else
29635c4bbdfSmrg                mods = 0;
29735c4bbdfSmrg            switch (interp->match & XkbSI_OpMask) {
29835c4bbdfSmrg            case XkbSI_NoneOf:
29935c4bbdfSmrg                match = ((interp->mods & mods) == 0);
30035c4bbdfSmrg                break;
30135c4bbdfSmrg            case XkbSI_AnyOfOrNone:
30235c4bbdfSmrg                match = ((mods == 0) || ((interp->mods & mods) != 0));
30335c4bbdfSmrg                break;
30435c4bbdfSmrg            case XkbSI_AnyOf:
30535c4bbdfSmrg                match = ((interp->mods & mods) != 0);
30635c4bbdfSmrg                break;
30735c4bbdfSmrg            case XkbSI_AllOf:
30835c4bbdfSmrg                match = ((interp->mods & mods) == interp->mods);
30935c4bbdfSmrg                break;
31035c4bbdfSmrg            case XkbSI_Exactly:
31135c4bbdfSmrg                match = (interp->mods == mods);
31235c4bbdfSmrg                break;
31335c4bbdfSmrg            default:
31435c4bbdfSmrg                match = 0;
31535c4bbdfSmrg                break;
31635c4bbdfSmrg            }
31735c4bbdfSmrg            if (match) {
31835c4bbdfSmrg                if (interp->sym != NoSymbol) {
31935c4bbdfSmrg                    return interp;
32035c4bbdfSmrg                }
32135c4bbdfSmrg                else if (rtrn == NULL) {
32235c4bbdfSmrg                    rtrn = interp;
32335c4bbdfSmrg                }
32435c4bbdfSmrg            }
32535c4bbdfSmrg        }
32605b261ecSmrg    }
32705b261ecSmrg    return rtrn;
32805b261ecSmrg}
32905b261ecSmrg
33005b261ecSmrgstatic void
33135c4bbdfSmrg_XkbAddKeyChange(KeyCode *pFirst, unsigned char *pNum, KeyCode newKey)
33205b261ecSmrg{
33335c4bbdfSmrg    KeyCode last;
33405b261ecSmrg
33535c4bbdfSmrg    last = (*pFirst) + (*pNum);
33635c4bbdfSmrg    if (newKey < *pFirst) {
33735c4bbdfSmrg        *pFirst = newKey;
33835c4bbdfSmrg        *pNum = (last - newKey) + 1;
33905b261ecSmrg    }
34035c4bbdfSmrg    else if (newKey > last) {
34135c4bbdfSmrg        *pNum = (last - *pFirst) + 1;
34205b261ecSmrg    }
34305b261ecSmrg    return;
34405b261ecSmrg}
34505b261ecSmrg
34605b261ecSmrgstatic void
34735c4bbdfSmrg_XkbSetActionKeyMods(XkbDescPtr xkb, XkbAction *act, unsigned mods)
34805b261ecSmrg{
34935c4bbdfSmrg    unsigned tmp;
35005b261ecSmrg
35105b261ecSmrg    switch (act->type) {
35235c4bbdfSmrg    case XkbSA_SetMods:
35335c4bbdfSmrg    case XkbSA_LatchMods:
35435c4bbdfSmrg    case XkbSA_LockMods:
35535c4bbdfSmrg        if (act->mods.flags & XkbSA_UseModMapMods)
35635c4bbdfSmrg            act->mods.real_mods = act->mods.mask = mods;
35735c4bbdfSmrg        if ((tmp = XkbModActionVMods(&act->mods)) != 0) {
35835c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
35935c4bbdfSmrg            act->mods.mask |= tmp;
36035c4bbdfSmrg        }
36135c4bbdfSmrg        break;
36235c4bbdfSmrg    case XkbSA_ISOLock:
36335c4bbdfSmrg        if (act->iso.flags & XkbSA_UseModMapMods)
36435c4bbdfSmrg            act->iso.real_mods = act->iso.mask = mods;
36535c4bbdfSmrg        if ((tmp = XkbModActionVMods(&act->iso)) != 0) {
36635c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
36735c4bbdfSmrg            act->iso.mask |= tmp;
36835c4bbdfSmrg        }
36935c4bbdfSmrg        break;
37005b261ecSmrg    }
37105b261ecSmrg    return;
37205b261ecSmrg}
37305b261ecSmrg
37405b261ecSmrg#define	IBUF_SIZE	8
37505b261ecSmrg
37605b261ecSmrgBool
37735c4bbdfSmrgXkbApplyCompatMapToKey(XkbDescPtr xkb, KeyCode key, XkbChangesPtr changes)
37805b261ecSmrg{
37935c4bbdfSmrg    KeySym *syms;
38035c4bbdfSmrg    unsigned char explicit, mods;
38135c4bbdfSmrg    XkbSymInterpretPtr *interps, ibuf[IBUF_SIZE];
38235c4bbdfSmrg    int n, nSyms, found;
38335c4bbdfSmrg    unsigned changed, tmp;
38435c4bbdfSmrg
38535c4bbdfSmrg    if ((!xkb) || (!xkb->map) || (!xkb->map->key_sym_map) ||
38635c4bbdfSmrg        (!xkb->compat) || (!xkb->compat->sym_interpret) ||
38735c4bbdfSmrg        (key < xkb->min_key_code) || (key > xkb->max_key_code)) {
38835c4bbdfSmrg        return FALSE;
38935c4bbdfSmrg    }
39035c4bbdfSmrg    if (((!xkb->server) || (!xkb->server->key_acts)) &&
39135c4bbdfSmrg        (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 0) != Success)) {
39235c4bbdfSmrg        return FALSE;
39335c4bbdfSmrg    }
39435c4bbdfSmrg    changed = 0;                /* keeps track of what has changed in _this_ call */
39535c4bbdfSmrg    explicit = xkb->server->explicit[key];
39635c4bbdfSmrg    if (explicit & XkbExplicitInterpretMask)    /* nothing to do */
39735c4bbdfSmrg        return TRUE;
39835c4bbdfSmrg    mods = (xkb->map->modmap ? xkb->map->modmap[key] : 0);
39935c4bbdfSmrg    nSyms = XkbKeyNumSyms(xkb, key);
40035c4bbdfSmrg    syms = XkbKeySymsPtr(xkb, key);
40135c4bbdfSmrg    if (nSyms > IBUF_SIZE) {
40235c4bbdfSmrg        interps = calloc(nSyms, sizeof(XkbSymInterpretPtr));
40335c4bbdfSmrg        if (interps == NULL) {
40435c4bbdfSmrg            interps = ibuf;
40535c4bbdfSmrg            nSyms = IBUF_SIZE;
40635c4bbdfSmrg        }
40705b261ecSmrg    }
40805b261ecSmrg    else {
40935c4bbdfSmrg        interps = ibuf;
41035c4bbdfSmrg    }
41135c4bbdfSmrg    found = 0;
41235c4bbdfSmrg    for (n = 0; n < nSyms; n++) {
41335c4bbdfSmrg        unsigned level = (n % XkbKeyGroupsWidth(xkb, key));
41435c4bbdfSmrg
41535c4bbdfSmrg        interps[n] = NULL;
41635c4bbdfSmrg        if (syms[n] != NoSymbol) {
41735c4bbdfSmrg            interps[n] = _XkbFindMatchingInterp(xkb, syms[n], mods, level);
41835c4bbdfSmrg            if (interps[n] && interps[n]->act.type != XkbSA_NoAction)
41935c4bbdfSmrg                found++;
42035c4bbdfSmrg            else
42135c4bbdfSmrg                interps[n] = NULL;
42235c4bbdfSmrg        }
42305b261ecSmrg    }
42405b261ecSmrg    /* 1/28/96 (ef) -- XXX! WORKING HERE */
42505b261ecSmrg    if (!found) {
42635c4bbdfSmrg        if (xkb->server->key_acts[key] != 0) {
42735c4bbdfSmrg            xkb->server->key_acts[key] = 0;
42835c4bbdfSmrg            changed |= XkbKeyActionsMask;
42935c4bbdfSmrg        }
43005b261ecSmrg    }
43105b261ecSmrg    else {
43235c4bbdfSmrg        XkbAction *pActs;
43335c4bbdfSmrg        unsigned int new_vmodmask;
43435c4bbdfSmrg
43535c4bbdfSmrg        changed |= XkbKeyActionsMask;
43635c4bbdfSmrg        pActs = XkbResizeKeyActions(xkb, key, nSyms);
43735c4bbdfSmrg        if (!pActs) {
43805b261ecSmrg            if (nSyms > IBUF_SIZE)
4396747b715Smrg                free(interps);
44035c4bbdfSmrg            return FALSE;
44135c4bbdfSmrg        }
44235c4bbdfSmrg        new_vmodmask = 0;
44335c4bbdfSmrg        for (n = 0; n < nSyms; n++) {
44435c4bbdfSmrg            if (interps[n]) {
44535c4bbdfSmrg                unsigned effMods;
44635c4bbdfSmrg
44735c4bbdfSmrg                pActs[n] = *((XkbAction *) &interps[n]->act);
44835c4bbdfSmrg                if ((n == 0) || ((interps[n]->match & XkbSI_LevelOneOnly) == 0)) {
44935c4bbdfSmrg                    effMods = mods;
45035c4bbdfSmrg                    if (interps[n]->virtual_mod != XkbNoModifier)
45135c4bbdfSmrg                        new_vmodmask |= (1 << interps[n]->virtual_mod);
45235c4bbdfSmrg                }
45335c4bbdfSmrg                else
45435c4bbdfSmrg                    effMods = 0;
45535c4bbdfSmrg                _XkbSetActionKeyMods(xkb, &pActs[n], effMods);
45635c4bbdfSmrg            }
45735c4bbdfSmrg            else
45835c4bbdfSmrg                pActs[n].type = XkbSA_NoAction;
45935c4bbdfSmrg        }
46035c4bbdfSmrg        if (((explicit & XkbExplicitVModMapMask) == 0) &&
46135c4bbdfSmrg            (xkb->server->vmodmap[key] != new_vmodmask)) {
46235c4bbdfSmrg            changed |= XkbVirtualModMapMask;
46335c4bbdfSmrg            xkb->server->vmodmap[key] = new_vmodmask;
46435c4bbdfSmrg        }
46535c4bbdfSmrg        if (interps[0]) {
46635c4bbdfSmrg            if ((interps[0]->flags & XkbSI_LockingKey) &&
46735c4bbdfSmrg                ((explicit & XkbExplicitBehaviorMask) == 0)) {
46835c4bbdfSmrg                xkb->server->behaviors[key].type = XkbKB_Lock;
46935c4bbdfSmrg                changed |= XkbKeyBehaviorsMask;
47035c4bbdfSmrg            }
47135c4bbdfSmrg            if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
47235c4bbdfSmrg                CARD8 old;
47335c4bbdfSmrg
47435c4bbdfSmrg                old = BitIsOn(xkb->ctrls->per_key_repeat, key);
47535c4bbdfSmrg                if (interps[0]->flags & XkbSI_AutoRepeat)
47635c4bbdfSmrg                    SetBit(xkb->ctrls->per_key_repeat, key);
47735c4bbdfSmrg                else
47835c4bbdfSmrg                    ClearBit(xkb->ctrls->per_key_repeat, key);
47935c4bbdfSmrg                if (changes && old != BitIsOn(xkb->ctrls->per_key_repeat, key))
48035c4bbdfSmrg                    changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
48135c4bbdfSmrg            }
48235c4bbdfSmrg        }
48335c4bbdfSmrg    }
48435c4bbdfSmrg    if ((!found) || (interps[0] == NULL)) {
48535c4bbdfSmrg        if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
48635c4bbdfSmrg            CARD8 old;
48735c4bbdfSmrg
48835c4bbdfSmrg            old = BitIsOn(xkb->ctrls->per_key_repeat, key);
48935c4bbdfSmrg            SetBit(xkb->ctrls->per_key_repeat, key);
49035c4bbdfSmrg            if (changes && (old != BitIsOn(xkb->ctrls->per_key_repeat, key)))
49135c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
49235c4bbdfSmrg        }
49335c4bbdfSmrg        if (((explicit & XkbExplicitBehaviorMask) == 0) &&
49435c4bbdfSmrg            (xkb->server->behaviors[key].type == XkbKB_Lock)) {
49535c4bbdfSmrg            xkb->server->behaviors[key].type = XkbKB_Default;
49635c4bbdfSmrg            changed |= XkbKeyBehaviorsMask;
49735c4bbdfSmrg        }
49805b261ecSmrg    }
49905b261ecSmrg    if (changes) {
50035c4bbdfSmrg        XkbMapChangesPtr mc;
50135c4bbdfSmrg
50235c4bbdfSmrg        mc = &changes->map;
50335c4bbdfSmrg        tmp = (changed & mc->changed);
50435c4bbdfSmrg        if (tmp & XkbKeyActionsMask)
50535c4bbdfSmrg            _XkbAddKeyChange(&mc->first_key_act, &mc->num_key_acts, key);
50635c4bbdfSmrg        else if (changed & XkbKeyActionsMask) {
50735c4bbdfSmrg            mc->changed |= XkbKeyActionsMask;
50835c4bbdfSmrg            mc->first_key_act = key;
50935c4bbdfSmrg            mc->num_key_acts = 1;
51035c4bbdfSmrg        }
51135c4bbdfSmrg        if (tmp & XkbKeyBehaviorsMask) {
51235c4bbdfSmrg            _XkbAddKeyChange(&mc->first_key_behavior, &mc->num_key_behaviors,
51335c4bbdfSmrg                             key);
51435c4bbdfSmrg        }
51535c4bbdfSmrg        else if (changed & XkbKeyBehaviorsMask) {
51635c4bbdfSmrg            mc->changed |= XkbKeyBehaviorsMask;
51735c4bbdfSmrg            mc->first_key_behavior = key;
51835c4bbdfSmrg            mc->num_key_behaviors = 1;
51935c4bbdfSmrg        }
52035c4bbdfSmrg        if (tmp & XkbVirtualModMapMask)
52135c4bbdfSmrg            _XkbAddKeyChange(&mc->first_vmodmap_key, &mc->num_vmodmap_keys,
52235c4bbdfSmrg                             key);
52335c4bbdfSmrg        else if (changed & XkbVirtualModMapMask) {
52435c4bbdfSmrg            mc->changed |= XkbVirtualModMapMask;
52535c4bbdfSmrg            mc->first_vmodmap_key = key;
52635c4bbdfSmrg            mc->num_vmodmap_keys = 1;
52735c4bbdfSmrg        }
52835c4bbdfSmrg        mc->changed |= changed;
52935c4bbdfSmrg    }
53035c4bbdfSmrg    if (interps != ibuf)
53135c4bbdfSmrg        free(interps);
5326747b715Smrg    return TRUE;
53305b261ecSmrg}
53405b261ecSmrg
53505b261ecSmrgStatus
53635c4bbdfSmrgXkbChangeTypesOfKey(XkbDescPtr xkb,
53735c4bbdfSmrg                    int key,
53835c4bbdfSmrg                    int nGroups,
53935c4bbdfSmrg                    unsigned groups, int *newTypesIn, XkbMapChangesPtr changes)
54005b261ecSmrg{
54135c4bbdfSmrg    XkbKeyTypePtr pOldType, pNewType;
54235c4bbdfSmrg    register int i;
54335c4bbdfSmrg    int width, nOldGroups, oldWidth, newTypes[XkbNumKbdGroups];
54435c4bbdfSmrg
54535c4bbdfSmrg    if ((!xkb) || (!XkbKeycodeInRange(xkb, key)) || (!xkb->map) ||
54635c4bbdfSmrg        (!xkb->map->types) || (!newTypesIn) ||
54735c4bbdfSmrg        ((groups & XkbAllGroupsMask) == 0) || (nGroups > XkbNumKbdGroups)) {
54835c4bbdfSmrg        return BadMatch;
54935c4bbdfSmrg    }
55035c4bbdfSmrg    if (nGroups == 0) {
55135c4bbdfSmrg        for (i = 0; i < XkbNumKbdGroups; i++) {
55235c4bbdfSmrg            xkb->map->key_sym_map[key].kt_index[i] = XkbOneLevelIndex;
55335c4bbdfSmrg        }
55435c4bbdfSmrg        i = xkb->map->key_sym_map[key].group_info;
55535c4bbdfSmrg        i = XkbSetNumGroups(i, 0);
55635c4bbdfSmrg        xkb->map->key_sym_map[key].group_info = i;
55735c4bbdfSmrg        XkbResizeKeySyms(xkb, key, 0);
55835c4bbdfSmrg        return Success;
55935c4bbdfSmrg    }
56035c4bbdfSmrg
56135c4bbdfSmrg    nOldGroups = XkbKeyNumGroups(xkb, key);
56235c4bbdfSmrg    oldWidth = XkbKeyGroupsWidth(xkb, key);
56335c4bbdfSmrg    for (width = i = 0; i < nGroups; i++) {
56435c4bbdfSmrg        if (groups & (1 << i))
56535c4bbdfSmrg            newTypes[i] = newTypesIn[i];
56635c4bbdfSmrg        else if (i < nOldGroups)
56735c4bbdfSmrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
56835c4bbdfSmrg        else if (nOldGroups > 0)
56935c4bbdfSmrg            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
57035c4bbdfSmrg        else
57135c4bbdfSmrg            newTypes[i] = XkbTwoLevelIndex;
57235c4bbdfSmrg        if (newTypes[i] > xkb->map->num_types)
57335c4bbdfSmrg            return BadMatch;
57435c4bbdfSmrg        pNewType = &xkb->map->types[newTypes[i]];
57535c4bbdfSmrg        if (pNewType->num_levels > width)
57635c4bbdfSmrg            width = pNewType->num_levels;
57735c4bbdfSmrg    }
57835c4bbdfSmrg    if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
57935c4bbdfSmrg        xkb->ctrls->num_groups = nGroups;
58035c4bbdfSmrg    if ((width != oldWidth) || (nGroups != nOldGroups)) {
58135c4bbdfSmrg        KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
58235c4bbdfSmrg        int nCopy;
58335c4bbdfSmrg
58435c4bbdfSmrg        if (nOldGroups == 0) {
58535c4bbdfSmrg            pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
58635c4bbdfSmrg            if (pSyms != NULL) {
58735c4bbdfSmrg                i = xkb->map->key_sym_map[key].group_info;
58835c4bbdfSmrg                i = XkbSetNumGroups(i, nGroups);
58935c4bbdfSmrg                xkb->map->key_sym_map[key].group_info = i;
59035c4bbdfSmrg                xkb->map->key_sym_map[key].width = width;
59135c4bbdfSmrg                for (i = 0; i < nGroups; i++) {
59235c4bbdfSmrg                    xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
59335c4bbdfSmrg                }
59435c4bbdfSmrg                return Success;
59535c4bbdfSmrg            }
59635c4bbdfSmrg            return BadAlloc;
59735c4bbdfSmrg        }
59835c4bbdfSmrg        pSyms = XkbKeySymsPtr(xkb, key);
59935c4bbdfSmrg        memcpy(oldSyms, pSyms, XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
60035c4bbdfSmrg        pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
60135c4bbdfSmrg        if (pSyms == NULL)
60235c4bbdfSmrg            return BadAlloc;
60335c4bbdfSmrg        memset(pSyms, 0, width * nGroups * sizeof(KeySym));
60435c4bbdfSmrg        for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
60535c4bbdfSmrg            pOldType = XkbKeyKeyType(xkb, key, i);
60635c4bbdfSmrg            pNewType = &xkb->map->types[newTypes[i]];
60735c4bbdfSmrg            if (pNewType->num_levels > pOldType->num_levels)
60835c4bbdfSmrg                nCopy = pOldType->num_levels;
60935c4bbdfSmrg            else
61035c4bbdfSmrg                nCopy = pNewType->num_levels;
61135c4bbdfSmrg            memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
61235c4bbdfSmrg                   nCopy * sizeof(KeySym));
61335c4bbdfSmrg        }
61435c4bbdfSmrg        if (XkbKeyHasActions(xkb, key)) {
61535c4bbdfSmrg            XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
61635c4bbdfSmrg
61735c4bbdfSmrg            pActs = XkbKeyActionsPtr(xkb, key);
61835c4bbdfSmrg            memcpy(oldActs, pActs, XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
61935c4bbdfSmrg            pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
62035c4bbdfSmrg            if (pActs == NULL)
62135c4bbdfSmrg                return BadAlloc;
62235c4bbdfSmrg            memset(pActs, 0, width * nGroups * sizeof(XkbAction));
62335c4bbdfSmrg            for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
62435c4bbdfSmrg                pOldType = XkbKeyKeyType(xkb, key, i);
62535c4bbdfSmrg                pNewType = &xkb->map->types[newTypes[i]];
62635c4bbdfSmrg                if (pNewType->num_levels > pOldType->num_levels)
62735c4bbdfSmrg                    nCopy = pOldType->num_levels;
62835c4bbdfSmrg                else
62935c4bbdfSmrg                    nCopy = pNewType->num_levels;
63035c4bbdfSmrg                memcpy(&pActs[i * width], &oldActs[i * oldWidth],
63135c4bbdfSmrg                       nCopy * sizeof(XkbAction));
63235c4bbdfSmrg            }
63335c4bbdfSmrg        }
63435c4bbdfSmrg        i = xkb->map->key_sym_map[key].group_info;
63535c4bbdfSmrg        i = XkbSetNumGroups(i, nGroups);
63635c4bbdfSmrg        xkb->map->key_sym_map[key].group_info = i;
63735c4bbdfSmrg        xkb->map->key_sym_map[key].width = width;
63835c4bbdfSmrg    }
63935c4bbdfSmrg    width = 0;
64035c4bbdfSmrg    for (i = 0; i < nGroups; i++) {
64135c4bbdfSmrg        xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
64235c4bbdfSmrg        if (xkb->map->types[newTypes[i]].num_levels > width)
64335c4bbdfSmrg            width = xkb->map->types[newTypes[i]].num_levels;
64435c4bbdfSmrg    }
64535c4bbdfSmrg    xkb->map->key_sym_map[key].width = width;
64635c4bbdfSmrg    if (changes != NULL) {
64735c4bbdfSmrg        if (changes->changed & XkbKeySymsMask) {
64835c4bbdfSmrg            _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
64935c4bbdfSmrg                             key);
65035c4bbdfSmrg        }
65135c4bbdfSmrg        else {
65235c4bbdfSmrg            changes->changed |= XkbKeySymsMask;
65335c4bbdfSmrg            changes->first_key_sym = key;
65435c4bbdfSmrg            changes->num_key_syms = 1;
65535c4bbdfSmrg        }
65605b261ecSmrg    }
65705b261ecSmrg    return Success;
65805b261ecSmrg}
65905b261ecSmrg
66005b261ecSmrg/***====================================================================***/
66105b261ecSmrg
66205b261ecSmrgBool
66335c4bbdfSmrgXkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
66405b261ecSmrg{
66535c4bbdfSmrg    register int i, bit;
66635c4bbdfSmrg    register unsigned mask;
66735c4bbdfSmrg
66835c4bbdfSmrg    if (xkb == NULL)
66935c4bbdfSmrg        return FALSE;
67035c4bbdfSmrg    if (virtual_mask == 0) {
67135c4bbdfSmrg        *mask_rtrn = 0;
67235c4bbdfSmrg        return TRUE;
67335c4bbdfSmrg    }
67435c4bbdfSmrg    if (xkb->server == NULL)
67535c4bbdfSmrg        return FALSE;
67635c4bbdfSmrg    for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
67735c4bbdfSmrg        if (virtual_mask & bit)
67835c4bbdfSmrg            mask |= xkb->server->vmods[i];
67935c4bbdfSmrg    }
68035c4bbdfSmrg    *mask_rtrn = mask;
6816747b715Smrg    return TRUE;
68205b261ecSmrg}
68305b261ecSmrg
68405b261ecSmrg/***====================================================================***/
68505b261ecSmrg
68605b261ecSmrgstatic Bool
68735c4bbdfSmrgXkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
68805b261ecSmrg{
68935c4bbdfSmrg    unsigned int tmp;
69005b261ecSmrg
69105b261ecSmrg    switch (act->type) {
69235c4bbdfSmrg    case XkbSA_SetMods:
69335c4bbdfSmrg    case XkbSA_LatchMods:
69435c4bbdfSmrg    case XkbSA_LockMods:
69535c4bbdfSmrg        if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
69635c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
69735c4bbdfSmrg            act->mods.mask = act->mods.real_mods;
69835c4bbdfSmrg            act->mods.mask |= tmp;
69935c4bbdfSmrg            return TRUE;
70035c4bbdfSmrg        }
70135c4bbdfSmrg        break;
70235c4bbdfSmrg    case XkbSA_ISOLock:
70335c4bbdfSmrg        if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
70435c4bbdfSmrg            XkbVirtualModsToReal(xkb, tmp, &tmp);
70535c4bbdfSmrg            act->iso.mask = act->iso.real_mods;
70635c4bbdfSmrg            act->iso.mask |= tmp;
70735c4bbdfSmrg            return TRUE;
70835c4bbdfSmrg        }
70935c4bbdfSmrg        break;
71005b261ecSmrg    }
7116747b715Smrg    return FALSE;
71205b261ecSmrg}
71305b261ecSmrg
71405b261ecSmrgstatic void
71535c4bbdfSmrgXkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
71635c4bbdfSmrg                            XkbKeyTypePtr type,
71735c4bbdfSmrg                            unsigned int changed, XkbChangesPtr changes)
71805b261ecSmrg{
71935c4bbdfSmrg    register unsigned int i;
72035c4bbdfSmrg    unsigned int mask;
72135c4bbdfSmrg
72235c4bbdfSmrg    XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
72335c4bbdfSmrg    type->mods.mask = type->mods.real_mods | mask;
72435c4bbdfSmrg    if ((type->map_count > 0) && (type->mods.vmods != 0)) {
72535c4bbdfSmrg        XkbKTMapEntryPtr entry;
72635c4bbdfSmrg
72735c4bbdfSmrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
72835c4bbdfSmrg            if (entry->mods.vmods != 0) {
72935c4bbdfSmrg                XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
73035c4bbdfSmrg                entry->mods.mask = entry->mods.real_mods | mask;
73135c4bbdfSmrg                /* entry is active if vmods are bound */
73235c4bbdfSmrg                entry->active = (mask != 0);
73335c4bbdfSmrg            }
73435c4bbdfSmrg            else
73535c4bbdfSmrg                entry->active = 1;
73635c4bbdfSmrg        }
73705b261ecSmrg    }
73805b261ecSmrg    if (changes) {
73935c4bbdfSmrg        int type_ndx;
74035c4bbdfSmrg
74135c4bbdfSmrg        type_ndx = type - xkb->map->types;
74235c4bbdfSmrg        if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
74335c4bbdfSmrg            return;
74435c4bbdfSmrg        if (changes->map.changed & XkbKeyTypesMask) {
74535c4bbdfSmrg            int last;
74635c4bbdfSmrg
74735c4bbdfSmrg            last = changes->map.first_type + changes->map.num_types - 1;
74835c4bbdfSmrg            if (type_ndx < changes->map.first_type) {
74935c4bbdfSmrg                changes->map.first_type = type_ndx;
75035c4bbdfSmrg                changes->map.num_types = (last - type_ndx) + 1;
75135c4bbdfSmrg            }
75235c4bbdfSmrg            else if (type_ndx > last) {
75335c4bbdfSmrg                changes->map.num_types =
75435c4bbdfSmrg                    (type_ndx - changes->map.first_type) + 1;
75535c4bbdfSmrg            }
75635c4bbdfSmrg        }
75735c4bbdfSmrg        else {
75835c4bbdfSmrg            changes->map.changed |= XkbKeyTypesMask;
75935c4bbdfSmrg            changes->map.first_type = type_ndx;
76035c4bbdfSmrg            changes->map.num_types = 1;
76135c4bbdfSmrg        }
76205b261ecSmrg    }
76305b261ecSmrg    return;
76405b261ecSmrg}
76505b261ecSmrg
76605b261ecSmrgBool
76735c4bbdfSmrgXkbApplyVirtualModChanges(XkbDescPtr xkb, unsigned changed,
76835c4bbdfSmrg                          XkbChangesPtr changes)
76905b261ecSmrg{
77035c4bbdfSmrg    register int i;
77135c4bbdfSmrg    unsigned int checkState = 0;
77235c4bbdfSmrg
77335c4bbdfSmrg    if ((!xkb) || (!xkb->map) || (changed == 0))
77435c4bbdfSmrg        return FALSE;
77535c4bbdfSmrg    for (i = 0; i < xkb->map->num_types; i++) {
77635c4bbdfSmrg        if (xkb->map->types[i].mods.vmods & changed)
77735c4bbdfSmrg            XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
77835c4bbdfSmrg                                        changes);
77935c4bbdfSmrg    }
78035c4bbdfSmrg    if (changed & xkb->ctrls->internal.vmods) {
78135c4bbdfSmrg        unsigned int newMask;
78235c4bbdfSmrg
78335c4bbdfSmrg        XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
78435c4bbdfSmrg        newMask |= xkb->ctrls->internal.real_mods;
78535c4bbdfSmrg        if (xkb->ctrls->internal.mask != newMask) {
78635c4bbdfSmrg            xkb->ctrls->internal.mask = newMask;
78735c4bbdfSmrg            if (changes) {
78835c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbInternalModsMask;
78935c4bbdfSmrg                checkState = TRUE;
79035c4bbdfSmrg            }
79135c4bbdfSmrg        }
79235c4bbdfSmrg    }
79335c4bbdfSmrg    if (changed & xkb->ctrls->ignore_lock.vmods) {
79435c4bbdfSmrg        unsigned int newMask;
79535c4bbdfSmrg
79635c4bbdfSmrg        XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
79735c4bbdfSmrg        newMask |= xkb->ctrls->ignore_lock.real_mods;
79835c4bbdfSmrg        if (xkb->ctrls->ignore_lock.mask != newMask) {
79935c4bbdfSmrg            xkb->ctrls->ignore_lock.mask = newMask;
80035c4bbdfSmrg            if (changes) {
80135c4bbdfSmrg                changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
80235c4bbdfSmrg                checkState = TRUE;
80335c4bbdfSmrg            }
80435c4bbdfSmrg        }
80535c4bbdfSmrg    }
80635c4bbdfSmrg    if (xkb->indicators != NULL) {
80735c4bbdfSmrg        XkbIndicatorMapPtr map;
80835c4bbdfSmrg
80935c4bbdfSmrg        map = &xkb->indicators->maps[0];
81035c4bbdfSmrg        for (i = 0; i < XkbNumIndicators; i++, map++) {
81135c4bbdfSmrg            if (map->mods.vmods & changed) {
81235c4bbdfSmrg                unsigned int newMask;
81335c4bbdfSmrg
81435c4bbdfSmrg                XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
81535c4bbdfSmrg                newMask |= map->mods.real_mods;
81635c4bbdfSmrg                if (newMask != map->mods.mask) {
81735c4bbdfSmrg                    map->mods.mask = newMask;
81835c4bbdfSmrg                    if (changes) {
81935c4bbdfSmrg                        changes->indicators.map_changes |= (1 << i);
82035c4bbdfSmrg                        checkState = TRUE;
82135c4bbdfSmrg                    }
82235c4bbdfSmrg                }
82335c4bbdfSmrg            }
82435c4bbdfSmrg        }
82535c4bbdfSmrg    }
82635c4bbdfSmrg    if (xkb->compat != NULL) {
82735c4bbdfSmrg        XkbCompatMapPtr compat;
82835c4bbdfSmrg
82935c4bbdfSmrg        compat = xkb->compat;
83035c4bbdfSmrg        for (i = 0; i < XkbNumKbdGroups; i++) {
83135c4bbdfSmrg            unsigned int newMask;
83235c4bbdfSmrg
83335c4bbdfSmrg            XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
83435c4bbdfSmrg            newMask |= compat->groups[i].real_mods;
83535c4bbdfSmrg            if (compat->groups[i].mask != newMask) {
83635c4bbdfSmrg                compat->groups[i].mask = newMask;
83735c4bbdfSmrg                if (changes) {
83835c4bbdfSmrg                    changes->compat.changed_groups |= (1 << i);
83935c4bbdfSmrg                    checkState = TRUE;
84035c4bbdfSmrg                }
84135c4bbdfSmrg            }
84235c4bbdfSmrg        }
84305b261ecSmrg    }
84405b261ecSmrg    if (xkb->map && xkb->server) {
84535c4bbdfSmrg        int highChange = 0, lowChange = -1;
84635c4bbdfSmrg
84735c4bbdfSmrg        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
84835c4bbdfSmrg            if (XkbKeyHasActions(xkb, i)) {
84935c4bbdfSmrg                register XkbAction *pAct;
85035c4bbdfSmrg                register int n;
85135c4bbdfSmrg
85235c4bbdfSmrg                pAct = XkbKeyActionsPtr(xkb, i);
85335c4bbdfSmrg                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
85435c4bbdfSmrg                    if ((pAct->type != XkbSA_NoAction) &&
85535c4bbdfSmrg                        XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
85635c4bbdfSmrg                        if (lowChange < 0)
85735c4bbdfSmrg                            lowChange = i;
85835c4bbdfSmrg                        highChange = i;
85935c4bbdfSmrg                    }
86035c4bbdfSmrg                }
86135c4bbdfSmrg            }
86235c4bbdfSmrg        }
86335c4bbdfSmrg        if (changes && (lowChange > 0)) {       /* something changed */
86435c4bbdfSmrg            if (changes->map.changed & XkbKeyActionsMask) {
86535c4bbdfSmrg                int last;
86635c4bbdfSmrg
86735c4bbdfSmrg                if (changes->map.first_key_act < lowChange)
86835c4bbdfSmrg                    lowChange = changes->map.first_key_act;
86935c4bbdfSmrg                last =
87035c4bbdfSmrg                    changes->map.first_key_act + changes->map.num_key_acts - 1;
87135c4bbdfSmrg                if (last > highChange)
87235c4bbdfSmrg                    highChange = last;
87335c4bbdfSmrg            }
87435c4bbdfSmrg            changes->map.changed |= XkbKeyActionsMask;
87535c4bbdfSmrg            changes->map.first_key_act = lowChange;
87635c4bbdfSmrg            changes->map.num_key_acts = (highChange - lowChange) + 1;
87735c4bbdfSmrg        }
87805b261ecSmrg    }
87905b261ecSmrg    return checkState;
88005b261ecSmrg}
881