1
0
Fork 0
mirror of https://github.com/alacritty/alacritty.git synced 2025-07-31 22:03:40 -04:00

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.
This commit is contained in:
Christian Duerr 2018-10-16 18:46:26 +00:00 committed by GitHub
parent 15e0deae2b
commit a727801f60
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 219 additions and 184 deletions

View file

@ -10,8 +10,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add support for windows - Add support for windows
- Add terminfo capabilities advertising support for changing the window title - Add terminfo capabilities advertising support for changing the window title
- Allow using scancodes in the key_bindings section
### Fixed ### Fixed
- Fixed erroneous results when using the `indexed_colors` config option - Fixed erroneous results when using the `indexed_colors` config option
## Version 0.2.1 ## Version 0.2.1

View file

@ -324,6 +324,12 @@ live_config_reload: true
# A full list with available key codes can be found here: # A full list with available key codes can be found here:
# https://docs.rs/glutin/*/glutin/enum.VirtualKeyCode.html#variants # 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`: # Values for `mods`:
# - Command # - Command
# - Control # - Control

View file

@ -321,6 +321,12 @@ live_config_reload: true
# A full list with available key codes can be found here: # A full list with available key codes can be found here:
# https://docs.rs/glutin/*/glutin/enum.VirtualKeyCode.html#variants # 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`: # Values for `mods`:
# - Command # - Command
# - Control # - Control

View file

