From f89d3bb659e0eb0498deb94b045b4adf3587754a Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sun, 9 Apr 2023 22:52:41 +0200 Subject: [PATCH] Reset char suppression for every key binding Previously the character suppression was only reset whenever a key was released. However this did not take key repetition into account. Now every key down also resets the character suppression. This should work since the `ReceivedCharacter` is always received immediately after the `KeyboardInput` without the chance of a racing condition where another keyboard event interrupts the two. --- alacritty/src/event.rs | 54 +++++++++++++++++++++++++++-- alacritty/src/input.rs | 77 ++++++------------------------------------ 2 files changed, 62 insertions(+), 69 deletions(-) diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs index 9a27963c..d4d0d968 100644 --- a/alacritty/src/event.rs +++ b/alacritty/src/event.rs @@ -218,6 +218,56 @@ impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext for ActionCon self.notifier.notify(val); } + fn received_char(&mut self, c: char) { + // Don't insert chars when we have IME running. + if self.display().ime.preedit().is_some() { + return; + } + + // Handle hint selection over anything else. + if self.display().hint_state.active() && !*self.suppress_chars { + self.hint_input(c); + return; + } + + // Pass keys to search and ignore them during `suppress_chars`. + let search_active = self.search_active(); + if *self.suppress_chars || search_active || self.terminal().mode().contains(TermMode::VI) { + if search_active && !*self.suppress_chars { + self.search_input(c); + } + + return; + } + + self.on_typing_start(); + + if self.terminal().grid().display_offset() != 0 { + self.scroll(Scroll::Bottom); + } + self.clear_selection(); + + let utf8_len = c.len_utf8(); + let mut bytes = vec![0; utf8_len]; + c.encode_utf8(&mut bytes[..]); + + #[cfg(not(target_os = "macos"))] + let alt_send_esc = true; + + // Don't send ESC when `OptionAsAlt` is used. This doesn't handle + // `Only{Left,Right}` variants due to inability to distinguish them. + #[cfg(target_os = "macos")] + let alt_send_esc = self.config().window.option_as_alt != OptionAsAlt::None; + + if alt_send_esc && *self.received_count() == 0 && self.modifiers().alt() && utf8_len == 1 { + bytes.insert(0, b'\x1b'); + } + + self.write_to_pty(bytes); + + *self.received_count() += 1; + } + /// Request a redraw. #[inline] fn mark_dirty(&mut self) { @@ -1288,7 +1338,7 @@ impl input::Processor> { self.key_input(input); }, WindowEvent::ModifiersChanged(modifiers) => self.modifiers_input(modifiers), - WindowEvent::ReceivedCharacter(c) => self.received_char(c), + WindowEvent::ReceivedCharacter(c) => self.ctx.received_char(c), WindowEvent::MouseInput { state, button, .. } => { self.ctx.window().set_mouse_visible(true); self.mouse_input(state, button); @@ -1336,7 +1386,7 @@ impl input::Processor> { *self.ctx.dirty = true; for ch in text.chars() { - self.received_char(ch); + self.ctx.received_char(ch); } self.ctx.update_cursor_blinking(); diff --git a/alacritty/src/input.rs b/alacritty/src/input.rs index 5728665a..5fe7da98 100644 --- a/alacritty/src/input.rs +++ b/alacritty/src/input.rs @@ -73,6 +73,7 @@ pub struct Processor> { pub trait ActionContext { fn write_to_pty>>(&self, _data: B) {} + fn received_char(&mut self, _c: char) {} fn mark_dirty(&mut self) {} fn size_info(&self) -> SizeInfo; fn copy_selection(&mut self, _ty: ClipboardType) {} @@ -152,10 +153,9 @@ impl Execute for Action { fn execute>(&self, ctx: &mut A) { match self { Action::Esc(s) => { - ctx.on_typing_start(); - ctx.clear_selection(); - ctx.scroll(Scroll::Bottom); - ctx.write_to_pty(s.clone().into_bytes()) + for c in s.chars() { + ctx.received_char(c); + } }, Action::Command(program) => ctx.spawn_daemon(program.program(), program.args()), Action::Hint(hint) => { @@ -936,12 +936,12 @@ impl> Processor { } } - match input.state { - ElementState::Pressed => { - *self.ctx.received_count() = 0; - self.process_key_bindings(input); - }, - ElementState::Released => *self.ctx.suppress_chars() = false, + // Reset character suppression. + *self.ctx.suppress_chars() = false; + + if let ElementState::Pressed = input.state { + *self.ctx.received_count() = 0; + self.process_key_bindings(input); } } @@ -964,63 +964,6 @@ impl> Processor { self.ctx.window().set_mouse_cursor(mouse_state); } - /// Process a received character. - pub fn received_char(&mut self, c: char) { - let suppress_chars = *self.ctx.suppress_chars(); - - // Don't insert chars when we have IME running. - if self.ctx.display().ime.preedit().is_some() { - return; - } - - // Handle hint selection over anything else. - if self.ctx.display().hint_state.active() && !suppress_chars { - self.ctx.hint_input(c); - return; - } - - // Pass keys to search and ignore them during `suppress_chars`. - let search_active = self.ctx.search_active(); - if suppress_chars || search_active || self.ctx.terminal().mode().contains(TermMode::VI) { - if search_active && !suppress_chars { - self.ctx.search_input(c); - } - - return; - } - - self.ctx.on_typing_start(); - - if self.ctx.terminal().grid().display_offset() != 0 { - self.ctx.scroll(Scroll::Bottom); - } - self.ctx.clear_selection(); - - let utf8_len = c.len_utf8(); - let mut bytes = vec![0; utf8_len]; - c.encode_utf8(&mut bytes[..]); - - #[cfg(not(target_os = "macos"))] - let alt_send_esc = true; - - // Don't send ESC when `OptionAsAlt` is used. This doesn't handle - // `Only{Left,Right}` variants due to inability to distinguish them. - #[cfg(target_os = "macos")] - let alt_send_esc = self.ctx.config().window.option_as_alt != OptionAsAlt::None; - - if alt_send_esc - && *self.ctx.received_count() == 0 - && self.ctx.modifiers().alt() - && utf8_len == 1 - { - bytes.insert(0, b'\x1b'); - } - - self.ctx.write_to_pty(bytes); - - *self.ctx.received_count() += 1; - } - /// Attempt to find a binding and execute its action. /// /// The provided mode, mods, and key must match what is allowed by a binding