Semphriss 13 часов назад
Родитель
Сommit
d474769878

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

@@ -1345,6 +1345,25 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         return false;
     }
 
+    /**
+     * This method is called by SDL using JNI.
+     */
+    static String getDeviceFormFactor()
+    {
+        // TODO: WearOS
+        if (isAndroidTV()) {
+            return "tv";
+        } else if (isVRHeadset()) {
+            return "headset";
+        } else if (isTablet()) {
+            return "tablet";
+        //} else if (isAndroidAutomotive()) {
+        //    return "car";
+        } else {
+            return "phone";
+        }
+    }
+
     public static double getDiagonal()
     {
         DisplayMetrics metrics = new DisplayMetrics();

+ 58 - 0
include/SDL3/SDL_system.h

@@ -655,6 +655,64 @@ extern SDL_DECLSPEC bool SDLCALL SDL_IsTablet(void);
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_IsTV(void);
 
+/**
+ * The possible form factors for a device.
+ *
+ * \since This enum is available since SDL 3.4.0.
+ *
+ * \sa SDL_GetDeviceFormFactor
+ * \sa SDL_GetDeviceFormFactorName
+ */
+typedef enum SDL_FormFactor {
+    SDL_FORMFACTOR_UNKNOWN = 0,
+    SDL_FORMFACTOR_DESKTOP,
+    SDL_FORMFACTOR_LAPTOP,
+    SDL_FORMFACTOR_PHONE,
+    SDL_FORMFACTOR_TABLET,
+    SDL_FORMFACTOR_CONSOLE,
+    SDL_FORMFACTOR_HANDHELD,
+    SDL_FORMFACTOR_WATCH,
+    SDL_FORMFACTOR_TV,
+    SDL_FORMFACTOR_HEADSET,
+    SDL_FORMFACTOR_CAR
+} SDL_FormFactor;
+
+/**
+ * Get the form factor of the current device.
+ *
+ * This function guesses what the device may be, but may report inaccurate or
+ * outright wrong results. For example, it may report a laptop as a desktop, or
+ * a car device as a phone.
+ *
+ * Depending on the usage, there may be different functions better suited for
+ * each purpose. For example, activating touch controls can be done by detecting
+ * the presence of a touchscreen rather than restricting to phones and tablets.
+ *
+ * \returns the best guess for the form factor of the current device.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_FormFactor
+ * \sa SDL_GetDeviceFormFactorName
+ */
+extern SDL_DECLSPEC SDL_FormFactor SDLCALL SDL_GetDeviceFormFactor(void);
+
+/**
+ * Get a short name for the current device.
+ *
+ * The name will be in English.
+ *
+ * \param form_factor the form factor to query.
+ * \returns a human-readable name for the given form factor, or
+ *          "SDL_FORMFACTOR_UNKNOWN" if the form factor isn't recognized.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_FormFactor
+ * \sa SDL_GetDeviceFormFactor
+ */
+extern SDL_DECLSPEC const char* SDLCALL SDL_GetDeviceFormFactorName(SDL_FormFactor form_factor);
+
 /**
  * Application sandbox environment.
  *

+ 44 - 13
src/SDL.c

@@ -849,28 +849,59 @@ bool SDL_IsPhone(void)
 
 bool SDL_IsTablet(void)
 {
-#ifdef SDL_PLATFORM_ANDROID
-    return SDL_IsAndroidTablet();
-#elif defined(SDL_PLATFORM_IOS)
-    extern bool SDL_IsIPad(void);
-    return SDL_IsIPad();
-#else
-    return false;
-#endif
+    return SDL_GetDeviceFormFactor() == SDL_FORMFACTOR_TABLET;
 }
 
 bool SDL_IsTV(void)
 {
-#ifdef SDL_PLATFORM_ANDROID
-    return SDL_IsAndroidTV();
+    return SDL_GetDeviceFormFactor() == SDL_FORMFACTOR_TV;
+}
+
+SDL_FormFactor SDL_GetDeviceFormFactor(void)
+{
+#ifdef SDL_FORMFACTOR_PRIVATE
+    return SDL_FORMFACTOR_PRIVATE;
+#elif defined(SDL_PLATFORM_ANDROID)
+    return SDL_GetAndroidDeviceFormFactor();
 #elif defined(SDL_PLATFORM_IOS)
-    extern bool SDL_IsAppleTV(void);
-    return SDL_IsAppleTV();
+    extern bool SDL_GetUIKitDeviceFormFactor(void);
+    return SDL_GetUIKitDeviceFormFactor();
+#elif defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) || defined(SDL_PLATFORM_PS2)
+    return SDL_FORMFACTOR_CONSOLE;
+#elif defined(SDL_PLATFORM_PSP) || defined(SDL_PLATFORM_VITA) || defined(SDL_PLATFORM_3DS)
+    return SDL_FORMFACTOR_HANDHELD;
+#elif defined(SDL_PLATFORM_QNXNTO)
+    /* TODO: QNX is used in BlackBerry phones and tablets, and in many embedded devices */
+    return SDL_FORMFACTOR_UNKNOWN;
+#elif defined(SDL_PLATFORM_WINGDK)
+    /* TODO: GDK can be either desktop Windows or XBox */
+    return SDL_FORMFACTOR_UNKNOWN;
 #else
-    return false;
+    return SDL_FORMFACTOR_DESKTOP;
 #endif
 }
 
