aboutsummaryrefslogtreecommitdiff
path: root/src/config.rs
diff options
context:
space:
mode:
authorJoe Wilm <joe@jwilm.com>2016-11-15 09:38:50 -0800
committerJoe Wilm <joe@jwilm.com>2016-11-17 17:17:54 -0800
commitd97996e19de6856c23c51d05ec10f10db41e309d (patch)
tree80e43240687249f5062bcd16d64492ae32b0625d /src/config.rs
parentcb2bc4eadd3d149fcae4d1b552be47bc5a9413d8 (diff)
downloadalacritty-d97996e19de6856c23c51d05ec10f10db41e309d.tar.gz
alacritty-d97996e19de6856c23c51d05ec10f10db41e309d.zip
Make bindings configurable from alacritty.yml
Bindings were previously hardcoded within input.rs; adding, removing, or changing a binding required a recompile! Now, bindings may be declared in alacritty.yml. Even better, bindings are live-reloaded when alacritty.yml is changed! One unexpected benefit of this change was that all of the special casing in input.rs has disappeared. Conversely, config.rs has gained complexity for all of the deserialization logic. Resolves #3.
Diffstat (limited to 'src/config.rs')
-rw-r--r--src/config.rs726
1 files changed, 725 insertions, 1 deletions
diff --git a/src/config.rs b/src/config.rs
index 33474ddb..b315fb86 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -7,14 +7,18 @@ use std::env;
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
+use std::str::FromStr;
use std::sync::mpsc;
use ::Rgb;
use font::Size;
use serde_yaml;
-use serde::{self, Error as SerdeError};
+use serde::{self, de, Error as SerdeError};
+use serde::de::{Visitor, MapVisitor};
use notify::{Watcher as WatcherApi, RecommendedWatcher as FileWatcher, op};
+use input::{Action, Binding, MouseBinding, KeyBinding};
+
/// Function that returns true for serde default
fn true_bool() -> bool {
true
@@ -42,6 +46,14 @@ pub struct Config {
/// The standard ANSI colors to use
#[serde(default)]
colors: Colors,
+
+ /// Keybindings
+ #[serde(default)]
+ key_bindings: Vec<KeyBinding>,
+
+ /// Bindings for the mouse
+ #[serde(default)]
+ mouse_bindings: Vec<MouseBinding>,
}
impl Default for Config {
@@ -52,7 +64,377 @@ impl Default for Config {
font: Default::default(),
render_timer: Default::default(),
colors: Default::default(),
+ key_bindings: Vec::new(),
+ mouse_bindings: Vec::new(),
+ }
+ }
+}
+
+/// Newtype for implementing deserialize on glutin Mods
+///
+/// Our deserialize impl wouldn't be covered by a derive(Deserialize); see the
+/// impl below.
+struct ModsWrapper(::glutin::Mods);
+
+impl ModsWrapper {
+ fn into_inner(self) -> ::glutin::Mods {
+ self.0
+ }
+}
+
+impl de::Deserialize for ModsWrapper {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
+ where D: de::Deserializer
+ {
+ struct ModsVisitor;
+
+ impl Visitor for ModsVisitor {
+ type Value = ModsWrapper;
+
+ fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<ModsWrapper, E>
+ where E: de::Error,
+ {
+ use ::glutin::{mods, Mods};
+ let mut res = Mods::empty();
+ for modifier in value.split('|') {
+ match modifier {
+ "Command" | "Super" => res = res | mods::SUPER,
+ "Shift" => res = res | mods::SHIFT,
+ "Alt" | "Option" => res = res | mods::ALT,
+ "Control" => res = res | mods::CONTROL,
+ _ => err_println!("unknown modifier {:?}", modifier),
+ }
+ }
+
+ Ok(ModsWrapper(res))
+ }
+ }
+
+ deserializer.deserialize_str(ModsVisitor)
+ }
+}
+
+struct ActionWrapper(::input::Action);
+
+impl ActionWrapper {
+ fn into_inner(self) -> ::input::Action {
+ self.0
+ }
+}
+
+impl de::Deserialize for ActionWrapper {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
+ where D: de::Deserializer
+ {
+ struct ActionVisitor;
+
+ impl Visitor for ActionVisitor {
+ type Value = ActionWrapper;
+
+ fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<ActionWrapper, E>
+ where E: de::Error,
+ {
+ Ok(ActionWrapper(match value {
+ "Paste" => Action::Paste,
+ "PasteSelection" => Action::PasteSelection,
+ _ => return Err(E::invalid_value("invalid value for Action")),
+ }))
+ }
}
+ deserializer.deserialize_str(ActionVisitor)
+ }
+}
+
+use ::term::{mode, TermMode};
+
+struct ModeWrapper {
+ pub mode: TermMode,
+ pub not_mode: TermMode,
+}
+
+impl de::Deserialize for ModeWrapper {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
+ where D: de::Deserializer
+ {
+ struct ModeVisitor;
+
+ impl Visitor for ModeVisitor {
+ type Value = ModeWrapper;
+
+ fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<ModeWrapper, E>
+ where E: de::Error,
+ {
+ let mut res = ModeWrapper {
+ mode: TermMode::empty(),
+ not_mode: TermMode::empty()
+ };
+
+ for modifier in value.split('|') {
+ match modifier {
+ "AppCursor" => res.mode = res.mode | mode::APP_CURSOR,
+ "~AppCursor" => res.not_mode = res.not_mode | mode::APP_CURSOR,
+ "AppKeypad" => res.mode = res.mode | mode::APP_KEYPAD,
+ "~AppKeypad" => res.not_mode = res.not_mode | mode::APP_KEYPAD,
+ _ => err_println!("unknown omde {:?}", modifier),
+ }
+ }
+
+ Ok(res)
+ }
+ }
+ deserializer.deserialize_str(ModeVisitor)
+ }
+}
+
+struct MouseButton(::glutin::MouseButton);
+
+impl MouseButton {
+ fn into_inner(self) -> ::glutin::MouseButton {
+ self.0
+ }
+}
+
+impl de::Deserialize for MouseButton {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
+ where D: de::Deserializer
+ {
+ struct MouseButtonVisitor;
+
+ impl Visitor for MouseButtonVisitor {
+ type Value = MouseButton;
+
+ fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<MouseButton, E>
+ where E: de::Error,
+ {
+ match value {
+ "Left" => Ok(MouseButton(::glutin::MouseButton::Left)),
+ "Right" => Ok(MouseButton(::glutin::MouseButton::Right)),
+ "Middle" => Ok(MouseButton(::glutin::MouseButton::Middle)),
+ _ => {
+ if let Ok(index) = u8::from_str(value) {
+ Ok(MouseButton(::glutin::MouseButton::Other(index)))
+ } else {
+ Err(E::invalid_value("mouse may be Left, Right, Middle, or u8"))
+ }
+ }
+ }
+ }
+ }
+
+ deserializer.deserialize_str(MouseButtonVisitor)
+ }
+}
+
+/// Bindings are deserialized into a RawBinding before being parsed as a
+/// KeyBinding or MouseBinding.
+struct RawBinding {
+ key: Option<::glutin::VirtualKeyCode>,
+ mouse: Option<::glutin::MouseButton>,
+ mods: ::glutin::Mods,
+ mode: TermMode,
+ notmode: TermMode,
+ action: Action,
+}
+
+impl RawBinding {
+ fn into_mouse_binding(self) -> ::std::result::Result<MouseBinding, Self> {
+ if self.mouse.is_some() {
+ Ok(MouseBinding {
+ button: self.mouse.unwrap(),
+ binding: Binding {
+ mods: self.mods,
+ action: self.action,
+ mode: self.mode,
+ notmode: self.notmode,
+ }
+ })
+ } else {
+ Err(self)
+ }
+ }
+
+ fn into_key_binding(self) -> ::std::result::Result<KeyBinding, Self> {
+ if self.key.is_some() {
+ Ok(KeyBinding {
+ key: self.key.unwrap(),
+ binding: Binding {
+ mods: self.mods,
+ action: self.action,
+ mode: self.mode,
+ notmode: self.notmode,
+ }
+ })
+ } else {
+ Err(self)
+ }
+ }
+}
+
+impl de::Deserialize for RawBinding {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
+ where D: de::Deserializer
+ {
+ enum Field {
+ Key,
+ Mods,
+ Mode,
+ Action,
+ Chars,
+ Mouse
+ }
+
+ impl de::Deserialize for Field {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Field, D::Error>
+ where D: de::Deserializer
+ {
+ struct FieldVisitor;
+
+ impl Visitor for FieldVisitor {
+ type Value = Field;
+
+ fn visit_str<E>(&mut self, value: &str) -> ::std::result::Result<Field, E>
+ where E: de::Error,
+ {
+ match value {
+ "key" => Ok(Field::Key),
+ "mods" => Ok(Field::Mods),
+ "mode" => Ok(Field::Mode),
+ "action" => Ok(Field::Action),
+ "chars" => Ok(Field::Chars),
+ "mouse" => Ok(Field::Mouse),
+ _ => Err(E::unknown_field(value)),
+ }
+ }
+ }
+
+ deserializer.deserialize_struct_field(FieldVisitor)
+ }
+ }
+
+ struct RawBindingVisitor;
+ impl Visitor for RawBindingVisitor {
+ type Value = RawBinding;
+
+ fn visit_map<V>(&mut self, mut visitor: V) -> ::std::result::Result<RawBinding, V::Error>
+ where V: MapVisitor,
+ {
+ let mut mods: Option<::glutin::Mods> = None;
+ let mut key: Option<::glutin::VirtualKeyCode> = None;
+ let mut chars: Option<String> = None;
+ let mut action: Option<::input::Action> = None;
+ let mut mode: Option<TermMode> = None;
+ let mut not_mode: Option<TermMode> = None;
+ let mut mouse: Option<::glutin::MouseButton> = None;
+
+ use ::serde::Error;
+
+ while let Some(struct_key) = visitor.visit_key::<Field>()? {
+ match struct_key {
+ Field::Key => {
+ if key.is_some() {
+ return Err(<V::Error as Error>::duplicate_field("key"));
+ }
+
+ let coherent_key = visitor.visit_value::<Key>()?;
+ key = Some(coherent_key.to_glutin_key());
+ },
+ Field::Mods => {
+ if mods.is_some() {
+ return Err(<V::Error as Error>::duplicate_field("mods"));
+ }
+
+ mods = Some(visitor.visit_value::<ModsWrapper>()?.into_inner());
+ },
+ Field::Mode => {
+ if mode.is_some() {
+ return Err(<V::Error as Error>::duplicate_field("mode"));
+ }
+
+ let mode_deserializer = visitor.visit_value::<ModeWrapper>()?;
+ mode = Some(mode_deserializer.mode);
+ not_mode = Some(mode_deserializer.not_mode);
+ },
+ Field::Action => {
+ if action.is_some() {
+ return Err(<V::Error as Error>::duplicate_field("action"));
+ }
+
+ action = Some(visitor.visit_value::<ActionWrapper>()?.into_inner());
+ },
+ Field::Chars => {
+ if chars.is_some() {
+ return Err(<V::Error as Error>::duplicate_field("chars"));
+ }
+
+ chars = Some(visitor.visit_value()?);
+ },
+ Field::Mouse => {
+ if chars.is_some() {
+ return Err(<V::Error as Error>::duplicate_field("mouse"));
+ }
+
+ mouse = Some(visitor.visit_value::<MouseButton>()?.into_inner());
+ }
+ }
+ }
+ visitor.end()?;
+ if key.is_none() {
+ return Err(V::Error::missing_field("key"));
+ }
+
+ let action = match (action, chars) {
+ (Some(_), Some(_)) => {
+ return Err(V::Error::custom("must specify only chars or action"));
+ },
+ (Some(action), _) => action,
+ (_, Some(chars)) => Action::Esc(chars),
+ _ => return Err(V::Error::custom("must specify chars or action"))
+ };
+
+ let mode = mode.unwrap_or_else(TermMode::empty);
+ let not_mode = not_mode.unwrap_or_else(TermMode::empty);
+ let mods = mods.unwrap_or_else(::glutin::Mods::empty);
+
+ if mouse.is_none() && key.is_none() {
+ return Err(V::Error::custom("bindings require mouse button or key"));
+ }
+
+ Ok(RawBinding {
+ mode: mode,
+ notmode: not_mode,
+ action: action,
+ key: key,
+ mouse: mouse,
+ mods: mods,
+ })
+ }
+ }
+
+ const FIELDS: &'static [&'static str] = &[
+ "key", "mods", "mode", "action", "chars", "mouse"
+ ];
+
+ deserializer.deserialize_struct("RawBinding", FIELDS, RawBindingVisitor)
+ }
+}
+
+impl de::Deserialize for MouseBinding {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
+ where D: de::Deserializer
+ {
+ let raw = RawBinding::deserialize(deserializer)?;
+ raw.into_mouse_binding()
+ .map_err(|_| D::Error::custom("expected mouse binding"))
+ }
+}
+
+impl de::Deserialize for KeyBinding {
+ fn deserialize<D>(deserializer: &mut D) -> ::std::result::Result<Self, D::Error>
+ where D: de::Deserializer
+ {
+ let raw = RawBinding::deserialize(deserializer)?;
+ raw.into_key_binding()
+ .map_err(|_| D::Error::custom("expected key binding"))
}
}
@@ -314,6 +696,14 @@ impl Config {
]
}
+ pub fn key_bindings(&self) -> &[KeyBinding] {
+ &self.key_bindings[..]
+ }
+
+ pub fn mouse_bindings(&self) -> &[MouseBinding] {
+ &self.mouse_bindings[..]
+ }
+
pub fn fg_color(&self) -> Rgb {
self.colors.primary.foreground
}
@@ -605,3 +995,337 @@ impl Watcher {
}))
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::Config;
+
+ static ALACRITTY_YML: &'static str =
+ include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/alacritty.yml"));
+
+ #[test]
+ fn parse_config() {
+ let config: Config = ::serde_yaml::from_str(ALACRITTY_YML)
+ .expect("deserialize config");
+
+ println!("config: {:#?}", config);
+ }
+}
+
+#[derive(Deserialize, Copy, Clone)]
+enum Key {
+ Key1,
+ Key2,
+ Key3,
+ Key4,
+ Key5,
+ Key6,
+ Key7,
+ Key8,
+ Key9,
+ Key0,
+
+ A,
+ B,
+ C,
+ D,
+ E,
+ F,
+ G,
+ H,
+ I,
+ J,
+ K,
+ L,
+ M,
+ N,
+ O,
+ P,
+ Q,
+ R,
+ S,
+ T,
+ U,
+ V,
+ W,
+ X,
+ Y,
+ Z,
+
+ Escape,
+
+ F1,
+ F2,
+ F3,
+ F4,
+ F5,
+ F6,
+ F7,
+ F8,
+ F9,
+ F10,
+ F11,
+ F12,
+ F13,
+ F14,
+ F15,
+
+ Snapshot,
+ Scroll,
+ Pause,
+ Insert,
+ Home,
+ Delete,
+ End,
+ PageDown,
+ PageUp,
+
+ Left,
+ Up,
+ Right,
+ Down,
+ Back,
+ Return,
+ Space,
+ Compose,
+ Numlock,
+ Numpad0,
+ Numpad1,
+ Numpad2,
+ Numpad3,
+ Numpad4,
+ Numpad5,
+ Numpad6,
+ Numpad7,
+ Numpad8,
+ Numpad9,
+
+ AbntC1,
+ AbntC2,
+ Add,
+ Apostrophe,
+ Apps,
+ At,
+ Ax,
+ Backslash,
+ Calculator,
+ Capital,
+ Colon,
+ Comma,
+ Convert,
+ Decimal,
+ Divide,
+ Equals,
+ Grave,
+ Kana,
+ Kanji,
+ LAlt,
+ LBracket,
+ LControl,
+ LMenu,
+ LShift,
+ LWin,
+ Mail,
+ MediaSelect,
+ MediaStop,
+ Minus,
+ Multiply,
+ Mute,
+ MyComputer,
+ NavigateForward,
+ NavigateBackward,
+ NextTrack,
+ NoConvert,
+ NumpadComma,
+ NumpadEnter,
+ NumpadEquals,
+ OEM102,
+ Period,
+ PlayPause,
+ Power,
+ PrevTrack,
+ RAlt,
+ RBracket,
+ RControl,
+ RMenu,
+ RShift,
+ RWin,
+ Semicolon,
+ Slash,
+ Sleep,
+ Stop,
+ Subtract,
+ Sysrq,
+ Tab,
+ Underline,
+ Unlabeled,
+ VolumeDown,
+ VolumeUp,
+ Wake,
+ WebBack,
+ WebFavorites,
+ WebForward,
+ WebHome,
+ WebRefresh,
+ WebSearch,
+ WebStop,
+ Yen,
+}
+
+impl Key {
+ fn to_glutin_key(&self) -> ::glutin::VirtualKeyCode {
+ // Thank you, vim macros!
+ match *self {
+ Key::Key1 => ::glutin::VirtualKeyCode::Key1,
+ Key::Key2 => ::glutin::VirtualKeyCode::Key2,
+ Key::Key3 => ::glutin::VirtualKeyCode::Key3,
+ Key::Key4 => ::glutin::VirtualKeyCode::Key4,
+ Key::Key5 => ::glutin::VirtualKeyCode::Key5,
+ Key::Key6 => ::glutin::VirtualKeyCode::Key6,
+ Key::Key7 => ::glutin::VirtualKeyCode::Key7,
+ Key::Key8 => ::glutin::VirtualKeyCode::Key8,
+ Key::Key9 => ::glutin::VirtualKeyCode::Key9,
+ Key::Key0 => ::glutin::VirtualKeyCode::Key0,
+ Key::A => ::glutin::VirtualKeyCode::A,
+ Key::B => ::glutin::VirtualKeyCode::B,
+ Key::C => ::glutin::VirtualKeyCode::C,
+ Key::D => ::glutin::VirtualKeyCode::D,
+ Key::E => ::glutin::VirtualKeyCode::E,
+ Key::F => ::glutin::VirtualKeyCode::F,
+ Key::G => ::glutin::VirtualKeyCode::G,
+ Key::H => ::glutin::VirtualKeyCode::H,
+ Key::I => ::glutin::VirtualKeyCode::I,
+ Key::J => ::glutin::VirtualKeyCode::J,
+ Key::K => ::glutin::VirtualKeyCode::K,
+ Key::L => ::glutin::VirtualKeyCode::L,
+ Key::M => ::glutin::VirtualKeyCode::M,
+ Key::N => ::glutin::VirtualKeyCode::N,
+ Key::O => ::glutin::VirtualKeyCode::O,
+ Key::P => ::glutin::VirtualKeyCode::P,
+ Key::Q => ::glutin::VirtualKeyCode::Q,
+ Key::R => ::glutin::VirtualKeyCode::R,
+ Key::S => ::glutin::VirtualKeyCode::S,
+ Key::T => ::glutin::VirtualKeyCode::T,
+ Key::U => ::glutin::VirtualKeyCode::U,
+ Key::V => ::glutin::VirtualKeyCode::V,
+ Key::W => ::glutin::VirtualKeyCode::W,
+ Key::X => ::glutin::VirtualKeyCode::X,
+ Key::Y => ::glutin::VirtualKeyCode::Y,
+ Key::Z => ::glutin::VirtualKeyCode::Z,
+ Key::Escape => ::glutin::VirtualKeyCode::Escape,
+ Key::F1 => ::glutin::VirtualKeyCode::F1,
+ Key::F2 => ::glutin::VirtualKeyCode::F2,
+ Key::F3 => ::glutin::VirtualKeyCode::F3,
+ Key::F4 => ::glutin::VirtualKeyCode::F4,
+ Key::F5 => ::glutin::VirtualKeyCode::F5,
+ Key::F6 => ::glutin::VirtualKeyCode::F6,
+ Key::F7 => ::glutin::VirtualKeyCode::F7,
+ Key::F8 => ::glutin::VirtualKeyCode::F8,
+ Key::F9 => ::glutin::VirtualKeyCode::F9,
+ Key::F10 => ::glutin::VirtualKeyCode::F10,
+ Key::F11 => ::glutin::VirtualKeyCode::F11,
+ Key::F12 => ::glutin::VirtualKeyCode::F12,
+ Key::F13 => ::glutin::VirtualKeyCode::F13,
+ Key::F14 => ::glutin::VirtualKeyCode::F14,
+ Key::F15 => ::glutin::VirtualKeyCode::F15,
+ Key::Snapshot => ::glutin::VirtualKeyCode::Snapshot,
+ Key::Scroll => ::glutin::VirtualKeyCode::Scroll,
+ Key::Pause => ::glutin::VirtualKeyCode::Pause,
+ Key::Insert => ::glutin::VirtualKeyCode::Insert,
+ Key::Home => ::glutin::VirtualKeyCode::Home,
+ Key::Delete => ::glutin::VirtualKeyCode::Delete,
+ Key::End => ::glutin::VirtualKeyCode::End,
+ Key::PageDown => ::glutin::VirtualKeyCode::PageDown,
+ Key::PageUp => ::glutin::VirtualKeyCode::PageUp,
+ Key::Left => ::glutin::VirtualKeyCode::Left,
+ Key::Up => ::glutin::VirtualKeyCode::Up,
+ Key::Right => ::glutin::VirtualKeyCode::Right,
+ Key::Down => ::glutin::VirtualKeyCode::Down,
+ Key::Back => ::glutin::VirtualKeyCode::Back,
+ Key::Return => ::glutin::VirtualKeyCode::Return,
+ Key::Space => ::glutin::VirtualKeyCode::Space,
+ Key::Compose => ::glutin::VirtualKeyCode::Compose,
+ Key::Numlock => ::glutin::VirtualKeyCode::Numlock,
+ Key::Numpad0 => ::glutin::VirtualKeyCode::Numpad0,
+ Key::Numpad1 => ::glutin::VirtualKeyCode::Numpad1,
+ Key::Numpad2 => ::glutin::VirtualKeyCode::Numpad2,
+ Key::Numpad3 => ::glutin::VirtualKeyCode::Numpad3,
+ Key::Numpad4 => ::glutin::VirtualKeyCode::Numpad4,
+ Key::Numpad5 => ::glutin::VirtualKeyCode::Numpad5,
+ Key::Numpad6 => ::glutin::VirtualKeyCode::Numpad6,
+ Key::Numpad7 => ::glutin::VirtualKeyCode::Numpad7,
+ Key::Numpad8 => ::glutin::VirtualKeyCode::Numpad8,
+ Key::Numpad9 => ::glutin::VirtualKeyCode::Numpad9,
+ Key::AbntC1 => ::glutin::VirtualKeyCode::AbntC1,
+ Key::AbntC2 => ::glutin::VirtualKeyCode::AbntC2,
+ Key::Add => ::glutin::VirtualKeyCode::Add,
+ Key::Apostrophe => ::glutin::VirtualKeyCode::Apostrophe,
+ Key::Apps => ::glutin::VirtualKeyCode::Apps,
+ Key::At => ::glutin::VirtualKeyCode::At,
+ Key::Ax => ::glutin::VirtualKeyCode::Ax,
+ Key::Backslash => ::glutin::VirtualKeyCode::Backslash,
+ Key::Calculator => ::glutin::VirtualKeyCode::Calculator,
+ Key::Capital => ::glutin::VirtualKeyCode::Capital,
+ Key::Colon => ::glutin::VirtualKeyCode::Colon,
+ Key::Comma => ::glutin::VirtualKeyCode::Comma,
+ Key::Convert => ::glutin::VirtualKeyCode::Convert,
+ Key::Decimal => ::glutin::VirtualKeyCode::Decimal,
+ Key::Divide => ::glutin::VirtualKeyCode::Divide,
+ Key::Equals => ::glutin::VirtualKeyCode::Equals,
+ Key::Grave => ::glutin::VirtualKeyCode::Grave,
+ Key::Kana => ::glutin::VirtualKeyCode::Kana,
+ Key::Kanji => ::glutin::VirtualKeyCode::Kanji,
+ Key::LAlt => ::glutin::VirtualKeyCode::LAlt,
+ Key::LBracket => ::glutin::VirtualKeyCode::LBracket,
+ Key::LControl => ::glutin::VirtualKeyCode::LControl,
+ Key::LMenu => ::glutin::VirtualKeyCode::LMenu,
+ Key::LShift => ::glutin::VirtualKeyCode::LShift,
+ Key::LWin => ::glutin::VirtualKeyCode::LWin,
+ Key::Mail => ::glutin::VirtualKeyCode::Mail,
+ Key::MediaSelect => ::glutin::VirtualKeyCode::MediaSelect,
+ Key::MediaStop => ::glutin::VirtualKeyCode::MediaStop,
+ Key::Minus => ::glutin::VirtualKeyCode::Minus,
+ Key::Multiply => ::glutin::VirtualKeyCode::Multiply,
+ Key::Mute => ::glutin::VirtualKeyCode::Mute,
+ Key::MyComputer => ::glutin::VirtualKeyCode::MyComputer,
+ Key::NavigateForward => ::glutin::VirtualKeyCode::NavigateForward,
+ Key::NavigateBackward => ::glutin::VirtualKeyCode::NavigateBackward,
+ Key::NextTrack => ::glutin::VirtualKeyCode::NextTrack,
+ Key::NoConvert => ::glutin::VirtualKeyCode::NoConvert,
+ Key::NumpadComma => ::glutin::VirtualKeyCode::NumpadComma,
+ Key::NumpadEnter => ::glutin::VirtualKeyCode::NumpadEnter,
+ Key::NumpadEquals => ::glutin::VirtualKeyCode::NumpadEquals,
+ Key::OEM102 => ::glutin::VirtualKeyCode::OEM102,
+ Key::Period => ::glutin::VirtualKeyCode::Period,
+ Key::PlayPause => ::glutin::VirtualKeyCode::PlayPause,
+ Key::Power => ::glutin::VirtualKeyCode::Power,
+ Key::PrevTrack => ::glutin::VirtualKeyCode::PrevTrack,
+ Key::RAlt => ::glutin::VirtualKeyCode::RAlt,
+ Key::RBracket => ::glutin::VirtualKeyCode::RBracket,
+ Key::RControl => ::glutin::VirtualKeyCode::RControl,
+ Key::RMenu => ::glutin::VirtualKeyCode::RMenu,
+ Key::RShift => ::glutin::VirtualKeyCode::RShift,
+ Key::RWin => ::glutin::VirtualKeyCode::RWin,
+ Key::Semicolon => ::glutin::VirtualKeyCode::Semicolon,
+ Key::Slash => ::glutin::VirtualKeyCode::Slash,
+ Key::Sleep => ::glutin::VirtualKeyCode::Sleep,
+ Key::Stop => ::glutin::VirtualKeyCode::Stop,
+ Key::Subtract => ::glutin::VirtualKeyCode::Subtract,
+ Key::Sysrq => ::glutin::VirtualKeyCode::Sysrq,
+ Key::Tab => ::glutin::VirtualKeyCode::Tab,
+ Key::Underline => ::glutin::VirtualKeyCode::Underline,
+ Key::Unlabeled => ::glutin::VirtualKeyCode::Unlabeled,
+ Key::VolumeDown => ::glutin::VirtualKeyCode::VolumeDown,
+ Key::VolumeUp => ::glutin::VirtualKeyCode::VolumeUp,
+ Key::Wake => ::glutin::VirtualKeyCode::Wake,
+ Key::WebBack => ::glutin::VirtualKeyCode::WebBack,
+ Key::WebFavorites => ::glutin::VirtualKeyCode::WebFavorites,
+ Key::WebForward => ::glutin::VirtualKeyCode::WebForward,
+ Key::WebHome => ::glutin::VirtualKeyCode::WebHome,
+ Key::WebRefresh => ::glutin::VirtualKeyCode::WebRefresh,
+ Key::WebSearch => ::glutin::VirtualKeyCode::WebSearch,
+ Key::WebStop => ::glutin::VirtualKeyCode::WebStop,
+ Key::Yen => ::glutin::VirtualKeyCode::Yen,
+ }
+ }
+}