fix: track modifier state and generate events if it is out of sync

This prevents fast scroll and other modifier functions getting stuck if events
are lost due to focus change.
This commit is contained in:
CJ van den Berg 2024-04-01 21:37:35 +02:00
parent f12694778b
commit 823d066a58

View file

@ -58,6 +58,13 @@ unflushed_events_count: usize = 0,
init_timer: ?tp.timeout,
sigwinch_signal: ?tp.signal = null,
no_sleep: bool = false,
mods: ModState = .{},
const ModState = struct {
ctrl: bool = false,
shift: bool = false,
alt: bool = false,
};
const init_delay = 1; // ms
@ -392,6 +399,7 @@ fn dispatch_input_event(self: *Self, ni: *nc.Input) tp.result {
self.unrendered_input_events_count += 1;
ni.modifiers &= nc.mod.CTRL | nc.mod.SHIFT | nc.mod.ALT | nc.mod.SUPER | nc.mod.META | nc.mod.HYPER;
if (keypress == nc.key.RESIZE) return;
try self.sync_mod_state(keypress, ni.modifiers);
if (keypress == nc.key.MOTION) {
if (ni.y == 0 and ni.x == 0 and ni.ypx == -1 and ni.xpx == -1) return;
self.dispatch_mouse(ni.y, ni.x, tp.self_pid(), tp.message.fmtbuf(&buf, .{
@ -666,6 +674,40 @@ fn save_config(self: *const Self) !void {
try root.write_config(self.config, self.a);
}
fn sync_mod_state(self: *Self, keypress: u32, modifiers: u32) tp.result {
if (keypress == nc.key.LCTRL or keypress == nc.key.RCTRL or keypress == nc.key.LALT or keypress == nc.key.RALT or
keypress == nc.key.LSHIFT or keypress == nc.key.RSHIFT or keypress == nc.key.LSUPER or keypress == nc.key.RSUPER) return;
if (nc.isCtrl(modifiers) and !self.mods.ctrl)
try self.send_key(nc.event_type.PRESS, nc.key.LCTRL, "lctrl", modifiers);
if (!nc.isCtrl(modifiers) and self.mods.ctrl)
try self.send_key(nc.event_type.RELEASE, nc.key.LCTRL, "lctrl", modifiers);
if (nc.isAlt(modifiers) and !self.mods.alt)
try self.send_key(nc.event_type.PRESS, nc.key.LALT, "lalt", modifiers);
if (!nc.isAlt(modifiers) and self.mods.alt)
try self.send_key(nc.event_type.RELEASE, nc.key.LALT, "lalt", modifiers);
if (nc.isShift(modifiers) and !self.mods.shift)
try self.send_key(nc.event_type.PRESS, nc.key.LSHIFT, "lshift", modifiers);
if (!nc.isShift(modifiers) and self.mods.shift)
try self.send_key(nc.event_type.RELEASE, nc.key.LSHIFT, "lshift", modifiers);
self.mods = .{
.ctrl = nc.isCtrl(modifiers),
.alt = nc.isAlt(modifiers),
.shift = nc.isShift(modifiers),
};
}
fn send_key(self: *Self, event_type: c_int, keypress: u32, key_string: []const u8, modifiers: u32) tp.result {
var buf: [256]u8 = undefined;
self.send_input(tp.self_pid(), tp.message.fmtbuf(&buf, .{
"I",
event_type,
keypress,
keypress,
key_string,
modifiers,
}) catch |e| return tp.exit_error(e));
}
const cmds = struct {
pub const Target = Self;
const Ctx = command.Context;