core: do not send repeat/release events if the press consumed a binding

Fixes #943
This commit is contained in:
Mitchell Hashimoto
2023-11-23 08:40:52 -08:00
parent b01264d6b7
commit b34e0f6ec7

View File

@ -71,6 +71,12 @@ renderer_thr: std.Thread,
/// Mouse state. /// Mouse state.
mouse: Mouse, mouse: Mouse,
/// The hash value of the last keybinding trigger that we performed. This
/// is only set if the last key input matched a keybinding, consumed it,
/// and performed it. This is used to prevent sending release/repeat events
/// for handled bindings.
last_binding_trigger: u64 = 0,
/// The terminal IO handler. /// The terminal IO handler.
io: termio.Impl, io: termio.Impl,
io_thread: termio.Thread, io_thread: termio.Thread,
@ -1123,7 +1129,7 @@ pub fn keyCallback(
// Before encoding, we see if we have any keybindings for this // Before encoding, we see if we have any keybindings for this
// key. Those always intercept before any encoding tasks. // key. Those always intercept before any encoding tasks.
binding: { binding: {
const binding_action: input.Binding.Action, const consumed = action: { const binding_action: input.Binding.Action, const binding_trigger: input.Binding.Trigger, const consumed = action: {
const binding_mods = event.mods.binding(); const binding_mods = event.mods.binding();
var trigger: input.Binding.Trigger = .{ var trigger: input.Binding.Trigger = .{
.mods = binding_mods, .mods = binding_mods,
@ -1133,6 +1139,7 @@ pub fn keyCallback(
const set = self.config.keybind.set; const set = self.config.keybind.set;
if (set.get(trigger)) |v| break :action .{ if (set.get(trigger)) |v| break :action .{
v, v,
trigger,
set.getConsumed(trigger), set.getConsumed(trigger),
}; };
@ -1140,6 +1147,7 @@ pub fn keyCallback(
trigger.physical = true; trigger.physical = true;
if (set.get(trigger)) |v| break :action .{ if (set.get(trigger)) |v| break :action .{
v, v,
trigger,
set.getConsumed(trigger), set.getConsumed(trigger),
}; };
@ -1149,18 +1157,28 @@ pub fn keyCallback(
// We only execute the binding on press/repeat but we still consume // We only execute the binding on press/repeat but we still consume
// the key on release so that we don't send any release events. // the key on release so that we don't send any release events.
log.debug("key event binding consumed={} action={}", .{ consumed, binding_action }); log.debug("key event binding consumed={} action={}", .{ consumed, binding_action });
const performed = if (event.action == .press or event.action == .repeat) const performed = if (event.action == .press or event.action == .repeat) press: {
try self.performBindingAction(binding_action) self.last_binding_trigger = 0;
else break :press try self.performBindingAction(binding_action);
false; } else false;
// If we consume this event, then we are done. If we don't consume // If we consume this event, then we are done. If we don't consume
// it, we processed the action but we still want to process our // it, we processed the action but we still want to process our
// encodings, too. // encodings, too.
if (consumed and performed) { if (consumed and performed) {
self.last_binding_trigger = binding_trigger.hash();
if (insp_ev) |*ev| ev.binding = binding_action; if (insp_ev) |*ev| ev.binding = binding_action;
return true; return true;
} }
// If we have a previous binding trigger and it matches this one,
// then we handled the down event so we don't want to send any further
// events.
if (self.last_binding_trigger > 0 and
self.last_binding_trigger == binding_trigger.hash())
{
return true;
}
} }
// If we allow KAM and KAM is enabled then we do nothing. // If we allow KAM and KAM is enabled then we do nothing.