Skip to content

Commit 965bfbe

Browse files
ribjb55
authored andcommitted
GameActivity PATCH: Support InputAvailable events
This makes a small change to the C glue code for GameActivity to send looper wake ups when new input is received (only sending a single wake up, until the application next handles input). This makes it possible to recognise that new input is available and send an `InputAvailable` event to the application - consistent with how NativeActivity can deliver `InputAvailable` events. This addresses a significant feature disparity between GameActivity and NativeActivity that meant GameActivity was not practically usable for GUI applications that wouldn't want to render continuously like a game.
1 parent d3ddd18 commit 965bfbe

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

android-activity/game-activity-csrc/game-activity/native_app_glue/android_native_app_glue.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,29 @@ void android_app_set_motion_event_filter(struct android_app* app,
480480
pthread_mutex_unlock(&app->mutex);
481481
}
482482

483+
bool android_app_input_available_wake_up(struct android_app* app) {
484+
pthread_mutex_lock(&app->mutex);
485+
bool available = app->inputAvailableWakeUp;
486+
app->inputAvailableWakeUp = false;
487+
pthread_mutex_unlock(&app->mutex);
488+
return available;
489+
}
490+
491+
// NB: should be called with the android_app->mutex held already
492+
static void notifyInput(struct android_app* android_app) {
493+
// Don't spam the mainloop with wake ups if we've already sent one
494+
if (android_app->inputSwapPending) {
495+
return;
496+
}
497+
498+
if (android_app->looper != NULL) {
499+
// for the app thread to know why it received the wake() up
500+
android_app->inputAvailableWakeUp = true;
501+
android_app->inputSwapPending = true;
502+
ALooper_wake(android_app->looper);
503+
}
504+
}
505+
483506
static bool onTouchEvent(GameActivity* activity,
484507
const GameActivityMotionEvent* event) {
485508
struct android_app* android_app = ToApp(activity);
@@ -511,6 +534,7 @@ static bool onTouchEvent(GameActivity* activity,
511534
memcpy(&inputBuffer->motionEvents[new_ix], event,
512535
sizeof(GameActivityMotionEvent));
513536
++inputBuffer->motionEventsCount;
537+
notifyInput(android_app);
514538

515539
android_app_write_cmd(android_app, APP_CMD_TOUCH_EVENT);
516540
pthread_mutex_unlock(&android_app->mutex);
@@ -531,6 +555,9 @@ struct android_input_buffer* android_app_swap_input_buffers(
531555
NATIVE_APP_GLUE_MAX_INPUT_BUFFERS;
532556
}
533557

558+
android_app->inputSwapPending = false;
559+
android_app->inputAvailableWakeUp = false;
560+
534561
pthread_mutex_unlock(&android_app->mutex);
535562

536563
return inputBuffer;
@@ -584,6 +611,7 @@ static bool onKey(GameActivity* activity, const GameActivityKeyEvent* event) {
584611
int new_ix = inputBuffer->keyEventsCount;
585612
memcpy(&inputBuffer->keyEvents[new_ix], event, sizeof(GameActivityKeyEvent));
586613
++inputBuffer->keyEventsCount;
614+
notifyInput(android_app);
587615

588616
android_app_write_cmd(android_app, APP_CMD_KEY_EVENT);
589617
pthread_mutex_unlock(&android_app->mutex);

android-activity/game-activity-csrc/game-activity/native_app_glue/android_native_app_glue.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,26 @@ struct android_app {
273273
android_key_event_filter keyEventFilter;
274274
android_motion_event_filter motionEventFilter;
275275

276+
// When new input is received we set both of these flags and use the looper to
277+
// wake up the application mainloop.
278+
//
279+
// To avoid spamming the mainloop with wake ups from lots of input though we
280+
// don't sent a wake up if the inputSwapPending flag is already set. (i.e.
281+
// we already expect input to be processed in a finite amount of time due to
282+
// our previous wake up)
283+
//
284+
// When a wake up is received then we will check this flag (clearing it
285+
// at the same time). If it was set then an InputAvailable event is sent to
286+
// the application - which should lead to all input being processed within
287+
// a finite amount of time.
288+
//
289+
// The next time android_app_swap_input_buffers is called, both flags will be
290+
// cleared.
291+
//
292+
// NB: both of these should only be read with the app mutex held
293+
bool inputAvailableWakeUp;
294+
bool inputSwapPending;
295+
276296
/** @endcond */
277297
};
278298

@@ -518,6 +538,11 @@ void android_app_set_motion_event_filter(struct android_app* app,
518538
*/
519539
void android_app_write_cmd(struct android_app* android_app, int8_t cmd);
520540

541+
/**
542+
* Determines if a looper wake up was due to new input becoming available
543+
*/
544+
bool android_app_input_available_wake_up(struct android_app* app);
545+
521546
#ifdef __cplusplus
522547
}
523548
#endif

0 commit comments

Comments
 (0)