From b56290d64081bb58a906c81431356ca0f8bec91c Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 27 May 2024 21:26:58 +0200 Subject: [PATCH] fix(vaxis): check modifier state is in sync on every input event --- src/renderer/vaxis/renderer.zig | 36 ++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/renderer/vaxis/renderer.zig b/src/renderer/vaxis/renderer.zig index 8b4107f..a5d45c4 100644 --- a/src/renderer/vaxis/renderer.zig +++ b/src/renderer/vaxis/renderer.zig @@ -26,6 +26,7 @@ vx: vaxis.Vaxis, no_alternate: bool, event_buffer: std.ArrayList(u8), input_buffer: std.ArrayList(u8), +mods: vaxis.Key.Modifiers = .{}, bracketed_paste: bool = false, bracketed_paste_buffer: std.ArrayList(u8), @@ -38,8 +39,6 @@ dispatch_event: ?*const fn (ctx: *anyopaque, cbor_msg: []const u8) void = null, logger: log.Logger, -const ModState = struct { ctrl: bool = false, shift: bool = false, alt: bool = false }; - const Event = union(enum) { key_press: vaxis.Key, winsize: vaxis.Winsize, @@ -155,6 +154,7 @@ pub fn process_input(self: *Self, input_: []const u8) !void { const event = result.event orelse continue; switch (event) { .key_press => |key_| { + try self.sync_mod_state(key_.codepoint, key_.mods); const cbor_msg = try self.fmtmsg(.{ "I", event_type.PRESS, @@ -182,7 +182,7 @@ pub fn process_input(self: *Self, input_: []const u8) !void { }, .mouse => |mouse_| { const mouse = self.vx.translateMouse(mouse_); - // const mouse = mouse_; + try self.sync_mod_state(0, .{ .ctrl = mouse.mods.ctrl, .shift = mouse.mods.shift, .alt = mouse.mods.alt }); if (self.dispatch_mouse) |f| switch (mouse.type) { .motion => f(self.handler_ctx, @intCast(mouse.row), @intCast(mouse.col), try self.fmtmsg(.{ "M", @@ -339,3 +339,33 @@ pub fn cursor_disable(self: *Self) void { pub fn ucs32_to_utf8(ucs32: []const u32, utf8: []u8) !usize { return @intCast(try std.unicode.utf8Encode(@intCast(ucs32[0]), utf8)); } + +fn sync_mod_state(self: *Self, keypress: u32, modifiers: vaxis.Key.Modifiers) !void { + if (modifiers.ctrl and !self.mods.ctrl and !(keypress == key.LCTRL or keypress == key.RCTRL)) + try self.send_sync_key(event_type.PRESS, key.LCTRL, "lctrl", modifiers); + if (!modifiers.ctrl and self.mods.ctrl and !(keypress == key.LCTRL or keypress == key.RCTRL)) + try self.send_sync_key(event_type.RELEASE, key.LCTRL, "lctrl", modifiers); + if (modifiers.alt and !self.mods.alt and !(keypress == key.LALT or keypress == key.RALT)) + try self.send_sync_key(event_type.PRESS, key.LALT, "lalt", modifiers); + if (!modifiers.alt and self.mods.alt and !(keypress == key.LALT or keypress == key.RALT)) + try self.send_sync_key(event_type.RELEASE, key.LALT, "lalt", modifiers); + if (modifiers.shift and !self.mods.shift and !(keypress == key.LSHIFT or keypress == key.RSHIFT)) + try self.send_sync_key(event_type.PRESS, key.LSHIFT, "lshift", modifiers); + if (!modifiers.shift and self.mods.shift and !(keypress == key.LSHIFT or keypress == key.RSHIFT)) + try self.send_sync_key(event_type.RELEASE, key.LSHIFT, "lshift", modifiers); + self.mods = modifiers; +} + +fn send_sync_key(self: *Self, event_type_: usize, keypress: u32, key_string: []const u8, modifiers: vaxis.Key.Modifiers) !void { + if (self.dispatch_input) |f| f( + self.handler_ctx, + try self.fmtmsg(.{ + "I", + event_type_, + keypress, + keypress, + key_string, + @as(u8, @bitCast(modifiers)), + }), + ); +}