From df0e26ca280186e408858c888362faa9d1d15985 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sat, 17 May 2025 20:00:34 +0900 Subject: [PATCH 01/16] switch: initial support for 3.2.14, based off 2.28.5 devkitpro repo Contains thread and timers as that's the bare minimum now. --- CMakeLists.txt | 20 +++++++-- cmake/sdlplatform.cmake | 2 + include/SDL3/SDL_platform_defines.h | 4 ++ include/build_config/SDL_build_config.h.cmake | 1 + src/dynapi/SDL_dynapi.h | 2 + src/thread/pthread/SDL_systhread.c | 24 +++++++++-- src/timer/switch/SDL_systimer.c | 42 +++++++++++++++++++ 7 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 src/timer/switch/SDL_systimer.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b9c768847ee3..54c9fa929b45f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,13 +140,13 @@ endif() # for the time being. This default will change to ON once this becomes # commonly supported in browsers or the Emscripten team makes a single # binary work everywhere. -if (UNIX_OR_MAC_SYS AND NOT EMSCRIPTEN) +if ((UNIX_OR_MAC_SYS OR NINTENDO_SWITCH) AND NOT EMSCRIPTEN) set(SDL_PTHREADS_DEFAULT ON) else() set(SDL_PTHREADS_DEFAULT OFF) endif() -if(UNIX_SYS OR ANDROID) +if((UNIX_SYS OR NINTENDO_SWITCH) OR ANDROID) set(SDL_CLOCK_GETTIME_DEFAULT ON) else() set(SDL_CLOCK_GETTIME_DEFAULT OFF) @@ -219,7 +219,7 @@ if(EMSCRIPTEN) set(SDL_SHARED_AVAILABLE OFF) endif() -if(VITA OR PSP OR PS2 OR N3DS OR RISCOS) +if(VITA OR PSP OR PS2 OR N3DS OR RISCOS OR NINTENDO_SWITCH) set(SDL_SHARED_AVAILABLE OFF) endif() @@ -2924,6 +2924,20 @@ elseif(N3DS) set(HAVE_SDL_LOCALE TRUE) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/io/n3ds/*.c") +elseif(NINTENDO_SWITCH) + sdl_link_dependency(nx LIBS nx) + + CheckPTHREAD() + + if(SDL_CLOCK_GETTIME) + set(HAVE_CLOCK_GETTIME 1) + endif() + + set(SDL_TIMER_SWITCH 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/switch/*.c") + set(HAVE_SDL_TIMERS TRUE) + + set(SDL_STATIC_PIC TRUE) endif() sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/SDL_dialog.c) diff --git a/cmake/sdlplatform.cmake b/cmake/sdlplatform.cmake index 677b187073ad2..bfec0c05a4b4a 100644 --- a/cmake/sdlplatform.cmake +++ b/cmake/sdlplatform.cmake @@ -2,6 +2,8 @@ function(SDL_DetectCMakePlatform) set(sdl_cmake_platform ) if(WIN32) set(sdl_cmake_platform Windows) + elseif(NINTENDO_SWITCH) + set(sdl_cmake_platform NintendoSwitch) elseif(PSP) set(sdl_cmake_platform psp) elseif(APPLE) diff --git a/include/SDL3/SDL_platform_defines.h b/include/SDL3/SDL_platform_defines.h index 6b240a8be4579..e2aa59cea4ab0 100644 --- a/include/SDL3/SDL_platform_defines.h +++ b/include/SDL3/SDL_platform_defines.h @@ -473,4 +473,8 @@ #define SDL_PLATFORM_3DS 1 #endif +#if defined(__SWITCH__) && __SWITCH__ +#define SDL_PLATFORM_SWITCH 1 +#endif + #endif /* SDL_platform_defines_h_ */ diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 6ce491e7d2fb9..e712b506ece1b 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -353,6 +353,7 @@ #cmakedefine SDL_TIMER_PSP 1 #cmakedefine SDL_TIMER_PS2 1 #cmakedefine SDL_TIMER_N3DS 1 +#cmakedefine SDL_TIMER_SWITCH 1 /* Enable various video drivers */ #cmakedefine SDL_VIDEO_DRIVER_ANDROID 1 diff --git a/src/dynapi/SDL_dynapi.h b/src/dynapi/SDL_dynapi.h index 99ef9a9e93f0f..d57aa4df7005b 100644 --- a/src/dynapi/SDL_dynapi.h +++ b/src/dynapi/SDL_dynapi.h @@ -63,6 +63,8 @@ #define SDL_DYNAMIC_API 0 // vitasdk doesn't support dynamic linking #elif defined(SDL_PLATFORM_3DS) #define SDL_DYNAMIC_API 0 // devkitARM doesn't support dynamic linking +#elif defined(SDL_PLATFORM_SWITCH) +#define SDL_DYNAMIC_API 0 // devkitA64 doesn't support dynamic linking #elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN) #define SDL_DYNAMIC_API 0 // we need dlopen(), but don't have it.... #endif diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c index ae4a94c2e273a..dac99641eb729 100644 --- a/src/thread/pthread/SDL_systhread.c +++ b/src/thread/pthread/SDL_systhread.c @@ -57,7 +57,11 @@ #include #endif -#ifdef HAVE_SIGNAL_H +#ifdef SDL_PLATFORM_SWITCH +#include +#endif + +#if defined(HAVE_SIGNAL_H) && !SDL_PLATFORM_SWITCH // List of signals to mask in the subthreads static const int sig_list[] = { SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH, @@ -121,7 +125,7 @@ bool SDL_SYS_CreateThread(SDL_Thread *thread, void SDL_SYS_SetupThread(const char *name) { -#ifdef HAVE_SIGNAL_H +#if defined(HAVE_SIGNAL_H) && !SDL_PLATFORM_SWITCH int i; sigset_t mask; #endif @@ -160,7 +164,7 @@ void SDL_SYS_SetupThread(const char *name) #endif } -#ifdef HAVE_SIGNAL_H +#if defined(HAVE_SIGNAL_H) && !SDL_PLATFORM_SWITCH // Mask asynchronous signals for this thread sigemptyset(&mask); for (i = 0; sig_list[i]; ++i) { @@ -188,6 +192,20 @@ bool SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) #ifdef SDL_PLATFORM_RISCOS // FIXME: Setting thread priority does not seem to be supported return true; +#elif SDL_PLATFORM_SWITCH + Result res; + if (priority == SDL_THREAD_PRIORITY_HIGH) { + res = svcSetThreadPriority(CUR_THREAD_HANDLE, 0x2B); + } else { + // 0x3B = preemptive threading + res = svcSetThreadPriority(CUR_THREAD_HANDLE, 0x3B); + } + + if (R_FAILED(res)) { + return SDL_SetError("SDL_SYS_SetThreadPriority: svcSetThreadPriority failed (%x)", res); + } + + return 0; #else struct sched_param sched; int policy; diff --git a/src/timer/switch/SDL_systimer.c b/src/timer/switch/SDL_systimer.c new file mode 100644 index 0000000000000..016bd5156e8d5 --- /dev/null +++ b/src/timer/switch/SDL_systimer.c @@ -0,0 +1,42 @@ +/* + 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" + +#ifdef SDL_TIMER_SWITCH + +#include + +Uint64 SDL_GetPerformanceCounter(void) +{ + return armGetSystemTick(); +} + +Uint64 SDL_GetPerformanceFrequency(void) +{ + return armGetSystemTickFreq(); +} + +void SDL_SYS_DelayNS(Uint64 ns) +{ + svcSleepThread(ns); +} + +#endif /* SDL_TIMER_SWITCH */ From e1bac06314142273f1d12e944c1dcf2f13fb87be Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 01:06:37 +0900 Subject: [PATCH 02/16] video: seed switch implementation --- src/video/switch/SDL_switchkeyboard.c | 69 +++++ src/video/switch/SDL_switchkeyboard.h | 34 +++ src/video/switch/SDL_switchmouse.c | 115 ++++++++ src/video/switch/SDL_switchmouse_c.h | 34 +++ src/video/switch/SDL_switchopengles.c | 53 ++++ src/video/switch/SDL_switchopengles.h | 49 ++++ src/video/switch/SDL_switchswkb.c | 111 ++++++++ src/video/switch/SDL_switchswkb.h | 20 ++ src/video/switch/SDL_switchtouch.c | 122 ++++++++ src/video/switch/SDL_switchtouch.h | 34 +++ src/video/switch/SDL_switchvideo.c | 390 ++++++++++++++++++++++++++ src/video/switch/SDL_switchvideo.h | 62 ++++ 12 files changed, 1093 insertions(+) create mode 100644 src/video/switch/SDL_switchkeyboard.c create mode 100644 src/video/switch/SDL_switchkeyboard.h create mode 100644 src/video/switch/SDL_switchmouse.c create mode 100644 src/video/switch/SDL_switchmouse_c.h create mode 100644 src/video/switch/SDL_switchopengles.c create mode 100644 src/video/switch/SDL_switchopengles.h create mode 100644 src/video/switch/SDL_switchswkb.c create mode 100644 src/video/switch/SDL_switchswkb.h create mode 100644 src/video/switch/SDL_switchtouch.c create mode 100644 src/video/switch/SDL_switchtouch.h create mode 100644 src/video/switch/SDL_switchvideo.c create mode 100644 src/video/switch/SDL_switchvideo.h diff --git a/src/video/switch/SDL_switchkeyboard.c b/src/video/switch/SDL_switchkeyboard.c new file mode 100644 index 0000000000000..5037f6ff42637 --- /dev/null +++ b/src/video/switch/SDL_switchkeyboard.c @@ -0,0 +1,69 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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" + +#if SDL_VIDEO_DRIVER_SWITCH + +#include + +#include "SDL_events.h" +#include "SDL_log.h" +#include "SDL_switchvideo.h" +#include "SDL_switchkeyboard.h" +#include "../../events/SDL_keyboard_c.h" + +static bool keys[SDL_NUM_SCANCODES] = {0}; + +void +SWITCH_InitKeyboard(void) { + hidInitializeKeyboard(); +} + +void +SWITCH_PollKeyboard(void) { + HidKeyboardState state; + SDL_Scancode scancode; + + if (SDL_GetFocusWindow() == NULL) { + return; + } + + if (hidGetKeyboardStates(&state, 1)) { + for (scancode = SDL_SCANCODE_UNKNOWN; scancode < (SDL_Scancode) HidKeyboardKey_RightGui; scancode++) { + bool pressed = hidKeyboardStateGetKey(&state, (int) scancode); + if (pressed && !keys[scancode]) { + SDL_SendKeyboardKey(pressed, scancode); + keys[scancode] = true; + } else if (!pressed && keys[scancode]) { + SDL_SendKeyboardKey(pressed, scancode); + keys[scancode] = false; + } + } + } +} + +void +SWITCH_QuitKeyboard(void) { +} + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchkeyboard.h b/src/video/switch/SDL_switchkeyboard.h new file mode 100644 index 0000000000000..a8355db78b8ef --- /dev/null +++ b/src/video/switch/SDL_switchkeyboard.h @@ -0,0 +1,34 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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. +*/ + +#ifndef _SDL_switchkeyboard_h +#define _SDL_switchkeyboard_h + +#include "../../SDL_internal.h" + +/* Keyboard functions */ +extern void SWITCH_InitKeyboard(void); +extern void SWITCH_PollKeyboard(void); +extern void SWITCH_QuitKeyboard(void); + +#endif /* _SDL_switchkeyboard_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchmouse.c b/src/video/switch/SDL_switchmouse.c new file mode 100644 index 0000000000000..d6d50b87e7719 --- /dev/null +++ b/src/video/switch/SDL_switchmouse.c @@ -0,0 +1,115 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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" + +#if SDL_VIDEO_DRIVER_SWITCH + +#include + +#include "SDL_timer.h" +#include "SDL_events.h" +#include "SDL_log.h" +#include "SDL_mouse.h" +#include "SDL_switchvideo.h" +#include "SDL_switchmouse_c.h" +#include "../../events/SDL_mouse_c.h" + +static uint64_t prev_buttons = 0; +static uint64_t last_timestamp = 0; +const uint64_t mouse_read_interval = 15; // in ms + +static int +SWITCH_SetRelativeMouseMode(SDL_bool enabled) +{ + return 0; +} + +void +SWITCH_InitMouse(void) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + mouse->SetRelativeMouseMode = SWITCH_SetRelativeMouseMode; + hidInitializeMouse(); +} + +void +SWITCH_PollMouse(void) +{ + SDL_Window *window = SDL_GetFocusWindow(); + HidMouseState mouse_state; + size_t state_count; + uint64_t changed_buttons; + uint64_t timestamp; + int dx, dy; + + // We skip polling mouse if no window is created + if (window == NULL) + return; + + state_count = hidGetMouseStates(&mouse_state, 1); + changed_buttons = mouse_state.buttons ^ prev_buttons; + + if (changed_buttons & HidMouseButton_Left) { + if (prev_buttons & HidMouseButton_Left) + SDL_SendMouseButton(window, 0, SDL_RELEASED, SDL_BUTTON_LEFT); + else + SDL_SendMouseButton(window, 0, SDL_PRESSED, SDL_BUTTON_LEFT); + } + if (changed_buttons & HidMouseButton_Right) { + if (prev_buttons & HidMouseButton_Right) + SDL_SendMouseButton(window, 0, SDL_RELEASED, SDL_BUTTON_RIGHT); + else + SDL_SendMouseButton(window, 0, SDL_PRESSED, SDL_BUTTON_RIGHT); + } + if (changed_buttons & HidMouseButton_Middle) { + if (prev_buttons & HidMouseButton_Middle) + SDL_SendMouseButton(window, 0, SDL_RELEASED, SDL_BUTTON_MIDDLE); + else + SDL_SendMouseButton(window, 0, SDL_PRESSED, SDL_BUTTON_MIDDLE); + } + + prev_buttons = mouse_state.buttons; + + timestamp = SDL_GetTicks(); + + if (SDL_TICKS_PASSED(timestamp, last_timestamp + mouse_read_interval)) { + // if hidMouseRead is called once per frame, a factor two on the velocities + // results in approximately the same mouse motion as reported by mouse_pos.x and mouse_pos.y + // but without the clamping to 1280 x 720 + if(state_count > 0) { + dx = mouse_state.delta_x * 2; + dy = mouse_state.delta_y * 2; + if (dx || dy) { + SDL_SendMouseMotion(window, 0, 1, dx, dy); + } + } + last_timestamp = timestamp; + } +} + +void +SWITCH_QuitMouse(void) +{ +} + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ + +/* vi: set ts=4 sw=4 expandtab: */ \ No newline at end of file diff --git a/src/video/switch/SDL_switchmouse_c.h b/src/video/switch/SDL_switchmouse_c.h new file mode 100644 index 0000000000000..c2bd2cfc06bf8 --- /dev/null +++ b/src/video/switch/SDL_switchmouse_c.h @@ -0,0 +1,34 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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. +*/ + +#ifndef _SDL_switchmouse_h +#define _SDL_switchmouse_h + +#include "../../SDL_internal.h" + +/* mouse functions */ +extern void SWITCH_InitMouse(void); +extern void SWITCH_PollMouse(void); +extern void SWITCH_QuitMouse(void); + +#endif /* _SDL_switchmouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchopengles.c b/src/video/switch/SDL_switchopengles.c new file mode 100644 index 0000000000000..efed92328661d --- /dev/null +++ b/src/video/switch/SDL_switchopengles.c @@ -0,0 +1,53 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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" +#include "SDL_log.h" + +#if SDL_VIDEO_DRIVER_SWITCH + +#include "SDL_video.h" +#include "SDL_switchopengles.h" +#include "SDL_switchvideo.h" + +/* EGL implementation of SDL OpenGL support */ + +void +SWITCH_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor) +{ + *mask = SDL_GL_CONTEXT_PROFILE_ES; + *major = 2; + *minor = 0; +} + +int +SWITCH_GLES_LoadLibrary(_THIS, const char *path) +{ + return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0); +} + +SDL_EGL_CreateContext_impl(SWITCH) +SDL_EGL_MakeCurrent_impl(SWITCH) +SDL_EGL_SwapWindow_impl(SWITCH) + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchopengles.h b/src/video/switch/SDL_switchopengles.h new file mode 100644 index 0000000000000..3beb5eea7c76b --- /dev/null +++ b/src/video/switch/SDL_switchopengles.h @@ -0,0 +1,49 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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_switchteopengles_h_ +#define SDL_switchteopengles_h_ + +#if SDL_VIDEO_DRIVER_SWITCH + +#include "../SDL_sysvideo.h" +#include "../SDL_egl_c.h" + +/* OpenGLES functions */ +#define SWITCH_GLES_GetAttribute SDL_EGL_GetAttribute +#define SWITCH_GLES_GetProcAddress SDL_EGL_GetProcAddress +#define SWITCH_GLES_UnloadLibrary SDL_EGL_UnloadLibrary +#define SWITCH_GLES_SetSwapInterval SDL_EGL_SetSwapInterval +#define SWITCH_GLES_GetSwapInterval SDL_EGL_GetSwapInterval +#define SWITCH_GLES_DeleteContext SDL_EGL_DeleteContext + +extern int SWITCH_GLES_LoadLibrary(_THIS, const char *path); +extern SDL_GLContext SWITCH_GLES_CreateContext(_THIS, SDL_Window *window); +extern int SWITCH_GLES_SwapWindow(_THIS, SDL_Window *window); +extern int SWITCH_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context); +extern void SWITCH_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor); +extern void SWITCH_GLES_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h); + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ +#endif /* SDL_switchteopengles_h_ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchswkb.c b/src/video/switch/SDL_switchswkb.c new file mode 100644 index 0000000000000..1a7a4b546c0ac --- /dev/null +++ b/src/video/switch/SDL_switchswkb.c @@ -0,0 +1,111 @@ +// +// Created by cpasjuste on 22/04/2020. +// + +#include "../../SDL_internal.h" + +#if SDL_VIDEO_DRIVER_SWITCH + +#include +#include "SDL_switchswkb.h" + +static SwkbdInline kbd; +static SwkbdAppearArg kbdAppearArg; +static bool kbdInited = SDL_FALSE; +static bool kbdShown = SDL_FALSE; + +void +SWITCH_InitSwkb() +{ +} + +void +SWITCH_PollSwkb(void) +{ + if(kbdInited) { + if(kbdShown) { + swkbdInlineUpdate(&kbd, NULL); + } else if(SDL_IsTextInputActive()) { + SDL_StopTextInput(); + } + } +} + +void +SWITCH_QuitSwkb() +{ + if(kbdInited) { + swkbdInlineClose(&kbd); + kbdInited = false; + } +} + +SDL_bool +SWITCH_HasScreenKeyboardSupport(_THIS) +{ + return SDL_TRUE; +} + +SDL_bool +SWITCH_IsScreenKeyboardShown(_THIS, SDL_Window *window) +{ + return kbdShown; +} + +static void +SWITCH_EnterCb(const char *str, SwkbdDecidedEnterArg* arg) +{ + if(arg->stringLen > 0) { + SDL_SendKeyboardText(str); + } + + kbdShown = false; +} + +static void +SWITCH_CancelCb(void) +{ + SDL_StopTextInput(); +} + +void +SWITCH_StartTextInput(_THIS) +{ + Result rc; + + if(!kbdInited) { + rc = swkbdInlineCreate(&kbd); + if (R_SUCCEEDED(rc)) { + rc = swkbdInlineLaunchForLibraryApplet(&kbd, SwkbdInlineMode_AppletDisplay, 0); + if(R_SUCCEEDED(rc)) { + swkbdInlineSetDecidedEnterCallback(&kbd, SWITCH_EnterCb); + swkbdInlineSetDecidedCancelCallback(&kbd, SWITCH_CancelCb); + swkbdInlineMakeAppearArg(&kbdAppearArg, SwkbdType_Normal); + swkbdInlineAppearArgSetOkButtonText(&kbdAppearArg, "Submit"); + kbdAppearArg.dicFlag = 1; + kbdAppearArg.returnButtonFlag = 1; + kbdInited = true; + } + } + } + + if(kbdInited) { + swkbdInlineSetInputText(&kbd, ""); + swkbdInlineSetCursorPos(&kbd, 0); + swkbdInlineUpdate(&kbd, NULL); + swkbdInlineAppear(&kbd, &kbdAppearArg); + kbdShown = true; + } +} + +void +SWITCH_StopTextInput(_THIS) +{ + if(kbdInited) { + swkbdInlineDisappear(&kbd); + } + + kbdShown = false; +} + +#endif diff --git a/src/video/switch/SDL_switchswkb.h b/src/video/switch/SDL_switchswkb.h new file mode 100644 index 0000000000000..988728c082e4e --- /dev/null +++ b/src/video/switch/SDL_switchswkb.h @@ -0,0 +1,20 @@ +// +// Created by cpasjuste on 22/04/2020. +// + +#ifndef SDL2_SDL_SWITCHSWKB_H +#define SDL2_SDL_SWITCHSWKB_H + +#include "../../events/SDL_events_c.h" + +extern void SWITCH_InitSwkb(); +extern void SWITCH_PollSwkb(); +extern void SWITCH_QuitSwkb(); + +extern SDL_bool SWITCH_HasScreenKeyboardSupport(_THIS); +extern SDL_bool SWITCH_IsScreenKeyboardShown(_THIS, SDL_Window * window); + +extern void SWITCH_StartTextInput(_THIS); +extern void SWITCH_StopTextInput(_THIS); + +#endif //SDL2_SDL_SWITCHSWKB_H diff --git a/src/video/switch/SDL_switchtouch.c b/src/video/switch/SDL_switchtouch.c new file mode 100644 index 0000000000000..d184f6709094d --- /dev/null +++ b/src/video/switch/SDL_switchtouch.c @@ -0,0 +1,122 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 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" + +#if SDL_VIDEO_DRIVER_SWITCH + +#include + +#include "SDL_events.h" +#include "SDL_hints.h" +#include "../../events/SDL_touch_c.h" +#include "../../video/SDL_sysvideo.h" + +static HidTouchScreenState touchState; +static HidTouchScreenState touchStateOld; + +void SWITCH_InitTouch(void) +{ + hidInitializeTouchScreen(); + SDL_AddTouch((SDL_TouchID) 0, SDL_TOUCH_DEVICE_DIRECT, "Switch"); + SDL_SetHintWithPriority(SDL_HINT_TOUCH_MOUSE_EVENTS, "0", SDL_HINT_DEFAULT); + SDL_memset(&touchState, 0, sizeof(HidTouchScreenState)); + SDL_memset(&touchStateOld, 0, sizeof(HidTouchScreenState)); +} + +void SWITCH_QuitTouch(void) +{ +} + +void SWITCH_PollTouch(void) +{ + const float rel_w = 1280.0f, rel_h = 720.0f; + SDL_Window *window = SDL_GetFocusWindow(); + SDL_TouchID id = 1; + SDL_bool found; + s32 i, j; + + if (!window) { + return; + } + + if (SDL_AddTouch(id, SDL_TOUCH_DEVICE_DIRECT, "") < 0) { + SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__); + } + + SDL_memcpy(&touchStateOld, &touchState, sizeof(touchState)); + + if (hidGetTouchScreenStates(&touchState, 1)) { + /* Finger down */ + if (touchStateOld.count < touchState.count) { + for (i = 0; i < touchState.count; i++) { + found = SDL_FALSE; + + for (j = 0; j < touchStateOld.count; j++) { + if (touchStateOld.touches[j].finger_id == touchState.touches[i].finger_id) { + found = SDL_TRUE; + break; + } + } + + if (!found) { + SDL_SendTouch(id, + touchState.touches[i].finger_id, + window, SDL_TRUE, + (float)touchState.touches[i].x / rel_w, + (float)touchState.touches[i].y / rel_h, 1); + } + } + } + + /* Scan for moves or up */ + for (i = 0; i < touchStateOld.count; i++) { + found = SDL_FALSE; + + for (j = 0; j < touchState.count; j++) { + if (touchState.touches[j].finger_id == touchStateOld.touches[i].finger_id) { + found = SDL_TRUE; + /* Finger moved */ + if (touchState.touches[j].x != touchStateOld.touches[i].x || touchState.touches[j].y != touchStateOld.touches[i].y) { + SDL_SendTouchMotion(id, + (SDL_FingerID)touchStateOld.touches[i].finger_id, window, + (float)touchState.touches[j].x / rel_w, + (float)touchState.touches[j].y / rel_h, 1); + } + break; + } + } + + if (!found) { + /* Finger Up */ + SDL_SendTouch(id, + (SDL_FingerID)touchStateOld.touches[i].finger_id, + window, + SDL_FALSE, + (float) touchStateOld.touches[i].x / rel_w, + (float) touchStateOld.touches[i].y / rel_h, 1); + } + } + } +} + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchtouch.h b/src/video/switch/SDL_switchtouch.h new file mode 100644 index 0000000000000..ac5908e398fba --- /dev/null +++ b/src/video/switch/SDL_switchtouch.h @@ -0,0 +1,34 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2017 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. +*/ + +#ifndef _SDL_switchtouch_h +#define _SDL_switchtouch_h + +#include "../../SDL_internal.h" + +/* Touch functions */ +extern void SWITCH_InitTouch(void); +extern void SWITCH_QuitTouch(void); +extern void SWITCH_PollTouch(void); + +#endif /* _SDL_switchtouch_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchvideo.c b/src/video/switch/SDL_switchvideo.c new file mode 100644 index 0000000000000..c55ed11d85d5d --- /dev/null +++ b/src/video/switch/SDL_switchvideo.c @@ -0,0 +1,390 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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" + +#if SDL_VIDEO_DRIVER_SWITCH + +#include "../SDL_sysvideo.h" +#include "../../render/SDL_sysrender.h" +#include "../../events/SDL_keyboard_c.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_windowevents_c.h" + +#include "SDL_switchvideo.h" +#include "SDL_switchopengles.h" +#include "SDL_switchtouch.h" +#include "SDL_switchkeyboard.h" +#include "SDL_switchmouse_c.h" +#include "SDL_switchswkb.h" + +/* Currently only one window */ +static SDL_Window *switch_window = NULL; +static AppletOperationMode operationMode; + +static void +SWITCH_Destroy(SDL_VideoDevice *device) +{ + if (device != NULL) { + if(device->driverdata != NULL) { + SDL_free(device->driverdata); + } + SDL_free(device); + } +} + +static SDL_VideoDevice * +SWITCH_CreateDevice() +{ + SDL_VideoDevice *device; + + /* Initialize SDL_VideoDevice structure */ + device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); + if (device == NULL) { + SDL_OutOfMemory(); + return NULL; + } + + /* Setup amount of available displays */ + device->num_displays = 0; + + /* Set device free function */ + device->free = SWITCH_Destroy; + + /* Setup all functions which we can handle */ + device->VideoInit = SWITCH_VideoInit; + device->VideoQuit = SWITCH_VideoQuit; + device->GetDisplayModes = SWITCH_GetDisplayModes; + device->SetDisplayMode = SWITCH_SetDisplayMode; + device->CreateSDLWindow = SWITCH_CreateWindow; + device->CreateSDLWindowFrom = SWITCH_CreateWindowFrom; + device->SetWindowTitle = SWITCH_SetWindowTitle; + device->SetWindowIcon = SWITCH_SetWindowIcon; + device->SetWindowPosition = SWITCH_SetWindowPosition; + device->SetWindowSize = SWITCH_SetWindowSize; + device->ShowWindow = SWITCH_ShowWindow; + device->HideWindow = SWITCH_HideWindow; + device->RaiseWindow = SWITCH_RaiseWindow; + device->MaximizeWindow = SWITCH_MaximizeWindow; + device->MinimizeWindow = SWITCH_MinimizeWindow; + device->RestoreWindow = SWITCH_RestoreWindow; + //device->SetWindowMouseGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 + //device->SetWindowKeyboardGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 + device->DestroyWindow = SWITCH_DestroyWindow; + + device->GL_LoadLibrary = SWITCH_GLES_LoadLibrary; + device->GL_GetProcAddress = SWITCH_GLES_GetProcAddress; + device->GL_UnloadLibrary = SWITCH_GLES_UnloadLibrary; + device->GL_CreateContext = SWITCH_GLES_CreateContext; + device->GL_MakeCurrent = SWITCH_GLES_MakeCurrent; + device->GL_SetSwapInterval = SWITCH_GLES_SetSwapInterval; + device->GL_GetSwapInterval = SWITCH_GLES_GetSwapInterval; + device->GL_SwapWindow = SWITCH_GLES_SwapWindow; + device->GL_DeleteContext = SWITCH_GLES_DeleteContext; + device->GL_DefaultProfileConfig = SWITCH_GLES_DefaultProfileConfig; + + device->StartTextInput = SWITCH_StartTextInput; + device->StopTextInput = SWITCH_StopTextInput; + device->HasScreenKeyboardSupport = SWITCH_HasScreenKeyboardSupport; + device->IsScreenKeyboardShown = SWITCH_IsScreenKeyboardShown; + + device->PumpEvents = SWITCH_PumpEvents; + + return device; +} + +VideoBootStrap SWITCH_bootstrap = { + "Switch", + "Nintendo Switch Video Driver", + SWITCH_CreateDevice +}; + +/*****************************************************************************/ +/* SDL Video and Display initialization/handling functions */ +/*****************************************************************************/ +int +SWITCH_VideoInit(_THIS) +{ + SDL_VideoDisplay display; + SDL_DisplayMode current_mode; + + SDL_zero(current_mode); + + if(appletGetOperationMode() == AppletOperationMode_Handheld) { + current_mode.w = 1280; + current_mode.h = 720; + } else { + current_mode.w = 1920; + current_mode.h = 1080; + } + + current_mode.refresh_rate = 60; + current_mode.format = SDL_PIXELFORMAT_RGBA8888; + current_mode.driverdata = NULL; + + SDL_zero(display); + display.desktop_mode = current_mode; + display.current_mode = current_mode; + display.driverdata = NULL; + SDL_AddVideoDisplay(&display, SDL_FALSE); + + // init psm service + psmInitialize(); + // init touch + SWITCH_InitTouch(); + // init keyboard + SWITCH_InitKeyboard(); + // init mouse + SWITCH_InitMouse(); + // init software keyboard + SWITCH_InitSwkb(); + + return 0; +} + +void +SWITCH_VideoQuit(_THIS) +{ + // this should not be needed if user code is right (SDL_GL_LoadLibrary/SDL_GL_UnloadLibrary calls match) + // this (user) error doesn't have the same effect on switch thought, as the driver needs to be unloaded (crash) + if(_this->gl_config.driver_loaded > 0) { + SWITCH_GLES_UnloadLibrary(_this); + _this->gl_config.driver_loaded = 0; + } + + // exit touch + SWITCH_QuitTouch(); + // exit keyboard + SWITCH_QuitKeyboard(); + // exit mouse + SWITCH_QuitMouse(); + // exit software keyboard + SWITCH_QuitSwkb(); + // exit psm service + psmExit(); +} + +void +SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display) +{ + SDL_DisplayMode mode; + + SDL_zero(mode); + mode.refresh_rate = 60; + mode.format = SDL_PIXELFORMAT_RGBA8888; + + // 1280x720 RGBA8888 + mode.w = 1280; + mode.h = 720; + SDL_AddDisplayMode(display, &mode); + + // 1920x1080 RGBA8888 + mode.w = 1920; + mode.h = 1080; + SDL_AddDisplayMode(display, &mode); +} + +int +SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) +{ + SDL_WindowData *data = (SDL_WindowData *) SDL_GetFocusWindow()->driverdata; + SDL_GLContext ctx = SDL_GL_GetCurrentContext(); + NWindow *nWindow = nwindowGetDefault(); + + if (data != NULL && data->egl_surface != EGL_NO_SURFACE) { + SDL_EGL_MakeCurrent(_this, NULL, NULL); + SDL_EGL_DestroySurface(_this, data->egl_surface); + nwindowSetDimensions(nWindow, mode->w, mode->h); + data->egl_surface = SDL_EGL_CreateSurface(_this, nWindow); + SDL_EGL_MakeCurrent(_this, data->egl_surface, ctx); + } + + return 0; +} + +int +SWITCH_CreateWindow(_THIS, SDL_Window *window) +{ + Result rc; + SDL_WindowData *window_data = NULL; + NWindow *nWindow = NULL; + + if (switch_window != NULL) { + return SDL_SetError("Switch only supports one window"); + } + + if (!_this->egl_data) { + return SDL_SetError("EGL not initialized"); + } + + window_data = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); + if (window_data == NULL) { + return SDL_OutOfMemory(); + } + + nWindow = nwindowGetDefault(); + + rc = nwindowSetDimensions(nWindow, window->w, window->h); + if (R_FAILED(rc)) { + return SDL_SetError("Could not set NWindow dimensions: 0x%x", rc); + } + + window_data->egl_surface = SDL_EGL_CreateSurface(_this, nWindow); + if (window_data->egl_surface == EGL_NO_SURFACE) { + return SDL_SetError("Could not create GLES window surface"); + } + + /* Setup driver data for this window */ + window->driverdata = window_data; + switch_window = window; + + /* starting operation mode */ + operationMode = appletGetOperationMode(); + + /* One window, it always has focus */ + SDL_SetMouseFocus(window); + SDL_SetKeyboardFocus(window); + + /* Window has been successfully created */ + return 0; +} + +void +SWITCH_DestroyWindow(_THIS, SDL_Window *window) +{ + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + + if (window == switch_window) { + if (data != NULL) { + if (data->egl_surface != EGL_NO_SURFACE) { + SDL_EGL_MakeCurrent(_this, NULL, NULL); + SDL_EGL_DestroySurface(_this, data->egl_surface); + } + if(window->driverdata != NULL) { + SDL_free(window->driverdata); + window->driverdata = NULL; + } + } + switch_window = NULL; + } +} + +int +SWITCH_CreateWindowFrom(_THIS, SDL_Window *window, const void *data) +{ + return -1; +} +void +SWITCH_SetWindowTitle(_THIS, SDL_Window *window) +{ +} +void +SWITCH_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon) +{ +} +void +SWITCH_SetWindowPosition(_THIS, SDL_Window *window) +{ +} +void +SWITCH_SetWindowSize(_THIS, SDL_Window *window) +{ + u32 w = 0, h = 0; + SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SDL_GLContext ctx = SDL_GL_GetCurrentContext(); + NWindow *nWindow = nwindowGetDefault(); + + if(window->w != w || window->h != h) { + if (data != NULL && data->egl_surface != EGL_NO_SURFACE) { + SDL_EGL_MakeCurrent(_this, NULL, NULL); + SDL_EGL_DestroySurface(_this, data->egl_surface); + nwindowSetDimensions(nWindow, window->w, window->h); + data->egl_surface = SDL_EGL_CreateSurface(_this, nWindow); + SDL_EGL_MakeCurrent(_this, data->egl_surface, ctx); + } + } +} +void +SWITCH_ShowWindow(_THIS, SDL_Window *window) +{ +} +void +SWITCH_HideWindow(_THIS, SDL_Window *window) +{ +} +void +SWITCH_RaiseWindow(_THIS, SDL_Window *window) +{ +} +void +SWITCH_MaximizeWindow(_THIS, SDL_Window *window) +{ +} +void +SWITCH_MinimizeWindow(_THIS, SDL_Window *window) +{ +} +void +SWITCH_RestoreWindow(_THIS, SDL_Window *window) +{ +} +void +SWITCH_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed) +{ +} + +void +SWITCH_PumpEvents(_THIS) +{ + AppletOperationMode om; + + if (!appletMainLoop()) { + SDL_Event ev; + ev.type = SDL_QUIT; + SDL_PushEvent(&ev); + return; + } + + // we don't want other inputs overlapping with software keyboard + if(!SDL_IsTextInputActive()) { + SWITCH_PollTouch(); + SWITCH_PollKeyboard(); + SWITCH_PollMouse(); + } + SWITCH_PollSwkb(); + + // handle docked / un-docked modes + // note that SDL_WINDOW_RESIZABLE is only possible in windowed mode, + // so we don't care about current fullscreen/windowed status + if(switch_window != NULL && switch_window->flags & SDL_WINDOW_RESIZABLE) { + om = appletGetOperationMode(); + if(om != operationMode) { + operationMode = om; + if(operationMode == AppletOperationMode_Handheld) { + SDL_SetWindowSize(switch_window, 1280, 720); + } else { + SDL_SetWindowSize(switch_window, 1920, 1080); + } + } + } +} + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ \ No newline at end of file diff --git a/src/video/switch/SDL_switchvideo.h b/src/video/switch/SDL_switchvideo.h new file mode 100644 index 0000000000000..d34643ed4571e --- /dev/null +++ b/src/video/switch/SDL_switchvideo.h @@ -0,0 +1,62 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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. +*/ + +#ifndef __SDL_SWITCHVIDEO_H__ +#define __SDL_SWITCHVIDEO_H__ + +#if SDL_VIDEO_DRIVER_SWITCH + +#include + +#include "../../SDL_internal.h" +#include "../SDL_sysvideo.h" + +#include "SDL_egl.h" + +typedef struct SDL_WindowData +{ + EGLSurface egl_surface; +} SDL_WindowData; + +int SWITCH_VideoInit(_THIS); +void SWITCH_VideoQuit(_THIS); +void SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display); +int SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode); +int SWITCH_CreateWindow(_THIS, SDL_Window *window); +int SWITCH_CreateWindowFrom(_THIS, SDL_Window *window, const void *data); +void SWITCH_SetWindowTitle(_THIS, SDL_Window *window); +void SWITCH_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon); +void SWITCH_SetWindowPosition(_THIS, SDL_Window *window); +void SWITCH_SetWindowSize(_THIS, SDL_Window *window); +void SWITCH_ShowWindow(_THIS, SDL_Window *window); +void SWITCH_HideWindow(_THIS, SDL_Window *window); +void SWITCH_RaiseWindow(_THIS, SDL_Window *window); +void SWITCH_MaximizeWindow(_THIS, SDL_Window *window); +void SWITCH_MinimizeWindow(_THIS, SDL_Window *window); +void SWITCH_RestoreWindow(_THIS, SDL_Window *window); +void SWITCH_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed); +void SWITCH_DestroyWindow(_THIS, SDL_Window *window); +void SWITCH_PumpEvents(_THIS); + +#endif /* SDL_VIDEO_DRIVER_SWITCH */ +#endif /* __SDL_SWITCHVIDEO_H__ */ + +/* vi: set ts=4 sw=4 expandtab: */ From ab45d57847083b7108c869a8c682db9040dc3fcd Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 01:08:05 +0900 Subject: [PATCH 03/16] video/switch: cosmetics --- src/video/switch/SDL_switchkeyboard.c | 22 +++--- src/video/switch/SDL_switchmouse.c | 22 +++--- src/video/switch/SDL_switchopengles.c | 14 ++-- src/video/switch/SDL_switchopengles.h | 10 +-- src/video/switch/SDL_switchswkb.c | 47 +++++------- src/video/switch/SDL_switchtouch.c | 10 +-- src/video/switch/SDL_switchvideo.c | 101 +++++++++++--------------- 7 files changed, 96 insertions(+), 130 deletions(-) diff --git a/src/video/switch/SDL_switchkeyboard.c b/src/video/switch/SDL_switchkeyboard.c index 5037f6ff42637..a8be4ea8c0042 100644 --- a/src/video/switch/SDL_switchkeyboard.c +++ b/src/video/switch/SDL_switchkeyboard.c @@ -24,21 +24,21 @@ #include +#include "../../events/SDL_keyboard_c.h" #include "SDL_events.h" #include "SDL_log.h" -#include "SDL_switchvideo.h" #include "SDL_switchkeyboard.h" -#include "../../events/SDL_keyboard_c.h" +#include "SDL_switchvideo.h" -static bool keys[SDL_NUM_SCANCODES] = {0}; +static bool keys[SDL_NUM_SCANCODES] = { 0 }; -void -SWITCH_InitKeyboard(void) { +void SWITCH_InitKeyboard(void) +{ hidInitializeKeyboard(); } -void -SWITCH_PollKeyboard(void) { +void SWITCH_PollKeyboard(void) +{ HidKeyboardState state; SDL_Scancode scancode; @@ -47,8 +47,8 @@ SWITCH_PollKeyboard(void) { } if (hidGetKeyboardStates(&state, 1)) { - for (scancode = SDL_SCANCODE_UNKNOWN; scancode < (SDL_Scancode) HidKeyboardKey_RightGui; scancode++) { - bool pressed = hidKeyboardStateGetKey(&state, (int) scancode); + for (scancode = SDL_SCANCODE_UNKNOWN; scancode < (SDL_Scancode)HidKeyboardKey_RightGui; scancode++) { + bool pressed = hidKeyboardStateGetKey(&state, (int)scancode); if (pressed && !keys[scancode]) { SDL_SendKeyboardKey(pressed, scancode); keys[scancode] = true; @@ -60,8 +60,8 @@ SWITCH_PollKeyboard(void) { } } -void -SWITCH_QuitKeyboard(void) { +void SWITCH_QuitKeyboard(void) +{ } #endif /* SDL_VIDEO_DRIVER_SWITCH */ diff --git a/src/video/switch/SDL_switchmouse.c b/src/video/switch/SDL_switchmouse.c index d6d50b87e7719..26dbf75774b56 100644 --- a/src/video/switch/SDL_switchmouse.c +++ b/src/video/switch/SDL_switchmouse.c @@ -24,34 +24,31 @@ #include -#include "SDL_timer.h" +#include "../../events/SDL_mouse_c.h" #include "SDL_events.h" #include "SDL_log.h" #include "SDL_mouse.h" -#include "SDL_switchvideo.h" #include "SDL_switchmouse_c.h" -#include "../../events/SDL_mouse_c.h" +#include "SDL_switchvideo.h" +#include "SDL_timer.h" static uint64_t prev_buttons = 0; static uint64_t last_timestamp = 0; const uint64_t mouse_read_interval = 15; // in ms -static int -SWITCH_SetRelativeMouseMode(SDL_bool enabled) +static int SWITCH_SetRelativeMouseMode(SDL_bool enabled) { return 0; } -void -SWITCH_InitMouse(void) +void SWITCH_InitMouse(void) { SDL_Mouse *mouse = SDL_GetMouse(); mouse->SetRelativeMouseMode = SWITCH_SetRelativeMouseMode; hidInitializeMouse(); } -void -SWITCH_PollMouse(void) +void SWITCH_PollMouse(void) { SDL_Window *window = SDL_GetFocusWindow(); HidMouseState mouse_state; @@ -94,7 +91,7 @@ SWITCH_PollMouse(void) // if hidMouseRead is called once per frame, a factor two on the velocities // results in approximately the same mouse motion as reported by mouse_pos.x and mouse_pos.y // but without the clamping to 1280 x 720 - if(state_count > 0) { + if (state_count > 0) { dx = mouse_state.delta_x * 2; dy = mouse_state.delta_y * 2; if (dx || dy) { @@ -105,11 +102,10 @@ SWITCH_PollMouse(void) } } -void -SWITCH_QuitMouse(void) +void SWITCH_QuitMouse(void) { } #endif /* SDL_VIDEO_DRIVER_SWITCH */ -/* vi: set ts=4 sw=4 expandtab: */ \ No newline at end of file +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchopengles.c b/src/video/switch/SDL_switchopengles.c index efed92328661d..81b1bc8730f13 100644 --- a/src/video/switch/SDL_switchopengles.c +++ b/src/video/switch/SDL_switchopengles.c @@ -24,30 +24,28 @@ #if SDL_VIDEO_DRIVER_SWITCH -#include "SDL_video.h" #include "SDL_switchopengles.h" #include "SDL_switchvideo.h" +#include "SDL_video.h" /* EGL implementation of SDL OpenGL support */ -void -SWITCH_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor) +void SWITCH_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor) { *mask = SDL_GL_CONTEXT_PROFILE_ES; *major = 2; *minor = 0; } -int -SWITCH_GLES_LoadLibrary(_THIS, const char *path) +int SWITCH_GLES_LoadLibrary(_THIS, const char *path) { return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0); } SDL_EGL_CreateContext_impl(SWITCH) -SDL_EGL_MakeCurrent_impl(SWITCH) -SDL_EGL_SwapWindow_impl(SWITCH) + SDL_EGL_MakeCurrent_impl(SWITCH) + SDL_EGL_SwapWindow_impl(SWITCH) #endif /* SDL_VIDEO_DRIVER_SWITCH */ -/* vi: set ts=4 sw=4 expandtab: */ + /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/switch/SDL_switchopengles.h b/src/video/switch/SDL_switchopengles.h index 3beb5eea7c76b..db979a56414a4 100644 --- a/src/video/switch/SDL_switchopengles.h +++ b/src/video/switch/SDL_switchopengles.h @@ -25,16 +25,16 @@ #if SDL_VIDEO_DRIVER_SWITCH -#include "../SDL_sysvideo.h" #include "../SDL_egl_c.h" +#include "../SDL_sysvideo.h" /* OpenGLES functions */ -#define SWITCH_GLES_GetAttribute SDL_EGL_GetAttribute -#define SWITCH_GLES_GetProcAddress SDL_EGL_GetProcAddress -#define SWITCH_GLES_UnloadLibrary SDL_EGL_UnloadLibrary +#define SWITCH_GLES_GetAttribute SDL_EGL_GetAttribute +#define SWITCH_GLES_GetProcAddress SDL_EGL_GetProcAddress +#define SWITCH_GLES_UnloadLibrary SDL_EGL_UnloadLibrary #define SWITCH_GLES_SetSwapInterval SDL_EGL_SetSwapInterval #define SWITCH_GLES_GetSwapInterval SDL_EGL_GetSwapInterval -#define SWITCH_GLES_DeleteContext SDL_EGL_DeleteContext +#define SWITCH_GLES_DeleteContext SDL_EGL_DeleteContext extern int SWITCH_GLES_LoadLibrary(_THIS, const char *path); extern SDL_GLContext SWITCH_GLES_CreateContext(_THIS, SDL_Window *window); diff --git a/src/video/switch/SDL_switchswkb.c b/src/video/switch/SDL_switchswkb.c index 1a7a4b546c0ac..d814368b80702 100644 --- a/src/video/switch/SDL_switchswkb.c +++ b/src/video/switch/SDL_switchswkb.c @@ -6,78 +6,70 @@ #if SDL_VIDEO_DRIVER_SWITCH -#include #include "SDL_switchswkb.h" +#include static SwkbdInline kbd; static SwkbdAppearArg kbdAppearArg; static bool kbdInited = SDL_FALSE; static bool kbdShown = SDL_FALSE; -void -SWITCH_InitSwkb() +void SWITCH_InitSwkb() { } -void -SWITCH_PollSwkb(void) +void SWITCH_PollSwkb(void) { - if(kbdInited) { - if(kbdShown) { + if (kbdInited) { + if (kbdShown) { swkbdInlineUpdate(&kbd, NULL); - } else if(SDL_IsTextInputActive()) { + } else if (SDL_IsTextInputActive()) { SDL_StopTextInput(); } } } -void -SWITCH_QuitSwkb() +void SWITCH_QuitSwkb() { - if(kbdInited) { + if (kbdInited) { swkbdInlineClose(&kbd); kbdInited = false; } } -SDL_bool -SWITCH_HasScreenKeyboardSupport(_THIS) +SDL_bool SWITCH_HasScreenKeyboardSupport(_THIS) { return SDL_TRUE; } -SDL_bool -SWITCH_IsScreenKeyboardShown(_THIS, SDL_Window *window) +SDL_bool SWITCH_IsScreenKeyboardShown(_THIS, SDL_Window *window) { return kbdShown; } -static void -SWITCH_EnterCb(const char *str, SwkbdDecidedEnterArg* arg) +static void SWITCH_EnterCb(const char *str, SwkbdDecidedEnterArg *arg) { - if(arg->stringLen > 0) { + if (arg->stringLen > 0) { SDL_SendKeyboardText(str); } kbdShown = false; } -static void -SWITCH_CancelCb(void) +static void SWITCH_CancelCb(void) { SDL_StopTextInput(); } -void -SWITCH_StartTextInput(_THIS) +void SWITCH_StartTextInput(_THIS) { Result rc; - if(!kbdInited) { + if (!kbdInited) { rc = swkbdInlineCreate(&kbd); if (R_SUCCEEDED(rc)) { rc = swkbdInlineLaunchForLibraryApplet(&kbd, SwkbdInlineMode_AppletDisplay, 0); - if(R_SUCCEEDED(rc)) { + if (R_SUCCEEDED(rc)) { swkbdInlineSetDecidedEnterCallback(&kbd, SWITCH_EnterCb); swkbdInlineSetDecidedCancelCallback(&kbd, SWITCH_CancelCb); swkbdInlineMakeAppearArg(&kbdAppearArg, SwkbdType_Normal); @@ -89,7 +81,7 @@ SWITCH_StartTextInput(_THIS) } } - if(kbdInited) { + if (kbdInited) { swkbdInlineSetInputText(&kbd, ""); swkbdInlineSetCursorPos(&kbd, 0); swkbdInlineUpdate(&kbd, NULL); @@ -98,10 +90,9 @@ SWITCH_StartTextInput(_THIS) } } -void -SWITCH_StopTextInput(_THIS) +void SWITCH_StopTextInput(_THIS) { - if(kbdInited) { + if (kbdInited) { swkbdInlineDisappear(&kbd); } diff --git a/src/video/switch/SDL_switchtouch.c b/src/video/switch/SDL_switchtouch.c index d184f6709094d..53e34679b359d 100644 --- a/src/video/switch/SDL_switchtouch.c +++ b/src/video/switch/SDL_switchtouch.c @@ -24,10 +24,10 @@ #include -#include "SDL_events.h" -#include "SDL_hints.h" #include "../../events/SDL_touch_c.h" #include "../../video/SDL_sysvideo.h" +#include "SDL_events.h" +#include "SDL_hints.h" static HidTouchScreenState touchState; static HidTouchScreenState touchStateOld; @@ -35,7 +35,7 @@ static HidTouchScreenState touchStateOld; void SWITCH_InitTouch(void) { hidInitializeTouchScreen(); - SDL_AddTouch((SDL_TouchID) 0, SDL_TOUCH_DEVICE_DIRECT, "Switch"); + SDL_AddTouch((SDL_TouchID)0, SDL_TOUCH_DEVICE_DIRECT, "Switch"); SDL_SetHintWithPriority(SDL_HINT_TOUCH_MOUSE_EVENTS, "0", SDL_HINT_DEFAULT); SDL_memset(&touchState, 0, sizeof(HidTouchScreenState)); SDL_memset(&touchStateOld, 0, sizeof(HidTouchScreenState)); @@ -110,8 +110,8 @@ void SWITCH_PollTouch(void) (SDL_FingerID)touchStateOld.touches[i].finger_id, window, SDL_FALSE, - (float) touchStateOld.touches[i].x / rel_w, - (float) touchStateOld.touches[i].y / rel_h, 1); + (float)touchStateOld.touches[i].x / rel_w, + (float)touchStateOld.touches[i].y / rel_h, 1); } } } diff --git a/src/video/switch/SDL_switchvideo.c b/src/video/switch/SDL_switchvideo.c index c55ed11d85d5d..1de3d6859ccda 100644 --- a/src/video/switch/SDL_switchvideo.c +++ b/src/video/switch/SDL_switchvideo.c @@ -23,18 +23,18 @@ #if SDL_VIDEO_DRIVER_SWITCH -#include "../SDL_sysvideo.h" -#include "../../render/SDL_sysrender.h" #include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_mouse_c.h" #include "../../events/SDL_windowevents_c.h" +#include "../../render/SDL_sysrender.h" +#include "../SDL_sysvideo.h" -#include "SDL_switchvideo.h" -#include "SDL_switchopengles.h" -#include "SDL_switchtouch.h" #include "SDL_switchkeyboard.h" #include "SDL_switchmouse_c.h" +#include "SDL_switchopengles.h" #include "SDL_switchswkb.h" +#include "SDL_switchtouch.h" +#include "SDL_switchvideo.h" /* Currently only one window */ static SDL_Window *switch_window = NULL; @@ -44,7 +44,7 @@ static void SWITCH_Destroy(SDL_VideoDevice *device) { if (device != NULL) { - if(device->driverdata != NULL) { + if (device->driverdata != NULL) { SDL_free(device->driverdata); } SDL_free(device); @@ -57,7 +57,7 @@ SWITCH_CreateDevice() SDL_VideoDevice *device; /* Initialize SDL_VideoDevice structure */ - device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); + device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); if (device == NULL) { SDL_OutOfMemory(); return NULL; @@ -86,8 +86,8 @@ SWITCH_CreateDevice() device->MaximizeWindow = SWITCH_MaximizeWindow; device->MinimizeWindow = SWITCH_MinimizeWindow; device->RestoreWindow = SWITCH_RestoreWindow; - //device->SetWindowMouseGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 - //device->SetWindowKeyboardGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 + // device->SetWindowMouseGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 + // device->SetWindowKeyboardGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 device->DestroyWindow = SWITCH_DestroyWindow; device->GL_LoadLibrary = SWITCH_GLES_LoadLibrary; @@ -120,15 +120,14 @@ VideoBootStrap SWITCH_bootstrap = { /*****************************************************************************/ /* SDL Video and Display initialization/handling functions */ /*****************************************************************************/ -int -SWITCH_VideoInit(_THIS) +int SWITCH_VideoInit(_THIS) { SDL_VideoDisplay display; SDL_DisplayMode current_mode; SDL_zero(current_mode); - if(appletGetOperationMode() == AppletOperationMode_Handheld) { + if (appletGetOperationMode() == AppletOperationMode_Handheld) { current_mode.w = 1280; current_mode.h = 720; } else { @@ -160,12 +159,11 @@ SWITCH_VideoInit(_THIS) return 0; } -void -SWITCH_VideoQuit(_THIS) +void SWITCH_VideoQuit(_THIS) { // this should not be needed if user code is right (SDL_GL_LoadLibrary/SDL_GL_UnloadLibrary calls match) // this (user) error doesn't have the same effect on switch thought, as the driver needs to be unloaded (crash) - if(_this->gl_config.driver_loaded > 0) { + if (_this->gl_config.driver_loaded > 0) { SWITCH_GLES_UnloadLibrary(_this); _this->gl_config.driver_loaded = 0; } @@ -182,8 +180,7 @@ SWITCH_VideoQuit(_THIS) psmExit(); } -void -SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display) +void SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display) { SDL_DisplayMode mode; @@ -202,10 +199,9 @@ SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display) SDL_AddDisplayMode(display, &mode); } -int -SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) +int SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) { - SDL_WindowData *data = (SDL_WindowData *) SDL_GetFocusWindow()->driverdata; + SDL_WindowData *data = (SDL_WindowData *)SDL_GetFocusWindow()->driverdata; SDL_GLContext ctx = SDL_GL_GetCurrentContext(); NWindow *nWindow = nwindowGetDefault(); @@ -220,8 +216,7 @@ SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) return 0; } -int -SWITCH_CreateWindow(_THIS, SDL_Window *window) +int SWITCH_CreateWindow(_THIS, SDL_Window *window) { Result rc; SDL_WindowData *window_data = NULL; @@ -235,7 +230,7 @@ SWITCH_CreateWindow(_THIS, SDL_Window *window) return SDL_SetError("EGL not initialized"); } - window_data = (SDL_WindowData *) SDL_calloc(1, sizeof(SDL_WindowData)); + window_data = (SDL_WindowData *)SDL_calloc(1, sizeof(SDL_WindowData)); if (window_data == NULL) { return SDL_OutOfMemory(); } @@ -267,10 +262,9 @@ SWITCH_CreateWindow(_THIS, SDL_Window *window) return 0; } -void -SWITCH_DestroyWindow(_THIS, SDL_Window *window) +void SWITCH_DestroyWindow(_THIS, SDL_Window *window) { - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SDL_WindowData *data = (SDL_WindowData *)window->driverdata; if (window == switch_window) { if (data != NULL) { @@ -278,7 +272,7 @@ SWITCH_DestroyWindow(_THIS, SDL_Window *window) SDL_EGL_MakeCurrent(_this, NULL, NULL); SDL_EGL_DestroySurface(_this, data->egl_surface); } - if(window->driverdata != NULL) { + if (window->driverdata != NULL) { SDL_free(window->driverdata); window->driverdata = NULL; } @@ -287,32 +281,27 @@ SWITCH_DestroyWindow(_THIS, SDL_Window *window) } } -int -SWITCH_CreateWindowFrom(_THIS, SDL_Window *window, const void *data) +int SWITCH_CreateWindowFrom(_THIS, SDL_Window *window, const void *data) { return -1; } -void -SWITCH_SetWindowTitle(_THIS, SDL_Window *window) +void SWITCH_SetWindowTitle(_THIS, SDL_Window *window) { } -void -SWITCH_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon) +void SWITCH_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon) { } -void -SWITCH_SetWindowPosition(_THIS, SDL_Window *window) +void SWITCH_SetWindowPosition(_THIS, SDL_Window *window) { } -void -SWITCH_SetWindowSize(_THIS, SDL_Window *window) +void SWITCH_SetWindowSize(_THIS, SDL_Window *window) { u32 w = 0, h = 0; - SDL_WindowData *data = (SDL_WindowData *) window->driverdata; + SDL_WindowData *data = (SDL_WindowData *)window->driverdata; SDL_GLContext ctx = SDL_GL_GetCurrentContext(); NWindow *nWindow = nwindowGetDefault(); - if(window->w != w || window->h != h) { + if (window->w != w || window->h != h) { if (data != NULL && data->egl_surface != EGL_NO_SURFACE) { SDL_EGL_MakeCurrent(_this, NULL, NULL); SDL_EGL_DestroySurface(_this, data->egl_surface); @@ -322,37 +311,29 @@ SWITCH_SetWindowSize(_THIS, SDL_Window *window) } } } -void -SWITCH_ShowWindow(_THIS, SDL_Window *window) +void SWITCH_ShowWindow(_THIS, SDL_Window *window) { } -void -SWITCH_HideWindow(_THIS, SDL_Window *window) +void SWITCH_HideWindow(_THIS, SDL_Window *window) { } -void -SWITCH_RaiseWindow(_THIS, SDL_Window *window) +void SWITCH_RaiseWindow(_THIS, SDL_Window *window) { } -void -SWITCH_MaximizeWindow(_THIS, SDL_Window *window) +void SWITCH_MaximizeWindow(_THIS, SDL_Window *window) { } -void -SWITCH_MinimizeWindow(_THIS, SDL_Window *window) +void SWITCH_MinimizeWindow(_THIS, SDL_Window *window) { } -void -SWITCH_RestoreWindow(_THIS, SDL_Window *window) +void SWITCH_RestoreWindow(_THIS, SDL_Window *window) { } -void -SWITCH_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed) +void SWITCH_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed) { } -void -SWITCH_PumpEvents(_THIS) +void SWITCH_PumpEvents(_THIS) { AppletOperationMode om; @@ -364,7 +345,7 @@ SWITCH_PumpEvents(_THIS) } // we don't want other inputs overlapping with software keyboard - if(!SDL_IsTextInputActive()) { + if (!SDL_IsTextInputActive()) { SWITCH_PollTouch(); SWITCH_PollKeyboard(); SWITCH_PollMouse(); @@ -374,11 +355,11 @@ SWITCH_PumpEvents(_THIS) // handle docked / un-docked modes // note that SDL_WINDOW_RESIZABLE is only possible in windowed mode, // so we don't care about current fullscreen/windowed status - if(switch_window != NULL && switch_window->flags & SDL_WINDOW_RESIZABLE) { + if (switch_window != NULL && switch_window->flags & SDL_WINDOW_RESIZABLE) { om = appletGetOperationMode(); - if(om != operationMode) { + if (om != operationMode) { operationMode = om; - if(operationMode == AppletOperationMode_Handheld) { + if (operationMode == AppletOperationMode_Handheld) { SDL_SetWindowSize(switch_window, 1280, 720); } else { SDL_SetWindowSize(switch_window, 1920, 1080); @@ -387,4 +368,4 @@ SWITCH_PumpEvents(_THIS) } } -#endif /* SDL_VIDEO_DRIVER_SWITCH */ \ No newline at end of file +#endif /* SDL_VIDEO_DRIVER_SWITCH */ From 9986e2a79d5e489a5198e7c434ae106cb16c5da4 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sat, 17 May 2025 21:35:46 +0900 Subject: [PATCH 04/16] switch/video: port implementation --- CMakeLists.txt | 16 ++ include/build_config/SDL_build_config.h.cmake | 1 + src/video/SDL_sysvideo.h | 1 + src/video/SDL_video.c | 3 + src/video/switch/SDL_switchkeyboard.c | 16 +- src/video/switch/SDL_switchkeyboard.h | 4 +- src/video/switch/SDL_switchmouse.c | 55 +++--- src/video/switch/SDL_switchmouse_c.h | 4 +- src/video/switch/SDL_switchopengles.c | 17 +- src/video/switch/SDL_switchopengles.h | 18 +- src/video/switch/SDL_switchswkb.c | 37 ++-- src/video/switch/SDL_switchswkb.h | 16 +- src/video/switch/SDL_switchtouch.c | 45 +++-- src/video/switch/SDL_switchtouch.h | 4 +- src/video/switch/SDL_switchvideo.c | 162 ++++++++++-------- src/video/switch/SDL_switchvideo.h | 32 +--- 16 files changed, 226 insertions(+), 205 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 54c9fa929b45f..3b62c70dc1608 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2927,6 +2927,22 @@ elseif(N3DS) elseif(NINTENDO_SWITCH) sdl_link_dependency(nx LIBS nx) + if(SDL_VIDEO) + set(SDL_VIDEO_DRIVER_SWITCH 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/switch/*.c") + set(HAVE_SDL_VIDEO TRUE) + + CheckEGL() + if(HAVE_OPENGL_EGL) + sdl_link_dependency(opengl LIBS EGL glapi drm_nouveau) + endif() + + CheckOpenGLES() + CheckOpenGL() + + sdl_compile_options(PRIVATE -DSDL_VIDEO_STATIC_ANGLE) + endif() + CheckPTHREAD() if(SDL_CLOCK_GETTIME) diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index e712b506ece1b..5c9f1987239f5 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -403,6 +403,7 @@ #cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE 1 #cmakedefine SDL_VIDEO_DRIVER_X11_XSYNC 1 #cmakedefine SDL_VIDEO_DRIVER_QNX 1 +#cmakedefine SDL_VIDEO_DRIVER_SWITCH 1 #cmakedefine SDL_VIDEO_RENDER_D3D 1 #cmakedefine SDL_VIDEO_RENDER_D3D11 1 diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 6da8bd2e1853e..32064c260fa3e 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -522,6 +522,7 @@ extern VideoBootStrap PSP_bootstrap; extern VideoBootStrap VITA_bootstrap; extern VideoBootStrap RISCOS_bootstrap; extern VideoBootStrap N3DS_bootstrap; +extern VideoBootStrap SWITCH_bootstrap; extern VideoBootStrap RPI_bootstrap; extern VideoBootStrap KMSDRM_bootstrap; extern VideoBootStrap DUMMY_bootstrap; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index abeb2cb6b5e2f..dd8959f6cc4e1 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -119,6 +119,9 @@ static VideoBootStrap *bootstrap[] = { #ifdef SDL_VIDEO_DRIVER_N3DS &N3DS_bootstrap, #endif +#ifdef SDL_VIDEO_DRIVER_SWITCH + &SWITCH_bootstrap, +#endif #ifdef SDL_VIDEO_DRIVER_KMSDRM &KMSDRM_bootstrap, #endif diff --git a/src/video/switch/SDL_switchkeyboard.c b/src/video/switch/SDL_switchkeyboard.c index a8be4ea8c0042..d4ebc61a70767 100644 --- a/src/video/switch/SDL_switchkeyboard.c +++ b/src/video/switch/SDL_switchkeyboard.c @@ -18,31 +18,29 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" - #if SDL_VIDEO_DRIVER_SWITCH #include #include "../../events/SDL_keyboard_c.h" -#include "SDL_events.h" -#include "SDL_log.h" #include "SDL_switchkeyboard.h" #include "SDL_switchvideo.h" -static bool keys[SDL_NUM_SCANCODES] = { 0 }; +static bool keys[SDL_SCANCODE_COUNT] = { 0 }; +static SDL_KeyboardID keyboard_id = 1; void SWITCH_InitKeyboard(void) { hidInitializeKeyboard(); + SDL_AddKeyboard(keyboard_id, NULL, false); } -void SWITCH_PollKeyboard(void) +void SWITCH_PollKeyboard(Uint64 timestamp) { HidKeyboardState state; SDL_Scancode scancode; - if (SDL_GetFocusWindow() == NULL) { + if (SDL_GetKeyboardFocus() == NULL) { return; } @@ -50,18 +48,18 @@ void SWITCH_PollKeyboard(void) for (scancode = SDL_SCANCODE_UNKNOWN; scancode < (SDL_Scancode)HidKeyboardKey_RightGui; scancode++) { bool pressed = hidKeyboardStateGetKey(&state, (int)scancode); if (pressed && !keys[scancode]) { - SDL_SendKeyboardKey(pressed, scancode); keys[scancode] = true; } else if (!pressed && keys[scancode]) { - SDL_SendKeyboardKey(pressed, scancode); keys[scancode] = false; } + SDL_SendKeyboardKey(timestamp, keyboard_id, pressed, scancode, keys[scancode]); } } } void SWITCH_QuitKeyboard(void) { + SDL_RemoveKeyboard(keyboard_id, false); } #endif /* SDL_VIDEO_DRIVER_SWITCH */ diff --git a/src/video/switch/SDL_switchkeyboard.h b/src/video/switch/SDL_switchkeyboard.h index a8355db78b8ef..ed8d0dd7a42bc 100644 --- a/src/video/switch/SDL_switchkeyboard.h +++ b/src/video/switch/SDL_switchkeyboard.h @@ -22,11 +22,11 @@ #ifndef _SDL_switchkeyboard_h #define _SDL_switchkeyboard_h -#include "../../SDL_internal.h" +#include "SDL_internal.h" /* Keyboard functions */ extern void SWITCH_InitKeyboard(void); -extern void SWITCH_PollKeyboard(void); +extern void SWITCH_PollKeyboard(Uint64 timestamp); extern void SWITCH_QuitKeyboard(void); #endif /* _SDL_switchkeyboard_h */ diff --git a/src/video/switch/SDL_switchmouse.c b/src/video/switch/SDL_switchmouse.c index 26dbf75774b56..1b5efc8eb12ae 100644 --- a/src/video/switch/SDL_switchmouse.c +++ b/src/video/switch/SDL_switchmouse.c @@ -18,27 +18,22 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" #if SDL_VIDEO_DRIVER_SWITCH #include #include "../../events/SDL_mouse_c.h" -#include "SDL_events.h" -#include "SDL_log.h" -#include "SDL_mouse.h" #include "SDL_switchmouse_c.h" -#include "SDL_switchvideo.h" -#include "SDL_timer.h" static uint64_t prev_buttons = 0; static uint64_t last_timestamp = 0; const uint64_t mouse_read_interval = 15; // in ms +static SDL_MouseID mouse_id = 1; -static int SWITCH_SetRelativeMouseMode(SDL_bool enabled) +static bool SWITCH_SetRelativeMouseMode(bool enabled) { - return 0; + return true; } void SWITCH_InitMouse(void) @@ -46,48 +41,51 @@ void SWITCH_InitMouse(void) SDL_Mouse *mouse = SDL_GetMouse(); mouse->SetRelativeMouseMode = SWITCH_SetRelativeMouseMode; hidInitializeMouse(); + + SDL_AddMouse(1, NULL, false); } -void SWITCH_PollMouse(void) +void SWITCH_PollMouse(Uint64 timestamp) { - SDL_Window *window = SDL_GetFocusWindow(); + SDL_Window *window = SDL_GetKeyboardFocus(); HidMouseState mouse_state; size_t state_count; uint64_t changed_buttons; - uint64_t timestamp; int dx, dy; // We skip polling mouse if no window is created - if (window == NULL) + if (window == NULL) { return; + } state_count = hidGetMouseStates(&mouse_state, 1); changed_buttons = mouse_state.buttons ^ prev_buttons; if (changed_buttons & HidMouseButton_Left) { - if (prev_buttons & HidMouseButton_Left) - SDL_SendMouseButton(window, 0, SDL_RELEASED, SDL_BUTTON_LEFT); - else - SDL_SendMouseButton(window, 0, SDL_PRESSED, SDL_BUTTON_LEFT); + if (prev_buttons & HidMouseButton_Left) { + SDL_SendMouseButton(timestamp, window, mouse_id, SDL_BUTTON_LEFT, false); + } else { + SDL_SendMouseButton(timestamp, window, mouse_id, SDL_BUTTON_LEFT, true); + } } if (changed_buttons & HidMouseButton_Right) { - if (prev_buttons & HidMouseButton_Right) - SDL_SendMouseButton(window, 0, SDL_RELEASED, SDL_BUTTON_RIGHT); - else - SDL_SendMouseButton(window, 0, SDL_PRESSED, SDL_BUTTON_RIGHT); + if (prev_buttons & HidMouseButton_Right) { + SDL_SendMouseButton(timestamp, window, mouse_id, SDL_BUTTON_RIGHT, false); + } else { + SDL_SendMouseButton(timestamp, window, mouse_id, SDL_BUTTON_RIGHT, true); + } } if (changed_buttons & HidMouseButton_Middle) { - if (prev_buttons & HidMouseButton_Middle) - SDL_SendMouseButton(window, 0, SDL_RELEASED, SDL_BUTTON_MIDDLE); - else - SDL_SendMouseButton(window, 0, SDL_PRESSED, SDL_BUTTON_MIDDLE); + if (prev_buttons & HidMouseButton_Middle) { + SDL_SendMouseButton(timestamp, window, mouse_id, SDL_BUTTON_MIDDLE, false); + } else { + SDL_SendMouseButton(timestamp, window, mouse_id, SDL_BUTTON_MIDDLE, true); + } } prev_buttons = mouse_state.buttons; - timestamp = SDL_GetTicks(); - - if (SDL_TICKS_PASSED(timestamp, last_timestamp + mouse_read_interval)) { + if (timestamp > last_timestamp + mouse_read_interval) { // if hidMouseRead is called once per frame, a factor two on the velocities // results in approximately the same mouse motion as reported by mouse_pos.x and mouse_pos.y // but without the clamping to 1280 x 720 @@ -95,7 +93,7 @@ void SWITCH_PollMouse(void) dx = mouse_state.delta_x * 2; dy = mouse_state.delta_y * 2; if (dx || dy) { - SDL_SendMouseMotion(window, 0, 1, dx, dy); + SDL_SendMouseMotion(timestamp, window, mouse_id, 1, dx, dy); } } last_timestamp = timestamp; @@ -104,6 +102,7 @@ void SWITCH_PollMouse(void) void SWITCH_QuitMouse(void) { + SDL_RemoveMouse(mouse_id, false); } #endif /* SDL_VIDEO_DRIVER_SWITCH */ diff --git a/src/video/switch/SDL_switchmouse_c.h b/src/video/switch/SDL_switchmouse_c.h index c2bd2cfc06bf8..d27b4e69d77f1 100644 --- a/src/video/switch/SDL_switchmouse_c.h +++ b/src/video/switch/SDL_switchmouse_c.h @@ -22,11 +22,11 @@ #ifndef _SDL_switchmouse_h #define _SDL_switchmouse_h -#include "../../SDL_internal.h" +#include "SDL_internal.h" /* mouse functions */ extern void SWITCH_InitMouse(void); -extern void SWITCH_PollMouse(void); +extern void SWITCH_PollMouse(Uint64 timestamp); extern void SWITCH_QuitMouse(void); #endif /* _SDL_switchmouse_h */ diff --git a/src/video/switch/SDL_switchopengles.c b/src/video/switch/SDL_switchopengles.c index 81b1bc8730f13..523d89171d9ec 100644 --- a/src/video/switch/SDL_switchopengles.c +++ b/src/video/switch/SDL_switchopengles.c @@ -18,33 +18,34 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ - -#include "../../SDL_internal.h" -#include "SDL_log.h" +#include "../../SDL_log_c.h" #if SDL_VIDEO_DRIVER_SWITCH #include "SDL_switchopengles.h" #include "SDL_switchvideo.h" -#include "SDL_video.h" /* EGL implementation of SDL OpenGL support */ -void SWITCH_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor) +void SWITCH_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor) { + (void)_this; + *mask = SDL_GL_CONTEXT_PROFILE_ES; *major = 2; *minor = 0; } -int SWITCH_GLES_LoadLibrary(_THIS, const char *path) +bool SWITCH_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path) { return SDL_EGL_LoadLibrary(_this, path, EGL_DEFAULT_DISPLAY, 0); } +// clang-format off SDL_EGL_CreateContext_impl(SWITCH) - SDL_EGL_MakeCurrent_impl(SWITCH) - SDL_EGL_SwapWindow_impl(SWITCH) +SDL_EGL_MakeCurrent_impl(SWITCH) +SDL_EGL_SwapWindow_impl(SWITCH) +// clang-format on #endif /* SDL_VIDEO_DRIVER_SWITCH */ diff --git a/src/video/switch/SDL_switchopengles.h b/src/video/switch/SDL_switchopengles.h index db979a56414a4..005423accd19a 100644 --- a/src/video/switch/SDL_switchopengles.h +++ b/src/video/switch/SDL_switchopengles.h @@ -29,19 +29,17 @@ #include "../SDL_sysvideo.h" /* OpenGLES functions */ -#define SWITCH_GLES_GetAttribute SDL_EGL_GetAttribute -#define SWITCH_GLES_GetProcAddress SDL_EGL_GetProcAddress +#define SWITCH_GLES_GetProcAddress SDL_EGL_GetProcAddressInternal #define SWITCH_GLES_UnloadLibrary SDL_EGL_UnloadLibrary #define SWITCH_GLES_SetSwapInterval SDL_EGL_SetSwapInterval #define SWITCH_GLES_GetSwapInterval SDL_EGL_GetSwapInterval -#define SWITCH_GLES_DeleteContext SDL_EGL_DeleteContext - -extern int SWITCH_GLES_LoadLibrary(_THIS, const char *path); -extern SDL_GLContext SWITCH_GLES_CreateContext(_THIS, SDL_Window *window); -extern int SWITCH_GLES_SwapWindow(_THIS, SDL_Window *window); -extern int SWITCH_GLES_MakeCurrent(_THIS, SDL_Window *window, SDL_GLContext context); -extern void SWITCH_GLES_DefaultProfileConfig(_THIS, int *mask, int *major, int *minor); -extern void SWITCH_GLES_GetDrawableSize(_THIS, SDL_Window *window, int *w, int *h); +#define SWITCH_GLES_DestroyContext SDL_EGL_DestroyContext + +extern bool SWITCH_GLES_LoadLibrary(SDL_VideoDevice *_this, const char *path); +extern SDL_GLContext SWITCH_GLES_CreateContext(SDL_VideoDevice *_this, SDL_Window *window); +extern bool SWITCH_GLES_SwapWindow(SDL_VideoDevice *_this, SDL_Window *window); +extern bool SWITCH_GLES_MakeCurrent(SDL_VideoDevice *_this, SDL_Window *window, SDL_GLContext context); +extern void SWITCH_GLES_DefaultProfileConfig(SDL_VideoDevice *_this, int *mask, int *major, int *minor); #endif /* SDL_VIDEO_DRIVER_SWITCH */ #endif /* SDL_switchteopengles_h_ */ diff --git a/src/video/switch/SDL_switchswkb.c b/src/video/switch/SDL_switchswkb.c index d814368b80702..09bb4161861b8 100644 --- a/src/video/switch/SDL_switchswkb.c +++ b/src/video/switch/SDL_switchswkb.c @@ -2,7 +2,7 @@ // Created by cpasjuste on 22/04/2020. // -#include "../../SDL_internal.h" +#include "SDL_internal.h" #if SDL_VIDEO_DRIVER_SWITCH @@ -11,25 +11,26 @@ static SwkbdInline kbd; static SwkbdAppearArg kbdAppearArg; -static bool kbdInited = SDL_FALSE; -static bool kbdShown = SDL_FALSE; +static bool kbdInited = false; +static bool kbdShown = false; +static SDL_Window *current_window = NULL; -void SWITCH_InitSwkb() +void SWITCH_InitSwkb(void) { } -void SWITCH_PollSwkb(void) +void SWITCH_PollSwkb(Uint64 timestamp) { if (kbdInited) { if (kbdShown) { swkbdInlineUpdate(&kbd, NULL); - } else if (SDL_IsTextInputActive()) { - SDL_StopTextInput(); + } else if (current_window != NULL && SDL_TextInputActive(current_window)) { + SDL_StopTextInput(current_window); } } } -void SWITCH_QuitSwkb() +void SWITCH_QuitSwkb(void) { if (kbdInited) { swkbdInlineClose(&kbd); @@ -37,12 +38,12 @@ void SWITCH_QuitSwkb() } } -SDL_bool SWITCH_HasScreenKeyboardSupport(_THIS) +bool SWITCH_HasScreenKeyboardSupport(SDL_VideoDevice *_this) { - return SDL_TRUE; + return true; } -SDL_bool SWITCH_IsScreenKeyboardShown(_THIS, SDL_Window *window) +bool SWITCH_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window) { return kbdShown; } @@ -58,10 +59,12 @@ static void SWITCH_EnterCb(const char *str, SwkbdDecidedEnterArg *arg) static void SWITCH_CancelCb(void) { - SDL_StopTextInput(); + if (current_window != NULL) { + SDL_StopTextInput(current_window); + } } -void SWITCH_StartTextInput(_THIS) +bool SWITCH_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props) { Result rc; @@ -70,6 +73,7 @@ void SWITCH_StartTextInput(_THIS) if (R_SUCCEEDED(rc)) { rc = swkbdInlineLaunchForLibraryApplet(&kbd, SwkbdInlineMode_AppletDisplay, 0); if (R_SUCCEEDED(rc)) { + current_window = window; swkbdInlineSetDecidedEnterCallback(&kbd, SWITCH_EnterCb); swkbdInlineSetDecidedCancelCallback(&kbd, SWITCH_CancelCb); swkbdInlineMakeAppearArg(&kbdAppearArg, SwkbdType_Normal); @@ -88,15 +92,20 @@ void SWITCH_StartTextInput(_THIS) swkbdInlineAppear(&kbd, &kbdAppearArg); kbdShown = true; } + + return true; } -void SWITCH_StopTextInput(_THIS) +bool SWITCH_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window) { if (kbdInited) { swkbdInlineDisappear(&kbd); } kbdShown = false; + current_window = NULL; + + return true; } #endif diff --git a/src/video/switch/SDL_switchswkb.h b/src/video/switch/SDL_switchswkb.h index 988728c082e4e..0f2e76d1e8682 100644 --- a/src/video/switch/SDL_switchswkb.h +++ b/src/video/switch/SDL_switchswkb.h @@ -7,14 +7,14 @@ #include "../../events/SDL_events_c.h" -extern void SWITCH_InitSwkb(); -extern void SWITCH_PollSwkb(); -extern void SWITCH_QuitSwkb(); +extern void SWITCH_InitSwkb(void); +extern void SWITCH_PollSwkb(Uint64 timestamp); +extern void SWITCH_QuitSwkb(void); -extern SDL_bool SWITCH_HasScreenKeyboardSupport(_THIS); -extern SDL_bool SWITCH_IsScreenKeyboardShown(_THIS, SDL_Window * window); +extern bool SWITCH_HasScreenKeyboardSupport(SDL_VideoDevice *_this); +extern bool SWITCH_IsScreenKeyboardShown(SDL_VideoDevice *_this, SDL_Window *window); -extern void SWITCH_StartTextInput(_THIS); -extern void SWITCH_StopTextInput(_THIS); +extern bool SWITCH_StartTextInput(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID props); +extern bool SWITCH_StopTextInput(SDL_VideoDevice *_this, SDL_Window *window); -#endif //SDL2_SDL_SWITCHSWKB_H +#endif // SDL2_SDL_SWITCHSWKB_H diff --git a/src/video/switch/SDL_switchtouch.c b/src/video/switch/SDL_switchtouch.c index 53e34679b359d..b4c67165af1ac 100644 --- a/src/video/switch/SDL_switchtouch.c +++ b/src/video/switch/SDL_switchtouch.c @@ -18,7 +18,7 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" +#include "SDL_internal.h" #if SDL_VIDEO_DRIVER_SWITCH @@ -26,16 +26,15 @@ #include "../../events/SDL_touch_c.h" #include "../../video/SDL_sysvideo.h" -#include "SDL_events.h" -#include "SDL_hints.h" static HidTouchScreenState touchState; static HidTouchScreenState touchStateOld; +static SDL_TouchID touch_id = 1; void SWITCH_InitTouch(void) { hidInitializeTouchScreen(); - SDL_AddTouch((SDL_TouchID)0, SDL_TOUCH_DEVICE_DIRECT, "Switch"); + SDL_AddTouch(touch_id, SDL_TOUCH_DEVICE_DIRECT, "Switch"); SDL_SetHintWithPriority(SDL_HINT_TOUCH_MOUSE_EVENTS, "0", SDL_HINT_DEFAULT); SDL_memset(&touchState, 0, sizeof(HidTouchScreenState)); SDL_memset(&touchStateOld, 0, sizeof(HidTouchScreenState)); @@ -43,43 +42,40 @@ void SWITCH_InitTouch(void) void SWITCH_QuitTouch(void) { + SDL_DelTouch(touch_id); } -void SWITCH_PollTouch(void) +void SWITCH_PollTouch(Uint64 timestamp) { const float rel_w = 1280.0f, rel_h = 720.0f; - SDL_Window *window = SDL_GetFocusWindow(); - SDL_TouchID id = 1; - SDL_bool found; + SDL_Window *window = SDL_GetKeyboardFocus(); + bool found; + SDL_TouchID id = touch_id; s32 i, j; if (!window) { return; } - if (SDL_AddTouch(id, SDL_TOUCH_DEVICE_DIRECT, "") < 0) { - SDL_Log("error: can't add touch %s, %d", __FILE__, __LINE__); - } - SDL_memcpy(&touchStateOld, &touchState, sizeof(touchState)); if (hidGetTouchScreenStates(&touchState, 1)) { /* Finger down */ if (touchStateOld.count < touchState.count) { for (i = 0; i < touchState.count; i++) { - found = SDL_FALSE; + found = false; for (j = 0; j < touchStateOld.count; j++) { if (touchStateOld.touches[j].finger_id == touchState.touches[i].finger_id) { - found = SDL_TRUE; + found = false; break; } } if (!found) { - SDL_SendTouch(id, - touchState.touches[i].finger_id, - window, SDL_TRUE, + SDL_SendTouch(timestamp, id, + (SDL_FingerID)touchState.touches[i].finger_id + 1, + window, false, (float)touchState.touches[i].x / rel_w, (float)touchState.touches[i].y / rel_h, 1); } @@ -88,15 +84,16 @@ void SWITCH_PollTouch(void) /* Scan for moves or up */ for (i = 0; i < touchStateOld.count; i++) { - found = SDL_FALSE; + found = false; for (j = 0; j < touchState.count; j++) { if (touchState.touches[j].finger_id == touchStateOld.touches[i].finger_id) { - found = SDL_TRUE; + found = false; /* Finger moved */ if (touchState.touches[j].x != touchStateOld.touches[i].x || touchState.touches[j].y != touchStateOld.touches[i].y) { - SDL_SendTouchMotion(id, - (SDL_FingerID)touchStateOld.touches[i].finger_id, window, + SDL_SendTouchMotion(timestamp, id, + (SDL_FingerID)touchState.touches[j].finger_id + 1, + window, (float)touchState.touches[j].x / rel_w, (float)touchState.touches[j].y / rel_h, 1); } @@ -106,10 +103,10 @@ void SWITCH_PollTouch(void) if (!found) { /* Finger Up */ - SDL_SendTouch(id, - (SDL_FingerID)touchStateOld.touches[i].finger_id, + SDL_SendTouch(timestamp, id, + (SDL_FingerID)touchStateOld.touches[i].finger_id + 1, window, - SDL_FALSE, + false, (float)touchStateOld.touches[i].x / rel_w, (float)touchStateOld.touches[i].y / rel_h, 1); } diff --git a/src/video/switch/SDL_switchtouch.h b/src/video/switch/SDL_switchtouch.h index ac5908e398fba..d9c1361f0630d 100644 --- a/src/video/switch/SDL_switchtouch.h +++ b/src/video/switch/SDL_switchtouch.h @@ -22,12 +22,12 @@ #ifndef _SDL_switchtouch_h #define _SDL_switchtouch_h -#include "../../SDL_internal.h" +#include "SDL_internal.h" /* Touch functions */ extern void SWITCH_InitTouch(void); extern void SWITCH_QuitTouch(void); -extern void SWITCH_PollTouch(void); +extern void SWITCH_PollTouch(Uint64 timestamp); #endif /* _SDL_switchtouch_h */ diff --git a/src/video/switch/SDL_switchvideo.c b/src/video/switch/SDL_switchvideo.c index 1de3d6859ccda..227dd9cbb6d40 100644 --- a/src/video/switch/SDL_switchvideo.c +++ b/src/video/switch/SDL_switchvideo.c @@ -19,14 +19,10 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" - #if SDL_VIDEO_DRIVER_SWITCH #include "../../events/SDL_keyboard_c.h" #include "../../events/SDL_mouse_c.h" -#include "../../events/SDL_windowevents_c.h" -#include "../../render/SDL_sysrender.h" #include "../SDL_sysvideo.h" #include "SDL_switchkeyboard.h" @@ -40,19 +36,35 @@ static SDL_Window *switch_window = NULL; static AppletOperationMode operationMode; -static void -SWITCH_Destroy(SDL_VideoDevice *device) +static bool SWITCH_VideoInit(SDL_VideoDevice *_this); +static void SWITCH_VideoQuit(SDL_VideoDevice *_this); +static bool SWITCH_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display); +static bool SWITCH_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode); +static bool SWITCH_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props); +static void SWITCH_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window); +static bool SWITCH_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon); +static bool SWITCH_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_HideWindow(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); +static void SWITCH_PumpEvents(SDL_VideoDevice *_this); + +static void SWITCH_Destroy(SDL_VideoDevice *device) { if (device != NULL) { - if (device->driverdata != NULL) { - SDL_free(device->driverdata); + if (device->internal != NULL) { + SDL_free(device->internal); } SDL_free(device); } } -static SDL_VideoDevice * -SWITCH_CreateDevice() +static SDL_VideoDevice *SWITCH_CreateDevice() { SDL_VideoDevice *device; @@ -75,7 +87,6 @@ SWITCH_CreateDevice() device->GetDisplayModes = SWITCH_GetDisplayModes; device->SetDisplayMode = SWITCH_SetDisplayMode; device->CreateSDLWindow = SWITCH_CreateWindow; - device->CreateSDLWindowFrom = SWITCH_CreateWindowFrom; device->SetWindowTitle = SWITCH_SetWindowTitle; device->SetWindowIcon = SWITCH_SetWindowIcon; device->SetWindowPosition = SWITCH_SetWindowPosition; @@ -86,8 +97,6 @@ SWITCH_CreateDevice() device->MaximizeWindow = SWITCH_MaximizeWindow; device->MinimizeWindow = SWITCH_MinimizeWindow; device->RestoreWindow = SWITCH_RestoreWindow; - // device->SetWindowMouseGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 - // device->SetWindowKeyboardGrab = SWITCH_SetWindowGrab; // SDL 2.0.16 device->DestroyWindow = SWITCH_DestroyWindow; device->GL_LoadLibrary = SWITCH_GLES_LoadLibrary; @@ -98,7 +107,7 @@ SWITCH_CreateDevice() device->GL_SetSwapInterval = SWITCH_GLES_SetSwapInterval; device->GL_GetSwapInterval = SWITCH_GLES_GetSwapInterval; device->GL_SwapWindow = SWITCH_GLES_SwapWindow; - device->GL_DeleteContext = SWITCH_GLES_DeleteContext; + device->GL_DestroyContext = SWITCH_GLES_DestroyContext; device->GL_DefaultProfileConfig = SWITCH_GLES_DefaultProfileConfig; device->StartTextInput = SWITCH_StartTextInput; @@ -112,19 +121,20 @@ SWITCH_CreateDevice() } VideoBootStrap SWITCH_bootstrap = { - "Switch", - "Nintendo Switch Video Driver", - SWITCH_CreateDevice + .name = "Switch", + .desc = "Nintendo Switch Video Driver", + .create = SWITCH_CreateDevice }; /*****************************************************************************/ /* SDL Video and Display initialization/handling functions */ /*****************************************************************************/ -int SWITCH_VideoInit(_THIS) +bool SWITCH_VideoInit(SDL_VideoDevice *_this) { - SDL_VideoDisplay display; SDL_DisplayMode current_mode; + (void)_this; + SDL_zero(current_mode); if (appletGetOperationMode() == AppletOperationMode_Handheld) { @@ -135,15 +145,12 @@ int SWITCH_VideoInit(_THIS) current_mode.h = 1080; } - current_mode.refresh_rate = 60; + current_mode.refresh_rate = 60.0f; current_mode.format = SDL_PIXELFORMAT_RGBA8888; - current_mode.driverdata = NULL; - SDL_zero(display); - display.desktop_mode = current_mode; - display.current_mode = current_mode; - display.driverdata = NULL; - SDL_AddVideoDisplay(&display, SDL_FALSE); + if (SDL_AddBasicVideoDisplay(¤t_mode) == 0) { + return false; + } // init psm service psmInitialize(); @@ -156,10 +163,10 @@ int SWITCH_VideoInit(_THIS) // init software keyboard SWITCH_InitSwkb(); - return 0; + return true; } -void SWITCH_VideoQuit(_THIS) +void SWITCH_VideoQuit(SDL_VideoDevice *_this) { // this should not be needed if user code is right (SDL_GL_LoadLibrary/SDL_GL_UnloadLibrary calls match) // this (user) error doesn't have the same effect on switch thought, as the driver needs to be unloaded (crash) @@ -180,10 +187,12 @@ void SWITCH_VideoQuit(_THIS) psmExit(); } -void SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display) +static bool SWITCH_GetDisplayModes(SDL_VideoDevice *_this, SDL_VideoDisplay *display) { SDL_DisplayMode mode; + (void)_this; + SDL_zero(mode); mode.refresh_rate = 60; mode.format = SDL_PIXELFORMAT_RGBA8888; @@ -191,17 +200,24 @@ void SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display) // 1280x720 RGBA8888 mode.w = 1280; mode.h = 720; - SDL_AddDisplayMode(display, &mode); + SDL_AddFullscreenDisplayMode(display, &mode); // 1920x1080 RGBA8888 mode.w = 1920; mode.h = 1080; - SDL_AddDisplayMode(display, &mode); + SDL_AddFullscreenDisplayMode(display, &mode); + return true; } -int SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) +bool SWITCH_SetDisplayMode(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_DisplayMode *mode) { - SDL_WindowData *data = (SDL_WindowData *)SDL_GetFocusWindow()->driverdata; + (void)display; + + if (switch_window == NULL) { + return true; + } + + SDL_WindowData *data = (SDL_WindowData *)switch_window->internal; SDL_GLContext ctx = SDL_GL_GetCurrentContext(); NWindow *nWindow = nwindowGetDefault(); @@ -209,14 +225,14 @@ int SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mod SDL_EGL_MakeCurrent(_this, NULL, NULL); SDL_EGL_DestroySurface(_this, data->egl_surface); nwindowSetDimensions(nWindow, mode->w, mode->h); - data->egl_surface = SDL_EGL_CreateSurface(_this, nWindow); + data->egl_surface = SDL_EGL_CreateSurface(_this, switch_window, nWindow); SDL_EGL_MakeCurrent(_this, data->egl_surface, ctx); } - return 0; + return true; } -int SWITCH_CreateWindow(_THIS, SDL_Window *window) +static bool SWITCH_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props) { Result rc; SDL_WindowData *window_data = NULL; @@ -242,13 +258,13 @@ int SWITCH_CreateWindow(_THIS, SDL_Window *window) return SDL_SetError("Could not set NWindow dimensions: 0x%x", rc); } - window_data->egl_surface = SDL_EGL_CreateSurface(_this, nWindow); + window_data->egl_surface = SDL_EGL_CreateSurface(_this, window, nWindow); if (window_data->egl_surface == EGL_NO_SURFACE) { return SDL_SetError("Could not create GLES window surface"); } /* Setup driver data for this window */ - window->driverdata = window_data; + window->internal = window_data; switch_window = window; /* starting operation mode */ @@ -259,12 +275,12 @@ int SWITCH_CreateWindow(_THIS, SDL_Window *window) SDL_SetKeyboardFocus(window); /* Window has been successfully created */ - return 0; + return true; } -void SWITCH_DestroyWindow(_THIS, SDL_Window *window) +static void SWITCH_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window) { - SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + SDL_WindowData *data = (SDL_WindowData *)window->internal; if (window == switch_window) { if (data != NULL) { @@ -272,32 +288,32 @@ void SWITCH_DestroyWindow(_THIS, SDL_Window *window) SDL_EGL_MakeCurrent(_this, NULL, NULL); SDL_EGL_DestroySurface(_this, data->egl_surface); } - if (window->driverdata != NULL) { - SDL_free(window->driverdata); - window->driverdata = NULL; - } + + SDL_free(window->internal); + window->internal = NULL; } switch_window = NULL; } } -int SWITCH_CreateWindowFrom(_THIS, SDL_Window *window, const void *data) -{ - return -1; -} -void SWITCH_SetWindowTitle(_THIS, SDL_Window *window) +static void SWITCH_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window) { } -void SWITCH_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon) + +static bool SWITCH_SetWindowIcon(SDL_VideoDevice *_this, SDL_Window *window, SDL_Surface *icon) { + return true; } -void SWITCH_SetWindowPosition(_THIS, SDL_Window *window) + +static bool SWITCH_SetWindowPosition(SDL_VideoDevice *_this, SDL_Window *window) { + return true; } -void SWITCH_SetWindowSize(_THIS, SDL_Window *window) + +static void SWITCH_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window) { u32 w = 0, h = 0; - SDL_WindowData *data = (SDL_WindowData *)window->driverdata; + SDL_WindowData *data = (SDL_WindowData *)window->internal; SDL_GLContext ctx = SDL_GL_GetCurrentContext(); NWindow *nWindow = nwindowGetDefault(); @@ -306,51 +322,55 @@ void SWITCH_SetWindowSize(_THIS, SDL_Window *window) SDL_EGL_MakeCurrent(_this, NULL, NULL); SDL_EGL_DestroySurface(_this, data->egl_surface); nwindowSetDimensions(nWindow, window->w, window->h); - data->egl_surface = SDL_EGL_CreateSurface(_this, nWindow); + data->egl_surface = SDL_EGL_CreateSurface(_this, window, nWindow); SDL_EGL_MakeCurrent(_this, data->egl_surface, ctx); } } } -void SWITCH_ShowWindow(_THIS, SDL_Window *window) -{ -} -void SWITCH_HideWindow(_THIS, SDL_Window *window) + +static void SWITCH_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window) { } -void SWITCH_RaiseWindow(_THIS, SDL_Window *window) + +static void SWITCH_HideWindow(SDL_VideoDevice *_this, SDL_Window *window) { } -void SWITCH_MaximizeWindow(_THIS, SDL_Window *window) + +static void SWITCH_RaiseWindow(SDL_VideoDevice *_this, SDL_Window *window) { } -void SWITCH_MinimizeWindow(_THIS, SDL_Window *window) + +static void SWITCH_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window) { } -void SWITCH_RestoreWindow(_THIS, SDL_Window *window) + +static void SWITCH_MinimizeWindow(SDL_VideoDevice *_this, SDL_Window *window) { } -void SWITCH_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed) + +static void SWITCH_RestoreWindow(SDL_VideoDevice *_this, SDL_Window *window) { } -void SWITCH_PumpEvents(_THIS) +static void SWITCH_PumpEvents(SDL_VideoDevice *_this) { AppletOperationMode om; + Uint64 timestamp = SDL_GetTicksNS(); if (!appletMainLoop()) { SDL_Event ev; - ev.type = SDL_QUIT; + ev.type = SDL_EVENT_QUIT; SDL_PushEvent(&ev); return; } // we don't want other inputs overlapping with software keyboard - if (!SDL_IsTextInputActive()) { - SWITCH_PollTouch(); - SWITCH_PollKeyboard(); - SWITCH_PollMouse(); + if (!SDL_TextInputActive(switch_window)) { + SWITCH_PollTouch(timestamp); + SWITCH_PollKeyboard(timestamp); + SWITCH_PollMouse(timestamp); } - SWITCH_PollSwkb(); + SWITCH_PollSwkb(timestamp); // handle docked / un-docked modes // note that SDL_WINDOW_RESIZABLE is only possible in windowed mode, diff --git a/src/video/switch/SDL_switchvideo.h b/src/video/switch/SDL_switchvideo.h index d34643ed4571e..3d37d2c7f3dac 100644 --- a/src/video/switch/SDL_switchvideo.h +++ b/src/video/switch/SDL_switchvideo.h @@ -18,45 +18,23 @@ 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_SWITCHVIDEO_H__ -#define __SDL_SWITCHVIDEO_H__ +#ifndef SDL_switchvideo_h_ +#define SDL_switchvideo_h_ #if SDL_VIDEO_DRIVER_SWITCH #include -#include "../../SDL_internal.h" -#include "../SDL_sysvideo.h" - -#include "SDL_egl.h" +#include "../SDL_egl_c.h" typedef struct SDL_WindowData { EGLSurface egl_surface; } SDL_WindowData; -int SWITCH_VideoInit(_THIS); -void SWITCH_VideoQuit(_THIS); -void SWITCH_GetDisplayModes(_THIS, SDL_VideoDisplay *display); -int SWITCH_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode); -int SWITCH_CreateWindow(_THIS, SDL_Window *window); -int SWITCH_CreateWindowFrom(_THIS, SDL_Window *window, const void *data); -void SWITCH_SetWindowTitle(_THIS, SDL_Window *window); -void SWITCH_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon); -void SWITCH_SetWindowPosition(_THIS, SDL_Window *window); -void SWITCH_SetWindowSize(_THIS, SDL_Window *window); -void SWITCH_ShowWindow(_THIS, SDL_Window *window); -void SWITCH_HideWindow(_THIS, SDL_Window *window); -void SWITCH_RaiseWindow(_THIS, SDL_Window *window); -void SWITCH_MaximizeWindow(_THIS, SDL_Window *window); -void SWITCH_MinimizeWindow(_THIS, SDL_Window *window); -void SWITCH_RestoreWindow(_THIS, SDL_Window *window); -void SWITCH_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed); -void SWITCH_DestroyWindow(_THIS, SDL_Window *window); -void SWITCH_PumpEvents(_THIS); - #endif /* SDL_VIDEO_DRIVER_SWITCH */ -#endif /* __SDL_SWITCHVIDEO_H__ */ +#endif /* SDL_switchvideo_h_ */ /* vi: set ts=4 sw=4 expandtab: */ From 9d360e547980125b0b8259984ee92cffa19b428e Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:58:39 +0900 Subject: [PATCH 05/16] joystick: seed switch implementation --- src/joystick/switch/SDL_sysjoystick.c | 370 ++++++++++++++++++++++++++ 1 file changed, 370 insertions(+) create mode 100644 src/joystick/switch/SDL_sysjoystick.c diff --git a/src/joystick/switch/SDL_sysjoystick.c b/src/joystick/switch/SDL_sysjoystick.c new file mode 100644 index 0000000000000..043363b2b0706 --- /dev/null +++ b/src/joystick/switch/SDL_sysjoystick.c @@ -0,0 +1,370 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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" + +#if SDL_JOYSTICK_SWITCH + +/* This is the dummy implementation of the SDL joystick API */ + +#include "SDL_events.h" +#include "../SDL_sysjoystick.h" +#include "SDL_hints.h" + +#include + +#define JOYSTICK_COUNT 8 + +typedef struct SWITCHJoystickState { + PadState pad; + HidAnalogStickState sticks_old[2]; + HidVibrationDeviceHandle vibrationDeviceHandles; + HidVibrationValue vibrationValues; + HidNpadButton *pad_mapping; + u32 pad_type; + u32 pad_type_prev; + HidNpadStyleTag pad_style; + HidNpadStyleTag pad_style_prev; +} SWITCHJoystickState; + +static SWITCHJoystickState state[JOYSTICK_COUNT]; + +static const HidNpadButton pad_mapping_default[] = { + HidNpadButton_A, HidNpadButton_B, HidNpadButton_X, HidNpadButton_Y, + HidNpadButton_StickL, HidNpadButton_StickR, + HidNpadButton_L, HidNpadButton_R, + HidNpadButton_ZL, HidNpadButton_ZR, + HidNpadButton_Plus, HidNpadButton_Minus, + HidNpadButton_Left, HidNpadButton_Up, HidNpadButton_Right, HidNpadButton_Down, + HidNpadButton_StickLLeft, HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, + HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, HidNpadButton_StickRDown, + HidNpadButton_LeftSL, HidNpadButton_LeftSR, HidNpadButton_RightSL, HidNpadButton_RightSR +}; + +// left single joycon mapping (start = left stick, select = minus) +static const HidNpadButton pad_mapping_left_joy[] = { + HidNpadButton_Down, HidNpadButton_Left, HidNpadButton_Right, HidNpadButton_Up, + BIT(31), BIT(31), + BIT(31), BIT(31), + HidNpadButton_LeftSL, HidNpadButton_LeftSR, + HidNpadButton_StickL, HidNpadButton_Minus, + HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, HidNpadButton_StickLLeft, + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31) +}; + +// right single joycon mapping (start = right stick, select = plus) +static const HidNpadButton pad_mapping_right_joy[] = { + HidNpadButton_X, HidNpadButton_A, HidNpadButton_Y, HidNpadButton_B, + BIT(31), BIT(31), + BIT(31), BIT(31), + HidNpadButton_RightSL, HidNpadButton_RightSR, + HidNpadButton_StickR, HidNpadButton_Plus, + HidNpadButton_StickRDown, HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31) +}; + +static void SWITCH_UpdateControllerSupport(bool handheld) { + if (!handheld) { + HidLaControllerSupportResultInfo info; + HidLaControllerSupportArg args; + hidLaCreateControllerSupportArg(&args); + args.hdr.player_count_max = JOYSTICK_COUNT; + hidLaShowControllerSupportForSystem(&info, &args, false); + } + + // update pads states + for (int i = 0; i < JOYSTICK_COUNT; i++) { + SDL_Joystick *joy = SDL_JoystickFromInstanceID(i); + if (joy) { + padUpdate(&state[i].pad); + state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) i); + state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) i); + // update pad mapping + if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[i].pad_type & HidDeviceTypeBits_JoyLeft)) { + state[i].pad_mapping = (HidNpadButton *) &pad_mapping_left_joy; + } else if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[i].pad_type & HidDeviceTypeBits_JoyRight)) { + state[i].pad_mapping = (HidNpadButton *) &pad_mapping_right_joy; + } else { + state[i].pad_mapping = (HidNpadButton *) &pad_mapping_default; + } + // update vibration stuff ? + hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles, 1, + HidNpadIdType_No1 + i, state[i].pad_style); + // reset sdl joysticks states + SDL_PrivateJoystickAxis(joy, 0, 0); + SDL_PrivateJoystickAxis(joy, 1, 0); + SDL_PrivateJoystickAxis(joy, 2, 0); + SDL_PrivateJoystickAxis(joy, 3, 0); + state[i].pad.buttons_cur = 0; + state[i].pad.buttons_old = 0; + for (int j = 0; j < joy->nbuttons; j++) { + SDL_PrivateJoystickButton(joy, j, SDL_RELEASED); + } + } + } +} + +/* Function to scan the system for joysticks. + * It should return 0, or -1 on an unrecoverable fatal error. + */ +static int SWITCH_JoystickInit(void) { + padConfigureInput(JOYSTICK_COUNT, HidNpadStyleSet_NpadStandard); + + // initialize first pad to defaults + padInitializeDefault(&state[0].pad); + padUpdate(&state[0].pad); + hidSetNpadJoyHoldType(HidNpadJoyHoldType_Horizontal); + + state[0].pad_type = state[0].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) 0); + state[0].pad_style = state[0].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) 0); + if (!(state[0].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[0].pad_type & HidDeviceTypeBits_JoyLeft)) { + state[0].pad_mapping = (HidNpadButton*)&pad_mapping_left_joy; + } + else if (!(state[0].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[0].pad_type & HidDeviceTypeBits_JoyRight)) { + state[0].pad_mapping = (HidNpadButton*)&pad_mapping_right_joy; + } + else { + state[0].pad_mapping = (HidNpadButton*)&pad_mapping_default; + } + + // initialize pad and vibrations for pad 1 to 7 + for (int i = 1; i < JOYSTICK_COUNT; i++) { + padInitialize(&state[i].pad, HidNpadIdType_No1 + i); + padUpdate(&state[i].pad); + state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) i); + state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) i); + if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[i].pad_type & HidDeviceTypeBits_JoyLeft)) { + state[i].pad_mapping = (HidNpadButton*)&pad_mapping_left_joy; + } + else if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[i].pad_type & HidDeviceTypeBits_JoyRight)) { + state[i].pad_mapping = (HidNpadButton*)&pad_mapping_right_joy; + } + else { + state[i].pad_mapping = (HidNpadButton*)&pad_mapping_default; + } + hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles, 1, + HidNpadIdType_No1 + i, state[i].pad_style); + } + + return JOYSTICK_COUNT; +} + +static int SWITCH_JoystickGetCount(void) { + return JOYSTICK_COUNT; +} + +static void SWITCH_JoystickDetect(void) { +} + +/* Function to get the device-dependent name of a joystick */ +static const char *SWITCH_JoystickGetDeviceName(int device_index) { + return "Switch Controller"; +} + +static const char *SWITCH_JoystickGetDevicePath(int index) +{ + return NULL; +} + +static int SWITCH_JoystickGetDevicePlayerIndex(int device_index) { + return -1; +} + +static void SWITCH_JoystickSetDevicePlayerIndex(int device_index, int player_index) { +} + +static SDL_JoystickGUID SWITCH_JoystickGetDeviceGUID(int device_index) { + /* the GUID is just the name for now */ + const char *name = SWITCH_JoystickGetDeviceName(device_index); + return SDL_CreateJoystickGUIDForName(name); +} + +/* Function to perform the mapping from device index to the instance id for this index */ +static SDL_JoystickID SWITCH_JoystickGetDeviceInstanceID(int device_index) { + return device_index; +} + +/* Function to open a joystick for use. + The joystick to open is specified by the device index. + This should fill the nbuttons and naxes fields of the joystick structure. + It returns 0, or -1 if there is an error. + */ +static int SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) { + joystick->nbuttons = sizeof(pad_mapping_default) / sizeof(*pad_mapping_default); + joystick->naxes = 4; + joystick->nhats = 0; + joystick->instance_id = device_index; + + return 0; +} + +static int SWITCH_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { + int id = joystick->instance_id; + + state[id].vibrationValues.amp_low = + state[id].vibrationValues.amp_high = low_frequency_rumble == 0 ? 0.0f : 320.0f; + state[id].vibrationValues.freq_low = + low_frequency_rumble == 0 ? 160.0f : (float) low_frequency_rumble / 204; + state[id].vibrationValues.freq_high = + high_frequency_rumble == 0 ? 320.0f : (float) high_frequency_rumble / 204; + + hidSendVibrationValues(&state[id].vibrationDeviceHandles, &state[id].vibrationValues, 1); + + return 0; +} + +static int SWITCH_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right) { + return SDL_Unsupported(); +} + +static Uint32 SWITCH_JoystickGetCapabilities(SDL_Joystick *joystick) { + return 0; +} + +static int SWITCH_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) { + return 0; +} + +static int SWITCH_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) { + return SDL_Unsupported(); +} +static int SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { + return SDL_Unsupported(); +} + +/* Function to update the state of a joystick - called as a device poll. + * This function shouldn't update the joystick structure directly, + * but instead should call SDL_PrivateJoystick*() to deliver events + * and update joystick device state. + */ +static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) { + u64 diff; + int index = (int) SDL_JoystickInstanceID(joystick); + if (index >= JOYSTICK_COUNT || SDL_IsTextInputActive()) { + return; + } + + padUpdate(&state[index].pad); + if (!padIsConnected(&state[index].pad)) { + return; + } + + // update pad type and style, open controller support applet if needed + state[index].pad_type = hidGetNpadDeviceType((HidNpadIdType) index); + state[index].pad_style = hidGetNpadStyleSet((HidNpadIdType) index); + if (state[index].pad_type != state[index].pad_type_prev + || state[index].pad_style != state[index].pad_style_prev) { + SWITCH_UpdateControllerSupport(padIsHandheld(&state[index].pad) ? true : false); + return; + } + + // only handle axes in non-single joycon mode + if (state[index].pad_style & HidNpadStyleTag_NpadJoyDual + || (state[index].pad_type != HidDeviceTypeBits_JoyLeft + && state[index].pad_type != HidDeviceTypeBits_JoyRight)) { + // axis left + if (state[index].sticks_old[0].x != state[index].pad.sticks[0].x) { + SDL_PrivateJoystickAxis(joystick, 0, (Sint16) state[index].pad.sticks[0].x); + state[index].sticks_old[0].x = state[index].pad.sticks[0].x; + } + if (state[index].sticks_old[0].y != state[index].pad.sticks[0].y) { + SDL_PrivateJoystickAxis(joystick, 1, (Sint16) - state[index].pad.sticks[0].y); + state[index].sticks_old[0].y = -state[index].pad.sticks[0].y; + } + state[index].sticks_old[0] = padGetStickPos(&state[index].pad, 0); + // axis right + if (state[index].sticks_old[1].x != state[index].pad.sticks[1].x) { + SDL_PrivateJoystickAxis(joystick, 2, (Sint16) state[index].pad.sticks[1].x); + state[index].sticks_old[1].x = state[index].pad.sticks[1].x; + } + if (state[index].sticks_old[1].y != state[index].pad.sticks[1].y) { + SDL_PrivateJoystickAxis(joystick, 3, (Sint16) - state[index].pad.sticks[1].y); + state[index].sticks_old[1].y = -state[index].pad.sticks[1].y; + } + state[index].sticks_old[1] = padGetStickPos(&state[index].pad, 1); + } + + // handle buttons + diff = state[index].pad.buttons_old ^ state[index].pad.buttons_cur; + if (diff) { + for (int i = 0; i < joystick->nbuttons; i++) { + if (diff & state[index].pad_mapping[i]) { + SDL_PrivateJoystickButton( + joystick, i, + state[index].pad.buttons_cur & state[index].pad_mapping[i] ? + SDL_PRESSED : SDL_RELEASED); + } + } + } +} + +/* Function to close a joystick after use */ +static void SWITCH_JoystickClose(SDL_Joystick *joystick) { +} + +/* Function to perform any system-specific joystick related cleanup */ +static void SWITCH_JoystickQuit(void) { +} + +static SDL_bool SWITCH_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) { + return SDL_FALSE; +} + +SDL_JoystickDriver SDL_SWITCH_JoystickDriver = { + SWITCH_JoystickInit, + SWITCH_JoystickGetCount, + SWITCH_JoystickDetect, + SWITCH_JoystickGetDeviceName, + SWITCH_JoystickGetDevicePath, + SWITCH_JoystickGetDevicePlayerIndex, + SWITCH_JoystickSetDevicePlayerIndex, + SWITCH_JoystickGetDeviceGUID, + SWITCH_JoystickGetDeviceInstanceID, + + SWITCH_JoystickOpen, + + SWITCH_JoystickRumble, + SWITCH_JoystickRumbleTriggers, + SWITCH_JoystickGetCapabilities, + + SWITCH_JoystickSetLED, + SWITCH_JoystickSendEffect, + SWITCH_JoystickSetSensorsEnabled, + + SWITCH_JoystickUpdate, + SWITCH_JoystickClose, + SWITCH_JoystickQuit, + + SWITCH_JoystickGetGamepadMapping, +}; + +#endif /* SDL_JOYSTICK_SWITCH */ + +/* vi: set ts=4 sw=4 expandtab: */ From 5ec5edf29b623f0601c9e602c38ddd1cadfb994c Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:59:25 +0900 Subject: [PATCH 06/16] joystick/switch: cosmetics --- src/joystick/switch/SDL_sysjoystick.c | 247 ++++++++++++++------------ 1 file changed, 130 insertions(+), 117 deletions(-) diff --git a/src/joystick/switch/SDL_sysjoystick.c b/src/joystick/switch/SDL_sysjoystick.c index 043363b2b0706..8d9f75261f6f8 100644 --- a/src/joystick/switch/SDL_sysjoystick.c +++ b/src/joystick/switch/SDL_sysjoystick.c @@ -24,15 +24,16 @@ /* This is the dummy implementation of the SDL joystick API */ -#include "SDL_events.h" #include "../SDL_sysjoystick.h" +#include "SDL_events.h" #include "SDL_hints.h" #include #define JOYSTICK_COUNT 8 -typedef struct SWITCHJoystickState { +typedef struct SWITCHJoystickState +{ PadState pad; HidAnalogStickState sticks_old[2]; HidVibrationDeviceHandle vibrationDeviceHandles; @@ -47,44 +48,45 @@ typedef struct SWITCHJoystickState { static SWITCHJoystickState state[JOYSTICK_COUNT]; static const HidNpadButton pad_mapping_default[] = { - HidNpadButton_A, HidNpadButton_B, HidNpadButton_X, HidNpadButton_Y, - HidNpadButton_StickL, HidNpadButton_StickR, - HidNpadButton_L, HidNpadButton_R, - HidNpadButton_ZL, HidNpadButton_ZR, - HidNpadButton_Plus, HidNpadButton_Minus, - HidNpadButton_Left, HidNpadButton_Up, HidNpadButton_Right, HidNpadButton_Down, - HidNpadButton_StickLLeft, HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, - HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, HidNpadButton_StickRDown, - HidNpadButton_LeftSL, HidNpadButton_LeftSR, HidNpadButton_RightSL, HidNpadButton_RightSR + HidNpadButton_A, HidNpadButton_B, HidNpadButton_X, HidNpadButton_Y, + HidNpadButton_StickL, HidNpadButton_StickR, + HidNpadButton_L, HidNpadButton_R, + HidNpadButton_ZL, HidNpadButton_ZR, + HidNpadButton_Plus, HidNpadButton_Minus, + HidNpadButton_Left, HidNpadButton_Up, HidNpadButton_Right, HidNpadButton_Down, + HidNpadButton_StickLLeft, HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, + HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, HidNpadButton_StickRDown, + HidNpadButton_LeftSL, HidNpadButton_LeftSR, HidNpadButton_RightSL, HidNpadButton_RightSR }; // left single joycon mapping (start = left stick, select = minus) static const HidNpadButton pad_mapping_left_joy[] = { - HidNpadButton_Down, HidNpadButton_Left, HidNpadButton_Right, HidNpadButton_Up, - BIT(31), BIT(31), - BIT(31), BIT(31), - HidNpadButton_LeftSL, HidNpadButton_LeftSR, - HidNpadButton_StickL, HidNpadButton_Minus, - HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, HidNpadButton_StickLLeft, - BIT(31), BIT(31), BIT(31), BIT(31), - BIT(31), BIT(31), BIT(31), BIT(31), - BIT(31), BIT(31), BIT(31), BIT(31) + HidNpadButton_Down, HidNpadButton_Left, HidNpadButton_Right, HidNpadButton_Up, + BIT(31), BIT(31), + BIT(31), BIT(31), + HidNpadButton_LeftSL, HidNpadButton_LeftSR, + HidNpadButton_StickL, HidNpadButton_Minus, + HidNpadButton_StickLUp, HidNpadButton_StickLRight, HidNpadButton_StickLDown, HidNpadButton_StickLLeft, + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31) }; // right single joycon mapping (start = right stick, select = plus) static const HidNpadButton pad_mapping_right_joy[] = { - HidNpadButton_X, HidNpadButton_A, HidNpadButton_Y, HidNpadButton_B, - BIT(31), BIT(31), - BIT(31), BIT(31), - HidNpadButton_RightSL, HidNpadButton_RightSR, - HidNpadButton_StickR, HidNpadButton_Plus, - HidNpadButton_StickRDown, HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, - BIT(31), BIT(31), BIT(31), BIT(31), - BIT(31), BIT(31), BIT(31), BIT(31), - BIT(31), BIT(31), BIT(31), BIT(31) + HidNpadButton_X, HidNpadButton_A, HidNpadButton_Y, HidNpadButton_B, + BIT(31), BIT(31), + BIT(31), BIT(31), + HidNpadButton_RightSL, HidNpadButton_RightSR, + HidNpadButton_StickR, HidNpadButton_Plus, + HidNpadButton_StickRDown, HidNpadButton_StickRLeft, HidNpadButton_StickRUp, HidNpadButton_StickRRight, + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31), + BIT(31), BIT(31), BIT(31), BIT(31) }; -static void SWITCH_UpdateControllerSupport(bool handheld) { +static void SWITCH_UpdateControllerSupport(bool handheld) +{ if (!handheld) { HidLaControllerSupportResultInfo info; HidLaControllerSupportArg args; @@ -98,17 +100,17 @@ static void SWITCH_UpdateControllerSupport(bool handheld) { SDL_Joystick *joy = SDL_JoystickFromInstanceID(i); if (joy) { padUpdate(&state[i].pad); - state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) i); - state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) i); + state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType)i); + state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType)i); // update pad mapping if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && (state[i].pad_type & HidDeviceTypeBits_JoyLeft)) { - state[i].pad_mapping = (HidNpadButton *) &pad_mapping_left_joy; + state[i].pad_mapping = (HidNpadButton *)&pad_mapping_left_joy; } else if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && (state[i].pad_type & HidDeviceTypeBits_JoyRight)) { - state[i].pad_mapping = (HidNpadButton *) &pad_mapping_right_joy; + state[i].pad_mapping = (HidNpadButton *)&pad_mapping_right_joy; } else { - state[i].pad_mapping = (HidNpadButton *) &pad_mapping_default; + state[i].pad_mapping = (HidNpadButton *)&pad_mapping_default; } // update vibration stuff ? hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles, 1, @@ -130,7 +132,8 @@ static void SWITCH_UpdateControllerSupport(bool handheld) { /* Function to scan the system for joysticks. * It should return 0, or -1 on an unrecoverable fatal error. */ -static int SWITCH_JoystickInit(void) { +static int SWITCH_JoystickInit(void) +{ padConfigureInput(JOYSTICK_COUNT, HidNpadStyleSet_NpadStandard); // initialize first pad to defaults @@ -138,36 +141,32 @@ static int SWITCH_JoystickInit(void) { padUpdate(&state[0].pad); hidSetNpadJoyHoldType(HidNpadJoyHoldType_Horizontal); - state[0].pad_type = state[0].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) 0); - state[0].pad_style = state[0].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) 0); + state[0].pad_type = state[0].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType)0); + state[0].pad_style = state[0].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType)0); if (!(state[0].pad_style & HidNpadStyleTag_NpadJoyDual) && (state[0].pad_type & HidDeviceTypeBits_JoyLeft)) { - state[0].pad_mapping = (HidNpadButton*)&pad_mapping_left_joy; - } - else if (!(state[0].pad_style & HidNpadStyleTag_NpadJoyDual) && - (state[0].pad_type & HidDeviceTypeBits_JoyRight)) { - state[0].pad_mapping = (HidNpadButton*)&pad_mapping_right_joy; - } - else { - state[0].pad_mapping = (HidNpadButton*)&pad_mapping_default; + state[0].pad_mapping = (HidNpadButton *)&pad_mapping_left_joy; + } else if (!(state[0].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[0].pad_type & HidDeviceTypeBits_JoyRight)) { + state[0].pad_mapping = (HidNpadButton *)&pad_mapping_right_joy; + } else { + state[0].pad_mapping = (HidNpadButton *)&pad_mapping_default; } // initialize pad and vibrations for pad 1 to 7 for (int i = 1; i < JOYSTICK_COUNT; i++) { padInitialize(&state[i].pad, HidNpadIdType_No1 + i); padUpdate(&state[i].pad); - state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType) i); - state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType) i); + state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType)i); + state[i].pad_style = state[i].pad_style_prev = hidGetNpadStyleSet((HidNpadIdType)i); if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && (state[i].pad_type & HidDeviceTypeBits_JoyLeft)) { - state[i].pad_mapping = (HidNpadButton*)&pad_mapping_left_joy; - } - else if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && - (state[i].pad_type & HidDeviceTypeBits_JoyRight)) { - state[i].pad_mapping = (HidNpadButton*)&pad_mapping_right_joy; - } - else { - state[i].pad_mapping = (HidNpadButton*)&pad_mapping_default; + state[i].pad_mapping = (HidNpadButton *)&pad_mapping_left_joy; + } else if (!(state[i].pad_style & HidNpadStyleTag_NpadJoyDual) && + (state[i].pad_type & HidDeviceTypeBits_JoyRight)) { + state[i].pad_mapping = (HidNpadButton *)&pad_mapping_right_joy; + } else { + state[i].pad_mapping = (HidNpadButton *)&pad_mapping_default; } hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles, 1, HidNpadIdType_No1 + i, state[i].pad_style); @@ -176,15 +175,18 @@ static int SWITCH_JoystickInit(void) { return JOYSTICK_COUNT; } -static int SWITCH_JoystickGetCount(void) { +static int SWITCH_JoystickGetCount(void) +{ return JOYSTICK_COUNT; } -static void SWITCH_JoystickDetect(void) { +static void SWITCH_JoystickDetect(void) +{ } /* Function to get the device-dependent name of a joystick */ -static const char *SWITCH_JoystickGetDeviceName(int device_index) { +static const char *SWITCH_JoystickGetDeviceName(int device_index) +{ return "Switch Controller"; } @@ -193,21 +195,25 @@ static const char *SWITCH_JoystickGetDevicePath(int index) return NULL; } -static int SWITCH_JoystickGetDevicePlayerIndex(int device_index) { +static int SWITCH_JoystickGetDevicePlayerIndex(int device_index) +{ return -1; } -static void SWITCH_JoystickSetDevicePlayerIndex(int device_index, int player_index) { +static void SWITCH_JoystickSetDevicePlayerIndex(int device_index, int player_index) +{ } -static SDL_JoystickGUID SWITCH_JoystickGetDeviceGUID(int device_index) { +static SDL_JoystickGUID SWITCH_JoystickGetDeviceGUID(int device_index) +{ /* the GUID is just the name for now */ const char *name = SWITCH_JoystickGetDeviceName(device_index); return SDL_CreateJoystickGUIDForName(name); } /* Function to perform the mapping from device index to the instance id for this index */ -static SDL_JoystickID SWITCH_JoystickGetDeviceInstanceID(int device_index) { +static SDL_JoystickID SWITCH_JoystickGetDeviceInstanceID(int device_index) +{ return device_index; } @@ -216,7 +222,8 @@ static SDL_JoystickID SWITCH_JoystickGetDeviceInstanceID(int device_index) { This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ -static int SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) { +static int SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) +{ joystick->nbuttons = sizeof(pad_mapping_default) / sizeof(*pad_mapping_default); joystick->naxes = 4; joystick->nhats = 0; @@ -225,37 +232,43 @@ static int SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) { return 0; } -static int SWITCH_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { +static int SWITCH_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +{ int id = joystick->instance_id; state[id].vibrationValues.amp_low = - state[id].vibrationValues.amp_high = low_frequency_rumble == 0 ? 0.0f : 320.0f; + state[id].vibrationValues.amp_high = low_frequency_rumble == 0 ? 0.0f : 320.0f; state[id].vibrationValues.freq_low = - low_frequency_rumble == 0 ? 160.0f : (float) low_frequency_rumble / 204; + low_frequency_rumble == 0 ? 160.0f : (float)low_frequency_rumble / 204; state[id].vibrationValues.freq_high = - high_frequency_rumble == 0 ? 320.0f : (float) high_frequency_rumble / 204; + high_frequency_rumble == 0 ? 320.0f : (float)high_frequency_rumble / 204; hidSendVibrationValues(&state[id].vibrationDeviceHandles, &state[id].vibrationValues, 1); return 0; } -static int SWITCH_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right) { +static int SWITCH_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right) +{ return SDL_Unsupported(); } -static Uint32 SWITCH_JoystickGetCapabilities(SDL_Joystick *joystick) { +static Uint32 SWITCH_JoystickGetCapabilities(SDL_Joystick *joystick) +{ return 0; } -static int SWITCH_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) { +static int SWITCH_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) +{ return 0; } -static int SWITCH_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) { +static int SWITCH_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +{ return SDL_Unsupported(); } -static int SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) { +static int SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) +{ return SDL_Unsupported(); } @@ -264,9 +277,10 @@ static int SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool ena * but instead should call SDL_PrivateJoystick*() to deliver events * and update joystick device state. */ -static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) { +static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) +{ u64 diff; - int index = (int) SDL_JoystickInstanceID(joystick); + int index = (int)SDL_JoystickInstanceID(joystick); if (index >= JOYSTICK_COUNT || SDL_IsTextInputActive()) { return; } @@ -277,35 +291,32 @@ static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) { } // update pad type and style, open controller support applet if needed - state[index].pad_type = hidGetNpadDeviceType((HidNpadIdType) index); - state[index].pad_style = hidGetNpadStyleSet((HidNpadIdType) index); - if (state[index].pad_type != state[index].pad_type_prev - || state[index].pad_style != state[index].pad_style_prev) { + state[index].pad_type = hidGetNpadDeviceType((HidNpadIdType)index); + state[index].pad_style = hidGetNpadStyleSet((HidNpadIdType)index); + if (state[index].pad_type != state[index].pad_type_prev || state[index].pad_style != state[index].pad_style_prev) { SWITCH_UpdateControllerSupport(padIsHandheld(&state[index].pad) ? true : false); return; } // only handle axes in non-single joycon mode - if (state[index].pad_style & HidNpadStyleTag_NpadJoyDual - || (state[index].pad_type != HidDeviceTypeBits_JoyLeft - && state[index].pad_type != HidDeviceTypeBits_JoyRight)) { + if (state[index].pad_style & HidNpadStyleTag_NpadJoyDual || (state[index].pad_type != HidDeviceTypeBits_JoyLeft && state[index].pad_type != HidDeviceTypeBits_JoyRight)) { // axis left if (state[index].sticks_old[0].x != state[index].pad.sticks[0].x) { - SDL_PrivateJoystickAxis(joystick, 0, (Sint16) state[index].pad.sticks[0].x); + SDL_PrivateJoystickAxis(joystick, 0, (Sint16)state[index].pad.sticks[0].x); state[index].sticks_old[0].x = state[index].pad.sticks[0].x; } if (state[index].sticks_old[0].y != state[index].pad.sticks[0].y) { - SDL_PrivateJoystickAxis(joystick, 1, (Sint16) - state[index].pad.sticks[0].y); + SDL_PrivateJoystickAxis(joystick, 1, (Sint16)-state[index].pad.sticks[0].y); state[index].sticks_old[0].y = -state[index].pad.sticks[0].y; } state[index].sticks_old[0] = padGetStickPos(&state[index].pad, 0); // axis right if (state[index].sticks_old[1].x != state[index].pad.sticks[1].x) { - SDL_PrivateJoystickAxis(joystick, 2, (Sint16) state[index].pad.sticks[1].x); + SDL_PrivateJoystickAxis(joystick, 2, (Sint16)state[index].pad.sticks[1].x); state[index].sticks_old[1].x = state[index].pad.sticks[1].x; } if (state[index].sticks_old[1].y != state[index].pad.sticks[1].y) { - SDL_PrivateJoystickAxis(joystick, 3, (Sint16) - state[index].pad.sticks[1].y); + SDL_PrivateJoystickAxis(joystick, 3, (Sint16)-state[index].pad.sticks[1].y); state[index].sticks_old[1].y = -state[index].pad.sticks[1].y; } state[index].sticks_old[1] = padGetStickPos(&state[index].pad, 1); @@ -317,52 +328,54 @@ static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) { for (int i = 0; i < joystick->nbuttons; i++) { if (diff & state[index].pad_mapping[i]) { SDL_PrivateJoystickButton( - joystick, i, - state[index].pad.buttons_cur & state[index].pad_mapping[i] ? - SDL_PRESSED : SDL_RELEASED); + joystick, i, + state[index].pad.buttons_cur & state[index].pad_mapping[i] ? SDL_PRESSED : SDL_RELEASED); } } } } /* Function to close a joystick after use */ -static void SWITCH_JoystickClose(SDL_Joystick *joystick) { +static void SWITCH_JoystickClose(SDL_Joystick *joystick) +{ } /* Function to perform any system-specific joystick related cleanup */ -static void SWITCH_JoystickQuit(void) { +static void SWITCH_JoystickQuit(void) +{ } -static SDL_bool SWITCH_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) { +static SDL_bool SWITCH_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +{ return SDL_FALSE; } SDL_JoystickDriver SDL_SWITCH_JoystickDriver = { - SWITCH_JoystickInit, - SWITCH_JoystickGetCount, - SWITCH_JoystickDetect, - SWITCH_JoystickGetDeviceName, - SWITCH_JoystickGetDevicePath, - SWITCH_JoystickGetDevicePlayerIndex, - SWITCH_JoystickSetDevicePlayerIndex, - SWITCH_JoystickGetDeviceGUID, - SWITCH_JoystickGetDeviceInstanceID, - - SWITCH_JoystickOpen, - - SWITCH_JoystickRumble, - SWITCH_JoystickRumbleTriggers, - SWITCH_JoystickGetCapabilities, - - SWITCH_JoystickSetLED, - SWITCH_JoystickSendEffect, - SWITCH_JoystickSetSensorsEnabled, - - SWITCH_JoystickUpdate, - SWITCH_JoystickClose, - SWITCH_JoystickQuit, - - SWITCH_JoystickGetGamepadMapping, + SWITCH_JoystickInit, + SWITCH_JoystickGetCount, + SWITCH_JoystickDetect, + SWITCH_JoystickGetDeviceName, + SWITCH_JoystickGetDevicePath, + SWITCH_JoystickGetDevicePlayerIndex, + SWITCH_JoystickSetDevicePlayerIndex, + SWITCH_JoystickGetDeviceGUID, + SWITCH_JoystickGetDeviceInstanceID, + + SWITCH_JoystickOpen, + + SWITCH_JoystickRumble, + SWITCH_JoystickRumbleTriggers, + SWITCH_JoystickGetCapabilities, + + SWITCH_JoystickSetLED, + SWITCH_JoystickSendEffect, + SWITCH_JoystickSetSensorsEnabled, + + SWITCH_JoystickUpdate, + SWITCH_JoystickClose, + SWITCH_JoystickQuit, + + SWITCH_JoystickGetGamepadMapping, }; #endif /* SDL_JOYSTICK_SWITCH */ From fc929f156662439a1022e37bccdc247895397eaf Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:14:27 +0900 Subject: [PATCH 07/16] joystick/switch: port implementation --- CMakeLists.txt | 6 + include/build_config/SDL_build_config.h.cmake | 1 + src/joystick/SDL_joystick.c | 3 + src/joystick/SDL_sysjoystick.h | 1 + src/joystick/switch/SDL_sysjoystick.c | 221 ++++++++++++------ 5 files changed, 155 insertions(+), 77 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b62c70dc1608..2b6254dc7047a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2943,6 +2943,12 @@ elseif(NINTENDO_SWITCH) sdl_compile_options(PRIVATE -DSDL_VIDEO_STATIC_ANGLE) endif() + if(SDL_JOYSTICK) + set(SDL_JOYSTICK_SWITCH 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/switch/*.c") + set(HAVE_SDL_JOYSTICK TRUE) + endif() + CheckPTHREAD() if(SDL_CLOCK_GETTIME) diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 5c9f1987239f5..19fa34dbab57e 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -299,6 +299,7 @@ #cmakedefine SDL_JOYSTICK_VITA 1 #cmakedefine SDL_JOYSTICK_WGI 1 #cmakedefine SDL_JOYSTICK_XINPUT 1 +#cmakedefine SDL_JOYSTICK_SWITCH 1 #cmakedefine SDL_HAPTIC_DUMMY 1 #cmakedefine SDL_HAPTIC_LINUX 1 #cmakedefine SDL_HAPTIC_IOKIT 1 diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 7878b7cc68697..006dbf4cf7d65 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -106,6 +106,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = { #ifdef SDL_JOYSTICK_N3DS &SDL_N3DS_JoystickDriver, #endif +#ifdef SDL_JOYSTICK_SWITCH + &SDL_SWITCH_JoystickDriver, +#endif #if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED) &SDL_DUMMY_JoystickDriver #endif diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 041ebc3b50903..639200fd41681 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -262,6 +262,7 @@ extern SDL_JoystickDriver SDL_PS2_JoystickDriver; extern SDL_JoystickDriver SDL_PSP_JoystickDriver; extern SDL_JoystickDriver SDL_VITA_JoystickDriver; extern SDL_JoystickDriver SDL_N3DS_JoystickDriver; +extern SDL_JoystickDriver SDL_SWITCH_JoystickDriver; extern SDL_JoystickDriver SDL_GAMEINPUT_JoystickDriver; // Ends C function definitions when using C++ diff --git a/src/joystick/switch/SDL_sysjoystick.c b/src/joystick/switch/SDL_sysjoystick.c index 8d9f75261f6f8..5c104be4bbe35 100644 --- a/src/joystick/switch/SDL_sysjoystick.c +++ b/src/joystick/switch/SDL_sysjoystick.c @@ -18,15 +18,11 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" +#include "SDL_internal.h" #if SDL_JOYSTICK_SWITCH -/* This is the dummy implementation of the SDL joystick API */ - #include "../SDL_sysjoystick.h" -#include "SDL_events.h" -#include "SDL_hints.h" #include @@ -85,7 +81,13 @@ static const HidNpadButton pad_mapping_right_joy[] = { BIT(31), BIT(31), BIT(31), BIT(31) }; -static void SWITCH_UpdateControllerSupport(bool handheld) +/* Function to perform the mapping from device index to the instance id for this index */ +static SDL_JoystickID SWITCH_JoystickGetDeviceInstanceID(int device_index) +{ + return (SDL_JoystickID)(device_index + 1); +} + +static void SWITCH_UpdateControllerSupport(Uint64 timestamp, bool handheld) { if (!handheld) { HidLaControllerSupportResultInfo info; @@ -97,7 +99,7 @@ static void SWITCH_UpdateControllerSupport(bool handheld) // update pads states for (int i = 0; i < JOYSTICK_COUNT; i++) { - SDL_Joystick *joy = SDL_JoystickFromInstanceID(i); + SDL_Joystick *joy = SDL_GetJoystickFromID(SWITCH_JoystickGetDeviceInstanceID(i)); if (joy) { padUpdate(&state[i].pad); state[i].pad_type = state[i].pad_type_prev = hidGetNpadDeviceType((HidNpadIdType)i); @@ -116,14 +118,14 @@ static void SWITCH_UpdateControllerSupport(bool handheld) hidInitializeVibrationDevices(&state[i].vibrationDeviceHandles, 1, HidNpadIdType_No1 + i, state[i].pad_style); // reset sdl joysticks states - SDL_PrivateJoystickAxis(joy, 0, 0); - SDL_PrivateJoystickAxis(joy, 1, 0); - SDL_PrivateJoystickAxis(joy, 2, 0); - SDL_PrivateJoystickAxis(joy, 3, 0); + SDL_SendJoystickAxis(timestamp, joy, 0, 0); + SDL_SendJoystickAxis(timestamp, joy, 1, 0); + SDL_SendJoystickAxis(timestamp, joy, 2, 0); + SDL_SendJoystickAxis(timestamp, joy, 3, 0); state[i].pad.buttons_cur = 0; state[i].pad.buttons_old = 0; for (int j = 0; j < joy->nbuttons; j++) { - SDL_PrivateJoystickButton(joy, j, SDL_RELEASED); + SDL_SendJoystickButton(timestamp, joy, j, false); } } } @@ -132,7 +134,7 @@ static void SWITCH_UpdateControllerSupport(bool handheld) /* Function to scan the system for joysticks. * It should return 0, or -1 on an unrecoverable fatal error. */ -static int SWITCH_JoystickInit(void) +static bool SWITCH_JoystickInit(void) { padConfigureInput(JOYSTICK_COUNT, HidNpadStyleSet_NpadStandard); @@ -172,7 +174,11 @@ static int SWITCH_JoystickInit(void) HidNpadIdType_No1 + i, state[i].pad_style); } - return JOYSTICK_COUNT; + for (int i = 0; i < JOYSTICK_COUNT; ++i) { + SDL_PrivateJoystickAdded(SWITCH_JoystickGetDeviceInstanceID(i)); + } + + return true; } static int SWITCH_JoystickGetCount(void) @@ -184,6 +190,12 @@ static void SWITCH_JoystickDetect(void) { } +static bool SWITCH_JoystickIsDevicePresent(Uint16 vendor_id, Uint16 product_id, Uint16 version, const char *name) +{ + // We don't override any other drivers + return false; +} + /* Function to get the device-dependent name of a joystick */ static const char *SWITCH_JoystickGetDeviceName(int device_index) { @@ -195,6 +207,11 @@ static const char *SWITCH_JoystickGetDevicePath(int index) return NULL; } +static int SWITCH_JoystickGetDeviceSteamVirtualGamepadSlot(int device_index) +{ + return -1; +} + static int SWITCH_JoystickGetDevicePlayerIndex(int device_index) { return -1; @@ -204,70 +221,62 @@ static void SWITCH_JoystickSetDevicePlayerIndex(int device_index, int player_ind { } -static SDL_JoystickGUID SWITCH_JoystickGetDeviceGUID(int device_index) +static SDL_GUID SWITCH_JoystickGetDeviceGUID(int device_index) { /* the GUID is just the name for now */ const char *name = SWITCH_JoystickGetDeviceName(device_index); return SDL_CreateJoystickGUIDForName(name); } -/* Function to perform the mapping from device index to the instance id for this index */ -static SDL_JoystickID SWITCH_JoystickGetDeviceInstanceID(int device_index) -{ - return device_index; -} - /* Function to open a joystick for use. The joystick to open is specified by the device index. This should fill the nbuttons and naxes fields of the joystick structure. It returns 0, or -1 if there is an error. */ -static int SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) +static bool SWITCH_JoystickOpen(SDL_Joystick *joystick, int device_index) { joystick->nbuttons = sizeof(pad_mapping_default) / sizeof(*pad_mapping_default); joystick->naxes = 4; joystick->nhats = 0; - joystick->instance_id = device_index; + joystick->instance_id = SWITCH_JoystickGetDeviceInstanceID(device_index); - return 0; + SDL_SetBooleanProperty(SDL_GetJoystickProperties(joystick), SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, true); + + return true; } -static int SWITCH_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) +static bool SWITCH_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) { - int id = joystick->instance_id; + int index = joystick->instance_id - 1; - state[id].vibrationValues.amp_low = - state[id].vibrationValues.amp_high = low_frequency_rumble == 0 ? 0.0f : 320.0f; - state[id].vibrationValues.freq_low = + state[index].vibrationValues.amp_low = + state[index].vibrationValues.amp_high = low_frequency_rumble == 0 ? 0.0f : 320.0f; + state[index].vibrationValues.freq_low = low_frequency_rumble == 0 ? 160.0f : (float)low_frequency_rumble / 204; - state[id].vibrationValues.freq_high = + state[index].vibrationValues.freq_high = high_frequency_rumble == 0 ? 320.0f : (float)high_frequency_rumble / 204; - hidSendVibrationValues(&state[id].vibrationDeviceHandles, &state[id].vibrationValues, 1); + hidSendVibrationValues(&state[index].vibrationDeviceHandles, &state[index].vibrationValues, 1); - return 0; + return true; } -static int SWITCH_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right) +static bool SWITCH_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left, Uint16 right) { return SDL_Unsupported(); } -static Uint32 SWITCH_JoystickGetCapabilities(SDL_Joystick *joystick) +static bool SWITCH_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) { return 0; } -static int SWITCH_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue) -{ - return 0; -} - -static int SWITCH_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) +static bool SWITCH_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size) { return SDL_Unsupported(); } -static int SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled) + +static bool SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, bool enabled) { return SDL_Unsupported(); } @@ -279,9 +288,12 @@ static int SWITCH_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool ena */ static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) { + Uint64 timestamp = SDL_GetTicksNS(); + u64 diff; - int index = (int)SDL_JoystickInstanceID(joystick); - if (index >= JOYSTICK_COUNT || SDL_IsTextInputActive()) { + int index = joystick->instance_id - 1; + + if (index >= JOYSTICK_COUNT || SDL_TextInputActive(SDL_GetKeyboardFocus())) { return; } @@ -294,7 +306,7 @@ static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) state[index].pad_type = hidGetNpadDeviceType((HidNpadIdType)index); state[index].pad_style = hidGetNpadStyleSet((HidNpadIdType)index); if (state[index].pad_type != state[index].pad_type_prev || state[index].pad_style != state[index].pad_style_prev) { - SWITCH_UpdateControllerSupport(padIsHandheld(&state[index].pad) ? true : false); + SWITCH_UpdateControllerSupport(timestamp, padIsHandheld(&state[index].pad) ? true : false); return; } @@ -302,21 +314,21 @@ static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) if (state[index].pad_style & HidNpadStyleTag_NpadJoyDual || (state[index].pad_type != HidDeviceTypeBits_JoyLeft && state[index].pad_type != HidDeviceTypeBits_JoyRight)) { // axis left if (state[index].sticks_old[0].x != state[index].pad.sticks[0].x) { - SDL_PrivateJoystickAxis(joystick, 0, (Sint16)state[index].pad.sticks[0].x); + SDL_SendJoystickAxis(timestamp, joystick, 0, (Sint16)state[index].pad.sticks[0].x); state[index].sticks_old[0].x = state[index].pad.sticks[0].x; } if (state[index].sticks_old[0].y != state[index].pad.sticks[0].y) { - SDL_PrivateJoystickAxis(joystick, 1, (Sint16)-state[index].pad.sticks[0].y); + SDL_SendJoystickAxis(timestamp, joystick, 1, (Sint16)-state[index].pad.sticks[0].y); state[index].sticks_old[0].y = -state[index].pad.sticks[0].y; } state[index].sticks_old[0] = padGetStickPos(&state[index].pad, 0); // axis right if (state[index].sticks_old[1].x != state[index].pad.sticks[1].x) { - SDL_PrivateJoystickAxis(joystick, 2, (Sint16)state[index].pad.sticks[1].x); + SDL_SendJoystickAxis(timestamp, joystick, 2, (Sint16)state[index].pad.sticks[1].x); state[index].sticks_old[1].x = state[index].pad.sticks[1].x; } if (state[index].sticks_old[1].y != state[index].pad.sticks[1].y) { - SDL_PrivateJoystickAxis(joystick, 3, (Sint16)-state[index].pad.sticks[1].y); + SDL_SendJoystickAxis(timestamp, joystick, 3, (Sint16)-state[index].pad.sticks[1].y); state[index].sticks_old[1].y = -state[index].pad.sticks[1].y; } state[index].sticks_old[1] = padGetStickPos(&state[index].pad, 1); @@ -327,9 +339,10 @@ static void SWITCH_JoystickUpdate(SDL_Joystick *joystick) if (diff) { for (int i = 0; i < joystick->nbuttons; i++) { if (diff & state[index].pad_mapping[i]) { - SDL_PrivateJoystickButton( + SDL_SendJoystickButton( + timestamp, joystick, i, - state[index].pad.buttons_cur & state[index].pad_mapping[i] ? SDL_PRESSED : SDL_RELEASED); + (state[index].pad.buttons_cur & state[index].pad_mapping[i]) != 0); } } } @@ -343,39 +356,93 @@ static void SWITCH_JoystickClose(SDL_Joystick *joystick) /* Function to perform any system-specific joystick related cleanup */ static void SWITCH_JoystickQuit(void) { + for (int i = 0; i < JOYSTICK_COUNT; ++i) { + SDL_PrivateJoystickRemoved(SWITCH_JoystickGetDeviceInstanceID(i)); + } } -static SDL_bool SWITCH_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) +static bool SWITCH_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out) { - return SDL_FALSE; + // clang-format off + *out = (SDL_GamepadMapping){ +#if 0 + /* + * This is as they are physically. + */ + .a = {.kind = EMappingKind_Button, .target = 0}, + .b = {.kind = EMappingKind_Button, .target = 1}, + .x = {.kind = EMappingKind_Button, .target = 2}, + .y = {.kind = EMappingKind_Button, .target = 3}, +#else + /* + * This is as they are when swapped, i.e. what everything else expects. + * This also matches the behaviour of the old SDL2 port. + */ + .a = {.kind = EMappingKind_Button, .target = 1}, + .b = {.kind = EMappingKind_Button, .target = 0}, + .x = {.kind = EMappingKind_Button, .target = 3}, + .y = {.kind = EMappingKind_Button, .target = 2}, +#endif + .back = {.kind = EMappingKind_Button, .target = 11}, + .guide = {.kind = EMappingKind_None, .target = 255}, + .start = {.kind = EMappingKind_Button, .target = 10}, + .leftstick = {.kind = EMappingKind_Button, .target = 4}, + .rightstick = {.kind = EMappingKind_Button, .target = 5}, + .leftshoulder = {.kind = EMappingKind_Button, .target = 6}, + .rightshoulder = {.kind = EMappingKind_Button, .target = 7}, + .dpup = {.kind = EMappingKind_Button, .target = 13}, + .dpdown = {.kind = EMappingKind_Button, .target = 15}, + .dpleft = {.kind = EMappingKind_Button, .target = 12}, + .dpright = {.kind = EMappingKind_Button, .target = 14}, + .misc1 = {.kind = EMappingKind_None, .target = 255}, + .misc2 = {.kind = EMappingKind_None, .target = 255}, + .misc3 = {.kind = EMappingKind_None, .target = 255}, + .misc4 = {.kind = EMappingKind_None, .target = 255}, + .misc5 = {.kind = EMappingKind_None, .target = 255}, + .misc6 = {.kind = EMappingKind_None, .target = 255}, + .right_paddle1 = {.kind = EMappingKind_None, .target = 255}, + .left_paddle1 = {.kind = EMappingKind_None, .target = 255}, + .right_paddle2 = {.kind = EMappingKind_None, .target = 255}, + .left_paddle2 = {.kind = EMappingKind_None, .target = 255}, + .leftx = {.kind = EMappingKind_Axis, .target = 0}, + .lefty = {.kind = EMappingKind_Axis, .target = 1}, + .rightx = {.kind = EMappingKind_Axis, .target = 2}, + .righty = {.kind = EMappingKind_Axis, .target = 3}, + .lefttrigger = {.kind = EMappingKind_Button, .target = 8}, + .righttrigger = {.kind = EMappingKind_Button, .target = 9}, + .touchpad = {.kind = EMappingKind_None, .target = 255}, + }; + // clang-format on + return true; } SDL_JoystickDriver SDL_SWITCH_JoystickDriver = { - SWITCH_JoystickInit, - SWITCH_JoystickGetCount, - SWITCH_JoystickDetect, - SWITCH_JoystickGetDeviceName, - SWITCH_JoystickGetDevicePath, - SWITCH_JoystickGetDevicePlayerIndex, - SWITCH_JoystickSetDevicePlayerIndex, - SWITCH_JoystickGetDeviceGUID, - SWITCH_JoystickGetDeviceInstanceID, - - SWITCH_JoystickOpen, - - SWITCH_JoystickRumble, - SWITCH_JoystickRumbleTriggers, - SWITCH_JoystickGetCapabilities, - - SWITCH_JoystickSetLED, - SWITCH_JoystickSendEffect, - SWITCH_JoystickSetSensorsEnabled, - - SWITCH_JoystickUpdate, - SWITCH_JoystickClose, - SWITCH_JoystickQuit, - - SWITCH_JoystickGetGamepadMapping, + .Init = SWITCH_JoystickInit, + .GetCount = SWITCH_JoystickGetCount, + .Detect = SWITCH_JoystickDetect, + .IsDevicePresent = SWITCH_JoystickIsDevicePresent, + .GetDeviceName = SWITCH_JoystickGetDeviceName, + .GetDevicePath = SWITCH_JoystickGetDevicePath, + .GetDeviceSteamVirtualGamepadSlot = SWITCH_JoystickGetDeviceSteamVirtualGamepadSlot, + .GetDevicePlayerIndex = SWITCH_JoystickGetDevicePlayerIndex, + .SetDevicePlayerIndex = SWITCH_JoystickSetDevicePlayerIndex, + .GetDeviceGUID = SWITCH_JoystickGetDeviceGUID, + .GetDeviceInstanceID = SWITCH_JoystickGetDeviceInstanceID, + + .Open = SWITCH_JoystickOpen, + + .Rumble = SWITCH_JoystickRumble, + .RumbleTriggers = SWITCH_JoystickRumbleTriggers, + + .SetLED = SWITCH_JoystickSetLED, + .SendEffect = SWITCH_JoystickSendEffect, + .SetSensorsEnabled = SWITCH_JoystickSetSensorsEnabled, + + .Update = SWITCH_JoystickUpdate, + .Close = SWITCH_JoystickClose, + .Quit = SWITCH_JoystickQuit, + + .GetGamepadMapping = SWITCH_JoystickGetGamepadMapping, }; #endif /* SDL_JOYSTICK_SWITCH */ From 71dc19b8f48be02130d3a98888e90ce172da5f02 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:45:01 +0900 Subject: [PATCH 08/16] power: seed switch implementation --- src/power/switch/SDL_syspower.c | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 src/power/switch/SDL_syspower.c diff --git a/src/power/switch/SDL_syspower.c b/src/power/switch/SDL_syspower.c new file mode 100644 index 0000000000000..86ae7875c01d7 --- /dev/null +++ b/src/power/switch/SDL_syspower.c @@ -0,0 +1,68 @@ +/* + 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_POWER_DISABLED +#if SDL_POWER_SWITCH + +#include +#include "SDL_power.h" + +SDL_bool +SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, + int *percent) { + PsmChargerType chargerType; + u32 charge; + //double age; + Result rc; + + rc = psmGetChargerType(&chargerType); + if (R_FAILED(rc)) { + *state = SDL_POWERSTATE_UNKNOWN; + *seconds = -1; + *percent = -1; + return SDL_FALSE; + } + + psmGetBatteryChargePercentage(&charge); + *percent = (int) charge; + + // TODO: use approximation for now, ~6h00 for a fully charged battery + *seconds = ((int) charge * 21600) / 100; + //psmGetBatteryAgePercentage(&age); + //*seconds = (int) age; + + if (chargerType == PsmChargerType_Unconnected) { + *state = SDL_POWERSTATE_ON_BATTERY; + } else if (chargerType == PsmChargerType_EnoughPower) { + *state = SDL_POWERSTATE_CHARGED; + } else { + *state = SDL_POWERSTATE_CHARGING; + } + + return SDL_TRUE; +} + +#endif /* SDL_POWER_SWITCH */ +#endif /* SDL_POWER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ From 6914a5c06c4efeaae2aa0c2cec19a2b0653bb247 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:47:19 +0900 Subject: [PATCH 09/16] power/switch: cosmetics --- src/power/switch/SDL_syspower.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/power/switch/SDL_syspower.c b/src/power/switch/SDL_syspower.c index 86ae7875c01d7..0521fe3b03183 100644 --- a/src/power/switch/SDL_syspower.c +++ b/src/power/switch/SDL_syspower.c @@ -24,15 +24,14 @@ #ifndef SDL_POWER_DISABLED #if SDL_POWER_SWITCH -#include #include "SDL_power.h" +#include -SDL_bool -SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, - int *percent) { +SDL_bool SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, int *percent) +{ PsmChargerType chargerType; u32 charge; - //double age; + // double age; Result rc; rc = psmGetChargerType(&chargerType); @@ -44,11 +43,11 @@ SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, } psmGetBatteryChargePercentage(&charge); - *percent = (int) charge; + *percent = (int)charge; // TODO: use approximation for now, ~6h00 for a fully charged battery - *seconds = ((int) charge * 21600) / 100; - //psmGetBatteryAgePercentage(&age); + *seconds = ((int)charge * 21600) / 100; + // psmGetBatteryAgePercentage(&age); //*seconds = (int) age; if (chargerType == PsmChargerType_Unconnected) { From c4f3dc7e20c3d7ee354efa5daca0d554085a7087 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:45:19 +0900 Subject: [PATCH 10/16] power/switch: port implementation --- CMakeLists.txt | 6 ++++++ include/build_config/SDL_build_config.h.cmake | 1 + src/power/SDL_power.c | 3 +++ src/power/SDL_syspower.h | 1 + src/power/switch/SDL_syspower.c | 15 ++++++--------- 5 files changed, 17 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b6254dc7047a..b67dfd19a43b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2943,6 +2943,12 @@ elseif(NINTENDO_SWITCH) sdl_compile_options(PRIVATE -DSDL_VIDEO_STATIC_ANGLE) endif() + if(SDL_POWER) + set(SDL_POWER_SWITCH 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/switch/*.c") + set(HAVE_SDL_POWER TRUE) + endif() + if(SDL_JOYSTICK) set(SDL_JOYSTICK_SWITCH 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/switch/*.c") diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 19fa34dbab57e..e92223ff5e440 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -451,6 +451,7 @@ #cmakedefine SDL_POWER_VITA 1 #cmakedefine SDL_POWER_PSP 1 #cmakedefine SDL_POWER_N3DS 1 +#cmakedefine SDL_POWER_SWITCH 1 /* Enable system filesystem support */ #cmakedefine SDL_FILESYSTEM_ANDROID 1 diff --git a/src/power/SDL_power.c b/src/power/SDL_power.c index 5dde3b145dbe4..f9ade4336f46b 100644 --- a/src/power/SDL_power.c +++ b/src/power/SDL_power.c @@ -71,6 +71,9 @@ static SDL_GetPowerInfo_Impl implementations[] = { #ifdef SDL_POWER_N3DS // handles N3DS. SDL_GetPowerInfo_N3DS, #endif +#ifdef SDL_POWER_SWITCH // handles N3DS. + SDL_GetPowerInfo_SWITCH, +#endif #ifdef SDL_POWER_EMSCRIPTEN // handles Emscripten SDL_GetPowerInfo_Emscripten, #endif diff --git a/src/power/SDL_syspower.h b/src/power/SDL_syspower.h index 5f8fa533e6a04..4bd0700b84aad 100644 --- a/src/power/SDL_syspower.h +++ b/src/power/SDL_syspower.h @@ -38,6 +38,7 @@ bool SDL_GetPowerInfo_Android(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_PSP(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_VITA(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_N3DS(SDL_PowerState *, int *, int *); +bool SDL_GetPowerInfo_SWITCH(SDL_PowerState *, int *, int *); bool SDL_GetPowerInfo_Emscripten(SDL_PowerState *, int *, int *); // this one is static in SDL_power.c diff --git a/src/power/switch/SDL_syspower.c b/src/power/switch/SDL_syspower.c index 0521fe3b03183..af182cb4cb30a 100644 --- a/src/power/switch/SDL_syspower.c +++ b/src/power/switch/SDL_syspower.c @@ -19,15 +19,13 @@ 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" +#include "SDL_internal.h" -#ifndef SDL_POWER_DISABLED -#if SDL_POWER_SWITCH +#if !defined(SDL_POWER_DISABLED) && defined(SDL_POWER_SWITCH) -#include "SDL_power.h" #include -SDL_bool SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, int *percent) +bool SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, int *percent) { PsmChargerType chargerType; u32 charge; @@ -39,7 +37,7 @@ SDL_bool SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, int *perce *state = SDL_POWERSTATE_UNKNOWN; *seconds = -1; *percent = -1; - return SDL_FALSE; + return false; } psmGetBatteryChargePercentage(&charge); @@ -58,10 +56,9 @@ SDL_bool SDL_GetPowerInfo_SWITCH(SDL_PowerState *state, int *seconds, int *perce *state = SDL_POWERSTATE_CHARGING; } - return SDL_TRUE; + return true; } -#endif /* SDL_POWER_SWITCH */ -#endif /* SDL_POWER_DISABLED */ +#endif /* vi: set ts=4 sw=4 expandtab: */ From 1dbc2cb31f94e00cf60aa8097dd3ad8472008e67 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:46:39 +0900 Subject: [PATCH 11/16] filesystem: seed switch implementation --- src/filesystem/switch/SDL_sysfilesystem.c | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/filesystem/switch/SDL_sysfilesystem.c diff --git a/src/filesystem/switch/SDL_sysfilesystem.c b/src/filesystem/switch/SDL_sysfilesystem.c new file mode 100644 index 0000000000000..6053c6f43207b --- /dev/null +++ b/src/filesystem/switch/SDL_sysfilesystem.c @@ -0,0 +1,67 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2020 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" + +#ifdef SDL_FILESYSTEM_SWITCH + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* System dependent filesystem routines */ + +#include +#include +#include + +#include "SDL_error.h" +#include "SDL_stdinc.h" +#include "SDL_filesystem.h" + +char * +SDL_GetBasePath(void) +{ + const char *basepath = "romfs:/"; + char *retval = SDL_strdup(basepath); + return retval; +} + +char * +SDL_GetPrefPath(const char *org, const char *app) +{ + char *ret = NULL; + char buf[PATH_MAX]; + size_t len; + + if (getcwd(buf, PATH_MAX)) { + len = strlen(buf) + 2; + ret = (char *) SDL_malloc(len); + if (!ret) { + SDL_OutOfMemory(); + return NULL; + } + SDL_snprintf(ret, len, "%s/", buf); + return ret; + } + + return NULL; +} + +#endif /* SDL_FILESYSTEM_SWITCH */ + +/* vi: set ts=4 sw=4 expandtab: */ From 647675aed655905a66d26fb6756ecd3c623cd983 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:48:27 +0900 Subject: [PATCH 12/16] filesystem/switch: cosmetics --- src/filesystem/switch/SDL_sysfilesystem.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/filesystem/switch/SDL_sysfilesystem.c b/src/filesystem/switch/SDL_sysfilesystem.c index 6053c6f43207b..594d0aa030ad1 100644 --- a/src/filesystem/switch/SDL_sysfilesystem.c +++ b/src/filesystem/switch/SDL_sysfilesystem.c @@ -25,24 +25,22 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* System dependent filesystem routines */ -#include #include +#include #include #include "SDL_error.h" -#include "SDL_stdinc.h" #include "SDL_filesystem.h" +#include "SDL_stdinc.h" -char * -SDL_GetBasePath(void) +char *SDL_GetBasePath(void) { const char *basepath = "romfs:/"; char *retval = SDL_strdup(basepath); return retval; } -char * -SDL_GetPrefPath(const char *org, const char *app) +char *SDL_GetPrefPath(const char *org, const char *app) { char *ret = NULL; char buf[PATH_MAX]; @@ -50,7 +48,7 @@ SDL_GetPrefPath(const char *org, const char *app) if (getcwd(buf, PATH_MAX)) { len = strlen(buf) + 2; - ret = (char *) SDL_malloc(len); + ret = (char *)SDL_malloc(len); if (!ret) { SDL_OutOfMemory(); return NULL; From 7472a59b95ccc6134b8b087a102b254ac41b4601 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 00:54:36 +0900 Subject: [PATCH 13/16] filesystem/switch: port implementation --- CMakeLists.txt | 4 ++++ include/build_config/SDL_build_config.h.cmake | 1 + src/filesystem/switch/SDL_sysfilesystem.c | 22 +++++++++---------- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b67dfd19a43b6..866683fe89e18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2943,6 +2943,10 @@ elseif(NINTENDO_SWITCH) sdl_compile_options(PRIVATE -DSDL_VIDEO_STATIC_ANGLE) endif() + set(SDL_FILESYSTEM_SWITCH 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/switch/*.c") + set(HAVE_SDL_FILESYSTEM TRUE) + if(SDL_POWER) set(SDL_POWER_SWITCH 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/power/switch/*.c") diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index e92223ff5e440..9bd604d6f46d9 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -466,6 +466,7 @@ #cmakedefine SDL_FILESYSTEM_PSP 1 #cmakedefine SDL_FILESYSTEM_PS2 1 #cmakedefine SDL_FILESYSTEM_N3DS 1 +#cmakedefine SDL_FILESYSTEM_SWITCH 1 /* Enable system storage support */ #cmakedefine SDL_STORAGE_STEAM @SDL_STORAGE_STEAM@ diff --git a/src/filesystem/switch/SDL_sysfilesystem.c b/src/filesystem/switch/SDL_sysfilesystem.c index 594d0aa030ad1..7b65bf7e6aa1b 100644 --- a/src/filesystem/switch/SDL_sysfilesystem.c +++ b/src/filesystem/switch/SDL_sysfilesystem.c @@ -18,29 +18,23 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" +#include "SDL_internal.h" #ifdef SDL_FILESYSTEM_SWITCH /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* System dependent filesystem routines */ -#include #include #include -#include "SDL_error.h" -#include "SDL_filesystem.h" -#include "SDL_stdinc.h" - -char *SDL_GetBasePath(void) +char *SDL_SYS_GetBasePath(void) { - const char *basepath = "romfs:/"; - char *retval = SDL_strdup(basepath); - return retval; + char *base_path = SDL_strdup("romfs:/"); + return base_path; } -char *SDL_GetPrefPath(const char *org, const char *app) +char *SDL_SYS_GetPrefPath(const char *org, const char *app) { char *ret = NULL; char buf[PATH_MAX]; @@ -60,6 +54,12 @@ char *SDL_GetPrefPath(const char *org, const char *app) return NULL; } +char *SDL_SYS_GetUserFolder(SDL_Folder folder) +{ + SDL_Unsupported(); + return NULL; +} + #endif /* SDL_FILESYSTEM_SWITCH */ /* vi: set ts=4 sw=4 expandtab: */ From 14d5a840df7c31e91c5b95c55c282c5bf54e0fbb Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 02:31:41 +0900 Subject: [PATCH 14/16] audio: seed switch implementation --- src/audio/switch/SDL_switchaudio.c | 227 +++++++++++++++++++++++++++++ src/audio/switch/SDL_switchaudio.h | 41 ++++++ 2 files changed, 268 insertions(+) create mode 100644 src/audio/switch/SDL_switchaudio.c create mode 100644 src/audio/switch/SDL_switchaudio.h diff --git a/src/audio/switch/SDL_switchaudio.c b/src/audio/switch/SDL_switchaudio.c new file mode 100644 index 0000000000000..33710b5aa4b56 --- /dev/null +++ b/src/audio/switch/SDL_switchaudio.c @@ -0,0 +1,227 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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" + +#if SDL_AUDIO_DRIVER_SWITCH + +#include +#include +#include +#include + +#include "SDL_audio.h" +#include "../SDL_audio_c.h" +#include "../SDL_audiodev_c.h" + +#include "SDL_switchaudio.h" + +static const AudioRendererConfig arConfig = + { + .output_rate = AudioRendererOutputRate_48kHz, + .num_voices = 24, + .num_effects = 0, + .num_sinks = 1, + .num_mix_objs = 1, + .num_mix_buffers = 2, + }; + +static int +SWITCHAUDIO_OpenDevice(_THIS, const char *devname) +{ + static const u8 sink_channels[] = {0, 1}; + SDL_bool supported_format = SDL_FALSE; + SDL_AudioFormat test_format; + Result res; + u32 size; + int mpid; + + this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); + if (this->hidden == NULL) { + return SDL_OutOfMemory(); + } + SDL_zerop(this->hidden); + + res = audrenInitialize(&arConfig); + if (R_FAILED(res)) { + return SDL_SetError("audrenInitialize failed (0x%x)", res); + } + this->hidden->audr_device = true; + + res = audrvCreate(&this->hidden->driver, &arConfig, 2); + if (R_FAILED(res)) { + return SDL_SetError("audrvCreate failed (0x%x)", res); + } + this->hidden->audr_driver = true; + + test_format = SDL_FirstAudioFormat(this->spec.format); + while ((!supported_format) && (test_format)) { + if (test_format == AUDIO_S16SYS) { + supported_format = SDL_TRUE; + } + else { + test_format = SDL_NextAudioFormat(); + } + } + if (!supported_format) { + return SDL_SetError("Unsupported audio format"); + } + + this->spec.format = test_format; + SDL_CalculateAudioSpec(&this->spec); + + size = (u32) ((this->spec.size * 2) + 0xfff) & ~0xfff; + this->hidden->pool = memalign(0x1000, size); + for (int i = 0; i < 2; i++) { + this->hidden->buffer[i].data_raw = this->hidden->pool; + this->hidden->buffer[i].size = this->spec.size * 2; + this->hidden->buffer[i].start_sample_offset = i * this->spec.samples; + this->hidden->buffer[i].end_sample_offset = this->hidden->buffer[i].start_sample_offset + this->spec.samples; + this->hidden->buffer_tmp = malloc(this->spec.size); + } + + mpid = audrvMemPoolAdd(&this->hidden->driver, this->hidden->pool, size); + audrvMemPoolAttach(&this->hidden->driver, mpid); + + audrvDeviceSinkAdd(&this->hidden->driver, AUDREN_DEFAULT_DEVICE_NAME, 2, sink_channels); + + res = audrenStartAudioRenderer(); + if (R_FAILED(res)) { + return SDL_SetError("audrenStartAudioRenderer failed (0x%x)", res); + } + + audrvVoiceInit(&this->hidden->driver, 0, this->spec.channels, PcmFormat_Int16, this->spec.freq); + audrvVoiceSetDestinationMix(&this->hidden->driver, 0, AUDREN_FINAL_MIX_ID); + if (this->spec.channels == 1) { + audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0); + audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 1); + } + else { + audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0); + audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 0, 1); + audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 1, 0); + audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 1, 1); + } + + audrvVoiceStart(&this->hidden->driver, 0); + + return 0; +} + +static void +SWITCHAUDIO_PlayDevice(_THIS) +{ + int current = -1; + for (int i = 0; i < 2; i++) { + if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Free + || this->hidden->buffer[i].state == AudioDriverWaveBufState_Done) { + current = i; + break; + } + } + + if (current >= 0) { + Uint8 *ptr = (Uint8 *) (this->hidden->pool + (current * this->spec.size)); + memcpy(ptr, this->hidden->buffer_tmp, this->spec.size); + armDCacheFlush(ptr, this->spec.size); + audrvVoiceAddWaveBuf(&this->hidden->driver, 0, &this->hidden->buffer[current]); + } + else if (!audrvVoiceIsPlaying(&this->hidden->driver, 0)) { + audrvVoiceStart(&this->hidden->driver, 0); + } + + audrvUpdate(&this->hidden->driver); + + if (current >= 0) { + while (this->hidden->buffer[current].state != AudioDriverWaveBufState_Playing) { + audrvUpdate(&this->hidden->driver); + audrenWaitFrame(); + } + } + else { + current = -1; + for (int i = 0; i < 2; i++) { + if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Playing) { + current = i; + break; + } + } + while (this->hidden->buffer[current].state == AudioDriverWaveBufState_Playing) { + audrvUpdate(&this->hidden->driver); + audrenWaitFrame(); + } + } +} + +static void +SWITCHAUDIO_WaitDevice(_THIS) +{ +} + +static Uint8 +*SWITCHAUDIO_GetDeviceBuf(_THIS) +{ + return this->hidden->buffer_tmp; +} + +static void +SWITCHAUDIO_CloseDevice(_THIS) +{ + if (this->hidden->audr_driver) { + audrvClose(&this->hidden->driver); + } + + if (this->hidden->audr_device) { + audrenExit(); + } + + if (this->hidden->buffer_tmp) { + free(this->hidden->buffer_tmp); + } + + SDL_free(this->hidden); +} + +static void +SWITCHAUDIO_ThreadInit(_THIS) +{ + +} + +static SDL_bool +SWITCHAUDIO_Init(SDL_AudioDriverImpl *impl) +{ + impl->OpenDevice = SWITCHAUDIO_OpenDevice; + impl->PlayDevice = SWITCHAUDIO_PlayDevice; + impl->WaitDevice = SWITCHAUDIO_WaitDevice; + impl->GetDeviceBuf = SWITCHAUDIO_GetDeviceBuf; + impl->CloseDevice = SWITCHAUDIO_CloseDevice; + impl->ThreadInit = SWITCHAUDIO_ThreadInit; + + impl->OnlyHasDefaultOutputDevice = 1; + + return 1; +} + +AudioBootStrap SWITCHAUDIO_bootstrap = { + "switch", "Nintendo Switch audio driver", SWITCHAUDIO_Init, 0 +}; + +#endif /* SDL_AUDIO_DRIVER_SWITCH */ diff --git a/src/audio/switch/SDL_switchaudio.h b/src/audio/switch/SDL_switchaudio.h new file mode 100644 index 0000000000000..f5e0340fb4ada --- /dev/null +++ b/src/audio/switch/SDL_switchaudio.h @@ -0,0 +1,41 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2018 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. +*/ + +#ifndef SDL_switchaudio_h_ +#define SDL_switchaudio_h_ + +#include +#include "../SDL_sysaudio.h" + +/* Hidden "this" pointer for the audio functions */ +#define _THIS SDL_AudioDevice *this + +struct SDL_PrivateAudioData +{ + AudioDriver driver; + AudioDriverWaveBuf buffer[2]; + void *buffer_tmp; + void *pool; + bool audr_device; + bool audr_driver; +}; + +#endif /* SDL_switchaudio_h_ */ From e9c5d0907383b59cd4f5b56969d5b4e0feecacca Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 02:32:48 +0900 Subject: [PATCH 15/16] audio/switch: cosmetics --- src/audio/switch/SDL_switchaudio.c | 70 ++++++++++++------------------ src/audio/switch/SDL_switchaudio.h | 4 +- 2 files changed, 30 insertions(+), 44 deletions(-) diff --git a/src/audio/switch/SDL_switchaudio.c b/src/audio/switch/SDL_switchaudio.c index 33710b5aa4b56..17bfa6b332948 100644 --- a/src/audio/switch/SDL_switchaudio.c +++ b/src/audio/switch/SDL_switchaudio.c @@ -22,38 +22,36 @@ #if SDL_AUDIO_DRIVER_SWITCH +#include #include -#include #include -#include +#include -#include "SDL_audio.h" #include "../SDL_audio_c.h" #include "../SDL_audiodev_c.h" +#include "SDL_audio.h" #include "SDL_switchaudio.h" -static const AudioRendererConfig arConfig = - { - .output_rate = AudioRendererOutputRate_48kHz, - .num_voices = 24, - .num_effects = 0, - .num_sinks = 1, - .num_mix_objs = 1, - .num_mix_buffers = 2, - }; - -static int -SWITCHAUDIO_OpenDevice(_THIS, const char *devname) +static const AudioRendererConfig arConfig = { + .output_rate = AudioRendererOutputRate_48kHz, + .num_voices = 24, + .num_effects = 0, + .num_sinks = 1, + .num_mix_objs = 1, + .num_mix_buffers = 2, +}; + +static int SWITCHAUDIO_OpenDevice(_THIS, const char *devname) { - static const u8 sink_channels[] = {0, 1}; + static const u8 sink_channels[] = { 0, 1 }; SDL_bool supported_format = SDL_FALSE; SDL_AudioFormat test_format; Result res; u32 size; int mpid; - this->hidden = (struct SDL_PrivateAudioData *) SDL_malloc(sizeof(*this->hidden)); + this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*this->hidden)); if (this->hidden == NULL) { return SDL_OutOfMemory(); } @@ -75,8 +73,7 @@ SWITCHAUDIO_OpenDevice(_THIS, const char *devname) while ((!supported_format) && (test_format)) { if (test_format == AUDIO_S16SYS) { supported_format = SDL_TRUE; - } - else { + } else { test_format = SDL_NextAudioFormat(); } } @@ -87,7 +84,7 @@ SWITCHAUDIO_OpenDevice(_THIS, const char *devname) this->spec.format = test_format; SDL_CalculateAudioSpec(&this->spec); - size = (u32) ((this->spec.size * 2) + 0xfff) & ~0xfff; + size = (u32)((this->spec.size * 2) + 0xfff) & ~0xfff; this->hidden->pool = memalign(0x1000, size); for (int i = 0; i < 2; i++) { this->hidden->buffer[i].data_raw = this->hidden->pool; @@ -112,8 +109,7 @@ SWITCHAUDIO_OpenDevice(_THIS, const char *devname) if (this->spec.channels == 1) { audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0); audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 1); - } - else { + } else { audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0); audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 0, 1); audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 1, 0); @@ -125,25 +121,22 @@ SWITCHAUDIO_OpenDevice(_THIS, const char *devname) return 0; } -static void -SWITCHAUDIO_PlayDevice(_THIS) +static void SWITCHAUDIO_PlayDevice(_THIS) { int current = -1; for (int i = 0; i < 2; i++) { - if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Free - || this->hidden->buffer[i].state == AudioDriverWaveBufState_Done) { + if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Free || this->hidden->buffer[i].state == AudioDriverWaveBufState_Done) { current = i; break; } } if (current >= 0) { - Uint8 *ptr = (Uint8 *) (this->hidden->pool + (current * this->spec.size)); + Uint8 *ptr = (Uint8 *)(this->hidden->pool + (current * this->spec.size)); memcpy(ptr, this->hidden->buffer_tmp, this->spec.size); armDCacheFlush(ptr, this->spec.size); audrvVoiceAddWaveBuf(&this->hidden->driver, 0, &this->hidden->buffer[current]); - } - else if (!audrvVoiceIsPlaying(&this->hidden->driver, 0)) { + } else if (!audrvVoiceIsPlaying(&this->hidden->driver, 0)) { audrvVoiceStart(&this->hidden->driver, 0); } @@ -154,8 +147,7 @@ SWITCHAUDIO_PlayDevice(_THIS) audrvUpdate(&this->hidden->driver); audrenWaitFrame(); } - } - else { + } else { current = -1; for (int i = 0; i < 2; i++) { if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Playing) { @@ -170,19 +162,16 @@ SWITCHAUDIO_PlayDevice(_THIS) } } -static void -SWITCHAUDIO_WaitDevice(_THIS) +static void SWITCHAUDIO_WaitDevice(_THIS) { } -static Uint8 -*SWITCHAUDIO_GetDeviceBuf(_THIS) +static Uint8 *SWITCHAUDIO_GetDeviceBuf(_THIS) { return this->hidden->buffer_tmp; } -static void -SWITCHAUDIO_CloseDevice(_THIS) +static void SWITCHAUDIO_CloseDevice(_THIS) { if (this->hidden->audr_driver) { audrvClose(&this->hidden->driver); @@ -199,14 +188,11 @@ SWITCHAUDIO_CloseDevice(_THIS) SDL_free(this->hidden); } -static void -SWITCHAUDIO_ThreadInit(_THIS) +static void SWITCHAUDIO_ThreadInit(_THIS) { - } -static SDL_bool -SWITCHAUDIO_Init(SDL_AudioDriverImpl *impl) +static SDL_bool SWITCHAUDIO_Init(SDL_AudioDriverImpl *impl) { impl->OpenDevice = SWITCHAUDIO_OpenDevice; impl->PlayDevice = SWITCHAUDIO_PlayDevice; diff --git a/src/audio/switch/SDL_switchaudio.h b/src/audio/switch/SDL_switchaudio.h index f5e0340fb4ada..6fcea71de04ac 100644 --- a/src/audio/switch/SDL_switchaudio.h +++ b/src/audio/switch/SDL_switchaudio.h @@ -22,11 +22,11 @@ #ifndef SDL_switchaudio_h_ #define SDL_switchaudio_h_ -#include #include "../SDL_sysaudio.h" +#include /* Hidden "this" pointer for the audio functions */ -#define _THIS SDL_AudioDevice *this +#define _THIS SDL_AudioDevice *this struct SDL_PrivateAudioData { From 553a97cd95256c7f288a12dc24a9306dc9930696 Mon Sep 17 00:00:00 2001 From: Zane van Iperen Date: Sun, 18 May 2025 03:42:54 +0900 Subject: [PATCH 16/16] audio/switch: port implementation --- CMakeLists.txt | 6 + include/build_config/SDL_build_config.h.cmake | 1 + src/audio/SDL_audio.c | 3 + src/audio/SDL_sysaudio.h | 1 + src/audio/switch/SDL_switchaudio.c | 174 +++++++++--------- src/audio/switch/SDL_switchaudio.h | 4 +- 6 files changed, 104 insertions(+), 85 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 866683fe89e18..c8c2e56ba04e3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2943,6 +2943,12 @@ elseif(NINTENDO_SWITCH) sdl_compile_options(PRIVATE -DSDL_VIDEO_STATIC_ANGLE) endif() + if(SDL_AUDIO) + set(SDL_AUDIO_DRIVER_SWITCH 1) + sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/switch/*.c") + set(HAVE_SDL_AUDIO TRUE) + endif() + set(SDL_FILESYSTEM_SWITCH 1) sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/switch/*.c") set(HAVE_SDL_FILESYSTEM TRUE) diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake index 9bd604d6f46d9..84f1c39b77673 100644 --- a/include/build_config/SDL_build_config.h.cmake +++ b/include/build_config/SDL_build_config.h.cmake @@ -272,6 +272,7 @@ #cmakedefine SDL_AUDIO_DRIVER_PSP 1 #cmakedefine SDL_AUDIO_DRIVER_PS2 1 #cmakedefine SDL_AUDIO_DRIVER_N3DS 1 +#cmakedefine SDL_AUDIO_DRIVER_SWITCH 1 #cmakedefine SDL_AUDIO_DRIVER_QNX 1 /* Enable various input drivers */ diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 5ddf97876c877..3819ddf2a6b7d 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -77,6 +77,9 @@ static const AudioBootStrap *const bootstrap[] = { #ifdef SDL_AUDIO_DRIVER_N3DS &N3DSAUDIO_bootstrap, #endif +#ifdef SDL_AUDIO_DRIVER_SWITCH + &SWITCHAUDIO_bootstrap, +#endif #ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN &EMSCRIPTENAUDIO_bootstrap, #endif diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 4a88bd2302410..e1b6be8da66f6 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -386,6 +386,7 @@ extern AudioBootStrap PS2AUDIO_bootstrap; extern AudioBootStrap PSPAUDIO_bootstrap; extern AudioBootStrap VITAAUD_bootstrap; extern AudioBootStrap N3DSAUDIO_bootstrap; +extern AudioBootStrap SWITCHAUDIO_bootstrap; extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap; extern AudioBootStrap QSAAUDIO_bootstrap; diff --git a/src/audio/switch/SDL_switchaudio.c b/src/audio/switch/SDL_switchaudio.c index 17bfa6b332948..83c0d7c385195 100644 --- a/src/audio/switch/SDL_switchaudio.c +++ b/src/audio/switch/SDL_switchaudio.c @@ -18,196 +18,206 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ -#include "../../SDL_internal.h" +#include "SDL_internal.h" #if SDL_AUDIO_DRIVER_SWITCH #include -#include -#include #include -#include "../SDL_audio_c.h" -#include "../SDL_audiodev_c.h" -#include "SDL_audio.h" - #include "SDL_switchaudio.h" +// clang-format off static const AudioRendererConfig arConfig = { - .output_rate = AudioRendererOutputRate_48kHz, - .num_voices = 24, - .num_effects = 0, - .num_sinks = 1, - .num_mix_objs = 1, + .output_rate = AudioRendererOutputRate_48kHz, + .num_voices = 24, + .num_effects = 0, + .num_sinks = 1, + .num_mix_objs = 1, .num_mix_buffers = 2, }; +// clang-format on -static int SWITCHAUDIO_OpenDevice(_THIS, const char *devname) +static bool SWITCHAUDIO_OpenDevice(SDL_AudioDevice *device) { static const u8 sink_channels[] = { 0, 1 }; - SDL_bool supported_format = SDL_FALSE; + bool supported_format = false; SDL_AudioFormat test_format; Result res; u32 size; int mpid; + const SDL_AudioFormat *closefmts; - this->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*this->hidden)); - if (this->hidden == NULL) { + device->hidden = (struct SDL_PrivateAudioData *)SDL_malloc(sizeof(*device->hidden)); + if (device->hidden == NULL) { return SDL_OutOfMemory(); } - SDL_zerop(this->hidden); + SDL_zerop(device->hidden); res = audrenInitialize(&arConfig); if (R_FAILED(res)) { return SDL_SetError("audrenInitialize failed (0x%x)", res); } - this->hidden->audr_device = true; + device->hidden->audr_device = true; - res = audrvCreate(&this->hidden->driver, &arConfig, 2); + res = audrvCreate(&device->hidden->driver, &arConfig, 2); if (R_FAILED(res)) { return SDL_SetError("audrvCreate failed (0x%x)", res); } - this->hidden->audr_driver = true; - - test_format = SDL_FirstAudioFormat(this->spec.format); - while ((!supported_format) && (test_format)) { - if (test_format == AUDIO_S16SYS) { - supported_format = SDL_TRUE; - } else { - test_format = SDL_NextAudioFormat(); + device->hidden->audr_driver = true; + + closefmts = SDL_ClosestAudioFormats(device->spec.format); + while ((test_format = *(closefmts++)) != 0) { + if (test_format == SDL_AUDIO_S16) { + supported_format = true; + break; } } + if (!supported_format) { return SDL_SetError("Unsupported audio format"); } - this->spec.format = test_format; - SDL_CalculateAudioSpec(&this->spec); + device->spec.format = test_format; + + SDL_UpdatedAudioDeviceFormat(device); + + if (device->buffer_size >= SDL_MAX_UINT32 / 2) { + return SDL_SetError("Mixing buffer is too large."); + } - size = (u32)((this->spec.size * 2) + 0xfff) & ~0xfff; - this->hidden->pool = memalign(0x1000, size); + size = (u32)((device->buffer_size * 2) + 0xfff) & ~0xfff; + device->hidden->pool = memalign(0x1000, size); for (int i = 0; i < 2; i++) { - this->hidden->buffer[i].data_raw = this->hidden->pool; - this->hidden->buffer[i].size = this->spec.size * 2; - this->hidden->buffer[i].start_sample_offset = i * this->spec.samples; - this->hidden->buffer[i].end_sample_offset = this->hidden->buffer[i].start_sample_offset + this->spec.samples; - this->hidden->buffer_tmp = malloc(this->spec.size); + device->hidden->buffer[i].data_raw = device->hidden->pool; + device->hidden->buffer[i].size = device->buffer_size * 2; + device->hidden->buffer[i].start_sample_offset = i * device->sample_frames; + device->hidden->buffer[i].end_sample_offset = device->hidden->buffer[i].start_sample_offset + device->sample_frames; + device->hidden->buffer_tmp = SDL_malloc(device->buffer_size); } - mpid = audrvMemPoolAdd(&this->hidden->driver, this->hidden->pool, size); - audrvMemPoolAttach(&this->hidden->driver, mpid); + mpid = audrvMemPoolAdd(&device->hidden->driver, device->hidden->pool, size); + audrvMemPoolAttach(&device->hidden->driver, mpid); - audrvDeviceSinkAdd(&this->hidden->driver, AUDREN_DEFAULT_DEVICE_NAME, 2, sink_channels); + audrvDeviceSinkAdd(&device->hidden->driver, AUDREN_DEFAULT_DEVICE_NAME, 2, sink_channels); res = audrenStartAudioRenderer(); if (R_FAILED(res)) { return SDL_SetError("audrenStartAudioRenderer failed (0x%x)", res); } - audrvVoiceInit(&this->hidden->driver, 0, this->spec.channels, PcmFormat_Int16, this->spec.freq); - audrvVoiceSetDestinationMix(&this->hidden->driver, 0, AUDREN_FINAL_MIX_ID); - if (this->spec.channels == 1) { - audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0); - audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 1); + audrvVoiceInit(&device->hidden->driver, 0, device->spec.channels, PcmFormat_Int16, device->spec.freq); + audrvVoiceSetDestinationMix(&device->hidden->driver, 0, AUDREN_FINAL_MIX_ID); + if (device->spec.channels == 1) { + audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 0, 0); + audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 0, 1); } else { - audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 0, 0); - audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 0, 1); - audrvVoiceSetMixFactor(&this->hidden->driver, 0, 0.0f, 1, 0); - audrvVoiceSetMixFactor(&this->hidden->driver, 0, 1.0f, 1, 1); + audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 0, 0); + audrvVoiceSetMixFactor(&device->hidden->driver, 0, 0.0f, 0, 1); + audrvVoiceSetMixFactor(&device->hidden->driver, 0, 0.0f, 1, 0); + audrvVoiceSetMixFactor(&device->hidden->driver, 0, 1.0f, 1, 1); } - audrvVoiceStart(&this->hidden->driver, 0); + audrvVoiceStart(&device->hidden->driver, 0); - return 0; + return true; } -static void SWITCHAUDIO_PlayDevice(_THIS) +static bool SWITCHAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen) { int current = -1; for (int i = 0; i < 2; i++) { - if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Free || this->hidden->buffer[i].state == AudioDriverWaveBufState_Done) { + if (device->hidden->buffer[i].state == AudioDriverWaveBufState_Free || device->hidden->buffer[i].state == AudioDriverWaveBufState_Done) { current = i; break; } } + /* paranoia */ + SDL_assert(buffer == device->hidden->buffer_tmp); + SDL_assert(buflen == device->buffer_size); + if (current >= 0) { - Uint8 *ptr = (Uint8 *)(this->hidden->pool + (current * this->spec.size)); - memcpy(ptr, this->hidden->buffer_tmp, this->spec.size); - armDCacheFlush(ptr, this->spec.size); - audrvVoiceAddWaveBuf(&this->hidden->driver, 0, &this->hidden->buffer[current]); - } else if (!audrvVoiceIsPlaying(&this->hidden->driver, 0)) { - audrvVoiceStart(&this->hidden->driver, 0); + Uint8 *ptr = (Uint8 *)(device->hidden->pool + (current * device->buffer_size)); + memcpy(ptr, device->hidden->buffer_tmp, device->buffer_size); + armDCacheFlush(ptr, device->buffer_size); + audrvVoiceAddWaveBuf(&device->hidden->driver, 0, &device->hidden->buffer[current]); + } else if (!audrvVoiceIsPlaying(&device->hidden->driver, 0)) { + audrvVoiceStart(&device->hidden->driver, 0); } - audrvUpdate(&this->hidden->driver); + audrvUpdate(&device->hidden->driver); if (current >= 0) { - while (this->hidden->buffer[current].state != AudioDriverWaveBufState_Playing) { - audrvUpdate(&this->hidden->driver); + while (device->hidden->buffer[current].state != AudioDriverWaveBufState_Playing) { + audrvUpdate(&device->hidden->driver); audrenWaitFrame(); } } else { current = -1; for (int i = 0; i < 2; i++) { - if (this->hidden->buffer[i].state == AudioDriverWaveBufState_Playing) { + if (device->hidden->buffer[i].state == AudioDriverWaveBufState_Playing) { current = i; break; } } - while (this->hidden->buffer[current].state == AudioDriverWaveBufState_Playing) { - audrvUpdate(&this->hidden->driver); + while (device->hidden->buffer[current].state == AudioDriverWaveBufState_Playing) { + audrvUpdate(&device->hidden->driver); audrenWaitFrame(); } } + + return true; } -static void SWITCHAUDIO_WaitDevice(_THIS) +static bool SWITCHAUDIO_WaitDevice(SDL_AudioDevice *device) { + return true; } -static Uint8 *SWITCHAUDIO_GetDeviceBuf(_THIS) +static Uint8 *SWITCHAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size) { - return this->hidden->buffer_tmp; + return device->hidden->buffer_tmp; } -static void SWITCHAUDIO_CloseDevice(_THIS) +static void SWITCHAUDIO_CloseDevice(SDL_AudioDevice *device) { - if (this->hidden->audr_driver) { - audrvClose(&this->hidden->driver); + if (device->hidden->audr_driver) { + audrvClose(&device->hidden->driver); } - if (this->hidden->audr_device) { + if (device->hidden->audr_device) { audrenExit(); } - if (this->hidden->buffer_tmp) { - free(this->hidden->buffer_tmp); + if (device->hidden->buffer_tmp) { + free(device->hidden->buffer_tmp); } - SDL_free(this->hidden); -} - -static void SWITCHAUDIO_ThreadInit(_THIS) -{ + SDL_free(device->hidden); } -static SDL_bool SWITCHAUDIO_Init(SDL_AudioDriverImpl *impl) +static bool SWITCHAUDIO_Init(SDL_AudioDriverImpl *impl) { impl->OpenDevice = SWITCHAUDIO_OpenDevice; impl->PlayDevice = SWITCHAUDIO_PlayDevice; impl->WaitDevice = SWITCHAUDIO_WaitDevice; impl->GetDeviceBuf = SWITCHAUDIO_GetDeviceBuf; impl->CloseDevice = SWITCHAUDIO_CloseDevice; - impl->ThreadInit = SWITCHAUDIO_ThreadInit; - impl->OnlyHasDefaultOutputDevice = 1; + impl->OnlyHasDefaultPlaybackDevice = true; return 1; } +// clang-format off AudioBootStrap SWITCHAUDIO_bootstrap = { - "switch", "Nintendo Switch audio driver", SWITCHAUDIO_Init, 0 + .name = "switch", + .desc = "Nintendo Switch audio driver", + .init = SWITCHAUDIO_Init, + .demand_only = false, + .is_preferred = true, }; +// clang-format on #endif /* SDL_AUDIO_DRIVER_SWITCH */ diff --git a/src/audio/switch/SDL_switchaudio.h b/src/audio/switch/SDL_switchaudio.h index 6fcea71de04ac..b8107e5519244 100644 --- a/src/audio/switch/SDL_switchaudio.h +++ b/src/audio/switch/SDL_switchaudio.h @@ -23,10 +23,8 @@ #define SDL_switchaudio_h_ #include "../SDL_sysaudio.h" -#include -/* Hidden "this" pointer for the audio functions */ -#define _THIS SDL_AudioDevice *this +#include struct SDL_PrivateAudioData {