Input: Clean up keymap change notifications

Keyboard map notifications are always generated from within XKB code,
which also takes care of copying the keysyms, etc.  If you need to
mangle the keymap yourself, generate a new core keymap/modmap, and pass
it to XkbApplyMappingChange.

SendMappingNotify is renamed to SendPointerMappingNotify (and ditto its
Device variants), which still only _sends_ the notifications, as opposed
to also doing the copying a la XkbApplyMappingChange.

Also have the modmap change code traverse the device hierachy, rather
than just going off the core keyboard.

Signed-off-by: Daniel Stone <daniel@fooishbar.org>
This commit is contained in:
Daniel Stone 2008-10-18 20:59:30 +01:00
parent 1d1a0f67ee
commit f06a9d2e05
11 changed files with 382 additions and 362 deletions

View File

@ -205,41 +205,20 @@ XIGetDevice(xEvent* xE)
static void static void
CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master) CopyKeyClass(DeviceIntPtr device, DeviceIntPtr master)
{ {
static DeviceIntPtr lastMapNotifyDevice = NULL; KeyClassPtr mk = master->key;
KeyClassPtr mk, dk; /* master, device */ KeyClassPtr dk = device->key;
int i; int i;
if (device == master) if (device == master)
return; return;
dk = device->key;
mk = master->key;
mk->curKeySyms.minKeyCode = dk->curKeySyms.minKeyCode;
mk->curKeySyms.maxKeyCode = dk->curKeySyms.maxKeyCode;
SetKeySymsMap(&mk->curKeySyms, &dk->curKeySyms); SetKeySymsMap(&mk->curKeySyms, &dk->curKeySyms);
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
mk->modifierKeyCount[i] = dk->modifierKeyCount[i]; mk->modifierKeyCount[i] = dk->modifierKeyCount[i];
if (!XkbCopyKeymap(dk->xkbInfo->desc, mk->xkbInfo->desc, True)) if (!XkbCopyDeviceKeymap(master, device))
FatalError("Couldn't pivot keymap from device to core!\n"); FatalError("Couldn't pivot keymap from device to core!\n");
/* Copy the state here. This means we'll only have consistency
* between state and active keymap, rather than between state and
* keycodes pressed, but there's pretty much no way to win here,
* so might as well go for the one that would seem to give the
* least nonsensical result. */
mk->xkbInfo->state = dk->xkbInfo->state;
if (lastMapNotifyDevice != master) {
SendMappingNotify(master, MappingKeyboard,
mk->curKeySyms.minKeyCode,
(mk->curKeySyms.maxKeyCode -
mk->curKeySyms.minKeyCode),
serverClient);
lastMapNotifyDevice = master;
}
} }
/** /**
@ -1661,23 +1640,15 @@ SetButtonMapping(ClientPtr client, DeviceIntPtr dev, int nElts, BYTE * map)
} }
void void
SendDeviceMappingNotify(ClientPtr client, CARD8 request, SendDevicePointerMappingNotify(ClientPtr client, DeviceIntPtr dev)
KeyCode firstKeyCode, CARD8 count, DeviceIntPtr dev)
{ {
xEvent event; xEvent event;
deviceMappingNotify *ev = (deviceMappingNotify *) & event; deviceMappingNotify *ev = (deviceMappingNotify *) & event;
ev->type = DeviceMappingNotify; ev->type = DeviceMappingNotify;
ev->request = request; ev->request = MappingPointer;
ev->deviceid = dev->id; ev->deviceid = dev->id;
ev->time = currentTime.milliseconds; ev->time = currentTime.milliseconds;
if (request == MappingKeyboard) {
ev->firstKeyCode = firstKeyCode;
ev->count = count;
}
if (request == MappingKeyboard || request == MappingModifier)
XkbApplyMappingChange(dev, request, firstKeyCode, count, client);
SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) ev, 1); SendEventToAllWindows(dev, DeviceMappingNotifyMask, (xEvent *) ev, 1);
} }
@ -1712,9 +1683,10 @@ ChangeKeyMapping(ClientPtr client,
keysyms.maxKeyCode = firstKeyCode + keyCodes - 1; keysyms.maxKeyCode = firstKeyCode + keyCodes - 1;
keysyms.mapWidth = keySymsPerKeyCode; keysyms.mapWidth = keySymsPerKeyCode;
keysyms.map = map; keysyms.map = map;
if (!SetKeySymsMap(&k->curKeySyms, &keysyms))
return BadAlloc; XkbApplyMappingChange(dev, &keysyms, firstKeyCode, keyCodes, NULL,
SendDeviceMappingNotify(client, MappingKeyboard, firstKeyCode, keyCodes, dev); serverClient);
return client->noClientException; return client->noClientException;
} }

View File

@ -121,7 +121,8 @@ ProcXSetDeviceButtonMapping(ClientPtr client)
} }
if (ret != MappingBusy) if (ret != MappingBusy)
SendDeviceMappingNotify(client, MappingPointer, 0, 0, dev); SendDevicePointerMappingNotify(client, dev);
return Success; return Success;
} }

View File

@ -1013,17 +1013,18 @@ QueryMinMaxKeyCodes(KeyCode *minCode, KeyCode *maxCode)
} }
} }
/* Notably, this function does not expand the destination's keycode range, or
* notify clients. */
Bool Bool
SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src) SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src)
{ {
int i, j; int i, j;
KeySym *tmp;
int rowDif = src->minKeyCode - dst->minKeyCode; int rowDif = src->minKeyCode - dst->minKeyCode;
/* if keysym map size changes, grow map first */ /* if keysym map size changes, grow map first */
if (src->mapWidth < dst->mapWidth) if (src->mapWidth < dst->mapWidth) {
{ for (i = src->minKeyCode; i <= src->maxKeyCode; i++) {
for (i = src->minKeyCode; i <= src->maxKeyCode; i++)
{
#define SI(r, c) (((r - src->minKeyCode) * src->mapWidth) + (c)) #define SI(r, c) (((r - src->minKeyCode) * src->mapWidth) + (c))
#define DI(r, c) (((r - dst->minKeyCode) * dst->mapWidth) + (c)) #define DI(r, c) (((r - dst->minKeyCode) * dst->mapWidth) + (c))
for (j = 0; j < src->mapWidth; j++) for (j = 0; j < src->mapWidth; j++)
@ -1035,39 +1036,37 @@ SetKeySymsMap(KeySymsPtr dst, KeySymsPtr src)
} }
return TRUE; return TRUE;
} }
else if (src->mapWidth > dst->mapWidth) else if (src->mapWidth > dst->mapWidth) {
{ i = sizeof(KeySym) * src->mapWidth *
KeySym *map;
int bytes = sizeof(KeySym) * src->mapWidth *
(dst->maxKeyCode - dst->minKeyCode + 1); (dst->maxKeyCode - dst->minKeyCode + 1);
map = (KeySym *)xcalloc(1, bytes); tmp = xcalloc(sizeof(KeySym), i);
if (!map) if (!tmp)
return FALSE; return FALSE;
if (dst->map)
{ if (dst->map) {
for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++) for (i = 0; i <= dst->maxKeyCode-dst->minKeyCode; i++)
memmove((char *)&map[i*src->mapWidth], memmove(&tmp[i * src->mapWidth], &dst->map[i * dst->mapWidth],
(char *)&dst->map[i*dst->mapWidth],
dst->mapWidth * sizeof(KeySym)); dst->mapWidth * sizeof(KeySym));
xfree(dst->map); xfree(dst->map);
} }
dst->mapWidth = src->mapWidth; dst->mapWidth = src->mapWidth;
dst->map = map; dst->map = tmp;
} else if (!dst->map) }
{ else if (!dst->map) {
KeySym *map; i = sizeof(KeySym) * src->mapWidth *
int bytes = sizeof(KeySym) * src->mapWidth *
(dst->maxKeyCode - dst->minKeyCode + 1); (dst->maxKeyCode - dst->minKeyCode + 1);
map = (KeySym *)xcalloc(1, bytes); tmp = xcalloc(sizeof(KeySym), i);
if (!map) if (!tmp)
return FALSE; return FALSE;
dst->map = map;
dst->map = tmp;
dst->mapWidth = src->mapWidth; dst->mapWidth = src->mapWidth;
} }
memmove((char *)&dst->map[rowDif * dst->mapWidth],
(char *)src->map, memmove(&dst->map[rowDif * dst->mapWidth], src->map,
(int)(src->maxKeyCode - src->minKeyCode + 1) * (src->maxKeyCode - src->minKeyCode + 1) *
dst->mapWidth * sizeof(KeySym)); dst->mapWidth * sizeof(KeySym));
return TRUE; return TRUE;
} }
@ -1398,32 +1397,22 @@ InitPointerDeviceStruct(DevicePtr device, CARD8 *map, int numButtons,
} }
_X_EXPORT void _X_EXPORT void
SendMappingNotify(DeviceIntPtr pDev, unsigned request, unsigned firstKeyCode, SendPointerMappingNotify(DeviceIntPtr pDev, ClientPtr client)
unsigned count, ClientPtr client)
{ {
int i; int i;
xEvent event; xEvent event;
event.u.u.type = MappingNotify; /* 0 is the server client. */
event.u.mappingNotify.request = request; for (i = 1; i < currentMaxClients; i++) {
if (request == MappingKeyboard) /* Don't send irrelevant events to naïve clients. */
{ if (PickPointer(clients[i]) != pDev)
event.u.mappingNotify.firstKeyCode = firstKeyCode;
event.u.mappingNotify.count = count;
}
if (request == MappingKeyboard || request == MappingModifier)
XkbApplyMappingChange(pDev,request,firstKeyCode,count, client);
/* 0 is the server client */
for (i=1; i<currentMaxClients; i++)
{
if (clients[i] && clients[i]->clientState == ClientStateRunning)
{
if (request == MappingKeyboard &&
clients[i]->xkbClientFlags != 0 &&
(clients[i]->mapNotifyMask & XkbKeySymsMask))
continue; continue;
if (clients[i] && clients[i]->clientState == ClientStateRunning) {
event.u.u.type = MappingNotify;
event.u.u.sequenceNumber = clients[i]->sequence; event.u.u.sequenceNumber = clients[i]->sequence;
event.u.mappingNotify.request = MappingPointer;
WriteEventsToClient(clients[i], 1, &event); WriteEventsToClient(clients[i], 1, &event);
} }
} }
@ -1516,7 +1505,7 @@ ProcChangeKeyboardMapping(ClientPtr client)
unsigned len; unsigned len;
KeySymsRec keysyms; KeySymsRec keysyms;
KeySymsPtr curKeySyms = &PickKeyboard(client)->key->curKeySyms; KeySymsPtr curKeySyms = &PickKeyboard(client)->key->curKeySyms;
DeviceIntPtr pDev = NULL; DeviceIntPtr pDev, tmp;
int rc; int rc;
REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq); REQUEST_AT_LEAST_SIZE(xChangeKeyboardMappingReq);
@ -1536,28 +1525,30 @@ ProcChangeKeyboardMapping(ClientPtr client)
return BadValue; return BadValue;
} }
for (pDev = inputInfo.devices; pDev; pDev = pDev->next) {
if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) {
rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
if (rc != Success)
return rc;
}
}
keysyms.minKeyCode = stuff->firstKeyCode; keysyms.minKeyCode = stuff->firstKeyCode;
keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1; keysyms.maxKeyCode = stuff->firstKeyCode + stuff->keyCodes - 1;
keysyms.mapWidth = stuff->keySymsPerKeyCode; keysyms.mapWidth = stuff->keySymsPerKeyCode;
keysyms.map = (KeySym *) &stuff[1]; keysyms.map = (KeySym *) &stuff[1];
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key)
if (!SetKeySymsMap(&pDev->key->curKeySyms, &keysyms))
return BadAlloc;
for (pDev = inputInfo.devices; pDev; pDev = pDev->next) pDev = PickKeyboard(client);
if (pDev->key && pDev->coreEvents) rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
SendDeviceMappingNotify(client, MappingKeyboard, if (rc != Success)
stuff->firstKeyCode, stuff->keyCodes, return rc;
pDev);
XkbApplyMappingChange(pDev, &keysyms, stuff->firstKeyCode,
stuff->keyCodes, NULL, client);
for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
if (tmp->isMaster || tmp->u.master != pDev)
continue;
rc = XaceHook(XACE_DEVICE_ACCESS, client, pDev, DixManageAccess);
if (rc != Success)
continue;
XkbApplyMappingChange(tmp, &keysyms, stuff->firstKeyCode,
stuff->keyCodes, NULL, client);
}
return client->noClientException; return client->noClientException;
} }
@ -1639,7 +1630,8 @@ ProcSetPointerMapping(ClientPtr client)
return Success; return Success;
} }
SendMappingNotify(ptr, MappingPointer, 0, 0, client); /* FIXME: Send mapping notifies for masters/slaves as well. */
SendPointerMappingNotify(ptr, client);
WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep); WriteReplyToClient(client, sizeof(xSetPointerMappingReply), &rep);
return Success; return Success;
} }

