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}