use concinnity_core::components::{InputKey, KeyEvent, KeyMods};
use objc2_app_kit::{NSEvent, NSEventModifierFlags};
#[derive(Default)]
pub(super) struct KeyState {
pub(super) forward: bool,
pub(super) backward: bool,
pub(super) left: bool,
pub(super) right: bool,
pub(super) sprint: bool,
pub(super) interact_pulse: bool,
pub(super) jump_pulse: bool,
pub(super) mouse_dx: f32,
pub(super) mouse_dy: f32,
pub(super) scroll_delta: f32,
pub(super) mouse_x: f32,
pub(super) mouse_y: f32,
pub(super) left_click_pulse: bool,
pub(super) left_button_down: bool,
pub(super) right_click_pulse: bool,
pub(super) hud_toggle_pulse: bool,
pub(super) escape_pulse: bool,
pub(super) events: Vec<KeyEvent>,
pub(super) shift_down: bool,
pub(super) control_down: bool,
pub(super) alt_down: bool,
pub(super) command_down: bool,
pub(super) discard_next_motion: bool,
pub(super) cursor_outside_window: bool,
}
pub(super) fn is_printable_glyph(c: char) -> bool {
!c.is_control() && !('\u{F700}'..='\u{F8FF}').contains(&c)
}
pub(super) fn printable_char(event: &NSEvent) -> Option<char> {
let text = event.characters()?.to_string();
let c = text.chars().next()?;
is_printable_glyph(c).then_some(c)
}
pub(super) fn event_mods(flags: NSEventModifierFlags) -> KeyMods {
KeyMods {
shift: flags.contains(NSEventModifierFlags::Shift),
ctrl: flags.contains(NSEventModifierFlags::Control),
alt: flags.contains(NSEventModifierFlags::Option),
cmd: flags.contains(NSEventModifierFlags::Command),
}
}
pub(super) fn key_from_mac(kc: u16) -> Option<InputKey> {
Some(match kc {
0 => InputKey::A,
11 => InputKey::B,
8 => InputKey::C,
2 => InputKey::D,
14 => InputKey::E,
3 => InputKey::F,
5 => InputKey::G,
4 => InputKey::H,
34 => InputKey::I,
38 => InputKey::J,
40 => InputKey::K,
37 => InputKey::L,
46 => InputKey::M,
45 => InputKey::N,
31 => InputKey::O,
35 => InputKey::P,
12 => InputKey::Q,
15 => InputKey::R,
1 => InputKey::S,
17 => InputKey::T,
32 => InputKey::U,
9 => InputKey::V,
13 => InputKey::W,
7 => InputKey::X,
16 => InputKey::Y,
6 => InputKey::Z,
29 => InputKey::Num0,
18 => InputKey::Num1,
19 => InputKey::Num2,
20 => InputKey::Num3,
21 => InputKey::Num4,
23 => InputKey::Num5,
22 => InputKey::Num6,
26 => InputKey::Num7,
28 => InputKey::Num8,
25 => InputKey::Num9,
49 => InputKey::Space,
48 => InputKey::Tab,
36 => InputKey::Enter,
51 => InputKey::Backspace,
117 => InputKey::Delete,
123 => InputKey::Left,
124 => InputKey::Right,
125 => InputKey::Down,
126 => InputKey::Up,
115 => InputKey::Home,
119 => InputKey::End,
116 => InputKey::PageUp,
121 => InputKey::PageDown,
27 => InputKey::Minus,
24 => InputKey::Equals,
33 => InputKey::LeftBracket,
30 => InputKey::RightBracket,
42 => InputKey::Backslash,
41 => InputKey::Semicolon,
39 => InputKey::Quote,
43 => InputKey::Comma,
47 => InputKey::Period,
44 => InputKey::Slash,
50 => InputKey::Backtick,
_ => return None,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn key_from_mac_covers_the_defaults() {
assert_eq!(key_from_mac(13), Some(InputKey::W));
assert_eq!(key_from_mac(0), Some(InputKey::A));
assert_eq!(key_from_mac(1), Some(InputKey::S));
assert_eq!(key_from_mac(2), Some(InputKey::D));
assert_eq!(key_from_mac(49), Some(InputKey::Space));
assert_eq!(key_from_mac(14), Some(InputKey::E));
assert_eq!(key_from_mac(53), None);
assert_eq!(key_from_mac(122), None);
}
#[test]
fn editing_keys_decode() {
assert_eq!(key_from_mac(51), Some(InputKey::Backspace));
assert_eq!(key_from_mac(117), Some(InputKey::Delete));
assert_eq!(key_from_mac(115), Some(InputKey::Home));
assert_eq!(key_from_mac(119), Some(InputKey::End));
assert_eq!(key_from_mac(116), Some(InputKey::PageUp));
assert_eq!(key_from_mac(121), Some(InputKey::PageDown));
}
#[test]
fn event_mods_read_each_flag() {
assert_eq!(event_mods(NSEventModifierFlags::empty()), KeyMods::NONE);
assert_eq!(event_mods(NSEventModifierFlags::Command), KeyMods::CMD);
let both = event_mods(NSEventModifierFlags::Option | NSEventModifierFlags::Shift);
assert!(both.alt && both.shift && !both.ctrl && !both.cmd);
}
#[test]
fn printable_glyph_filter() {
assert!(is_printable_glyph('a'));
assert!(is_printable_glyph('Z'));
assert!(is_printable_glyph(' '));
assert!(is_printable_glyph('/'));
assert!(!is_printable_glyph('\u{8}')); assert!(!is_printable_glyph('\r')); assert!(!is_printable_glyph('\u{7f}')); assert!(!is_printable_glyph('\u{F702}')); }
}