summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaércio de Sousa <laerciosousa@sme-mogidascruzes.sp.gov.br>2016-02-25 16:37:57 -0300
committerAdam Jackson <ajax@redhat.com>2016-03-01 11:00:34 -0500
commit9c88cb9b059111e0531852f3fa8fa571c0306f57 (patch)
tree65980bff491aad069c1e76f3f010bfd523b51be4
parentdaa6d2d58f65b9301b1b1f3c6df07719ecb5c03d (diff)
kdrive/ephyr: map host X server's keymap into Xephyr, if supported
Currently Xephyr doesn't inherit host X server's keymap, which may lead to keymap mismatches when using a non-US keyboard in a window inside Xephyr. This patch makes Xephyr change its keymap to match host X server's one (unless XKB support is disabled), using xcb-xkb to retrieve the needed XKB controls. This implementation is analogous to Xnest one at commit 83fef4235. Supersedes: https://patchwork.freedesktop.org/patch/67504 Reviewed-by: Adam Jackson <ajax@redhat.com> Signed-off-by: Laércio de Sousa <laerciosousa@sme-mogidascruzes.sp.gov.br>
-rw-r--r--configure.ac2
-rw-r--r--hw/kdrive/ephyr/ephyr.c28
-rw-r--r--hw/kdrive/ephyr/hostx.c131
-rw-r--r--hw/kdrive/ephyr/hostx.h9
-rw-r--r--hw/kdrive/src/kinput.c8
5 files changed, 151 insertions, 27 deletions
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 = keySyms.minKeyCode;
+ ki->maxScanCode = keySyms.maxKeyCode;
+
+ if (ki->name != NULL) {
+ free(ki->name);
}
- ki->minScanCode = ephyrKeySyms.minKeyCode;
- ki->maxScanCode = ephyrKeySyms.maxKeyCode;
- 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 <xcb/shape.h>
#include <xcb/xcb_keysyms.h>
#include <xcb/randr.h>
+#include <xcb/xkb.h>
#ifdef GLAMOR
#include <epoxy/gl.h>
#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
@@ -44,11 +44,6 @@
typedef struct EphyrHostXVars EphyrHostXVars;
typedef struct {
- int minKeyCode;
- int maxKeyCode;
-} EphyrKeySyms;
-
-typedef struct {
VisualID visualid;
int screen;
int depth;
@@ -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");