diff --git a/android-activity/src/game_activity/input.rs b/android-activity/src/game_activity/input.rs index 957e24b..2f53612 100644 --- a/android-activity/src/game_activity/input.rs +++ b/android-activity/src/game_activity/input.rs @@ -13,12 +13,10 @@ // The `Class` was also bound differently to `android-ndk-rs` considering how the class is defined // by masking bits from the `Source`. -use std::convert::TryInto; - use crate::activity_impl::ffi::{GameActivityKeyEvent, GameActivityMotionEvent}; use crate::input::{ - Axis, ButtonState, Class, EdgeFlags, KeyAction, KeyEventFlags, Keycode, MetaState, - MotionAction, MotionEventFlags, Pointer, PointersIter, Source, ToolType, + Axis, ButtonState, EdgeFlags, KeyAction, KeyEventFlags, Keycode, MetaState, MotionAction, + MotionEventFlags, Pointer, PointersIter, Source, ToolType, }; // Note: try to keep this wrapper API compatible with the AInputEvent API if possible @@ -50,14 +48,7 @@ impl<'a> MotionEvent<'a> { #[inline] pub fn source(&self) -> Source { let source = self.ga_event.source as u32; - source.try_into().unwrap_or(Source::Unknown) - } - - /// Get the class of the event source. - /// - #[inline] - pub fn class(&self) -> Class { - Class::from(self.source()) + source.into() } /// Get the device id associated with the event. @@ -73,7 +64,7 @@ impl<'a> MotionEvent<'a> { #[inline] pub fn action(&self) -> MotionAction { let action = self.ga_event.action as u32 & ndk_sys::AMOTION_EVENT_ACTION_MASK; - action.try_into().unwrap() + action.into() } /// Returns the pointer index of an `Up` or `Down` event. @@ -275,7 +266,8 @@ impl<'a> PointerImpl<'a> { #[inline] pub fn axis_value(&self, axis: Axis) -> f32 { let pointer = &self.event.ga_event.pointers[self.index]; - pointer.axisValues[axis as u32 as usize] + let axis: u32 = axis.into(); + pointer.axisValues[axis as usize] } #[inline] @@ -294,7 +286,7 @@ impl<'a> PointerImpl<'a> { pub fn tool_type(&self) -> ToolType { let pointer = &self.event.ga_event.pointers[self.index]; let tool_type = pointer.toolType as u32; - tool_type.try_into().unwrap() + tool_type.into() } } @@ -662,14 +654,7 @@ impl<'a> KeyEvent<'a> { #[inline] pub fn source(&self) -> Source { let source = self.ga_event.source as u32; - source.try_into().unwrap_or(Source::Unknown) - } - - /// Get the class of the event source. - /// - #[inline] - pub fn class(&self) -> Class { - Class::from(self.source()) + source.into() } /// Get the device id associated with the event. @@ -685,13 +670,13 @@ impl<'a> KeyEvent<'a> { #[inline] pub fn action(&self) -> KeyAction { let action = self.ga_event.action as u32; - action.try_into().unwrap() + action.into() } #[inline] pub fn action_button(&self) -> KeyAction { let action = self.ga_event.action as u32; - action.try_into().unwrap() + action.into() } /// Returns the last time the key was pressed. This is on the scale of @@ -721,7 +706,7 @@ impl<'a> KeyEvent<'a> { #[inline] pub fn key_code(&self) -> Keycode { let keycode = self.ga_event.keyCode as u32; - keycode.try_into().unwrap_or(Keycode::Unknown) + keycode.into() } /// Returns the number of repeats of a key. diff --git a/android-activity/src/game_activity/mod.rs b/android-activity/src/game_activity/mod.rs index 5809e9b..f9904d1 100644 --- a/android-activity/src/game_activity/mod.rs +++ b/android-activity/src/game_activity/mod.rs @@ -548,10 +548,12 @@ impl AndroidAppInner { } pub fn enable_motion_axis(&mut self, axis: Axis) { + let axis: u32 = axis.into(); unsafe { ffi::GameActivityPointerAxes_enableAxis(axis as i32) } } pub fn disable_motion_axis(&mut self, axis: Axis) { + let axis: u32 = axis.into(); unsafe { ffi::GameActivityPointerAxes_disableAxis(axis as i32) } } diff --git a/android-activity/src/input.rs b/android-activity/src/input.rs index 55390f8..95fe17a 100644 --- a/android-activity/src/input.rs +++ b/android-activity/src/input.rs @@ -1,5 +1,4 @@ use bitflags::bitflags; -use num_enum::{IntoPrimitive, TryFromPrimitive}; pub use crate::activity_impl::input::*; use crate::InputStatus; @@ -10,7 +9,17 @@ pub use sdk::*; /// An enum representing the source of an [`MotionEvent`] or [`KeyEvent`] /// /// See [the InputDevice docs](https://developer.android.com/reference/android/view/InputDevice#SOURCE_ANY) -#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +/// +/// # Android Extensible Enum +/// +/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and +/// should be handled similar to a `#[non_exhaustive]` enum to maintain +/// forwards compatibility. +/// +/// This implements `Into` and `From` for converting to/from Android +/// SDK integer values. +/// +#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)] #[repr(u32)] pub enum Source { BluetoothStylus = 0x0000c002, @@ -36,9 +45,36 @@ pub enum Source { TouchNavigation = 0x00200000, Trackball = 0x00010004, - Unknown = 0, + // We need to consider that the enum variants may be extended across + // different versions of Android (i.e. effectively at runtime) but at the + // same time we don't want it to be an API break to extend this enum in + // future releases of `android-activity` with new variants from the latest + // NDK/SDK. + // + // We can't just use `#[non_exhaustive]` because that only really helps + // when adding new variants in sync with android-activity releases. + // + // On the other hand we also can't rely on a catch-all `Unknown(u32)` that + // only really helps with unknown variants seen at runtime. + // + // What we aim for instead is to have a hidden catch-all variant that + // is considered (practically) unmatchable so code is forced to have + // a `unknown => {}` catch-all pattern match that will cover unknown variants + // either in the form of Rust variants added in future versions or + // in the form of an `__Unknown(u32)` integer that represents an unknown + // variant seen at runtime. + // + // Any `unknown => {}` pattern match can rely on `IntoPrimitive` to convert + // the `unknown` variant to the integer that comes from the Android SDK + // in case that values needs to be passed on, even without knowing its + // semantic meaning at compile time. + #[doc(hidden)] + #[num_enum(catch_all)] + __Unknown(u32), } +// ndk_sys doesn't currently have the `TRACKBALL` flag so we define our +// own internal class constants for now bitflags! { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] struct SourceFlags: u32 { @@ -53,37 +89,31 @@ bitflags! { } } -/// An enum representing the class of a [`MotionEvent`] or [`KeyEvent`] source -/// -/// See [the InputDevice docs](https://developer.android.com/reference/android/view/InputDevice#SOURCE_CLASS_MASK) -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum Class { - None, - Button, - Pointer, - Trackball, - Position, - Joystick, -} - -impl From for Class { - fn from(source: u32) -> Self { - let class = SourceFlags::from_bits_truncate(source); - match class { - SourceFlags::BUTTON => Class::Button, - SourceFlags::POINTER => Class::Pointer, - SourceFlags::TRACKBALL => Class::Trackball, - SourceFlags::POSITION => Class::Position, - SourceFlags::JOYSTICK => Class::Joystick, - _ => Class::None, - } +impl Source { + #[inline] + pub fn is_button_class(self) -> bool { + let class = SourceFlags::from_bits_truncate(self.into()); + class.contains(SourceFlags::BUTTON) } -} - -impl From for Class { - fn from(source: Source) -> Self { - let source: u32 = source.into(); - source.into() + #[inline] + pub fn is_pointer_class(self) -> bool { + let class = SourceFlags::from_bits_truncate(self.into()); + class.contains(SourceFlags::POINTER) + } + #[inline] + pub fn is_trackball_class(self) -> bool { + let class = SourceFlags::from_bits_truncate(self.into()); + class.contains(SourceFlags::TRACKBALL) + } + #[inline] + pub fn is_position_class(self) -> bool { + let class = SourceFlags::from_bits_truncate(self.into()); + class.contains(SourceFlags::POSITION) + } + #[inline] + pub fn is_joystick_class(self) -> bool { + let class = SourceFlags::from_bits_truncate(self.into()); + class.contains(SourceFlags::JOYSTICK) } } @@ -174,7 +204,17 @@ impl From for MetaState { /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-29) -#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +/// +/// # Android Extensible Enum +/// +/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and +/// should be handled similar to a `#[non_exhaustive]` enum to maintain +/// forwards compatibility. +/// +/// This implements `Into` and `From` for converting to/from Android +/// SDK integer values. +/// +#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)] #[repr(u32)] pub enum MotionAction { Down = ndk_sys::AMOTION_EVENT_ACTION_DOWN, @@ -190,19 +230,26 @@ pub enum MotionAction { HoverExit = ndk_sys::AMOTION_EVENT_ACTION_HOVER_EXIT, ButtonPress = ndk_sys::AMOTION_EVENT_ACTION_BUTTON_PRESS, ButtonRelease = ndk_sys::AMOTION_EVENT_ACTION_BUTTON_RELEASE, -} -impl From for MotionAction { - fn from(value: ndk::event::MotionAction) -> Self { - let inner: u32 = value.into(); - inner.try_into().unwrap() // TODO: use into() when we bump the MSRV to 1.68 - } + #[doc(hidden)] + #[num_enum(catch_all)] + __Unknown(u32), } /// An axis of a motion event. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-32) -#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +/// +/// # Android Extensible Enum +/// +/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and +/// should be handled similar to a `#[non_exhaustive]` enum to maintain +/// forwards compatibility. +/// +/// This implements `Into` and `From` for converting to/from Android +/// SDK integer values. +/// +#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)] #[repr(u32)] pub enum Axis { X = ndk_sys::AMOTION_EVENT_AXIS_X, @@ -250,19 +297,26 @@ pub enum Axis { Generic14 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_14, Generic15 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_15, Generic16 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_16, -} -impl From for Axis { - fn from(value: ndk::event::Axis) -> Self { - let inner: u32 = value.into(); - inner.try_into().unwrap() // TODO: replace with into() when we can bump MSRV to 1.68! - } + #[doc(hidden)] + #[num_enum(catch_all)] + __Unknown(u32), } /// The tool type of a pointer. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-48) -#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +/// +/// # Android Extensible Enum +/// +/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and +/// should be handled similar to a `#[non_exhaustive]` enum to maintain +/// forwards compatibility. +/// +/// Implements `Into` and `From` for converting to/from Android SDK +/// integer values. +/// +#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)] #[repr(u32)] pub enum ToolType { /// Unknown tool type. @@ -284,6 +338,10 @@ pub enum ToolType { /// The tool is a palm and should be rejected Palm = ndk_sys::AMOTION_EVENT_TOOL_TYPE_PALM, + + #[doc(hidden)] + #[num_enum(catch_all)] + __Unknown(u32), } /// A bitfield representing the state of buttons during a motion event. @@ -382,25 +440,42 @@ impl From for MotionEventFlags { /// Key actions. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-27) -#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +/// +/// # Android Extensible Enum +/// +/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and +/// should be handled similar to a `#[non_exhaustive]` enum to maintain +/// forwards compatibility. +/// +/// Implements `Into` and `From` for converting to/from Android SDK +/// integer values. +/// +#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)] #[repr(u32)] pub enum KeyAction { Down = ndk_sys::AKEY_EVENT_ACTION_DOWN, Up = ndk_sys::AKEY_EVENT_ACTION_UP, Multiple = ndk_sys::AKEY_EVENT_ACTION_MULTIPLE, -} -impl From for KeyAction { - fn from(value: ndk::event::KeyAction) -> Self { - let inner: u32 = value.into(); - inner.try_into().unwrap() // TODO: replace with into() when we can bump MSRV to 1.68! - } + #[doc(hidden)] + #[num_enum(catch_all)] + __Unknown(u32), } /// Key codes. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-39) -#[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] +/// +/// # Android Extensible Enum +/// +/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and +/// should be handled similar to a `#[non_exhaustive]` enum to maintain +/// forwards compatibility. +/// +/// Implements `Into` and `From` for converting to/from Android SDK +/// integer values. +/// +#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)] #[repr(u32)] pub enum Keycode { Unknown = ndk_sys::AKEYCODE_UNKNOWN, @@ -692,13 +767,10 @@ pub enum Keycode { ThumbsUp = ndk_sys::AKEYCODE_THUMBS_UP, ThumbsDown = ndk_sys::AKEYCODE_THUMBS_DOWN, ProfileSwitch = ndk_sys::AKEYCODE_PROFILE_SWITCH, -} -impl From for Keycode { - fn from(value: ndk::event::Keycode) -> Self { - let inner: u32 = value.into(); - inner.try_into().unwrap() // TODO: replace with into() when we can bump MSRV to 1.68! - } + #[doc(hidden)] + #[num_enum(catch_all)] + __Unknown(u32), } /// Flags associated with [`KeyEvent`]. diff --git a/android-activity/src/input/sdk.rs b/android-activity/src/input/sdk.rs index f03a41b..ad4517d 100644 --- a/android-activity/src/input/sdk.rs +++ b/android-activity/src/input/sdk.rs @@ -17,7 +17,22 @@ use crate::{ jni_utils, }; -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +/// An enum representing the types of keyboards that may generate key events +/// +/// See [getKeyboardType() docs](https://developer.android.com/reference/android/view/KeyCharacterMap#getKeyboardType()) +/// +/// # Android Extensible Enum +/// +/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and +/// should be handled similar to a `#[non_exhaustive]` enum to maintain +/// forwards compatibility. +/// +/// This implements `Into` and `From` for converting to/from Android +/// SDK integer values. +#[derive( + Debug, Clone, Copy, PartialEq, Eq, Hash, num_enum::FromPrimitive, num_enum::IntoPrimitive, +)] +#[repr(u32)] pub enum KeyboardType { /// A numeric (12-key) keyboard. /// @@ -50,33 +65,9 @@ pub enum KeyboardType { /// A special function keyboard consists only of non-printing keys such as HOME and POWER that are not actually used for typing. SpecialFunction, - /// An unknown type of keyboard - Unknown(i32), -} - -impl From for KeyboardType { - fn from(value: i32) -> Self { - match value { - 1 => KeyboardType::Numeric, - 2 => KeyboardType::Predictive, - 3 => KeyboardType::Alpha, - 4 => KeyboardType::Full, - 5 => KeyboardType::SpecialFunction, - unknown => KeyboardType::Unknown(unknown), - } - } -} -impl From for i32 { - fn from(value: KeyboardType) -> i32 { - match value { - KeyboardType::Numeric => 1, - KeyboardType::Predictive => 2, - KeyboardType::Alpha => 3, - KeyboardType::Full => 4, - KeyboardType::SpecialFunction => 5, - KeyboardType::Unknown(unknown) => unknown, - } - } + #[doc(hidden)] + #[num_enum(catch_all)] + __Unknown(u32), } /// Either represents, a unicode character or combining accent from a @@ -353,6 +344,7 @@ impl KeyCharacterMap { let keyboard_type = self .binding .get_keyboard_type(&mut env, self.key_map.as_obj())?; + let keyboard_type = keyboard_type as u32; Ok(keyboard_type.into()) } } diff --git a/android-activity/src/lib.rs b/android-activity/src/lib.rs index cbbe7d2..448fc57 100644 --- a/android-activity/src/lib.rs +++ b/android-activity/src/lib.rs @@ -51,6 +51,49 @@ //! //! These are undone after `android_main()` returns //! +//! # Android Extensible Enums +//! +//! There are numerous enums in the `android-activity` API which are effectively +//! bindings to enums declared in the Android SDK which need to be considered +//! _runtime_ extensible. +//! +//! Any enum variants that come from the Android SDK may be extended in future +//! versions of Android and your code could be exposed to new variants if you +//! build an application that might be installed on new versions of Android. +//! +//! This crate follows a convention of adding a hidden `__Unknown(u32)` variant +//! to these enum to ensure we can always do lossless conversions between the +//! integers from the SDK and our corresponding Rust enums. This can be +//! important in case you need to pass certain variants back to the SDK +//! regardless of whether you knew about that variants specific semantics at +//! compile time. +//! +//! You should never include this `__Unknown(u32)` variant within any exhaustive +//! pattern match and should instead treat the enums like `#[non_exhaustive]` +//! enums that require you to add a catch-all for any `unknown => {}` values. +//! +//! Any code that would exhaustively include the `__Unknown(u32)` variant when +//! pattern matching can not be guaranteed to be forwards compatible with new +//! releases of `android-activity` which may add new Rust variants to these +//! enums without requiring a breaking semver bump. +//! +//! You can (infallibly) convert these enums to and from primitive `u32` values +//! using `.into()`: +//! +//! For example, here is how you could ensure forwards compatibility with both +//! compile-time and runtime extensions of a `SomeEnum` enum: +//! +//! ```rust +//! match some_enum { +//! SomeEnum::Foo => {}, +//! SomeEnum::Bar => {}, +//! unhandled => { +//! let sdk_val: u32 = unhandled.into(); +//! println!("Unhandled enum variant {some_enum:?} has SDK value: {sdk_val}"); +//! } +//! } +//! ``` +//! //! [`Activity`]: https://developer.android.com/reference/android/app/Activity //! [`NativeActivity`]: https://developer.android.com/reference/android/app/NativeActivity //! [ndk_concepts]: https://developer.android.com/ndk/guides/concepts#naa diff --git a/android-activity/src/native_activity/input.rs b/android-activity/src/native_activity/input.rs index 8a2d0b2..ddf9928 100644 --- a/android-activity/src/native_activity/input.rs +++ b/android-activity/src/native_activity/input.rs @@ -1,8 +1,8 @@ use std::marker::PhantomData; use crate::input::{ - Axis, ButtonState, Class, EdgeFlags, KeyAction, Keycode, MetaState, MotionAction, - MotionEventFlags, Pointer, PointersIter, Source, ToolType, + Axis, ButtonState, EdgeFlags, KeyAction, Keycode, MetaState, MotionAction, MotionEventFlags, + Pointer, PointersIter, Source, ToolType, }; /// A motion event @@ -32,18 +32,11 @@ impl<'a> MotionEvent<'a> { pub fn source(&self) -> Source { // XXX: we use `AInputEvent_getSource` directly (instead of calling // ndk_event.source()) since we have our own `Source` enum that we - // share between backends, which may not exactly match the ndk crate's - // `Source` enum. + // share between backends, which may also capture unknown variants + // added in new versions of Android. let source = unsafe { ndk_sys::AInputEvent_getSource(self.ndk_event.ptr().as_ptr()) as u32 }; - source.try_into().unwrap_or(Source::Unknown) - } - - /// Get the class of the event source. - /// - #[inline] - pub fn class(&self) -> Class { - Class::from(self.source()) + source.into() } /// Get the device id associated with the event. @@ -58,7 +51,11 @@ impl<'a> MotionEvent<'a> { /// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getActionMasked()) #[inline] pub fn action(&self) -> MotionAction { - self.ndk_event.action().into() + // XXX: we use `AInputEvent_getAction` directly since we have our own + // `KeyAction` enum that we share between backends, which may also + // capture unknown variants added in new versions of Android. + let action = unsafe { ndk_sys::AKeyEvent_getAction(self.ndk_event.ptr().as_ptr()) as u32 }; + action.into() } /// Returns the pointer index of an `Up` or `Down` event. @@ -250,8 +247,13 @@ impl<'a> PointerImpl<'a> { #[inline] pub fn axis_value(&self, axis: Axis) -> f32 { let value: u32 = axis.into(); - let ndk_axis = value.try_into().unwrap(); - self.ndk_pointer.axis_value(ndk_axis) + if let Ok(ndk_axis) = value.try_into() { + self.ndk_pointer.axis_value(ndk_axis) + } else { + // FIXME: We should also be able to query `Axis::__Unknown(u32)` values + // that can't currently be queried via the `ndk` `Pointer` API + 0.0f32 + } } #[inline] @@ -267,7 +269,7 @@ impl<'a> PointerImpl<'a> { #[inline] pub fn tool_type(&self) -> ToolType { let value: u32 = self.ndk_pointer.tool_type().into(); - value.try_into().unwrap() + value.into() } } @@ -323,18 +325,11 @@ impl<'a> KeyEvent<'a> { pub fn source(&self) -> Source { // XXX: we use `AInputEvent_getSource` directly (instead of calling // ndk_event.source()) since we have our own `Source` enum that we - // share between backends, which may not exactly match the ndk crate's - // `Source` enum. + // share between backends, which may also capture unknown variants + // added in new versions of Android. let source = unsafe { ndk_sys::AInputEvent_getSource(self.ndk_event.ptr().as_ptr()) as u32 }; - source.try_into().unwrap_or(Source::Unknown) - } - - /// Get the class of the event source. - /// - #[inline] - pub fn class(&self) -> Class { - Class::from(self.source()) + source.into() } /// Get the device id associated with the event. @@ -349,7 +344,11 @@ impl<'a> KeyEvent<'a> { /// See [the KeyEvent docs](https://developer.android.com/reference/android/view/KeyEvent#getAction()) #[inline] pub fn action(&self) -> KeyAction { - self.ndk_event.action().into() + // XXX: we use `AInputEvent_getAction` directly since we have our own + // `KeyAction` enum that we share between backends, which may also + // capture unknown variants added in new versions of Android. + let action = unsafe { ndk_sys::AKeyEvent_getAction(self.ndk_event.ptr().as_ptr()) as u32 }; + action.into() } /// Returns the last time the key was pressed. This is on the scale of @@ -378,7 +377,12 @@ impl<'a> KeyEvent<'a> { /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getkeycode) #[inline] pub fn key_code(&self) -> Keycode { - self.ndk_event.key_code().into() + // XXX: we use `AInputEvent_getKeyCode` directly since we have our own + // `Keycode` enum that we share between backends, which may also + // capture unknown variants added in new versions of Android. + let keycode = + unsafe { ndk_sys::AKeyEvent_getKeyCode(self.ndk_event.ptr().as_ptr()) as u32 }; + keycode.into() } /// Returns the number of repeats of a key.