use std::collections::HashMap;
use winit;
pub use winit::event::{ElementState, MouseButton, VirtualKeyCode};
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
pub struct ModifiersState {
pub ctrl: bool,
pub alt: bool,
pub shift: bool,
pub meta: bool,
}
impl From<winit::event::ModifiersState> for ModifiersState {
fn from(m: winit::event::ModifiersState) -> Self {
ModifiersState {
ctrl: m.ctrl(),
alt: m.alt(),
shift: m.shift(),
meta: m.logo(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum KeyboardEvent {
Character(char),
KeyPress {
scancode: u32,
state: ElementState,
virtual_keycode: Option<VirtualKeyCode>,
modifiers: ModifiersState,
},
}
impl From<winit::event::KeyboardInput> for KeyboardEvent {
fn from(k: winit::event::KeyboardInput) -> Self {
#[allow(deprecated)]
KeyboardEvent::KeyPress {
scancode: k.scancode,
state: k.state,
virtual_keycode: k.virtual_keycode,
modifiers: k.modifiers.into(),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum MouseEvent {
CursorMoved {
sprite_position: (u32, u32),
absolute_position: (f64, f64),
},
CursorEntered,
CursorLeft,
Button {
state: ElementState,
button: MouseButton,
modifiers: ModifiersState,
},
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum WindowEvent {
Destroyed,
CloseRequested,
Focused(bool),
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Event {
Window(WindowEvent),
Keyboard(KeyboardEvent),
Mouse(MouseEvent),
}
impl std::convert::TryFrom<winit::event::Event<'_, ()>> for Event {
type Error = ();
fn try_from(e: winit::event::Event<'_, ()>) -> Result<Self, Self::Error> {
match &e {
winit::event::Event::WindowEvent { event: w, .. } => match w {
winit::event::WindowEvent::CloseRequested => {
Ok(Event::Window(WindowEvent::CloseRequested))
}
winit::event::WindowEvent::Destroyed => Ok(Event::Window(WindowEvent::Destroyed)),
winit::event::WindowEvent::Focused(focused) => {
Ok(Event::Window(WindowEvent::Focused(*focused)))
}
winit::event::WindowEvent::CursorEntered { .. } => {
Ok(Event::Mouse(MouseEvent::CursorEntered))
}
winit::event::WindowEvent::CursorLeft { .. } => {
Ok(Event::Mouse(MouseEvent::CursorLeft))
}
winit::event::WindowEvent::KeyboardInput { input, .. } => {
Ok(Event::Keyboard((*input).into()))
}
#[allow(deprecated)]
winit::event::WindowEvent::MouseInput {
state,
button,
modifiers,
..
} => Ok(Event::Mouse(MouseEvent::Button {
state: *state,
button: *button,
modifiers: (*modifiers).into(),
})),
winit::event::WindowEvent::CursorMoved { .. } => Err(()),
_ => Err(()),
},
_ => Err(()),
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct KeyBinding {
key: VirtualKeyCode,
shift: bool,
ctrl: bool,
alt: bool,
meta: bool,
}
impl KeyBinding {
pub fn new(key: VirtualKeyCode) -> Self {
KeyBinding {
key: key,
shift: false,
ctrl: false,
alt: false,
meta: false,
}
}
pub fn ctrl(mut self) -> Self {
self.ctrl = true;
self
}
pub fn shift(mut self) -> Self {
self.shift = true;
self
}
pub fn alt(mut self) -> Self {
self.alt = true;
self
}
pub fn meta(mut self) -> Self {
self.meta = true;
self
}
pub fn matches(&self, event: winit::event::KeyboardInput) -> bool {
if event.state == winit::event::ElementState::Pressed {
#[allow(deprecated)]
match event.virtual_keycode {
None => false,
Some(vk) => {
if vk == self.key {
self.shift == event.modifiers.shift()
&& self.ctrl == event.modifiers.ctrl()
&& self.alt == event.modifiers.alt()
&& self.meta == event.modifiers.logo()
} else {
false
}
}
}
} else {
false
}
}
fn try_from_event(event: winit::event::KeyboardInput) -> Option<KeyBinding> {
if event.state == winit::event::ElementState::Pressed {
#[allow(deprecated)]
match event.virtual_keycode {
None => None,
Some(vk) => Some(KeyBinding {
key: vk,
shift: event.modifiers.shift(),
ctrl: event.modifiers.ctrl(),
alt: event.modifiers.alt(),
meta: event.modifiers.logo(),
}),
}
} else {
None
}
}
}
pub struct EventDispatcher<C> {
key_bindings: HashMap<KeyBinding, C>,
window_close_command: Option<C>,
command_queue: std::sync::mpsc::SyncSender<C>,
}
impl<C: Clone> EventDispatcher<C> {
pub fn bind(&mut self, key: KeyBinding, command: C) {
self.key_bindings.insert(key, command);
}
pub fn set_window_close_command(&mut self, command: C) {
self.window_close_command = Some(command);
}
pub fn new(command_queue: std::sync::mpsc::SyncSender<C>) -> Self {
EventDispatcher {
key_bindings: HashMap::<KeyBinding, C>::new(),
window_close_command: None,
command_queue: command_queue,
}
}
pub fn dispatch(&self, event: &Event) -> Result<(), std::sync::mpsc::SendError<C>> {
match event {
_ => {}
};
Ok(())
}
}
#[cfg(test)]
mod tests {
#[test]
fn match_event() {
use super::*;
let kb = KeyBinding::new(VirtualKeyCode::Z);
assert!(kb.matches(
#[allow(deprecated)]
winit::event::KeyboardInput {
scancode: 0,
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Z),
modifiers: winit::event::ModifiersState::default()
}
));
assert!(!kb.matches(
#[allow(deprecated)]
winit::event::KeyboardInput {
scancode: 0,
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::X),
modifiers: winit::event::ModifiersState::default()
}
));
assert!(!kb.matches(
#[allow(deprecated)]
winit::event::KeyboardInput {
scancode: 0,
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Z),
modifiers: winit::event::ModifiersState::SHIFT
}
));
assert!(!kb.matches(
#[allow(deprecated)]
winit::event::KeyboardInput {
scancode: 0,
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Z),
modifiers: winit::event::ModifiersState::CTRL
}
));
assert!(!kb.matches(
#[allow(deprecated)]
winit::event::KeyboardInput {
scancode: 0,
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Z),
modifiers: winit::event::ModifiersState::ALT
}
));
assert!(!kb.matches(
#[allow(deprecated)]
winit::event::KeyboardInput {
scancode: 0,
state: winit::event::ElementState::Pressed,
virtual_keycode: Some(VirtualKeyCode::Z),
modifiers: winit::event::ModifiersState::LOGO
}
));
}
}