use winit::event::{KeyEvent as WinitKeyEvent, MouseButton as WinitMouseButton};
use winit::keyboard::{Key as WinitKey, ModifiersState, NamedKey};
use winit::window::{CursorIcon as WinitCursor, Window as WinitWindow};
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "redox"
))]
use winit::platform::modifier_supplement::KeyEventExtModifierSupplement;
use crate::cursor::CursorIcon;
use crate::event::{Key, Modifiers, MouseButton};
pub fn mouse_button(b: WinitMouseButton) -> MouseButton {
match b {
WinitMouseButton::Left => MouseButton::Left,
WinitMouseButton::Right => MouseButton::Right,
WinitMouseButton::Middle => MouseButton::Middle,
WinitMouseButton::Other(n) => MouseButton::Other(n as u8),
_ => MouseButton::Other(255),
}
}
pub fn modifiers(s: ModifiersState) -> Modifiers {
Modifiers {
shift: s.shift_key(),
ctrl: s.control_key(),
alt: s.alt_key(),
meta: s.super_key(),
}
}
pub fn key(k: &WinitKey) -> Option<Key> {
Some(match k {
WinitKey::Named(NamedKey::ArrowUp) => Key::ArrowUp,
WinitKey::Named(NamedKey::ArrowDown) => Key::ArrowDown,
WinitKey::Named(NamedKey::ArrowLeft) => Key::ArrowLeft,
WinitKey::Named(NamedKey::ArrowRight) => Key::ArrowRight,
WinitKey::Named(NamedKey::Enter) => Key::Enter,
WinitKey::Named(NamedKey::Space) => Key::Char(' '),
WinitKey::Named(NamedKey::Tab) => Key::Tab,
WinitKey::Named(NamedKey::Escape) => Key::Escape,
WinitKey::Named(NamedKey::Backspace) => Key::Backspace,
WinitKey::Named(NamedKey::Home) => Key::Home,
WinitKey::Named(NamedKey::End) => Key::End,
WinitKey::Named(NamedKey::Delete) => Key::Delete,
WinitKey::Named(NamedKey::Insert) => Key::Insert,
WinitKey::Named(NamedKey::PageUp) => Key::Other("PageUp".into()),
WinitKey::Named(NamedKey::PageDown) => Key::Other("PageDown".into()),
WinitKey::Character(s) => Key::Char(s.chars().next()?),
_ => return None,
})
}
pub fn key_event(event: &WinitKeyEvent, mods: Modifiers) -> Option<Key> {
key(&shortcut_logical_key(event, mods))
}
#[cfg(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "redox"
))]
fn shortcut_logical_key(event: &WinitKeyEvent, mods: Modifiers) -> WinitKey {
shortcut_logical_key_from_keys(
event.logical_key.clone(),
event.key_without_modifiers(),
mods,
)
}
#[cfg(not(any(
target_os = "windows",
target_os = "macos",
target_os = "linux",
target_os = "redox"
)))]
fn shortcut_logical_key(event: &WinitKeyEvent, _: Modifiers) -> WinitKey {
event.logical_key.clone()
}
fn shortcut_logical_key_from_keys(
logical_key: WinitKey,
modifierless_key: WinitKey,
mods: Modifiers,
) -> WinitKey {
if mods.ctrl || mods.meta {
modifierless_key
} else {
logical_key
}
}
pub fn cursor_icon(icon: CursorIcon) -> WinitCursor {
match icon {
CursorIcon::Default => WinitCursor::Default,
CursorIcon::None => WinitCursor::Default,
CursorIcon::ContextMenu => WinitCursor::ContextMenu,
CursorIcon::Help => WinitCursor::Help,
CursorIcon::PointingHand => WinitCursor::Pointer,
CursorIcon::Progress => WinitCursor::Progress,
CursorIcon::Wait => WinitCursor::Wait,
CursorIcon::Cell => WinitCursor::Cell,
CursorIcon::Crosshair => WinitCursor::Crosshair,
CursorIcon::Text => WinitCursor::Text,
CursorIcon::VerticalText => WinitCursor::VerticalText,
CursorIcon::Alias => WinitCursor::Alias,
CursorIcon::Copy => WinitCursor::Copy,
CursorIcon::Move => WinitCursor::Move,
CursorIcon::NoDrop => WinitCursor::NoDrop,
CursorIcon::NotAllowed => WinitCursor::NotAllowed,
CursorIcon::Grab => WinitCursor::Grab,
CursorIcon::Grabbing => WinitCursor::Grabbing,
CursorIcon::AllScroll => WinitCursor::AllScroll,
CursorIcon::ResizeHorizontal => WinitCursor::EwResize,
CursorIcon::ResizeNeSw => WinitCursor::NeswResize,
CursorIcon::ResizeNwSe => WinitCursor::NwseResize,
CursorIcon::ResizeVertical => WinitCursor::NsResize,
CursorIcon::ResizeEast => WinitCursor::EResize,
CursorIcon::ResizeSouthEast => WinitCursor::SeResize,
CursorIcon::ResizeSouth => WinitCursor::SResize,
CursorIcon::ResizeSouthWest => WinitCursor::SwResize,
CursorIcon::ResizeWest => WinitCursor::WResize,
CursorIcon::ResizeNorthWest => WinitCursor::NwResize,
CursorIcon::ResizeNorth => WinitCursor::NResize,
CursorIcon::ResizeNorthEast => WinitCursor::NeResize,
CursorIcon::ResizeColumn => WinitCursor::ColResize,
CursorIcon::ResizeRow => WinitCursor::RowResize,
CursorIcon::ZoomIn => WinitCursor::ZoomIn,
CursorIcon::ZoomOut => WinitCursor::ZoomOut,
}
}
pub fn apply_cursor(window: &WinitWindow, icon: CursorIcon) {
if icon == CursorIcon::None {
window.set_cursor_visible(false);
} else {
window.set_cursor_visible(true);
window.set_cursor(cursor_icon(icon));
}
}
#[cfg(test)]
mod tests {
use super::*;
fn shortcut_key(logical_key: WinitKey, modifierless_key: WinitKey, mods: Modifiers) -> Key {
key(&shortcut_logical_key_from_keys(
logical_key,
modifierless_key,
mods,
))
.unwrap()
}
#[test]
fn ctrl_clipboard_shortcuts_use_modifierless_character() {
let mods = Modifiers {
ctrl: true,
..Modifiers::default()
};
assert_eq!(
shortcut_key(
WinitKey::Character("\u{3}".into()),
WinitKey::Character("c".into()),
mods,
),
Key::Char('c')
);
assert_eq!(
shortcut_key(
WinitKey::Character("\u{16}".into()),
WinitKey::Character("v".into()),
mods,
),
Key::Char('v')
);
}
#[test]
fn plain_text_input_keeps_logical_character() {
assert_eq!(
shortcut_key(
WinitKey::Character("C".into()),
WinitKey::Character("c".into()),
Modifiers::default(),
),
Key::Char('C')
);
}
}