View File

@ -132,8 +132,7 @@ check_modmap_change_slave(ClientPtr client, DeviceIntPtr master,
static void static void
do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap) do_modmap_change(ClientPtr client, DeviceIntPtr dev, CARD8 *modmap)
{ {
memcpy(dev->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH); XkbApplyMappingChange(dev, NULL, 0, 0, modmap, serverClient);
SendDeviceMappingNotify(client, MappingModifier, 0, 0, dev);
} }
/* Rebuild modmap (key -> mod) from map (mod -> key). */ /* Rebuild modmap (key -> mod) from map (mod -> key). */
@ -165,7 +164,7 @@ change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap,
{ {
int ret; int ret;
CARD8 modmap[MAP_LENGTH]; CARD8 modmap[MAP_LENGTH];
DeviceIntPtr slave; DeviceIntPtr tmp;
ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod); ret = build_modmap_from_modkeymap(modmap, modkeymap, max_keys_per_mod);
if (ret != Success) if (ret != Success)
@ -177,12 +176,21 @@ change_modmap(ClientPtr client, DeviceIntPtr dev, KeyCode *modkeymap,
return ret; return ret;
do_modmap_change(client, dev, modmap); do_modmap_change(client, dev, modmap);
/* If we're acting on a master, change the slaves as well. */ /* Change any attached masters/slaves. */
if (dev->isMaster) { if (dev->isMaster) {
for (slave = inputInfo.devices; slave; slave = slave->next) { for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
if (slave != dev && !slave->isMaster && slave->u.master == dev) if (!tmp->isMaster && tmp->u.master == dev)
if (check_modmap_change_slave(client, dev, slave, modmap)) if (check_modmap_change_slave(client, dev, tmp, modmap))
do_modmap_change(client, slave, modmap); do_modmap_change(client, tmp, modmap);
}
}
else {
for (tmp = inputInfo.devices; tmp; tmp = tmp->next) {
if (tmp->isMaster && tmp->u.lastSlave == dev) {
/* If this fails, expect the results to be weird. */
if (check_modmap_change(client, tmp, modmap))
do_modmap_change(client, tmp, modmap);
}
} }
} }

View File

@ -293,26 +293,15 @@ static void DarwinLoadKeyboardMapping(KeySymsRec *keySyms) {
* DarwinKeyboardSetDeviceKeyMap * DarwinKeyboardSetDeviceKeyMap
* Load a keymap into the keyboard device * Load a keymap into the keyboard device
*/ */
static void DarwinKeyboardSetDeviceKeyMap(KeySymsRec *keySyms) { static void DarwinKeyboardSetDeviceKeyMap(KeySymsRec *keySyms, CARD8 *modmap) {
DeviceIntPtr pDev; DeviceIntPtr pDev;
/* From ProcSetModifierMapping */
SendMappingNotify(darwinKeyboard, MappingModifier, 0, 0, serverClient);
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
if (pDev->key && pDev->coreEvents)
SendDeviceMappingNotify(serverClient, MappingModifier, 0, 0, pDev);
/* From ProcChangeKeyboardMapping */
for (pDev = inputInfo.devices; pDev; pDev = pDev->next) for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key) if ((pDev->coreEvents || pDev == inputInfo.keyboard) && pDev->key)
assert(SetKeySymsMap(&pDev->key->curKeySyms, keySyms)); XkbApplyMappingChange(pDev, XkbKeySymsMask | XkbModifierMapMask,
keysyms, keysyms.minKeyCode,
SendMappingNotify(darwinKeyboard, MappingKeyboard, keySyms->minKeyCode, keysyms.maxKeyCode - keysyms.minKeyCode + 1,
keySyms->maxKeyCode - keySyms->minKeyCode + 1, serverClient); modmap, serverClient);
for (pDev = inputInfo.devices; pDev; pDev = pDev->next)
if (pDev->key && pDev->coreEvents)
SendDeviceMappingNotify(serverClient, MappingKeyboard, keySyms->minKeyCode,
keySyms->maxKeyCode - keySyms->minKeyCode + 1, pDev);
} }
/* /*
@ -340,14 +329,11 @@ void DarwinKeyboardInit(DeviceIntPtr pDev) {
//XkbSetRulesDflts("base", "pc105", "us", NULL, NULL); //XkbSetRulesDflts("base", "pc105", "us", NULL, NULL);
pthread_mutex_lock(&keyInfo_mutex); pthread_mutex_lock(&keyInfo_mutex);
assert(XkbInitKeyboardDeviceStruct(pDev, &names, &keySyms, keyInfo.modMap, assert(XkbInitKeyboardDeviceStruct(pDev, &names, &keySyms, QuartzBell,
QuartzBell, DarwinChangeKeyboardControl)); DarwinChangeKeyboardControl));
assert(pDev->key->xkbInfo->desc->map->modmap!=NULL); assert(keyInfo.modMap!=NULL);
memcpy(pDev->key->xkbInfo->desc->map->modmap, keyInfo.modMap, sizeof(keyInfo.modMap));
pthread_mutex_unlock(&keyInfo_mutex); pthread_mutex_unlock(&keyInfo_mutex);
QuartzXkbUpdate(pDev);
#else
pthread_mutex_lock(&keyInfo_mutex); pthread_mutex_lock(&keyInfo_mutex);
assert( InitKeyboardDeviceStruct( (DevicePtr)pDev, &keySyms, assert( InitKeyboardDeviceStruct( (DevicePtr)pDev, &keySyms,
QuartzBell, QuartzBell,
@ -373,7 +359,7 @@ void DarwinKeyboardInit(DeviceIntPtr pDev) {
XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn); XkbSetRepeatKeys(pDev, -1, AutoRepeatModeOn);
} }
DarwinKeyboardSetDeviceKeyMap(&keySyms); DarwinKeyboardSetDeviceKeyMap(&keySyms, keyInfo.modMap);
} }
void DarwinKeyboardReloadHandler(int screenNum, xEventPtr xe, DeviceIntPtr pDev, int nevents) { void DarwinKeyboardReloadHandler(int screenNum, xEventPtr xe, DeviceIntPtr pDev, int nevents) {

View File

@ -137,11 +137,8 @@ extern _X_EXPORT int SetButtonMapping (
int /* nElts */, int /* nElts */,
BYTE * /* map */); BYTE * /* map */);
extern _X_EXPORT void SendDeviceMappingNotify( extern _X_EXPORT void SendDevicePointerMappingNotify(
ClientPtr /* client, */, ClientPtr /* client, */,
CARD8 /* request, */,
KeyCode /* firstKeyCode */,
CARD8 /* count */,
DeviceIntPtr /* dev */); DeviceIntPtr /* dev */);
extern _X_EXPORT int ChangeKeyMapping( extern _X_EXPORT int ChangeKeyMapping(

View File

@ -368,11 +368,8 @@ extern _X_EXPORT Bool InitKeyboardDeviceStruct(
BellProcPtr /*bellProc*/, BellProcPtr /*bellProc*/,
KbdCtrlProcPtr /*controlProc*/); KbdCtrlProcPtr /*controlProc*/);
extern _X_EXPORT void SendMappingNotify( extern _X_EXPORT void SendPointerMappingNotify(
DeviceIntPtr /* pDev */, DeviceIntPtr /* pDev */,
unsigned int /*request*/,
unsigned int /*firstKeyCode*/,
unsigned int /*count*/,
ClientPtr /* client */); ClientPtr /* client */);
extern _X_EXPORT Bool BadDeviceMap( extern _X_EXPORT Bool BadDeviceMap(

View File

@ -538,9 +538,10 @@ extern _X_EXPORT void XkbUpdateCoreDescription(
extern _X_EXPORT void XkbApplyMappingChange( extern _X_EXPORT void XkbApplyMappingChange(
DeviceIntPtr /* pXDev */, DeviceIntPtr /* pXDev */,
CARD8 /* request */, KeySymsPtr /* map */,
KeyCode /* firstKey */, KeyCode /* firstKey */,
CARD8 /* num */, CARD8 /* num */,
CARD8 * /* modmap */,
ClientPtr /* client */ ClientPtr /* client */
); );
@ -955,8 +956,11 @@ extern _X_EXPORT void XkbSendNewKeyboardNotify(
extern Bool XkbCopyKeymap( extern Bool XkbCopyKeymap(
XkbDescPtr /* dst */, XkbDescPtr /* dst */,
XkbDescPtr /* src */, XkbDescPtr /* src */);
Bool /* sendNotifies */);
extern Bool XkbCopyDeviceKeymap(
DeviceIntPtr /* dst */,
DeviceIntPtr /* src */);
#include "xkbfile.h" #include "xkbfile.h"
#include <X11/extensions/XKMformat.h> #include <X11/extensions/XKMformat.h>

View File

@ -5837,8 +5837,7 @@ ProcXkbGetKbdByName(ClientPtr client)
(dev->id == inputInfo.keyboard->id && tmpd->key && (dev->id == inputInfo.keyboard->id && tmpd->key &&
tmpd->coreEvents)) { tmpd->coreEvents)) {
if (tmpd != dev) if (tmpd != dev)
XkbCopyKeymap(dev->key->xkbInfo->desc, XkbCopyDeviceKeymap(tmpd, dev);
tmpd->key->xkbInfo->desc, True);
XkbUpdateCoreDescription(tmpd, True); XkbUpdateCoreDescription(tmpd, True);
if (tmpd->kbdfeed && tmpd->kbdfeed->xkb_sli) { if (tmpd->kbdfeed && tmpd->kbdfeed->xkb_sli) {

View File

@ -35,6 +35,8 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <X11/extensions/XI.h> #include <X11/extensions/XI.h>
#include <X11/extensions/XIproto.h> #include <X11/extensions/XIproto.h>
#include "inputstr.h" #include "inputstr.h"
#include "exevents.h"
#include "exglobals.h"
#include "windowstr.h" #include "windowstr.h"
#include "exevents.h" #include "exevents.h"
#include <xkbsrv.h> #include <xkbsrv.h>
@ -42,58 +44,151 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE.
/***====================================================================***/ /***====================================================================***/
/*
* This function sends out two kinds of notification:
* - Core mapping notify events sent to clients for whom kbd is the
* current core ('picked') keyboard _and_ have not explicitly
* selected for XKB mapping notify events;
* - Xi mapping events, sent unconditionally to all clients who have
* explicitly selected for them (including those who have explicitly
* selected for XKB mapping notify events!).
*/
static void
XkbSendLegacyMapNotify(DeviceIntPtr kbd, CARD16 xkb_event, CARD16 changed,
int first_key, int num_keys)
{
int i;
int keymap_changed = 0;
int modmap_changed = 0;
xEvent core_mn;
deviceMappingNotify xi_mn;
CARD32 time = GetTimeInMillis();
if (xkb_event == XkbNewKeyboardNotify) {
if (changed & XkbNKN_KeycodesMask) {
keymap_changed = 1;
modmap_changed = 1;
}
}
else if (xkb_event == XkbMapNotify) {
if (changed & XkbKeySymsMask)
keymap_changed = 1;
if (changed & XkbModifierMapMask)
modmap_changed = 1;
}
if (!keymap_changed && !modmap_changed)
return;
core_mn.u.u.type = MappingNotify;
xi_mn.type = DeviceMappingNotify;
xi_mn.deviceid = kbd->id;
xi_mn.time = time;
/* 0 is serverClient. */
for (i = 1; i < currentMaxClients; i++) {
if (!clients[i] || clients[i]->clientState != ClientStateRunning)
continue;
/* Ignore clients which will have already received this.
* Inconsistent with themselves, but consistent with previous
* behaviour.*/
if (xkb_event == XkbMapNotify && (clients[i]->mapNotifyMask & changed))
continue;
if (xkb_event == XkbNewKeyboardNotify &&
(clients[i]->xkbClientFlags & _XkbClientInitialized))
continue;
/* Don't send core events to clients who don't know about us. */
if (!XIShouldNotify(clients[i], kbd))
continue;
core_mn.u.u.sequenceNumber = clients[i]->sequence;
if (keymap_changed) {
core_mn.u.mappingNotify.request = MappingKeyboard;
/* Clip the keycode range to what the client knows about, so it
* doesn't freak out. */
if (first_key >= clients[i]->minKC)
core_mn.u.mappingNotify.firstKeyCode = first_key;
else
core_mn.u.mappingNotify.firstKeyCode = clients[i]->minKC;
if (first_key + num_keys - 1 <= clients[i]->maxKC)
core_mn.u.mappingNotify.count = num_keys;
else
core_mn.u.mappingNotify.count = clients[i]->maxKC -
clients[i]->minKC + 1;
WriteEventsToClient(clients[i], 1, &core_mn);
}
if (modmap_changed) {
core_mn.u.mappingNotify.request = MappingModifier;
core_mn.u.mappingNotify.firstKeyCode = 0;
core_mn.u.mappingNotify.count = 0;
WriteEventsToClient(clients[i], 1, &core_mn);
}
}
/* Hmm, maybe we can accidentally generate Xi events for core devices
* here? Clients might be upset, but that seems better than the
* alternative of stale keymaps. -ds */
if (keymap_changed) {
xi_mn.request = MappingKeyboard;
xi_mn.firstKeyCode = first_key;
xi_mn.count = num_keys;
SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
1);
}
if (modmap_changed) {
xi_mn.request = MappingModifier;
xi_mn.firstKeyCode = 0;
xi_mn.count = 0;
SendEventToAllWindows(kbd, DeviceMappingNotifyMask, (xEvent *) &xi_mn,
1);
}
}
/***====================================================================***/
void void
XkbSendNewKeyboardNotify(DeviceIntPtr kbd,xkbNewKeyboardNotify *pNKN) XkbSendNewKeyboardNotify(DeviceIntPtr kbd,xkbNewKeyboardNotify *pNKN)
{ {
register int i; int i;
Time time; Time time = GetTimeInMillis();
CARD16 changed; CARD16 changed = pNKN->changed;
pNKN->type = XkbEventCode + XkbEventBase; pNKN->type = XkbEventCode + XkbEventBase;
pNKN->xkbType = XkbNewKeyboardNotify; pNKN->xkbType = XkbNewKeyboardNotify;
pNKN->time = time = GetTimeInMillis();
changed = pNKN->changed;
for (i=1; i<currentMaxClients; i++) { for (i=1; i<currentMaxClients; i++) {
if ((!clients[i]) || clients[i]->clientGone || if (!clients[i] || clients[i]->clientState != ClientStateRunning)
(clients[i]->requestVector==InitialVector)) { continue;
if (!(clients[i]->newKeyboardNotifyMask & changed))
continue;
if (!XIShouldNotify(clients[i], kbd))
continue; continue;
}
if (clients[i]->xkbClientFlags&_XkbClientInitialized) {
if (clients[i]->newKeyboardNotifyMask&changed) {
pNKN->sequenceNumber = clients[i]->sequence; pNKN->sequenceNumber = clients[i]->sequence;
pNKN->time = time; pNKN->time = time;
pNKN->changed = changed; pNKN->changed = changed;
if (clients[i]->swapped) { if (clients[i]->swapped) {
register int n; int n;
swaps(&pNKN->sequenceNumber,n); swaps(&pNKN->sequenceNumber,n);
swapl(&pNKN->time,n); swapl(&pNKN->time,n);
swaps(&pNKN->changed,n); swaps(&pNKN->changed,n);
} }
WriteToClient(clients[i],sizeof(xEvent),(char *)pNKN); WriteToClient(clients[i], sizeof(xEvent), pNKN);
if (changed & XkbNKN_KeycodesMask) { if (changed & XkbNKN_KeycodesMask) {
clients[i]->minKC = pNKN->minKeyCode; clients[i]->minKC = pNKN->minKeyCode;
clients[i]->maxKC = pNKN->maxKeyCode; clients[i]->maxKC = pNKN->maxKeyCode;
} }
} }
}
else if (changed&XkbNKN_KeycodesMask) { XkbSendLegacyMapNotify(kbd, XkbNewKeyboardNotify, changed, pNKN->minKeyCode,
xEvent event; pNKN->maxKeyCode - pNKN->minKeyCode + 1);
event.u.u.type= MappingNotify;
event.u.mappingNotify.request= MappingKeyboard;
event.u.mappingNotify.firstKeyCode= clients[i]->minKC;
event.u.mappingNotify.count= clients[i]->maxKC-clients[i]->minKC+1;
event.u.u.sequenceNumber= clients[i]->sequence;
if (clients[i]->swapped) {
int n;
swaps(&event.u.u.sequenceNumber,n);
}
WriteToClient(clients[i],SIZEOF(xEvent), (char *)&event);
event.u.mappingNotify.request= MappingModifier;
WriteToClient(clients[i],SIZEOF(xEvent), (char *)&event);
}
}
return; return;
} }
@ -139,7 +234,8 @@ register CARD16 changed,bState;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->stateNotifyMask&changed)) { (interest->stateNotifyMask&changed) &&
XIShouldNotify(interest->client,kbd)) {
pSN->sequenceNumber = interest->client->sequence; pSN->sequenceNumber = interest->client->sequence;
pSN->time = time; pSN->time = time;
pSN->changed = changed; pSN->changed = changed;
@ -160,49 +256,50 @@ register CARD16 changed,bState;
/***====================================================================***/ /***====================================================================***/
/*
* This function sends out XKB mapping notify events to clients which
* have explicitly selected for them. Core and Xi events are handled by
* XkbSendLegacyMapNotify. */
void void
XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify *pMN) XkbSendMapNotify(DeviceIntPtr kbd, xkbMapNotify *pMN)
{ {
int i; int i;
XkbSrvInfoPtr xkbi; CARD32 time = GetTimeInMillis();
unsigned time = 0,initialized; CARD16 changed = pMN->changed;
CARD16 changed; XkbSrvInfoPtr xkbi = kbd->key->xkbInfo;
if (!kbd->key || !kbd->key->xkbInfo)
return;
xkbi = kbd->key->xkbInfo;
initialized= 0;
changed = pMN->changed;
pMN->minKeyCode = xkbi->desc->min_key_code; pMN->minKeyCode = xkbi->desc->min_key_code;
pMN->maxKeyCode = xkbi->desc->max_key_code; pMN->maxKeyCode = xkbi->desc->max_key_code;
for (i=1; i<currentMaxClients; i++) {
if (clients[i] && ! clients[i]->clientGone &&
(clients[i]->requestVector != InitialVector) &&
(clients[i]->xkbClientFlags&_XkbClientInitialized) &&
(clients[i]->mapNotifyMask&changed))
{
if (!initialized) {
pMN->type = XkbEventCode + XkbEventBase; pMN->type = XkbEventCode + XkbEventBase;
pMN->xkbType = XkbMapNotify; pMN->xkbType = XkbMapNotify;
pMN->deviceID = kbd->id; pMN->deviceID = kbd->id;
time = GetTimeInMillis();
initialized= 1; /* 0 is serverClient. */
} for (i = 1; i < currentMaxClients; i++) {
if (!clients[i] || clients[i]->clientState != ClientStateRunning)
continue;
if (!(clients[i]->mapNotifyMask & changed))
continue;
if (!XIShouldNotify(clients[i], kbd))
continue;
pMN->time = time; pMN->time = time;
pMN->sequenceNumber = clients[i]->sequence; pMN->sequenceNumber = clients[i]->sequence;
pMN->changed = changed; pMN->changed = changed;
if (clients[i]->swapped) { if (clients[i]->swapped) {
register int n; int n;
swaps(&pMN->sequenceNumber, n); swaps(&pMN->sequenceNumber, n);
swapl(&pMN->time, n); swapl(&pMN->time, n);
swaps(&pMN->changed, n); swaps(&pMN->changed, n);
} }
WriteToClient(clients[i],sizeof(xEvent),(char *)pMN); WriteToClient(clients[i], sizeof(xEvent), pMN);
} }
}
return; XkbSendLegacyMapNotify(kbd, XkbMapNotify, changed, pMN->firstKeySym,
pMN->nKeySyms);
} }
int int
@ -306,7 +403,8 @@ Time time = 0;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->ctrlsNotifyMask&changedControls)) { (interest->ctrlsNotifyMask&changedControls) &&
XIShouldNotify(interest->client, kbd)) {
if (!initialized) { if (!initialized) {
pCN->type = XkbEventCode + XkbEventBase; pCN->type = XkbEventCode + XkbEventBase;
pCN->xkbType = XkbControlsNotify; pCN->xkbType = XkbControlsNotify;
@ -354,6 +452,7 @@ CARD32 state,changed;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
XIShouldNotify(interest->client, kbd) &&
(((xkbType==XkbIndicatorStateNotify)&& (((xkbType==XkbIndicatorStateNotify)&&
(interest->iStateNotifyMask&changed))|| (interest->iStateNotifyMask&changed))||
((xkbType==XkbIndicatorMapNotify)&& ((xkbType==XkbIndicatorMapNotify)&&
@ -437,7 +536,8 @@ XID winID = 0;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->bellNotifyMask)) { (interest->bellNotifyMask) &&
XIShouldNotify(interest->client,kbd)) {
if (!initialized) { if (!initialized) {
time = GetTimeInMillis(); time = GetTimeInMillis();
bn.type = XkbEventCode + XkbEventBase; bn.type = XkbEventCode + XkbEventBase;
@ -491,7 +591,8 @@ CARD16 sk_delay,db_delay;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->accessXNotifyMask&(1<<pEv->detail))) { (interest->accessXNotifyMask&(1<<pEv->detail)) &&
XIShouldNotify(interest->client, kbd)) {
if (!initialized) { if (!initialized) {
pEv->type = XkbEventCode + XkbEventBase; pEv->type = XkbEventCode + XkbEventBase;
pEv->xkbType = XkbAccessXNotify; pEv->xkbType = XkbAccessXNotify;
@ -538,7 +639,8 @@ CARD32 changedIndicators;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->namesNotifyMask&pEv->changed)) { (interest->namesNotifyMask&pEv->changed) &&
XIShouldNotify(interest->client, kbd)) {
if (!initialized) { if (!initialized) {
pEv->type = XkbEventCode + XkbEventBase; pEv->type = XkbEventCode + XkbEventBase;
pEv->xkbType = XkbNamesNotify; pEv->xkbType = XkbNamesNotify;
@ -583,7 +685,8 @@ CARD16 firstSI = 0, nSI = 0, nTotalSI = 0;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->compatNotifyMask)) { (interest->compatNotifyMask) &&
XIShouldNotify(interest->client, kbd)) {
if (!initialized) { if (!initialized) {
pEv->type = XkbEventCode + XkbEventBase; pEv->type = XkbEventCode + XkbEventBase;
pEv->xkbType = XkbCompatMapNotify; pEv->xkbType = XkbCompatMapNotify;
@ -635,7 +738,8 @@ Time time = 0;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->actionMessageMask)) { (interest->actionMessageMask) &&
XIShouldNotify(interest->client, kbd)) {
if (!initialized) { if (!initialized) {
pEv->type = XkbEventCode + XkbEventBase; pEv->type = XkbEventCode + XkbEventBase;
pEv->xkbType = XkbActionMessage; pEv->xkbType = XkbActionMessage;
@ -681,7 +785,8 @@ CARD16 reason;
if ((!interest->client->clientGone) && if ((!interest->client->clientGone) &&
(interest->client->requestVector != InitialVector) && (interest->client->requestVector != InitialVector) &&
(interest->client->xkbClientFlags&_XkbClientInitialized) && (interest->client->xkbClientFlags&_XkbClientInitialized) &&
(interest->extDevNotifyMask&reason)) { (interest->extDevNotifyMask&reason) &&
XIShouldNotify(interest->client, dev)) {
if (!initialized) { if (!initialized) {
pEv->type = XkbEventCode + XkbEventBase; pEv->type = XkbEventCode + XkbEventBase;
pEv->xkbType = XkbExtensionDeviceNotify; pEv->xkbType = XkbExtensionDeviceNotify;

View File

@ -563,41 +563,52 @@ XkbSetRepeatKeys(DeviceIntPtr pXDev,int key,int onoff)
return; return;
} }
/* Applies a change to a single device, does not traverse the device tree. */
void void
XkbApplyMappingChange( DeviceIntPtr kbd, XkbApplyMappingChange(DeviceIntPtr kbd, KeySymsPtr map, KeyCode first_key,
CARD8 request, CARD8 num_keys, CARD8 *modmap, ClientPtr client)
KeyCode firstKey,
CARD8 num,
ClientPtr client)
{ {
XkbDescPtr xkb = kbd->key->xkbInfo->desc;
XkbEventCauseRec cause; XkbEventCauseRec cause;
XkbChangesRec changes; XkbChangesRec changes;
unsigned check; unsigned int check;
bzero(&changes,sizeof(XkbChangesRec)); memset(&changes, 0, sizeof(changes));
memset(&cause, 0, sizeof(cause));
if (map && first_key && num_keys) {
check = 0; check = 0;
if (request==MappingKeyboard) {
XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client); XkbSetCauseCoreReq(&cause, X_ChangeKeyboardMapping, client);
XkbUpdateKeyTypesFromCore(kbd,firstKey,num,&changes);
XkbUpdateActions(kbd,firstKey,num,&changes,&check,&cause);
if (check)
XkbCheckSecondaryEffects(kbd->key->xkbInfo,check,&changes,&cause);
}
else if (request==MappingModifier) {
XkbDescPtr xkb= kbd->key->xkbInfo->desc;
if (!SetKeySymsMap(&kbd->key->curKeySyms, map))
FatalError("XkbApplyMappingChange: failed to copy core keymap!\n");
XkbUpdateKeyTypesFromCore(kbd, first_key, num_keys, &changes);
XkbUpdateActions(kbd, first_key, num_keys, &changes, &check, &cause);
if (check)
XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause);
}
if (modmap) {
/* A keymap change can imply a modmap change, se we prefer the
* former. */
if (!cause.mjr)
XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client); XkbSetCauseCoreReq(&cause,X_SetModifierMapping,client);
num = xkb->max_key_code-xkb->min_key_code+1;
check = 0;
num_keys = xkb->max_key_code - xkb->min_key_code + 1;
changes.map.changed |= XkbModifierMapMask; changes.map.changed |= XkbModifierMapMask;
changes.map.first_modmap_key = xkb->min_key_code; changes.map.first_modmap_key = xkb->min_key_code;
changes.map.num_modmap_keys= num; changes.map.num_modmap_keys = num_keys;
XkbUpdateActions(kbd,xkb->min_key_code,num,&changes,&check,&cause); memcpy(kbd->key->xkbInfo->desc->map->modmap, modmap, MAP_LENGTH);
XkbUpdateActions(kbd, xkb->min_key_code, num_keys, &changes, &check,
&cause);
if (check) if (check)
XkbCheckSecondaryEffects(kbd->key->xkbInfo,check,&changes,&cause); XkbCheckSecondaryEffects(kbd->key->xkbInfo, 1, &changes, &cause);
} }
/* 3/26/94 (ef) -- XXX! Doesn't deal with input extension requests */
XkbSendNotification(kbd, &changes, &cause); XkbSendNotification(kbd, &changes, &cause);
return;
} }
void void
@ -2062,17 +2073,8 @@ _XkbCopyControls(XkbDescPtr src, XkbDescPtr dst)
*/ */
Bool Bool
XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies) XkbCopyKeymap(XkbDescPtr dst, XkbDescPtr src)
{ {
DeviceIntPtr pDev = NULL, tmpDev = NULL;
xkbMapNotify mn;
xkbNewKeyboardNotify nkn;
XkbEventCauseRec cause;
XkbChangesRec changes;
unsigned int check = 0;
memset(&changes, 0, sizeof(changes));
memset(&cause, 0, sizeof(cause));
if (!src || !dst) { if (!src || !dst) {
DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst); DebugF("XkbCopyKeymap: src (%p) or dst (%p) is NULL\n", src, dst);
@ -2111,79 +2113,36 @@ XkbCopyKeymap(XkbDescPtr src, XkbDescPtr dst, Bool sendNotifies)
return FALSE; return FALSE;
} }
for (tmpDev = inputInfo.devices; tmpDev && !pDev; tmpDev = tmpDev->next) {
if (tmpDev->key && tmpDev->key->xkbInfo &&
tmpDev->key->xkbInfo->desc == dst) {
pDev = tmpDev;
break;
}
}
for (tmpDev = inputInfo.off_devices; tmpDev && !pDev;
tmpDev = tmpDev->next) {
if (tmpDev->key && tmpDev->key->xkbInfo &&
tmpDev->key->xkbInfo->desc == dst) {
pDev = tmpDev;
break;
}
}
if (sendNotifies) {
if (!pDev) {
ErrorF("[xkb] XkbCopyKeymap: asked for notifies, but can't find device!\n");
}
else {
/* send NewKeyboardNotify if the keycode range changed, else
* just MapNotify. we also need to send NKN if the geometry
* changed (obviously ...). */
if ((src->min_key_code != dst->min_key_code ||
src->max_key_code != dst->max_key_code)) {
nkn.oldMinKeyCode = dst->min_key_code;
nkn.oldMaxKeyCode = dst->max_key_code;
nkn.deviceID = nkn.oldDeviceID = pDev->id;
nkn.minKeyCode = src->min_key_code;
nkn.maxKeyCode = src->max_key_code;
nkn.requestMajor = XkbReqCode;
nkn.requestMinor = X_kbSetMap; /* XXX bare-faced lie */
nkn.changed = XkbAllNewKeyboardEventsMask;
XkbSendNewKeyboardNotify(pDev, &nkn);
} else
{
mn.deviceID = pDev->id;
mn.minKeyCode = src->min_key_code;
mn.maxKeyCode = src->max_key_code;
mn.firstType = 0;
mn.nTypes = src->map->num_types;
mn.firstKeySym = src->min_key_code;
mn.nKeySyms = XkbNumKeys(src);
mn.firstKeyAct = src->min_key_code;
mn.nKeyActs = XkbNumKeys(src);
/* Cargo-culted from ProcXkbGetMap. */
mn.firstKeyBehavior = src->min_key_code;
mn.nKeyBehaviors = XkbNumKeys(src);
mn.firstKeyExplicit = src->min_key_code;
mn.nKeyExplicit = XkbNumKeys(src);
mn.firstModMapKey = src->min_key_code;
mn.nModMapKeys = XkbNumKeys(src);
mn.firstVModMapKey = src->min_key_code;
mn.nVModMapKeys = XkbNumKeys(src);
mn.virtualMods = ~0; /* ??? */
mn.changed = XkbAllMapComponentsMask;
XkbSendMapNotify(pDev, &mn);
}
XkbUpdateActions(pDev, dst->min_key_code,
XkbNumKeys(pDev->key->xkbInfo->desc), &changes,
&check, &cause);
if (check)
XkbCheckSecondaryEffects(pDev->key->xkbInfo, check, &changes,
&cause);
memcpy(pDev->kbdfeed->ctrl.autoRepeats, dst->ctrls->per_key_repeat,
XkbPerKeyBitArraySize);
}
}
dst->min_key_code = src->min_key_code; dst->min_key_code = src->min_key_code;
dst->max_key_code = src->max_key_code; dst->max_key_code = src->max_key_code;
return TRUE; return TRUE;
} }
Bool
XkbCopyDeviceKeymap(DeviceIntPtr dst, DeviceIntPtr src)
{
xkbNewKeyboardNotify nkn;
Bool ret;
if (!dst->key || !src->key)
return FALSE;
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.requestMajor = XkbReqCode;
nkn.requestMinor = X_kbSetMap; /* Near enough's good enough. */
nkn.changed = XkbNKN_KeycodesMask;
if (src->key->xkbInfo->desc->geom)
nkn.changed |= XkbNKN_GeometryMask;
ret = XkbCopyKeymap(dst->key->xkbInfo->desc, src->key->xkbInfo->desc);
if (ret)
XkbSendNewKeyboardNotify(dst, &nkn);
return ret;
}