diff --git a/configure.ac b/configure.ac index 312fc6930..c16684159 100644 --- a/configure.ac +++ b/configure.ac @@ -2393,7 +2393,7 @@ if test "$KDRIVE" = yes; then AC_DEFINE(KDRIVE_MOUSE, 1, [Enable KDrive mouse driver]) fi - XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms xcb-randr" + XEPHYR_REQUIRED_LIBS="xau xdmcp xcb xcb-shape xcb-render xcb-renderutil xcb-aux xcb-image xcb-icccm xcb-shm xcb-keysyms xcb-randr xcb-xkb" if test "x$XV" = xyes; then XEPHYR_REQUIRED_LIBS="$XEPHYR_REQUIRED_LIBS xcb-xv" fi diff --git a/hw/kdrive/ephyr/ephyr.c b/hw/kdrive/ephyr/ephyr.c index a272882d4..f6897ccf0 100644 --- a/hw/kdrive/ephyr/ephyr.c +++ b/hw/kdrive/ephyr/ephyr.c @@ -47,7 +47,6 @@ extern Bool ephyr_glamor; KdKeyboardInfo *ephyrKbd; KdPointerInfo *ephyrMouse; -EphyrKeySyms ephyrKeySyms; Bool ephyrNoDRI = FALSE; Bool ephyrNoXV = FALSE; @@ -1291,16 +1290,29 @@ KdPointerDriver EphyrMouseDriver = { static Status EphyrKeyboardInit(KdKeyboardInfo * ki) { + KeySymsRec keySyms; + CARD8 modmap[MAP_LENGTH]; + XkbControlsRec controls; + ki->driverPrivate = (EphyrKbdPrivate *) calloc(sizeof(EphyrKbdPrivate), 1); - hostx_load_keymap(); - if (!ephyrKeySyms.minKeyCode) { - ErrorF("Couldn't load keymap from host\n"); - return BadAlloc; + + if (hostx_load_keymap(&keySyms, modmap, &controls)) { + XkbApplyMappingChange(ki->dixdev, &keySyms, + keySyms.minKeyCode, + keySyms.maxKeyCode - keySyms.minKeyCode + 1, + modmap, serverClient); + XkbDDXChangeControls(ki->dixdev, &controls, &controls); + free(keySyms.map); } - ki->minScanCode = ephyrKeySyms.minKeyCode; - ki->maxScanCode = ephyrKeySyms.maxKeyCode; - free(ki->name); + + ki->minScanCode = keySyms.minKeyCode; + ki->maxScanCode = keySyms.maxKeyCode; + + if (ki->name != NULL) { + free(ki->name); + } + ki->name = strdup("Xephyr virtual keyboard"); ephyrKbd = ki; return Success; diff --git a/hw/kdrive/ephyr/hostx.c b/hw/kdrive/ephyr/hostx.c index ce9facacc..cdb12b0e6 100644 --- a/hw/kdrive/ephyr/hostx.c +++ b/hw/kdrive/ephyr/hostx.c @@ -52,6 +52,7 @@ #include #include #include +#include #ifdef GLAMOR #include #include "glamor.h" @@ -86,8 +87,6 @@ static EphyrHostXVars HostX; static int HostXWantDamageDebug = 0; -extern EphyrKeySyms ephyrKeySyms; - extern Bool EphyrWantResize; char *ephyrResName = NULL; @@ -1082,18 +1081,136 @@ hostx_paint_debug_rect(KdScreenInfo *screen, nanosleep(&tspec, NULL); } -void -hostx_load_keymap(void) +Bool +hostx_load_keymap(KeySymsPtr keySyms, CARD8 *modmap, XkbControlsPtr controls) { int min_keycode, max_keycode; + int map_width; + size_t i, j; + int keymap_len; + xcb_keysym_t *keymap; + xcb_keycode_t *modifier_map; + xcb_get_keyboard_mapping_cookie_t mapping_c; + xcb_get_keyboard_mapping_reply_t *mapping_r; + xcb_get_modifier_mapping_cookie_t modifier_c; + xcb_get_modifier_mapping_reply_t *modifier_r; + xcb_xkb_use_extension_cookie_t use_c; + xcb_xkb_use_extension_reply_t *use_r; + xcb_xkb_get_controls_cookie_t controls_c; + xcb_xkb_get_controls_reply_t *controls_r; + /* First of all, collect host X server's + * min_keycode and max_keycode, which are + * independent from XKB support. */ min_keycode = xcb_get_setup(HostX.conn)->min_keycode; max_keycode = xcb_get_setup(HostX.conn)->max_keycode; EPHYR_DBG("min: %d, max: %d", min_keycode, max_keycode); - ephyrKeySyms.minKeyCode = min_keycode; - ephyrKeySyms.maxKeyCode = max_keycode; + keySyms->minKeyCode = min_keycode; + keySyms->maxKeyCode = max_keycode; + + /* Check for XKB availability in host X server */ + if (!hostx_has_extension(&xcb_xkb_id)) { + EPHYR_LOG_ERROR("XKB extension is not supported in host X server."); + return FALSE; + } + + use_c = xcb_xkb_use_extension(HostX.conn, + XCB_XKB_MAJOR_VERSION, + XCB_XKB_MINOR_VERSION); + use_r = xcb_xkb_use_extension_reply(HostX.conn, use_c, NULL); + + if (!use_r) { + EPHYR_LOG_ERROR("Couldn't use XKB extension."); + return FALSE; + } else if (!use_r->supported) { + EPHYR_LOG_ERROR("XKB extension is not supported in host X server."); + free(use_r); + return FALSE; + } + + free(use_r); + + /* Send all needed XCB requests at once, + * and process the replies as needed. */ + mapping_c = xcb_get_keyboard_mapping(HostX.conn, + min_keycode, + max_keycode - min_keycode + 1); + modifier_c = xcb_get_modifier_mapping(HostX.conn); + controls_c = xcb_xkb_get_controls(HostX.conn, + XCB_XKB_ID_USE_CORE_KBD); + + mapping_r = xcb_get_keyboard_mapping_reply(HostX.conn, + mapping_c, + NULL); + + if (!mapping_r) { + EPHYR_LOG_ERROR("xcb_get_keyboard_mapping_reply() failed."); + return FALSE; + } + + map_width = mapping_r->keysyms_per_keycode; + keymap = xcb_get_keyboard_mapping_keysyms(mapping_r); + keymap_len = xcb_get_keyboard_mapping_keysyms_length(mapping_r); + + keySyms->mapWidth = map_width; + keySyms->map = calloc(keymap_len, sizeof(KeySym)); + + if (!keySyms->map) { + EPHYR_LOG_ERROR("Failed to allocate KeySym map."); + free(mapping_r); + return FALSE; + } + + for (i = 0; i < keymap_len; i++) { + keySyms->map[i] = keymap[i]; + } + + free(mapping_r); + + modifier_r = xcb_get_modifier_mapping_reply(HostX.conn, + modifier_c, + NULL); + + if (!modifier_r) { + EPHYR_LOG_ERROR("xcb_get_modifier_mapping_reply() failed."); + return FALSE; + } + + modifier_map = xcb_get_modifier_mapping_keycodes(modifier_r); + memset(modmap, 0, sizeof(CARD8) * MAP_LENGTH); + + for (j = 0; j < 8; j++) { + for (i = 0; i < modifier_r->keycodes_per_modifier; i++) { + CARD8 keycode; + + if ((keycode = modifier_map[j * modifier_r->keycodes_per_modifier + i])) { + modmap[keycode] |= 1 << j; + } + } + } + + free(modifier_r); + + controls_r = xcb_xkb_get_controls_reply(HostX.conn, + controls_c, + NULL); + + if (!controls_r) { + EPHYR_LOG_ERROR("xcb_xkb_get_controls_reply() failed."); + return FALSE; + } + + controls->enabled_ctrls = controls_r->enabledControls; + + for (i = 0; i < XkbPerKeyBitArraySize; i++) { + controls->per_key_repeat[i] = controls_r->perKeyRepeat[i]; + } + + free(controls_r); + + return TRUE; } xcb_connection_t * diff --git a/hw/kdrive/ephyr/hostx.h b/hw/kdrive/ephyr/hostx.h index 5e642dc70..96d73948b 100644 --- a/hw/kdrive/ephyr/hostx.h +++ b/hw/kdrive/ephyr/hostx.h @@ -43,11 +43,6 @@ typedef struct EphyrHostXVars EphyrHostXVars; -typedef struct { - int minKeyCode; - int maxKeyCode; -} EphyrKeySyms; - typedef struct { VisualID visualid; int screen; @@ -153,8 +148,8 @@ void hostx_paint_rect(KdScreenInfo *screen, int sx, int sy, int dx, int dy, int width, int height); -void - hostx_load_keymap(void); +Bool +hostx_load_keymap(KeySymsPtr keySyms, CARD8 *modmap, XkbControlsPtr controls); xcb_connection_t * hostx_get_xcbconn(void); diff --git a/hw/kdrive/src/kinput.c b/hw/kdrive/src/kinput.c index ae19a9def..52be7ad2e 100644 --- a/hw/kdrive/src/kinput.c +++ b/hw/kdrive/src/kinput.c @@ -759,10 +759,6 @@ KdKeyboardProc(DeviceIntPtr pDevice, int onoff) return BadImplementation; } - if ((*ki->driver->Init) (ki) != Success) { - return !Success; - } - memset(&rmlvo, 0, sizeof(rmlvo)); rmlvo.rules = ki->xkbRules; rmlvo.model = ki->xkbModel; @@ -775,6 +771,10 @@ KdKeyboardProc(DeviceIntPtr pDevice, int onoff) return BadImplementation; } + if ((*ki->driver->Init) (ki) != Success) { + return !Success; + } + xiclass = AtomFromName(XI_KEYBOARD); AssignTypeAndName(pDevice, xiclass, ki->name ? ki->name : "Generic KDrive Keyboard");