From f9b5d227af6c74e03c4f1320e0c80b12536a1ad8 Mon Sep 17 00:00:00 2001 From: underscorediscovery Date: Tue, 22 Dec 2015 15:30:29 -0330 Subject: [PATCH] SDL 9901:c9cae280468f --- include/SDL_config_iphoneos.h | 8 +- include/SDL_events.h | 3 + include/SDL_hints.h | 14 + include/SDL_joystick.h | 15 + include/SDL_revision.h | 4 +- src/core/android/SDL_android.c | 20 +- src/core/android/SDL_android.h | 5 +- src/core/windows/SDL_xinput.c | 3 + src/core/windows/SDL_xinput.h | 38 ++ src/dynapi/SDL_dynapi_overrides.h | 1 + src/dynapi/SDL_dynapi_procs.h | 1 + src/events/SDL_events.c | 6 + src/events/SDL_events_c.h | 1 + src/haptic/linux/SDL_syshaptic.c | 9 +- src/joystick/SDL_gamecontrollerdb.h | 8 + src/joystick/SDL_gamecontrollerdb.h.new | 65 +++ src/joystick/SDL_joystick.c | 35 +- src/joystick/SDL_joystick_c.h | 2 + src/joystick/SDL_sysjoystick.h | 1 + src/joystick/iphoneos/SDL_sysjoystick.m | 478 ++++++++++++++++++++-- src/joystick/iphoneos/SDL_sysjoystick_c.h | 55 +++ src/joystick/windows/SDL_xinputjoystick.c | 50 ++- src/render/direct3d11/SDL_render_d3d11.c | 2 +- src/video/SDL_video.c | 13 +- src/video/android/SDL_androidkeyboard.c | 16 + src/video/cocoa/SDL_cocoakeyboard.m | 9 +- src/video/cocoa/SDL_cocoawindow.m | 4 +- src/video/uikit/SDL_uikitmessagebox.m | 164 ++++++-- src/video/uikit/SDL_uikitopengles.m | 2 - src/video/uikit/SDL_uikitviewcontroller.h | 2 - src/video/uikit/SDL_uikitviewcontroller.m | 6 - src/video/windows/SDL_windowsevents.c | 35 +- src/video/windows/SDL_windowskeyboard.c | 4 +- src/video/windows/SDL_windowsmodes.c | 160 ++++---- src/video/windows/SDL_windowsmodes.h | 8 +- src/video/windows/SDL_windowswindow.c | 28 +- src/video/windows/SDL_windowswindow.h | 3 +- src/video/x11/SDL_x11events.c | 2 + src/video/x11/SDL_x11window.c | 22 +- 39 files changed, 1066 insertions(+), 236 deletions(-) create mode 100644 src/joystick/SDL_gamecontrollerdb.h.new create mode 100644 src/joystick/iphoneos/SDL_sysjoystick_c.h diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h index a605b707c..2d741c389 100644 --- a/include/SDL_config_iphoneos.h +++ b/include/SDL_config_iphoneos.h @@ -115,8 +115,11 @@ /* Enable the stub haptic driver (src/haptic/dummy/\*.c) */ #define SDL_HAPTIC_DUMMY 1 +/* Enable MFi joystick support */ +#define SDL_JOYSTICK_MFI 1 + /* Enable Unix style SO loading */ -/* Technically this works, but it violates the iPhone developer agreement */ +/* Technically this works, but violates the iOS dev agreement prior to iOS 8 */ /* #define SDL_LOADSO_DLOPEN 1 */ /* Enable the stub shared object loader (src/loadso/dummy/\*.c) */ @@ -148,9 +151,6 @@ /* enable iOS extended launch screen */ #define SDL_IPHONE_LAUNCHSCREEN 1 -/* enable joystick subsystem */ -#define SDL_JOYSTICK_DISABLED 0 - /* Set max recognized G-force from accelerometer See src/joystick/uikit/SDL_sysjoystick.m for notes on why this is needed */ diff --git a/include/SDL_events.h b/include/SDL_events.h index 2ccb10132..8a364c2ad 100644 --- a/include/SDL_events.h +++ b/include/SDL_events.h @@ -94,6 +94,9 @@ typedef enum SDL_KEYUP, /**< Key released */ SDL_TEXTEDITING, /**< Keyboard text editing (composition) */ SDL_TEXTINPUT, /**< Keyboard text input */ + SDL_KEYMAPCHANGED, /**< Keymap changed due to a system event such as an + input language or keyboard layout change. + */ /* Mouse events */ SDL_MOUSEMOTION = 0x400, /**< Mouse moved */ diff --git a/include/SDL_hints.h b/include/SDL_hints.h index fd14051f2..c28cbad8a 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -185,6 +185,20 @@ extern "C" { */ #define SDL_HINT_VIDEO_X11_XRANDR "SDL_VIDEO_X11_XRANDR" +/** + * \brief A variable controlling whether the X11 _NET_WM_PING protocol should be supported. + * + * This variable can be set to the following values: + * "0" - Disable _NET_WM_PING + * "1" - Enable _NET_WM_PING + * + * By default SDL will use _NET_WM_PING, but for applications that know they + * will not always be able to respond to ping requests in a timely manner they can + * turn it off to avoid the window manager thinking the app is hung. + * The hint is checked in CreateWindow. + */ +#define SDL_HINT_VIDEO_X11_NET_WM_PING "SDL_VIDEO_X11_NET_WM_PING" + /** * \brief A variable controlling whether the window frame and title bar are interactive when the cursor is hidden * diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h index cad06a86c..a707e6c38 100644 --- a/include/SDL_joystick.h +++ b/include/SDL_joystick.h @@ -71,6 +71,16 @@ typedef struct { typedef Sint32 SDL_JoystickID; +typedef enum +{ + SDL_JOYSTICK_POWER_UNKNOWN = -1, + SDL_JOYSTICK_POWER_EMPTY, + SDL_JOYSTICK_POWER_LOW, + SDL_JOYSTICK_POWER_MEDIUM, + SDL_JOYSTICK_POWER_FULL, + SDL_JOYSTICK_POWER_WIRED, + SDL_JOYSTICK_POWER_MAX +} SDL_JoystickPowerLevel; /* Function prototypes */ /** @@ -242,6 +252,11 @@ extern DECLSPEC Uint8 SDLCALL SDL_JoystickGetButton(SDL_Joystick * joystick, */ extern DECLSPEC void SDLCALL SDL_JoystickClose(SDL_Joystick * joystick); +/** +* Return the battery level of this joystick +*/ +extern DECLSPEC SDL_JoystickPowerLevel SDLCALL SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick); + /* Ends C function definitions when using C++ */ #ifdef __cplusplus diff --git a/include/SDL_revision.h b/include/SDL_revision.h index 580532e94..76c0758b9 100644 --- a/include/SDL_revision.h +++ b/include/SDL_revision.h @@ -1,2 +1,2 @@ -#define SDL_REVISION "hg-9871:381981a8adb6" -#define SDL_REVISION_NUMBER 9871 +#define SDL_REVISION "hg-9901:c9cae280468f" +#define SDL_REVISION_NUMBER 9901 diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c index 96cc48699..be948d225 100644 --- a/src/core/android/SDL_android.c +++ b/src/core/android/SDL_android.c @@ -71,7 +71,6 @@ static jclass mActivityClass; /* method signatures */ static jmethodID midGetNativeSurface; -static jmethodID midFlipBuffers; static jmethodID midAudioInit; static jmethodID midAudioWriteShortBuffer; static jmethodID midAudioWriteByteBuffer; @@ -119,8 +118,6 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "getNativeSurface","()Landroid/view/Surface;"); - midFlipBuffers = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, - "flipBuffers","()V"); midAudioInit = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, "audioInit", "(IZZI)I"); midAudioWriteShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass, @@ -134,7 +131,7 @@ JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls) bHasNewData = SDL_FALSE; - if(!midGetNativeSurface || !midFlipBuffers || !midAudioInit || + if (!midGetNativeSurface || !midAudioInit || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioQuit || !midPollInputDevices) { __android_log_print(ANDROID_LOG_WARN, "SDL", "SDL: Couldn't locate Java callbacks, check that they're named and typed correctly"); } @@ -267,11 +264,6 @@ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeSurfaceDestroyed( } -JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_nativeFlipBuffers(JNIEnv* env, jclass jcls) -{ - SDL_GL_SwapWindow(Android_Window); -} - /* Keydown */ JNIEXPORT void JNICALL Java_org_libsdl_app_SDLActivity_onNativeKeyDown( JNIEnv* env, jclass jcls, jint keycode) @@ -478,12 +470,6 @@ ANativeWindow* Android_JNI_GetNativeWindow(void) return anw; } -void Android_JNI_SwapWindow(void) -{ - JNIEnv *mEnv = Android_JNI_GetEnv(); - (*mEnv)->CallStaticVoidMethod(mEnv, mActivityClass, midFlipBuffers); -} - void Android_JNI_SetActivityTitle(const char *title) { jmethodID mid; @@ -788,6 +774,10 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx) /* Try fallback to APK expansion files */ mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context), "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;"); + if (!mid) { + SDL_SetError("No openAPKExpansionInputStream() in Java class"); + goto failure; /* Java class is missing the required method */ + } inputStream = (*mEnv)->CallObjectMethod(mEnv, context, mid, fileNameJString); /* Exception is checked first because it always needs to be cleared. diff --git a/src/core/android/SDL_android.h b/src/core/android/SDL_android.h index 378fa0582..758e3023c 100644 --- a/src/core/android/SDL_android.h +++ b/src/core/android/SDL_android.h @@ -33,9 +33,6 @@ extern "C" { #include "SDL_rect.h" /* Interface from the SDL library into the Android Java activity */ -/* extern SDL_bool Android_JNI_CreateContext(int majorVersion, int minorVersion, int red, int green, int blue, int alpha, int buffer, int depth, int stencil, int buffers, int samples); -extern SDL_bool Android_JNI_DeleteContext(void); */ -extern void Android_JNI_SwapWindow(void); extern void Android_JNI_SetActivityTitle(const char *title); extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]); extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect); @@ -64,7 +61,7 @@ SDL_bool Android_JNI_HasClipboardText(void); /* Power support */ int Android_JNI_GetPowerInfo(int* plugged, int* charged, int* battery, int* seconds, int* percent); - + /* Joystick support */ void Android_JNI_PollInputDevices(void); diff --git a/src/core/windows/SDL_xinput.c b/src/core/windows/SDL_xinput.c index f892a8d94..1e13faea6 100644 --- a/src/core/windows/SDL_xinput.c +++ b/src/core/windows/SDL_xinput.c @@ -29,6 +29,7 @@ XInputGetState_t SDL_XInputGetState = NULL; XInputSetState_t SDL_XInputSetState = NULL; XInputGetCapabilities_t SDL_XInputGetCapabilities = NULL; +XInputGetBatteryInformation_t SDL_XInputGetBatteryInformation = NULL; DWORD SDL_XInputVersion = 0; static HANDLE s_pXInputDLL = 0; @@ -55,6 +56,7 @@ WIN_LoadXInputDLL(void) SDL_XInputGetState = (XInputGetState_t)XInputGetState; SDL_XInputSetState = (XInputSetState_t)XInputSetState; SDL_XInputGetCapabilities = (XInputGetCapabilities_t)XInputGetCapabilities; + SDL_XInputGetBatteryInformation = (XInputGetBatteryInformation_t)XInputGetBatteryInformation; /* XInput 1.4 ships with Windows 8 and 8.1: */ SDL_XInputVersion = (1 << 16) | 4; @@ -108,6 +110,7 @@ WIN_LoadXInputDLL(void) } SDL_XInputSetState = (XInputSetState_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputSetState"); SDL_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress((HMODULE)s_pXInputDLL, "XInputGetCapabilities"); + SDL_XInputGetBatteryInformation = (XInputGetBatteryInformation_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetBatteryInformation" ); if (!SDL_XInputGetState || !SDL_XInputSetState || !SDL_XInputGetCapabilities) { WIN_UnloadXInputDLL(); return -1; diff --git a/src/core/windows/SDL_xinput.h b/src/core/windows/SDL_xinput.h index 5c5773763..664edd0c5 100644 --- a/src/core/windows/SDL_xinput.h +++ b/src/core/windows/SDL_xinput.h @@ -76,6 +76,29 @@ #define XINPUT_GAMEPAD_GUIDE 0x0400 #endif +#ifndef BATTERY_DEVTYPE_GAMEPAD +#define BATTERY_DEVTYPE_GAMEPAD 0x00 +#endif +#ifndef BATTERY_TYPE_WIRED +#define BATTERY_TYPE_WIRED 0x01 +#endif + +#ifndef BATTERY_TYPE_UNKNOWN +#define BATTERY_TYPE_UNKNOWN 0xFF +#endif +#ifndef BATTERY_LEVEL_EMPTY +#define BATTERY_LEVEL_EMPTY 0x00 +#endif +#ifndef BATTERY_LEVEL_LOW +#define BATTERY_LEVEL_LOW 0x01 +#endif +#ifndef BATTERY_LEVEL_MEDIUM +#define BATTERY_LEVEL_MEDIUM 0x02 +#endif +#ifndef BATTERY_LEVEL_FULL +#define BATTERY_LEVEL_FULL 0x03 +#endif + /* typedef's for XInput structs we use */ typedef struct { @@ -95,6 +118,12 @@ typedef struct XINPUT_GAMEPAD_EX Gamepad; } XINPUT_STATE_EX; +typedef struct _XINPUT_BATTERY_INFORMATION +{ + BYTE BatteryType; + BYTE BatteryLevel; +} XINPUT_BATTERY_INFORMATION, *PXINPUT_BATTERY_INFORMATION; + /* Forward decl's for XInput API's we load dynamically and use if available */ typedef DWORD (WINAPI *XInputGetState_t) ( @@ -115,17 +144,26 @@ typedef DWORD (WINAPI *XInputGetCapabilities_t) XINPUT_CAPABILITIES* pCapabilities /* [out] Receives the capabilities */ ); +typedef DWORD (WINAPI *XInputGetBatteryInformation_t) + ( + _In_ DWORD dwUserIndex, + _In_ BYTE devType, + _Out_ XINPUT_BATTERY_INFORMATION *pBatteryInformation + ); + extern int WIN_LoadXInputDLL(void); extern void WIN_UnloadXInputDLL(void); extern XInputGetState_t SDL_XInputGetState; extern XInputSetState_t SDL_XInputSetState; extern XInputGetCapabilities_t SDL_XInputGetCapabilities; +extern XInputGetBatteryInformation_t SDL_XInputGetBatteryInformation; extern DWORD SDL_XInputVersion; /* ((major << 16) & 0xFF00) | (minor & 0xFF) */ #define XINPUTGETSTATE SDL_XInputGetState #define XINPUTSETSTATE SDL_XInputSetState #define XINPUTGETCAPABILITIES SDL_XInputGetCapabilities +#define XINPUTGETBATTERYINFORMATION SDL_XInputGetBatteryInformation #endif /* HAVE_XINPUT_H */ diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 3ae3ed89e..6daacd75f 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -594,3 +594,4 @@ #define SDL_ClearQueuedAudio SDL_ClearQueuedAudio_REAL #define SDL_GetGrabbedWindow SDL_GetGrabbedWindow_REAL #define SDL_SetWindowsMessageHook SDL_SetWindowsMessageHook_REAL +#define SDL_JoystickCurrentPowerLevel SDL_JoystickCurrentPowerLevel_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index d085fe5e1..f864a13dd 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -628,3 +628,4 @@ SDL_DYNAPI_PROC(SDL_Window*,SDL_GetGrabbedWindow,(void),(),return) SDL_DYNAPI_PROC(void,SDL_SetWindowsMessageHook,(SDL_WindowsMessageHook a, void *b),(a,b),) #endif SDL_DYNAPI_PROC(int,SDL_GetDisplayDPI,(int a, float *b, float *c, float *d),(a,b,c,d),return) +SDL_DYNAPI_PROC(SDL_JoystickPowerLevel,SDL_JoystickCurrentPowerLevel,(SDL_Joystick *a),(a),return) diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c index 4f5bb2d9a..513cb55ed 100644 --- a/src/events/SDL_events.c +++ b/src/events/SDL_events.c @@ -649,4 +649,10 @@ SDL_SendSysWMEvent(SDL_SysWMmsg * message) return (posted); } +int +SDL_SendKeymapChangedEvent(void) +{ + return SDL_SendAppEvent(SDL_KEYMAPCHANGED); +} + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/events/SDL_events_c.h b/src/events/SDL_events_c.h index ebd983d36..0ead5f304 100644 --- a/src/events/SDL_events_c.h +++ b/src/events/SDL_events_c.h @@ -38,6 +38,7 @@ extern void SDL_QuitInterrupt(void); extern int SDL_SendAppEvent(SDL_EventType eventType); extern int SDL_SendSysWMEvent(SDL_SysWMmsg * message); +extern int SDL_SendKeymapChangedEvent(void); extern int SDL_QuitInit(void); extern int SDL_SendQuit(void); diff --git a/src/haptic/linux/SDL_syshaptic.c b/src/haptic/linux/SDL_syshaptic.c index ab0a57077..659252b54 100644 --- a/src/haptic/linux/SDL_syshaptic.c +++ b/src/haptic/linux/SDL_syshaptic.c @@ -465,7 +465,7 @@ SDL_SYS_HapticOpen(SDL_Haptic * haptic) } /* Set the fname. */ - haptic->hwdata->fname = item->fname; + haptic->hwdata->fname = SDL_strdup( item->fname ); return 0; } @@ -542,11 +542,12 @@ SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) /* Find the joystick in the haptic list. */ for (item = SDL_hapticlist; item; item = item->next) { if (SDL_strcmp(item->fname, joystick->hwdata->fname) == 0) { - haptic->index = device_index; break; } ++device_index; } + haptic->index = device_index; + if (device_index >= MAX_HAPTICS) { return SDL_SetError("Haptic: Joystick doesn't have Haptic capabilities"); } @@ -561,7 +562,8 @@ SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick) return -1; } - haptic->hwdata->fname = item->fname; + haptic->hwdata->fname = SDL_strdup( joystick->hwdata->fname ); + return 0; } @@ -583,6 +585,7 @@ SDL_SYS_HapticClose(SDL_Haptic * haptic) close(haptic->hwdata->fd); /* Free */ + SDL_free(haptic->hwdata->fname); SDL_free(haptic->hwdata); haptic->hwdata = NULL; } diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index d6c23a832..d9193b73a 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -36,6 +36,7 @@ static const char *s_ControllerMappings [] = #endif #if SDL_JOYSTICK_DINPUT "341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "e8206058000000000000504944564944,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,", "ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", "6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ @@ -46,6 +47,7 @@ static const char *s_ControllerMappings [] = "4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", #endif #if defined(__MACOSX__) + "830500000000000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ "6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", @@ -56,6 +58,7 @@ static const char *s_ControllerMappings [] = "5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,", #endif #if defined(__LINUX__) + "03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,", "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,", "030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", @@ -65,6 +68,7 @@ static const char *s_ControllerMappings [] = "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", "03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,", + "050000007e0500003003000001000000,Nintendo Wii Remote Pro Controller,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "050000003620000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,", "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", "03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", @@ -82,6 +86,10 @@ static const char *s_ControllerMappings [] = #if defined(__ANDROID__) "4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,", #endif +#if defined(SDL_JOYSTICK_MFI) + "4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,", + "4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,", +#endif #if defined(SDL_JOYSTICK_EMSCRIPTEN) "emscripten,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", #endif diff --git a/src/joystick/SDL_gamecontrollerdb.h.new b/src/joystick/SDL_gamecontrollerdb.h.new new file mode 100644 index 000000000..7f6c7b29f --- /dev/null +++ b/src/joystick/SDL_gamecontrollerdb.h.new @@ -0,0 +1,65 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + 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_config.h" + + +/* Default mappings we support + + The easiest way to generate a new mapping is to start Steam in Big Picture + mode, configure your joystick and then look in config/config.vdf in your + Steam installation directory for the "SDL_GamepadBind" entry. + */ +static const char *s_ControllerMappings [] = +{ +#ifdef SDL_JOYSTICK_DINPUT + "341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", + "6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ + "88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,", + "4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", + "25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,", + "xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,", +#elif defined(__MACOSX__) + "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", + "6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ + "6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,", + "6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* This includes F710 in DInput mode and the "Logitech Cordless RumblePad 2", at the very least. */ + "4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", + "5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,", +#elif defined(__LINUX__) + "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", + "03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,", + "030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", + "030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ + "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,", + "030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", + "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", +#endif + NULL +}; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 192e0539c..532748cde 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -178,6 +178,7 @@ SDL_JoystickOpen(int device_index) if (joystick->buttons) { SDL_memset(joystick->buttons, 0, joystick->nbuttons * sizeof(Uint8)); } + joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN; /* Add joystick to list */ ++joystick->ref_count; @@ -619,10 +620,10 @@ SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state) /* Make sure we're not getting garbage or duplicate events */ if (button >= joystick->nbuttons) { return 0; - } - if (state == joystick->buttons[button]) { - return 0; - } + } + if (state == joystick->buttons[button]) { + return 0; + } /* We ignore events if we don't have keyboard focus, except for button * release. */ @@ -669,14 +670,17 @@ SDL_JoystickUpdate(void) int i; /* Tell the app that everything is centered/unpressed... */ - for (i = 0; i < joystick->naxes; i++) + for (i = 0; i < joystick->naxes; i++) { SDL_PrivateJoystickAxis(joystick, i, 0); + } - for (i = 0; i < joystick->nbuttons; i++) + for (i = 0; i < joystick->nbuttons; i++) { SDL_PrivateJoystickButton(joystick, i, 0); + } - for (i = 0; i < joystick->nhats; i++) + for (i = 0; i < joystick->nhats; i++) { SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED); + } joystick->force_recentering = SDL_FALSE; } @@ -822,4 +826,21 @@ SDL_JoystickGUID SDL_JoystickGetGUIDFromString(const char *pchGUID) } +/* update the power level for this joystick */ +void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel) +{ + joystick->epowerlevel = ePowerLevel; +} + + +/* return its power level */ +SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick) +{ + if (!SDL_PrivateJoystickValid(joystick)) { + return (SDL_JOYSTICK_POWER_UNKNOWN); + } + return joystick->epowerlevel; +} + + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index ee4a14a37..2da74bd3c 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -41,6 +41,8 @@ extern int SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value); extern int SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state); +extern void SDL_PrivateJoystickBatteryLevel( SDL_Joystick * joystick, + SDL_JoystickPowerLevel ePowerLevel ); /* Internal sanity checking functions */ extern int SDL_PrivateJoystickValid(SDL_Joystick * joystick); diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 7c104b500..f03e40429 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -54,6 +54,7 @@ struct _SDL_Joystick int ref_count; /* Reference count for multiple opens */ SDL_bool force_recentering; /* SDL_TRUE if this device needs to have its state reset to 0 */ + SDL_JoystickPowerLevel epowerlevel; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */ struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */ }; diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index d7a7fcbce..38c0ffe17 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -21,6 +21,10 @@ #include "../../SDL_internal.h" /* This is the iOS implementation of the SDL joystick API */ +#include "SDL_sysjoystick_c.h" + +/* needed for SDL_IPHONE_MAX_GFORCE macro */ +#include "SDL_config_iphoneos.h" #include "SDL_joystick.h" #include "SDL_hints.h" @@ -28,15 +32,221 @@ #include "../SDL_sysjoystick.h" #include "../SDL_joystick_c.h" +#if !SDL_EVENTS_DISABLED +#include "../../events/SDL_events_c.h" +#endif + #import -/* needed for SDL_IPHONE_MAX_GFORCE macro */ -#import "SDL_config_iphoneos.h" +#ifdef SDL_JOYSTICK_MFI +#import -const char *accelerometerName = "iOS Accelerometer"; +static id connectObserver = nil; +static id disconnectObserver = nil; +#endif /* SDL_JOYSTICK_MFI */ +static const char *accelerometerName = "iOS Accelerometer"; static CMMotionManager *motionManager = nil; + +static SDL_JoystickDeviceItem *deviceList = NULL; + static int numjoysticks = 0; +static SDL_JoystickID instancecounter = 0; + +static SDL_JoystickDeviceItem * +GetDeviceForIndex(int device_index) +{ + SDL_JoystickDeviceItem *device = deviceList; + int i = 0; + + while (i < device_index) { + if (device == NULL) { + return NULL; + } + device = device->next; + i++; + } + + return device; +} + +static void +SDL_SYS_AddMFIJoystickDevice(SDL_JoystickDeviceItem *device, GCController *controller) +{ +#ifdef SDL_JOYSTICK_MFI + const char *name = NULL; + /* Explicitly retain the controller because SDL_JoystickDeviceItem is a + * struct, and ARC doesn't work with structs. */ + device->controller = (__bridge GCController *) CFBridgingRetain(controller); + + if (controller.vendorName) { + name = controller.vendorName.UTF8String; + } + + if (!name) { + name = "MFi Gamepad"; + } + + device->name = SDL_strdup(name); + + device->guid.data[0] = 'M'; + device->guid.data[1] = 'F'; + device->guid.data[2] = 'i'; + device->guid.data[3] = 'G'; + device->guid.data[4] = 'a'; + device->guid.data[5] = 'm'; + device->guid.data[6] = 'e'; + device->guid.data[7] = 'p'; + device->guid.data[8] = 'a'; + device->guid.data[9] = 'd'; + + if (controller.extendedGamepad) { + device->guid.data[10] = 1; + } else if (controller.gamepad) { + device->guid.data[10] = 2; + } + + if (controller.extendedGamepad) { + device->naxes = 6; /* 2 thumbsticks and 2 triggers */ + device->nhats = 1; /* d-pad */ + device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */ + } else if (controller.gamepad) { + device->naxes = 0; /* no traditional analog inputs */ + device->nhats = 1; /* d-pad */ + device->nbuttons = 7; /* ABXY, shoulder buttons, pause button */ + } + /* TODO: Handle micro profiles on tvOS. */ +#endif +} + +static void +SDL_SYS_AddJoystickDevice(GCController *controller, SDL_bool accelerometer) +{ + SDL_JoystickDeviceItem *device = deviceList; +#if !SDL_EVENTS_DISABLED + SDL_Event event; +#endif + + while (device != NULL) { + if (device->controller == controller) { + return; + } + device = device->next; + } + + device = (SDL_JoystickDeviceItem *) SDL_malloc(sizeof(SDL_JoystickDeviceItem)); + if (device == NULL) { + return; + } + + SDL_zerop(device); + + device->accelerometer = accelerometer; + device->instance_id = instancecounter++; + + if (accelerometer) { + device->name = SDL_strdup(accelerometerName); + device->naxes = 3; /* Device acceleration in the x, y, and z axes. */ + device->nhats = 0; + device->nbuttons = 0; + + /* Use the accelerometer name as a GUID. */ + SDL_memcpy(&device->guid.data, device->name, SDL_min(sizeof(SDL_JoystickGUID), SDL_strlen(device->name))); + } else if (controller) { + SDL_SYS_AddMFIJoystickDevice(device, controller); + } + + if (deviceList == NULL) { + deviceList = device; + } else { + SDL_JoystickDeviceItem *lastdevice = deviceList; + while (lastdevice->next != NULL) { + lastdevice = lastdevice->next; + } + lastdevice->next = device; + } + + ++numjoysticks; + +#if !SDL_EVENTS_DISABLED + event.type = SDL_JOYDEVICEADDED; + + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.jdevice.which = numjoysticks - 1; + if ((SDL_EventOK == NULL) || + (*SDL_EventOK)(SDL_EventOKParam, &event)) { + SDL_PushEvent(&event); + } + } +#endif /* !SDL_EVENTS_DISABLED */ +} + +static SDL_JoystickDeviceItem * +SDL_SYS_RemoveJoystickDevice(SDL_JoystickDeviceItem *device) +{ + SDL_JoystickDeviceItem *prev = NULL; + SDL_JoystickDeviceItem *next = NULL; + SDL_JoystickDeviceItem *item = deviceList; +#if !SDL_EVENTS_DISABLED + SDL_Event event; +#endif + + if (device == NULL) { + return NULL; + } + + next = device->next; + + while (item != NULL) { + if (item == device) { + break; + } + prev = item; + item = item->next; + } + + /* Unlink the device item from the device list. */ + if (prev) { + prev->next = device->next; + } else if (device == deviceList) { + deviceList = device->next; + } + + if (device->joystick) { + device->joystick->hwdata = NULL; + } + +#ifdef SDL_JOYSTICK_MFI + @autoreleasepool { + if (device->controller) { + /* The controller was explicitly retained in the struct, so it + * should be explicitly released before freeing the struct. */ + GCController *controller = CFBridgingRelease((__bridge CFTypeRef)(device->controller)); + controller.controllerPausedHandler = nil; + device->controller = nil; + } + } +#endif /* SDL_JOYSTICK_MFI */ + + --numjoysticks; + +#if !SDL_EVENTS_DISABLED + event.type = SDL_JOYDEVICEREMOVED; + + if (SDL_GetEventState(event.type) == SDL_ENABLE) { + event.jdevice.which = device->instance_id; + if ((SDL_EventOK == NULL) || + (*SDL_EventOK)(SDL_EventOKParam, &event)) { + SDL_PushEvent(&event); + } + } +#endif /* !SDL_EVENTS_DISABLED */ + + SDL_free(device->name); + SDL_free(device); + + return next; +} /* Function to scan the system for joysticks. * Joystick 0 should be the system default joystick. @@ -45,10 +255,48 @@ int SDL_SYS_JoystickInit(void) { - const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK); - if (!hint || SDL_atoi(hint)) { - /* Default behavior, accelerometer as joystick */ - numjoysticks = 1; + @autoreleasepool { + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + const char *hint = SDL_GetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK); + + if (!hint || SDL_atoi(hint)) { + /* Default behavior, accelerometer as joystick */ + SDL_SYS_AddJoystickDevice(nil, SDL_TRUE); + } + +#ifdef SDL_JOYSTICK_MFI + /* GameController.framework was added in iOS 7. */ + if (![GCController class]) { + return numjoysticks; + } + + for (GCController *controller in [GCController controllers]) { + SDL_SYS_AddJoystickDevice(controller, SDL_FALSE); + } + + connectObserver = [center addObserverForName:GCControllerDidConnectNotification + object:nil + queue:nil + usingBlock:^(NSNotification *note) { + GCController *controller = note.object; + SDL_SYS_AddJoystickDevice(controller, SDL_FALSE); + }]; + + disconnectObserver = [center addObserverForName:GCControllerDidDisconnectNotification + object:nil + queue:nil + usingBlock:^(NSNotification *note) { + GCController *controller = note.object; + SDL_JoystickDeviceItem *device = deviceList; + while (device != NULL) { + if (device->controller == controller) { + SDL_SYS_RemoveJoystickDevice(device); + break; + } + device = device->next; + } + }]; +#endif /* SDL_JOYSTICK_MFI */ } return numjoysticks; @@ -67,13 +315,15 @@ void SDL_SYS_JoystickDetect() const char * SDL_SYS_JoystickNameForDeviceIndex(int device_index) { - return accelerometerName; + SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index); + return device ? device->name : "Unknown"; } /* Function to perform the mapping from device index to the instance id for this index */ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) { - return device_index; + SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index); + return device ? device->instance_id : 0; } /* Function to open a joystick for use. @@ -84,38 +334,61 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index) int SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index) { - joystick->naxes = 3; - joystick->nhats = 0; + SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index); + if (device == NULL) { + return SDL_SetError("Could not open Joystick: no hardware device for the specified index"); + } + + joystick->hwdata = device; + joystick->instance_id = device->instance_id; + + joystick->naxes = device->naxes; + joystick->nhats = device->nhats; + joystick->nbuttons = device->nbuttons; joystick->nballs = 0; - joystick->nbuttons = 0; + + device->joystick = joystick; @autoreleasepool { - if (motionManager == nil) { - motionManager = [[CMMotionManager alloc] init]; + if (device->accelerometer) { + if (motionManager == nil) { + motionManager = [[CMMotionManager alloc] init]; + } + + /* Shorter times between updates can significantly increase CPU usage. */ + motionManager.accelerometerUpdateInterval = 0.1; + [motionManager startAccelerometerUpdates]; + } else { +#ifdef SDL_JOYSTICK_MFI + GCController *controller = device->controller; + controller.controllerPausedHandler = ^(GCController *controller) { + if (joystick->hwdata) { + ++joystick->hwdata->num_pause_presses; + } + }; +#endif /* SDL_JOYSTICK_MFI */ } - - /* Shorter times between updates can significantly increase CPU usage. */ - motionManager.accelerometerUpdateInterval = 0.1; - [motionManager startAccelerometerUpdates]; } return 0; } /* Function to determine if this joystick is attached to the system right now */ -SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick) +SDL_bool +SDL_SYS_JoystickAttached(SDL_Joystick *joystick) { - return SDL_TRUE; + return joystick->hwdata != NULL; } -static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) +static void +SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) { const float maxgforce = SDL_IPHONE_MAX_GFORCE; const SInt16 maxsint16 = 0x7FFF; CMAcceleration accel; @autoreleasepool { - if (!motionManager.accelerometerActive) { + if (!motionManager.isAccelerometerActive) { return; } @@ -144,9 +417,94 @@ static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) accel.z = SDL_min(SDL_max(accel.z, -maxgforce), maxgforce); /* pass in data mapped to range of SInt16 */ - SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16); + SDL_PrivateJoystickAxis(joystick, 0, (accel.x / maxgforce) * maxsint16); SDL_PrivateJoystickAxis(joystick, 1, -(accel.y / maxgforce) * maxsint16); - SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16); + SDL_PrivateJoystickAxis(joystick, 2, (accel.z / maxgforce) * maxsint16); +} + +#ifdef SDL_JOYSTICK_MFI +static Uint8 +SDL_SYS_MFIJoystickHatStateForDPad(GCControllerDirectionPad *dpad) +{ + Uint8 hat = 0; + + if (dpad.up.isPressed) { + hat |= SDL_HAT_UP; + } else if (dpad.down.isPressed) { + hat |= SDL_HAT_DOWN; + } + + if (dpad.left.isPressed) { + hat |= SDL_HAT_LEFT; + } else if (dpad.right.isPressed) { + hat |= SDL_HAT_RIGHT; + } + + if (hat == 0) { + return SDL_HAT_CENTERED; + } + + return hat; +} +#endif + +static void +SDL_SYS_MFIJoystickUpdate(SDL_Joystick * joystick) +{ +#ifdef SDL_JOYSTICK_MFI + @autoreleasepool { + GCController *controller = joystick->hwdata->controller; + Uint8 hatstate = SDL_HAT_CENTERED; + int i; + + if (controller.extendedGamepad) { + GCExtendedGamepad *gamepad = controller.extendedGamepad; + + /* Axis order matches the XInput Windows mappings. */ + SDL_PrivateJoystickAxis(joystick, 0, (Sint16) (gamepad.leftThumbstick.xAxis.value * 32767)); + SDL_PrivateJoystickAxis(joystick, 1, (Sint16) (gamepad.leftThumbstick.yAxis.value * 32767)); + SDL_PrivateJoystickAxis(joystick, 2, (Sint16) (gamepad.leftTrigger.value * 32767)); + SDL_PrivateJoystickAxis(joystick, 3, (Sint16) (gamepad.rightThumbstick.xAxis.value * 32767)); + SDL_PrivateJoystickAxis(joystick, 4, (Sint16) (gamepad.rightThumbstick.yAxis.value * 32767)); + SDL_PrivateJoystickAxis(joystick, 5, (Sint16) (gamepad.rightTrigger.value * 32767)); + + hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad); + + /* Button order matches the XInput Windows mappings. */ + SDL_PrivateJoystickButton(joystick, 0, gamepad.buttonA.isPressed); + SDL_PrivateJoystickButton(joystick, 1, gamepad.buttonB.isPressed); + SDL_PrivateJoystickButton(joystick, 2, gamepad.buttonX.isPressed); + SDL_PrivateJoystickButton(joystick, 3, gamepad.buttonY.isPressed); + SDL_PrivateJoystickButton(joystick, 4, gamepad.leftShoulder.isPressed); + SDL_PrivateJoystickButton(joystick, 5, gamepad.rightShoulder.isPressed); + } else if (controller.gamepad) { + GCGamepad *gamepad = controller.gamepad; + + hatstate = SDL_SYS_MFIJoystickHatStateForDPad(gamepad.dpad); + + /* Button order matches the XInput Windows mappings. */ + SDL_PrivateJoystickButton(joystick, 0, gamepad.buttonA.isPressed); + SDL_PrivateJoystickButton(joystick, 1, gamepad.buttonB.isPressed); + SDL_PrivateJoystickButton(joystick, 2, gamepad.buttonX.isPressed); + SDL_PrivateJoystickButton(joystick, 3, gamepad.buttonY.isPressed); + SDL_PrivateJoystickButton(joystick, 4, gamepad.leftShoulder.isPressed); + SDL_PrivateJoystickButton(joystick, 5, gamepad.rightShoulder.isPressed); + } + /* TODO: Handle micro profiles on tvOS. */ + + SDL_PrivateJoystickHat(joystick, 0, hatstate); + + for (i = 0; i < joystick->hwdata->num_pause_presses; i++) { + /* The pause button is always last. */ + Uint8 pausebutton = joystick->nbuttons - 1; + + SDL_PrivateJoystickButton(joystick, pausebutton, 1); + SDL_PrivateJoystickButton(joystick, pausebutton, 0); + } + + joystick->hwdata->num_pause_presses = 0; + } +#endif } /* Function to update the state of a joystick - called as a device poll. @@ -157,15 +515,40 @@ static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) void SDL_SYS_JoystickUpdate(SDL_Joystick * joystick) { - SDL_SYS_AccelerometerUpdate(joystick); + SDL_JoystickDeviceItem *device = joystick->hwdata; + + if (device == NULL) { + return; + } + + if (device->accelerometer) { + SDL_SYS_AccelerometerUpdate(joystick); + } else if (device->controller) { + SDL_SYS_MFIJoystickUpdate(joystick); + } } /* Function to close a joystick after use */ void SDL_SYS_JoystickClose(SDL_Joystick * joystick) { + SDL_JoystickDeviceItem *device = joystick->hwdata; + + if (device == NULL) { + return; + } + + device->joystick = NULL; + @autoreleasepool { - [motionManager stopAccelerometerUpdates]; + if (device->accelerometer) { + [motionManager stopAccelerometerUpdates]; + } else if (device->controller) { +#ifdef SDL_JOYSTICK_MFI + GCController *controller = device->controller; + controller.controllerPausedHandler = nil; +#endif + } } } @@ -174,29 +557,52 @@ static void SDL_SYS_AccelerometerUpdate(SDL_Joystick * joystick) SDL_SYS_JoystickQuit(void) { @autoreleasepool { +#ifdef SDL_JOYSTICK_MFI + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + + if (connectObserver) { + [center removeObserver:connectObserver name:GCControllerDidConnectNotification object:nil]; + connectObserver = nil; + } + + if (disconnectObserver) { + [center removeObserver:disconnectObserver name:GCControllerDidDisconnectNotification object:nil]; + disconnectObserver = nil; + } +#endif /* SDL_JOYSTICK_MFI */ + + while (deviceList != NULL) { + SDL_SYS_RemoveJoystickDevice(deviceList); + } + motionManager = nil; } numjoysticks = 0; } -SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index ) +SDL_JoystickGUID +SDL_SYS_JoystickGetDeviceGUID( int device_index ) { + SDL_JoystickDeviceItem *device = GetDeviceForIndex(device_index); SDL_JoystickGUID guid; - /* the GUID is just the first 16 chars of the name for now */ - const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index ); - SDL_zero( guid ); - SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) ); + if (device) { + guid = device->guid; + } else { + SDL_zero(guid); + } return guid; } -SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) +SDL_JoystickGUID +SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick) { SDL_JoystickGUID guid; - /* the GUID is just the first 16 chars of the name for now */ - const char *name = joystick->name; - SDL_zero( guid ); - SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) ); + if (joystick->hwdata) { + guid = joystick->hwdata->guid; + } else { + SDL_zero(guid); + } return guid; } diff --git a/src/joystick/iphoneos/SDL_sysjoystick_c.h b/src/joystick/iphoneos/SDL_sysjoystick_c.h new file mode 100644 index 000000000..4d21d90ab --- /dev/null +++ b/src/joystick/iphoneos/SDL_sysjoystick_c.h @@ -0,0 +1,55 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2015 Sam Lantinga + + 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_JOYSTICK_IOS_H +#define SDL_JOYSTICK_IOS_H + +#include "SDL_stdinc.h" +#include "../SDL_sysjoystick.h" + +@class GCController; + +typedef struct joystick_hwdata +{ + SDL_bool accelerometer; + + GCController __unsafe_unretained *controller; + int num_pause_presses; + + char *name; + SDL_Joystick *joystick; + SDL_JoystickID instance_id; + SDL_JoystickGUID guid; + + int naxes; + int nbuttons; + int nhats; + + struct joystick_hwdata *next; +} joystick_hwdata; + +typedef joystick_hwdata SDL_JoystickDeviceItem; + +#endif /* SDL_JOYSTICK_IOS_H */ + + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/joystick/windows/SDL_xinputjoystick.c b/src/joystick/windows/SDL_xinputjoystick.c index b1c22ab1f..b3a4c9e6d 100644 --- a/src/joystick/windows/SDL_xinputjoystick.c +++ b/src/joystick/windows/SDL_xinputjoystick.c @@ -221,8 +221,39 @@ SDL_XINPUT_JoystickOpen(SDL_Joystick * joystick, JoyStick_DeviceData *joystickde return 0; } +static void +UpdateXInputJoystickBatteryInformation(SDL_Joystick * joystick, XINPUT_BATTERY_INFORMATION *pBatteryInformation) +{ + if ( pBatteryInformation->BatteryType != BATTERY_TYPE_UNKNOWN ) + { + SDL_JoystickPowerLevel ePowerLevel = SDL_JOYSTICK_POWER_UNKNOWN; + if (pBatteryInformation->BatteryType == BATTERY_TYPE_WIRED) { + ePowerLevel = SDL_JOYSTICK_POWER_WIRED; + } else { + switch ( pBatteryInformation->BatteryLevel ) + { + case BATTERY_LEVEL_EMPTY: + ePowerLevel = SDL_JOYSTICK_POWER_EMPTY; + break; + case BATTERY_LEVEL_LOW: + ePowerLevel = SDL_JOYSTICK_POWER_LOW; + break; + case BATTERY_LEVEL_MEDIUM: + ePowerLevel = SDL_JOYSTICK_POWER_MEDIUM; + break; + default: + case BATTERY_LEVEL_FULL: + ePowerLevel = SDL_JOYSTICK_POWER_FULL; + break; + } + } + + SDL_PrivateJoystickBatteryLevel( joystick, ePowerLevel ); + } +} + static void -UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState) +UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION *pBatteryInformation) { static WORD s_XInputButtons[] = { XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT, @@ -244,10 +275,12 @@ UpdateXInputJoystickState_OLD(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputS for (button = 0; button < SDL_arraysize(s_XInputButtons); ++button) { SDL_PrivateJoystickButton(joystick, button, (wButtons & s_XInputButtons[button]) ? SDL_PRESSED : SDL_RELEASED); } + + UpdateXInputJoystickBatteryInformation( joystick, pBatteryInformation ); } static void -UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState) +UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState, XINPUT_BATTERY_INFORMATION *pBatteryInformation) { static WORD s_XInputButtons[] = { XINPUT_GAMEPAD_A, XINPUT_GAMEPAD_B, XINPUT_GAMEPAD_X, XINPUT_GAMEPAD_Y, @@ -283,6 +316,8 @@ UpdateXInputJoystickState(SDL_Joystick * joystick, XINPUT_STATE_EX *pXInputState hat |= SDL_HAT_RIGHT; } SDL_PrivateJoystickHat(joystick, 0, hat); + + UpdateXInputJoystickBatteryInformation( joystick, pBatteryInformation ); } void @@ -290,6 +325,7 @@ SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick) { HRESULT result; XINPUT_STATE_EX XInputState; + XINPUT_BATTERY_INFORMATION XBatteryInformation; if (!XINPUTGETSTATE) return; @@ -301,12 +337,18 @@ SDL_XINPUT_JoystickUpdate(SDL_Joystick * joystick) return; } + SDL_zero( XBatteryInformation ); + if ( XINPUTGETBATTERYINFORMATION ) + { + result = XINPUTGETBATTERYINFORMATION( joystick->hwdata->userid, BATTERY_DEVTYPE_GAMEPAD, &XBatteryInformation ); + } + /* only fire events if the data changed from last time */ if (XInputState.dwPacketNumber && XInputState.dwPacketNumber != joystick->hwdata->dwPacketNumber) { if (SDL_XInputUseOldJoystickMapping()) { - UpdateXInputJoystickState_OLD(joystick, &XInputState); + UpdateXInputJoystickState_OLD(joystick, &XInputState, &XBatteryInformation); } else { - UpdateXInputJoystickState(joystick, &XInputState); + UpdateXInputJoystickState(joystick, &XInputState, &XBatteryInformation); } joystick->hwdata->dwPacketNumber = XInputState.dwPacketNumber; } diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index 78d67144f..ebe4100aa 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -2504,7 +2504,7 @@ D3D11_RenderDrawPoints(SDL_Renderer * renderer, a = (float)(renderer->a / 255.0f); vertices = SDL_stack_alloc(VertexPositionColor, count); - for (i = 0; i < min(count, 128); ++i) { + for (i = 0; i < count; ++i) { const VertexPositionColor v = { { points[i].x, points[i].y, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } }; vertices[i] = v; } diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index a89399d9d..7aa0aaaab 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1136,8 +1136,19 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) /* if we are in the process of hiding don't go back to fullscreen */ if ( window->is_hiding && fullscreen ) return 0; - + #ifdef __MACOSX__ + /* If we're switching between a fullscreen Space and "normal" fullscreen, we need to get back to normal first. */ + if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN)) { + Cocoa_SetWindowFullscreenSpace(window, SDL_FALSE); + } else if (fullscreen && ((window->last_fullscreen_flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN) && ((window->flags & FULLSCREEN_MASK) == SDL_WINDOW_FULLSCREEN_DESKTOP)) { + display = SDL_GetDisplayForWindow(window); + SDL_SetDisplayModeForDisplay(display, NULL); + if (_this->SetWindowFullscreen) { + _this->SetWindowFullscreen(_this, window, display, SDL_FALSE); + } + } + if (Cocoa_SetWindowFullscreenSpace(window, fullscreen)) { window->last_fullscreen_flags = window->flags; return 0; diff --git a/src/video/android/SDL_androidkeyboard.c b/src/video/android/SDL_androidkeyboard.c index d75e42ada..a61235175 100644 --- a/src/video/android/SDL_androidkeyboard.c +++ b/src/video/android/SDL_androidkeyboard.c @@ -300,6 +300,22 @@ static SDL_Scancode Android_Keycodes[] = { 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, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + SDL_SCANCODE_UNKNOWN, + 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 */ }; static SDL_Scancode diff --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m index 41ecf1f63..9abca976a 100644 --- a/src/video/cocoa/SDL_cocoakeyboard.m +++ b/src/video/cocoa/SDL_cocoakeyboard.m @@ -398,7 +398,7 @@ - (NSArray *) validAttributesForMarkedText } static void -UpdateKeymap(SDL_VideoData *data) +UpdateKeymap(SDL_VideoData *data, SDL_bool send_event) { TISInputSourceRef key_layout; const void *chr_data; @@ -454,6 +454,9 @@ - (NSArray *) validAttributesForMarkedText } } SDL_SetKeymap(0, keymap, SDL_NUM_SCANCODES); + if (send_event) { + SDL_SendKeymapChangedEvent(); + } return; } @@ -466,7 +469,7 @@ - (NSArray *) validAttributesForMarkedText { SDL_VideoData *data = (SDL_VideoData *) _this->driverdata; - UpdateKeymap(data); + UpdateKeymap(data, SDL_FALSE); /* Set our own names for the platform-dependent but layout-independent keys */ /* This key is NumLock on the MacBook keyboard. :) */ @@ -564,7 +567,7 @@ - (NSArray *) validAttributesForMarkedText case NSKeyDown: if (![event isARepeat]) { /* See if we need to rebuild the keyboard layout */ - UpdateKeymap(data); + UpdateKeymap(data, SDL_TRUE); } SDL_SendKeyboardKey(SDL_PRESSED, code); diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 258c67733..1ab5baca0 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -1602,8 +1602,10 @@ - (void)resetCursorRects } if ( data && (window->flags & SDL_WINDOW_FULLSCREEN) ) { - if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS)) { + if (SDL_ShouldAllowTopmost() && (window->flags & SDL_WINDOW_INPUT_FOCUS) + && ![data->listener isInFullscreenSpace]) { /* OpenGL is rendering to the window, so make it visible! */ + /* Doing this in 10.11 while in a Space breaks things (bug #3152) */ [data->nswindow setLevel:CGShieldingWindowLevel()]; } else { [data->nswindow setLevel:kCGNormalWindowLevel]; diff --git a/src/video/uikit/SDL_uikitmessagebox.m b/src/video/uikit/SDL_uikitmessagebox.m index dea8bdc69..6c980d472 100644 --- a/src/video/uikit/SDL_uikitmessagebox.m +++ b/src/video/uikit/SDL_uikitmessagebox.m @@ -24,15 +24,103 @@ #include "SDL.h" #include "SDL_uikitvideo.h" - +#include "SDL_uikitwindow.h" /* Display a UIKit message box */ static SDL_bool s_showingMessageBox = SDL_FALSE; +SDL_bool +UIKit_ShowingMessageBox() +{ + return s_showingMessageBox; +} + +static void +UIKit_WaitUntilMessageBoxClosed(const SDL_MessageBoxData *messageboxdata, int *clickedindex) +{ + *clickedindex = messageboxdata->numbuttons; + + @autoreleasepool { + /* Run the main event loop until the alert has finished */ + /* Note that this needs to be done on the main thread */ + s_showingMessageBox = SDL_TRUE; + while ((*clickedindex) == messageboxdata->numbuttons) { + [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; + } + s_showingMessageBox = SDL_FALSE; + } +} + +static BOOL +UIKit_ShowMessageBoxAlertController(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ +#ifdef __IPHONE_8_0 + int i; + int __block clickedindex = messageboxdata->numbuttons; + const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; + UIWindow *window = nil; + UIWindow *alertwindow = nil; + + if (![UIAlertController class]) { + return NO; + } + + UIAlertController *alert; + alert = [UIAlertController alertControllerWithTitle:@(messageboxdata->title) + message:@(messageboxdata->message) + preferredStyle:UIAlertControllerStyleAlert]; + + for (i = 0; i < messageboxdata->numbuttons; i++) { + UIAlertAction *action; + UIAlertActionStyle style = UIAlertActionStyleDefault; + + if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) { + style = UIAlertActionStyleCancel; + } + + action = [UIAlertAction actionWithTitle:@(buttons[i].text) + style:style + handler:^(UIAlertAction *action) { + clickedindex = i; + }]; + [alert addAction:action]; + } + + if (messageboxdata->window) { + SDL_WindowData *data = (__bridge SDL_WindowData *) messageboxdata->window->driverdata; + window = data.uiwindow; + } + + if (window == nil || window.rootViewController == nil) { + alertwindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; + alertwindow.rootViewController = [UIViewController new]; + alertwindow.windowLevel = UIWindowLevelAlert; + + window = alertwindow; + + [alertwindow makeKeyAndVisible]; + } + + [window.rootViewController presentViewController:alert animated:YES completion:nil]; + UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex); + + if (alertwindow) { + alertwindow.hidden = YES; + } + + *buttonid = messageboxdata->buttons[clickedindex].buttonid; + return YES; +#else + return NO; +#endif /* __IPHONE_8_0 */ +} + +/* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 @interface SDLAlertViewDelegate : NSObject -@property (nonatomic, assign) int clickedIndex; +@property (nonatomic, assign) int *clickedIndex; @end @@ -40,52 +128,62 @@ @implementation SDLAlertViewDelegate - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { - _clickedIndex = (int)buttonIndex; + if (_clickedIndex != NULL) { + *_clickedIndex = (int) buttonIndex; + } } @end +#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ - -SDL_bool -UIKit_ShowingMessageBox() -{ - return s_showingMessageBox; -} - -int -UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +static BOOL +UIKit_ShowMessageBoxAlertView(const SDL_MessageBoxData *messageboxdata, int *buttonid) { + /* UIAlertView is deprecated in iOS 8+ in favor of UIAlertController. */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 int i; + int clickedindex = messageboxdata->numbuttons; const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons; + UIAlertView *alert = [[UIAlertView alloc] init]; + SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init]; - @autoreleasepool { - UIAlertView *alert = [[UIAlertView alloc] init]; - SDLAlertViewDelegate *delegate = [[SDLAlertViewDelegate alloc] init]; + alert.delegate = delegate; + alert.title = @(messageboxdata->title); + alert.message = @(messageboxdata->message); - alert.delegate = delegate; - alert.title = @(messageboxdata->title); - alert.message = @(messageboxdata->message); + for (i = 0; i < messageboxdata->numbuttons; i++) { + [alert addButtonWithTitle:@(buttons[i].text)]; + } - for (i = 0; i < messageboxdata->numbuttons; ++i) { - [alert addButtonWithTitle:@(buttons[i].text)]; - } + delegate.clickedIndex = &clickedindex; - /* Set up for showing the alert */ - delegate.clickedIndex = messageboxdata->numbuttons; + [alert show]; - [alert show]; + UIKit_WaitUntilMessageBoxClosed(messageboxdata, &clickedindex); - /* Run the main event loop until the alert has finished */ - /* Note that this needs to be done on the main thread */ - s_showingMessageBox = SDL_TRUE; - while (delegate.clickedIndex == messageboxdata->numbuttons) { - [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; - } - s_showingMessageBox = SDL_FALSE; + alert.delegate = nil; - *buttonid = messageboxdata->buttons[delegate.clickedIndex].buttonid; + *buttonid = messageboxdata->buttons[clickedindex].buttonid; + return YES; +#else + return NO; +#endif /* __IPHONE_OS_VERSION_MIN_REQUIRED < 80000 */ +} + +int +UIKit_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + BOOL success = NO; + + @autoreleasepool { + success = UIKit_ShowMessageBoxAlertController(messageboxdata, buttonid); + if (!success) { + success = UIKit_ShowMessageBoxAlertView(messageboxdata, buttonid); + } + } - alert.delegate = nil; + if (!success) { + return SDL_SetError("Could not show message box."); } return 0; diff --git a/src/video/uikit/SDL_uikitopengles.m b/src/video/uikit/SDL_uikitopengles.m index e9c26e318..ef901247f 100644 --- a/src/video/uikit/SDL_uikitopengles.m +++ b/src/video/uikit/SDL_uikitopengles.m @@ -52,8 +52,6 @@ - (void)dealloc @end -static int UIKit_GL_Initialize(_THIS); - void * UIKit_GL_GetProcAddress(_THIS, const char *proc) { diff --git a/src/video/uikit/SDL_uikitviewcontroller.h b/src/video/uikit/SDL_uikitviewcontroller.h index 17db0b26a..e8462b8e2 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.h +++ b/src/video/uikit/SDL_uikitviewcontroller.h @@ -47,9 +47,7 @@ - (void)loadView; - (void)viewDidLayoutSubviews; - (NSUInteger)supportedInterfaceOrientations; -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient; - (BOOL)prefersStatusBarHidden; -- (UIStatusBarStyle)preferredStatusBarStyle; #if SDL_IPHONE_KEYBOARD - (void)showKeyboard; diff --git a/src/video/uikit/SDL_uikitviewcontroller.m b/src/video/uikit/SDL_uikitviewcontroller.m index e1667aac8..112638eb2 100644 --- a/src/video/uikit/SDL_uikitviewcontroller.m +++ b/src/video/uikit/SDL_uikitviewcontroller.m @@ -135,12 +135,6 @@ - (BOOL)prefersStatusBarHidden return (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_BORDERLESS)) != 0; } -- (UIStatusBarStyle)preferredStatusBarStyle -{ - /* We assume most SDL apps don't have a bright white background. */ - return UIStatusBarStyleLightContent; -} - /* ---- Keyboard related functionality below this line ---- */ diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c index 8f3ec6855..3ce8291df 100644 --- a/src/video/windows/SDL_windowsevents.c +++ b/src/video/windows/SDL_windowsevents.c @@ -607,25 +607,26 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) break; case WM_UNICHAR: - if ( wParam == UNICODE_NOCHAR ) { - returnCode = 1; - break; - } - /* otherwise fall through to below */ - case WM_CHAR: - { - char text[5]; - if ( WIN_ConvertUTF32toUTF8( (UINT32)wParam, text ) ) { - SDL_SendKeyboardText( text ); - } - } - returnCode = 0; + if ( wParam == UNICODE_NOCHAR ) { + returnCode = 1; + break; + } + /* otherwise fall through to below */ + case WM_CHAR: + { + char text[5]; + if ( WIN_ConvertUTF32toUTF8( (UINT32)wParam, text ) ) { + SDL_SendKeyboardText( text ); + } + } + returnCode = 0; break; #ifdef WM_INPUTLANGCHANGE case WM_INPUTLANGCHANGE: { WIN_UpdateKeymap(); + SDL_SendKeymapChangedEvent(); } returnCode = 1; break; @@ -735,7 +736,7 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) int x, y; int w, h; - if (data->in_border_change) { + if (data->initializing || data->in_border_change) { break; } @@ -813,9 +814,9 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) case WM_SYSCOMMAND: { - if ((wParam & 0xFFF0) == SC_KEYMENU) { - return (0); - } + if ((wParam & 0xFFF0) == SC_KEYMENU) { + return (0); + } #if defined(SC_SCREENSAVE) || defined(SC_MONITORPOWER) /* Don't start the screensaver or blank the monitor in fullscreen apps */ diff --git a/src/video/windows/SDL_windowskeyboard.c b/src/video/windows/SDL_windowskeyboard.c index 02f7b630f..d56f4042a 100644 --- a/src/video/windows/SDL_windowskeyboard.c +++ b/src/video/windows/SDL_windowskeyboard.c @@ -124,7 +124,7 @@ WIN_UpdateKeymap() /* If this key is one of the non-mappable keys, ignore it */ /* Not mapping numbers fixes the French layout, giving numeric keycodes for the number keys, which is the expected behavior */ if ((keymap[scancode] & SDLK_SCANCODE_MASK) || - /* scancode == SDL_SCANCODE_GRAVE || */ /* Uncomment this line to re-enable the behavior of not mapping the "`"(grave) key to the users actual keyboard layout */ + /* scancode == SDL_SCANCODE_GRAVE || */ /* Uncomment this line to re-enable the behavior of not mapping the "`"(grave) key to the users actual keyboard layout */ (scancode >= SDL_SCANCODE_1 && scancode <= SDL_SCANCODE_0) ) { continue; } @@ -402,7 +402,7 @@ IME_GetReadingString(SDL_VideoData *videodata, HWND hwnd) INT err = 0; BOOL vertical = FALSE; UINT maxuilen = 0; - static OSVERSIONINFOA osversion; + static OSVERSIONINFOA osversion; if (videodata->ime_uiless) return; diff --git a/src/video/windows/SDL_windowsmodes.c b/src/video/windows/SDL_windowsmodes.c index f5f2b8a8a..7cb4ea5b8 100644 --- a/src/video/windows/SDL_windowsmodes.c +++ b/src/video/windows/SDL_windowsmodes.c @@ -30,43 +30,43 @@ #endif typedef struct _WIN_GetMonitorDPIData { - SDL_VideoData *vid_data; - SDL_DisplayMode *mode; - SDL_DisplayModeData *mode_data; + SDL_VideoData *vid_data; + SDL_DisplayMode *mode; + SDL_DisplayModeData *mode_data; } WIN_GetMonitorDPIData; static BOOL CALLBACK WIN_GetMonitorDPI(HMONITOR hMonitor, - HDC hdcMonitor, - LPRECT lprcMonitor, - LPARAM dwData) + HDC hdcMonitor, + LPRECT lprcMonitor, + LPARAM dwData) { - WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData; - UINT hdpi, vdpi; - - if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK && - hdpi > 0 && - vdpi > 0) { - float hsize, vsize; - - data->mode_data->HorzDPI = (float)hdpi; - data->mode_data->VertDPI = (float)vdpi; - - // Figure out the monitor size and compute the diagonal DPI. - hsize = data->mode->w / data->mode_data->HorzDPI; - vsize = data->mode->h / data->mode_data->VertDPI; - - data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w, - data->mode->h, - hsize, - vsize ); - - // We can only handle one DPI per display mode so end the enumeration. - return FALSE; - } - - // We didn't get DPI information so keep going. - return TRUE; + WIN_GetMonitorDPIData *data = (WIN_GetMonitorDPIData*) dwData; + UINT hdpi, vdpi; + + if (data->vid_data->GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &hdpi, &vdpi) == S_OK && + hdpi > 0 && + vdpi > 0) { + float hsize, vsize; + + data->mode_data->HorzDPI = (float)hdpi; + data->mode_data->VertDPI = (float)vdpi; + + // Figure out the monitor size and compute the diagonal DPI. + hsize = data->mode->w / data->mode_data->HorzDPI; + vsize = data->mode->h / data->mode_data->VertDPI; + + data->mode_data->DiagDPI = SDL_ComputeDiagonalDPI( data->mode->w, + data->mode->h, + hsize, + vsize ); + + // We can only handle one DPI per display mode so end the enumeration. + return FALSE; + } + + // We didn't get DPI information so keep going. + return TRUE; } static SDL_bool @@ -91,11 +91,11 @@ WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mod data->DeviceMode.dmFields = (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY | DM_DISPLAYFLAGS); - data->ScaleX = 1.0f; - data->ScaleY = 1.0f; - data->DiagDPI = 0.0f; - data->HorzDPI = 0.0f; - data->VertDPI = 0.0f; + data->ScaleX = 1.0f; + data->ScaleY = 1.0f; + data->DiagDPI = 0.0f; + data->HorzDPI = 0.0f; + data->VertDPI = 0.0f; /* Fill in the mode information */ mode->format = SDL_PIXELFORMAT_UNKNOWN; @@ -109,43 +109,43 @@ WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mod char bmi_data[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)]; LPBITMAPINFO bmi; HBITMAP hbm; - int logical_width = GetDeviceCaps( hdc, HORZRES ); - int logical_height = GetDeviceCaps( hdc, VERTRES ); - - data->ScaleX = (float)logical_width / devmode.dmPelsWidth; - data->ScaleY = (float)logical_height / devmode.dmPelsHeight; - mode->w = logical_width; - mode->h = logical_height; - - // WIN_GetMonitorDPI needs mode->w and mode->h - // so only call after those are set. - if (vid_data->GetDpiForMonitor) { - WIN_GetMonitorDPIData dpi_data; + int logical_width = GetDeviceCaps( hdc, HORZRES ); + int logical_height = GetDeviceCaps( hdc, VERTRES ); + + data->ScaleX = (float)logical_width / devmode.dmPelsWidth; + data->ScaleY = (float)logical_height / devmode.dmPelsHeight; + mode->w = logical_width; + mode->h = logical_height; + + // WIN_GetMonitorDPI needs mode->w and mode->h + // so only call after those are set. + if (vid_data->GetDpiForMonitor) { + WIN_GetMonitorDPIData dpi_data; RECT monitor_rect; - dpi_data.vid_data = vid_data; - dpi_data.mode = mode; - dpi_data.mode_data = data; + dpi_data.vid_data = vid_data; + dpi_data.mode = mode; + dpi_data.mode_data = data; monitor_rect.left = devmode.dmPosition.x; monitor_rect.top = devmode.dmPosition.y; monitor_rect.right = monitor_rect.left + 1; monitor_rect.bottom = monitor_rect.top + 1; - EnumDisplayMonitors(NULL, &monitor_rect, WIN_GetMonitorDPI, (LPARAM)&dpi_data); - } else { - // We don't have the Windows 8.1 routine so just - // get system DPI. - data->HorzDPI = (float)GetDeviceCaps( hdc, LOGPIXELSX ); - data->VertDPI = (float)GetDeviceCaps( hdc, LOGPIXELSY ); - if (data->HorzDPI == data->VertDPI) { - data->DiagDPI = data->HorzDPI; - } else { - data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w, - mode->h, - (float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f, - (float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f ); - } - } - + EnumDisplayMonitors(NULL, &monitor_rect, WIN_GetMonitorDPI, (LPARAM)&dpi_data); + } else { + // We don't have the Windows 8.1 routine so just + // get system DPI. + data->HorzDPI = (float)GetDeviceCaps( hdc, LOGPIXELSX ); + data->VertDPI = (float)GetDeviceCaps( hdc, LOGPIXELSY ); + if (data->HorzDPI == data->VertDPI) { + data->DiagDPI = data->HorzDPI; + } else { + data->DiagDPI = SDL_ComputeDiagonalDPI( mode->w, + mode->h, + (float)GetDeviceCaps( hdc, HORZSIZE ) / 25.4f, + (float)GetDeviceCaps( hdc, VERTSIZE ) / 25.4f ); + } + } + SDL_zero(bmi_data); bmi = (LPBITMAPINFO) bmi_data; bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); @@ -175,7 +175,7 @@ WIN_GetDisplayMode(_THIS, LPCTSTR deviceName, DWORD index, SDL_DisplayMode * mod } else if (bmi->bmiHeader.biBitCount == 4) { mode->format = SDL_PIXELFORMAT_INDEX4LSB; } - } else { + } else { /* FIXME: Can we tell what this will be? */ if ((devmode.dmFields & DM_BITSPERPEL) == DM_BITSPERPEL) { switch (devmode.dmBitsPerPel) { @@ -319,17 +319,17 @@ WIN_GetDisplayDPI(_THIS, SDL_VideoDisplay * display, float * ddpi, float * hdpi, { SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata; - if (ddpi) { - *ddpi = data->DiagDPI; - } - if (hdpi) { - *hdpi = data->HorzDPI; - } - if (vdpi) { - *vdpi = data->VertDPI; - } - - return data->DiagDPI != 0.0f ? 0 : -1; + if (ddpi) { + *ddpi = data->DiagDPI; + } + if (hdpi) { + *hdpi = data->HorzDPI; + } + if (vdpi) { + *vdpi = data->VertDPI; + } + + return data->DiagDPI != 0.0f ? 0 : -1; } void diff --git a/src/video/windows/SDL_windowsmodes.h b/src/video/windows/SDL_windowsmodes.h index ba0964a3b..2bf9f4c86 100644 --- a/src/video/windows/SDL_windowsmodes.h +++ b/src/video/windows/SDL_windowsmodes.h @@ -31,11 +31,11 @@ typedef struct typedef struct { DEVMODE DeviceMode; - float ScaleX; - float ScaleY; + float ScaleX; + float ScaleY; float DiagDPI; - float HorzDPI; - float VertDPI; + float HorzDPI; + float VertDPI; } SDL_DisplayModeData; extern int WIN_InitModes(_THIS); diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c index 2dc5386d7..70e80a95a 100644 --- a/src/video/windows/SDL_windowswindow.c +++ b/src/video/windows/SDL_windowswindow.c @@ -109,7 +109,7 @@ WIN_SetWindowPositionInternal(_THIS, SDL_Window * window, UINT flags) y = window->y + rect.top; data->expected_resize = SDL_TRUE; - SetWindowPos( hwnd, top, x, y, w, h, flags ); + SetWindowPos(hwnd, top, x, y, w, h, flags); data->expected_resize = SDL_FALSE; } @@ -130,6 +130,7 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created) data->created = created; data->mouse_button_flags = 0; data->videodata = videodata; + data->initializing = SDL_TRUE; window->driverdata = data; @@ -165,7 +166,26 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created) int h = rect.bottom; if ((window->w && window->w != w) || (window->h && window->h != h)) { /* We tried to create a window larger than the desktop and Windows didn't allow it. Override! */ - WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE); + RECT rect; + DWORD style; + BOOL menu; + int x, y; + int w, h; + + /* Figure out what the window area will be */ + style = GetWindowLong(hwnd, GWL_STYLE); + rect.left = 0; + rect.top = 0; + rect.right = window->w; + rect.bottom = window->h; + menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL); + AdjustWindowRectEx(&rect, style, menu, 0); + w = (rect.right - rect.left); + h = (rect.bottom - rect.top); + x = window->x + rect.left; + y = window->y + rect.top; + + SetWindowPos(hwnd, HWND_NOTOPMOST, x, y, w, h, SWP_NOCOPYBITS | SWP_NOZORDER | SWP_NOACTIVATE); } else { window->w = w; window->h = h; @@ -236,6 +256,8 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, SDL_bool created) /* Enable dropping files */ DragAcceptFiles(hwnd, TRUE); + data->initializing = SDL_FALSE; + /* All done! */ return 0; } @@ -492,7 +514,7 @@ WIN_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered) } data->in_border_change = SDL_TRUE; - SetWindowLong( hwnd, GWL_STYLE, style ); + SetWindowLong(hwnd, GWL_STYLE, style); WIN_SetWindowPositionInternal(_this, window, SWP_NOCOPYBITS | SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOACTIVATE); data->in_border_change = SDL_FALSE; } diff --git a/src/video/windows/SDL_windowswindow.h b/src/video/windows/SDL_windowswindow.h index 32ce279ed..6b8b0c2d3 100644 --- a/src/video/windows/SDL_windowswindow.h +++ b/src/video/windows/SDL_windowswindow.h @@ -37,10 +37,11 @@ typedef struct WNDPROC wndproc; SDL_bool created; WPARAM mouse_button_flags; + SDL_bool initializing; SDL_bool expected_resize; SDL_bool in_border_change; SDL_bool in_title_click; - SDL_bool focus_click_pending; + SDL_bool focus_click_pending; struct SDL_VideoData *videodata; #if SDL_VIDEO_OPENGL_EGL EGLSurface egl_surface; diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 7ec4edf75..2f730c440 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -625,6 +625,7 @@ X11_DispatchEvent(_THIS) } X11_UpdateKeymap(_this); + SDL_SendKeymapChangedEvent(); } return; } @@ -1143,6 +1144,7 @@ X11_DispatchEvent(_THIS) notice and reinit our keymap here. This might not be the right approach, but it seems to work. */ X11_UpdateKeymap(_this); + SDL_SendKeymapChangedEvent(); } } break; diff --git a/src/video/x11/SDL_x11window.c b/src/video/x11/SDL_x11window.c index 2a7799705..b95056111 100644 --- a/src/video/x11/SDL_x11window.c +++ b/src/video/x11/SDL_x11window.c @@ -542,11 +542,23 @@ X11_CreateWindow(_THIS, SDL_Window * window) (unsigned char *)&_NET_WM_BYPASS_COMPOSITOR_HINT_ON, 1); { - Atom protocols[] = { - data->WM_DELETE_WINDOW, /* Allow window to be deleted by the WM */ - data->_NET_WM_PING, /* Respond so WM knows we're alive */ - }; - X11_XSetWMProtocols(display, w, protocols, sizeof (protocols) / sizeof (protocols[0])); + Atom protocols[2]; + int proto_count = 0; + const char *ping_hint; + + protocols[proto_count] = data->WM_DELETE_WINDOW; /* Allow window to be deleted by the WM */ + proto_count++; + + ping_hint = SDL_GetHint(SDL_HINT_VIDEO_X11_NET_WM_PING); + /* Default to using ping if there is no hint */ + if (!ping_hint || SDL_atoi(ping_hint)) { + protocols[proto_count] = data->_NET_WM_PING; /* Respond so WM knows we're alive */ + proto_count++; + } + + SDL_assert(proto_count <= sizeof(protocols) / sizeof(protocols[0])); + + X11_XSetWMProtocols(display, w, protocols, proto_count); } if (SetupWindowData(_this, window, w, SDL_TRUE) < 0) {