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

@ -80,8 +80,8 @@ use crate::{
WindowEvent,
},
event_loop::{ControlFlow, DeviceEvents, EventLoopClosed, EventLoopWindowTarget as RootELW},
keyboard::{KeyCode, ModifiersState},
platform::{pump_events::PumpStatus, scancode::KeyCodeExtScancode},
keyboard::{KeyCode, ModifiersState, PhysicalKey},
platform::{pump_events::PumpStatus, scancode::PhysicalKeyExtScancode},
platform_impl::platform::{
dark_mode::try_theme,
dpi::{become_dpi_aware, dpi_to_scale_factor},
@ -2518,7 +2518,7 @@ unsafe fn handle_raw_input<T: 'static>(userdata: &ThreadMsgTargetData<T>, data:
// https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503
return;
}
let code = if keyboard.VKey == VK_NUMLOCK {
let physical_key = if keyboard.VKey == VK_NUMLOCK {
// Historically, the NumLock and the Pause key were one and the same physical key.
// The user could trigger Pause by pressing Ctrl+NumLock.
// Now these are often physically separate and the two keys can be differentiated by
@ -2531,47 +2531,49 @@ unsafe fn handle_raw_input<T: 'static>(userdata: &ThreadMsgTargetData<T>, data:
// For more on this, read the article by Raymond Chen, titled:
// "Why does Ctrl+ScrollLock cancel dialogs?"
// https://devblogs.microsoft.com/oldnewthing/20080211-00/?p=23503
KeyCode::NumLock
PhysicalKey::Code(KeyCode::NumLock)
} else {
KeyCode::from_scancode(scancode as u32)
PhysicalKey::from_scancode(scancode as u32)
};
if keyboard.VKey == VK_SHIFT {
match code {
KeyCode::NumpadDecimal
| KeyCode::Numpad0
| KeyCode::Numpad1
| KeyCode::Numpad2
| KeyCode::Numpad3
| KeyCode::Numpad4
| KeyCode::Numpad5
| KeyCode::Numpad6
| KeyCode::Numpad7
| KeyCode::Numpad8
| KeyCode::Numpad9 => {
// On Windows, holding the Shift key makes numpad keys behave as if NumLock
// wasn't active. The way this is exposed to applications by the system is that
// the application receives a fake key release event for the shift key at the
// moment when the numpad key is pressed, just before receiving the numpad key
// as well.
//
// The issue is that in the raw device event (here), the fake shift release
// event reports the numpad key as the scancode. Unfortunately, the event doesn't
// have any information to tell whether it's the left shift or the right shift
// that needs to get the fake release (or press) event so we don't forward this
// event to the application at all.
//
// For more on this, read the article by Raymond Chen, titled:
// "The shift key overrides NumLock"
// https://devblogs.microsoft.com/oldnewthing/20040906-00/?p=37953
return;
if let PhysicalKey::Code(code) = physical_key {
match code {
KeyCode::NumpadDecimal
| KeyCode::Numpad0
| KeyCode::Numpad1
| KeyCode::Numpad2
| KeyCode::Numpad3
| KeyCode::Numpad4
| KeyCode::Numpad5
| KeyCode::Numpad6
| KeyCode::Numpad7
| KeyCode::Numpad8
| KeyCode::Numpad9 => {
// On Windows, holding the Shift key makes numpad keys behave as if NumLock
// wasn't active. The way this is exposed to applications by the system is that
// the application receives a fake key release event for the shift key at the
// moment when the numpad key is pressed, just before receiving the numpad key
// as well.
//
// The issue is that in the raw device event (here), the fake shift release
// event reports the numpad key as the scancode. Unfortunately, the event doesn't
// have any information to tell whether it's the left shift or the right shift
// that needs to get the fake release (or press) event so we don't forward this
// event to the application at all.
//
// For more on this, read the article by Raymond Chen, titled:
// "The shift key overrides NumLock"
// https://devblogs.microsoft.com/oldnewthing/20040906-00/?p=37953
return;
}
_ => (),
}
_ => (),
}
}
userdata.send_event(Event::DeviceEvent {
device_id,
event: Key(RawKeyEvent {
physical_key: code,
physical_key,
state,
}),
});

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)),
})
}
}

View file

