879 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			879 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
/************************************************************
 | 
						|
Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
 | 
						|
 | 
						|
Permission to use, copy, modify, and distribute this
 | 
						|
software and its documentation for any purpose and without
 | 
						|
fee is hereby granted, provided that the above copyright
 | 
						|
notice appear in all copies and that both that copyright
 | 
						|
notice and this permission notice appear in supporting
 | 
						|
documentation, and that the name of Silicon Graphics not be
 | 
						|
used in advertising or publicity pertaining to distribution
 | 
						|
of the software without specific prior written permission.
 | 
						|
Silicon Graphics makes no representation about the suitability
 | 
						|
of this software for any purpose. It is provided "as is"
 | 
						|
without any express or implied warranty.
 | 
						|
 | 
						|
SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
 | 
						|
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 | 
						|
AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
 | 
						|
GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
 | 
						|
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | 
						|
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 | 
						|
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
 | 
						|
THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 | 
						|
********************************************************/
 | 
						|
 | 
						|
#ifdef HAVE_DIX_CONFIG_H
 | 
						|
#include <dix-config.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <X11/X.h>
 | 
						|
#include <X11/Xproto.h>
 | 
						|
#include "misc.h"
 | 
						|
#include "inputstr.h"
 | 
						|
#include <X11/keysym.h>
 | 
						|
#define	XKBSRV_NEED_FILE_FUNCS
 | 
						|
#include <xkbsrv.h>
 | 
						|
 | 
						|
/***====================================================================***/
 | 
						|
 | 
						|
#define	CORE_SYM(i)	(i<map_width?core_syms[i]:NoSymbol)
 | 
						|
#define	XKB_OFFSET(g,l)	(((g)*groupsWidth)+(l))
 | 
						|
 | 
						|
int
 | 
						|
