qt: Add xkbcommon keyboard support for Wayland

This commit is contained in:
RichardG867
2023-04-08 00:31:25 -03:00
parent 078e8cca0c
commit bbbe0ec88d
7 changed files with 279 additions and 2 deletions

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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

View File

@@ -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);

View 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, &registry_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);
}

View 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();

View File

@@ -77,6 +77,7 @@ xkbcommon_x11_init()
}
xkbcommon_init(keymap);
goto err_conn;
err_ctx:
xkb_context_unref(ctx);