From a727801f60286282795e850637de7e21f15d4114 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Tue, 16 Oct 2018 18:46:26 +0000 Subject: [PATCH] Allow the usage of scancodes in the config This change should allow the usage of scancodes in the configuration file. When a VirtualKeyCode for glutin is not present, this should now allow the user to use the scancodes instead. If the user specifiecs a key with its scancode even though the key has a VirtualKeyCode, it should still work. The behavior of directly specifying a VirtualKeyCode should be unchanged by this. This fixes #1265. --- CHANGELOG.md | 2 + alacritty.yml | 6 + alacritty_macos.yml | 6 + src/config.rs | 342 +++++++++++++++++++++++--------------------- src/event.rs | 5 +- src/input.rs | 42 +++--- 6 files changed, 219 insertions(+), 184 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7231fb89..397d7c99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add support for windows - Add terminfo capabilities advertising support for changing the window title +- Allow using scancodes in the key_bindings section ### Fixed + - Fixed erroneous results when using the `indexed_colors` config option ## Version 0.2.1 diff --git a/alacritty.yml b/alacritty.yml index 11a9e6ae..63bb7a4b 100644 --- a/alacritty.yml +++ b/alacritty.yml @@ -324,6 +324,12 @@ live_config_reload: true # A full list with available key codes can be found here: # https://docs.rs/glutin/*/glutin/enum.VirtualKeyCode.html#variants # +# Instead of using the name of the keys, the `key` field also supports using +# the scancode of the desired key. Scancodes have to be specified as a +# decimal number. +# This command will allow you to display the hex scancodes for certain keys: +# `showkey --scancodes` +# # Values for `mods`: # - Command # - Control diff --git a/alacritty_macos.yml b/alacritty_macos.yml index 1feffbd1..b9abc58e 100644 --- a/alacritty_macos.yml +++ b/alacritty_macos.yml @@ -321,6 +321,12 @@ live_config_reload: true # A full list with available key codes can be found here: # https://docs.rs/glutin/*/glutin/enum.VirtualKeyCode.html#variants # +# Instead of using the name of the keys, the `key` field also supports using +# the scancode of the desired key. Scancodes have to be specified as a +# decimal number. +# This command will allow you to display the hex scancodes for certain keys: +# `showkey --scancodes` +# # Values for `mods`: # - Command # - Control diff --git a/src/config.rs b/src/config.rs index c7d7ea58..069eef0e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -837,7 +837,7 @@ impl<'a> de::Deserialize<'a> for MouseButton { /// Bindings are deserialized into a `RawBinding` before being parsed as a /// `KeyBinding` or `MouseBinding`. struct RawBinding { - key: Option<::glutin::VirtualKeyCode>, + key: Option, mouse: Option<::glutin::MouseButton>, mods: ModifiersState, mode: TermMode, @@ -941,7 +941,7 @@ impl<'a> de::Deserialize<'a> for RawBinding { where V: MapAccess<'a>, { let mut mods: Option = None; - let mut key: Option<::glutin::VirtualKeyCode> = None; + let mut key: Option = None; let mut chars: Option = None; let mut action: Option<::input::Action> = None; let mut mode: Option = None; @@ -958,8 +958,21 @@ impl<'a> de::Deserialize<'a> for RawBinding { return Err(::duplicate_field("key")); } - let coherent_key = map.next_value::()?; - key = Some(coherent_key.to_glutin_key()); + let val = map.next_value::()?; + if val.is_u64() { + let scancode = val.as_u64().unwrap(); + if scancode > u64::from(::std::u32::MAX) { + return Err(::custom(format!( + "invalid key binding, scancode too big: {}", + scancode + ))); + } + key = Some(Key::Scancode(scancode as u32)); + } else { + let k = Key::deserialize(val) + .map_err(V::Error::custom)?; + key = Some(k); + } }, Field::Mods => { if mods.is_some() { @@ -2059,8 +2072,9 @@ mod tests { } #[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))] -#[derive(Deserialize, Copy, Clone)] -enum Key { +#[derive(Deserialize, Copy, Clone, Debug, Eq, PartialEq)] +pub enum Key { + Scancode(u32), Key1, Key2, Key3, @@ -2218,164 +2232,164 @@ enum Key { } impl Key { - fn to_glutin_key(self) -> ::glutin::VirtualKeyCode { - use ::glutin::VirtualKeyCode::*; - // Thank you, vim macros! - match self { - Key::Key1 => Key1, - Key::Key2 => Key2, - Key::Key3 => Key3, - Key::Key4 => Key4, - Key::Key5 => Key5, - Key::Key6 => Key6, - Key::Key7 => Key7, - Key::Key8 => Key8, - Key::Key9 => Key9, - Key::Key0 => Key0, - Key::A => A, - Key::B => B, - Key::C => C, - Key::D => D, - Key::E => E, - Key::F => F, - Key::G => G, - Key::H => H, - Key::I => I, - Key::J => J, - Key::K => K, - Key::L => L, - Key::M => M, - Key::N => N, - Key::O => O, - Key::P => P, - Key::Q => Q, - Key::R => R, - Key::S => S, - Key::T => T, - Key::U => U, - Key::V => V, - Key::W => W, - Key::X => X, - Key::Y => Y, - Key::Z => Z, - Key::Escape => Escape, - Key::F1 => F1, - Key::F2 => F2, - Key::F3 => F3, - Key::F4 => F4, - Key::F5 => F5, - Key::F6 => F6, - Key::F7 => F7, - Key::F8 => F8, - Key::F9 => F9, - Key::F10 => F10, - Key::F11 => F11, - Key::F12 => F12, - Key::F13 => F13, - Key::F14 => F14, - Key::F15 => F15, - Key::Snapshot => Snapshot, - Key::Scroll => Scroll, - Key::Pause => Pause, - Key::Insert => Insert, - Key::Home => Home, - Key::Delete => Delete, - Key::End => End, - Key::PageDown => PageDown, - Key::PageUp => PageUp, - Key::Left => Left, - Key::Up => Up, - Key::Right => Right, - Key::Down => Down, - Key::Back => Back, - Key::Return => Return, - Key::Space => Space, - Key::Compose => Compose, - Key::Numlock => Numlock, - Key::Numpad0 => Numpad0, - Key::Numpad1 => Numpad1, - Key::Numpad2 => Numpad2, - Key::Numpad3 => Numpad3, - Key::Numpad4 => Numpad4, - Key::Numpad5 => Numpad5, - Key::Numpad6 => Numpad6, - Key::Numpad7 => Numpad7, - Key::Numpad8 => Numpad8, - Key::Numpad9 => Numpad9, - Key::AbntC1 => AbntC1, - Key::AbntC2 => AbntC2, - Key::Add => Add, - Key::Apostrophe => Apostrophe, - Key::Apps => Apps, - Key::At => At, - Key::Ax => Ax, - Key::Backslash => Backslash, - Key::Calculator => Calculator, - Key::Capital => Capital, - Key::Colon => Colon, - Key::Comma => Comma, - Key::Convert => Convert, - Key::Decimal => Decimal, - Key::Divide => Divide, - Key::Equals => Equals, - Key::Grave => Grave, - Key::Kana => Kana, - Key::Kanji => Kanji, - Key::LAlt => LAlt, - Key::LBracket => LBracket, - Key::LControl => LControl, - Key::LMenu => LMenu, - Key::LShift => LShift, - Key::LWin => LWin, - Key::Mail => Mail, - Key::MediaSelect => MediaSelect, - Key::MediaStop => MediaStop, - Key::Minus => Minus, - Key::Multiply => Multiply, - Key::Mute => Mute, - Key::MyComputer => MyComputer, - Key::NavigateForward => NavigateForward, - Key::NavigateBackward => NavigateBackward, - Key::NextTrack => NextTrack, - Key::NoConvert => NoConvert, - Key::NumpadComma => NumpadComma, - Key::NumpadEnter => NumpadEnter, - Key::NumpadEquals => NumpadEquals, - Key::OEM102 => OEM102, - Key::Period => Period, - Key::PlayPause => PlayPause, - Key::Power => Power, - Key::PrevTrack => PrevTrack, - Key::RAlt => RAlt, - Key::RBracket => RBracket, - Key::RControl => RControl, - Key::RMenu => RMenu, - Key::RShift => RShift, - Key::RWin => RWin, - Key::Semicolon => Semicolon, - Key::Slash => Slash, - Key::Sleep => Sleep, - Key::Stop => Stop, - Key::Subtract => Subtract, - Key::Sysrq => Sysrq, - Key::Tab => Tab, - Key::Underline => Underline, - Key::Unlabeled => Unlabeled, - Key::VolumeDown => VolumeDown, - Key::VolumeUp => VolumeUp, - Key::Wake => Wake, - Key::WebBack => WebBack, - Key::WebFavorites => WebFavorites, - Key::WebForward => WebForward, - Key::WebHome => WebHome, - Key::WebRefresh => WebRefresh, - Key::WebSearch => WebSearch, - Key::WebStop => WebStop, - Key::Yen => Yen, - Key::Caret => Caret, - Key::Copy => Copy, - Key::Paste => Paste, - Key::Cut => Cut, + pub fn from_glutin_input(key: ::glutin::VirtualKeyCode) -> Self { + use glutin::VirtualKeyCode::*; + // Thank you, vim macros and regex! + match key { + Key1 => Key::Key1, + Key2 => Key::Key2, + Key3 => Key::Key3, + Key4 => Key::Key4, + Key5 => Key::Key5, + Key6 => Key::Key6, + Key7 => Key::Key7, + Key8 => Key::Key8, + Key9 => Key::Key9, + Key0 => Key::Key0, + A => Key::A, + B => Key::B, + C => Key::C, + D => Key::D, + E => Key::E, + F => Key::F, + G => Key::G, + H => Key::H, + I => Key::I, + J => Key::J, + K => Key::K, + L => Key::L, + M => Key::M, + N => Key::N, + O => Key::O, + P => Key::P, + Q => Key::Q, + R => Key::R, + S => Key::S, + T => Key::T, + U => Key::U, + V => Key::V, + W => Key::W, + X => Key::X, + Y => Key::Y, + Z => Key::Z, + Escape => Key::Escape, + F1 => Key::F1, + F2 => Key::F2, + F3 => Key::F3, + F4 => Key::F4, + F5 => Key::F5, + F6 => Key::F6, + F7 => Key::F7, + F8 => Key::F8, + F9 => Key::F9, + F10 => Key::F10, + F11 => Key::F11, + F12 => Key::F12, + F13 => Key::F13, + F14 => Key::F14, + F15 => Key::F15, + Snapshot => Key::Snapshot, + Scroll => Key::Scroll, + Pause => Key::Pause, + Insert => Key::Insert, + Home => Key::Home, + Delete => Key::Delete, + End => Key::End, + PageDown => Key::PageDown, + PageUp => Key::PageUp, + Left => Key::Left, + Up => Key::Up, + Right => Key::Right, + Down => Key::Down, + Back => Key::Back, + Return => Key::Return, + Space => Key::Space, + Compose => Key::Compose, + Numlock => Key::Numlock, + Numpad0 => Key::Numpad0, + Numpad1 => Key::Numpad1, + Numpad2 => Key::Numpad2, + Numpad3 => Key::Numpad3, + Numpad4 => Key::Numpad4, + Numpad5 => Key::Numpad5, + Numpad6 => Key::Numpad6, + Numpad7 => Key::Numpad7, + Numpad8 => Key::Numpad8, + Numpad9 => Key::Numpad9, + AbntC1 => Key::AbntC1, + AbntC2 => Key::AbntC2, + Add => Key::Add, + Apostrophe => Key::Apostrophe, + Apps => Key::Apps, + At => Key::At, + Ax => Key::Ax, + Backslash => Key::Backslash, + Calculator => Key::Calculator, + Capital => Key::Capital, + Colon => Key::Colon, + Comma => Key::Comma, + Convert => Key::Convert, + Decimal => Key::Decimal, + Divide => Key::Divide, + Equals => Key::Equals, + Grave => Key::Grave, + Kana => Key::Kana, + Kanji => Key::Kanji, + LAlt => Key::LAlt, + LBracket => Key::LBracket, + LControl => Key::LControl, + LMenu => Key::LMenu, + LShift => Key::LShift, + LWin => Key::LWin, + Mail => Key::Mail, + MediaSelect => Key::MediaSelect, + MediaStop => Key::MediaStop, + Minus => Key::Minus, + Multiply => Key::Multiply, + Mute => Key::Mute, + MyComputer => Key::MyComputer, + NavigateForward => Key::NavigateForward, + NavigateBackward => Key::NavigateBackward, + NextTrack => Key::NextTrack, + NoConvert => Key::NoConvert, + NumpadComma => Key::NumpadComma, + NumpadEnter => Key::NumpadEnter, + NumpadEquals => Key::NumpadEquals, + OEM102 => Key::OEM102, + Period => Key::Period, + PlayPause => Key::PlayPause, + Power => Key::Power, + PrevTrack => Key::PrevTrack, + RAlt => Key::RAlt, + RBracket => Key::RBracket, + RControl => Key::RControl, + RMenu => Key::RMenu, + RShift => Key::RShift, + RWin => Key::RWin, + Semicolon => Key::Semicolon, + Slash => Key::Slash, + Sleep => Key::Sleep, + Stop => Key::Stop, + Subtract => Key::Subtract, + Sysrq => Key::Sysrq, + Tab => Key::Tab, + Underline => Key::Underline, + Unlabeled => Key::Unlabeled, + VolumeDown => Key::VolumeDown, + VolumeUp => Key::VolumeUp, + Wake => Key::Wake, + WebBack => Key::WebBack, + WebFavorites => Key::WebFavorites, + WebForward => Key::WebForward, + WebHome => Key::WebHome, + WebRefresh => Key::WebRefresh, + WebSearch => Key::WebSearch, + WebStop => Key::WebStop, + Yen => Key::Yen, + Caret => Key::Caret, + Copy => Key::Copy, + Paste => Key::Paste, + Cut => Key::Cut, } } } diff --git a/src/event.rs b/src/event.rs index 9db0680d..eef04a8c 100644 --- a/src/event.rs +++ b/src/event.rs @@ -334,9 +334,8 @@ impl Processor { processor.ctx.terminal.dirty = true; }, KeyboardInput { input, .. } => { - let glutin::KeyboardInput { state, virtual_keycode, modifiers, .. } = input; - processor.process_key(state, virtual_keycode, modifiers); - if state == ElementState::Pressed { + processor.process_key(input); + if input.state == ElementState::Pressed { // Hide cursor while typing *hide_cursor = true; } diff --git a/src/input.rs b/src/input.rs index 6d3b407a..ed9aa7fc 100644 --- a/src/input.rs +++ b/src/input.rs @@ -26,9 +26,9 @@ use std::time::Instant; use std::os::unix::process::CommandExt; use copypasta::{Clipboard, Load, Buffer as ClipboardBuffer}; -use glutin::{ElementState, VirtualKeyCode, MouseButton, TouchPhase, MouseScrollDelta, ModifiersState}; +use glutin::{ElementState, MouseButton, TouchPhase, MouseScrollDelta, ModifiersState, KeyboardInput}; -use config; +use config::{self, Key}; use grid::Scroll; use event::{ClickState, Mouse}; use index::{Line, Column, Side, Point}; @@ -100,7 +100,7 @@ pub struct Binding { } /// Bindings that are triggered by a keyboard key -pub type KeyBinding = Binding; +pub type KeyBinding = Binding; /// Bindings that are triggered by a mouse button pub type MouseBinding = Binding; @@ -618,24 +618,18 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// Process key input /// /// If a keybinding was run, returns true. Otherwise returns false. - pub fn process_key( - &mut self, - state: ElementState, - key: Option, - mods: ModifiersState, - ) { - match (key, state) { - (Some(key), ElementState::Pressed) => { - *self.ctx.last_modifiers() = mods; + pub fn process_key(&mut self, input: KeyboardInput) { + match input.state { + ElementState::Pressed => { + *self.ctx.last_modifiers() = input.modifiers; *self.ctx.received_count() = 0; *self.ctx.suppress_chars() = false; - if self.process_key_bindings(mods, key) { + if self.process_key_bindings(input) { *self.ctx.suppress_chars() = true; } }, - (_, ElementState::Released) => *self.ctx.suppress_chars() = false, - _ => () + ElementState::Released => *self.ctx.suppress_chars() = false, } } @@ -668,10 +662,24 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> { /// for its action to be executed. /// /// Returns true if an action is executed. - fn process_key_bindings(&mut self, mods: ModifiersState, key: VirtualKeyCode) -> bool { + fn process_key_bindings(&mut self, input: KeyboardInput) -> bool { let mut has_binding = false; for binding in self.key_bindings { - if binding.is_triggered_by(self.ctx.terminal_mode(), mods, &key) { + let is_triggered = match binding.trigger { + Key::Scancode(_) => binding.is_triggered_by( + self.ctx.terminal_mode(), + input.modifiers, + &Key::Scancode(input.scancode), + ), + _ => if let Some(key) = input.virtual_keycode { + let key = Key::from_glutin_input(key); + binding.is_triggered_by(self.ctx.terminal_mode(), input.modifiers, &key) + } else { + false + }, + }; + + if is_triggered { // binding was triggered; run the action binding.execute(&mut self.ctx); has_binding = true;