qt: Add xkbcommon keyboard support for Wayland
This commit is contained in:
@@ -402,6 +402,9 @@ if (UNIX AND NOT APPLE AND NOT HAIKU)
|
||||
ecm_add_wayland_client_protocol(WL_SOURCE_VAR PROTOCOL ${CMAKE_SOURCE_DIR}/wl_protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1)
|
||||
target_include_directories(ui PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${Qt${QT_MAJOR}Gui_PRIVATE_INCLUDE_DIRS})
|
||||
target_sources(ui PRIVATE ${WL_SOURCE_VAR} wl_mouse.cpp)
|
||||
if (XKBCOMMON_FOUND)
|
||||
target_sources(ui PRIVATE xkbcommon_wl_keyboard.cpp)
|
||||
endif()
|
||||
target_compile_definitions(ui PRIVATE WAYLAND)
|
||||
endif()
|
||||
endif()
|
||||
|
@@ -101,6 +101,9 @@ extern int qt_nvr_save(void);
|
||||
# ifdef XKBCOMMON_X11
|
||||
# include "xkbcommon_x11_keyboard.hpp"
|
||||
# endif
|
||||
# ifdef WAYLAND
|
||||
# include "xkbcommon_wl_keyboard.hpp"
|
||||
# endif
|
||||
# endif
|
||||
# include <X11/Xlib.h>
|
||||
# include <X11/keysym.h>
|
||||
@@ -652,9 +655,18 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
ui->actionCursor_Puck->setChecked(true);
|
||||
}
|
||||
|
||||
#ifdef XKBCOMMON_X11
|
||||
#ifdef XKBCOMMON
|
||||
# ifdef XKBCOMMON_X11
|
||||
if (QApplication::platformName().contains("xcb"))
|
||||
xkbcommon_x11_init();
|
||||
else
|
||||
# endif
|
||||
# ifdef WAYLAND
|
||||
if (QApplication::platformName().contains("wayland"))
|
||||
xkbcommon_wl_init();
|
||||
else
|
||||
# endif
|
||||
{}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -228,7 +228,14 @@ struct xkb_keymap *xkbcommon_keymap = nullptr;
|
||||
void
|
||||
xkbcommon_init(struct xkb_keymap *keymap)
|
||||
{
|
||||
xkbcommon_keymap = keymap;
|
||||
if (keymap)
|
||||
xkbcommon_keymap = keymap;
|
||||
}
|
||||
|
||||
void
|
||||
xkbcommon_close()
|
||||
{
|
||||
xkbcommon_keymap = NULL;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
|
@@ -16,4 +16,5 @@
|
||||
*/
|
||||
extern void *xkbcommon_keymap;
|
||||
void xkbcommon_init(struct xkb_keymap *keymap);
|
||||
void xkbcommon_close();
|
||||
uint16_t xkbcommon_translate(uint32_t keycode);
|
||||
|
236
src/qt/xkbcommon_wl_keyboard.cpp
Normal file
236
src/qt/xkbcommon_wl_keyboard.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* xkbcommon Wayland keyboard input module.
|
||||
*
|
||||
* Heavily inspired by libxkbcommon interactive-wayland.c
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2023 RichardG.
|
||||
*/
|
||||
extern "C" {
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <86box/86box.h>
|
||||
};
|
||||
#include "xkbcommon_keyboard.hpp"
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-util.h>
|
||||
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#include <QtDebug>
|
||||
#include <QGuiApplication>
|
||||
|
||||
typedef struct {
|
||||
struct wl_seat *wl_seat;
|
||||
struct wl_keyboard *wl_kbd;
|
||||
uint32_t version;
|
||||
|
||||
struct xkb_keymap *keymap;
|
||||
|
||||
struct wl_list link;
|
||||
} seat_t;
|
||||
|
||||
static bool wl_init_ok = false;
|
||||
static struct wl_list seats;
|
||||
static struct xkb_context *ctx;
|
||||
|
||||
static void
|
||||
xkbcommon_wl_set_keymap()
|
||||
{
|
||||
/* Grab keymap from the first seat with one. */
|
||||
seat_t *seat, *tmp;
|
||||
wl_list_for_each_safe(seat, tmp, &seats, link) {
|
||||
if (seat->keymap) {
|
||||
xkbcommon_init(seat->keymap);
|
||||
return;
|
||||
}
|
||||
}
|
||||
xkbcommon_close();
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_keymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format,
|
||||
int fd, uint32_t size)
|
||||
{
|
||||
seat_t *seat = (seat_t *) data;
|
||||
|
||||
char *buf = (char *) mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
||||
if (!buf) {
|
||||
qWarning() << "XKB Keyboard: Failed to mmap keymap with error" << errno;
|
||||
return;
|
||||
}
|
||||
|
||||
seat->keymap = xkb_keymap_new_from_buffer(ctx, buf, size - 1,
|
||||
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||
XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
munmap(buf, size);
|
||||
close(fd);
|
||||
if (!seat->keymap) {
|
||||
qWarning() << "XKB Keyboard: Keymap compilation failed";
|
||||
return;
|
||||
}
|
||||
|
||||
xkbcommon_wl_set_keymap();
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_enter(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
|
||||
struct wl_surface *surf, struct wl_array *keys)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_leave(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
|
||||
struct wl_surface *surf)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_key(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, uint32_t time,
|
||||
uint32_t key, uint32_t state)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_modifiers(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
|
||||
uint32_t mods_depressed, uint32_t mods_latched,
|
||||
uint32_t mods_locked, uint32_t group)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
kbd_repeat_info(void *data, struct wl_keyboard *wl_kbd, int32_t rate,
|
||||
int32_t delay)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_keyboard_listener kbd_listener = {
|
||||
kbd_keymap,
|
||||
kbd_enter,
|
||||
kbd_leave,
|
||||
kbd_key,
|
||||
kbd_modifiers,
|
||||
kbd_repeat_info
|
||||
};
|
||||
|
||||
static void
|
||||
seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t caps)
|
||||
{
|
||||
seat_t *seat = (seat_t *) data;
|
||||
|
||||
if (!seat->wl_kbd && (caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
|
||||
seat->wl_kbd = wl_seat_get_keyboard(seat->wl_seat);
|
||||
wl_keyboard_add_listener(seat->wl_kbd, &kbd_listener, seat);
|
||||
} else if (seat->wl_kbd && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
|
||||
if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
|
||||
wl_keyboard_release(seat->wl_kbd);
|
||||
else
|
||||
wl_keyboard_destroy(seat->wl_kbd);
|
||||
|
||||
static struct xkb_keymap *keymap = seat->keymap;
|
||||
seat->keymap = NULL;
|
||||
xkbcommon_wl_set_keymap();
|
||||
xkb_keymap_unref(keymap);
|
||||
|
||||
seat->wl_kbd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
seat_name(void *data, struct wl_seat *wl_seat, const char *name)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_seat_listener seat_listener = {
|
||||
seat_capabilities,
|
||||
seat_name
|
||||
};
|
||||
|
||||
static void
|
||||
display_handle_global(void *data, struct wl_registry *wl_registry, uint32_t id,
|
||||
const char *interface, uint32_t version)
|
||||
{
|
||||
if (!strcmp(interface, "wl_seat")) {
|
||||
seat_t *seat = (seat_t *) malloc(sizeof(seat_t));
|
||||
memset(seat, 0, sizeof(seat_t));
|
||||
|
||||
seat->wl_seat = (wl_seat *) wl_registry_bind(wl_registry, id, &wl_seat_interface, MIN(version, 5));
|
||||
wl_seat_add_listener(seat->wl_seat, &seat_listener, seat);
|
||||
wl_list_insert(&seats, &seat->link);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
display_global_remove(void *data, struct wl_registry *wl_registry, uint32_t id)
|
||||
{
|
||||
xkbcommon_close();
|
||||
|
||||
seat_t *seat, *tmp;
|
||||
wl_list_for_each_safe(seat, tmp, &seats, link) {
|
||||
if (seat->wl_kbd) {
|
||||
if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
|
||||
wl_keyboard_release(seat->wl_kbd);
|
||||
else
|
||||
wl_keyboard_destroy(seat->wl_kbd);
|
||||
|
||||
xkb_keymap_unref(seat->keymap);
|
||||
}
|
||||
|
||||
if (seat->version >= WL_SEAT_RELEASE_SINCE_VERSION)
|
||||
wl_seat_release(seat->wl_seat);
|
||||
else
|
||||
wl_seat_destroy(seat->wl_seat);
|
||||
|
||||
wl_list_remove(&seat->link);
|
||||
free(seat);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
display_handle_global,
|
||||
display_global_remove
|
||||
};
|
||||
|
||||
void
|
||||
xkbcommon_wl_init()
|
||||
{
|
||||
if (wl_init_ok)
|
||||
return;
|
||||
|
||||
wl_list_init(&seats);
|
||||
|
||||
ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
|
||||
if (!ctx) {
|
||||
qWarning() << "XKB Keyboard: XKB context creation failed";
|
||||
return;
|
||||
}
|
||||
|
||||
wl_display *display = (wl_display *) QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_display");
|
||||
if (display) {
|
||||
auto registry = wl_display_get_registry(display);
|
||||
if (registry) {
|
||||
wl_registry_add_listener(registry, ®istry_listener, nullptr);
|
||||
wl_display_roundtrip(display);
|
||||
wl_display_roundtrip(display);
|
||||
} else {
|
||||
goto err_ctx;
|
||||
}
|
||||
} else {
|
||||
goto err_ctx;
|
||||
}
|
||||
wl_init_ok = true;
|
||||
return;
|
||||
|
||||
err_ctx:
|
||||
xkb_context_unref(ctx);
|
||||
}
|
17
src/qt/xkbcommon_wl_keyboard.hpp
Normal file
17
src/qt/xkbcommon_wl_keyboard.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for xkbcommon Wayland keyboard input module.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Authors: RichardG, <richardg867@gmail.com>
|
||||
*
|
||||
* Copyright 2023 RichardG.
|
||||
*/
|
||||
void xkbcommon_wl_init();
|
@@ -77,6 +77,7 @@ xkbcommon_x11_init()
|
||||
}
|
||||
|
||||
xkbcommon_init(keymap);
|
||||
goto err_conn;
|
||||
|
||||
err_ctx:
|
||||
xkb_context_unref(ctx);
|
||||
|
Reference in New Issue
Block a user