From a1ff0d39bcb544ff00f260226ffcfd582a790e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 17 Mar 2021 15:43:38 +0100 Subject: [PATCH 01/13] Get the web-sys backend to compile --- .../web/event_loop/window_target.rs | 53 +++-- src/platform_impl/web/mod.rs | 4 + src/platform_impl/web/web_sys/canvas.rs | 23 +- .../web/web_sys/canvas/mouse_handler.rs | 3 +- .../web/web_sys/canvas/pointer_handler.rs | 3 +- src/platform_impl/web/web_sys/event.rs | 199 +++--------------- src/platform_impl/web/window.rs | 4 + 7 files changed, 87 insertions(+), 202 deletions(-) diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 367556a7a1..521df0b54e 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -1,9 +1,15 @@ -use super::{super::monitor, backend, device, proxy::Proxy, runner, window}; +use super::{ + super::{monitor, KeyEventExtra}, + backend, device, + proxy::Proxy, + runner, window, +}; use crate::dpi::{PhysicalSize, Size}; use crate::event::{ - DeviceEvent, DeviceId, ElementState, Event, KeyboardInput, TouchPhase, WindowEvent, + DeviceEvent, DeviceId, ElementState, Event, KeyEvent, RawKeyEvent, TouchPhase, WindowEvent, }; use crate::event_loop::ControlFlow; +use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState}; use crate::monitor::MonitorHandle as RootMH; use crate::window::{Theme, WindowId}; use std::cell::RefCell; @@ -68,17 +74,20 @@ impl WindowTarget { }); let runner = self.runner.clone(); - canvas.on_keyboard_press(move |scancode, virtual_keycode, modifiers| { + canvas.on_keyboard_press(move |physical_key, logical_key, text, location, repeat| { #[allow(deprecated)] runner.send_event(Event::WindowEvent { window_id: WindowId(id), event: WindowEvent::KeyboardInput { device_id: DeviceId(unsafe { device::Id::dummy() }), - input: KeyboardInput { - scancode, - state: ElementState::Pressed, - virtual_keycode, - modifiers, + event: KeyEvent { + physical_key, + logical_key, + text, + location, + state: ElementState::Released, + repeat, + platform_specific: KeyEventExtra, }, is_synthetic: false, }, @@ -86,30 +95,34 @@ impl WindowTarget { }); let runner = self.runner.clone(); - canvas.on_keyboard_release(move |scancode, virtual_keycode, modifiers| { + canvas.on_keyboard_release(move |physical_key, logical_key, text, location, repeat| { #[allow(deprecated)] runner.send_event(Event::WindowEvent { window_id: WindowId(id), event: WindowEvent::KeyboardInput { device_id: DeviceId(unsafe { device::Id::dummy() }), - input: KeyboardInput { - scancode, + event: KeyEvent { + physical_key, + logical_key, + text, + location, state: ElementState::Released, - virtual_keycode, - modifiers, + repeat, + platform_specific: KeyEventExtra, }, is_synthetic: false, }, - }); + }) }); let runner = self.runner.clone(); - canvas.on_received_character(move |char_code| { - runner.send_event(Event::WindowEvent { - window_id: WindowId(id), - event: WindowEvent::ReceivedCharacter(char_code), - }); - }); + // TODO: What to do here? + // canvas.on_received_character(move |char_code| { + // runner.send_event(Event::WindowEvent { + // window_id: WindowId(id), + // event: WindowEvent::ReceivedCharacter(char_code), + // }); + // }); let runner = self.runner.clone(); canvas.on_cursor_leave(move |pointer_id| { diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index 8c7f993fb0..9cf6bcca52 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -44,3 +44,7 @@ pub(crate) struct ScaleChangeArgs { old_scale: f64, new_scale: f64, } + +// TODO: Where should I put this? +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub(crate) struct KeyEventExtra; diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 8d68e5aaab..e6982d78ee 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -3,7 +3,8 @@ use super::event_handle::EventListenerHandle; use super::media_query_handle::MediaQueryListHandle; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::error::OsError as RootOE; -use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode}; +use crate::event::{MouseButton, MouseScrollDelta}; +use crate::keyboard::{Key, KeyCode, ModifiersState, KeyLocation}; use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; use std::cell::RefCell; @@ -150,16 +151,18 @@ impl Canvas { pub fn on_keyboard_release(&mut self, mut handler: F) where - F: 'static + FnMut(ScanCode, Option, ModifiersState), + F: 'static + FnMut(KeyCode, Key<'static>, Option<&'static str>, KeyLocation, bool), { self.on_keyboard_release = Some(self.common.add_user_event( "keyup", move |event: KeyboardEvent| { event.prevent_default(); handler( - event::scan_code(&event), - event::virtual_key_code(&event), - event::keyboard_modifiers(&event), + event::key_code(&event), + event::key(&event), + event::key_text(&event), + event::key_location(&event), + event::key_repeat(&event), ); }, )); @@ -167,7 +170,7 @@ impl Canvas { pub fn on_keyboard_press(&mut self, mut handler: F) where - F: 'static + FnMut(ScanCode, Option, ModifiersState), + F: 'static + FnMut(KeyCode, Key<'static>, Option<&'static str>, KeyLocation, bool), { self.on_keyboard_press = Some(self.common.add_user_event( "keydown", @@ -184,9 +187,11 @@ impl Canvas { event.prevent_default(); } handler( - event::scan_code(&event), - event::virtual_key_code(&event), - event::keyboard_modifiers(&event), + event::key_code(&event), + event::key(&event), + event::key_text(&event), + event::key_location(&event), + event::key_repeat(&event), ); }, )); diff --git a/src/platform_impl/web/web_sys/canvas/mouse_handler.rs b/src/platform_impl/web/web_sys/canvas/mouse_handler.rs index 81e2aead02..a2939c351b 100644 --- a/src/platform_impl/web/web_sys/canvas/mouse_handler.rs +++ b/src/platform_impl/web/web_sys/canvas/mouse_handler.rs @@ -1,7 +1,8 @@ use super::event; use super::EventListenerHandle; use crate::dpi::PhysicalPosition; -use crate::event::{ModifiersState, MouseButton}; +use crate::event::MouseButton; +use crate::keyboard::ModifiersState; use std::cell::RefCell; use std::rc::Rc; diff --git a/src/platform_impl/web/web_sys/canvas/pointer_handler.rs b/src/platform_impl/web/web_sys/canvas/pointer_handler.rs index 85a99eb8ab..8d15d1cbb6 100644 --- a/src/platform_impl/web/web_sys/canvas/pointer_handler.rs +++ b/src/platform_impl/web/web_sys/canvas/pointer_handler.rs @@ -1,7 +1,8 @@ use super::event; use super::EventListenerHandle; use crate::dpi::PhysicalPosition; -use crate::event::{ModifiersState, MouseButton}; +use crate::event::MouseButton; +use crate::keyboard::ModifiersState; use web_sys::PointerEvent; diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index fb6c52d3b0..b311de563f 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -1,5 +1,6 @@ use crate::dpi::LogicalPosition; -use crate::event::{ModifiersState, MouseButton, MouseScrollDelta, ScanCode, VirtualKeyCode}; +use crate::event::{MouseButton, MouseScrollDelta}; +use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState}; use std::convert::TryInto; use web_sys::{HtmlCanvasElement, KeyboardEvent, MouseEvent, WheelEvent}; @@ -16,9 +17,9 @@ pub fn mouse_button(event: &MouseEvent) -> MouseButton { pub fn mouse_modifiers(event: &MouseEvent) -> ModifiersState { let mut m = ModifiersState::empty(); m.set(ModifiersState::SHIFT, event.shift_key()); - m.set(ModifiersState::CTRL, event.ctrl_key()); + m.set(ModifiersState::CONTROL, event.ctrl_key()); m.set(ModifiersState::ALT, event.alt_key()); - m.set(ModifiersState::LOGO, event.meta_key()); + m.set(ModifiersState::SUPER, event.meta_key()); m } @@ -61,182 +62,38 @@ pub fn mouse_scroll_delta(event: &WheelEvent) -> Option { } } -pub fn scan_code(event: &KeyboardEvent) -> ScanCode { - match event.key_code() { - 0 => event.char_code(), - i => i, - } +pub fn key_code(event: &KeyboardEvent) -> KeyCode { + // TODO: Fill out stub. + let code = event.code(); + KeyCode::Enter +} + +pub fn key(event: &KeyboardEvent) -> Key<'static> { + // TODO: Fill out stub. + Key::Enter +} + +pub fn key_text(event: &KeyboardEvent) -> Option<&'static str> { + // TODO: Fill out stub. + None +} + +pub fn key_location(event: &KeyboardEvent) -> KeyLocation { + // TODO: Fill out stub. + KeyLocation::Standard } -pub fn virtual_key_code(event: &KeyboardEvent) -> Option { - Some(match &event.code()[..] { - "Digit1" => VirtualKeyCode::Key1, - "Digit2" => VirtualKeyCode::Key2, - "Digit3" => VirtualKeyCode::Key3, - "Digit4" => VirtualKeyCode::Key4, - "Digit5" => VirtualKeyCode::Key5, - "Digit6" => VirtualKeyCode::Key6, - "Digit7" => VirtualKeyCode::Key7, - "Digit8" => VirtualKeyCode::Key8, - "Digit9" => VirtualKeyCode::Key9, - "Digit0" => VirtualKeyCode::Key0, - "KeyA" => VirtualKeyCode::A, - "KeyB" => VirtualKeyCode::B, - "KeyC" => VirtualKeyCode::C, - "KeyD" => VirtualKeyCode::D, - "KeyE" => VirtualKeyCode::E, - "KeyF" => VirtualKeyCode::F, - "KeyG" => VirtualKeyCode::G, - "KeyH" => VirtualKeyCode::H, - "KeyI" => VirtualKeyCode::I, - "KeyJ" => VirtualKeyCode::J, - "KeyK" => VirtualKeyCode::K, - "KeyL" => VirtualKeyCode::L, - "KeyM" => VirtualKeyCode::M, - "KeyN" => VirtualKeyCode::N, - "KeyO" => VirtualKeyCode::O, - "KeyP" => VirtualKeyCode::P, - "KeyQ" => VirtualKeyCode::Q, - "KeyR" => VirtualKeyCode::R, - "KeyS" => VirtualKeyCode::S, - "KeyT" => VirtualKeyCode::T, - "KeyU" => VirtualKeyCode::U, - "KeyV" => VirtualKeyCode::V, - "KeyW" => VirtualKeyCode::W, - "KeyX" => VirtualKeyCode::X, - "KeyY" => VirtualKeyCode::Y, - "KeyZ" => VirtualKeyCode::Z, - "Escape" => VirtualKeyCode::Escape, - "F1" => VirtualKeyCode::F1, - "F2" => VirtualKeyCode::F2, - "F3" => VirtualKeyCode::F3, - "F4" => VirtualKeyCode::F4, - "F5" => VirtualKeyCode::F5, - "F6" => VirtualKeyCode::F6, - "F7" => VirtualKeyCode::F7, - "F8" => VirtualKeyCode::F8, - "F9" => VirtualKeyCode::F9, - "F10" => VirtualKeyCode::F10, - "F11" => VirtualKeyCode::F11, - "F12" => VirtualKeyCode::F12, - "F13" => VirtualKeyCode::F13, - "F14" => VirtualKeyCode::F14, - "F15" => VirtualKeyCode::F15, - "F16" => VirtualKeyCode::F16, - "F17" => VirtualKeyCode::F17, - "F18" => VirtualKeyCode::F18, - "F19" => VirtualKeyCode::F19, - "F20" => VirtualKeyCode::F20, - "F21" => VirtualKeyCode::F21, - "F22" => VirtualKeyCode::F22, - "F23" => VirtualKeyCode::F23, - "F24" => VirtualKeyCode::F24, - "PrintScreen" => VirtualKeyCode::Snapshot, - "ScrollLock" => VirtualKeyCode::Scroll, - "Pause" => VirtualKeyCode::Pause, - "Insert" => VirtualKeyCode::Insert, - "Home" => VirtualKeyCode::Home, - "Delete" => VirtualKeyCode::Delete, - "End" => VirtualKeyCode::End, - "PageDown" => VirtualKeyCode::PageDown, - "PageUp" => VirtualKeyCode::PageUp, - "ArrowLeft" => VirtualKeyCode::Left, - "ArrowUp" => VirtualKeyCode::Up, - "ArrowRight" => VirtualKeyCode::Right, - "ArrowDown" => VirtualKeyCode::Down, - "Backspace" => VirtualKeyCode::Back, - "Enter" => VirtualKeyCode::Return, - "Space" => VirtualKeyCode::Space, - "Compose" => VirtualKeyCode::Compose, - "Caret" => VirtualKeyCode::Caret, - "NumLock" => VirtualKeyCode::Numlock, - "Numpad0" => VirtualKeyCode::Numpad0, - "Numpad1" => VirtualKeyCode::Numpad1, - "Numpad2" => VirtualKeyCode::Numpad2, - "Numpad3" => VirtualKeyCode::Numpad3, - "Numpad4" => VirtualKeyCode::Numpad4, - "Numpad5" => VirtualKeyCode::Numpad5, - "Numpad6" => VirtualKeyCode::Numpad6, - "Numpad7" => VirtualKeyCode::Numpad7, - "Numpad8" => VirtualKeyCode::Numpad8, - "Numpad9" => VirtualKeyCode::Numpad9, - "AbntC1" => VirtualKeyCode::AbntC1, - "AbntC2" => VirtualKeyCode::AbntC2, - "NumpadAdd" => VirtualKeyCode::NumpadAdd, - "Quote" => VirtualKeyCode::Apostrophe, - "Apps" => VirtualKeyCode::Apps, - "At" => VirtualKeyCode::At, - "Ax" => VirtualKeyCode::Ax, - "Backslash" => VirtualKeyCode::Backslash, - "Calculator" => VirtualKeyCode::Calculator, - "Capital" => VirtualKeyCode::Capital, - "Semicolon" => VirtualKeyCode::Semicolon, - "Comma" => VirtualKeyCode::Comma, - "Convert" => VirtualKeyCode::Convert, - "NumpadDecimal" => VirtualKeyCode::NumpadDecimal, - "NumpadDivide" => VirtualKeyCode::NumpadDivide, - "Equal" => VirtualKeyCode::Equals, - "Backquote" => VirtualKeyCode::Grave, - "Kana" => VirtualKeyCode::Kana, - "Kanji" => VirtualKeyCode::Kanji, - "AltLeft" => VirtualKeyCode::LAlt, - "BracketLeft" => VirtualKeyCode::LBracket, - "ControlLeft" => VirtualKeyCode::LControl, - "ShiftLeft" => VirtualKeyCode::LShift, - "MetaLeft" => VirtualKeyCode::LWin, - "Mail" => VirtualKeyCode::Mail, - "MediaSelect" => VirtualKeyCode::MediaSelect, - "MediaStop" => VirtualKeyCode::MediaStop, - "Minus" => VirtualKeyCode::Minus, - "NumpadMultiply" => VirtualKeyCode::NumpadMultiply, - "Mute" => VirtualKeyCode::Mute, - "LaunchMyComputer" => VirtualKeyCode::MyComputer, - "NavigateForward" => VirtualKeyCode::NavigateForward, - "NavigateBackward" => VirtualKeyCode::NavigateBackward, - "NextTrack" => VirtualKeyCode::NextTrack, - "NoConvert" => VirtualKeyCode::NoConvert, - "NumpadComma" => VirtualKeyCode::NumpadComma, - "NumpadEnter" => VirtualKeyCode::NumpadEnter, - "NumpadEquals" => VirtualKeyCode::NumpadEquals, - "OEM102" => VirtualKeyCode::OEM102, - "Period" => VirtualKeyCode::Period, - "PlayPause" => VirtualKeyCode::PlayPause, - "Power" => VirtualKeyCode::Power, - "PrevTrack" => VirtualKeyCode::PrevTrack, - "AltRight" => VirtualKeyCode::RAlt, - "BracketRight" => VirtualKeyCode::RBracket, - "ControlRight" => VirtualKeyCode::RControl, - "ShiftRight" => VirtualKeyCode::RShift, - "MetaRight" => VirtualKeyCode::RWin, - "Slash" => VirtualKeyCode::Slash, - "Sleep" => VirtualKeyCode::Sleep, - "Stop" => VirtualKeyCode::Stop, - "NumpadSubtract" => VirtualKeyCode::NumpadSubtract, - "Sysrq" => VirtualKeyCode::Sysrq, - "Tab" => VirtualKeyCode::Tab, - "Underline" => VirtualKeyCode::Underline, - "Unlabeled" => VirtualKeyCode::Unlabeled, - "AudioVolumeDown" => VirtualKeyCode::VolumeDown, - "AudioVolumeUp" => VirtualKeyCode::VolumeUp, - "Wake" => VirtualKeyCode::Wake, - "WebBack" => VirtualKeyCode::WebBack, - "WebFavorites" => VirtualKeyCode::WebFavorites, - "WebForward" => VirtualKeyCode::WebForward, - "WebHome" => VirtualKeyCode::WebHome, - "WebRefresh" => VirtualKeyCode::WebRefresh, - "WebSearch" => VirtualKeyCode::WebSearch, - "WebStop" => VirtualKeyCode::WebStop, - "Yen" => VirtualKeyCode::Yen, - _ => return None, - }) +pub fn key_repeat(event: &KeyboardEvent) -> bool { + // TODO: Fill out stub. + false } pub fn keyboard_modifiers(event: &KeyboardEvent) -> ModifiersState { let mut m = ModifiersState::empty(); m.set(ModifiersState::SHIFT, event.shift_key()); - m.set(ModifiersState::CTRL, event.ctrl_key()); + m.set(ModifiersState::CONTROL, event.ctrl_key()); m.set(ModifiersState::ALT, event.alt_key()); - m.set(ModifiersState::LOGO, event.meta_key()); + m.set(ModifiersState::SUPER, event.meta_key()); m } diff --git a/src/platform_impl/web/window.rs b/src/platform_impl/web/window.rs index 19fac1b93b..a579bcfa82 100644 --- a/src/platform_impl/web/window.rs +++ b/src/platform_impl/web/window.rs @@ -330,6 +330,10 @@ impl Window { handle.id = self.id.0; RawWindowHandle::Web(handle) } + + pub fn reset_dead_keys(&self) { + // Not supported + } } impl Drop for Window { From 1ab522b773f9b5dbe6a66671f0614d6d5d4cf9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Wed, 17 Mar 2021 21:10:30 +0100 Subject: [PATCH 02/13] Get a super-minimal MVP for web-sys --- src/keyboard.rs | 1039 ++++++++++++++++- .../web/event_loop/window_target.rs | 9 +- src/platform_impl/web/web_sys/canvas.rs | 38 +- src/platform_impl/web/web_sys/event.rs | 63 +- 4 files changed, 1099 insertions(+), 50 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 28983cfaf4..878967f626 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -176,10 +176,11 @@ pub enum NativeKeyCode { Windows(u16), MacOS(u32), XKB(u32), + Web(&'static str), } impl std::fmt::Debug for NativeKeyCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - use NativeKeyCode::{MacOS, Unidentified, Windows, XKB}; + use NativeKeyCode::{MacOS, Unidentified, Web, Windows, XKB}; let mut debug_tuple; match self { Unidentified => { @@ -197,6 +198,10 @@ impl std::fmt::Debug for NativeKeyCode { debug_tuple = f.debug_tuple(name_of!(XKB)); debug_tuple.field(v); } + Web(v) => { + debug_tuple = f.debug_tuple(name_of!(Web)); + debug_tuple.field(v); + } } debug_tuple.finish() } @@ -659,6 +664,409 @@ pub enum KeyCode { F35, } +impl KeyCode { + pub fn from_key_code_attribute_value(kcav: &str) -> Self { + match kcav { + "Backquote" => KeyCode::Backquote, + "Backslash" => KeyCode::Backslash, + "BracketLeft" => KeyCode::BracketLeft, + "BracketRight" => KeyCode::BracketRight, + "Comma" => KeyCode::Comma, + "Digit0" => KeyCode::Digit0, + "Digit1" => KeyCode::Digit1, + "Digit2" => KeyCode::Digit2, + "Digit3" => KeyCode::Digit3, + "Digit4" => KeyCode::Digit4, + "Digit5" => KeyCode::Digit5, + "Digit6" => KeyCode::Digit6, + "Digit7" => KeyCode::Digit7, + "Digit8" => KeyCode::Digit8, + "Digit9" => KeyCode::Digit9, + "Equal" => KeyCode::Equal, + "IntlBackslash" => KeyCode::IntlBackslash, + "IntlRo" => KeyCode::IntlRo, + "IntlYen" => KeyCode::IntlYen, + "KeyA" => KeyCode::KeyA, + "KeyB" => KeyCode::KeyB, + "KeyC" => KeyCode::KeyC, + "KeyD" => KeyCode::KeyD, + "KeyE" => KeyCode::KeyE, + "KeyF" => KeyCode::KeyF, + "KeyG" => KeyCode::KeyG, + "KeyH" => KeyCode::KeyH, + "KeyI" => KeyCode::KeyI, + "KeyJ" => KeyCode::KeyJ, + "KeyK" => KeyCode::KeyK, + "KeyL" => KeyCode::KeyL, + "KeyM" => KeyCode::KeyM, + "KeyN" => KeyCode::KeyN, + "KeyO" => KeyCode::KeyO, + "KeyP" => KeyCode::KeyP, + "KeyQ" => KeyCode::KeyQ, + "KeyR" => KeyCode::KeyR, + "KeyS" => KeyCode::KeyS, + "KeyT" => KeyCode::KeyT, + "KeyU" => KeyCode::KeyU, + "KeyV" => KeyCode::KeyV, + "KeyW" => KeyCode::KeyW, + "KeyX" => KeyCode::KeyX, + "KeyY" => KeyCode::KeyY, + "KeyZ" => KeyCode::KeyZ, + "Minus" => KeyCode::Minus, + "Period" => KeyCode::Period, + "Quote" => KeyCode::Quote, + "Semicolon" => KeyCode::Semicolon, + "Slash" => KeyCode::Slash, + "AltLeft" => KeyCode::AltLeft, + "AltRight" => KeyCode::AltRight, + "Backspace" => KeyCode::Backspace, + "CapsLock" => KeyCode::CapsLock, + "ContextMenu" => KeyCode::ContextMenu, + "ControlLeft" => KeyCode::ControlLeft, + "ControlRight" => KeyCode::ControlRight, + "Enter" => KeyCode::Enter, + "MetaLeft" => KeyCode::SuperLeft, + "MetaRight" => KeyCode::SuperRight, + "ShiftLeft" => KeyCode::ShiftLeft, + "ShiftRight" => KeyCode::ShiftRight, + "Space" => KeyCode::Space, + "Tab" => KeyCode::Tab, + "Convert" => KeyCode::Convert, + "KanaMode" => KeyCode::KanaMode, + "Lang1" => KeyCode::Lang1, + "Lang2" => KeyCode::Lang2, + "Lang3" => KeyCode::Lang3, + "Lang4" => KeyCode::Lang4, + "Lang5" => KeyCode::Lang5, + "NonConvert" => KeyCode::NonConvert, + "Delete" => KeyCode::Delete, + "End" => KeyCode::End, + "Help" => KeyCode::Help, + "Home" => KeyCode::Home, + "Insert" => KeyCode::Insert, + "PageDown" => KeyCode::PageDown, + "PageUp" => KeyCode::PageUp, + "ArrowDown" => KeyCode::ArrowDown, + "ArrowLeft" => KeyCode::ArrowLeft, + "ArrowRight" => KeyCode::ArrowRight, + "ArrowUp" => KeyCode::ArrowUp, + "NumLock" => KeyCode::NumLock, + "Numpad0" => KeyCode::Numpad0, + "Numpad1" => KeyCode::Numpad1, + "Numpad2" => KeyCode::Numpad2, + "Numpad3" => KeyCode::Numpad3, + "Numpad4" => KeyCode::Numpad4, + "Numpad5" => KeyCode::Numpad5, + "Numpad6" => KeyCode::Numpad6, + "Numpad7" => KeyCode::Numpad7, + "Numpad8" => KeyCode::Numpad8, + "Numpad9" => KeyCode::Numpad9, + "NumpadAdd" => KeyCode::NumpadAdd, + "NumpadBackspace" => KeyCode::NumpadBackspace, + "NumpadClear" => KeyCode::NumpadClear, + "NumpadClearEntry" => KeyCode::NumpadClearEntry, + "NumpadComma" => KeyCode::NumpadComma, + "NumpadDecimal" => KeyCode::NumpadDecimal, + "NumpadDivide" => KeyCode::NumpadDivide, + "NumpadEnter" => KeyCode::NumpadEnter, + "NumpadEqual" => KeyCode::NumpadEqual, + "NumpadHash" => KeyCode::NumpadHash, + "NumpadMemoryAdd" => KeyCode::NumpadMemoryAdd, + "NumpadMemoryClear" => KeyCode::NumpadMemoryClear, + "NumpadMemoryRecall" => KeyCode::NumpadMemoryRecall, + "NumpadMemoryStore" => KeyCode::NumpadMemoryStore, + "NumpadMemorySubtract" => KeyCode::NumpadMemorySubtract, + "NumpadMultiply" => KeyCode::NumpadMultiply, + "NumpadParenLeft" => KeyCode::NumpadParenLeft, + "NumpadParenRight" => KeyCode::NumpadParenRight, + "NumpadStar" => KeyCode::NumpadStar, + "NumpadSubtract" => KeyCode::NumpadSubtract, + "Escape" => KeyCode::Escape, + "Fn" => KeyCode::Fn, + "FnLock" => KeyCode::FnLock, + "PrintScreen" => KeyCode::PrintScreen, + "ScrollLock" => KeyCode::ScrollLock, + "Pause" => KeyCode::Pause, + "BrowserBack" => KeyCode::BrowserBack, + "BrowserFavorites" => KeyCode::BrowserFavorites, + "BrowserForward" => KeyCode::BrowserForward, + "BrowserHome" => KeyCode::BrowserHome, + "BrowserRefresh" => KeyCode::BrowserRefresh, + "BrowserSearch" => KeyCode::BrowserSearch, + "BrowserStop" => KeyCode::BrowserStop, + "Eject" => KeyCode::Eject, + "LaunchApp1" => KeyCode::LaunchApp1, + "LaunchApp2" => KeyCode::LaunchApp2, + "LaunchMail" => KeyCode::LaunchMail, + "MediaPlayPause" => KeyCode::MediaPlayPause, + "MediaSelect" => KeyCode::MediaSelect, + "MediaStop" => KeyCode::MediaStop, + "MediaTrackNext" => KeyCode::MediaTrackNext, + "MediaTrackPrevious" => KeyCode::MediaTrackPrevious, + "Power" => KeyCode::Power, + "Sleep" => KeyCode::Sleep, + "AudioVolumeDown" => KeyCode::AudioVolumeDown, + "AudioVolumeMute" => KeyCode::AudioVolumeMute, + "AudioVolumeUp" => KeyCode::AudioVolumeUp, + "WakeUp" => KeyCode::WakeUp, + "Hyper" => KeyCode::Hyper, + "Turbo" => KeyCode::Turbo, + "Abort" => KeyCode::Abort, + "Resume" => KeyCode::Resume, + "Suspend" => KeyCode::Suspend, + "Again" => KeyCode::Again, + "Copy" => KeyCode::Copy, + "Cut" => KeyCode::Cut, + "Find" => KeyCode::Find, + "Open" => KeyCode::Open, + "Paste" => KeyCode::Paste, + "Props" => KeyCode::Props, + "Select" => KeyCode::Select, + "Undo" => KeyCode::Undo, + "Hiragana" => KeyCode::Hiragana, + "Katakana" => KeyCode::Katakana, + "F1" => KeyCode::F1, + "F2" => KeyCode::F2, + "F3" => KeyCode::F3, + "F4" => KeyCode::F4, + "F5" => KeyCode::F5, + "F6" => KeyCode::F6, + "F7" => KeyCode::F7, + "F8" => KeyCode::F8, + "F9" => KeyCode::F9, + "F10" => KeyCode::F10, + "F11" => KeyCode::F11, + "F12" => KeyCode::F12, + "F13" => KeyCode::F13, + "F14" => KeyCode::F14, + "F15" => KeyCode::F15, + "F16" => KeyCode::F16, + "F17" => KeyCode::F17, + "F18" => KeyCode::F18, + "F19" => KeyCode::F19, + "F20" => KeyCode::F20, + "F21" => KeyCode::F21, + "F22" => KeyCode::F22, + "F23" => KeyCode::F23, + "F24" => KeyCode::F24, + "F25" => KeyCode::F25, + "F26" => KeyCode::F26, + "F27" => KeyCode::F27, + "F28" => KeyCode::F28, + "F29" => KeyCode::F29, + "F30" => KeyCode::F30, + "F31" => KeyCode::F31, + "F32" => KeyCode::F32, + "F33" => KeyCode::F33, + "F34" => KeyCode::F34, + "F35" => KeyCode::F35, + // TODO: Fix unbounded leak + string @ _ => KeyCode::Unidentified(NativeKeyCode::Web(Box::leak( + String::from(string).into_boxed_str(), + ))), + } + } + + pub fn to_key_code_attribute_value(&self) -> &'static str { + match self { + KeyCode::Unidentified(_) => "Unidentified", + KeyCode::Backquote => "Backquote", + KeyCode::Backslash => "Backslash", + KeyCode::BracketLeft => "BracketLeft", + KeyCode::BracketRight => "BracketRight", + KeyCode::Comma => "Comma", + KeyCode::Digit0 => "Digit0", + KeyCode::Digit1 => "Digit1", + KeyCode::Digit2 => "Digit2", + KeyCode::Digit3 => "Digit3", + KeyCode::Digit4 => "Digit4", + KeyCode::Digit5 => "Digit5", + KeyCode::Digit6 => "Digit6", + KeyCode::Digit7 => "Digit7", + KeyCode::Digit8 => "Digit8", + KeyCode::Digit9 => "Digit9", + KeyCode::Equal => "Equal", + KeyCode::IntlBackslash => "IntlBackslash", + KeyCode::IntlRo => "IntlRo", + KeyCode::IntlYen => "IntlYen", + KeyCode::KeyA => "KeyA", + KeyCode::KeyB => "KeyB", + KeyCode::KeyC => "KeyC", + KeyCode::KeyD => "KeyD", + KeyCode::KeyE => "KeyE", + KeyCode::KeyF => "KeyF", + KeyCode::KeyG => "KeyG", + KeyCode::KeyH => "KeyH", + KeyCode::KeyI => "KeyI", + KeyCode::KeyJ => "KeyJ", + KeyCode::KeyK => "KeyK", + KeyCode::KeyL => "KeyL", + KeyCode::KeyM => "KeyM", + KeyCode::KeyN => "KeyN", + KeyCode::KeyO => "KeyO", + KeyCode::KeyP => "KeyP", + KeyCode::KeyQ => "KeyQ", + KeyCode::KeyR => "KeyR", + KeyCode::KeyS => "KeyS", + KeyCode::KeyT => "KeyT", + KeyCode::KeyU => "KeyU", + KeyCode::KeyV => "KeyV", + KeyCode::KeyW => "KeyW", + KeyCode::KeyX => "KeyX", + KeyCode::KeyY => "KeyY", + KeyCode::KeyZ => "KeyZ", + KeyCode::Minus => "Minus", + KeyCode::Period => "Period", + KeyCode::Quote => "Quote", + KeyCode::Semicolon => "Semicolon", + KeyCode::Slash => "Slash", + KeyCode::AltLeft => "AltLeft", + KeyCode::AltRight => "AltRight", + KeyCode::Backspace => "Backspace", + KeyCode::CapsLock => "CapsLock", + KeyCode::ContextMenu => "ContextMenu", + KeyCode::ControlLeft => "ControlLeft", + KeyCode::ControlRight => "ControlRight", + KeyCode::Enter => "Enter", + KeyCode::SuperLeft => "MetaLeft", + KeyCode::SuperRight => "MetaRight", + KeyCode::ShiftLeft => "ShiftLeft", + KeyCode::ShiftRight => "ShiftRight", + KeyCode::Space => "Space", + KeyCode::Tab => "Tab", + KeyCode::Convert => "Convert", + KeyCode::KanaMode => "KanaMode", + KeyCode::Lang1 => "Lang1", + KeyCode::Lang2 => "Lang2", + KeyCode::Lang3 => "Lang3", + KeyCode::Lang4 => "Lang4", + KeyCode::Lang5 => "Lang5", + KeyCode::NonConvert => "NonConvert", + KeyCode::Delete => "Delete", + KeyCode::End => "End", + KeyCode::Help => "Help", + KeyCode::Home => "Home", + KeyCode::Insert => "Insert", + KeyCode::PageDown => "PageDown", + KeyCode::PageUp => "PageUp", + KeyCode::ArrowDown => "ArrowDown", + KeyCode::ArrowLeft => "ArrowLeft", + KeyCode::ArrowRight => "ArrowRight", + KeyCode::ArrowUp => "ArrowUp", + KeyCode::NumLock => "NumLock", + KeyCode::Numpad0 => "Numpad0", + KeyCode::Numpad1 => "Numpad1", + KeyCode::Numpad2 => "Numpad2", + KeyCode::Numpad3 => "Numpad3", + KeyCode::Numpad4 => "Numpad4", + KeyCode::Numpad5 => "Numpad5", + KeyCode::Numpad6 => "Numpad6", + KeyCode::Numpad7 => "Numpad7", + KeyCode::Numpad8 => "Numpad8", + KeyCode::Numpad9 => "Numpad9", + KeyCode::NumpadAdd => "NumpadAdd", + KeyCode::NumpadBackspace => "NumpadBackspace", + KeyCode::NumpadClear => "NumpadClear", + KeyCode::NumpadClearEntry => "NumpadClearEntry", + KeyCode::NumpadComma => "NumpadComma", + KeyCode::NumpadDecimal => "NumpadDecimal", + KeyCode::NumpadDivide => "NumpadDivide", + KeyCode::NumpadEnter => "NumpadEnter", + KeyCode::NumpadEqual => "NumpadEqual", + KeyCode::NumpadHash => "NumpadHash", + KeyCode::NumpadMemoryAdd => "NumpadMemoryAdd", + KeyCode::NumpadMemoryClear => "NumpadMemoryClear", + KeyCode::NumpadMemoryRecall => "NumpadMemoryRecall", + KeyCode::NumpadMemoryStore => "NumpadMemoryStore", + KeyCode::NumpadMemorySubtract => "NumpadMemorySubtract", + KeyCode::NumpadMultiply => "NumpadMultiply", + KeyCode::NumpadParenLeft => "NumpadParenLeft", + KeyCode::NumpadParenRight => "NumpadParenRight", + KeyCode::NumpadStar => "NumpadStar", + KeyCode::NumpadSubtract => "NumpadSubtract", + KeyCode::Escape => "Escape", + KeyCode::Fn => "Fn", + KeyCode::FnLock => "FnLock", + KeyCode::PrintScreen => "PrintScreen", + KeyCode::ScrollLock => "ScrollLock", + KeyCode::Pause => "Pause", + KeyCode::BrowserBack => "BrowserBack", + KeyCode::BrowserFavorites => "BrowserFavorites", + KeyCode::BrowserForward => "BrowserForward", + KeyCode::BrowserHome => "BrowserHome", + KeyCode::BrowserRefresh => "BrowserRefresh", + KeyCode::BrowserSearch => "BrowserSearch", + KeyCode::BrowserStop => "BrowserStop", + KeyCode::Eject => "Eject", + KeyCode::LaunchApp1 => "LaunchApp1", + KeyCode::LaunchApp2 => "LaunchApp2", + KeyCode::LaunchMail => "LaunchMail", + KeyCode::MediaPlayPause => "MediaPlayPause", + KeyCode::MediaSelect => "MediaSelect", + KeyCode::MediaStop => "MediaStop", + KeyCode::MediaTrackNext => "MediaTrackNext", + KeyCode::MediaTrackPrevious => "MediaTrackPrevious", + KeyCode::Power => "Power", + KeyCode::Sleep => "Sleep", + KeyCode::AudioVolumeDown => "AudioVolumeDown", + KeyCode::AudioVolumeMute => "AudioVolumeMute", + KeyCode::AudioVolumeUp => "AudioVolumeUp", + KeyCode::WakeUp => "WakeUp", + KeyCode::Hyper => "Hyper", + KeyCode::Turbo => "Turbo", + KeyCode::Abort => "Abort", + KeyCode::Resume => "Resume", + KeyCode::Suspend => "Suspend", + KeyCode::Again => "Again", + KeyCode::Copy => "Copy", + KeyCode::Cut => "Cut", + KeyCode::Find => "Find", + KeyCode::Open => "Open", + KeyCode::Paste => "Paste", + KeyCode::Props => "Props", + KeyCode::Select => "Select", + KeyCode::Undo => "Undo", + KeyCode::Hiragana => "Hiragana", + KeyCode::Katakana => "Katakana", + KeyCode::F1 => "F1", + KeyCode::F2 => "F2", + KeyCode::F3 => "F3", + KeyCode::F4 => "F4", + KeyCode::F5 => "F5", + KeyCode::F6 => "F6", + KeyCode::F7 => "F7", + KeyCode::F8 => "F8", + KeyCode::F9 => "F9", + KeyCode::F10 => "F10", + KeyCode::F11 => "F11", + KeyCode::F12 => "F12", + KeyCode::F13 => "F13", + KeyCode::F14 => "F14", + KeyCode::F15 => "F15", + KeyCode::F16 => "F16", + KeyCode::F17 => "F17", + KeyCode::F18 => "F18", + KeyCode::F19 => "F19", + KeyCode::F20 => "F20", + KeyCode::F21 => "F21", + KeyCode::F22 => "F22", + KeyCode::F23 => "F23", + KeyCode::F24 => "F24", + KeyCode::F25 => "F25", + KeyCode::F26 => "F26", + KeyCode::F27 => "F27", + KeyCode::F28 => "F28", + KeyCode::F29 => "F29", + KeyCode::F30 => "F30", + KeyCode::F31 => "F31", + KeyCode::F32 => "F32", + KeyCode::F33 => "F33", + KeyCode::F34 => "F34", + KeyCode::F35 => "F35", + } + } +} + /// Key represents the meaning of a keypress. /// /// This mostly conforms to the UI Events Specification's [`KeyboardEvent.key`] with a few @@ -1393,6 +1801,635 @@ pub enum Key<'a> { F35, } +impl<'a> Key<'a> { + pub fn from_key_attribute_value(kav: &'a str) -> Self { + match kav { + // TODO: Report this in a better way. + "Unidentified" => Key::Unidentified(NativeKeyCode::Web("Unidentified")), + "Dead" => Key::Dead(None), + "Alt" => Key::Alt, + "AltGraph" => Key::AltGraph, + "CapsLock" => Key::CapsLock, + "Control" => Key::Control, + "Fn" => Key::Fn, + "FnLock" => Key::FnLock, + "NumLock" => Key::NumLock, + "ScrollLock" => Key::ScrollLock, + "Shift" => Key::Shift, + "Symbol" => Key::Symbol, + "SymbolLock" => Key::SymbolLock, + "Hyper" => Key::Hyper, + "Meta" => Key::Super, + "Enter" => Key::Enter, + "Tab" => Key::Tab, + "Space" => Key::Space, + "ArrowDown" => Key::ArrowDown, + "ArrowLeft" => Key::ArrowLeft, + "ArrowRight" => Key::ArrowRight, + "ArrowUp" => Key::ArrowUp, + "End" => Key::End, + "Home" => Key::Home, + "PageDown" => Key::PageDown, + "PageUp" => Key::PageUp, + "Backspace" => Key::Backspace, + "Clear" => Key::Clear, + "Copy" => Key::Copy, + "CrSel" => Key::CrSel, + "Cut" => Key::Cut, + "Delete" => Key::Delete, + "EraseEof" => Key::EraseEof, + "ExSel" => Key::ExSel, + "Insert" => Key::Insert, + "Paste" => Key::Paste, + "Redo" => Key::Redo, + "Undo" => Key::Undo, + "Accept" => Key::Accept, + "Again" => Key::Again, + "Attn" => Key::Attn, + "Cancel" => Key::Cancel, + "ContextMenu" => Key::ContextMenu, + "Escape" => Key::Escape, + "Execute" => Key::Execute, + "Find" => Key::Find, + "Help" => Key::Help, + "Pause" => Key::Pause, + "Play" => Key::Play, + "Props" => Key::Props, + "Select" => Key::Select, + "ZoomIn" => Key::ZoomIn, + "ZoomOut" => Key::ZoomOut, + "BrightnessDown" => Key::BrightnessDown, + "BrightnessUp" => Key::BrightnessUp, + "Eject" => Key::Eject, + "LogOff" => Key::LogOff, + "Power" => Key::Power, + "PowerOff" => Key::PowerOff, + "PrintScreen" => Key::PrintScreen, + "Hibernate" => Key::Hibernate, + "Standby" => Key::Standby, + "WakeUp" => Key::WakeUp, + "AllCandidates" => Key::AllCandidates, + "Alphanumeric" => Key::Alphanumeric, + "CodeInput" => Key::CodeInput, + "Compose" => Key::Compose, + "Convert" => Key::Convert, + "FinalMode" => Key::FinalMode, + "GroupFirst" => Key::GroupFirst, + "GroupLast" => Key::GroupLast, + "GroupNext" => Key::GroupNext, + "GroupPrevious" => Key::GroupPrevious, + "ModeChange" => Key::ModeChange, + "NextCandidate" => Key::NextCandidate, + "NonConvert" => Key::NonConvert, + "PreviousCandidate" => Key::PreviousCandidate, + "Process" => Key::Process, + "SingleCandidate" => Key::SingleCandidate, + "HangulMode" => Key::HangulMode, + "HanjaMode" => Key::HanjaMode, + "JunjaMode" => Key::JunjaMode, + "Eisu" => Key::Eisu, + "Hankaku" => Key::Hankaku, + "Hiragana" => Key::Hiragana, + "HiraganaKatakana" => Key::HiraganaKatakana, + "KanaMode" => Key::KanaMode, + "KanjiMode" => Key::KanjiMode, + "Katakana" => Key::Katakana, + "Romaji" => Key::Romaji, + "Zenkaku" => Key::Zenkaku, + "ZenkakuHankaku" => Key::ZenkakuHankaku, + "Soft1" => Key::Soft1, + "Soft2" => Key::Soft2, + "Soft3" => Key::Soft3, + "Soft4" => Key::Soft4, + "ChannelDown" => Key::ChannelDown, + "ChannelUp" => Key::ChannelUp, + "Close" => Key::Close, + "MailForward" => Key::MailForward, + "MailReply" => Key::MailReply, + "MailSend" => Key::MailSend, + "MediaClose" => Key::MediaClose, + "MediaFastForward" => Key::MediaFastForward, + "MediaPause" => Key::MediaPause, + "MediaPlay" => Key::MediaPlay, + "MediaPlayPause" => Key::MediaPlayPause, + "MediaRecord" => Key::MediaRecord, + "MediaRewind" => Key::MediaRewind, + "MediaStop" => Key::MediaStop, + "MediaTrackNext" => Key::MediaTrackNext, + "MediaTrackPrevious" => Key::MediaTrackPrevious, + "New" => Key::New, + "Open" => Key::Open, + "Print" => Key::Print, + "Save" => Key::Save, + "SpellCheck" => Key::SpellCheck, + "Key11" => Key::Key11, + "Key12" => Key::Key12, + "AudioBalanceLeft" => Key::AudioBalanceLeft, + "AudioBalanceRight" => Key::AudioBalanceRight, + "AudioBassBoostDown" => Key::AudioBassBoostDown, + "AudioBassBoostToggle" => Key::AudioBassBoostToggle, + "AudioBassBoostUp" => Key::AudioBassBoostUp, + "AudioFaderFront" => Key::AudioFaderFront, + "AudioFaderRear" => Key::AudioFaderRear, + "AudioSurroundModeNext" => Key::AudioSurroundModeNext, + "AudioTrebleDown" => Key::AudioTrebleDown, + "AudioTrebleUp" => Key::AudioTrebleUp, + "AudioVolumeDown" => Key::AudioVolumeDown, + "AudioVolumeUp" => Key::AudioVolumeUp, + "AudioVolumeMute" => Key::AudioVolumeMute, + "MicrophoneToggle" => Key::MicrophoneToggle, + "MicrophoneVolumeDown" => Key::MicrophoneVolumeDown, + "MicrophoneVolumeUp" => Key::MicrophoneVolumeUp, + "MicrophoneVolumeMute" => Key::MicrophoneVolumeMute, + "SpeechCorrectionList" => Key::SpeechCorrectionList, + "SpeechInputToggle" => Key::SpeechInputToggle, + "LaunchApplication1" => Key::LaunchApplication1, + "LaunchApplication2" => Key::LaunchApplication2, + "LaunchCalendar" => Key::LaunchCalendar, + "LaunchContacts" => Key::LaunchContacts, + "LaunchMail" => Key::LaunchMail, + "LaunchMediaPlayer" => Key::LaunchMediaPlayer, + "LaunchMusicPlayer" => Key::LaunchMusicPlayer, + "LaunchPhone" => Key::LaunchPhone, + "LaunchScreenSaver" => Key::LaunchScreenSaver, + "LaunchSpreadsheet" => Key::LaunchSpreadsheet, + "LaunchWebBrowser" => Key::LaunchWebBrowser, + "LaunchWebCam" => Key::LaunchWebCam, + "LaunchWordProcessor" => Key::LaunchWordProcessor, + "BrowserBack" => Key::BrowserBack, + "BrowserFavorites" => Key::BrowserFavorites, + "BrowserForward" => Key::BrowserForward, + "BrowserHome" => Key::BrowserHome, + "BrowserRefresh" => Key::BrowserRefresh, + "BrowserSearch" => Key::BrowserSearch, + "BrowserStop" => Key::BrowserStop, + "AppSwitch" => Key::AppSwitch, + "Call" => Key::Call, + "Camera" => Key::Camera, + "CameraFocus" => Key::CameraFocus, + "EndCall" => Key::EndCall, + "GoBack" => Key::GoBack, + "GoHome" => Key::GoHome, + "HeadsetHook" => Key::HeadsetHook, + "LastNumberRedial" => Key::LastNumberRedial, + "Notification" => Key::Notification, + "MannerMode" => Key::MannerMode, + "VoiceDial" => Key::VoiceDial, + "TV" => Key::TV, + "TV3DMode" => Key::TV3DMode, + "TVAntennaCable" => Key::TVAntennaCable, + "TVAudioDescription" => Key::TVAudioDescription, + "TVAudioDescriptionMixDown" => Key::TVAudioDescriptionMixDown, + "TVAudioDescriptionMixUp" => Key::TVAudioDescriptionMixUp, + "TVContentsMenu" => Key::TVContentsMenu, + "TVDataService" => Key::TVDataService, + "TVInput" => Key::TVInput, + "TVInputComponent1" => Key::TVInputComponent1, + "TVInputComponent2" => Key::TVInputComponent2, + "TVInputComposite1" => Key::TVInputComposite1, + "TVInputComposite2" => Key::TVInputComposite2, + "TVInputHDMI1" => Key::TVInputHDMI1, + "TVInputHDMI2" => Key::TVInputHDMI2, + "TVInputHDMI3" => Key::TVInputHDMI3, + "TVInputHDMI4" => Key::TVInputHDMI4, + "TVInputVGA1" => Key::TVInputVGA1, + "TVMediaContext" => Key::TVMediaContext, + "TVNetwork" => Key::TVNetwork, + "TVNumberEntry" => Key::TVNumberEntry, + "TVPower" => Key::TVPower, + "TVRadioService" => Key::TVRadioService, + "TVSatellite" => Key::TVSatellite, + "TVSatelliteBS" => Key::TVSatelliteBS, + "TVSatelliteCS" => Key::TVSatelliteCS, + "TVSatelliteToggle" => Key::TVSatelliteToggle, + "TVTerrestrialAnalog" => Key::TVTerrestrialAnalog, + "TVTerrestrialDigital" => Key::TVTerrestrialDigital, + "TVTimer" => Key::TVTimer, + "AVRInput" => Key::AVRInput, + "AVRPower" => Key::AVRPower, + "ColorF0Red" => Key::ColorF0Red, + "ColorF1Green" => Key::ColorF1Green, + "ColorF2Yellow" => Key::ColorF2Yellow, + "ColorF3Blue" => Key::ColorF3Blue, + "ColorF4Grey" => Key::ColorF4Grey, + "ColorF5Brown" => Key::ColorF5Brown, + "ClosedCaptionToggle" => Key::ClosedCaptionToggle, + "Dimmer" => Key::Dimmer, + "DisplaySwap" => Key::DisplaySwap, + "DVR" => Key::DVR, + "Exit" => Key::Exit, + "FavoriteClear0" => Key::FavoriteClear0, + "FavoriteClear1" => Key::FavoriteClear1, + "FavoriteClear2" => Key::FavoriteClear2, + "FavoriteClear3" => Key::FavoriteClear3, + "FavoriteRecall0" => Key::FavoriteRecall0, + "FavoriteRecall1" => Key::FavoriteRecall1, + "FavoriteRecall2" => Key::FavoriteRecall2, + "FavoriteRecall3" => Key::FavoriteRecall3, + "FavoriteStore0" => Key::FavoriteStore0, + "FavoriteStore1" => Key::FavoriteStore1, + "FavoriteStore2" => Key::FavoriteStore2, + "FavoriteStore3" => Key::FavoriteStore3, + "Guide" => Key::Guide, + "GuideNextDay" => Key::GuideNextDay, + "GuidePreviousDay" => Key::GuidePreviousDay, + "Info" => Key::Info, + "InstantReplay" => Key::InstantReplay, + "Link" => Key::Link, + "ListProgram" => Key::ListProgram, + "LiveContent" => Key::LiveContent, + "Lock" => Key::Lock, + "MediaApps" => Key::MediaApps, + "MediaAudioTrack" => Key::MediaAudioTrack, + "MediaLast" => Key::MediaLast, + "MediaSkipBackward" => Key::MediaSkipBackward, + "MediaSkipForward" => Key::MediaSkipForward, + "MediaStepBackward" => Key::MediaStepBackward, + "MediaStepForward" => Key::MediaStepForward, + "MediaTopMenu" => Key::MediaTopMenu, + "NavigateIn" => Key::NavigateIn, + "NavigateNext" => Key::NavigateNext, + "NavigateOut" => Key::NavigateOut, + "NavigatePrevious" => Key::NavigatePrevious, + "NextFavoriteChannel" => Key::NextFavoriteChannel, + "NextUserProfile" => Key::NextUserProfile, + "OnDemand" => Key::OnDemand, + "Pairing" => Key::Pairing, + "PinPDown" => Key::PinPDown, + "PinPMove" => Key::PinPMove, + "PinPToggle" => Key::PinPToggle, + "PinPUp" => Key::PinPUp, + "PlaySpeedDown" => Key::PlaySpeedDown, + "PlaySpeedReset" => Key::PlaySpeedReset, + "PlaySpeedUp" => Key::PlaySpeedUp, + "RandomToggle" => Key::RandomToggle, + "RcLowBattery" => Key::RcLowBattery, + "RecordSpeedNext" => Key::RecordSpeedNext, + "RfBypass" => Key::RfBypass, + "ScanChannelsToggle" => Key::ScanChannelsToggle, + "ScreenModeNext" => Key::ScreenModeNext, + "Settings" => Key::Settings, + "SplitScreenToggle" => Key::SplitScreenToggle, + "STBInput" => Key::STBInput, + "STBPower" => Key::STBPower, + "Subtitle" => Key::Subtitle, + "Teletext" => Key::Teletext, + "VideoModeNext" => Key::VideoModeNext, + "Wink" => Key::Wink, + "ZoomToggle" => Key::ZoomToggle, + "F1" => Key::F1, + "F2" => Key::F2, + "F3" => Key::F3, + "F4" => Key::F4, + "F5" => Key::F5, + "F6" => Key::F6, + "F7" => Key::F7, + "F8" => Key::F8, + "F9" => Key::F9, + "F10" => Key::F10, + "F11" => Key::F11, + "F12" => Key::F12, + "F13" => Key::F13, + "F14" => Key::F14, + "F15" => Key::F15, + "F16" => Key::F16, + "F17" => Key::F17, + "F18" => Key::F18, + "F19" => Key::F19, + "F20" => Key::F20, + "F21" => Key::F21, + "F22" => Key::F22, + "F23" => Key::F23, + "F24" => Key::F24, + "F25" => Key::F25, + "F26" => Key::F26, + "F27" => Key::F27, + "F28" => Key::F28, + "F29" => Key::F29, + "F30" => Key::F30, + "F31" => Key::F31, + "F32" => Key::F32, + "F33" => Key::F33, + "F34" => Key::F34, + "F35" => Key::F35, + string @ _ => Key::Character(string), + } + } + + pub fn as_key_code_attribute_value(&self) -> &str { + match self { + Key::Character(character) => character, + Key::Unidentified(_) => "Unidentified", + Key::Dead(_) => "Dead", + Key::Alt => "Alt", + Key::AltGraph => "AltGraph", + Key::CapsLock => "CapsLock", + Key::Control => "Control", + Key::Fn => "Fn", + Key::FnLock => "FnLock", + Key::NumLock => "NumLock", + Key::ScrollLock => "ScrollLock", + Key::Shift => "Shift", + Key::Symbol => "Symbol", + Key::SymbolLock => "SymbolLock", + Key::Hyper => "Hyper", + Key::Super => "Meta", + Key::Enter => "Enter", + Key::Tab => "Tab", + Key::Space => "Space", + Key::ArrowDown => "ArrowDown", + Key::ArrowLeft => "ArrowLeft", + Key::ArrowRight => "ArrowRight", + Key::ArrowUp => "ArrowUp", + Key::End => "End", + Key::Home => "Home", + Key::PageDown => "PageDown", + Key::PageUp => "PageUp", + Key::Backspace => "Backspace", + Key::Clear => "Clear", + Key::Copy => "Copy", + Key::CrSel => "CrSel", + Key::Cut => "Cut", + Key::Delete => "Delete", + Key::EraseEof => "EraseEof", + Key::ExSel => "ExSel", + Key::Insert => "Insert", + Key::Paste => "Paste", + Key::Redo => "Redo", + Key::Undo => "Undo", + Key::Accept => "Accept", + Key::Again => "Again", + Key::Attn => "Attn", + Key::Cancel => "Cancel", + Key::ContextMenu => "ContextMenu", + Key::Escape => "Escape", + Key::Execute => "Execute", + Key::Find => "Find", + Key::Help => "Help", + Key::Pause => "Pause", + Key::Play => "Play", + Key::Props => "Props", + Key::Select => "Select", + Key::ZoomIn => "ZoomIn", + Key::ZoomOut => "ZoomOut", + Key::BrightnessDown => "BrightnessDown", + Key::BrightnessUp => "BrightnessUp", + Key::Eject => "Eject", + Key::LogOff => "LogOff", + Key::Power => "Power", + Key::PowerOff => "PowerOff", + Key::PrintScreen => "PrintScreen", + Key::Hibernate => "Hibernate", + Key::Standby => "Standby", + Key::WakeUp => "WakeUp", + Key::AllCandidates => "AllCandidates", + Key::Alphanumeric => "Alphanumeric", + Key::CodeInput => "CodeInput", + Key::Compose => "Compose", + Key::Convert => "Convert", + Key::FinalMode => "FinalMode", + Key::GroupFirst => "GroupFirst", + Key::GroupLast => "GroupLast", + Key::GroupNext => "GroupNext", + Key::GroupPrevious => "GroupPrevious", + Key::ModeChange => "ModeChange", + Key::NextCandidate => "NextCandidate", + Key::NonConvert => "NonConvert", + Key::PreviousCandidate => "PreviousCandidate", + Key::Process => "Process", + Key::SingleCandidate => "SingleCandidate", + Key::HangulMode => "HangulMode", + Key::HanjaMode => "HanjaMode", + Key::JunjaMode => "JunjaMode", + Key::Eisu => "Eisu", + Key::Hankaku => "Hankaku", + Key::Hiragana => "Hiragana", + Key::HiraganaKatakana => "HiraganaKatakana", + Key::KanaMode => "KanaMode", + Key::KanjiMode => "KanjiMode", + Key::Katakana => "Katakana", + Key::Romaji => "Romaji", + Key::Zenkaku => "Zenkaku", + Key::ZenkakuHankaku => "ZenkakuHankaku", + Key::Soft1 => "Soft1", + Key::Soft2 => "Soft2", + Key::Soft3 => "Soft3", + Key::Soft4 => "Soft4", + Key::ChannelDown => "ChannelDown", + Key::ChannelUp => "ChannelUp", + Key::Close => "Close", + Key::MailForward => "MailForward", + Key::MailReply => "MailReply", + Key::MailSend => "MailSend", + Key::MediaClose => "MediaClose", + Key::MediaFastForward => "MediaFastForward", + Key::MediaPause => "MediaPause", + Key::MediaPlay => "MediaPlay", + Key::MediaPlayPause => "MediaPlayPause", + Key::MediaRecord => "MediaRecord", + Key::MediaRewind => "MediaRewind", + Key::MediaStop => "MediaStop", + Key::MediaTrackNext => "MediaTrackNext", + Key::MediaTrackPrevious => "MediaTrackPrevious", + Key::New => "New", + Key::Open => "Open", + Key::Print => "Print", + Key::Save => "Save", + Key::SpellCheck => "SpellCheck", + Key::Key11 => "Key11", + Key::Key12 => "Key12", + Key::AudioBalanceLeft => "AudioBalanceLeft", + Key::AudioBalanceRight => "AudioBalanceRight", + Key::AudioBassBoostDown => "AudioBassBoostDown", + Key::AudioBassBoostToggle => "AudioBassBoostToggle", + Key::AudioBassBoostUp => "AudioBassBoostUp", + Key::AudioFaderFront => "AudioFaderFront", + Key::AudioFaderRear => "AudioFaderRear", + Key::AudioSurroundModeNext => "AudioSurroundModeNext", + Key::AudioTrebleDown => "AudioTrebleDown", + Key::AudioTrebleUp => "AudioTrebleUp", + Key::AudioVolumeDown => "AudioVolumeDown", + Key::AudioVolumeUp => "AudioVolumeUp", + Key::AudioVolumeMute => "AudioVolumeMute", + Key::MicrophoneToggle => "MicrophoneToggle", + Key::MicrophoneVolumeDown => "MicrophoneVolumeDown", + Key::MicrophoneVolumeUp => "MicrophoneVolumeUp", + Key::MicrophoneVolumeMute => "MicrophoneVolumeMute", + Key::SpeechCorrectionList => "SpeechCorrectionList", + Key::SpeechInputToggle => "SpeechInputToggle", + Key::LaunchApplication1 => "LaunchApplication1", + Key::LaunchApplication2 => "LaunchApplication2", + Key::LaunchCalendar => "LaunchCalendar", + Key::LaunchContacts => "LaunchContacts", + Key::LaunchMail => "LaunchMail", + Key::LaunchMediaPlayer => "LaunchMediaPlayer", + Key::LaunchMusicPlayer => "LaunchMusicPlayer", + Key::LaunchPhone => "LaunchPhone", + Key::LaunchScreenSaver => "LaunchScreenSaver", + Key::LaunchSpreadsheet => "LaunchSpreadsheet", + Key::LaunchWebBrowser => "LaunchWebBrowser", + Key::LaunchWebCam => "LaunchWebCam", + Key::LaunchWordProcessor => "LaunchWordProcessor", + Key::BrowserBack => "BrowserBack", + Key::BrowserFavorites => "BrowserFavorites", + Key::BrowserForward => "BrowserForward", + Key::BrowserHome => "BrowserHome", + Key::BrowserRefresh => "BrowserRefresh", + Key::BrowserSearch => "BrowserSearch", + Key::BrowserStop => "BrowserStop", + Key::AppSwitch => "AppSwitch", + Key::Call => "Call", + Key::Camera => "Camera", + Key::CameraFocus => "CameraFocus", + Key::EndCall => "EndCall", + Key::GoBack => "GoBack", + Key::GoHome => "GoHome", + Key::HeadsetHook => "HeadsetHook", + Key::LastNumberRedial => "LastNumberRedial", + Key::Notification => "Notification", + Key::MannerMode => "MannerMode", + Key::VoiceDial => "VoiceDial", + Key::TV => "TV", + Key::TV3DMode => "TV3DMode", + Key::TVAntennaCable => "TVAntennaCable", + Key::TVAudioDescription => "TVAudioDescription", + Key::TVAudioDescriptionMixDown => "TVAudioDescriptionMixDown", + Key::TVAudioDescriptionMixUp => "TVAudioDescriptionMixUp", + Key::TVContentsMenu => "TVContentsMenu", + Key::TVDataService => "TVDataService", + Key::TVInput => "TVInput", + Key::TVInputComponent1 => "TVInputComponent1", + Key::TVInputComponent2 => "TVInputComponent2", + Key::TVInputComposite1 => "TVInputComposite1", + Key::TVInputComposite2 => "TVInputComposite2", + Key::TVInputHDMI1 => "TVInputHDMI1", + Key::TVInputHDMI2 => "TVInputHDMI2", + Key::TVInputHDMI3 => "TVInputHDMI3", + Key::TVInputHDMI4 => "TVInputHDMI4", + Key::TVInputVGA1 => "TVInputVGA1", + Key::TVMediaContext => "TVMediaContext", + Key::TVNetwork => "TVNetwork", + Key::TVNumberEntry => "TVNumberEntry", + Key::TVPower => "TVPower", + Key::TVRadioService => "TVRadioService", + Key::TVSatellite => "TVSatellite", + Key::TVSatelliteBS => "TVSatelliteBS", + Key::TVSatelliteCS => "TVSatelliteCS", + Key::TVSatelliteToggle => "TVSatelliteToggle", + Key::TVTerrestrialAnalog => "TVTerrestrialAnalog", + Key::TVTerrestrialDigital => "TVTerrestrialDigital", + Key::TVTimer => "TVTimer", + Key::AVRInput => "AVRInput", + Key::AVRPower => "AVRPower", + Key::ColorF0Red => "ColorF0Red", + Key::ColorF1Green => "ColorF1Green", + Key::ColorF2Yellow => "ColorF2Yellow", + Key::ColorF3Blue => "ColorF3Blue", + Key::ColorF4Grey => "ColorF4Grey", + Key::ColorF5Brown => "ColorF5Brown", + Key::ClosedCaptionToggle => "ClosedCaptionToggle", + Key::Dimmer => "Dimmer", + Key::DisplaySwap => "DisplaySwap", + Key::DVR => "DVR", + Key::Exit => "Exit", + Key::FavoriteClear0 => "FavoriteClear0", + Key::FavoriteClear1 => "FavoriteClear1", + Key::FavoriteClear2 => "FavoriteClear2", + Key::FavoriteClear3 => "FavoriteClear3", + Key::FavoriteRecall0 => "FavoriteRecall0", + Key::FavoriteRecall1 => "FavoriteRecall1", + Key::FavoriteRecall2 => "FavoriteRecall2", + Key::FavoriteRecall3 => "FavoriteRecall3", + Key::FavoriteStore0 => "FavoriteStore0", + Key::FavoriteStore1 => "FavoriteStore1", + Key::FavoriteStore2 => "FavoriteStore2", + Key::FavoriteStore3 => "FavoriteStore3", + Key::Guide => "Guide", + Key::GuideNextDay => "GuideNextDay", + Key::GuidePreviousDay => "GuidePreviousDay", + Key::Info => "Info", + Key::InstantReplay => "InstantReplay", + Key::Link => "Link", + Key::ListProgram => "ListProgram", + Key::LiveContent => "LiveContent", + Key::Lock => "Lock", + Key::MediaApps => "MediaApps", + Key::MediaAudioTrack => "MediaAudioTrack", + Key::MediaLast => "MediaLast", + Key::MediaSkipBackward => "MediaSkipBackward", + Key::MediaSkipForward => "MediaSkipForward", + Key::MediaStepBackward => "MediaStepBackward", + Key::MediaStepForward => "MediaStepForward", + Key::MediaTopMenu => "MediaTopMenu", + Key::NavigateIn => "NavigateIn", + Key::NavigateNext => "NavigateNext", + Key::NavigateOut => "NavigateOut", + Key::NavigatePrevious => "NavigatePrevious", + Key::NextFavoriteChannel => "NextFavoriteChannel", + Key::NextUserProfile => "NextUserProfile", + Key::OnDemand => "OnDemand", + Key::Pairing => "Pairing", + Key::PinPDown => "PinPDown", + Key::PinPMove => "PinPMove", + Key::PinPToggle => "PinPToggle", + Key::PinPUp => "PinPUp", + Key::PlaySpeedDown => "PlaySpeedDown", + Key::PlaySpeedReset => "PlaySpeedReset", + Key::PlaySpeedUp => "PlaySpeedUp", + Key::RandomToggle => "RandomToggle", + Key::RcLowBattery => "RcLowBattery", + Key::RecordSpeedNext => "RecordSpeedNext", + Key::RfBypass => "RfBypass", + Key::ScanChannelsToggle => "ScanChannelsToggle", + Key::ScreenModeNext => "ScreenModeNext", + Key::Settings => "Settings", + Key::SplitScreenToggle => "SplitScreenToggle", + Key::STBInput => "STBInput", + Key::STBPower => "STBPower", + Key::Subtitle => "Subtitle", + Key::Teletext => "Teletext", + Key::VideoModeNext => "VideoModeNext", + Key::Wink => "Wink", + Key::ZoomToggle => "ZoomToggle", + Key::F1 => "F1", + Key::F2 => "F2", + Key::F3 => "F3", + Key::F4 => "F4", + Key::F5 => "F5", + Key::F6 => "F6", + Key::F7 => "F7", + Key::F8 => "F8", + Key::F9 => "F9", + Key::F10 => "F10", + Key::F11 => "F11", + Key::F12 => "F12", + Key::F13 => "F13", + Key::F14 => "F14", + Key::F15 => "F15", + Key::F16 => "F16", + Key::F17 => "F17", + Key::F18 => "F18", + Key::F19 => "F19", + Key::F20 => "F20", + Key::F21 => "F21", + Key::F22 => "F22", + Key::F23 => "F23", + Key::F24 => "F24", + Key::F25 => "F25", + Key::F26 => "F26", + Key::F27 => "F27", + Key::F28 => "F28", + Key::F29 => "F29", + Key::F30 => "F30", + Key::F31 => "F31", + Key::F32 => "F32", + Key::F33 => "F33", + Key::F34 => "F34", + Key::F35 => "F35", + } + } +} + impl<'a> Key<'a> { pub fn to_text(&self) -> Option<&'a str> { match self { diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 521df0b54e..757926e441 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -5,11 +5,8 @@ use super::{ runner, window, }; use crate::dpi::{PhysicalSize, Size}; -use crate::event::{ - DeviceEvent, DeviceId, ElementState, Event, KeyEvent, RawKeyEvent, TouchPhase, WindowEvent, -}; +use crate::event::{DeviceEvent, DeviceId, ElementState, Event, KeyEvent, TouchPhase, WindowEvent}; use crate::event_loop::ControlFlow; -use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState}; use crate::monitor::MonitorHandle as RootMH; use crate::window::{Theme, WindowId}; use std::cell::RefCell; @@ -85,7 +82,7 @@ impl WindowTarget { logical_key, text, location, - state: ElementState::Released, + state: ElementState::Pressed, repeat, platform_specific: KeyEventExtra, }, @@ -115,8 +112,8 @@ impl WindowTarget { }) }); - let runner = self.runner.clone(); // TODO: What to do here? + // let runner = self.runner.clone(); // canvas.on_received_character(move |char_code| { // runner.send_event(Event::WindowEvent { // window_id: WindowId(id), diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index e6982d78ee..429d4da417 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -4,7 +4,7 @@ use super::media_query_handle::MediaQueryListHandle; use crate::dpi::{LogicalPosition, PhysicalPosition, PhysicalSize}; use crate::error::OsError as RootOE; use crate::event::{MouseButton, MouseScrollDelta}; -use crate::keyboard::{Key, KeyCode, ModifiersState, KeyLocation}; +use crate::keyboard::{Key, KeyCode, KeyLocation, ModifiersState}; use crate::platform_impl::{OsError, PlatformSpecificWindowBuilderAttributes}; use std::cell::RefCell; @@ -197,24 +197,24 @@ impl Canvas { )); } - pub fn on_received_character(&mut self, mut handler: F) - where - F: 'static + FnMut(char), - { - // TODO: Use `beforeinput`. - // - // The `keypress` event is deprecated, but there does not seem to be a - // viable/compatible alternative as of now. `beforeinput` is still widely - // unsupported. - self.on_received_character = Some(self.common.add_user_event( - "keypress", - move |event: KeyboardEvent| { - // Supress further handling to stop keys like the space key from scrolling the page. - event.prevent_default(); - handler(event::codepoint(&event)); - }, - )); - } + // pub fn on_received_character(&mut self, mut handler: F) + // where + // F: 'static + FnMut(char), + // { + // // TODO: Use `beforeinput`. + // // + // // The `keypress` event is deprecated, but there does not seem to be a + // // viable/compatible alternative as of now. `beforeinput` is still widely + // // unsupported. + // self.on_received_character = Some(self.common.add_user_event( + // "keypress", + // move |event: KeyboardEvent| { + // // Supress further handling to stop keys like the space key from scrolling the page. + // event.prevent_default(); + // handler(event::codepoint(&event)); + // }, + // )); + // } pub fn on_cursor_leave(&mut self, handler: F) where diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index b311de563f..79929d69f3 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -63,43 +63,58 @@ pub fn mouse_scroll_delta(event: &WheelEvent) -> Option { } pub fn key_code(event: &KeyboardEvent) -> KeyCode { - // TODO: Fill out stub. let code = event.code(); - KeyCode::Enter + KeyCode::from_key_code_attribute_value(&code) } pub fn key(event: &KeyboardEvent) -> Key<'static> { - // TODO: Fill out stub. - Key::Enter + let key = event.key(); + // TODO: Fix unbounded leak + let key = Box::leak(String::from(key).into_boxed_str()); + Key::from_key_attribute_value(key) } pub fn key_text(event: &KeyboardEvent) -> Option<&'static str> { - // TODO: Fill out stub. - None + let key = event.key(); + if let Key::Character(text) = Key::from_key_attribute_value(&key) { + // TODO: Fix unbounded leak + Some(Box::leak(String::from(text).into_boxed_str())) + } else { + None + } } pub fn key_location(event: &KeyboardEvent) -> KeyLocation { - // TODO: Fill out stub. - KeyLocation::Standard + let location = event.location(); + // TODO: Use constants rather than integer literals? + match location { + 0 => KeyLocation::Standard, + 1 => KeyLocation::Left, + 2 => KeyLocation::Right, + 3 => KeyLocation::Numpad, + // TODO: Is this reasonable to do? + _ => KeyLocation::Standard, + } } pub fn key_repeat(event: &KeyboardEvent) -> bool { - // TODO: Fill out stub. - false + event.repeat() } -pub fn keyboard_modifiers(event: &KeyboardEvent) -> ModifiersState { - let mut m = ModifiersState::empty(); - m.set(ModifiersState::SHIFT, event.shift_key()); - m.set(ModifiersState::CONTROL, event.ctrl_key()); - m.set(ModifiersState::ALT, event.alt_key()); - m.set(ModifiersState::SUPER, event.meta_key()); - m -} +// TODO: What should be done about `KeyboardEvent.isComposing`? -pub fn codepoint(event: &KeyboardEvent) -> char { - // `event.key()` always returns a non-empty `String`. Therefore, this should - // never panic. - // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key - event.key().chars().next().unwrap() -} +// pub fn keyboard_modifiers(event: &KeyboardEvent) -> ModifiersState { +// let mut m = ModifiersState::empty(); +// m.set(ModifiersState::SHIFT, event.shift_key()); +// m.set(ModifiersState::CONTROL, event.ctrl_key()); +// m.set(ModifiersState::ALT, event.alt_key()); +// m.set(ModifiersState::SUPER, event.meta_key()); +// m +// } + +// pub fn codepoint(event: &KeyboardEvent) -> char { +// // `event.key()` always returns a non-empty `String`. Therefore, this should +// // never panic. +// // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key +// event.key().chars().next().unwrap() +// } From c687a4e8380d2142b218382da83de1b8457de11c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Fri, 14 May 2021 14:57:02 +0200 Subject: [PATCH 03/13] Use a literal whitespace character --- src/keyboard.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index 878967f626..5dd99be9d4 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -729,7 +729,7 @@ impl KeyCode { "MetaRight" => KeyCode::SuperRight, "ShiftLeft" => KeyCode::ShiftLeft, "ShiftRight" => KeyCode::ShiftRight, - "Space" => KeyCode::Space, + " " => KeyCode::Space, "Tab" => KeyCode::Tab, "Convert" => KeyCode::Convert, "KanaMode" => KeyCode::KanaMode, @@ -932,7 +932,7 @@ impl KeyCode { KeyCode::SuperRight => "MetaRight", KeyCode::ShiftLeft => "ShiftLeft", KeyCode::ShiftRight => "ShiftRight", - KeyCode::Space => "Space", + KeyCode::Space => " ", KeyCode::Tab => "Tab", KeyCode::Convert => "Convert", KeyCode::KanaMode => "KanaMode", From ccef4cf7aaf918f2ca161471fab7ef6b90e605ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Fri, 14 May 2021 17:49:40 +0200 Subject: [PATCH 04/13] Move conversion functions into a web submodule --- src/keyboard.rs | 1032 ----------------------------- src/platform_impl/web/keyboard.rs | 521 +++++++++++++++ src/platform_impl/web/mod.rs | 1 + 3 files changed, 522 insertions(+), 1032 deletions(-) create mode 100644 src/platform_impl/web/keyboard.rs diff --git a/src/keyboard.rs b/src/keyboard.rs index 5dd99be9d4..a4390318d3 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -664,409 +664,6 @@ pub enum KeyCode { F35, } -impl KeyCode { - pub fn from_key_code_attribute_value(kcav: &str) -> Self { - match kcav { - "Backquote" => KeyCode::Backquote, - "Backslash" => KeyCode::Backslash, - "BracketLeft" => KeyCode::BracketLeft, - "BracketRight" => KeyCode::BracketRight, - "Comma" => KeyCode::Comma, - "Digit0" => KeyCode::Digit0, - "Digit1" => KeyCode::Digit1, - "Digit2" => KeyCode::Digit2, - "Digit3" => KeyCode::Digit3, - "Digit4" => KeyCode::Digit4, - "Digit5" => KeyCode::Digit5, - "Digit6" => KeyCode::Digit6, - "Digit7" => KeyCode::Digit7, - "Digit8" => KeyCode::Digit8, - "Digit9" => KeyCode::Digit9, - "Equal" => KeyCode::Equal, - "IntlBackslash" => KeyCode::IntlBackslash, - "IntlRo" => KeyCode::IntlRo, - "IntlYen" => KeyCode::IntlYen, - "KeyA" => KeyCode::KeyA, - "KeyB" => KeyCode::KeyB, - "KeyC" => KeyCode::KeyC, - "KeyD" => KeyCode::KeyD, - "KeyE" => KeyCode::KeyE, - "KeyF" => KeyCode::KeyF, - "KeyG" => KeyCode::KeyG, - "KeyH" => KeyCode::KeyH, - "KeyI" => KeyCode::KeyI, - "KeyJ" => KeyCode::KeyJ, - "KeyK" => KeyCode::KeyK, - "KeyL" => KeyCode::KeyL, - "KeyM" => KeyCode::KeyM, - "KeyN" => KeyCode::KeyN, - "KeyO" => KeyCode::KeyO, - "KeyP" => KeyCode::KeyP, - "KeyQ" => KeyCode::KeyQ, - "KeyR" => KeyCode::KeyR, - "KeyS" => KeyCode::KeyS, - "KeyT" => KeyCode::KeyT, - "KeyU" => KeyCode::KeyU, - "KeyV" => KeyCode::KeyV, - "KeyW" => KeyCode::KeyW, - "KeyX" => KeyCode::KeyX, - "KeyY" => KeyCode::KeyY, - "KeyZ" => KeyCode::KeyZ, - "Minus" => KeyCode::Minus, - "Period" => KeyCode::Period, - "Quote" => KeyCode::Quote, - "Semicolon" => KeyCode::Semicolon, - "Slash" => KeyCode::Slash, - "AltLeft" => KeyCode::AltLeft, - "AltRight" => KeyCode::AltRight, - "Backspace" => KeyCode::Backspace, - "CapsLock" => KeyCode::CapsLock, - "ContextMenu" => KeyCode::ContextMenu, - "ControlLeft" => KeyCode::ControlLeft, - "ControlRight" => KeyCode::ControlRight, - "Enter" => KeyCode::Enter, - "MetaLeft" => KeyCode::SuperLeft, - "MetaRight" => KeyCode::SuperRight, - "ShiftLeft" => KeyCode::ShiftLeft, - "ShiftRight" => KeyCode::ShiftRight, - " " => KeyCode::Space, - "Tab" => KeyCode::Tab, - "Convert" => KeyCode::Convert, - "KanaMode" => KeyCode::KanaMode, - "Lang1" => KeyCode::Lang1, - "Lang2" => KeyCode::Lang2, - "Lang3" => KeyCode::Lang3, - "Lang4" => KeyCode::Lang4, - "Lang5" => KeyCode::Lang5, - "NonConvert" => KeyCode::NonConvert, - "Delete" => KeyCode::Delete, - "End" => KeyCode::End, - "Help" => KeyCode::Help, - "Home" => KeyCode::Home, - "Insert" => KeyCode::Insert, - "PageDown" => KeyCode::PageDown, - "PageUp" => KeyCode::PageUp, - "ArrowDown" => KeyCode::ArrowDown, - "ArrowLeft" => KeyCode::ArrowLeft, - "ArrowRight" => KeyCode::ArrowRight, - "ArrowUp" => KeyCode::ArrowUp, - "NumLock" => KeyCode::NumLock, - "Numpad0" => KeyCode::Numpad0, - "Numpad1" => KeyCode::Numpad1, - "Numpad2" => KeyCode::Numpad2, - "Numpad3" => KeyCode::Numpad3, - "Numpad4" => KeyCode::Numpad4, - "Numpad5" => KeyCode::Numpad5, - "Numpad6" => KeyCode::Numpad6, - "Numpad7" => KeyCode::Numpad7, - "Numpad8" => KeyCode::Numpad8, - "Numpad9" => KeyCode::Numpad9, - "NumpadAdd" => KeyCode::NumpadAdd, - "NumpadBackspace" => KeyCode::NumpadBackspace, - "NumpadClear" => KeyCode::NumpadClear, - "NumpadClearEntry" => KeyCode::NumpadClearEntry, - "NumpadComma" => KeyCode::NumpadComma, - "NumpadDecimal" => KeyCode::NumpadDecimal, - "NumpadDivide" => KeyCode::NumpadDivide, - "NumpadEnter" => KeyCode::NumpadEnter, - "NumpadEqual" => KeyCode::NumpadEqual, - "NumpadHash" => KeyCode::NumpadHash, - "NumpadMemoryAdd" => KeyCode::NumpadMemoryAdd, - "NumpadMemoryClear" => KeyCode::NumpadMemoryClear, - "NumpadMemoryRecall" => KeyCode::NumpadMemoryRecall, - "NumpadMemoryStore" => KeyCode::NumpadMemoryStore, - "NumpadMemorySubtract" => KeyCode::NumpadMemorySubtract, - "NumpadMultiply" => KeyCode::NumpadMultiply, - "NumpadParenLeft" => KeyCode::NumpadParenLeft, - "NumpadParenRight" => KeyCode::NumpadParenRight, - "NumpadStar" => KeyCode::NumpadStar, - "NumpadSubtract" => KeyCode::NumpadSubtract, - "Escape" => KeyCode::Escape, - "Fn" => KeyCode::Fn, - "FnLock" => KeyCode::FnLock, - "PrintScreen" => KeyCode::PrintScreen, - "ScrollLock" => KeyCode::ScrollLock, - "Pause" => KeyCode::Pause, - "BrowserBack" => KeyCode::BrowserBack, - "BrowserFavorites" => KeyCode::BrowserFavorites, - "BrowserForward" => KeyCode::BrowserForward, - "BrowserHome" => KeyCode::BrowserHome, - "BrowserRefresh" => KeyCode::BrowserRefresh, - "BrowserSearch" => KeyCode::BrowserSearch, - "BrowserStop" => KeyCode::BrowserStop, - "Eject" => KeyCode::Eject, - "LaunchApp1" => KeyCode::LaunchApp1, - "LaunchApp2" => KeyCode::LaunchApp2, - "LaunchMail" => KeyCode::LaunchMail, - "MediaPlayPause" => KeyCode::MediaPlayPause, - "MediaSelect" => KeyCode::MediaSelect, - "MediaStop" => KeyCode::MediaStop, - "MediaTrackNext" => KeyCode::MediaTrackNext, - "MediaTrackPrevious" => KeyCode::MediaTrackPrevious, - "Power" => KeyCode::Power, - "Sleep" => KeyCode::Sleep, - "AudioVolumeDown" => KeyCode::AudioVolumeDown, - "AudioVolumeMute" => KeyCode::AudioVolumeMute, - "AudioVolumeUp" => KeyCode::AudioVolumeUp, - "WakeUp" => KeyCode::WakeUp, - "Hyper" => KeyCode::Hyper, - "Turbo" => KeyCode::Turbo, - "Abort" => KeyCode::Abort, - "Resume" => KeyCode::Resume, - "Suspend" => KeyCode::Suspend, - "Again" => KeyCode::Again, - "Copy" => KeyCode::Copy, - "Cut" => KeyCode::Cut, - "Find" => KeyCode::Find, - "Open" => KeyCode::Open, - "Paste" => KeyCode::Paste, - "Props" => KeyCode::Props, - "Select" => KeyCode::Select, - "Undo" => KeyCode::Undo, - "Hiragana" => KeyCode::Hiragana, - "Katakana" => KeyCode::Katakana, - "F1" => KeyCode::F1, - "F2" => KeyCode::F2, - "F3" => KeyCode::F3, - "F4" => KeyCode::F4, - "F5" => KeyCode::F5, - "F6" => KeyCode::F6, - "F7" => KeyCode::F7, - "F8" => KeyCode::F8, - "F9" => KeyCode::F9, - "F10" => KeyCode::F10, - "F11" => KeyCode::F11, - "F12" => KeyCode::F12, - "F13" => KeyCode::F13, - "F14" => KeyCode::F14, - "F15" => KeyCode::F15, - "F16" => KeyCode::F16, - "F17" => KeyCode::F17, - "F18" => KeyCode::F18, - "F19" => KeyCode::F19, - "F20" => KeyCode::F20, - "F21" => KeyCode::F21, - "F22" => KeyCode::F22, - "F23" => KeyCode::F23, - "F24" => KeyCode::F24, - "F25" => KeyCode::F25, - "F26" => KeyCode::F26, - "F27" => KeyCode::F27, - "F28" => KeyCode::F28, - "F29" => KeyCode::F29, - "F30" => KeyCode::F30, - "F31" => KeyCode::F31, - "F32" => KeyCode::F32, - "F33" => KeyCode::F33, - "F34" => KeyCode::F34, - "F35" => KeyCode::F35, - // TODO: Fix unbounded leak - string @ _ => KeyCode::Unidentified(NativeKeyCode::Web(Box::leak( - String::from(string).into_boxed_str(), - ))), - } - } - - pub fn to_key_code_attribute_value(&self) -> &'static str { - match self { - KeyCode::Unidentified(_) => "Unidentified", - KeyCode::Backquote => "Backquote", - KeyCode::Backslash => "Backslash", - KeyCode::BracketLeft => "BracketLeft", - KeyCode::BracketRight => "BracketRight", - KeyCode::Comma => "Comma", - KeyCode::Digit0 => "Digit0", - KeyCode::Digit1 => "Digit1", - KeyCode::Digit2 => "Digit2", - KeyCode::Digit3 => "Digit3", - KeyCode::Digit4 => "Digit4", - KeyCode::Digit5 => "Digit5", - KeyCode::Digit6 => "Digit6", - KeyCode::Digit7 => "Digit7", - KeyCode::Digit8 => "Digit8", - KeyCode::Digit9 => "Digit9", - KeyCode::Equal => "Equal", - KeyCode::IntlBackslash => "IntlBackslash", - KeyCode::IntlRo => "IntlRo", - KeyCode::IntlYen => "IntlYen", - KeyCode::KeyA => "KeyA", - KeyCode::KeyB => "KeyB", - KeyCode::KeyC => "KeyC", - KeyCode::KeyD => "KeyD", - KeyCode::KeyE => "KeyE", - KeyCode::KeyF => "KeyF", - KeyCode::KeyG => "KeyG", - KeyCode::KeyH => "KeyH", - KeyCode::KeyI => "KeyI", - KeyCode::KeyJ => "KeyJ", - KeyCode::KeyK => "KeyK", - KeyCode::KeyL => "KeyL", - KeyCode::KeyM => "KeyM", - KeyCode::KeyN => "KeyN", - KeyCode::KeyO => "KeyO", - KeyCode::KeyP => "KeyP", - KeyCode::KeyQ => "KeyQ", - KeyCode::KeyR => "KeyR", - KeyCode::KeyS => "KeyS", - KeyCode::KeyT => "KeyT", - KeyCode::KeyU => "KeyU", - KeyCode::KeyV => "KeyV", - KeyCode::KeyW => "KeyW", - KeyCode::KeyX => "KeyX", - KeyCode::KeyY => "KeyY", - KeyCode::KeyZ => "KeyZ", - KeyCode::Minus => "Minus", - KeyCode::Period => "Period", - KeyCode::Quote => "Quote", - KeyCode::Semicolon => "Semicolon", - KeyCode::Slash => "Slash", - KeyCode::AltLeft => "AltLeft", - KeyCode::AltRight => "AltRight", - KeyCode::Backspace => "Backspace", - KeyCode::CapsLock => "CapsLock", - KeyCode::ContextMenu => "ContextMenu", - KeyCode::ControlLeft => "ControlLeft", - KeyCode::ControlRight => "ControlRight", - KeyCode::Enter => "Enter", - KeyCode::SuperLeft => "MetaLeft", - KeyCode::SuperRight => "MetaRight", - KeyCode::ShiftLeft => "ShiftLeft", - KeyCode::ShiftRight => "ShiftRight", - KeyCode::Space => " ", - KeyCode::Tab => "Tab", - KeyCode::Convert => "Convert", - KeyCode::KanaMode => "KanaMode", - KeyCode::Lang1 => "Lang1", - KeyCode::Lang2 => "Lang2", - KeyCode::Lang3 => "Lang3", - KeyCode::Lang4 => "Lang4", - KeyCode::Lang5 => "Lang5", - KeyCode::NonConvert => "NonConvert", - KeyCode::Delete => "Delete", - KeyCode::End => "End", - KeyCode::Help => "Help", - KeyCode::Home => "Home", - KeyCode::Insert => "Insert", - KeyCode::PageDown => "PageDown", - KeyCode::PageUp => "PageUp", - KeyCode::ArrowDown => "ArrowDown", - KeyCode::ArrowLeft => "ArrowLeft", - KeyCode::ArrowRight => "ArrowRight", - KeyCode::ArrowUp => "ArrowUp", - KeyCode::NumLock => "NumLock", - KeyCode::Numpad0 => "Numpad0", - KeyCode::Numpad1 => "Numpad1", - KeyCode::Numpad2 => "Numpad2", - KeyCode::Numpad3 => "Numpad3", - KeyCode::Numpad4 => "Numpad4", - KeyCode::Numpad5 => "Numpad5", - KeyCode::Numpad6 => "Numpad6", - KeyCode::Numpad7 => "Numpad7", - KeyCode::Numpad8 => "Numpad8", - KeyCode::Numpad9 => "Numpad9", - KeyCode::NumpadAdd => "NumpadAdd", - KeyCode::NumpadBackspace => "NumpadBackspace", - KeyCode::NumpadClear => "NumpadClear", - KeyCode::NumpadClearEntry => "NumpadClearEntry", - KeyCode::NumpadComma => "NumpadComma", - KeyCode::NumpadDecimal => "NumpadDecimal", - KeyCode::NumpadDivide => "NumpadDivide", - KeyCode::NumpadEnter => "NumpadEnter", - KeyCode::NumpadEqual => "NumpadEqual", - KeyCode::NumpadHash => "NumpadHash", - KeyCode::NumpadMemoryAdd => "NumpadMemoryAdd", - KeyCode::NumpadMemoryClear => "NumpadMemoryClear", - KeyCode::NumpadMemoryRecall => "NumpadMemoryRecall", - KeyCode::NumpadMemoryStore => "NumpadMemoryStore", - KeyCode::NumpadMemorySubtract => "NumpadMemorySubtract", - KeyCode::NumpadMultiply => "NumpadMultiply", - KeyCode::NumpadParenLeft => "NumpadParenLeft", - KeyCode::NumpadParenRight => "NumpadParenRight", - KeyCode::NumpadStar => "NumpadStar", - KeyCode::NumpadSubtract => "NumpadSubtract", - KeyCode::Escape => "Escape", - KeyCode::Fn => "Fn", - KeyCode::FnLock => "FnLock", - KeyCode::PrintScreen => "PrintScreen", - KeyCode::ScrollLock => "ScrollLock", - KeyCode::Pause => "Pause", - KeyCode::BrowserBack => "BrowserBack", - KeyCode::BrowserFavorites => "BrowserFavorites", - KeyCode::BrowserForward => "BrowserForward", - KeyCode::BrowserHome => "BrowserHome", - KeyCode::BrowserRefresh => "BrowserRefresh", - KeyCode::BrowserSearch => "BrowserSearch", - KeyCode::BrowserStop => "BrowserStop", - KeyCode::Eject => "Eject", - KeyCode::LaunchApp1 => "LaunchApp1", - KeyCode::LaunchApp2 => "LaunchApp2", - KeyCode::LaunchMail => "LaunchMail", - KeyCode::MediaPlayPause => "MediaPlayPause", - KeyCode::MediaSelect => "MediaSelect", - KeyCode::MediaStop => "MediaStop", - KeyCode::MediaTrackNext => "MediaTrackNext", - KeyCode::MediaTrackPrevious => "MediaTrackPrevious", - KeyCode::Power => "Power", - KeyCode::Sleep => "Sleep", - KeyCode::AudioVolumeDown => "AudioVolumeDown", - KeyCode::AudioVolumeMute => "AudioVolumeMute", - KeyCode::AudioVolumeUp => "AudioVolumeUp", - KeyCode::WakeUp => "WakeUp", - KeyCode::Hyper => "Hyper", - KeyCode::Turbo => "Turbo", - KeyCode::Abort => "Abort", - KeyCode::Resume => "Resume", - KeyCode::Suspend => "Suspend", - KeyCode::Again => "Again", - KeyCode::Copy => "Copy", - KeyCode::Cut => "Cut", - KeyCode::Find => "Find", - KeyCode::Open => "Open", - KeyCode::Paste => "Paste", - KeyCode::Props => "Props", - KeyCode::Select => "Select", - KeyCode::Undo => "Undo", - KeyCode::Hiragana => "Hiragana", - KeyCode::Katakana => "Katakana", - KeyCode::F1 => "F1", - KeyCode::F2 => "F2", - KeyCode::F3 => "F3", - KeyCode::F4 => "F4", - KeyCode::F5 => "F5", - KeyCode::F6 => "F6", - KeyCode::F7 => "F7", - KeyCode::F8 => "F8", - KeyCode::F9 => "F9", - KeyCode::F10 => "F10", - KeyCode::F11 => "F11", - KeyCode::F12 => "F12", - KeyCode::F13 => "F13", - KeyCode::F14 => "F14", - KeyCode::F15 => "F15", - KeyCode::F16 => "F16", - KeyCode::F17 => "F17", - KeyCode::F18 => "F18", - KeyCode::F19 => "F19", - KeyCode::F20 => "F20", - KeyCode::F21 => "F21", - KeyCode::F22 => "F22", - KeyCode::F23 => "F23", - KeyCode::F24 => "F24", - KeyCode::F25 => "F25", - KeyCode::F26 => "F26", - KeyCode::F27 => "F27", - KeyCode::F28 => "F28", - KeyCode::F29 => "F29", - KeyCode::F30 => "F30", - KeyCode::F31 => "F31", - KeyCode::F32 => "F32", - KeyCode::F33 => "F33", - KeyCode::F34 => "F34", - KeyCode::F35 => "F35", - } - } -} - /// Key represents the meaning of a keypress. /// /// This mostly conforms to the UI Events Specification's [`KeyboardEvent.key`] with a few @@ -1801,635 +1398,6 @@ pub enum Key<'a> { F35, } -impl<'a> Key<'a> { - pub fn from_key_attribute_value(kav: &'a str) -> Self { - match kav { - // TODO: Report this in a better way. - "Unidentified" => Key::Unidentified(NativeKeyCode::Web("Unidentified")), - "Dead" => Key::Dead(None), - "Alt" => Key::Alt, - "AltGraph" => Key::AltGraph, - "CapsLock" => Key::CapsLock, - "Control" => Key::Control, - "Fn" => Key::Fn, - "FnLock" => Key::FnLock, - "NumLock" => Key::NumLock, - "ScrollLock" => Key::ScrollLock, - "Shift" => Key::Shift, - "Symbol" => Key::Symbol, - "SymbolLock" => Key::SymbolLock, - "Hyper" => Key::Hyper, - "Meta" => Key::Super, - "Enter" => Key::Enter, - "Tab" => Key::Tab, - "Space" => Key::Space, - "ArrowDown" => Key::ArrowDown, - "ArrowLeft" => Key::ArrowLeft, - "ArrowRight" => Key::ArrowRight, - "ArrowUp" => Key::ArrowUp, - "End" => Key::End, - "Home" => Key::Home, - "PageDown" => Key::PageDown, - "PageUp" => Key::PageUp, - "Backspace" => Key::Backspace, - "Clear" => Key::Clear, - "Copy" => Key::Copy, - "CrSel" => Key::CrSel, - "Cut" => Key::Cut, - "Delete" => Key::Delete, - "EraseEof" => Key::EraseEof, - "ExSel" => Key::ExSel, - "Insert" => Key::Insert, - "Paste" => Key::Paste, - "Redo" => Key::Redo, - "Undo" => Key::Undo, - "Accept" => Key::Accept, - "Again" => Key::Again, - "Attn" => Key::Attn, - "Cancel" => Key::Cancel, - "ContextMenu" => Key::ContextMenu, - "Escape" => Key::Escape, - "Execute" => Key::Execute, - "Find" => Key::Find, - "Help" => Key::Help, - "Pause" => Key::Pause, - "Play" => Key::Play, - "Props" => Key::Props, - "Select" => Key::Select, - "ZoomIn" => Key::ZoomIn, - "ZoomOut" => Key::ZoomOut, - "BrightnessDown" => Key::BrightnessDown, - "BrightnessUp" => Key::BrightnessUp, - "Eject" => Key::Eject, - "LogOff" => Key::LogOff, - "Power" => Key::Power, - "PowerOff" => Key::PowerOff, - "PrintScreen" => Key::PrintScreen, - "Hibernate" => Key::Hibernate, - "Standby" => Key::Standby, - "WakeUp" => Key::WakeUp, - "AllCandidates" => Key::AllCandidates, - "Alphanumeric" => Key::Alphanumeric, - "CodeInput" => Key::CodeInput, - "Compose" => Key::Compose, - "Convert" => Key::Convert, - "FinalMode" => Key::FinalMode, - "GroupFirst" => Key::GroupFirst, - "GroupLast" => Key::GroupLast, - "GroupNext" => Key::GroupNext, - "GroupPrevious" => Key::GroupPrevious, - "ModeChange" => Key::ModeChange, - "NextCandidate" => Key::NextCandidate, - "NonConvert" => Key::NonConvert, - "PreviousCandidate" => Key::PreviousCandidate, - "Process" => Key::Process, - "SingleCandidate" => Key::SingleCandidate, - "HangulMode" => Key::HangulMode, - "HanjaMode" => Key::HanjaMode, - "JunjaMode" => Key::JunjaMode, - "Eisu" => Key::Eisu, - "Hankaku" => Key::Hankaku, - "Hiragana" => Key::Hiragana, - "HiraganaKatakana" => Key::HiraganaKatakana, - "KanaMode" => Key::KanaMode, - "KanjiMode" => Key::KanjiMode, - "Katakana" => Key::Katakana, - "Romaji" => Key::Romaji, - "Zenkaku" => Key::Zenkaku, - "ZenkakuHankaku" => Key::ZenkakuHankaku, - "Soft1" => Key::Soft1, - "Soft2" => Key::Soft2, - "Soft3" => Key::Soft3, - "Soft4" => Key::Soft4, - "ChannelDown" => Key::ChannelDown, - "ChannelUp" => Key::ChannelUp, - "Close" => Key::Close, - "MailForward" => Key::MailForward, - "MailReply" => Key::MailReply, - "MailSend" => Key::MailSend, - "MediaClose" => Key::MediaClose, - "MediaFastForward" => Key::MediaFastForward, - "MediaPause" => Key::MediaPause, - "MediaPlay" => Key::MediaPlay, - "MediaPlayPause" => Key::MediaPlayPause, - "MediaRecord" => Key::MediaRecord, - "MediaRewind" => Key::MediaRewind, - "MediaStop" => Key::MediaStop, - "MediaTrackNext" => Key::MediaTrackNext, - "MediaTrackPrevious" => Key::MediaTrackPrevious, - "New" => Key::New, - "Open" => Key::Open, - "Print" => Key::Print, - "Save" => Key::Save, - "SpellCheck" => Key::SpellCheck, - "Key11" => Key::Key11, - "Key12" => Key::Key12, - "AudioBalanceLeft" => Key::AudioBalanceLeft, - "AudioBalanceRight" => Key::AudioBalanceRight, - "AudioBassBoostDown" => Key::AudioBassBoostDown, - "AudioBassBoostToggle" => Key::AudioBassBoostToggle, - "AudioBassBoostUp" => Key::AudioBassBoostUp, - "AudioFaderFront" => Key::AudioFaderFront, - "AudioFaderRear" => Key::AudioFaderRear, - "AudioSurroundModeNext" => Key::AudioSurroundModeNext, - "AudioTrebleDown" => Key::AudioTrebleDown, - "AudioTrebleUp" => Key::AudioTrebleUp, - "AudioVolumeDown" => Key::AudioVolumeDown, - "AudioVolumeUp" => Key::AudioVolumeUp, - "AudioVolumeMute" => Key::AudioVolumeMute, - "MicrophoneToggle" => Key::MicrophoneToggle, - "MicrophoneVolumeDown" => Key::MicrophoneVolumeDown, - "MicrophoneVolumeUp" => Key::MicrophoneVolumeUp, - "MicrophoneVolumeMute" => Key::MicrophoneVolumeMute, - "SpeechCorrectionList" => Key::SpeechCorrectionList, - "SpeechInputToggle" => Key::SpeechInputToggle, - "LaunchApplication1" => Key::LaunchApplication1, - "LaunchApplication2" => Key::LaunchApplication2, - "LaunchCalendar" => Key::LaunchCalendar, - "LaunchContacts" => Key::LaunchContacts, - "LaunchMail" => Key::LaunchMail, - "LaunchMediaPlayer" => Key::LaunchMediaPlayer, - "LaunchMusicPlayer" => Key::LaunchMusicPlayer, - "LaunchPhone" => Key::LaunchPhone, - "LaunchScreenSaver" => Key::LaunchScreenSaver, - "LaunchSpreadsheet" => Key::LaunchSpreadsheet, - "LaunchWebBrowser" => Key::LaunchWebBrowser, - "LaunchWebCam" => Key::LaunchWebCam, - "LaunchWordProcessor" => Key::LaunchWordProcessor, - "BrowserBack" => Key::BrowserBack, - "BrowserFavorites" => Key::BrowserFavorites, - "BrowserForward" => Key::BrowserForward, - "BrowserHome" => Key::BrowserHome, - "BrowserRefresh" => Key::BrowserRefresh, - "BrowserSearch" => Key::BrowserSearch, - "BrowserStop" => Key::BrowserStop, - "AppSwitch" => Key::AppSwitch, - "Call" => Key::Call, - "Camera" => Key::Camera, - "CameraFocus" => Key::CameraFocus, - "EndCall" => Key::EndCall, - "GoBack" => Key::GoBack, - "GoHome" => Key::GoHome, - "HeadsetHook" => Key::HeadsetHook, - "LastNumberRedial" => Key::LastNumberRedial, - "Notification" => Key::Notification, - "MannerMode" => Key::MannerMode, - "VoiceDial" => Key::VoiceDial, - "TV" => Key::TV, - "TV3DMode" => Key::TV3DMode, - "TVAntennaCable" => Key::TVAntennaCable, - "TVAudioDescription" => Key::TVAudioDescription, - "TVAudioDescriptionMixDown" => Key::TVAudioDescriptionMixDown, - "TVAudioDescriptionMixUp" => Key::TVAudioDescriptionMixUp, - "TVContentsMenu" => Key::TVContentsMenu, - "TVDataService" => Key::TVDataService, - "TVInput" => Key::TVInput, - "TVInputComponent1" => Key::TVInputComponent1, - "TVInputComponent2" => Key::TVInputComponent2, - "TVInputComposite1" => Key::TVInputComposite1, - "TVInputComposite2" => Key::TVInputComposite2, - "TVInputHDMI1" => Key::TVInputHDMI1, - "TVInputHDMI2" => Key::TVInputHDMI2, - "TVInputHDMI3" => Key::TVInputHDMI3, - "TVInputHDMI4" => Key::TVInputHDMI4, - "TVInputVGA1" => Key::TVInputVGA1, - "TVMediaContext" => Key::TVMediaContext, - "TVNetwork" => Key::TVNetwork, - "TVNumberEntry" => Key::TVNumberEntry, - "TVPower" => Key::TVPower, - "TVRadioService" => Key::TVRadioService, - "TVSatellite" => Key::TVSatellite, - "TVSatelliteBS" => Key::TVSatelliteBS, - "TVSatelliteCS" => Key::TVSatelliteCS, - "TVSatelliteToggle" => Key::TVSatelliteToggle, - "TVTerrestrialAnalog" => Key::TVTerrestrialAnalog, - "TVTerrestrialDigital" => Key::TVTerrestrialDigital, - "TVTimer" => Key::TVTimer, - "AVRInput" => Key::AVRInput, - "AVRPower" => Key::AVRPower, - "ColorF0Red" => Key::ColorF0Red, - "ColorF1Green" => Key::ColorF1Green, - "ColorF2Yellow" => Key::ColorF2Yellow, - "ColorF3Blue" => Key::ColorF3Blue, - "ColorF4Grey" => Key::ColorF4Grey, - "ColorF5Brown" => Key::ColorF5Brown, - "ClosedCaptionToggle" => Key::ClosedCaptionToggle, - "Dimmer" => Key::Dimmer, - "DisplaySwap" => Key::DisplaySwap, - "DVR" => Key::DVR, - "Exit" => Key::Exit, - "FavoriteClear0" => Key::FavoriteClear0, - "FavoriteClear1" => Key::FavoriteClear1, - "FavoriteClear2" => Key::FavoriteClear2, - "FavoriteClear3" => Key::FavoriteClear3, - "FavoriteRecall0" => Key::FavoriteRecall0, - "FavoriteRecall1" => Key::FavoriteRecall1, - "FavoriteRecall2" => Key::FavoriteRecall2, - "FavoriteRecall3" => Key::FavoriteRecall3, - "FavoriteStore0" => Key::FavoriteStore0, - "FavoriteStore1" => Key::FavoriteStore1, - "FavoriteStore2" => Key::FavoriteStore2, - "FavoriteStore3" => Key::FavoriteStore3, - "Guide" => Key::Guide, - "GuideNextDay" => Key::GuideNextDay, - "GuidePreviousDay" => Key::GuidePreviousDay, - "Info" => Key::Info, - "InstantReplay" => Key::InstantReplay, - "Link" => Key::Link, - "ListProgram" => Key::ListProgram, - "LiveContent" => Key::LiveContent, - "Lock" => Key::Lock, - "MediaApps" => Key::MediaApps, - "MediaAudioTrack" => Key::MediaAudioTrack, - "MediaLast" => Key::MediaLast, - "MediaSkipBackward" => Key::MediaSkipBackward, - "MediaSkipForward" => Key::MediaSkipForward, - "MediaStepBackward" => Key::MediaStepBackward, - "MediaStepForward" => Key::MediaStepForward, - "MediaTopMenu" => Key::MediaTopMenu, - "NavigateIn" => Key::NavigateIn, - "NavigateNext" => Key::NavigateNext, - "NavigateOut" => Key::NavigateOut, - "NavigatePrevious" => Key::NavigatePrevious, - "NextFavoriteChannel" => Key::NextFavoriteChannel, - "NextUserProfile" => Key::NextUserProfile, - "OnDemand" => Key::OnDemand, - "Pairing" => Key::Pairing, - "PinPDown" => Key::PinPDown, - "PinPMove" => Key::PinPMove, - "PinPToggle" => Key::PinPToggle, - "PinPUp" => Key::PinPUp, - "PlaySpeedDown" => Key::PlaySpeedDown, - "PlaySpeedReset" => Key::PlaySpeedReset, - "PlaySpeedUp" => Key::PlaySpeedUp, - "RandomToggle" => Key::RandomToggle, - "RcLowBattery" => Key::RcLowBattery, - "RecordSpeedNext" => Key::RecordSpeedNext, - "RfBypass" => Key::RfBypass, - "ScanChannelsToggle" => Key::ScanChannelsToggle, - "ScreenModeNext" => Key::ScreenModeNext, - "Settings" => Key::Settings, - "SplitScreenToggle" => Key::SplitScreenToggle, - "STBInput" => Key::STBInput, - "STBPower" => Key::STBPower, - "Subtitle" => Key::Subtitle, - "Teletext" => Key::Teletext, - "VideoModeNext" => Key::VideoModeNext, - "Wink" => Key::Wink, - "ZoomToggle" => Key::ZoomToggle, - "F1" => Key::F1, - "F2" => Key::F2, - "F3" => Key::F3, - "F4" => Key::F4, - "F5" => Key::F5, - "F6" => Key::F6, - "F7" => Key::F7, - "F8" => Key::F8, - "F9" => Key::F9, - "F10" => Key::F10, - "F11" => Key::F11, - "F12" => Key::F12, - "F13" => Key::F13, - "F14" => Key::F14, - "F15" => Key::F15, - "F16" => Key::F16, - "F17" => Key::F17, - "F18" => Key::F18, - "F19" => Key::F19, - "F20" => Key::F20, - "F21" => Key::F21, - "F22" => Key::F22, - "F23" => Key::F23, - "F24" => Key::F24, - "F25" => Key::F25, - "F26" => Key::F26, - "F27" => Key::F27, - "F28" => Key::F28, - "F29" => Key::F29, - "F30" => Key::F30, - "F31" => Key::F31, - "F32" => Key::F32, - "F33" => Key::F33, - "F34" => Key::F34, - "F35" => Key::F35, - string @ _ => Key::Character(string), - } - } - - pub fn as_key_code_attribute_value(&self) -> &str { - match self { - Key::Character(character) => character, - Key::Unidentified(_) => "Unidentified", - Key::Dead(_) => "Dead", - Key::Alt => "Alt", - Key::AltGraph => "AltGraph", - Key::CapsLock => "CapsLock", - Key::Control => "Control", - Key::Fn => "Fn", - Key::FnLock => "FnLock", - Key::NumLock => "NumLock", - Key::ScrollLock => "ScrollLock", - Key::Shift => "Shift", - Key::Symbol => "Symbol", - Key::SymbolLock => "SymbolLock", - Key::Hyper => "Hyper", - Key::Super => "Meta", - Key::Enter => "Enter", - Key::Tab => "Tab", - Key::Space => "Space", - Key::ArrowDown => "ArrowDown", - Key::ArrowLeft => "ArrowLeft", - Key::ArrowRight => "ArrowRight", - Key::ArrowUp => "ArrowUp", - Key::End => "End", - Key::Home => "Home", - Key::PageDown => "PageDown", - Key::PageUp => "PageUp", - Key::Backspace => "Backspace", - Key::Clear => "Clear", - Key::Copy => "Copy", - Key::CrSel => "CrSel", - Key::Cut => "Cut", - Key::Delete => "Delete", - Key::EraseEof => "EraseEof", - Key::ExSel => "ExSel", - Key::Insert => "Insert", - Key::Paste => "Paste", - Key::Redo => "Redo", - Key::Undo => "Undo", - Key::Accept => "Accept", - Key::Again => "Again", - Key::Attn => "Attn", - Key::Cancel => "Cancel", - Key::ContextMenu => "ContextMenu", - Key::Escape => "Escape", - Key::Execute => "Execute", - Key::Find => "Find", - Key::Help => "Help", - Key::Pause => "Pause", - Key::Play => "Play", - Key::Props => "Props", - Key::Select => "Select", - Key::ZoomIn => "ZoomIn", - Key::ZoomOut => "ZoomOut", - Key::BrightnessDown => "BrightnessDown", - Key::BrightnessUp => "BrightnessUp", - Key::Eject => "Eject", - Key::LogOff => "LogOff", - Key::Power => "Power", - Key::PowerOff => "PowerOff", - Key::PrintScreen => "PrintScreen", - Key::Hibernate => "Hibernate", - Key::Standby => "Standby", - Key::WakeUp => "WakeUp", - Key::AllCandidates => "AllCandidates", - Key::Alphanumeric => "Alphanumeric", - Key::CodeInput => "CodeInput", - Key::Compose => "Compose", - Key::Convert => "Convert", - Key::FinalMode => "FinalMode", - Key::GroupFirst => "GroupFirst", - Key::GroupLast => "GroupLast", - Key::GroupNext => "GroupNext", - Key::GroupPrevious => "GroupPrevious", - Key::ModeChange => "ModeChange", - Key::NextCandidate => "NextCandidate", - Key::NonConvert => "NonConvert", - Key::PreviousCandidate => "PreviousCandidate", - Key::Process => "Process", - Key::SingleCandidate => "SingleCandidate", - Key::HangulMode => "HangulMode", - Key::HanjaMode => "HanjaMode", - Key::JunjaMode => "JunjaMode", - Key::Eisu => "Eisu", - Key::Hankaku => "Hankaku", - Key::Hiragana => "Hiragana", - Key::HiraganaKatakana => "HiraganaKatakana", - Key::KanaMode => "KanaMode", - Key::KanjiMode => "KanjiMode", - Key::Katakana => "Katakana", - Key::Romaji => "Romaji", - Key::Zenkaku => "Zenkaku", - Key::ZenkakuHankaku => "ZenkakuHankaku", - Key::Soft1 => "Soft1", - Key::Soft2 => "Soft2", - Key::Soft3 => "Soft3", - Key::Soft4 => "Soft4", - Key::ChannelDown => "ChannelDown", - Key::ChannelUp => "ChannelUp", - Key::Close => "Close", - Key::MailForward => "MailForward", - Key::MailReply => "MailReply", - Key::MailSend => "MailSend", - Key::MediaClose => "MediaClose", - Key::MediaFastForward => "MediaFastForward", - Key::MediaPause => "MediaPause", - Key::MediaPlay => "MediaPlay", - Key::MediaPlayPause => "MediaPlayPause", - Key::MediaRecord => "MediaRecord", - Key::MediaRewind => "MediaRewind", - Key::MediaStop => "MediaStop", - Key::MediaTrackNext => "MediaTrackNext", - Key::MediaTrackPrevious => "MediaTrackPrevious", - Key::New => "New", - Key::Open => "Open", - Key::Print => "Print", - Key::Save => "Save", - Key::SpellCheck => "SpellCheck", - Key::Key11 => "Key11", - Key::Key12 => "Key12", - Key::AudioBalanceLeft => "AudioBalanceLeft", - Key::AudioBalanceRight => "AudioBalanceRight", - Key::AudioBassBoostDown => "AudioBassBoostDown", - Key::AudioBassBoostToggle => "AudioBassBoostToggle", - Key::AudioBassBoostUp => "AudioBassBoostUp", - Key::AudioFaderFront => "AudioFaderFront", - Key::AudioFaderRear => "AudioFaderRear", - Key::AudioSurroundModeNext => "AudioSurroundModeNext", - Key::AudioTrebleDown => "AudioTrebleDown", - Key::AudioTrebleUp => "AudioTrebleUp", - Key::AudioVolumeDown => "AudioVolumeDown", - Key::AudioVolumeUp => "AudioVolumeUp", - Key::AudioVolumeMute => "AudioVolumeMute", - Key::MicrophoneToggle => "MicrophoneToggle", - Key::MicrophoneVolumeDown => "MicrophoneVolumeDown", - Key::MicrophoneVolumeUp => "MicrophoneVolumeUp", - Key::MicrophoneVolumeMute => "MicrophoneVolumeMute", - Key::SpeechCorrectionList => "SpeechCorrectionList", - Key::SpeechInputToggle => "SpeechInputToggle", - Key::LaunchApplication1 => "LaunchApplication1", - Key::LaunchApplication2 => "LaunchApplication2", - Key::LaunchCalendar => "LaunchCalendar", - Key::LaunchContacts => "LaunchContacts", - Key::LaunchMail => "LaunchMail", - Key::LaunchMediaPlayer => "LaunchMediaPlayer", - Key::LaunchMusicPlayer => "LaunchMusicPlayer", - Key::LaunchPhone => "LaunchPhone", - Key::LaunchScreenSaver => "LaunchScreenSaver", - Key::LaunchSpreadsheet => "LaunchSpreadsheet", - Key::LaunchWebBrowser => "LaunchWebBrowser", - Key::LaunchWebCam => "LaunchWebCam", - Key::LaunchWordProcessor => "LaunchWordProcessor", - Key::BrowserBack => "BrowserBack", - Key::BrowserFavorites => "BrowserFavorites", - Key::BrowserForward => "BrowserForward", - Key::BrowserHome => "BrowserHome", - Key::BrowserRefresh => "BrowserRefresh", - Key::BrowserSearch => "BrowserSearch", - Key::BrowserStop => "BrowserStop", - Key::AppSwitch => "AppSwitch", - Key::Call => "Call", - Key::Camera => "Camera", - Key::CameraFocus => "CameraFocus", - Key::EndCall => "EndCall", - Key::GoBack => "GoBack", - Key::GoHome => "GoHome", - Key::HeadsetHook => "HeadsetHook", - Key::LastNumberRedial => "LastNumberRedial", - Key::Notification => "Notification", - Key::MannerMode => "MannerMode", - Key::VoiceDial => "VoiceDial", - Key::TV => "TV", - Key::TV3DMode => "TV3DMode", - Key::TVAntennaCable => "TVAntennaCable", - Key::TVAudioDescription => "TVAudioDescription", - Key::TVAudioDescriptionMixDown => "TVAudioDescriptionMixDown", - Key::TVAudioDescriptionMixUp => "TVAudioDescriptionMixUp", - Key::TVContentsMenu => "TVContentsMenu", - Key::TVDataService => "TVDataService", - Key::TVInput => "TVInput", - Key::TVInputComponent1 => "TVInputComponent1", - Key::TVInputComponent2 => "TVInputComponent2", - Key::TVInputComposite1 => "TVInputComposite1", - Key::TVInputComposite2 => "TVInputComposite2", - Key::TVInputHDMI1 => "TVInputHDMI1", - Key::TVInputHDMI2 => "TVInputHDMI2", - Key::TVInputHDMI3 => "TVInputHDMI3", - Key::TVInputHDMI4 => "TVInputHDMI4", - Key::TVInputVGA1 => "TVInputVGA1", - Key::TVMediaContext => "TVMediaContext", - Key::TVNetwork => "TVNetwork", - Key::TVNumberEntry => "TVNumberEntry", - Key::TVPower => "TVPower", - Key::TVRadioService => "TVRadioService", - Key::TVSatellite => "TVSatellite", - Key::TVSatelliteBS => "TVSatelliteBS", - Key::TVSatelliteCS => "TVSatelliteCS", - Key::TVSatelliteToggle => "TVSatelliteToggle", - Key::TVTerrestrialAnalog => "TVTerrestrialAnalog", - Key::TVTerrestrialDigital => "TVTerrestrialDigital", - Key::TVTimer => "TVTimer", - Key::AVRInput => "AVRInput", - Key::AVRPower => "AVRPower", - Key::ColorF0Red => "ColorF0Red", - Key::ColorF1Green => "ColorF1Green", - Key::ColorF2Yellow => "ColorF2Yellow", - Key::ColorF3Blue => "ColorF3Blue", - Key::ColorF4Grey => "ColorF4Grey", - Key::ColorF5Brown => "ColorF5Brown", - Key::ClosedCaptionToggle => "ClosedCaptionToggle", - Key::Dimmer => "Dimmer", - Key::DisplaySwap => "DisplaySwap", - Key::DVR => "DVR", - Key::Exit => "Exit", - Key::FavoriteClear0 => "FavoriteClear0", - Key::FavoriteClear1 => "FavoriteClear1", - Key::FavoriteClear2 => "FavoriteClear2", - Key::FavoriteClear3 => "FavoriteClear3", - Key::FavoriteRecall0 => "FavoriteRecall0", - Key::FavoriteRecall1 => "FavoriteRecall1", - Key::FavoriteRecall2 => "FavoriteRecall2", - Key::FavoriteRecall3 => "FavoriteRecall3", - Key::FavoriteStore0 => "FavoriteStore0", - Key::FavoriteStore1 => "FavoriteStore1", - Key::FavoriteStore2 => "FavoriteStore2", - Key::FavoriteStore3 => "FavoriteStore3", - Key::Guide => "Guide", - Key::GuideNextDay => "GuideNextDay", - Key::GuidePreviousDay => "GuidePreviousDay", - Key::Info => "Info", - Key::InstantReplay => "InstantReplay", - Key::Link => "Link", - Key::ListProgram => "ListProgram", - Key::LiveContent => "LiveContent", - Key::Lock => "Lock", - Key::MediaApps => "MediaApps", - Key::MediaAudioTrack => "MediaAudioTrack", - Key::MediaLast => "MediaLast", - Key::MediaSkipBackward => "MediaSkipBackward", - Key::MediaSkipForward => "MediaSkipForward", - Key::MediaStepBackward => "MediaStepBackward", - Key::MediaStepForward => "MediaStepForward", - Key::MediaTopMenu => "MediaTopMenu", - Key::NavigateIn => "NavigateIn", - Key::NavigateNext => "NavigateNext", - Key::NavigateOut => "NavigateOut", - Key::NavigatePrevious => "NavigatePrevious", - Key::NextFavoriteChannel => "NextFavoriteChannel", - Key::NextUserProfile => "NextUserProfile", - Key::OnDemand => "OnDemand", - Key::Pairing => "Pairing", - Key::PinPDown => "PinPDown", - Key::PinPMove => "PinPMove", - Key::PinPToggle => "PinPToggle", - Key::PinPUp => "PinPUp", - Key::PlaySpeedDown => "PlaySpeedDown", - Key::PlaySpeedReset => "PlaySpeedReset", - Key::PlaySpeedUp => "PlaySpeedUp", - Key::RandomToggle => "RandomToggle", - Key::RcLowBattery => "RcLowBattery", - Key::RecordSpeedNext => "RecordSpeedNext", - Key::RfBypass => "RfBypass", - Key::ScanChannelsToggle => "ScanChannelsToggle", - Key::ScreenModeNext => "ScreenModeNext", - Key::Settings => "Settings", - Key::SplitScreenToggle => "SplitScreenToggle", - Key::STBInput => "STBInput", - Key::STBPower => "STBPower", - Key::Subtitle => "Subtitle", - Key::Teletext => "Teletext", - Key::VideoModeNext => "VideoModeNext", - Key::Wink => "Wink", - Key::ZoomToggle => "ZoomToggle", - Key::F1 => "F1", - Key::F2 => "F2", - Key::F3 => "F3", - Key::F4 => "F4", - Key::F5 => "F5", - Key::F6 => "F6", - Key::F7 => "F7", - Key::F8 => "F8", - Key::F9 => "F9", - Key::F10 => "F10", - Key::F11 => "F11", - Key::F12 => "F12", - Key::F13 => "F13", - Key::F14 => "F14", - Key::F15 => "F15", - Key::F16 => "F16", - Key::F17 => "F17", - Key::F18 => "F18", - Key::F19 => "F19", - Key::F20 => "F20", - Key::F21 => "F21", - Key::F22 => "F22", - Key::F23 => "F23", - Key::F24 => "F24", - Key::F25 => "F25", - Key::F26 => "F26", - Key::F27 => "F27", - Key::F28 => "F28", - Key::F29 => "F29", - Key::F30 => "F30", - Key::F31 => "F31", - Key::F32 => "F32", - Key::F33 => "F33", - Key::F34 => "F34", - Key::F35 => "F35", - } - } -} - impl<'a> Key<'a> { pub fn to_text(&self) -> Option<&'a str> { match self { diff --git a/src/platform_impl/web/keyboard.rs b/src/platform_impl/web/keyboard.rs new file mode 100644 index 0000000000..35b1cbfa93 --- /dev/null +++ b/src/platform_impl/web/keyboard.rs @@ -0,0 +1,521 @@ +use crate::keyboard::{Key, KeyCode, NativeKeyCode}; + +impl<'a> Key<'a> { + pub(crate) fn from_key_attribute_value(kav: &'a str) -> Self { + match kav { + // TODO: Report this in a better way. + "Unidentified" => Key::Unidentified(NativeKeyCode::Web("Unidentified")), + "Dead" => Key::Dead(None), + "Alt" => Key::Alt, + "AltGraph" => Key::AltGraph, + "CapsLock" => Key::CapsLock, + "Control" => Key::Control, + "Fn" => Key::Fn, + "FnLock" => Key::FnLock, + "NumLock" => Key::NumLock, + "ScrollLock" => Key::ScrollLock, + "Shift" => Key::Shift, + "Symbol" => Key::Symbol, + "SymbolLock" => Key::SymbolLock, + "Hyper" => Key::Hyper, + "Meta" => Key::Super, + "Enter" => Key::Enter, + "Tab" => Key::Tab, + " " => Key::Space, + "ArrowDown" => Key::ArrowDown, + "ArrowLeft" => Key::ArrowLeft, + "ArrowRight" => Key::ArrowRight, + "ArrowUp" => Key::ArrowUp, + "End" => Key::End, + "Home" => Key::Home, + "PageDown" => Key::PageDown, + "PageUp" => Key::PageUp, + "Backspace" => Key::Backspace, + "Clear" => Key::Clear, + "Copy" => Key::Copy, + "CrSel" => Key::CrSel, + "Cut" => Key::Cut, + "Delete" => Key::Delete, + "EraseEof" => Key::EraseEof, + "ExSel" => Key::ExSel, + "Insert" => Key::Insert, + "Paste" => Key::Paste, + "Redo" => Key::Redo, + "Undo" => Key::Undo, + "Accept" => Key::Accept, + "Again" => Key::Again, + "Attn" => Key::Attn, + "Cancel" => Key::Cancel, + "ContextMenu" => Key::ContextMenu, + "Escape" => Key::Escape, + "Execute" => Key::Execute, + "Find" => Key::Find, + "Help" => Key::Help, + "Pause" => Key::Pause, + "Play" => Key::Play, + "Props" => Key::Props, + "Select" => Key::Select, + "ZoomIn" => Key::ZoomIn, + "ZoomOut" => Key::ZoomOut, + "BrightnessDown" => Key::BrightnessDown, + "BrightnessUp" => Key::BrightnessUp, + "Eject" => Key::Eject, + "LogOff" => Key::LogOff, + "Power" => Key::Power, + "PowerOff" => Key::PowerOff, + "PrintScreen" => Key::PrintScreen, + "Hibernate" => Key::Hibernate, + "Standby" => Key::Standby, + "WakeUp" => Key::WakeUp, + "AllCandidates" => Key::AllCandidates, + "Alphanumeric" => Key::Alphanumeric, + "CodeInput" => Key::CodeInput, + "Compose" => Key::Compose, + "Convert" => Key::Convert, + "FinalMode" => Key::FinalMode, + "GroupFirst" => Key::GroupFirst, + "GroupLast" => Key::GroupLast, + "GroupNext" => Key::GroupNext, + "GroupPrevious" => Key::GroupPrevious, + "ModeChange" => Key::ModeChange, + "NextCandidate" => Key::NextCandidate, + "NonConvert" => Key::NonConvert, + "PreviousCandidate" => Key::PreviousCandidate, + "Process" => Key::Process, + "SingleCandidate" => Key::SingleCandidate, + "HangulMode" => Key::HangulMode, + "HanjaMode" => Key::HanjaMode, + "JunjaMode" => Key::JunjaMode, + "Eisu" => Key::Eisu, + "Hankaku" => Key::Hankaku, + "Hiragana" => Key::Hiragana, + "HiraganaKatakana" => Key::HiraganaKatakana, + "KanaMode" => Key::KanaMode, + "KanjiMode" => Key::KanjiMode, + "Katakana" => Key::Katakana, + "Romaji" => Key::Romaji, + "Zenkaku" => Key::Zenkaku, + "ZenkakuHankaku" => Key::ZenkakuHankaku, + "Soft1" => Key::Soft1, + "Soft2" => Key::Soft2, + "Soft3" => Key::Soft3, + "Soft4" => Key::Soft4, + "ChannelDown" => Key::ChannelDown, + "ChannelUp" => Key::ChannelUp, + "Close" => Key::Close, + "MailForward" => Key::MailForward, + "MailReply" => Key::MailReply, + "MailSend" => Key::MailSend, + "MediaClose" => Key::MediaClose, + "MediaFastForward" => Key::MediaFastForward, + "MediaPause" => Key::MediaPause, + "MediaPlay" => Key::MediaPlay, + "MediaPlayPause" => Key::MediaPlayPause, + "MediaRecord" => Key::MediaRecord, + "MediaRewind" => Key::MediaRewind, + "MediaStop" => Key::MediaStop, + "MediaTrackNext" => Key::MediaTrackNext, + "MediaTrackPrevious" => Key::MediaTrackPrevious, + "New" => Key::New, + "Open" => Key::Open, + "Print" => Key::Print, + "Save" => Key::Save, + "SpellCheck" => Key::SpellCheck, + "Key11" => Key::Key11, + "Key12" => Key::Key12, + "AudioBalanceLeft" => Key::AudioBalanceLeft, + "AudioBalanceRight" => Key::AudioBalanceRight, + "AudioBassBoostDown" => Key::AudioBassBoostDown, + "AudioBassBoostToggle" => Key::AudioBassBoostToggle, + "AudioBassBoostUp" => Key::AudioBassBoostUp, + "AudioFaderFront" => Key::AudioFaderFront, + "AudioFaderRear" => Key::AudioFaderRear, + "AudioSurroundModeNext" => Key::AudioSurroundModeNext, + "AudioTrebleDown" => Key::AudioTrebleDown, + "AudioTrebleUp" => Key::AudioTrebleUp, + "AudioVolumeDown" => Key::AudioVolumeDown, + "AudioVolumeUp" => Key::AudioVolumeUp, + "AudioVolumeMute" => Key::AudioVolumeMute, + "MicrophoneToggle" => Key::MicrophoneToggle, + "MicrophoneVolumeDown" => Key::MicrophoneVolumeDown, + "MicrophoneVolumeUp" => Key::MicrophoneVolumeUp, + "MicrophoneVolumeMute" => Key::MicrophoneVolumeMute, + "SpeechCorrectionList" => Key::SpeechCorrectionList, + "SpeechInputToggle" => Key::SpeechInputToggle, + "LaunchApplication1" => Key::LaunchApplication1, + "LaunchApplication2" => Key::LaunchApplication2, + "LaunchCalendar" => Key::LaunchCalendar, + "LaunchContacts" => Key::LaunchContacts, + "LaunchMail" => Key::LaunchMail, + "LaunchMediaPlayer" => Key::LaunchMediaPlayer, + "LaunchMusicPlayer" => Key::LaunchMusicPlayer, + "LaunchPhone" => Key::LaunchPhone, + "LaunchScreenSaver" => Key::LaunchScreenSaver, + "LaunchSpreadsheet" => Key::LaunchSpreadsheet, + "LaunchWebBrowser" => Key::LaunchWebBrowser, + "LaunchWebCam" => Key::LaunchWebCam, + "LaunchWordProcessor" => Key::LaunchWordProcessor, + "BrowserBack" => Key::BrowserBack, + "BrowserFavorites" => Key::BrowserFavorites, + "BrowserForward" => Key::BrowserForward, + "BrowserHome" => Key::BrowserHome, + "BrowserRefresh" => Key::BrowserRefresh, + "BrowserSearch" => Key::BrowserSearch, + "BrowserStop" => Key::BrowserStop, + "AppSwitch" => Key::AppSwitch, + "Call" => Key::Call, + "Camera" => Key::Camera, + "CameraFocus" => Key::CameraFocus, + "EndCall" => Key::EndCall, + "GoBack" => Key::GoBack, + "GoHome" => Key::GoHome, + "HeadsetHook" => Key::HeadsetHook, + "LastNumberRedial" => Key::LastNumberRedial, + "Notification" => Key::Notification, + "MannerMode" => Key::MannerMode, + "VoiceDial" => Key::VoiceDial, + "TV" => Key::TV, + "TV3DMode" => Key::TV3DMode, + "TVAntennaCable" => Key::TVAntennaCable, + "TVAudioDescription" => Key::TVAudioDescription, + "TVAudioDescriptionMixDown" => Key::TVAudioDescriptionMixDown, + "TVAudioDescriptionMixUp" => Key::TVAudioDescriptionMixUp, + "TVContentsMenu" => Key::TVContentsMenu, + "TVDataService" => Key::TVDataService, + "TVInput" => Key::TVInput, + "TVInputComponent1" => Key::TVInputComponent1, + "TVInputComponent2" => Key::TVInputComponent2, + "TVInputComposite1" => Key::TVInputComposite1, + "TVInputComposite2" => Key::TVInputComposite2, + "TVInputHDMI1" => Key::TVInputHDMI1, + "TVInputHDMI2" => Key::TVInputHDMI2, + "TVInputHDMI3" => Key::TVInputHDMI3, + "TVInputHDMI4" => Key::TVInputHDMI4, + "TVInputVGA1" => Key::TVInputVGA1, + "TVMediaContext" => Key::TVMediaContext, + "TVNetwork" => Key::TVNetwork, + "TVNumberEntry" => Key::TVNumberEntry, + "TVPower" => Key::TVPower, + "TVRadioService" => Key::TVRadioService, + "TVSatellite" => Key::TVSatellite, + "TVSatelliteBS" => Key::TVSatelliteBS, + "TVSatelliteCS" => Key::TVSatelliteCS, + "TVSatelliteToggle" => Key::TVSatelliteToggle, + "TVTerrestrialAnalog" => Key::TVTerrestrialAnalog, + "TVTerrestrialDigital" => Key::TVTerrestrialDigital, + "TVTimer" => Key::TVTimer, + "AVRInput" => Key::AVRInput, + "AVRPower" => Key::AVRPower, + "ColorF0Red" => Key::ColorF0Red, + "ColorF1Green" => Key::ColorF1Green, + "ColorF2Yellow" => Key::ColorF2Yellow, + "ColorF3Blue" => Key::ColorF3Blue, + "ColorF4Grey" => Key::ColorF4Grey, + "ColorF5Brown" => Key::ColorF5Brown, + "ClosedCaptionToggle" => Key::ClosedCaptionToggle, + "Dimmer" => Key::Dimmer, + "DisplaySwap" => Key::DisplaySwap, + "DVR" => Key::DVR, + "Exit" => Key::Exit, + "FavoriteClear0" => Key::FavoriteClear0, + "FavoriteClear1" => Key::FavoriteClear1, + "FavoriteClear2" => Key::FavoriteClear2, + "FavoriteClear3" => Key::FavoriteClear3, + "FavoriteRecall0" => Key::FavoriteRecall0, + "FavoriteRecall1" => Key::FavoriteRecall1, + "FavoriteRecall2" => Key::FavoriteRecall2, + "FavoriteRecall3" => Key::FavoriteRecall3, + "FavoriteStore0" => Key::FavoriteStore0, + "FavoriteStore1" => Key::FavoriteStore1, + "FavoriteStore2" => Key::FavoriteStore2, + "FavoriteStore3" => Key::FavoriteStore3, + "Guide" => Key::Guide, + "GuideNextDay" => Key::GuideNextDay, + "GuidePreviousDay" => Key::GuidePreviousDay, + "Info" => Key::Info, + "InstantReplay" => Key::InstantReplay, + "Link" => Key::Link, + "ListProgram" => Key::ListProgram, + "LiveContent" => Key::LiveContent, + "Lock" => Key::Lock, + "MediaApps" => Key::MediaApps, + "MediaAudioTrack" => Key::MediaAudioTrack, + "MediaLast" => Key::MediaLast, + "MediaSkipBackward" => Key::MediaSkipBackward, + "MediaSkipForward" => Key::MediaSkipForward, + "MediaStepBackward" => Key::MediaStepBackward, + "MediaStepForward" => Key::MediaStepForward, + "MediaTopMenu" => Key::MediaTopMenu, + "NavigateIn" => Key::NavigateIn, + "NavigateNext" => Key::NavigateNext, + "NavigateOut" => Key::NavigateOut, + "NavigatePrevious" => Key::NavigatePrevious, + "NextFavoriteChannel" => Key::NextFavoriteChannel, + "NextUserProfile" => Key::NextUserProfile, + "OnDemand" => Key::OnDemand, + "Pairing" => Key::Pairing, + "PinPDown" => Key::PinPDown, + "PinPMove" => Key::PinPMove, + "PinPToggle" => Key::PinPToggle, + "PinPUp" => Key::PinPUp, + "PlaySpeedDown" => Key::PlaySpeedDown, + "PlaySpeedReset" => Key::PlaySpeedReset, + "PlaySpeedUp" => Key::PlaySpeedUp, + "RandomToggle" => Key::RandomToggle, + "RcLowBattery" => Key::RcLowBattery, + "RecordSpeedNext" => Key::RecordSpeedNext, + "RfBypass" => Key::RfBypass, + "ScanChannelsToggle" => Key::ScanChannelsToggle, + "ScreenModeNext" => Key::ScreenModeNext, + "Settings" => Key::Settings, + "SplitScreenToggle" => Key::SplitScreenToggle, + "STBInput" => Key::STBInput, + "STBPower" => Key::STBPower, + "Subtitle" => Key::Subtitle, + "Teletext" => Key::Teletext, + "VideoModeNext" => Key::VideoModeNext, + "Wink" => Key::Wink, + "ZoomToggle" => Key::ZoomToggle, + "F1" => Key::F1, + "F2" => Key::F2, + "F3" => Key::F3, + "F4" => Key::F4, + "F5" => Key::F5, + "F6" => Key::F6, + "F7" => Key::F7, + "F8" => Key::F8, + "F9" => Key::F9, + "F10" => Key::F10, + "F11" => Key::F11, + "F12" => Key::F12, + "F13" => Key::F13, + "F14" => Key::F14, + "F15" => Key::F15, + "F16" => Key::F16, + "F17" => Key::F17, + "F18" => Key::F18, + "F19" => Key::F19, + "F20" => Key::F20, + "F21" => Key::F21, + "F22" => Key::F22, + "F23" => Key::F23, + "F24" => Key::F24, + "F25" => Key::F25, + "F26" => Key::F26, + "F27" => Key::F27, + "F28" => Key::F28, + "F29" => Key::F29, + "F30" => Key::F30, + "F31" => Key::F31, + "F32" => Key::F32, + "F33" => Key::F33, + "F34" => Key::F34, + "F35" => Key::F35, + string @ _ => Key::Character(string), + } + } +} + +impl KeyCode { + pub fn from_key_code_attribute_value(kcav: &str) -> Self { + match kcav { + "Backquote" => KeyCode::Backquote, + "Backslash" => KeyCode::Backslash, + "BracketLeft" => KeyCode::BracketLeft, + "BracketRight" => KeyCode::BracketRight, + "Comma" => KeyCode::Comma, + "Digit0" => KeyCode::Digit0, + "Digit1" => KeyCode::Digit1, + "Digit2" => KeyCode::Digit2, + "Digit3" => KeyCode::Digit3, + "Digit4" => KeyCode::Digit4, + "Digit5" => KeyCode::Digit5, + "Digit6" => KeyCode::Digit6, + "Digit7" => KeyCode::Digit7, + "Digit8" => KeyCode::Digit8, + "Digit9" => KeyCode::Digit9, + "Equal" => KeyCode::Equal, + "IntlBackslash" => KeyCode::IntlBackslash, + "IntlRo" => KeyCode::IntlRo, + "IntlYen" => KeyCode::IntlYen, + "KeyA" => KeyCode::KeyA, + "KeyB" => KeyCode::KeyB, + "KeyC" => KeyCode::KeyC, + "KeyD" => KeyCode::KeyD, + "KeyE" => KeyCode::KeyE, + "KeyF" => KeyCode::KeyF, + "KeyG" => KeyCode::KeyG, + "KeyH" => KeyCode::KeyH, + "KeyI" => KeyCode::KeyI, + "KeyJ" => KeyCode::KeyJ, + "KeyK" => KeyCode::KeyK, + "KeyL" => KeyCode::KeyL, + "KeyM" => KeyCode::KeyM, + "KeyN" => KeyCode::KeyN, + "KeyO" => KeyCode::KeyO, + "KeyP" => KeyCode::KeyP, + "KeyQ" => KeyCode::KeyQ, + "KeyR" => KeyCode::KeyR, + "KeyS" => KeyCode::KeyS, + "KeyT" => KeyCode::KeyT, + "KeyU" => KeyCode::KeyU, + "KeyV" => KeyCode::KeyV, + "KeyW" => KeyCode::KeyW, + "KeyX" => KeyCode::KeyX, + "KeyY" => KeyCode::KeyY, + "KeyZ" => KeyCode::KeyZ, + "Minus" => KeyCode::Minus, + "Period" => KeyCode::Period, + "Quote" => KeyCode::Quote, + "Semicolon" => KeyCode::Semicolon, + "Slash" => KeyCode::Slash, + "AltLeft" => KeyCode::AltLeft, + "AltRight" => KeyCode::AltRight, + "Backspace" => KeyCode::Backspace, + "CapsLock" => KeyCode::CapsLock, + "ContextMenu" => KeyCode::ContextMenu, + "ControlLeft" => KeyCode::ControlLeft, + "ControlRight" => KeyCode::ControlRight, + "Enter" => KeyCode::Enter, + "MetaLeft" => KeyCode::SuperLeft, + "MetaRight" => KeyCode::SuperRight, + "ShiftLeft" => KeyCode::ShiftLeft, + "ShiftRight" => KeyCode::ShiftRight, + "Space" => KeyCode::Space, + "Tab" => KeyCode::Tab, + "Convert" => KeyCode::Convert, + "KanaMode" => KeyCode::KanaMode, + "Lang1" => KeyCode::Lang1, + "Lang2" => KeyCode::Lang2, + "Lang3" => KeyCode::Lang3, + "Lang4" => KeyCode::Lang4, + "Lang5" => KeyCode::Lang5, + "NonConvert" => KeyCode::NonConvert, + "Delete" => KeyCode::Delete, + "End" => KeyCode::End, + "Help" => KeyCode::Help, + "Home" => KeyCode::Home, + "Insert" => KeyCode::Insert, + "PageDown" => KeyCode::PageDown, + "PageUp" => KeyCode::PageUp, + "ArrowDown" => KeyCode::ArrowDown, + "ArrowLeft" => KeyCode::ArrowLeft, + "ArrowRight" => KeyCode::ArrowRight, + "ArrowUp" => KeyCode::ArrowUp, + "NumLock" => KeyCode::NumLock, + "Numpad0" => KeyCode::Numpad0, + "Numpad1" => KeyCode::Numpad1, + "Numpad2" => KeyCode::Numpad2, + "Numpad3" => KeyCode::Numpad3, + "Numpad4" => KeyCode::Numpad4, + "Numpad5" => KeyCode::Numpad5, + "Numpad6" => KeyCode::Numpad6, + "Numpad7" => KeyCode::Numpad7, + "Numpad8" => KeyCode::Numpad8, + "Numpad9" => KeyCode::Numpad9, + "NumpadAdd" => KeyCode::NumpadAdd, + "NumpadBackspace" => KeyCode::NumpadBackspace, + "NumpadClear" => KeyCode::NumpadClear, + "NumpadClearEntry" => KeyCode::NumpadClearEntry, + "NumpadComma" => KeyCode::NumpadComma, + "NumpadDecimal" => KeyCode::NumpadDecimal, + "NumpadDivide" => KeyCode::NumpadDivide, + "NumpadEnter" => KeyCode::NumpadEnter, + "NumpadEqual" => KeyCode::NumpadEqual, + "NumpadHash" => KeyCode::NumpadHash, + "NumpadMemoryAdd" => KeyCode::NumpadMemoryAdd, + "NumpadMemoryClear" => KeyCode::NumpadMemoryClear, + "NumpadMemoryRecall" => KeyCode::NumpadMemoryRecall, + "NumpadMemoryStore" => KeyCode::NumpadMemoryStore, + "NumpadMemorySubtract" => KeyCode::NumpadMemorySubtract, + "NumpadMultiply" => KeyCode::NumpadMultiply, + "NumpadParenLeft" => KeyCode::NumpadParenLeft, + "NumpadParenRight" => KeyCode::NumpadParenRight, + "NumpadStar" => KeyCode::NumpadStar, + "NumpadSubtract" => KeyCode::NumpadSubtract, + "Escape" => KeyCode::Escape, + "Fn" => KeyCode::Fn, + "FnLock" => KeyCode::FnLock, + "PrintScreen" => KeyCode::PrintScreen, + "ScrollLock" => KeyCode::ScrollLock, + "Pause" => KeyCode::Pause, + "BrowserBack" => KeyCode::BrowserBack, + "BrowserFavorites" => KeyCode::BrowserFavorites, + "BrowserForward" => KeyCode::BrowserForward, + "BrowserHome" => KeyCode::BrowserHome, + "BrowserRefresh" => KeyCode::BrowserRefresh, + "BrowserSearch" => KeyCode::BrowserSearch, + "BrowserStop" => KeyCode::BrowserStop, + "Eject" => KeyCode::Eject, + "LaunchApp1" => KeyCode::LaunchApp1, + "LaunchApp2" => KeyCode::LaunchApp2, + "LaunchMail" => KeyCode::LaunchMail, + "MediaPlayPause" => KeyCode::MediaPlayPause, + "MediaSelect" => KeyCode::MediaSelect, + "MediaStop" => KeyCode::MediaStop, + "MediaTrackNext" => KeyCode::MediaTrackNext, + "MediaTrackPrevious" => KeyCode::MediaTrackPrevious, + "Power" => KeyCode::Power, + "Sleep" => KeyCode::Sleep, + "AudioVolumeDown" => KeyCode::AudioVolumeDown, + "AudioVolumeMute" => KeyCode::AudioVolumeMute, + "AudioVolumeUp" => KeyCode::AudioVolumeUp, + "WakeUp" => KeyCode::WakeUp, + "Hyper" => KeyCode::Hyper, + "Turbo" => KeyCode::Turbo, + "Abort" => KeyCode::Abort, + "Resume" => KeyCode::Resume, + "Suspend" => KeyCode::Suspend, + "Again" => KeyCode::Again, + "Copy" => KeyCode::Copy, + "Cut" => KeyCode::Cut, + "Find" => KeyCode::Find, + "Open" => KeyCode::Open, + "Paste" => KeyCode::Paste, + "Props" => KeyCode::Props, + "Select" => KeyCode::Select, + "Undo" => KeyCode::Undo, + "Hiragana" => KeyCode::Hiragana, + "Katakana" => KeyCode::Katakana, + "F1" => KeyCode::F1, + "F2" => KeyCode::F2, + "F3" => KeyCode::F3, + "F4" => KeyCode::F4, + "F5" => KeyCode::F5, + "F6" => KeyCode::F6, + "F7" => KeyCode::F7, + "F8" => KeyCode::F8, + "F9" => KeyCode::F9, + "F10" => KeyCode::F10, + "F11" => KeyCode::F11, + "F12" => KeyCode::F12, + "F13" => KeyCode::F13, + "F14" => KeyCode::F14, + "F15" => KeyCode::F15, + "F16" => KeyCode::F16, + "F17" => KeyCode::F17, + "F18" => KeyCode::F18, + "F19" => KeyCode::F19, + "F20" => KeyCode::F20, + "F21" => KeyCode::F21, + "F22" => KeyCode::F22, + "F23" => KeyCode::F23, + "F24" => KeyCode::F24, + "F25" => KeyCode::F25, + "F26" => KeyCode::F26, + "F27" => KeyCode::F27, + "F28" => KeyCode::F28, + "F29" => KeyCode::F29, + "F30" => KeyCode::F30, + "F31" => KeyCode::F31, + "F32" => KeyCode::F32, + "F33" => KeyCode::F33, + "F34" => KeyCode::F34, + "F35" => KeyCode::F35, + // TODO: Fix unbounded leak + string @ _ => KeyCode::Unidentified(NativeKeyCode::Web(Box::leak( + String::from(string).into_boxed_str(), + ))), + } + } +} diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index 9cf6bcca52..2c3deca3a6 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -22,6 +22,7 @@ mod error; mod event_loop; mod monitor; mod window; +mod keyboard; #[path = "web_sys/mod.rs"] mod backend; From e8d14a48c19bd545d55a604da521b4b159f3d24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 16 May 2021 20:51:29 +0200 Subject: [PATCH 05/13] Remove embedding of non-matched strings This is to appease `serde` for the time being. --- src/keyboard.rs | 6 +++--- src/platform_impl/web/keyboard.rs | 8 ++------ 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index a4390318d3..e2e029f921 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -176,7 +176,8 @@ pub enum NativeKeyCode { Windows(u16), MacOS(u32), XKB(u32), - Web(&'static str), + // TODO: Embed the non-matched string in a way that pleases serde. + Web(), } impl std::fmt::Debug for NativeKeyCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -198,9 +199,8 @@ impl std::fmt::Debug for NativeKeyCode { debug_tuple = f.debug_tuple(name_of!(XKB)); debug_tuple.field(v); } - Web(v) => { + Web() => { debug_tuple = f.debug_tuple(name_of!(Web)); - debug_tuple.field(v); } } debug_tuple.finish() diff --git a/src/platform_impl/web/keyboard.rs b/src/platform_impl/web/keyboard.rs index 35b1cbfa93..999bf2107a 100644 --- a/src/platform_impl/web/keyboard.rs +++ b/src/platform_impl/web/keyboard.rs @@ -3,8 +3,7 @@ use crate::keyboard::{Key, KeyCode, NativeKeyCode}; impl<'a> Key<'a> { pub(crate) fn from_key_attribute_value(kav: &'a str) -> Self { match kav { - // TODO: Report this in a better way. - "Unidentified" => Key::Unidentified(NativeKeyCode::Web("Unidentified")), + "Unidentified" => Key::Unidentified(NativeKeyCode::Web()), "Dead" => Key::Dead(None), "Alt" => Key::Alt, "AltGraph" => Key::AltGraph, @@ -512,10 +511,7 @@ impl KeyCode { "F33" => KeyCode::F33, "F34" => KeyCode::F34, "F35" => KeyCode::F35, - // TODO: Fix unbounded leak - string @ _ => KeyCode::Unidentified(NativeKeyCode::Web(Box::leak( - String::from(string).into_boxed_str(), - ))), + _ => KeyCode::Unidentified(NativeKeyCode::Web()), } } } From 74851a42fc398c68f8b27c255aae52d0b3e282e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Sun, 16 May 2021 21:11:32 +0200 Subject: [PATCH 06/13] Wire up `ReceivedImeText` --- Cargo.toml | 1 + .../web/event_loop/window_target.rs | 17 +++---- src/platform_impl/web/web_sys/canvas.rs | 48 ++++++------------- 3 files changed, 25 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d65620d493..5b15d56f9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -104,6 +104,7 @@ features = [ 'console', "AddEventListenerOptions", 'CssStyleDeclaration', + 'CompositionEvent', 'BeforeUnloadEvent', 'Document', 'DomRect', diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 757926e441..2496418f24 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -112,14 +112,15 @@ impl WindowTarget { }) }); - // TODO: What to do here? - // let runner = self.runner.clone(); - // canvas.on_received_character(move |char_code| { - // runner.send_event(Event::WindowEvent { - // window_id: WindowId(id), - // event: WindowEvent::ReceivedCharacter(char_code), - // }); - // }); + let runner = self.runner.clone(); + canvas.on_composition_end(move |data| { + if let Some(data) = data { + runner.send_event(Event::WindowEvent { + window_id: WindowId(id), + event: WindowEvent::ReceivedImeText(data), + }); + } + }); let runner = self.runner.clone(); canvas.on_cursor_leave(move |pointer_id| { diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 429d4da417..567a59f25c 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -12,7 +12,7 @@ use std::rc::Rc; use wasm_bindgen::{closure::Closure, JsCast}; use web_sys::{ - AddEventListenerOptions, Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, + AddEventListenerOptions, CompositionEvent, Event, FocusEvent, HtmlCanvasElement, KeyboardEvent, MediaQueryListEvent, MouseEvent, WheelEvent, }; @@ -26,7 +26,7 @@ pub struct Canvas { on_blur: Option>, on_keyboard_release: Option>, on_keyboard_press: Option>, - on_received_character: Option>, + on_composition_end: Option>, on_mouse_wheel: Option>, on_fullscreen_change: Option>, on_dark_mode: Option, @@ -82,7 +82,7 @@ impl Canvas { on_focus: None, on_keyboard_release: None, on_keyboard_press: None, - on_received_character: None, + on_composition_end: None, on_mouse_wheel: None, on_fullscreen_change: None, on_dark_mode: None, @@ -175,17 +175,7 @@ impl Canvas { self.on_keyboard_press = Some(self.common.add_user_event( "keydown", move |event: KeyboardEvent| { - // event.prevent_default() would suppress subsequent on_received_character() calls. That - // supression is correct for key sequences like Tab/Shift-Tab, Ctrl+R, PgUp/Down to - // scroll, etc. We should not do it for key sequences that result in meaningful character - // input though. - let event_key = &event.key(); - let is_key_string = event_key.len() == 1 || !event_key.is_ascii(); - let is_shortcut_modifiers = - (event.ctrl_key() || event.alt_key()) && !event.get_modifier_state("AltGr"); - if !is_key_string || is_shortcut_modifiers { - event.prevent_default(); - } + event.prevent_default(); handler( event::key_code(&event), event::key(&event), @@ -197,24 +187,17 @@ impl Canvas { )); } - // pub fn on_received_character(&mut self, mut handler: F) - // where - // F: 'static + FnMut(char), - // { - // // TODO: Use `beforeinput`. - // // - // // The `keypress` event is deprecated, but there does not seem to be a - // // viable/compatible alternative as of now. `beforeinput` is still widely - // // unsupported. - // self.on_received_character = Some(self.common.add_user_event( - // "keypress", - // move |event: KeyboardEvent| { - // // Supress further handling to stop keys like the space key from scrolling the page. - // event.prevent_default(); - // handler(event::codepoint(&event)); - // }, - // )); - // } + pub fn on_composition_end(&mut self, mut handler: F) + where + F: 'static + FnMut(Option), + { + self.on_composition_end = Some(self.common.add_user_event( + "compositionend", + move |event: CompositionEvent| { + handler(event.data()); + }, + )); + } pub fn on_cursor_leave(&mut self, handler: F) where @@ -313,7 +296,6 @@ impl Canvas { self.on_blur = None; self.on_keyboard_release = None; self.on_keyboard_press = None; - self.on_received_character = None; self.on_mouse_wheel = None; self.on_fullscreen_change = None; self.on_dark_mode = None; From 7e41dd9e934f8fad4a3b24a550c09e6007bfacb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Thu, 18 Mar 2021 20:32:51 +0100 Subject: [PATCH 07/13] Add `ModifiersChanged` events --- .../web/event_loop/window_target.rs | 133 +++++++++++++----- src/platform_impl/web/web_sys/canvas.rs | 14 +- src/platform_impl/web/web_sys/event.rs | 17 +-- 3 files changed, 113 insertions(+), 51 deletions(-) diff --git a/src/platform_impl/web/event_loop/window_target.rs b/src/platform_impl/web/event_loop/window_target.rs index 2496418f24..d6578b0ff0 100644 --- a/src/platform_impl/web/event_loop/window_target.rs +++ b/src/platform_impl/web/event_loop/window_target.rs @@ -7,21 +7,43 @@ use super::{ use crate::dpi::{PhysicalSize, Size}; use crate::event::{DeviceEvent, DeviceId, ElementState, Event, KeyEvent, TouchPhase, WindowEvent}; use crate::event_loop::ControlFlow; +use crate::keyboard::ModifiersState; use crate::monitor::MonitorHandle as RootMH; use crate::window::{Theme, WindowId}; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::clone::Clone; use std::collections::{vec_deque::IntoIter as VecDequeIter, VecDeque}; use std::rc::Rc; +#[derive(Default)] +struct ModifiersShared(Rc>); + +impl ModifiersShared { + fn set(&self, new: ModifiersState) { + self.0.set(new) + } + + fn get(&self) -> ModifiersState { + self.0.get() + } +} + +impl Clone for ModifiersShared { + fn clone(&self) -> Self { + Self(Rc::clone(&self.0)) + } +} + pub struct WindowTarget { pub(crate) runner: runner::Shared, + modifiers: ModifiersShared, } impl Clone for WindowTarget { fn clone(&self) -> Self { WindowTarget { runner: self.runner.clone(), + modifiers: self.modifiers.clone(), } } } @@ -30,6 +52,7 @@ impl WindowTarget { pub fn new() -> Self { WindowTarget { runner: runner::Shared::new(), + modifiers: ModifiersShared::default(), } } @@ -71,46 +94,78 @@ impl WindowTarget { }); let runner = self.runner.clone(); - canvas.on_keyboard_press(move |physical_key, logical_key, text, location, repeat| { - #[allow(deprecated)] - runner.send_event(Event::WindowEvent { - window_id: WindowId(id), - event: WindowEvent::KeyboardInput { - device_id: DeviceId(unsafe { device::Id::dummy() }), - event: KeyEvent { - physical_key, - logical_key, - text, - location, - state: ElementState::Pressed, - repeat, - platform_specific: KeyEventExtra, - }, - is_synthetic: false, - }, - }); - }); + let modifiers = self.modifiers.clone(); + canvas.on_keyboard_press( + move |physical_key, logical_key, text, location, repeat, new_modifiers| { + let active_modifiers = modifiers.get() | new_modifiers; + let modifiers_changed = if modifiers.get() != active_modifiers { + modifiers.set(active_modifiers); + Some(Event::WindowEvent { + window_id: WindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers), + }) + } else { + None + }; + + runner.send_events( + std::iter::once(Event::WindowEvent { + window_id: WindowId(id), + event: WindowEvent::KeyboardInput { + device_id: DeviceId(unsafe { device::Id::dummy() }), + event: KeyEvent { + physical_key, + logical_key, + text, + location, + state: ElementState::Pressed, + repeat, + platform_specific: KeyEventExtra, + }, + is_synthetic: false, + }, + }) + .chain(modifiers_changed), + ); + }, + ); let runner = self.runner.clone(); - canvas.on_keyboard_release(move |physical_key, logical_key, text, location, repeat| { - #[allow(deprecated)] - runner.send_event(Event::WindowEvent { - window_id: WindowId(id), - event: WindowEvent::KeyboardInput { - device_id: DeviceId(unsafe { device::Id::dummy() }), - event: KeyEvent { - physical_key, - logical_key, - text, - location, - state: ElementState::Released, - repeat, - platform_specific: KeyEventExtra, - }, - is_synthetic: false, - }, - }) - }); + let modifiers = self.modifiers.clone(); + canvas.on_keyboard_release( + move |physical_key, logical_key, text, location, repeat, new_modifiers| { + let active_modifiers = modifiers.get() & !new_modifiers; + let modifiers_changed = if modifiers.get() != active_modifiers { + modifiers.set(active_modifiers); + Some(Event::WindowEvent { + window_id: WindowId(id), + event: WindowEvent::ModifiersChanged(active_modifiers), + }) + } else { + None + }; + + runner.send_events( + std::iter::once(Event::WindowEvent { + window_id: WindowId(id), + event: WindowEvent::KeyboardInput { + device_id: DeviceId(unsafe { device::Id::dummy() }), + event: KeyEvent { + physical_key, + logical_key, + text, + location, + state: ElementState::Released, + repeat, + platform_specific: KeyEventExtra, + }, + is_synthetic: false, + }, + }) + .chain(modifiers_changed), + ) + }, + ); let runner = self.runner.clone(); canvas.on_composition_end(move |data| { diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 567a59f25c..75e5d750ae 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -151,18 +151,21 @@ impl Canvas { pub fn on_keyboard_release(&mut self, mut handler: F) where - F: 'static + FnMut(KeyCode, Key<'static>, Option<&'static str>, KeyLocation, bool), + F: 'static + + FnMut(KeyCode, Key<'static>, Option<&'static str>, KeyLocation, bool, ModifiersState), { self.on_keyboard_release = Some(self.common.add_user_event( "keyup", move |event: KeyboardEvent| { event.prevent_default(); + let key = event::key(&event); handler( event::key_code(&event), - event::key(&event), + key, event::key_text(&event), event::key_location(&event), event::key_repeat(&event), + event::keyboard_modifiers(key), ); }, )); @@ -170,18 +173,21 @@ impl Canvas { pub fn on_keyboard_press(&mut self, mut handler: F) where - F: 'static + FnMut(KeyCode, Key<'static>, Option<&'static str>, KeyLocation, bool), + F: 'static + + FnMut(KeyCode, Key<'static>, Option<&'static str>, KeyLocation, bool, ModifiersState), { self.on_keyboard_press = Some(self.common.add_user_event( "keydown", move |event: KeyboardEvent| { event.prevent_default(); + let key = event::key(&event); handler( event::key_code(&event), - event::key(&event), + key, event::key_text(&event), event::key_location(&event), event::key_repeat(&event), + event::keyboard_modifiers(key), ); }, )); diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 79929d69f3..f5b45f3fd5 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -103,14 +103,15 @@ pub fn key_repeat(event: &KeyboardEvent) -> bool { // TODO: What should be done about `KeyboardEvent.isComposing`? -// pub fn keyboard_modifiers(event: &KeyboardEvent) -> ModifiersState { -// let mut m = ModifiersState::empty(); -// m.set(ModifiersState::SHIFT, event.shift_key()); -// m.set(ModifiersState::CONTROL, event.ctrl_key()); -// m.set(ModifiersState::ALT, event.alt_key()); -// m.set(ModifiersState::SUPER, event.meta_key()); -// m -// } +pub fn keyboard_modifiers(key: Key<'_>) -> ModifiersState { + match key { + Key::Shift => ModifiersState::SHIFT, + Key::Control => ModifiersState::CONTROL, + Key::Alt => ModifiersState::ALT, + Key::Super => ModifiersState::SUPER, + _ => ModifiersState::empty(), + } +} // pub fn codepoint(event: &KeyboardEvent) -> char { // // `event.key()` always returns a non-empty `String`. Therefore, this should From 8aa2b4f4dc745745b55aa707ec1dc9acca76b3ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 21 Jun 2021 09:43:21 +0200 Subject: [PATCH 08/13] Remove redundant `key_repeat` function --- src/platform_impl/web/web_sys/canvas.rs | 4 ++-- src/platform_impl/web/web_sys/event.rs | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 75e5d750ae..1c2b0084c1 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -164,7 +164,7 @@ impl Canvas { key, event::key_text(&event), event::key_location(&event), - event::key_repeat(&event), + event.repeat(), event::keyboard_modifiers(key), ); }, @@ -186,7 +186,7 @@ impl Canvas { key, event::key_text(&event), event::key_location(&event), - event::key_repeat(&event), + event.repeat(), event::keyboard_modifiers(key), ); }, diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index f5b45f3fd5..a49c567f1b 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -97,10 +97,6 @@ pub fn key_location(event: &KeyboardEvent) -> KeyLocation { } } -pub fn key_repeat(event: &KeyboardEvent) -> bool { - event.repeat() -} - // TODO: What should be done about `KeyboardEvent.isComposing`? pub fn keyboard_modifiers(key: Key<'_>) -> ModifiersState { From ffb32203e3255c91dba36cabb92893b6d05720f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 21 Jun 2021 09:48:47 +0200 Subject: [PATCH 09/13] Resolve decision on key location values --- src/platform_impl/web/web_sys/event.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index a49c567f1b..7434140398 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -86,13 +86,13 @@ pub fn key_text(event: &KeyboardEvent) -> Option<&'static str> { pub fn key_location(event: &KeyboardEvent) -> KeyLocation { let location = event.location(); - // TODO: Use constants rather than integer literals? + // As defined in the UIEvents specification + // https://w3c.github.io/uievents/#idl-keyboardevent match location { 0 => KeyLocation::Standard, 1 => KeyLocation::Left, 2 => KeyLocation::Right, 3 => KeyLocation::Numpad, - // TODO: Is this reasonable to do? _ => KeyLocation::Standard, } } From fcb24eb3392f4161c7a964a9a25544a495be4e2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 21 Jun 2021 09:51:44 +0200 Subject: [PATCH 10/13] Move the `KeyEventExtra` struct somewhere else --- src/platform_impl/web/keyboard.rs | 3 +++ src/platform_impl/web/mod.rs | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/platform_impl/web/keyboard.rs b/src/platform_impl/web/keyboard.rs index 999bf2107a..7d72647a59 100644 --- a/src/platform_impl/web/keyboard.rs +++ b/src/platform_impl/web/keyboard.rs @@ -1,5 +1,8 @@ use crate::keyboard::{Key, KeyCode, NativeKeyCode}; +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub(crate) struct KeyEventExtra; + impl<'a> Key<'a> { pub(crate) fn from_key_attribute_value(kav: &'a str) -> Self { match kav { diff --git a/src/platform_impl/web/mod.rs b/src/platform_impl/web/mod.rs index 2c3deca3a6..c7a69b5bf9 100644 --- a/src/platform_impl/web/mod.rs +++ b/src/platform_impl/web/mod.rs @@ -38,6 +38,7 @@ pub use self::window::{ Window, }; +pub(crate) use self::keyboard::KeyEventExtra; pub(crate) use crate::icon::NoIcon as PlatformIcon; #[derive(Clone, Copy)] @@ -45,7 +46,3 @@ pub(crate) struct ScaleChangeArgs { old_scale: f64, new_scale: f64, } - -// TODO: Where should I put this? -#[derive(Debug, Clone, Eq, PartialEq, Hash)] -pub(crate) struct KeyEventExtra; From 46f22cf275692b6a4704d24b87bf1c05c0a41237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 21 Jun 2021 09:56:41 +0200 Subject: [PATCH 11/13] Use a `String` in `NativeKeyCode::Web`. As a direct result of this, `NativeKeyCode`, `Key`, `KeyCode` and `RawKeyEvent` no longer implement `Copy`. --- src/event.rs | 2 +- src/keyboard.rs | 12 ++++++------ src/platform_impl/web/keyboard.rs | 4 ++-- src/platform_impl/web/web_sys/canvas.rs | 6 ++++-- src/platform_impl/web/web_sys/event.rs | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/event.rs b/src/event.rs index 7e172cad47..22806162a2 100644 --- a/src/event.rs +++ b/src/event.rs @@ -618,7 +618,7 @@ pub enum DeviceEvent { /// repeat or the initial keypress. An application may emulate this by, for /// example keeping a Map/Set of pressed keys and determining whether a keypress /// corresponds to an already pressed key. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Clone, Eq, PartialEq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RawKeyEvent { pub physical_key: keyboard::KeyCode, diff --git a/src/keyboard.rs b/src/keyboard.rs index e2e029f921..21086557b0 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -169,15 +169,14 @@ mod modifiers_serde { } /// Contains the platform-native physical key identifier (aka scancode) -#[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum NativeKeyCode { Unidentified, Windows(u16), MacOS(u32), XKB(u32), - // TODO: Embed the non-matched string in a way that pleases serde. - Web(), + Web(String), } impl std::fmt::Debug for NativeKeyCode { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -199,8 +198,9 @@ impl std::fmt::Debug for NativeKeyCode { debug_tuple = f.debug_tuple(name_of!(XKB)); debug_tuple.field(v); } - Web() => { + Web(v) => { debug_tuple = f.debug_tuple(name_of!(Web)); + debug_tuple.field(v); } } debug_tuple.finish() @@ -218,7 +218,7 @@ impl std::fmt::Debug for NativeKeyCode { /// /// [`KeyboardEvent.code`]: https://w3c.github.io/uievents-code/#code-value-tables #[non_exhaustive] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum KeyCode { /// This variant is used when the key cannot be translated to any @@ -678,7 +678,7 @@ pub enum KeyCode { /// /// [`KeyboardEvent.key`]: https://w3c.github.io/uievents-key/ #[non_exhaustive] -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Key<'a> { /// A key string that corresponds to the character typed by the user, taking into account the diff --git a/src/platform_impl/web/keyboard.rs b/src/platform_impl/web/keyboard.rs index 7d72647a59..6938f1c4a7 100644 --- a/src/platform_impl/web/keyboard.rs +++ b/src/platform_impl/web/keyboard.rs @@ -6,7 +6,7 @@ pub(crate) struct KeyEventExtra; impl<'a> Key<'a> { pub(crate) fn from_key_attribute_value(kav: &'a str) -> Self { match kav { - "Unidentified" => Key::Unidentified(NativeKeyCode::Web()), + "Unidentified" => Key::Unidentified(NativeKeyCode::Web(kav.to_string())), "Dead" => Key::Dead(None), "Alt" => Key::Alt, "AltGraph" => Key::AltGraph, @@ -514,7 +514,7 @@ impl KeyCode { "F33" => KeyCode::F33, "F34" => KeyCode::F34, "F35" => KeyCode::F35, - _ => KeyCode::Unidentified(NativeKeyCode::Web()), + _ => KeyCode::Unidentified(NativeKeyCode::Web(kcav.to_string())), } } } diff --git a/src/platform_impl/web/web_sys/canvas.rs b/src/platform_impl/web/web_sys/canvas.rs index 1c2b0084c1..bcc901cfd1 100644 --- a/src/platform_impl/web/web_sys/canvas.rs +++ b/src/platform_impl/web/web_sys/canvas.rs @@ -159,13 +159,14 @@ impl Canvas { move |event: KeyboardEvent| { event.prevent_default(); let key = event::key(&event); + let modifiers = event::keyboard_modifiers(&key); handler( event::key_code(&event), key, event::key_text(&event), event::key_location(&event), event.repeat(), - event::keyboard_modifiers(key), + modifiers, ); }, )); @@ -181,13 +182,14 @@ impl Canvas { move |event: KeyboardEvent| { event.prevent_default(); let key = event::key(&event); + let modifiers = event::keyboard_modifiers(&key); handler( event::key_code(&event), key, event::key_text(&event), event::key_location(&event), event.repeat(), - event::keyboard_modifiers(key), + modifiers, ); }, )); diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 7434140398..5a4e7190d4 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -99,7 +99,7 @@ pub fn key_location(event: &KeyboardEvent) -> KeyLocation { // TODO: What should be done about `KeyboardEvent.isComposing`? -pub fn keyboard_modifiers(key: Key<'_>) -> ModifiersState { +pub fn keyboard_modifiers(key: &Key<'_>) -> ModifiersState { match key { Key::Shift => ModifiersState::SHIFT, Key::Control => ModifiersState::CONTROL, From 39e84cc6195ccfc61e1e1a560a77ce941ba4b748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 21 Jun 2021 10:32:09 +0200 Subject: [PATCH 12/13] Fix text for `Space`, `Tab`, and `Enter` --- src/platform_impl/web/web_sys/event.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 5a4e7190d4..883efacd33 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -76,11 +76,15 @@ pub fn key(event: &KeyboardEvent) -> Key<'static> { pub fn key_text(event: &KeyboardEvent) -> Option<&'static str> { let key = event.key(); - if let Key::Character(text) = Key::from_key_attribute_value(&key) { - // TODO: Fix unbounded leak - Some(Box::leak(String::from(text).into_boxed_str())) - } else { - None + match Key::from_key_attribute_value(&key) { + Key::Character(text) => { + // TODO: Fix unbounded leak + Some(Box::leak(String::from(text).into_boxed_str())) + } + Key::Tab => Some(Box::leak(String::from("\t").into_boxed_str())), + Key::Enter => Some(Box::leak(String::from("\r").into_boxed_str())), + Key::Space => Some(Box::leak(String::from(" ").into_boxed_str())), + _ => None, } } From 2c7ba7739fcd9a064e0ae1dc667175b1d6866336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Markus=20R=C3=B8yset?= Date: Mon, 21 Jun 2021 10:43:28 +0200 Subject: [PATCH 13/13] Use a proper string cache --- src/platform_impl/web/web_sys/event.rs | 38 +++++++++++++++++++------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/src/platform_impl/web/web_sys/event.rs b/src/platform_impl/web/web_sys/event.rs index 883efacd33..4e193fec57 100644 --- a/src/platform_impl/web/web_sys/event.rs +++ b/src/platform_impl/web/web_sys/event.rs @@ -69,23 +69,41 @@ pub fn key_code(event: &KeyboardEvent) -> KeyCode { pub fn key(event: &KeyboardEvent) -> Key<'static> { let key = event.key(); - // TODO: Fix unbounded leak - let key = Box::leak(String::from(key).into_boxed_str()); + let key = cached_string(key); Key::from_key_attribute_value(key) } pub fn key_text(event: &KeyboardEvent) -> Option<&'static str> { let key = event.key(); - match Key::from_key_attribute_value(&key) { - Key::Character(text) => { - // TODO: Fix unbounded leak - Some(Box::leak(String::from(text).into_boxed_str())) - } - Key::Tab => Some(Box::leak(String::from("\t").into_boxed_str())), - Key::Enter => Some(Box::leak(String::from("\r").into_boxed_str())), - Key::Space => Some(Box::leak(String::from(" ").into_boxed_str())), + let key = Key::from_key_attribute_value(&key); + match &key { + Key::Character(text) => Some(*text), + Key::Tab => Some("\t"), + Key::Enter => Some("\r"), + Key::Space => Some(" "), _ => None, } + .map(cached_string) +} + +fn cached_string>(string: S) -> &'static str { + use std::collections::HashSet; + use std::sync::Mutex; + + lazy_static::lazy_static! { + static ref STRING_CACHE: Mutex> = Mutex::new(HashSet::new()); + }; + + let string = string.as_ref(); + let mut cache = STRING_CACHE.lock().unwrap(); + if let Some(string) = cache.get(string) { + *string + } else { + // borrowck couldn't quite figure out this one on its own + let string: &'static str = Box::leak(String::from(string).into_boxed_str()); + cache.insert(string); + string + } } pub fn key_location(event: &KeyboardEvent) -> KeyLocation {