Revise Key and KeyCode enums

Split `Key` into clear categories, like `Named`, `Dead`, Character`, `Unidentified`
removing the `#[non_exhaustive]` from the `Key` itself.

Similar action was done for the `KeyCode`.

Fixes: #2995
Co-authored-by: Kirill Chibisov <contact@kchibisov.com>
This commit is contained in:
Diggory Hardy 2023-10-19 15:27:49 +01:00 committed by GitHub
parent b9e1e96eaa
commit acfeff5327
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1456 additions and 1277 deletions

View file

@ -37,8 +37,8 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::{
event::{ElementState, KeyEvent},
keyboard::{Key, KeyCode, KeyLocation, NativeKey, NativeKeyCode},
platform::scancode::KeyCodeExtScancode,
keyboard::{Key, KeyCode, KeyLocation, NamedKey, NativeKey, NativeKeyCode, PhysicalKey},
platform::scancode::PhysicalKeyExtScancode,
platform_impl::platform::{
event_loop::ProcResult,
keyboard_layout::{Layout, LayoutCache, WindowsModifiers, LAYOUT_CACHE},
@ -264,8 +264,8 @@ impl KeyEventBuilder {
let mod_no_ctrl = mod_state.remove_only_ctrl();
let num_lock_on = kbd_state[VK_NUMLOCK as usize] & 1 != 0;
let vkey = event_info.vkey;
let keycode = &event_info.code;
let key = layout.get_key(mod_no_ctrl, num_lock_on, vkey, keycode);
let physical_key = &event_info.physical_key;
let key = layout.get_key(mod_no_ctrl, num_lock_on, vkey, physical_key);
event_info.text = PartialText::Text(key.to_text().map(SmolStr::new));
}
let ev = event_info.finalize();
@ -454,15 +454,16 @@ impl KeyEventBuilder {
return None;
}
let scancode = scancode as ExScancode;
let code = KeyCode::from_scancode(scancode as u32);
let physical_key = PhysicalKey::from_scancode(scancode as u32);
let mods = if caps_lock_on {
WindowsModifiers::CAPS_LOCK
} else {
WindowsModifiers::empty()
};
let layout = layouts.layouts.get(&(locale_id as u64)).unwrap();
let logical_key = layout.get_key(mods, num_lock_on, vk, &code);
let key_without_modifiers = layout.get_key(WindowsModifiers::empty(), false, vk, &code);
let logical_key = layout.get_key(mods, num_lock_on, vk, &physical_key);
let key_without_modifiers =
layout.get_key(WindowsModifiers::empty(), false, vk, &physical_key);
let text = if key_state == ElementState::Pressed {
logical_key.to_text().map(SmolStr::new)
} else {
@ -474,7 +475,7 @@ impl KeyEventBuilder {
key_without_modifiers,
key_state,
is_repeat: false,
code,
physical_key,
location: get_location(scancode, locale_id),
utf16parts: Vec::with_capacity(8),
text: PartialText::Text(text.clone()),
@ -511,7 +512,7 @@ struct PartialKeyEventInfo {
vkey: VIRTUAL_KEY,
key_state: ElementState,
is_repeat: bool,
code: KeyCode,
physical_key: PhysicalKey,
location: KeyLocation,
logical_key: PartialLogicalKey,
@ -543,7 +544,7 @@ impl PartialKeyEventInfo {
} else {
new_ex_scancode(lparam_struct.scancode, lparam_struct.extended)
};
let code = KeyCode::from_scancode(scancode as u32);
let physical_key = PhysicalKey::from_scancode(scancode as u32);
let location = get_location(scancode, layout.hkl as HKL);
let kbd_state = get_kbd_state();
@ -558,16 +559,17 @@ impl PartialKeyEventInfo {
// "Why does Ctrl+ScrollLock cancel dialogs?"
// https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503
let code_as_key = if mods.contains(WindowsModifiers::CONTROL) {
match code {
KeyCode::NumLock => Some(Key::NumLock),
KeyCode::Pause => Some(Key::Pause),
match physical_key {
PhysicalKey::Code(KeyCode::NumLock) => Some(Key::Named(NamedKey::NumLock)),
PhysicalKey::Code(KeyCode::Pause) => Some(Key::Named(NamedKey::Pause)),
_ => None,
}
} else {
None
};
let preliminary_logical_key = layout.get_key(mods_without_ctrl, num_lock_on, vkey, &code);
let preliminary_logical_key =
layout.get_key(mods_without_ctrl, num_lock_on, vkey, &physical_key);
let key_is_char = matches!(preliminary_logical_key, Key::Character(_));
let is_pressed = state == ElementState::Pressed;
@ -583,7 +585,7 @@ impl PartialKeyEventInfo {
let key_without_modifiers = if let Some(key) = code_as_key {
key
} else {
match layout.get_key(NO_MODS, false, vkey, &code) {
match layout.get_key(NO_MODS, false, vkey, &physical_key) {
// We convert dead keys into their character.
// The reason for this is that `key_without_modifiers` is designed for key-bindings,
// but the US International layout treats `'` (apostrophe) as a dead key and the
@ -609,7 +611,7 @@ impl PartialKeyEventInfo {
logical_key,
key_without_modifiers,
is_repeat: lparam_struct.is_repeat,
code,
physical_key,
location,
utf16parts: Vec::with_capacity(8),
text: PartialText::System(Vec::new()),
@ -656,7 +658,7 @@ impl PartialKeyEventInfo {
};
KeyEvent {
physical_key: self.code,
physical_key: self.physical_key,
logical_key,
text,
location: self.location,
@ -740,7 +742,10 @@ fn get_async_kbd_state() -> [u8; 256] {
/// the next event is a right Alt (AltGr) event. If this is the case, the current event must be the
/// fake Ctrl event.
fn is_current_fake(curr_info: &PartialKeyEventInfo, next_msg: MSG, layout: &Layout) -> bool {
let curr_is_ctrl = matches!(curr_info.logical_key, PartialLogicalKey::This(Key::Control));
let curr_is_ctrl = matches!(
curr_info.logical_key,
PartialLogicalKey::This(Key::Named(NamedKey::Control))
);
if layout.has_alt_graph {
let next_code = ex_scancode_from_lparam(next_msg.lParam);
let next_is_altgr = next_code == 0xE038; // 0xE038 is right alt
@ -937,7 +942,7 @@ fn get_location(scancode: ExScancode, hkl: HKL) -> KeyLocation {
}
}
impl KeyCodeExtScancode for KeyCode {
impl PhysicalKeyExtScancode for PhysicalKey {
fn to_scancode(self) -> Option<u32> {
// See `from_scancode` for more info
@ -946,7 +951,17 @@ impl KeyCodeExtScancode for KeyCode {
let primary_lang_id = primarylangid(loword(hkl as u32));
let is_korean = primary_lang_id as u32 == LANG_KOREAN;
match self {
let code = match self {
PhysicalKey::Code(code) => code,
PhysicalKey::Unidentified(code) => {
return match code {
NativeKeyCode::Windows(scancode) => Some(scancode as u32),
_ => None,
};
}
};
match code {
KeyCode::Backquote => Some(0x0029),
KeyCode::Backslash => Some(0x002B),
KeyCode::Backspace => Some(0x000E),
@ -1106,17 +1121,16 @@ impl KeyCodeExtScancode for KeyCode {
KeyCode::AudioVolumeDown => Some(0xE02E),
KeyCode::AudioVolumeMute => Some(0xE020),
KeyCode::AudioVolumeUp => Some(0xE030),
KeyCode::Unidentified(NativeKeyCode::Windows(scancode)) => Some(scancode as u32),
_ => None,
}
}
fn from_scancode(scancode: u32) -> KeyCode {
fn from_scancode(scancode: u32) -> PhysicalKey {
// See: https://www.win.tue.nl/~aeb/linux/kbd/scancodes-1.html
// and: https://www.w3.org/TR/uievents-code/
// and: The widget/NativeKeyToDOMCodeName.h file in the firefox source
match scancode {
PhysicalKey::Code(match scancode {
0x0029 => KeyCode::Backquote,
0x002B => KeyCode::Backslash,
0x000E => KeyCode::Backspace,
@ -1266,7 +1280,7 @@ impl KeyCodeExtScancode for KeyCode {
0xE02E => KeyCode::AudioVolumeDown,
0xE020 => KeyCode::AudioVolumeMute,
0xE030 => KeyCode::AudioVolumeUp,
_ => KeyCode::Unidentified(NativeKeyCode::Windows(scancode as u16)),
}
_ => return PhysicalKey::Unidentified(NativeKeyCode::Windows(scancode as u16)),
})
}
}