diff options
author | David Reveman <davidr@novell.com> | 2008-09-17 12:10:34 -0400 |
---|---|---|
committer | David Reveman <davidr@novell.com> | 2008-10-30 03:37:42 -0400 |
commit | e54dce132f843220ebccfee1a40d3633a7ac37ff (patch) | |
tree | 75101f4b9b84a216d471d30961f9dbbefd92dd7d /hw/dmx | |
parent | 7d2698526bb97ec11a5ffe3f5ec194eb8d2ea49b (diff) |
Add simple keycode mapping system.
Only keycodes from backend server with fully matching
keysyms are mapped to local keycodes and processed as
input events.
A truly independent backend server keymap can be obtained
by using a separate master device.
Diffstat (limited to 'hw/dmx')
-rw-r--r-- | hw/dmx/dmxinput.c | 189 | ||||
-rw-r--r-- | hw/dmx/dmxinput.h | 2 |
2 files changed, 182 insertions, 9 deletions
diff --git a/hw/dmx/dmxinput.c b/hw/dmx/dmxinput.c index 352cc2301..120c61e02 100644 --- a/hw/dmx/dmxinput.c +++ b/hw/dmx/dmxinput.c @@ -53,6 +53,126 @@ static EventListPtr dmxEvents = NULL; +static void +dmxUpdateKeycodeMap (DeviceIntPtr pDevice) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection); + KeySymsPtr dst = &pDevice->key->curKeySyms; + KeySymsPtr src = &pDevPriv->keySyms; + int width = src->mapWidth; + int i; + + if (!pDevice->isMaster && pDevice->u.master && pDevice->u.master->key) + dst = &pDevice->u.master->key->curKeySyms; + + if (dst->mapWidth < width) + width = dst->mapWidth; + + memset (pDevPriv->keycode, 0, + sizeof (KeyCode) * (setup->max_keycode - setup->min_keycode)); + + for (i = src->minKeyCode - setup->min_keycode; + i < (src->maxKeyCode - src->minKeyCode); + i++) + { + int j; + + for (j = 0; j < (dst->maxKeyCode - dst->minKeyCode); j++) + { + int k; + + for (k = 0; k < i; k++) + if (pDevPriv->keycode[k] == (dst->minKeyCode + j)) + break; + + /* make sure the keycode is not already in use */ + if (k < i) + continue; + + for (k = 0; k < width; k++) + if (dst->map[j * dst->mapWidth + k] != + src->map[i * src->mapWidth + k]) + break; + + if (k == width) + break; + } + + if (j < (dst->maxKeyCode - dst->minKeyCode)) + pDevPriv->keycode[i] = dst->minKeyCode + j; + } +} + +static void +dmxUpdateKeyboardMapping (DeviceIntPtr pDevice, + int first, + int count) +{ + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + KeySymsRec keysyms; + xcb_keysym_t *syms; + int n; + + if (pDevPriv->deviceId >= 0) + { + xcb_input_get_device_key_mapping_reply_t *reply; + + reply = xcb_input_get_device_key_mapping_reply + (dmxScreen->connection, + xcb_input_get_device_key_mapping (dmxScreen->connection, + pDevPriv->deviceId, + first, + count), + NULL); + + if (reply) + { + syms = xcb_input_get_device_key_mapping_keysyms (reply); + n = xcb_input_get_device_key_mapping_keysyms_length (reply); + + keysyms.minKeyCode = first; + keysyms.maxKeyCode = first + n - 1; + keysyms.mapWidth = reply->keysyms_per_keycode; + keysyms.map = (KeySym *) syms; + + SetKeySymsMap (&pDevPriv->keySyms, &keysyms); + + free (reply); + } + } + else + { + xcb_get_keyboard_mapping_reply_t *reply; + + reply = xcb_get_keyboard_mapping_reply + (dmxScreen->connection, + xcb_get_keyboard_mapping (dmxScreen->connection, + first, + count), + NULL); + + if (reply) + { + syms = xcb_get_keyboard_mapping_keysyms (reply); + n = xcb_get_keyboard_mapping_keysyms_length (reply); + + keysyms.minKeyCode = first; + keysyms.maxKeyCode = first + n - 1; + keysyms.mapWidth = reply->keysyms_per_keycode; + keysyms.map = (KeySym *) syms; + + SetKeySymsMap (&pDevPriv->keySyms, &keysyms); + + free (reply); + } + } + + dmxUpdateKeycodeMap (pDevice); +} + static DeviceIntPtr dmxGetButtonDevice (DMXInputInfo *dmxInput, XID deviceId) @@ -131,17 +251,28 @@ dmxKeyEvent (DeviceIntPtr pDevice, int key, int type) { - int i, nEvents; + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection); + int nEvents = 0; - GetEventList (&dmxEvents); - nEvents = GetKeyboardEvents (dmxEvents, pDevice, type, key); - for (i = 0; i < nEvents; i++) - mieqEnqueue (pDevice, dmxEvents[i].event); + if (key >= setup->min_keycode && key <= setup->max_keycode) + { + int keycode = pDevPriv->keycode[key - setup->min_keycode]; + + if (keycode) + { + int i; + + GetEventList (&dmxEvents); + nEvents = GetKeyboardEvents (dmxEvents, pDevice, type, keycode); + for (i = 0; i < nEvents; i++) + mieqEnqueue (pDevice, dmxEvents[i].event); + } + } if (key > 0 && key <= 255) { - dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); - switch (type) { case XCB_KEY_PRESS: pDevPriv->state[key >> 3] |= 1 << (key & 7); @@ -499,6 +630,15 @@ dmxDeviceKeyboardEventCheck (DeviceIntPtr pDevice, dmxUpdateKeyState (pKeyDev, state); } break; + case XCB_MAPPING_NOTIFY: { + xcb_mapping_notify_event_t *xmapping = + (xcb_mapping_notify_event_t *) event; + + if (xmapping->request == XCB_MAPPING_KEYBOARD) + dmxUpdateKeyboardMapping (pKeyDev, + xmapping->first_keycode, + xmapping->count); + } break; default: if (id < 0) return FALSE; @@ -565,6 +705,18 @@ dmxDeviceKeyboardEventCheck (DeviceIntPtr pDevice, memcpy (&pDevPriv->keysbuttons[4], xstate->keys, 28); dmxUpdateKeyState (pKeyDev, pDevPriv->keysbuttons); } break; + case XCB_INPUT_DEVICE_MAPPING_NOTIFY: { + xcb_input_device_mapping_notify_event_t *xmapping = + (xcb_input_device_mapping_notify_event_t *) event; + + if (id != (xmapping->device_id & DEVICE_BITS)) + return FALSE; + + if (xmapping->request == XCB_MAPPING_KEYBOARD) + dmxUpdateKeyboardMapping (pKeyDev, + xmapping->first_keycode, + xmapping->count); + } break; default: return FALSE; } @@ -956,8 +1108,21 @@ dmxKeyboardBell (int volume, static int dmxKeyboardOn (DeviceIntPtr pDevice) { - dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); - DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + dmxDevicePrivPtr pDevPriv = DMX_GET_DEVICE_PRIV (pDevice); + DMXScreenInfo *dmxScreen = (DMXScreenInfo *) pDevPriv->dmxInput; + const xcb_setup_t *setup = xcb_get_setup (dmxScreen->connection); + int nKeycode = setup->max_keycode - setup->min_keycode; + + pDevPriv->keycode = xalloc (nKeycode * sizeof (KeyCode)); + if (!pDevPriv->keycode) + return -1; + + pDevPriv->keySyms.map = (KeySym *) NULL; + pDevPriv->keySyms.mapWidth = 0; + pDevPriv->keySyms.minKeyCode = setup->min_keycode; + pDevPriv->keySyms.maxKeyCode = setup->max_keycode; + + dmxUpdateKeyboardMapping (pDevice, setup->min_keycode, nKeycode); if (pDevPriv->deviceId >= 0) { @@ -970,6 +1135,7 @@ dmxKeyboardOn (DeviceIntPtr pDevice) { dmxLog (dmxWarning, "Cannot open %s device (id=%d) on %s\n", pDevice->name, pDevPriv->deviceId, dmxScreen->name); + xfree (pDevPriv->keycode); return -1; } @@ -1021,6 +1187,11 @@ dmxKeyboardOff (DeviceIntPtr pDevice) dmxScreen->rootEventMask); XLIB_EPILOGUE (dmxScreen); } + + if (pDevPriv->keySyms.map) + xfree (pDevPriv->keySyms.map); + + xfree (pDevPriv->keycode); } static int diff --git a/hw/dmx/dmxinput.h b/hw/dmx/dmxinput.h index a6dd45c5c..f211bde90 100644 --- a/hw/dmx/dmxinput.h +++ b/hw/dmx/dmxinput.h @@ -36,6 +36,8 @@ typedef struct _dmxDevicePriv { XDevice *device; char state[32]; char keysbuttons[32]; + KeySymsRec keySyms; + KeyCode *keycode; xcb_void_cookie_t grab; Bool (*EventCheck) (DeviceIntPtr, xcb_generic_event_t *); |