2023-05-28 20:02:59 +02:00
|
|
|
use std::ffi::c_void;
|
2019-05-01 17:03:30 -06:00
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
use core_foundation::{
|
|
|
|
|
base::CFRelease,
|
|
|
|
|
data::{CFDataGetBytePtr, CFDataRef},
|
|
|
|
|
};
|
2022-09-08 16:45:29 +02:00
|
|
|
use objc2::rc::{Id, Shared};
|
2023-05-28 20:02:59 +02:00
|
|
|
use smol_str::SmolStr;
|
2019-05-01 17:03:30 -06:00
|
|
|
|
2022-09-08 16:45:29 +02:00
|
|
|
use super::appkit::{NSEvent, NSEventModifierFlags};
|
|
|
|
|
use super::window::WinitWindow;
|
2019-06-21 11:33:15 -04:00
|
|
|
use crate::{
|
2020-01-04 01:32:34 -05:00
|
|
|
dpi::LogicalSize,
|
2023-05-28 20:02:59 +02:00
|
|
|
event::{ElementState, Event, KeyEvent, Modifiers},
|
|
|
|
|
keyboard::{
|
|
|
|
|
Key, KeyCode, KeyLocation, ModifiersKeys, ModifiersState, NativeKey, NativeKeyCode,
|
|
|
|
|
},
|
|
|
|
|
platform::{modifier_supplement::KeyEventExtModifierSupplement, scancode::KeyCodeExtScancode},
|
|
|
|
|
platform_impl::platform::{
|
|
|
|
|
ffi,
|
|
|
|
|
util::{get_kbd_type, Never},
|
|
|
|
|
},
|
2019-05-01 17:03:30 -06:00
|
|
|
};
|
|
|
|
|
|
2020-01-04 01:32:34 -05:00
|
|
|
#[derive(Debug)]
|
2022-09-08 16:45:29 +02:00
|
|
|
pub(crate) enum EventWrapper {
|
2020-01-04 01:32:34 -05:00
|
|
|
StaticEvent(Event<'static, Never>),
|
|
|
|
|
EventProxy(EventProxy),
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-08 16:45:29 +02:00
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub(crate) enum EventProxy {
|
2020-01-03 14:52:27 -05:00
|
|
|
DpiChangedProxy {
|
2022-09-08 16:45:29 +02:00
|
|
|
window: Id<WinitWindow, Shared>,
|
2020-01-04 01:33:07 -05:00
|
|
|
suggested_size: LogicalSize<f64>,
|
2020-01-03 14:52:27 -05:00
|
|
|
scale_factor: f64,
|
2020-01-04 01:32:34 -05:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
|
|
|
pub struct KeyEventExtra {
|
|
|
|
|
pub text_with_all_modifiers: Option<SmolStr>,
|
|
|
|
|
pub key_without_modifiers: Key,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl KeyEventExtModifierSupplement for KeyEvent {
|
|
|
|
|
fn text_with_all_modifiers(&self) -> Option<&str> {
|
|
|
|
|
self.platform_specific
|
|
|
|
|
.text_with_all_modifiers
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| s.as_str())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn key_without_modifiers(&self) -> Key {
|
|
|
|
|
self.platform_specific.key_without_modifiers.clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_modifierless_char(scancode: u16) -> Key {
|
|
|
|
|
let mut string = [0; 16];
|
|
|
|
|
let input_source;
|
|
|
|
|
let layout;
|
|
|
|
|
unsafe {
|
|
|
|
|
input_source = ffi::TISCopyCurrentKeyboardLayoutInputSource();
|
|
|
|
|
if input_source.is_null() {
|
|
|
|
|
log::error!("`TISCopyCurrentKeyboardLayoutInputSource` returned null ptr");
|
|
|
|
|
return Key::Unidentified(NativeKey::MacOS(scancode));
|
|
|
|
|
}
|
|
|
|
|
let layout_data =
|
|
|
|
|
ffi::TISGetInputSourceProperty(input_source, ffi::kTISPropertyUnicodeKeyLayoutData);
|
|
|
|
|
if layout_data.is_null() {
|
|
|
|
|
CFRelease(input_source as *mut c_void);
|
|
|
|
|
log::error!("`TISGetInputSourceProperty` returned null ptr");
|
|
|
|
|
return Key::Unidentified(NativeKey::MacOS(scancode));
|
|
|
|
|
}
|
|
|
|
|
layout = CFDataGetBytePtr(layout_data as CFDataRef) as *const ffi::UCKeyboardLayout;
|
|
|
|
|
}
|
|
|
|
|
let keyboard_type = get_kbd_type();
|
|
|
|
|
|
|
|
|
|
let mut result_len = 0;
|
|
|
|
|
let mut dead_keys = 0;
|
|
|
|
|
let modifiers = 0;
|
|
|
|
|
let translate_result = unsafe {
|
|
|
|
|
ffi::UCKeyTranslate(
|
|
|
|
|
layout,
|
|
|
|
|
scancode,
|
|
|
|
|
ffi::kUCKeyActionDisplay,
|
|
|
|
|
modifiers,
|
|
|
|
|
keyboard_type as u32,
|
|
|
|
|
ffi::kUCKeyTranslateNoDeadKeysMask,
|
|
|
|
|
&mut dead_keys,
|
|
|
|
|
string.len() as ffi::UniCharCount,
|
|
|
|
|
&mut result_len,
|
|
|
|
|
string.as_mut_ptr(),
|
|
|
|
|
)
|
|
|
|
|
};
|
|
|
|
|
unsafe {
|
|
|
|
|
CFRelease(input_source as *mut c_void);
|
|
|
|
|
}
|
|
|
|
|
if translate_result != 0 {
|
|
|
|
|
log::error!(
|
|
|
|
|
"`UCKeyTranslate` returned with the non-zero value: {}",
|
|
|
|
|
translate_result
|
|
|
|
|
);
|
|
|
|
|
return Key::Unidentified(NativeKey::MacOS(scancode));
|
|
|
|
|
}
|
|
|
|
|
if result_len == 0 {
|
|
|
|
|
log::error!("`UCKeyTranslate` was succesful but gave a string of 0 length.");
|
|
|
|
|
return Key::Unidentified(NativeKey::MacOS(scancode));
|
|
|
|
|
}
|
|
|
|
|
let chars = String::from_utf16_lossy(&string[0..result_len as usize]);
|
|
|
|
|
Key::Character(SmolStr::new(chars))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_logical_key_char(ns_event: &NSEvent, modifierless_chars: &str) -> Key {
|
|
|
|
|
let string = ns_event
|
|
|
|
|
.charactersIgnoringModifiers()
|
|
|
|
|
.map(|s| s.to_string())
|
|
|
|
|
.unwrap_or_else(String::new);
|
|
|
|
|
if string.is_empty() {
|
|
|
|
|
// Probably a dead key
|
|
|
|
|
let first_char = modifierless_chars.chars().next();
|
|
|
|
|
return Key::Dead(first_char);
|
|
|
|
|
}
|
|
|
|
|
Key::Character(SmolStr::new(string))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create `KeyEvent` for the given `NSEvent`.
|
|
|
|
|
///
|
|
|
|
|
/// This function shouldn't be called when the IME input is in process.
|
|
|
|
|
pub(crate) fn create_key_event(
|
|
|
|
|
ns_event: &NSEvent,
|
|
|
|
|
is_press: bool,
|
|
|
|
|
is_repeat: bool,
|
|
|
|
|
key_override: Option<KeyCode>,
|
|
|
|
|
) -> KeyEvent {
|
|
|
|
|
use ElementState::{Pressed, Released};
|
|
|
|
|
let state = if is_press { Pressed } else { Released };
|
|
|
|
|
|
|
|
|
|
let scancode = ns_event.key_code();
|
|
|
|
|
let mut physical_key = key_override.unwrap_or_else(|| KeyCode::from_scancode(scancode as u32));
|
|
|
|
|
|
|
|
|
|
let text_with_all_modifiers: Option<SmolStr> = if key_override.is_some() {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
let characters = ns_event
|
|
|
|
|
.characters()
|
|
|
|
|
.map(|s| s.to_string())
|
|
|
|
|
.unwrap_or_else(String::new);
|
|
|
|
|
if characters.is_empty() {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
|
|
|
|
if matches!(physical_key, KeyCode::Unidentified(_)) {
|
|
|
|
|
// The key may be one of the funky function keys
|
|
|
|
|
physical_key = extra_function_key_to_code(scancode, &characters);
|
|
|
|
|
}
|
|
|
|
|
Some(SmolStr::new(characters))
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let key_from_code = code_to_key(physical_key, scancode);
|
|
|
|
|
let (logical_key, key_without_modifiers) = if matches!(key_from_code, Key::Unidentified(_)) {
|
|
|
|
|
let key_without_modifiers = get_modifierless_char(scancode);
|
|
|
|
|
|
|
|
|
|
let modifiers = NSEvent::modifierFlags(ns_event);
|
|
|
|
|
let has_ctrl = modifiers.contains(NSEventModifierFlags::NSControlKeyMask);
|
|
|
|
|
|
|
|
|
|
let logical_key = match text_with_all_modifiers.as_ref() {
|
|
|
|
|
// Only checking for ctrl here, not checking for alt because we DO want to
|
|
|
|
|
// include its effect in the key. For example if -on the Germay layout- one
|
|
|
|
|
// presses alt+8, the logical key should be "{"
|
|
|
|
|
// Also not checking if this is a release event because then this issue would
|
|
|
|
|
// still affect the key release.
|
|
|
|
|
Some(text) if !has_ctrl => Key::Character(text.clone()),
|
|
|
|
|
_ => {
|
|
|
|
|
let modifierless_chars = match key_without_modifiers.as_ref() {
|
|
|
|
|
Key::Character(ch) => ch,
|
|
|
|
|
_ => "",
|
|
|
|
|
};
|
|
|
|
|
get_logical_key_char(ns_event, modifierless_chars)
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
(logical_key, key_without_modifiers)
|
|
|
|
|
} else {
|
|
|
|
|
(key_from_code.clone(), key_from_code)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let text = if is_press {
|
|
|
|
|
logical_key.to_text().map(SmolStr::new)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let location = code_to_location(physical_key);
|
|
|
|
|
|
|
|
|
|
KeyEvent {
|
|
|
|
|
location,
|
|
|
|
|
logical_key,
|
|
|
|
|
physical_key,
|
|
|
|
|
repeat: is_repeat,
|
|
|
|
|
state,
|
|
|
|
|
text,
|
|
|
|
|
platform_specific: KeyEventExtra {
|
|
|
|
|
key_without_modifiers,
|
|
|
|
|
text_with_all_modifiers,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn code_to_key(code: KeyCode, scancode: u16) -> Key {
|
|
|
|
|
match code {
|
|
|
|
|
KeyCode::Enter => Key::Enter,
|
|
|
|
|
KeyCode::Tab => Key::Tab,
|
|
|
|
|
KeyCode::Space => Key::Space,
|
|
|
|
|
KeyCode::Backspace => Key::Backspace,
|
|
|
|
|
KeyCode::Escape => Key::Escape,
|
|
|
|
|
KeyCode::SuperRight => Key::Super,
|
|
|
|
|
KeyCode::SuperLeft => Key::Super,
|
|
|
|
|
KeyCode::ShiftLeft => Key::Shift,
|
|
|
|
|
KeyCode::AltLeft => Key::Alt,
|
|
|
|
|
KeyCode::ControlLeft => Key::Control,
|
|
|
|
|
KeyCode::ShiftRight => Key::Shift,
|
|
|
|
|
KeyCode::AltRight => Key::Alt,
|
|
|
|
|
KeyCode::ControlRight => Key::Control,
|
|
|
|
|
|
|
|
|
|
KeyCode::NumLock => Key::NumLock,
|
|
|
|
|
KeyCode::AudioVolumeUp => Key::AudioVolumeUp,
|
|
|
|
|
KeyCode::AudioVolumeDown => Key::AudioVolumeDown,
|
|
|
|
|
|
|
|
|
|
// Other numpad keys all generate text on macOS (if I understand correctly)
|
|
|
|
|
KeyCode::NumpadEnter => Key::Enter,
|
|
|
|
|
|
|
|
|
|
KeyCode::F1 => Key::F1,
|
|
|
|
|
KeyCode::F2 => Key::F2,
|
|
|
|
|
KeyCode::F3 => Key::F3,
|
|
|
|
|
KeyCode::F4 => Key::F4,
|
|
|
|
|
KeyCode::F5 => Key::F5,
|
|
|
|
|
KeyCode::F6 => Key::F6,
|
|
|
|
|
KeyCode::F7 => Key::F7,
|
|
|
|
|
KeyCode::F8 => Key::F8,
|
|
|
|
|
KeyCode::F9 => Key::F9,
|
|
|
|
|
KeyCode::F10 => Key::F10,
|
|
|
|
|
KeyCode::F11 => Key::F11,
|
|
|
|
|
KeyCode::F12 => Key::F12,
|
|
|
|
|
KeyCode::F13 => Key::F13,
|
|
|
|
|
KeyCode::F14 => Key::F14,
|
|
|
|
|
KeyCode::F15 => Key::F15,
|
|
|
|
|
KeyCode::F16 => Key::F16,
|
|
|
|
|
KeyCode::F17 => Key::F17,
|
|
|
|
|
KeyCode::F18 => Key::F18,
|
|
|
|
|
KeyCode::F19 => Key::F19,
|
|
|
|
|
KeyCode::F20 => Key::F20,
|
|
|
|
|
|
|
|
|
|
KeyCode::Insert => Key::Insert,
|
|
|
|
|
KeyCode::Home => Key::Home,
|
|
|
|
|
KeyCode::PageUp => Key::PageUp,
|
|
|
|
|
KeyCode::Delete => Key::Delete,
|
|
|
|
|
KeyCode::End => Key::End,
|
|
|
|
|
KeyCode::PageDown => Key::PageDown,
|
|
|
|
|
KeyCode::ArrowLeft => Key::ArrowLeft,
|
|
|
|
|
KeyCode::ArrowRight => Key::ArrowRight,
|
|
|
|
|
KeyCode::ArrowDown => Key::ArrowDown,
|
|
|
|
|
KeyCode::ArrowUp => Key::ArrowUp,
|
|
|
|
|
_ => Key::Unidentified(NativeKey::MacOS(scancode)),
|
|
|
|
|
}
|
2019-05-01 17:03:30 -06:00
|
|
|
}
|
|
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
pub fn code_to_location(code: KeyCode) -> KeyLocation {
|
|
|
|
|
match code {
|
|
|
|
|
KeyCode::SuperRight => KeyLocation::Right,
|
|
|
|
|
KeyCode::SuperLeft => KeyLocation::Left,
|
|
|
|
|
KeyCode::ShiftLeft => KeyLocation::Left,
|
|
|
|
|
KeyCode::AltLeft => KeyLocation::Left,
|
|
|
|
|
KeyCode::ControlLeft => KeyLocation::Left,
|
|
|
|
|
KeyCode::ShiftRight => KeyLocation::Right,
|
|
|
|
|
KeyCode::AltRight => KeyLocation::Right,
|
|
|
|
|
KeyCode::ControlRight => KeyLocation::Right,
|
|
|
|
|
|
|
|
|
|
KeyCode::NumLock => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::NumpadDecimal => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::NumpadMultiply => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::NumpadAdd => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::NumpadDivide => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::NumpadEnter => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::NumpadSubtract => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::NumpadEqual => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad0 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad1 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad2 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad3 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad4 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad5 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad6 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad7 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad8 => KeyLocation::Numpad,
|
|
|
|
|
KeyCode::Numpad9 => KeyLocation::Numpad,
|
|
|
|
|
|
|
|
|
|
_ => KeyLocation::Standard,
|
|
|
|
|
}
|
2019-05-01 17:03:30 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// While F1-F20 have scancodes we can match on, we have to check against UTF-16
|
|
|
|
|
// constants for the rest.
|
|
|
|
|
// https://developer.apple.com/documentation/appkit/1535851-function-key_unicodes?preferredLanguage=occ
|
2023-05-28 20:02:59 +02:00
|
|
|
pub fn extra_function_key_to_code(scancode: u16, string: &str) -> KeyCode {
|
2019-05-01 17:03:30 -06:00
|
|
|
if let Some(ch) = string.encode_utf16().next() {
|
2023-05-28 20:02:59 +02:00
|
|
|
match ch {
|
|
|
|
|
0xf718 => KeyCode::F21,
|
|
|
|
|
0xf719 => KeyCode::F22,
|
|
|
|
|
0xf71a => KeyCode::F23,
|
|
|
|
|
0xf71b => KeyCode::F24,
|
|
|
|
|
_ => KeyCode::Unidentified(NativeKeyCode::MacOS(scancode)),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
KeyCode::Unidentified(NativeKeyCode::MacOS(scancode))
|
2019-05-01 17:03:30 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
pub(super) fn event_mods(event: &NSEvent) -> Modifiers {
|
2022-09-08 16:45:29 +02:00
|
|
|
let flags = event.modifierFlags();
|
2023-05-28 20:02:59 +02:00
|
|
|
let mut state = ModifiersState::empty();
|
|
|
|
|
let mut pressed_mods = ModifiersKeys::empty();
|
|
|
|
|
|
|
|
|
|
state.set(
|
2019-12-28 15:36:06 -05:00
|
|
|
ModifiersState::SHIFT,
|
|
|
|
|
flags.contains(NSEventModifierFlags::NSShiftKeyMask),
|
|
|
|
|
);
|
2023-05-28 20:02:59 +02:00
|
|
|
|
|
|
|
|
pressed_mods.set(ModifiersKeys::LSHIFT, event.lshift_pressed());
|
|
|
|
|
pressed_mods.set(ModifiersKeys::RSHIFT, event.rshift_pressed());
|
|
|
|
|
|
|
|
|
|
state.set(
|
|
|
|
|
ModifiersState::CONTROL,
|
2019-12-28 15:36:06 -05:00
|
|
|
flags.contains(NSEventModifierFlags::NSControlKeyMask),
|
|
|
|
|
);
|
2023-05-28 20:02:59 +02:00
|
|
|
|
|
|
|
|
pressed_mods.set(ModifiersKeys::LCONTROL, event.lctrl_pressed());
|
|
|
|
|
pressed_mods.set(ModifiersKeys::RCONTROL, event.rctrl_pressed());
|
|
|
|
|
|
|
|
|
|
state.set(
|
2019-12-28 15:36:06 -05:00
|
|
|
ModifiersState::ALT,
|
|
|
|
|
flags.contains(NSEventModifierFlags::NSAlternateKeyMask),
|
|
|
|
|
);
|
2023-05-28 20:02:59 +02:00
|
|
|
|
|
|
|
|
pressed_mods.set(ModifiersKeys::LALT, event.lalt_pressed());
|
|
|
|
|
pressed_mods.set(ModifiersKeys::RALT, event.ralt_pressed());
|
|
|
|
|
|
|
|
|
|
state.set(
|
|
|
|
|
ModifiersState::SUPER,
|
2019-12-28 15:36:06 -05:00
|
|
|
flags.contains(NSEventModifierFlags::NSCommandKeyMask),
|
|
|
|
|
);
|
2023-05-28 20:02:59 +02:00
|
|
|
|
|
|
|
|
pressed_mods.set(ModifiersKeys::LSUPER, event.lcmd_pressed());
|
|
|
|
|
pressed_mods.set(ModifiersKeys::RSUPER, event.rcmd_pressed());
|
|
|
|
|
|
|
|
|
|
Modifiers {
|
|
|
|
|
state,
|
|
|
|
|
pressed_mods,
|
|
|
|
|
}
|
2019-05-01 17:03:30 -06:00
|
|
|
}
|
|
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
impl KeyCodeExtScancode for KeyCode {
|
|
|
|
|
fn to_scancode(self) -> Option<u32> {
|
|
|
|
|
match self {
|
|
|
|
|
KeyCode::KeyA => Some(0x00),
|
|
|
|
|
KeyCode::KeyS => Some(0x01),
|
|
|
|
|
KeyCode::KeyD => Some(0x02),
|
|
|
|
|
KeyCode::KeyF => Some(0x03),
|
|
|
|
|
KeyCode::KeyH => Some(0x04),
|
|
|
|
|
KeyCode::KeyG => Some(0x05),
|
|
|
|
|
KeyCode::KeyZ => Some(0x06),
|
|
|
|
|
KeyCode::KeyX => Some(0x07),
|
|
|
|
|
KeyCode::KeyC => Some(0x08),
|
|
|
|
|
KeyCode::KeyV => Some(0x09),
|
|
|
|
|
KeyCode::KeyB => Some(0x0b),
|
|
|
|
|
KeyCode::KeyQ => Some(0x0c),
|
|
|
|
|
KeyCode::KeyW => Some(0x0d),
|
|
|
|
|
KeyCode::KeyE => Some(0x0e),
|
|
|
|
|
KeyCode::KeyR => Some(0x0f),
|
|
|
|
|
KeyCode::KeyY => Some(0x10),
|
|
|
|
|
KeyCode::KeyT => Some(0x11),
|
|
|
|
|
KeyCode::Digit1 => Some(0x12),
|
|
|
|
|
KeyCode::Digit2 => Some(0x13),
|
|
|
|
|
KeyCode::Digit3 => Some(0x14),
|
|
|
|
|
KeyCode::Digit4 => Some(0x15),
|
|
|
|
|
KeyCode::Digit6 => Some(0x16),
|
|
|
|
|
KeyCode::Digit5 => Some(0x17),
|
|
|
|
|
KeyCode::Equal => Some(0x18),
|
|
|
|
|
KeyCode::Digit9 => Some(0x19),
|
|
|
|
|
KeyCode::Digit7 => Some(0x1a),
|
|
|
|
|
KeyCode::Minus => Some(0x1b),
|
|
|
|
|
KeyCode::Digit8 => Some(0x1c),
|
|
|
|
|
KeyCode::Digit0 => Some(0x1d),
|
|
|
|
|
KeyCode::BracketRight => Some(0x1e),
|
|
|
|
|
KeyCode::KeyO => Some(0x1f),
|
|
|
|
|
KeyCode::KeyU => Some(0x20),
|
|
|
|
|
KeyCode::BracketLeft => Some(0x21),
|
|
|
|
|
KeyCode::KeyI => Some(0x22),
|
|
|
|
|
KeyCode::KeyP => Some(0x23),
|
|
|
|
|
KeyCode::Enter => Some(0x24),
|
|
|
|
|
KeyCode::KeyL => Some(0x25),
|
|
|
|
|
KeyCode::KeyJ => Some(0x26),
|
|
|
|
|
KeyCode::Quote => Some(0x27),
|
|
|
|
|
KeyCode::KeyK => Some(0x28),
|
|
|
|
|
KeyCode::Semicolon => Some(0x29),
|
|
|
|
|
KeyCode::Backslash => Some(0x2a),
|
|
|
|
|
KeyCode::Comma => Some(0x2b),
|
|
|
|
|
KeyCode::Slash => Some(0x2c),
|
|
|
|
|
KeyCode::KeyN => Some(0x2d),
|
|
|
|
|
KeyCode::KeyM => Some(0x2e),
|
|
|
|
|
KeyCode::Period => Some(0x2f),
|
|
|
|
|
KeyCode::Tab => Some(0x30),
|
|
|
|
|
KeyCode::Space => Some(0x31),
|
|
|
|
|
KeyCode::Backquote => Some(0x32),
|
|
|
|
|
KeyCode::Backspace => Some(0x33),
|
|
|
|
|
KeyCode::Escape => Some(0x35),
|
|
|
|
|
KeyCode::SuperRight => Some(0x36),
|
|
|
|
|
KeyCode::SuperLeft => Some(0x37),
|
|
|
|
|
KeyCode::ShiftLeft => Some(0x38),
|
|
|
|
|
KeyCode::AltLeft => Some(0x3a),
|
|
|
|
|
KeyCode::ControlLeft => Some(0x3b),
|
|
|
|
|
KeyCode::ShiftRight => Some(0x3c),
|
|
|
|
|
KeyCode::AltRight => Some(0x3d),
|
|
|
|
|
KeyCode::ControlRight => Some(0x3e),
|
|
|
|
|
KeyCode::F17 => Some(0x40),
|
|
|
|
|
KeyCode::NumpadDecimal => Some(0x41),
|
|
|
|
|
KeyCode::NumpadMultiply => Some(0x43),
|
|
|
|
|
KeyCode::NumpadAdd => Some(0x45),
|
|
|
|
|
KeyCode::NumLock => Some(0x47),
|
|
|
|
|
KeyCode::AudioVolumeUp => Some(0x49),
|
|
|
|
|
KeyCode::AudioVolumeDown => Some(0x4a),
|
|
|
|
|
KeyCode::NumpadDivide => Some(0x4b),
|
|
|
|
|
KeyCode::NumpadEnter => Some(0x4c),
|
|
|
|
|
KeyCode::NumpadSubtract => Some(0x4e),
|
|
|
|
|
KeyCode::F18 => Some(0x4f),
|
|
|
|
|
KeyCode::F19 => Some(0x50),
|
|
|
|
|
KeyCode::NumpadEqual => Some(0x51),
|
|
|
|
|
KeyCode::Numpad0 => Some(0x52),
|
|
|
|
|
KeyCode::Numpad1 => Some(0x53),
|
|
|
|
|
KeyCode::Numpad2 => Some(0x54),
|
|
|
|
|
KeyCode::Numpad3 => Some(0x55),
|
|
|
|
|
KeyCode::Numpad4 => Some(0x56),
|
|
|
|
|
KeyCode::Numpad5 => Some(0x57),
|
|
|
|
|
KeyCode::Numpad6 => Some(0x58),
|
|
|
|
|
KeyCode::Numpad7 => Some(0x59),
|
|
|
|
|
KeyCode::F20 => Some(0x5a),
|
|
|
|
|
KeyCode::Numpad8 => Some(0x5b),
|
|
|
|
|
KeyCode::Numpad9 => Some(0x5c),
|
|
|
|
|
KeyCode::IntlYen => Some(0x5d),
|
|
|
|
|
KeyCode::F5 => Some(0x60),
|
|
|
|
|
KeyCode::F6 => Some(0x61),
|
|
|
|
|
KeyCode::F7 => Some(0x62),
|
|
|
|
|
KeyCode::F3 => Some(0x63),
|
|
|
|
|
KeyCode::F8 => Some(0x64),
|
|
|
|
|
KeyCode::F9 => Some(0x65),
|
|
|
|
|
KeyCode::F11 => Some(0x67),
|
|
|
|
|
KeyCode::F13 => Some(0x69),
|
|
|
|
|
KeyCode::F16 => Some(0x6a),
|
|
|
|
|
KeyCode::F14 => Some(0x6b),
|
|
|
|
|
KeyCode::F10 => Some(0x6d),
|
|
|
|
|
KeyCode::F12 => Some(0x6f),
|
|
|
|
|
KeyCode::F15 => Some(0x71),
|
|
|
|
|
KeyCode::Insert => Some(0x72),
|
|
|
|
|
KeyCode::Home => Some(0x73),
|
|
|
|
|
KeyCode::PageUp => Some(0x74),
|
|
|
|
|
KeyCode::Delete => Some(0x75),
|
|
|
|
|
KeyCode::F4 => Some(0x76),
|
|
|
|
|
KeyCode::End => Some(0x77),
|
|
|
|
|
KeyCode::F2 => Some(0x78),
|
|
|
|
|
KeyCode::PageDown => Some(0x79),
|
|
|
|
|
KeyCode::F1 => Some(0x7a),
|
|
|
|
|
KeyCode::ArrowLeft => Some(0x7b),
|
|
|
|
|
KeyCode::ArrowRight => Some(0x7c),
|
|
|
|
|
KeyCode::ArrowDown => Some(0x7d),
|
|
|
|
|
KeyCode::ArrowUp => Some(0x7e),
|
|
|
|
|
_ => None,
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-01 17:03:30 -06:00
|
|
|
|
2023-05-28 20:02:59 +02:00
|
|
|
fn from_scancode(scancode: u32) -> KeyCode {
|
|
|
|
|
match scancode {
|
|
|
|
|
0x00 => KeyCode::KeyA,
|
|
|
|
|
0x01 => KeyCode::KeyS,
|
|
|
|
|
0x02 => KeyCode::KeyD,
|
|
|
|
|
0x03 => KeyCode::KeyF,
|
|
|
|
|
0x04 => KeyCode::KeyH,
|
|
|
|
|
0x05 => KeyCode::KeyG,
|
|
|
|
|
0x06 => KeyCode::KeyZ,
|
|
|
|
|
0x07 => KeyCode::KeyX,
|
|
|
|
|
0x08 => KeyCode::KeyC,
|
|
|
|
|
0x09 => KeyCode::KeyV,
|
|
|
|
|
//0x0a => World 1,
|
|
|
|
|
0x0b => KeyCode::KeyB,
|
|
|
|
|
0x0c => KeyCode::KeyQ,
|
|
|
|
|
0x0d => KeyCode::KeyW,
|
|
|
|
|
0x0e => KeyCode::KeyE,
|
|
|
|
|
0x0f => KeyCode::KeyR,
|
|
|
|
|
0x10 => KeyCode::KeyY,
|
|
|
|
|
0x11 => KeyCode::KeyT,
|
|
|
|
|
0x12 => KeyCode::Digit1,
|
|
|
|
|
0x13 => KeyCode::Digit2,
|
|
|
|
|
0x14 => KeyCode::Digit3,
|
|
|
|
|
0x15 => KeyCode::Digit4,
|
|
|
|
|
0x16 => KeyCode::Digit6,
|
|
|
|
|
0x17 => KeyCode::Digit5,
|
|
|
|
|
0x18 => KeyCode::Equal,
|
|
|
|
|
0x19 => KeyCode::Digit9,
|
|
|
|
|
0x1a => KeyCode::Digit7,
|
|
|
|
|
0x1b => KeyCode::Minus,
|
|
|
|
|
0x1c => KeyCode::Digit8,
|
|
|
|
|
0x1d => KeyCode::Digit0,
|
|
|
|
|
0x1e => KeyCode::BracketRight,
|
|
|
|
|
0x1f => KeyCode::KeyO,
|
|
|
|
|
0x20 => KeyCode::KeyU,
|
|
|
|
|
0x21 => KeyCode::BracketLeft,
|
|
|
|
|
0x22 => KeyCode::KeyI,
|
|
|
|
|
0x23 => KeyCode::KeyP,
|
|
|
|
|
0x24 => KeyCode::Enter,
|
|
|
|
|
0x25 => KeyCode::KeyL,
|
|
|
|
|
0x26 => KeyCode::KeyJ,
|
|
|
|
|
0x27 => KeyCode::Quote,
|
|
|
|
|
0x28 => KeyCode::KeyK,
|
|
|
|
|
0x29 => KeyCode::Semicolon,
|
|
|
|
|
0x2a => KeyCode::Backslash,
|
|
|
|
|
0x2b => KeyCode::Comma,
|
|
|
|
|
0x2c => KeyCode::Slash,
|
|
|
|
|
0x2d => KeyCode::KeyN,
|
|
|
|
|
0x2e => KeyCode::KeyM,
|
|
|
|
|
0x2f => KeyCode::Period,
|
|
|
|
|
0x30 => KeyCode::Tab,
|
|
|
|
|
0x31 => KeyCode::Space,
|
|
|
|
|
0x32 => KeyCode::Backquote,
|
|
|
|
|
0x33 => KeyCode::Backspace,
|
|
|
|
|
//0x34 => unknown,
|
|
|
|
|
0x35 => KeyCode::Escape,
|
|
|
|
|
0x36 => KeyCode::SuperRight,
|
|
|
|
|
0x37 => KeyCode::SuperLeft,
|
|
|
|
|
0x38 => KeyCode::ShiftLeft,
|
|
|
|
|
0x39 => KeyCode::CapsLock,
|
|
|
|
|
0x3a => KeyCode::AltLeft,
|
|
|
|
|
0x3b => KeyCode::ControlLeft,
|
|
|
|
|
0x3c => KeyCode::ShiftRight,
|
|
|
|
|
0x3d => KeyCode::AltRight,
|
|
|
|
|
0x3e => KeyCode::ControlRight,
|
|
|
|
|
0x3f => KeyCode::Fn,
|
|
|
|
|
0x40 => KeyCode::F17,
|
|
|
|
|
0x41 => KeyCode::NumpadDecimal,
|
|
|
|
|
//0x42 -> unknown,
|
|
|
|
|
0x43 => KeyCode::NumpadMultiply,
|
|
|
|
|
//0x44 => unknown,
|
|
|
|
|
0x45 => KeyCode::NumpadAdd,
|
|
|
|
|
//0x46 => unknown,
|
|
|
|
|
0x47 => KeyCode::NumLock,
|
|
|
|
|
//0x48 => KeyCode::NumpadClear,
|
|
|
|
|
|
|
|
|
|
// TODO: (Artur) for me, kVK_VolumeUp is 0x48
|
|
|
|
|
// macOS 10.11
|
|
|
|
|
// /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/HIToolbox.framework/Versions/A/Headers/Events.h
|
|
|
|
|
0x49 => KeyCode::AudioVolumeUp,
|
|
|
|
|
0x4a => KeyCode::AudioVolumeDown,
|
|
|
|
|
0x4b => KeyCode::NumpadDivide,
|
|
|
|
|
0x4c => KeyCode::NumpadEnter,
|
|
|
|
|
//0x4d => unknown,
|
|
|
|
|
0x4e => KeyCode::NumpadSubtract,
|
|
|
|
|
0x4f => KeyCode::F18,
|
|
|
|
|
0x50 => KeyCode::F19,
|
|
|
|
|
0x51 => KeyCode::NumpadEqual,
|
|
|
|
|
0x52 => KeyCode::Numpad0,
|
|
|
|
|
0x53 => KeyCode::Numpad1,
|
|
|
|
|
0x54 => KeyCode::Numpad2,
|
|
|
|
|
0x55 => KeyCode::Numpad3,
|
|
|
|
|
0x56 => KeyCode::Numpad4,
|
|
|
|
|
0x57 => KeyCode::Numpad5,
|
|
|
|
|
0x58 => KeyCode::Numpad6,
|
|
|
|
|
0x59 => KeyCode::Numpad7,
|
|
|
|
|
0x5a => KeyCode::F20,
|
|
|
|
|
0x5b => KeyCode::Numpad8,
|
|
|
|
|
0x5c => KeyCode::Numpad9,
|
|
|
|
|
0x5d => KeyCode::IntlYen,
|
|
|
|
|
//0x5e => JIS Ro,
|
|
|
|
|
//0x5f => unknown,
|
|
|
|
|
0x60 => KeyCode::F5,
|
|
|
|
|
0x61 => KeyCode::F6,
|
|
|
|
|
0x62 => KeyCode::F7,
|
|
|
|
|
0x63 => KeyCode::F3,
|
|
|
|
|
0x64 => KeyCode::F8,
|
|
|
|
|
0x65 => KeyCode::F9,
|
|
|
|
|
//0x66 => JIS Eisuu (macOS),
|
|
|
|
|
0x67 => KeyCode::F11,
|
|
|
|
|
//0x68 => JIS Kanna (macOS),
|
|
|
|
|
0x69 => KeyCode::F13,
|
|
|
|
|
0x6a => KeyCode::F16,
|
|
|
|
|
0x6b => KeyCode::F14,
|
|
|
|
|
//0x6c => unknown,
|
|
|
|
|
0x6d => KeyCode::F10,
|
|
|
|
|
//0x6e => unknown,
|
|
|
|
|
0x6f => KeyCode::F12,
|
|
|
|
|
//0x70 => unknown,
|
|
|
|
|
0x71 => KeyCode::F15,
|
|
|
|
|
0x72 => KeyCode::Insert,
|
|
|
|
|
0x73 => KeyCode::Home,
|
|
|
|
|
0x74 => KeyCode::PageUp,
|
|
|
|
|
0x75 => KeyCode::Delete,
|
|
|
|
|
0x76 => KeyCode::F4,
|
|
|
|
|
0x77 => KeyCode::End,
|
|
|
|
|
0x78 => KeyCode::F2,
|
|
|
|
|
0x79 => KeyCode::PageDown,
|
|
|
|
|
0x7a => KeyCode::F1,
|
|
|
|
|
0x7b => KeyCode::ArrowLeft,
|
|
|
|
|
0x7c => KeyCode::ArrowRight,
|
|
|
|
|
0x7d => KeyCode::ArrowDown,
|
|
|
|
|
0x7e => KeyCode::ArrowUp,
|
|
|
|
|
//0x7f => unknown,
|
|
|
|
|
|
|
|
|
|
// 0xA is the caret (^) an macOS's German QERTZ layout. This key is at the same location as
|
|
|
|
|
// backquote (`) on Windows' US layout.
|
|
|
|
|
0xa => KeyCode::Backquote,
|
|
|
|
|
_ => KeyCode::Unidentified(NativeKeyCode::MacOS(scancode as u16)),
|
|
|
|
|
}
|
2019-05-01 17:03:30 -06:00
|
|
|
}
|
|
|
|
|
}
|