From 5a68e98db062f2de49f980b8b30a2f9d3aecfae1 Mon Sep 17 00:00:00 2001 From: frazou <4470714+Frazew@users.noreply.github.com> Date: Sat, 15 Mar 2025 23:14:35 +0100 Subject: [PATCH] Fix selection clearing in kitty keyboard mode When Kitty's keyboard protocol is used and Report all keys as escape codes flag (8) is enabled, modifier key escape codes trigger the usual "write something to the terminal" code path, which clears the selection / scrolls down etc. This behavior is mostly unexpected, and makes some actions more painful to perform (for instance copying text becomes harder: hitting CTRL to begin the CTRL+SHIFT+C sequence clears the selection). This patch clears the selection only if the key event is not a modifier key, which aligns with Alacritty's usual behavior. Fixes #8509. --- CHANGELOG.md | 1 + alacritty/src/input/keyboard.rs | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf13eb7a..4c2cc6cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ Notable changes to the `alacritty_terminal` crate are documented in its ### Fixed - Crash when OpenGL context resets +- Modifier keys clearing selection with kitty keyboard protocol enabled ## 0.15.1 diff --git a/alacritty/src/input/keyboard.rs b/alacritty/src/input/keyboard.rs index 417f599b..ccdeac3f 100644 --- a/alacritty/src/input/keyboard.rs +++ b/alacritty/src/input/keyboard.rs @@ -77,6 +77,7 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> { let mods = if self.alt_send_esc(&key, text) { mods } else { mods & !ModifiersState::ALT }; let build_key_sequence = Self::should_build_sequence(&key, text, mode, mods); + let is_modifier_key = Self::is_modifier_key(&key); let bytes = if build_key_sequence { build_sequence(key, mods, mode) @@ -92,7 +93,10 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> { // Write only if we have something to write. if !bytes.is_empty() { - self.ctx.on_terminal_input_start(); + // Don't clear selection/scroll down when writing escaped modifier keys. + if !is_modifier_key { + self.ctx.on_terminal_input_start(); + } self.ctx.write_to_pty(bytes); } } @@ -125,6 +129,16 @@ impl<T: EventListener, A: ActionContext<T>> Processor<T, A> { } } + fn is_modifier_key(key: &KeyEvent) -> bool { + matches!( + key.logical_key.as_ref(), + Key::Named(NamedKey::Shift) + | Key::Named(NamedKey::Control) + | Key::Named(NamedKey::Alt) + | Key::Named(NamedKey::Super) + ) + } + /// Check whether we should try to build escape sequence for the [`KeyEvent`]. fn should_build_sequence( key: &KeyEvent,