[vlc-commits] xdg-shell: implement keyboard events
Rémi Denis-Courmont
git at videolan.org
Thu May 24 08:00:22 CEST 2018
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue May 22 23:45:30 2018 +0300| [2ef29b66b9de04bc06d29a14032756ad57c1287e] | committer: Rémi Denis-Courmont
xdg-shell: implement keyboard events
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=2ef29b66b9de04bc06d29a14032756ad57c1287e
---
configure.ac | 7 ++
modules/video_output/Makefile.am | 15 ++-
modules/video_output/wayland/input.c | 188 ++++++++++++++++++++++++++++++++++-
3 files changed, 202 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index 547e5c5a4f..e0af7ee6c8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3179,6 +3179,12 @@ AS_IF([test "${enable_wayland}" != "no"], [
AC_MSG_ERROR([${WAYLAND_EGL_PKG_ERRORS}.])
])
])
+
+ PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon], [
+ have_xkbcommon="yes"
+ ], [
+ AC_MSG_WARN([${XKBCOMMON_PKG_ERRORS}])
+ ])
], [
AS_IF([test -n "${enable_wayland}"], [
AC_MSG_ERROR([${WAYLAND_CLIENT_PKG_ERRORS}.])
@@ -3189,6 +3195,7 @@ AC_SUBST([WAYLAND_PROTOCOLS])
AC_SUBST([WAYLAND_SCANNER])
AM_CONDITIONAL([HAVE_WAYLAND], [test "${have_wayland}" = "yes"])
AM_CONDITIONAL([HAVE_WAYLAND_EGL], [test "${have_wayland_egl}" = "yes"])
+AM_CONDITIONAL([HAVE_XKBCOMMON], [test "${have_xkbcommon}" = "yes"])
dnl
diff --git a/modules/video_output/Makefile.am b/modules/video_output/Makefile.am
index 4a33e11fca..279f461efd 100644
--- a/modules/video_output/Makefile.am
+++ b/modules/video_output/Makefile.am
@@ -208,11 +208,12 @@ nodist_libwl_shell_plugin_la_SOURCES = \
video_output/wayland/server-decoration-protocol.c
libwl_shell_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) \
-I$(builddir)/video_output/wayland
-libwl_shell_plugin_la_CFLAGS = $(WAYLAND_CLIENT_CFLAGS)
-libwl_shell_plugin_la_LIBADD = $(WAYLAND_CLIENT_LIBS) $(LIBPTHREAD)
+libwl_shell_plugin_la_CFLAGS = $(libxdg_shell_plugin_la_CFLAGS)
+libwl_shell_plugin_la_LIBADD = $(libxdg_shell_plugin_la_LIBADD)
libxdg_shell_plugin_la_SOURCES = \
video_output/wayland/input.h video_output/wayland/input.c \
+ video_output/xcb/vlc_xkb.h video_output/xcb/xkb.c \
video_output/wayland/xdg-shell.c
nodist_libxdg_shell_plugin_la_SOURCES = \
video_output/wayland/xdg-shell-client-protocol.h \
@@ -221,8 +222,14 @@ nodist_libxdg_shell_plugin_la_SOURCES = \
video_output/wayland/server-decoration-protocol.c
libxdg_shell_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -DXDG_SHELL \
-I$(builddir)/video_output/wayland
-libxdg_shell_plugin_la_CFLAGS = $(WAYLAND_CLIENT_CFLAGS)
-libxdg_shell_plugin_la_LIBADD = $(WAYLAND_CLIENT_LIBS) $(LIBPTHREAD)
+libxdg_shell_plugin_la_CFLAGS = \
+ $(WAYLAND_CLIENT_CFLAGS) $(XKBCOMMON_CFLAGS)
+libxdg_shell_plugin_la_LIBADD = \
+ $(WAYLAND_CLIENT_LIBS) $(XKBCOMMON_LIBS) $(LIBPTHREAD)
+if HAVE_XKBCOMMON
+libwl_shell_plugin_la_CPPFLAGS += -DHAVE_XKBCOMMON
+libxdg_shell_plugin_la_CPPFLAGS += -DHAVE_XKBCOMMON
+endif
video_output/wayland/xdg-shell-client-protocol.h: \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml \
diff --git a/modules/video_output/wayland/input.c b/modules/video_output/wayland/input.c
index b65e8cdd3a..8796c6f1f3 100644
--- a/modules/video_output/wayland/input.c
+++ b/modules/video_output/wayland/input.c
@@ -27,11 +27,17 @@
#include <assert.h>
#include <inttypes.h>
#include <stdlib.h>
+#include <sys/mman.h>
#include <linux/input-event-codes.h>
#include <wayland-client.h>
+#ifdef HAVE_XKBCOMMON
+# include <xkbcommon/xkbcommon.h>
+# include "../xcb/vlc_xkb.h"
+#endif
#include <vlc_common.h>
#include <vlc_vout_window.h>
#include <vlc_mouse.h>
+#include <vlc_fs.h>
#include "input.h"
@@ -40,6 +46,12 @@ struct seat_data
vout_window_t *owner;
struct wl_seat *seat;
struct wl_pointer *pointer;
+#ifdef HAVE_XKBCOMMON
+ struct xkb_context *xkb;
+ struct wl_keyboard *keyboard;
+ struct xkb_keymap *keymap;
+ struct xkb_state *keystate;
+#endif
uint32_t version;
struct wl_list node;
@@ -190,8 +202,154 @@ static void pointer_destroy(struct seat_data *sd)
wl_pointer_release(sd->pointer);
else
wl_pointer_destroy(sd->pointer);
+
+ sd->pointer = NULL;
+}
+
+#ifdef HAVE_XKBCOMMON
+static void keyboard_keymap_cb(void *data, struct wl_keyboard *keyboard,
+ uint32_t format, int fd, uint32_t size)
+{
+ struct seat_data *sd = data;
+ vout_window_t *wnd = sd->owner;
+ void *map;
+
+ msg_Dbg(wnd, "format %"PRIu32" keymap of %"PRIu32" bytes", format, size);
+
+ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
+ {
+ msg_Err(wnd, "unsupported keymap format %"PRIu32, format);
+ goto out;
+ }
+
+ size++; /* trailing nul */
+
+ map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+ if (map == MAP_FAILED)
+ goto out;
+
+ assert(((char *)map)[size - 1] == '\0');
+ sd->keymap = xkb_keymap_new_from_string(sd->xkb, map,
+ XKB_KEYMAP_FORMAT_TEXT_V1,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+ munmap(map, size);
+
+ if (sd->keymap != NULL)
+ sd->keystate = xkb_state_new(sd->keymap);
+ else
+ msg_Err(wnd, "keymap parse error");
+
+out:
+ vlc_close(fd);
+ (void) keyboard;
+}
+
+static void keyboard_enter_cb(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, struct wl_surface *surface,
+ struct wl_array *keys)
+{
+ (void) data; (void) keyboard; (void) serial; (void) surface; (void) keys;
+}
+
+static void keyboard_leave_cb(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, struct wl_surface *surface)
+{
+ (void) data; (void) keyboard; (void) serial; (void) surface;}
+
+static void keyboard_key_cb(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, uint32_t time, uint32_t keycode,
+ uint32_t state)
+{
+ struct seat_data *sd = data;
+ vout_window_t *wnd = sd->owner;
+ uint_fast32_t vk;
+
+ if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
+ return;
+ if (unlikely(sd->keystate == NULL))
+ return;
+
+ vk = vlc_xkb_get_one(sd->keystate, keycode);
+ if (vk)
+ {
+ msg_Dbg(wnd, "key: 0x%08"PRIxFAST32" (XKB: 0x%04"PRIx32")",
+ vk, keycode);
+ vout_window_ReportKeyPress(wnd, vk);
+ }
+
+ (void) keyboard; (void) serial; (void) time;
+}
+
+static void keyboard_modifiers_cb(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, uint32_t depressed,
+ uint32_t latched, uint32_t locked,
+ uint32_t group)
+{
+ struct seat_data *sd = data;
+
+ if (unlikely(sd->keystate == NULL))
+ return;
+
+ xkb_state_update_mask(sd->keystate, depressed, latched, locked,
+ 0, 0, group);
+
+ (void) keyboard; (void) serial;
}
+static void keyboard_repeat_info_cb(void *data, struct wl_keyboard *keyboard,
+ int32_t rate, int32_t delay)
+{
+ struct seat_data *sd = data;
+ vout_window_t *wnd = sd->owner;
+
+ msg_Dbg(wnd, "keyboard repeat info: %d Hz after %d ms", rate, delay);
+ (void) keyboard;
+}
+
+static const struct wl_keyboard_listener keyboard_cbs =
+{
+ keyboard_keymap_cb,
+ keyboard_enter_cb,
+ keyboard_leave_cb,
+ keyboard_key_cb,
+ keyboard_modifiers_cb,
+ keyboard_repeat_info_cb,
+};
+
+static void keyboard_create(struct seat_data *sd)
+{
+ if (sd->keyboard != NULL)
+ return;
+
+ sd->keyboard = wl_seat_get_keyboard(sd->seat);
+ if (likely(sd->keyboard != NULL))
+ {
+ sd->keymap = NULL;
+ wl_keyboard_add_listener(sd->keyboard, &keyboard_cbs, sd);
+ }
+}
+
+static void keyboard_destroy(struct seat_data *sd)
+{
+ if (sd->keyboard == NULL)
+ return;
+
+ if (sd->version >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
+ wl_keyboard_release(sd->keyboard);
+ else
+ wl_keyboard_destroy(sd->keyboard);
+
+ if (sd->keymap != NULL)
+ {
+ if (sd->keystate != NULL)
+ xkb_state_unref(sd->keystate);
+ xkb_keymap_unref(sd->keymap);
+ }
+
+ sd->keyboard = NULL;
+}
+#endif /* HAVE_XKBCOMMON */
+
static void seat_capabilities_cb(void *data, struct wl_seat *seat,
uint32_t capabilities)
{
@@ -208,6 +366,16 @@ static void seat_capabilities_cb(void *data, struct wl_seat *seat,
}
else
pointer_destroy(sd);
+
+#ifdef HAVE_XKBCOMMON
+ if (capabilities & WL_SEAT_CAPABILITY_KEYBOARD)
+ {
+ if (sd->xkb != NULL)
+ keyboard_create(sd);
+ }
+ else
+ keyboard_destroy(sd);
+#endif
}
static void seat_name_cb(void *data, struct wl_seat *seat, const char *name)
@@ -234,10 +402,6 @@ int seat_create(vout_window_t *wnd, struct wl_registry *registry,
if (version > 5)
version = 5;
- sd->owner = wnd;
- sd->pointer = NULL;
- sd->version = version;
-
sd->seat = wl_registry_bind(registry, name, &wl_seat_interface, version);
if (unlikely(sd->seat == NULL))
{
@@ -245,6 +409,16 @@ int seat_create(vout_window_t *wnd, struct wl_registry *registry,
return -1;
}
+ sd->owner = wnd;
+ sd->pointer = NULL;
+#ifdef HAVE_XKBCOMMON
+ if (var_InheritBool(wnd, "keyboard-events"))
+ sd->xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+
+ sd->keyboard = NULL;
+#endif
+ sd->version = version;
+
wl_seat_add_listener(sd->seat, &seat_cbs, sd);
wl_list_insert(list, &sd->node);
return 0;
@@ -254,6 +428,12 @@ static void seat_destroy(struct seat_data *sd)
{
wl_list_remove(&sd->node);
+#ifdef HAVE_XKBCOMMON
+ keyboard_destroy(sd);
+
+ if (sd->xkb != NULL)
+ xkb_context_unref(sd->xkb);
+#endif
pointer_destroy(sd);
if (sd->version >= WL_SEAT_RELEASE_SINCE_VERSION)
More information about the vlc-commits
mailing list