Add key and mouse event support that typechecks

This commit is contained in:
Ryan Goldstein 2019-03-02 12:31:16 -05:00
parent c088f8bd03
commit f698d451df
2 changed files with 293 additions and 23 deletions

View file

@ -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;

View file

@ -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<T>(target: &EventLoopWindowTarget<T>, window: WindowAttributes, platform: PlatformSpecificWindowBuilderAttributes) -> Result<Self, CreationError> {
unimplemented!();
}
@ -309,9 +313,9 @@ impl<T> EventLoop<T> {
// 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<T> EventLoop<T> {
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<T> EventLoop<T> {
}
}
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<T: JsSerialize>(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<VirtualKeyCode> {
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<T> {
data: Rc<RefCell<EventLoopData<T>>>