use crate::{Key, KeyInput, Mods};
use iced::keyboard::key::Named;
use iced::keyboard::{Event as KeyEvent, Key as IcedKey, Modifiers};
use iced::Event;
impl From<&IcedKey> for Key {
fn from(key: &IcedKey) -> Self {
match key {
IcedKey::Character(s) => {
let mut chars = s.chars();
if let (Some(c), None) = (chars.next(), chars.next()) {
Self::Char(c)
} else {
Self::Unidentified
}
}
IcedKey::Named(named) => match named {
Named::Space => Self::Char(' '),
Named::ArrowUp => Self::Up,
Named::ArrowRight => Self::Right,
Named::ArrowDown => Self::Down,
Named::ArrowLeft => Self::Left,
Named::Enter => Self::Enter,
Named::Backspace => Self::Backspace,
Named::Delete => Self::Delete,
Named::Home => Self::Home,
Named::End => Self::End,
Named::PageUp => Self::PageUp,
Named::PageDown => Self::PageDown,
Named::Escape => Self::Esc,
Named::Tab => Self::Tab,
Named::Insert => Self::Insert,
Named::Copy => Self::Copy,
Named::Cut => Self::Cut,
Named::Paste => Self::Paste,
Named::Clear => Self::Clear,
Named::Undo => Self::Undo,
Named::Redo => Self::Redo,
Named::Help => Self::Help,
Named::ZoomIn => Self::ZoomIn,
Named::ZoomOut => Self::ZoomOut,
Named::ZoomToggle => Self::ZoomToggle,
Named::ScrollLock => Self::ScrollLock,
Named::NumLock => Self::NumLock,
Named::PrintScreen => Self::PrintScreen,
Named::ContextMenu => Self::Menu,
Named::MediaPlay => Self::Play,
Named::MediaPause => Self::Pause,
Named::MediaPlayPause => Self::PlayPause,
Named::MediaStop => Self::Stop,
Named::MediaRewind => Self::Rewind,
Named::MediaTrackNext => Self::NextTrack,
Named::MediaTrackPrevious => Self::PrevTrack,
Named::AudioVolumeUp => Self::VolumeUp,
Named::AudioVolumeDown => Self::VolumeDown,
Named::AudioVolumeMute => Self::Mute,
Named::F1 => Self::F1,
Named::F2 => Self::F2,
Named::F3 => Self::F3,
Named::F4 => Self::F4,
Named::F5 => Self::F5,
Named::F6 => Self::F6,
Named::F7 => Self::F7,
Named::F8 => Self::F8,
Named::F9 => Self::F9,
Named::F10 => Self::F10,
Named::F11 => Self::F11,
Named::F12 => Self::F12,
Named::F13 => Self::F13,
Named::F14 => Self::F14,
Named::F15 => Self::F15,
Named::F16 => Self::F16,
Named::F17 => Self::F17,
Named::F18 => Self::F18,
Named::F19 => Self::F19,
Named::F20 => Self::F20,
Named::F21 => Self::F21,
Named::F22 => Self::F22,
Named::F23 => Self::F23,
Named::F24 => Self::F24,
Named::F25 => Self::F25,
Named::F26 => Self::F26,
Named::F27 => Self::F27,
Named::F28 => Self::F28,
Named::F29 => Self::F29,
Named::F30 => Self::F30,
Named::F31 => Self::F31,
Named::F32 => Self::F32,
Named::F33 => Self::F33,
Named::F34 => Self::F34,
Named::F35 => Self::F35,
Named::Alt
| Named::Control
| Named::Shift
| Named::Super
| Named::Hyper
| Named::Meta
| Named::Symbol => Self::Ignored,
_ => Self::Unidentified,
},
IcedKey::Unidentified => Self::Unidentified,
}
}
}
impl From<IcedKey> for Key {
fn from(key: IcedKey) -> Self {
Self::from(&key)
}
}
impl From<&Modifiers> for Mods {
fn from(from: &Modifiers) -> Self {
let mut to = Mods::NONE;
if from.contains(Modifiers::CTRL) {
to |= Mods::CTRL;
}
if from.contains(Modifiers::ALT) {
to |= Mods::ALT;
}
if from.contains(Modifiers::LOGO) {
to |= Mods::SUPER;
}
if from.contains(Modifiers::SHIFT) {
to |= Mods::SHIFT;
}
to
}
}
impl From<Modifiers> for Mods {
fn from(mods: Modifiers) -> Self {
Self::from(&mods)
}
}
impl From<&KeyEvent> for KeyInput {
fn from(event: &KeyEvent) -> Self {
match event {
KeyEvent::KeyPressed {
modified_key,
modifiers,
..
} => Self::new(modified_key, modifiers),
_ => Key::Ignored.into(),
}
}
}
impl From<KeyEvent> for KeyInput {
fn from(event: KeyEvent) -> Self {
Self::from(&event)
}
}
impl From<&Event> for KeyInput {
fn from(event: &Event) -> Self {
match event {
Event::Keyboard(event) => event.into(),
_ => Key::Ignored.into(),
}
}
}
impl From<Event> for KeyInput {
fn from(event: Event) -> Self {
Self::from(&event)
}
}
#[cfg(test)]
mod tests {
use super::*;
use iced::keyboard::key::{Code, Physical};
use iced::keyboard::Location;
use iced::window::Event as WindowEvent;
#[test]
fn key_to_key() {
assert_eq!(Key::from(IcedKey::Character("+".into())), Key::Char('+'));
assert_eq!(Key::from(IcedKey::Named(Named::Space)), Key::Char(' '));
assert_eq!(Key::from(IcedKey::Named(Named::ArrowUp)), Key::Up);
assert_eq!(Key::from(IcedKey::Named(Named::Control)), Key::Ignored);
assert_eq!(Key::from(IcedKey::Unidentified), Key::Unidentified);
assert_eq!(Key::from(IcedKey::Named(Named::Compose)), Key::Unidentified);
}
#[test]
fn modifiers_to_mods() {
assert_eq!(Mods::from(Modifiers::empty()), Mods::NONE);
assert_eq!(Mods::from(Modifiers::CTRL), Mods::CTRL);
assert_eq!(
Mods::from(Modifiers::CTRL | Modifiers::ALT),
Mods::CTRL | Mods::ALT,
);
assert_eq!(Mods::from(Modifiers::LOGO), Mods::SUPER);
assert_eq!(Mods::from(Modifiers::SHIFT), Mods::SHIFT);
}
#[test]
fn key_event_to_input() {
assert_eq!(
KeyInput::from(KeyEvent::KeyPressed {
key: IcedKey::Character("x".into()),
modified_key: IcedKey::Character("X".into()),
physical_key: Physical::Code(Code::KeyX),
location: Location::Standard,
modifiers: Modifiers::SHIFT,
text: Some("X".into()),
}),
KeyInput::from(Key::Char('X')),
);
assert_eq!(
KeyInput::from(KeyEvent::KeyReleased {
key: IcedKey::Character("x".into()),
location: Location::Standard,
modifiers: Modifiers::CTRL,
}),
KeyInput::from(Key::Ignored),
);
}
#[test]
fn event_to_input() {
assert_eq!(
KeyInput::from(Event::Keyboard(KeyEvent::KeyPressed {
key: IcedKey::Character("x".into()),
modified_key: IcedKey::Character("X".into()),
physical_key: Physical::Code(Code::KeyX),
location: Location::Standard,
modifiers: Modifiers::SHIFT,
text: Some("X".into()),
})),
KeyInput::from(Key::Char('X')),
);
assert_eq!(
KeyInput::from(Event::Window(WindowEvent::Closed)),
KeyInput::from(Key::Ignored),
);
}
}