+const char* SDL_GetDeviceFormFactorName(SDL_FormFactor form_factor)
+{
+    switch (form_factor)
+    {
+#define CASE(x) case x: return #x;
+    default:
+    CASE(SDL_FORMFACTOR_UNKNOWN)
+    CASE(SDL_FORMFACTOR_DESKTOP)
+    CASE(SDL_FORMFACTOR_LAPTOP)
+    CASE(SDL_FORMFACTOR_PHONE)
+    CASE(SDL_FORMFACTOR_TABLET)
+    CASE(SDL_FORMFACTOR_CONSOLE)
+    CASE(SDL_FORMFACTOR_HANDHELD)
+    CASE(SDL_FORMFACTOR_WATCH)
+    CASE(SDL_FORMFACTOR_TV)
+    CASE(SDL_FORMFACTOR_HEADSET)
+    CASE(SDL_FORMFACTOR_CAR)
+#undef CASE
+    }
+}
+
 static SDL_Sandbox SDL_DetectSandbox(void)
 {
 #if defined(SDL_PLATFORM_LINUX)

+ 36 - 0
src/core/android/SDL_android.c

@@ -369,6 +369,7 @@ static jmethodID midClipboardSetText;
 static jmethodID midCreateCustomCursor;
 static jmethodID midDestroyCustomCursor;
 static jmethodID midGetContext;
+static jmethodID midGetDeviceFormFactor;
 static jmethodID midGetManifestEnvironmentVariables;
 static jmethodID midGetNativeSurface;
 static jmethodID midInitTouch;
@@ -659,6 +660,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
     midCreateCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "createCustomCursor", "([IIIII)I");
     midDestroyCustomCursor = (*env)->GetStaticMethodID(env, mActivityClass, "destroyCustomCursor", "(I)V");
     midGetContext = (*env)->GetStaticMethodID(env, mActivityClass, "getContext", "()Landroid/app/Activity;");
+    midGetDeviceFormFactor = (*env)->GetStaticMethodID(env, mActivityClass, "getDeviceFormFactor", "()Ljava/lang/String;");
     midGetManifestEnvironmentVariables = (*env)->GetStaticMethodID(env, mActivityClass, "getManifestEnvironmentVariables", "()Z");
     midGetNativeSurface = (*env)->GetStaticMethodID(env, mActivityClass, "getNativeSurface", "()Landroid/view/Surface;");
     midInitTouch = (*env)->GetStaticMethodID(env, mActivityClass, "initTouch", "()V");
@@ -691,6 +693,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
         !midCreateCustomCursor ||
         !midDestroyCustomCursor ||
         !midGetContext ||
+        !midGetDeviceFormFactor ||
         !midGetManifestEnvironmentVariables ||
         !midGetNativeSurface ||
         !midInitTouch ||
@@ -3505,4 +3508,37 @@ bool Android_JNI_ShowFileDialog(
     return true;
 }
 
+SDL_FormFactor SDL_GetAndroidDeviceFormFactor(void)
+{
+    JNIEnv *env = Android_JNI_GetEnv();
+    SDL_FormFactor form_factor = SDL_FORMFACTOR_UNKNOWN;
+    jstring string;
+
+    string = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetDeviceFormFactor);
+    if (string) {
+        const char *utf = (*env)->GetStringUTFChars(env, string, 0);
+        if (utf) {
+            if (SDL_strcmp(utf, "tv") == 0) {
+                form_factor = SDL_FORMFACTOR_TV;
+            } else if (SDL_strcmp(utf, "tablet") == 0) {
+                form_factor = SDL_FORMFACTOR_TABLET;
+            } else if (SDL_strcmp(utf, "phone") == 0) {
+                form_factor = SDL_FORMFACTOR_PHONE;
+            } else if (SDL_strcmp(utf, "car") == 0) {
+                form_factor = SDL_FORMFACTOR_CAR;
+            } else if (SDL_strcmp(utf, "headset") == 0) {
+                form_factor = SDL_FORMFACTOR_HEADSET;
+            } else if (SDL_strcmp(utf, "watch") == 0) {
+                form_factor = SDL_FORMFACTOR_WATCH;
+            } else {
+                form_factor = SDL_FORMFACTOR_UNKNOWN;
+            }
+            (*env)->ReleaseStringUTFChars(env, string, utf);
+        }
+        (*env)->DeleteLocalRef(env, string);
+    }
+
+    return form_factor;
+}
+
 #endif // SDL_PLATFORM_ANDROID

