use keyboard_types::{Code, Key, KeyState, KeyboardEvent, Location, Modifiers};
use log::info;
use winit::event::{ElementState, KeyEvent};
use winit::keyboard::{Key as LogicalKey, KeyCode, ModifiersState, NamedKey, PhysicalKey};
#[cfg(macos)]
pub const CMD_OR_CONTROL: Modifiers = Modifiers::META;
#[cfg(not(macos))]
pub const CMD_OR_CONTROL: Modifiers = Modifiers::CONTROL;
#[cfg(macos)]
pub const CMD_OR_ALT: Modifiers = Modifiers::META;
#[cfg(not(macos))]
pub const CMD_OR_ALT: Modifiers = Modifiers::ALT;
macro_rules! logical_to_winit_key {
(@opt $_: ident, $optional: expr) => {
$optional
};
(@opt $variant: ident) => {
Key::$variant
};
($key: ident $(,$variant: ident $(=> $matchto: expr)?)+) => {
match $key {
LogicalKey::Character(c) => Key::Character(c.to_string()),
$(LogicalKey::Named(NamedKey::$variant) => logical_to_winit_key!(@opt $variant $(, $matchto)?),)+
_ => Key::Unidentified,
}
};
}
fn get_servo_key_from_winit_key(key: &LogicalKey) -> Key {
logical_to_winit_key! {
key,
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
PrintScreen,
Pause, Insert, Home, Delete, End, PageDown, PageUp,
ArrowLeft, ArrowUp, ArrowRight, ArrowDown,
Backspace, Enter,
Compose,
NumLock,
LaunchApplication2, CapsLock,
Convert,
KanaMode, KanjiMode, Alt,
Control, Shift, Meta, LaunchMail,
MediaStop,
AudioVolumeMute, LaunchApplication1,
MediaTrackNext, NonConvert,
MediaPlayPause, Power, MediaTrackPrevious,
Standby,
Tab,
AudioVolumeDown, AudioVolumeUp, WakeUp, BrowserBack, BrowserFavorites, BrowserForward, BrowserHome, BrowserRefresh, BrowserSearch, BrowserStop,
Copy,
Paste,
Cut,
Space => Key::Character(" ".to_string())
}
}
macro_rules! map_key_location {
($key_code: ident $(, $location: ident : $k1: ident $(| $kn: ident)*)+) => {
match $key_code {
$(KeyCode::$k1 $(| KeyCode::$kn)* => Location::$location,)+
_ => Location::Standard,
}
};
}
fn get_servo_location_from_physical_key(physical_key: PhysicalKey) -> Location {
let key_code = if let PhysicalKey::Code(key_code) = physical_key {
key_code
} else {
return Location::Standard;
};
map_key_location!(
key_code,
Left: ShiftLeft | ControlLeft | AltLeft | SuperLeft,
Right: ShiftRight | ControlRight | AltRight | SuperRight,
Numpad: Numpad0 | Numpad1 | Numpad2 | Numpad3 | Numpad4 | Numpad5 | Numpad6 | Numpad7 | Numpad8 | Numpad9
| NumpadComma | NumpadEnter | NumpadEqual | NumpadAdd | NumpadSubtract | NumpadMultiply | NumpadDivide
| NumpadDecimal | NumpadBackspace | NumpadStar
)
}
macro_rules! physical_key_to_code {
(@opt $_: ident, $optional: ident) => {
Code::$optional
};
(@opt $variant: ident) => {
Code::$variant
};
($key_code: ident $(, $pk: ident $(=> $matchto: ident)?)+) => {
match $key_code {
$(KeyCode::$pk => physical_key_to_code!(@opt $pk $(, $matchto)?),)+
_ => Code::Unidentified,
}
};
}
fn get_servo_code_from_physical_key(physical_key: PhysicalKey) -> Code {
let key_code = if let PhysicalKey::Code(key_code) = physical_key {
key_code
} else {
return Code::Unidentified;
};
physical_key_to_code! {key_code,
Escape, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
Backquote, Digit1, Digit2, Digit3, Digit4, Digit5, Digit6, Digit7, Digit8, Digit9, Digit0, Minus, Equal, Backspace,
Tab, KeyQ, KeyW, KeyE, KeyR, KeyT, KeyY, KeyU, KeyI, KeyO, KeyP, BracketLeft, BracketRight, Backslash,
CapsLock, KeyA, KeyS, KeyD, KeyF, KeyG, KeyH, KeyJ, KeyK, KeyL, Semicolon, Quote, Enter,
ShiftLeft, KeyZ, KeyX, KeyC, KeyV, KeyB, KeyN, KeyM, Comma, Period, Slash, ShiftRight,
ControlLeft, AltLeft, Space, AltRight, ControlRight,
PrintScreen, ScrollLock, Pause,
Insert, Home, PageUp,
Delete, End, PageDown,
ArrowUp, ArrowLeft, ArrowDown, ArrowRight,
NumLock, NumpadDivide, NumpadMultiply, NumpadStar, NumpadSubtract,
Numpad7, Numpad8, Numpad9, NumpadAdd,
Numpad4, Numpad5, Numpad6,
Numpad1, Numpad2, Numpad3, NumpadEnter,
Numpad0, NumpadDecimal,
NumpadParenLeft, NumpadParenRight, NumpadComma, NumpadHash, NumpadBackspace
}
}
fn get_modifiers(mods: ModifiersState) -> Modifiers {
let mut modifiers = Modifiers::empty();
modifiers.set(Modifiers::CONTROL, mods.control_key());
modifiers.set(Modifiers::SHIFT, mods.shift_key());
modifiers.set(Modifiers::ALT, mods.alt_key());
modifiers.set(Modifiers::META, mods.super_key());
modifiers
}
pub fn keyboard_event_from_winit(input: &KeyEvent, state: ModifiersState) -> KeyboardEvent {
info!("winit keyboard input: {:?}", input);
KeyboardEvent {
state: match input.state {
ElementState::Pressed => KeyState::Down,
ElementState::Released => KeyState::Up,
},
key: get_servo_key_from_winit_key(&input.logical_key),
code: get_servo_code_from_physical_key(input.physical_key),
location: get_servo_location_from_physical_key(input.physical_key),
modifiers: get_modifiers(state),
repeat: false,
is_composing: false,
}
}