diff --git a/src/keyboard.rs b/src/keyboard.rs
index bed3c0c4c6..acad629793 100644
--- a/src/keyboard.rs
+++ b/src/keyboard.rs
@@ -176,10 +176,14 @@ pub enum NativeKeyCode {
Windows(u16),
MacOS(u16),
XKB(u32),
+
+ /// This is the android "key code" of the event as returned by
+ /// `KeyEvent.getKeyCode()`
+ Android(u32),
}
impl std::fmt::Debug for NativeKeyCode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- use NativeKeyCode::{MacOS, Unidentified, Windows, XKB};
+ use NativeKeyCode::{Android, MacOS, Unidentified, Windows, XKB};
let mut debug_tuple;
match self {
Unidentified => {
@@ -197,6 +201,10 @@ impl std::fmt::Debug for NativeKeyCode {
debug_tuple = f.debug_tuple(name_of!(XKB));
debug_tuple.field(v);
}
+ Android(v) => {
+ debug_tuple = f.debug_tuple(name_of!(Android));
+ debug_tuple.field(&format_args!("0x{:04X}", v));
+ }
}
debug_tuple.finish()
}
@@ -508,10 +516,13 @@ pub enum KeyCode {
/// Pause Break
Pause,
/// Some laptops place this key to the left of the ↑ key.
+ ///
+ /// This also the "back" button (triangle) on Android.
BrowserBack,
BrowserFavorites,
/// Some laptops place this key to the right of the ↑ key.
BrowserForward,
+ /// The "home" button on Android.
BrowserHome,
BrowserRefresh,
BrowserSearch,
diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs
index 4dc3bb4aff..6f45455839 100644
--- a/src/platform_impl/android/mod.rs
+++ b/src/platform_impl/android/mod.rs
@@ -4,6 +4,7 @@ use crate::{
dpi::{PhysicalPosition, PhysicalSize, Position, Size},
error, event,
event_loop::{self, ControlFlow},
+ keyboard::{Key, KeyCode, KeyLocation, NativeKeyCode},
monitor, window,
};
use ndk::{
@@ -12,8 +13,10 @@ use ndk::{
looper::{ForeignLooper, Poll, ThreadLooper},
};
use ndk_glue::{Event, Rect};
+use ndk_sys::AKeyEvent_getKeyCode;
use std::{
collections::VecDeque,
+ convert::TryInto,
sync::{Arc, Mutex, RwLock},
time::{Duration, Instant},
};
@@ -41,6 +44,9 @@ fn poll(poll: Poll) -> Option {
}
}
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct KeyEventExtra {}
+
pub struct EventLoop {
window_target: event_loop::EventLoopWindowTarget,
user_queue: Arc>>,
@@ -245,16 +251,35 @@ impl EventLoop {
KeyAction::Up => event::ElementState::Released,
_ => event::ElementState::Released,
};
- #[allow(deprecated)]
+
+ // 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.
+ let keycode_u32 = unsafe {
+ AKeyEvent_getKeyCode(key.ptr().as_ptr()) as u32
+ };
+ let keycode = keycode_u32
+ .try_into()
+ .unwrap_or(ndk::event::Keycode::Unknown);
+ let physical_key = KeyCode::Unidentified(
+ NativeKeyCode::Android(keycode.into()),
+ );
+ let native = NativeKeyCode::Android(keycode_u32);
+ let logical_key = keycode_to_logical(keycode, native);
+ // TODO: maybe use getUnicodeChar to get the logical key
+
let event = event::Event::WindowEvent {
window_id,
event: event::WindowEvent::KeyboardInput {
device_id,
- input: event::KeyboardInput {
- scancode: key.scan_code() as u32,
+ event: event::KeyEvent {
state,
- virtual_keycode: None,
- modifiers: event::ModifiersState::default(),
+ physical_key,
+ logical_key,
+ location: keycode_to_location(keycode),
+ repeat: key.repeat_count() > 0,
+ text: None,
+ platform_specific: KeyEventExtra {},
},
is_synthetic: false,
},
@@ -581,6 +606,8 @@ impl Window {
pub fn content_rect(&self) -> Rect {
ndk_glue::content_rect()
}
+
+ pub fn reset_dead_keys(&self) {}
}
#[derive(Default, Clone, Debug)]
@@ -669,3 +696,377 @@ impl VideoMode {
}
}
}
+
+fn keycode_to_logical(keycode: ndk::event::Keycode, native: NativeKeyCode) -> Key<'static> {
+ 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,
+ }
+}