876 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			876 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.
 | |
| 
 | |
| ********************************************************/
 | |
| 
 | |
| #include <dix-config.h>
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <X11/X.h>
 | |
| #include <X11/Xproto.h>
 | |
| #include "misc.h"
 | |
| #include "inputstr.h"
 | |
| #include <X11/keysym.h>
 | |
| #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) || (xkb->server == NULL)) {
 | |
|         *mask_rtrn = 0;
 | |
|         return FALSE;
 | |
|     }
 | |
|     if (virtual_mask == 0) {
 | |
|         *mask_rtrn = 0;
 | |
|         return TRUE;
 | |
|     }
 | |
|     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;
 | |
| }
 |