Skip to content

Commit 4255201

Browse files
author
Semphris
committed
Detect device form factor
1 parent 8b924df commit 4255201

File tree

9 files changed

+140
-18
lines changed

9 files changed

+140
-18
lines changed

android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

+19
Original file line numberDiff line numberDiff line change
@@ -1303,6 +1303,25 @@ public static boolean isVRHeadset() {
13031303
return false;
13041304
}
13051305

1306+
/**
1307+
* This method is called by SDL using JNI.
1308+
*/
1309+
static String getDeviceFormFactor()
1310+
{
1311+
// TODO: WearOS
1312+
if (isAndroidTV()) {
1313+
return "tv";
1314+
} else if (isVRHeadset()) {
1315+
return "vr";
1316+
} else if (isTablet()) {
1317+
return "tablet";
1318+
//} else if (isAndroidAutomotive()) {
1319+
// return "car";
1320+
} else {
1321+
return "phone";
1322+
}
1323+
}
1324+
13061325
public static double getDiagonal()
13071326
{
13081327
DisplayMetrics metrics = new DisplayMetrics();

include/SDL3/SDL_system.h

+40
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,46 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsTablet(void);
620620
*/
621621
extern SDL_DECLSPEC bool SDLCALL SDL_IsTV(void);
622622

623+
/**
624+
* The possible form factors for a device.
625+
*
626+
* \since This enum is available since SDL 3.4.0.
627+
*
628+
* \sa SDL_GetDeviceFormFactor
629+
*/
630+
typedef enum SDL_FormFactor {
631+
SDL_FORMFACTOR_UNKNOWN = 0,
632+
SDL_FORMFACTOR_DESKTOP,
633+
SDL_FORMFACTOR_LAPTOP,
634+
SDL_FORMFACTOR_PHONE,
635+
SDL_FORMFACTOR_TABLET,
636+
SDL_FORMFACTOR_CONSOLE,
637+
SDL_FORMFACTOR_HANDHELD,
638+
SDL_FORMFACTOR_WATCH,
639+
SDL_FORMFACTOR_TV,
640+
SDL_FORMFACTOR_VR,
641+
SDL_FORMFACTOR_CAR
642+
} SDL_FormFactor;
643+
644+
/**
645+
* Get the form factor of the current device.
646+
*
647+
* This function guesses what the device may be, but may report inaccurate or
648+
* outright wrong results. For example, it may report a laptop as a desktop, or
649+
* a car device as a phone.
650+
*
651+
* Depending on the usage, there may be different functions better suited for
652+
* each purpose. For example, activating touch controls can be done by detecting
653+
* the presence of a touchscreen rather than restricting to phones and tablets.
654+
*
655+
* \returns the best guess for the form factor of the current device.
656+
*
657+
* \since This function is available since SDL 3.4.0.
658+
*
659+
* \sa SDL_FormFactor
660+
*/
661+
extern SDL_DECLSPEC SDL_FormFactor SDLCALL SDL_GetDeviceFormFactor(void);
662+
623663
/**
624664
* Application sandbox environment.
625665
*

src/SDL.c

+23-12
Original file line numberDiff line numberDiff line change
@@ -769,25 +769,36 @@ const char *SDL_GetPlatform(void)
769769

770770
bool SDL_IsTablet(void)
771771
{
772-
#ifdef SDL_PLATFORM_ANDROID
773-
return SDL_IsAndroidTablet();
774-
#elif defined(SDL_PLATFORM_IOS)
775-
extern bool SDL_IsIPad(void);
776-
return SDL_IsIPad();
777-
#else
778-
return false;
779-
#endif
772+
return SDL_GetDeviceFormFactor() == SDL_FORMFACTOR_TABLET;
780773
}
781774

782775
bool SDL_IsTV(void)
783776
{
777+
return SDL_GetDeviceFormFactor() == SDL_FORMFACTOR_TV;
778+
}
779+
780+
SDL_FormFactor SDL_GetDeviceFormFactor(void)
781+
{
782+
/* TODO: SDL private platforms? */
784783
#ifdef SDL_PLATFORM_ANDROID
785-
return SDL_IsAndroidTV();
784+
return SDL_GetAndroidDeviceFormFactor();
786785
#elif defined(SDL_PLATFORM_IOS)
787-
extern bool SDL_IsAppleTV(void);
788-
return SDL_IsAppleTV();
786+
extern bool SDL_GetUIKitDeviceFormFactor(void);
787+
return SDL_GetUIKitDeviceFormFactor();
788+
#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) || defined(SDL_PLATFORM_PS2)
789+
return SDL_FORMFACTOR_CONSOLE;
790+
#elif defined(SDL_PLATFORM_PSP) || defined(SDL_PLATFORM_VITA) || defined(SDL_PLATFORM_3DS)
791+
return SDL_FORMFACTOR_HANDHELD;
792+
#elif defined(SDL_PLATFORM_QNXNTO)
793+
/* TODO: QNX is used in BlackBerry phones and tablets, and in many embedded devices */
794+
return SDL_FORMFACTOR_UNKNOWN;
795+
#elif defined(SDL_PLATFORM_WINGDK)
796+
/* TODO: GDK can be either desktop Windows or XBox */
797+
return SDL_FORMFACTOR_UNKNOWN;
798+
#elif defined(SDL_PLATFORM_HAIKU) || defined(SDL_PLATFORM_BSDI) || defined(SDL_PLATFORM_HPUX) || defined(SDL_PLATFORM_IRIX) || defined(SDL_PLATFORM_EMSCRIPTEN) || defined(SDL_PLATFORM_OS2) || defined(SDL_PLATFORM_OSF) || defined(SDL_PLATFORM_RISCOS) || defined(SDL_PLATFORM_SOLARIS) || defined(SDL_PLATFORM_WIN32)
799+
return SDL_FORMFACTOR_DESKTOP;
789800
#else
790-
return false;
801+
return SDL_FORMFACTOR_UNKNOWN;
791802
#endif
792803
}
793804

