From f698d451df95bf6a41a594462020eb8ea4424216 Mon Sep 17 00:00:00 2001 From: Ryan Goldstein Date: Sat, 2 Mar 2019 12:31:16 -0500 Subject: [PATCH] Add key and mouse event support that typechecks --- src/lib.rs | 1 + src/platform_impl/stdweb/mod.rs | 315 +++++++++++++++++++++++++++++--- 2 files changed, 293 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 4155fa25..07d908b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,6 +112,7 @@ extern crate percent_encoding; #[cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))] extern crate smithay_client_toolkit as sctk; #[cfg(feature = "stdweb")] +#[macro_use] extern crate stdweb; pub mod dpi; diff --git a/src/platform_impl/stdweb/mod.rs b/src/platform_impl/stdweb/mod.rs index 72701136..cea168da 100644 --- a/src/platform_impl/stdweb/mod.rs +++ b/src/platform_impl/stdweb/mod.rs @@ -1,16 +1,18 @@ use dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize}; -use event::{Event, StartCause}; +use event::{DeviceEvent, DeviceId as RootDI, ElementState, Event, KeyboardInput, ModifiersState, MouseButton, ScanCode, StartCause, VirtualKeyCode, WindowEvent}; use event_loop::{ControlFlow, EventLoopWindowTarget as RootELW, EventLoopClosed}; use icon::Icon; use monitor::{MonitorHandle as RootMH}; -use window::{CreationError, MouseCursor, WindowAttributes}; +use window::{CreationError, MouseCursor, WindowId as RootWI, WindowAttributes}; use stdweb::{ + JsSerialize, traits::*, + unstable::TryInto, web::{ document, event::*, html_element::CanvasElement, - } + }, }; use std::cell::{RefCell, RefMut}; use std::collections::VecDeque; @@ -19,15 +21,18 @@ use std::marker::PhantomData; use std::rc::Rc; // TODO: dpi +// TODO: close events (stdweb PR required) // TODO: pointer locking (stdweb PR required) +// TODO: mouse wheel events (stdweb PR required) +// TODO: key event: .which() (stdweb PR) // TODO: should there be a maximization / fullscreen API? #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DeviceId; +pub struct DeviceId(i32); impl DeviceId { pub unsafe fn dummy() -> Self { - DeviceId + DeviceId(0) } } @@ -66,7 +71,6 @@ pub struct Window { } impl Window { - // TODO: type of window_target pub fn new(target: &EventLoopWindowTarget, window: WindowAttributes, platform: PlatformSpecificWindowBuilderAttributes) -> Result { unimplemented!(); } @@ -309,9 +313,9 @@ impl EventLoop { // TODO: file dropping, PathBuf isn't useful for web let document = &document(); - self.add_event(document, |data, event: BlurEvent| { + self.add_event(document, |mut data, event: BlurEvent| { }); - self.add_event(document, |data, event: FocusEvent| { + self.add_event(document, |mut data, event: FocusEvent| { }); // TODO: what to do after attaching events @@ -345,27 +349,96 @@ impl EventLoop { fn register_window(&self, other: &Window) { let canvas = &other.canvas; - self.add_event(canvas, |data, event: KeyDownEvent| { - // TODO: received character - // TODO: keyboard input + self.add_event(canvas, |mut data, event: KeyDownEvent| { + let key = event.key(); + let mut characters = key.chars(); + let first = characters.next(); + let second = characters.next(); + if let (Some(key), None) = (first, second) { + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::ReceivedCharacter(key) + }); + } + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::KeyboardInput { + // TODO: is there a way to get keyboard device? + device_id: RootDI(unsafe { DeviceId::dummy() }), + input: KeyboardInput { + scancode: scancode(&event), + state: ElementState::Pressed, + virtual_keycode: button_mapping(&event), + modifiers: keyboard_modifiers_state(&event), + } + } + }); }); - self.add_event(canvas, |data, event: KeyUpEvent| { - // TODO: keyboard input + self.add_event(canvas, |mut data, event: KeyUpEvent| { + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::KeyboardInput { + // TODO: is there a way to get keyboard device? + device_id: RootDI(unsafe { DeviceId::dummy() }), + input: KeyboardInput { + scancode: scancode(&event), + state: ElementState::Released, + virtual_keycode: button_mapping(&event), + modifiers: keyboard_modifiers_state(&event), + } + } + }); }); - self.add_event(canvas, |data, _: PointerOutEvent| { - // TODO + self.add_event(canvas, |mut data, event: PointerOutEvent| { + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::CursorLeft { + device_id: RootDI(DeviceId(event.pointer_id())) + } + }); }); - self.add_event(canvas, |data, _: PointerOverEvent| { - // TODO + self.add_event(canvas, |mut data, event: PointerOverEvent| { + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::CursorEntered { + device_id: RootDI(DeviceId(event.pointer_id())) + } + }); }); - self.add_event(canvas, |data, event: PointerMoveEvent| { - // TODO: mouse move + self.add_event(canvas, |mut data, event: PointerMoveEvent| { + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::CursorMoved { + device_id: RootDI(DeviceId(event.pointer_id())), + position: LogicalPosition { + x: event.offset_x(), + y: event.offset_y() + }, + modifiers: mouse_modifiers_state(&event) + } + }); }); - self.add_event(canvas, |data, event: PointerUpEvent| { - // TODO: mouse pointers + self.add_event(canvas, |mut data, event: PointerUpEvent| { + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::MouseInput { + device_id: RootDI(DeviceId(event.pointer_id())), + state: ElementState::Pressed, + button: mouse_button(&event), + modifiers: mouse_modifiers_state(&event) + } + }); }); - self.add_event(canvas, |data, event: PointerDownEvent| { - // TODO: mouse pointers + self.add_event(canvas, |mut data, event: PointerDownEvent| { + data.events.push_back(Event::WindowEvent { + window_id: RootWI(WindowId), + event: WindowEvent::MouseInput { + device_id: RootDI(DeviceId(event.pointer_id())), + state: ElementState::Released, + button: mouse_button(&event), + modifiers: mouse_modifiers_state(&event) + } + }); }); } @@ -383,6 +456,202 @@ impl EventLoop { } } +fn mouse_modifiers_state(event: &impl IMouseEvent) -> ModifiersState { + ModifiersState { + shift: event.shift_key(), + ctrl: event.ctrl_key(), + alt: event.alt_key(), + logo: event.meta_key(), + } +} + +fn mouse_button(event: &impl IMouseEvent) -> MouseButton { + match event.button() { + stdweb::web::event::MouseButton::Left => MouseButton::Left, + stdweb::web::event::MouseButton::Right => MouseButton::Right, + stdweb::web::event::MouseButton::Wheel => MouseButton::Middle, + stdweb::web::event::MouseButton::Button4 => MouseButton::Other(0), + stdweb::web::event::MouseButton::Button5 => MouseButton::Other(1), + } +} + +fn keyboard_modifiers_state(event: &impl IKeyboardEvent) -> ModifiersState { + ModifiersState { + shift: event.shift_key(), + ctrl: event.ctrl_key(), + alt: event.alt_key(), + logo: event.meta_key(), + } +} + +fn scancode(event: &T) -> ScanCode { + let which = js! ( return @{event}.which(); ); + which.try_into().expect("The which value should be a number") +} + +fn button_mapping(event: &impl IKeyboardEvent) -> 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::Add, + "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::Decimal, + "NumpadDivide" => VirtualKeyCode::Divide, + "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::Multiply, + "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::Subtract, + "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 + }) +} + #[derive(Clone)] pub struct EventLoopProxy { data: Rc>>