XkbKeyTypesForCoreSymbols(XkbDescPtr xkb,
 | 
						|
                          int map_width,
 | 
						|
                          KeySym * core_syms,
 | 
						|
                          unsigned int protected,
 | 
						|
                          int *types_inout, KeySym * xkb_syms_rtrn)
 | 
						|
{
 | 
						|
    register int i;
 | 
						|
    unsigned int empty;
 | 
						|
    int nSyms[XkbNumKbdGroups];
 | 
						|
    int nGroups, tmp, groupsWidth;
 | 
						|
    BOOL replicated = FALSE;
 | 
						|
 | 
						|
    /* Section 12.2 of the protocol describes this process in more detail */
 | 
						|
    /* Step 1:  find the # of symbols in the core mapping per group */
 | 
						|
    groupsWidth = 2;
 | 
						|
    for (i = 0; i < XkbNumKbdGroups; i++) {
 | 
						|
        if ((protected & (1 << i)) && (types_inout[i] < xkb->map->num_types)) {
 | 
						|
            nSyms[i] = xkb->map->types[types_inout[i]].num_levels;
 | 
						|
            if (nSyms[i] > groupsWidth)
 | 
						|
                groupsWidth = nSyms[i];
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            types_inout[i] = XkbTwoLevelIndex;  /* don't really know, yet */
 | 
						|
            nSyms[i] = 2;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (nSyms[XkbGroup1Index] < 2)
 | 
						|
        nSyms[XkbGroup1Index] = 2;
 | 
						|
    if (nSyms[XkbGroup2Index] < 2)
 | 
						|
        nSyms[XkbGroup2Index] = 2;
 | 
						|
    /* Step 2:  Copy the symbols from the core ordering to XKB ordering */
 | 
						|
    /*          symbols in the core are in the order:                   */
 | 
						|
    /*          G1L1 G1L2 G2L1 G2L2 [G1L[3-n]] [G2L[3-n]] [G3L*] [G3L*] */
 | 
						|
    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 0)] = CORE_SYM(0);
 | 
						|
    xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, 1)] = CORE_SYM(1);
 | 
						|
    for (i = 2; i < nSyms[XkbGroup1Index]; i++) {
 | 
						|
        xkb_syms_rtrn[XKB_OFFSET(XkbGroup1Index, i)] = CORE_SYM(2 + i);
 | 
						|
    }
 | 
						|
    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 0)] = CORE_SYM(2);
 | 
						|
    xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, 1)] = CORE_SYM(3);
 | 
						|
    tmp = 2 + (nSyms[XkbGroup1Index] - 2);      /* offset to extra group2 syms */
 | 
						|
    for (i = 2; i < nSyms[XkbGroup2Index]; i++) {
 | 
						|
        xkb_syms_rtrn[XKB_OFFSET(XkbGroup2Index, i)] = CORE_SYM(tmp + i);
 | 
						|
    }
 | 
						|
 | 
						|
    /* Special case: if only the first group is explicit, and the symbols
 | 
						|
     * replicate across all groups, then we have a Section 12.4 replication */
 | 
						|
    if ((protected & ~XkbExplicitKeyType1Mask) == 0) {
 | 
						|
        int j, width = nSyms[XkbGroup1Index];
 | 
						|
 | 
						|
        replicated = TRUE;
 | 
						|
 | 
						|
        /* Check ABAB in ABABCDECDEABCDE */
 | 
						|
        if ((width > 0 && CORE_SYM(0) != CORE_SYM(2)) ||
 | 
						|
            (width > 1 && CORE_SYM(1) != CORE_SYM(3)))
 | 
						|
            replicated = FALSE;
 | 
						|
 | 
						|
        /* Check CDECDE in ABABCDECDEABCDE */
 | 
						|
        for (i = 2; i < width && replicated; i++) {
 | 
						|
            if (CORE_SYM(2 + i) != CORE_SYM(i + width))
 | 
						|
                replicated = FALSE;
 | 
						|
        }
 | 
						|
 | 
						|
        /* Check ABCDE in ABABCDECDEABCDE */
 | 
						|
        for (j = 2; replicated &&
 | 
						|
             j < XkbNumKbdGroups && map_width >= width * (j + 1); j++) {
 | 
						|
            for (i = 0; i < width && replicated; i++) {
 | 
						|
                if (CORE_SYM(((i < 2) ? i : 2 + i)) != CORE_SYM(i + width * j))
 | 
						|
                    replicated = FALSE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (replicated) {
 | 
						|
        nSyms[XkbGroup2Index] = 0;
 | 
						|
        nSyms[XkbGroup3Index] = 0;
 | 
						|
        nSyms[XkbGroup4Index] = 0;
 | 
						|
        nGroups = 1;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        tmp = nSyms[XkbGroup1Index] + nSyms[XkbGroup2Index];
 | 
						|
        if ((tmp >= map_width) &&
 | 
						|
            ((protected & (XkbExplicitKeyType3Mask | XkbExplicitKeyType4Mask))
 | 
						|
             == 0)) {
 | 
						|
            nSyms[XkbGroup3Index] = 0;
 | 
						|
            nSyms[XkbGroup4Index] = 0;
 | 
						|
            nGroups = 2;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            nGroups = 3;
 | 
						|
            for (i = 0; i < nSyms[XkbGroup3Index]; i++, tmp++) {
 | 
						|
                xkb_syms_rtrn[XKB_OFFSET(XkbGroup3Index, i)] = CORE_SYM(tmp);
 | 
						|
            }
 | 
						|
            if ((tmp < map_width) || (protected & XkbExplicitKeyType4Mask)) {
 | 
						|
                nGroups = 4;
 | 
						|
                for (i = 0; i < nSyms[XkbGroup4Index]; i++, tmp++) {
 | 
						|
                    xkb_syms_rtrn[XKB_OFFSET(XkbGroup4Index, i)] =
 | 
						|
                        CORE_SYM(tmp);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                nSyms[XkbGroup4Index] = 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /* steps 3&4: alphanumeric expansion,  assign canonical types */
 | 
						|
    empty = 0;
 | 
						|
    for (i = 0; i < nGroups; i++) {
 | 
						|
        KeySym *syms;
 | 
						|
 | 
						|
        syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
 | 
						|
        if ((nSyms[i] > 1) && (syms[1] == NoSymbol) && (syms[0] != NoSymbol)) {
 | 
						|
            KeySym upper, lower;
 | 
						|
 | 
						|
            XkbConvertCase(syms[0], &lower, &upper);
 | 
						|
            if (upper != lower) {
 | 
						|
                xkb_syms_rtrn[XKB_OFFSET(i, 0)] = lower;
 | 
						|
                xkb_syms_rtrn[XKB_OFFSET(i, 1)] = upper;
 | 
						|
                if ((protected & (1 << i)) == 0)
 | 
						|
                    types_inout[i] = XkbAlphabeticIndex;
 | 
						|
            }
 | 
						|
            else if ((protected & (1 << i)) == 0) {
 | 
						|
                types_inout[i] = XkbOneLevelIndex;
 | 
						|
                /*      nSyms[i]=       1; */
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (((protected & (1 << i)) == 0) &&
 | 
						|
            (types_inout[i] == XkbTwoLevelIndex)) {
 | 
						|
            if (XkbKSIsKeypad(syms[0]) || XkbKSIsKeypad(syms[1]))
 | 
						|
                types_inout[i] = XkbKeypadIndex;
 | 
						|
            else {
 | 
						|
                KeySym upper, lower;
 | 
						|
 | 
						|
                XkbConvertCase(syms[0], &lower, &upper);
 | 
						|
                if ((syms[0] == lower) && (syms[1] == upper))
 | 
						|
                    types_inout[i] = XkbAlphabeticIndex;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (syms[0] == NoSymbol) {
 | 
						|
            register int n;
 | 
						|
            Bool found;
 | 
						|
 | 
						|
            for (n = 1, found = FALSE; (!found) && (n < nSyms[i]); n++) {
 | 
						|
                found = (syms[n] != NoSymbol);
 | 
						|
            }
 | 
						|
            if (!found)
 | 
						|
                empty |= (1 << i);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /* step 5: squoosh out empty groups */
 | 
						|
    if (empty) {
 | 
						|
        for (i = nGroups - 1; i >= 0; i--) {
 | 
						|
            if (((empty & (1 << i)) == 0) || (protected & (1 << i)))
 | 
						|
                break;
 | 
						|
            nGroups--;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (nGroups < 1)
 | 
						|
        return 0;
 | 
						|
 | 
						|
    /* step 6: replicate group 1 into group two, if necessary */
 | 
						|
    if ((nGroups > 1) &&
 | 
						|
        ((empty & (XkbGroup1Mask | XkbGroup2Mask)) == XkbGroup2Mask)) {
 | 
						|
        if ((protected & (XkbExplicitKeyType1Mask | XkbExplicitKeyType2Mask)) ==
 | 
						|
            0) {
 | 
						|
            nSyms[XkbGroup2Index] = nSyms[XkbGroup1Index];
 | 
						|
            types_inout[XkbGroup2Index] = types_inout[XkbGroup1Index];
 | 
						|
            memcpy((char *) &xkb_syms_rtrn[2], (char *) xkb_syms_rtrn,
 | 
						|
                   2 * sizeof(KeySym));
 | 
						|
        }
 | 
						|
        else if (types_inout[XkbGroup1Index] == types_inout[XkbGroup2Index]) {
 | 
						|
            memcpy((char *) &xkb_syms_rtrn[nSyms[XkbGroup1Index]],
 | 
						|
                   (char *) xkb_syms_rtrn,
 | 
						|
                   nSyms[XkbGroup1Index] * sizeof(KeySym));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /* step 7: check for all groups identical or all width 1
 | 
						|
     *
 | 
						|
     * Special feature: if group 1 has an explicit type and all other groups
 | 
						|
     * have canonical types with same symbols, we assume it's info lost from
 | 
						|
     * the core replication.
 | 
						|
     */
 | 
						|
    if (nGroups > 1) {
 | 
						|
        Bool sameType, allOneLevel, canonical = TRUE;
 | 
						|
 | 
						|
        allOneLevel = (xkb->map->types[types_inout[0]].num_levels == 1);
 | 
						|
        for (i = 1, sameType = TRUE; (allOneLevel || sameType) && (i < nGroups);
 | 
						|
             i++) {
 | 
						|
            sameType = (sameType &&
 | 
						|
                        (types_inout[i] == types_inout[XkbGroup1Index]));
 | 
						|
            if (allOneLevel)
 | 
						|
                allOneLevel = (xkb->map->types[types_inout[i]].num_levels == 1);
 | 
						|
            if (types_inout[i] > XkbLastRequiredType)
 | 
						|
                canonical = FALSE;
 | 
						|
        }
 | 
						|
        if (((sameType) || canonical) &&
 | 
						|
            (!(protected &
 | 
						|
               (XkbExplicitKeyTypesMask & ~XkbExplicitKeyType1Mask)))) {
 | 
						|
            register int s;
 | 
						|
            Bool identical;
 | 
						|
 | 
						|
            for (i = 1, identical = TRUE; identical && (i < nGroups); i++) {
 | 
						|
                KeySym *syms;
 | 
						|
 | 
						|
                if (nSyms[i] != nSyms[XkbGroup1Index])
 | 
						|
                    identical = FALSE;
 | 
						|
                syms = &xkb_syms_rtrn[XKB_OFFSET(i, 0)];
 | 
						|
                for (s = 0; identical && (s < nSyms[i]); s++) {
 | 
						|
                    if (syms[s] != xkb_syms_rtrn[s])
 | 
						|
                        identical = FALSE;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if (identical)
 | 
						|
                nGroups = 1;
 | 
						|
        }
 | 
						|
        if (allOneLevel && (nGroups > 1)) {
 | 
						|
            KeySym *syms;
 | 
						|
 | 
						|
            syms = &xkb_syms_rtrn[nSyms[XkbGroup1Index]];
 | 
						|
            nSyms[XkbGroup1Index] = 1;
 | 
						|
            for (i = 1; i < nGroups; i++) {
 | 
						|
                xkb_syms_rtrn[i] = syms[0];
 | 
						|
                syms += nSyms[i];
 | 
						|
                nSyms[i] = 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return nGroups;
 | 
						|
}
 | 
						|
 | 
						|
static XkbSymInterpretPtr
 | 
						|
_XkbFindMatchingInterp(XkbDescPtr xkb,
 | 
						|
                       KeySym sym, unsigned int real_mods, unsigned int level)
 | 
						|
{
 | 
						|
    register unsigned i;
 | 
						|
    XkbSymInterpretPtr interp, rtrn;
 | 
						|
    CARD8 mods;
 | 
						|
 | 
						|
    rtrn = NULL;
 | 
						|
    interp = xkb->compat->sym_interpret;
 | 
						|
    for (i = 0; i < xkb->compat->num_si; i++, interp++) {
 | 
						|
        if ((interp->sym == NoSymbol) || (sym == interp->sym)) {
 | 
						|
            int match;
 | 
						|
 | 
						|
            if ((level == 0) || ((interp->match & XkbSI_LevelOneOnly) == 0))
 | 
						|
                mods = real_mods;
 | 
						|
            else
 | 
						|
                mods = 0;
 | 
						|
            switch (interp->match & XkbSI_OpMask) {
 | 
						|
            case XkbSI_NoneOf:
 | 
						|
                match = ((interp->mods & mods) == 0);
 | 
						|
                break;
 | 
						|
            case XkbSI_AnyOfOrNone:
 | 
						|
                match = ((mods == 0) || ((interp->mods & mods) != 0));
 | 
						|
                break;
 | 
						|
            case XkbSI_AnyOf:
 | 
						|
                match = ((interp->mods & mods) != 0);
 | 
						|
                break;
 | 
						|
            case XkbSI_AllOf:
 | 
						|
                match = ((interp->mods & mods) == interp->mods);
 | 
						|
                break;
 | 
						|
            case XkbSI_Exactly:
 | 
						|
                match = (interp->mods == mods);
 | 
						|
                break;
 | 
						|
            default:
 | 
						|
                match = 0;
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            if (match) {
 | 
						|
                if (interp->sym != NoSymbol) {
 | 
						|
                    return interp;
 | 
						|
                }
 | 
						|
                else if (rtrn == NULL) {
 | 
						|
                    rtrn = interp;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return rtrn;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
_XkbAddKeyChange(KeyCode *pFirst, unsigned char *pNum, KeyCode newKey)
 | 
						|
{
 | 
						|
    KeyCode last;
 | 
						|
 | 
						|
    last = (*pFirst) + (*pNum);
 | 
						|
    if (newKey < *pFirst) {
 | 
						|
        *pFirst = newKey;
 | 
						|
        *pNum = (last - newKey) + 1;
 | 
						|
    }
 | 
						|
    else if (newKey > last) {
 | 
						|
        *pNum = (last - *pFirst) + 1;
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
_XkbSetActionKeyMods(XkbDescPtr xkb, XkbAction *act, unsigned mods)
 | 
						|
{
 | 
						|
    unsigned tmp;
 | 
						|
 | 
						|
    switch (act->type) {
 | 
						|
    case XkbSA_SetMods:
 | 
						|
    case XkbSA_LatchMods:
 | 
						|
    case XkbSA_LockMods:
 | 
						|
        if (act->mods.flags & XkbSA_UseModMapMods)
 | 
						|
            act->mods.real_mods = act->mods.mask = mods;
 | 
						|
        if ((tmp = XkbModActionVMods(&act->mods)) != 0) {
 | 
						|
            XkbVirtualModsToReal(xkb, tmp, &tmp);
 | 
						|
            act->mods.mask |= tmp;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    case XkbSA_ISOLock:
 | 
						|
        if (act->iso.flags & XkbSA_UseModMapMods)
 | 
						|
            act->iso.real_mods = act->iso.mask = mods;
 | 
						|
        if ((tmp = XkbModActionVMods(&act->iso)) != 0) {
 | 
						|
            XkbVirtualModsToReal(xkb, tmp, &tmp);
 | 
						|
            act->iso.mask |= tmp;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#define	IBUF_SIZE	8
 | 
						|
 | 
						|
Bool
 | 
						|
XkbApplyCompatMapToKey(XkbDescPtr xkb, KeyCode key, XkbChangesPtr changes)
 | 
						|
{
 | 
						|
    KeySym *syms;
 | 
						|
    unsigned char explicit, mods;
 | 
						|
    XkbSymInterpretPtr *interps, ibuf[IBUF_SIZE];
 | 
						|
    int n, nSyms, found;
 | 
						|
    unsigned changed, tmp;
 | 
						|
 | 
						|
    if ((!xkb) || (!xkb->map) || (!xkb->map->key_sym_map) ||
 | 
						|
        (!xkb->compat) || (!xkb->compat->sym_interpret) ||
 | 
						|
        (key < xkb->min_key_code) || (key > xkb->max_key_code)) {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
    if (((!xkb->server) || (!xkb->server->key_acts)) &&
 | 
						|
        (XkbAllocServerMap(xkb, XkbAllServerInfoMask, 0) != Success)) {
 | 
						|
        return FALSE;
 | 
						|
    }
 | 
						|
    changed = 0;                /* keeps track of what has changed in _this_ call */
 | 
						|
    explicit = xkb->server->explicit[key];
 | 
						|
    if (explicit & XkbExplicitInterpretMask)    /* nothing to do */
 | 
						|
        return TRUE;
 | 
						|
    mods = (xkb->map->modmap ? xkb->map->modmap[key] : 0);
 | 
						|
    nSyms = XkbKeyNumSyms(xkb, key);
 | 
						|
    syms = XkbKeySymsPtr(xkb, key);
 | 
						|
    if (nSyms > IBUF_SIZE) {
 | 
						|
        interps = calloc(nSyms, sizeof(XkbSymInterpretPtr));
 | 
						|
        if (interps == NULL) {
 | 
						|
            interps = ibuf;
 | 
						|
            nSyms = IBUF_SIZE;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        interps = ibuf;
 | 
						|
    }
 | 
						|
    found = 0;
 | 
						|
    for (n = 0; n < nSyms; n++) {
 | 
						|
        unsigned level = (n % XkbKeyGroupsWidth(xkb, key));
 | 
						|
 | 
						|
        interps[n] = NULL;
 | 
						|
        if (syms[n] != NoSymbol) {
 | 
						|
            interps[n] = _XkbFindMatchingInterp(xkb, syms[n], mods, level);
 | 
						|
            if (interps[n] && interps[n]->act.type != XkbSA_NoAction)
 | 
						|
                found++;
 | 
						|
            else
 | 
						|
                interps[n] = NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    /* 1/28/96 (ef) -- XXX! WORKING HERE */
 | 
						|
    if (!found) {
 | 
						|
        if (xkb->server->key_acts[key] != 0) {
 | 
						|
            xkb->server->key_acts[key] = 0;
 | 
						|
            changed |= XkbKeyActionsMask;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        XkbAction *pActs;
 | 
						|
        unsigned int new_vmodmask;
 | 
						|
 | 
						|
        changed |= XkbKeyActionsMask;
 | 
						|
        pActs = XkbResizeKeyActions(xkb, key, nSyms);
 | 
						|
        if (!pActs) {
 | 
						|
            if (nSyms > IBUF_SIZE)
 | 
						|
                free(interps);
 | 
						|
            return FALSE;
 | 
						|
        }
 | 
						|
        new_vmodmask = 0;
 | 
						|
        for (n = 0; n < nSyms; n++) {
 | 
						|
            if (interps[n]) {
 | 
						|
                unsigned effMods;
 | 
						|
 | 
						|
                pActs[n] = *((XkbAction *) &interps[n]->act);
 | 
						|
                if ((n == 0) || ((interps[n]->match & XkbSI_LevelOneOnly) == 0)) {
 | 
						|
                    effMods = mods;
 | 
						|
                    if (interps[n]->virtual_mod != XkbNoModifier)
 | 
						|
                        new_vmodmask |= (1 << interps[n]->virtual_mod);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                    effMods = 0;
 | 
						|
                _XkbSetActionKeyMods(xkb, &pActs[n], effMods);
 | 
						|
            }
 | 
						|
            else
 | 
						|
                pActs[n].type = XkbSA_NoAction;
 | 
						|
        }
 | 
						|
        if (((explicit & XkbExplicitVModMapMask) == 0) &&
 | 
						|
            (xkb->server->vmodmap[key] != new_vmodmask)) {
 | 
						|
            changed |= XkbVirtualModMapMask;
 | 
						|
            xkb->server->vmodmap[key] = new_vmodmask;
 | 
						|
        }
 | 
						|
        if (interps[0]) {
 | 
						|
            if ((interps[0]->flags & XkbSI_LockingKey) &&
 | 
						|
                ((explicit & XkbExplicitBehaviorMask) == 0)) {
 | 
						|
                xkb->server->behaviors[key].type = XkbKB_Lock;
 | 
						|
                changed |= XkbKeyBehaviorsMask;
 | 
						|
            }
 | 
						|
            if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
 | 
						|
                CARD8 old;
 | 
						|
 | 
						|
                old = BitIsOn(xkb->ctrls->per_key_repeat, key);
 | 
						|
                if (interps[0]->flags & XkbSI_AutoRepeat)
 | 
						|
                    SetBit(xkb->ctrls->per_key_repeat, key);
 | 
						|
                else
 | 
						|
                    ClearBit(xkb->ctrls->per_key_repeat, key);
 | 
						|
                if (changes && old != BitIsOn(xkb->ctrls->per_key_repeat, key))
 | 
						|
                    changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if ((!found) || (interps[0] == NULL)) {
 | 
						|
        if (((explicit & XkbExplicitAutoRepeatMask) == 0) && (xkb->ctrls)) {
 | 
						|
            CARD8 old;
 | 
						|
 | 
						|
            old = BitIsOn(xkb->ctrls->per_key_repeat, key);
 | 
						|
            SetBit(xkb->ctrls->per_key_repeat, key);
 | 
						|
            if (changes && (old != BitIsOn(xkb->ctrls->per_key_repeat, key)))
 | 
						|
                changes->ctrls.changed_ctrls |= XkbPerKeyRepeatMask;
 | 
						|
        }
 | 
						|
        if (((explicit & XkbExplicitBehaviorMask) == 0) &&
 | 
						|
            (xkb->server->behaviors[key].type == XkbKB_Lock)) {
 | 
						|
            xkb->server->behaviors[key].type = XkbKB_Default;
 | 
						|
            changed |= XkbKeyBehaviorsMask;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (changes) {
 | 
						|
        XkbMapChangesPtr mc;
 | 
						|
 | 
						|
        mc = &changes->map;
 | 
						|
        tmp = (changed & mc->changed);
 | 
						|
        if (tmp & XkbKeyActionsMask)
 | 
						|
            _XkbAddKeyChange(&mc->first_key_act, &mc->num_key_acts, key);
 | 
						|
        else if (changed & XkbKeyActionsMask) {
 | 
						|
            mc->changed |= XkbKeyActionsMask;
 | 
						|
            mc->first_key_act = key;
 | 
						|
            mc->num_key_acts = 1;
 | 
						|
        }
 | 
						|
        if (tmp & XkbKeyBehaviorsMask) {
 | 
						|
            _XkbAddKeyChange(&mc->first_key_behavior, &mc->num_key_behaviors,
 | 
						|
                             key);
 | 
						|
        }
 | 
						|
        else if (changed & XkbKeyBehaviorsMask) {
 | 
						|
            mc->changed |= XkbKeyBehaviorsMask;
 | 
						|
            mc->first_key_behavior = key;
 | 
						|
            mc->num_key_behaviors = 1;
 | 
						|
        }
 | 
						|
        if (tmp & XkbVirtualModMapMask)
 | 
						|
            _XkbAddKeyChange(&mc->first_vmodmap_key, &mc->num_vmodmap_keys,
 | 
						|
                             key);
 | 
						|
        else if (changed & XkbVirtualModMapMask) {
 | 
						|
            mc->changed |= XkbVirtualModMapMask;
 | 
						|
            mc->first_vmodmap_key = key;
 | 
						|
            mc->num_vmodmap_keys = 1;
 | 
						|
        }
 | 
						|
        mc->changed |= changed;
 | 
						|
    }
 | 
						|
    if (interps != ibuf)
 | 
						|
        free(interps);
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
Status
 | 
						|
XkbChangeTypesOfKey(XkbDescPtr xkb,
 | 
						|
                    int key,
 | 
						|
                    int nGroups,
 | 
						|
                    unsigned groups, int *newTypesIn, XkbMapChangesPtr changes)
 | 
						|
{
 | 
						|
    XkbKeyTypePtr pOldType, pNewType;
 | 
						|
    register int i;
 | 
						|
    int width, nOldGroups, oldWidth, newTypes[XkbNumKbdGroups];
 | 
						|
 | 
						|
    if ((!xkb) || (!XkbKeycodeInRange(xkb, key)) || (!xkb->map) ||
 | 
						|
        (!xkb->map->types) || (!newTypesIn) ||
 | 
						|
        ((groups & XkbAllGroupsMask) == 0) || (nGroups > XkbNumKbdGroups)) {
 | 
						|
        return BadMatch;
 | 
						|
    }
 | 
						|
    if (nGroups == 0) {
 | 
						|
        for (i = 0; i < XkbNumKbdGroups; i++) {
 | 
						|
            xkb->map->key_sym_map[key].kt_index[i] = XkbOneLevelIndex;
 | 
						|
        }
 | 
						|
        i = xkb->map->key_sym_map[key].group_info;
 | 
						|
        i = XkbSetNumGroups(i, 0);
 | 
						|
        xkb->map->key_sym_map[key].group_info = i;
 | 
						|
        XkbResizeKeySyms(xkb, key, 0);
 | 
						|
        return Success;
 | 
						|
    }
 | 
						|
 | 
						|
    nOldGroups = XkbKeyNumGroups(xkb, key);
 | 
						|
    oldWidth = XkbKeyGroupsWidth(xkb, key);
 | 
						|
    for (width = i = 0; i < nGroups; i++) {
 | 
						|
        if (groups & (1 << i))
 | 
						|
            newTypes[i] = newTypesIn[i];
 | 
						|
        else if (i < nOldGroups)
 | 
						|
            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, i);
 | 
						|
        else if (nOldGroups > 0)
 | 
						|
            newTypes[i] = XkbKeyKeyTypeIndex(xkb, key, XkbGroup1Index);
 | 
						|
        else
 | 
						|
            newTypes[i] = XkbTwoLevelIndex;
 | 
						|
        if (newTypes[i] > xkb->map->num_types)
 | 
						|
            return BadMatch;
 | 
						|
        pNewType = &xkb->map->types[newTypes[i]];
 | 
						|
        if (pNewType->num_levels > width)
 | 
						|
            width = pNewType->num_levels;
 | 
						|
    }
 | 
						|
    if ((xkb->ctrls) && (nGroups > xkb->ctrls->num_groups))
 | 
						|
        xkb->ctrls->num_groups = nGroups;
 | 
						|
    if ((width != oldWidth) || (nGroups != nOldGroups)) {
 | 
						|
        KeySym oldSyms[XkbMaxSymsPerKey], *pSyms;
 | 
						|
        int nCopy;
 | 
						|
 | 
						|
        if (nOldGroups == 0) {
 | 
						|
            pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
 | 
						|
            if (pSyms != NULL) {
 | 
						|
                i = xkb->map->key_sym_map[key].group_info;
 | 
						|
                i = XkbSetNumGroups(i, nGroups);
 | 
						|
                xkb->map->key_sym_map[key].group_info = i;
 | 
						|
                xkb->map->key_sym_map[key].width = width;
 | 
						|
                for (i = 0; i < nGroups; i++) {
 | 
						|
                    xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
 | 
						|
                }
 | 
						|
                return Success;
 | 
						|
            }
 | 
						|
            return BadAlloc;
 | 
						|
        }
 | 
						|
        pSyms = XkbKeySymsPtr(xkb, key);
 | 
						|
        memcpy(oldSyms, pSyms, XkbKeyNumSyms(xkb, key) * sizeof(KeySym));
 | 
						|
        pSyms = XkbResizeKeySyms(xkb, key, width * nGroups);
 | 
						|
        if (pSyms == NULL)
 | 
						|
            return BadAlloc;
 | 
						|
        memset(pSyms, 0, width * nGroups * sizeof(KeySym));
 | 
						|
        for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
 | 
						|
            pOldType = XkbKeyKeyType(xkb, key, i);
 | 
						|
            pNewType = &xkb->map->types[newTypes[i]];
 | 
						|
            if (pNewType->num_levels > pOldType->num_levels)
 | 
						|
                nCopy = pOldType->num_levels;
 | 
						|
            else
 | 
						|
                nCopy = pNewType->num_levels;
 | 
						|
            memcpy(&pSyms[i * width], &oldSyms[i * oldWidth],
 | 
						|
                   nCopy * sizeof(KeySym));
 | 
						|
        }
 | 
						|
        if (XkbKeyHasActions(xkb, key)) {
 | 
						|
            XkbAction oldActs[XkbMaxSymsPerKey], *pActs;
 | 
						|
 | 
						|
            pActs = XkbKeyActionsPtr(xkb, key);
 | 
						|
            memcpy(oldActs, pActs, XkbKeyNumSyms(xkb, key) * sizeof(XkbAction));
 | 
						|
            pActs = XkbResizeKeyActions(xkb, key, width * nGroups);
 | 
						|
            if (pActs == NULL)
 | 
						|
                return BadAlloc;
 | 
						|
            memset(pActs, 0, width * nGroups * sizeof(XkbAction));
 | 
						|
            for (i = 0; (i < nGroups) && (i < nOldGroups); i++) {
 | 
						|
                pOldType = XkbKeyKeyType(xkb, key, i);
 | 
						|
                pNewType = &xkb->map->types[newTypes[i]];
 | 
						|
                if (pNewType->num_levels > pOldType->num_levels)
 | 
						|
                    nCopy = pOldType->num_levels;
 | 
						|
                else
 | 
						|
                    nCopy = pNewType->num_levels;
 | 
						|
                memcpy(&pActs[i * width], &oldActs[i * oldWidth],
 | 
						|
                       nCopy * sizeof(XkbAction));
 | 
						|
            }
 | 
						|
        }
 | 
						|
        i = xkb->map->key_sym_map[key].group_info;
 | 
						|
        i = XkbSetNumGroups(i, nGroups);
 | 
						|
        xkb->map->key_sym_map[key].group_info = i;
 | 
						|
        xkb->map->key_sym_map[key].width = width;
 | 
						|
    }
 | 
						|
    width = 0;
 | 
						|
    for (i = 0; i < nGroups; i++) {
 | 
						|
        xkb->map->key_sym_map[key].kt_index[i] = newTypes[i];
 | 
						|
        if (xkb->map->types[newTypes[i]].num_levels > width)
 | 
						|
            width = xkb->map->types[newTypes[i]].num_levels;
 | 
						|
    }
 | 
						|
    xkb->map->key_sym_map[key].width = width;
 | 
						|
    if (changes != NULL) {
 | 
						|
        if (changes->changed & XkbKeySymsMask) {
 | 
						|
            _XkbAddKeyChange(&changes->first_key_sym, &changes->num_key_syms,
 | 
						|
                             key);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            changes->changed |= XkbKeySymsMask;
 | 
						|
            changes->first_key_sym = key;
 | 
						|
            changes->num_key_syms = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return Success;
 | 
						|
}
 | 
						|
 | 
						|
/***====================================================================***/
 | 
						|
 | 
						|
Bool
 | 
						|
XkbVirtualModsToReal(XkbDescPtr xkb, unsigned virtual_mask, unsigned *mask_rtrn)
 | 
						|
{
 | 
						|
    register int i, bit;
 | 
						|
    register unsigned mask;
 | 
						|
 | 
						|
    if (xkb == NULL)
 | 
						|
        return FALSE;
 | 
						|
    if (virtual_mask == 0) {
 | 
						|
        *mask_rtrn = 0;
 | 
						|
        return TRUE;
 | 
						|
    }
 | 
						|
    if (xkb->server == NULL)
 | 
						|
        return FALSE;
 | 
						|
    for (i = mask = 0, bit = 1; i < XkbNumVirtualMods; i++, bit <<= 1) {
 | 
						|
        if (virtual_mask & bit)
 | 
						|
            mask |= xkb->server->vmods[i];
 | 
						|
    }
 | 
						|
    *mask_rtrn = mask;
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/***====================================================================***/
 | 
						|
 | 
						|
static Bool
 | 
						|
XkbUpdateActionVirtualMods(XkbDescPtr xkb, XkbAction *act, unsigned changed)
 | 
						|
{
 | 
						|
    unsigned int tmp;
 | 
						|
 | 
						|
    switch (act->type) {
 | 
						|
    case XkbSA_SetMods:
 | 
						|
    case XkbSA_LatchMods:
 | 
						|
    case XkbSA_LockMods:
 | 
						|
        if (((tmp = XkbModActionVMods(&act->mods)) & changed) != 0) {
 | 
						|
            XkbVirtualModsToReal(xkb, tmp, &tmp);
 | 
						|
            act->mods.mask = act->mods.real_mods;
 | 
						|
            act->mods.mask |= tmp;
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    case XkbSA_ISOLock:
 | 
						|
        if ((((tmp = XkbModActionVMods(&act->iso)) != 0) & changed) != 0) {
 | 
						|
            XkbVirtualModsToReal(xkb, tmp, &tmp);
 | 
						|
            act->iso.mask = act->iso.real_mods;
 | 
						|
            act->iso.mask |= tmp;
 | 
						|
            return TRUE;
 | 
						|
        }
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
XkbUpdateKeyTypeVirtualMods(XkbDescPtr xkb,
 | 
						|
                            XkbKeyTypePtr type,
 | 
						|
                            unsigned int changed, XkbChangesPtr changes)
 | 
						|
{
 | 
						|
    register unsigned int i;
 | 
						|
    unsigned int mask;
 | 
						|
 | 
						|
    XkbVirtualModsToReal(xkb, type->mods.vmods, &mask);
 | 
						|
    type->mods.mask = type->mods.real_mods | mask;
 | 
						|
    if ((type->map_count > 0) && (type->mods.vmods != 0)) {
 | 
						|
        XkbKTMapEntryPtr entry;
 | 
						|
 | 
						|
        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
 | 
						|
            if (entry->mods.vmods != 0) {
 | 
						|
                XkbVirtualModsToReal(xkb, entry->mods.vmods, &mask);
 | 
						|
                entry->mods.mask = entry->mods.real_mods | mask;
 | 
						|
                /* entry is active if vmods are bound */
 | 
						|
                entry->active = (mask != 0);
 | 
						|
            }
 | 
						|
            else
 | 
						|
                entry->active = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (changes) {
 | 
						|
        int type_ndx;
 | 
						|
 | 
						|
        type_ndx = type - xkb->map->types;
 | 
						|
        if ((type_ndx < 0) || (type_ndx > xkb->map->num_types))
 | 
						|
            return;
 | 
						|
        if (changes->map.changed & XkbKeyTypesMask) {
 | 
						|
            int last;
 | 
						|
 | 
						|
            last = changes->map.first_type + changes->map.num_types - 1;
 | 
						|
            if (type_ndx < changes->map.first_type) {
 | 
						|
                changes->map.first_type = type_ndx;
 | 
						|
                changes->map.num_types = (last - type_ndx) + 1;
 | 
						|
            }
 | 
						|
            else if (type_ndx > last) {
 | 
						|
                changes->map.num_types =
 | 
						|
                    (type_ndx - changes->map.first_type) + 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            changes->map.changed |= XkbKeyTypesMask;
 | 
						|
            changes->map.first_type = type_ndx;
 | 
						|
            changes->map.num_types = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
Bool
 | 
						|
XkbApplyVirtualModChanges(XkbDescPtr xkb, unsigned changed,
 | 
						|
                          XkbChangesPtr changes)
 | 
						|
{
 | 
						|
    register int i;
 | 
						|
    unsigned int checkState = 0;
 | 
						|
 | 
						|
    if ((!xkb) || (!xkb->map) || (changed == 0))
 | 
						|
        return FALSE;
 | 
						|
    for (i = 0; i < xkb->map->num_types; i++) {
 | 
						|
        if (xkb->map->types[i].mods.vmods & changed)
 | 
						|
            XkbUpdateKeyTypeVirtualMods(xkb, &xkb->map->types[i], changed,
 | 
						|
                                        changes);
 | 
						|
    }
 | 
						|
    if (changed & xkb->ctrls->internal.vmods) {
 | 
						|
        unsigned int newMask;
 | 
						|
 | 
						|
        XkbVirtualModsToReal(xkb, xkb->ctrls->internal.vmods, &newMask);
 | 
						|
        newMask |= xkb->ctrls->internal.real_mods;
 | 
						|
        if (xkb->ctrls->internal.mask != newMask) {
 | 
						|
            xkb->ctrls->internal.mask = newMask;
 | 
						|
            if (changes) {
 | 
						|
                changes->ctrls.changed_ctrls |= XkbInternalModsMask;
 | 
						|
                checkState = TRUE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (changed & xkb->ctrls->ignore_lock.vmods) {
 | 
						|
        unsigned int newMask;
 | 
						|
 | 
						|
        XkbVirtualModsToReal(xkb, xkb->ctrls->ignore_lock.vmods, &newMask);
 | 
						|
        newMask |= xkb->ctrls->ignore_lock.real_mods;
 | 
						|
        if (xkb->ctrls->ignore_lock.mask != newMask) {
 | 
						|
            xkb->ctrls->ignore_lock.mask = newMask;
 | 
						|
            if (changes) {
 | 
						|
                changes->ctrls.changed_ctrls |= XkbIgnoreLockModsMask;
 | 
						|
                checkState = TRUE;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (xkb->indicators != NULL) {
 | 
						|
        XkbIndicatorMapPtr map;
 | 
						|
 | 
						|
        map = &xkb->indicators->maps[0];
 | 
						|
        for (i = 0; i < XkbNumIndicators; i++, map++) {
 | 
						|
            if (map->mods.vmods & changed) {
 | 
						|
                unsigned int newMask;
 | 
						|
 | 
						|
                XkbVirtualModsToReal(xkb, map->mods.vmods, &newMask);
 | 
						|
                newMask |= map->mods.real_mods;
 | 
						|
                if (newMask != map->mods.mask) {
 | 
						|
                    map->mods.mask = newMask;
 | 
						|
                    if (changes) {
 | 
						|
                        changes->indicators.map_changes |= (1 << i);
 | 
						|
                        checkState = TRUE;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (xkb->compat != NULL) {
 | 
						|
        XkbCompatMapPtr compat;
 | 
						|
 | 
						|
        compat = xkb->compat;
 | 
						|
        for (i = 0; i < XkbNumKbdGroups; i++) {
 | 
						|
            unsigned int newMask;
 | 
						|
 | 
						|
            XkbVirtualModsToReal(xkb, compat->groups[i].vmods, &newMask);
 | 
						|
            newMask |= compat->groups[i].real_mods;
 | 
						|
            if (compat->groups[i].mask != newMask) {
 | 
						|
                compat->groups[i].mask = newMask;
 | 
						|
                if (changes) {
 | 
						|
                    changes->compat.changed_groups |= (1 << i);
 | 
						|
                    checkState = TRUE;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (xkb->map && xkb->server) {
 | 
						|
        int highChange = 0, lowChange = -1;
 | 
						|
 | 
						|
        for (i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
 | 
						|
            if (XkbKeyHasActions(xkb, i)) {
 | 
						|
                register XkbAction *pAct;
 | 
						|
                register int n;
 | 
						|
 | 
						|
                pAct = XkbKeyActionsPtr(xkb, i);
 | 
						|
                for (n = XkbKeyNumActions(xkb, i); n > 0; n--, pAct++) {
 | 
						|
                    if ((pAct->type != XkbSA_NoAction) &&
 | 
						|
                        XkbUpdateActionVirtualMods(xkb, pAct, changed)) {
 | 
						|
                        if (lowChange < 0)
 | 
						|
                            lowChange = i;
 | 
						|
                        highChange = i;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (changes && (lowChange > 0)) {       /* something changed */
 | 
						|
            if (changes->map.changed & XkbKeyActionsMask) {
 | 
						|
                int last;
 | 
						|
 | 
						|
                if (changes->map.first_key_act < lowChange)
 | 
						|
                    lowChange = changes->map.first_key_act;
 | 
						|
                last =
 | 
						|
                    changes->map.first_key_act + changes->map.num_key_acts - 1;
 | 
						|
                if (last > highChange)
 | 
						|
                    highChange = last;
 | 
						|
            }
 | 
						|
            changes->map.changed |= XkbKeyActionsMask;
 | 
						|
            changes->map.first_key_act = lowChange;
 | 
						|
            changes->map.num_key_acts = (highChange - lowChange) + 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return checkState;
 | 
						|
}
 |