Compare commits

...

4 Commits

Author SHA1 Message Date
Marijn Suijten ea5932b272 Revert "input: Replace open-coded types with ndk::event definitions (#163)"
This reverts commit 51d05d48c8 for
backwards compatibility with the existing `0.6` releases.
2026-01-08 00:43:13 +00:00
Robert Bragg 618c8d6de5 game-activty: ignore APP_CMD_SOFTWARE_KB_VIS_CHANGED w/o panic
APP_CMD_SOFTWARE_KB_VIS_CHANGED in the GameActivity backend is
intended for notifying the android_main thread that the soft keyboard
visibility has changed.

There's currently no Rust event / API for this, and so it wasn't being
handled in poll_events but that was leading to a unreachable panic when
GameActivity would send this APP_CMD when showing soft keyboards.

We don't currently plan to expose any public API / event for this since
it's based on monitoring IME insets and applications should instead be able
to check insets after getting InsetsChanged events.

For the sake of minimizing patches to the upstream GameActivity code
this makes it so poll_events can ignore this APP_CMD as a NOOP.
2026-01-08 00:40:48 +00:00
Robert Bragg 23c9933354 Add support for InputEvent::TextAction events
This exposes IME actions via an InputEvent::TextAction event so that
it's possible to recognise when text entry via an input method is
finished.

This adds an `TextInputAction` enum to represent the action key on a soft
keyboard, such as "Done".

For example, this makes it possible to emit Ime::Commit events in Winit.
2026-01-08 00:32:41 +00:00
Robert Bragg 8912aaba71 Import android-games-sdk changes for 4.0.0
This imports the SDK from commit 8fa58b0e145ec28e726fa2b1c7e7a52af925ca35, from:
https://github.com/rust-mobile/android-games-sdk/commits/android-activity-4.0.0

This includes one "notify android_main of editor actions" patch which will make
it possible to forward editor actions and support IME Commit events in Winit)

# notify android_main of editor actions

This adds a pendingEditorActions member to android_app that is set via
onEditorAction and the android_main thread is notified via notifyInput
instead of re-instating APP_CMD_EDITOR_ACTION.

The idea is that the android_main thread should check for
android_app->pendingEditorActions whenever input events are polled/iterated.

# FFI bindings update

