Merge remote-tracking branch 'whot/for-keith'

This commit is contained in:
Keith Packard 2014-03-19 06:43:14 -07:00
commit 4fb31e4824
7 changed files with 275 additions and 91 deletions

View File

@ -230,7 +230,7 @@ CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
mk->sourceid = device->id;
if (!XkbCopyDeviceKeymap(master, device))
if (!XkbDeviceApplyKeymap(master, device->key->xkbInfo->desc))
FatalError("Couldn't pivot keymap from device to core!\n");
}

View File

@ -385,6 +385,12 @@ extern _X_EXPORT Bool InitKeyboardDeviceStruct(DeviceIntPtr /*device */ ,
KbdCtrlProcPtr /*controlProc */
);
extern _X_EXPORT Bool InitKeyboardDeviceStructFromString(DeviceIntPtr dev,
const char *keymap,
int keymap_length,
BellProcPtr bell_func,
KbdCtrlProcPtr ctrl_func);
extern int ApplyPointerMapping(DeviceIntPtr /* pDev */ ,
CARD8 * /* map */ ,
int /* len */ ,

View File

@ -824,8 +824,8 @@ extern _X_EXPORT void XkbSendNewKeyboardNotify(DeviceIntPtr /* kbd */ ,
extern Bool XkbCopyKeymap(XkbDescPtr /* dst */ ,
XkbDescPtr /* src */ );
extern _X_EXPORT Bool XkbCopyDeviceKeymap(DeviceIntPtr /* dst */ ,
DeviceIntPtr /* src */ );
extern _X_EXPORT Bool XkbDeviceApplyKeymap(DeviceIntPtr /* dst */ ,
XkbDescPtr /* src */ );
extern void XkbFilterEvents(ClientPtr /* pClient */ ,
int /* nEvents */ ,
@ -841,6 +841,9 @@ extern void XkbFakeDeviceButton(DeviceIntPtr /* dev */ ,
int /* press */ ,
int /* button */ );
extern _X_EXPORT void XkbCopyControls(XkbDescPtr /* dst */ ,
XkbDescPtr /* src */ );
#include "xkbfile.h"
#include "xkbrules.h"
@ -873,4 +876,8 @@ extern _X_EXPORT XkbDescPtr XkbCompileKeymap(DeviceIntPtr /* dev */ ,
XkbRMLVOSet * /* rmlvo */
);
extern _X_EXPORT XkbDescPtr XkbCompileKeymapFromString(DeviceIntPtr dev,
const char *keymap,
int keymap_length);
#endif /* _XKBSRV_H_ */

View File

@ -68,6 +68,9 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define PATHSEPARATOR "/"
#endif
static unsigned
LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn);
static void
OutputDirectory(char *outdir, size_t size)
{
@ -90,11 +93,17 @@ OutputDirectory(char *outdir, size_t size)
}
}
static Bool
XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
XkbComponentNamesPtr names,
unsigned want,
unsigned need, char *nameRtrn, int nameRtrnLen)
/**
* Callback invoked by XkbRunXkbComp. Write to out to talk to xkbcomp.
*/
typedef void (*xkbcomp_buffer_callback)(FILE *out, void *userdata);
/**
* Start xkbcomp, let the callback write into xkbcomp's stdin. When done,
* return a strdup'd copy of the file name we've written to.
*/
static char *
RunXkbComp(xkbcomp_buffer_callback callback, void *userdata)
{
FILE *out;
char *buf = NULL, keymap[PATH_MAX], xkm_output_dir[PATH_MAX];
@ -155,7 +164,7 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
if (!buf) {
LogMessage(X_ERROR,
"XKB: Could not invoke xkbcomp: not enough memory\n");
return FALSE;
return NULL;
}
#ifndef WIN32
@ -165,13 +174,9 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
#endif
if (out != NULL) {
#ifdef DEBUG
if (xkbDebugFlags) {
ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
XkbWriteXKBKeymapForNames(stderr, names, xkb, want, need);
}
#endif
XkbWriteXKBKeymapForNames(out, names, xkb, want, need);
/* Now write to xkbcomp */
(*callback)(out, userdata);
#ifndef WIN32
if (Pclose(out) == 0)
#else
@ -180,14 +185,11 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
{
if (xkbDebugFlags)
DebugF("[xkb] xkb executes: %s\n", buf);
if (nameRtrn) {
strlcpy(nameRtrn, keymap, nameRtrnLen);
}
free(buf);
#ifdef WIN32
unlink(tmpname);
#endif
return TRUE;
return xnfstrdup(keymap);
}
else
LogMessage(X_ERROR, "Error compiling keymap (%s)\n", keymap);
@ -203,14 +205,101 @@ XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
LogMessage(X_ERROR, "Could not open file %s\n", tmpname);
#endif
}
if (nameRtrn)
nameRtrn[0] = '\0';
free(buf);
return FALSE;
return NULL;
}
typedef struct {
XkbDescPtr xkb;
XkbComponentNamesPtr names;
unsigned int want;
unsigned int need;
} XkbKeymapNamesCtx;
static void
xkb_write_keymap_for_names_cb(FILE *out, void *userdata)
{
XkbKeymapNamesCtx *ctx = userdata;
#ifdef DEBUG
if (xkbDebugFlags) {
ErrorF("[xkb] XkbDDXCompileKeymapByNames compiling keymap:\n");
XkbWriteXKBKeymapForNames(stderr, ctx->names, ctx->xkb, ctx->want, ctx->need);
}
#endif
XkbWriteXKBKeymapForNames(out, ctx->names, ctx->xkb, ctx->want, ctx->need);
}
static Bool
XkbDDXCompileKeymapByNames(XkbDescPtr xkb,
XkbComponentNamesPtr names,
unsigned want,
unsigned need, char *nameRtrn, int nameRtrnLen)
{
char *keymap;
Bool rc = FALSE;
XkbKeymapNamesCtx ctx = {
.xkb = xkb,
.names = names,
.want = want,
.need = need
};
keymap = RunXkbComp(xkb_write_keymap_for_names_cb, &ctx);
if (keymap) {
if(nameRtrn)
strlcpy(nameRtrn, keymap, nameRtrnLen);
free(keymap);
rc = TRUE;
} else if (nameRtrn)
*nameRtrn = '\0';
return rc;
}
typedef struct {
const char *keymap;
size_t len;
} XkbKeymapString;
static void
xkb_write_keymap_string_cb(FILE *out, void *userdata)
{
XkbKeymapString *s = userdata;
fwrite(s->keymap, s->len, 1, out);
}
static unsigned int
XkbDDXLoadKeymapFromString(DeviceIntPtr keybd,
const char *keymap, int keymap_length,
unsigned int want,
unsigned int need,
XkbDescPtr *xkbRtrn)
{
unsigned int have;
char *map_name;
XkbKeymapString map = {
.keymap = keymap,
.len = keymap_length
};
*xkbRtrn = NULL;
map_name = RunXkbComp(xkb_write_keymap_string_cb, &map);
if (!map_name) {
LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
return 0;
}
have = LoadXKM(want, need, map_name, xkbRtrn);
free(map_name);
return have;
}
static FILE *
XkbDDXOpenConfigFile(char *mapName, char *fileNameRtrn, int fileNameRtrnLen)
XkbDDXOpenConfigFile(const char *mapName, char *fileNameRtrn, int fileNameRtrnLen)
{
char buf[PATH_MAX], xkm_output_dir[PATH_MAX];
FILE *file;
@ -245,37 +334,14 @@ XkbDDXOpenConfigFile(char *mapName, char *fileNameRtrn, int fileNameRtrnLen)
return file;
}
unsigned
XkbDDXLoadKeymapByNames(DeviceIntPtr keybd,
XkbComponentNamesPtr names,
unsigned want,
unsigned need,
XkbDescPtr *xkbRtrn, char *nameRtrn, int nameRtrnLen)
static unsigned
LoadXKM(unsigned want, unsigned need, const char *keymap, XkbDescPtr *xkbRtrn)
{
XkbDescPtr xkb;
FILE *file;
char fileName[PATH_MAX];
unsigned missing;
*xkbRtrn = NULL;
if ((keybd == NULL) || (keybd->key == NULL) ||
(keybd->key->xkbInfo == NULL))
xkb = NULL;
else
xkb = keybd->key->xkbInfo->desc;
if ((names->keycodes == NULL) && (names->types == NULL) &&
(names->compat == NULL) && (names->symbols == NULL) &&
(names->geometry == NULL)) {
LogMessage(X_ERROR, "XKB: No components provided for device %s\n",
keybd->name ? keybd->name : "(unnamed keyboard)");
return 0;
}
else if (!XkbDDXCompileKeymapByNames(xkb, names, want, need,
nameRtrn, nameRtrnLen)) {
LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
return 0;
}
file = XkbDDXOpenConfigFile(nameRtrn, fileName, PATH_MAX);
file = XkbDDXOpenConfigFile(keymap, fileName, PATH_MAX);
if (file == NULL) {
LogMessage(X_ERROR, "Couldn't open compiled keymap file %s\n",
fileName);
@ -297,6 +363,37 @@ XkbDDXLoadKeymapByNames(DeviceIntPtr keybd,
return (need | want) & (~missing);
}
unsigned
XkbDDXLoadKeymapByNames(DeviceIntPtr keybd,
XkbComponentNamesPtr names,
unsigned want,
unsigned need,
XkbDescPtr *xkbRtrn, char *nameRtrn, int nameRtrnLen)
{
XkbDescPtr xkb;
*xkbRtrn = NULL;
if ((keybd == NULL) || (keybd->key == NULL) ||
(keybd->key->xkbInfo == NULL))
xkb = NULL;
else
xkb = keybd->key->xkbInfo->desc;
if ((names->keycodes == NULL) && (names->types == NULL) &&
(names->compat == NULL) && (names->symbols == NULL) &&
(names->geometry == NULL)) {
LogMessage(X_ERROR, "XKB: No components provided for device %s\n",
keybd->name ? keybd->name : "(unnamed keyboard)");
return 0;
}
else if (!XkbDDXCompileKeymapByNames(xkb, names, want, need,
nameRtrn, nameRtrnLen)) {
LogMessage(X_ERROR, "XKB: Couldn't compile keymap\n");
return 0;
}
return LoadXKM(want, need, nameRtrn, xkbRtrn);
}
Bool
XkbDDXNamesFromRules(DeviceIntPtr keybd,
const char *rules_name,
@ -390,6 +487,29 @@ XkbCompileKeymapForDevice(DeviceIntPtr dev, XkbRMLVOSet * rmlvo, int need)
return xkb;
}
static XkbDescPtr
KeymapOrDefaults(DeviceIntPtr dev, XkbDescPtr xkb)
{
XkbRMLVOSet dflts;
if (xkb)
return xkb;
/* we didn't get what we really needed. And that will likely leave
* us with a keyboard that doesn't work. Use the defaults instead */
LogMessage(X_ERROR, "XKB: Failed to load keymap. Loading default "
"keymap instead.\n");
XkbGetRulesDflts(&dflts);
xkb = XkbCompileKeymapForDevice(dev, &dflts, 0);
XkbFreeRMLVOSet(&dflts, FALSE);
return xkb;
}
XkbDescPtr
XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet * rmlvo)
{
@ -407,20 +527,34 @@ XkbCompileKeymap(DeviceIntPtr dev, XkbRMLVOSet * rmlvo)
xkb = XkbCompileKeymapForDevice(dev, rmlvo, need);
if (!xkb) {
XkbRMLVOSet dflts;
return KeymapOrDefaults(dev, xkb);
}
/* we didn't get what we really needed. And that will likely leave
* us with a keyboard that doesn't work. Use the defaults instead */
LogMessage(X_ERROR, "XKB: Failed to load keymap. Loading default "
"keymap instead.\n");
XkbDescPtr
XkbCompileKeymapFromString(DeviceIntPtr dev,
const char *keymap, int keymap_length)
{
XkbDescPtr xkb;
unsigned int need, provided;
XkbGetRulesDflts(&dflts);
xkb = XkbCompileKeymapForDevice(dev, &dflts, 0);
XkbFreeRMLVOSet(&dflts, FALSE);
if (!dev || !keymap) {
LogMessage(X_ERROR, "XKB: No device or keymap specified\n");
return NULL;
}
return xkb;
/* These are the components we really really need */
need = XkmSymbolsMask | XkmCompatMapMask | XkmTypesMask |
XkmKeyNamesMask | XkmVirtualModsMask;
provided =
XkbDDXLoadKeymapFromString(dev, keymap, keymap_length,
XkmAllIndicesMask, need, &xkb);
if ((need & provided) != need) {
if (xkb) {
XkbFreeKeyboard(xkb, 0, TRUE);
xkb = NULL;
}
}
return KeymapOrDefaults(dev, xkb);
}

View File

@ -5950,25 +5950,13 @@ ProcXkbGetKbdByName(ClientPtr client)
if (rep.loaded) {
XkbDescPtr old_xkb;
xkbNewKeyboardNotify nkn;
int i, nG, nTG;
old_xkb = xkb;
xkb = new;
dev->key->xkbInfo->desc = xkb;
new = old_xkb; /* so it'll get freed automatically */
*xkb->ctrls = *old_xkb->ctrls;
for (nG = nTG = 0, i = xkb->min_key_code; i <= xkb->max_key_code; i++) {
nG = XkbKeyNumGroups(xkb, i);
if (nG >= XkbNumKbdGroups) {
nTG = XkbNumKbdGroups;
break;
}
if (nG > nTG) {
nTG = nG;
}
}
xkb->ctrls->num_groups = nTG;
XkbCopyControls(xkb, old_xkb);
nkn.deviceID = nkn.oldDeviceID = dev->id;
nkn.minKeyCode = new->min_key_code;
@ -5991,7 +5979,7 @@ ProcXkbGetKbdByName(ClientPtr client)
continue;
if (tmpd != dev)
XkbCopyDeviceKeymap(tmpd, dev);
XkbDeviceApplyKeymap(tmpd, xkb);
if (tmpd->kbdfeed && tmpd->kbdfeed->xkb_sli) {
old_sli = tmpd->kbdfeed->xkb_sli;

View File

@ -505,9 +505,10 @@ XkbInitControls(DeviceIntPtr pXDev, XkbSrvInfoPtr xkbi)
return Success;
}
_X_EXPORT Bool
InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
static Bool
InitKeyboardDeviceStructInternal(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
const char *keymap, int keymap_length,
BellProcPtr bell_func, KbdCtrlProcPtr ctrl_func)
{
int i;
unsigned int check;
@ -521,8 +522,9 @@ InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
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) {
if (!rmlvo && !keymap) {
rmlvo = &rmlvo_dflts;
XkbGetRulesDflts(rmlvo);
}
@ -550,7 +552,7 @@ InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
}
dev->key->xkbInfo = xkbi;
if (xkb_cached_map && !XkbCompareUsedRMLVO(rmlvo)) {
if (xkb_cached_map && (keymap || (rmlvo && !XkbCompareUsedRMLVO(rmlvo)))) {
XkbFreeKeyboard(xkb_cached_map, XkbAllComponentsMask, TRUE);
xkb_cached_map = NULL;
}
@ -558,7 +560,11 @@ InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
if (xkb_cached_map)
LogMessageVerb(X_INFO, 4, "XKB: Reusing cached keymap\n");
else {
xkb_cached_map = XkbCompileKeymap(dev, rmlvo);
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;
@ -627,8 +633,10 @@ InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
dev->kbdfeed->CtrlProc(dev, &dev->kbdfeed->ctrl);
XkbSetRulesDflts(rmlvo);
XkbSetRulesUsed(rmlvo);
if (rmlvo) {
XkbSetRulesDflts(rmlvo);
XkbSetRulesUsed(rmlvo);
}
XkbFreeRMLVOSet(&rmlvo_dflts, FALSE);
return TRUE;
@ -647,6 +655,24 @@ InitKeyboardDeviceStruct(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
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);
}
/***====================================================================***/
/*

View File

@ -1999,28 +1999,28 @@ XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src)
}
Bool
XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src)
XkbDeviceApplyKeymap(DeviceIntPtr dst, XkbDescPtr desc)
{
xkbNewKeyboardNotify nkn;
Bool ret;
if (!dst->key || !src->key)
if (!dst->key || !desc)
return FALSE;
memset(&nkn, 0, sizeof(xkbNewKeyboardNotify));
nkn.oldMinKeyCode = dst->key->xkbInfo->desc->min_key_code;
nkn.oldMaxKeyCode = dst->key->xkbInfo->desc->max_key_code;
nkn.deviceID = dst->id;
nkn.oldDeviceID = dst->id; /* maybe src->id? */
nkn.minKeyCode = src->key->xkbInfo->desc->min_key_code;
nkn.maxKeyCode = src->key->xkbInfo->desc->max_key_code;
nkn.oldDeviceID = dst->id;
nkn.minKeyCode = desc->min_key_code;
nkn.maxKeyCode = desc->max_key_code;
nkn.requestMajor = XkbReqCode;
nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */
nkn.changed = XkbNKN_KeycodesMask;
if (src->key->xkbInfo->desc->geom)
if (desc->geom)
nkn.changed |= XkbNKN_GeometryMask;
ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc);
ret = XkbCopyKeymap(dst->key->xkbInfo->desc, desc);
if (ret)
XkbSendNewKeyboardNotify(dst, &nkn);
@ -2090,3 +2090,26 @@ XkbMergeLockedPtrBtns(DeviceIntPtr master)
xkbi->lockedPtrButtons |= d->key->xkbInfo->lockedPtrButtons;
}
}
void
XkbCopyControls(XkbDescPtr dst, XkbDescPtr src)
{
int i, nG, nTG;
if (!dst || !src)
return;
*dst->ctrls = *src->ctrls;
for (nG = nTG = 0, i = dst->min_key_code; i <= dst->max_key_code; i++) {
nG = XkbKeyNumGroups(dst, i);
if (nG >= XkbNumKbdGroups) {
nTG = XkbNumKbdGroups;
break;
}
if (nG > nTG) {
nTG = nG;
}
}
dst->ctrls->num_groups = nTG;
}