13d1aa5738
The long-deferred Android display stage (design/stats-unification.md; plan 4.1 of design/client-parity-and-network-resilience.md): AMediaCodec_setOnFrameRenderedCallback (API 26, under the minSdk-28 floor ⇒ hard-linked via ndk-sys) reports SurfaceFlinger's per-frame render timestamp, giving the HUD the spec's `display` = decoded→displayed term and the directly-measured capture→displayed end-to-end headline on both decode loops. Falls back per spec to the v1 capture→decoded endpoint on any window without render callbacks (the platform may drop them under load), and to it permanently if registration is refused. - The render timestamp arrives on CLOCK_MONOTONIC; it's re-based onto CLOCK_REALTIME against monotonic-now at callback time, which also cancels the (batchable) callback delivery lag. - The `ndk` crate exposes neither the callback nor the codec pointer needed to bind it raw, so the workspace pins `ndk` 0.9.0 to a vendored copy (clients/android/native/ vendor/ndk) whose ONLY change makes MediaCodec::as_ptr public — the "as_ptr patch". Workspace-excluded so host builds never compile it; drop when upstream exposes either. - nativeVideoStats grows to 26 doubles (22–25: dispValid, displayP50, e2eDispP50/P95; 0–21 unchanged for older readers); StatsOverlay moves headline endpoint + equation together so the equation always tiles the headline interval. Verified: host cargo check/test/clippy, aarch64-linux-android check/clippy, Kotlin app+kit+tests compile, roborazzi HUD render shows the full 4-term equation. Device verification rides plan 4.2's phone A/B. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1584 lines
54 KiB
Rust
1584 lines
54 KiB
Rust
//! 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
|
|
//! [`android.view.MotionEvent`]: https://developer.android.com/reference/android/view/MotionEvent
|
|
//! [`android.view.KeyEvent`]: https://developer.android.com/reference/android/view/KeyEvent
|
|
|
|
use std::ptr::NonNull;
|
|
|
|
#[cfg(feature = "api-level-31")]
|
|
use jni_sys::{jobject, JNIEnv};
|
|
use num_enum::{FromPrimitive, IntoPrimitive};
|
|
|
|
/// A native [`AInputEvent *`]
|
|
///
|
|
/// [`AInputEvent *`]: https://developer.android.com/ndk/reference/group/input#ainputevent
|
|
#[derive(Debug)]
|
|
#[non_exhaustive]
|
|
pub enum InputEvent {
|
|
MotionEvent(MotionEvent),
|
|
KeyEvent(KeyEvent),
|
|
}
|
|
|
|
/// Wraps a Java [`InputEvent`] acquired from [`KeyEvent::from_java()`] or
|
|
/// [`MotionEvent::from_java()`] with respective [`Drop`] semantics.
|
|
#[cfg(feature = "api-level-31")]
|
|
#[derive(Debug)]
|
|
pub struct InputEventJava(InputEvent);
|
|
|
|
#[cfg(feature = "api-level-31")]
|
|
impl Drop for InputEventJava {
|
|
/// Releases interface objects created by [`KeyEvent::from_java()`] or
|
|
/// [`MotionEvent::from_java()`].
|
|
///
|
|
/// The underlying Java object remains valid and does not change its state.
|
|
#[doc(alias = "AInputEvent_release")]
|
|
fn drop(&mut self) {
|
|
let ptr = match self.0 {
|
|
InputEvent::MotionEvent(MotionEvent { ptr })
|
|
| InputEvent::KeyEvent(KeyEvent { ptr }) => ptr.as_ptr().cast(),
|
|
};
|
|
unsafe { ffi::AInputEvent_release(ptr) }
|
|
}
|
|
}
|
|
|
|
/// An enum representing the source of an [`InputEvent`].
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
|
|
#[repr(i32)]
|
|
#[non_exhaustive]
|
|
pub enum Source {
|
|
Unknown = ffi::AINPUT_SOURCE_UNKNOWN as i32,
|
|
Keyboard = ffi::AINPUT_SOURCE_KEYBOARD as i32,
|
|
Dpad = ffi::AINPUT_SOURCE_DPAD as i32,
|
|
Gamepad = ffi::AINPUT_SOURCE_GAMEPAD as i32,
|
|
Touchscreen = ffi::AINPUT_SOURCE_TOUCHSCREEN as i32,
|
|
Mouse = ffi::AINPUT_SOURCE_MOUSE as i32,
|
|
Stylus = ffi::AINPUT_SOURCE_STYLUS as i32,
|
|
BluetoothStylus = ffi::AINPUT_SOURCE_BLUETOOTH_STYLUS as i32,
|
|
Trackball = ffi::AINPUT_SOURCE_TRACKBALL as i32,
|
|
MouseRelative = ffi::AINPUT_SOURCE_MOUSE_RELATIVE as i32,
|
|
Touchpad = ffi::AINPUT_SOURCE_TOUCHPAD as i32,
|
|
TouchNavigation = ffi::AINPUT_SOURCE_TOUCH_NAVIGATION as i32,
|
|
Joystick = ffi::AINPUT_SOURCE_JOYSTICK as i32,
|
|
Hdmi = ffi::AINPUT_SOURCE_HDMI as i32,
|
|
Sensor = ffi::AINPUT_SOURCE_SENSOR as i32,
|
|
RotaryEncoder = ffi::AINPUT_SOURCE_ROTARY_ENCODER as i32,
|
|
Any = ffi::AINPUT_SOURCE_ANY as i32,
|
|
|
|
#[doc(hidden)]
|
|
#[num_enum(catch_all)]
|
|
__Unknown(i32),
|
|
}
|
|
|
|
impl Source {
|
|
pub fn class(self) -> SourceClass {
|
|
let class = i32::from(self) & ffi::AINPUT_SOURCE_CLASS_MASK as i32;
|
|
// The mask fits in a u8.
|
|
SourceClass::from_bits_retain(class as u8)
|
|
}
|
|
}
|
|
|
|
bitflags::bitflags! {
|
|
/// Flags representing the class of an [`InputEvent`] [`Source`].
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
pub struct SourceClass : u8 {
|
|
#[doc(alias = "AINPUT_SOURCE_CLASS_BUTTON")]
|
|
const BUTTON = ffi::AINPUT_SOURCE_CLASS_BUTTON as u8;
|
|
#[doc(alias = "AINPUT_SOURCE_CLASS_POINTER")]
|
|
const POINTER = ffi::AINPUT_SOURCE_CLASS_POINTER as u8;
|
|
#[doc(alias = "AINPUT_SOURCE_CLASS_NAVIGATION")]
|
|
const NAVIGATION = ffi::AINPUT_SOURCE_CLASS_NAVIGATION as u8;
|
|
#[doc(alias = "AINPUT_SOURCE_CLASS_POSITION")]
|
|
const POSITION = ffi::AINPUT_SOURCE_CLASS_POSITION as u8;
|
|
#[doc(alias = "AINPUT_SOURCE_CLASS_JOYSTICK")]
|
|
const JOYSTICK = ffi::AINPUT_SOURCE_CLASS_JOYSTICK as u8;
|
|
|
|
// https://docs.rs/bitflags/latest/bitflags/#externally-defined-flags
|
|
const _ = ffi::AINPUT_SOURCE_CLASS_MASK as u8;
|
|
}
|
|
}
|
|
|
|
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<ffi::AInputEvent>) -> 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<ffi::AInputEvent> {
|
|
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()) };
|
|
source.into()
|
|
}
|
|
|
|
/// 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.
|
|
#[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<ffi::AInputEvent>,
|
|
}
|
|
|
|
// TODO: thread safety?
|
|
|
|
/// A motion action.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
|
|
#[repr(i32)]
|
|
#[non_exhaustive]
|
|
pub enum MotionAction {
|
|
Down = ffi::AMOTION_EVENT_ACTION_DOWN as i32,
|
|
Up = ffi::AMOTION_EVENT_ACTION_UP as i32,
|
|
Move = ffi::AMOTION_EVENT_ACTION_MOVE as i32,
|
|
Cancel = ffi::AMOTION_EVENT_ACTION_CANCEL as i32,
|
|
Outside = ffi::AMOTION_EVENT_ACTION_OUTSIDE as i32,
|
|
PointerDown = ffi::AMOTION_EVENT_ACTION_POINTER_DOWN as i32,
|
|
PointerUp = ffi::AMOTION_EVENT_ACTION_POINTER_UP as i32,
|
|
HoverMove = ffi::AMOTION_EVENT_ACTION_HOVER_MOVE as i32,
|
|
Scroll = ffi::AMOTION_EVENT_ACTION_SCROLL as i32,
|
|
HoverEnter = ffi::AMOTION_EVENT_ACTION_HOVER_ENTER as i32,
|
|
HoverExit = ffi::AMOTION_EVENT_ACTION_HOVER_EXIT as i32,
|
|
ButtonPress = ffi::AMOTION_EVENT_ACTION_BUTTON_PRESS as i32,
|
|
ButtonRelease = ffi::AMOTION_EVENT_ACTION_BUTTON_RELEASE as i32,
|
|
|
|
#[doc(hidden)]
|
|
#[num_enum(catch_all)]
|
|
__Unknown(i32),
|
|
}
|
|
|
|
/// An axis of a motion event.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
|
|
#[repr(i32)]
|
|
#[non_exhaustive]
|
|
pub enum Axis {
|
|
X = ffi::AMOTION_EVENT_AXIS_X as i32,
|
|
Y = ffi::AMOTION_EVENT_AXIS_Y as i32,
|
|
Pressure = ffi::AMOTION_EVENT_AXIS_PRESSURE as i32,
|
|
Size = ffi::AMOTION_EVENT_AXIS_SIZE as i32,
|
|
TouchMajor = ffi::AMOTION_EVENT_AXIS_TOUCH_MAJOR as i32,
|
|
TouchMinor = ffi::AMOTION_EVENT_AXIS_TOUCH_MINOR as i32,
|
|
ToolMajor = ffi::AMOTION_EVENT_AXIS_TOOL_MAJOR as i32,
|
|
ToolMinor = ffi::AMOTION_EVENT_AXIS_TOOL_MINOR as i32,
|
|
Orientation = ffi::AMOTION_EVENT_AXIS_ORIENTATION as i32,
|
|
Vscroll = ffi::AMOTION_EVENT_AXIS_VSCROLL as i32,
|
|
Hscroll = ffi::AMOTION_EVENT_AXIS_HSCROLL as i32,
|
|
Z = ffi::AMOTION_EVENT_AXIS_Z as i32,
|
|
Rx = ffi::AMOTION_EVENT_AXIS_RX as i32,
|
|
Ry = ffi::AMOTION_EVENT_AXIS_RY as i32,
|
|
Rz = ffi::AMOTION_EVENT_AXIS_RZ as i32,
|
|
HatX = ffi::AMOTION_EVENT_AXIS_HAT_X as i32,
|
|
HatY = ffi::AMOTION_EVENT_AXIS_HAT_Y as i32,
|
|
Ltrigger = ffi::AMOTION_EVENT_AXIS_LTRIGGER as i32,
|
|
Rtrigger = ffi::AMOTION_EVENT_AXIS_RTRIGGER as i32,
|
|
Throttle = ffi::AMOTION_EVENT_AXIS_THROTTLE as i32,
|
|
Rudder = ffi::AMOTION_EVENT_AXIS_RUDDER as i32,
|
|
Wheel = ffi::AMOTION_EVENT_AXIS_WHEEL as i32,
|
|
Gas = ffi::AMOTION_EVENT_AXIS_GAS as i32,
|
|
Brake = ffi::AMOTION_EVENT_AXIS_BRAKE as i32,
|
|
Distance = ffi::AMOTION_EVENT_AXIS_DISTANCE as i32,
|
|
Tilt = ffi::AMOTION_EVENT_AXIS_TILT as i32,
|
|
Scroll = ffi::AMOTION_EVENT_AXIS_SCROLL as i32,
|
|
RelativeX = ffi::AMOTION_EVENT_AXIS_RELATIVE_X as i32,
|
|
RelativeY = ffi::AMOTION_EVENT_AXIS_RELATIVE_Y as i32,
|
|
Generic1 = ffi::AMOTION_EVENT_AXIS_GENERIC_1 as i32,
|
|
Generic2 = ffi::AMOTION_EVENT_AXIS_GENERIC_2 as i32,
|
|
Generic3 = ffi::AMOTION_EVENT_AXIS_GENERIC_3 as i32,
|
|
Generic4 = ffi::AMOTION_EVENT_AXIS_GENERIC_4 as i32,
|
|
Generic5 = ffi::AMOTION_EVENT_AXIS_GENERIC_5 as i32,
|
|
Generic6 = ffi::AMOTION_EVENT_AXIS_GENERIC_6 as i32,
|
|
Generic7 = ffi::AMOTION_EVENT_AXIS_GENERIC_7 as i32,
|
|
Generic8 = ffi::AMOTION_EVENT_AXIS_GENERIC_8 as i32,
|
|
Generic9 = ffi::AMOTION_EVENT_AXIS_GENERIC_9 as i32,
|
|
Generic10 = ffi::AMOTION_EVENT_AXIS_GENERIC_10 as i32,
|
|
Generic11 = ffi::AMOTION_EVENT_AXIS_GENERIC_11 as i32,
|
|
Generic12 = ffi::AMOTION_EVENT_AXIS_GENERIC_12 as i32,
|
|
Generic13 = ffi::AMOTION_EVENT_AXIS_GENERIC_13 as i32,
|
|
Generic14 = ffi::AMOTION_EVENT_AXIS_GENERIC_14 as i32,
|
|
Generic15 = ffi::AMOTION_EVENT_AXIS_GENERIC_15 as i32,
|
|
Generic16 = ffi::AMOTION_EVENT_AXIS_GENERIC_16 as i32,
|
|
|
|
#[doc(hidden)]
|
|
#[num_enum(catch_all)]
|
|
__Unknown(i32),
|
|
}
|
|
|
|
/// The tool type of a pointer.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
|
|
#[repr(i32)]
|
|
#[non_exhaustive]
|
|
pub enum ToolType {
|
|
Unknown = ffi::AMOTION_EVENT_TOOL_TYPE_UNKNOWN as i32,
|
|
Finger = ffi::AMOTION_EVENT_TOOL_TYPE_FINGER as i32,
|
|
Stylus = ffi::AMOTION_EVENT_TOOL_TYPE_STYLUS as i32,
|
|
Mouse = ffi::AMOTION_EVENT_TOOL_TYPE_MOUSE as i32,
|
|
Eraser = ffi::AMOTION_EVENT_TOOL_TYPE_ERASER as i32,
|
|
Palm = ffi::AMOTION_EVENT_TOOL_TYPE_PALM as i32,
|
|
|
|
#[doc(hidden)]
|
|
#[num_enum(catch_all)]
|
|
__Unknown(i32),
|
|
}
|
|
|
|
/// A bitfield representing the state of buttons during a motion event.
|
|
#[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.
|
|
#[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`].
|
|
#[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<ffi::AInputEvent>) -> Self {
|
|
Self { ptr }
|
|
}
|
|
|
|
/// Creates a native [`InputEvent`] object that is a copy of the specified
|
|
/// Java [`android.view.MotionEvent`]. The result may be used with generic and
|
|
/// [`MotionEvent`]-specific functions.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This function should be called with a healthy JVM pointer and with a non-null
|
|
/// [`android.view.MotionEvent`].
|
|
///
|
|
/// [`android.view.MotionEvent`]: https://developer.android.com/reference/android/view/MotionEvent
|
|
#[cfg(feature = "api-level-31")]
|
|
#[doc(alias = "AMotionEvent_fromJava")]
|
|
pub unsafe fn from_java(env: *mut JNIEnv, key_event: jobject) -> Option<InputEventJava> {
|
|
let ptr = unsafe { ffi::AMotionEvent_fromJava(env, key_event) };
|
|
Some(InputEventJava(InputEvent::MotionEvent(Self::from_ptr(
|
|
NonNull::new(ptr.cast_mut())?,
|
|
))))
|
|
}
|
|
|
|
/// Returns a pointer to the native [`ffi::AInputEvent`].
|
|
#[inline]
|
|
pub fn ptr(&self) -> NonNull<ffi::AInputEvent> {
|
|
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()) };
|
|
source.into()
|
|
}
|
|
|
|
/// 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()) }
|
|
& ffi::AMOTION_EVENT_ACTION_MASK as i32;
|
|
action.into()
|
|
}
|
|
|
|
/// 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<ffi::AInputEvent>,
|
|
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.into(), 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) };
|
|
tool_type.into()
|
|
}
|
|
}
|
|
|
|
/// An iterator over the pointers in a [`MotionEvent`].
|
|
#[derive(Debug)]
|
|
pub struct PointersIter<'a> {
|
|
event: NonNull<ffi::AInputEvent>,
|
|
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<Pointer<'a>> {
|
|
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<usize>) {
|
|
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<ffi::AInputEvent>,
|
|
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<ffi::AInputEvent>,
|
|
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<HistoricalMotionEvent<'a>> {
|
|
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<usize>) {
|
|
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<HistoricalMotionEvent<'a>> {
|
|
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<ffi::AInputEvent>,
|
|
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.into(),
|
|
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<ffi::AInputEvent>,
|
|
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<HistoricalPointer<'a>> {
|
|
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<usize>) {
|
|
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<ffi::AInputEvent>,
|
|
}
|
|
|
|
// 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, FromPrimitive, IntoPrimitive)]
|
|
#[repr(i32)]
|
|
#[non_exhaustive]
|
|
pub enum KeyAction {
|
|
Down = ffi::AKEY_EVENT_ACTION_DOWN as i32,
|
|
Up = ffi::AKEY_EVENT_ACTION_UP as i32,
|
|
Multiple = ffi::AKEY_EVENT_ACTION_MULTIPLE as i32,
|
|
|
|
#[doc(hidden)]
|
|
#[num_enum(catch_all)]
|
|
__Unknown(i32),
|
|
}
|
|
|
|
/// Key codes.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, IntoPrimitive)]
|
|
#[repr(i32)]
|
|
#[non_exhaustive]
|
|
pub enum Keycode {
|
|
Unknown = ffi::AKEYCODE_UNKNOWN as i32,
|
|
SoftLeft = ffi::AKEYCODE_SOFT_LEFT as i32,
|
|
SoftRight = ffi::AKEYCODE_SOFT_RIGHT as i32,
|
|
Home = ffi::AKEYCODE_HOME as i32,
|
|
Back = ffi::AKEYCODE_BACK as i32,
|
|
Call = ffi::AKEYCODE_CALL as i32,
|
|
Endcall = ffi::AKEYCODE_ENDCALL as i32,
|
|
Keycode0 = ffi::AKEYCODE_0 as i32,
|
|
Keycode1 = ffi::AKEYCODE_1 as i32,
|
|
Keycode2 = ffi::AKEYCODE_2 as i32,
|
|
Keycode3 = ffi::AKEYCODE_3 as i32,
|
|
Keycode4 = ffi::AKEYCODE_4 as i32,
|
|
Keycode5 = ffi::AKEYCODE_5 as i32,
|
|
Keycode6 = ffi::AKEYCODE_6 as i32,
|
|
Keycode7 = ffi::AKEYCODE_7 as i32,
|
|
Keycode8 = ffi::AKEYCODE_8 as i32,
|
|
Keycode9 = ffi::AKEYCODE_9 as i32,
|
|
Star = ffi::AKEYCODE_STAR as i32,
|
|
Pound = ffi::AKEYCODE_POUND as i32,
|
|
DpadUp = ffi::AKEYCODE_DPAD_UP as i32,
|
|
DpadDown = ffi::AKEYCODE_DPAD_DOWN as i32,
|
|
DpadLeft = ffi::AKEYCODE_DPAD_LEFT as i32,
|
|
DpadRight = ffi::AKEYCODE_DPAD_RIGHT as i32,
|
|
DpadCenter = ffi::AKEYCODE_DPAD_CENTER as i32,
|
|
VolumeUp = ffi::AKEYCODE_VOLUME_UP as i32,
|
|
VolumeDown = ffi::AKEYCODE_VOLUME_DOWN as i32,
|
|
Power = ffi::AKEYCODE_POWER as i32,
|
|
Camera = ffi::AKEYCODE_CAMERA as i32,
|
|
Clear = ffi::AKEYCODE_CLEAR as i32,
|
|
A = ffi::AKEYCODE_A as i32,
|
|
B = ffi::AKEYCODE_B as i32,
|
|
C = ffi::AKEYCODE_C as i32,
|
|
D = ffi::AKEYCODE_D as i32,
|
|
E = ffi::AKEYCODE_E as i32,
|
|
F = ffi::AKEYCODE_F as i32,
|
|
G = ffi::AKEYCODE_G as i32,
|
|
H = ffi::AKEYCODE_H as i32,
|
|
I = ffi::AKEYCODE_I as i32,
|
|
J = ffi::AKEYCODE_J as i32,
|
|
K = ffi::AKEYCODE_K as i32,
|
|
L = ffi::AKEYCODE_L as i32,
|
|
M = ffi::AKEYCODE_M as i32,
|
|
N = ffi::AKEYCODE_N as i32,
|
|
O = ffi::AKEYCODE_O as i32,
|
|
P = ffi::AKEYCODE_P as i32,
|
|
Q = ffi::AKEYCODE_Q as i32,
|
|
R = ffi::AKEYCODE_R as i32,
|
|
S = ffi::AKEYCODE_S as i32,
|
|
T = ffi::AKEYCODE_T as i32,
|
|
U = ffi::AKEYCODE_U as i32,
|
|
V = ffi::AKEYCODE_V as i32,
|
|
W = ffi::AKEYCODE_W as i32,
|
|
X = ffi::AKEYCODE_X as i32,
|
|
Y = ffi::AKEYCODE_Y as i32,
|
|
Z = ffi::AKEYCODE_Z as i32,
|
|
Comma = ffi::AKEYCODE_COMMA as i32,
|
|
Period = ffi::AKEYCODE_PERIOD as i32,
|
|
AltLeft = ffi::AKEYCODE_ALT_LEFT as i32,
|
|
AltRight = ffi::AKEYCODE_ALT_RIGHT as i32,
|
|
ShiftLeft = ffi::AKEYCODE_SHIFT_LEFT as i32,
|
|
ShiftRight = ffi::AKEYCODE_SHIFT_RIGHT as i32,
|
|
Tab = ffi::AKEYCODE_TAB as i32,
|
|
Space = ffi::AKEYCODE_SPACE as i32,
|
|
Sym = ffi::AKEYCODE_SYM as i32,
|
|
Explorer = ffi::AKEYCODE_EXPLORER as i32,
|
|
Envelope = ffi::AKEYCODE_ENVELOPE as i32,
|
|
Enter = ffi::AKEYCODE_ENTER as i32,
|
|
Del = ffi::AKEYCODE_DEL as i32,
|
|
Grave = ffi::AKEYCODE_GRAVE as i32,
|
|
Minus = ffi::AKEYCODE_MINUS as i32,
|
|
Equals = ffi::AKEYCODE_EQUALS as i32,
|
|
LeftBracket = ffi::AKEYCODE_LEFT_BRACKET as i32,
|
|
RightBracket = ffi::AKEYCODE_RIGHT_BRACKET as i32,
|
|
Backslash = ffi::AKEYCODE_BACKSLASH as i32,
|
|
Semicolon = ffi::AKEYCODE_SEMICOLON as i32,
|
|
Apostrophe = ffi::AKEYCODE_APOSTROPHE as i32,
|
|
Slash = ffi::AKEYCODE_SLASH as i32,
|
|
At = ffi::AKEYCODE_AT as i32,
|
|
Num = ffi::AKEYCODE_NUM as i32,
|
|
Headsethook = ffi::AKEYCODE_HEADSETHOOK as i32,
|
|
Focus = ffi::AKEYCODE_FOCUS as i32,
|
|
Plus = ffi::AKEYCODE_PLUS as i32,
|
|
Menu = ffi::AKEYCODE_MENU as i32,
|
|
Notification = ffi::AKEYCODE_NOTIFICATION as i32,
|
|
Search = ffi::AKEYCODE_SEARCH as i32,
|
|
MediaPlayPause = ffi::AKEYCODE_MEDIA_PLAY_PAUSE as i32,
|
|
MediaStop = ffi::AKEYCODE_MEDIA_STOP as i32,
|
|
MediaNext = ffi::AKEYCODE_MEDIA_NEXT as i32,
|
|
MediaPrevious = ffi::AKEYCODE_MEDIA_PREVIOUS as i32,
|
|
MediaRewind = ffi::AKEYCODE_MEDIA_REWIND as i32,
|
|
MediaFastForward = ffi::AKEYCODE_MEDIA_FAST_FORWARD as i32,
|
|
Mute = ffi::AKEYCODE_MUTE as i32,
|
|
PageUp = ffi::AKEYCODE_PAGE_UP as i32,
|
|
PageDown = ffi::AKEYCODE_PAGE_DOWN as i32,
|
|
Pictsymbols = ffi::AKEYCODE_PICTSYMBOLS as i32,
|
|
SwitchCharset = ffi::AKEYCODE_SWITCH_CHARSET as i32,
|
|
ButtonA = ffi::AKEYCODE_BUTTON_A as i32,
|
|
ButtonB = ffi::AKEYCODE_BUTTON_B as i32,
|
|
ButtonC = ffi::AKEYCODE_BUTTON_C as i32,
|
|
ButtonX = ffi::AKEYCODE_BUTTON_X as i32,
|
|
ButtonY = ffi::AKEYCODE_BUTTON_Y as i32,
|
|
ButtonZ = ffi::AKEYCODE_BUTTON_Z as i32,
|
|
ButtonL1 = ffi::AKEYCODE_BUTTON_L1 as i32,
|
|
ButtonR1 = ffi::AKEYCODE_BUTTON_R1 as i32,
|
|
ButtonL2 = ffi::AKEYCODE_BUTTON_L2 as i32,
|
|
ButtonR2 = ffi::AKEYCODE_BUTTON_R2 as i32,
|
|
ButtonThumbl = ffi::AKEYCODE_BUTTON_THUMBL as i32,
|
|
ButtonThumbr = ffi::AKEYCODE_BUTTON_THUMBR as i32,
|
|
ButtonStart = ffi::AKEYCODE_BUTTON_START as i32,
|
|
ButtonSelect = ffi::AKEYCODE_BUTTON_SELECT as i32,
|
|
ButtonMode = ffi::AKEYCODE_BUTTON_MODE as i32,
|
|
Escape = ffi::AKEYCODE_ESCAPE as i32,
|
|
ForwardDel = ffi::AKEYCODE_FORWARD_DEL as i32,
|
|
CtrlLeft = ffi::AKEYCODE_CTRL_LEFT as i32,
|
|
CtrlRight = ffi::AKEYCODE_CTRL_RIGHT as i32,
|
|
CapsLock = ffi::AKEYCODE_CAPS_LOCK as i32,
|
|
ScrollLock = ffi::AKEYCODE_SCROLL_LOCK as i32,
|
|
MetaLeft = ffi::AKEYCODE_META_LEFT as i32,
|
|
MetaRight = ffi::AKEYCODE_META_RIGHT as i32,
|
|
Function = ffi::AKEYCODE_FUNCTION as i32,
|
|
Sysrq = ffi::AKEYCODE_SYSRQ as i32,
|
|
Break = ffi::AKEYCODE_BREAK as i32,
|
|
MoveHome = ffi::AKEYCODE_MOVE_HOME as i32,
|
|
MoveEnd = ffi::AKEYCODE_MOVE_END as i32,
|
|
Insert = ffi::AKEYCODE_INSERT as i32,
|
|
Forward = ffi::AKEYCODE_FORWARD as i32,
|
|
MediaPlay = ffi::AKEYCODE_MEDIA_PLAY as i32,
|
|
MediaPause = ffi::AKEYCODE_MEDIA_PAUSE as i32,
|
|
MediaClose = ffi::AKEYCODE_MEDIA_CLOSE as i32,
|
|
MediaEject = ffi::AKEYCODE_MEDIA_EJECT as i32,
|
|
MediaRecord = ffi::AKEYCODE_MEDIA_RECORD as i32,
|
|
F1 = ffi::AKEYCODE_F1 as i32,
|
|
F2 = ffi::AKEYCODE_F2 as i32,
|
|
F3 = ffi::AKEYCODE_F3 as i32,
|
|
F4 = ffi::AKEYCODE_F4 as i32,
|
|
F5 = ffi::AKEYCODE_F5 as i32,
|
|
F6 = ffi::AKEYCODE_F6 as i32,
|
|
F7 = ffi::AKEYCODE_F7 as i32,
|
|
F8 = ffi::AKEYCODE_F8 as i32,
|
|
F9 = ffi::AKEYCODE_F9 as i32,
|
|
F10 = ffi::AKEYCODE_F10 as i32,
|
|
F11 = ffi::AKEYCODE_F11 as i32,
|
|
F12 = ffi::AKEYCODE_F12 as i32,
|
|
NumLock = ffi::AKEYCODE_NUM_LOCK as i32,
|
|
Numpad0 = ffi::AKEYCODE_NUMPAD_0 as i32,
|
|
Numpad1 = ffi::AKEYCODE_NUMPAD_1 as i32,
|
|
Numpad2 = ffi::AKEYCODE_NUMPAD_2 as i32,
|
|
Numpad3 = ffi::AKEYCODE_NUMPAD_3 as i32,
|
|
Numpad4 = ffi::AKEYCODE_NUMPAD_4 as i32,
|
|
Numpad5 = ffi::AKEYCODE_NUMPAD_5 as i32,
|
|
Numpad6 = ffi::AKEYCODE_NUMPAD_6 as i32,
|
|
Numpad7 = ffi::AKEYCODE_NUMPAD_7 as i32,
|
|
Numpad8 = ffi::AKEYCODE_NUMPAD_8 as i32,
|
|
Numpad9 = ffi::AKEYCODE_NUMPAD_9 as i32,
|
|
NumpadDivide = ffi::AKEYCODE_NUMPAD_DIVIDE as i32,
|
|
NumpadMultiply = ffi::AKEYCODE_NUMPAD_MULTIPLY as i32,
|
|
NumpadSubtract = ffi::AKEYCODE_NUMPAD_SUBTRACT as i32,
|
|
NumpadAdd = ffi::AKEYCODE_NUMPAD_ADD as i32,
|
|
NumpadDot = ffi::AKEYCODE_NUMPAD_DOT as i32,
|
|
NumpadComma = ffi::AKEYCODE_NUMPAD_COMMA as i32,
|
|
NumpadEnter = ffi::AKEYCODE_NUMPAD_ENTER as i32,
|
|
NumpadEquals = ffi::AKEYCODE_NUMPAD_EQUALS as i32,
|
|
NumpadLeftParen = ffi::AKEYCODE_NUMPAD_LEFT_PAREN as i32,
|
|
NumpadRightParen = ffi::AKEYCODE_NUMPAD_RIGHT_PAREN as i32,
|
|
VolumeMute = ffi::AKEYCODE_VOLUME_MUTE as i32,
|
|
Info = ffi::AKEYCODE_INFO as i32,
|
|
ChannelUp = ffi::AKEYCODE_CHANNEL_UP as i32,
|
|
ChannelDown = ffi::AKEYCODE_CHANNEL_DOWN as i32,
|
|
ZoomIn = ffi::AKEYCODE_ZOOM_IN as i32,
|
|
ZoomOut = ffi::AKEYCODE_ZOOM_OUT as i32,
|
|
Tv = ffi::AKEYCODE_TV as i32,
|
|
Window = ffi::AKEYCODE_WINDOW as i32,
|
|
Guide = ffi::AKEYCODE_GUIDE as i32,
|
|
Dvr = ffi::AKEYCODE_DVR as i32,
|
|
Bookmark = ffi::AKEYCODE_BOOKMARK as i32,
|
|
Captions = ffi::AKEYCODE_CAPTIONS as i32,
|
|
Settings = ffi::AKEYCODE_SETTINGS as i32,
|
|
TvPower = ffi::AKEYCODE_TV_POWER as i32,
|
|
TvInput = ffi::AKEYCODE_TV_INPUT as i32,
|
|
StbPower = ffi::AKEYCODE_STB_POWER as i32,
|
|
StbInput = ffi::AKEYCODE_STB_INPUT as i32,
|
|
AvrPower = ffi::AKEYCODE_AVR_POWER as i32,
|
|
AvrInput = ffi::AKEYCODE_AVR_INPUT as i32,
|
|
ProgRed = ffi::AKEYCODE_PROG_RED as i32,
|
|
ProgGreen = ffi::AKEYCODE_PROG_GREEN as i32,
|
|
ProgYellow = ffi::AKEYCODE_PROG_YELLOW as i32,
|
|
ProgBlue = ffi::AKEYCODE_PROG_BLUE as i32,
|
|
AppSwitch = ffi::AKEYCODE_APP_SWITCH as i32,
|
|
Button1 = ffi::AKEYCODE_BUTTON_1 as i32,
|
|
Button2 = ffi::AKEYCODE_BUTTON_2 as i32,
|
|
Button3 = ffi::AKEYCODE_BUTTON_3 as i32,
|
|
Button4 = ffi::AKEYCODE_BUTTON_4 as i32,
|
|
Button5 = ffi::AKEYCODE_BUTTON_5 as i32,
|
|
Button6 = ffi::AKEYCODE_BUTTON_6 as i32,
|
|
Button7 = ffi::AKEYCODE_BUTTON_7 as i32,
|
|
Button8 = ffi::AKEYCODE_BUTTON_8 as i32,
|
|
Button9 = ffi::AKEYCODE_BUTTON_9 as i32,
|
|
Button10 = ffi::AKEYCODE_BUTTON_10 as i32,
|
|
Button11 = ffi::AKEYCODE_BUTTON_11 as i32,
|
|
Button12 = ffi::AKEYCODE_BUTTON_12 as i32,
|
|
Button13 = ffi::AKEYCODE_BUTTON_13 as i32,
|
|
Button14 = ffi::AKEYCODE_BUTTON_14 as i32,
|
|
Button15 = ffi::AKEYCODE_BUTTON_15 as i32,
|
|
Button16 = ffi::AKEYCODE_BUTTON_16 as i32,
|
|
LanguageSwitch = ffi::AKEYCODE_LANGUAGE_SWITCH as i32,
|
|
MannerMode = ffi::AKEYCODE_MANNER_MODE as i32,
|
|
Keycode3dMode = ffi::AKEYCODE_3D_MODE as i32,
|
|
Contacts = ffi::AKEYCODE_CONTACTS as i32,
|
|
Calendar = ffi::AKEYCODE_CALENDAR as i32,
|
|
Music = ffi::AKEYCODE_MUSIC as i32,
|
|
Calculator = ffi::AKEYCODE_CALCULATOR as i32,
|
|
ZenkakuHankaku = ffi::AKEYCODE_ZENKAKU_HANKAKU as i32,
|
|
Eisu = ffi::AKEYCODE_EISU as i32,
|
|
Muhenkan = ffi::AKEYCODE_MUHENKAN as i32,
|
|
Henkan = ffi::AKEYCODE_HENKAN as i32,
|
|
KatakanaHiragana = ffi::AKEYCODE_KATAKANA_HIRAGANA as i32,
|
|
Yen = ffi::AKEYCODE_YEN as i32,
|
|
Ro = ffi::AKEYCODE_RO as i32,
|
|
Kana = ffi::AKEYCODE_KANA as i32,
|
|
Assist = ffi::AKEYCODE_ASSIST as i32,
|
|
BrightnessDown = ffi::AKEYCODE_BRIGHTNESS_DOWN as i32,
|
|
BrightnessUp = ffi::AKEYCODE_BRIGHTNESS_UP as i32,
|
|
MediaAudioTrack = ffi::AKEYCODE_MEDIA_AUDIO_TRACK as i32,
|
|
Sleep = ffi::AKEYCODE_SLEEP as i32,
|
|
Wakeup = ffi::AKEYCODE_WAKEUP as i32,
|
|
Pairing = ffi::AKEYCODE_PAIRING as i32,
|
|
MediaTopMenu = ffi::AKEYCODE_MEDIA_TOP_MENU as i32,
|
|
Keycode11 = ffi::AKEYCODE_11 as i32,
|
|
Keycode12 = ffi::AKEYCODE_12 as i32,
|
|
LastChannel = ffi::AKEYCODE_LAST_CHANNEL as i32,
|
|
TvDataService = ffi::AKEYCODE_TV_DATA_SERVICE as i32,
|
|
VoiceAssist = ffi::AKEYCODE_VOICE_ASSIST as i32,
|
|
TvRadioService = ffi::AKEYCODE_TV_RADIO_SERVICE as i32,
|
|
TvTeletext = ffi::AKEYCODE_TV_TELETEXT as i32,
|
|
TvNumberEntry = ffi::AKEYCODE_TV_NUMBER_ENTRY as i32,
|
|
TvTerrestrialAnalog = ffi::AKEYCODE_TV_TERRESTRIAL_ANALOG as i32,
|
|
TvTerrestrialDigital = ffi::AKEYCODE_TV_TERRESTRIAL_DIGITAL as i32,
|
|
TvSatellite = ffi::AKEYCODE_TV_SATELLITE as i32,
|
|
TvSatelliteBs = ffi::AKEYCODE_TV_SATELLITE_BS as i32,
|
|
TvSatelliteCs = ffi::AKEYCODE_TV_SATELLITE_CS as i32,
|
|
TvSatelliteService = ffi::AKEYCODE_TV_SATELLITE_SERVICE as i32,
|
|
TvNetwork = ffi::AKEYCODE_TV_NETWORK as i32,
|
|
TvAntennaCable = ffi::AKEYCODE_TV_ANTENNA_CABLE as i32,
|
|
TvInputHdmi1 = ffi::AKEYCODE_TV_INPUT_HDMI_1 as i32,
|
|
TvInputHdmi2 = ffi::AKEYCODE_TV_INPUT_HDMI_2 as i32,
|
|
TvInputHdmi3 = ffi::AKEYCODE_TV_INPUT_HDMI_3 as i32,
|
|
TvInputHdmi4 = ffi::AKEYCODE_TV_INPUT_HDMI_4 as i32,
|
|
TvInputComposite1 = ffi::AKEYCODE_TV_INPUT_COMPOSITE_1 as i32,
|
|
TvInputComposite2 = ffi::AKEYCODE_TV_INPUT_COMPOSITE_2 as i32,
|
|
TvInputComponent1 = ffi::AKEYCODE_TV_INPUT_COMPONENT_1 as i32,
|
|
TvInputComponent2 = ffi::AKEYCODE_TV_INPUT_COMPONENT_2 as i32,
|
|
TvInputVga1 = ffi::AKEYCODE_TV_INPUT_VGA_1 as i32,
|
|
TvAudioDescription = ffi::AKEYCODE_TV_AUDIO_DESCRIPTION as i32,
|
|
TvAudioDescriptionMixUp = ffi::AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP as i32,
|
|
TvAudioDescriptionMixDown = ffi::AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN as i32,
|
|
TvZoomMode = ffi::AKEYCODE_TV_ZOOM_MODE as i32,
|
|
TvContentsMenu = ffi::AKEYCODE_TV_CONTENTS_MENU as i32,
|
|
TvMediaContextMenu = ffi::AKEYCODE_TV_MEDIA_CONTEXT_MENU as i32,
|
|
TvTimerProgramming = ffi::AKEYCODE_TV_TIMER_PROGRAMMING as i32,
|
|
Help = ffi::AKEYCODE_HELP as i32,
|
|
NavigatePrevious = ffi::AKEYCODE_NAVIGATE_PREVIOUS as i32,
|
|
NavigateNext = ffi::AKEYCODE_NAVIGATE_NEXT as i32,
|
|
NavigateIn = ffi::AKEYCODE_NAVIGATE_IN as i32,
|
|
NavigateOut = ffi::AKEYCODE_NAVIGATE_OUT as i32,
|
|
StemPrimary = ffi::AKEYCODE_STEM_PRIMARY as i32,
|
|
Stem1 = ffi::AKEYCODE_STEM_1 as i32,
|
|
Stem2 = ffi::AKEYCODE_STEM_2 as i32,
|
|
Stem3 = ffi::AKEYCODE_STEM_3 as i32,
|
|
DpadUpLeft = ffi::AKEYCODE_DPAD_UP_LEFT as i32,
|
|
DpadDownLeft = ffi::AKEYCODE_DPAD_DOWN_LEFT as i32,
|
|
DpadUpRight = ffi::AKEYCODE_DPAD_UP_RIGHT as i32,
|
|
DpadDownRight = ffi::AKEYCODE_DPAD_DOWN_RIGHT as i32,
|
|
MediaSkipForward = ffi::AKEYCODE_MEDIA_SKIP_FORWARD as i32,
|
|
MediaSkipBackward = ffi::AKEYCODE_MEDIA_SKIP_BACKWARD as i32,
|
|
MediaStepForward = ffi::AKEYCODE_MEDIA_STEP_FORWARD as i32,
|
|
MediaStepBackward = ffi::AKEYCODE_MEDIA_STEP_BACKWARD as i32,
|
|
SoftSleep = ffi::AKEYCODE_SOFT_SLEEP as i32,
|
|
Cut = ffi::AKEYCODE_CUT as i32,
|
|
Copy = ffi::AKEYCODE_COPY as i32,
|
|
Paste = ffi::AKEYCODE_PASTE as i32,
|
|
SystemNavigationUp = ffi::AKEYCODE_SYSTEM_NAVIGATION_UP as i32,
|
|
SystemNavigationDown = ffi::AKEYCODE_SYSTEM_NAVIGATION_DOWN as i32,
|
|
SystemNavigationLeft = ffi::AKEYCODE_SYSTEM_NAVIGATION_LEFT as i32,
|
|
SystemNavigationRight = ffi::AKEYCODE_SYSTEM_NAVIGATION_RIGHT as i32,
|
|
AllApps = ffi::AKEYCODE_ALL_APPS as i32,
|
|
Refresh = ffi::AKEYCODE_REFRESH as i32,
|
|
ThumbsUp = ffi::AKEYCODE_THUMBS_UP as i32,
|
|
ThumbsDown = ffi::AKEYCODE_THUMBS_DOWN as i32,
|
|
ProfileSwitch = ffi::AKEYCODE_PROFILE_SWITCH as i32,
|
|
|
|
#[doc(hidden)]
|
|
#[num_enum(catch_all)]
|
|
__Unknown(i32),
|
|
}
|
|
|
|
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<ffi::AInputEvent>) -> Self {
|
|
Self { ptr }
|
|
}
|
|
|
|
/// Creates a native [`InputEvent`] object that is a copy of the specified Java
|
|
/// [`android.view.KeyEvent`]. The result may be used with generic and [`KeyEvent`]-specific
|
|
/// functions.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// This function should be called with a healthy JVM pointer and with a non-null
|
|
/// [`android.view.KeyEvent`].
|
|
///
|
|
/// [`android.view.KeyEvent`]: https://developer.android.com/reference/android/view/KeyEvent
|
|
#[cfg(feature = "api-level-31")]
|
|
#[doc(alias = "AKeyEvent_fromJava")]
|
|
pub unsafe fn from_java(env: *mut JNIEnv, key_event: jobject) -> Option<InputEventJava> {
|
|
let ptr = unsafe { ffi::AKeyEvent_fromJava(env, key_event) };
|
|
Some(InputEventJava(InputEvent::KeyEvent(Self::from_ptr(
|
|
NonNull::new(ptr.cast_mut())?,
|
|
))))
|
|
}
|
|
|
|
/// Returns a pointer to the native [`ffi::AInputEvent`].
|
|
#[inline]
|
|
pub fn ptr(&self) -> NonNull<ffi::AInputEvent> {
|
|
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()) };
|
|
action.into()
|
|
}
|
|
|
|
/// 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()) };
|
|
source.into()
|
|
}
|
|
|
|
/// 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()) };
|
|
keycode.into()
|
|
}
|
|
|
|
/// 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`].
|
|
#[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) }
|
|
}
|
|
}
|