From 0584fde12625832d16a600a0900641cbb9a8b1c8 Mon Sep 17 00:00:00 2001 From: Isaac Freund Date: Sun, 22 Mar 2020 22:42:55 +0100 Subject: WIP massive refactor --- src/keyboard.zig | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/keyboard.zig (limited to 'src/keyboard.zig') diff --git a/src/keyboard.zig b/src/keyboard.zig new file mode 100644 index 0000000..e769ac0 --- /dev/null +++ b/src/keyboard.zig @@ -0,0 +1,117 @@ +const std = @import("std"); +const c = @import("c.zig").c; + +const Keyboard = struct { + seat: *Seat, + device: *c.wlr_input_device, + + listen_modifiers: c.wl_listener, + listen_key: c.wl_listener, + + pub fn init(seat: *Seat, device: *c.wlr_input_device) @This() { + var keyboard = @This(){ + .seat = seat, + .device = device, + + .listen_modifiers = c.wl_listener{ + .link = undefined, + .notify = handle_modifiers, + }, + .listen_key = c.wl_listener{ + .link = undefined, + .notify = handle_key, + }, + }; + + // We need to prepare an XKB keymap and assign it to the keyboard. This + // assumes the defaults (e.g. layout = "us"). + const rules = c.xkb_rule_names{ + .rules = null, + .model = null, + .layout = null, + .variant = null, + .options = null, + }; + const context = c.xkb_context_new(c.enum_xkb_context_flags.XKB_CONTEXT_NO_FLAGS); + defer c.xkb_context_unref(context); + + const keymap = man_c.xkb_map_new_from_names( + context, + &rules, + c.enum_xkb_keymap_compile_flags.XKB_KEYMAP_COMPILE_NO_FLAGS, + ); + defer c.xkb_keymap_unref(keymap); + + var keyboard_device = device.*.unnamed_37.keyboard; + c.wlr_keyboard_set_keymap(keyboard_device, keymap); + c.wlr_keyboard_set_repeat_info(keyboard_device, 25, 600); + + // Setup listeners for keyboard events + c.wl_signal_add(&keyboard_device.*.events.modifiers, &keyboard.*.listen_modifiers); + c.wl_signal_add(&keyboard_device.*.events.key, &keyboard.*.listen_key); + + return keyboard; + } + + fn handle_modifiers(listener: [*c]c.wl_listener, data: ?*c_void) callconv(.C) void { + // This event is raised when a modifier key, such as shift or alt, is + // pressed. We simply communicate this to the client. */ + var keyboard = @fieldParentPtr(Keyboard, "listen_modifiers", listener); + + // A seat can only have one keyboard, but this is a limitation of the + // Wayland protocol - not wlroots. We assign all connected keyboards to the + // same seat. You can swap out the underlying wlr_keyboard like this and + // wlr_seat handles this transparently. + c.wlr_seat_set_keyboard(keyboard.*.server.*.seat, keyboard.*.device); + + // Send modifiers to the client. + c.wlr_seat_keyboard_notify_modifiers(keyboard.*.server.*.seat, &keyboard.*.device.*.unnamed_37.keyboard.*.modifiers); + } + + fn handle_key(listener: [*c]c.wl_listener, data: ?*c_void) callconv(.C) void { + // This event is raised when a key is pressed or released. + const keyboard = @fieldParentPtr(Keyboard, "listen_key", listener); + const event = @ptrCast( + *c.wlr_event_keyboard_key, + @alignCast(@alignOf(*c.wlr_event_keyboard_key), data), + ); + + const server = keyboard.*.server; + const seat = server.*.seat; + const keyboard_device = keyboard.*.device.*.unnamed_37.keyboard; + + // Translate libinput keycode -> xkbcommon + const keycode = event.*.keycode + 8; + // Get a list of keysyms based on the keymap for this keyboard + var syms: *c.xkb_keysym_t = undefined; + const nsyms = c.xkb_state_key_get_syms(keyboard_device.*.xkb_state, keycode, &syms); + + var handled = false; + const modifiers = c.wlr_keyboard_get_modifiers(keyboard_device); + if (modifiers & @intCast(u32, c.WLR_MODIFIER_LOGO) != 0 and + event.*.state == c.enum_wlr_key_state.WLR_KEY_PRESSED) + { + // If mod is held down and this button was _pressed_, we attempt to + // process it as a compositor keybinding. + var i: usize = 0; + while (i < nsyms) { + handled = keyboard.seat.server.handle_keybinding(syms[i]); + if (handled) { + break; + } + i += 1; + } + } + + if (!handled) { + // Otherwise, we pass it along to the client. + c.wlr_seat_set_keyboard(seat, keyboard.*.device); + c.wlr_seat_keyboard_notify_key( + seat, + event.*.time_msec, + event.*.keycode, + @intCast(u32, @enumToInt(event.*.state)), + ); + } + } +}; -- cgit v1.2.3