src/core/android/SDL_android.c

+36
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ static jmethodID midClipboardSetText;
346346
static jmethodID midCreateCustomCursor;
347347
static jmethodID midDestroyCustomCursor;
348348
static jmethodID midGetContext;
349+
static jmethodID midGetDeviceFormFactor;
349350
static jmethodID midGetManifestEnvironmentVariables;
350351
static jmethodID midGetNativeSurface;
351352
static jmethodID midInitTouch;
@@ -635,6 +636,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
635636
midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "createCustomCursor", "([IIIII)I");
636637
midDestroyCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "destroyCustomCursor", "(I)V");
637638
midGetContext = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/content/Context;");
639+
midGetDeviceFormFactor = (*env)->GetStaticMethodID(env, mActivityClass, "getDeviceFormFactor", "()Ljava/lang/String;");
638640
midGetManifestEnvironmentVariables = (*env)->GetStaticMethodID(env, mActivityClass, "getManifestEnvironmentVariables", "()Z");
639641
midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface", "()Landroid/view/Surface;");
640642
midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass, "initTouch", "()V");
@@ -667,6 +669,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
667669
!midCreateCustomCursor ||
668670
!midDestroyCustomCursor ||
669671
!midGetContext ||
672+
!midGetDeviceFormFactor ||
670673
!midGetManifestEnvironmentVariables ||
671674
!midGetNativeSurface ||
672675
!midInitTouch ||
@@ -2821,4 +2824,37 @@ bool Android_JNI_OpenFileDialog(
28212824
return true;
28222825
}
28232826

2827+
SDL_FormFactor SDL_GetAndroidDeviceFormFactor(void)
2828+
{
2829+
JNIEnv *env = Android_JNI_GetEnv();
2830+
SDL_FormFactor form_factor = SDL_FORMFACTOR_UNKNOWN;
2831+
jstring string;
2832+
2833+
string = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetDeviceFormFactor);
2834+
if (string) {
2835+
const char *utf = (*env)->GetStringUTFChars(env, string, 0);
2836+
if (utf) {
2837+
if (SDL_strcmp(utf, "tv") == 0) {
2838+
form_factor = SDL_FORMFACTOR_TV;
2839+
} else if (SDL_strcmp(utf, "tablet") == 0) {
2840+
form_factor = SDL_FORMFACTOR_TABLET;
2841+
} else if (SDL_strcmp(utf, "phone") == 0) {
2842+
form_factor = SDL_FORMFACTOR_PHONE;
2843+
} else if (SDL_strcmp(utf, "car") == 0) {
2844+
form_factor = SDL_FORMFACTOR_CAR;
2845+
} else if (SDL_strcmp(utf, "vr") == 0) {
2846+
form_factor = SDL_FORMFACTOR_VR;
2847+
} else if (SDL_strcmp(utf, "watch") == 0) {
2848+
form_factor = SDL_FORMFACTOR_WATCH;
2849+
} else {
2850+
form_factor = SDL_FORMFACTOR_UNKNOWN;
2851+
}
2852+
(*env)->ReleaseStringUTFChars(env, string, utf);
2853+
}
2854+
(*env)->DeleteLocalRef(env, string);
2855+
}
2856+
2857+
return form_factor;
2858+
}
2859+
28242860
#endif // SDL_PLATFORM_ANDROID

