river/src/keyboard.zig

112 lines
4.3 KiB
Zig
Raw Normal View History

2020-03-22 14:42:55 -07:00
const std = @import("std");
const c = @import("c.zig").c;
2020-03-23 08:50:20 -07:00
const Seat = @import("seat.zig").Seat;
pub const Keyboard = struct {
2020-03-22 14:42:55 -07:00
seat: *Seat,
device: *c.wlr_input_device,
listen_modifiers: c.wl_listener,
listen_key: c.wl_listener,
pub fn init(self: *@This(), seat: *Seat, device: *c.wlr_input_device) !void {
self.seat = seat;
self.device = device;
2020-03-22 14:42:55 -07:00
// 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) orelse
return error.CantCreateXkbContext;
2020-03-22 14:42:55 -07:00
defer c.xkb_context_unref(context);
2020-03-23 08:50:20 -07:00
const keymap = c.xkb_keymap_new_from_names(
2020-03-22 14:42:55 -07:00
context,
&rules,
c.enum_xkb_keymap_compile_flags.XKB_KEYMAP_COMPILE_NO_FLAGS,
) orelse
return error.CantCreateXkbKeymap;
2020-03-22 14:42:55 -07:00
defer c.xkb_keymap_unref(keymap);
var keyboard_device = self.device.unnamed_37.keyboard;
// TODO: handle failure after https://github.com/swaywm/wlroots/pull/2081
2020-03-22 14:42:55 -07:00
c.wlr_keyboard_set_keymap(keyboard_device, keymap);
c.wlr_keyboard_set_repeat_info(keyboard_device, 25, 600);
// Setup listeners for keyboard events
self.listen_modifiers.notify = handle_modifiers;
c.wl_signal_add(&keyboard_device.*.events.modifiers, &self.listen_modifiers);
2020-03-22 14:42:55 -07:00
self.listen_key.notify = handle_key;
c.wl_signal_add(&keyboard_device.*.events.key, &self.listen_key);
2020-03-22 14:42:55 -07:00
}
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.
2020-03-23 08:50:20 -07:00
c.wlr_seat_set_keyboard(keyboard.seat.wlr_seat, keyboard.*.device);
2020-03-22 14:42:55 -07:00
// Send modifiers to the client.
2020-03-23 08:50:20 -07:00
c.wlr_seat_keyboard_notify_modifiers(keyboard.seat.wlr_seat, &keyboard.*.device.*.unnamed_37.keyboard.*.modifiers);
2020-03-22 14:42:55 -07:00
}
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),
);
2020-03-23 08:50:20 -07:00
const keyboard_device = keyboard.device.unnamed_37.keyboard;
2020-03-22 14:42:55 -07:00
// Translate libinput keycode -> xkbcommon
2020-03-23 08:50:20 -07:00
const keycode = event.keycode + 8;
2020-03-22 14:42:55 -07:00
// Get a list of keysyms based on the keymap for this keyboard
2020-03-23 08:50:20 -07:00
var syms: ?[*]c.xkb_keysym_t = undefined;
2020-03-22 14:42:55 -07:00
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
2020-03-23 08:50:20 -07:00
event.state == c.enum_wlr_key_state.WLR_KEY_PRESSED)
2020-03-22 14:42:55 -07:00
{
// 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) {
2020-03-23 08:50:20 -07:00
handled = keyboard.seat.server.handle_keybinding(syms.?[i]);
2020-03-22 14:42:55 -07:00
if (handled) {
break;
}
i += 1;
}
}
if (!handled) {
// Otherwise, we pass it along to the client.
2020-03-23 08:50:20 -07:00
const wlr_seat = keyboard.seat.wlr_seat;
c.wlr_seat_set_keyboard(wlr_seat, keyboard.device);
2020-03-22 14:42:55 -07:00
c.wlr_seat_keyboard_notify_key(
2020-03-23 08:50:20 -07:00
wlr_seat,
event.time_msec,
event.keycode,
@intCast(u32, @enumToInt(event.state)),
2020-03-22 14:42:55 -07:00
);
}
}
};