diff --git a/android-activity/src/game_activity/input.rs b/android-activity/src/game_activity/input.rs index dd9a19f..ac951be 100644 --- a/android-activity/src/game_activity/input.rs +++ b/android-activity/src/game_activity/input.rs @@ -13,91 +13,19 @@ // The `Class` was also bound differently to `android-ndk-rs` considering how the class is defined // by masking bits from the `Source`. -use crate::game_activity::ffi::{GameActivityKeyEvent, GameActivityMotionEvent}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use std::{convert::TryInto, ops::Deref}; -use bitflags::bitflags; +use crate::game_activity::ffi::{GameActivityKeyEvent, GameActivityMotionEvent}; +use crate::input::{Class, Source}; // Note: try to keep this wrapper API compatible with the AInputEvent API if possible #[derive(Debug, Clone)] #[non_exhaustive] -pub enum InputEvent { - MotionEvent(MotionEvent), - KeyEvent(KeyEvent), -} - -/// 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)] -#[repr(i32)] -pub enum Source { - BluetoothStylus = 0x0000c002, - Dpad = 0x00000201, - /// Either a gamepad or a joystick - Gamepad = 0x00000401, - Hdmi = 0x02000001, - /// Either a gamepad or a joystick - Joystick = 0x01000010, - /// Pretty much any device with buttons. Query the keyboard type to determine - /// if it has alphabetic keys and can be used for text entry. - Keyboard = 0x00000101, - /// A pointing device, such as a mouse or trackpad - Mouse = 0x00002002, - /// A pointing device, such as a mouse or trackpad whose relative motions should be treated as navigation events - MouseRelative = 0x00020004, - /// An input device akin to a scroll wheel - RotaryEncoder = 0x00400000, - Sensor = 0x04000000, - Stylus = 0x00004002, - Touchpad = 0x00100008, - Touchscreen = 0x00001002, - TouchNavigation = 0x00200000, - Trackball = 0x00010004, - - Unknown = 0, -} - -bitflags! { - struct SourceFlags: u32 { - const CLASS_MASK = 0x000000ff; - - const BUTTON = 0x00000001; - const POINTER = 0x00000002; - const TRACKBALL = 0x00000004; - const POSITION = 0x00000008; - const JOYSTICK = 0x00000010; - const NONE = 0; - } -} - -/// 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: i32) -> Self { - let class = SourceFlags::from_bits_truncate(source as u32); - match class { - SourceFlags::BUTTON => Class::Button, - SourceFlags::POINTER => Class::Pointer, - SourceFlags::TRACKBALL => Class::Trackball, - SourceFlags::POSITION => Class::Position, - SourceFlags::JOYSTICK => Class::Joystick, - _ => Class::None, - } - } +pub enum InputEvent<'a> { + MotionEvent(MotionEvent<'a>), + KeyEvent(KeyEvent<'a>), } /// A bitfield representing the state of modifier keys during an event. @@ -182,15 +110,15 @@ impl MetaState { /// For general discussion of motion events in Android, see [the relevant /// javadoc](https://developer.android.com/reference/android/view/MotionEvent). #[derive(Clone, Debug)] -pub struct MotionEvent { - ga_event: GameActivityMotionEvent, +pub struct MotionEvent<'a> { + ga_event: &'a GameActivityMotionEvent, } -impl Deref for MotionEvent { +impl<'a> Deref for MotionEvent<'a> { type Target = GameActivityMotionEvent; fn deref(&self) -> &Self::Target { - &self.ga_event + self.ga_event } } @@ -358,8 +286,8 @@ impl MotionEventFlags { } } -impl MotionEvent { - pub(crate) fn new(ga_event: GameActivityMotionEvent) -> Self { +impl<'a> MotionEvent<'a> { + pub(crate) fn new(ga_event: &'a GameActivityMotionEvent) -> Self { Self { ga_event } } @@ -367,14 +295,15 @@ impl MotionEvent { /// #[inline] pub fn source(&self) -> Source { - self.source.try_into().unwrap_or(Source::Unknown) + let source = self.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) + Class::from(self.source()) } /// Get the device id associated with the event. @@ -569,7 +498,7 @@ impl MotionEvent { /// A view into the data of a specific pointer in a motion event. #[derive(Debug)] pub struct Pointer<'a> { - event: &'a MotionEvent, + event: &'a MotionEvent<'a>, index: usize, } @@ -659,7 +588,7 @@ impl<'a> Pointer<'a> { /// An iterator over the pointers in a [`MotionEvent`]. #[derive(Debug)] pub struct PointersIter<'a> { - event: &'a MotionEvent, + event: &'a MotionEvent<'a>, next_index: usize, count: usize, } @@ -1004,15 +933,15 @@ impl ExactSizeIterator for HistoricalPointersIter<'_> { /// For general discussion of key events in Android, see [the relevant /// javadoc](https://developer.android.com/reference/android/view/KeyEvent). #[derive(Debug, Clone)] -pub struct KeyEvent { - ga_event: GameActivityKeyEvent, +pub struct KeyEvent<'a> { + ga_event: &'a GameActivityKeyEvent, } -impl Deref for KeyEvent { +impl<'a> Deref for KeyEvent<'a> { type Target = GameActivityKeyEvent; fn deref(&self) -> &Self::Target { - &self.ga_event + self.ga_event } } @@ -1324,8 +1253,8 @@ pub enum Keycode { ProfileSwitch = ndk_sys::AKEYCODE_PROFILE_SWITCH, } -impl KeyEvent { - pub(crate) fn new(ga_event: GameActivityKeyEvent) -> Self { +impl<'a> KeyEvent<'a> { + pub(crate) fn new(ga_event: &'a GameActivityKeyEvent) -> Self { Self { ga_event } } @@ -1333,14 +1262,15 @@ impl KeyEvent { /// #[inline] pub fn source(&self) -> Source { - self.source.try_into().unwrap_or(Source::Unknown) + let source = self.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) + Class::from(self.source()) } /// Get the device id associated with the event. @@ -1461,7 +1391,7 @@ impl KeyEventFlags { } } -impl KeyEvent { +impl<'a> KeyEvent<'a> { /// Flags associated with this [`KeyEvent`]. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getflags) diff --git a/android-activity/src/game_activity/mod.rs b/android-activity/src/game_activity/mod.rs index 8aa01e9..0813fa3 100644 --- a/android-activity/src/game_activity/mod.rs +++ b/android-activity/src/game_activity/mod.rs @@ -404,10 +404,12 @@ impl AndroidAppInner { InputBuffer::from_ptr(NonNull::new_unchecked(input_buffer)) }; - for key_event in buf.key_events_iter() { + let mut keys_iter = KeyEventsLendingIterator::new(&buf); + while let Some(key_event) = keys_iter.next() { callback(&InputEvent::KeyEvent(key_event)); } - for motion_event in buf.motion_events_iter() { + let mut motion_iter = MotionEventsLendingIterator::new(&buf); + while let Some(motion_event) = motion_iter.next() { callback(&InputEvent::MotionEvent(motion_event)); } } @@ -434,46 +436,58 @@ impl AndroidAppInner { } } -struct MotionEventsIterator<'a> { +struct MotionEventsLendingIterator<'a> { pos: usize, count: usize, buffer: &'a InputBuffer<'a>, } -impl<'a> Iterator for MotionEventsIterator<'a> { - type Item = MotionEvent; - - fn next(&mut self) -> Option { +// A kind of lending iterator but since our MSRV is 1.60 we can't handle this +// via a generic trait. The iteration of motion events is entirely private +// though so this is ok for now. +impl<'a> MotionEventsLendingIterator<'a> { + fn new(buffer: &'a InputBuffer<'a>) -> Self { + Self { + pos: 0, + count: buffer.motion_events_count(), + buffer, + } + } + fn next(&mut self) -> Option> { if self.pos < self.count { - unsafe { - let ga_event = (*self.buffer.ptr.as_ptr()).motionEvents[self.pos]; - let event = MotionEvent::new(ga_event); - self.pos += 1; - Some(event) - } + let ga_event = unsafe { &(*self.buffer.ptr.as_ptr()).motionEvents[self.pos] }; + let event = MotionEvent::new(ga_event); + self.pos += 1; + Some(event) } else { None } } } -struct KeyEventsIterator<'a> { +struct KeyEventsLendingIterator<'a> { pos: usize, count: usize, buffer: &'a InputBuffer<'a>, } -impl<'a> Iterator for KeyEventsIterator<'a> { - type Item = KeyEvent; - - fn next(&mut self) -> Option { +// A kind of lending iterator but since our MSRV is 1.60 we can't handle this +// via a generic trait. The iteration of key events is entirely private +// though so this is ok for now. +impl<'a> KeyEventsLendingIterator<'a> { + fn new(buffer: &'a InputBuffer<'a>) -> Self { + Self { + pos: 0, + count: buffer.key_events_count(), + buffer, + } + } + fn next(&mut self) -> Option> { if self.pos < self.count { - unsafe { - let ga_event = (*self.buffer.ptr.as_ptr()).keyEvents[self.pos]; - let event = KeyEvent::new(ga_event); - self.pos += 1; - Some(event) - } + let ga_event = unsafe { &(*self.buffer.ptr.as_ptr()).keyEvents[self.pos] }; + let event = KeyEvent::new(ga_event); + self.pos += 1; + Some(event) } else { None } @@ -493,29 +507,12 @@ impl<'a> InputBuffer<'a> { } } - // XXX: It's really not ideal here that Rust iterators can't yield values - // that borrow from the iterator, so we implicitly have to copy the - // events as we iterate... - pub fn motion_events_iter(&self) -> MotionEventsIterator { - unsafe { - let count = (*self.ptr.as_ptr()).motionEventsCount as usize; - MotionEventsIterator { - pos: 0, - count, - buffer: self, - } - } + pub fn motion_events_count(&self) -> usize { + unsafe { (*self.ptr.as_ptr()).motionEventsCount as usize } } - pub fn key_events_iter(&self) -> KeyEventsIterator { - unsafe { - let count = (*self.ptr.as_ptr()).keyEventsCount as usize; - KeyEventsIterator { - pos: 0, - count, - buffer: self, - } - } + pub fn key_events_count(&self) -> usize { + unsafe { (*self.ptr.as_ptr()).keyEventsCount as usize } } } diff --git a/android-activity/src/input.rs b/android-activity/src/input.rs new file mode 100644 index 0000000..3653260 --- /dev/null +++ b/android-activity/src/input.rs @@ -0,0 +1,83 @@ +use bitflags::bitflags; +use num_enum::{IntoPrimitive, TryFromPrimitive}; + +pub use crate::activity_impl::input::*; + +/// 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)] +#[repr(u32)] +pub enum Source { + BluetoothStylus = 0x0000c002, + Dpad = 0x00000201, + /// Either a gamepad or a joystick + Gamepad = 0x00000401, + Hdmi = 0x02000001, + /// Either a gamepad or a joystick + Joystick = 0x01000010, + /// Pretty much any device with buttons. Query the keyboard type to determine + /// if it has alphabetic keys and can be used for text entry. + Keyboard = 0x00000101, + /// A pointing device, such as a mouse or trackpad + Mouse = 0x00002002, + /// A pointing device, such as a mouse or trackpad whose relative motions should be treated as navigation events + MouseRelative = 0x00020004, + /// An input device akin to a scroll wheel + RotaryEncoder = 0x00400000, + Sensor = 0x04000000, + Stylus = 0x00004002, + Touchpad = 0x00100008, + Touchscreen = 0x00001002, + TouchNavigation = 0x00200000, + Trackball = 0x00010004, + + Unknown = 0, +} + +bitflags! { + struct SourceFlags: u32 { + const CLASS_MASK = 0x000000ff; + + const BUTTON = 0x00000001; + const POINTER = 0x00000002; + const TRACKBALL = 0x00000004; + const POSITION = 0x00000008; + const JOYSTICK = 0x00000010; + const NONE = 0; + } +} + +/// 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 as u32); + 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 From for Class { + fn from(source: Source) -> Self { + let source: u32 = source.into(); + source.into() + } +} diff --git a/android-activity/src/lib.rs b/android-activity/src/lib.rs index a3da060..134444d 100644 --- a/android-activity/src/lib.rs +++ b/android-activity/src/lib.rs @@ -106,7 +106,7 @@ mod game_activity; #[cfg(feature = "game-activity")] use game_activity as activity_impl; -pub use activity_impl::input; +pub mod input; mod config; pub use config::ConfigurationRef; diff --git a/android-activity/src/native_activity/input.rs b/android-activity/src/native_activity/input.rs new file mode 100644 index 0000000..17e8f4b --- /dev/null +++ b/android-activity/src/native_activity/input.rs @@ -0,0 +1,340 @@ +use std::marker::PhantomData; + +pub use ndk::event::{ + Axis, ButtonState, EdgeFlags, KeyAction, KeyEventFlags, Keycode, MetaState, MotionAction, + MotionEventFlags, Pointer, PointersIter, +}; + +use crate::input::{Class, Source}; + +/// A motion event +/// +/// For general discussion of motion events in Android, see [the relevant +/// javadoc](https://developer.android.com/reference/android/view/MotionEvent). +#[derive(Debug)] +#[repr(transparent)] +pub struct MotionEvent<'a> { + ndk_event: ndk::event::MotionEvent, + _lifetime: PhantomData<&'a ndk::event::MotionEvent>, +} +impl<'a> MotionEvent<'a> { + pub(crate) fn new(ndk_event: ndk::event::MotionEvent) -> Self { + Self { + ndk_event, + _lifetime: PhantomData, + } + } + pub(crate) fn into_ndk_event(self) -> ndk::event::MotionEvent { + self.ndk_event + } + + /// Get the source of the event. + /// + #[inline] + 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. + 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()) + } + + /// Get the device id associated with the event. + /// + #[inline] + pub fn device_id(&self) -> i32 { + self.ndk_event.device_id() + } + + /// Returns the motion action associated with the event. + /// + /// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getActionMasked()) + #[inline] + pub fn action(&self) -> MotionAction { + self.ndk_event.action() + } + + /// Returns the pointer index of an `Up` or `Down` event. + /// + /// Pointer indices can change per motion event. For an identifier that stays the same, see + /// [`Pointer::pointer_id()`]. + /// + /// This only has a meaning when the [action](Self::action) is one of [`Up`](MotionAction::Up), + /// [`Down`](MotionAction::Down), [`PointerUp`](MotionAction::PointerUp), + /// or [`PointerDown`](MotionAction::PointerDown). + #[inline] + pub fn pointer_index(&self) -> usize { + self.ndk_event.pointer_index() + } + + /* + /// Returns the pointer id associated with the given pointer index. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getpointerid) + // TODO: look at output with out-of-range pointer index + // Probably -1 though + pub fn pointer_id_for(&self, pointer_index: usize) -> i32 { + unsafe { ndk_sys::AMotionEvent_getPointerId(self.ndk_event.ptr.as_ptr(), pointer_index) } + } + */ + + /// Returns the number of pointers in this event + /// + /// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getPointerCount()) + #[inline] + pub fn pointer_count(&self) -> usize { + self.ndk_event.pointer_count() + } + + /// An iterator over the pointers in this motion event + #[inline] + pub fn pointers(&self) -> PointersIter<'_> { + self.ndk_event.pointers() + } + + /// The pointer at a given pointer index. Panics if the pointer index is out of bounds. + /// + /// If you need to loop over all the pointers, prefer the [`pointers()`](Self::pointers) method. + #[inline] + pub fn pointer_at_index(&self, index: usize) -> Pointer<'_> { + self.ndk_event.pointer_at_index(index) + } + + /* + XXX: Not currently supported with GameActivity so we don't currently expose for NativeActivity + either, for consistency. + + /// Returns the size of the history contained in this event. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_gethistorysize) + #[inline] + pub fn history_size(&self) -> usize { + self.ndk_event.history_size() + } + + /// An iterator over the historical events contained in this event. + #[inline] + pub fn history(&self) -> HistoricalMotionEventsIter<'_> { + self.ndk_event.history() + } + */ + + /// Returns the state of any modifier keys that were pressed during the event. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getmetastate) + #[inline] + pub fn meta_state(&self) -> MetaState { + self.ndk_event.meta_state() + } + + /// Returns the button state during this event, as a bitfield. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getbuttonstate) + #[inline] + pub fn button_state(&self) -> ButtonState { + self.ndk_event.button_state() + } + + /// Returns the time of the start of this gesture, in the `java.lang.System.nanoTime()` time + /// base + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getdowntime) + #[inline] + pub fn down_time(&self) -> i64 { + self.ndk_event.down_time() + } + + /// Returns a bitfield indicating which edges were touched by this event. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getedgeflags) + #[inline] + pub fn edge_flags(&self) -> EdgeFlags { + self.ndk_event.edge_flags() + } + + /// Returns the time of this event, in the `java.lang.System.nanoTime()` time base + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_geteventtime) + #[inline] + pub fn event_time(&self) -> i64 { + self.ndk_event.event_time() + } + + /// The flags associated with a motion event. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getflags) + #[inline] + pub fn flags(&self) -> MotionEventFlags { + self.ndk_event.flags() + } + + /* Missing from GameActivity currently... + /// Returns the offset in the x direction between the coordinates and the raw coordinates + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getxoffset) + #[inline] + pub fn x_offset(&self) -> f32 { + self.ndk_event.x_offset() + } + + /// Returns the offset in the y direction between the coordinates and the raw coordinates + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getyoffset) + #[inline] + pub fn y_offset(&self) -> f32 { + self.ndk_event.y_offset() + } + */ + + /// Returns the precision of the x value of the coordinates + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getxprecision) + #[inline] + pub fn x_precision(&self) -> f32 { + self.ndk_event.x_precision() + } + + /// Returns the precision of the y value of the coordinates + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getyprecision) + #[inline] + pub fn y_precision(&self) -> f32 { + self.ndk_event.y_precision() + } +} + +/// A key event +/// +/// For general discussion of key events in Android, see [the relevant +/// javadoc](https://developer.android.com/reference/android/view/KeyEvent). +#[derive(Debug)] +#[repr(transparent)] +pub struct KeyEvent<'a> { + ndk_event: ndk::event::KeyEvent, + _lifetime: PhantomData<&'a ndk::event::KeyEvent>, +} +impl<'a> KeyEvent<'a> { + pub(crate) fn new(ndk_event: ndk::event::KeyEvent) -> Self { + Self { + ndk_event, + _lifetime: PhantomData, + } + } + pub(crate) fn into_ndk_event(self) -> ndk::event::KeyEvent { + self.ndk_event + } + + /// Get the source of the event. + /// + #[inline] + 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. + 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()) + } + + /// Get the device id associated with the event. + /// + #[inline] + pub fn device_id(&self) -> i32 { + self.ndk_event.device_id() + } + + /// Returns the key action associated with the event. + /// + /// See [the KeyEvent docs](https://developer.android.com/reference/android/view/KeyEvent#getAction()) + #[inline] + pub fn action(&self) -> KeyAction { + self.ndk_event.action() + } + + /// Returns the last time the key was pressed. This is on the scale of + /// `java.lang.System.nanoTime()`, which has nanosecond precision, but no defined start time. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getdowntime) + #[inline] + pub fn down_time(&self) -> i64 { + self.ndk_event.down_time() + } + + /// Returns the time this event occured. This is on the scale of + /// `java.lang.System.nanoTime()`, which has nanosecond precision, but no defined start time. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_geteventtime) + #[inline] + pub fn event_time(&self) -> i64 { + self.ndk_event.event_time() + } + + /// Returns the keycode associated with this key event + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getkeycode) + #[inline] + pub fn key_code(&self) -> Keycode { + self.ndk_event.key_code() + } + + /// Returns the number of repeats of a key. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getrepeatcount) + #[inline] + pub fn repeat_count(&self) -> i32 { + self.ndk_event.repeat_count() + } + + /// Returns the hardware keycode of a key. This varies from device to device. + /// + /// See [the NDK + /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getscancode) + #[inline] + pub fn scan_code(&self) -> i32 { + self.ndk_event.scan_code() + } +} + +// We use our own wrapper type for input events to have better consistency +// with GameActivity and ensure the enum can be extended without needing a +// semver bump +/// Enum of possible input events +#[derive(Debug)] +#[non_exhaustive] +pub enum InputEvent<'a> { + MotionEvent(self::MotionEvent<'a>), + KeyEvent(self::KeyEvent<'a>), +} diff --git a/android-activity/src/native_activity/mod.rs b/android-activity/src/native_activity/mod.rs index a276476..c52d81a 100644 --- a/android-activity/src/native_activity/mod.rs +++ b/android-activity/src/native_activity/mod.rs @@ -17,26 +17,10 @@ use crate::{ util, AndroidApp, ConfigurationRef, InputStatus, MainEvent, PollEvent, Rect, WindowManagerFlags, }; -use self::glue::NativeActivityGlue; - -pub mod input { - pub use ndk::event::{ - Axis, ButtonState, EdgeFlags, KeyAction, KeyEvent, KeyEventFlags, Keycode, MetaState, - MotionAction, MotionEvent, MotionEventFlags, Pointer, Source, - }; - - // We use our own wrapper type for input events to have better consistency - // with GameActivity and ensure the enum can be extended without needing a - // semver bump - #[derive(Debug)] - #[non_exhaustive] - pub enum InputEvent { - MotionEvent(self::MotionEvent), - KeyEvent(self::KeyEvent), - } -} +pub mod input; mod glue; +use self::glue::NativeActivityGlue; pub const LOOPER_ID_MAIN: libc::c_int = 1; pub const LOOPER_ID_INPUT: libc::c_int = 2; @@ -385,14 +369,22 @@ impl AndroidAppInner { while let Ok(Some(event)) = queue.get_event() { if let Some(ndk_event) = queue.pre_dispatch(event) { let event = match ndk_event { - ndk::event::InputEvent::MotionEvent(e) => input::InputEvent::MotionEvent(e), - ndk::event::InputEvent::KeyEvent(e) => input::InputEvent::KeyEvent(e), + ndk::event::InputEvent::MotionEvent(e) => { + input::InputEvent::MotionEvent(input::MotionEvent::new(e)) + } + ndk::event::InputEvent::KeyEvent(e) => { + input::InputEvent::KeyEvent(input::KeyEvent::new(e)) + } }; let handled = callback(&event); let ndk_event = match event { - input::InputEvent::MotionEvent(e) => ndk::event::InputEvent::MotionEvent(e), - input::InputEvent::KeyEvent(e) => ndk::event::InputEvent::KeyEvent(e), + input::InputEvent::MotionEvent(e) => { + ndk::event::InputEvent::MotionEvent(e.into_ndk_event()) + } + input::InputEvent::KeyEvent(e) => { + ndk::event::InputEvent::KeyEvent(e.into_ndk_event()) + } }; queue.finish_event(ndk_event, matches!(handled, InputStatus::Handled)); }