@ -837,7 +837,7 @@ impl<'a> de::Deserialize<'a> for MouseButton {
/// Bindings are deserialized into a `RawBinding` before being parsed as a /// Bindings are deserialized into a `RawBinding` before being parsed as a
/// `KeyBinding` or `MouseBinding`. /// `KeyBinding` or `MouseBinding`.
struct RawBinding { struct RawBinding {
key: Option<::glutin::VirtualKeyCode>, key: Option<Key>,
mouse: Option<::glutin::MouseButton>, mouse: Option<::glutin::MouseButton>,
mods: ModifiersState, mods: ModifiersState,
mode: TermMode, mode: TermMode,
@ -941,7 +941,7 @@ impl<'a> de::Deserialize<'a> for RawBinding {
where V: MapAccess<'a>, where V: MapAccess<'a>,
{ {
let mut mods: Option<ModifiersState> = None; let mut mods: Option<ModifiersState> = None;
let mut key: Option<::glutin::VirtualKeyCode> = None; let mut key: Option<Key> = None;
let mut chars: Option<String> = None; let mut chars: Option<String> = None;
let mut action: Option<::input::Action> = None; let mut action: Option<::input::Action> = None;
let mut mode: Option<TermMode> = None; let mut mode: Option<TermMode> = None;
@ -958,8 +958,21 @@ impl<'a> de::Deserialize<'a> for RawBinding {
return Err(<V::Error as Error>::duplicate_field("key")); return Err(<V::Error as Error>::duplicate_field("key"));
} }
let coherent_key = map.next_value::<Key>()?; let val = map.next_value::<serde_yaml::Value>()?;
key = Some(coherent_key.to_glutin_key()); if val.is_u64() {
let scancode = val.as_u64().unwrap();
if scancode > u64::from(::std::u32::MAX) {
return Err(<V::Error as Error>::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 => { Field::Mods => {
if mods.is_some() { if mods.is_some() {
@ -2059,8 +2072,9 @@ mod tests {
} }
#[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))] #[cfg_attr(feature = "cargo-clippy", allow(enum_variant_names))]
#[derive(Deserialize, Copy, Clone)] #[derive(Deserialize, Copy, Clone, Debug, Eq, PartialEq)]
enum Key { pub enum Key {
Scancode(u32),
Key1, Key1,
Key2, Key2,
Key3, Key3,
@ -2218,164 +2232,164 @@ enum Key {
} }
impl Key { impl Key {
fn to_glutin_key(self) -> ::glutin::VirtualKeyCode { pub fn from_glutin_input(key: ::glutin::VirtualKeyCode) -> Self {
use ::glutin::VirtualKeyCode::*; use glutin::VirtualKeyCode::*;
// Thank you, vim macros! // Thank you, vim macros and regex!
match self { match key {
Key::Key1 => Key1, Key1 => Key::Key1,
Key::Key2 => Key2, Key2 => Key::Key2,
Key::Key3 => Key3, Key3 => Key::Key3,
Key::Key4 => Key4, Key4 => Key::Key4,
Key::Key5 => Key5, Key5 => Key::Key5,
Key::Key6 => Key6, Key6 => Key::Key6,
Key::Key7 => Key7, Key7 => Key::Key7,
Key::Key8 => Key8, Key8 => Key::Key8,
Key::Key9 => Key9, Key9 => Key::Key9,
Key::Key0 => Key0, Key0 => Key::Key0,
Key::A => A, A => Key::A,
Key::B => B, B => Key::B,
Key::C => C, C => Key::C,
Key::D => D, D => Key::D,
Key::E => E, E => Key::E,
Key::F => F, F => Key::F,
Key::G => G, G => Key::G,
Key::H => H, H => Key::H,
Key::I => I, I => Key::I,
Key::J => J, J => Key::J,
Key::K => K, K => Key::K,
Key::L => L, L => Key::L,
Key::M => M, M => Key::M,
Key::N => N, N => Key::N,
Key::O => O, O => Key::O,
Key::P => P, P => Key::P,
Key::Q => Q, Q => Key::Q,
Key::R => R, R => Key::R,
Key::S => S, S => Key::S,
Key::T => T, T => Key::T,
Key::U => U, U => Key::U,
Key::V => V, V => Key::V,
Key::W => W, W => Key::W,
Key::X => X, X => Key::X,
Key::Y => Y, Y => Key::Y,
Key::Z => Z, Z => Key::Z,
Key::Escape => Escape, Escape => Key::Escape,
Key::F1 => F1, F1 => Key::F1,
Key::F2 => F2, F2 => Key::F2,
Key::F3 => F3, F3 => Key::F3,
Key::F4 => F4, F4 => Key::F4,
Key::F5 => F5, F5 => Key::F5,
Key::F6 => F6, F6 => Key::F6,
Key::F7 => F7, F7 => Key::F7,
Key::F8 => F8, F8 => Key::F8,
Key::F9 => F9, F9 => Key::F9,
Key::F10 => F10, F10 => Key::F10,
Key::F11 => F11, F11 => Key::F11,
Key::F12 => F12, F12 => Key::F12,
Key::F13 => F13, F13 => Key::F13,
Key::F14 => F14, F14 => Key::F14,
Key::F15 => F15, F15 => Key::F15,
Key::Snapshot => Snapshot, Snapshot => Key::Snapshot,
Key::Scroll => Scroll, Scroll => Key::Scroll,
Key::Pause => Pause, Pause => Key::Pause,
Key::Insert => Insert, Insert => Key::Insert,
Key::Home => Home, Home => Key::Home,
Key::Delete => Delete, Delete => Key::Delete,
Key::End => End, End => Key::End,
Key::PageDown => PageDown, PageDown => Key::PageDown,
Key::PageUp => PageUp, PageUp => Key::PageUp,
Key::Left => Left, Left => Key::Left,
Key::Up => Up, Up => Key::Up,
Key::Right => Right, Right => Key::Right,
Key::Down => Down, Down => Key::Down,
Key::Back => Back, Back => Key::Back,
Key::Return => Return, Return => Key::Return,
Key::Space => Space, Space => Key::Space,
Key::Compose => Compose, Compose => Key::Compose,
Key::Numlock => Numlock, Numlock => Key::Numlock,
Key::Numpad0 => Numpad0, Numpad0 => Key::Numpad0,
Key::Numpad1 => Numpad1, Numpad1 => Key::Numpad1,
Key::Numpad2 => Numpad2, Numpad2 => Key::Numpad2,
Key::Numpad3 => Numpad3, Numpad3 => Key::Numpad3,
Key::Numpad4 => Numpad4, Numpad4 => Key::Numpad4,
Key::Numpad5 => Numpad5, Numpad5 => Key::Numpad5,
Key::Numpad6 => Numpad6, Numpad6 => Key::Numpad6,
Key::Numpad7 => Numpad7, Numpad7 => Key::Numpad7,
Key::Numpad8 => Numpad8, Numpad8 => Key::Numpad8,
Key::Numpad9 => Numpad9, Numpad9 => Key::Numpad9,
Key::AbntC1 => AbntC1, AbntC1 => Key::AbntC1,
Key::AbntC2 => AbntC2, AbntC2 => Key::AbntC2,
Key::Add => Add, Add => Key::Add,
Key::Apostrophe => Apostrophe, Apostrophe => Key::Apostrophe,
Key::Apps => Apps, Apps => Key::Apps,
Key::At => At, At => Key::At,
Key::Ax => Ax, Ax => Key::Ax,
Key::Backslash => Backslash, Backslash => Key::Backslash,
Key::Calculator => Calculator, Calculator => Key::Calculator,
Key::Capital => Capital, Capital => Key::Capital,
Key::Colon => Colon, Colon => Key::Colon,
Key::Comma => Comma, Comma => Key::Comma,
Key::Convert => Convert, Convert => Key::Convert,
Key::Decimal => Decimal, Decimal => Key::Decimal,
Key::Divide => Divide, Divide => Key::Divide,
Key::Equals => Equals, Equals => Key::Equals,
Key::Grave => Grave, Grave => Key::Grave,
Key::Kana => Kana, Kana => Key::Kana,
Key::Kanji => Kanji, Kanji => Key::Kanji,
Key::LAlt => LAlt, LAlt => Key::LAlt,
Key::LBracket => LBracket, LBracket => Key::LBracket,
Key::LControl => LControl, LControl => Key::LControl,
Key::LMenu => LMenu, LMenu => Key::LMenu,
Key::LShift => LShift, LShift => Key::LShift,
Key::LWin => LWin, LWin => Key::LWin,
Key::Mail => Mail, Mail => Key::Mail,
Key::MediaSelect => MediaSelect, MediaSelect => Key::MediaSelect,
Key::MediaStop => MediaStop, MediaStop => Key::MediaStop,
Key::Minus => Minus, Minus => Key::Minus,
Key::Multiply => Multiply, Multiply => Key::Multiply,
Key::Mute => Mute, Mute => Key::Mute,
Key::MyComputer => MyComputer, MyComputer => Key::MyComputer,
Key::NavigateForward => NavigateForward, NavigateForward => Key::NavigateForward,
Key::NavigateBackward => NavigateBackward, NavigateBackward => Key::NavigateBackward,
Key::NextTrack => NextTrack, NextTrack => Key::NextTrack,
Key::NoConvert => NoConvert, NoConvert => Key::NoConvert,
Key::NumpadComma => NumpadComma, NumpadComma => Key::NumpadComma,
Key::NumpadEnter => NumpadEnter, NumpadEnter => Key::NumpadEnter,
Key::NumpadEquals => NumpadEquals, NumpadEquals => Key::NumpadEquals,
Key::OEM102 => OEM102, OEM102 => Key::OEM102,
Key::Period => Period, Period => Key::Period,
Key::PlayPause => PlayPause, PlayPause => Key::PlayPause,
Key::Power => Power, Power => Key::Power,
Key::PrevTrack => PrevTrack, PrevTrack => Key::PrevTrack,
Key::RAlt => RAlt, RAlt => Key::RAlt,
Key::RBracket => RBracket, RBracket => Key::RBracket,
Key::RControl => RControl, RControl => Key::RControl,
Key::RMenu => RMenu, RMenu => Key::RMenu,
Key::RShift => RShift, RShift => Key::RShift,
Key::RWin => RWin, RWin => Key::RWin,
Key::Semicolon => Semicolon, Semicolon => Key::Semicolon,
Key::Slash => Slash, Slash => Key::Slash,
Key::Sleep => Sleep, Sleep => Key::Sleep,
Key::Stop => Stop, Stop => Key::Stop,
Key::Subtract => Subtract, Subtract => Key::Subtract,
Key::Sysrq => Sysrq, Sysrq => Key::Sysrq,
Key::Tab => Tab, Tab => Key::Tab,
Key::Underline => Underline, Underline => Key::Underline,
Key::Unlabeled => Unlabeled, Unlabeled => Key::Unlabeled,
Key::VolumeDown => VolumeDown, VolumeDown => Key::VolumeDown,
Key::VolumeUp => VolumeUp, VolumeUp => Key::VolumeUp,
Key::Wake => Wake, Wake => Key::Wake,
Key::WebBack => WebBack, WebBack => Key::WebBack,
Key::WebFavorites => WebFavorites, WebFavorites => Key::WebFavorites,
Key::WebForward => WebForward, WebForward => Key::WebForward,
Key::WebHome => WebHome, WebHome => Key::WebHome,
Key::WebRefresh => WebRefresh, WebRefresh => Key::WebRefresh,
Key::WebSearch => WebSearch, WebSearch => Key::WebSearch,
Key::WebStop => WebStop, WebStop => Key::WebStop,
Key::Yen => Yen, Yen => Key::Yen,
Key::Caret => Caret, Caret => Key::Caret,
Key::Copy => Copy, Copy => Key::Copy,
Key::Paste => Paste, Paste => Key::Paste,
Key::Cut => Cut, Cut => Key::Cut,
} }
} }
} }

View file

@ -334,9 +334,8 @@ impl<N: Notify> Processor<N> {
processor.ctx.terminal.dirty = true; processor.ctx.terminal.dirty = true;
}, },
KeyboardInput { input, .. } => { KeyboardInput { input, .. } => {
let glutin::KeyboardInput { state, virtual_keycode, modifiers, .. } = input; processor.process_key(input);
processor.process_key(state, virtual_keycode, modifiers); if input.state == ElementState::Pressed {
if state == ElementState::Pressed {
// Hide cursor while typing // Hide cursor while typing
*hide_cursor = true; *hide_cursor = true;
} }

View file

@ -26,9 +26,9 @@ use std::time::Instant;
use std::os::unix::process::CommandExt; use std::os::unix::process::CommandExt;
use copypasta::{Clipboard, Load, Buffer as ClipboardBuffer}; 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 grid::Scroll;
use event::{ClickState, Mouse}; use event::{ClickState, Mouse};
use index::{Line, Column, Side, Point}; use index::{Line, Column, Side, Point};
@ -100,7 +100,7 @@ pub struct Binding<T> {
} }
/// Bindings that are triggered by a keyboard key /// Bindings that are triggered by a keyboard key
pub type KeyBinding = Binding<VirtualKeyCode>; pub type KeyBinding = Binding<Key>;
/// Bindings that are triggered by a mouse button /// Bindings that are triggered by a mouse button
pub type MouseBinding = Binding<MouseButton>; pub type MouseBinding = Binding<MouseButton>;
@ -618,24 +618,18 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
/// Process key input /// Process key input
/// ///
/// If a keybinding was run, returns true. Otherwise returns false. /// If a keybinding was run, returns true. Otherwise returns false.
pub fn process_key( pub fn process_key(&mut self, input: KeyboardInput) {
&mut self, match input.state {
state: ElementState, ElementState::Pressed => {
key: Option<VirtualKeyCode>, *self.ctx.last_modifiers() = input.modifiers;
mods: ModifiersState,
) {
match (key, state) {
(Some(key), ElementState::Pressed) => {
*self.ctx.last_modifiers() = mods;
*self.ctx.received_count() = 0; *self.ctx.received_count() = 0;
*self.ctx.suppress_chars() = false; *self.ctx.suppress_chars() = false;
if self.process_key_bindings(mods, key) { if self.process_key_bindings(input) {
*self.ctx.suppress_chars() = true; *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. /// for its action to be executed.
/// ///
/// Returns true if an action is 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; let mut has_binding = false;
for binding in self.key_bindings { 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 was triggered; run the action
binding.execute(&mut self.ctx); binding.execute(&mut self.ctx);
has_binding = true; has_binding = true;