From 7929999c1c9b9a3ad8966f36663fc4514b517216 Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Wed, 21 Jun 2023 18:49:44 +0100 Subject: [PATCH] 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. --- src/platform_impl/android/keycodes.rs | 521 ++++++++++++++++++++++++++ src/platform_impl/android/mod.rs | 422 +-------------------- 2 files changed, 534 insertions(+), 409 deletions(-) create mode 100644 src/platform_impl/android/keycodes.rs diff --git a/src/platform_impl/android/keycodes.rs b/src/platform_impl/android/keycodes.rs new file mode 100644 index 00000000..8933e796 --- /dev/null +++ b/src/platform_impl/android/keycodes.rs @@ -0,0 +1,521 @@ +use android_activity::input::Keycode; + +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())), + } +} + +// TODO: We need to expose getUnicodeChar via android-activity instead of having +// a fixed mapping from key codes +pub fn to_logical(keycode: Keycode, native: NativeKey) -> Key { + use android_activity::input::Keycode::*; + + match keycode { + Unknown => Key::Unidentified(native), + + // Can be added on demand + SoftLeft => Key::Unidentified(native), + SoftRight => Key::Unidentified(native), + + // 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, + + //------------------------------------------------------------------------------- + // Reporting unidentified, because the specific character is layout dependent. + // (I'm not sure though) + 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, + + Menu => Key::Unidentified(native), + + 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, + 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), + // ----------------------------------------------------------------- + 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, + Window => Key::Unidentified(native), + 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, + 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), + 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, + Yen => Key::Unidentified(native), + Ro => Key::Unidentified(native), + Kana => Key::KanjiMode, + Assist => Key::Unidentified(native), + BrightnessDown => Key::BrightnessDown, + BrightnessUp => Key::BrightnessUp, + MediaAudioTrack => Key::MediaAudioTrack, + Sleep => Key::Standby, + Wakeup => Key::WakeUp, + Pairing => Key::Pairing, + MediaTopMenu => Key::MediaTopMenu, + Keycode11 => Key::Unidentified(native), + Keycode12 => Key::Unidentified(native), + 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, + 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), + MediaSkipForward => Key::MediaSkipForward, + MediaSkipBackward => Key::MediaSkipBackward, + MediaStepForward => Key::MediaStepForward, + MediaStepBackward => Key::MediaStepBackward, + SoftSleep => Key::Unidentified(native), + Cut => Key::Cut, + Copy => Key::Copy, + Paste => Key::Paste, + SystemNavigationUp => Key::Unidentified(native), + SystemNavigationDown => Key::Unidentified(native), + SystemNavigationLeft => Key::Unidentified(native), + SystemNavigationRight => Key::Unidentified(native), + AllApps => Key::Unidentified(native), + Refresh => Key::BrowserRefresh, + ThumbsUp => Key::Unidentified(native), + ThumbsDown => Key::Unidentified(native), + ProfileSwitch => Key::Unidentified(native), + } +} + +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, + } +} diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index 1f8dd8ea..b48d3acc 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -2,7 +2,6 @@ use std::{ collections::VecDeque, - convert::TryInto, hash::Hash, sync::{ atomic::{AtomicBool, Ordering}, @@ -11,7 +10,7 @@ use std::{ time::{Duration, Instant}, }; -use android_activity::input::{InputEvent, KeyAction, MotionAction}; +use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction}; use android_activity::{ AndroidApp, AndroidAppWaker, ConfigurationRef, InputStatus, MainEvent, Rect, }; @@ -20,21 +19,20 @@ use raw_window_handle::{ AndroidDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, }; -#[cfg(feature = "android-native-activity")] -use ndk_sys::AKeyEvent_getKeyCode; - use crate::platform_impl::Fullscreen; use crate::{ dpi::{PhysicalPosition, PhysicalSize, Position, Size}, error, event::{self, StartCause}, event_loop::{self, ControlFlow, EventLoopWindowTarget as RootELW}, - keyboard::{Key, KeyCode, KeyLocation, NativeKey, NativeKeyCode}, + keyboard::NativeKey, window::{ self, CursorGrabMode, ImePurpose, ResizeDirection, Theme, WindowButtons, WindowLevel, }, }; +mod keycodes; + static HAS_FOCUS: Lazy> = Lazy::new(|| RwLock::new(true)); struct PeekableReceiver { @@ -408,45 +406,25 @@ impl EventLoop { } InputEvent::KeyEvent(key) => { match key.key_code() { - // Flagg keys related to volume as unhandled. While winit does not have a way for applications + // Flag keys related to volume as unhandled. While winit does not have a way for applications // to configure what keys to flag as handled, this appears to be a good default until winit // can be configured. - ndk::event::Keycode::VolumeUp | - ndk::event::Keycode::VolumeDown | - ndk::event::Keycode::VolumeMute => { + Keycode::VolumeUp | + Keycode::VolumeDown | + Keycode::VolumeMute => { if self.ignore_volume_keys { input_status = InputStatus::Unhandled } }, - _ => { + keycode => { let state = match key.action() { KeyAction::Down => event::ElementState::Pressed, KeyAction::Up => event::ElementState::Released, _ => event::ElementState::Released, }; - #[cfg(feature = "android-native-activity")] - let (keycode_u32, scancode_u32) = unsafe { - // We abuse the fact that `android_activity`'s `KeyEvent` is `repr(transparent)` - let event = (key as *const android_activity::input::KeyEvent<'_>).cast::(); - // We use the unsafe function directly because we want to forward the - // keycode value even if it doesn't have a variant defined in the ndk - // crate. - ( - AKeyEvent_getKeyCode((*event).ptr().as_ptr()) as u32, - (*event).scan_code() as u32 - ) - }; - #[cfg(feature = "android-game-activity")] - let (keycode_u32, scancode_u32) = (key.keyCode as u32, key.scanCode as u32); - let keycode = keycode_u32 - .try_into() - .unwrap_or(ndk::event::Keycode::Unknown); - let physical_key = KeyCode::Unidentified( - NativeKeyCode::Android(scancode_u32), - ); - let native = NativeKey::Android(keycode_u32); - let logical_key = keycode_to_logical(keycode, native); + let native = NativeKey::Android(keycode.into()); + let logical_key = keycodes::to_logical(keycode, native); // TODO: maybe use getUnicodeChar to get the logical key let event = event::Event::WindowEvent { @@ -455,9 +433,9 @@ impl EventLoop { device_id: event::DeviceId(DeviceId), event: event::KeyEvent { state, - physical_key, + physical_key: keycodes::to_physical_keycode(keycode), logical_key, - location: keycode_to_location(keycode), + location: keycodes::to_location(keycode), repeat: key.repeat_count() > 0, text: None, platform_specific: KeyEventExtra {}, @@ -1077,377 +1055,3 @@ impl VideoMode { self.monitor.clone() } } - -fn keycode_to_logical(keycode: ndk::event::Keycode, native: NativeKey) -> Key { - use ndk::event::Keycode::*; - - // The android `Keycode` is sort-of layout dependent. More specifically - // if I press the Z key using a US layout, then I get KEYCODE_Z, - // but if I press the same key after switching to a HUN layout, I get - // KEYCODE_Y. - // - // To prevents us from using this value to determine the `physical_key` - // (also know as winit's `KeyCode`) - // - // Unfortunately the documentation says that the scancode values - // "are not reliable and vary from device to device". Which seems to mean - // that there's no way to reliably get the physical_key on android. - - match keycode { - Unknown => Key::Unidentified(native), - - // Can be added on demand - SoftLeft => Key::Unidentified(native), - SoftRight => Key::Unidentified(native), - - // 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, - - //------------------------------------------------------------------------------- - // Reporting unidentified, because the specific character is layout dependent. - // (I'm not sure though) - Keycode0 => Key::Unidentified(native), - Keycode1 => Key::Unidentified(native), - Keycode2 => Key::Unidentified(native), - Keycode3 => Key::Unidentified(native), - Keycode4 => Key::Unidentified(native), - Keycode5 => Key::Unidentified(native), - Keycode6 => Key::Unidentified(native), - Keycode7 => Key::Unidentified(native), - Keycode8 => Key::Unidentified(native), - Keycode9 => Key::Unidentified(native), - Star => Key::Unidentified(native), - Pound => Key::Unidentified(native), - A => Key::Unidentified(native), - B => Key::Unidentified(native), - C => Key::Unidentified(native), - D => Key::Unidentified(native), - E => Key::Unidentified(native), - F => Key::Unidentified(native), - G => Key::Unidentified(native), - H => Key::Unidentified(native), - I => Key::Unidentified(native), - J => Key::Unidentified(native), - K => Key::Unidentified(native), - L => Key::Unidentified(native), - M => Key::Unidentified(native), - N => Key::Unidentified(native), - O => Key::Unidentified(native), - P => Key::Unidentified(native), - Q => Key::Unidentified(native), - R => Key::Unidentified(native), - S => Key::Unidentified(native), - T => Key::Unidentified(native), - U => Key::Unidentified(native), - V => Key::Unidentified(native), - W => Key::Unidentified(native), - X => Key::Unidentified(native), - Y => Key::Unidentified(native), - Z => Key::Unidentified(native), - Comma => Key::Unidentified(native), - Period => Key::Unidentified(native), - Grave => Key::Unidentified(native), - Minus => Key::Unidentified(native), - Equals => Key::Unidentified(native), - LeftBracket => Key::Unidentified(native), - RightBracket => Key::Unidentified(native), - Backslash => Key::Unidentified(native), - Semicolon => Key::Unidentified(native), - Apostrophe => Key::Unidentified(native), - Slash => Key::Unidentified(native), - At => Key::Unidentified(native), - Plus => Key::Unidentified(native), - //------------------------------------------------------------------------------- - 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, - - Menu => Key::Unidentified(native), - - 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, - 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), - // ----------------------------------------------------------------- - 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::Unidentified(native), - Numpad1 => Key::Unidentified(native), - Numpad2 => Key::Unidentified(native), - Numpad3 => Key::Unidentified(native), - Numpad4 => Key::Unidentified(native), - Numpad5 => Key::Unidentified(native), - Numpad6 => Key::Unidentified(native), - Numpad7 => Key::Unidentified(native), - Numpad8 => Key::Unidentified(native), - Numpad9 => Key::Unidentified(native), - NumpadDivide => Key::Unidentified(native), - NumpadMultiply => Key::Unidentified(native), - NumpadSubtract => Key::Unidentified(native), - NumpadAdd => Key::Unidentified(native), - NumpadDot => Key::Unidentified(native), - NumpadComma => Key::Unidentified(native), - NumpadEnter => Key::Unidentified(native), - NumpadEquals => Key::Unidentified(native), - NumpadLeftParen => Key::Unidentified(native), - NumpadRightParen => Key::Unidentified(native), - - VolumeMute => Key::AudioVolumeMute, - Info => Key::Info, - ChannelUp => Key::ChannelUp, - ChannelDown => Key::ChannelDown, - ZoomIn => Key::ZoomIn, - ZoomOut => Key::ZoomOut, - Tv => Key::TV, - Window => Key::Unidentified(native), - 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, - 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), - 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, - Yen => Key::Unidentified(native), - Ro => Key::Unidentified(native), - Kana => Key::KanjiMode, - Assist => Key::Unidentified(native), - BrightnessDown => Key::BrightnessDown, - BrightnessUp => Key::BrightnessUp, - MediaAudioTrack => Key::MediaAudioTrack, - Sleep => Key::Standby, - Wakeup => Key::WakeUp, - Pairing => Key::Pairing, - MediaTopMenu => Key::MediaTopMenu, - Keycode11 => Key::Unidentified(native), - Keycode12 => Key::Unidentified(native), - 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, - 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), - MediaSkipForward => Key::MediaSkipForward, - MediaSkipBackward => Key::MediaSkipBackward, - MediaStepForward => Key::MediaStepForward, - MediaStepBackward => Key::MediaStepBackward, - SoftSleep => Key::Unidentified(native), - Cut => Key::Cut, - Copy => Key::Copy, - Paste => Key::Paste, - SystemNavigationUp => Key::Unidentified(native), - SystemNavigationDown => Key::Unidentified(native), - SystemNavigationLeft => Key::Unidentified(native), - SystemNavigationRight => Key::Unidentified(native), - AllApps => Key::Unidentified(native), - Refresh => Key::BrowserRefresh, - ThumbsUp => Key::Unidentified(native), - ThumbsDown => Key::Unidentified(native), - ProfileSwitch => Key::Unidentified(native), - } -} - -fn keycode_to_location(keycode: ndk::event::Keycode) -> KeyLocation { - use ndk::event::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, - } -}