android_activity/native_activity/
input.rs

1use std::marker::PhantomData;
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<'a> MotionEvent<'a> {
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                ndk_pointers_iter: self.ndk_event.pointers(),
115            },
116        }
117    }
118
119    /// The pointer at a given pointer index. Panics if the pointer index is out of bounds.
120    ///
121    /// If you need to loop over all the pointers, prefer the [`pointers()`](Self::pointers) method.
122    #[inline]
123    pub fn pointer_at_index(&self, index: usize) -> Pointer<'_> {
124        Pointer {
125            inner: PointerImpl {
126                ndk_pointer: self.ndk_event.pointer_at_index(index),
127            },
128        }
129    }
130
131    /*
132    XXX: Not currently supported with GameActivity so we don't currently expose for NativeActivity
133    either, for consistency.
134
135    /// Returns the size of the history contained in this event.
136    ///
137    /// See [the NDK
138    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_gethistorysize)
139    #[inline]
140    pub fn history_size(&self) -> usize {
141        self.ndk_event.history_size()
142    }
143
144    /// An iterator over the historical events contained in this event.
145    #[inline]
146    pub fn history(&self) -> HistoricalMotionEventsIter<'_> {
147        self.ndk_event.history()
148    }
149    */
150
151    /// Returns the state of any modifier keys that were pressed during the event.
152    ///
153    /// See [the NDK
154    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getmetastate)
155    #[inline]
156    pub fn meta_state(&self) -> MetaState {
157        self.ndk_event.meta_state().into()
158    }
159
160    /// Returns the button state during this event, as a bitfield.
161    ///
162    /// See [the NDK
163    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getbuttonstate)
164    #[inline]
165    pub fn button_state(&self) -> ButtonState {
166        self.ndk_event.button_state().into()
167    }
168
169    /// Returns the time of the start of this gesture, in the `java.lang.System.nanoTime()` time
170    /// base
171    ///
172    /// See [the NDK
173    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getdowntime)
174    #[inline]
175    pub fn down_time(&self) -> i64 {
176        self.ndk_event.down_time()
177    }
178
179    /// Returns a bitfield indicating which edges were touched by this event.
180    ///
181    /// See [the NDK
182    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getedgeflags)
183    #[inline]
184    pub fn edge_flags(&self) -> EdgeFlags {
185        self.ndk_event.edge_flags().into()
186    }
187
188    /// Returns the time of this event, in the `java.lang.System.nanoTime()` time base
189    ///
190    /// See [the NDK
191    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_geteventtime)
192    #[inline]
193    pub fn event_time(&self) -> i64 {
194        self.ndk_event.event_time()
195    }
196
197    /// The flags associated with a motion event.
198    ///
199    /// See [the NDK
200    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getflags)
201    #[inline]
202    pub fn flags(&self) -> MotionEventFlags {
203        self.ndk_event.flags().into()
204    }
205
206    /* Missing from GameActivity currently...
207    /// Returns the offset in the x direction between the coordinates and the raw coordinates
208    ///
209    /// See [the NDK
210    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getxoffset)
211    #[inline]
212    pub fn x_offset(&self) -> f32 {
213        self.ndk_event.x_offset()
214    }
215
216    /// Returns the offset in the y direction between the coordinates and the raw coordinates
217    ///
218    /// See [the NDK
219    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getyoffset)
220    #[inline]
221    pub fn y_offset(&self) -> f32 {
222        self.ndk_event.y_offset()
223    }
224    */
225
226    /// Returns the precision of the x value of the coordinates
227    ///
228    /// See [the NDK
229    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getxprecision)
230    #[inline]
231    pub fn x_precision(&self) -> f32 {
232        self.ndk_event.x_precision()
233    }
234
235    /// Returns the precision of the y value of the coordinates
236    ///
237    /// See [the NDK
238    /// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getyprecision)
239    #[inline]
240    pub fn y_precision(&self) -> f32 {
241        self.ndk_event.y_precision()
242    }
243}
244
245/// A view into the data of a specific pointer in a motion event.
246#[derive(Debug)]
247pub(crate) struct PointerImpl<'a> {
248    ndk_pointer: ndk::event::Pointer<'a>,
249}
250
251impl<'a> PointerImpl<'a> {
252    #[inline]
253    pub fn pointer_index(&self) -> usize {
254        self.ndk_pointer.pointer_index()
255    }
256
257    #[inline]
258    pub fn pointer_id(&self) -> i32 {
259        self.ndk_pointer.pointer_id()
260    }
261
262    #[inline]
263    pub fn axis_value(&self, axis: Axis) -> f32 {
264        let value: u32 = axis.into();
265        let value = value as i32;
266        self.ndk_pointer.axis_value(value.into())
267    }
268
269    #[inline]
270    pub fn raw_x(&self) -> f32 {
271        self.ndk_pointer.raw_x()
272    }
273
274    #[inline]
275    pub fn raw_y(&self) -> f32 {
276        self.ndk_pointer.raw_y()
277    }
278
279    #[inline]
280    pub fn tool_type(&self) -> ToolType {
281        let value: i32 = self.ndk_pointer.tool_type().into();
282        let value = value as u32;
283        value.into()
284    }
285}
286
287/// An iterator over the pointers in a [`MotionEvent`].
288#[derive(Debug)]
289pub(crate) struct PointersIterImpl<'a> {
290    ndk_pointers_iter: ndk::event::PointersIter<'a>,
291}
292
293impl<'a> Iterator for PointersIterImpl<'a> {
294    type Item = Pointer<'a>;
295    fn next(&mut self) -> Option<Pointer<'a>> {
296        self.ndk_pointers_iter.next().map(|ndk_pointer| Pointer {
297            inner: PointerImpl { ndk_pointer },
298        })
299    }
300
301    fn size_hint(&self) -> (usize, Option<usize>) {
302        self.ndk_pointers_iter.size_hint()
303    }
304}
305
306impl<'a> ExactSizeIterator for PointersIterImpl<'a> {
307    fn len(&self) -> usize {
308        self.ndk_pointers_iter.len()
309    }
310}
311
312/// A key event
313///
314/// For general discussion of key events in Android, see [the relevant
315/// javadoc](https://developer.android.com/reference/android/view/KeyEvent).
316#[derive(Debug)]
317#[repr(transparent)]
318pub struct KeyEvent<'a> {
319    ndk_event: ndk::event::KeyEvent,
320    _lifetime: PhantomData<&'a ndk::event::KeyEvent>,
321}
322impl<'a> KeyEvent<'a> {
323    pub(crate) fn new(ndk_event: ndk::event::KeyEvent) -> Self {
324        Self {
325            ndk_event,
326            _lifetime: PhantomData,
327        }
328    }
329    pub(crate) fn into_ndk_event(self) -> ndk::event::KeyEvent {
330        self.ndk_event
331    }
332
333    /// Get the source of the event.
334    ///
335    #[inline]
336    pub fn source(&self) -> Source {
337        // XXX: we use `AInputEvent_getSource` directly (instead of calling
338        // ndk_event.source()) since we have our own `Source` enum that we
339        // share between backends, which may also capture unknown variants
340        // added in new versions of Android.
341        let source =
342            unsafe { ndk_sys::AInputEvent_getSource(self.ndk_event.ptr().as_ptr()) as u32 };
343        source.into()
344    }
345
346    /// Get the device id associated with the event.
347    ///
348    #[inline]
349    pub fn device_id(&self) -> i32 {
350        self.ndk_event.device_id()
351    }
352
353    /// Returns the key action associated with the event.
354    ///
355    /// See [the KeyEvent docs](https://developer.android.com/reference/android/view/KeyEvent#getAction())
356    #[inline]
357    pub fn action(&self) -> KeyAction {
358        // XXX: we use `AInputEvent_getAction` directly since we have our own
359        // `KeyAction` enum that we share between backends, which may also
360        // capture unknown variants added in new versions of Android.
361        let action = unsafe { ndk_sys::AKeyEvent_getAction(self.ndk_event.ptr().as_ptr()) as u32 };
362        action.into()
363    }
364
365    /// Returns the last time the key was pressed.  This is on the scale of
366    /// `java.lang.System.nanoTime()`, which has nanosecond precision, but no defined start time.
367    ///
368    /// See [the NDK
369    /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getdowntime)
370    #[inline]
371    pub fn down_time(&self) -> i64 {
372        self.ndk_event.down_time()
373    }
374
375    /// Returns the time this event occured.  This is on the scale of
376    /// `java.lang.System.nanoTime()`, which has nanosecond precision, but no defined start time.
377    ///
378    /// See [the NDK
379    /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_geteventtime)
380    #[inline]
381    pub fn event_time(&self) -> i64 {
382        self.ndk_event.event_time()
383    }
384
385    /// Returns the keycode associated with this key event
386    ///
387    /// See [the NDK
388    /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getkeycode)
389    #[inline]
390    pub fn key_code(&self) -> Keycode {
391        // XXX: we use `AInputEvent_getKeyCode` directly since we have our own
392        // `Keycode` enum that we share between backends, which may also
393        // capture unknown variants added in new versions of Android.
394        let keycode =
395            unsafe { ndk_sys::AKeyEvent_getKeyCode(self.ndk_event.ptr().as_ptr()) as u32 };
396        keycode.into()
397    }
398
399    /// Returns the number of repeats of a key.
400    ///
401    /// See [the NDK
402    /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getrepeatcount)
403    #[inline]
404    pub fn repeat_count(&self) -> i32 {
405        self.ndk_event.repeat_count()
406    }
407
408    /// Returns the hardware keycode of a key.  This varies from device to device.
409    ///
410    /// See [the NDK
411    /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getscancode)
412    #[inline]
413    pub fn scan_code(&self) -> i32 {
414        self.ndk_event.scan_code()
415    }
416
417    /// Returns the state of the modifiers during this key event, represented by a bitmask.
418    ///
419    /// See [the NDK
420    /// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getmetastate)
421    #[inline]
422    pub fn meta_state(&self) -> MetaState {
423        self.ndk_event.meta_state().into()
424    }
425}
426
427// We use our own wrapper type for input events to have better consistency
428// with GameActivity and ensure the enum can be extended without needing a
429// semver bump
430/// Enum of possible input events
431#[derive(Debug)]
432#[non_exhaustive]
433pub enum InputEvent<'a> {
434    MotionEvent(self::MotionEvent<'a>),
435    KeyEvent(self::KeyEvent<'a>),
436    TextEvent(crate::input::TextInputState),
437}