Skip to main content

floem/views/editor/keypress/
key.rs

1use std::{
2    fmt::Display,
3    hash::{Hash, Hasher},
4    str::FromStr,
5};
6
7use crate::keyboard::{Key, KeyCode, NativeKey, PhysicalKey};
8
9#[derive(Clone, Debug, Eq)]
10pub enum KeyInput {
11    Keyboard(crate::keyboard::Key, crate::keyboard::PhysicalKey),
12    Pointer(crate::pointer::PointerButton),
13}
14
15impl KeyInput {
16    fn keyboard_from_str(s: &str) -> Option<(Key, PhysicalKey)> {
17        // Checks if it is a character key
18        fn is_key_string(s: &str) -> bool {
19            s.chars().all(|c| !c.is_control()) && s.chars().skip(1).all(|c| !c.is_ascii())
20        }
21
22        fn char_to_keycode(char: &str) -> PhysicalKey {
23            match char {
24                "a" => PhysicalKey::Code(KeyCode::KeyA),
25                "b" => PhysicalKey::Code(KeyCode::KeyB),
26                "c" => PhysicalKey::Code(KeyCode::KeyC),
27                "d" => PhysicalKey::Code(KeyCode::KeyD),
28                "e" => PhysicalKey::Code(KeyCode::KeyE),
29                "f" => PhysicalKey::Code(KeyCode::KeyF),
30                "g" => PhysicalKey::Code(KeyCode::KeyG),
31                "h" => PhysicalKey::Code(KeyCode::KeyH),
32                "i" => PhysicalKey::Code(KeyCode::KeyI),
33                "j" => PhysicalKey::Code(KeyCode::KeyJ),
34                "k" => PhysicalKey::Code(KeyCode::KeyK),
35                "l" => PhysicalKey::Code(KeyCode::KeyL),
36                "m" => PhysicalKey::Code(KeyCode::KeyM),
37                "n" => PhysicalKey::Code(KeyCode::KeyN),
38                "o" => PhysicalKey::Code(KeyCode::KeyO),
39                "p" => PhysicalKey::Code(KeyCode::KeyP),
40                "q" => PhysicalKey::Code(KeyCode::KeyQ),
41                "r" => PhysicalKey::Code(KeyCode::KeyR),
42                "s" => PhysicalKey::Code(KeyCode::KeyS),
43                "t" => PhysicalKey::Code(KeyCode::KeyT),
44                "u" => PhysicalKey::Code(KeyCode::KeyU),
45                "v" => PhysicalKey::Code(KeyCode::KeyV),
46                "w" => PhysicalKey::Code(KeyCode::KeyW),
47                "x" => PhysicalKey::Code(KeyCode::KeyX),
48                "y" => PhysicalKey::Code(KeyCode::KeyY),
49                "z" => PhysicalKey::Code(KeyCode::KeyZ),
50                "=" => PhysicalKey::Code(KeyCode::Equal),
51                "-" => PhysicalKey::Code(KeyCode::Minus),
52                "0" => PhysicalKey::Code(KeyCode::Digit0),
53                "1" => PhysicalKey::Code(KeyCode::Digit1),
54                "2" => PhysicalKey::Code(KeyCode::Digit2),
55                "3" => PhysicalKey::Code(KeyCode::Digit3),
56                "4" => PhysicalKey::Code(KeyCode::Digit4),
57                "5" => PhysicalKey::Code(KeyCode::Digit5),
58                "6" => PhysicalKey::Code(KeyCode::Digit6),
59                "7" => PhysicalKey::Code(KeyCode::Digit7),
60                "8" => PhysicalKey::Code(KeyCode::Digit8),
61                "9" => PhysicalKey::Code(KeyCode::Digit9),
62                "`" => PhysicalKey::Code(KeyCode::Backquote),
63                "/" => PhysicalKey::Code(KeyCode::Slash),
64                "\\" => PhysicalKey::Code(KeyCode::Backslash),
65                "," => PhysicalKey::Code(KeyCode::Comma),
66                "." => PhysicalKey::Code(KeyCode::Period),
67                "*" => PhysicalKey::Code(KeyCode::NumpadMultiply),
68                "+" => PhysicalKey::Code(KeyCode::NumpadAdd),
69                ";" => PhysicalKey::Code(KeyCode::Semicolon),
70                "'" => PhysicalKey::Code(KeyCode::Quote),
71                "[" => PhysicalKey::Code(KeyCode::BracketLeft),
72                "]" => PhysicalKey::Code(KeyCode::BracketRight),
73                "<" => PhysicalKey::Code(KeyCode::IntlBackslash),
74                _ => PhysicalKey::Code(KeyCode::Fn),
75            }
76        }
77
78        // Import into scope to reduce noise
79        use crate::keyboard::NamedKey::*;
80        Some(match s {
81            s if is_key_string(s) => {
82                let char = Key::Character(s.into());
83                (char.clone(), char_to_keycode(char.to_text().unwrap()))
84            }
85            "unidentified" => (
86                Key::Unidentified(NativeKey::Unidentified),
87                PhysicalKey::Code(KeyCode::Fn),
88            ),
89            "alt" => (Key::Named(Alt), PhysicalKey::Code(KeyCode::AltLeft)),
90            "altgraph" => (Key::Named(AltGraph), PhysicalKey::Code(KeyCode::AltRight)),
91            "capslock" => (Key::Named(CapsLock), PhysicalKey::Code(KeyCode::CapsLock)),
92            "control" => (Key::Named(Control), PhysicalKey::Code(KeyCode::ControlLeft)),
93            "fn" => (Key::Named(Fn), PhysicalKey::Code(KeyCode::Fn)),
94            "fnlock" => (Key::Named(FnLock), PhysicalKey::Code(KeyCode::FnLock)),
95            "meta" => (Key::Named(Meta), PhysicalKey::Code(KeyCode::Meta)),
96            "numlock" => (Key::Named(NumLock), PhysicalKey::Code(KeyCode::NumLock)),
97            "scrolllock" => (
98                Key::Named(ScrollLock),
99                PhysicalKey::Code(KeyCode::ScrollLock),
100            ),
101            "shift" => (Key::Named(Shift), PhysicalKey::Code(KeyCode::ShiftLeft)),
102            "symbol" => (Key::Named(Symbol), PhysicalKey::Code(KeyCode::Fn)),
103            "symbollock" => (Key::Named(SymbolLock), PhysicalKey::Code(KeyCode::Fn)),
104            "hyper" => (Key::Named(Hyper), PhysicalKey::Code(KeyCode::Hyper)),
105            "super" => (Key::Named(Super), PhysicalKey::Code(KeyCode::Meta)),
106            "enter" => (Key::Named(Enter), PhysicalKey::Code(KeyCode::Enter)),
107            "tab" => (Key::Named(Tab), PhysicalKey::Code(KeyCode::Tab)),
108            "arrowdown" => (Key::Named(ArrowDown), PhysicalKey::Code(KeyCode::ArrowDown)),
109            "arrowleft" => (Key::Named(ArrowLeft), PhysicalKey::Code(KeyCode::ArrowLeft)),
110            "arrowright" => (
111                Key::Named(ArrowRight),
112                PhysicalKey::Code(KeyCode::ArrowRight),
113            ),
114            "arrowup" => (Key::Named(ArrowUp), PhysicalKey::Code(KeyCode::ArrowUp)),
115            "end" => (Key::Named(End), PhysicalKey::Code(KeyCode::End)),
116            "home" => (Key::Named(Home), PhysicalKey::Code(KeyCode::Home)),
117            "pagedown" => (Key::Named(PageDown), PhysicalKey::Code(KeyCode::PageDown)),
118            "pageup" => (Key::Named(PageUp), PhysicalKey::Code(KeyCode::PageUp)),
119            "backspace" => (Key::Named(Backspace), PhysicalKey::Code(KeyCode::Backspace)),
120            "clear" => (Key::Named(Clear), PhysicalKey::Code(KeyCode::Fn)),
121            "copy" => (Key::Named(Copy), PhysicalKey::Code(KeyCode::Copy)),
122            "crsel" => (Key::Named(CrSel), PhysicalKey::Code(KeyCode::Fn)),
123            "cut" => (Key::Named(Cut), PhysicalKey::Code(KeyCode::Cut)),
124            "delete" => (Key::Named(Delete), PhysicalKey::Code(KeyCode::Delete)),
125            "eraseeof" => (Key::Named(EraseEof), PhysicalKey::Code(KeyCode::Fn)),
126            "exsel" => (Key::Named(ExSel), PhysicalKey::Code(KeyCode::Fn)),
127            "insert" => (Key::Named(Insert), PhysicalKey::Code(KeyCode::Insert)),
128            "paste" => (Key::Named(Paste), PhysicalKey::Code(KeyCode::Paste)),
129            "redo" => (Key::Named(Redo), PhysicalKey::Code(KeyCode::Fn)),
130            "undo" => (Key::Named(Undo), PhysicalKey::Code(KeyCode::Undo)),
131            "accept" => (Key::Named(Accept), PhysicalKey::Code(KeyCode::Fn)),
132            "again" => (Key::Named(Again), PhysicalKey::Code(KeyCode::Again)),
133            "attn" => (Key::Named(Attn), PhysicalKey::Code(KeyCode::Fn)),
134            "cancel" => (Key::Named(Cancel), PhysicalKey::Code(KeyCode::Fn)),
135            "contextmenu" => (
136                Key::Named(ContextMenu),
137                PhysicalKey::Code(KeyCode::ContextMenu),
138            ),
139            "escape" => (Key::Named(Escape), PhysicalKey::Code(KeyCode::Escape)),
140            "execute" => (Key::Named(Execute), PhysicalKey::Code(KeyCode::Fn)),
141            "find" => (Key::Named(Find), PhysicalKey::Code(KeyCode::Find)),
142            "help" => (Key::Named(Help), PhysicalKey::Code(KeyCode::Help)),
143            "pause" => (Key::Named(Pause), PhysicalKey::Code(KeyCode::Pause)),
144            "play" => (Key::Named(Play), PhysicalKey::Code(KeyCode::MediaPlayPause)),
145            "props" => (Key::Named(Props), PhysicalKey::Code(KeyCode::Props)),
146            "select" => (Key::Named(Select), PhysicalKey::Code(KeyCode::Select)),
147            "zoomin" => (Key::Named(ZoomIn), PhysicalKey::Code(KeyCode::Fn)),
148            "zoomout" => (Key::Named(ZoomOut), PhysicalKey::Code(KeyCode::Fn)),
149            "brightnessdown" => (Key::Named(BrightnessDown), PhysicalKey::Code(KeyCode::Fn)),
150            "brightnessup" => (Key::Named(BrightnessUp), PhysicalKey::Code(KeyCode::Fn)),
151            "eject" => (Key::Named(Eject), PhysicalKey::Code(KeyCode::Eject)),
152            "logoff" => (Key::Named(LogOff), PhysicalKey::Code(KeyCode::Fn)),
153            "power" => (Key::Named(Power), PhysicalKey::Code(KeyCode::Power)),
154            "poweroff" => (Key::Named(PowerOff), PhysicalKey::Code(KeyCode::Fn)),
155            "printscreen" => (
156                Key::Named(PrintScreen),
157                PhysicalKey::Code(KeyCode::PrintScreen),
158            ),
159            "hibernate" => (Key::Named(Hibernate), PhysicalKey::Code(KeyCode::Fn)),
160            "standby" => (Key::Named(Standby), PhysicalKey::Code(KeyCode::Fn)),
161            "wakeup" => (Key::Named(WakeUp), PhysicalKey::Code(KeyCode::WakeUp)),
162            "allcandidates" => (Key::Named(AllCandidates), PhysicalKey::Code(KeyCode::Fn)),
163            "alphanumeric" => (Key::Named(Alphanumeric), PhysicalKey::Code(KeyCode::Fn)),
164            "codeinput" => (Key::Named(CodeInput), PhysicalKey::Code(KeyCode::Fn)),
165            "compose" => (Key::Named(Compose), PhysicalKey::Code(KeyCode::Fn)),
166            "convert" => (Key::Named(Convert), PhysicalKey::Code(KeyCode::Convert)),
167            "dead" => (Key::Dead(None), PhysicalKey::Code(KeyCode::Fn)),
168            "finalmode" => (Key::Named(FinalMode), PhysicalKey::Code(KeyCode::Fn)),
169            "groupfirst" => (Key::Named(GroupFirst), PhysicalKey::Code(KeyCode::Fn)),
170            "grouplast" => (Key::Named(GroupLast), PhysicalKey::Code(KeyCode::Fn)),
171            "groupnext" => (Key::Named(GroupNext), PhysicalKey::Code(KeyCode::Fn)),
172            "groupprevious" => (Key::Named(GroupPrevious), PhysicalKey::Code(KeyCode::Fn)),
173            "modechange" => (Key::Named(ModeChange), PhysicalKey::Code(KeyCode::Fn)),
174            "nextcandidate" => (Key::Named(NextCandidate), PhysicalKey::Code(KeyCode::Fn)),
175            "nonconvert" => (
176                Key::Named(NonConvert),
177                PhysicalKey::Code(KeyCode::NonConvert),
178            ),
179            "previouscandidate" => (
180                Key::Named(PreviousCandidate),
181                PhysicalKey::Code(KeyCode::Fn),
182            ),
183            "process" => (Key::Named(Process), PhysicalKey::Code(KeyCode::Fn)),
184            "singlecandidate" => (Key::Named(SingleCandidate), PhysicalKey::Code(KeyCode::Fn)),
185            "hangulmode" => (Key::Named(HangulMode), PhysicalKey::Code(KeyCode::Fn)),
186            "hanjamode" => (Key::Named(HanjaMode), PhysicalKey::Code(KeyCode::Fn)),
187            "junjamode" => (Key::Named(JunjaMode), PhysicalKey::Code(KeyCode::Fn)),
188            "eisu" => (Key::Named(Eisu), PhysicalKey::Code(KeyCode::Fn)),
189            "hankaku" => (Key::Named(Hankaku), PhysicalKey::Code(KeyCode::Fn)),
190            "hiragana" => (Key::Named(Hiragana), PhysicalKey::Code(KeyCode::Hiragana)),
191            "hiraganakatakana" => (Key::Named(HiraganaKatakana), PhysicalKey::Code(KeyCode::Fn)),
192            "kanamode" => (Key::Named(KanaMode), PhysicalKey::Code(KeyCode::KanaMode)),
193            "kanjimode" => (Key::Named(KanjiMode), PhysicalKey::Code(KeyCode::Fn)),
194            "katakana" => (Key::Named(Katakana), PhysicalKey::Code(KeyCode::Katakana)),
195            "romaji" => (Key::Named(Romaji), PhysicalKey::Code(KeyCode::Fn)),
196            "zenkaku" => (Key::Named(Zenkaku), PhysicalKey::Code(KeyCode::Fn)),
197            "zenkakuhankaku" => (Key::Named(ZenkakuHankaku), PhysicalKey::Code(KeyCode::Fn)),
198            "f1" => (Key::Named(F1), PhysicalKey::Code(KeyCode::F1)),
199            "f2" => (Key::Named(F2), PhysicalKey::Code(KeyCode::F2)),
200            "f3" => (Key::Named(F3), PhysicalKey::Code(KeyCode::F3)),
201            "f4" => (Key::Named(F4), PhysicalKey::Code(KeyCode::F4)),
202            "f5" => (Key::Named(F5), PhysicalKey::Code(KeyCode::F5)),
203            "f6" => (Key::Named(F6), PhysicalKey::Code(KeyCode::F6)),
204            "f7" => (Key::Named(F7), PhysicalKey::Code(KeyCode::F7)),
205            "f8" => (Key::Named(F8), PhysicalKey::Code(KeyCode::F8)),
206            "f9" => (Key::Named(F9), PhysicalKey::Code(KeyCode::F9)),
207            "f10" => (Key::Named(F10), PhysicalKey::Code(KeyCode::F10)),
208            "f11" => (Key::Named(F11), PhysicalKey::Code(KeyCode::F11)),
209            "f12" => (Key::Named(F12), PhysicalKey::Code(KeyCode::F12)),
210            "soft1" => (Key::Named(Soft1), PhysicalKey::Code(KeyCode::Fn)),
211            "soft2" => (Key::Named(Soft2), PhysicalKey::Code(KeyCode::Fn)),
212            "soft3" => (Key::Named(Soft3), PhysicalKey::Code(KeyCode::Fn)),
213            "soft4" => (Key::Named(Soft4), PhysicalKey::Code(KeyCode::Fn)),
214            "channeldown" => (Key::Named(ChannelDown), PhysicalKey::Code(KeyCode::Fn)),
215            "channelup" => (Key::Named(ChannelUp), PhysicalKey::Code(KeyCode::Fn)),
216            "close" => (Key::Named(Close), PhysicalKey::Code(KeyCode::Fn)),
217            "mailforward" => (Key::Named(MailForward), PhysicalKey::Code(KeyCode::Fn)),
218            "mailreply" => (Key::Named(MailReply), PhysicalKey::Code(KeyCode::Fn)),
219            "mailsend" => (Key::Named(MailSend), PhysicalKey::Code(KeyCode::Fn)),
220            "mediaclose" => (Key::Named(MediaClose), PhysicalKey::Code(KeyCode::Fn)),
221            "mediafastforward" => (Key::Named(MediaFastForward), PhysicalKey::Code(KeyCode::Fn)),
222            "mediapause" => (Key::Named(MediaPause), PhysicalKey::Code(KeyCode::Fn)),
223            "mediaplay" => (Key::Named(MediaPlay), PhysicalKey::Code(KeyCode::Fn)),
224            "mediaplaypause" => (
225                Key::Named(MediaPlayPause),
226                PhysicalKey::Code(KeyCode::MediaPlayPause),
227            ),
228            "mediarecord" => (Key::Named(MediaRecord), PhysicalKey::Code(KeyCode::Fn)),
229            "mediarewind" => (Key::Named(MediaRewind), PhysicalKey::Code(KeyCode::Fn)),
230            "mediastop" => (Key::Named(MediaStop), PhysicalKey::Code(KeyCode::MediaStop)),
231            "mediatracknext" => (
232                Key::Named(MediaTrackNext),
233                PhysicalKey::Code(KeyCode::MediaTrackNext),
234            ),
235            "mediatrackprevious" => (
236                Key::Named(MediaTrackPrevious),
237                PhysicalKey::Code(KeyCode::MediaTrackPrevious),
238            ),
239            "new" => (Key::Named(New), PhysicalKey::Code(KeyCode::Fn)),
240            "open" => (Key::Named(Open), PhysicalKey::Code(KeyCode::Open)),
241            "print" => (Key::Named(Print), PhysicalKey::Code(KeyCode::Fn)),
242            "save" => (Key::Named(Save), PhysicalKey::Code(KeyCode::Fn)),
243            "spellcheck" => (Key::Named(SpellCheck), PhysicalKey::Code(KeyCode::Fn)),
244            "key11" => (Key::Named(Key11), PhysicalKey::Code(KeyCode::Fn)),
245            "key12" => (Key::Named(Key12), PhysicalKey::Code(KeyCode::Fn)),
246            "audiobalanceleft" => (Key::Named(AudioBalanceLeft), PhysicalKey::Code(KeyCode::Fn)),
247            "audiobalanceright" => (
248                Key::Named(AudioBalanceRight),
249                PhysicalKey::Code(KeyCode::Fn),
250            ),
251            "audiobassboostdown" => (
252                Key::Named(AudioBassBoostDown),
253                PhysicalKey::Code(KeyCode::Fn),
254            ),
255            "audiobassboosttoggle" => (
256                Key::Named(AudioBassBoostToggle),
257                PhysicalKey::Code(KeyCode::Fn),
258            ),
259            "audiobassboostup" => (Key::Named(AudioBassBoostUp), PhysicalKey::Code(KeyCode::Fn)),
260            "audiofaderfront" => (Key::Named(AudioFaderFront), PhysicalKey::Code(KeyCode::Fn)),
261            "audiofaderrear" => (Key::Named(AudioFaderRear), PhysicalKey::Code(KeyCode::Fn)),
262            "audiosurroundmodenext" => (
263                Key::Named(AudioSurroundModeNext),
264                PhysicalKey::Code(KeyCode::Fn),
265            ),
266            "audiotrebledown" => (Key::Named(AudioTrebleDown), PhysicalKey::Code(KeyCode::Fn)),
267            "audiotrebleup" => (Key::Named(AudioTrebleUp), PhysicalKey::Code(KeyCode::Fn)),
268            "audiovolumedown" => (
269                Key::Named(AudioVolumeDown),
270                PhysicalKey::Code(KeyCode::AudioVolumeDown),
271            ),
272            "audiovolumeup" => (
273                Key::Named(AudioVolumeUp),
274                PhysicalKey::Code(KeyCode::AudioVolumeUp),
275            ),
276            "audiovolumemute" => (
277                Key::Named(AudioVolumeMute),
278                PhysicalKey::Code(KeyCode::AudioVolumeMute),
279            ),
280            "microphonetoggle" => (Key::Named(MicrophoneToggle), PhysicalKey::Code(KeyCode::Fn)),
281            "microphonevolumedown" => (
282                Key::Named(MicrophoneVolumeDown),
283                PhysicalKey::Code(KeyCode::Fn),
284            ),
285            "microphonevolumeup" => (
286                Key::Named(MicrophoneVolumeUp),
287                PhysicalKey::Code(KeyCode::Fn),
288            ),
289            "microphonevolumemute" => (
290                Key::Named(MicrophoneVolumeMute),
291                PhysicalKey::Code(KeyCode::Fn),
292            ),
293            "speechcorrectionlist" => (
294                Key::Named(SpeechCorrectionList),
295                PhysicalKey::Code(KeyCode::Fn),
296            ),
297            "speechinputtoggle" => (
298                Key::Named(SpeechInputToggle),
299                PhysicalKey::Code(KeyCode::Fn),
300            ),
301            "launchapplication1" => (
302                Key::Named(LaunchApplication1),
303                PhysicalKey::Code(KeyCode::Fn),
304            ),
305            "launchapplication2" => (
306                Key::Named(LaunchApplication2),
307                PhysicalKey::Code(KeyCode::Fn),
308            ),
309            "launchcalendar" => (Key::Named(LaunchCalendar), PhysicalKey::Code(KeyCode::Fn)),
310            "launchcontacts" => (Key::Named(LaunchContacts), PhysicalKey::Code(KeyCode::Fn)),
311            "launchmail" => (
312                Key::Named(LaunchMail),
313                PhysicalKey::Code(KeyCode::LaunchMail),
314            ),
315            "launchmediaplayer" => (
316                Key::Named(LaunchMediaPlayer),
317                PhysicalKey::Code(KeyCode::Fn),
318            ),
319            "launchmusicplayer" => (
320                Key::Named(LaunchMusicPlayer),
321                PhysicalKey::Code(KeyCode::Fn),
322            ),
323            "launchphone" => (Key::Named(LaunchPhone), PhysicalKey::Code(KeyCode::Fn)),
324            "launchscreensaver" => (
325                Key::Named(LaunchScreenSaver),
326                PhysicalKey::Code(KeyCode::Fn),
327            ),
328            "launchspreadsheet" => (
329                Key::Named(LaunchSpreadsheet),
330                PhysicalKey::Code(KeyCode::Fn),
331            ),
332            "launchwebbrowser" => (Key::Named(LaunchWebBrowser), PhysicalKey::Code(KeyCode::Fn)),
333            "launchwebcam" => (Key::Named(LaunchWebCam), PhysicalKey::Code(KeyCode::Fn)),
334            "launchwordprocessor" => (
335                Key::Named(LaunchWordProcessor),
336                PhysicalKey::Code(KeyCode::Fn),
337            ),
338            "browserback" => (
339                Key::Named(BrowserBack),
340                PhysicalKey::Code(KeyCode::BrowserBack),
341            ),
342            "browserfavorites" => (
343                Key::Named(BrowserFavorites),
344                PhysicalKey::Code(KeyCode::BrowserFavorites),
345            ),
346            "browserforward" => (
347                Key::Named(BrowserForward),
348                PhysicalKey::Code(KeyCode::BrowserForward),
349            ),
350            "browserhome" => (
351                Key::Named(BrowserHome),
352                PhysicalKey::Code(KeyCode::BrowserHome),
353            ),
354            "browserrefresh" => (
355                Key::Named(BrowserRefresh),
356                PhysicalKey::Code(KeyCode::BrowserRefresh),
357            ),
358            "browsersearch" => (
359                Key::Named(BrowserSearch),
360                PhysicalKey::Code(KeyCode::BrowserSearch),
361            ),
362            "browserstop" => (
363                Key::Named(BrowserStop),
364                PhysicalKey::Code(KeyCode::BrowserStop),
365            ),
366            "appswitch" => (Key::Named(AppSwitch), PhysicalKey::Code(KeyCode::Fn)),
367            "call" => (Key::Named(Call), PhysicalKey::Code(KeyCode::Fn)),
368            "camera" => (Key::Named(Camera), PhysicalKey::Code(KeyCode::Fn)),
369            "camerafocus" => (Key::Named(CameraFocus), PhysicalKey::Code(KeyCode::Fn)),
370            "endcall" => (Key::Named(EndCall), PhysicalKey::Code(KeyCode::Fn)),
371            "goback" => (Key::Named(GoBack), PhysicalKey::Code(KeyCode::Fn)),
372            "gohome" => (Key::Named(GoHome), PhysicalKey::Code(KeyCode::Fn)),
373            "headsethook" => (Key::Named(HeadsetHook), PhysicalKey::Code(KeyCode::Fn)),
374            "lastnumberredial" => (Key::Named(LastNumberRedial), PhysicalKey::Code(KeyCode::Fn)),
375            "notification" => (Key::Named(Notification), PhysicalKey::Code(KeyCode::Fn)),
376            "mannermode" => (Key::Named(MannerMode), PhysicalKey::Code(KeyCode::Fn)),
377            "voicedial" => (Key::Named(VoiceDial), PhysicalKey::Code(KeyCode::Fn)),
378            "tv" => (Key::Named(TV), PhysicalKey::Code(KeyCode::Fn)),
379            "tv3dmode" => (Key::Named(TV3DMode), PhysicalKey::Code(KeyCode::Fn)),
380            "tvantennacable" => (Key::Named(TVAntennaCable), PhysicalKey::Code(KeyCode::Fn)),
381            "tvaudiodescription" => (
382                Key::Named(TVAudioDescription),
383                PhysicalKey::Code(KeyCode::Fn),
384            ),
385            "tvaudiodescriptionmixdown" => (
386                Key::Named(TVAudioDescriptionMixDown),
387                PhysicalKey::Code(KeyCode::Fn),
388            ),
389            "tvaudiodescriptionmixup" => (
390                Key::Named(TVAudioDescriptionMixUp),
391                PhysicalKey::Code(KeyCode::Fn),
392            ),
393            "tvcontentsmenu" => (Key::Named(TVContentsMenu), PhysicalKey::Code(KeyCode::Fn)),
394            "tvdataservice" => (Key::Named(TVDataService), PhysicalKey::Code(KeyCode::Fn)),
395            "tvinput" => (Key::Named(TVInput), PhysicalKey::Code(KeyCode::Fn)),
396            "tvinputcomponent1" => (
397                Key::Named(TVInputComponent1),
398                PhysicalKey::Code(KeyCode::Fn),
399            ),
400            "tvinputcomponent2" => (
401                Key::Named(TVInputComponent2),
402                PhysicalKey::Code(KeyCode::Fn),
403            ),
404            "tvinputcomposite1" => (
405                Key::Named(TVInputComposite1),
406                PhysicalKey::Code(KeyCode::Fn),
407            ),
408            "tvinputcomposite2" => (
409                Key::Named(TVInputComposite2),
410                PhysicalKey::Code(KeyCode::Fn),
411            ),
412            "tvinputhdmi1" => (Key::Named(TVInputHDMI1), PhysicalKey::Code(KeyCode::Fn)),
413            "tvinputhdmi2" => (Key::Named(TVInputHDMI2), PhysicalKey::Code(KeyCode::Fn)),
414            "tvinputhdmi3" => (Key::Named(TVInputHDMI3), PhysicalKey::Code(KeyCode::Fn)),
415            "tvinputhdmi4" => (Key::Named(TVInputHDMI4), PhysicalKey::Code(KeyCode::Fn)),
416            "tvinputvga1" => (Key::Named(TVInputVGA1), PhysicalKey::Code(KeyCode::Fn)),
417            "tvmediacontext" => (Key::Named(TVMediaContext), PhysicalKey::Code(KeyCode::Fn)),
418            "tvnetwork" => (Key::Named(TVNetwork), PhysicalKey::Code(KeyCode::Fn)),
419            "tvnumberentry" => (Key::Named(TVNumberEntry), PhysicalKey::Code(KeyCode::Fn)),
420            "tvpower" => (Key::Named(TVPower), PhysicalKey::Code(KeyCode::Fn)),
421            "tvradioservice" => (Key::Named(TVRadioService), PhysicalKey::Code(KeyCode::Fn)),
422            "tvsatellite" => (Key::Named(TVSatellite), PhysicalKey::Code(KeyCode::Fn)),
423            "tvsatellitebs" => (Key::Named(TVSatelliteBS), PhysicalKey::Code(KeyCode::Fn)),
424            "tvsatellitecs" => (Key::Named(TVSatelliteCS), PhysicalKey::Code(KeyCode::Fn)),
425            "tvsatellitetoggle" => (
426                Key::Named(TVSatelliteToggle),
427                PhysicalKey::Code(KeyCode::Fn),
428            ),
429            "tvterrestrialanalog" => (
430                Key::Named(TVTerrestrialAnalog),
431                PhysicalKey::Code(KeyCode::Fn),
432            ),
433            "tvterrestrialdigital" => (
434                Key::Named(TVTerrestrialDigital),
435                PhysicalKey::Code(KeyCode::Fn),
436            ),
437            "tvtimer" => (Key::Named(TVTimer), PhysicalKey::Code(KeyCode::Fn)),
438            "avrinput" => (Key::Named(AVRInput), PhysicalKey::Code(KeyCode::Fn)),
439            "avrpower" => (Key::Named(AVRPower), PhysicalKey::Code(KeyCode::Fn)),
440            "colorf0red" => (Key::Named(ColorF0Red), PhysicalKey::Code(KeyCode::Fn)),
441            "colorf1green" => (Key::Named(ColorF1Green), PhysicalKey::Code(KeyCode::Fn)),
442            "colorf2yellow" => (Key::Named(ColorF2Yellow), PhysicalKey::Code(KeyCode::Fn)),
443            "colorf3blue" => (Key::Named(ColorF3Blue), PhysicalKey::Code(KeyCode::Fn)),
444            "colorf4grey" => (Key::Named(ColorF4Grey), PhysicalKey::Code(KeyCode::Fn)),
445            "colorf5brown" => (Key::Named(ColorF5Brown), PhysicalKey::Code(KeyCode::Fn)),
446            "closedcaptiontoggle" => (
447                Key::Named(ClosedCaptionToggle),
448                PhysicalKey::Code(KeyCode::Fn),
449            ),
450            "dimmer" => (Key::Named(Dimmer), PhysicalKey::Code(KeyCode::Fn)),
451            "displayswap" => (Key::Named(DisplaySwap), PhysicalKey::Code(KeyCode::Fn)),
452            "dvr" => (Key::Named(DVR), PhysicalKey::Code(KeyCode::Fn)),
453            "exit" => (Key::Named(Exit), PhysicalKey::Code(KeyCode::Fn)),
454            "favoriteclear0" => (Key::Named(FavoriteClear0), PhysicalKey::Code(KeyCode::Fn)),
455            "favoriteclear1" => (Key::Named(FavoriteClear1), PhysicalKey::Code(KeyCode::Fn)),
456            "favoriteclear2" => (Key::Named(FavoriteClear2), PhysicalKey::Code(KeyCode::Fn)),
457            "favoriteclear3" => (Key::Named(FavoriteClear3), PhysicalKey::Code(KeyCode::Fn)),
458            "favoriterecall0" => (Key::Named(FavoriteRecall0), PhysicalKey::Code(KeyCode::Fn)),
459            "favoriterecall1" => (Key::Named(FavoriteRecall1), PhysicalKey::Code(KeyCode::Fn)),
460            "favoriterecall2" => (Key::Named(FavoriteRecall2), PhysicalKey::Code(KeyCode::Fn)),
461            "favoriterecall3" => (Key::Named(FavoriteRecall3), PhysicalKey::Code(KeyCode::Fn)),
462            "favoritestore0" => (Key::Named(FavoriteStore0), PhysicalKey::Code(KeyCode::Fn)),
463            "favoritestore1" => (Key::Named(FavoriteStore1), PhysicalKey::Code(KeyCode::Fn)),
464            "favoritestore2" => (Key::Named(FavoriteStore2), PhysicalKey::Code(KeyCode::Fn)),
465            "favoritestore3" => (Key::Named(FavoriteStore3), PhysicalKey::Code(KeyCode::Fn)),
466            "guide" => (Key::Named(Guide), PhysicalKey::Code(KeyCode::Fn)),
467            "guidenextday" => (Key::Named(GuideNextDay), PhysicalKey::Code(KeyCode::Fn)),
468            "guidepreviousday" => (Key::Named(GuidePreviousDay), PhysicalKey::Code(KeyCode::Fn)),
469            "info" => (Key::Named(Info), PhysicalKey::Code(KeyCode::Fn)),
470            "instantreplay" => (Key::Named(InstantReplay), PhysicalKey::Code(KeyCode::Fn)),
471            "link" => (Key::Named(Link), PhysicalKey::Code(KeyCode::Fn)),
472            "listprogram" => (Key::Named(ListProgram), PhysicalKey::Code(KeyCode::Fn)),
473            "livecontent" => (Key::Named(LiveContent), PhysicalKey::Code(KeyCode::Fn)),
474            "lock" => (Key::Named(Lock), PhysicalKey::Code(KeyCode::Fn)),
475            "mediaapps" => (Key::Named(MediaApps), PhysicalKey::Code(KeyCode::Fn)),
476            "mediaaudiotrack" => (Key::Named(MediaAudioTrack), PhysicalKey::Code(KeyCode::Fn)),
477            "medialast" => (Key::Named(MediaLast), PhysicalKey::Code(KeyCode::Fn)),
478            "mediaskipbackward" => (
479                Key::Named(MediaSkipBackward),
480                PhysicalKey::Code(KeyCode::Fn),
481            ),
482            "mediaskipforward" => (Key::Named(MediaSkipForward), PhysicalKey::Code(KeyCode::Fn)),
483            "mediastepbackward" => (
484                Key::Named(MediaStepBackward),
485                PhysicalKey::Code(KeyCode::Fn),
486            ),
487            "mediastepforward" => (Key::Named(MediaStepForward), PhysicalKey::Code(KeyCode::Fn)),
488            "mediatopmenu" => (Key::Named(MediaTopMenu), PhysicalKey::Code(KeyCode::Fn)),
489            "navigatein" => (Key::Named(NavigateIn), PhysicalKey::Code(KeyCode::Fn)),
490            "navigatenext" => (Key::Named(NavigateNext), PhysicalKey::Code(KeyCode::Fn)),
491            "navigateout" => (Key::Named(NavigateOut), PhysicalKey::Code(KeyCode::Fn)),
492            "navigateprevious" => (Key::Named(NavigatePrevious), PhysicalKey::Code(KeyCode::Fn)),
493            "nextfavoritechannel" => (
494                Key::Named(NextFavoriteChannel),
495                PhysicalKey::Code(KeyCode::Fn),
496            ),
497            "nextuserprofile" => (Key::Named(NextUserProfile), PhysicalKey::Code(KeyCode::Fn)),
498            "ondemand" => (Key::Named(OnDemand), PhysicalKey::Code(KeyCode::Fn)),
499            "pairing" => (Key::Named(Pairing), PhysicalKey::Code(KeyCode::Fn)),
500            "pinpdown" => (Key::Named(PinPDown), PhysicalKey::Code(KeyCode::Fn)),
501            "pinpmove" => (Key::Named(PinPMove), PhysicalKey::Code(KeyCode::Fn)),
502            "pinptoggle" => (Key::Named(PinPToggle), PhysicalKey::Code(KeyCode::Fn)),
503            "pinpup" => (Key::Named(PinPUp), PhysicalKey::Code(KeyCode::Fn)),
504            "playspeeddown" => (Key::Named(PlaySpeedDown), PhysicalKey::Code(KeyCode::Fn)),
505            "playspeedreset" => (Key::Named(PlaySpeedReset), PhysicalKey::Code(KeyCode::Fn)),
506            "playspeedup" => (Key::Named(PlaySpeedUp), PhysicalKey::Code(KeyCode::Fn)),
507            "randomtoggle" => (Key::Named(RandomToggle), PhysicalKey::Code(KeyCode::Fn)),
508            "rclowbattery" => (Key::Named(RcLowBattery), PhysicalKey::Code(KeyCode::Fn)),
509            "recordspeednext" => (Key::Named(RecordSpeedNext), PhysicalKey::Code(KeyCode::Fn)),
510            "rfbypass" => (Key::Named(RfBypass), PhysicalKey::Code(KeyCode::Fn)),
511            "scanchannelstoggle" => (
512                Key::Named(ScanChannelsToggle),
513                PhysicalKey::Code(KeyCode::Fn),
514            ),
515            "screenmodenext" => (Key::Named(ScreenModeNext), PhysicalKey::Code(KeyCode::Fn)),
516            "settings" => (Key::Named(Settings), PhysicalKey::Code(KeyCode::Fn)),
517            "splitscreentoggle" => (
518                Key::Named(SplitScreenToggle),
519                PhysicalKey::Code(KeyCode::Fn),
520            ),
521            "stbinput" => (Key::Named(STBInput), PhysicalKey::Code(KeyCode::Fn)),
522            "stbpower" => (Key::Named(STBPower), PhysicalKey::Code(KeyCode::Fn)),
523            "subtitle" => (Key::Named(Subtitle), PhysicalKey::Code(KeyCode::Fn)),
524            "teletext" => (Key::Named(Teletext), PhysicalKey::Code(KeyCode::Fn)),
525            "videomodenext" => (Key::Named(VideoModeNext), PhysicalKey::Code(KeyCode::Fn)),
526            "wink" => (Key::Named(Wink), PhysicalKey::Code(KeyCode::Fn)),
527            "zoomtoggle" => (Key::Named(ZoomToggle), PhysicalKey::Code(KeyCode::Fn)),
528
529            // Custom key name mappings
530            "esc" => (Key::Named(Escape), PhysicalKey::Code(KeyCode::Escape)),
531            "space" => (Key::Named(Space), PhysicalKey::Code(KeyCode::Space)),
532            "bs" => (Key::Named(Backspace), PhysicalKey::Code(KeyCode::Backspace)),
533            "up" => (Key::Named(ArrowUp), PhysicalKey::Code(KeyCode::ArrowUp)),
534            "down" => (Key::Named(ArrowDown), PhysicalKey::Code(KeyCode::ArrowDown)),
535            "right" => (
536                Key::Named(ArrowRight),
537                PhysicalKey::Code(KeyCode::ArrowRight),
538            ),
539            "left" => (Key::Named(ArrowLeft), PhysicalKey::Code(KeyCode::ArrowLeft)),
540            "del" => (Key::Named(Delete), PhysicalKey::Code(KeyCode::Delete)),
541
542            _ => return None,
543        })
544    }
545
546    fn mouse_from_str(s: &str) -> Option<crate::pointer::PointerButton> {
547        use crate::pointer::PointerButton as B;
548
549        Some(match s {
550            "mousemiddle" => B::Auxiliary,
551            "mouseforward" => B::X2,
552            "mousebackward" => B::X1,
553            _ => return None,
554        })
555    }
556}
557
558impl Display for KeyInput {
559    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
560        use crate::pointer::PointerButton as B;
561
562        match self {
563            Self::Keyboard(_key, key_code) => match key_code {
564                PhysicalKey::Unidentified(_) => f.write_str("Unidentified"),
565                PhysicalKey::Code(KeyCode::Backquote) => f.write_str("`"),
566                PhysicalKey::Code(KeyCode::Backslash) => f.write_str("\\"),
567                PhysicalKey::Code(KeyCode::BracketLeft) => f.write_str("["),
568                PhysicalKey::Code(KeyCode::BracketRight) => f.write_str("]"),
569                PhysicalKey::Code(KeyCode::Comma) => f.write_str(","),
570                PhysicalKey::Code(KeyCode::Digit0) => f.write_str("0"),
571                PhysicalKey::Code(KeyCode::Digit1) => f.write_str("1"),
572                PhysicalKey::Code(KeyCode::Digit2) => f.write_str("2"),
573                PhysicalKey::Code(KeyCode::Digit3) => f.write_str("3"),
574                PhysicalKey::Code(KeyCode::Digit4) => f.write_str("4"),
575                PhysicalKey::Code(KeyCode::Digit5) => f.write_str("5"),
576                PhysicalKey::Code(KeyCode::Digit6) => f.write_str("6"),
577                PhysicalKey::Code(KeyCode::Digit7) => f.write_str("7"),
578                PhysicalKey::Code(KeyCode::Digit8) => f.write_str("8"),
579                PhysicalKey::Code(KeyCode::Digit9) => f.write_str("9"),
580                PhysicalKey::Code(KeyCode::Equal) => f.write_str("="),
581                PhysicalKey::Code(KeyCode::IntlBackslash) => f.write_str("<"),
582                PhysicalKey::Code(KeyCode::IntlRo) => f.write_str("IntlRo"),
583                PhysicalKey::Code(KeyCode::IntlYen) => f.write_str("IntlYen"),
584                PhysicalKey::Code(KeyCode::KeyA) => f.write_str("A"),
585                PhysicalKey::Code(KeyCode::KeyB) => f.write_str("B"),
586                PhysicalKey::Code(KeyCode::KeyC) => f.write_str("C"),
587                PhysicalKey::Code(KeyCode::KeyD) => f.write_str("D"),
588                PhysicalKey::Code(KeyCode::KeyE) => f.write_str("E"),
589                PhysicalKey::Code(KeyCode::KeyF) => f.write_str("F"),
590                PhysicalKey::Code(KeyCode::KeyG) => f.write_str("G"),
591                PhysicalKey::Code(KeyCode::KeyH) => f.write_str("H"),
592                PhysicalKey::Code(KeyCode::KeyI) => f.write_str("I"),
593                PhysicalKey::Code(KeyCode::KeyJ) => f.write_str("J"),
594                PhysicalKey::Code(KeyCode::KeyK) => f.write_str("K"),
595                PhysicalKey::Code(KeyCode::KeyL) => f.write_str("L"),
596                PhysicalKey::Code(KeyCode::KeyM) => f.write_str("M"),
597                PhysicalKey::Code(KeyCode::KeyN) => f.write_str("N"),
598                PhysicalKey::Code(KeyCode::KeyO) => f.write_str("O"),
599                PhysicalKey::Code(KeyCode::KeyP) => f.write_str("P"),
600                PhysicalKey::Code(KeyCode::KeyQ) => f.write_str("Q"),
601                PhysicalKey::Code(KeyCode::KeyR) => f.write_str("R"),
602                PhysicalKey::Code(KeyCode::KeyS) => f.write_str("S"),
603                PhysicalKey::Code(KeyCode::KeyT) => f.write_str("T"),
604                PhysicalKey::Code(KeyCode::KeyU) => f.write_str("U"),
605                PhysicalKey::Code(KeyCode::KeyV) => f.write_str("V"),
606                PhysicalKey::Code(KeyCode::KeyW) => f.write_str("W"),
607                PhysicalKey::Code(KeyCode::KeyX) => f.write_str("X"),
608                PhysicalKey::Code(KeyCode::KeyY) => f.write_str("Y"),
609                PhysicalKey::Code(KeyCode::KeyZ) => f.write_str("Z"),
610                PhysicalKey::Code(KeyCode::Minus) => f.write_str("-"),
611                PhysicalKey::Code(KeyCode::Period) => f.write_str("."),
612                PhysicalKey::Code(KeyCode::Quote) => f.write_str("'"),
613                PhysicalKey::Code(KeyCode::Semicolon) => f.write_str(";"),
614                PhysicalKey::Code(KeyCode::Slash) => f.write_str("/"),
615                PhysicalKey::Code(KeyCode::AltLeft) => f.write_str("Alt"),
616                PhysicalKey::Code(KeyCode::AltRight) => f.write_str("Alt"),
617                PhysicalKey::Code(KeyCode::Backspace) => f.write_str("backspace"),
618                PhysicalKey::Code(KeyCode::CapsLock) => f.write_str("CapsLock"),
619                PhysicalKey::Code(KeyCode::ContextMenu) => f.write_str("ContextMenu"),
620                PhysicalKey::Code(KeyCode::ControlLeft) => f.write_str("Ctrl"),
621                PhysicalKey::Code(KeyCode::ControlRight) => f.write_str("Ctrl"),
622                PhysicalKey::Code(KeyCode::Enter) => f.write_str("Enter"),
623                PhysicalKey::Code(KeyCode::SuperLeft) => match std::env::consts::OS {
624                    "macos" => f.write_str("Cmd"),
625                    "windows" => f.write_str("Win"),
626                    _ => f.write_str("Meta"),
627                },
628                PhysicalKey::Code(KeyCode::SuperRight) => match std::env::consts::OS {
629                    "macos" => f.write_str("Cmd"),
630                    "windows" => f.write_str("Win"),
631                    _ => f.write_str("Meta"),
632                },
633                PhysicalKey::Code(KeyCode::ShiftLeft) => f.write_str("Shift"),
634                PhysicalKey::Code(KeyCode::ShiftRight) => f.write_str("Shift"),
635                PhysicalKey::Code(KeyCode::Space) => f.write_str("Space"),
636                PhysicalKey::Code(KeyCode::Tab) => f.write_str("Tab"),
637                PhysicalKey::Code(KeyCode::Convert) => f.write_str("Convert"),
638                PhysicalKey::Code(KeyCode::KanaMode) => f.write_str("KanaMode"),
639                PhysicalKey::Code(KeyCode::Lang1) => f.write_str("Lang1"),
640                PhysicalKey::Code(KeyCode::Lang2) => f.write_str("Lang2"),
641                PhysicalKey::Code(KeyCode::Lang3) => f.write_str("Lang3"),
642                PhysicalKey::Code(KeyCode::Lang4) => f.write_str("Lang4"),
643                PhysicalKey::Code(KeyCode::Lang5) => f.write_str("Lang5"),
644                PhysicalKey::Code(KeyCode::NonConvert) => f.write_str("NonConvert"),
645                PhysicalKey::Code(KeyCode::Delete) => f.write_str("Delete"),
646                PhysicalKey::Code(KeyCode::End) => f.write_str("End"),
647                PhysicalKey::Code(KeyCode::Help) => f.write_str("Help"),
648                PhysicalKey::Code(KeyCode::Home) => f.write_str("Home"),
649                PhysicalKey::Code(KeyCode::Insert) => f.write_str("Insert"),
650                PhysicalKey::Code(KeyCode::PageDown) => f.write_str("PageDown"),
651                PhysicalKey::Code(KeyCode::PageUp) => f.write_str("PageUp"),
652                PhysicalKey::Code(KeyCode::ArrowDown) => f.write_str("Down"),
653                PhysicalKey::Code(KeyCode::ArrowLeft) => f.write_str("Left"),
654                PhysicalKey::Code(KeyCode::ArrowRight) => f.write_str("Right"),
655                PhysicalKey::Code(KeyCode::ArrowUp) => f.write_str("Up"),
656                PhysicalKey::Code(KeyCode::NumLock) => f.write_str("NumLock"),
657                PhysicalKey::Code(KeyCode::Numpad0) => f.write_str("Numpad0"),
658                PhysicalKey::Code(KeyCode::Numpad1) => f.write_str("Numpad1"),
659                PhysicalKey::Code(KeyCode::Numpad2) => f.write_str("Numpad2"),
660                PhysicalKey::Code(KeyCode::Numpad3) => f.write_str("Numpad3"),
661                PhysicalKey::Code(KeyCode::Numpad4) => f.write_str("Numpad4"),
662                PhysicalKey::Code(KeyCode::Numpad5) => f.write_str("Numpad5"),
663                PhysicalKey::Code(KeyCode::Numpad6) => f.write_str("Numpad6"),
664                PhysicalKey::Code(KeyCode::Numpad7) => f.write_str("Numpad7"),
665                PhysicalKey::Code(KeyCode::Numpad8) => f.write_str("Numpad8"),
666                PhysicalKey::Code(KeyCode::Numpad9) => f.write_str("Numpad9"),
667                PhysicalKey::Code(KeyCode::NumpadAdd) => f.write_str("NumpadAdd"),
668                PhysicalKey::Code(KeyCode::NumpadBackspace) => f.write_str("NumpadBackspace"),
669                PhysicalKey::Code(KeyCode::NumpadClear) => f.write_str("NumpadClear"),
670                PhysicalKey::Code(KeyCode::NumpadClearEntry) => f.write_str("NumpadClearEntry"),
671                PhysicalKey::Code(KeyCode::NumpadComma) => f.write_str("NumpadComma"),
672                PhysicalKey::Code(KeyCode::NumpadDecimal) => f.write_str("NumpadDecimal"),
673                PhysicalKey::Code(KeyCode::NumpadDivide) => f.write_str("NumpadDivide"),
674                PhysicalKey::Code(KeyCode::NumpadEnter) => f.write_str("NumpadEnter"),
675                PhysicalKey::Code(KeyCode::NumpadEqual) => f.write_str("NumpadEqual"),
676                PhysicalKey::Code(KeyCode::NumpadHash) => f.write_str("NumpadHash"),
677                PhysicalKey::Code(KeyCode::NumpadMemoryAdd) => f.write_str("NumpadMemoryAdd"),
678                PhysicalKey::Code(KeyCode::NumpadMemoryClear) => f.write_str("NumpadMemoryClear"),
679                PhysicalKey::Code(KeyCode::NumpadMemoryRecall) => f.write_str("NumpadMemoryRecall"),
680                PhysicalKey::Code(KeyCode::NumpadMemoryStore) => f.write_str("NumpadMemoryStore"),
681                PhysicalKey::Code(KeyCode::NumpadMemorySubtract) => {
682                    f.write_str("NumpadMemorySubtract")
683                }
684                PhysicalKey::Code(KeyCode::NumpadMultiply) => f.write_str("NumpadMultiply"),
685                PhysicalKey::Code(KeyCode::NumpadParenLeft) => f.write_str("NumpadParenLeft"),
686                PhysicalKey::Code(KeyCode::NumpadParenRight) => f.write_str("NumpadParenRight"),
687                PhysicalKey::Code(KeyCode::NumpadStar) => f.write_str("NumpadStar"),
688                PhysicalKey::Code(KeyCode::NumpadSubtract) => f.write_str("NumpadSubtract"),
689                PhysicalKey::Code(KeyCode::Escape) => f.write_str("Escape"),
690                PhysicalKey::Code(KeyCode::Fn) => f.write_str("Fn"),
691                PhysicalKey::Code(KeyCode::FnLock) => f.write_str("FnLock"),
692                PhysicalKey::Code(KeyCode::PrintScreen) => f.write_str("PrintScreen"),
693                PhysicalKey::Code(KeyCode::ScrollLock) => f.write_str("ScrollLock"),
694                PhysicalKey::Code(KeyCode::Pause) => f.write_str("Pause"),
695                PhysicalKey::Code(KeyCode::BrowserBack) => f.write_str("BrowserBack"),
696                PhysicalKey::Code(KeyCode::BrowserFavorites) => f.write_str("BrowserFavorites"),
697                PhysicalKey::Code(KeyCode::BrowserForward) => f.write_str("BrowserForward"),
698                PhysicalKey::Code(KeyCode::BrowserHome) => f.write_str("BrowserHome"),
699                PhysicalKey::Code(KeyCode::BrowserRefresh) => f.write_str("BrowserRefresh"),
700                PhysicalKey::Code(KeyCode::BrowserSearch) => f.write_str("BrowserSearch"),
701                PhysicalKey::Code(KeyCode::BrowserStop) => f.write_str("BrowserStop"),
702                PhysicalKey::Code(KeyCode::Eject) => f.write_str("Eject"),
703                PhysicalKey::Code(KeyCode::LaunchApp1) => f.write_str("LaunchApp1"),
704                PhysicalKey::Code(KeyCode::LaunchApp2) => f.write_str("LaunchApp2"),
705                PhysicalKey::Code(KeyCode::LaunchMail) => f.write_str("LaunchMail"),
706                PhysicalKey::Code(KeyCode::MediaPlayPause) => f.write_str("MediaPlayPause"),
707                PhysicalKey::Code(KeyCode::MediaSelect) => f.write_str("MediaSelect"),
708                PhysicalKey::Code(KeyCode::MediaStop) => f.write_str("MediaStop"),
709                PhysicalKey::Code(KeyCode::MediaTrackNext) => f.write_str("MediaTrackNext"),
710                PhysicalKey::Code(KeyCode::MediaTrackPrevious) => f.write_str("MediaTrackPrevious"),
711                PhysicalKey::Code(KeyCode::Power) => f.write_str("Power"),
712                PhysicalKey::Code(KeyCode::Sleep) => f.write_str("Sleep"),
713                PhysicalKey::Code(KeyCode::AudioVolumeDown) => f.write_str("AudioVolumeDown"),
714                PhysicalKey::Code(KeyCode::AudioVolumeMute) => f.write_str("AudioVolumeMute"),
715                PhysicalKey::Code(KeyCode::AudioVolumeUp) => f.write_str("AudioVolumeUp"),
716                PhysicalKey::Code(KeyCode::WakeUp) => f.write_str("WakeUp"),
717                PhysicalKey::Code(KeyCode::Meta) => match std::env::consts::OS {
718                    "macos" => f.write_str("Cmd"),
719                    "windows" => f.write_str("Win"),
720                    _ => f.write_str("Meta"),
721                },
722                PhysicalKey::Code(KeyCode::Hyper) => f.write_str("Hyper"),
723                PhysicalKey::Code(KeyCode::Turbo) => f.write_str("Turbo"),
724                PhysicalKey::Code(KeyCode::Abort) => f.write_str("Abort"),
725                PhysicalKey::Code(KeyCode::Resume) => f.write_str("Resume"),
726                PhysicalKey::Code(KeyCode::Suspend) => f.write_str("Suspend"),
727                PhysicalKey::Code(KeyCode::Again) => f.write_str("Again"),
728                PhysicalKey::Code(KeyCode::Copy) => f.write_str("Copy"),
729                PhysicalKey::Code(KeyCode::Cut) => f.write_str("Cut"),
730                PhysicalKey::Code(KeyCode::Find) => f.write_str("Find"),
731                PhysicalKey::Code(KeyCode::Open) => f.write_str("Open"),
732                PhysicalKey::Code(KeyCode::Paste) => f.write_str("Paste"),
733                PhysicalKey::Code(KeyCode::Props) => f.write_str("Props"),
734                PhysicalKey::Code(KeyCode::Select) => f.write_str("Select"),
735                PhysicalKey::Code(KeyCode::Undo) => f.write_str("Undo"),
736                PhysicalKey::Code(KeyCode::Hiragana) => f.write_str("Hiragana"),
737                PhysicalKey::Code(KeyCode::Katakana) => f.write_str("Katakana"),
738                PhysicalKey::Code(KeyCode::F1) => f.write_str("F1"),
739                PhysicalKey::Code(KeyCode::F2) => f.write_str("F2"),
740                PhysicalKey::Code(KeyCode::F3) => f.write_str("F3"),
741                PhysicalKey::Code(KeyCode::F4) => f.write_str("F4"),
742                PhysicalKey::Code(KeyCode::F5) => f.write_str("F5"),
743                PhysicalKey::Code(KeyCode::F6) => f.write_str("F6"),
744                PhysicalKey::Code(KeyCode::F7) => f.write_str("F7"),
745                PhysicalKey::Code(KeyCode::F8) => f.write_str("F8"),
746                PhysicalKey::Code(KeyCode::F9) => f.write_str("F9"),
747                PhysicalKey::Code(KeyCode::F10) => f.write_str("F10"),
748                PhysicalKey::Code(KeyCode::F11) => f.write_str("F11"),
749                PhysicalKey::Code(KeyCode::F12) => f.write_str("F12"),
750                PhysicalKey::Code(KeyCode::F13) => f.write_str("F13"),
751                PhysicalKey::Code(KeyCode::F14) => f.write_str("F14"),
752                PhysicalKey::Code(KeyCode::F15) => f.write_str("F15"),
753                PhysicalKey::Code(KeyCode::F16) => f.write_str("F16"),
754                PhysicalKey::Code(KeyCode::F17) => f.write_str("F17"),
755                PhysicalKey::Code(KeyCode::F18) => f.write_str("F18"),
756                PhysicalKey::Code(KeyCode::F19) => f.write_str("F19"),
757                PhysicalKey::Code(KeyCode::F20) => f.write_str("F20"),
758                PhysicalKey::Code(KeyCode::F21) => f.write_str("F21"),
759                PhysicalKey::Code(KeyCode::F22) => f.write_str("F22"),
760                PhysicalKey::Code(KeyCode::F23) => f.write_str("F23"),
761                PhysicalKey::Code(KeyCode::F24) => f.write_str("F24"),
762                PhysicalKey::Code(KeyCode::F25) => f.write_str("F25"),
763                PhysicalKey::Code(KeyCode::F26) => f.write_str("F26"),
764                PhysicalKey::Code(KeyCode::F27) => f.write_str("F27"),
765                PhysicalKey::Code(KeyCode::F28) => f.write_str("F28"),
766                PhysicalKey::Code(KeyCode::F29) => f.write_str("F29"),
767                PhysicalKey::Code(KeyCode::F30) => f.write_str("F30"),
768                PhysicalKey::Code(KeyCode::F31) => f.write_str("F31"),
769                PhysicalKey::Code(KeyCode::F32) => f.write_str("F32"),
770                PhysicalKey::Code(KeyCode::F33) => f.write_str("F33"),
771                PhysicalKey::Code(KeyCode::F34) => f.write_str("F34"),
772                PhysicalKey::Code(KeyCode::F35) => f.write_str("F35"),
773                _ => f.write_str("Unidentified"),
774            },
775            Self::Pointer(B::Auxiliary) => f.write_str("MouseMiddle"),
776            Self::Pointer(B::X2) => f.write_str("MouseForward"),
777            Self::Pointer(B::X1) => f.write_str("MouseBackward"),
778            Self::Pointer(_) => f.write_str("MouseUnimplemented"),
779        }
780    }
781}
782
783impl FromStr for KeyInput {
784    type Err = ();
785
786    fn from_str(s: &str) -> Result<Self, Self::Err> {
787        let s = s.to_lowercase();
788
789        KeyInput::keyboard_from_str(&s)
790            .map(|key| KeyInput::Keyboard(key.0, key.1))
791            .or_else(|| KeyInput::mouse_from_str(&s).map(KeyInput::Pointer))
792            .ok_or(())
793    }
794}
795
796impl Hash for KeyInput {
797    fn hash<H: Hasher>(&self, state: &mut H) {
798        match self {
799            Self::Keyboard(_key, key_code) => key_code.hash(state),
800            // TODO: Implement `Hash` for `druid::MouseButton`
801            Self::Pointer(btn) => (*btn as u8).hash(state),
802        }
803    }
804}
805
806impl PartialEq for KeyInput {
807    fn eq(&self, other: &Self) -> bool {
808        match (self, other) {
809            (KeyInput::Keyboard(_key_a, key_code_a), KeyInput::Keyboard(_key_b, key_code_b)) => {
810                key_code_a.eq(key_code_b)
811            }
812            (KeyInput::Pointer(a), KeyInput::Pointer(b)) => a.eq(b),
813            _ => false,
814        }
815    }
816}