@ -52,8 +52,8 @@ use windows_sys::Win32::{
};
use crate::{
keyboard::{Key, KeyCode, ModifiersState, NativeKey},
platform::scancode::KeyCodeExtScancode,
keyboard::{Key, KeyCode, ModifiersState, NamedKey, NativeKey, PhysicalKey},
platform::scancode::PhysicalKeyExtScancode,
platform_impl::{loword, primarylangid},
};
@ -224,7 +224,7 @@ impl Layout {
mods: WindowsModifiers,
num_lock_on: bool,
vkey: VIRTUAL_KEY,
keycode: &KeyCode,
physical_key: &PhysicalKey,
) -> Key {
let native_code = NativeKey::Windows(vkey);
@ -252,9 +252,11 @@ impl Layout {
} else if let Some(key) = self.numlock_off_keys.get(&vkey) {
return key.clone();
}
if let Some(keys) = self.keys.get(&mods) {
if let Some(key) = keys.get(keycode) {
return key.clone();
if let PhysicalKey::Code(code) = physical_key {
if let Some(keys) = self.keys.get(&mods) {
if let Some(key) = keys.get(code) {
return key.clone();
}
}
}
Key::Unidentified(native_code)
@ -334,7 +336,11 @@ impl LayoutCache {
if scancode == 0 {
continue;
}
let keycode = KeyCode::from_scancode(scancode);
let keycode = match PhysicalKey::from_scancode(scancode) {
PhysicalKey::Code(code) => code,
// TODO: validate that we can skip on unidentified keys (probably never occurs?)
_ => continue,
};
if !is_numpad_specific(vk as VIRTUAL_KEY) && NUMPAD_KEYCODES.contains(&keycode) {
let native_code = NativeKey::Windows(vk as VIRTUAL_KEY);
let map_vkey = keycode_to_vkey(keycode, locale_id);
@ -382,7 +388,11 @@ impl LayoutCache {
}
let native_code = NativeKey::Windows(vk as VIRTUAL_KEY);
let key_code = KeyCode::from_scancode(scancode);
let key_code = match PhysicalKey::from_scancode(scancode) {
PhysicalKey::Code(code) => code,
// TODO: validate that we can skip on unidentified keys (probably never occurs?)
_ => continue,
};
// Let's try to get the key from just the scancode and vk
// We don't necessarily know yet if AltGraph is present on this layout so we'll
// assume it isn't. Then we'll do a second pass where we set the "AltRight" keys to
@ -446,7 +456,7 @@ impl LayoutCache {
let mod_state = WindowsModifiers::from_bits_retain(mod_state);
if let Some(keys) = layout.keys.get_mut(&mod_state) {
if let Some(key) = keys.get_mut(&KeyCode::AltRight) {
*key = Key::AltGraph;
*key = Key::Named(NamedKey::AltGraph);
}
}
}
@ -733,7 +743,6 @@ fn keycode_to_vkey(keycode: KeyCode, hkl: u64) -> VIRTUAL_KEY {
KeyCode::F33 => 0,
KeyCode::F34 => 0,
KeyCode::F35 => 0,
KeyCode::Unidentified(_) => 0,
_ => 0,
}
}
@ -769,56 +778,56 @@ fn vkey_to_non_char_key(
VK_MBUTTON => Key::Unidentified(NativeKey::Unidentified), // Mouse
VK_XBUTTON1 => Key::Unidentified(NativeKey::Unidentified), // Mouse
VK_XBUTTON2 => Key::Unidentified(NativeKey::Unidentified), // Mouse
VK_BACK => Key::Backspace,
VK_TAB => Key::Tab,
VK_CLEAR => Key::Clear,
VK_RETURN => Key::Enter,
VK_SHIFT => Key::Shift,
VK_CONTROL => Key::Control,
VK_MENU => Key::Alt,
VK_PAUSE => Key::Pause,
VK_CAPITAL => Key::CapsLock,
VK_BACK => Key::Named(NamedKey::Backspace),
VK_TAB => Key::Named(NamedKey::Tab),
VK_CLEAR => Key::Named(NamedKey::Clear),
VK_RETURN => Key::Named(NamedKey::Enter),
VK_SHIFT => Key::Named(NamedKey::Shift),
VK_CONTROL => Key::Named(NamedKey::Control),
VK_MENU => Key::Named(NamedKey::Alt),
VK_PAUSE => Key::Named(NamedKey::Pause),
VK_CAPITAL => Key::Named(NamedKey::CapsLock),
//VK_HANGEUL => Key::HangulMode, // Deprecated in favour of VK_HANGUL
//VK_HANGEUL => Key::Named(NamedKey::HangulMode), // Deprecated in favour of VK_HANGUL
// VK_HANGUL and VK_KANA are defined as the same constant, therefore
// we use appropriate conditions to differentate between them
VK_HANGUL if is_korean => Key::HangulMode,
VK_KANA if is_japanese => Key::KanaMode,
VK_HANGUL if is_korean => Key::Named(NamedKey::HangulMode),
VK_KANA if is_japanese => Key::Named(NamedKey::KanaMode),
VK_JUNJA => Key::JunjaMode,
VK_FINAL => Key::FinalMode,
VK_JUNJA => Key::Named(NamedKey::JunjaMode),
VK_FINAL => Key::Named(NamedKey::FinalMode),
// VK_HANJA and VK_KANJI are defined as the same constant, therefore
// we use appropriate conditions to differentate between them
VK_HANJA if is_korean => Key::HanjaMode,
VK_KANJI if is_japanese => Key::KanjiMode,
VK_HANJA if is_korean => Key::Named(NamedKey::HanjaMode),
VK_KANJI if is_japanese => Key::Named(NamedKey::KanjiMode),
VK_ESCAPE => Key::Escape,
VK_CONVERT => Key::Convert,
VK_NONCONVERT => Key::NonConvert,
VK_ACCEPT => Key::Accept,
VK_MODECHANGE => Key::ModeChange,
VK_SPACE => Key::Space,
VK_PRIOR => Key::PageUp,
VK_NEXT => Key::PageDown,
VK_END => Key::End,
VK_HOME => Key::Home,
VK_LEFT => Key::ArrowLeft,
VK_UP => Key::ArrowUp,
VK_RIGHT => Key::ArrowRight,
VK_DOWN => Key::ArrowDown,
VK_SELECT => Key::Select,
VK_PRINT => Key::Print,
VK_EXECUTE => Key::Execute,
VK_SNAPSHOT => Key::PrintScreen,
VK_INSERT => Key::Insert,
VK_DELETE => Key::Delete,
VK_HELP => Key::Help,
VK_LWIN => Key::Super,
VK_RWIN => Key::Super,
VK_APPS => Key::ContextMenu,
VK_SLEEP => Key::Standby,
VK_ESCAPE => Key::Named(NamedKey::Escape),
VK_CONVERT => Key::Named(NamedKey::Convert),
VK_NONCONVERT => Key::Named(NamedKey::NonConvert),
VK_ACCEPT => Key::Named(NamedKey::Accept),
VK_MODECHANGE => Key::Named(NamedKey::ModeChange),
VK_SPACE => Key::Named(NamedKey::Space),
VK_PRIOR => Key::Named(NamedKey::PageUp),
VK_NEXT => Key::Named(NamedKey::PageDown),
VK_END => Key::Named(NamedKey::End),
VK_HOME => Key::Named(NamedKey::Home),
VK_LEFT => Key::Named(NamedKey::ArrowLeft),
VK_UP => Key::Named(NamedKey::ArrowUp),
VK_RIGHT => Key::Named(NamedKey::ArrowRight),
VK_DOWN => Key::Named(NamedKey::ArrowDown),
VK_SELECT => Key::Named(NamedKey::Select),
VK_PRINT => Key::Named(NamedKey::Print),
VK_EXECUTE => Key::Named(NamedKey::Execute),
VK_SNAPSHOT => Key::Named(NamedKey::PrintScreen),
VK_INSERT => Key::Named(NamedKey::Insert),
VK_DELETE => Key::Named(NamedKey::Delete),
VK_HELP => Key::Named(NamedKey::Help),
VK_LWIN => Key::Named(NamedKey::Super),
VK_RWIN => Key::Named(NamedKey::Super),
VK_APPS => Key::Named(NamedKey::ContextMenu),
VK_SLEEP => Key::Named(NamedKey::Standby),
// Numpad keys produce characters
VK_NUMPAD0 => Key::Unidentified(native_code),
@ -838,30 +847,30 @@ fn vkey_to_non_char_key(
VK_DECIMAL => Key::Unidentified(native_code),
VK_DIVIDE => Key::Unidentified(native_code),
VK_F1 => Key::F1,
VK_F2 => Key::F2,
VK_F3 => Key::F3,
VK_F4 => Key::F4,
VK_F5 => Key::F5,
VK_F6 => Key::F6,
VK_F7 => Key::F7,
VK_F8 => Key::F8,
VK_F9 => Key::F9,
VK_F10 => Key::F10,
VK_F11 => Key::F11,
VK_F12 => Key::F12,
VK_F13 => Key::F13,
VK_F14 => Key::F14,
VK_F15 => Key::F15,
VK_F16 => Key::F16,
VK_F17 => Key::F17,
VK_F18 => Key::F18,
VK_F19 => Key::F19,
VK_F20 => Key::F20,
VK_F21 => Key::F21,
VK_F22 => Key::F22,
VK_F23 => Key::F23,
VK_F24 => Key::F24,
VK_F1 => Key::Named(NamedKey::F1),
VK_F2 => Key::Named(NamedKey::F2),
VK_F3 => Key::Named(NamedKey::F3),
VK_F4 => Key::Named(NamedKey::F4),
VK_F5 => Key::Named(NamedKey::F5),
VK_F6 => Key::Named(NamedKey::F6),
VK_F7 => Key::Named(NamedKey::F7),
VK_F8 => Key::Named(NamedKey::F8),
VK_F9 => Key::Named(NamedKey::F9),
VK_F10 => Key::Named(NamedKey::F10),
VK_F11 => Key::Named(NamedKey::F11),
VK_F12 => Key::Named(NamedKey::F12),
VK_F13 => Key::Named(NamedKey::F13),
VK_F14 => Key::Named(NamedKey::F14),
VK_F15 => Key::Named(NamedKey::F15),
VK_F16 => Key::Named(NamedKey::F16),
VK_F17 => Key::Named(NamedKey::F17),
VK_F18 => Key::Named(NamedKey::F18),
VK_F19 => Key::Named(NamedKey::F19),
VK_F20 => Key::Named(NamedKey::F20),
VK_F21 => Key::Named(NamedKey::F21),
VK_F22 => Key::Named(NamedKey::F22),
VK_F23 => Key::Named(NamedKey::F23),
VK_F24 => Key::Named(NamedKey::F24),
VK_NAVIGATION_VIEW => Key::Unidentified(native_code),
VK_NAVIGATION_MENU => Key::Unidentified(native_code),
VK_NAVIGATION_UP => Key::Unidentified(native_code),
@ -870,44 +879,44 @@ fn vkey_to_non_char_key(
VK_NAVIGATION_RIGHT => Key::Unidentified(native_code),
VK_NAVIGATION_ACCEPT => Key::Unidentified(native_code),
VK_NAVIGATION_CANCEL => Key::Unidentified(native_code),
VK_NUMLOCK => Key::NumLock,
VK_SCROLL => Key::ScrollLock,
VK_NUMLOCK => Key::Named(NamedKey::NumLock),
VK_SCROLL => Key::Named(NamedKey::ScrollLock),
VK_OEM_NEC_EQUAL => Key::Unidentified(native_code),
//VK_OEM_FJ_JISHO => Key::Unidentified(native_code), // Conflicts with `VK_OEM_NEC_EQUAL`
VK_OEM_FJ_MASSHOU => Key::Unidentified(native_code),
VK_OEM_FJ_TOUROKU => Key::Unidentified(native_code),
VK_OEM_FJ_LOYA => Key::Unidentified(native_code),
VK_OEM_FJ_ROYA => Key::Unidentified(native_code),
VK_LSHIFT => Key::Shift,
VK_RSHIFT => Key::Shift,
VK_LCONTROL => Key::Control,
VK_RCONTROL => Key::Control,
VK_LMENU => Key::Alt,
VK_LSHIFT => Key::Named(NamedKey::Shift),
VK_RSHIFT => Key::Named(NamedKey::Shift),
VK_LCONTROL => Key::Named(NamedKey::Control),
VK_RCONTROL => Key::Named(NamedKey::Control),
VK_LMENU => Key::Named(NamedKey::Alt),
VK_RMENU => {
if has_alt_graph {
Key::AltGraph
Key::Named(NamedKey::AltGraph)
} else {
Key::Alt
Key::Named(NamedKey::Alt)
}
}
VK_BROWSER_BACK => Key::BrowserBack,
VK_BROWSER_FORWARD => Key::BrowserForward,
VK_BROWSER_REFRESH => Key::BrowserRefresh,
VK_BROWSER_STOP => Key::BrowserStop,
VK_BROWSER_SEARCH => Key::BrowserSearch,
VK_BROWSER_FAVORITES => Key::BrowserFavorites,
VK_BROWSER_HOME => Key::BrowserHome,
VK_VOLUME_MUTE => Key::AudioVolumeMute,
VK_VOLUME_DOWN => Key::AudioVolumeDown,
VK_VOLUME_UP => Key::AudioVolumeUp,
VK_MEDIA_NEXT_TRACK => Key::MediaTrackNext,
VK_MEDIA_PREV_TRACK => Key::MediaTrackPrevious,
VK_MEDIA_STOP => Key::MediaStop,
VK_MEDIA_PLAY_PAUSE => Key::MediaPlayPause,
VK_LAUNCH_MAIL => Key::LaunchMail,
VK_LAUNCH_MEDIA_SELECT => Key::LaunchMediaPlayer,
VK_LAUNCH_APP1 => Key::LaunchApplication1,
VK_LAUNCH_APP2 => Key::LaunchApplication2,
VK_BROWSER_BACK => Key::Named(NamedKey::BrowserBack),
VK_BROWSER_FORWARD => Key::Named(NamedKey::BrowserForward),
VK_BROWSER_REFRESH => Key::Named(NamedKey::BrowserRefresh),
VK_BROWSER_STOP => Key::Named(NamedKey::BrowserStop),
VK_BROWSER_SEARCH => Key::Named(NamedKey::BrowserSearch),
VK_BROWSER_FAVORITES => Key::Named(NamedKey::BrowserFavorites),
VK_BROWSER_HOME => Key::Named(NamedKey::BrowserHome),
VK_VOLUME_MUTE => Key::Named(NamedKey::AudioVolumeMute),
VK_VOLUME_DOWN => Key::Named(NamedKey::AudioVolumeDown),
VK_VOLUME_UP => Key::Named(NamedKey::AudioVolumeUp),
VK_MEDIA_NEXT_TRACK => Key::Named(NamedKey::MediaTrackNext),
VK_MEDIA_PREV_TRACK => Key::Named(NamedKey::MediaTrackPrevious),
VK_MEDIA_STOP => Key::Named(NamedKey::MediaStop),
VK_MEDIA_PLAY_PAUSE => Key::Named(NamedKey::MediaPlayPause),
VK_LAUNCH_MAIL => Key::Named(NamedKey::LaunchMail),
VK_LAUNCH_MEDIA_SELECT => Key::Named(NamedKey::LaunchMediaPlayer),
VK_LAUNCH_APP1 => Key::Named(NamedKey::LaunchApplication1),
VK_LAUNCH_APP2 => Key::Named(NamedKey::LaunchApplication2),
// This function only converts "non-printable"
VK_OEM_1 => Key::Unidentified(native_code),
@ -955,7 +964,7 @@ fn vkey_to_non_char_key(
VK_ICO_HELP => Key::Unidentified(native_code),
VK_ICO_00 => Key::Unidentified(native_code),
VK_PROCESSKEY => Key::Process,
VK_PROCESSKEY => Key::Named(NamedKey::Process),
VK_ICO_CLEAR => Key::Unidentified(native_code),
VK_PACKET => Key::Unidentified(native_code),
@ -967,32 +976,32 @@ fn vkey_to_non_char_key(
VK_OEM_WSCTRL => Key::Unidentified(native_code),
VK_OEM_CUSEL => Key::Unidentified(native_code),
VK_OEM_ATTN => Key::Attn,
VK_OEM_ATTN => Key::Named(NamedKey::Attn),
VK_OEM_FINISH => {
if is_japanese {
Key::Katakana
Key::Named(NamedKey::Katakana)
} else {
// This matches IE and Firefox behaviour according to
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
// At the time of writing, there is no `Key::Finish` variant as
// At the time of writing, there is no `NamedKey::Finish` variant as
// Finish is not mentionned at https://w3c.github.io/uievents-key/
// Also see: https://github.com/pyfisch/keyboard-types/issues/9
Key::Unidentified(native_code)
}
}
VK_OEM_COPY => Key::Copy,
VK_OEM_AUTO => Key::Hankaku,
VK_OEM_ENLW => Key::Zenkaku,
VK_OEM_BACKTAB => Key::Romaji,
VK_ATTN => Key::KanaMode,
VK_CRSEL => Key::CrSel,
VK_EXSEL => Key::ExSel,
VK_EREOF => Key::EraseEof,
VK_PLAY => Key::Play,
VK_ZOOM => Key::ZoomToggle,
VK_OEM_COPY => Key::Named(NamedKey::Copy),
VK_OEM_AUTO => Key::Named(NamedKey::Hankaku),
VK_OEM_ENLW => Key::Named(NamedKey::Zenkaku),
VK_OEM_BACKTAB => Key::Named(NamedKey::Romaji),
VK_ATTN => Key::Named(NamedKey::KanaMode),
VK_CRSEL => Key::Named(NamedKey::CrSel),
VK_EXSEL => Key::Named(NamedKey::ExSel),
VK_EREOF => Key::Named(NamedKey::EraseEof),
VK_PLAY => Key::Named(NamedKey::Play),
VK_ZOOM => Key::Named(NamedKey::ZoomToggle),
VK_NONAME => Key::Unidentified(native_code),
VK_PA1 => Key::Unidentified(native_code),
VK_OEM_CLEAR => Key::Clear,
VK_OEM_CLEAR => Key::Named(NamedKey::Clear),
_ => Key::Unidentified(native_code),
}
}