~sircmpwn/gdwlroots

a450d43b845af54aca6be1980ccb2087b24b0296 — Drew DeVault 1 year, 5 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();