change build system to CMake and use SDL3 for everything

This commit is contained in:
Sven Balzer
2025-02-24 19:47:40 +01:00
parent e6a5a00dcb
commit 74e0d78a4c
2052 changed files with 981424 additions and 1461 deletions
@@ -0,0 +1,44 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidvideo.h"
#include "SDL_androidclipboard.h"
#include "../../core/android/SDL_android.h"
bool Android_SetClipboardText(SDL_VideoDevice *_this, const char *text)
{
return Android_JNI_SetClipboardText(text);
}
char *Android_GetClipboardText(SDL_VideoDevice *_this)
{
return Android_JNI_GetClipboardText();
}
bool Android_HasClipboardText(SDL_VideoDevice *_this)
{
return Android_JNI_HasClipboardText();
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,30 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidclipboard_h_
#define SDL_androidclipboard_h_
extern bool Android_SetClipboardText(SDL_VideoDevice *_this, const char *text);
extern char *Android_GetClipboardText(SDL_VideoDevice *_this);
extern bool Android_HasClipboardText(SDL_VideoDevice *_this);
#endif // SDL_androidclipboard_h_
@@ -0,0 +1,269 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidevents.h"
#include "SDL_androidkeyboard.h"
#include "SDL_androidwindow.h"
#include "../SDL_sysvideo.h"
#include "../../events/SDL_events_c.h"
#include "../../audio/aaudio/SDL_aaudio.h"
#include "../../audio/openslES/SDL_openslES.h"
#ifdef SDL_VIDEO_OPENGL_EGL
static void android_egl_context_restore(SDL_Window *window)
{
if (window) {
SDL_WindowData *data = window->internal;
SDL_GL_MakeCurrent(window, NULL);
if (!SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context)) {
// The context is no longer valid, create a new one
data->egl_context = (EGLContext)SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(window, (SDL_GLContext)data->egl_context);
SDL_Event event;
SDL_zero(event);
event.type = SDL_EVENT_RENDER_DEVICE_RESET;
event.render.windowID = SDL_GetWindowID(window);
SDL_PushEvent(&event);
}
data->backup_done = false;
if (data->has_swap_interval) {
SDL_GL_SetSwapInterval(data->swap_interval);
}
}
}
static void android_egl_context_backup(SDL_Window *window)
{
if (window) {
int interval = 0;
// Keep a copy of the EGL Context so we can try to restore it when we resume
SDL_WindowData *data = window->internal;
data->egl_context = SDL_GL_GetCurrentContext();
// Save/Restore the swap interval / vsync
if (SDL_GL_GetSwapInterval(&interval)) {
data->has_swap_interval = 1;
data->swap_interval = interval;
}
// We need to do this so the EGLSurface can be freed
SDL_GL_MakeCurrent(window, NULL);
data->backup_done = true;
}
}
#endif
/*
* Android_ResumeSem and Android_PauseSem are signaled from Java_org_libsdl_app_SDLActivity_nativePause and Java_org_libsdl_app_SDLActivity_nativeResume
*/
static bool Android_EventsInitialized;
static bool Android_BlockOnPause = true;
static bool Android_Paused;
static bool Android_PausedAudio;
static bool Android_Destroyed;
void Android_InitEvents(void)
{
if (!Android_EventsInitialized) {
Android_BlockOnPause = SDL_GetHintBoolean(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, true);
Android_Paused = false;
Android_Destroyed = false;
Android_EventsInitialized = true;
}
}
static void Android_PauseAudio(void)
{
OPENSLES_PauseDevices();
AAUDIO_PauseDevices();
Android_PausedAudio = true;
}
static void Android_ResumeAudio(void)
{
if (Android_PausedAudio) {
OPENSLES_ResumeDevices();
AAUDIO_ResumeDevices();
Android_PausedAudio = false;
}
}
static void Android_OnPause(void)
{
SDL_OnApplicationWillEnterBackground();
SDL_OnApplicationDidEnterBackground();
/* The semantics are that as soon as the enter background event
* has been queued, the app will block. The application should
* do any life cycle handling in an event filter while the event
* was being queued.
*/
#ifdef SDL_VIDEO_OPENGL_EGL
if (Android_Window && !Android_Window->external_graphics_context) {
Android_LockActivityMutex();
android_egl_context_backup(Android_Window);
Android_UnlockActivityMutex();
}
#endif
if (Android_BlockOnPause) {
// We're blocking, also pause audio
Android_PauseAudio();
}
Android_Paused = true;
}
static void Android_OnResume(void)
{
Android_Paused = false;
SDL_OnApplicationWillEnterForeground();
Android_ResumeAudio();
#ifdef SDL_VIDEO_OPENGL_EGL
// Restore the GL Context from here, as this operation is thread dependent
if (Android_Window && !Android_Window->external_graphics_context && !SDL_HasEvent(SDL_EVENT_QUIT)) {
Android_LockActivityMutex();
android_egl_context_restore(Android_Window);
Android_UnlockActivityMutex();
}
#endif
// Make sure SW Keyboard is restored when an app becomes foreground
if (Android_Window) {
Android_RestoreScreenKeyboardOnResume(SDL_GetVideoDevice(), Android_Window);
}
SDL_OnApplicationDidEnterForeground();
}
static void Android_OnLowMemory(void)
{
SDL_SendAppEvent(SDL_EVENT_LOW_MEMORY);
}
static void Android_OnDestroy(void)
{
// Make sure we unblock any audio processing before we quit
Android_ResumeAudio();
/* Discard previous events. The user should have handled state storage
* in SDL_EVENT_WILL_ENTER_BACKGROUND. After nativeSendQuit() is called, no
* events other than SDL_EVENT_QUIT and SDL_EVENT_TERMINATING should fire */
SDL_FlushEvents(SDL_EVENT_FIRST, SDL_EVENT_LAST);
SDL_SendQuit();
SDL_SendAppEvent(SDL_EVENT_TERMINATING);
Android_Destroyed = true;
}
static void Android_HandleLifecycleEvent(SDL_AndroidLifecycleEvent event)
{
switch (event) {
case SDL_ANDROID_LIFECYCLE_WAKE:
// Nothing to do, just return
break;
case SDL_ANDROID_LIFECYCLE_PAUSE:
Android_OnPause();
break;
case SDL_ANDROID_LIFECYCLE_RESUME:
Android_OnResume();
break;
case SDL_ANDROID_LIFECYCLE_LOWMEMORY:
Android_OnLowMemory();
break;
case SDL_ANDROID_LIFECYCLE_DESTROY:
Android_OnDestroy();
break;
default:
break;
}
}
static Sint64 GetLifecycleEventTimeout(bool paused, Sint64 timeoutNS)
{
if (Android_Paused) {
if (Android_BlockOnPause) {
timeoutNS = -1;
} else if (timeoutNS == 0) {
timeoutNS = SDL_MS_TO_NS(100);
}
}
return timeoutNS;
}
void Android_PumpEvents(Sint64 timeoutNS)
{
SDL_AndroidLifecycleEvent event;
bool paused = Android_Paused;
while (!Android_Destroyed &&
Android_WaitLifecycleEvent(&event, GetLifecycleEventTimeout(paused, timeoutNS))) {
Android_HandleLifecycleEvent(event);
switch (event) {
case SDL_ANDROID_LIFECYCLE_WAKE:
// Finish handling events quickly if we're not paused
timeoutNS = 0;
break;
case SDL_ANDROID_LIFECYCLE_PAUSE:
// Finish handling events at the current timeout and return to process events one more time before blocking.
break;
case SDL_ANDROID_LIFECYCLE_RESUME:
// Finish handling events at the resume state timeout
paused = false;
break;
default:
break;
}
}
}
bool Android_WaitActiveAndLockActivity(void)
{
while (Android_Paused && !Android_Destroyed) {
Android_PumpEvents(-1);
}
if (Android_Destroyed) {
SDL_SetError("Android activity has been destroyed");
return false;
}
Android_LockActivityMutex();
return true;
}
void Android_QuitEvents(void)
{
Android_EventsInitialized = false;
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,26 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
extern void Android_InitEvents(void);
extern void Android_PumpEvents(Sint64 timeoutNS);
extern bool Android_WaitActiveAndLockActivity(void);
extern void Android_QuitEvents(void);
@@ -0,0 +1,88 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_DRIVER_ANDROID) && defined(SDL_VIDEO_OPENGL_EGL)
// Android SDL video driver implementation
#include "../SDL_egl_c.h"
#include "SDL_androidwindow.h"
#include "SDL_androidvideo.h"
#include "SDL_androidevents.h"
#include "SDL_androidgl.h"
#include "../../core/android/SDL_android.h"
#include <android/log.h>
#include <dlfcn.h>
bool Android_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context)
{
if (window && context) {
return SDL_EGL_MakeCurrent(_this, window->internal->egl_surface, context);
} else {
return SDL_EGL_MakeCurrent(_this, NULL, NULL);
}
}
SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window)
{
SDL_GLContext result;
if (!Android_WaitActiveAndLockActivity()) {
return NULL;
}
result = SDL_EGL_CreateContext(_this, window->internal->egl_surface);
Android_UnlockActivityMutex();
return result;
}
bool Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
bool result;
Android_LockActivityMutex();
/* The following two calls existed in the original Java code
* If you happen to have a device that's affected by their removal,
* please report to our bug tracker. -- Gabriel
*/
/*_this->egl_data->eglWaitNative(EGL_CORE_NATIVE_ENGINE);
_this->egl_data->eglWaitGL();*/
result = SDL_EGL_SwapBuffers(_this, window->internal->egl_surface);
Android_UnlockActivityMutex();
return result;
}
bool Android_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
return SDL_EGL_LoadLibrary(_this, path, (NativeDisplayType)0, 0);
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidgl_h_
#define SDL_androidgl_h_
extern SDL_GLContext Android_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window);
extern bool Android_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context);
extern bool Android_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern bool Android_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path);
#endif // SDL_androidgl_h_
@@ -0,0 +1,468 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include <android/log.h>
#include "../../events/SDL_events_c.h"
#include "SDL_androidkeyboard.h"
#include "../../core/android/SDL_android.h"
#define TYPE_CLASS_TEXT 0x00000001
#define TYPE_CLASS_NUMBER 0x00000002
#define TYPE_CLASS_PHONE 0x00000003
#define TYPE_CLASS_DATETIME 0x00000004
#define TYPE_DATETIME_VARIATION_NORMAL 0x00000000
#define TYPE_DATETIME_VARIATION_DATE 0x00000010
#define TYPE_DATETIME_VARIATION_TIME 0x00000020
#define TYPE_NUMBER_VARIATION_NORMAL 0x00000000
#define TYPE_NUMBER_VARIATION_PASSWORD 0x00000010
#define TYPE_NUMBER_FLAG_SIGNED 0x00001000
#define TYPE_NUMBER_FLAG_DECIMAL 0x00002000
#define TYPE_TEXT_FLAG_CAP_CHARACTERS 0x00001000
#define TYPE_TEXT_FLAG_CAP_WORDS 0x00002000
#define TYPE_TEXT_FLAG_CAP_SENTENCES 0x00004000
#define TYPE_TEXT_FLAG_AUTO_CORRECT 0x00008000
#define TYPE_TEXT_FLAG_AUTO_COMPLETE 0x00010000
#define TYPE_TEXT_FLAG_MULTI_LINE 0x00020000
#define TYPE_TEXT_FLAG_IME_MULTI_LINE 0x00040000
#define TYPE_TEXT_FLAG_NO_SUGGESTIONS 0x00080000
#define TYPE_TEXT_VARIATION_NORMAL 0x00000000
#define TYPE_TEXT_VARIATION_URI 0x00000010
#define TYPE_TEXT_VARIATION_EMAIL_ADDRESS 0x00000020
#define TYPE_TEXT_VARIATION_EMAIL_SUBJECT 0x00000030
#define TYPE_TEXT_VARIATION_SHORT_MESSAGE 0x00000040
#define TYPE_TEXT_VARIATION_LONG_MESSAGE 0x00000050
#define TYPE_TEXT_VARIATION_PERSON_NAME 0x00000060
#define TYPE_TEXT_VARIATION_POSTAL_ADDRESS 0x00000070
#define TYPE_TEXT_VARIATION_PASSWORD 0x00000080
#define TYPE_TEXT_VARIATION_VISIBLE_PASSWORD 0x00000090
#define TYPE_TEXT_VARIATION_WEB_EDIT_TEXT 0x000000a0
#define TYPE_TEXT_VARIATION_FILTER 0x000000b0
#define TYPE_TEXT_VARIATION_PHONETIC 0x000000c0
#define TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS 0x000000d0
#define TYPE_TEXT_VARIATION_WEB_PASSWORD 0x000000e0
static SDL_Scancode Android_Keycodes[] = {
SDL_SCANCODE_UNKNOWN, // AKEYCODE_UNKNOWN
SDL_SCANCODE_SOFTLEFT, // AKEYCODE_SOFT_LEFT
SDL_SCANCODE_SOFTRIGHT, // AKEYCODE_SOFT_RIGHT
SDL_SCANCODE_AC_HOME, // AKEYCODE_HOME
SDL_SCANCODE_AC_BACK, // AKEYCODE_BACK
SDL_SCANCODE_CALL, // AKEYCODE_CALL
SDL_SCANCODE_ENDCALL, // AKEYCODE_ENDCALL
SDL_SCANCODE_0, // AKEYCODE_0
SDL_SCANCODE_1, // AKEYCODE_1
SDL_SCANCODE_2, // AKEYCODE_2
SDL_SCANCODE_3, // AKEYCODE_3
SDL_SCANCODE_4, // AKEYCODE_4
SDL_SCANCODE_5, // AKEYCODE_5
SDL_SCANCODE_6, // AKEYCODE_6
SDL_SCANCODE_7, // AKEYCODE_7
SDL_SCANCODE_8, // AKEYCODE_8
SDL_SCANCODE_9, // AKEYCODE_9
SDL_SCANCODE_UNKNOWN, // AKEYCODE_STAR
SDL_SCANCODE_UNKNOWN, // AKEYCODE_POUND
SDL_SCANCODE_UP, // AKEYCODE_DPAD_UP
SDL_SCANCODE_DOWN, // AKEYCODE_DPAD_DOWN
SDL_SCANCODE_LEFT, // AKEYCODE_DPAD_LEFT
SDL_SCANCODE_RIGHT, // AKEYCODE_DPAD_RIGHT
SDL_SCANCODE_SELECT, // AKEYCODE_DPAD_CENTER
SDL_SCANCODE_VOLUMEUP, // AKEYCODE_VOLUME_UP
SDL_SCANCODE_VOLUMEDOWN, // AKEYCODE_VOLUME_DOWN
SDL_SCANCODE_POWER, // AKEYCODE_POWER
SDL_SCANCODE_UNKNOWN, // AKEYCODE_CAMERA
SDL_SCANCODE_CLEAR, // AKEYCODE_CLEAR
SDL_SCANCODE_A, // AKEYCODE_A
SDL_SCANCODE_B, // AKEYCODE_B
SDL_SCANCODE_C, // AKEYCODE_C
SDL_SCANCODE_D, // AKEYCODE_D
SDL_SCANCODE_E, // AKEYCODE_E
SDL_SCANCODE_F, // AKEYCODE_F
SDL_SCANCODE_G, // AKEYCODE_G
SDL_SCANCODE_H, // AKEYCODE_H
SDL_SCANCODE_I, // AKEYCODE_I
SDL_SCANCODE_J, // AKEYCODE_J
SDL_SCANCODE_K, // AKEYCODE_K
SDL_SCANCODE_L, // AKEYCODE_L
SDL_SCANCODE_M, // AKEYCODE_M
SDL_SCANCODE_N, // AKEYCODE_N
SDL_SCANCODE_O, // AKEYCODE_O
SDL_SCANCODE_P, // AKEYCODE_P
SDL_SCANCODE_Q, // AKEYCODE_Q
SDL_SCANCODE_R, // AKEYCODE_R
SDL_SCANCODE_S, // AKEYCODE_S
SDL_SCANCODE_T, // AKEYCODE_T
SDL_SCANCODE_U, // AKEYCODE_U
SDL_SCANCODE_V, // AKEYCODE_V
SDL_SCANCODE_W, // AKEYCODE_W
SDL_SCANCODE_X, // AKEYCODE_X
SDL_SCANCODE_Y, // AKEYCODE_Y
SDL_SCANCODE_Z, // AKEYCODE_Z
SDL_SCANCODE_COMMA, // AKEYCODE_COMMA
SDL_SCANCODE_PERIOD, // AKEYCODE_PERIOD
SDL_SCANCODE_LALT, // AKEYCODE_ALT_LEFT
SDL_SCANCODE_RALT, // AKEYCODE_ALT_RIGHT
SDL_SCANCODE_LSHIFT, // AKEYCODE_SHIFT_LEFT
SDL_SCANCODE_RSHIFT, // AKEYCODE_SHIFT_RIGHT
SDL_SCANCODE_TAB, // AKEYCODE_TAB
SDL_SCANCODE_SPACE, // AKEYCODE_SPACE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_SYM
SDL_SCANCODE_UNKNOWN, // AKEYCODE_EXPLORER
SDL_SCANCODE_UNKNOWN, // AKEYCODE_ENVELOPE
SDL_SCANCODE_RETURN, // AKEYCODE_ENTER
SDL_SCANCODE_BACKSPACE, // AKEYCODE_DEL
SDL_SCANCODE_GRAVE, // AKEYCODE_GRAVE
SDL_SCANCODE_MINUS, // AKEYCODE_MINUS
SDL_SCANCODE_EQUALS, // AKEYCODE_EQUALS
SDL_SCANCODE_LEFTBRACKET, // AKEYCODE_LEFT_BRACKET
SDL_SCANCODE_RIGHTBRACKET, // AKEYCODE_RIGHT_BRACKET
SDL_SCANCODE_BACKSLASH, // AKEYCODE_BACKSLASH
SDL_SCANCODE_SEMICOLON, // AKEYCODE_SEMICOLON
SDL_SCANCODE_APOSTROPHE, // AKEYCODE_APOSTROPHE
SDL_SCANCODE_SLASH, // AKEYCODE_SLASH
SDL_SCANCODE_UNKNOWN, // AKEYCODE_AT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_NUM
SDL_SCANCODE_UNKNOWN, // AKEYCODE_HEADSETHOOK
SDL_SCANCODE_UNKNOWN, // AKEYCODE_FOCUS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_PLUS
SDL_SCANCODE_MENU, // AKEYCODE_MENU
SDL_SCANCODE_UNKNOWN, // AKEYCODE_NOTIFICATION
SDL_SCANCODE_AC_SEARCH, // AKEYCODE_SEARCH
SDL_SCANCODE_MEDIA_PLAY_PAUSE, // AKEYCODE_MEDIA_PLAY_PAUSE
SDL_SCANCODE_MEDIA_STOP, // AKEYCODE_MEDIA_STOP
SDL_SCANCODE_MEDIA_NEXT_TRACK, // AKEYCODE_MEDIA_NEXT
SDL_SCANCODE_MEDIA_PREVIOUS_TRACK, // AKEYCODE_MEDIA_PREVIOUS
SDL_SCANCODE_MEDIA_REWIND, // AKEYCODE_MEDIA_REWIND
SDL_SCANCODE_MEDIA_FAST_FORWARD, // AKEYCODE_MEDIA_FAST_FORWARD
SDL_SCANCODE_MUTE, // AKEYCODE_MUTE
SDL_SCANCODE_PAGEUP, // AKEYCODE_PAGE_UP
SDL_SCANCODE_PAGEDOWN, // AKEYCODE_PAGE_DOWN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_PICTSYMBOLS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_SWITCH_CHARSET
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_A
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_B
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_C
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_X
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_Y
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_Z
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_L1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_R1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_L2
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_R2
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_THUMBL
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_THUMBR
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_START
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_SELECT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_MODE
SDL_SCANCODE_ESCAPE, // AKEYCODE_ESCAPE
SDL_SCANCODE_DELETE, // AKEYCODE_FORWARD_DEL
SDL_SCANCODE_LCTRL, // AKEYCODE_CTRL_LEFT
SDL_SCANCODE_RCTRL, // AKEYCODE_CTRL_RIGHT
SDL_SCANCODE_CAPSLOCK, // AKEYCODE_CAPS_LOCK
SDL_SCANCODE_SCROLLLOCK, // AKEYCODE_SCROLL_LOCK
SDL_SCANCODE_LGUI, // AKEYCODE_META_LEFT
SDL_SCANCODE_RGUI, // AKEYCODE_META_RIGHT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_FUNCTION
SDL_SCANCODE_PRINTSCREEN, // AKEYCODE_SYSRQ
SDL_SCANCODE_PAUSE, // AKEYCODE_BREAK
SDL_SCANCODE_HOME, // AKEYCODE_MOVE_HOME
SDL_SCANCODE_END, // AKEYCODE_MOVE_END
SDL_SCANCODE_INSERT, // AKEYCODE_INSERT
SDL_SCANCODE_AC_FORWARD, // AKEYCODE_FORWARD
SDL_SCANCODE_MEDIA_PLAY, // AKEYCODE_MEDIA_PLAY
SDL_SCANCODE_MEDIA_PAUSE, // AKEYCODE_MEDIA_PAUSE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_CLOSE
SDL_SCANCODE_MEDIA_EJECT, // AKEYCODE_MEDIA_EJECT
SDL_SCANCODE_MEDIA_RECORD, // AKEYCODE_MEDIA_RECORD
SDL_SCANCODE_F1, // AKEYCODE_F1
SDL_SCANCODE_F2, // AKEYCODE_F2
SDL_SCANCODE_F3, // AKEYCODE_F3
SDL_SCANCODE_F4, // AKEYCODE_F4
SDL_SCANCODE_F5, // AKEYCODE_F5
SDL_SCANCODE_F6, // AKEYCODE_F6
SDL_SCANCODE_F7, // AKEYCODE_F7
SDL_SCANCODE_F8, // AKEYCODE_F8
SDL_SCANCODE_F9, // AKEYCODE_F9
SDL_SCANCODE_F10, // AKEYCODE_F10
SDL_SCANCODE_F11, // AKEYCODE_F11
SDL_SCANCODE_F12, // AKEYCODE_F12
SDL_SCANCODE_NUMLOCKCLEAR, // AKEYCODE_NUM_LOCK
SDL_SCANCODE_KP_0, // AKEYCODE_NUMPAD_0
SDL_SCANCODE_KP_1, // AKEYCODE_NUMPAD_1
SDL_SCANCODE_KP_2, // AKEYCODE_NUMPAD_2
SDL_SCANCODE_KP_3, // AKEYCODE_NUMPAD_3
SDL_SCANCODE_KP_4, // AKEYCODE_NUMPAD_4
SDL_SCANCODE_KP_5, // AKEYCODE_NUMPAD_5
SDL_SCANCODE_KP_6, // AKEYCODE_NUMPAD_6
SDL_SCANCODE_KP_7, // AKEYCODE_NUMPAD_7
SDL_SCANCODE_KP_8, // AKEYCODE_NUMPAD_8
SDL_SCANCODE_KP_9, // AKEYCODE_NUMPAD_9
SDL_SCANCODE_KP_DIVIDE, // AKEYCODE_NUMPAD_DIVIDE
SDL_SCANCODE_KP_MULTIPLY, // AKEYCODE_NUMPAD_MULTIPLY
SDL_SCANCODE_KP_MINUS, // AKEYCODE_NUMPAD_SUBTRACT
SDL_SCANCODE_KP_PLUS, // AKEYCODE_NUMPAD_ADD
SDL_SCANCODE_KP_PERIOD, // AKEYCODE_NUMPAD_DOT
SDL_SCANCODE_KP_COMMA, // AKEYCODE_NUMPAD_COMMA
SDL_SCANCODE_KP_ENTER, // AKEYCODE_NUMPAD_ENTER
SDL_SCANCODE_KP_EQUALS, // AKEYCODE_NUMPAD_EQUALS
SDL_SCANCODE_KP_LEFTPAREN, // AKEYCODE_NUMPAD_LEFT_PAREN
SDL_SCANCODE_KP_RIGHTPAREN, // AKEYCODE_NUMPAD_RIGHT_PAREN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_VOLUME_MUTE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_INFO
SDL_SCANCODE_CHANNEL_INCREMENT, // AKEYCODE_CHANNEL_UP
SDL_SCANCODE_CHANNEL_INCREMENT, // AKEYCODE_CHANNEL_DOWN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_ZOOM_IN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_ZOOM_OUT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV
SDL_SCANCODE_UNKNOWN, // AKEYCODE_WINDOW
SDL_SCANCODE_UNKNOWN, // AKEYCODE_GUIDE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_DVR
SDL_SCANCODE_AC_BOOKMARKS, // AKEYCODE_BOOKMARK
SDL_SCANCODE_UNKNOWN, // AKEYCODE_CAPTIONS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_SETTINGS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_POWER
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_STB_POWER
SDL_SCANCODE_UNKNOWN, // AKEYCODE_STB_INPUT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_AVR_POWER
SDL_SCANCODE_UNKNOWN, // AKEYCODE_AVR_INPUT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_PROG_RED
SDL_SCANCODE_UNKNOWN, // AKEYCODE_PROG_GREEN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_PROG_YELLOW
SDL_SCANCODE_UNKNOWN, // AKEYCODE_PROG_BLUE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_APP_SWITCH
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_2
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_3
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_4
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_5
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_6
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_7
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_8
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_9
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_10
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_11
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_12
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_13
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_14
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_15
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BUTTON_16
SDL_SCANCODE_UNKNOWN, // AKEYCODE_LANGUAGE_SWITCH
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MANNER_MODE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_3D_MODE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_CONTACTS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_CALENDAR
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MUSIC
SDL_SCANCODE_UNKNOWN, // AKEYCODE_CALCULATOR
SDL_SCANCODE_LANG5, // AKEYCODE_ZENKAKU_HANKAKU
SDL_SCANCODE_UNKNOWN, // AKEYCODE_EISU
SDL_SCANCODE_INTERNATIONAL5, // AKEYCODE_MUHENKAN
SDL_SCANCODE_INTERNATIONAL4, // AKEYCODE_HENKAN
SDL_SCANCODE_LANG3, // AKEYCODE_KATAKANA_HIRAGANA
SDL_SCANCODE_INTERNATIONAL3, // AKEYCODE_YEN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_RO
SDL_SCANCODE_UNKNOWN, // AKEYCODE_KANA
SDL_SCANCODE_UNKNOWN, // AKEYCODE_ASSIST
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BRIGHTNESS_DOWN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_BRIGHTNESS_UP
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_AUDIO_TRACK
SDL_SCANCODE_SLEEP, // AKEYCODE_SLEEP
SDL_SCANCODE_UNKNOWN, // AKEYCODE_WAKEUP
SDL_SCANCODE_UNKNOWN, // AKEYCODE_PAIRING
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_TOP_MENU
SDL_SCANCODE_UNKNOWN, // AKEYCODE_11
SDL_SCANCODE_UNKNOWN, // AKEYCODE_12
SDL_SCANCODE_UNKNOWN, // AKEYCODE_LAST_CHANNEL
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_DATA_SERVICE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_VOICE_ASSIST
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_RADIO_SERVICE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_TELETEXT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_NUMBER_ENTRY
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_TERRESTRIAL_ANALOG
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_TERRESTRIAL_DIGITAL
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_SATELLITE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_SATELLITE_BS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_SATELLITE_CS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_SATELLITE_SERVICE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_NETWORK
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_ANTENNA_CABLE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_HDMI_1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_HDMI_2
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_HDMI_3
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_HDMI_4
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_COMPOSITE_1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_COMPOSITE_2
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_COMPONENT_1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_COMPONENT_2
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_INPUT_VGA_1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_AUDIO_DESCRIPTION
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_ZOOM_MODE
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_CONTENTS_MENU
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_MEDIA_CONTEXT_MENU
SDL_SCANCODE_UNKNOWN, // AKEYCODE_TV_TIMER_PROGRAMMING
SDL_SCANCODE_HELP, // AKEYCODE_HELP
SDL_SCANCODE_UNKNOWN, // AKEYCODE_NAVIGATE_PREVIOUS
SDL_SCANCODE_UNKNOWN, // AKEYCODE_NAVIGATE_NEXT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_NAVIGATE_IN
SDL_SCANCODE_UNKNOWN, // AKEYCODE_NAVIGATE_OUT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_STEM_PRIMARY
SDL_SCANCODE_UNKNOWN, // AKEYCODE_STEM_1
SDL_SCANCODE_UNKNOWN, // AKEYCODE_STEM_2
SDL_SCANCODE_UNKNOWN, // AKEYCODE_STEM_3
SDL_SCANCODE_UNKNOWN, // AKEYCODE_DPAD_UP_LEFT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_DPAD_DOWN_LEFT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_DPAD_UP_RIGHT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_DPAD_DOWN_RIGHT
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_SKIP_FORWARD
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_SKIP_BACKWARD
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_STEP_FORWARD
SDL_SCANCODE_UNKNOWN, // AKEYCODE_MEDIA_STEP_BACKWARD
SDL_SCANCODE_UNKNOWN, // AKEYCODE_SOFT_SLEEP
SDL_SCANCODE_CUT, // AKEYCODE_CUT
SDL_SCANCODE_COPY, // AKEYCODE_COPY
SDL_SCANCODE_PASTE, // AKEYCODE_PASTE
};
static bool SDL_screen_keyboard_shown;
static SDL_Scancode TranslateKeycode(int keycode)
{
SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
if (keycode < SDL_arraysize(Android_Keycodes)) {
scancode = Android_Keycodes[keycode];
}
if (scancode == SDL_SCANCODE_UNKNOWN) {
__android_log_print(ANDROID_LOG_INFO, "SDL", "Unknown keycode %d", keycode);
}
return scancode;
}
void Android_OnKeyDown(int keycode)
{
SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, keycode, TranslateKeycode(keycode), true);
}
void Android_OnKeyUp(int keycode)
{
SDL_SendKeyboardKey(0, SDL_DEFAULT_KEYBOARD_ID, keycode, TranslateKeycode(keycode), false);
}
bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this)
{
return true;
}
void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props)
{
int input_type = 0;
if (SDL_HasProperty(props, SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER)) {
input_type = (int)SDL_GetNumberProperty(props, SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER, 0);
} else {
switch (SDL_GetTextInputType(props)) {
default:
case SDL_TEXTINPUT_TYPE_TEXT:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_NORMAL);
break;
case SDL_TEXTINPUT_TYPE_TEXT_NAME:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PERSON_NAME);
break;
case SDL_TEXTINPUT_TYPE_TEXT_EMAIL:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
break;
case SDL_TEXTINPUT_TYPE_TEXT_USERNAME:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_NORMAL);
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_PASSWORD);
break;
case SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE:
input_type = (TYPE_CLASS_TEXT | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
break;
case SDL_TEXTINPUT_TYPE_NUMBER:
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL);
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN:
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_PASSWORD);
break;
case SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE:
input_type = (TYPE_CLASS_NUMBER | TYPE_NUMBER_VARIATION_NORMAL);
break;
}
switch (SDL_GetTextInputCapitalization(props)) {
default:
case SDL_CAPITALIZE_NONE:
break;
case SDL_CAPITALIZE_LETTERS:
input_type |= TYPE_TEXT_FLAG_CAP_CHARACTERS;
break;
case SDL_CAPITALIZE_WORDS:
input_type |= TYPE_TEXT_FLAG_CAP_WORDS;
break;
case SDL_CAPITALIZE_SENTENCES:
input_type |= TYPE_TEXT_FLAG_CAP_SENTENCES;
break;
}
if (SDL_GetTextInputAutocorrect(props)) {
input_type |= (TYPE_TEXT_FLAG_AUTO_CORRECT | TYPE_TEXT_FLAG_AUTO_COMPLETE);
}
if (SDL_GetTextInputMultiline(props)) {
input_type |= TYPE_TEXT_FLAG_MULTI_LINE;
}
}
Android_JNI_ShowScreenKeyboard(input_type, &window->text_input_rect);
SDL_screen_keyboard_shown = true;
}
void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_JNI_HideScreenKeyboard();
SDL_screen_keyboard_shown = false;
}
void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window)
{
if (SDL_screen_keyboard_shown) {
Android_ShowScreenKeyboard(_this, window, window->text_input_props);
}
}
bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window)
{
return Android_JNI_IsScreenKeyboardShown();
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,32 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_androidvideo.h"
extern void Android_OnKeyDown(int keycode);
extern void Android_OnKeyUp(int keycode);
extern bool Android_HasScreenKeyboardSupport(SDL_VideoDevice *_this);
extern void Android_ShowScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props);
extern void Android_HideScreenKeyboard(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_RestoreScreenKeyboardOnResume(SDL_VideoDevice *_this, SDL_Window *window);
extern bool Android_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window);
@@ -0,0 +1,33 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidmessagebox.h"
#include "../../core/android/SDL_android.h"
bool Android_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID)
{
return Android_JNI_ShowMessageBox(messageboxdata, buttonID);
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
extern bool Android_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonID);
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,250 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidmouse.h"
#include "../../events/SDL_mouse_c.h"
#include "../../core/android/SDL_android.h"
// See Android's MotionEvent class for constants
#define ACTION_DOWN 0
#define ACTION_UP 1
#define ACTION_MOVE 2
#define ACTION_HOVER_MOVE 7
#define ACTION_SCROLL 8
#define BUTTON_PRIMARY 1
#define BUTTON_SECONDARY 2
#define BUTTON_TERTIARY 4
#define BUTTON_BACK 8
#define BUTTON_FORWARD 16
struct SDL_CursorData
{
int custom_cursor;
int system_cursor;
};
// Last known Android mouse button state (includes all buttons)
static int last_state;
// Blank cursor
static SDL_Cursor *empty_cursor;
static SDL_Cursor *Android_WrapCursor(int custom_cursor, int system_cursor)
{
SDL_Cursor *cursor;
cursor = SDL_calloc(1, sizeof(*cursor));
if (cursor) {
SDL_CursorData *data = (SDL_CursorData *)SDL_calloc(1, sizeof(*data));
if (data) {
data->custom_cursor = custom_cursor;
data->system_cursor = system_cursor;
cursor->internal = data;
} else {
SDL_free(cursor);
cursor = NULL;
}
}
return cursor;
}
static SDL_Cursor *Android_CreateDefaultCursor(void)
{
SDL_SystemCursor id = SDL_GetDefaultSystemCursor();
return Android_WrapCursor(0, id);
}
static SDL_Cursor *Android_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y)
{
int custom_cursor;
SDL_Surface *converted;
converted = SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888);
if (!converted) {
return NULL;
}
custom_cursor = Android_JNI_CreateCustomCursor(converted, hot_x, hot_y);
SDL_DestroySurface(converted);
if (!custom_cursor) {
SDL_Unsupported();
return NULL;
}
return Android_WrapCursor(custom_cursor, 0);
}
static SDL_Cursor *Android_CreateSystemCursor(SDL_SystemCursor id)
{
return Android_WrapCursor(0, id);
}
static void Android_FreeCursor(SDL_Cursor *cursor)
{
SDL_CursorData *data = cursor->internal;
if (data->custom_cursor != 0) {
Android_JNI_DestroyCustomCursor(data->custom_cursor);
}
SDL_free(cursor->internal);
SDL_free(cursor);
}
static SDL_Cursor *Android_CreateEmptyCursor(void)
{
if (!empty_cursor) {
SDL_Surface *empty_surface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ARGB8888);
if (empty_surface) {
SDL_memset(empty_surface->pixels, 0, (size_t)empty_surface->h * empty_surface->pitch);
empty_cursor = Android_CreateCursor(empty_surface, 0, 0);
SDL_DestroySurface(empty_surface);
}
}
return empty_cursor;
}
static void Android_DestroyEmptyCursor(void)
{
if (empty_cursor) {
Android_FreeCursor(empty_cursor);
empty_cursor = NULL;
}
}
static bool Android_ShowCursor(SDL_Cursor *cursor)
{
if (!cursor) {
cursor = Android_CreateEmptyCursor();
}
if (cursor) {
SDL_CursorData *data = cursor->internal;
if (data->custom_cursor) {
if (!Android_JNI_SetCustomCursor(data->custom_cursor)) {
return SDL_Unsupported();
}
} else {
if (!Android_JNI_SetSystemCursor(data->system_cursor)) {
return SDL_Unsupported();
}
}
return true;
} else {
// SDL error set inside Android_CreateEmptyCursor()
return false;
}
}
static bool Android_SetRelativeMouseMode(bool enabled)
{
if (!Android_JNI_SupportsRelativeMouse()) {
return SDL_Unsupported();
}
if (!Android_JNI_SetRelativeMouseEnabled(enabled)) {
return SDL_Unsupported();
}
return true;
}
void Android_InitMouse(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
mouse->CreateCursor = Android_CreateCursor;
mouse->CreateSystemCursor = Android_CreateSystemCursor;
mouse->ShowCursor = Android_ShowCursor;
mouse->FreeCursor = Android_FreeCursor;
mouse->SetRelativeMouseMode = Android_SetRelativeMouseMode;
SDL_SetDefaultCursor(Android_CreateDefaultCursor());
last_state = 0;
}
void Android_QuitMouse(void)
{
Android_DestroyEmptyCursor();
}
// Translate Android mouse button state to SDL mouse button
static Uint8 TranslateButton(int state)
{
if (state & BUTTON_PRIMARY) {
return SDL_BUTTON_LEFT;
} else if (state & BUTTON_SECONDARY) {
return SDL_BUTTON_RIGHT;
} else if (state & BUTTON_TERTIARY) {
return SDL_BUTTON_MIDDLE;
} else if (state & BUTTON_FORWARD) {
return SDL_BUTTON_X1;
} else if (state & BUTTON_BACK) {
return SDL_BUTTON_X2;
} else {
return 0;
}
}
void Android_OnMouse(SDL_Window *window, int state, int action, float x, float y, bool relative)
{
int changes;
Uint8 button;
if (!window) {
return;
}
switch (action) {
case ACTION_DOWN:
changes = state & ~last_state;
button = TranslateButton(changes);
last_state = state;
SDL_SendMouseMotion(0, window, SDL_DEFAULT_MOUSE_ID, relative, x, y);
SDL_SendMouseButton(0, window, SDL_DEFAULT_MOUSE_ID, button, true);
break;
case ACTION_UP:
changes = last_state & ~state;
button = TranslateButton(changes);
last_state = state;
SDL_SendMouseMotion(0, window, SDL_DEFAULT_MOUSE_ID, relative, x, y);
SDL_SendMouseButton(0, window, SDL_DEFAULT_MOUSE_ID, button, false);
break;
case ACTION_MOVE:
case ACTION_HOVER_MOVE:
SDL_SendMouseMotion(0, window, SDL_DEFAULT_MOUSE_ID, relative, x, y);
break;
case ACTION_SCROLL:
SDL_SendMouseWheel(0, window, SDL_DEFAULT_MOUSE_ID, x, y, SDL_MOUSEWHEEL_NORMAL);
break;
default:
break;
}
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,31 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef SDL_androidmouse_h_
#define SDL_androidmouse_h_
#include "SDL_androidvideo.h"
extern void Android_InitMouse(void);
extern void Android_OnMouse(SDL_Window *window, int button, int action, float x, float y, bool relative);
extern void Android_QuitMouse(void);
#endif // SDL_androidmouse_h_
@@ -0,0 +1,98 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "SDL_androidpen.h"
#include "../../events/SDL_pen_c.h"
#include "../../core/android/SDL_android.h"
#define ACTION_DOWN 0
#define ACTION_UP 1
#define ACTION_CANCEL 3
#define ACTION_POINTER_DOWN 5
#define ACTION_POINTER_UP 6
#define ACTION_HOVER_EXIT 10
void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p)
{
if (!window) {
return;
}
// pointer index starts from zero.
pen_id_in++;
SDL_PenID pen = SDL_FindPenByHandle((void *) (size_t) pen_id_in);
if (!pen) {
// TODO: Query JNI for pen device info
SDL_PenInfo peninfo;
SDL_zero(peninfo);
peninfo.capabilities = SDL_PEN_CAPABILITY_PRESSURE | SDL_PEN_CAPABILITY_ERASER;
peninfo.num_buttons = 2;
peninfo.subtype = SDL_PEN_TYPE_PEN;
pen = SDL_AddPenDevice(0, NULL, &peninfo, (void *) (size_t) pen_id_in);
if (!pen) {
SDL_Log("error: can't add a pen device %d", pen_id_in);
return;
}
}
SDL_SendPenMotion(0, pen, window, x, y);
SDL_SendPenAxis(0, pen, window, SDL_PEN_AXIS_PRESSURE, p);
// TODO: add more axis
SDL_PenInputFlags current = SDL_GetPenStatus(pen, NULL, 0);
int diff = current ^ button;
if (diff != 0) {
// Android only exposes BUTTON_STYLUS_PRIMARY and BUTTON_STYLUS_SECONDARY
if (diff & SDL_PEN_INPUT_BUTTON_1)
SDL_SendPenButton(0, pen, window, 1, (button & SDL_PEN_INPUT_BUTTON_1) != 0);
if (diff & SDL_PEN_INPUT_BUTTON_2)
SDL_SendPenButton(0, pen, window, 2, (button & SDL_PEN_INPUT_BUTTON_2) != 0);
}
// button contains DOWN/ERASER_TIP on DOWN/UP regardless of pressed state, use action to distinguish
// we don't compare tip flags above because MotionEvent.getButtonState doesn't return stylus tip/eraser state.
switch (action) {
case ACTION_CANCEL:
case ACTION_HOVER_EXIT:
SDL_RemovePenDevice(0, pen);
break;
case ACTION_DOWN:
case ACTION_POINTER_DOWN:
SDL_SendPenTouch(0, pen, window, (button & SDL_PEN_INPUT_ERASER_TIP) != 0, true);
break;
case ACTION_UP:
case ACTION_POINTER_UP:
SDL_SendPenTouch(0, pen, window, (button & SDL_PEN_INPUT_ERASER_TIP) != 0, false);
break;
default:
break;
}
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,25 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_androidvideo.h"
extern void Android_OnPen(SDL_Window *window, int pen_id_in, int button, int action, float x, float y, float p);
@@ -0,0 +1,96 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include <android/log.h>
#include "SDL_androidtouch.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_touch_c.h"
#include "../../core/android/SDL_android.h"
#define ACTION_DOWN 0
#define ACTION_UP 1
#define ACTION_MOVE 2
#define ACTION_CANCEL 3
// #define ACTION_OUTSIDE 4
#define ACTION_POINTER_DOWN 5
#define ACTION_POINTER_UP 6
void Android_InitTouch(void)
{
// Add all touch devices
Android_JNI_InitTouch();
}
void Android_QuitTouch(void)
{
}
void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p)
{
SDL_TouchID touchDeviceId = 0;
SDL_FingerID fingerId = 0;
if (!window) {
return;
}
/* Touch device -1 appears when using Android emulator, eg:
* adb shell input mouse tap 100 100
* adb shell input touchscreen tap 100 100
*/
touchDeviceId = (SDL_TouchID)(touch_device_id_in + 2);
// Finger ID should be greater than 0
fingerId = (SDL_FingerID)(pointer_finger_id_in + 1);
if (SDL_AddTouch(touchDeviceId, SDL_TOUCH_DEVICE_DIRECT, "") < 0) {
SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__);
}
switch (action) {
case ACTION_DOWN:
case ACTION_POINTER_DOWN:
SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_DOWN, x, y, p);
break;
case ACTION_MOVE:
SDL_SendTouchMotion(0, touchDeviceId, fingerId, window, x, y, p);
break;
case ACTION_UP:
case ACTION_POINTER_UP:
SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_UP, x, y, p);
break;
case ACTION_CANCEL:
SDL_SendTouch(0, touchDeviceId, fingerId, window, SDL_EVENT_FINGER_CANCELED, x, y, p);
break;
default:
break;
}
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,27 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "SDL_androidvideo.h"
extern void Android_InitTouch(void);
extern void Android_QuitTouch(void);
extern void Android_OnTouch(SDL_Window *window, int touch_device_id_in, int pointer_finger_id_in, int action, float x, float y, float p);
@@ -0,0 +1,330 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
// Android SDL video driver implementation
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
#include "../../events/SDL_windowevents_c.h"
#include "SDL_androidvideo.h"
#include "SDL_androidgl.h"
#include "SDL_androidclipboard.h"
#include "SDL_androidevents.h"
#include "SDL_androidkeyboard.h"
#include "SDL_androidmouse.h"
#include "SDL_androidtouch.h"
#include "SDL_androidwindow.h"
#include "SDL_androidvulkan.h"
#include "SDL_androidmessagebox.h"
#define ANDROID_VID_DRIVER_NAME "android"
// Initialization/Query functions
static bool Android_VideoInit(SDL_VideoDevice *_this);
static void Android_VideoQuit(SDL_VideoDevice *_this);
#include "../SDL_egl_c.h"
#define Android_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal
#define Android_GLES_UnloadLibrary SDL_EGL_UnloadLibrary
#define Android_GLES_SetSwapInterval SDL_EGL_SetSwapInterval
#define Android_GLES_GetSwapInterval SDL_EGL_GetSwapInterval
#define Android_GLES_DestroyContext SDL_EGL_DestroyContext
// Android driver bootstrap functions
// These are filled in with real values in Android_SetScreenResolution on init (before SDL_main())
int Android_SurfaceWidth = 0;
int Android_SurfaceHeight = 0;
static int Android_DeviceWidth = 0;
static int Android_DeviceHeight = 0;
static Uint32 Android_ScreenFormat = SDL_PIXELFORMAT_RGB565; // Default SurfaceView format, in case this is queried before being filled
float Android_ScreenDensity = 1.0f;
static float Android_ScreenRate = 0.0f;
static SDL_DisplayOrientation Android_ScreenOrientation = SDL_ORIENTATION_UNKNOWN;
int Android_SafeInsetLeft = 0;
int Android_SafeInsetRight = 0;
int Android_SafeInsetTop = 0;
int Android_SafeInsetBottom = 0;
static SDL_SystemTheme Android_SystemTheme;
static bool Android_SuspendScreenSaver(SDL_VideoDevice *_this)
{
return Android_JNI_SuspendScreenSaver(_this->suspend_screensaver);
}
static void Android_DeleteDevice(SDL_VideoDevice *device)
{
SDL_free(device->internal);
SDL_free(device);
}
static SDL_VideoDevice *Android_CreateDevice(void)
{
SDL_VideoDevice *device;
SDL_VideoData *data;
// Initialize all variables that we clean on shutdown
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (!device) {
return NULL;
}
data = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
if (!data) {
SDL_free(device);
return NULL;
}
device->internal = data;
device->system_theme = Android_SystemTheme;
// Set the function pointers
device->VideoInit = Android_VideoInit;
device->VideoQuit = Android_VideoQuit;
device->CreateSDLWindow = Android_CreateWindow;
device->SetWindowTitle = Android_SetWindowTitle;
device->SetWindowFullscreen = Android_SetWindowFullscreen;
device->MinimizeWindow = Android_MinimizeWindow;
device->SetWindowResizable = Android_SetWindowResizable;
device->DestroyWindow = Android_DestroyWindow;
device->free = Android_DeleteDevice;
// GL pointers
#ifdef SDL_VIDEO_OPENGL_EGL
device->GL_LoadLibrary = Android_GLES_LoadLibrary;
device->GL_GetProcAddress = Android_GLES_GetProcAddress;
device->GL_UnloadLibrary = Android_GLES_UnloadLibrary;
device->GL_CreateContext = Android_GLES_CreateContext;
device->GL_MakeCurrent = Android_GLES_MakeCurrent;
device->GL_SetSwapInterval = Android_GLES_SetSwapInterval;
device->GL_GetSwapInterval = Android_GLES_GetSwapInterval;
device->GL_SwapWindow = Android_GLES_SwapWindow;
device->GL_DestroyContext = Android_GLES_DestroyContext;
#endif
#ifdef SDL_VIDEO_VULKAN
device->Vulkan_LoadLibrary = Android_Vulkan_LoadLibrary;
device->Vulkan_UnloadLibrary = Android_Vulkan_UnloadLibrary;
device->Vulkan_GetInstanceExtensions = Android_Vulkan_GetInstanceExtensions;
device->Vulkan_CreateSurface = Android_Vulkan_CreateSurface;
device->Vulkan_DestroySurface = Android_Vulkan_DestroySurface;
#endif
// Screensaver
device->SuspendScreenSaver = Android_SuspendScreenSaver;
// Screen keyboard
device->HasScreenKeyboardSupport = Android_HasScreenKeyboardSupport;
device->ShowScreenKeyboard = Android_ShowScreenKeyboard;
device->HideScreenKeyboard = Android_HideScreenKeyboard;
device->IsScreenKeyboardShown = Android_IsScreenKeyboardShown;
// Clipboard
device->SetClipboardText = Android_SetClipboardText;
device->GetClipboardText = Android_GetClipboardText;
device->HasClipboardText = Android_HasClipboardText;
device->device_caps = VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS;
return device;
}
VideoBootStrap Android_bootstrap = {
ANDROID_VID_DRIVER_NAME, "SDL Android video driver",
Android_CreateDevice,
Android_ShowMessageBox
};
bool Android_VideoInit(SDL_VideoDevice *_this)
{
SDL_VideoData *videodata = _this->internal;
SDL_DisplayID displayID;
SDL_VideoDisplay *display;
SDL_DisplayMode mode;
videodata->isPaused = false;
videodata->isPausing = false;
SDL_zero(mode);
mode.format = Android_ScreenFormat;
mode.w = Android_DeviceWidth;
mode.h = Android_DeviceHeight;
mode.refresh_rate = Android_ScreenRate;
displayID = SDL_AddBasicVideoDisplay(&mode);
if (displayID == 0) {
return false;
}
display = SDL_GetVideoDisplay(displayID);
display->natural_orientation = Android_JNI_GetDisplayNaturalOrientation();
display->current_orientation = Android_JNI_GetDisplayCurrentOrientation();
display->content_scale = Android_ScreenDensity;
Android_InitTouch();
Android_InitMouse();
// We're done!
return true;
}
void Android_VideoQuit(SDL_VideoDevice *_this)
{
Android_QuitMouse();
Android_QuitTouch();
}
void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float density, float rate)
{
Android_SurfaceWidth = surfaceWidth;
Android_SurfaceHeight = surfaceHeight;
Android_DeviceWidth = deviceWidth;
Android_DeviceHeight = deviceHeight;
Android_ScreenDensity = (density > 0.0f) ? density : 1.0f;
Android_ScreenRate = rate;
}
static Uint32 format_to_pixelFormat(int format)
{
Uint32 pf;
if (format == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) { // 1
pf = SDL_PIXELFORMAT_RGBA8888;
} else if (format == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM) { // 2
pf = SDL_PIXELFORMAT_RGBX8888;
} else if (format == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM) { // 3
pf = SDL_PIXELFORMAT_RGB24;
} else if (format == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM) { // 4
pf = SDL_PIXELFORMAT_RGB565;
} else if (format == 5) {
pf = SDL_PIXELFORMAT_BGRA8888;
} else if (format == 6) {
pf = SDL_PIXELFORMAT_RGBA5551;
} else if (format == 7) {
pf = SDL_PIXELFORMAT_RGBA4444;
} else if (format == 0x115) {
// HAL_PIXEL_FORMAT_BGR_565
pf = SDL_PIXELFORMAT_RGB565;
} else {
pf = SDL_PIXELFORMAT_UNKNOWN;
}
return pf;
}
void Android_SetFormat(int format_wanted, int format_got)
{
Uint32 pf_wanted;
Uint32 pf_got;
pf_wanted = format_to_pixelFormat(format_wanted);
pf_got = format_to_pixelFormat(format_got);
Android_ScreenFormat = pf_got;
SDL_Log("pixel format wanted %s (%d), got %s (%d)",
SDL_GetPixelFormatName(pf_wanted), format_wanted,
SDL_GetPixelFormatName(pf_got), format_got);
}
static void Android_SendOrientationUpdate(void)
{
/* If we've received a compatible resize event, update the
* orientation immediately, otherwise wait for the display
* resize event.
*/
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->num_displays > 0) {
SDL_VideoDisplay *display = device->displays[0];
bool mode_landscape = (display->desktop_mode.w > display->desktop_mode.h);
bool sensor_landscape = (Android_ScreenOrientation == SDL_ORIENTATION_LANDSCAPE || Android_ScreenOrientation == SDL_ORIENTATION_LANDSCAPE_FLIPPED);
if (sensor_landscape == mode_landscape) {
SDL_SendDisplayEvent(display, SDL_EVENT_DISPLAY_ORIENTATION, Android_ScreenOrientation, 0);
}
}
}
void Android_SetOrientation(SDL_DisplayOrientation orientation)
{
Android_ScreenOrientation = orientation;
Android_SendOrientationUpdate();
}
void Android_SendResize(SDL_Window *window)
{
/*
Update the resolution of the desktop mode, so that the window
can be properly resized. The screen resolution change can for
example happen when the Activity enters or exits immersive mode,
which can happen after VideoInit().
*/
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (device && device->num_displays > 0) {
SDL_VideoDisplay *display = device->displays[0];
SDL_DisplayMode desktop_mode;
SDL_zero(desktop_mode);
desktop_mode.format = Android_ScreenFormat;
desktop_mode.w = Android_DeviceWidth;
desktop_mode.h = Android_DeviceHeight;
desktop_mode.refresh_rate = Android_ScreenRate;
SDL_SetDesktopDisplayMode(display, &desktop_mode);
Android_SendOrientationUpdate();
}
if (window) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, Android_SurfaceWidth, Android_SurfaceHeight);
}
}
void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom)
{
Android_SafeInsetLeft = left;
Android_SafeInsetRight = right;
Android_SafeInsetTop = top;
Android_SafeInsetBottom = bottom;
if (Android_Window) {
SDL_SetWindowSafeAreaInsets(Android_Window, left, right, top, bottom);
}
}
void Android_SetDarkMode(bool enabled)
{
SDL_VideoDevice *device = SDL_GetVideoDevice();
if (enabled) {
Android_SystemTheme = SDL_SYSTEM_THEME_DARK;
} else {
Android_SystemTheme = SDL_SYSTEM_THEME_LIGHT;
}
if (device) {
SDL_SetSystemTheme(Android_SystemTheme);
}
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,52 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidvideo_h_
#define SDL_androidvideo_h_
#include "../SDL_sysvideo.h"
// Called by the JNI layer when the screen changes size or format
extern void Android_SetScreenResolution(int surfaceWidth, int surfaceHeight, int deviceWidth, int deviceHeight, float density, float rate);
extern void Android_SetFormat(int format_wanted, int format_got);
extern void Android_SetOrientation(SDL_DisplayOrientation orientation);
extern void Android_SendResize(SDL_Window *window);
extern void Android_SetWindowSafeAreaInsets(int left, int right, int top, int bottom);
extern void Android_SetDarkMode(bool enabled);
// Private display data
struct SDL_VideoData
{
int isPaused;
int isPausing;
};
extern int Android_SurfaceWidth;
extern int Android_SurfaceHeight;
extern float Android_ScreenDensity;
extern int Android_SafeInsetLeft;
extern int Android_SafeInsetRight;
extern int Android_SafeInsetTop;
extern int Android_SafeInsetBottom;
#endif // SDL_androidvideo_h_
@@ -0,0 +1,171 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.c.
*/
#include "SDL_internal.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_ANDROID)
#include "../SDL_vulkan_internal.h"
#include "SDL_androidvideo.h"
#include "SDL_androidwindow.h"
#include "SDL_androidvulkan.h"
bool Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path)
{
VkExtensionProperties *extensions = NULL;
Uint32 i, extensionCount = 0;
bool hasSurfaceExtension = false;
bool hasAndroidSurfaceExtension = false;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL;
if (_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan already loaded");
}
// Load the Vulkan loader library
if (!path) {
path = SDL_GetHint(SDL_HINT_VULKAN_LIBRARY);
}
if (!path) {
path = "libvulkan.so";
}
_this->vulkan_config.loader_handle = SDL_LoadObject(path);
if (!_this->vulkan_config.loader_handle) {
return false;
}
SDL_strlcpy(_this->vulkan_config.loader_path, path,
SDL_arraysize(_this->vulkan_config.loader_path));
vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_LoadFunction(
_this->vulkan_config.loader_handle, "vkGetInstanceProcAddr");
if (!vkGetInstanceProcAddr) {
goto fail;
}
_this->vulkan_config.vkGetInstanceProcAddr = (void *)vkGetInstanceProcAddr;
_this->vulkan_config.vkEnumerateInstanceExtensionProperties =
(void *)((PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr)(
VK_NULL_HANDLE, "vkEnumerateInstanceExtensionProperties");
if (!_this->vulkan_config.vkEnumerateInstanceExtensionProperties) {
goto fail;
}
extensions = SDL_Vulkan_CreateInstanceExtensionsList(
(PFN_vkEnumerateInstanceExtensionProperties)
_this->vulkan_config.vkEnumerateInstanceExtensionProperties,
&extensionCount);
if (!extensions) {
goto fail;
}
for (i = 0; i < extensionCount; i++) {
if (SDL_strcmp(VK_KHR_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasSurfaceExtension = true;
} else if (SDL_strcmp(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME, extensions[i].extensionName) == 0) {
hasAndroidSurfaceExtension = true;
}
}
SDL_free(extensions);
if (!hasSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_SURFACE_EXTENSION_NAME " extension");
goto fail;
} else if (!hasAndroidSurfaceExtension) {
SDL_SetError("Installed Vulkan doesn't implement the " VK_KHR_ANDROID_SURFACE_EXTENSION_NAME "extension");
goto fail;
}
return true;
fail:
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
return false;
}
void Android_Vulkan_UnloadLibrary(SDL_VideoDevice *_this)
{
if (_this->vulkan_config.loader_handle) {
SDL_UnloadObject(_this->vulkan_config.loader_handle);
_this->vulkan_config.loader_handle = NULL;
}
}
char const* const* Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this,
Uint32 *count)
{
static const char *const extensionsForAndroid[] = {
VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
};
if (count) {
*count = SDL_arraysize(extensionsForAndroid);
}
return extensionsForAndroid;
}
bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
const struct VkAllocationCallbacks *allocator,
VkSurfaceKHR *surface)
{
SDL_WindowData *windowData = window->internal;
PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr =
(PFN_vkGetInstanceProcAddr)_this->vulkan_config.vkGetInstanceProcAddr;
PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR =
(PFN_vkCreateAndroidSurfaceKHR)vkGetInstanceProcAddr(
instance,
"vkCreateAndroidSurfaceKHR");
VkAndroidSurfaceCreateInfoKHR createInfo;
VkResult result;
if (!_this->vulkan_config.loader_handle) {
return SDL_SetError("Vulkan is not loaded");
}
if (!vkCreateAndroidSurfaceKHR) {
return SDL_SetError(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
" extension is not enabled in the Vulkan instance.");
}
SDL_zero(createInfo);
createInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
createInfo.pNext = NULL;
createInfo.flags = 0;
createInfo.window = windowData->native_window;
result = vkCreateAndroidSurfaceKHR(instance, &createInfo, allocator, surface);
if (result != VK_SUCCESS) {
return SDL_SetError("vkCreateAndroidSurfaceKHR failed: %s", SDL_Vulkan_GetResultString(result));
}
return true;
}
void Android_Vulkan_DestroySurface(SDL_VideoDevice *_this,
VkInstance instance,
VkSurfaceKHR surface,
const struct VkAllocationCallbacks *allocator)
{
if (_this->vulkan_config.loader_handle) {
SDL_Vulkan_DestroySurface_Internal(_this->vulkan_config.vkGetInstanceProcAddr, instance, surface, allocator);
}
}
#endif
@@ -0,0 +1,52 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
/*
* @author Mark Callow, www.edgewise-consulting.com. Based on Jacob Lifshay's
* SDL_x11vulkan.h.
*/
#include "SDL_internal.h"
#ifndef SDL_androidvulkan_h_
#define SDL_androidvulkan_h_
#include "../SDL_vulkan_internal.h"
#include "../SDL_sysvideo.h"
#if defined(SDL_VIDEO_VULKAN) && defined(SDL_VIDEO_DRIVER_ANDROID)
extern bool Android_Vulkan_LoadLibrary(SDL_VideoDevice *_this, const char *path);
extern void Android_Vulkan_UnloadLibrary(SDL_VideoDevice *_this);
extern char const* const* Android_Vulkan_GetInstanceExtensions(SDL_VideoDevice *_this, Uint32 *count);
extern bool Android_Vulkan_CreateSurface(SDL_VideoDevice *_this,
SDL_Window *window,
VkInstance instance,
const struct VkAllocationCallbacks *allocator,
VkSurfaceKHR *surface);
extern void Android_Vulkan_DestroySurface(SDL_VideoDevice *_this,
VkInstance instance,
VkSurfaceKHR surface,
const struct VkAllocationCallbacks *allocator);
#endif
#endif // SDL_androidvulkan_h_
@@ -0,0 +1,204 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef SDL_VIDEO_DRIVER_ANDROID
#include "../SDL_sysvideo.h"
#include "../../events/SDL_keyboard_c.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_windowevents_c.h"
#include "../../core/android/SDL_android.h"
#include "SDL_androidvideo.h"
#include "SDL_androidevents.h"
#include "SDL_androidwindow.h"
// Currently only one window
SDL_Window *Android_Window = NULL;
bool Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props)
{
SDL_WindowData *data;
bool result = true;
if (!Android_WaitActiveAndLockActivity()) {
return false;
}
if (Android_Window) {
result = SDL_SetError("Android only supports one window");
goto endfunction;
}
// Set orientation
Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
// Adjust the window data to match the screen
window->x = 0;
window->y = 0;
window->w = Android_SurfaceWidth;
window->h = Android_SurfaceHeight;
// One window, it always has focus
SDL_SetMouseFocus(window);
SDL_SetKeyboardFocus(window);
data = (SDL_WindowData *)SDL_calloc(1, sizeof(*data));
if (!data) {
result = false;
goto endfunction;
}
data->native_window = Android_JNI_GetNativeWindow();
if (!data->native_window) {
SDL_free(data);
result = SDL_SetError("Could not fetch native window");
goto endfunction;
}
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER, data->native_window);
/* Do not create EGLSurface for Vulkan window since it will then make the window
incompatible with vkCreateAndroidSurfaceKHR */
#ifdef SDL_VIDEO_OPENGL_EGL
if (window->flags & SDL_WINDOW_OPENGL) {
data->egl_surface = SDL_EGL_CreateSurface(_this, window, (NativeWindowType)data->native_window);
if (data->egl_surface == EGL_NO_SURFACE) {
ANativeWindow_release(data->native_window);
SDL_free(data);
result = false;
goto endfunction;
}
}
SDL_SetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_ANDROID_SURFACE_POINTER, data->egl_surface);
#endif
SDL_SetWindowSafeAreaInsets(window, Android_SafeInsetLeft, Android_SafeInsetRight, Android_SafeInsetTop, Android_SafeInsetBottom);
window->internal = data;
Android_Window = window;
endfunction:
Android_UnlockActivityMutex();
return result;
}
void Android_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_JNI_SetActivityTitle(window->title);
}
SDL_FullscreenResult Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen)
{
Android_LockActivityMutex();
if (window == Android_Window) {
SDL_WindowData *data;
int old_w, old_h, new_w, new_h;
// If the window is being destroyed don't change visible state
if (!window->is_destroying) {
Android_JNI_SetWindowStyle(fullscreen);
}
/* Ensure our size matches reality after we've executed the window style change.
*
* It is possible that we've set width and height to the full-size display, but on
* Samsung DeX or Chromebooks or other windowed Android environemtns, our window may
* still not be the full display size.
*/
if (!SDL_IsDeXMode() && !SDL_IsChromebook()) {
goto endfunction;
}
data = window->internal;
if (!data || !data->native_window) {
if (data && !data->native_window) {
SDL_SetError("Missing native window");
}
goto endfunction;
}
old_w = window->w;
old_h = window->h;
new_w = ANativeWindow_getWidth(data->native_window);
new_h = ANativeWindow_getHeight(data->native_window);
if (new_w < 0 || new_h < 0) {
SDL_SetError("ANativeWindow_getWidth/Height() fails");
}
if (old_w != new_w || old_h != new_h) {
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_RESIZED, new_w, new_h);
}
}
endfunction:
Android_UnlockActivityMutex();
return SDL_FULLSCREEN_SUCCEEDED;
}
void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_JNI_MinizeWindow();
}
void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable)
{
// Set orientation
Android_JNI_SetOrientation(window->w, window->h, window->flags & SDL_WINDOW_RESIZABLE, SDL_GetHint(SDL_HINT_ORIENTATIONS));
}
void Android_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window)
{
Android_LockActivityMutex();
if (window == Android_Window) {
Android_Window = NULL;
if (window->internal) {
SDL_WindowData *data = window->internal;
#ifdef SDL_VIDEO_OPENGL_EGL
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_DestroySurface(_this, data->egl_surface);
}
#endif
if (data->native_window) {
ANativeWindow_release(data->native_window);
}
SDL_free(window->internal);
window->internal = NULL;
}
}
Android_UnlockActivityMutex();
}
#endif // SDL_VIDEO_DRIVER_ANDROID
@@ -0,0 +1,51 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifndef SDL_androidwindow_h_
#define SDL_androidwindow_h_
#include "../../core/android/SDL_android.h"
#include "../SDL_egl_c.h"
extern bool Android_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);
extern void Android_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_FullscreenResult Android_SetWindowFullscreen(SDL_VideoDevice *_this, SDL_Window *window, SDL_VideoDisplay *display, SDL_FullscreenOp fullscreen);
extern void Android_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern void Android_SetWindowResizable(SDL_VideoDevice *_this, SDL_Window *window, bool resizable);
extern void Android_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window);
extern SDL_Window *Android_Window;
struct SDL_WindowData
{
#ifdef SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
EGLContext egl_context; // We use this to preserve the context when losing focus
int has_swap_interval; // Save/Restore the swap interval / vsync
int swap_interval;
#endif
bool backup_done;
ANativeWindow *native_window;
};
#endif // SDL_androidwindow_h_