From 9c108b548667f9f5637cb0fc6d3e63a4f3af4e18 Mon Sep 17 00:00:00 2001 From: Michael Davis Date: Sat, 6 Jul 2024 10:49:27 -0400 Subject: [PATCH] Support bindings with the Super (Cmd/Win/Meta) modifier Terminals which support the enhanced keyboard protocol send events for keys pressed with the Super modifier (Windows/Linux key or the Command key). The only changes that are needed to support this in Helix are: * Mapping the modifier from crossterm's KeyModifiers to Helix's KeyModifiers. * Representing and parsing the modifier from the KeyEvent text representation. * Documenting the ability to remap it. When writing keybindings, use 'Meta-', 'Cmd-' or 'Win-' which are all synonymous. For example: [keys.normal] Cmd-s = ":write" will trigger for the Windows or Linux keys and the Command key plus 's'. --- book/src/remapping.md | 18 ++++++++++++++++-- helix-view/src/input.rs | 34 +++++++++++++++++++++++++++++++++- helix-view/src/keyboard.rs | 7 +++++++ 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/book/src/remapping.md b/book/src/remapping.md index d762c6add..650929498 100644 --- a/book/src/remapping.md +++ b/book/src/remapping.md @@ -50,8 +50,22 @@ t = ":run-shell-command cargo test" ## Special keys and modifiers -Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes -`C-`, `S-` and `A-`. Special keys are encoded as follows: +Ctrl, Shift and Alt modifiers are encoded respectively with the prefixes `C-`, `S-` and `A-`. + +The [Super key](https://en.wikipedia.org/wiki/Super_key_(keyboard_button)) - the Windows/Linux +key or the Command key on Mac keyboards - is also supported when using a terminal emulator that +supports the [enhanced keyboard protocol](https://github.com/helix-editor/helix/wiki/Terminal-Support#enhanced-keyboard-protocol). +The super key is encoded with prefixes `Meta-`, `Cmd-` or `Win-`. These are all synonyms for the +super modifier - binding a key with a `Win-` modifier will mean it can be used with the +Windows/Linux key or the Command key. + +```toml +[keys.normal] +C-s = ":write" # Ctrl and 's' to write +Cmd-s = ":write" # Cmd or Win or Meta and 's' to write +``` + +Special keys are encoded as follows: | Key name | Representation | | --- | --- | diff --git a/helix-view/src/input.rs b/helix-view/src/input.rs index 5f5067eac..acf366aac 100644 --- a/helix-view/src/input.rs +++ b/helix-view/src/input.rs @@ -162,7 +162,12 @@ pub(crate) mod keys { impl fmt::Display for KeyEvent { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!( - "{}{}{}", + "{}{}{}{}", + if self.modifiers.contains(KeyModifiers::SUPER) { + "Meta-" + } else { + "" + }, if self.modifiers.contains(KeyModifiers::SHIFT) { "S-" } else { @@ -312,6 +317,10 @@ impl UnicodeWidthStr for KeyEvent { if self.modifiers.contains(KeyModifiers::CONTROL) { width += 2; } + if self.modifiers.contains(KeyModifiers::SUPER) { + // "-Meta" + width += 5; + } width } @@ -396,6 +405,7 @@ impl std::str::FromStr for KeyEvent { "S" => KeyModifiers::SHIFT, "A" => KeyModifiers::ALT, "C" => KeyModifiers::CONTROL, + "Meta" | "Cmd" | "Win" => KeyModifiers::SUPER, _ => return Err(anyhow!("Invalid key modifier '{}-'", token)), }; @@ -709,6 +719,28 @@ mod test { modifiers: KeyModifiers::NONE } ); + + assert_eq!( + str::parse::("Meta-c").unwrap(), + KeyEvent { + code: KeyCode::Char('c'), + modifiers: KeyModifiers::SUPER + } + ); + assert_eq!( + str::parse::("Win-s").unwrap(), + KeyEvent { + code: KeyCode::Char('s'), + modifiers: KeyModifiers::SUPER + } + ); + assert_eq!( + str::parse::("Cmd-d").unwrap(), + KeyEvent { + code: KeyCode::Char('d'), + modifiers: KeyModifiers::SUPER + } + ); } #[test] diff --git a/helix-view/src/keyboard.rs b/helix-view/src/keyboard.rs index 080bce8dd..d816a52ef 100644 --- a/helix-view/src/keyboard.rs +++ b/helix-view/src/keyboard.rs @@ -7,6 +7,7 @@ bitflags! { const SHIFT = 0b0000_0001; const CONTROL = 0b0000_0010; const ALT = 0b0000_0100; + const SUPER = 0b0000_1000; const NONE = 0b0000_0000; } } @@ -27,6 +28,9 @@ impl From for crossterm::event::KeyModifiers { if key_modifiers.contains(KeyModifiers::ALT) { result.insert(CKeyModifiers::ALT); } + if key_modifiers.contains(KeyModifiers::SUPER) { + result.insert(CKeyModifiers::SUPER); + } result } @@ -48,6 +52,9 @@ impl From for KeyModifiers { if val.contains(CKeyModifiers::ALT) { result.insert(KeyModifiers::ALT); } + if val.contains(CKeyModifiers::SUPER) { + result.insert(KeyModifiers::SUPER); + } result }