From a515853569d2ca38235bec75f3ec9f0d6aa084cb Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 18 Jun 2018 13:14:02 -0700 Subject: [PATCH] Added support for external mouse in Samsung DeX mode relative mode doesn't work, but absolute coordinates are functional --- .../main/java/org/libsdl/app/SDLActivity.java | 37 ++++++++++++++++++- .../org/libsdl/app/SDLControllerManager.java | 1 + include/SDL_system.h | 5 +++ src/core/android/SDL_android.c | 11 +++++- src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/events/SDL_mouse.c | 3 ++ 7 files changed, 56 insertions(+), 3 deletions(-) diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java index 3cf84c66286ca..e04d1c8f22a46 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -670,6 +670,17 @@ public static boolean isScreenKeyboardShown() */ public static boolean supportsRelativeMouse() { + // ChromeOS doesn't provide relative mouse motion via the Android 7 APIs + if (isChromebook()) { + return false; + } + + // Samsung DeX mode doesn't support relative mice properly under Android 7 APIs, + // and simply returns no data under Android 8 APIs. + if (isDeXMode()) { + return false; + } + return SDLActivity.getMotionListener().supportsRelativeMouse(); } @@ -678,6 +689,10 @@ public static boolean supportsRelativeMouse() */ public static boolean setRelativeMouseEnabled(boolean enabled) { + if (enabled && !supportsRelativeMouse()) { + return false; + } + return SDLActivity.getMotionListener().setRelativeMouseEnabled(enabled); } @@ -713,6 +728,23 @@ public static boolean isChromebook() { return getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management"); } + /** + * This method is called by SDL using JNI. + */ + public static boolean isDeXMode() { + if (Build.VERSION.SDK_INT < 24) { + return false; + } + try { + final Configuration config = getContext().getResources().getConfiguration(); + final Class configClass = config.getClass(); + return configClass.getField("SEM_DESKTOP_MODE_ENABLED").getInt(configClass) + == configClass.getField("semDesktopModeEnabled").getInt(config); + } catch(Exception ignored) { + return false; + } + } + /** * This method is called by SDL using JNI. */ @@ -1313,7 +1345,7 @@ public SDLSurface(Context context) { setOnGenericMotionListener(SDLActivity.getMotionListener()); } - if (Build.VERSION.SDK_INT >= 26) { + if ((Build.VERSION.SDK_INT >= 26) && !SDLActivity.isDeXMode()) { setOnCapturedPointerListener(new SDLCapturedPointerListener_API26()); } @@ -1544,7 +1576,8 @@ public boolean onTouch(View v, MotionEvent event) { float x,y,p; // !!! FIXME: dump this SDK check after 2.0.4 ships and require API14. - if (event.getSource() == InputDevice.SOURCE_MOUSE && SDLActivity.mSeparateMouseAndTouch) { + // 12290 = Samsung DeX mode desktop mouse + if ((event.getSource() == InputDevice.SOURCE_MOUSE || event.getSource() == 12290) && SDLActivity.mSeparateMouseAndTouch) { if (Build.VERSION.SDK_INT < 14) { mouseButton = 1; // all mouse buttons are the left button } else { diff --git a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java index f97dd20f4e494..bd6a2ad790725 100644 --- a/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java +++ b/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java @@ -692,6 +692,7 @@ public boolean onGenericMotion(View v, MotionEvent event) { return SDLControllerManager.handleJoystickMotionEvent(event); case InputDevice.SOURCE_MOUSE: + case 12290: // DeX desktop mouse cursor is a separate non-standard input type. if (!SDLActivity.mSeparateMouseAndTouch) { break; } diff --git a/include/SDL_system.h b/include/SDL_system.h index 6d6832d0f5da7..06fce3537f583 100644 --- a/include/SDL_system.h +++ b/include/SDL_system.h @@ -130,6 +130,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_IsAndroidTV(void); */ extern DECLSPEC SDL_bool SDLCALL SDL_IsChromebook(void); +/** + \brief Return true is the application is running on a Samsung DeX docking station + */ +extern DECLSPEC SDL_bool SDLCALL SDL_IsDeXMode(void); + /** See the official Android developer guide for more information: http://developer.android.com/guide/topics/data/data-storage.html diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 29a55a9b11786..f5f5d1389c165 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -215,6 +215,7 @@ static jmethodID midSetOrientation; static jmethodID midGetContext; static jmethodID midIsAndroidTV; static jmethodID midIsChromebook; +static jmethodID midIsDeXMode; static jmethodID midInputGetInputDeviceIds; static jmethodID midSendMessage; static jmethodID midShowTextInput; @@ -320,6 +321,8 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c "isAndroidTV","()Z"); midIsChromebook = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "isChromebook", "()Z"); + midIsDeXMode = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, + "isDeXMode", "()Z"); midInputGetInputDeviceIds = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "inputGetInputDeviceIds", "(I)[I"); midSendMessage = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, @@ -354,7 +357,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c !midClipboardSetText || !midClipboardGetText || !midClipboardHasText || !midOpenAPKExpansionInputStream || !midGetManifestEnvironmentVariables || !midGetDisplayDPI || !midCreateCustomCursor || !midSetCustomCursor || !midSetSystemCursor || !midSupportsRelativeMouse || !midSetRelativeMouseEnabled || - !midIsChromebook) { + !midIsChromebook || !midIsDeXMode) { __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?"); } @@ -2036,6 +2039,12 @@ SDL_bool SDL_IsChromebook(void) return (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsChromebook); } +SDL_bool SDL_IsDeXMode(void) +{ + JNIEnv *env = Android_JNI_GetEnv(); + return (*env)->CallStaticBooleanMethod(env, mActivityClass, midIsDeXMode); +} + const char * SDL_AndroidGetInternalStoragePath(void) { static char *s_AndroidInternalFilesPath = NULL; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 8d32232210488..84730f49a0666 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -673,3 +673,4 @@ #define SDL_LinuxSetThreadPriority SDL_LinuxSetThreadPriority_REAL #define SDL_HasAVX512F SDL_HasAVX512F_REAL #define SDL_IsChromebook SDL_IsChromebook_REAL +#define SDL_IsDeXMode SDL_IsDeXMode_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 3d2a1a3150bb0..a95428ad1f853 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -714,4 +714,5 @@ SDL_DYNAPI_PROC(int,SDL_LinuxSetThreadPriority,(Sint64 a, int b),(a,b),return) SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX512F,(void),(),return) #ifdef __ANDROID__ SDL_DYNAPI_PROC(SDL_bool,SDL_IsChromebook,(void),(),return) +SDL_DYNAPI_PROC(SDL_bool,SDL_IsDeXMode,(void),(),return) #endif diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c index 135292eee51dd..55d248eed7ffd 100644 --- a/src/events/SDL_mouse.c +++ b/src/events/SDL_mouse.c @@ -721,6 +721,9 @@ SDL_SetRelativeMouseMode(SDL_bool enabled) } else if (mouse->SetRelativeMouseMode(enabled) < 0) { if (enabled) { /* Fall back to warp mode if native relative mode failed */ + if (!mouse->WarpMouse) { + return SDL_SetError("No relative mode implementation available"); + } mouse->relative_mode_warp = SDL_TRUE; } }