src/core/android/SDL_android.h

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ int SDL_GetAndroidSDKVersion(void);
147147

148148
bool SDL_IsAndroidTablet(void);
149149
bool SDL_IsAndroidTV(void);
150+
SDL_FormFactor SDL_GetAndroidDeviceFormFactor(void);
150151

151152
// File Dialogs
152153
bool Android_JNI_OpenFileDialog(SDL_DialogFileCallback callback, void* userdata,

src/dynapi/SDL_dynapi.sym

+1
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,7 @@ SDL3_0.0.0 {
12421242
SDL_SetGPURenderStateFragmentUniforms;
12431243
SDL_SetRenderGPUState;
12441244
SDL_DestroyGPURenderState;
1245+
SDL_GetDeviceFormFactor;
12451246
# extra symbols go here (don't modify this line)
12461247
local: *;
12471248
};

src/dynapi/SDL_dynapi_overrides.h

+1
Original file line numberDiff line numberDiff line change
@@ -1267,3 +1267,4 @@
12671267
#define SDL_SetGPURenderStateFragmentUniforms SDL_SetGPURenderStateFragmentUniforms_REAL
12681268
#define SDL_SetRenderGPUState SDL_SetRenderGPUState_REAL
12691269
#define SDL_DestroyGPURenderState SDL_DestroyGPURenderState_REAL
1270+
#define SDL_GetDeviceFormFactor SDL_GetDeviceFormFactor_REAL

src/dynapi/SDL_dynapi_procs.h

+1
Original file line numberDiff line numberDiff line change
@@ -1275,3 +1275,4 @@ SDL_DYNAPI_PROC(SDL_GPURenderState*,SDL_CreateGPURenderState,(SDL_Renderer *a,SD
12751275
SDL_DYNAPI_PROC(bool,SDL_SetGPURenderStateFragmentUniforms,(SDL_GPURenderState *a,Uint32 b,const void *c,Uint32 d),(a,b,c,d),return)
12761276
SDL_DYNAPI_PROC(bool,SDL_SetRenderGPUState,(SDL_Renderer *a,SDL_GPURenderState *b),(a,b),return)
12771277
SDL_DYNAPI_PROC(void,SDL_DestroyGPURenderState,(SDL_GPURenderState *a),(a),)
1278+
SDL_DYNAPI_PROC(SDL_FormFactor,SDL_GetDeviceFormFactor,(void),(),return)

src/video/uikit/SDL_uikitvideo.m

+18-6
Original file line numberDiff line numberDiff line change
@@ -301,14 +301,26 @@ void SDL_NSLog(const char *prefix, const char *text)
301301
* This doesn't really have anything to do with the interfaces of the SDL video
302302
* subsystem, but we need to stuff this into an Objective-C source code file.
303303
*/
304-
bool SDL_IsIPad(void)
305-
{
306-
return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad);
307-
}
308304

309-
bool SDL_IsAppleTV(void)
305+
bool SDL_GetUIKitDeviceFormFactor(void)
310306
{
311-
return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomTV);
307+
// TODO: Apple Watch
308+
switch ([UIDevice currentDevice].userInterfaceIdiom) {
309+
case UIUserInterfaceIdiomPhone:
310+
return SDL_FORMFACTOR_PHONE;
311+
case UIUserInterfaceIdiomPad:
312+
return SDL_FORMFACTOR_TABLET;
313+
case UIUserInterfaceIdiomTV:
314+
return SDL_FORMFACTOR_TV;
315+
case UIUserInterfaceIdiomCarPlay:
316+
return SDL_FORMFACTOR_CAR;
317+
case UIUserInterfaceIdiomMac:
318+
return SDL_FORMFACTOR_DESKTOP;
319+
case UIUserInterfaceIdiomVision:
320+
return SDL_FORMFACTOR_VR;
321+
default:
322+
return SDL_FORMFACTOR_UNKNOWN;
323+
}
312324
}
313325

314326
#endif // SDL_VIDEO_DRIVER_UIKIT

0 commit comments

Comments
 (0)