//! Bindings for [`AInputEvent`, `AKeyEvent` and `AMotionEvent`] //! //! Most of these operations directly wrap functions in the NDK. //! //! See also the Java docs for [`android.view.InputEvent`], [`android.view.MotionEvent`], and //! [`android.view.KeyEvent`]. //! //! [`AInputEvent`, `AKeyEvent` and `AMotionEvent`]: https://developer.android.com/ndk/reference/group/input //! [`android.view.InputEvent`]: https://developer.android.com/reference/android/view/InputEvent.html //! [`android.view.MotionEvent`]: https://developer.android.com/reference/android/view/MotionEvent.html //! [`android.view.KeyEvent`]: https://developer.android.com/reference/android/view/KeyEvent use num_enum::{IntoPrimitive, TryFromPrimitive}; use std::ptr::NonNull; /// A native [`AInputEvent *`] /// /// [`AInputEvent *`]: https://developer.android.com/ndk/reference/group/input#ainputevent #[derive(Debug)] pub enum InputEvent { MotionEvent(MotionEvent), KeyEvent(KeyEvent), } /// An enum representing the source of an [`InputEvent`]. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-36) #[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[repr(u32)] pub enum Source { Unknown = ffi::AINPUT_SOURCE_UNKNOWN, Keyboard = ffi::AINPUT_SOURCE_KEYBOARD, Dpad = ffi::AINPUT_SOURCE_DPAD, Gamepad = ffi::AINPUT_SOURCE_GAMEPAD, Touchscreen = ffi::AINPUT_SOURCE_TOUCHSCREEN, Mouse = ffi::AINPUT_SOURCE_MOUSE, Stylus = ffi::AINPUT_SOURCE_STYLUS, BluetoothStylus = ffi::AINPUT_SOURCE_BLUETOOTH_STYLUS, Trackball = ffi::AINPUT_SOURCE_TRACKBALL, MouseRelative = ffi::AINPUT_SOURCE_MOUSE_RELATIVE, Touchpad = ffi::AINPUT_SOURCE_TOUCHPAD, TouchNavigation = ffi::AINPUT_SOURCE_TOUCH_NAVIGATION, Joystick = ffi::AINPUT_SOURCE_JOYSTICK, Hdmi = ffi::AINPUT_SOURCE_HDMI, Sensor = ffi::AINPUT_SOURCE_SENSOR, RotaryEncoder = ffi::AINPUT_SOURCE_ROTARY_ENCODER, Any = ffi::AINPUT_SOURCE_ANY, } /// An enum representing the class of an [`InputEvent`] source. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-35) #[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[repr(u32)] enum Class { None = ffi::AINPUT_SOURCE_CLASS_NONE, Button = ffi::AINPUT_SOURCE_CLASS_BUTTON, Pointer = ffi::AINPUT_SOURCE_CLASS_POINTER, Navigation = ffi::AINPUT_SOURCE_CLASS_NAVIGATION, Position = ffi::AINPUT_SOURCE_CLASS_POSITION, Joystick = ffi::AINPUT_SOURCE_CLASS_JOYSTICK, } impl InputEvent { /// Initialize an [`InputEvent`] from a pointer /// /// # Safety /// By calling this function, you assert that the pointer is a valid pointer to a /// native [`ffi::AInputEvent`]. #[inline] pub unsafe fn from_ptr(ptr: NonNull) -> Self { match ffi::AInputEvent_getType(ptr.as_ptr()) as u32 { ffi::AINPUT_EVENT_TYPE_KEY => InputEvent::KeyEvent(KeyEvent::from_ptr(ptr)), ffi::AINPUT_EVENT_TYPE_MOTION => InputEvent::MotionEvent(MotionEvent::from_ptr(ptr)), x => panic!("Bad event type received: {}", x), } } /// Returns a pointer to the native [`ffi::AInputEvent`]. #[inline] pub fn ptr(&self) -> NonNull { match self { InputEvent::MotionEvent(MotionEvent { ptr }) => *ptr, InputEvent::KeyEvent(KeyEvent { ptr }) => *ptr, } } /// Get the source of the event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#ainputevent_getsource) #[inline] pub fn source(&self) -> Source { let source = unsafe { ffi::AInputEvent_getSource(self.ptr().as_ptr()) as u32 }; source.try_into().unwrap_or(Source::Unknown) } /// Get the device id associated with the event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#ainputevent_getdeviceid) #[inline] pub fn device_id(&self) -> i32 { unsafe { ffi::AInputEvent_getDeviceId(self.ptr().as_ptr()) } } } /// A bitfield representing the state of modifier keys during an event. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-25) #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct MetaState(pub u32); impl MetaState { #[inline] pub fn alt_on(self) -> bool { self.0 & ffi::AMETA_ALT_ON != 0 } #[inline] pub fn alt_left_on(self) -> bool { self.0 & ffi::AMETA_ALT_LEFT_ON != 0 } #[inline] pub fn alt_right_on(self) -> bool { self.0 & ffi::AMETA_ALT_RIGHT_ON != 0 } #[inline] pub fn shift_on(self) -> bool { self.0 & ffi::AMETA_SHIFT_ON != 0 } #[inline] pub fn shift_left_on(self) -> bool { self.0 & ffi::AMETA_SHIFT_LEFT_ON != 0 } #[inline] pub fn shift_right_on(self) -> bool { self.0 & ffi::AMETA_SHIFT_RIGHT_ON != 0 } #[inline] pub fn sym_on(self) -> bool { self.0 & ffi::AMETA_SYM_ON != 0 } #[inline] pub fn function_on(self) -> bool { self.0 & ffi::AMETA_FUNCTION_ON != 0 } #[inline] pub fn ctrl_on(self) -> bool { self.0 & ffi::AMETA_CTRL_ON != 0 } #[inline] pub fn ctrl_left_on(self) -> bool { self.0 & ffi::AMETA_CTRL_LEFT_ON != 0 } #[inline] pub fn ctrl_right_on(self) -> bool { self.0 & ffi::AMETA_CTRL_RIGHT_ON != 0 } #[inline] pub fn meta_on(self) -> bool { self.0 & ffi::AMETA_META_ON != 0 } #[inline] pub fn meta_left_on(self) -> bool { self.0 & ffi::AMETA_META_LEFT_ON != 0 } #[inline] pub fn meta_right_on(self) -> bool { self.0 & ffi::AMETA_META_RIGHT_ON != 0 } #[inline] pub fn caps_lock_on(self) -> bool { self.0 & ffi::AMETA_CAPS_LOCK_ON != 0 } #[inline] pub fn num_lock_on(self) -> bool { self.0 & ffi::AMETA_NUM_LOCK_ON != 0 } #[inline] pub fn scroll_lock_on(self) -> bool { self.0 & ffi::AMETA_SCROLL_LOCK_ON != 0 } } /// A motion event /// /// Wraps an [`AInputEvent *`] of the [`ffi::AINPUT_EVENT_TYPE_MOTION`] type. /// /// For general discussion of motion events in Android, see [the relevant /// javadoc](https://developer.android.com/reference/android/view/MotionEvent). /// /// [`AInputEvent *`]: https://developer.android.com/ndk/reference/group/input#ainputevent #[derive(Clone, Debug)] pub struct MotionEvent { ptr: NonNull, } // TODO: thread safety? /// A motion action. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-29) #[derive(Copy, Clone, Debug, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)] #[repr(u32)] pub enum MotionAction { Down = ffi::AMOTION_EVENT_ACTION_DOWN, Up = ffi::AMOTION_EVENT_ACTION_UP, Move = ffi::AMOTION_EVENT_ACTION_MOVE, Cancel = ffi::AMOTION_EVENT_ACTION_CANCEL, Outside = ffi::AMOTION_EVENT_ACTION_OUTSIDE, PointerDown = ffi::AMOTION_EVENT_ACTION_POINTER_DOWN, PointerUp = ffi::AMOTION_EVENT_ACTION_POINTER_UP, HoverMove = ffi::AMOTION_EVENT_ACTION_HOVER_MOVE, Scroll = ffi::AMOTION_EVENT_ACTION_SCROLL, HoverEnter = ffi::AMOTION_EVENT_ACTION_HOVER_ENTER, HoverExit = ffi::AMOTION_EVENT_ACTION_HOVER_EXIT, ButtonPress = ffi::AMOTION_EVENT_ACTION_BUTTON_PRESS, ButtonRelease = ffi::AMOTION_EVENT_ACTION_BUTTON_RELEASE, } /// 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)] #[repr(u32)] pub enum Axis { X = ffi::AMOTION_EVENT_AXIS_X, Y = ffi::AMOTION_EVENT_AXIS_Y, Pressure = ffi::AMOTION_EVENT_AXIS_PRESSURE, Size = ffi::AMOTION_EVENT_AXIS_SIZE, TouchMajor = ffi::AMOTION_EVENT_AXIS_TOUCH_MAJOR, TouchMinor = ffi::AMOTION_EVENT_AXIS_TOUCH_MINOR, ToolMajor = ffi::AMOTION_EVENT_AXIS_TOOL_MAJOR, ToolMinor = ffi::AMOTION_EVENT_AXIS_TOOL_MINOR, Orientation = ffi::AMOTION_EVENT_AXIS_ORIENTATION, Vscroll = ffi::AMOTION_EVENT_AXIS_VSCROLL, Hscroll = ffi::AMOTION_EVENT_AXIS_HSCROLL, Z = ffi::AMOTION_EVENT_AXIS_Z, Rx = ffi::AMOTION_EVENT_AXIS_RX, Ry = ffi::AMOTION_EVENT_AXIS_RY, Rz = ffi::AMOTION_EVENT_AXIS_RZ, HatX = ffi::AMOTION_EVENT_AXIS_HAT_X, HatY = ffi::AMOTION_EVENT_AXIS_HAT_Y, Ltrigger = ffi::AMOTION_EVENT_AXIS_LTRIGGER, Rtrigger = ffi::AMOTION_EVENT_AXIS_RTRIGGER, Throttle = ffi::AMOTION_EVENT_AXIS_THROTTLE, Rudder = ffi::AMOTION_EVENT_AXIS_RUDDER, Wheel = ffi::AMOTION_EVENT_AXIS_WHEEL, Gas = ffi::AMOTION_EVENT_AXIS_GAS, Brake = ffi::AMOTION_EVENT_AXIS_BRAKE, Distance = ffi::AMOTION_EVENT_AXIS_DISTANCE, Tilt = ffi::AMOTION_EVENT_AXIS_TILT, Scroll = ffi::AMOTION_EVENT_AXIS_SCROLL, RelativeX = ffi::AMOTION_EVENT_AXIS_RELATIVE_X, RelativeY = ffi::AMOTION_EVENT_AXIS_RELATIVE_Y, Generic1 = ffi::AMOTION_EVENT_AXIS_GENERIC_1, Generic2 = ffi::AMOTION_EVENT_AXIS_GENERIC_2, Generic3 = ffi::AMOTION_EVENT_AXIS_GENERIC_3, Generic4 = ffi::AMOTION_EVENT_AXIS_GENERIC_4, Generic5 = ffi::AMOTION_EVENT_AXIS_GENERIC_5, Generic6 = ffi::AMOTION_EVENT_AXIS_GENERIC_6, Generic7 = ffi::AMOTION_EVENT_AXIS_GENERIC_7, Generic8 = ffi::AMOTION_EVENT_AXIS_GENERIC_8, Generic9 = ffi::AMOTION_EVENT_AXIS_GENERIC_9, Generic10 = ffi::AMOTION_EVENT_AXIS_GENERIC_10, Generic11 = ffi::AMOTION_EVENT_AXIS_GENERIC_11, Generic12 = ffi::AMOTION_EVENT_AXIS_GENERIC_12, Generic13 = ffi::AMOTION_EVENT_AXIS_GENERIC_13, Generic14 = ffi::AMOTION_EVENT_AXIS_GENERIC_14, Generic15 = ffi::AMOTION_EVENT_AXIS_GENERIC_15, Generic16 = ffi::AMOTION_EVENT_AXIS_GENERIC_16, } /// 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)] #[repr(u32)] pub enum ToolType { Unknown = ffi::AMOTION_EVENT_TOOL_TYPE_UNKNOWN, Finger = ffi::AMOTION_EVENT_TOOL_TYPE_FINGER, Stylus = ffi::AMOTION_EVENT_TOOL_TYPE_STYLUS, Mouse = ffi::AMOTION_EVENT_TOOL_TYPE_MOUSE, Eraser = ffi::AMOTION_EVENT_TOOL_TYPE_ERASER, Palm = ffi::AMOTION_EVENT_TOOL_TYPE_PALM, } /// A bitfield representing the state of buttons during a motion event. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-33) #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct ButtonState(pub u32); impl ButtonState { #[inline] pub fn primary(self) -> bool { self.0 & ffi::AMOTION_EVENT_BUTTON_PRIMARY != 0 } #[inline] pub fn secondary(self) -> bool { self.0 & ffi::AMOTION_EVENT_BUTTON_SECONDARY != 0 } #[inline] pub fn teriary(self) -> bool { self.0 & ffi::AMOTION_EVENT_BUTTON_TERTIARY != 0 } #[inline] pub fn back(self) -> bool { self.0 & ffi::AMOTION_EVENT_BUTTON_BACK != 0 } #[inline] pub fn forward(self) -> bool { self.0 & ffi::AMOTION_EVENT_BUTTON_FORWARD != 0 } #[inline] pub fn stylus_primary(self) -> bool { self.0 & ffi::AMOTION_EVENT_BUTTON_STYLUS_PRIMARY != 0 } #[inline] pub fn stylus_secondary(self) -> bool { self.0 & ffi::AMOTION_EVENT_BUTTON_STYLUS_SECONDARY != 0 } } /// A bitfield representing which edges were touched by a motion event. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-31) #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct EdgeFlags(pub u32); impl EdgeFlags { #[inline] pub fn top(self) -> bool { self.0 & ffi::AMOTION_EVENT_EDGE_FLAG_TOP != 0 } #[inline] pub fn bottom(self) -> bool { self.0 & ffi::AMOTION_EVENT_EDGE_FLAG_BOTTOM != 0 } #[inline] pub fn left(self) -> bool { self.0 & ffi::AMOTION_EVENT_EDGE_FLAG_LEFT != 0 } #[inline] pub fn right(self) -> bool { self.0 & ffi::AMOTION_EVENT_EDGE_FLAG_RIGHT != 0 } } /// Flags associated with this [`MotionEvent`]. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-30) #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct MotionEventFlags(pub u32); impl MotionEventFlags { #[inline] pub fn window_is_obscured(self) -> bool { self.0 & ffi::AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED != 0 } } impl MotionEvent { /// Constructs a MotionEvent from a pointer to a native [`ffi::AInputEvent`] /// /// # Safety /// By calling this method, you assert that the pointer is a valid, non-null pointer to a /// native [`ffi::AInputEvent`] and that [`ffi::AInputEvent`] /// is an `AMotionEvent`. #[inline] pub unsafe fn from_ptr(ptr: NonNull) -> Self { Self { ptr } } /// Returns a pointer to the native [`ffi::AInputEvent`] #[inline] pub fn ptr(&self) -> NonNull { self.ptr } /// Get the source of the event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#ainputevent_getsource) #[inline] pub fn source(&self) -> Source { let source = unsafe { ffi::AInputEvent_getSource(self.ptr.as_ptr()) as u32 }; source.try_into().unwrap_or(Source::Unknown) } /// Get the device id associated with the event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#ainputevent_getdeviceid) #[inline] pub fn device_id(&self) -> i32 { unsafe { ffi::AInputEvent_getDeviceId(self.ptr.as_ptr()) } } /// Returns the motion action associated with the event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getaction) #[inline] pub fn action(&self) -> MotionAction { let action = unsafe { ffi::AMotionEvent_getAction(self.ptr.as_ptr()) as u32 & ffi::AMOTION_EVENT_ACTION_MASK }; action.try_into().unwrap() } /// 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 { let action = unsafe { ffi::AMotionEvent_getAction(self.ptr.as_ptr()) as u32 }; let index = (action & ffi::AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> ffi::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; index as usize } /* /// 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 { ffi::AMotionEvent_getPointerId(self.ptr.as_ptr(), pointer_index) } } */ /// Returns the number of pointers in this event /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getpointercount) #[inline] pub fn pointer_count(&self) -> usize { unsafe { ffi::AMotionEvent_getPointerCount(self.ptr.as_ptr()) } } /// An iterator over the pointers in this motion event #[inline] pub fn pointers(&self) -> PointersIter<'_> { PointersIter { event: self.ptr, next_index: 0, count: self.pointer_count(), _marker: std::marker::PhantomData, } } /// 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<'_> { if index >= self.pointer_count() { panic!("Pointer index {} is out of bounds", index); } Pointer { event: self.ptr, index, _marker: std::marker::PhantomData, } } /// 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 { unsafe { ffi::AMotionEvent_getHistorySize(self.ptr.as_ptr()) } } /// An iterator over the historical events contained in this event. #[inline] pub fn history(&self) -> HistoricalMotionEventsIter<'_> { HistoricalMotionEventsIter { event: self.ptr, next_history_index: 0, history_size: self.history_size(), _marker: std::marker::PhantomData, } } /// 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 { unsafe { MetaState(ffi::AMotionEvent_getMetaState(self.ptr.as_ptr()) as u32) } } /// 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 { unsafe { ButtonState(ffi::AMotionEvent_getButtonState(self.ptr.as_ptr()) as u32) } } /// 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 { unsafe { ffi::AMotionEvent_getDownTime(self.ptr.as_ptr()) } } /// 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 { unsafe { EdgeFlags(ffi::AMotionEvent_getEdgeFlags(self.ptr.as_ptr()) as u32) } } /// 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 { unsafe { ffi::AMotionEvent_getEventTime(self.ptr.as_ptr()) } } /// 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 { unsafe { MotionEventFlags(ffi::AMotionEvent_getFlags(self.ptr.as_ptr()) as u32) } } /// 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 { unsafe { ffi::AMotionEvent_getXOffset(self.ptr.as_ptr()) } } /// 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 { unsafe { ffi::AMotionEvent_getYOffset(self.ptr.as_ptr()) } } /// 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 { unsafe { ffi::AMotionEvent_getXPrecision(self.ptr.as_ptr()) } } /// 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 { unsafe { ffi::AMotionEvent_getYPrecision(self.ptr.as_ptr()) } } } /// A view into the data of a specific pointer in a motion event. #[derive(Debug)] pub struct Pointer<'a> { event: NonNull, index: usize, _marker: std::marker::PhantomData<&'a MotionEvent>, } // TODO: thread safety? impl<'a> Pointer<'a> { #[inline] pub fn pointer_index(&self) -> usize { self.index } #[inline] pub fn pointer_id(&self) -> i32 { unsafe { ffi::AMotionEvent_getPointerId(self.event.as_ptr(), self.index) } } #[inline] pub fn axis_value(&self, axis: Axis) -> f32 { unsafe { ffi::AMotionEvent_getAxisValue(self.event.as_ptr(), axis as i32, self.index) } } #[inline] pub fn orientation(&self) -> f32 { unsafe { ffi::AMotionEvent_getOrientation(self.event.as_ptr(), self.index) } } #[inline] pub fn pressure(&self) -> f32 { unsafe { ffi::AMotionEvent_getPressure(self.event.as_ptr(), self.index) } } #[inline] pub fn raw_x(&self) -> f32 { unsafe { ffi::AMotionEvent_getRawX(self.event.as_ptr(), self.index) } } #[inline] pub fn raw_y(&self) -> f32 { unsafe { ffi::AMotionEvent_getRawY(self.event.as_ptr(), self.index) } } #[inline] pub fn x(&self) -> f32 { unsafe { ffi::AMotionEvent_getX(self.event.as_ptr(), self.index) } } #[inline] pub fn y(&self) -> f32 { unsafe { ffi::AMotionEvent_getY(self.event.as_ptr(), self.index) } } #[inline] pub fn size(&self) -> f32 { unsafe { ffi::AMotionEvent_getSize(self.event.as_ptr(), self.index) } } #[inline] pub fn tool_major(&self) -> f32 { unsafe { ffi::AMotionEvent_getToolMajor(self.event.as_ptr(), self.index) } } #[inline] pub fn tool_minor(&self) -> f32 { unsafe { ffi::AMotionEvent_getToolMinor(self.event.as_ptr(), self.index) } } #[inline] pub fn touch_major(&self) -> f32 { unsafe { ffi::AMotionEvent_getTouchMajor(self.event.as_ptr(), self.index) } } #[inline] pub fn touch_minor(&self) -> f32 { unsafe { ffi::AMotionEvent_getTouchMinor(self.event.as_ptr(), self.index) } } #[inline] pub fn tool_type(&self) -> ToolType { let tool_type = unsafe { ffi::AMotionEvent_getToolType(self.event.as_ptr(), self.index) as u32 }; tool_type.try_into().unwrap() } } /// An iterator over the pointers in a [`MotionEvent`]. #[derive(Debug)] pub struct PointersIter<'a> { event: NonNull, next_index: usize, count: usize, _marker: std::marker::PhantomData<&'a MotionEvent>, } // TODO: thread safety? impl<'a> Iterator for PointersIter<'a> { type Item = Pointer<'a>; fn next(&mut self) -> Option> { if self.next_index < self.count { let ptr = Pointer { event: self.event, index: self.next_index, _marker: std::marker::PhantomData, }; self.next_index += 1; Some(ptr) } else { None } } fn size_hint(&self) -> (usize, Option) { let size = self.count - self.next_index; (size, Some(size)) } } impl<'a> ExactSizeIterator for PointersIter<'a> { fn len(&self) -> usize { self.count - self.next_index } } /// Represents a view into a past moment of a motion event #[derive(Debug)] pub struct HistoricalMotionEvent<'a> { event: NonNull, history_index: usize, _marker: std::marker::PhantomData<&'a MotionEvent>, } // TODO: thread safety? impl<'a> HistoricalMotionEvent<'a> { /// Returns the "history index" associated with this historical event. Older events have smaller indices. #[inline] pub fn history_index(&self) -> usize { self.history_index } /// Returns the time of the historical event, in the `java.lang.System.nanoTime()` time base /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_gethistoricaleventtime) #[inline] pub fn event_time(&self) -> i64 { unsafe { ffi::AMotionEvent_getHistoricalEventTime(self.event.as_ptr(), self.history_index) } } /// An iterator over the pointers of this historical motion event #[inline] pub fn pointers(&self) -> HistoricalPointersIter<'a> { HistoricalPointersIter { event: self.event, history_index: self.history_index, next_pointer_index: 0, pointer_count: unsafe { ffi::AMotionEvent_getPointerCount(self.event.as_ptr()) }, _marker: std::marker::PhantomData, } } } /// An iterator over all the historical moments in a [`MotionEvent`]. /// /// It iterates from oldest to newest. #[derive(Debug)] pub struct HistoricalMotionEventsIter<'a> { event: NonNull, next_history_index: usize, history_size: usize, _marker: std::marker::PhantomData<&'a MotionEvent>, } // TODO: thread safety? impl<'a> Iterator for HistoricalMotionEventsIter<'a> { type Item = HistoricalMotionEvent<'a>; fn next(&mut self) -> Option> { if self.next_history_index < self.history_size { let res = HistoricalMotionEvent { event: self.event, history_index: self.next_history_index, _marker: std::marker::PhantomData, }; self.next_history_index += 1; Some(res) } else { None } } fn size_hint(&self) -> (usize, Option) { let size = self.history_size - self.next_history_index; (size, Some(size)) } } impl ExactSizeIterator for HistoricalMotionEventsIter<'_> { fn len(&self) -> usize { self.history_size - self.next_history_index } } impl<'a> DoubleEndedIterator for HistoricalMotionEventsIter<'a> { fn next_back(&mut self) -> Option> { if self.next_history_index < self.history_size { self.history_size -= 1; Some(HistoricalMotionEvent { event: self.event, history_index: self.history_size, _marker: std::marker::PhantomData, }) } else { None } } } /// A view into a pointer at a historical moment #[derive(Debug)] pub struct HistoricalPointer<'a> { event: NonNull, pointer_index: usize, history_index: usize, _marker: std::marker::PhantomData<&'a MotionEvent>, } // TODO: thread safety? impl<'a> HistoricalPointer<'a> { #[inline] pub fn pointer_index(&self) -> usize { self.pointer_index } #[inline] pub fn pointer_id(&self) -> i32 { unsafe { ffi::AMotionEvent_getPointerId(self.event.as_ptr(), self.pointer_index) } } #[inline] pub fn history_index(&self) -> usize { self.history_index } #[inline] pub fn axis_value(&self, axis: Axis) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalAxisValue( self.event.as_ptr(), axis as i32, self.pointer_index, self.history_index, ) } } #[inline] pub fn orientation(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalOrientation( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn pressure(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalPressure( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn raw_x(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalRawX( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn raw_y(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalRawY( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn x(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalX( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn y(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalY( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn size(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalSize( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn tool_major(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalToolMajor( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn tool_minor(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalToolMinor( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn touch_major(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalTouchMajor( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } #[inline] pub fn touch_minor(&self) -> f32 { unsafe { ffi::AMotionEvent_getHistoricalTouchMinor( self.event.as_ptr(), self.pointer_index, self.history_index, ) } } } /// An iterator over the pointers in a historical motion event #[derive(Debug)] pub struct HistoricalPointersIter<'a> { event: NonNull, history_index: usize, next_pointer_index: usize, pointer_count: usize, _marker: std::marker::PhantomData<&'a MotionEvent>, } // TODO: thread safety? impl<'a> Iterator for HistoricalPointersIter<'a> { type Item = HistoricalPointer<'a>; fn next(&mut self) -> Option> { if self.next_pointer_index < self.pointer_count { let ptr = HistoricalPointer { event: self.event, history_index: self.history_index, pointer_index: self.next_pointer_index, _marker: std::marker::PhantomData, }; self.next_pointer_index += 1; Some(ptr) } else { None } } fn size_hint(&self) -> (usize, Option) { let size = self.pointer_count - self.next_pointer_index; (size, Some(size)) } } impl ExactSizeIterator for HistoricalPointersIter<'_> { fn len(&self) -> usize { self.pointer_count - self.next_pointer_index } } /// A key event /// /// Wraps an [`AInputEvent *`] of the [`ffi::AINPUT_EVENT_TYPE_KEY`] type. /// /// For general discussion of key events in Android, see [the relevant /// javadoc](https://developer.android.com/reference/android/view/KeyEvent). /// /// [`AInputEvent *`]: https://developer.android.com/ndk/reference/group/input#ainputevent #[derive(Debug)] pub struct KeyEvent { ptr: NonNull, } // TODO: thread safety? /// 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)] #[repr(u32)] pub enum KeyAction { Down = ffi::AKEY_EVENT_ACTION_DOWN, Up = ffi::AKEY_EVENT_ACTION_UP, Multiple = ffi::AKEY_EVENT_ACTION_MULTIPLE, } /// 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)] #[repr(u32)] pub enum Keycode { Unknown = ffi::AKEYCODE_UNKNOWN, SoftLeft = ffi::AKEYCODE_SOFT_LEFT, SoftRight = ffi::AKEYCODE_SOFT_RIGHT, Home = ffi::AKEYCODE_HOME, Back = ffi::AKEYCODE_BACK, Call = ffi::AKEYCODE_CALL, Endcall = ffi::AKEYCODE_ENDCALL, Keycode0 = ffi::AKEYCODE_0, Keycode1 = ffi::AKEYCODE_1, Keycode2 = ffi::AKEYCODE_2, Keycode3 = ffi::AKEYCODE_3, Keycode4 = ffi::AKEYCODE_4, Keycode5 = ffi::AKEYCODE_5, Keycode6 = ffi::AKEYCODE_6, Keycode7 = ffi::AKEYCODE_7, Keycode8 = ffi::AKEYCODE_8, Keycode9 = ffi::AKEYCODE_9, Star = ffi::AKEYCODE_STAR, Pound = ffi::AKEYCODE_POUND, DpadUp = ffi::AKEYCODE_DPAD_UP, DpadDown = ffi::AKEYCODE_DPAD_DOWN, DpadLeft = ffi::AKEYCODE_DPAD_LEFT, DpadRight = ffi::AKEYCODE_DPAD_RIGHT, DpadCenter = ffi::AKEYCODE_DPAD_CENTER, VolumeUp = ffi::AKEYCODE_VOLUME_UP, VolumeDown = ffi::AKEYCODE_VOLUME_DOWN, Power = ffi::AKEYCODE_POWER, Camera = ffi::AKEYCODE_CAMERA, Clear = ffi::AKEYCODE_CLEAR, A = ffi::AKEYCODE_A, B = ffi::AKEYCODE_B, C = ffi::AKEYCODE_C, D = ffi::AKEYCODE_D, E = ffi::AKEYCODE_E, F = ffi::AKEYCODE_F, G = ffi::AKEYCODE_G, H = ffi::AKEYCODE_H, I = ffi::AKEYCODE_I, J = ffi::AKEYCODE_J, K = ffi::AKEYCODE_K, L = ffi::AKEYCODE_L, M = ffi::AKEYCODE_M, N = ffi::AKEYCODE_N, O = ffi::AKEYCODE_O, P = ffi::AKEYCODE_P, Q = ffi::AKEYCODE_Q, R = ffi::AKEYCODE_R, S = ffi::AKEYCODE_S, T = ffi::AKEYCODE_T, U = ffi::AKEYCODE_U, V = ffi::AKEYCODE_V, W = ffi::AKEYCODE_W, X = ffi::AKEYCODE_X, Y = ffi::AKEYCODE_Y, Z = ffi::AKEYCODE_Z, Comma = ffi::AKEYCODE_COMMA, Period = ffi::AKEYCODE_PERIOD, AltLeft = ffi::AKEYCODE_ALT_LEFT, AltRight = ffi::AKEYCODE_ALT_RIGHT, ShiftLeft = ffi::AKEYCODE_SHIFT_LEFT, ShiftRight = ffi::AKEYCODE_SHIFT_RIGHT, Tab = ffi::AKEYCODE_TAB, Space = ffi::AKEYCODE_SPACE, Sym = ffi::AKEYCODE_SYM, Explorer = ffi::AKEYCODE_EXPLORER, Envelope = ffi::AKEYCODE_ENVELOPE, Enter = ffi::AKEYCODE_ENTER, Del = ffi::AKEYCODE_DEL, Grave = ffi::AKEYCODE_GRAVE, Minus = ffi::AKEYCODE_MINUS, Equals = ffi::AKEYCODE_EQUALS, LeftBracket = ffi::AKEYCODE_LEFT_BRACKET, RightBracket = ffi::AKEYCODE_RIGHT_BRACKET, Backslash = ffi::AKEYCODE_BACKSLASH, Semicolon = ffi::AKEYCODE_SEMICOLON, Apostrophe = ffi::AKEYCODE_APOSTROPHE, Slash = ffi::AKEYCODE_SLASH, At = ffi::AKEYCODE_AT, Num = ffi::AKEYCODE_NUM, Headsethook = ffi::AKEYCODE_HEADSETHOOK, Focus = ffi::AKEYCODE_FOCUS, Plus = ffi::AKEYCODE_PLUS, Menu = ffi::AKEYCODE_MENU, Notification = ffi::AKEYCODE_NOTIFICATION, Search = ffi::AKEYCODE_SEARCH, MediaPlayPause = ffi::AKEYCODE_MEDIA_PLAY_PAUSE, MediaStop = ffi::AKEYCODE_MEDIA_STOP, MediaNext = ffi::AKEYCODE_MEDIA_NEXT, MediaPrevious = ffi::AKEYCODE_MEDIA_PREVIOUS, MediaRewind = ffi::AKEYCODE_MEDIA_REWIND, MediaFastForward = ffi::AKEYCODE_MEDIA_FAST_FORWARD, Mute = ffi::AKEYCODE_MUTE, PageUp = ffi::AKEYCODE_PAGE_UP, PageDown = ffi::AKEYCODE_PAGE_DOWN, Pictsymbols = ffi::AKEYCODE_PICTSYMBOLS, SwitchCharset = ffi::AKEYCODE_SWITCH_CHARSET, ButtonA = ffi::AKEYCODE_BUTTON_A, ButtonB = ffi::AKEYCODE_BUTTON_B, ButtonC = ffi::AKEYCODE_BUTTON_C, ButtonX = ffi::AKEYCODE_BUTTON_X, ButtonY = ffi::AKEYCODE_BUTTON_Y, ButtonZ = ffi::AKEYCODE_BUTTON_Z, ButtonL1 = ffi::AKEYCODE_BUTTON_L1, ButtonR1 = ffi::AKEYCODE_BUTTON_R1, ButtonL2 = ffi::AKEYCODE_BUTTON_L2, ButtonR2 = ffi::AKEYCODE_BUTTON_R2, ButtonThumbl = ffi::AKEYCODE_BUTTON_THUMBL, ButtonThumbr = ffi::AKEYCODE_BUTTON_THUMBR, ButtonStart = ffi::AKEYCODE_BUTTON_START, ButtonSelect = ffi::AKEYCODE_BUTTON_SELECT, ButtonMode = ffi::AKEYCODE_BUTTON_MODE, Escape = ffi::AKEYCODE_ESCAPE, ForwardDel = ffi::AKEYCODE_FORWARD_DEL, CtrlLeft = ffi::AKEYCODE_CTRL_LEFT, CtrlRight = ffi::AKEYCODE_CTRL_RIGHT, CapsLock = ffi::AKEYCODE_CAPS_LOCK, ScrollLock = ffi::AKEYCODE_SCROLL_LOCK, MetaLeft = ffi::AKEYCODE_META_LEFT, MetaRight = ffi::AKEYCODE_META_RIGHT, Function = ffi::AKEYCODE_FUNCTION, Sysrq = ffi::AKEYCODE_SYSRQ, Break = ffi::AKEYCODE_BREAK, MoveHome = ffi::AKEYCODE_MOVE_HOME, MoveEnd = ffi::AKEYCODE_MOVE_END, Insert = ffi::AKEYCODE_INSERT, Forward = ffi::AKEYCODE_FORWARD, MediaPlay = ffi::AKEYCODE_MEDIA_PLAY, MediaPause = ffi::AKEYCODE_MEDIA_PAUSE, MediaClose = ffi::AKEYCODE_MEDIA_CLOSE, MediaEject = ffi::AKEYCODE_MEDIA_EJECT, MediaRecord = ffi::AKEYCODE_MEDIA_RECORD, F1 = ffi::AKEYCODE_F1, F2 = ffi::AKEYCODE_F2, F3 = ffi::AKEYCODE_F3, F4 = ffi::AKEYCODE_F4, F5 = ffi::AKEYCODE_F5, F6 = ffi::AKEYCODE_F6, F7 = ffi::AKEYCODE_F7, F8 = ffi::AKEYCODE_F8, F9 = ffi::AKEYCODE_F9, F10 = ffi::AKEYCODE_F10, F11 = ffi::AKEYCODE_F11, F12 = ffi::AKEYCODE_F12, NumLock = ffi::AKEYCODE_NUM_LOCK, Numpad0 = ffi::AKEYCODE_NUMPAD_0, Numpad1 = ffi::AKEYCODE_NUMPAD_1, Numpad2 = ffi::AKEYCODE_NUMPAD_2, Numpad3 = ffi::AKEYCODE_NUMPAD_3, Numpad4 = ffi::AKEYCODE_NUMPAD_4, Numpad5 = ffi::AKEYCODE_NUMPAD_5, Numpad6 = ffi::AKEYCODE_NUMPAD_6, Numpad7 = ffi::AKEYCODE_NUMPAD_7, Numpad8 = ffi::AKEYCODE_NUMPAD_8, Numpad9 = ffi::AKEYCODE_NUMPAD_9, NumpadDivide = ffi::AKEYCODE_NUMPAD_DIVIDE, NumpadMultiply = ffi::AKEYCODE_NUMPAD_MULTIPLY, NumpadSubtract = ffi::AKEYCODE_NUMPAD_SUBTRACT, NumpadAdd = ffi::AKEYCODE_NUMPAD_ADD, NumpadDot = ffi::AKEYCODE_NUMPAD_DOT, NumpadComma = ffi::AKEYCODE_NUMPAD_COMMA, NumpadEnter = ffi::AKEYCODE_NUMPAD_ENTER, NumpadEquals = ffi::AKEYCODE_NUMPAD_EQUALS, NumpadLeftParen = ffi::AKEYCODE_NUMPAD_LEFT_PAREN, NumpadRightParen = ffi::AKEYCODE_NUMPAD_RIGHT_PAREN, VolumeMute = ffi::AKEYCODE_VOLUME_MUTE, Info = ffi::AKEYCODE_INFO, ChannelUp = ffi::AKEYCODE_CHANNEL_UP, ChannelDown = ffi::AKEYCODE_CHANNEL_DOWN, ZoomIn = ffi::AKEYCODE_ZOOM_IN, ZoomOut = ffi::AKEYCODE_ZOOM_OUT, Tv = ffi::AKEYCODE_TV, Window = ffi::AKEYCODE_WINDOW, Guide = ffi::AKEYCODE_GUIDE, Dvr = ffi::AKEYCODE_DVR, Bookmark = ffi::AKEYCODE_BOOKMARK, Captions = ffi::AKEYCODE_CAPTIONS, Settings = ffi::AKEYCODE_SETTINGS, TvPower = ffi::AKEYCODE_TV_POWER, TvInput = ffi::AKEYCODE_TV_INPUT, StbPower = ffi::AKEYCODE_STB_POWER, StbInput = ffi::AKEYCODE_STB_INPUT, AvrPower = ffi::AKEYCODE_AVR_POWER, AvrInput = ffi::AKEYCODE_AVR_INPUT, ProgRed = ffi::AKEYCODE_PROG_RED, ProgGreen = ffi::AKEYCODE_PROG_GREEN, ProgYellow = ffi::AKEYCODE_PROG_YELLOW, ProgBlue = ffi::AKEYCODE_PROG_BLUE, AppSwitch = ffi::AKEYCODE_APP_SWITCH, Button1 = ffi::AKEYCODE_BUTTON_1, Button2 = ffi::AKEYCODE_BUTTON_2, Button3 = ffi::AKEYCODE_BUTTON_3, Button4 = ffi::AKEYCODE_BUTTON_4, Button5 = ffi::AKEYCODE_BUTTON_5, Button6 = ffi::AKEYCODE_BUTTON_6, Button7 = ffi::AKEYCODE_BUTTON_7, Button8 = ffi::AKEYCODE_BUTTON_8, Button9 = ffi::AKEYCODE_BUTTON_9, Button10 = ffi::AKEYCODE_BUTTON_10, Button11 = ffi::AKEYCODE_BUTTON_11, Button12 = ffi::AKEYCODE_BUTTON_12, Button13 = ffi::AKEYCODE_BUTTON_13, Button14 = ffi::AKEYCODE_BUTTON_14, Button15 = ffi::AKEYCODE_BUTTON_15, Button16 = ffi::AKEYCODE_BUTTON_16, LanguageSwitch = ffi::AKEYCODE_LANGUAGE_SWITCH, MannerMode = ffi::AKEYCODE_MANNER_MODE, Keycode3dMode = ffi::AKEYCODE_3D_MODE, Contacts = ffi::AKEYCODE_CONTACTS, Calendar = ffi::AKEYCODE_CALENDAR, Music = ffi::AKEYCODE_MUSIC, Calculator = ffi::AKEYCODE_CALCULATOR, ZenkakuHankaku = ffi::AKEYCODE_ZENKAKU_HANKAKU, Eisu = ffi::AKEYCODE_EISU, Muhenkan = ffi::AKEYCODE_MUHENKAN, Henkan = ffi::AKEYCODE_HENKAN, KatakanaHiragana = ffi::AKEYCODE_KATAKANA_HIRAGANA, Yen = ffi::AKEYCODE_YEN, Ro = ffi::AKEYCODE_RO, Kana = ffi::AKEYCODE_KANA, Assist = ffi::AKEYCODE_ASSIST, BrightnessDown = ffi::AKEYCODE_BRIGHTNESS_DOWN, BrightnessUp = ffi::AKEYCODE_BRIGHTNESS_UP, MediaAudioTrack = ffi::AKEYCODE_MEDIA_AUDIO_TRACK, Sleep = ffi::AKEYCODE_SLEEP, Wakeup = ffi::AKEYCODE_WAKEUP, Pairing = ffi::AKEYCODE_PAIRING, MediaTopMenu = ffi::AKEYCODE_MEDIA_TOP_MENU, Keycode11 = ffi::AKEYCODE_11, Keycode12 = ffi::AKEYCODE_12, LastChannel = ffi::AKEYCODE_LAST_CHANNEL, TvDataService = ffi::AKEYCODE_TV_DATA_SERVICE, VoiceAssist = ffi::AKEYCODE_VOICE_ASSIST, TvRadioService = ffi::AKEYCODE_TV_RADIO_SERVICE, TvTeletext = ffi::AKEYCODE_TV_TELETEXT, TvNumberEntry = ffi::AKEYCODE_TV_NUMBER_ENTRY, TvTerrestrialAnalog = ffi::AKEYCODE_TV_TERRESTRIAL_ANALOG, TvTerrestrialDigital = ffi::AKEYCODE_TV_TERRESTRIAL_DIGITAL, TvSatellite = ffi::AKEYCODE_TV_SATELLITE, TvSatelliteBs = ffi::AKEYCODE_TV_SATELLITE_BS, TvSatelliteCs = ffi::AKEYCODE_TV_SATELLITE_CS, TvSatelliteService = ffi::AKEYCODE_TV_SATELLITE_SERVICE, TvNetwork = ffi::AKEYCODE_TV_NETWORK, TvAntennaCable = ffi::AKEYCODE_TV_ANTENNA_CABLE, TvInputHdmi1 = ffi::AKEYCODE_TV_INPUT_HDMI_1, TvInputHdmi2 = ffi::AKEYCODE_TV_INPUT_HDMI_2, TvInputHdmi3 = ffi::AKEYCODE_TV_INPUT_HDMI_3, TvInputHdmi4 = ffi::AKEYCODE_TV_INPUT_HDMI_4, TvInputComposite1 = ffi::AKEYCODE_TV_INPUT_COMPOSITE_1, TvInputComposite2 = ffi::AKEYCODE_TV_INPUT_COMPOSITE_2, TvInputComponent1 = ffi::AKEYCODE_TV_INPUT_COMPONENT_1, TvInputComponent2 = ffi::AKEYCODE_TV_INPUT_COMPONENT_2, TvInputVga1 = ffi::AKEYCODE_TV_INPUT_VGA_1, TvAudioDescription = ffi::AKEYCODE_TV_AUDIO_DESCRIPTION, TvAudioDescriptionMixUp = ffi::AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP, TvAudioDescriptionMixDown = ffi::AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN, TvZoomMode = ffi::AKEYCODE_TV_ZOOM_MODE, TvContentsMenu = ffi::AKEYCODE_TV_CONTENTS_MENU, TvMediaContextMenu = ffi::AKEYCODE_TV_MEDIA_CONTEXT_MENU, TvTimerProgramming = ffi::AKEYCODE_TV_TIMER_PROGRAMMING, Help = ffi::AKEYCODE_HELP, NavigatePrevious = ffi::AKEYCODE_NAVIGATE_PREVIOUS, NavigateNext = ffi::AKEYCODE_NAVIGATE_NEXT, NavigateIn = ffi::AKEYCODE_NAVIGATE_IN, NavigateOut = ffi::AKEYCODE_NAVIGATE_OUT, StemPrimary = ffi::AKEYCODE_STEM_PRIMARY, Stem1 = ffi::AKEYCODE_STEM_1, Stem2 = ffi::AKEYCODE_STEM_2, Stem3 = ffi::AKEYCODE_STEM_3, DpadUpLeft = ffi::AKEYCODE_DPAD_UP_LEFT, DpadDownLeft = ffi::AKEYCODE_DPAD_DOWN_LEFT, DpadUpRight = ffi::AKEYCODE_DPAD_UP_RIGHT, DpadDownRight = ffi::AKEYCODE_DPAD_DOWN_RIGHT, MediaSkipForward = ffi::AKEYCODE_MEDIA_SKIP_FORWARD, MediaSkipBackward = ffi::AKEYCODE_MEDIA_SKIP_BACKWARD, MediaStepForward = ffi::AKEYCODE_MEDIA_STEP_FORWARD, MediaStepBackward = ffi::AKEYCODE_MEDIA_STEP_BACKWARD, SoftSleep = ffi::AKEYCODE_SOFT_SLEEP, Cut = ffi::AKEYCODE_CUT, Copy = ffi::AKEYCODE_COPY, Paste = ffi::AKEYCODE_PASTE, SystemNavigationUp = ffi::AKEYCODE_SYSTEM_NAVIGATION_UP, SystemNavigationDown = ffi::AKEYCODE_SYSTEM_NAVIGATION_DOWN, SystemNavigationLeft = ffi::AKEYCODE_SYSTEM_NAVIGATION_LEFT, SystemNavigationRight = ffi::AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AllApps = ffi::AKEYCODE_ALL_APPS, Refresh = ffi::AKEYCODE_REFRESH, ThumbsUp = ffi::AKEYCODE_THUMBS_UP, ThumbsDown = ffi::AKEYCODE_THUMBS_DOWN, ProfileSwitch = ffi::AKEYCODE_PROFILE_SWITCH, } impl KeyEvent { /// Constructs a KeyEvent from a pointer to a native [`ffi::AInputEvent`] /// /// # Safety /// By calling this method, you assert that the pointer is a valid, non-null pointer to an /// [`ffi::AInputEvent`], and that [`ffi::AInputEvent`] is an `AKeyEvent`. #[inline] pub unsafe fn from_ptr(ptr: NonNull) -> Self { Self { ptr } } /// Returns a pointer to the native [`ffi::AInputEvent`] #[inline] pub fn ptr(&self) -> NonNull { self.ptr } /// Returns the key action represented by this event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getaction) #[inline] pub fn action(&self) -> KeyAction { let action = unsafe { ffi::AKeyEvent_getAction(self.ptr.as_ptr()) as u32 }; action.try_into().unwrap() } /// Get the source of the event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#ainputevent_getsource) #[inline] pub fn source(&self) -> Source { let source = unsafe { ffi::AInputEvent_getSource(self.ptr.as_ptr()) as u32 }; source.try_into().unwrap_or(Source::Unknown) } /// Get the device id associated with the event. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#ainputevent_getdeviceid) #[inline] pub fn device_id(&self) -> i32 { unsafe { ffi::AInputEvent_getDeviceId(self.ptr.as_ptr()) } } /// 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 { unsafe { ffi::AKeyEvent_getDownTime(self.ptr.as_ptr()) } } /// 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 { unsafe { ffi::AKeyEvent_getEventTime(self.ptr.as_ptr()) } } /// 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 { let keycode = unsafe { ffi::AKeyEvent_getKeyCode(self.ptr.as_ptr()) as u32 }; keycode.try_into().unwrap_or(Keycode::Unknown) } /// 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 { unsafe { ffi::AKeyEvent_getRepeatCount(self.ptr.as_ptr()) } } /// 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 { unsafe { ffi::AKeyEvent_getScanCode(self.ptr.as_ptr()) } } } /// Flags associated with [`KeyEvent`]. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-28) #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct KeyEventFlags(pub u32); impl KeyEventFlags { #[inline] pub fn cancelled(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_CANCELED != 0 } #[inline] pub fn cancelled_long_press(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_CANCELED_LONG_PRESS != 0 } #[inline] pub fn editor_action(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_EDITOR_ACTION != 0 } #[inline] pub fn fallback(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_FALLBACK != 0 } #[inline] pub fn from_system(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_FROM_SYSTEM != 0 } #[inline] pub fn keep_touch_mode(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_KEEP_TOUCH_MODE != 0 } #[inline] pub fn long_press(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_LONG_PRESS != 0 } #[inline] pub fn soft_keyboard(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_SOFT_KEYBOARD != 0 } #[inline] pub fn tracking(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_TRACKING != 0 } #[inline] pub fn virtual_hard_key(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY != 0 } #[inline] pub fn woke_here(&self) -> bool { self.0 & ffi::AKEY_EVENT_FLAG_WOKE_HERE != 0 } } impl KeyEvent { /// Flags associated with this [`KeyEvent`]. /// /// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getflags) #[inline] pub fn flags(&self) -> KeyEventFlags { unsafe { KeyEventFlags(ffi::AKeyEvent_getFlags(self.ptr.as_ptr()) as u32) } } /// Returns the state of the modifiers during this key event, represented by a bitmask. /// /// See [the NDK /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getmetastate) #[inline] pub fn meta_state(&self) -> MetaState { unsafe { MetaState(ffi::AKeyEvent_getMetaState(self.ptr.as_ptr()) as u32) } } }