Skip to main content

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}