diff --git a/src/keyboard.zig b/src/keyboard.zig new file mode 100644 index 0000000..49cd989 --- /dev/null +++ b/src/keyboard.zig @@ -0,0 +1,91 @@ +const Keyboard = @This(); + +const std = @import("std"); +const gpa = std.heap.c_allocator; + +const wl = @import("wayland").server.wl; +const wlr = @import("wlroots"); +const xkb = @import("xkbcommon"); + +const Server = @import("server.zig"); + +server: *Server, +link: wl.list.Link = undefined, +device: *wlr.InputDevice, + +modifiers: wl.Listener(*wlr.Keyboard) = .init(handleModifiers), +key: wl.Listener(*wlr.Keyboard.event.Key) = .init(handleKey), +destroy: wl.Listener(*wlr.InputDevice) = .init(handleDestroy), + +pub fn create(server: *Server, device: *wlr.InputDevice) !void { + const keyboard = try gpa.create(Keyboard); + errdefer gpa.destroy(keyboard); + + keyboard.* = .{ + .server = server, + .device = device, + }; + + const context = xkb.Context.new(.no_flags) orelse return error.ContextFailed; + defer context.unref(); + const keymap = xkb.Keymap.newFromNames(context, null, .no_flags) orelse return error.KeymapFailed; + defer keymap.unref(); + + const wlr_keyboard = device.toKeyboard(); + // TODO: configure this via lua later + if (!wlr_keyboard.setKeymap(keymap)) return error.SetKeymapFailed; + wlr_keyboard.setRepeatInfo(25, 600); + + wlr_keyboard.events.modifiers.add(&keyboard.modifiers); + wlr_keyboard.events.key.add(&keyboard.key); + device.events.destroy.add(&keyboard.destroy); + + std.log.debug("adding keyboard: {s}", .{keyboard.*.device.*.name orelse "(null)"}); + + server.seat.setKeyboard(wlr_keyboard); + server.keyboards.append(keyboard); +} + +pub fn handleModifiers(listener: *wl.Listener(*wlr.Keyboard), wlr_keyboard: *wlr.Keyboard) void { + const keyboard: *Keyboard = @fieldParentPtr("modifiers", listener); + keyboard.server.seat.setKeyboard(wlr_keyboard); + keyboard.server.seat.keyboardNotifyModifiers(&wlr_keyboard.modifiers); +} + +pub fn handleKey(listener: *wl.Listener(*wlr.Keyboard.event.Key), event: *wlr.Keyboard.event.Key) void { + const keyboard: *Keyboard = @fieldParentPtr("key", listener); + const wlr_keyboard = keyboard.device.toKeyboard(); + + // Translate libinput keycode -> xkbcommon + // const keycode = event.keycode + 8; + + // TODO: lua handle keybinds here + const handled = false; + if (wlr_keyboard.getModifiers().alt and event.state == .pressed) { + // for (wlr_keyboard.xkb_state.?.keyGetSyms(keycode)) |sym| { + // if (keyboard.server.handleKeybind(sym)) { + // handled = true; + // break; + // } + // } + } + + if (!handled) { + keyboard.server.seat.setKeyboard(wlr_keyboard); + keyboard.server.seat.keyboardNotifyKey(event.time_msec, event.keycode, event.state); + } +} + +pub fn handleDestroy(listener: *wl.Listener(*wlr.InputDevice), _: *wlr.InputDevice) void { + const keyboard: *Keyboard = @fieldParentPtr("destroy", listener); + + std.log.debug("removing keyboard: {s}", .{keyboard.*.device.*.name orelse "(null)"}); + + keyboard.link.remove(); + + keyboard.modifiers.link.remove(); + keyboard.key.link.remove(); + keyboard.destroy.link.remove(); + + gpa.destroy(keyboard); +} diff --git a/src/server.zig b/src/server.zig index bf3fbbc..5939a08 100644 --- a/src/server.zig +++ b/src/server.zig @@ -7,6 +7,7 @@ const wl = @import("wayland").server.wl; const wlr = @import("wlroots"); const Output = @import("output.zig"); +const Keyboard = @import("keyboard.zig"); allocator: *wlr.Allocator, backend: *wlr.Backend, @@ -16,14 +17,18 @@ output_layout: *wlr.OutputLayout, renderer: *wlr.Renderer, scene: *wlr.Scene, scene_output_layout: *wlr.SceneOutputLayout, -seat: *wlr.Seat, session: ?*wlr.Session, shm: *wlr.Shm, wl_server: *wl.Server, xdg_shell: *wlr.XdgShell, +// Input things +seat: *wlr.Seat, +keyboards: wl.list.Head(Keyboard, .link) = undefined, + // Listeners new_output: wl.Listener(*wlr.Output) = .init(newOutput), +new_input: wl.Listener(*wlr.InputDevice) = .init(newInput), pub fn init(server: *Server) !void { const wl_server = try wl.Server.create(); @@ -55,11 +60,10 @@ pub fn init(server: *Server) !void { try server.renderer.initServer(wl_server); - _ = try wlr.Compositor.create(server.wl_server, 6, server.renderer); - _ = try wlr.Subcompositor.create(server.wl_server); - _ = try wlr.DataDeviceManager.create(server.wl_server); - server.backend.events.new_output.add(&server.new_output); + server.backend.events.new_input.add(&server.new_input); + + server.keyboards.init(); } fn newOutput(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void { @@ -82,3 +86,21 @@ fn newOutput(listener: *wl.Listener(*wlr.Output), wlr_output: *wlr.Output) void return; }; } + +fn newInput(listener: *wl.Listener(*wlr.InputDevice), device: *wlr.InputDevice) void { + const server: *Server = @fieldParentPtr("new_input", listener); + switch (device.type) { + .keyboard => Keyboard.create(server, device) catch |err| { + std.log.err("failed to create keyboard: {}", .{err}); + return; + }, + // TODO: impl cursor + // .pointer => server.cursor.attachInputDevice(device), + else => {}, + } + + server.seat.setCapabilities(.{ + .pointer = true, + .keyboard = server.keyboards.length() > 0, + }); +}