compositor-x11: Use XKB StateNotify to synchronise state
Make sure that we always have the exact same view of the keyboard state as the host server by using XKB StateNotify events to update our state exactly rather than relying on key events. In particular, this fixes key state during grabs, where we either miss modifiers completely or get them stuck permanently, depending on the nature of the grab and the implementation of the X window manager/compositor. The downside, however, is that Weston wakes up on every modifier change, regardless of whether or not it has focus. Signed-off-by: Daniel Stone <daniel@fooishbar.org>
This commit is contained in:
parent
05d58682b3
commit
e2faa120ef
@ -149,6 +149,7 @@ x11_compositor_setup_xkb(struct x11_compositor *c)
|
||||
#else
|
||||
const xcb_query_extension_reply_t *ext;
|
||||
xcb_generic_error_t *error;
|
||||
xcb_void_cookie_t select;
|
||||
xcb_xkb_per_client_flags_cookie_t pcf;
|
||||
xcb_xkb_per_client_flags_reply_t *pcf_reply;
|
||||
|
||||
@ -162,6 +163,20 @@ x11_compositor_setup_xkb(struct x11_compositor *c)
|
||||
}
|
||||
c->xkb_event_base = ext->first_event;
|
||||
|
||||
select = xcb_xkb_select_events(c->conn,
|
||||
XCB_XKB_ID_USE_CORE_KBD,
|
||||
XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
|
||||
0,
|
||||
XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
|
||||
0,
|
||||
0,
|
||||
NULL);
|
||||
error = xcb_request_check(c->conn, select);
|
||||
if (error) {
|
||||
weston_log("error: failed to select for XKB state events\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pcf = xcb_xkb_per_client_flags(c->conn,
|
||||
XCB_XKB_ID_USE_CORE_KBD,
|
||||
XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
|
||||
@ -595,6 +610,51 @@ x11_compositor_find_output(struct x11_compositor *c, xcb_window_t window)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XCB_XKB
|
||||
static uint32_t
|
||||
get_xkb_mod_mask(struct x11_compositor *c, uint32_t in)
|
||||
{
|
||||
struct weston_xkb_info *info = &c->base.seat->xkb_info;
|
||||
uint32_t ret = 0;
|
||||
|
||||
if ((in & ShiftMask) && info->shift_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->shift_mod);
|
||||
if ((in & LockMask) && info->caps_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->caps_mod);
|
||||
if ((in & ControlMask) && info->ctrl_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->ctrl_mod);
|
||||
if ((in & Mod1Mask) && info->alt_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->alt_mod);
|
||||
if ((in & Mod2Mask) && info->mod2_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->mod2_mod);
|
||||
if ((in & Mod3Mask) && info->mod3_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->mod3_mod);
|
||||
if ((in & Mod4Mask) && info->super_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->super_mod);
|
||||
if ((in & Mod5Mask) && info->mod5_mod != XKB_MOD_INVALID)
|
||||
ret |= (1 << info->mod5_mod);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
update_xkb_state(struct x11_compositor *c, xcb_xkb_state_notify_event_t *state)
|
||||
{
|
||||
struct weston_compositor *ec = &c->base;
|
||||
struct wl_seat *seat = &ec->seat->seat;
|
||||
|
||||
xkb_state_update_mask(c->base.seat->xkb_state.state,
|
||||
get_xkb_mod_mask(c, state->baseMods),
|
||||
get_xkb_mod_mask(c, state->latchedMods),
|
||||
get_xkb_mod_mask(c, state->lockedMods),
|
||||
0,
|
||||
0,
|
||||
state->group);
|
||||
|
||||
notify_modifiers(seat, wl_display_next_serial(c->base.wl_display));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
x11_compositor_deliver_button_event(struct x11_compositor *c,
|
||||
xcb_generic_event_t *event, int state)
|
||||
@ -755,7 +815,8 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
|
||||
weston_compositor_get_time(),
|
||||
key_press->detail - 8,
|
||||
WL_KEYBOARD_KEY_STATE_PRESSED,
|
||||
STATE_UPDATE_AUTOMATIC);
|
||||
c->has_xkb ? STATE_UPDATE_NONE :
|
||||
STATE_UPDATE_AUTOMATIC);
|
||||
break;
|
||||
case XCB_KEY_RELEASE:
|
||||
/* If we don't have XKB, we need to use the lame
|
||||
@ -769,7 +830,7 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
|
||||
weston_compositor_get_time(),
|
||||
key_release->detail - 8,
|
||||
WL_KEYBOARD_KEY_STATE_RELEASED,
|
||||
STATE_UPDATE_AUTOMATIC);
|
||||
STATE_UPDATE_NONE);
|
||||
break;
|
||||
case XCB_BUTTON_PRESS:
|
||||
x11_compositor_deliver_button_event(c, event, 1);
|
||||
@ -840,6 +901,16 @@ x11_compositor_handle_event(int fd, uint32_t mask, void *data)
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HAVE_XCB_XKB
|
||||
if (c->has_xkb &&
|
||||
(event->response_type & ~0x80) == c->xkb_event_base) {
|
||||
xcb_xkb_state_notify_event_t *state =
|
||||
(xcb_xkb_state_notify_event_t *) event;
|
||||
if (state->xkbType == XCB_XKB_STATE_NOTIFY)
|
||||
update_xkb_state(c, state);
|
||||
}
|
||||
#endif
|
||||
|
||||
count++;
|
||||
if (prev != event)
|
||||
free (event);
|
||||
|
Loading…
x
Reference in New Issue
Block a user