winit/src/platform_impl/android/keycodes.rs

604 lines
24 KiB
Rust
Raw Normal View History

Android: Support unicode character mapping + dead keys Up until now the Android backend has been directly mapping key codes which essentially just represent the "physical" cap of the key (quoted since this also related to virtual keyboards). Since we didn't account for any meta keys either it meant the backend only supported a 1:1 mapping from key codes, which only covers a tiny subset of characters. For example you couldn't type a colon since there's no keycode for that and we didn't try and map Shift+Semicolon into a colon character. This has been tricky to support because the `NativeActivity` class doesn't have direct access to the Java `KeyEvent` object which exposes a more convenient `getUnicodeChar` API. It is now possible to query a `KeyCharcterMap` for the device associated with a `KeyEvent` via the `AndroidApp::device_key_character_map` API which provides a binding to the SDK `KeyCharacterMap` API in Java: https://developer.android.com/reference/android/view/KeyCharacterMap This is effectively what `getUnicodeChar` is implemented based on and is a bit more general purpose. `KeyCharacterMap` lets us map a key_code + meta_state from a `KeyEvent` into either a unicode character or dead key accent that can be combined with the following key. This mapping is done based on the user's chosen layout for the keyboard. To enable support for key character maps the `AndroidApp::input_events()` API was replaced by `AndroidApp::input_events_iter()` which returns a (lending) iterator for events. This was changed because the previous design made it difficult to allow other AndroidApp APIs to be used while iterating events (mainly because AndroidApp held a lock over the backend during iteration)
2023-08-07 23:56:42 +01:00
use android_activity::{
input::{KeyAction, KeyEvent, KeyMapChar, Keycode},
AndroidApp,
};
Android: rework keycode handling (#2890) The recent overhaul of the keyboard API broke keyboard input on Android. The recent keyboard changes also broke building against the game-activity backend of android-activity because it was assumed that the backend is based on the NDK input API which isn't the case with with game-activity since it doesn't use the InputQueue API from the NDK. Any alphanumeric keycodes were being mapped to `Unidentified` Keys which meant even crude keyboard input support was broken. We do need to expose `getUnicodeChar` (or the ability to look up characters based on the current character map and modifiers) but for now we should at least map alphanumeric keycodes to `Key::Character` for basic interim support of virtual keyboards. This moves all the keycode mapping into a separate `keycodes.rs` file to reduce clutter. This adds back the mapping from Android key codes to Winit key codes that we had before the keyboard API overhaul. Android activity does expose scan codes but key codes currently seem like the more appropriate mapping to Winit physical key codes. This removes the gnarly, unsafe cfg() guarded digging into 'native-activity' and 'game-activity' specific implementation details. I never intended to expose these details in the public API and really hope to avoid there being a release of Winit that would depend on this. I'm also hoping/considering if I can get away with sealing this without necessarily requiring a semver breaking release of android_activity since this absolutely should never have been possible, and can probably safely assume this was the only code in the wild that has briefly done this. I'm also a bit unclear as to what led to doing this. There is a `.key_code()` and `.scan_code()` getter and we even already accessed the keycode in the Android backend so I'm not sure how those APIs were missed.
2023-06-21 18:49:44 +01:00
use crate::keyboard::{Key, KeyCode, KeyLocation, NativeKey, NativeKeyCode};
pub fn to_physical_keycode(keycode: Keycode) -> KeyCode {
match keycode {
Keycode::A => KeyCode::KeyA,
Keycode::B => KeyCode::KeyB,
Keycode::C => KeyCode::KeyC,
Keycode::D => KeyCode::KeyD,
Keycode::E => KeyCode::KeyE,
Keycode::F => KeyCode::KeyF,
Keycode::G => KeyCode::KeyG,
Keycode::H => KeyCode::KeyH,
Keycode::I => KeyCode::KeyI,
Keycode::J => KeyCode::KeyJ,
Keycode::K => KeyCode::KeyK,
Keycode::L => KeyCode::KeyL,
Keycode::M => KeyCode::KeyM,
Keycode::N => KeyCode::KeyN,
Keycode::O => KeyCode::KeyO,
Keycode::P => KeyCode::KeyP,
Keycode::Q => KeyCode::KeyQ,
Keycode::R => KeyCode::KeyR,
Keycode::S => KeyCode::KeyS,
Keycode::T => KeyCode::KeyT,
Keycode::U => KeyCode::KeyU,
Keycode::V => KeyCode::KeyV,
Keycode::W => KeyCode::KeyW,
Keycode::X => KeyCode::KeyX,
Keycode::Y => KeyCode::KeyY,
Keycode::Z => KeyCode::KeyZ,
Keycode::Keycode0 => KeyCode::Digit0,
Keycode::Keycode1 => KeyCode::Digit1,
Keycode::Keycode2 => KeyCode::Digit2,
Keycode::Keycode3 => KeyCode::Digit3,
Keycode::Keycode4 => KeyCode::Digit4,
Keycode::Keycode5 => KeyCode::Digit5,
Keycode::Keycode6 => KeyCode::Digit6,
Keycode::Keycode7 => KeyCode::Digit7,
Keycode::Keycode8 => KeyCode::Digit8,
Keycode::Keycode9 => KeyCode::Digit9,
Keycode::Numpad0 => KeyCode::Numpad0,
Keycode::Numpad1 => KeyCode::Numpad1,
Keycode::Numpad2 => KeyCode::Numpad2,
Keycode::Numpad3 => KeyCode::Numpad3,
Keycode::Numpad4 => KeyCode::Numpad4,
Keycode::Numpad5 => KeyCode::Numpad5,
Keycode::Numpad6 => KeyCode::Numpad6,
Keycode::Numpad7 => KeyCode::Numpad7,
Keycode::Numpad8 => KeyCode::Numpad8,
Keycode::Numpad9 => KeyCode::Numpad9,
Keycode::NumpadAdd => KeyCode::NumpadAdd,
Keycode::NumpadSubtract => KeyCode::NumpadSubtract,
Keycode::NumpadMultiply => KeyCode::NumpadMultiply,
Keycode::NumpadDivide => KeyCode::NumpadDivide,
Keycode::NumpadEnter => KeyCode::NumpadEnter,
Keycode::NumpadEquals => KeyCode::NumpadEqual,
Keycode::NumpadComma => KeyCode::NumpadComma,
Keycode::NumpadDot => KeyCode::NumpadDecimal,
Keycode::NumLock => KeyCode::NumLock,
Keycode::DpadLeft => KeyCode::ArrowLeft,
Keycode::DpadRight => KeyCode::ArrowRight,
Keycode::DpadUp => KeyCode::ArrowUp,
Keycode::DpadDown => KeyCode::ArrowDown,
Keycode::F1 => KeyCode::F1,
Keycode::F2 => KeyCode::F2,
Keycode::F3 => KeyCode::F3,
Keycode::F4 => KeyCode::F4,
Keycode::F5 => KeyCode::F5,
Keycode::F6 => KeyCode::F6,
Keycode::F7 => KeyCode::F7,
Keycode::F8 => KeyCode::F8,
Keycode::F9 => KeyCode::F9,
Keycode::F10 => KeyCode::F10,
Keycode::F11 => KeyCode::F11,
Keycode::F12 => KeyCode::F12,
Keycode::Space => KeyCode::Space,
Keycode::Escape => KeyCode::Escape,
Keycode::Enter => KeyCode::Enter, // not on the Numpad
Keycode::Tab => KeyCode::Tab,
Keycode::PageUp => KeyCode::PageUp,
Keycode::PageDown => KeyCode::PageDown,
Keycode::MoveHome => KeyCode::Home,
Keycode::MoveEnd => KeyCode::End,
Keycode::Insert => KeyCode::Insert,
Keycode::Del => KeyCode::Backspace, // Backspace (above Enter)
Keycode::ForwardDel => KeyCode::Delete, // Delete (below Insert)
Keycode::Copy => KeyCode::Copy,
Keycode::Paste => KeyCode::Paste,
Keycode::Cut => KeyCode::Cut,
Keycode::VolumeUp => KeyCode::AudioVolumeUp,
Keycode::VolumeDown => KeyCode::AudioVolumeDown,
Keycode::VolumeMute => KeyCode::AudioVolumeMute,
//Keycode::Mute => None, // Microphone mute
Keycode::MediaPlayPause => KeyCode::MediaPlayPause,
Keycode::MediaStop => KeyCode::MediaStop,
Keycode::MediaNext => KeyCode::MediaTrackNext,
Keycode::MediaPrevious => KeyCode::MediaTrackPrevious,
Keycode::Plus => KeyCode::Equal,
Keycode::Minus => KeyCode::Minus,
// Winit doesn't differentiate both '+' and '=', considering they are usually
// on the same physical key
Keycode::Equals => KeyCode::Equal,
Keycode::Semicolon => KeyCode::Semicolon,
Keycode::Slash => KeyCode::Slash,
Keycode::Backslash => KeyCode::Backslash,
Keycode::Comma => KeyCode::Comma,
Keycode::Period => KeyCode::Period,
Keycode::Apostrophe => KeyCode::Quote,
Keycode::Grave => KeyCode::Backquote,
// Winit doesn't expose a SysRq code, so map to PrintScreen since it's
// usually the same physical key
Keycode::Sysrq => KeyCode::PrintScreen,
// These are usually the same (Pause/Break)
Keycode::Break => KeyCode::Pause,
// These are exactly the same
Keycode::ScrollLock => KeyCode::ScrollLock,
Keycode::Yen => KeyCode::IntlYen,
Keycode::Kana => KeyCode::Lang1,
Keycode::KatakanaHiragana => KeyCode::KanaMode,
Keycode::CtrlLeft => KeyCode::ControlLeft,
Keycode::CtrlRight => KeyCode::ControlRight,
Keycode::ShiftLeft => KeyCode::ShiftLeft,
Keycode::ShiftRight => KeyCode::ShiftRight,
Keycode::AltLeft => KeyCode::AltLeft,
Keycode::AltRight => KeyCode::AltRight,
Keycode::MetaLeft => KeyCode::SuperLeft,
Keycode::MetaRight => KeyCode::SuperRight,
Keycode::LeftBracket => KeyCode::BracketLeft,
Keycode::RightBracket => KeyCode::BracketRight,
Keycode::Power => KeyCode::Power,
Keycode::Sleep => KeyCode::Sleep, // what about SoftSleep?
Keycode::Wakeup => KeyCode::WakeUp,
keycode => KeyCode::Unidentified(NativeKeyCode::Android(keycode.into())),
}
}
Android: Support unicode character mapping + dead keys Up until now the Android backend has been directly mapping key codes which essentially just represent the "physical" cap of the key (quoted since this also related to virtual keyboards). Since we didn't account for any meta keys either it meant the backend only supported a 1:1 mapping from key codes, which only covers a tiny subset of characters. For example you couldn't type a colon since there's no keycode for that and we didn't try and map Shift+Semicolon into a colon character. This has been tricky to support because the `NativeActivity` class doesn't have direct access to the Java `KeyEvent` object which exposes a more convenient `getUnicodeChar` API. It is now possible to query a `KeyCharcterMap` for the device associated with a `KeyEvent` via the `AndroidApp::device_key_character_map` API which provides a binding to the SDK `KeyCharacterMap` API in Java: https://developer.android.com/reference/android/view/KeyCharacterMap This is effectively what `getUnicodeChar` is implemented based on and is a bit more general purpose. `KeyCharacterMap` lets us map a key_code + meta_state from a `KeyEvent` into either a unicode character or dead key accent that can be combined with the following key. This mapping is done based on the user's chosen layout for the keyboard. To enable support for key character maps the `AndroidApp::input_events()` API was replaced by `AndroidApp::input_events_iter()` which returns a (lending) iterator for events. This was changed because the previous design made it difficult to allow other AndroidApp APIs to be used while iterating events (mainly because AndroidApp held a lock over the backend during iteration)
2023-08-07 23:56:42 +01:00
/// Tries to map the `key_event` to a `KeyMapChar` containing a unicode character or dead key accent
///
/// This takes a `KeyEvent` and looks up its corresponding `KeyCharacterMap` and
/// uses that to try and map the `key_code` + `meta_state` to a unicode
/// character or a dead key that can be combined with the next key press.
pub fn character_map_and_combine_key(
app: &AndroidApp,
key_event: &KeyEvent<'_>,
combining_accent: &mut Option<char>,
) -> Option<KeyMapChar> {
let device_id = key_event.device_id();
let key_map = match app.device_key_character_map(device_id) {
Ok(key_map) => key_map,
Err(err) => {
log::warn!("Failed to look up `KeyCharacterMap` for device {device_id}: {err:?}");
return None;
}
};
match key_map.get(key_event.key_code(), key_event.meta_state()) {
Ok(KeyMapChar::Unicode(unicode)) => {
// Only do dead key combining on key down
if key_event.action() == KeyAction::Down {
let combined_unicode = if let Some(accent) = combining_accent {
match key_map.get_dead_char(*accent, unicode) {
Ok(Some(key)) => Some(key),
Ok(None) => None,
Err(err) => {
log::warn!("KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}");
None
}
}
} else {
Some(unicode)
};
*combining_accent = None;
combined_unicode.map(KeyMapChar::Unicode)
} else {
Some(KeyMapChar::Unicode(unicode))
}
}
Ok(KeyMapChar::CombiningAccent(accent)) => {
if key_event.action() == KeyAction::Down {
*combining_accent = Some(accent);
}
Some(KeyMapChar::CombiningAccent(accent))
}
Ok(KeyMapChar::None) => {
// Leave any combining_accent state in tact (seems to match how other
// Android apps work)
None
}
Err(err) => {
log::warn!("KeyEvent: Failed to get key map character: {err:?}");
*combining_accent = None;
None
}
}
}
Android: rework keycode handling (#2890) The recent overhaul of the keyboard API broke keyboard input on Android. The recent keyboard changes also broke building against the game-activity backend of android-activity because it was assumed that the backend is based on the NDK input API which isn't the case with with game-activity since it doesn't use the InputQueue API from the NDK. Any alphanumeric keycodes were being mapped to `Unidentified` Keys which meant even crude keyboard input support was broken. We do need to expose `getUnicodeChar` (or the ability to look up characters based on the current character map and modifiers) but for now we should at least map alphanumeric keycodes to `Key::Character` for basic interim support of virtual keyboards. This moves all the keycode mapping into a separate `keycodes.rs` file to reduce clutter. This adds back the mapping from Android key codes to Winit key codes that we had before the keyboard API overhaul. Android activity does expose scan codes but key codes currently seem like the more appropriate mapping to Winit physical key codes. This removes the gnarly, unsafe cfg() guarded digging into 'native-activity' and 'game-activity' specific implementation details. I never intended to expose these details in the public API and really hope to avoid there being a release of Winit that would depend on this. I'm also hoping/considering if I can get away with sealing this without necessarily requiring a semver breaking release of android_activity since this absolutely should never have been possible, and can probably safely assume this was the only code in the wild that has briefly done this. I'm also a bit unclear as to what led to doing this. There is a `.key_code()` and `.scan_code()` getter and we even already accessed the keycode in the Android backend so I'm not sure how those APIs were missed.
2023-06-21 18:49:44 +01:00
Android: Support unicode character mapping + dead keys Up until now the Android backend has been directly mapping key codes which essentially just represent the "physical" cap of the key (quoted since this also related to virtual keyboards). Since we didn't account for any meta keys either it meant the backend only supported a 1:1 mapping from key codes, which only covers a tiny subset of characters. For example you couldn't type a colon since there's no keycode for that and we didn't try and map Shift+Semicolon into a colon character. This has been tricky to support because the `NativeActivity` class doesn't have direct access to the Java `KeyEvent` object which exposes a more convenient `getUnicodeChar` API. It is now possible to query a `KeyCharcterMap` for the device associated with a `KeyEvent` via the `AndroidApp::device_key_character_map` API which provides a binding to the SDK `KeyCharacterMap` API in Java: https://developer.android.com/reference/android/view/KeyCharacterMap This is effectively what `getUnicodeChar` is implemented based on and is a bit more general purpose. `KeyCharacterMap` lets us map a key_code + meta_state from a `KeyEvent` into either a unicode character or dead key accent that can be combined with the following key. This mapping is done based on the user's chosen layout for the keyboard. To enable support for key character maps the `AndroidApp::input_events()` API was replaced by `AndroidApp::input_events_iter()` which returns a (lending) iterator for events. This was changed because the previous design made it difficult to allow other AndroidApp APIs to be used while iterating events (mainly because AndroidApp held a lock over the backend during iteration)
2023-08-07 23:56:42 +01:00
pub fn to_logical(key_char: Option<KeyMapChar>, keycode: Keycode) -> Key {
use android_activity::input::Keycode::*;
Android: rework keycode handling (#2890) The recent overhaul of the keyboard API broke keyboard input on Android. The recent keyboard changes also broke building against the game-activity backend of android-activity because it was assumed that the backend is based on the NDK input API which isn't the case with with game-activity since it doesn't use the InputQueue API from the NDK. Any alphanumeric keycodes were being mapped to `Unidentified` Keys which meant even crude keyboard input support was broken. We do need to expose `getUnicodeChar` (or the ability to look up characters based on the current character map and modifiers) but for now we should at least map alphanumeric keycodes to `Key::Character` for basic interim support of virtual keyboards. This moves all the keycode mapping into a separate `keycodes.rs` file to reduce clutter. This adds back the mapping from Android key codes to Winit key codes that we had before the keyboard API overhaul. Android activity does expose scan codes but key codes currently seem like the more appropriate mapping to Winit physical key codes. This removes the gnarly, unsafe cfg() guarded digging into 'native-activity' and 'game-activity' specific implementation details. I never intended to expose these details in the public API and really hope to avoid there being a release of Winit that would depend on this. I'm also hoping/considering if I can get away with sealing this without necessarily requiring a semver breaking release of android_activity since this absolutely should never have been possible, and can probably safely assume this was the only code in the wild that has briefly done this. I'm also a bit unclear as to what led to doing this. There is a `.key_code()` and `.scan_code()` getter and we even already accessed the keycode in the Android backend so I'm not sure how those APIs were missed.
2023-06-21 18:49:44 +01:00
Android: Support unicode character mapping + dead keys Up until now the Android backend has been directly mapping key codes which essentially just represent the "physical" cap of the key (quoted since this also related to virtual keyboards). Since we didn't account for any meta keys either it meant the backend only supported a 1:1 mapping from key codes, which only covers a tiny subset of characters. For example you couldn't type a colon since there's no keycode for that and we didn't try and map Shift+Semicolon into a colon character. This has been tricky to support because the `NativeActivity` class doesn't have direct access to the Java `KeyEvent` object which exposes a more convenient `getUnicodeChar` API. It is now possible to query a `KeyCharcterMap` for the device associated with a `KeyEvent` via the `AndroidApp::device_key_character_map` API which provides a binding to the SDK `KeyCharacterMap` API in Java: https://developer.android.com/reference/android/view/KeyCharacterMap This is effectively what `getUnicodeChar` is implemented based on and is a bit more general purpose. `KeyCharacterMap` lets us map a key_code + meta_state from a `KeyEvent` into either a unicode character or dead key accent that can be combined with the following key. This mapping is done based on the user's chosen layout for the keyboard. To enable support for key character maps the `AndroidApp::input_events()` API was replaced by `AndroidApp::input_events_iter()` which returns a (lending) iterator for events. This was changed because the previous design made it difficult to allow other AndroidApp APIs to be used while iterating events (mainly because AndroidApp held a lock over the backend during iteration)
2023-08-07 23:56:42 +01:00
let native = NativeKey::Android(keycode.into());
match key_char {
Some(KeyMapChar::Unicode(c)) => Key::Character(smol_str::SmolStr::from_iter([c])),
Android: Support unicode character mapping + dead keys Up until now the Android backend has been directly mapping key codes which essentially just represent the "physical" cap of the key (quoted since this also related to virtual keyboards). Since we didn't account for any meta keys either it meant the backend only supported a 1:1 mapping from key codes, which only covers a tiny subset of characters. For example you couldn't type a colon since there's no keycode for that and we didn't try and map Shift+Semicolon into a colon character. This has been tricky to support because the `NativeActivity` class doesn't have direct access to the Java `KeyEvent` object which exposes a more convenient `getUnicodeChar` API. It is now possible to query a `KeyCharcterMap` for the device associated with a `KeyEvent` via the `AndroidApp::device_key_character_map` API which provides a binding to the SDK `KeyCharacterMap` API in Java: https://developer.android.com/reference/android/view/KeyCharacterMap This is effectively what `getUnicodeChar` is implemented based on and is a bit more general purpose. `KeyCharacterMap` lets us map a key_code + meta_state from a `KeyEvent` into either a unicode character or dead key accent that can be combined with the following key. This mapping is done based on the user's chosen layout for the keyboard. To enable support for key character maps the `AndroidApp::input_events()` API was replaced by `AndroidApp::input_events_iter()` which returns a (lending) iterator for events. This was changed because the previous design made it difficult to allow other AndroidApp APIs to be used while iterating events (mainly because AndroidApp held a lock over the backend during iteration)
2023-08-07 23:56:42 +01:00
Some(KeyMapChar::CombiningAccent(c)) => Key::Dead(Some(c)),
None | Some(KeyMapChar::None) => match keycode {
// Using `BrowserHome` instead of `GoHome` according to
// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
Home => Key::BrowserHome,
Back => Key::BrowserBack,
Call => Key::Call,
Endcall => Key::EndCall,
//-------------------------------------------------------------------------------
// These should be redundant because they should have already been matched
// as `KeyMapChar::Unicode`, but also matched here as a fallback
Keycode0 => Key::Character("0".into()),
Keycode1 => Key::Character("1".into()),
Keycode2 => Key::Character("2".into()),
Keycode3 => Key::Character("3".into()),
Keycode4 => Key::Character("4".into()),
Keycode5 => Key::Character("5".into()),
Keycode6 => Key::Character("6".into()),
Keycode7 => Key::Character("7".into()),
Keycode8 => Key::Character("8".into()),
Keycode9 => Key::Character("9".into()),
Star => Key::Character("*".into()),
Pound => Key::Character("#".into()),
A => Key::Character("a".into()),
B => Key::Character("b".into()),
C => Key::Character("c".into()),
D => Key::Character("d".into()),
E => Key::Character("e".into()),
F => Key::Character("f".into()),
G => Key::Character("g".into()),
H => Key::Character("h".into()),
I => Key::Character("i".into()),
J => Key::Character("j".into()),
K => Key::Character("k".into()),
L => Key::Character("l".into()),
M => Key::Character("m".into()),
N => Key::Character("n".into()),
O => Key::Character("o".into()),
P => Key::Character("p".into()),
Q => Key::Character("q".into()),
R => Key::Character("r".into()),
S => Key::Character("s".into()),
T => Key::Character("t".into()),
U => Key::Character("u".into()),
V => Key::Character("v".into()),
W => Key::Character("w".into()),
X => Key::Character("x".into()),
Y => Key::Character("y".into()),
Z => Key::Character("z".into()),
Comma => Key::Character(",".into()),
Period => Key::Character(".".into()),
Grave => Key::Character("`".into()),
Minus => Key::Character("-".into()),
Equals => Key::Character("=".into()),
LeftBracket => Key::Character("[".into()),
RightBracket => Key::Character("]".into()),
Backslash => Key::Character("\\".into()),
Semicolon => Key::Character(";".into()),
Apostrophe => Key::Character("'".into()),
Slash => Key::Character("/".into()),
At => Key::Character("@".into()),
Plus => Key::Character("+".into()),
//-------------------------------------------------------------------------------
DpadUp => Key::ArrowUp,
DpadDown => Key::ArrowDown,
DpadLeft => Key::ArrowLeft,
DpadRight => Key::ArrowRight,
DpadCenter => Key::Enter,
VolumeUp => Key::AudioVolumeUp,
VolumeDown => Key::AudioVolumeDown,
Power => Key::Power,
Camera => Key::Camera,
Clear => Key::Clear,
AltLeft => Key::Alt,
AltRight => Key::Alt,
ShiftLeft => Key::Shift,
ShiftRight => Key::Shift,
Tab => Key::Tab,
Space => Key::Space,
Sym => Key::Symbol,
Explorer => Key::LaunchWebBrowser,
Envelope => Key::LaunchMail,
Enter => Key::Enter,
Del => Key::Backspace,
// According to https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_NUM
Num => Key::Alt,
Headsethook => Key::HeadsetHook,
Focus => Key::CameraFocus,
Notification => Key::Notification,
Search => Key::BrowserSearch,
MediaPlayPause => Key::MediaPlayPause,
MediaStop => Key::MediaStop,
MediaNext => Key::MediaTrackNext,
MediaPrevious => Key::MediaTrackPrevious,
MediaRewind => Key::MediaRewind,
MediaFastForward => Key::MediaFastForward,
Mute => Key::MicrophoneVolumeMute,
PageUp => Key::PageUp,
PageDown => Key::PageDown,
Escape => Key::Escape,
ForwardDel => Key::Delete,
CtrlLeft => Key::Control,
CtrlRight => Key::Control,
CapsLock => Key::CapsLock,
ScrollLock => Key::ScrollLock,
MetaLeft => Key::Super,
MetaRight => Key::Super,
Function => Key::Fn,
Sysrq => Key::PrintScreen,
Break => Key::Pause,
MoveHome => Key::Home,
MoveEnd => Key::End,
Insert => Key::Insert,
Forward => Key::BrowserForward,
MediaPlay => Key::MediaPlay,
MediaPause => Key::MediaPause,
MediaClose => Key::MediaClose,
MediaEject => Key::Eject,
MediaRecord => Key::MediaRecord,
F1 => Key::F1,
F2 => Key::F2,
F3 => Key::F3,
F4 => Key::F4,
F5 => Key::F5,
F6 => Key::F6,
F7 => Key::F7,
F8 => Key::F8,
F9 => Key::F9,
F10 => Key::F10,
F11 => Key::F11,
F12 => Key::F12,
NumLock => Key::NumLock,
Numpad0 => Key::Character("0".into()),
Numpad1 => Key::Character("1".into()),
Numpad2 => Key::Character("2".into()),
Numpad3 => Key::Character("3".into()),
Numpad4 => Key::Character("4".into()),
Numpad5 => Key::Character("5".into()),
Numpad6 => Key::Character("6".into()),
Numpad7 => Key::Character("7".into()),
Numpad8 => Key::Character("8".into()),
Numpad9 => Key::Character("9".into()),
NumpadDivide => Key::Character("/".into()),
NumpadMultiply => Key::Character("*".into()),
NumpadSubtract => Key::Character("-".into()),
NumpadAdd => Key::Character("+".into()),
NumpadDot => Key::Character(".".into()),
NumpadComma => Key::Character(",".into()),
NumpadEnter => Key::Enter,
NumpadEquals => Key::Character("=".into()),
NumpadLeftParen => Key::Character("(".into()),
NumpadRightParen => Key::Character(")".into()),
VolumeMute => Key::AudioVolumeMute,
Info => Key::Info,
ChannelUp => Key::ChannelUp,
ChannelDown => Key::ChannelDown,
ZoomIn => Key::ZoomIn,
ZoomOut => Key::ZoomOut,
Tv => Key::TV,
Guide => Key::Guide,
Dvr => Key::DVR,
Bookmark => Key::BrowserFavorites,
Captions => Key::ClosedCaptionToggle,
Settings => Key::Settings,
TvPower => Key::TVPower,
TvInput => Key::TVInput,
StbPower => Key::STBPower,
StbInput => Key::STBInput,
AvrPower => Key::AVRPower,
AvrInput => Key::AVRInput,
ProgRed => Key::ColorF0Red,
ProgGreen => Key::ColorF1Green,
ProgYellow => Key::ColorF2Yellow,
ProgBlue => Key::ColorF3Blue,
AppSwitch => Key::AppSwitch,
LanguageSwitch => Key::GroupNext,
MannerMode => Key::MannerMode,
Keycode3dMode => Key::TV3DMode,
Contacts => Key::LaunchContacts,
Calendar => Key::LaunchCalendar,
Music => Key::LaunchMusicPlayer,
Calculator => Key::LaunchApplication2,
ZenkakuHankaku => Key::ZenkakuHankaku,
Eisu => Key::Eisu,
Muhenkan => Key::NonConvert,
Henkan => Key::Convert,
KatakanaHiragana => Key::HiraganaKatakana,
Kana => Key::KanjiMode,
BrightnessDown => Key::BrightnessDown,
BrightnessUp => Key::BrightnessUp,
MediaAudioTrack => Key::MediaAudioTrack,
Sleep => Key::Standby,
Wakeup => Key::WakeUp,
Pairing => Key::Pairing,
MediaTopMenu => Key::MediaTopMenu,
LastChannel => Key::MediaLast,
TvDataService => Key::TVDataService,
VoiceAssist => Key::VoiceDial,
TvRadioService => Key::TVRadioService,
TvTeletext => Key::Teletext,
TvNumberEntry => Key::TVNumberEntry,
TvTerrestrialAnalog => Key::TVTerrestrialAnalog,
TvTerrestrialDigital => Key::TVTerrestrialDigital,
TvSatellite => Key::TVSatellite,
TvSatelliteBs => Key::TVSatelliteBS,
TvSatelliteCs => Key::TVSatelliteCS,
TvSatelliteService => Key::TVSatelliteToggle,
TvNetwork => Key::TVNetwork,
TvAntennaCable => Key::TVAntennaCable,
TvInputHdmi1 => Key::TVInputHDMI1,
TvInputHdmi2 => Key::TVInputHDMI2,
TvInputHdmi3 => Key::TVInputHDMI3,
TvInputHdmi4 => Key::TVInputHDMI4,
TvInputComposite1 => Key::TVInputComposite1,
TvInputComposite2 => Key::TVInputComposite2,
TvInputComponent1 => Key::TVInputComponent1,
TvInputComponent2 => Key::TVInputComponent2,
TvInputVga1 => Key::TVInputVGA1,
TvAudioDescription => Key::TVAudioDescription,
TvAudioDescriptionMixUp => Key::TVAudioDescriptionMixUp,
TvAudioDescriptionMixDown => Key::TVAudioDescriptionMixDown,
TvZoomMode => Key::ZoomToggle,
TvContentsMenu => Key::TVContentsMenu,
TvMediaContextMenu => Key::TVMediaContext,
TvTimerProgramming => Key::TVTimer,
Help => Key::Help,
NavigatePrevious => Key::NavigatePrevious,
NavigateNext => Key::NavigateNext,
NavigateIn => Key::NavigateIn,
NavigateOut => Key::NavigateOut,
MediaSkipForward => Key::MediaSkipForward,
MediaSkipBackward => Key::MediaSkipBackward,
MediaStepForward => Key::MediaStepForward,
MediaStepBackward => Key::MediaStepBackward,
Cut => Key::Cut,
Copy => Key::Copy,
Paste => Key::Paste,
Refresh => Key::BrowserRefresh,
// -----------------------------------------------------------------
// Keycodes that don't have a logical Key mapping
// -----------------------------------------------------------------
Unknown => Key::Unidentified(native),
// Can be added on demand
SoftLeft => Key::Unidentified(native),
SoftRight => Key::Unidentified(native),
Menu => Key::Unidentified(native),
Pictsymbols => Key::Unidentified(native),
SwitchCharset => Key::Unidentified(native),
// -----------------------------------------------------------------
// Gamepad events should be exposed through a separate API, not
// keyboard events
ButtonA => Key::Unidentified(native),
ButtonB => Key::Unidentified(native),
ButtonC => Key::Unidentified(native),
ButtonX => Key::Unidentified(native),
ButtonY => Key::Unidentified(native),
ButtonZ => Key::Unidentified(native),
ButtonL1 => Key::Unidentified(native),
ButtonR1 => Key::Unidentified(native),
ButtonL2 => Key::Unidentified(native),
ButtonR2 => Key::Unidentified(native),
ButtonThumbl => Key::Unidentified(native),
ButtonThumbr => Key::Unidentified(native),
ButtonStart => Key::Unidentified(native),
ButtonSelect => Key::Unidentified(native),
ButtonMode => Key::Unidentified(native),
// -----------------------------------------------------------------
Window => Key::Unidentified(native),
Button1 => Key::Unidentified(native),
Button2 => Key::Unidentified(native),
Button3 => Key::Unidentified(native),
Button4 => Key::Unidentified(native),
Button5 => Key::Unidentified(native),
Button6 => Key::Unidentified(native),
Button7 => Key::Unidentified(native),
Button8 => Key::Unidentified(native),
Button9 => Key::Unidentified(native),
Button10 => Key::Unidentified(native),
Button11 => Key::Unidentified(native),
Button12 => Key::Unidentified(native),
Button13 => Key::Unidentified(native),
Button14 => Key::Unidentified(native),
Button15 => Key::Unidentified(native),
Button16 => Key::Unidentified(native),
Yen => Key::Unidentified(native),
Ro => Key::Unidentified(native),
Assist => Key::Unidentified(native),
Keycode11 => Key::Unidentified(native),
Keycode12 => Key::Unidentified(native),
StemPrimary => Key::Unidentified(native),
Stem1 => Key::Unidentified(native),
Stem2 => Key::Unidentified(native),
Stem3 => Key::Unidentified(native),
DpadUpLeft => Key::Unidentified(native),
DpadDownLeft => Key::Unidentified(native),
DpadUpRight => Key::Unidentified(native),
DpadDownRight => Key::Unidentified(native),
SoftSleep => Key::Unidentified(native),
SystemNavigationUp => Key::Unidentified(native),
SystemNavigationDown => Key::Unidentified(native),
SystemNavigationLeft => Key::Unidentified(native),
SystemNavigationRight => Key::Unidentified(native),
AllApps => Key::Unidentified(native),
ThumbsUp => Key::Unidentified(native),
ThumbsDown => Key::Unidentified(native),
ProfileSwitch => Key::Unidentified(native),
},
Android: rework keycode handling (#2890) The recent overhaul of the keyboard API broke keyboard input on Android. The recent keyboard changes also broke building against the game-activity backend of android-activity because it was assumed that the backend is based on the NDK input API which isn't the case with with game-activity since it doesn't use the InputQueue API from the NDK. Any alphanumeric keycodes were being mapped to `Unidentified` Keys which meant even crude keyboard input support was broken. We do need to expose `getUnicodeChar` (or the ability to look up characters based on the current character map and modifiers) but for now we should at least map alphanumeric keycodes to `Key::Character` for basic interim support of virtual keyboards. This moves all the keycode mapping into a separate `keycodes.rs` file to reduce clutter. This adds back the mapping from Android key codes to Winit key codes that we had before the keyboard API overhaul. Android activity does expose scan codes but key codes currently seem like the more appropriate mapping to Winit physical key codes. This removes the gnarly, unsafe cfg() guarded digging into 'native-activity' and 'game-activity' specific implementation details. I never intended to expose these details in the public API and really hope to avoid there being a release of Winit that would depend on this. I'm also hoping/considering if I can get away with sealing this without necessarily requiring a semver breaking release of android_activity since this absolutely should never have been possible, and can probably safely assume this was the only code in the wild that has briefly done this. I'm also a bit unclear as to what led to doing this. There is a `.key_code()` and `.scan_code()` getter and we even already accessed the keycode in the Android backend so I'm not sure how those APIs were missed.
2023-06-21 18:49:44 +01:00
}
}
pub fn to_location(keycode: Keycode) -> KeyLocation {
use android_activity::input::Keycode::*;
match keycode {
AltLeft => KeyLocation::Left,
AltRight => KeyLocation::Right,
ShiftLeft => KeyLocation::Left,
ShiftRight => KeyLocation::Right,
// According to https://developer.android.com/reference/android/view/KeyEvent#KEYCODE_NUM
Num => KeyLocation::Left,
CtrlLeft => KeyLocation::Left,
CtrlRight => KeyLocation::Right,
MetaLeft => KeyLocation::Left,
MetaRight => KeyLocation::Right,
NumLock => KeyLocation::Numpad,
Numpad0 => KeyLocation::Numpad,
Numpad1 => KeyLocation::Numpad,
Numpad2 => KeyLocation::Numpad,
Numpad3 => KeyLocation::Numpad,
Numpad4 => KeyLocation::Numpad,
Numpad5 => KeyLocation::Numpad,
Numpad6 => KeyLocation::Numpad,
Numpad7 => KeyLocation::Numpad,
Numpad8 => KeyLocation::Numpad,
Numpad9 => KeyLocation::Numpad,
NumpadDivide => KeyLocation::Numpad,
NumpadMultiply => KeyLocation::Numpad,
NumpadSubtract => KeyLocation::Numpad,
NumpadAdd => KeyLocation::Numpad,
NumpadDot => KeyLocation::Numpad,
NumpadComma => KeyLocation::Numpad,
NumpadEnter => KeyLocation::Numpad,
NumpadEquals => KeyLocation::Numpad,
NumpadLeftParen => KeyLocation::Numpad,
NumpadRightParen => KeyLocation::Numpad,
_ => KeyLocation::Standard,
}
}