980 lines
27 KiB
C
980 lines
27 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>
|
|
#define NEED_EVENTS
|
|
#define NEED_REPLIES
|
|
#include <X11/Xproto.h>
|
|
#include "misc.h"
|
|
#include "inputstr.h"
|
|
#include <X11/keysym.h>
|
|
#define XKBSRV_NEED_FILE_FUNCS
|
|
#include <X11/extensions/XKBsrv.h>
|
|
|
|
/***====================================================================***/
|
|
|
|
Status
|
|
XkbAllocClientMap(XkbDescPtr xkb,unsigned which,unsigned nTotalTypes)
|
|
{
|
|
register int i;
|
|
XkbClientMapPtr map;
|
|
|
|
if ((xkb==NULL)||((nTotalTypes>0)&&(nTotalTypes<XkbNumRequiredTypes)))
|
|
return BadValue;
|
|
if ((which&XkbKeySymsMask)&&
|
|
((!XkbIsLegalKeycode(xkb->min_key_code))||
|
|
(!XkbIsLegalKeycode(xkb->max_key_code))||
|
|
(xkb->max_key_code<xkb->min_key_code))) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"bad keycode (%d,%d) in XkbAllocClientMap\n",
|
|
xkb->min_key_code,xkb->max_key_code);
|
|
#endif
|
|
return BadValue;
|
|
}
|
|
|
|
if (xkb->map==NULL) {
|
|
map= _XkbTypedCalloc(1,XkbClientMapRec);
|
|
if (map==NULL)
|
|
return BadAlloc;
|
|
xkb->map= map;
|
|
}
|
|
else map= xkb->map;
|
|
|
|
if ((which&XkbKeyTypesMask)&&(nTotalTypes>0)) {
|
|
if (map->types==NULL) {
|
|
map->types= _XkbTypedCalloc(nTotalTypes,XkbKeyTypeRec);
|
|
if (map->types==NULL)
|
|
return BadAlloc;
|
|
map->num_types= 0;
|
|
map->size_types= nTotalTypes;
|
|
}
|
|
else if (map->size_types<nTotalTypes) {
|
|
XkbKeyTypeRec *prev_types = map->types;
|
|
|
|
map->types= _XkbTypedRealloc(map->types,nTotalTypes,XkbKeyTypeRec);
|
|
if (map->types==NULL) {
|
|
_XkbFree(prev_types);
|
|
map->num_types= map->size_types= 0;
|
|
return BadAlloc;
|
|
}
|
|
map->size_types= nTotalTypes;
|
|
bzero(&map->types[map->num_types],
|
|
((map->size_types-map->num_types)*sizeof(XkbKeyTypeRec)));
|
|
}
|
|
}
|
|
if (which&XkbKeySymsMask) {
|
|
int nKeys= XkbNumKeys(xkb);
|
|
if (map->syms==NULL) {
|
|
map->size_syms= (nKeys*15)/10;
|
|
map->syms= _XkbTypedCalloc(map->size_syms,KeySym);
|
|
if (!map->syms) {
|
|
map->size_syms= 0;
|
|
return BadAlloc;
|
|
}
|
|
map->num_syms= 1;
|
|
map->syms[0]= NoSymbol;
|
|
}
|
|
if (map->key_sym_map==NULL) {
|
|
i= xkb->max_key_code+1;
|
|
map->key_sym_map= _XkbTypedCalloc(i,XkbSymMapRec);
|
|
if (map->key_sym_map==NULL)
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
if (which&XkbModifierMapMask) {
|
|
if ((!XkbIsLegalKeycode(xkb->min_key_code))||
|
|
(!XkbIsLegalKeycode(xkb->max_key_code))||
|
|
(xkb->max_key_code<xkb->min_key_code))
|
|
return BadMatch;
|
|
if (map->modmap==NULL) {
|
|
i= xkb->max_key_code+1;
|
|
map->modmap= _XkbTypedCalloc(i,unsigned char);
|
|
if (map->modmap==NULL)
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
Status
|
|
XkbAllocServerMap(XkbDescPtr xkb,unsigned which,unsigned nNewActions)
|
|
{
|
|
register int i;
|
|
XkbServerMapPtr map;
|
|
|
|
if (xkb==NULL)
|
|
return BadMatch;
|
|
if (xkb->server==NULL) {
|
|
map= _XkbTypedCalloc(1,XkbServerMapRec);
|
|
if (map==NULL)
|
|
return BadAlloc;
|
|
for (i=0;i<XkbNumVirtualMods;i++) {
|
|
map->vmods[i]= XkbNoModifierMask;
|
|
}
|
|
xkb->server= map;
|
|
}
|
|
else map= xkb->server;
|
|
if (which&XkbExplicitComponentsMask) {
|
|
if ((!XkbIsLegalKeycode(xkb->min_key_code))||
|
|
(!XkbIsLegalKeycode(xkb->max_key_code))||
|
|
(xkb->max_key_code<xkb->min_key_code))
|
|
return BadMatch;
|
|
if (map->explicit==NULL) {
|
|
i= xkb->max_key_code+1;
|
|
map->explicit= _XkbTypedCalloc(i,unsigned char);
|
|
if (map->explicit==NULL)
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
if (which&XkbKeyActionsMask) {
|
|
if ((!XkbIsLegalKeycode(xkb->min_key_code))||
|
|
(!XkbIsLegalKeycode(xkb->max_key_code))||
|
|
(xkb->max_key_code<xkb->min_key_code))
|
|
return BadMatch;
|
|
if (nNewActions<1)
|
|
nNewActions= 1;
|
|
if (map->acts==NULL) {
|
|
map->acts= _XkbTypedCalloc((nNewActions+1),XkbAction);
|
|
if (map->acts==NULL)
|
|
return BadAlloc;
|
|
map->num_acts= 1;
|
|
map->size_acts= nNewActions+1;
|
|
}
|
|
else if ((map->size_acts-map->num_acts)<nNewActions) {
|
|
unsigned need;
|
|
XkbAction *prev_acts = map->acts;
|
|
need= map->num_acts+nNewActions;
|
|
map->acts= _XkbTypedRealloc(map->acts,need,XkbAction);
|
|
if (map->acts==NULL) {
|
|
_XkbFree(prev_acts);
|
|
map->num_acts= map->size_acts= 0;
|
|
return BadAlloc;
|
|
}
|
|
map->size_acts= need;
|
|
bzero(&map->acts[map->num_acts],
|
|
((map->size_acts-map->num_acts)*sizeof(XkbAction)));
|
|
}
|
|
if (map->key_acts==NULL) {
|
|
i= xkb->max_key_code+1;
|
|
map->key_acts= _XkbTypedCalloc(i,unsigned short);
|
|
if (map->key_acts==NULL)
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
if (which&XkbKeyBehaviorsMask) {
|
|
if ((!XkbIsLegalKeycode(xkb->min_key_code))||
|
|
(!XkbIsLegalKeycode(xkb->max_key_code))||
|
|
(xkb->max_key_code<xkb->min_key_code))
|
|
return BadMatch;
|
|
if (map->behaviors==NULL) {
|
|
i= xkb->max_key_code+1;
|
|
map->behaviors= _XkbTypedCalloc(i,XkbBehavior);
|
|
if (map->behaviors==NULL)
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
if (which&XkbVirtualModMapMask) {
|
|
if ((!XkbIsLegalKeycode(xkb->min_key_code))||
|
|
(!XkbIsLegalKeycode(xkb->max_key_code))||
|
|
(xkb->max_key_code<xkb->min_key_code))
|
|
return BadMatch;
|
|
if (map->vmodmap==NULL) {
|
|
i= xkb->max_key_code+1;
|
|
map->vmodmap= _XkbTypedCalloc(i,unsigned short);
|
|
if (map->vmodmap==NULL)
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
Status
|
|
XkbCopyKeyType(XkbKeyTypePtr from,XkbKeyTypePtr into)
|
|
{
|
|
if ((!from)||(!into))
|
|
return BadMatch;
|
|
if (into->map) {
|
|
_XkbFree(into->map);
|
|
into->map= NULL;
|
|
}
|
|
if (into->preserve) {
|
|
_XkbFree(into->preserve);
|
|
into->preserve= NULL;
|
|
}
|
|
if (into->level_names) {
|
|
_XkbFree(into->level_names);
|
|
into->level_names= NULL;
|
|
}
|
|
*into= *from;
|
|
if ((from->map)&&(into->map_count>0)) {
|
|
into->map= _XkbTypedCalloc(into->map_count,XkbKTMapEntryRec);
|
|
if (!into->map)
|
|
return BadAlloc;
|
|
memcpy(into->map,from->map,into->map_count*sizeof(XkbKTMapEntryRec));
|
|
}
|
|
if ((from->preserve)&&(into->map_count>0)) {
|
|
into->preserve= _XkbTypedCalloc(into->map_count,XkbModsRec);
|
|
if (!into->preserve)
|
|
return BadAlloc;
|
|
memcpy(into->preserve,from->preserve,
|
|
into->map_count*sizeof(XkbModsRec));
|
|
}
|
|
if ((from->level_names)&&(into->num_levels>0)) {
|
|
into->level_names= _XkbTypedCalloc(into->num_levels,Atom);
|
|
if (!into->level_names)
|
|
return BadAlloc;
|
|
memcpy(into->level_names,from->level_names,
|
|
into->num_levels*sizeof(Atom));
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
Status
|
|
XkbCopyKeyTypes(XkbKeyTypePtr from,XkbKeyTypePtr into,int num_types)
|
|
{
|
|
register int i,rtrn;
|
|
|
|
if ((!from)||(!into)||(num_types<0))
|
|
return BadMatch;
|
|
for (i=0;i<num_types;i++) {
|
|
if ((rtrn= XkbCopyKeyType(from++,into++))!=Success)
|
|
return rtrn;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
XkbKeyTypePtr
|
|
XkbAddKeyType( XkbDescPtr xkb,
|
|
Atom name,
|
|
int map_count,
|
|
Bool want_preserve,
|
|
int num_lvls)
|
|
{
|
|
register int i;
|
|
unsigned tmp;
|
|
XkbKeyTypePtr type;
|
|
XkbClientMapPtr map;
|
|
|
|
if ((!xkb)||(num_lvls<1))
|
|
return NULL;
|
|
map= xkb->map;
|
|
if ((map)&&(map->types)) {
|
|
for (i=0;i<map->num_types;i++) {
|
|
if (map->types[i].name==name) {
|
|
Status status;
|
|
status=XkbResizeKeyType(xkb,i,map_count,want_preserve,num_lvls);
|
|
return (status==Success?&map->types[i]:NULL);
|
|
}
|
|
}
|
|
}
|
|
if ((!map)||(!map->types)||(!map->num_types<XkbNumRequiredTypes)) {
|
|
tmp= XkbNumRequiredTypes+1;
|
|
if (XkbAllocClientMap(xkb,XkbKeyTypesMask,tmp)!=Success)
|
|
return NULL;
|
|
map = xkb->map;
|
|
tmp= 0;
|
|
if (map->num_types<=XkbKeypadIndex)
|
|
tmp|= XkbKeypadMask;
|
|
if (map->num_types<=XkbAlphabeticIndex)
|
|
tmp|= XkbAlphabeticMask;
|
|
if (map->num_types<=XkbTwoLevelIndex)
|
|
tmp|= XkbTwoLevelMask;
|
|
if (map->num_types<=XkbOneLevelIndex)
|
|
tmp|= XkbOneLevelMask;
|
|
if (XkbInitCanonicalKeyTypes(xkb,tmp,XkbNoModifier)==Success) {
|
|
for (i=0;i<map->num_types;i++) {
|
|
Status status;
|
|
if (map->types[i].name!=name)
|
|
continue;
|
|
status=XkbResizeKeyType(xkb,i,map_count,want_preserve,num_lvls);
|
|
return (status==Success?&map->types[i]:NULL);
|
|
}
|
|
}
|
|
}
|
|
if ((map->num_types<=map->size_types)&&
|
|
(XkbAllocClientMap(xkb,XkbKeyTypesMask,map->num_types+1)!=Success)) {
|
|
return NULL;
|
|
}
|
|
type= &map->types[map->num_types];
|
|
map->num_types++;
|
|
bzero((char *)type,sizeof(XkbKeyTypeRec));
|
|
type->num_levels= num_lvls;
|
|
type->map_count= map_count;
|
|
type->name= name;
|
|
if (map_count>0) {
|
|
type->map= _XkbTypedCalloc(map_count,XkbKTMapEntryRec);
|
|
if (!type->map) {
|
|
map->num_types--;
|
|
return NULL;
|
|
}
|
|
if (want_preserve) {
|
|
type->preserve= _XkbTypedCalloc(map_count,XkbModsRec);
|
|
if (!type->preserve) {
|
|
_XkbFree(type->map);
|
|
map->num_types--;
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
return type;
|
|
}
|
|
|
|
Status
|
|
XkbResizeKeyType( XkbDescPtr xkb,
|
|
int type_ndx,
|
|
int map_count,
|
|
Bool want_preserve,
|
|
int new_num_lvls)
|
|
{
|
|
XkbKeyTypePtr type;
|
|
KeyCode matchingKeys[XkbMaxKeyCount],nMatchingKeys;
|
|
|
|
if ((type_ndx<0)||(type_ndx>=xkb->map->num_types)||(map_count<0)||
|
|
(new_num_lvls<1))
|
|
return BadValue;
|
|
switch (type_ndx) {
|
|
case XkbOneLevelIndex:
|
|
if (new_num_lvls!=1)
|
|
return BadMatch;
|
|
break;
|
|
case XkbTwoLevelIndex:
|
|
case XkbAlphabeticIndex:
|
|
case XkbKeypadIndex:
|
|
if (new_num_lvls!=2)
|
|
return BadMatch;
|
|
break;
|
|
}
|
|
type= &xkb->map->types[type_ndx];
|
|
if (map_count==0) {
|
|
if (type->map!=NULL)
|
|
_XkbFree(type->map);
|
|
type->map= NULL;
|
|
if (type->preserve!=NULL)
|
|
_XkbFree(type->preserve);
|
|
type->preserve= NULL;
|
|
type->map_count= 0;
|
|
}
|
|
else {
|
|
XkbKTMapEntryRec *prev_map = type->map;
|
|
|
|
if ((map_count>type->map_count)||(type->map==NULL))
|
|
type->map=_XkbTypedRealloc(type->map,map_count,XkbKTMapEntryRec);
|
|
if (!type->map) {
|
|
if (prev_map)
|
|
_XkbFree(prev_map);
|
|
return BadAlloc;
|
|
}
|
|
if (want_preserve) {
|
|
XkbModsRec *prev_preserve = type->preserve;
|
|
|
|
if ((map_count>type->map_count)||(type->preserve==NULL)) {
|
|
type->preserve= _XkbTypedRealloc(type->preserve,map_count,
|
|
XkbModsRec);
|
|
}
|
|
if (!type->preserve) {
|
|
if (prev_preserve)
|
|
_XkbFree(prev_preserve);
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
else if (type->preserve!=NULL) {
|
|
_XkbFree(type->preserve);
|
|
type->preserve= NULL;
|
|
}
|
|
type->map_count= map_count;
|
|
}
|
|
|
|
if ((new_num_lvls>type->num_levels)||(type->level_names==NULL)) {
|
|
Atom * prev_level_names = type->level_names;
|
|
|
|
type->level_names=_XkbTypedRealloc(type->level_names,new_num_lvls,Atom);
|
|
if (!type->level_names) {
|
|
if (prev_level_names)
|
|
_XkbFree(prev_level_names);
|
|
return BadAlloc;
|
|
}
|
|
}
|
|
/*
|
|
* Here's the theory:
|
|
* If the width of the type changed, we might have to resize the symbol
|
|
* maps for any keys that use the type for one or more groups. This is
|
|
* expensive, so we'll try to cull out any keys that are obviously okay:
|
|
* In any case:
|
|
* - keys that have a group width <= the old width are okay (because
|
|
* they could not possibly have been associated with the old type)
|
|
* If the key type increased in size:
|
|
* - keys that already have a group width >= to the new width are okay
|
|
* + keys that have a group width >= the old width but < the new width
|
|
* might have to be enlarged.
|
|
* If the key type decreased in size:
|
|
* - keys that have a group width > the old width don't have to be
|
|
* resized (because they must have some other wider type associated
|
|
* with some group).
|
|
* + keys that have a group width == the old width might have to be
|
|
* shrunk.
|
|
* The possibilities marked with '+' require us to examine the key types
|
|
* associated with each group for the key.
|
|
*/
|
|
bzero(matchingKeys,XkbMaxKeyCount*sizeof(KeyCode));
|
|
nMatchingKeys= 0;
|
|
if (new_num_lvls>type->num_levels) {
|
|
int nTotal;
|
|
KeySym * newSyms;
|
|
int width,match,nResize;
|
|
register int i,g,nSyms;
|
|
|
|
nResize= 0;
|
|
for (nTotal=1,i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
|
|
width= XkbKeyGroupsWidth(xkb,i);
|
|
if (width<type->num_levels)
|
|
continue;
|
|
for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
|
|
if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
|
|
matchingKeys[nMatchingKeys++]= i;
|
|
match= 1;
|
|
}
|
|
}
|
|
if ((!match)||(width>=new_num_lvls))
|
|
nTotal+= XkbKeyNumSyms(xkb,i);
|
|
else {
|
|
nTotal+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
|
|
nResize++;
|
|
}
|
|
}
|
|
if (nResize>0) {
|
|
int nextMatch;
|
|
xkb->map->size_syms= (nTotal*12)/10;
|
|
newSyms = _XkbTypedCalloc(xkb->map->size_syms,KeySym);
|
|
if (newSyms==NULL)
|
|
return BadAlloc;
|
|
nextMatch= 0;
|
|
nSyms= 1;
|
|
for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
|
|
if (matchingKeys[nextMatch]==i) {
|
|
KeySym *pOld;
|
|
nextMatch++;
|
|
width= XkbKeyGroupsWidth(xkb,i);
|
|
pOld= XkbKeySymsPtr(xkb,i);
|
|
for (g=XkbKeyNumGroups(xkb,i)-1;g>=0;g--) {
|
|
memcpy(&newSyms[nSyms+(new_num_lvls*g)],&pOld[width*g],
|
|
width*sizeof(KeySym));
|
|
}
|
|
xkb->map->key_sym_map[i].offset= nSyms;
|
|
nSyms+= XkbKeyNumGroups(xkb,i)*new_num_lvls;
|
|
}
|
|
else {
|
|
memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),
|
|
XkbKeyNumSyms(xkb,i)*sizeof(KeySym));
|
|
xkb->map->key_sym_map[i].offset= nSyms;
|
|
nSyms+= XkbKeyNumSyms(xkb,i);
|
|
}
|
|
}
|
|
type->num_levels= new_num_lvls;
|
|
_XkbFree(xkb->map->syms);
|
|
xkb->map->syms= newSyms;
|
|
xkb->map->num_syms= nSyms;
|
|
return Success;
|
|
}
|
|
}
|
|
else if (new_num_lvls<type->num_levels) {
|
|
int width,match;
|
|
register int g,i;
|
|
for (i=xkb->min_key_code;i<=xkb->max_key_code;i++) {
|
|
width= XkbKeyGroupsWidth(xkb,i);
|
|
if (width<type->num_levels)
|
|
continue;
|
|
for (match=0,g=XkbKeyNumGroups(xkb,i)-1;(g>=0)&&(!match);g--) {
|
|
if (XkbKeyKeyTypeIndex(xkb,i,g)==type_ndx) {
|
|
matchingKeys[nMatchingKeys++]= i;
|
|
match= 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (nMatchingKeys>0) {
|
|
int key,firstClear;
|
|
register int i,g;
|
|
if (new_num_lvls>type->num_levels)
|
|
firstClear= type->num_levels;
|
|
else firstClear= new_num_lvls;
|
|
for (i=0;i<nMatchingKeys;i++) {
|
|
KeySym * pSyms;
|
|
int width,nClear;
|
|
|
|
key= matchingKeys[i];
|
|
width= XkbKeyGroupsWidth(xkb,key);
|
|
nClear= width-firstClear;
|
|
pSyms= XkbKeySymsPtr(xkb,key);
|
|
for (g=XkbKeyNumGroups(xkb,key)-1;g>=0;g--) {
|
|
if (XkbKeyKeyTypeIndex(xkb,key,g)==type_ndx) {
|
|
if (nClear>0)
|
|
bzero(&pSyms[g*width+firstClear],nClear*sizeof(KeySym));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
type->num_levels= new_num_lvls;
|
|
return Success;
|
|
}
|
|
|
|
KeySym *
|
|
XkbResizeKeySyms(XkbDescPtr xkb,int key,int needed)
|
|
{
|
|
register int i,nSyms,nKeySyms;
|
|
unsigned nOldSyms;
|
|
KeySym *newSyms;
|
|
|
|
if (needed==0) {
|
|
xkb->map->key_sym_map[key].offset= 0;
|
|
return xkb->map->syms;
|
|
}
|
|
nOldSyms= XkbKeyNumSyms(xkb,key);
|
|
if (nOldSyms>=(unsigned)needed) {
|
|
return XkbKeySymsPtr(xkb,key);
|
|
}
|
|
if (xkb->map->size_syms-xkb->map->num_syms>=(unsigned)needed) {
|
|
if (nOldSyms>0) {
|
|
memcpy(&xkb->map->syms[xkb->map->num_syms],XkbKeySymsPtr(xkb,key),
|
|
nOldSyms*sizeof(KeySym));
|
|
}
|
|
if ((needed-nOldSyms)>0) {
|
|
bzero(&xkb->map->syms[xkb->map->num_syms+XkbKeyNumSyms(xkb,key)],
|
|
(needed-nOldSyms)*sizeof(KeySym));
|
|
}
|
|
xkb->map->key_sym_map[key].offset = xkb->map->num_syms;
|
|
xkb->map->num_syms+= needed;
|
|
return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
|
|
}
|
|
xkb->map->size_syms+= (needed>32?needed:32);
|
|
newSyms = _XkbTypedCalloc(xkb->map->size_syms,KeySym);
|
|
if (newSyms==NULL)
|
|
return NULL;
|
|
newSyms[0]= NoSymbol;
|
|
nSyms = 1;
|
|
for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
|
|
int nCopy;
|
|
|
|
nCopy= nKeySyms= XkbKeyNumSyms(xkb,i);
|
|
if ((nKeySyms==0)&&(i!=key))
|
|
continue;
|
|
if (i==key)
|
|
nKeySyms= needed;
|
|
if (nCopy!=0)
|
|
memcpy(&newSyms[nSyms],XkbKeySymsPtr(xkb,i),nCopy*sizeof(KeySym));
|
|
if (nKeySyms>nCopy)
|
|
bzero(&newSyms[nSyms+nCopy],(nKeySyms-nCopy)*sizeof(KeySym));
|
|
xkb->map->key_sym_map[i].offset = nSyms;
|
|
nSyms+= nKeySyms;
|
|
}
|
|
_XkbFree(xkb->map->syms);
|
|
xkb->map->syms = newSyms;
|
|
xkb->map->num_syms = nSyms;
|
|
return &xkb->map->syms[xkb->map->key_sym_map[key].offset];
|
|
}
|
|
|
|
static unsigned
|
|
_ExtendRange( unsigned int old_flags,
|
|
unsigned int flag,
|
|
KeyCode newKC,
|
|
KeyCode * old_min,
|
|
unsigned char * old_num)
|
|
{
|
|
if ((old_flags&flag)==0) {
|
|
old_flags|= flag;
|
|
*old_min= newKC;
|
|
*old_num= 1;
|
|
}
|
|
else {
|
|
int last= (*old_min)+(*old_num)-1;
|
|
if (newKC<*old_min) {
|
|
*old_min= newKC;
|
|
*old_num= (last-newKC)+1;
|
|
}
|
|
else if (newKC>last) {
|
|
*old_num= (newKC-(*old_min))+1;
|
|
}
|
|
}
|
|
return old_flags;
|
|
}
|
|
|
|
Status
|
|
XkbChangeKeycodeRange( XkbDescPtr xkb,
|
|
int minKC,
|
|
int maxKC,
|
|
XkbChangesPtr changes)
|
|
{
|
|
int tmp;
|
|
|
|
if ((!xkb)||(minKC<XkbMinLegalKeyCode)||(maxKC>XkbMaxLegalKeyCode))
|
|
return BadValue;
|
|
if (minKC>maxKC)
|
|
return BadMatch;
|
|
if (minKC<xkb->min_key_code) {
|
|
if (changes)
|
|
changes->map.min_key_code= minKC;
|
|
tmp= xkb->min_key_code-minKC;
|
|
if (xkb->map) {
|
|
if (xkb->map->key_sym_map) {
|
|
bzero((char *)&xkb->map->key_sym_map[minKC],
|
|
tmp*sizeof(XkbSymMapRec));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbKeySymsMask,minKC,
|
|
&changes->map.first_key_sym,
|
|
&changes->map.num_key_syms);
|
|
}
|
|
}
|
|
if (xkb->map->modmap) {
|
|
bzero((char *)&xkb->map->modmap[minKC],tmp);
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbModifierMapMask,minKC,
|
|
&changes->map.first_modmap_key,
|
|
&changes->map.num_modmap_keys);
|
|
}
|
|
}
|
|
}
|
|
if (xkb->server) {
|
|
if (xkb->server->behaviors) {
|
|
bzero((char *)&xkb->server->behaviors[minKC],
|
|
tmp*sizeof(XkbBehavior));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbKeyBehaviorsMask,minKC,
|
|
&changes->map.first_key_behavior,
|
|
&changes->map.num_key_behaviors);
|
|
}
|
|
}
|
|
if (xkb->server->key_acts) {
|
|
bzero((char *)&xkb->server->key_acts[minKC],
|
|
tmp*sizeof(unsigned short));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbKeyActionsMask,minKC,
|
|
&changes->map.first_key_act,
|
|
&changes->map.num_key_acts);
|
|
}
|
|
}
|
|
if (xkb->server->vmodmap) {
|
|
bzero((char *)&xkb->server->vmodmap[minKC],
|
|
tmp*sizeof(unsigned short));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbVirtualModMapMask,minKC,
|
|
&changes->map.first_modmap_key,
|
|
&changes->map.num_vmodmap_keys);
|
|
}
|
|
}
|
|
}
|
|
if ((xkb->names)&&(xkb->names->keys)) {
|
|
bzero((char *)&xkb->names->keys[minKC],tmp*sizeof(XkbKeyNameRec));
|
|
if (changes) {
|
|
changes->names.changed= _ExtendRange(changes->names.changed,
|
|
XkbKeyNamesMask,minKC,
|
|
&changes->names.first_key,
|
|
&changes->names.num_keys);
|
|
}
|
|
}
|
|
xkb->min_key_code= minKC;
|
|
}
|
|
if (maxKC>xkb->max_key_code) {
|
|
if (changes)
|
|
changes->map.max_key_code= maxKC;
|
|
tmp= maxKC-xkb->max_key_code;
|
|
if (xkb->map) {
|
|
if (xkb->map->key_sym_map) {
|
|
XkbSymMapRec *prev_key_sym_map = xkb->map->key_sym_map;
|
|
|
|
xkb->map->key_sym_map= _XkbTypedRealloc(xkb->map->key_sym_map,
|
|
(maxKC+1),XkbSymMapRec);
|
|
if (!xkb->map->key_sym_map) {
|
|
_XkbFree(prev_key_sym_map);
|
|
return BadAlloc;
|
|
}
|
|
bzero((char *)&xkb->map->key_sym_map[xkb->max_key_code],
|
|
tmp*sizeof(XkbSymMapRec));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbKeySymsMask,maxKC,
|
|
&changes->map.first_key_sym,
|
|
&changes->map.num_key_syms);
|
|
}
|
|
}
|
|
if (xkb->map->modmap) {
|
|
unsigned char *prev_modmap = xkb->map->modmap;
|
|
|
|
xkb->map->modmap= _XkbTypedRealloc(xkb->map->modmap,
|
|
(maxKC+1),unsigned char);
|
|
if (!xkb->map->modmap) {
|
|
_XkbFree(prev_modmap);
|
|
return BadAlloc;
|
|
}
|
|
bzero((char *)&xkb->map->modmap[xkb->max_key_code],tmp);
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbModifierMapMask,maxKC,
|
|
&changes->map.first_modmap_key,
|
|
&changes->map.num_modmap_keys);
|
|
}
|
|
}
|
|
}
|
|
if (xkb->server) {
|
|
if (xkb->server->behaviors) {
|
|
XkbBehavior *prev_behaviors = xkb->server->behaviors;
|
|
|
|
xkb->server->behaviors=_XkbTypedRealloc(xkb->server->behaviors,
|
|
(maxKC+1),XkbBehavior);
|
|
if (!xkb->server->behaviors) {
|
|
_XkbFree(prev_behaviors);
|
|
return BadAlloc;
|
|
}
|
|
bzero((char *)&xkb->server->behaviors[xkb->max_key_code],
|
|
tmp*sizeof(XkbBehavior));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbKeyBehaviorsMask,maxKC,
|
|
&changes->map.first_key_behavior,
|
|
&changes->map.num_key_behaviors);
|
|
}
|
|
}
|
|
if (xkb->server->key_acts) {
|
|
unsigned short *prev_key_acts = xkb->server->key_acts;
|
|
|
|
xkb->server->key_acts= _XkbTypedRealloc(xkb->server->key_acts,
|
|
(maxKC+1),unsigned short);
|
|
if (!xkb->server->key_acts) {
|
|
_XkbFree(prev_key_acts);
|
|
return BadAlloc;
|
|
}
|
|
bzero((char *)&xkb->server->key_acts[xkb->max_key_code],
|
|
tmp*sizeof(unsigned short));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbKeyActionsMask,maxKC,
|
|
&changes->map.first_key_act,
|
|
&changes->map.num_key_acts);
|
|
}
|
|
}
|
|
if (xkb->server->vmodmap) {
|
|
unsigned short *prev_vmodmap = xkb->server->vmodmap;
|
|
|
|
xkb->server->vmodmap= _XkbTypedRealloc(xkb->server->vmodmap,
|
|
(maxKC+1),unsigned short);
|
|
if (!xkb->server->vmodmap) {
|
|
_XkbFree(prev_vmodmap);
|
|
return BadAlloc;
|
|
}
|
|
bzero((char *)&xkb->server->vmodmap[xkb->max_key_code],
|
|
tmp*sizeof(unsigned short));
|
|
if (changes) {
|
|
changes->map.changed= _ExtendRange(changes->map.changed,
|
|
XkbVirtualModMapMask,maxKC,
|
|
&changes->map.first_modmap_key,
|
|
&changes->map.num_vmodmap_keys);
|
|
}
|
|
}
|
|
}
|
|
if ((xkb->names)&&(xkb->names->keys)) {
|
|
XkbKeyNameRec *prev_keys = xkb->names->keys;
|
|
|
|
xkb->names->keys= _XkbTypedRealloc(xkb->names->keys,
|
|
(maxKC+1),XkbKeyNameRec);
|
|
if (!xkb->names->keys) {
|
|
_XkbFree(prev_keys);
|
|
return BadAlloc;
|
|
}
|
|
bzero((char *)&xkb->names->keys[xkb->max_key_code],
|
|
tmp*sizeof(XkbKeyNameRec));
|
|
if (changes) {
|
|
changes->names.changed= _ExtendRange(changes->names.changed,
|
|
XkbKeyNamesMask,maxKC,
|
|
&changes->names.first_key,
|
|
&changes->names.num_keys);
|
|
}
|
|
}
|
|
xkb->max_key_code= maxKC;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
XkbAction *
|
|
XkbResizeKeyActions(XkbDescPtr xkb,int key,int needed)
|
|
{
|
|
register int i,nActs;
|
|
XkbAction *newActs;
|
|
|
|
if (needed==0) {
|
|
xkb->server->key_acts[key]= 0;
|
|
return NULL;
|
|
}
|
|
if (XkbKeyHasActions(xkb,key)&&(XkbKeyNumSyms(xkb,key)>=(unsigned)needed))
|
|
return XkbKeyActionsPtr(xkb,key);
|
|
if (xkb->server->size_acts-xkb->server->num_acts>=(unsigned)needed) {
|
|
xkb->server->key_acts[key]= xkb->server->num_acts;
|
|
xkb->server->num_acts+= needed;
|
|
return &xkb->server->acts[xkb->server->key_acts[key]];
|
|
}
|
|
xkb->server->size_acts= xkb->server->num_acts+needed+8;
|
|
newActs = _XkbTypedCalloc(xkb->server->size_acts,XkbAction);
|
|
if (newActs==NULL)
|
|
return NULL;
|
|
newActs[0].type = XkbSA_NoAction;
|
|
nActs = 1;
|
|
for (i=xkb->min_key_code;i<=(int)xkb->max_key_code;i++) {
|
|
int nKeyActs,nCopy;
|
|
|
|
if ((xkb->server->key_acts[i]==0)&&(i!=key))
|
|
continue;
|
|
|
|
nCopy= nKeyActs= XkbKeyNumActions(xkb,i);
|
|
if (i==key) {
|
|
nKeyActs= needed;
|
|
if (needed<nCopy)
|
|
nCopy= needed;
|
|
}
|
|
|
|
if (nCopy>0)
|
|
memcpy(&newActs[nActs],XkbKeyActionsPtr(xkb,i),
|
|
nCopy*sizeof(XkbAction));
|
|
if (nCopy<nKeyActs)
|
|
bzero(&newActs[nActs+nCopy],(nKeyActs-nCopy)*sizeof(XkbAction));
|
|
xkb->server->key_acts[i]= nActs;
|
|
nActs+= nKeyActs;
|
|
}
|
|
_XkbFree(xkb->server->acts);
|
|
xkb->server->acts = newActs;
|
|
xkb->server->num_acts= nActs;
|
|
return &xkb->server->acts[xkb->server->key_acts[key]];
|
|
}
|
|
|
|
void
|
|
XkbFreeClientMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
|
|
{
|
|
XkbClientMapPtr map;
|
|
|
|
if ((xkb==NULL)||(xkb->map==NULL))
|
|
return;
|
|
if (freeMap)
|
|
what= XkbAllClientInfoMask;
|
|
map= xkb->map;
|
|
if (what&XkbKeyTypesMask) {
|
|
if (map->types!=NULL) {
|
|
if (map->num_types>0) {
|
|
register int i;
|
|
XkbKeyTypePtr type;
|
|
for (i=0,type=map->types;i<map->num_types;i++,type++) {
|
|
if (type->map!=NULL) {
|
|
_XkbFree(type->map);
|
|
type->map= NULL;
|
|
}
|
|
if (type->preserve!=NULL) {
|
|
_XkbFree(type->preserve);
|
|
type->preserve= NULL;
|
|
}
|
|
type->map_count= 0;
|
|
if (type->level_names!=NULL) {
|
|
_XkbFree(type->level_names);
|
|
type->level_names= NULL;
|
|
}
|
|
}
|
|
}
|
|
_XkbFree(map->types);
|
|
map->num_types= map->size_types= 0;
|
|
map->types= NULL;
|
|
}
|
|
}
|
|
if (what&XkbKeySymsMask) {
|
|
if (map->key_sym_map!=NULL) {
|
|
_XkbFree(map->key_sym_map);
|
|
map->key_sym_map= NULL;
|
|
}
|
|
if (map->syms!=NULL) {
|
|
_XkbFree(map->syms);
|
|
map->size_syms= map->num_syms= 0;
|
|
map->syms= NULL;
|
|
}
|
|
}
|
|
if ((what&XkbModifierMapMask)&&(map->modmap!=NULL)) {
|
|
_XkbFree(map->modmap);
|
|
map->modmap= NULL;
|
|
}
|
|
if (freeMap) {
|
|
_XkbFree(xkb->map);
|
|
xkb->map= NULL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbFreeServerMap(XkbDescPtr xkb,unsigned what,Bool freeMap)
|
|
{
|
|
XkbServerMapPtr map;
|
|
|
|
if ((xkb==NULL)||(xkb->server==NULL))
|
|
return;
|
|
if (freeMap)
|
|
what= XkbAllServerInfoMask;
|
|
map= xkb->server;
|
|
if ((what&XkbExplicitComponentsMask)&&(map->explicit!=NULL)) {
|
|
_XkbFree(map->explicit);
|
|
map->explicit= NULL;
|
|
}
|
|
if (what&XkbKeyActionsMask) {
|
|
if (map->key_acts!=NULL) {
|
|
_XkbFree(map->key_acts);
|
|
map->key_acts= NULL;
|
|
}
|
|
if (map->acts!=NULL) {
|
|
_XkbFree(map->acts);
|
|
map->num_acts= map->size_acts= 0;
|
|
map->acts= NULL;
|
|
}
|
|
}
|
|
if ((what&XkbKeyBehaviorsMask)&&(map->behaviors!=NULL)) {
|
|
_XkbFree(map->behaviors);
|
|
map->behaviors= NULL;
|
|
}
|
|
if ((what&XkbVirtualModMapMask)&&(map->vmodmap!=NULL)) {
|
|
_XkbFree(map->vmodmap);
|
|
map->vmodmap= NULL;
|
|
}
|
|
|
|
if (freeMap) {
|
|
_XkbFree(xkb->server);
|
|
xkb->server= NULL;
|
|
}
|
|
return;
|
|
}
|