841 lines
24 KiB
C
841 lines
24 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>
|
|
#elif defined(HAVE_CONFIG_H)
|
|
#include <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;
|
|
}
|