+ 1 - 0
src/core/android/SDL_android.h

@@ -151,6 +151,7 @@ int SDL_GetAndroidSDKVersion(void);
 
 bool SDL_IsAndroidTablet(void);
 bool SDL_IsAndroidTV(void);
+SDL_FormFactor SDL_GetAndroidDeviceFormFactor(void);
 
 char *SDL_GetAndroidPackageName(void);  // this is a SDL_malloc'd string the caller will own.
 

+ 2 - 0
src/dynapi/SDL_dynapi.exports

@@ -1298,3 +1298,5 @@ _SDL_RequestNotificationPermission
 _SDL_ShowNotificationWithProperties
 _SDL_ShowNotification
 _SDL_RemoveNotification
+_SDL_GetDeviceFormFactor
+_SDL_GetDeviceFormFactorName

+ 2 - 0
src/dynapi/SDL_dynapi.sym

@@ -1299,6 +1299,8 @@ SDL3_0.0.0 {
     SDL_ShowNotificationWithProperties;
     SDL_ShowNotification;
     SDL_RemoveNotification;
+    SDL_GetDeviceFormFactor;
+    SDL_GetDeviceFormFactorName;
     # extra symbols go here (don't modify this line)
   local: *;
 };

+ 2 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -1325,3 +1325,5 @@
 #define SDL_ShowNotificationWithProperties SDL_ShowNotificationWithProperties_REAL
 #define SDL_ShowNotification SDL_ShowNotification_REAL
 #define SDL_RemoveNotification SDL_RemoveNotification_REAL
+#define SDL_GetDeviceFormFactor SDL_GetDeviceFormFactor_REAL
+#define SDL_GetDeviceFormFactorName SDL_GetDeviceFormFactorName_REAL

+ 2 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -1333,3 +1333,5 @@ SDL_DYNAPI_PROC(bool,SDL_RequestNotificationPermission,(void),(),return)
 SDL_DYNAPI_PROC(SDL_NotificationID,SDL_ShowNotificationWithProperties,(SDL_PropertiesID a),(a),return)
 SDL_DYNAPI_PROC(SDL_NotificationID,SDL_ShowNotification,(const char *a,const char *b,SDL_Surface *c,SDL_NotificationAction *d,int e),(a,b,c,d,e),return)
 SDL_DYNAPI_PROC(bool,SDL_RemoveNotification,(SDL_NotificationID a),(a),return)
+SDL_DYNAPI_PROC(SDL_FormFactor,SDL_GetDeviceFormFactor,(void),(),return)
+SDL_DYNAPI_PROC(const char*,SDL_GetDeviceFormFactorName,(SDL_FormFactor a),(a),return)

+ 18 - 6
src/video/uikit/SDL_uikitvideo.m

@@ -384,14 +384,26 @@ void SDL_NSLog(const char *prefix, const char *text)
  * This doesn't really have anything to do with the interfaces of the SDL video
  * subsystem, but we need to stuff this into an Objective-C source code file.
  */
-bool SDL_IsIPad(void)
-{
-    return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad);
-}
 
-bool SDL_IsAppleTV(void)
+bool SDL_GetUIKitDeviceFormFactor(void)
 {
-    return ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomTV);
+    // TODO: Apple Watch
+    switch ([UIDevice currentDevice].userInterfaceIdiom) {
+    case UIUserInterfaceIdiomPhone:
+        return SDL_FORMFACTOR_PHONE;
+    case UIUserInterfaceIdiomPad:
+        return SDL_FORMFACTOR_TABLET;
+    case UIUserInterfaceIdiomTV:
+        return SDL_FORMFACTOR_TV;
+    case UIUserInterfaceIdiomCarPlay:
+        return SDL_FORMFACTOR_CAR;
+    case UIUserInterfaceIdiomMac:
+        return SDL_FORMFACTOR_DESKTOP;
+    case UIUserInterfaceIdiomVision:
+        return SDL_FORMFACTOR_HEADSET;
+    default:
+        return SDL_FORMFACTOR_UNKNOWN;
+    }
 }
 
 #endif // SDL_VIDEO_DRIVER_UIKIT