Krolyxon
Commit 8b10288

Branches

Tags

Refs →

remagesrcinputmod.rs

120 lines · 4.0 KB · Rust

1//! Keyboard and mouse input: vim key notation, per-mode keymaps, and the bridge from winit.
2
3pub mod keymap;
4pub mod keys;
5
6use winit::event::MouseButton;
7use winit::keyboard::{Key as WinitKey, ModifiersState, NamedKey};
8
9use keys::{Button, Code, Key, Mods, Named, Scroll};
10
11pub fn mods(m: ModifiersState) -> Mods {
12 Mods {
13 ctrl: m.control_key(),
14 alt: m.alt_key(),
15 shift: m.shift_key(),
16 sup: m.super_key(),
17 }
18}
19
20/// A key press in vim terms. Modifier keys on their own, dead keys and unnamed keys give `None`.
21pub fn key(key: &WinitKey, m: ModifiersState) -> Option<Key> {
22 let code = match key {
23 WinitKey::Character(s) => {
24 let mut chars = s.chars();
25 match (chars.next(), chars.next()) {
26 (Some(c), None) => Code::Char(c),
27 _ => return None,
28 }
29 }
30 WinitKey::Named(n) => Code::Named(match n {
31 NamedKey::Space => Named::Space,
32 NamedKey::Enter => Named::Enter,
33 NamedKey::Escape => Named::Esc,
34 NamedKey::Tab => Named::Tab,
35 NamedKey::Backspace => Named::Backspace,
36 NamedKey::Delete => Named::Delete,
37 NamedKey::Insert => Named::Insert,
38 NamedKey::Home => Named::Home,
39 NamedKey::End => Named::End,
40 NamedKey::PageUp => Named::PageUp,
41 NamedKey::PageDown => Named::PageDown,
42 NamedKey::ArrowUp => Named::Up,
43 NamedKey::ArrowDown => Named::Down,
44 NamedKey::ArrowLeft => Named::Left,
45 NamedKey::ArrowRight => Named::Right,
46 other => {
47 return function_key(*other)
48 .map(Named::F)
49 .map(|f| Key::new(mods(m), Code::Named(f)));
50 }
51 }),
52 _ => return None,
53 };
54 Some(Key::new(mods(m), code))
55}
56
57fn function_key(n: NamedKey) -> Option<u8> {
58 use NamedKey::*;
59 const F: [NamedKey; 35] = [
60 F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20,
61 F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, F32, F33, F34, F35,
62 ];
63 F.iter().position(|f| *f == n).map(|i| i as u8 + 1)
64}
65
66pub fn button(b: MouseButton, m: ModifiersState) -> Option<Key> {
67 let b = match b {
68 MouseButton::Left => Button::Left,
69 MouseButton::Right => Button::Right,
70 MouseButton::Middle => Button::Middle,
71 MouseButton::Back => Button::Back,
72 MouseButton::Forward => Button::Forward,
73 MouseButton::Other(_) => return None,
74 };
75 Some(Key::new(mods(m), Code::Mouse(b)))
76}
77
78pub fn scroll(dir: Scroll, m: ModifiersState) -> Key {
79 Key::new(mods(m), Code::Scroll(dir))
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use keys::KeySeq;
86
87 fn k(s: &str) -> Key {
88 s.parse::<KeySeq>().unwrap().0[0]
89 }
90
91 #[test]
92 fn winit_keys_match_notation() {
93 let none = ModifiersState::empty();
94 let ch = |s: &str| WinitKey::Character(s.into());
95 assert_eq!(key(&ch("n"), none), Some(k("n")));
96 // Shift is already in the character.
97 assert_eq!(key(&ch("G"), ModifiersState::SHIFT), Some(k("G")));
98 assert_eq!(key(&ch("?"), ModifiersState::SHIFT), Some(k("?")));
99 assert_eq!(key(&ch("x"), ModifiersState::CONTROL), Some(k("<C-x>")));
100 assert_eq!(key(&ch(" "), none), Some(k("<Space>")));
101 assert_eq!(
102 key(&WinitKey::Named(NamedKey::Space), ModifiersState::CONTROL),
103 Some(k("<C-Space>"))
104 );
105 assert_eq!(
106 key(&WinitKey::Named(NamedKey::Tab), ModifiersState::SHIFT),
107 Some(k("<S-Tab>"))
108 );
109 assert_eq!(key(&WinitKey::Named(NamedKey::F5), none), Some(k("<F5>")));
110 assert_eq!(
111 key(&WinitKey::Named(NamedKey::Shift), ModifiersState::SHIFT),
112 None
113 );
114 assert_eq!(button(MouseButton::Right, none), Some(k("<RightMouse>")));
115 assert_eq!(
116 scroll(Scroll::Up, ModifiersState::CONTROL),
117 k("<C-ScrollUp>")
118 );
119 }
120}