[vlc-commits] xcb/window: implement XKeyboard using xkbcommon
Rémi Denis-Courmont
git at videolan.org
Tue May 29 21:00:47 CEST 2018
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue May 29 21:52:25 2018 +0300| [d06b1c458f47b70f489c4d1aa02e554d6c3bc2a6] | committer: Rémi Denis-Courmont
xcb/window: implement XKeyboard using xkbcommon
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=d06b1c458f47b70f489c4d1aa02e554d6c3bc2a6
---
configure.ac | 14 ++-
modules/video_output/Makefile.am | 10 +-
modules/video_output/xcb/window.c | 233 ++++++++++++++++++++++++++++----------
3 files changed, 193 insertions(+), 64 deletions(-)
diff --git a/configure.ac b/configure.ac
index 078a588aca..40d78663d5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3077,6 +3077,7 @@ have_xcb="no"
have_xcb_keysyms="no"
have_xcb_randr="no"
have_xcb_xvideo="no"
+have_xcb_xkb="no"
AS_IF([test "${enable_xcb}" != "no"], [
dnl libxcb
PKG_CHECK_MODULES(XCB, [xcb >= 1.6])
@@ -3091,15 +3092,26 @@ AS_IF([test "${enable_xcb}" != "no"], [
PKG_CHECK_MODULES(XCB_RANDR, [xcb-randr >= 1.3], [have_xcb_randr="yes"])
+ PKG_CHECK_MODULES([XCB_XKB], [xcb-xkb], [
+ PKG_CHECK_MODULES([XKBCOMMON_X11], [xkbcommon-x11], [
+ have_xcb_xkb="yes"
+ ], [
+ AC_MSG_WARN([${XKBCOMMON_X11_PKG_ERRORS}. Hotkeys will not work.])
+ ])
+ ], [
+ AC_MSG_WARN([${XCB_XKB_PKG_ERRORS}. Hotkeys will not work.])
+ ])
+
dnl xcb-utils
PKG_CHECK_MODULES(XCB_KEYSYMS, [xcb-keysyms >= 0.3.4], [have_xcb_keysyms="yes"], [
- AC_MSG_WARN([${XCB_KEYSYMS_PKG_ERRORS}. Hotkeys will not work.])
+ AC_MSG_WARN([${XCB_KEYSYMS_PKG_ERRORS}])
])
])
AM_CONDITIONAL([HAVE_XCB], [test "${have_xcb}" = "yes"])
AM_CONDITIONAL([HAVE_XCB_KEYSYMS], [test "${have_xcb_keysyms}" = "yes"])
AM_CONDITIONAL([HAVE_XCB_RANDR], [test "${have_xcb_randr}" = "yes"])
AM_CONDITIONAL([HAVE_XCB_XVIDEO], [test "${have_xcb_xvideo}" = "yes"])
+AM_CONDITIONAL([HAVE_XCB_XKB], [test "${have_xcb_xkb}" = "yes"])
dnl
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index a6ad7fba02..2f27c27735 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -150,8 +150,10 @@ libxcb_xv_plugin_la_LIBADD = libvlc_xcb_events.la \
libxcb_window_plugin_la_SOURCES = video_output/xcb/window.c
libxcb_window_plugin_la_CFLAGS = $(AM_CFLAGS) \
$(CFLAGS_xcb_window) \
- $(XPROTO_CFLAGS) $(XCB_CFLAGS) $(XCB_KEYSYMS_CFLAGS)
-libxcb_window_plugin_la_LIBADD = $(XPROTO_LIBS) $(XCB_LIBS) $(XCB_KEYSYMS_LIBS)
+ $(XPROTO_CFLAGS) $(XCB_CFLAGS) \
+ $(XCB_XKB_CFLAGS) $(XKBCOMMON_X11_CFLAGS)
+libxcb_window_plugin_la_LIBADD = $(XPROTO_LIBS) $(XCB_LIBS) \
+ $(XCB_XKB_LIBS) $(XKBCOMMON_X11_LIBS)
libegl_x11_plugin_la_SOURCES = video_output/opengl/egl.c
libegl_x11_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DUSE_PLATFORM_X11=1
@@ -165,11 +167,11 @@ libglx_plugin_la_LIBADD = $(GL_LIBS) $(X_LIBS) $(X_PRE_LIBS) -lX11
if HAVE_XCB
pkglib_LTLIBRARIES += libvlc_xcb_events.la
vout_LTLIBRARIES += libxcb_x11_plugin.la libxcb_window_plugin.la
-if HAVE_XCB_KEYSYMS
+if HAVE_XCB_XKB
libxcb_window_plugin_la_SOURCES += \
video_output/xcb/keysym.h video_output/xcb/xcb_keysym.h \
video_output/xcb/vlc_xkb.h video_output/xcb/xkb.c
-libxcb_window_plugin_la_CFLAGS += -DHAVE_XCB_KEYSYMS
+libxcb_window_plugin_la_CFLAGS += -DHAVE_XCB_XKB -DHAVE_XKBCOMMON
endif
if HAVE_XCB_XVIDEO
vout_LTLIBRARIES += libxcb_xv_plugin.la
diff --git a/modules/video_output/xcb/window.c b/modules/video_output/xcb/window.c
index 1e4eae8a06..134d313c12 100644
--- a/modules/video_output/xcb/window.c
+++ b/modules/video_output/xcb/window.c
@@ -31,8 +31,9 @@
#include <limits.h> /* _POSIX_HOST_NAME_MAX */
#include <xcb/xcb.h>
-#ifdef HAVE_XCB_KEYSYMS
-# include <xcb/xcb_keysyms.h>
+#ifdef HAVE_XCB_XKB
+# include <xcb/xkb.h>
+# include <xkbcommon/xkbcommon-x11.h>
# include "vlc_xkb.h"
#endif
typedef xcb_atom_t Atom;
@@ -47,9 +48,6 @@ typedef xcb_atom_t Atom;
struct vout_window_sys_t
{
xcb_connection_t *conn;
-#ifdef HAVE_XCB_KEYSYMS
- xcb_key_symbols_t *keys;
-#endif
vlc_thread_t thread;
xcb_window_t root;
@@ -58,9 +56,162 @@ struct vout_window_sys_t
xcb_atom_t wm_state_below;
xcb_atom_t wm_state_fullscreen;
+#ifdef HAVE_XCB_XKB
+ struct
+ {
+ struct xkb_context *ctx;
+ struct xkb_keymap *map;
+ struct xkb_state *state;
+ uint8_t base;
+ } xkb;
+#endif
+
bool embedded;
};
+#ifdef HAVE_XCB_XKB
+static int InitKeyboard(vout_window_t *wnd)
+{
+ vout_window_sys_t *sys = wnd->sys;
+ xcb_connection_t *conn = sys->conn;
+
+ int32_t core = xkb_x11_get_core_keyboard_device_id(conn);
+ if (core == -1)
+ return -1;
+
+ sys->xkb.map = xkb_x11_keymap_new_from_device(sys->xkb.ctx, conn, core,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ if (unlikely(sys->xkb.map == NULL))
+ return -1;
+
+ sys->xkb.state = xkb_x11_state_new_from_device(sys->xkb.map, conn, core);
+ if (unlikely(sys->xkb.state == NULL))
+ {
+ xkb_keymap_unref(sys->xkb.map);
+ sys->xkb.map = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+static void DeinitKeyboard(vout_window_t *wnd)
+{
+ vout_window_sys_t *sys = wnd->sys;
+
+ if (sys->xkb.map == NULL)
+ return;
+
+ xkb_state_unref(sys->xkb.state);
+ xkb_keymap_unref(sys->xkb.map);
+ sys->xkb.map = NULL;
+}
+
+static void ProcessKeyboardEvent(vout_window_t *wnd,
+ const xcb_generic_event_t *ev)
+{
+ vout_window_sys_t *sys = wnd->sys;
+
+ switch (ev->pad0)
+ {
+ case XCB_XKB_NEW_KEYBOARD_NOTIFY:
+ case XCB_XKB_MAP_NOTIFY:
+ msg_Dbg(wnd, "refreshing keyboard mapping");
+ DeinitKeyboard(wnd);
+ InitKeyboard(wnd);
+ break;
+
+ case XCB_XKB_STATE_NOTIFY:
+ if (sys->xkb.map != NULL)
+ {
+ const xcb_xkb_state_notify_event_t *ne = (void *)ev;
+
+ xkb_state_update_mask(sys->xkb.state, ne->baseMods,
+ ne->latchedMods, ne->lockedMods,
+ ne->baseGroup, ne->latchedGroup,
+ ne->lockedGroup);
+ }
+ break;
+ }
+}
+
+static int InitKeyboardExtension(vout_window_t *wnd)
+{
+ vout_window_sys_t *sys = wnd->sys;
+ xcb_connection_t *conn = sys->conn;
+ uint16_t maj, min;
+
+ if (!xkb_x11_setup_xkb_extension(conn, XKB_X11_MIN_MAJOR_XKB_VERSION,
+ XKB_X11_MIN_MINOR_XKB_VERSION,
+ XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
+ &maj, &min, &sys->xkb.base, NULL))
+ {
+ msg_Err(wnd, "XKeyboard initialization error");
+ return 0;
+ }
+
+ msg_Dbg(wnd, "XKeyboard v%"PRIu16".%"PRIu16" initialized", maj, min);
+ sys->xkb.ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ if (unlikely(sys->xkb.ctx == NULL))
+ return -1;
+
+ /* Events: new KB, keymap change, state (modifiers) change */
+ const uint16_t affect = XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY
+ | XCB_XKB_EVENT_TYPE_MAP_NOTIFY
+ | XCB_XKB_EVENT_TYPE_STATE_NOTIFY;
+ /* Map event sub-types: everything except key behaviours */
+ const uint16_t map_parts = XCB_XKB_MAP_PART_KEY_TYPES
+ | XCB_XKB_MAP_PART_KEY_SYMS
+ | XCB_XKB_MAP_PART_MODIFIER_MAP
+ | XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS
+ | XCB_XKB_MAP_PART_KEY_ACTIONS
+ | XCB_XKB_MAP_PART_VIRTUAL_MODS
+ | XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP;
+ static const xcb_xkb_select_events_details_t details =
+ {
+ /* New keyboard details */
+ .affectNewKeyboard = XCB_XKB_NKN_DETAIL_KEYCODES,
+ .newKeyboardDetails = XCB_XKB_NKN_DETAIL_KEYCODES,
+ /* State event sub-types: as per xkb_state_update_mask() */
+#define STATE_PARTS XCB_XKB_STATE_PART_MODIFIER_BASE \
+ | XCB_XKB_STATE_PART_MODIFIER_LATCH \
+ | XCB_XKB_STATE_PART_MODIFIER_LOCK \
+ | XCB_XKB_STATE_PART_GROUP_BASE \
+ | XCB_XKB_STATE_PART_GROUP_LATCH \
+ | XCB_XKB_STATE_PART_GROUP_LOCK
+ .affectState = STATE_PARTS,
+ .stateDetails = STATE_PARTS,
+ };
+
+ int32_t core = xkb_x11_get_core_keyboard_device_id(conn);
+ if (core == -1)
+ {
+ xkb_context_unref(sys->xkb.ctx);
+ sys->xkb.ctx = NULL;
+ return -1;
+ }
+
+ xcb_xkb_select_events_aux(conn, core, affect, 0, 0, map_parts, map_parts,
+ &details);
+
+ InitKeyboard(wnd);
+ return 0;
+}
+
+static void DeinitKeyboardExtension(vout_window_t *wnd)
+{
+ vout_window_sys_t *sys = wnd->sys;
+
+ if (sys->xkb.ctx == NULL)
+ return;
+
+ DeinitKeyboard(wnd);
+ xkb_context_unref(sys->xkb.ctx);
+}
+#else
+# define InitKeyboardExtension(w) (w, -1)
+# define DeinitKeyboardExtension(w) ((void)(w))
+#endif
+
static xcb_cursor_t CursorCreate(xcb_connection_t *conn, xcb_window_t root)
{
xcb_cursor_t cur = xcb_generate_id(conn);
@@ -80,29 +231,14 @@ static int ProcessEvent(vout_window_t *wnd, xcb_generic_event_t *ev)
{
case XCB_KEY_PRESS:
{
-#ifdef HAVE_XCB_KEYSYMS
+#ifdef HAVE_XCB_XKB
xcb_key_press_event_t *e = (xcb_key_press_event_t *)ev;
- xcb_keysym_t sym = xcb_key_press_lookup_keysym(sys->keys, e, 0);
- uint_fast32_t vk = vlc_xkb_convert_keysym(sym);
+ uint_fast32_t vk = vlc_xkb_get_one(sys->xkb.state, e->detail);
msg_Dbg(wnd, "key: 0x%08"PRIxFAST32" (X11: 0x%04"PRIx32")",
- vk, sym);
+ vk, e->detail);
if (vk == KEY_UNSET)
break;
- if (e->state & XCB_MOD_MASK_SHIFT) /* Shift */
- vk |= KEY_MODIFIER_SHIFT;
- /* XCB_MOD_MASK_LOCK */ /* Caps Lock */
- if (e->state & XCB_MOD_MASK_CONTROL) /* Control */
- vk |= KEY_MODIFIER_CTRL;
- if (e->state & XCB_MOD_MASK_1) /* Alternate */
- vk |= KEY_MODIFIER_ALT;
- /* XCB_MOD_MASK_2 */ /* Numeric Pad Lock */
- if (e->state & XCB_MOD_MASK_3) /* Super */
- vk |= KEY_MODIFIER_META;
- if (e->state & XCB_MOD_MASK_4) /* Meta */
- vk |= KEY_MODIFIER_META;
- if (e->state & XCB_MOD_MASK_5) /* Alternate Graphic */
- vk |= KEY_MODIFIER_ALT;
vout_window_ReportKeyPress(wnd, vk);
#endif
@@ -151,17 +287,16 @@ static int ProcessEvent(vout_window_t *wnd, xcb_generic_event_t *ev)
break;
case XCB_MAPPING_NOTIFY:
- {
-#ifdef HAVE_XCB_KEYSYMS
- xcb_mapping_notify_event_t *e = (xcb_mapping_notify_event_t *)ev;
-
- msg_Dbg(wnd, "refreshing keyboard mapping");
- xcb_refresh_keyboard_mapping(sys->keys, e);
-#endif
break;
- }
default:
+#ifdef HAVE_XCB_XKB
+ if (sys->xkb.ctx != NULL && ev->response_type == sys->xkb.base)
+ {
+ ProcessKeyboardEvent(wnd, ev);
+ break;
+ }
+#endif
msg_Dbg (wnd, "unhandled event %"PRIu8, ev->response_type);
}
@@ -488,12 +623,8 @@ static int Open (vout_window_t *wnd, const vout_window_cfg_t *cfg)
wnd->sys = p_sys;
p_sys->conn = conn;
-#ifdef HAVE_XCB_KEYSYMS
- if (var_InheritBool (wnd, "keyboard-events"))
- p_sys->keys = xcb_key_symbols_alloc(conn);
- else
- p_sys->keys = NULL;
-#endif
+ if (var_InheritBool(wnd, "keyboard-events"))
+ InitKeyboardExtension(wnd);
p_sys->root = scr->root;
/* ICCCM
@@ -565,10 +696,7 @@ static int Open (vout_window_t *wnd, const vout_window_cfg_t *cfg)
* request from this thread must be completed at this point. */
if (vlc_clone (&p_sys->thread, Thread, wnd, VLC_THREAD_PRIORITY_LOW))
{
-#ifdef HAVE_XCB_KEYSYMS
- if (p_sys->keys != NULL)
- xcb_key_symbols_free(p_sys->keys);
-#endif
+ DeinitKeyboardExtension(wnd);
goto error;
}
@@ -593,11 +721,8 @@ static void Close (vout_window_t *wnd)
vlc_cancel (p_sys->thread);
vlc_join (p_sys->thread, NULL);
-#ifdef HAVE_XCB_KEYSYMS
- if (p_sys->keys != NULL)
- xcb_key_symbols_free(p_sys->keys);
-#endif
+ DeinitKeyboardExtension(wnd);
xcb_disconnect (conn);
free (wnd->display.x11);
free (p_sys);
@@ -724,18 +849,11 @@ static int EmOpen (vout_window_t *wnd, const vout_window_cfg_t *cfg)
vout_window_ReportSize(wnd, geo->width, geo->height);
free (geo);
-#ifdef HAVE_XCB_KEYSYMS
/* Try to subscribe to keyboard and mouse events (only one X11 client can
* subscribe to input events, so this can fail). */
- if (var_InheritBool (wnd, "keyboard-events"))
- {
- p_sys->keys = xcb_key_symbols_alloc(conn);
- if (p_sys->keys != NULL)
- value |= XCB_EVENT_MASK_KEY_PRESS;
- }
- else
- p_sys->keys = NULL;
-#endif
+ if (var_InheritBool(wnd, "keyboard-events")
+ && InitKeyboardExtension(wnd) == 0)
+ value |= XCB_EVENT_MASK_KEY_PRESS;
if (var_InheritBool(wnd, "mouse-events"))
value |= XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE;
@@ -746,10 +864,7 @@ static int EmOpen (vout_window_t *wnd, const vout_window_cfg_t *cfg)
CacheAtoms (p_sys);
if (vlc_clone (&p_sys->thread, Thread, wnd, VLC_THREAD_PRIORITY_LOW))
{
-#ifdef HAVE_XCB_KEYSYMS
- if (p_sys->keys != NULL)
- xcb_key_symbols_free(p_sys->keys);
-#endif
+ DeinitKeyboardExtension(wnd);
goto error;
}
More information about the vlc-commits
mailing list