1a66cad3fb
Tested by bru@, jsg@ and others
826 lines
24 KiB
C
826 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>
|
|
#endif
|
|
|
|
#include <xkb-config.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <math.h>
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/keysym.h>
|
|
#include <X11/Xatom.h>
|
|
#include "misc.h"
|
|
#include "inputstr.h"
|
|
#include "opaque.h"
|
|
#include "property.h"
|
|
#include "scrnintstr.h"
|
|
#define XKBSRV_NEED_FILE_FUNCS
|
|
#include <xkbsrv.h>
|
|
#include "xkbgeom.h"
|
|
#include <X11/extensions/XKMformat.h>
|
|
#include "xkbfile.h"
|
|
#include "xkb.h"
|
|
|
|
#define CREATE_ATOM(s) MakeAtom(s,sizeof(s)-1,1)
|
|
|
|
#if defined(__alpha) || defined(__alpha__)
|
|
#define LED_COMPOSE 2
|
|
#define LED_CAPS 3
|
|
#define LED_SCROLL 4
|
|
#define LED_NUM 5
|
|
#define PHYS_LEDS 0x1f
|
|
#else
|
|
#ifdef __sun
|
|
#define LED_NUM 1
|
|
#define LED_SCROLL 2
|
|
#define LED_COMPOSE 3
|
|
#define LED_CAPS 4
|
|
#define PHYS_LEDS 0x0f
|
|
#else
|
|
#define LED_CAPS 1
|
|
#define LED_NUM 2
|
|
#define LED_SCROLL 3
|
|
#define PHYS_LEDS 0x07
|
|
#endif
|
|
#endif
|
|
|
|
#define MAX_TOC 16
|
|
typedef struct _SrvXkmInfo {
|
|
DeviceIntPtr dev;
|
|
FILE *file;
|
|
XkbDescPtr xkb;
|
|
} SrvXkmInfo;
|
|
|
|
/***====================================================================***/
|
|
|
|
#ifndef XKB_DFLT_RULES_PROP
|
|
#define XKB_DFLT_RULES_PROP TRUE
|
|
#endif
|
|
|
|
const char *XkbBaseDirectory = XKB_BASE_DIRECTORY;
|
|
const char *XkbBinDirectory = XKB_BIN_DIRECTORY;
|
|
static int XkbWantAccessX = 0;
|
|
|
|
static char *XkbRulesDflt = NULL;
|
|
static char *XkbModelDflt = NULL;
|
|
static char *XkbLayoutDflt = NULL;
|
|
static char *XkbVariantDflt = NULL;
|
|
static char *XkbOptionsDflt = NULL;
|
|
|
|
static char *XkbRulesUsed = NULL;
|
|
static char *XkbModelUsed = NULL;
|
|
static char *XkbLayoutUsed = NULL;
|
|
static char *XkbVariantUsed = NULL;
|
|
static char *XkbOptionsUsed = NULL;
|
|
|
|
static XkbDescPtr xkb_cached_map = NULL;
|
|
|
|
static Bool XkbWantRulesProp = XKB_DFLT_RULES_PROP;
|
|
|
|
/***====================================================================***/
|
|
|
|
/**
|
|
* Get the current default XKB rules.
|
|
* Caller must free the data in rmlvo.
|
|
*/
|
|
void
|
|
XkbGetRulesDflts(XkbRMLVOSet * rmlvo)
|
|
{
|
|
rmlvo->rules = strdup(XkbRulesDflt ? XkbRulesDflt : XKB_DFLT_RULES);
|
|
rmlvo->model = strdup(XkbModelDflt ? XkbModelDflt : XKB_DFLT_MODEL);
|
|
rmlvo->layout = strdup(XkbLayoutDflt ? XkbLayoutDflt : XKB_DFLT_LAYOUT);
|
|
rmlvo->variant = strdup(XkbVariantDflt ? XkbVariantDflt : XKB_DFLT_VARIANT);
|
|
rmlvo->options = strdup(XkbOptionsDflt ? XkbOptionsDflt : XKB_DFLT_OPTIONS);
|
|
}
|
|
|
|
void
|
|
XkbFreeRMLVOSet(XkbRMLVOSet * rmlvo, Bool freeRMLVO)
|
|
{
|
|
if (!rmlvo)
|
|
return;
|
|
|
|
free(rmlvo->rules);
|
|
free(rmlvo->model);
|
|
free(rmlvo->layout);
|
|
free(rmlvo->variant);
|
|
free(rmlvo->options);
|
|
|
|
if (freeRMLVO)
|
|
free(rmlvo);
|
|
else
|
|
memset(rmlvo, 0, sizeof(XkbRMLVOSet));
|
|
}
|
|
|
|
static Bool
|
|
XkbWriteRulesProp(ClientPtr client, void *closure)
|
|
{
|
|
int len, out;
|
|
Atom name;
|
|
char *pval;
|
|
|
|
len = (XkbRulesUsed ? strlen(XkbRulesUsed) : 0);
|
|
len += (XkbModelUsed ? strlen(XkbModelUsed) : 0);
|
|
len += (XkbLayoutUsed ? strlen(XkbLayoutUsed) : 0);
|
|
len += (XkbVariantUsed ? strlen(XkbVariantUsed) : 0);
|
|
len += (XkbOptionsUsed ? strlen(XkbOptionsUsed) : 0);
|
|
if (len < 1)
|
|
return TRUE;
|
|
|
|
len += 5; /* trailing NULs */
|
|
|
|
name =
|
|
MakeAtom(_XKB_RF_NAMES_PROP_ATOM, strlen(_XKB_RF_NAMES_PROP_ATOM), 1);
|
|
if (name == None) {
|
|
ErrorF("[xkb] Atom error: %s not created\n", _XKB_RF_NAMES_PROP_ATOM);
|
|
return TRUE;
|
|
}
|
|
pval = (char *) malloc(len);
|
|
if (!pval) {
|
|
ErrorF("[xkb] Allocation error: %s proprerty not created\n",
|
|
_XKB_RF_NAMES_PROP_ATOM);
|
|
return TRUE;
|
|
}
|
|
out = 0;
|
|
if (XkbRulesUsed) {
|
|
strcpy(&pval[out], XkbRulesUsed);
|
|
out += strlen(XkbRulesUsed);
|
|
}
|
|
pval[out++] = '\0';
|
|
if (XkbModelUsed) {
|
|
strcpy(&pval[out], XkbModelUsed);
|
|
out += strlen(XkbModelUsed);
|
|
}
|
|
pval[out++] = '\0';
|
|
if (XkbLayoutUsed) {
|
|
strcpy(&pval[out], XkbLayoutUsed);
|
|
out += strlen(XkbLayoutUsed);
|
|
}
|
|
pval[out++] = '\0';
|
|
if (XkbVariantUsed) {
|
|
strcpy(&pval[out], XkbVariantUsed);
|
|
out += strlen(XkbVariantUsed);
|
|
}
|
|
pval[out++] = '\0';
|
|
if (XkbOptionsUsed) {
|
|
strcpy(&pval[out], XkbOptionsUsed);
|
|
out += strlen(XkbOptionsUsed);
|
|
}
|
|
pval[out++] = '\0';
|
|
if (out != len) {
|
|
ErrorF("[xkb] Internal Error! bad size (%d!=%d) for _XKB_RULES_NAMES\n",
|
|
out, len);
|
|
}
|
|
dixChangeWindowProperty(serverClient, screenInfo.screens[0]->root, name,
|
|
XA_STRING, 8, PropModeReplace, len, pval, TRUE);
|
|
free(pval);
|
|
return TRUE;
|
|
}
|
|
|
|
void
|
|
XkbInitRules(XkbRMLVOSet *rmlvo,
|
|
const char *rules,
|
|
const char *model,
|
|
const char *layout,
|
|
const char *variant,
|
|
const char *options)
|
|
{
|
|
rmlvo->rules = rules ? xnfstrdup(rules) : NULL;
|
|
rmlvo->model = model ? xnfstrdup(model) : NULL;
|
|
rmlvo->layout = layout ? xnfstrdup(layout) : NULL;
|
|
rmlvo->variant = variant ? xnfstrdup(variant) : NULL;
|
|
rmlvo->options = options ? xnfstrdup(options) : NULL;
|
|
}
|
|
|
|
static void
|
|
XkbSetRulesUsed(XkbRMLVOSet * rmlvo)
|
|
{
|
|
free(XkbRulesUsed);
|
|
XkbRulesUsed = (rmlvo->rules ? Xstrdup(rmlvo->rules) : NULL);
|
|
free(XkbModelUsed);
|
|
XkbModelUsed = (rmlvo->model ? Xstrdup(rmlvo->model) : NULL);
|
|
free(XkbLayoutUsed);
|
|
XkbLayoutUsed = (rmlvo->layout ? Xstrdup(rmlvo->layout) : NULL);
|
|
free(XkbVariantUsed);
|
|
XkbVariantUsed = (rmlvo->variant ? Xstrdup(rmlvo->variant) : NULL);
|
|
free(XkbOptionsUsed);
|
|
XkbOptionsUsed = (rmlvo->options ? Xstrdup(rmlvo->options) : NULL);
|
|
if (XkbWantRulesProp)
|
|
QueueWorkProc(XkbWriteRulesProp, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbSetRulesDflts(XkbRMLVOSet * rmlvo)
|
|
{
|
|
if (rmlvo->rules) {
|
|
free(XkbRulesDflt);
|
|
XkbRulesDflt = Xstrdup(rmlvo->rules);
|
|
}
|
|
if (rmlvo->model) {
|
|
free(XkbModelDflt);
|
|
XkbModelDflt = Xstrdup(rmlvo->model);
|
|
}
|
|
if (rmlvo->layout) {
|
|
free(XkbLayoutDflt);
|
|
XkbLayoutDflt = Xstrdup(rmlvo->layout);
|
|
}
|
|
if (rmlvo->variant) {
|
|
free(XkbVariantDflt);
|
|
XkbVariantDflt = Xstrdup(rmlvo->variant);
|
|
}
|
|
if (rmlvo->options) {
|
|
free(XkbOptionsDflt);
|
|
XkbOptionsDflt = Xstrdup(rmlvo->options);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void
|
|
XkbDeleteRulesUsed(void)
|
|
{
|
|
free(XkbRulesUsed);
|
|
XkbRulesUsed = NULL;
|
|
free(XkbModelUsed);
|
|
XkbModelUsed = NULL;
|
|
free(XkbLayoutUsed);
|
|
XkbLayoutUsed = NULL;
|
|
free(XkbVariantUsed);
|
|
XkbVariantUsed = NULL;
|
|
free(XkbOptionsUsed);
|
|
XkbOptionsUsed = NULL;
|
|
}
|
|
|
|
void
|
|
XkbDeleteRulesDflts(void)
|
|
{
|
|
free(XkbRulesDflt);
|
|
XkbRulesDflt = NULL;
|
|
free(XkbModelDflt);
|
|
XkbModelDflt = NULL;
|
|
free(XkbLayoutDflt);
|
|
XkbLayoutDflt = NULL;
|
|
free(XkbVariantDflt);
|
|
XkbVariantDflt = NULL;
|
|
free(XkbOptionsDflt);
|
|
XkbOptionsDflt = NULL;
|
|
|
|
XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE);
|
|
xkb_cached_map = NULL;
|
|
}
|
|
|
|
#define DIFFERS(a, b) (strcmp((a) ? (a) : "", (b) ? (b) : "") != 0)
|
|
|
|
static Bool
|
|
XkbCompareUsedRMLVO(XkbRMLVOSet * rmlvo)
|
|
{
|
|
if (DIFFERS(rmlvo->rules, XkbRulesUsed) ||
|
|
DIFFERS(rmlvo->model, XkbModelUsed) ||
|
|
DIFFERS(rmlvo->layout, XkbLayoutUsed) ||
|
|
DIFFERS(rmlvo->variant, XkbVariantUsed) ||
|
|
DIFFERS(rmlvo->options, XkbOptionsUsed))
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
#undef DIFFERS
|
|
|
|
/***====================================================================***/
|
|
|
|
#include "xkbDflts.h"
|
|
|
|
static Bool
|
|
XkbInitKeyTypes(XkbDescPtr xkb)
|
|
{
|
|
if (xkb->defined & XkmTypesMask)
|
|
return TRUE;
|
|
|
|
initTypeNames(NULL);
|
|
if (XkbAllocClientMap(xkb, XkbKeyTypesMask, num_dflt_types) != Success)
|
|
return FALSE;
|
|
if (XkbCopyKeyTypes(dflt_types, xkb->map->types, num_dflt_types) != Success) {
|
|
return FALSE;
|
|
}
|
|
xkb->map->size_types = xkb->map->num_types = num_dflt_types;
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
XkbInitRadioGroups(XkbSrvInfoPtr xkbi)
|
|
{
|
|
xkbi->nRadioGroups = 0;
|
|
xkbi->radioGroups = NULL;
|
|
return;
|
|
}
|
|
|
|
static Status
|
|
XkbInitCompatStructs(XkbDescPtr xkb)
|
|
{
|
|
register int i;
|
|
XkbCompatMapPtr compat;
|
|
|
|
if (xkb->defined & XkmCompatMapMask)
|
|
return TRUE;
|
|
|
|
if (XkbAllocCompatMap(xkb, XkbAllCompatMask, num_dfltSI) != Success)
|
|
return BadAlloc;
|
|
compat = xkb->compat;
|
|
if (compat->sym_interpret) {
|
|
compat->num_si = num_dfltSI;
|
|
memcpy((char *) compat->sym_interpret, (char *) dfltSI, sizeof(dfltSI));
|
|
}
|
|
for (i = 0; i < XkbNumKbdGroups; i++) {
|
|
compat->groups[i] = compatMap.groups[i];
|
|
if (compat->groups[i].vmods != 0) {
|
|
unsigned mask;
|
|
|
|
mask = XkbMaskForVMask(xkb, compat->groups[i].vmods);
|
|
compat->groups[i].mask = compat->groups[i].real_mods | mask;
|
|
}
|
|
else
|
|
compat->groups[i].mask = compat->groups[i].real_mods;
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
XkbInitSemantics(XkbDescPtr xkb)
|
|
{
|
|
XkbInitKeyTypes(xkb);
|
|
XkbInitCompatStructs(xkb);
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
static Status
|
|
XkbInitNames(XkbSrvInfoPtr xkbi)
|
|
{
|
|
XkbDescPtr xkb;
|
|
XkbNamesPtr names;
|
|
Status rtrn;
|
|
Atom unknown;
|
|
|
|
xkb = xkbi->desc;
|
|
if ((rtrn = XkbAllocNames(xkb, XkbAllNamesMask, 0, 0)) != Success)
|
|
return rtrn;
|
|
unknown = CREATE_ATOM("unknown");
|
|
names = xkb->names;
|
|
if (names->keycodes == None)
|
|
names->keycodes = unknown;
|
|
if (names->geometry == None)
|
|
names->geometry = unknown;
|
|
if (names->phys_symbols == None)
|
|
names->phys_symbols = unknown;
|
|
if (names->symbols == None)
|
|
names->symbols = unknown;
|
|
if (names->types == None)
|
|
names->types = unknown;
|
|
if (names->compat == None)
|
|
names->compat = unknown;
|
|
if (!(xkb->defined & XkmVirtualModsMask)) {
|
|
if (names->vmods[vmod_NumLock] == None)
|
|
names->vmods[vmod_NumLock] = CREATE_ATOM("NumLock");
|
|
if (names->vmods[vmod_Alt] == None)
|
|
names->vmods[vmod_Alt] = CREATE_ATOM("Alt");
|
|
if (names->vmods[vmod_AltGr] == None)
|
|
names->vmods[vmod_AltGr] = CREATE_ATOM("ModeSwitch");
|
|
}
|
|
|
|
if (!(xkb->defined & XkmIndicatorsMask) ||
|
|
!(xkb->defined & XkmGeometryMask)) {
|
|
initIndicatorNames(NULL, xkb);
|
|
if (names->indicators[LED_CAPS - 1] == None)
|
|
names->indicators[LED_CAPS - 1] = CREATE_ATOM("Caps Lock");
|
|
if (names->indicators[LED_NUM - 1] == None)
|
|
names->indicators[LED_NUM - 1] = CREATE_ATOM("Num Lock");
|
|
if (names->indicators[LED_SCROLL - 1] == None)
|
|
names->indicators[LED_SCROLL - 1] = CREATE_ATOM("Scroll Lock");
|
|
#ifdef LED_COMPOSE
|
|
if (names->indicators[LED_COMPOSE - 1] == None)
|
|
names->indicators[LED_COMPOSE - 1] = CREATE_ATOM("Compose");
|
|
#endif
|
|
}
|
|
|
|
if (xkb->geom != NULL)
|
|
names->geometry = xkb->geom->name;
|
|
else
|
|
names->geometry = unknown;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static Status
|
|
XkbInitIndicatorMap(XkbSrvInfoPtr xkbi)
|
|
{
|
|
XkbDescPtr xkb;
|
|
XkbIndicatorPtr map;
|
|
XkbSrvLedInfoPtr sli;
|
|
|
|
xkb = xkbi->desc;
|
|
if (XkbAllocIndicatorMaps(xkb) != Success)
|
|
return BadAlloc;
|
|
|
|
if (!(xkb->defined & XkmIndicatorsMask)) {
|
|
map = xkb->indicators;
|
|
map->phys_indicators = PHYS_LEDS;
|
|
map->maps[LED_CAPS - 1].flags = XkbIM_NoExplicit;
|
|
map->maps[LED_CAPS - 1].which_mods = XkbIM_UseLocked;
|
|
map->maps[LED_CAPS - 1].mods.mask = LockMask;
|
|
map->maps[LED_CAPS - 1].mods.real_mods = LockMask;
|
|
|
|
map->maps[LED_NUM - 1].flags = XkbIM_NoExplicit;
|
|
map->maps[LED_NUM - 1].which_mods = XkbIM_UseLocked;
|
|
map->maps[LED_NUM - 1].mods.mask = 0;
|
|
map->maps[LED_NUM - 1].mods.real_mods = 0;
|
|
map->maps[LED_NUM - 1].mods.vmods = vmod_NumLockMask;
|
|
|
|
map->maps[LED_SCROLL - 1].flags = XkbIM_NoExplicit;
|
|
map->maps[LED_SCROLL - 1].which_mods = XkbIM_UseLocked;
|
|
map->maps[LED_SCROLL - 1].mods.mask = Mod3Mask;
|
|
map->maps[LED_SCROLL - 1].mods.real_mods = Mod3Mask;
|
|
}
|
|
|
|
sli = XkbFindSrvLedInfo(xkbi->device, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
if (sli)
|
|
XkbCheckIndicatorMaps(xkbi->device, sli, XkbAllIndicatorsMask);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static Status
|
|
XkbInitControls(DeviceIntPtr pXDev, XkbSrvInfoPtr xkbi)
|
|
{
|
|
XkbDescPtr xkb;
|
|
XkbControlsPtr ctrls;
|
|
|
|
xkb = xkbi->desc;
|
|
/* 12/31/94 (ef) -- XXX! Should check if controls loaded from file */
|
|
if (XkbAllocControls(xkb, XkbAllControlsMask) != Success)
|
|
FatalError("Couldn't allocate keyboard controls\n");
|
|
ctrls = xkb->ctrls;
|
|
if (!(xkb->defined & XkmSymbolsMask))
|
|
ctrls->num_groups = 1;
|
|
ctrls->groups_wrap = XkbSetGroupInfo(1, XkbWrapIntoRange, 0);
|
|
ctrls->internal.mask = 0;
|
|
ctrls->internal.real_mods = 0;
|
|
ctrls->internal.vmods = 0;
|
|
ctrls->ignore_lock.mask = 0;
|
|
ctrls->ignore_lock.real_mods = 0;
|
|
ctrls->ignore_lock.vmods = 0;
|
|
ctrls->enabled_ctrls = XkbAccessXTimeoutMask | XkbRepeatKeysMask |
|
|
XkbMouseKeysAccelMask | XkbAudibleBellMask | XkbIgnoreGroupLockMask;
|
|
if (XkbWantAccessX)
|
|
ctrls->enabled_ctrls |= XkbAccessXKeysMask;
|
|
AccessXInit(pXDev);
|
|
return Success;
|
|
}
|
|
|
|
static Bool
|
|
InitKeyboardDeviceStructInternal(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
|
|
const char *keymap, int keymap_length,
|
|
BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
|
|
{
|
|
int i;
|
|
unsigned int check;
|
|
XkbSrvInfoPtr xkbi;
|
|
XkbDescPtr xkb;
|
|
XkbSrvLedInfoPtr sli;
|
|
XkbChangesRec changes;
|
|
XkbEventCauseRec cause;
|
|
XkbRMLVOSet rmlvo_dflts = { NULL };
|
|
|
|
BUG_RETURN_VAL(dev == NULL, FALSE);
|
|
BUG_RETURN_VAL(dev->key != NULL, FALSE);
|
|
BUG_RETURN_VAL(dev->kbdfeed != NULL, FALSE);
|
|
BUG_RETURN_VAL(rmlvo && keymap, FALSE);
|
|
|
|
if (!rmlvo && !keymap) {
|
|
rmlvo = &rmlvo_dflts;
|
|
XkbGetRulesDflts(rmlvo);
|
|
}
|
|
|
|
memset(&changes, 0, sizeof(changes));
|
|
XkbSetCauseUnknown(&cause);
|
|
|
|
dev->key = calloc(1, sizeof(*dev->key));
|
|
if (!dev->key) {
|
|
ErrorF("XKB: Failed to allocate key class\n");
|
|
return FALSE;
|
|
}
|
|
dev->key->sourceid = dev->id;
|
|
|
|
dev->kbdfeed = calloc(1, sizeof(*dev->kbdfeed));
|
|
if (!dev->kbdfeed) {
|
|
ErrorF("XKB: Failed to allocate key feedback class\n");
|
|
goto unwind_key;
|
|
}
|
|
|
|
xkbi = calloc(1, sizeof(*xkbi));
|
|
if (!xkbi) {
|
|
ErrorF("XKB: Failed to allocate XKB info\n");
|
|
goto unwind_kbdfeed;
|
|
}
|
|
dev->key->xkbInfo = xkbi;
|
|
|
|
if (xkb_cached_map && (keymap || (rmlvo && !XkbCompareUsedRMLVO(rmlvo)))) {
|
|
XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE);
|
|
xkb_cached_map = NULL;
|
|
}
|
|
|
|
if (xkb_cached_map)
|
|
LogMessageVerb(X_INFO, 4, "XKB: Reusing cached keymap\n");
|
|
else {
|
|
if (rmlvo)
|
|
xkb_cached_map = XkbCompileKeymap(dev, rmlvo);
|
|
else
|
|
xkb_cached_map = XkbCompileKeymapFromString(dev, keymap, keymap_length);
|
|
|
|
if (!xkb_cached_map) {
|
|
ErrorF("XKB: Failed to compile keymap\n");
|
|
goto unwind_info;
|
|
}
|
|
}
|
|
|
|
xkb = XkbAllocKeyboard();
|
|
if (!xkb) {
|
|
ErrorF("XKB: Failed to allocate keyboard description\n");
|
|
goto unwind_info;
|
|
}
|
|
|
|
if (!XkbCopyKeymap(xkb, xkb_cached_map)) {
|
|
ErrorF("XKB: Failed to copy keymap\n");
|
|
goto unwind_desc;
|
|
}
|
|
xkb->defined = xkb_cached_map->defined;
|
|
xkb->flags = xkb_cached_map->flags;
|
|
xkb->device_spec = xkb_cached_map->device_spec;
|
|
xkbi->desc = xkb;
|
|
|
|
if (xkb->min_key_code == 0)
|
|
xkb->min_key_code = 8;
|
|
if (xkb->max_key_code == 0)
|
|
xkb->max_key_code = 255;
|
|
|
|
i = XkbNumKeys(xkb) / 3 + 1;
|
|
if (XkbAllocClientMap(xkb, XkbAllClientInfoMask, 0) != Success)
|
|
goto unwind_desc;
|
|
if (XkbAllocServerMap(xkb, XkbAllServerInfoMask, i) != Success)
|
|
goto unwind_desc;
|
|
|
|
xkbi->dfltPtrDelta = 1;
|
|
xkbi->device = dev;
|
|
|
|
XkbInitSemantics(xkb);
|
|
XkbInitNames(xkbi);
|
|
XkbInitRadioGroups(xkbi);
|
|
|
|
XkbInitControls(dev, xkbi);
|
|
|
|
XkbInitIndicatorMap(xkbi);
|
|
|
|
XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &changes,
|
|
&check, &cause);
|
|
|
|
if (!dev->focus)
|
|
InitFocusClassDeviceStruct(dev);
|
|
|
|
xkbi->kbdProc = ctrl_func;
|
|
dev->kbdfeed->BellProc = bell_func;
|
|
dev->kbdfeed->CtrlProc = XkbDDXKeybdCtrlProc;
|
|
|
|
dev->kbdfeed->ctrl = defaultKeyboardControl;
|
|
if (dev->kbdfeed->ctrl.autoRepeat)
|
|
xkb->ctrls->enabled_ctrls |= XkbRepeatKeysMask;
|
|
|
|
memcpy(dev->kbdfeed->ctrl.autoRepeats, xkb->ctrls->per_key_repeat,
|
|
XkbPerKeyBitArraySize);
|
|
|
|
sli = XkbFindSrvLedInfo(dev, XkbDfltXIClass, XkbDfltXIId, 0);
|
|
if (sli)
|
|
XkbCheckIndicatorMaps(dev, sli, XkbAllIndicatorsMask);
|
|
else
|
|
DebugF("XKB: No indicator feedback in XkbFinishInit!\n");
|
|
|
|
dev->kbdfeed->CtrlProc(dev, &dev->kbdfeed->ctrl);
|
|
|
|
if (rmlvo) {
|
|
XkbSetRulesDflts(rmlvo);
|
|
XkbSetRulesUsed(rmlvo);
|
|
}
|
|
XkbFreeRMLVOSet(&rmlvo_dflts, FALSE);
|
|
|
|
return TRUE;
|
|
|
|
unwind_desc:
|
|
XkbFreeKeyboard(xkb, 0, TRUE);
|
|
unwind_info:
|
|
free(xkbi);
|
|
dev->key->xkbInfo = NULL;
|
|
unwind_kbdfeed:
|
|
free(dev->kbdfeed);
|
|
dev->kbdfeed = NULL;
|
|
unwind_key:
|
|
free(dev->key);
|
|
dev->key = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
|
|
BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
|
|
{
|
|
return InitKeyboardDeviceStructInternal(dev, rmlvo,
|
|
NULL, 0, bell_func, ctrl_func);
|
|
}
|
|
|
|
_X_EXPORT Bool
|
|
InitKeyboardDeviceStructFromString(DeviceIntPtr dev,
|
|
const char *keymap, int keymap_length,
|
|
BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
|
|
{
|
|
return InitKeyboardDeviceStructInternal(dev, NULL,
|
|
keymap, keymap_length,
|
|
bell_func, ctrl_func);
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
/*
|
|
* Be very careful about what does and doesn't get freed by this
|
|
* function. To reduce fragmentation, XkbInitDevice allocates a
|
|
* single huge block per device and divides it up into most of the
|
|
* fixed-size structures for the device. Don't free anything that
|
|
* is part of this larger block.
|
|
*/
|
|
void
|
|
XkbFreeInfo(XkbSrvInfoPtr xkbi)
|
|
{
|
|
free(xkbi->radioGroups);
|
|
xkbi->radioGroups = NULL;
|
|
if (xkbi->mouseKeyTimer) {
|
|
TimerFree(xkbi->mouseKeyTimer);
|
|
xkbi->mouseKeyTimer = NULL;
|
|
}
|
|
if (xkbi->slowKeysTimer) {
|
|
TimerFree(xkbi->slowKeysTimer);
|
|
xkbi->slowKeysTimer = NULL;
|
|
}
|
|
if (xkbi->bounceKeysTimer) {
|
|
TimerFree(xkbi->bounceKeysTimer);
|
|
xkbi->bounceKeysTimer = NULL;
|
|
}
|
|
if (xkbi->repeatKeyTimer) {
|
|
TimerFree(xkbi->repeatKeyTimer);
|
|
xkbi->repeatKeyTimer = NULL;
|
|
}
|
|
if (xkbi->krgTimer) {
|
|
TimerFree(xkbi->krgTimer);
|
|
xkbi->krgTimer = NULL;
|
|
}
|
|
xkbi->beepType = _BEEP_NONE;
|
|
if (xkbi->beepTimer) {
|
|
TimerFree(xkbi->beepTimer);
|
|
xkbi->beepTimer = NULL;
|
|
}
|
|
if (xkbi->desc) {
|
|
XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, TRUE);
|
|
xkbi->desc = NULL;
|
|
}
|
|
free(xkbi);
|
|
return;
|
|
}
|
|
|
|
/***====================================================================***/
|
|
|
|
extern int XkbDfltRepeatDelay;
|
|
extern int XkbDfltRepeatInterval;
|
|
|
|
extern unsigned short XkbDfltAccessXTimeout;
|
|
extern unsigned int XkbDfltAccessXTimeoutMask;
|
|
extern unsigned int XkbDfltAccessXFeedback;
|
|
extern unsigned char XkbDfltAccessXOptions;
|
|
|
|
int
|
|
XkbProcessArguments(int argc, char *argv[], int i)
|
|
{
|
|
if (strncmp(argv[i], "-xkbdir", 7) == 0) {
|
|
if (++i < argc) {
|
|
#if !defined(WIN32) && !defined(__CYGWIN__)
|
|
if (getuid() != geteuid()) {
|
|
LogMessage(X_WARNING,
|
|
"-xkbdir is not available for setuid X servers\n");
|
|
return -1;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
if (strlen(argv[i]) < PATH_MAX) {
|
|
XkbBaseDirectory = argv[i];
|
|
return 2;
|
|
}
|
|
else {
|
|
LogMessage(X_ERROR, "-xkbdir pathname too long\n");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
return -1;
|
|
}
|
|
}
|
|
else if ((strncmp(argv[i], "-accessx", 8) == 0) ||
|
|
(strncmp(argv[i], "+accessx", 8) == 0)) {
|
|
int j = 1;
|
|
|
|
if (argv[i][0] == '-')
|
|
XkbWantAccessX = 0;
|
|
else {
|
|
XkbWantAccessX = 1;
|
|
|
|
if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
|
|
XkbDfltAccessXTimeout = atoi(argv[++i]);
|
|
j++;
|
|
|
|
if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
|
|
/*
|
|
* presumption that the reasonably useful range of
|
|
* values fits in 0..MAXINT since SunOS 4 doesn't
|
|
* have strtoul.
|
|
*/
|
|
XkbDfltAccessXTimeoutMask = (unsigned int)
|
|
strtol(argv[++i], NULL, 16);
|
|
j++;
|
|
}
|
|
if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
|
|
if (argv[++i][0] == '1')
|
|
XkbDfltAccessXFeedback = XkbAccessXFeedbackMask;
|
|
else
|
|
XkbDfltAccessXFeedback = 0;
|
|
j++;
|
|
}
|
|
if (((i + 1) < argc) && (isdigit(argv[i + 1][0]))) {
|
|
XkbDfltAccessXOptions = (unsigned char)
|
|
strtol(argv[++i], NULL, 16);
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
return j;
|
|
}
|
|
if ((strcmp(argv[i], "-ardelay") == 0) || (strcmp(argv[i], "-ar1") == 0)) { /* -ardelay int */
|
|
if (++i >= argc)
|
|
UseMsg();
|
|
else
|
|
XkbDfltRepeatDelay = (long) atoi(argv[i]);
|
|
return 2;
|
|
}
|
|
if ((strcmp(argv[i], "-arinterval") == 0) || (strcmp(argv[i], "-ar2") == 0)) { /* -arinterval int */
|
|
if (++i >= argc)
|
|
UseMsg();
|
|
else
|
|
XkbDfltRepeatInterval = (long) atoi(argv[i]);
|
|
return 2;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
XkbUseMsg(void)
|
|
{
|
|
ErrorF
|
|
("[+-]accessx [ timeout [ timeout_mask [ feedback [ options_mask] ] ] ]\n");
|
|
ErrorF(" enable/disable accessx key sequences\n");
|
|
ErrorF("-ardelay set XKB autorepeat delay\n");
|
|
ErrorF("-arinterval set XKB autorepeat interval\n");
|
|
}
|