Also updates the FFI bindings via generate-bindings.sh
2026-01-07 23:51:13 +00:00
13 changed files with 1165 additions and 195 deletions
+6 -11
View File
@@ -6,19 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Changed
- input: Replaced custom types with their `ndk` crate equivalent.
> [!NOTE]
> These types existed because the `ndk` crate didn't provide them in an extensible way. Now that they have the `#[non_exhaustive]` flag and contain a `__Unknown(T)` variant to provide lossless conversions, and not to mention use an ABI type that matches how it is being used by most functions (when the original constants were defined in a "typeless" way), the `ndk` types are used and reexported once again.
### Added
> [!IMPORTANT]
> **Relevant breaking changes**:
> - `repr()` types for some `enum`s have changed to match the ABI type that is used by most functions that are returning or consuming this wrapper type.
> - `Source::is_xxx_class()` functions are replaced by querying `Source::class()` and comparing against variants from the returned `SourceClass` `bitflags` enum.
> - `SourceFlags::TRACKBALL` (from `Source::is_trackball_class()`) is named `SourceClass::NAVIGATION` in the `ndk`.
- rust-version bumped to 1.73.0 ([#193](https://github.com/rust-mobile/android-activity/pull/193))
- The `ndk` and `ndk-sys` crates are now re-exported under `android_activity::ndk` and `android_activity::ndk_sys` ([#194](https://github.com/rust-mobile/android-activity/pull/194))
- input: TextInputAction enum representing action button types on soft keyboards.
- input: InputEvent::TextAction event for handling action button presses from soft keyboards.
### Changed
- rust-version bumped to 1.73.0 ([#193](https://github.com/rust-mobile/android-activity/pull/193))
- GameActivity updated to 4.0.0 (requires the corresponding 4.0.0 `.aar` release from Google) ([#191](https://github.com/rust-mobile/android-activity/pull/191))
## [0.6.0] - 2024-04-26
-1
View File
@@ -32,7 +32,6 @@ default = []
game-activity = []
native-activity = []
api-level-30 = ["ndk/api-level-30"]
api-level-33 = ["api-level-30", "ndk/api-level-33"]
[dependencies]
log = "0.4"
@@ -226,6 +226,10 @@ struct android_app {
* thread, so we can't say that this is only valid within the `APP_CMD_` handler.
*/
int editorAction;
/**
* true when editorAction has been set
*/
bool pendingEditorAction;
/**
* Current state of the app's activity. May be either APP_CMD_START,
@@ -726,9 +726,15 @@ static bool onEditorAction(GameActivity* activity, int action) {
// XXX: this is a racy design that could lose InputConnection actions if the
// application doesn't manage to look at app->editorAction before another
// action is delivered.
if (android_app->pendingEditorAction) {
LOGW("Dropping editor action %d because previous action %d not yet "
"handled",
action, android_app->editorAction);
}
android_app->editorAction = action;
// TODO: buffer these actions like other input events
//notifyInput(android_app);
android_app->pendingEditorAction = true;
notifyInput(android_app);
// TODO: buffer IME text events and editor actions like other input events
//android_app_write_cmd(android_app, APP_CMD_EDITOR_ACTION);
pthread_mutex_unlock(&android_app->mutex);
@@ -6259,6 +6259,8 @@ pub struct android_app {
pub softwareKeyboardVisible: bool,
#[doc = " Last editor action. Valid within APP_CMD_SOFTWARE_KB_VIS_CHANGED handler.\n\n Note: the upstream comment above isn't accurate.\n - `APP_CMD_SOFTWARE_KB_VIS_CHANGED` is associated with `softwareKeyboardVisible`\n changes, not `editorAction`.\n - `APP_CMD_EDITOR_ACTION` is associated with this state but unlike for\n `window` state there's no synchonization that blocks the Java main\n thread, so we can't say that this is only valid within the `APP_CMD_` handler."]
pub editorAction: ::std::os::raw::c_int,
#[doc = " true when editorAction has been set"]
pub pendingEditorAction: bool,
#[doc = " Current state of the app's activity. May be either APP_CMD_START,\n APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP."]
pub activityState: ::std::os::raw::c_int,
#[doc = " This is non-zero when the application's GameActivity is being\n destroyed and waiting for the app thread to complete."]
@@ -6292,7 +6294,7 @@ fn bindgen_test_layout_android_app() {
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<android_app>(),
392usize,
400usize,
"Size of android_app"
);
assert_eq!(
@@ -6356,108 +6358,113 @@ fn bindgen_test_layout_android_app() {
"Offset of field: android_app::editorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
unsafe { ::std::ptr::addr_of!((*ptr).pendingEditorAction) as usize - ptr as usize },
88usize,
"Offset of field: android_app::pendingEditorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
92usize,
"Offset of field: android_app::activityState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyRequested) as usize - ptr as usize },
92usize,
96usize,
"Offset of field: android_app::destroyRequested"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputBuffers) as usize - ptr as usize },
96usize,
104usize,
"Offset of field: android_app::inputBuffers"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).currentInputBuffer) as usize - ptr as usize },
192usize,
200usize,
"Offset of field: android_app::currentInputBuffer"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).textInputState) as usize - ptr as usize },
196usize,
204usize,
"Offset of field: android_app::textInputState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).mutex) as usize - ptr as usize },
200usize,
208usize,
"Offset of field: android_app::mutex"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cond) as usize - ptr as usize },
240usize,
248usize,
"Offset of field: android_app::cond"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgread) as usize - ptr as usize },
288usize,
296usize,
"Offset of field: android_app::msgread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgwrite) as usize - ptr as usize },
292usize,
300usize,
"Offset of field: android_app::msgwrite"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).thread) as usize - ptr as usize },
296usize,
304usize,
"Offset of field: android_app::thread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cmdPollSource) as usize - ptr as usize },
304usize,
312usize,
"Offset of field: android_app::cmdPollSource"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).running) as usize - ptr as usize },
328usize,
336usize,
"Offset of field: android_app::running"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).stateSaved) as usize - ptr as usize },
332usize,
340usize,
"Offset of field: android_app::stateSaved"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyed) as usize - ptr as usize },
336usize,
344usize,
"Offset of field: android_app::destroyed"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).redrawNeeded) as usize - ptr as usize },
340usize,
348usize,
"Offset of field: android_app::redrawNeeded"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingWindow) as usize - ptr as usize },
344usize,
352usize,
"Offset of field: android_app::pendingWindow"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingContentRect) as usize - ptr as usize },
352usize,
360usize,
"Offset of field: android_app::pendingContentRect"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).keyEventFilter) as usize - ptr as usize },
368usize,
376usize,
"Offset of field: android_app::keyEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).motionEventFilter) as usize - ptr as usize },
376usize,
384usize,
"Offset of field: android_app::motionEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputAvailableWakeUp) as usize - ptr as usize },
384usize,
392usize,
"Offset of field: android_app::inputAvailableWakeUp"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputSwapPending) as usize - ptr as usize },
385usize,
393usize,
"Offset of field: android_app::inputSwapPending"
);
}
+29 -22
View File
@@ -6724,6 +6724,8 @@ pub struct android_app {
pub softwareKeyboardVisible: bool,
#[doc = " Last editor action. Valid within APP_CMD_SOFTWARE_KB_VIS_CHANGED handler.\n\n Note: the upstream comment above isn't accurate.\n - `APP_CMD_SOFTWARE_KB_VIS_CHANGED` is associated with `softwareKeyboardVisible`\n changes, not `editorAction`.\n - `APP_CMD_EDITOR_ACTION` is associated with this state but unlike for\n `window` state there's no synchonization that blocks the Java main\n thread, so we can't say that this is only valid within the `APP_CMD_` handler."]
pub editorAction: ::std::os::raw::c_int,
#[doc = " true when editorAction has been set"]
pub pendingEditorAction: bool,
#[doc = " Current state of the app's activity. May be either APP_CMD_START,\n APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP."]
pub activityState: ::std::os::raw::c_int,
#[doc = " This is non-zero when the application's GameActivity is being\n destroyed and waiting for the app thread to complete."]
@@ -6757,7 +6759,7 @@ fn bindgen_test_layout_android_app() {
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<android_app>(),
248usize,
256usize,
"Size of android_app"
);
assert_eq!(
@@ -6821,108 +6823,113 @@ fn bindgen_test_layout_android_app() {
"Offset of field: android_app::editorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
unsafe { ::std::ptr::addr_of!((*ptr).pendingEditorAction) as usize - ptr as usize },
56usize,
"Offset of field: android_app::pendingEditorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
60usize,
"Offset of field: android_app::activityState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyRequested) as usize - ptr as usize },
60usize,
64usize,
"Offset of field: android_app::destroyRequested"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputBuffers) as usize - ptr as usize },
64usize,
72usize,
"Offset of field: android_app::inputBuffers"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).currentInputBuffer) as usize - ptr as usize },
160usize,
168usize,
"Offset of field: android_app::currentInputBuffer"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).textInputState) as usize - ptr as usize },
164usize,
172usize,
"Offset of field: android_app::textInputState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).mutex) as usize - ptr as usize },
168usize,
176usize,
"Offset of field: android_app::mutex"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cond) as usize - ptr as usize },
172usize,
180usize,
"Offset of field: android_app::cond"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgread) as usize - ptr as usize },
176usize,
184usize,
"Offset of field: android_app::msgread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgwrite) as usize - ptr as usize },
180usize,
188usize,
"Offset of field: android_app::msgwrite"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).thread) as usize - ptr as usize },
184usize,
192usize,
"Offset of field: android_app::thread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cmdPollSource) as usize - ptr as usize },
188usize,
196usize,
"Offset of field: android_app::cmdPollSource"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).running) as usize - ptr as usize },
200usize,
208usize,
"Offset of field: android_app::running"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).stateSaved) as usize - ptr as usize },
204usize,
212usize,
"Offset of field: android_app::stateSaved"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyed) as usize - ptr as usize },
208usize,
216usize,
"Offset of field: android_app::destroyed"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).redrawNeeded) as usize - ptr as usize },
212usize,
220usize,
"Offset of field: android_app::redrawNeeded"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingWindow) as usize - ptr as usize },
216usize,
224usize,
"Offset of field: android_app::pendingWindow"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingContentRect) as usize - ptr as usize },
220usize,
228usize,
"Offset of field: android_app::pendingContentRect"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).keyEventFilter) as usize - ptr as usize },
236usize,
244usize,
"Offset of field: android_app::keyEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).motionEventFilter) as usize - ptr as usize },
240usize,
248usize,
"Offset of field: android_app::motionEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputAvailableWakeUp) as usize - ptr as usize },
244usize,
252usize,
"Offset of field: android_app::inputAvailableWakeUp"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputSwapPending) as usize - ptr as usize },
245usize,
253usize,
"Offset of field: android_app::inputSwapPending"
);
}
+29 -22
View File
@@ -7442,6 +7442,8 @@ pub struct android_app {
pub softwareKeyboardVisible: bool,
#[doc = " Last editor action. Valid within APP_CMD_SOFTWARE_KB_VIS_CHANGED handler.\n\n Note: the upstream comment above isn't accurate.\n - `APP_CMD_SOFTWARE_KB_VIS_CHANGED` is associated with `softwareKeyboardVisible`\n changes, not `editorAction`.\n - `APP_CMD_EDITOR_ACTION` is associated with this state but unlike for\n `window` state there's no synchonization that blocks the Java main\n thread, so we can't say that this is only valid within the `APP_CMD_` handler."]
pub editorAction: ::std::os::raw::c_int,
#[doc = " true when editorAction has been set"]
pub pendingEditorAction: bool,
#[doc = " Current state of the app's activity. May be either APP_CMD_START,\n APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP."]
pub activityState: ::std::os::raw::c_int,
#[doc = " This is non-zero when the application's GameActivity is being\n destroyed and waiting for the app thread to complete."]
@@ -7475,7 +7477,7 @@ fn bindgen_test_layout_android_app() {
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<android_app>(),
232usize,
236usize,
"Size of android_app"
);
assert_eq!(
@@ -7539,108 +7541,113 @@ fn bindgen_test_layout_android_app() {
"Offset of field: android_app::editorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
unsafe { ::std::ptr::addr_of!((*ptr).pendingEditorAction) as usize - ptr as usize },
56usize,
"Offset of field: android_app::pendingEditorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
60usize,
"Offset of field: android_app::activityState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyRequested) as usize - ptr as usize },
60usize,
64usize,
"Offset of field: android_app::destroyRequested"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputBuffers) as usize - ptr as usize },
64usize,
68usize,
"Offset of field: android_app::inputBuffers"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).currentInputBuffer) as usize - ptr as usize },
144usize,
148usize,
"Offset of field: android_app::currentInputBuffer"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).textInputState) as usize - ptr as usize },
148usize,
152usize,
"Offset of field: android_app::textInputState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).mutex) as usize - ptr as usize },
152usize,
156usize,
"Offset of field: android_app::mutex"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cond) as usize - ptr as usize },
156usize,
160usize,
"Offset of field: android_app::cond"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgread) as usize - ptr as usize },
160usize,
164usize,
"Offset of field: android_app::msgread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgwrite) as usize - ptr as usize },
164usize,
168usize,
"Offset of field: android_app::msgwrite"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).thread) as usize - ptr as usize },
168usize,
172usize,
"Offset of field: android_app::thread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cmdPollSource) as usize - ptr as usize },
172usize,
176usize,
"Offset of field: android_app::cmdPollSource"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).running) as usize - ptr as usize },
184usize,
188usize,
"Offset of field: android_app::running"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).stateSaved) as usize - ptr as usize },
188usize,
192usize,
"Offset of field: android_app::stateSaved"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyed) as usize - ptr as usize },
192usize,
196usize,
"Offset of field: android_app::destroyed"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).redrawNeeded) as usize - ptr as usize },
196usize,
200usize,
"Offset of field: android_app::redrawNeeded"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingWindow) as usize - ptr as usize },
200usize,
204usize,
"Offset of field: android_app::pendingWindow"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingContentRect) as usize - ptr as usize },
204usize,
208usize,
"Offset of field: android_app::pendingContentRect"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).keyEventFilter) as usize - ptr as usize },
220usize,
224usize,
"Offset of field: android_app::keyEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).motionEventFilter) as usize - ptr as usize },
224usize,
228usize,
"Offset of field: android_app::motionEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputAvailableWakeUp) as usize - ptr as usize },
228usize,
232usize,
"Offset of field: android_app::inputAvailableWakeUp"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputSwapPending) as usize - ptr as usize },
229usize,
233usize,
"Offset of field: android_app::inputSwapPending"
);
}
@@ -7466,6 +7466,8 @@ pub struct android_app {
pub softwareKeyboardVisible: bool,
#[doc = " Last editor action. Valid within APP_CMD_SOFTWARE_KB_VIS_CHANGED handler.\n\n Note: the upstream comment above isn't accurate.\n - `APP_CMD_SOFTWARE_KB_VIS_CHANGED` is associated with `softwareKeyboardVisible`\n changes, not `editorAction`.\n - `APP_CMD_EDITOR_ACTION` is associated with this state but unlike for\n `window` state there's no synchonization that blocks the Java main\n thread, so we can't say that this is only valid within the `APP_CMD_` handler."]
pub editorAction: ::std::os::raw::c_int,
#[doc = " true when editorAction has been set"]
pub pendingEditorAction: bool,
#[doc = " Current state of the app's activity. May be either APP_CMD_START,\n APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP."]
pub activityState: ::std::os::raw::c_int,
#[doc = " This is non-zero when the application's GameActivity is being\n destroyed and waiting for the app thread to complete."]
@@ -7499,7 +7501,7 @@ fn bindgen_test_layout_android_app() {
let ptr = UNINIT.as_ptr();
assert_eq!(
::std::mem::size_of::<android_app>(),
392usize,
400usize,
"Size of android_app"
);
assert_eq!(
@@ -7563,108 +7565,113 @@ fn bindgen_test_layout_android_app() {
"Offset of field: android_app::editorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
unsafe { ::std::ptr::addr_of!((*ptr).pendingEditorAction) as usize - ptr as usize },
88usize,
"Offset of field: android_app::pendingEditorAction"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).activityState) as usize - ptr as usize },
92usize,
"Offset of field: android_app::activityState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyRequested) as usize - ptr as usize },
92usize,
96usize,
"Offset of field: android_app::destroyRequested"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputBuffers) as usize - ptr as usize },
96usize,
104usize,
"Offset of field: android_app::inputBuffers"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).currentInputBuffer) as usize - ptr as usize },
192usize,
200usize,
"Offset of field: android_app::currentInputBuffer"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).textInputState) as usize - ptr as usize },
196usize,
204usize,
"Offset of field: android_app::textInputState"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).mutex) as usize - ptr as usize },
200usize,
208usize,
"Offset of field: android_app::mutex"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cond) as usize - ptr as usize },
240usize,
248usize,
"Offset of field: android_app::cond"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgread) as usize - ptr as usize },
288usize,
296usize,
"Offset of field: android_app::msgread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).msgwrite) as usize - ptr as usize },
292usize,
300usize,
"Offset of field: android_app::msgwrite"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).thread) as usize - ptr as usize },
296usize,
304usize,
"Offset of field: android_app::thread"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).cmdPollSource) as usize - ptr as usize },
304usize,
312usize,
"Offset of field: android_app::cmdPollSource"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).running) as usize - ptr as usize },
328usize,
336usize,
"Offset of field: android_app::running"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).stateSaved) as usize - ptr as usize },
332usize,
340usize,
"Offset of field: android_app::stateSaved"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).destroyed) as usize - ptr as usize },
336usize,
344usize,
"Offset of field: android_app::destroyed"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).redrawNeeded) as usize - ptr as usize },
340usize,
348usize,
"Offset of field: android_app::redrawNeeded"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingWindow) as usize - ptr as usize },
344usize,
352usize,
"Offset of field: android_app::pendingWindow"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).pendingContentRect) as usize - ptr as usize },
352usize,
360usize,
"Offset of field: android_app::pendingContentRect"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).keyEventFilter) as usize - ptr as usize },
368usize,
376usize,
"Offset of field: android_app::keyEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).motionEventFilter) as usize - ptr as usize },
376usize,
384usize,
"Offset of field: android_app::motionEventFilter"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputAvailableWakeUp) as usize - ptr as usize },
384usize,
392usize,
"Offset of field: android_app::inputAvailableWakeUp"
);
assert_eq!(
unsafe { ::std::ptr::addr_of!((*ptr).inputSwapPending) as usize - ptr as usize },
385usize,
393usize,
"Offset of field: android_app::inputSwapPending"
);
}
+12 -13
View File
@@ -13,12 +13,10 @@
// The `Class` was also bound differently to `android-ndk-rs` considering how the class is defined
// by masking bits from the `Source`.
use ndk::event::ButtonState;
use crate::activity_impl::ffi::{GameActivityKeyEvent, GameActivityMotionEvent};
use crate::input::{
Axis, Button, EdgeFlags, KeyAction, KeyEventFlags, Keycode, MetaState, MotionAction,
MotionEventFlags, Pointer, PointersIter, Source, ToolType,
Axis, Button, ButtonState, EdgeFlags, KeyAction, KeyEventFlags, Keycode, MetaState,
MotionAction, MotionEventFlags, Pointer, PointersIter, Source, ToolType,
};
// Note: try to keep this wrapper API compatible with the AInputEvent API if possible
@@ -29,6 +27,7 @@ pub enum InputEvent<'a> {
MotionEvent(MotionEvent<'a>),
KeyEvent(KeyEvent<'a>),
TextEvent(crate::input::TextInputState),
TextAction(crate::input::TextInputAction),
}
/// A motion event.
@@ -49,7 +48,7 @@ impl<'a> MotionEvent<'a> {
///
#[inline]
pub fn source(&self) -> Source {
let source = self.ga_event.source;
let source = self.ga_event.source as u32;
source.into()
}
@@ -65,7 +64,7 @@ impl<'a> MotionEvent<'a> {
/// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getActionMasked())
#[inline]
pub fn action(&self) -> MotionAction {
let action = self.ga_event.action & ndk_sys::AMOTION_EVENT_ACTION_MASK as i32;
let action = self.ga_event.action as u32 & ndk_sys::AMOTION_EVENT_ACTION_MASK;
action.into()
}
@@ -178,7 +177,6 @@ impl<'a> MotionEvent<'a> {
/// See [the NDK
/// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getbuttonstate)
#[inline]
// TODO: Button enum to signify only one bitflag can be set?
pub fn button_state(&self) -> ButtonState {
ButtonState(self.ga_event.buttonState as u32)
}
@@ -281,7 +279,7 @@ impl PointerImpl<'_> {
#[inline]
pub fn axis_value(&self, axis: Axis) -> f32 {
let pointer = &self.event.ga_event.pointers[self.index];
let axis: i32 = axis.into();
let axis: u32 = axis.into();
pointer.axisValues[axis as usize]
}
@@ -300,7 +298,8 @@ impl PointerImpl<'_> {
#[inline]
pub fn tool_type(&self) -> ToolType {
let pointer = &self.event.ga_event.pointers[self.index];
pointer.toolType.into()
let tool_type = pointer.toolType as u32;
tool_type.into()
}
}
@@ -667,7 +666,7 @@ impl<'a> KeyEvent<'a> {
///
#[inline]
pub fn source(&self) -> Source {
let source = self.ga_event.source;
let source = self.ga_event.source as u32;
source.into()
}
@@ -683,13 +682,13 @@ impl<'a> KeyEvent<'a> {
/// See [the KeyEvent docs](https://developer.android.com/reference/android/view/KeyEvent#getAction())
#[inline]
pub fn action(&self) -> KeyAction {
let action = self.ga_event.action;
let action = self.ga_event.action as u32;
action.into()
}
#[inline]
pub fn action_button(&self) -> KeyAction {
let action = self.ga_event.action;
let action = self.ga_event.action as u32;
action.into()
}
@@ -719,7 +718,7 @@ impl<'a> KeyEvent<'a> {
/// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getkeycode)
#[inline]
pub fn key_code(&self) -> Keycode {
let keycode = self.ga_event.keyCode;
let keycode = self.ga_event.keyCode as u32;
keycode.into()
}
+105 -53
View File
@@ -21,7 +21,7 @@ use ndk::configuration::Configuration;
use ndk::native_window::NativeWindow;
use crate::error::InternalResult;
use crate::input::{Axis, KeyCharacterMap, KeyCharacterMapBinding};
use crate::input::{Axis, KeyCharacterMap, KeyCharacterMapBinding, TextInputAction};
use crate::jni_utils::{self, CloneJavaVM};
use crate::util::{abort_on_panic, forward_stdio_to_logcat, log_panic, try_get_path_from_ptr};
use crate::{
@@ -174,9 +174,6 @@ impl NativeAppGlue {
};
let out_ptr = &mut out_state as *mut TextInputState;
let app_ptr = self.as_ptr();
(*app_ptr).textInputState = 0;
// NEON WARNING:
//
// It's not clearly documented but the GameActivity API over the
@@ -204,6 +201,14 @@ impl NativeAppGlue {
}
}
pub fn take_text_input_state(&self) -> TextInputState {
unsafe {
let app_ptr = self.as_ptr();
(*app_ptr).textInputState = 0;
}
self.text_input_state()
}
// TODO: move into a trait
pub fn set_text_input_state(&self, state: TextInputState) {
unsafe {
@@ -247,6 +252,18 @@ impl NativeAppGlue {
ffi::GameActivity_setTextInputState(activity, &ffi_state as *const _);
}
}
pub fn take_pending_editor_action(&self) -> Option<i32> {
unsafe {
let app_ptr = self.as_ptr();
if (*app_ptr).pendingEditorAction {
(*app_ptr).pendingEditorAction = false;
Some((*app_ptr).editorAction)
} else {
None
}
}
}
}
#[derive(Debug)]
@@ -351,46 +368,61 @@ impl AndroidAppInner {
let cmd = match cmd_i as ffi::NativeAppGlueAppCmd {
//NativeAppGlueAppCmd_UNUSED_APP_CMD_INPUT_CHANGED => AndroidAppMainEvent::InputChanged,
ffi::NativeAppGlueAppCmd_APP_CMD_INIT_WINDOW => {
MainEvent::InitWindow {}
Some(MainEvent::InitWindow {})
}
ffi::NativeAppGlueAppCmd_APP_CMD_TERM_WINDOW => {
MainEvent::TerminateWindow {}
Some(MainEvent::TerminateWindow {})
}
ffi::NativeAppGlueAppCmd_APP_CMD_WINDOW_RESIZED => {
MainEvent::WindowResized {}
Some(MainEvent::WindowResized {})
}
ffi::NativeAppGlueAppCmd_APP_CMD_WINDOW_REDRAW_NEEDED => {
MainEvent::RedrawNeeded {}
Some(MainEvent::RedrawNeeded {})
}
ffi::NativeAppGlueAppCmd_APP_CMD_CONTENT_RECT_CHANGED => {
MainEvent::ContentRectChanged {}
Some(MainEvent::ContentRectChanged {})
}
ffi::NativeAppGlueAppCmd_APP_CMD_GAINED_FOCUS => {
MainEvent::GainedFocus
Some(MainEvent::GainedFocus)
}
ffi::NativeAppGlueAppCmd_APP_CMD_LOST_FOCUS => {
MainEvent::LostFocus
Some(MainEvent::LostFocus)
}
ffi::NativeAppGlueAppCmd_APP_CMD_CONFIG_CHANGED => {
MainEvent::ConfigChanged {}
Some(MainEvent::ConfigChanged {})
}
ffi::NativeAppGlueAppCmd_APP_CMD_LOW_MEMORY => {
MainEvent::LowMemory
Some(MainEvent::LowMemory)
}
ffi::NativeAppGlueAppCmd_APP_CMD_START => {
Some(MainEvent::Start)
}
ffi::NativeAppGlueAppCmd_APP_CMD_RESUME => {
Some(MainEvent::Resume {
loader: StateLoader { app: self },
})
}
ffi::NativeAppGlueAppCmd_APP_CMD_START => MainEvent::Start,
ffi::NativeAppGlueAppCmd_APP_CMD_RESUME => MainEvent::Resume {
loader: StateLoader { app: self },
},
ffi::NativeAppGlueAppCmd_APP_CMD_SAVE_STATE => {
MainEvent::SaveState {
Some(MainEvent::SaveState {
saver: StateSaver { app: self },
}
})
}
ffi::NativeAppGlueAppCmd_APP_CMD_PAUSE => {
Some(MainEvent::Pause)
}
ffi::NativeAppGlueAppCmd_APP_CMD_STOP => Some(MainEvent::Stop),
ffi::NativeAppGlueAppCmd_APP_CMD_DESTROY => {
Some(MainEvent::Destroy)
}
ffi::NativeAppGlueAppCmd_APP_CMD_PAUSE => MainEvent::Pause,
ffi::NativeAppGlueAppCmd_APP_CMD_STOP => MainEvent::Stop,
ffi::NativeAppGlueAppCmd_APP_CMD_DESTROY => MainEvent::Destroy,
ffi::NativeAppGlueAppCmd_APP_CMD_WINDOW_INSETS_CHANGED => {
MainEvent::InsetsChanged {}
Some(MainEvent::InsetsChanged {})
}
ffi::NativeAppGlueAppCmd_APP_CMD_SOFTWARE_KB_VIS_CHANGED => {
// NOOP: we ignore these events because they are driven by a
// potentially-unreliable heuristic (based on watching for
// inset changes) and we don't currently have a public event
// for exposing this state.
None
}
_ => unreachable!(),
};
@@ -399,30 +431,35 @@ impl AndroidAppInner {
trace!("Calling android_app_pre_exec_cmd({cmd_i})");
ffi::android_app_pre_exec_cmd(native_app.as_ptr(), cmd_i);
match cmd {
MainEvent::ConfigChanged { .. } => {
self.config.replace(Configuration::clone_from_ptr(
NonNull::new_unchecked((*native_app.as_ptr()).config),
));
}
MainEvent::InitWindow { .. } => {
let win_ptr = (*native_app.as_ptr()).window;
// It's important that we use ::clone_from_ptr() here
// because NativeWindow has a Drop implementation that
// will unconditionally _release() the native window
*self.native_window.write().unwrap() =
Some(NativeWindow::clone_from_ptr(
NonNull::new(win_ptr).unwrap(),
));
}
MainEvent::TerminateWindow { .. } => {
*self.native_window.write().unwrap() = None;
}
_ => {}
}
trace!("Invoking callback for ID_MAIN command = {:?}", cmd);
callback(PollEvent::Main(cmd));
if let Some(cmd) = cmd {
match cmd {
MainEvent::ConfigChanged { .. } => {
self.config.replace(Configuration::clone_from_ptr(
NonNull::new_unchecked(
(*native_app.as_ptr()).config,
),
));
}
MainEvent::InitWindow { .. } => {
let win_ptr = (*native_app.as_ptr()).window;
// It's important that we use ::clone_from_ptr() here
// because NativeWindow has a Drop implementation that
// will unconditionally _release() the native window
*self.native_window.write().unwrap() =
Some(NativeWindow::clone_from_ptr(
NonNull::new(win_ptr).unwrap(),
));
}
MainEvent::TerminateWindow { .. } => {
*self.native_window.write().unwrap() = None;
}
_ => {}
}
trace!("Invoking callback for ID_MAIN command = {:?}", cmd);
callback(PollEvent::Main(cmd));
}
trace!("Calling android_app_post_exec_cmd({cmd_i})");
ffi::android_app_post_exec_cmd(native_app.as_ptr(), cmd_i);
@@ -547,11 +584,13 @@ impl AndroidAppInner {
}
pub fn enable_motion_axis(&mut self, axis: Axis) {
unsafe { ffi::GameActivityPointerAxes_enableAxis(axis.into()) }
let axis: u32 = axis.into();
unsafe { ffi::GameActivityPointerAxes_enableAxis(axis as i32) }
}
pub fn disable_motion_axis(&mut self, axis: Axis) {
unsafe { ffi::GameActivityPointerAxes_disableAxis(axis.into()) }
let axis: u32 = axis.into();
unsafe { ffi::GameActivityPointerAxes_disableAxis(axis as i32) }
}
pub fn create_waker(&self) -> AndroidAppWaker {
@@ -782,7 +821,8 @@ impl<'a> From<Arc<InputReceiver>> for InputIteratorInner<'a> {
_receiver: receiver,
buffered,
native_app,
text_event_checked: false,
ime_text_input_state_checked: false,
ime_editor_action_checked: false,
}
}
}
@@ -799,7 +839,8 @@ pub(crate) struct InputIteratorInner<'a> {
buffered: Option<BufferedEvents<'a>>,
native_app: NativeAppGlue,
text_event_checked: bool,
ime_text_input_state_checked: bool,
ime_editor_action_checked: bool,
}
impl InputIteratorInner<'_> {
@@ -819,8 +860,10 @@ impl InputIteratorInner<'_> {
self.buffered = None;
}
if !self.text_event_checked {
self.text_event_checked = true;
// We make sure any input state changes are sent before we check
// for editor actions, so actions will apply to the latest state.
if !self.ime_text_input_state_checked {
self.ime_text_input_state_checked = true;
unsafe {
let app_ptr = self.native_app.as_ptr();
@@ -832,12 +875,21 @@ impl InputIteratorInner<'_> {
// the compiler isn't reordering code so this gets flagged
// before the java main thread really updates the state.
if (*app_ptr).textInputState != 0 {
let state = self.native_app.text_input_state(); // Will clear .textInputState
let state = self.native_app.take_text_input_state(); // Will clear .textInputState
let _ = callback(&InputEvent::TextEvent(state));
return true;
}
}
}
if !self.ime_editor_action_checked {
self.ime_editor_action_checked = true;
if let Some(action) = self.native_app.take_pending_editor_action() {
let _ = callback(&InputEvent::TextAction(TextInputAction::from(action)));
return true;
}
}
false
}
}
+860 -4
View File
@@ -1,7 +1,4 @@
pub use ndk::event::{
Axis, EdgeFlags, KeyAction, KeyEventFlags, Keycode, MetaState, MotionAction, MotionEventFlags,
Source, SourceClass, ToolType,
};
use bitflags::bitflags;
pub use crate::activity_impl::input::*;
use crate::InputStatus;
@@ -9,6 +6,238 @@ use crate::InputStatus;
mod sdk;
pub use sdk::*;
/// An enum representing the source of an [`MotionEvent`] or [`KeyEvent`]
///
/// See [the InputDevice docs](https://developer.android.com/reference/android/view/InputDevice#SOURCE_ANY)
///
/// # Android Extensible Enum
///
/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and
/// should be handled similar to a `#[non_exhaustive]` enum to maintain
/// forwards compatibility.
///
/// This implements `Into<u32>` and `From<u32>` for converting to/from Android
/// SDK integer values.
///
#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
#[non_exhaustive]
#[repr(u32)]
pub enum Source {
BluetoothStylus = 0x0000c002,
Dpad = 0x00000201,
/// Either a gamepad or a joystick
Gamepad = 0x00000401,
Hdmi = 0x02000001,
/// Either a gamepad or a joystick
Joystick = 0x01000010,
/// Pretty much any device with buttons. Query the keyboard type to determine
/// if it has alphabetic keys and can be used for text entry.
Keyboard = 0x00000101,
/// A pointing device, such as a mouse or trackpad
Mouse = 0x00002002,
/// A pointing device, such as a mouse or trackpad whose relative motions should be treated as navigation events
MouseRelative = 0x00020004,
/// An input device akin to a scroll wheel
RotaryEncoder = 0x00400000,
Sensor = 0x04000000,
Stylus = 0x00004002,
Touchpad = 0x00100008,
Touchscreen = 0x00001002,
TouchNavigation = 0x00200000,
Trackball = 0x00010004,
// We need to consider that the enum variants may be extended across
// different versions of Android (i.e. effectively at runtime) but at the
// same time we don't want it to be an API break to extend this enum in
// future releases of `android-activity` with new variants from the latest
// NDK/SDK.
//
// We can't just use `#[non_exhaustive]` because that only really helps
// when adding new variants in sync with android-activity releases.
//
// On the other hand we also can't rely on a catch-all `Unknown(u32)` that
// only really helps with unknown variants seen at runtime.
//
// What we aim for instead is to have a hidden catch-all variant that
// is considered (practically) unmatchable so code is forced to have
// a `unknown => {}` catch-all pattern match that will cover unknown variants
// either in the form of Rust variants added in future versions or
// in the form of an `__Unknown(u32)` integer that represents an unknown
// variant seen at runtime.
//
// Any `unknown => {}` pattern match can rely on `IntoPrimitive` to convert
// the `unknown` variant to the integer that comes from the Android SDK
// in case that values needs to be passed on, even without knowing its
// semantic meaning at compile time.
#[doc(hidden)]
#[num_enum(catch_all)]
__Unknown(u32),
}
// ndk_sys doesn't currently have the `TRACKBALL` flag so we define our
// own internal class constants for now
bitflags! {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
struct SourceFlags: u32 {
const CLASS_MASK = 0x000000ff;
const BUTTON = 0x00000001;
const POINTER = 0x00000002;
const TRACKBALL = 0x00000004;
const POSITION = 0x00000008;
const JOYSTICK = 0x00000010;
const NONE = 0;
}
}
impl Source {
#[inline]
pub fn is_button_class(self) -> bool {
let class = SourceFlags::from_bits_truncate(self.into());
class.contains(SourceFlags::BUTTON)
}
#[inline]
pub fn is_pointer_class(self) -> bool {
let class = SourceFlags::from_bits_truncate(self.into());
class.contains(SourceFlags::POINTER)
}
#[inline]
pub fn is_trackball_class(self) -> bool {
let class = SourceFlags::from_bits_truncate(self.into());
class.contains(SourceFlags::TRACKBALL)
}
#[inline]
pub fn is_position_class(self) -> bool {
let class = SourceFlags::from_bits_truncate(self.into());
class.contains(SourceFlags::POSITION)
}
#[inline]
pub fn is_joystick_class(self) -> bool {
let class = SourceFlags::from_bits_truncate(self.into());
class.contains(SourceFlags::JOYSTICK)
}
}
/// A bitfield representing the state of modifier keys during an event.
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-25)
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MetaState(pub u32);
impl MetaState {
#[inline]
pub fn alt_on(self) -> bool {
self.0 & ndk_sys::AMETA_ALT_ON != 0
}
#[inline]
pub fn alt_left_on(self) -> bool {
self.0 & ndk_sys::AMETA_ALT_LEFT_ON != 0
}
#[inline]
pub fn alt_right_on(self) -> bool {
self.0 & ndk_sys::AMETA_ALT_RIGHT_ON != 0
}
#[inline]
pub fn shift_on(self) -> bool {
self.0 & ndk_sys::AMETA_SHIFT_ON != 0
}
#[inline]
pub fn shift_left_on(self) -> bool {
self.0 & ndk_sys::AMETA_SHIFT_LEFT_ON != 0
}
#[inline]
pub fn shift_right_on(self) -> bool {
self.0 & ndk_sys::AMETA_SHIFT_RIGHT_ON != 0
}
#[inline]
pub fn sym_on(self) -> bool {
self.0 & ndk_sys::AMETA_SYM_ON != 0
}
#[inline]
pub fn function_on(self) -> bool {
self.0 & ndk_sys::AMETA_FUNCTION_ON != 0
}
#[inline]
pub fn ctrl_on(self) -> bool {
self.0 & ndk_sys::AMETA_CTRL_ON != 0
}
#[inline]
pub fn ctrl_left_on(self) -> bool {
self.0 & ndk_sys::AMETA_CTRL_LEFT_ON != 0
}
#[inline]
pub fn ctrl_right_on(self) -> bool {
self.0 & ndk_sys::AMETA_CTRL_RIGHT_ON != 0
}
#[inline]
pub fn meta_on(self) -> bool {
self.0 & ndk_sys::AMETA_META_ON != 0
}
#[inline]
pub fn meta_left_on(self) -> bool {
self.0 & ndk_sys::AMETA_META_LEFT_ON != 0
}
#[inline]
pub fn meta_right_on(self) -> bool {
self.0 & ndk_sys::AMETA_META_RIGHT_ON != 0
}
#[inline]
pub fn caps_lock_on(self) -> bool {
self.0 & ndk_sys::AMETA_CAPS_LOCK_ON != 0
}
#[inline]
pub fn num_lock_on(self) -> bool {
self.0 & ndk_sys::AMETA_NUM_LOCK_ON != 0
}
#[inline]
pub fn scroll_lock_on(self) -> bool {
self.0 & ndk_sys::AMETA_SCROLL_LOCK_ON != 0
}
}
impl From<ndk::event::MetaState> for MetaState {
fn from(value: ndk::event::MetaState) -> Self {
Self(value.0)
}
}
/// A motion action.
///
/// See [the NDK
/// docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-29)
///
/// # Android Extensible Enum
///
/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and
/// should be handled similar to a `#[non_exhaustive]` enum to maintain
/// forwards compatibility.
///
/// This implements `Into<u32>` and `From<u32>` for converting to/from Android
/// SDK integer values.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
#[non_exhaustive]
#[repr(u32)]
pub enum MotionAction {
Down = ndk_sys::AMOTION_EVENT_ACTION_DOWN,
Up = ndk_sys::AMOTION_EVENT_ACTION_UP,
Move = ndk_sys::AMOTION_EVENT_ACTION_MOVE,
Cancel = ndk_sys::AMOTION_EVENT_ACTION_CANCEL,
Outside = ndk_sys::AMOTION_EVENT_ACTION_OUTSIDE,
PointerDown = ndk_sys::AMOTION_EVENT_ACTION_POINTER_DOWN,
PointerUp = ndk_sys::AMOTION_EVENT_ACTION_POINTER_UP,
HoverMove = ndk_sys::AMOTION_EVENT_ACTION_HOVER_MOVE,
Scroll = ndk_sys::AMOTION_EVENT_ACTION_SCROLL,
HoverEnter = ndk_sys::AMOTION_EVENT_ACTION_HOVER_ENTER,
HoverExit = ndk_sys::AMOTION_EVENT_ACTION_HOVER_EXIT,
ButtonPress = ndk_sys::AMOTION_EVENT_ACTION_BUTTON_PRESS,
ButtonRelease = ndk_sys::AMOTION_EVENT_ACTION_BUTTON_RELEASE,
#[doc(hidden)]
#[num_enum(catch_all)]
__Unknown(u32),
}
/// Identifies buttons that are associated with motion events.
///
/// See [the NDK
@@ -40,6 +269,606 @@ pub enum Button {
__Unknown(u32),
}
/// An axis of a motion event.
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-32)
///
/// # Android Extensible Enum
///
/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and
/// should be handled similar to a `#[non_exhaustive]` enum to maintain
/// forwards compatibility.
///
/// This implements `Into<u32>` and `From<u32>` for converting to/from Android
/// SDK integer values.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
#[non_exhaustive]
#[repr(u32)]
pub enum Axis {
X = ndk_sys::AMOTION_EVENT_AXIS_X,
Y = ndk_sys::AMOTION_EVENT_AXIS_Y,
Pressure = ndk_sys::AMOTION_EVENT_AXIS_PRESSURE,
Size = ndk_sys::AMOTION_EVENT_AXIS_SIZE,
TouchMajor = ndk_sys::AMOTION_EVENT_AXIS_TOUCH_MAJOR,
TouchMinor = ndk_sys::AMOTION_EVENT_AXIS_TOUCH_MINOR,
ToolMajor = ndk_sys::AMOTION_EVENT_AXIS_TOOL_MAJOR,
ToolMinor = ndk_sys::AMOTION_EVENT_AXIS_TOOL_MINOR,
Orientation = ndk_sys::AMOTION_EVENT_AXIS_ORIENTATION,
Vscroll = ndk_sys::AMOTION_EVENT_AXIS_VSCROLL,
Hscroll = ndk_sys::AMOTION_EVENT_AXIS_HSCROLL,
Z = ndk_sys::AMOTION_EVENT_AXIS_Z,
Rx = ndk_sys::AMOTION_EVENT_AXIS_RX,
Ry = ndk_sys::AMOTION_EVENT_AXIS_RY,
Rz = ndk_sys::AMOTION_EVENT_AXIS_RZ,
HatX = ndk_sys::AMOTION_EVENT_AXIS_HAT_X,
HatY = ndk_sys::AMOTION_EVENT_AXIS_HAT_Y,
Ltrigger = ndk_sys::AMOTION_EVENT_AXIS_LTRIGGER,
Rtrigger = ndk_sys::AMOTION_EVENT_AXIS_RTRIGGER,
Throttle = ndk_sys::AMOTION_EVENT_AXIS_THROTTLE,
Rudder = ndk_sys::AMOTION_EVENT_AXIS_RUDDER,
Wheel = ndk_sys::AMOTION_EVENT_AXIS_WHEEL,
Gas = ndk_sys::AMOTION_EVENT_AXIS_GAS,
Brake = ndk_sys::AMOTION_EVENT_AXIS_BRAKE,
Distance = ndk_sys::AMOTION_EVENT_AXIS_DISTANCE,
Tilt = ndk_sys::AMOTION_EVENT_AXIS_TILT,
Scroll = ndk_sys::AMOTION_EVENT_AXIS_SCROLL,
RelativeX = ndk_sys::AMOTION_EVENT_AXIS_RELATIVE_X,
RelativeY = ndk_sys::AMOTION_EVENT_AXIS_RELATIVE_Y,
Generic1 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_1,
Generic2 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_2,
Generic3 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_3,
Generic4 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_4,
Generic5 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_5,
Generic6 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_6,
Generic7 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_7,
Generic8 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_8,
Generic9 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_9,
Generic10 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_10,
Generic11 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_11,
Generic12 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_12,
Generic13 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_13,
Generic14 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_14,
Generic15 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_15,
Generic16 = ndk_sys::AMOTION_EVENT_AXIS_GENERIC_16,
#[doc(hidden)]
#[num_enum(catch_all)]
__Unknown(u32),
}
/// The tool type of a pointer.
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-48)
///
/// # Android Extensible Enum
///
/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and
/// should be handled similar to a `#[non_exhaustive]` enum to maintain
/// forwards compatibility.
///
/// Implements `Into<u32>` and `From<u32>` for converting to/from Android SDK
/// integer values.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
#[non_exhaustive]
#[repr(u32)]
pub enum ToolType {
/// Unknown tool type.
///
/// This constant is used when the tool type is not known or is not relevant, such as for a trackball or other non-pointing device.
Unknown = ndk_sys::AMOTION_EVENT_TOOL_TYPE_UNKNOWN,
/// The tool is a finger.
Finger = ndk_sys::AMOTION_EVENT_TOOL_TYPE_FINGER,
/// The tool is a stylus.
Stylus = ndk_sys::AMOTION_EVENT_TOOL_TYPE_STYLUS,
/// The tool is a mouse.
Mouse = ndk_sys::AMOTION_EVENT_TOOL_TYPE_MOUSE,
/// The tool is an eraser or a stylus being used in an inverted posture.
Eraser = ndk_sys::AMOTION_EVENT_TOOL_TYPE_ERASER,
/// The tool is a palm and should be rejected
Palm = ndk_sys::AMOTION_EVENT_TOOL_TYPE_PALM,
#[doc(hidden)]
#[num_enum(catch_all)]
__Unknown(u32),
}
/// A bitfield representing the state of buttons during a motion event.
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-33)
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ButtonState(pub u32);
impl ButtonState {
#[inline]
pub fn primary(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_BUTTON_PRIMARY != 0
}
#[inline]
pub fn secondary(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_BUTTON_SECONDARY != 0
}
#[inline]
pub fn teriary(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_BUTTON_TERTIARY != 0
}
#[inline]
pub fn back(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_BUTTON_BACK != 0
}
#[inline]
pub fn forward(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_BUTTON_FORWARD != 0
}
#[inline]
pub fn stylus_primary(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_BUTTON_STYLUS_PRIMARY != 0
}
#[inline]
pub fn stylus_secondary(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_BUTTON_STYLUS_SECONDARY != 0
}
}
impl From<ndk::event::ButtonState> for ButtonState {
fn from(value: ndk::event::ButtonState) -> Self {
Self(value.0)
}
}
/// A bitfield representing which edges were touched by a motion event.
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-31)
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct EdgeFlags(pub u32);
impl EdgeFlags {
#[inline]
pub fn top(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_EDGE_FLAG_TOP != 0
}
#[inline]
pub fn bottom(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_EDGE_FLAG_BOTTOM != 0
}
#[inline]
pub fn left(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_EDGE_FLAG_LEFT != 0
}
#[inline]
pub fn right(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_EDGE_FLAG_RIGHT != 0
}
}
impl From<ndk::event::EdgeFlags> for EdgeFlags {
fn from(value: ndk::event::EdgeFlags) -> Self {
Self(value.0)
}
}
/// Flags associated with this [`MotionEvent`].
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-30)
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct MotionEventFlags(pub u32);
impl MotionEventFlags {
#[inline]
pub fn window_is_obscured(self) -> bool {
self.0 & ndk_sys::AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED != 0
}
}
impl From<ndk::event::MotionEventFlags> for MotionEventFlags {
fn from(value: ndk::event::MotionEventFlags) -> Self {
Self(value.0)
}
}
/// Key actions.
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-27)
///
/// # Android Extensible Enum
///
/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and
/// should be handled similar to a `#[non_exhaustive]` enum to maintain
/// forwards compatibility.
///
/// Implements `Into<u32>` and `From<u32>` for converting to/from Android SDK
/// integer values.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
#[non_exhaustive]
#[repr(u32)]
pub enum KeyAction {
Down = ndk_sys::AKEY_EVENT_ACTION_DOWN,
Up = ndk_sys::AKEY_EVENT_ACTION_UP,
Multiple = ndk_sys::AKEY_EVENT_ACTION_MULTIPLE,
#[doc(hidden)]
#[num_enum(catch_all)]
__Unknown(u32),
}
/// Key codes.
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-39)
///
/// # Android Extensible Enum
///
/// This is a runtime [extensible enum](`crate#android-extensible-enums`) and
/// should be handled similar to a `#[non_exhaustive]` enum to maintain
/// forwards compatibility.
///
/// Implements `Into<u32>` and `From<u32>` for converting to/from Android SDK
/// integer values.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
#[non_exhaustive]
#[repr(u32)]
pub enum Keycode {
Unknown = ndk_sys::AKEYCODE_UNKNOWN,
SoftLeft = ndk_sys::AKEYCODE_SOFT_LEFT,
SoftRight = ndk_sys::AKEYCODE_SOFT_RIGHT,
Home = ndk_sys::AKEYCODE_HOME,
Back = ndk_sys::AKEYCODE_BACK,
Call = ndk_sys::AKEYCODE_CALL,
Endcall = ndk_sys::AKEYCODE_ENDCALL,
Keycode0 = ndk_sys::AKEYCODE_0,
Keycode1 = ndk_sys::AKEYCODE_1,
Keycode2 = ndk_sys::AKEYCODE_2,
Keycode3 = ndk_sys::AKEYCODE_3,
Keycode4 = ndk_sys::AKEYCODE_4,
Keycode5 = ndk_sys::AKEYCODE_5,
Keycode6 = ndk_sys::AKEYCODE_6,
Keycode7 = ndk_sys::AKEYCODE_7,
Keycode8 = ndk_sys::AKEYCODE_8,
Keycode9 = ndk_sys::AKEYCODE_9,
Star = ndk_sys::AKEYCODE_STAR,
Pound = ndk_sys::AKEYCODE_POUND,
DpadUp = ndk_sys::AKEYCODE_DPAD_UP,
DpadDown = ndk_sys::AKEYCODE_DPAD_DOWN,
DpadLeft = ndk_sys::AKEYCODE_DPAD_LEFT,
DpadRight = ndk_sys::AKEYCODE_DPAD_RIGHT,
DpadCenter = ndk_sys::AKEYCODE_DPAD_CENTER,
VolumeUp = ndk_sys::AKEYCODE_VOLUME_UP,
VolumeDown = ndk_sys::AKEYCODE_VOLUME_DOWN,
Power = ndk_sys::AKEYCODE_POWER,
Camera = ndk_sys::AKEYCODE_CAMERA,
Clear = ndk_sys::AKEYCODE_CLEAR,
A = ndk_sys::AKEYCODE_A,
B = ndk_sys::AKEYCODE_B,
C = ndk_sys::AKEYCODE_C,
D = ndk_sys::AKEYCODE_D,
E = ndk_sys::AKEYCODE_E,
F = ndk_sys::AKEYCODE_F,
G = ndk_sys::AKEYCODE_G,
H = ndk_sys::AKEYCODE_H,
I = ndk_sys::AKEYCODE_I,
J = ndk_sys::AKEYCODE_J,
K = ndk_sys::AKEYCODE_K,
L = ndk_sys::AKEYCODE_L,
M = ndk_sys::AKEYCODE_M,
N = ndk_sys::AKEYCODE_N,
O = ndk_sys::AKEYCODE_O,
P = ndk_sys::AKEYCODE_P,
Q = ndk_sys::AKEYCODE_Q,
R = ndk_sys::AKEYCODE_R,
S = ndk_sys::AKEYCODE_S,
T = ndk_sys::AKEYCODE_T,
U = ndk_sys::AKEYCODE_U,
V = ndk_sys::AKEYCODE_V,
W = ndk_sys::AKEYCODE_W,
X = ndk_sys::AKEYCODE_X,
Y = ndk_sys::AKEYCODE_Y,
Z = ndk_sys::AKEYCODE_Z,
Comma = ndk_sys::AKEYCODE_COMMA,
Period = ndk_sys::AKEYCODE_PERIOD,
AltLeft = ndk_sys::AKEYCODE_ALT_LEFT,
AltRight = ndk_sys::AKEYCODE_ALT_RIGHT,
ShiftLeft = ndk_sys::AKEYCODE_SHIFT_LEFT,
ShiftRight = ndk_sys::AKEYCODE_SHIFT_RIGHT,
Tab = ndk_sys::AKEYCODE_TAB,
Space = ndk_sys::AKEYCODE_SPACE,
Sym = ndk_sys::AKEYCODE_SYM,
Explorer = ndk_sys::AKEYCODE_EXPLORER,
Envelope = ndk_sys::AKEYCODE_ENVELOPE,
Enter = ndk_sys::AKEYCODE_ENTER,
Del = ndk_sys::AKEYCODE_DEL,
Grave = ndk_sys::AKEYCODE_GRAVE,
Minus = ndk_sys::AKEYCODE_MINUS,
Equals = ndk_sys::AKEYCODE_EQUALS,
LeftBracket = ndk_sys::AKEYCODE_LEFT_BRACKET,
RightBracket = ndk_sys::AKEYCODE_RIGHT_BRACKET,
Backslash = ndk_sys::AKEYCODE_BACKSLASH,
Semicolon = ndk_sys::AKEYCODE_SEMICOLON,
Apostrophe = ndk_sys::AKEYCODE_APOSTROPHE,
Slash = ndk_sys::AKEYCODE_SLASH,
At = ndk_sys::AKEYCODE_AT,
Num = ndk_sys::AKEYCODE_NUM,
Headsethook = ndk_sys::AKEYCODE_HEADSETHOOK,
Focus = ndk_sys::AKEYCODE_FOCUS,
Plus = ndk_sys::AKEYCODE_PLUS,
Menu = ndk_sys::AKEYCODE_MENU,
Notification = ndk_sys::AKEYCODE_NOTIFICATION,
Search = ndk_sys::AKEYCODE_SEARCH,
MediaPlayPause = ndk_sys::AKEYCODE_MEDIA_PLAY_PAUSE,
MediaStop = ndk_sys::AKEYCODE_MEDIA_STOP,
MediaNext = ndk_sys::AKEYCODE_MEDIA_NEXT,
MediaPrevious = ndk_sys::AKEYCODE_MEDIA_PREVIOUS,
MediaRewind = ndk_sys::AKEYCODE_MEDIA_REWIND,
MediaFastForward = ndk_sys::AKEYCODE_MEDIA_FAST_FORWARD,
Mute = ndk_sys::AKEYCODE_MUTE,
PageUp = ndk_sys::AKEYCODE_PAGE_UP,
PageDown = ndk_sys::AKEYCODE_PAGE_DOWN,
Pictsymbols = ndk_sys::AKEYCODE_PICTSYMBOLS,
SwitchCharset = ndk_sys::AKEYCODE_SWITCH_CHARSET,
ButtonA = ndk_sys::AKEYCODE_BUTTON_A,
ButtonB = ndk_sys::AKEYCODE_BUTTON_B,
ButtonC = ndk_sys::AKEYCODE_BUTTON_C,
ButtonX = ndk_sys::AKEYCODE_BUTTON_X,
ButtonY = ndk_sys::AKEYCODE_BUTTON_Y,
ButtonZ = ndk_sys::AKEYCODE_BUTTON_Z,
ButtonL1 = ndk_sys::AKEYCODE_BUTTON_L1,
ButtonR1 = ndk_sys::AKEYCODE_BUTTON_R1,
ButtonL2 = ndk_sys::AKEYCODE_BUTTON_L2,
ButtonR2 = ndk_sys::AKEYCODE_BUTTON_R2,
ButtonThumbl = ndk_sys::AKEYCODE_BUTTON_THUMBL,
ButtonThumbr = ndk_sys::AKEYCODE_BUTTON_THUMBR,
ButtonStart = ndk_sys::AKEYCODE_BUTTON_START,
ButtonSelect = ndk_sys::AKEYCODE_BUTTON_SELECT,
ButtonMode = ndk_sys::AKEYCODE_BUTTON_MODE,
Escape = ndk_sys::AKEYCODE_ESCAPE,
ForwardDel = ndk_sys::AKEYCODE_FORWARD_DEL,
CtrlLeft = ndk_sys::AKEYCODE_CTRL_LEFT,
CtrlRight = ndk_sys::AKEYCODE_CTRL_RIGHT,
CapsLock = ndk_sys::AKEYCODE_CAPS_LOCK,
ScrollLock = ndk_sys::AKEYCODE_SCROLL_LOCK,
MetaLeft = ndk_sys::AKEYCODE_META_LEFT,
MetaRight = ndk_sys::AKEYCODE_META_RIGHT,
Function = ndk_sys::AKEYCODE_FUNCTION,
Sysrq = ndk_sys::AKEYCODE_SYSRQ,
Break = ndk_sys::AKEYCODE_BREAK,
MoveHome = ndk_sys::AKEYCODE_MOVE_HOME,
MoveEnd = ndk_sys::AKEYCODE_MOVE_END,
Insert = ndk_sys::AKEYCODE_INSERT,
Forward = ndk_sys::AKEYCODE_FORWARD,
MediaPlay = ndk_sys::AKEYCODE_MEDIA_PLAY,
MediaPause = ndk_sys::AKEYCODE_MEDIA_PAUSE,
MediaClose = ndk_sys::AKEYCODE_MEDIA_CLOSE,
MediaEject = ndk_sys::AKEYCODE_MEDIA_EJECT,
MediaRecord = ndk_sys::AKEYCODE_MEDIA_RECORD,
F1 = ndk_sys::AKEYCODE_F1,
F2 = ndk_sys::AKEYCODE_F2,
F3 = ndk_sys::AKEYCODE_F3,
F4 = ndk_sys::AKEYCODE_F4,
F5 = ndk_sys::AKEYCODE_F5,
F6 = ndk_sys::AKEYCODE_F6,
F7 = ndk_sys::AKEYCODE_F7,
F8 = ndk_sys::AKEYCODE_F8,
F9 = ndk_sys::AKEYCODE_F9,
F10 = ndk_sys::AKEYCODE_F10,
F11 = ndk_sys::AKEYCODE_F11,
F12 = ndk_sys::AKEYCODE_F12,
NumLock = ndk_sys::AKEYCODE_NUM_LOCK,
Numpad0 = ndk_sys::AKEYCODE_NUMPAD_0,
Numpad1 = ndk_sys::AKEYCODE_NUMPAD_1,
Numpad2 = ndk_sys::AKEYCODE_NUMPAD_2,
Numpad3 = ndk_sys::AKEYCODE_NUMPAD_3,
Numpad4 = ndk_sys::AKEYCODE_NUMPAD_4,
Numpad5 = ndk_sys::AKEYCODE_NUMPAD_5,
Numpad6 = ndk_sys::AKEYCODE_NUMPAD_6,
Numpad7 = ndk_sys::AKEYCODE_NUMPAD_7,
Numpad8 = ndk_sys::AKEYCODE_NUMPAD_8,
Numpad9 = ndk_sys::AKEYCODE_NUMPAD_9,
NumpadDivide = ndk_sys::AKEYCODE_NUMPAD_DIVIDE,
NumpadMultiply = ndk_sys::AKEYCODE_NUMPAD_MULTIPLY,
NumpadSubtract = ndk_sys::AKEYCODE_NUMPAD_SUBTRACT,
NumpadAdd = ndk_sys::AKEYCODE_NUMPAD_ADD,
NumpadDot = ndk_sys::AKEYCODE_NUMPAD_DOT,
NumpadComma = ndk_sys::AKEYCODE_NUMPAD_COMMA,
NumpadEnter = ndk_sys::AKEYCODE_NUMPAD_ENTER,
NumpadEquals = ndk_sys::AKEYCODE_NUMPAD_EQUALS,
NumpadLeftParen = ndk_sys::AKEYCODE_NUMPAD_LEFT_PAREN,
NumpadRightParen = ndk_sys::AKEYCODE_NUMPAD_RIGHT_PAREN,
VolumeMute = ndk_sys::AKEYCODE_VOLUME_MUTE,
Info = ndk_sys::AKEYCODE_INFO,
ChannelUp = ndk_sys::AKEYCODE_CHANNEL_UP,
ChannelDown = ndk_sys::AKEYCODE_CHANNEL_DOWN,
ZoomIn = ndk_sys::AKEYCODE_ZOOM_IN,
ZoomOut = ndk_sys::AKEYCODE_ZOOM_OUT,
Tv = ndk_sys::AKEYCODE_TV,
Window = ndk_sys::AKEYCODE_WINDOW,
Guide = ndk_sys::AKEYCODE_GUIDE,
Dvr = ndk_sys::AKEYCODE_DVR,
Bookmark = ndk_sys::AKEYCODE_BOOKMARK,
Captions = ndk_sys::AKEYCODE_CAPTIONS,
Settings = ndk_sys::AKEYCODE_SETTINGS,
TvPower = ndk_sys::AKEYCODE_TV_POWER,
TvInput = ndk_sys::AKEYCODE_TV_INPUT,
StbPower = ndk_sys::AKEYCODE_STB_POWER,
StbInput = ndk_sys::AKEYCODE_STB_INPUT,
AvrPower = ndk_sys::AKEYCODE_AVR_POWER,
AvrInput = ndk_sys::AKEYCODE_AVR_INPUT,
ProgRed = ndk_sys::AKEYCODE_PROG_RED,
ProgGreen = ndk_sys::AKEYCODE_PROG_GREEN,
ProgYellow = ndk_sys::AKEYCODE_PROG_YELLOW,
ProgBlue = ndk_sys::AKEYCODE_PROG_BLUE,
AppSwitch = ndk_sys::AKEYCODE_APP_SWITCH,
Button1 = ndk_sys::AKEYCODE_BUTTON_1,
Button2 = ndk_sys::AKEYCODE_BUTTON_2,
Button3 = ndk_sys::AKEYCODE_BUTTON_3,
Button4 = ndk_sys::AKEYCODE_BUTTON_4,
Button5 = ndk_sys::AKEYCODE_BUTTON_5,
Button6 = ndk_sys::AKEYCODE_BUTTON_6,
Button7 = ndk_sys::AKEYCODE_BUTTON_7,
Button8 = ndk_sys::AKEYCODE_BUTTON_8,
Button9 = ndk_sys::AKEYCODE_BUTTON_9,
Button10 = ndk_sys::AKEYCODE_BUTTON_10,
Button11 = ndk_sys::AKEYCODE_BUTTON_11,
Button12 = ndk_sys::AKEYCODE_BUTTON_12,
Button13 = ndk_sys::AKEYCODE_BUTTON_13,
Button14 = ndk_sys::AKEYCODE_BUTTON_14,
Button15 = ndk_sys::AKEYCODE_BUTTON_15,
Button16 = ndk_sys::AKEYCODE_BUTTON_16,
LanguageSwitch = ndk_sys::AKEYCODE_LANGUAGE_SWITCH,
MannerMode = ndk_sys::AKEYCODE_MANNER_MODE,
Keycode3dMode = ndk_sys::AKEYCODE_3D_MODE,
Contacts = ndk_sys::AKEYCODE_CONTACTS,
Calendar = ndk_sys::AKEYCODE_CALENDAR,
Music = ndk_sys::AKEYCODE_MUSIC,
Calculator = ndk_sys::AKEYCODE_CALCULATOR,
ZenkakuHankaku = ndk_sys::AKEYCODE_ZENKAKU_HANKAKU,
Eisu = ndk_sys::AKEYCODE_EISU,
Muhenkan = ndk_sys::AKEYCODE_MUHENKAN,
Henkan = ndk_sys::AKEYCODE_HENKAN,
KatakanaHiragana = ndk_sys::AKEYCODE_KATAKANA_HIRAGANA,
Yen = ndk_sys::AKEYCODE_YEN,
Ro = ndk_sys::AKEYCODE_RO,
Kana = ndk_sys::AKEYCODE_KANA,
Assist = ndk_sys::AKEYCODE_ASSIST,
BrightnessDown = ndk_sys::AKEYCODE_BRIGHTNESS_DOWN,
BrightnessUp = ndk_sys::AKEYCODE_BRIGHTNESS_UP,
MediaAudioTrack = ndk_sys::AKEYCODE_MEDIA_AUDIO_TRACK,
Sleep = ndk_sys::AKEYCODE_SLEEP,
Wakeup = ndk_sys::AKEYCODE_WAKEUP,
Pairing = ndk_sys::AKEYCODE_PAIRING,
MediaTopMenu = ndk_sys::AKEYCODE_MEDIA_TOP_MENU,
Keycode11 = ndk_sys::AKEYCODE_11,
Keycode12 = ndk_sys::AKEYCODE_12,
LastChannel = ndk_sys::AKEYCODE_LAST_CHANNEL,
TvDataService = ndk_sys::AKEYCODE_TV_DATA_SERVICE,
VoiceAssist = ndk_sys::AKEYCODE_VOICE_ASSIST,
TvRadioService = ndk_sys::AKEYCODE_TV_RADIO_SERVICE,
TvTeletext = ndk_sys::AKEYCODE_TV_TELETEXT,
TvNumberEntry = ndk_sys::AKEYCODE_TV_NUMBER_ENTRY,
TvTerrestrialAnalog = ndk_sys::AKEYCODE_TV_TERRESTRIAL_ANALOG,
TvTerrestrialDigital = ndk_sys::AKEYCODE_TV_TERRESTRIAL_DIGITAL,
TvSatellite = ndk_sys::AKEYCODE_TV_SATELLITE,
TvSatelliteBs = ndk_sys::AKEYCODE_TV_SATELLITE_BS,
TvSatelliteCs = ndk_sys::AKEYCODE_TV_SATELLITE_CS,
TvSatelliteService = ndk_sys::AKEYCODE_TV_SATELLITE_SERVICE,
TvNetwork = ndk_sys::AKEYCODE_TV_NETWORK,
TvAntennaCable = ndk_sys::AKEYCODE_TV_ANTENNA_CABLE,
TvInputHdmi1 = ndk_sys::AKEYCODE_TV_INPUT_HDMI_1,
TvInputHdmi2 = ndk_sys::AKEYCODE_TV_INPUT_HDMI_2,
TvInputHdmi3 = ndk_sys::AKEYCODE_TV_INPUT_HDMI_3,
TvInputHdmi4 = ndk_sys::AKEYCODE_TV_INPUT_HDMI_4,
TvInputComposite1 = ndk_sys::AKEYCODE_TV_INPUT_COMPOSITE_1,
TvInputComposite2 = ndk_sys::AKEYCODE_TV_INPUT_COMPOSITE_2,
TvInputComponent1 = ndk_sys::AKEYCODE_TV_INPUT_COMPONENT_1,
TvInputComponent2 = ndk_sys::AKEYCODE_TV_INPUT_COMPONENT_2,
TvInputVga1 = ndk_sys::AKEYCODE_TV_INPUT_VGA_1,
TvAudioDescription = ndk_sys::AKEYCODE_TV_AUDIO_DESCRIPTION,
TvAudioDescriptionMixUp = ndk_sys::AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP,
TvAudioDescriptionMixDown = ndk_sys::AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN,
TvZoomMode = ndk_sys::AKEYCODE_TV_ZOOM_MODE,
TvContentsMenu = ndk_sys::AKEYCODE_TV_CONTENTS_MENU,
TvMediaContextMenu = ndk_sys::AKEYCODE_TV_MEDIA_CONTEXT_MENU,
TvTimerProgramming = ndk_sys::AKEYCODE_TV_TIMER_PROGRAMMING,
Help = ndk_sys::AKEYCODE_HELP,
NavigatePrevious = ndk_sys::AKEYCODE_NAVIGATE_PREVIOUS,
NavigateNext = ndk_sys::AKEYCODE_NAVIGATE_NEXT,
NavigateIn = ndk_sys::AKEYCODE_NAVIGATE_IN,
NavigateOut = ndk_sys::AKEYCODE_NAVIGATE_OUT,
StemPrimary = ndk_sys::AKEYCODE_STEM_PRIMARY,
Stem1 = ndk_sys::AKEYCODE_STEM_1,
Stem2 = ndk_sys::AKEYCODE_STEM_2,
Stem3 = ndk_sys::AKEYCODE_STEM_3,
DpadUpLeft = ndk_sys::AKEYCODE_DPAD_UP_LEFT,
DpadDownLeft = ndk_sys::AKEYCODE_DPAD_DOWN_LEFT,
DpadUpRight = ndk_sys::AKEYCODE_DPAD_UP_RIGHT,
DpadDownRight = ndk_sys::AKEYCODE_DPAD_DOWN_RIGHT,
MediaSkipForward = ndk_sys::AKEYCODE_MEDIA_SKIP_FORWARD,
MediaSkipBackward = ndk_sys::AKEYCODE_MEDIA_SKIP_BACKWARD,
MediaStepForward = ndk_sys::AKEYCODE_MEDIA_STEP_FORWARD,
MediaStepBackward = ndk_sys::AKEYCODE_MEDIA_STEP_BACKWARD,
SoftSleep = ndk_sys::AKEYCODE_SOFT_SLEEP,
Cut = ndk_sys::AKEYCODE_CUT,
Copy = ndk_sys::AKEYCODE_COPY,
Paste = ndk_sys::AKEYCODE_PASTE,
SystemNavigationUp = ndk_sys::AKEYCODE_SYSTEM_NAVIGATION_UP,
SystemNavigationDown = ndk_sys::AKEYCODE_SYSTEM_NAVIGATION_DOWN,
SystemNavigationLeft = ndk_sys::AKEYCODE_SYSTEM_NAVIGATION_LEFT,
SystemNavigationRight = ndk_sys::AKEYCODE_SYSTEM_NAVIGATION_RIGHT,
AllApps = ndk_sys::AKEYCODE_ALL_APPS,
Refresh = ndk_sys::AKEYCODE_REFRESH,
ThumbsUp = ndk_sys::AKEYCODE_THUMBS_UP,
ThumbsDown = ndk_sys::AKEYCODE_THUMBS_DOWN,
ProfileSwitch = ndk_sys::AKEYCODE_PROFILE_SWITCH,
#[doc(hidden)]
#[num_enum(catch_all)]
__Unknown(u32),
}
/// Flags associated with [`KeyEvent`].
///
/// See [the NDK docs](https://developer.android.com/ndk/reference/group/input#anonymous-enum-28)
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct KeyEventFlags(pub u32);
impl KeyEventFlags {
#[inline]
pub fn cancelled(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_CANCELED != 0
}
#[inline]
pub fn cancelled_long_press(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_CANCELED_LONG_PRESS != 0
}
#[inline]
pub fn editor_action(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_EDITOR_ACTION != 0
}
#[inline]
pub fn fallback(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_FALLBACK != 0
}
#[inline]
pub fn from_system(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_FROM_SYSTEM != 0
}
#[inline]
pub fn keep_touch_mode(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_KEEP_TOUCH_MODE != 0
}
#[inline]
pub fn long_press(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_LONG_PRESS != 0
}
#[inline]
pub fn soft_keyboard(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_SOFT_KEYBOARD != 0
}
#[inline]
pub fn tracking(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_TRACKING != 0
}
#[inline]
pub fn virtual_hard_key(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY != 0
}
#[inline]
pub fn woke_here(&self) -> bool {
self.0 & ndk_sys::AKEY_EVENT_FLAG_WOKE_HERE != 0
}
}
impl From<ndk::event::KeyEventFlags> for KeyEventFlags {
fn from(value: ndk::event::KeyEventFlags) -> Self {
Self(value.0)
}
}
/// This struct holds a span within a region of text from `start` to `end`.
///
/// The `start` index may be greater than the `end` index (swapping `start` and `end` will represent the same span)
@@ -78,6 +907,33 @@ pub struct TextInputState {
pub compose_region: Option<TextSpan>,
}
// Represents the action button on a soft keyboard.
#[derive(Debug, Clone, Copy, PartialEq, Eq, num_enum::FromPrimitive, num_enum::IntoPrimitive)]
#[non_exhaustive]
#[repr(i32)]
pub enum TextInputAction {
/// Let receiver decide what logical action to perform
Unspecified = 0,
/// No action - receiver could instead interpret as an "enter" key that inserts a newline character
None = 1,
/// Navigate to the input location (such as a URL)
Go = 2,
/// Search based on the input text
Search = 3,
/// Send the input to the target
Send = 4,
/// Move to the next input field
Next = 5,
/// Indicate that input is done
Done = 6,
/// Move to the previous input field
Previous = 7,
#[doc(hidden)]
#[num_enum(catch_all)]
__Unknown(i32),
}
/// An exclusive, lending iterator for input events
pub struct InputIterator<'a> {
pub(crate) inner: crate::activity_impl::InputIteratorInner<'a>,
+4 -2
View File
@@ -246,8 +246,10 @@ impl KeyCharacterMap {
/// a [`AppError::JavaError`] in case there is a spurious JNI error or an exception
/// is caught.
pub fn get(&self, key_code: Keycode, meta_state: MetaState) -> Result<KeyMapChar, AppError> {
let key_code = key_code.into();
let meta_state = meta_state.0 as i32;
let key_code: u32 = key_code.into();
let key_code = key_code as jni_sys::jint;
let meta_state: u32 = meta_state.0;
let meta_state = meta_state as jni_sys::jint;
// Since we expect this API to be called from the `main` thread then we expect to already be
// attached to the JVM
+50 -21
View File
@@ -1,10 +1,8 @@
use std::marker::PhantomData;
use ndk::event::ButtonState;
use crate::input::{
Axis, EdgeFlags, KeyAction, Keycode, MetaState, MotionAction, MotionEventFlags, Pointer,
PointersIter, Source, ToolType,
Axis, Button, ButtonState, EdgeFlags, KeyAction, Keycode, MetaState, MotionAction,
MotionEventFlags, Pointer, PointersIter, Source, ToolType,
};
/// A motion event
@@ -32,7 +30,13 @@ impl MotionEvent<'_> {
///
#[inline]
pub fn source(&self) -> Source {
self.ndk_event.source()
// XXX: we use `AInputEvent_getSource` directly (instead of calling
// ndk_event.source()) since we have our own `Source` enum that we
// share between backends, which may also capture unknown variants
// added in new versions of Android.
let source =
unsafe { ndk_sys::AInputEvent_getSource(self.ndk_event.ptr().as_ptr()) as u32 };
source.into()
}
/// Get the device id associated with the event.
@@ -47,7 +51,13 @@ impl MotionEvent<'_> {
/// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getActionMasked())
#[inline]
pub fn action(&self) -> MotionAction {
self.ndk_event.action()
// XXX: we use `AMotionEvent_getAction` directly since we have our own
// `MotionAction` enum that we share between backends, which may also
// capture unknown variants added in new versions of Android.
let action =
unsafe { ndk_sys::AMotionEvent_getAction(self.ndk_event.ptr().as_ptr()) as u32 }
& ndk_sys::AMOTION_EVENT_ACTION_MASK;
action.into()
}
/// Returns which button has been modified during a press or release action.
@@ -57,11 +67,10 @@ impl MotionEvent<'_> {
///
/// See [the MotionEvent docs](https://developer.android.com/reference/android/view/MotionEvent#getActionButton())
#[inline]
#[cfg(feature = "api-level-33")]
#[doc(alias = "AMotionEvent_getActionButton")]
// TODO: Button enum to signify only one bitflag can be set?
pub fn action_button(&self) -> ButtonState {
self.ndk_event.action_button()
pub fn action_button(&self) -> Button {
let action_button =
unsafe { ndk_sys::AMotionEvent_getActionButton(self.ndk_event.ptr().as_ptr()) as u32 };
action_button.into()
}
/// Returns the pointer index of an `Up` or `Down` event.
@@ -145,7 +154,7 @@ impl MotionEvent<'_> {
/// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getmetastate)
#[inline]
pub fn meta_state(&self) -> MetaState {
self.ndk_event.meta_state()
self.ndk_event.meta_state().into()
}
/// Returns the button state during this event, as a bitfield.
@@ -154,7 +163,7 @@ impl MotionEvent<'_> {
/// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getbuttonstate)
#[inline]
pub fn button_state(&self) -> ButtonState {
self.ndk_event.button_state()
self.ndk_event.button_state().into()
}
/// Returns the time of the start of this gesture, in the `java.lang.System.nanoTime()` time
@@ -173,7 +182,7 @@ impl MotionEvent<'_> {
/// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getedgeflags)
#[inline]
pub fn edge_flags(&self) -> EdgeFlags {
self.ndk_event.edge_flags()
self.ndk_event.edge_flags().into()
}
/// Returns the time of this event, in the `java.lang.System.nanoTime()` time base
@@ -191,7 +200,7 @@ impl MotionEvent<'_> {
/// docs](https://developer.android.com/ndk/reference/group/input#amotionevent_getflags)
#[inline]
pub fn flags(&self) -> MotionEventFlags {
self.ndk_event.flags()
self.ndk_event.flags().into()
}
/* Missing from GameActivity currently...
@@ -252,7 +261,8 @@ impl PointerImpl<'_> {
#[inline]
pub fn axis_value(&self, axis: Axis) -> f32 {
let value: i32 = axis.into();
let value: u32 = axis.into();
let value = value as i32;
self.ndk_pointer.axis_value(value.into())
}
@@ -269,6 +279,7 @@ impl PointerImpl<'_> {
#[inline]
pub fn tool_type(&self) -> ToolType {
let value: i32 = self.ndk_pointer.tool_type().into();
let value = value as u32;
value.into()
}
}
@@ -320,9 +331,16 @@ impl KeyEvent<'_> {
}
/// Get the source of the event.
///
#[inline]
pub fn source(&self) -> Source {
self.ndk_event.source()
// XXX: we use `AInputEvent_getSource` directly (instead of calling
// ndk_event.source()) since we have our own `Source` enum that we
// share between backends, which may also capture unknown variants
// added in new versions of Android.
let source =
unsafe { ndk_sys::AInputEvent_getSource(self.ndk_event.ptr().as_ptr()) as u32 };
source.into()
}
/// Get the device id associated with the event.
@@ -337,7 +355,11 @@ impl KeyEvent<'_> {
/// See [the KeyEvent docs](https://developer.android.com/reference/android/view/KeyEvent#getAction())
#[inline]
pub fn action(&self) -> KeyAction {
self.ndk_event.action()
// XXX: we use `AInputEvent_getAction` directly since we have our own
// `KeyAction` enum that we share between backends, which may also
// capture unknown variants added in new versions of Android.
let action = unsafe { ndk_sys::AKeyEvent_getAction(self.ndk_event.ptr().as_ptr()) as u32 };
action.into()
}
/// Returns the last time the key was pressed. This is on the scale of
@@ -366,7 +388,12 @@ impl KeyEvent<'_> {
/// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getkeycode)
#[inline]
pub fn key_code(&self) -> Keycode {
self.ndk_event.key_code()
// XXX: we use `AInputEvent_getKeyCode` directly since we have our own
// `Keycode` enum that we share between backends, which may also
// capture unknown variants added in new versions of Android.
let keycode =
unsafe { ndk_sys::AKeyEvent_getKeyCode(self.ndk_event.ptr().as_ptr()) as u32 };
keycode.into()
}
/// Returns the number of repeats of a key.
@@ -393,12 +420,13 @@ impl KeyEvent<'_> {
/// docs](https://developer.android.com/ndk/reference/group/input#akeyevent_getmetastate)
#[inline]
pub fn meta_state(&self) -> MetaState {
self.ndk_event.meta_state()
self.ndk_event.meta_state().into()
}
}
// We use our own wrapper type for input events to have better consistency
// with GameActivity
// with GameActivity and ensure the enum can be extended without needing a
// semver bump
/// Enum of possible input events
#[derive(Debug)]
#[non_exhaustive]
@@ -406,4 +434,5 @@ pub enum InputEvent<'a> {
MotionEvent(self::MotionEvent<'a>),
KeyEvent(self::KeyEvent<'a>),
TextEvent(crate::input::TextInputState),
TextAction(crate::input::TextInputAction),
}