android_activity/native_activity/input.rs
1use std::{iter::FusedIterator, marker::PhantomData, ptr::NonNull};
2
3use crate::input::{
4 Axis, Button, ButtonState, EdgeFlags, KeyAction, Keycode, MetaState, MotionAction,
5 MotionEventFlags, Pointer, PointersIter, Source, ToolType,
6};
7
8/// A motion event
9///
10/// For general discussion of motion events in Android, see [the relevant
11/// javadoc](https://developer.android.com/reference/android/view/MotionEvent).
12#[derive(Debug)]
13#[repr(transparent)]
14pub struct MotionEvent<'a> {
15 ndk_event: ndk::event::MotionEvent,
16 _lifetime: PhantomData<&'a ndk::event::MotionEvent>,
17}
18impl MotionEvent<'_> {
19 pub(crate) fn new(ndk_event: ndk::event::MotionEvent) -> Self {
20 Self {
21 ndk_event,
22 _lifetime: PhantomData,
23 }
24 }
25 pub(crate) fn into_ndk_event(self) -> ndk::event::MotionEvent {
26 self.ndk_event
27 }
28
29 /// Get the source of the event.
30 ///
31 #[inline]
32 pub fn source(&self) -> Source {
33 // XXX: we use `AInputEvent_getSource` directly (instead of calling
34 // ndk_event.source()) since we have our own `Source` enum that we
35 // share between backends, which may also capture unknown variants
36 // added in new versions of Android.
37 let source =
38 unsafe { ndk_sys::AInputEvent_getSource(self.ndk_event.ptr().as_ptr()) as u32 };
39 source.into()
40 }
41
42 /// Get the device id associated with the event.
43 ///
44 #[inline]
45 pub fn device_id(&self) -> i32 {
46 self.ndk_event.device_id()
47 }
48
49 /// Returns the motion action associated with the event.
50 ///
51 /// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getActionMasked())
52 #[inline]
53 pub fn action(&self) -> MotionAction {
54 // XXX: we use `AMotionEvent_getAction` directly since we have our own
55 // `MotionAction` enum that we share between backends, which may also
56 // capture unknown variants added in new versions of Android.
57 let action =
58 unsafe { ndk_sys::AMotionEvent_getAction(self.ndk_event.ptr().as_ptr()) as u32 }
59 & ndk_sys::AMOTION_EVENT_ACTION_MASK;
60 action.into()
61 }
62
63 /// Returns which button has been modified during a press or release action.
64 ///
65 /// For actions other than [`MotionAction::ButtonPress`] and
66 /// [`MotionAction::ButtonRelease`] the returned value is undefined.
67 ///
68 /// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getActionButton())
69 #[inline]
70 pub fn action_button(&self) -> Button {
71 let action_button =
72 unsafe { ndk_sys::AMotionEvent_getActionButton(self.ndk_event.ptr().as_ptr()) as u32 };
73 action_button.into()
74 }
75
76 /// Returns the pointer index of an `Up` or `Down` event.
77 ///
78 /// Pointer indices can change per motion event. For an identifier that stays the same, see
79 /// [`Pointer::pointer_id()`].
80 ///
81 /// This only has a meaning when the [action](Self::action) is one of [`Up`](MotionAction::Up),
82 /// [`Down`](MotionAction::Down), [`PointerUp`](MotionAction::PointerUp),
83 /// or [`PointerDown`](MotionAction::PointerDown).
84 #[inline]
85 pub fn pointer_index(&self) -> usize {
86 self.ndk_event.pointer_index()
87 }
88
89 /*
90 /// Returns the pointer id associated with the given pointer index.
91 ///
92 /// See [the NDK
93 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getpointerid)
94 // TODO: look at output with out-of-range pointer index
95 // Probably -1 though
96 pub fn pointer_id_for(&self, pointer_index: usize) -> i32 {
97 unsafe { ndk_sys::AMotionEvent_getPointerId(self.ndk_event.ptr.as_ptr(), pointer_index) }
98 }
99 */
100
101 /// Returns the number of pointers in this event
102 ///
103 /// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getPointerCount())
104 #[inline]
105 pub fn pointer_count(&self) -> usize {
106 self.ndk_event.pointer_count()
107 }
108
109 /// An iterator over the pointers in this motion event
110 #[inline]
111 pub fn pointers(&self) -> PointersIter<'_> {
112 PointersIter {
113 inner: PointersIterImpl {
114 event: self.ndk_event.ptr(),
115 pointer_index: 0,
116 pointer_count: self.ndk_event.pointer_count(),
117 _marker: std::marker::PhantomData,
118 },
119 }
120 }
121
122 /// The pointer at a given pointer index. Panics if the pointer index is out of bounds.
123 ///
124 /// If you need to loop over all the pointers, prefer the [`pointers()`](Self::pointers) method.
125 #[inline]
126 pub fn pointer_at_index(&self, index: usize) -> Pointer<'_> {
127 Pointer {
128 inner: PointerImpl {
129 event: self.ndk_event.ptr(),
130 pointer_index: index,
131 _marker: std::marker::PhantomData,
132 },
133 }
134 }
135
136 /// Returns the state of any modifier keys that were pressed during the event.
137 ///
138 /// See [the NDK
139 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getmetastate)
140 #[inline]
141 pub fn meta_state(&self) -> MetaState {
142 self.ndk_event.meta_state().into()
143 }
144
145 /// Returns the button state during this event, as a bitfield.
146 ///
147 /// See [the NDK
148 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getbuttonstate)
149 #[inline]
150 pub fn button_state(&self) -> ButtonState {
151 self.ndk_event.button_state().into()
152 }
153
154 /// Returns the time of the start of this gesture, in the `java.lang.System.nanoTime()` time
155 /// base
156 ///
157 /// See [the NDK
158 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getdowntime)
159 #[inline]
160 pub fn down_time(&self) -> i64 {
161 self.ndk_event.down_time()
162 }
163
164 /// Returns a bitfield indicating which edges were touched by this event.
165 ///
166 /// See [the NDK
167 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getedgeflags)
168 #[inline]
169 pub fn edge_flags(&self) -> EdgeFlags {
170 self.ndk_event.edge_flags().into()
171 }
172
173 /// Returns the time of this event, in the `java.lang.System.nanoTime()` time base
174 ///
175 /// See [the NDK
176 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_geteventtime)
177 #[inline]
178 pub fn event_time(&self) -> i64 {
179 self.ndk_event.event_time()
180 }
181
182 /// The flags associated with a motion event.
183 ///
184 /// See [the NDK
185 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getflags)
186 #[inline]
187 pub fn flags(&self) -> MotionEventFlags {
188 self.ndk_event.flags().into()
189 }
190
191 /* Missing from GameActivity currently...
192 /// Returns the offset in the x direction between the coordinates and the raw coordinates
193 ///
194 /// See [the NDK
195 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getxoffset)
196 #[inline]
197 pub fn x_offset(&self) -> f32 {
198 self.ndk_event.x_offset()
199 }
200
201 /// Returns the offset in the y direction between the coordinates and the raw coordinates
202 ///
203 /// See [the NDK
204 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getyoffset)
205 #[inline]
206 pub fn y_offset(&self) -> f32 {
207 self.ndk_event.y_offset()
208 }
209 */
210
211 /// Returns the precision of the x value of the coordinates
212 ///
213 /// See [the NDK
214 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getxprecision)
215 #[inline]
216 pub fn x_precision(&self) -> f32 {
217 self.ndk_event.x_precision()
218 }
219
220 /// Returns the precision of the y value of the coordinates
221 ///
222 /// See [the NDK
223 /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getyprecision)
224 #[inline]
225 pub fn y_precision(&self) -> f32 {
226 self.ndk_event.y_precision()
227 }
228}
229
230/// A view into the data of a specific pointer in a motion event.
231#[derive(Debug)]
232pub(crate) struct PointerImpl<'a> {
233 event: NonNull<ndk_sys::AInputEvent>,
234 pointer_index: usize,
235 _marker: std::marker::PhantomData<&'a MotionEvent<'a>>,
236}
237
238impl PointerImpl<'_> {
239 #[inline]
240 pub fn pointer_index(&self) -> usize {
241 self.pointer_index
242 }
243
244 #[inline]
245 pub fn pointer_id(&self) -> i32 {
246 unsafe { ndk_sys::AMotionEvent_getPointerId(self.event.as_ptr(), self.pointer_index) }
247 }
248
249 #[inline]
250 pub fn axis_value(&self, axis: Axis) -> f32 {
251 let value: u32 = axis.into();
252 let value = value as i32;
253 unsafe {
254 ndk_sys::AMotionEvent_getAxisValue(self.event.as_ptr(), value, self.pointer_index)
255 }
256 }
257
258 #[inline]
259 pub fn raw_x(&self) -> f32 {
260 unsafe { ndk_sys::AMotionEvent_getRawX(self.event.as_ptr(), self.pointer_index) }
261 }
262
263 #[inline]
264 pub fn raw_y(&self) -> f32 {
265 unsafe { ndk_sys::AMotionEvent_getRawY(self.event.as_ptr(), self.pointer_index) }
266 }
267
268 #[inline]
269 pub fn tool_type(&self) -> ToolType {
270 let value =
271 unsafe { ndk_sys::AMotionEvent_getToolType(self.event.as_ptr(), self.pointer_index) };
272 let value = value as u32;
273 value.into()
274 }
275
276 pub fn history(&self) -> crate::input::PointerHistoryIter<'_> {
277 let history_size =
278 unsafe { ndk_sys::AMotionEvent_getHistorySize(self.event.as_ptr()) } as usize;
279 crate::input::PointerHistoryIter {
280 inner: PointerHistoryIterImpl {
281 event: self.event,
282 pointer_index: self.pointer_index,
283 front: 0,
284 back: history_size,
285 _marker: std::marker::PhantomData,
286 },
287 }
288 }
289}
290
291#[derive(Debug)]
292pub(crate) struct PointersIterImpl<'a> {
293 event: NonNull<ndk_sys::AInputEvent>,
294 pointer_count: usize,
295 pointer_index: usize,
296 _marker: std::marker::PhantomData<&'a MotionEvent<'a>>,
297}
298
299impl<'a> Iterator for PointersIterImpl<'a> {
300 type Item = Pointer<'a>;
301 fn next(&mut self) -> Option<Pointer<'a>> {
302 if self.pointer_index == self.pointer_count {
303 return None;
304 }
305 let pointer = Pointer {
306 inner: PointerImpl {
307 event: self.event,
308 pointer_index: self.pointer_index,
309 _marker: std::marker::PhantomData,
310 },
311 };
312 self.pointer_index += 1;
313 Some(pointer)
314 }
315
316 fn size_hint(&self) -> (usize, Option<usize>) {
317 let remaining = self.pointer_count - self.pointer_index;
318 (remaining, Some(remaining))
319 }
320}
321
322impl ExactSizeIterator for PointersIterImpl<'_> {}
323
324/// A view into a pointer at a historical moment
325#[derive(Debug)]
326pub struct HistoricalPointerImpl<'a> {
327 event: NonNull<ndk_sys::AInputEvent>,
328 pointer_index: usize,
329 history_index: usize,
330 _marker: std::marker::PhantomData<&'a MotionEvent<'a>>,
331}
332
333impl<'a> HistoricalPointerImpl<'a> {
334 #[inline]
335 pub fn pointer_index(&self) -> usize {
336 self.pointer_index
337 }
338
339 /// Returns the time of the historical event, in the `java.lang.System.nanoTime()` time base
340 ///
341 /// See [`MotionEvent.getHistoricalEventTimeNanos`](https://developer.android.com/reference/android/view/MotionEvent#getHistoricalEventTimeNanos(int)) SDK docs
342 #[inline]
343 pub fn event_time(&self) -> i64 {
344 unsafe {
345 ndk_sys::AMotionEvent_getHistoricalEventTime(self.event.as_ptr(), self.history_index)
346 }
347 }
348
349 #[inline]
350 pub fn pointer_id(&self) -> i32 {
351 unsafe { ndk_sys::AMotionEvent_getPointerId(self.event.as_ptr(), self.pointer_index) }
352 }
353
354 #[inline]
355 pub fn history_index(&self) -> usize {
356 self.history_index
357 }
358
359 #[inline]
360 pub fn axis_value(&self, axis: Axis) -> f32 {
361 unsafe {
362 ndk_sys::AMotionEvent_getHistoricalAxisValue(
363 self.event.as_ptr(),
364 Into::<u32>::into(axis) as i32,
365 self.pointer_index,
366 self.history_index,
367 )
368 }
369 }
370}
371
372/// An iterator over the historical points of a specific pointer in a [`MotionEvent`].
373#[derive(Debug)]
374pub struct PointerHistoryIterImpl<'a> {
375 event: NonNull<ndk_sys::AInputEvent>,
376 pointer_index: usize,
377 front: usize,
378 back: usize,
379 _marker: std::marker::PhantomData<&'a MotionEvent<'a>>,
380}
381
382impl<'a> Iterator for PointerHistoryIterImpl<'a> {
383 type Item = crate::input::HistoricalPointer<'a>;
384
385 fn next(&mut self) -> Option<crate::input::HistoricalPointer<'a>> {
386 if self.front == self.back {
387 return None;
388 }
389
390 let history_index = self.front;
391 self.front += 1;
392 Some(crate::input::HistoricalPointer {
393 inner: crate::input::HistoricalPointerImpl {
394 event: self.event,
395 history_index,
396 pointer_index: self.pointer_index,
397 _marker: std::marker::PhantomData,
398 },
399 })
400 }
401
402 fn size_hint(&self) -> (usize, Option<usize>) {
403 let size = self.back - self.front;
404 (size, Some(size))
405 }
406}
407impl<'a> DoubleEndedIterator for PointerHistoryIterImpl<'a> {
408 fn next_back(&mut self) -> Option<crate::input::HistoricalPointer<'a>> {
409 if self.front == self.back {
410 return None;
411 }
412
413 self.back -= 1;
414 let history_index = self.back;
415 Some(crate::input::HistoricalPointer {
416 inner: crate::input::HistoricalPointerImpl {
417 event: self.event,
418 history_index,
419 pointer_index: self.pointer_index,
420 _marker: std::marker::PhantomData,
421 },
422 })
423 }
424}
425impl ExactSizeIterator for PointerHistoryIterImpl<'_> {}
426impl FusedIterator for PointerHistoryIterImpl<'_> {}
427
428/// A key event
429///
430/// For general discussion of key events in Android, see [the relevant
431/// javadoc](https://developer.android.com/reference/android/view/KeyEvent).
432#[derive(Debug)]
433#[repr(transparent)]
434pub struct KeyEvent<'a> {
435 ndk_event: ndk::event::KeyEvent,
436 _lifetime: PhantomData<&'a ndk::event::KeyEvent>,
437}
438impl KeyEvent<'_> {
439 pub(crate) fn new(ndk_event: ndk::event::KeyEvent) -> Self {
440 Self {
441 ndk_event,
442 _lifetime: PhantomData,
443 }
444 }
445 pub(crate) fn into_ndk_event(self) -> ndk::event::KeyEvent {
446 self.ndk_event
447 }
448
449 /// Get the source of the event.
450 ///
451 #[inline]
452 pub fn source(&self) -> Source {
453 // XXX: we use `AInputEvent_getSource` directly (instead of calling
454 // ndk_event.source()) since we have our own `Source` enum that we
455 // share between backends, which may also capture unknown variants
456 // added in new versions of Android.
457 let source =
458 unsafe { ndk_sys::AInputEvent_getSource(self.ndk_event.ptr().as_ptr()) as u32 };
459 source.into()
460 }
461
462 /// Get the device id associated with the event.
463 ///
464 #[inline]
465 pub fn device_id(&self) -> i32 {
466 self.ndk_event.device_id()
467 }
468
469 /// Returns the key action associated with the event.
470 ///
471 /// See [the KeyEvent docs](https://developer.android.com/reference/android/view/KeyEvent#getAction())
472 #[inline]
473 pub fn action(&self) -> KeyAction {
474 // XXX: we use `AInputEvent_getAction` directly since we have our own
475 // `KeyAction` enum that we share between backends, which may also
476 // capture unknown variants added in new versions of Android.
477 let action = unsafe { ndk_sys::AKeyEvent_getAction(self.ndk_event.ptr().as_ptr()) as u32 };
478 action.into()
479 }
480
481 /// Returns the last time the key was pressed. This is on the scale of
482 /// `java.lang.System.nanoTime()`, which has nanosecond precision, but no defined start time.
483 ///
484 /// See [the NDK
485 /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getdowntime)
486 #[inline]
487 pub fn down_time(&self) -> i64 {
488 self.ndk_event.down_time()
489 }
490
491 /// Returns the time this event occured. This is on the scale of
492 /// `java.lang.System.nanoTime()`, which has nanosecond precision, but no defined start time.
493 ///
494 /// See [the NDK
495 /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_geteventtime)
496 #[inline]
497 pub fn event_time(&self) -> i64 {
498 self.ndk_event.event_time()
499 }
500
501 /// Returns the keycode associated with this key event
502 ///
503 /// See [the NDK
504 /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getkeycode)
505 #[inline]
506 pub fn key_code(&self) -> Keycode {
507 // XXX: we use `AInputEvent_getKeyCode` directly since we have our own
508 // `Keycode` enum that we share between backends, which may also
509 // capture unknown variants added in new versions of Android.
510 let keycode =
511 unsafe { ndk_sys::AKeyEvent_getKeyCode(self.ndk_event.ptr().as_ptr()) as u32 };
512 keycode.into()
513 }
514
515 /// Returns the number of repeats of a key.
516 ///
517 /// See [the NDK
518 /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getrepeatcount)
519 #[inline]
520 pub fn repeat_count(&self) -> i32 {
521 self.ndk_event.repeat_count()
522 }
523
524 /// Returns the hardware keycode of a key. This varies from device to device.
525 ///
526 /// See [the NDK
527 /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getscancode)
528 #[inline]
529 pub fn scan_code(&self) -> i32 {
530 self.ndk_event.scan_code()
531 }
532
533 /// Returns the state of the modifiers during this key event, represented by a bitmask.
534 ///
535 /// See [the NDK
536 /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getmetastate)
537 #[inline]
538 pub fn meta_state(&self) -> MetaState {
539 self.ndk_event.meta_state().into()
540 }
541}
542
543// We use our own wrapper type for input events to have better consistency
544// with GameActivity and ensure the enum can be extended without needing a
545// semver bump
546/// Enum of possible input events
547#[derive(Debug)]
548#[non_exhaustive]
549pub enum InputEvent<'a> {
550 MotionEvent(self::MotionEvent<'a>),
551 KeyEvent(self::KeyEvent<'a>),
552 TextEvent(crate::input::TextInputState),
553 TextAction(crate::input::TextInputAction),
554}