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>
This commit is contained in:
parent
daa6d2d58f
commit
9c88cb9b05
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 *
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue