a450d43b845af54aca6be1980ccb2087b24b0296 — Drew DeVault 8 months ago 07efbbe
Rig up WlrKeyboard and WlrSeat events
5 files changed, 147 insertions(+), 3 deletions(-)

M SCsub
M wlr_keyboard.cpp
M wlr_keyboard.h
M wlr_seat.cpp
M wlr_seat.h
M SCsub => SCsub +1 -0
@@ 1,5 1,6 @@
 # SCsub
 Import('env')
+env.ParseConfig("pkg-config xkbcommon --cflags --libs")
 env.ParseConfig("pkg-config wlroots --cflags --libs")
 env.ParseConfig("pkg-config wayland-server --cflags --libs")
 

M wlr_keyboard.cpp => wlr_keyboard.cpp +77 -3
@@ 1,3 1,4 @@
+#include <assert.h>
 #include <time.h>
 #include "core/object.h"
 #include "core/os/input_event.h"


@@ 5,7 6,9 @@
 #include "scene/main/node.h"
 #include "wlr_keyboard.h"
 extern "C" {
+#include <xkbcommon/xkbcommon.h>
 #include <wlr/interfaces/wlr_keyboard.h>
+#include <wlr/interfaces/wlr_input_device.h>
 #include <wlr/types/wlr_keyboard.h>
 
 static void keyboard_destroy(struct wlr_keyboard *kb) {


@@ 21,13 24,67 @@ static const struct wlr_keyboard_impl keyboard_impl = {
 void WlrKeyboard::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("_input", "event"),
 			&WlrKeyboard::_input);
+
+	ADD_SIGNAL(MethodInfo("key", PropertyInfo(Variant::OBJECT,
+				"keyboard", PROPERTY_HINT_RESOURCE_TYPE, "WlrKeyboard"),
+			PropertyInfo(Variant::OBJECT,
+				"key_event", PROPERTY_HINT_RESOURCE_TYPE, "WlrEventKeyboardKey")));
+	ADD_SIGNAL(MethodInfo("modifiers", PropertyInfo(Variant::OBJECT,
+			"keyboard", PROPERTY_HINT_RESOURCE_TYPE, "WlrKeyboard")));
+}
+
+extern "C" {
+
+void WlrKeyboard::handle_key(struct wl_listener *listener, void *data) {
+	WlrKeyboard *keyboard = wl_container_of(listener, keyboard, key);
+	struct wlr_event_keyboard_key *event =
+		(struct wlr_event_keyboard_key *)data;
+	auto gdevent = new WlrEventKeyboardKey(event);
+	keyboard->emit_signal("key", keyboard, gdevent);
+}
+
+void WlrKeyboard::handle_modifiers(struct wl_listener *listener, void *data) {
+	WlrKeyboard *keyboard = wl_container_of(listener, keyboard, modifiers);
+	keyboard->emit_signal("modifiers", keyboard);
+}
+
+}
+
+void WlrKeyboard::ensure_keyboard() {
+	struct xkb_rule_names rules = { 0 };
+
+	wlr_keyboard_init(&wlr_keyboard, &keyboard_impl);
+	// TODO: configure xkb with godot properties?
+	rules.rules = getenv("XKB_DEFAULT_RULES");
+	rules.model = getenv("XKB_DEFAULT_MODEL");
+	rules.layout = getenv("XKB_DEFAULT_LAYOUT");
+	rules.variant = getenv("XKB_DEFAULT_VARIANT");
+	rules.options = getenv("XKB_DEFAULT_OPTIONS");
+	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+	assert(context);
+	struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules,
+			XKB_KEYMAP_COMPILE_NO_FLAGS);
+	assert(keymap);
+	wlr_keyboard_set_keymap(&wlr_keyboard, keymap);
+	xkb_keymap_unref(keymap);
+	xkb_context_unref(context);
+
+	wlr_input_device_init(&wlr_input_device, WLR_INPUT_DEVICE_KEYBOARD,
+			NULL, "Godot", 1, 1);
+	wlr_input_device.keyboard = &wlr_keyboard;
+
+	key.notify = handle_key;
+	wl_signal_add(&wlr_keyboard.events.key, &key);
+	modifiers.notify = handle_modifiers;
+	wl_signal_add(&wlr_keyboard.events.modifiers, &modifiers);
+
+	keyboard_init = true;
 }
 
 void WlrKeyboard::_notification(int p_what) {
 	switch (p_what) {
 	case NOTIFICATION_ENTER_TREE:
-		wlr_keyboard_init(&wlr_keyboard, &keyboard_impl);
-		keyboard_init = true;
+		ensure_keyboard();
 		set_process_input(true);
 		break;
 	case NOTIFICATION_EXIT_TREE:


@@ 50,13 107,17 @@ void WlrKeyboard::_input(const Ref<InputEvent> &p_event) {
 	if (k.is_valid()) {
 		struct wlr_event_keyboard_key event = { 0 };
 		event.time_msec = timespec_to_msec(&now);
-		event.keycode = eudev_from_godot(k->get_scancode()) - 8;
+		event.keycode = eudev_from_godot(k->get_scancode());
 		event.state = k->is_pressed() ? WLR_KEY_PRESSED : WLR_KEY_RELEASED;
 		event.update_state = true;
 		wlr_keyboard_notify_key(&wlr_keyboard, &event);
 	}
 }
 
+struct wlr_input_device *WlrKeyboard::get_wlr_input_device() {
+	return &wlr_input_device;
+}
+
 WlrKeyboard::WlrKeyboard() {
 	keyboard_init = false;
 	wlr_keyboard = { 0 };


@@ 67,3 128,16 @@ WlrKeyboard::~WlrKeyboard() {
 		wlr_keyboard_destroy(&wlr_keyboard);
 	}
 }
+
+
+WlrEventKeyboardKey::WlrEventKeyboardKey() {
+	/* Not used */
+}
+
+WlrEventKeyboardKey::WlrEventKeyboardKey(struct wlr_event_keyboard_key *event) {
+	this->event = event;
+}
+
+struct wlr_event_keyboard_key *WlrEventKeyboardKey::get_wlr_event() {
+	return event;
+}

M wlr_keyboard.h => wlr_keyboard.h +27 -0
@@ 6,15 6,40 @@
 #include "wayland_display.h"
 extern "C" {
 #include <wayland-server.h>
+#include <wlr/types/wlr_input_device.h>
 #include <wlr/types/wlr_keyboard.h>
 }
 
+// TODO: gdscript users may want to create synthetic key events with this
+class WlrEventKeyboardKey : public Object {
+	GDCLASS(WlrEventKeyboardKey, Object);
+
+	struct wlr_event_keyboard_key *event;
+
+protected:
+	WlrEventKeyboardKey(); // Required by Object
+
+public:
+	WlrEventKeyboardKey(struct wlr_event_keyboard_key *event);
+
+	struct wlr_event_keyboard_key *get_wlr_event();
+};
+
 class WlrKeyboard : public Node {
 	GDCLASS(WlrKeyboard, Node);
 
 	bool keyboard_init;
+	struct wlr_input_device wlr_input_device;
 	struct wlr_keyboard wlr_keyboard;
 
+	struct wl_listener key;
+	struct wl_listener modifiers;
+
+	static void handle_key(struct wl_listener *listener, void *data);
+	static void handle_modifiers(struct wl_listener *listener, void *data);
+
+	void ensure_keyboard();
+
 protected:
 	static void _bind_methods();
 	virtual void _notification(int p_what);


@@ 23,6 48,8 @@ protected:
 public:
 	WlrKeyboard();
 	~WlrKeyboard();
+
+	struct wlr_input_device *get_wlr_input_device();
 };
 
 #endif

M wlr_seat.cpp => wlr_seat.cpp +36 -0
@@ 152,6 152,34 @@ bool WlrSeat::validate_grab_serial(uint32_t serial) {
 	return wlr_seat_validate_grab_serial(wlr_seat, serial);
 }
 
+void WlrSeat::set_keyboard(Variant _keyboard) {
+	auto keyboard = dynamic_cast<WlrKeyboard *>((Object *)_keyboard);
+	wlr_seat_set_keyboard(wlr_seat, keyboard->get_wlr_input_device());
+}
+
+void WlrSeat::keyboard_notify_enter(Variant _surface) {
+	auto surface = dynamic_cast<WlrSurface *>((Object *)_surface);
+	struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(wlr_seat);
+	wlr_seat_keyboard_notify_enter(wlr_seat, surface->get_wlr_surface(),
+		keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
+}
+
+void WlrSeat::keyboard_notify_key(Variant _key_event) {
+	struct timespec now;
+	clock_gettime(CLOCK_MONOTONIC, &now);
+	auto key_event = dynamic_cast<WlrEventKeyboardKey *>((Object *)_key_event);
+	auto event = key_event->get_wlr_event();
+	wlr_seat_keyboard_notify_key(wlr_seat, timespec_to_msec(&now),
+			event->keycode, event->state);
+}
+
+void WlrSeat::keyboard_notify_modifiers() {
+	struct timespec now;
+	clock_gettime(CLOCK_MONOTONIC, &now);
+	struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(wlr_seat);
+	wlr_seat_keyboard_notify_modifiers(wlr_seat, &keyboard->modifiers);
+}
+
 void WlrSeat::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_capabilities", "capabilities"),
 			&WlrSeat::set_capabilities);


@@ 169,6 197,14 @@ void WlrSeat::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("pointer_notify_frame"),
 			&WlrSeat::pointer_notify_frame);
 
+	ClassDB::bind_method(D_METHOD("set_keyboard"), &WlrSeat::set_keyboard);
+	ClassDB::bind_method(D_METHOD("keyboard_notify_enter", "surface"),
+			&WlrSeat::keyboard_notify_enter);
+	ClassDB::bind_method(D_METHOD("keyboard_notify_key", "key_event"),
+			&WlrSeat::keyboard_notify_key);
+	ClassDB::bind_method(D_METHOD("keyboard_notify_modifiers"),
+			&WlrSeat::keyboard_notify_modifiers);
+
 	ClassDB::bind_method(D_METHOD("validate_grab_serial", "serial"),
 			&WlrSeat::validate_grab_serial);
 

M wlr_seat.h => wlr_seat.h +6 -0
@@ 6,6 6,7 @@
 #include "scene/main/node.h"
 #include "wayland_display.h"
 #include "wayland_global.h"
+#include "wlr_keyboard.h"
 #include "wlr_surface.h"
 extern "C" {
 #include <wayland-server.h>


@@ 44,6 45,11 @@ public:
 	void pointer_notify_frame();
 	void pointer_clear_focus();
 
+	void set_keyboard(Variant _keyboard);
+	void keyboard_notify_enter(Variant _surface);
+	void keyboard_notify_key(Variant key_event);
+	void keyboard_notify_modifiers();
+
 	bool validate_grab_serial(uint32_t serial);
 
 	WlrSeat();