InputManager: Switch to SDL3

This commit is contained in:
Stenzek 2025-01-24 15:40:29 +10:00
parent 573b2eb529
commit 4e97420b3b
No known key found for this signature in database
14 changed files with 385 additions and 323 deletions

View File

@ -9,7 +9,7 @@ endif()
set(THREADS_PREFER_PTHREAD_FLAG ON) set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED) find_package(Threads REQUIRED)
find_package(SDL2 2.30.8 REQUIRED) find_package(SDL3 3.2.0 REQUIRED)
find_package(Zstd 1.5.6 REQUIRED) find_package(Zstd 1.5.6 REQUIRED)
find_package(WebP REQUIRED) # v1.4.0, spews an error on Linux because no pkg-config. find_package(WebP REQUIRED) # v1.4.0, spews an error on Linux because no pkg-config.
find_package(ZLIB REQUIRED) # 1.3, but Mac currently doesn't use it. find_package(ZLIB REQUIRED) # 1.3, but Mac currently doesn't use it.

View File

@ -90,7 +90,7 @@ LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44 LIBPNG=1.6.44
LIBWEBP=1.4.0 LIBWEBP=1.4.0
LIBZIP=1.11.2 LIBZIP=1.11.2
SDL2=2.30.11 SDL3=3.2.0
QT=6.8.1 QT=6.8.1
ZSTD=1.5.6 ZSTD=1.5.6
@ -108,7 +108,7 @@ cd deps-build
if [ "$SKIP_DOWNLOAD" != true ]; then if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L \ curl -C - -L \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \ -O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \ -O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL3/SDL3-$SDL3.tar.gz" \
-o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \ -o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \
-o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \ -o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \
-o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \ -o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \
@ -118,7 +118,7 @@ fi
cat > SHASUMS <<EOF cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz bf308f92c5688b1479faf5cfe24af72f3cd4ce08d0c0670d6ce55bc2ec1e9a5e SDL3-$SDL3.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz 3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz 3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
@ -349,13 +349,13 @@ if [ "$SKIP_FREETYPE" != true ]; then
cd .. cd ..
fi fi
echo "Building SDL2..." echo "Building SDL..."
rm -fr "SDL2-$SDL2" rm -fr "SDL3-$SDL3"
tar xf "SDL2-$SDL2.tar.gz" tar xf "SDL3-$SDL3.tar.gz"
cd "SDL2-$SDL2" cd "SDL3-$SDL3"
# needed because -Isystem with chroot/usr/include breaks # needed because -Isystem with chroot/usr/include breaks
patch -p1 < "$SCRIPTDIR/sdl2-disable-isystem.patch" patch -p1 < "$SCRIPTDIR/sdl2-disable-isystem.patch"
cmake -B build "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja cmake -B build "${CMAKE_COMMON[@]}" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja
cmake --build build --parallel cmake --build build --parallel
ninja -C build install ninja -C build install
cd .. cd ..

View File

@ -72,7 +72,7 @@ LIBJPEGTURBO=3.0.4
LIBPNG=1.6.44 LIBPNG=1.6.44
LIBWEBP=1.4.0 LIBWEBP=1.4.0
LIBZIP=1.11.2 LIBZIP=1.11.2
SDL2=2.30.11 SDL3=3.2.0
QT=6.8.1 QT=6.8.1
ZSTD=1.5.6 ZSTD=1.5.6
@ -89,7 +89,7 @@ cd deps-build
if [ "$SKIP_DOWNLOAD" != true ]; then if [ "$SKIP_DOWNLOAD" != true ]; then
curl -C - -L \ curl -C - -L \
-O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \ -O "https://github.com/ianlancetaylor/libbacktrace/archive/$LIBBACKTRACE.tar.gz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \ -O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL3/SDL3-$SDL3.tar.gz" \
-o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \ -o "cpuinfo-$CPUINFO.tar.gz" "https://github.com/stenzek/cpuinfo/archive/$CPUINFO.tar.gz" \
-o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \ -o "discord-rpc-$DISCORD_RPC.tar.gz" "https://github.com/stenzek/discord-rpc/archive/$DISCORD_RPC.tar.gz" \
-o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \ -o "lunasvg-$LUNASVG.tar.gz" "https://github.com/stenzek/lunasvg/archive/$LUNASVG.tar.gz" \
@ -99,7 +99,7 @@ fi
cat > SHASUMS <<EOF cat > SHASUMS <<EOF
baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz baf8aebd22002b762d803ba0e1e389b6b4415159334e9d34bba1a938f6de8ce6 $LIBBACKTRACE.tar.gz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz bf308f92c5688b1479faf5cfe24af72f3cd4ce08d0c0670d6ce55bc2ec1e9a5e SDL3-$SDL3.tar.gz
e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz e1351218d270db49c3dddcba04fb2153b09731ea3fa6830e423f5952f44585be cpuinfo-$CPUINFO.tar.gz
3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz 3eea5ccce6670c126282f1ba4d32c19d486db49a1a5cbfb8d6f48774784d310c discord-rpc-$DISCORD_RPC.tar.gz
3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz 3998b024b0d442614a9ee270e76e018bb37a17b8c6941212171731123cbbcac7 lunasvg-$LUNASVG.tar.gz
@ -297,11 +297,11 @@ if [ "$SKIP_FREETYPE" != true ]; then
cd .. cd ..
fi fi
echo "Building SDL2..." echo "Building SDL..."
rm -fr "SDL2-$SDL2" rm -fr "SDL3-$SDL3"
tar xf "SDL2-$SDL2.tar.gz" tar xf "SDL3-$SDL3.tar.gz"
cd "SDL2-$SDL2" cd "SDL3-$SDL3"
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$INSTALLDIR" -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja
cmake --build build --parallel cmake --build build --parallel
ninja -C build install ninja -C build install
cd .. cd ..

View File

@ -38,7 +38,7 @@ fi
FREETYPE=2.13.3 FREETYPE=2.13.3
HARFBUZZ=10.1.0 HARFBUZZ=10.1.0
SDL2=2.30.11 SDL3=3.2.0
ZSTD=1.5.6 ZSTD=1.5.6
LIBPNG=1.6.44 LIBPNG=1.6.44
LIBJPEGTURBO=3.0.4 LIBJPEGTURBO=3.0.4
@ -86,7 +86,7 @@ c758fdce8587641b00403ee0df2cd5d30cbea7803d43c65fddd76224f7b49b88 harfbuzz-$HARF
99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b libjpeg-turbo-$LIBJPEGTURBO.tar.gz
61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 libwebp-$LIBWEBP.tar.gz
5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz 5d471308cef4c4752bbcf973d9cd37ba4cb53739116c30349d4764ba1410dfc1 libzip-$LIBZIP.tar.xz
8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f SDL2-$SDL2.tar.gz bf308f92c5688b1479faf5cfe24af72f3cd4ce08d0c0670d6ce55bc2ec1e9a5e SDL3-$SDL3.tar.gz
8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz 8c29e06cf42aacc1eafc4077ae2ec6c6fcb96a626157e0593d5e82a34fd403c1 zstd-$ZSTD.tar.gz
40973d44970dbc83ef302b0609f2e74982be2d85916dd2ee7472d30678a7abe6 ffmpeg-$FFMPEG.tar.xz 40973d44970dbc83ef302b0609f2e74982be2d85916dd2ee7472d30678a7abe6 ffmpeg-$FFMPEG.tar.xz
f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz f415a09385030c6510a936155ce211f617c31506db5fbc563e804345f1ecf56e v$MOLTENVK.tar.gz
@ -109,7 +109,7 @@ curl -L \
-O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \ -O "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/$LIBJPEGTURBO/libjpeg-turbo-$LIBJPEGTURBO.tar.gz" \
-O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \ -O "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$LIBWEBP.tar.gz" \
-O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz" \ -O "https://github.com/nih-at/libzip/releases/download/v$LIBZIP/libzip-$LIBZIP.tar.xz" \
-O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL2/SDL2-$SDL2.tar.gz" \ -O "https://github.com/libsdl-org/SDL/releases/download/release-$SDL3/SDL3-$SDL3.tar.gz" \
-O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \ -O "https://github.com/facebook/zstd/releases/download/v$ZSTD/zstd-$ZSTD.tar.gz" \
-O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \ -O "https://ffmpeg.org/releases/ffmpeg-$FFMPEG.tar.xz" \
-O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \ -O "https://github.com/KhronosGroup/MoltenVK/archive/refs/tags/v$MOLTENVK.tar.gz" \
@ -222,11 +222,11 @@ cmake --build build --parallel
cmake --install build cmake --install build
cd .. cd ..
echo "Installing SDL2..." echo "Installing SDL..."
rm -fr "SDL2-$SDL2" rm -fr "SDL3-$SDL3"
tar xf "SDL2-$SDL2.tar.gz" tar xf "SDL3-$SDL3.tar.gz"
cd "SDL2-$SDL2" cd "SDL3-$SDL3"
cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON cmake -B build "${CMAKE_COMMON[@]}" "$CMAKE_ARCH_UNIVERSAL" -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -DSDL_X11=OFF -DBUILD_SHARED_LIBS=ON
make -C build "-j$NPROCS" make -C build "-j$NPROCS"
make -C build install make -C build install
cd .. cd ..

View File

@ -51,7 +51,7 @@ set LIBJPEGTURBO=3.0.4
set LIBPNG=1644 set LIBPNG=1644
set QT=6.8.1 set QT=6.8.1
set QTMINOR=6.8 set QTMINOR=6.8
set SDL2=2.30.11 set SDL3=3.2.0
set WEBP=1.4.0 set WEBP=1.4.0
set LIBZIP=1.11.2 set LIBZIP=1.11.2
set ZLIB=1.3.1 set ZLIB=1.3.1
@ -71,7 +71,7 @@ call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.o
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error call :downloadfile "SDL3-%SDL3%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL3%/SDL3-%SDL3%.zip" abe7114fa42edcc8097856787fa5d37f256d97e365b71368b60764fe7c10e4f8 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
@ -186,14 +186,14 @@ cmake --build build --parallel || goto error
ninja -C build install || goto error ninja -C build install || goto error
cd .. || goto error cd .. || goto error
echo Building SDL2... echo Building SDL...
rmdir /S /Q "SDL2-%SDL2%" rmdir /S /Q "SDL3-%SDL3%"
%SEVENZIP% x "SDL2-%SDL2%.zip" || goto error %SEVENZIP% x "SDL3-%SDL3%.zip" || goto error
cd "SDL2-%SDL2%" || goto error cd "SDL3-%SDL3%" || goto error
cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error cmake -B build %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja || goto error
cmake --build build --parallel || goto error cmake --build build --parallel || goto error
ninja -C build install || goto error ninja -C build install || goto error
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
cd .. || goto error cd .. || goto error
if %DEBUG%==1 ( if %DEBUG%==1 (

View File

@ -49,7 +49,7 @@ set LIBJPEGTURBO=3.0.4
set LIBPNG=1644 set LIBPNG=1644
set QT=6.8.1 set QT=6.8.1
set QTMINOR=6.8 set QTMINOR=6.8
set SDL2=2.30.11 set SDL3=3.2.0
set WEBP=1.4.0 set WEBP=1.4.0
set LIBZIP=1.11.2 set LIBZIP=1.11.2
set ZLIB=1.3.1 set ZLIB=1.3.1
@ -69,7 +69,7 @@ call :downloadfile "freetype-%FREETYPE%.tar.gz" "https://download.savannah.gnu.o
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error call :downloadfile "harfbuzz-%HARFBUZZ%.zip" "https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip" f93ff7ec6f2fcb9242256976a7e6d1da2588b5e57a559fb71a025b74bd1f5539 || goto error
call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error call :downloadfile "lpng%LIBPNG%.zip" "https://download.sourceforge.net/libpng/lpng%LIBPNG%.zip" 7d7571a1faa1898b69888716dfdea0e4d466f1a5cf518e6aa626df2242bbadbe || goto error
call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error call :downloadfile "libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" "https://github.com/libjpeg-turbo/libjpeg-turbo/releases/download/%LIBJPEGTURBO%/libjpeg-turbo-%LIBJPEGTURBO%.tar.gz" 99130559e7d62e8d695f2c0eaeef912c5828d5b84a0537dcb24c9678c9d5b76b || goto error
call :downloadfile "SDL2-%SDL2%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL2%/SDL2-%SDL2%.zip" a0b3e7ac5f708042683ff0f22e069bdf75563540c615f9854ecc9bc8913e2488 || goto error call :downloadfile "SDL3-%SDL3%.zip" "https://github.com/libsdl-org/SDL/releases/download/release-%SDL3%/SDL3-%SDL3%.zip" abe7114fa42edcc8097856787fa5d37f256d97e365b71368b60764fe7c10e4f8 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" e22d997bd15b795a176c8da62c8c1da0a674eb534e02f7c01ca507bf11bce0c3 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 247a0a58039275a5a4fb499a600a90f66dc6e00321bb6f86a9b8d8020344d853 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 57bd332e5550ff70a852560c591b786b6ba587c5e41cb5ef91038d82db137ab9 || goto error
@ -184,13 +184,13 @@ ninja -C build install || goto error
cd .. || goto error cd .. || goto error
echo Building SDL... echo Building SDL...
rmdir /S /Q "SDL2-%SDL2%" rmdir /S /Q "SDL3-%SDL3%"
%SEVENZIP% x "SDL2-%SDL2%.zip" || goto error %SEVENZIP% x "SDL3-%SDL3%.zip" || goto error
cd "SDL2-%SDL2%" || goto error cd "SDL3-%SDL3%" || goto error
cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -G Ninja || goto error cmake -B build -DCMAKE_BUILD_TYPE=Release %FORCEPDB% -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DSDL_SHARED=ON -DSDL_STATIC=OFF -DSDL_TESTS=OFF -G Ninja || goto error
cmake --build build --parallel || goto error cmake --build build --parallel || goto error
ninja -C build install || goto error ninja -C build install || goto error
copy build\SDL2.pdb "%INSTALLDIR%\bin" || goto error copy build\SDL3.pdb "%INSTALLDIR%\bin" || goto error
cd .. || goto error cd .. || goto error
if %DEBUG%==1 ( if %DEBUG%==1 (

View File

@ -1,7 +1,7 @@
# SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> # SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
# SPDX-License-Identifier: CC-BY-NC-ND-4.0 # SPDX-License-Identifier: CC-BY-NC-ND-4.0
name: sdl2 name: sdl3
buildsystem: cmake-ninja buildsystem: cmake-ninja
builddir: true builddir: true
config-opts: config-opts:
@ -14,8 +14,8 @@ build-options:
strip: true strip: true
sources: sources:
- type: archive - type: archive
url: "https://github.com/libsdl-org/SDL/releases/download/release-2.30.11/SDL2-2.30.11.tar.gz" url: "https://github.com/libsdl-org/SDL/releases/download/release-3.2.0/SDL3-3.2.0.tar.gz"
sha256: "8b8d4aef2038533da814965220f88f77d60dfa0f32685f80ead65e501337da7f" sha256: "bf308f92c5688b1479faf5cfe24af72f3cd4ce08d0c0670d6ce55bc2ec1e9a5e"
cleanup: cleanup:
- /bin - /bin
- /include - /include

View File

@ -32,7 +32,7 @@ modules:
# Dependencies. # Dependencies.
- "modules/10-libbacktrace.yaml" - "modules/10-libbacktrace.yaml"
- "modules/11-libzip.yaml" - "modules/11-libzip.yaml"
- "modules/20-sdl2.yaml" - "modules/20-sdl3.yaml"
- "modules/21-shaderc.yaml" - "modules/21-shaderc.yaml"
- "modules/22-spirv-cross.yaml" - "modules/22-spirv-cross.yaml"
- "modules/23-cpuinfo.yaml" - "modules/23-cpuinfo.yaml"

View File

@ -214,7 +214,7 @@ if(WIN32)
#set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations") #set_source_files_properties(${TS_FILES} PROPERTIES OUTPUT_LOCATION "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/translations")
set(DEPS_TO_COPY cpuinfo.dll discord-rpc.dll dxcompiler.dll dxil.dll freetype.dll harfbuzz.dll jpeg62.dll libpng16.dll set(DEPS_TO_COPY cpuinfo.dll discord-rpc.dll dxcompiler.dll dxil.dll freetype.dll harfbuzz.dll jpeg62.dll libpng16.dll
libsharpyuv.dll libwebp.dll lunasvg.dll SDL2.dll shaderc_shared.dll soundtouch.dll spirv-cross-c-shared.dll libsharpyuv.dll libwebp.dll lunasvg.dll SDL3.dll shaderc_shared.dll soundtouch.dll spirv-cross-c-shared.dll
zlib1.dll zstd.dll) zlib1.dll zstd.dll)
foreach(DEP ${DEPS_TO_COPY}) foreach(DEP ${DEPS_TO_COPY})
list(APPEND DEP_BINS "${CMAKE_PREFIX_PATH}/bin/${DEP}") list(APPEND DEP_BINS "${CMAKE_PREFIX_PATH}/bin/${DEP}")

View File

@ -191,7 +191,7 @@ if(NOT ANDROID)
) )
target_link_libraries(util PUBLIC target_link_libraries(util PUBLIC
cubeb cubeb
SDL2::SDL2 SDL3::SDL3
) )
# FFmpeg loaded dynamically on demand. # FFmpeg loaded dynamically on demand.
target_include_directories(util PUBLIC ${FFMPEG_INCLUDE_DIRS}) target_include_directories(util PUBLIC ${FFMPEG_INCLUDE_DIRS})
@ -317,7 +317,7 @@ function(add_util_resources target)
set_target_properties(${target} PROPERTIES INSTALL_RPATH "$ORIGIN") set_target_properties(${target} PROPERTIES INSTALL_RPATH "$ORIGIN")
# Copy dependency libraries to installation directory. # Copy dependency libraries to installation directory.
install_imported_dep_library(SDL2::SDL2) install_imported_dep_library(SDL3::SDL3)
install_imported_dep_library(Shaderc::shaderc_shared) install_imported_dep_library(Shaderc::shaderc_shared)
install_imported_dep_library(spirv-cross-c-shared) install_imported_dep_library(spirv-cross-c-shared)
install_imported_dep_library(SoundTouch::SoundTouchDLL) install_imported_dep_library(SoundTouch::SoundTouchDLL)

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> // SPDX-FileCopyrightText: 2019-2025 Connor McLaughlin <stenzek@gmail.com>
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 // SPDX-License-Identifier: CC-BY-NC-ND-4.0
#include "audio_stream.h" #include "audio_stream.h"
@ -7,11 +7,12 @@
#include "common/error.h" #include "common/error.h"
#include "common/log.h" #include "common/log.h"
#include <SDL.h> #include <SDL3/SDL.h>
LOG_CHANNEL(SDL); LOG_CHANNEL(SDL);
namespace { namespace {
class SDLAudioStream final : public AudioStream class SDLAudioStream final : public AudioStream
{ {
public: public:
@ -24,11 +25,9 @@ public:
void CloseDevice(); void CloseDevice();
protected: protected:
ALWAYS_INLINE bool IsOpen() const { return (m_device_id != 0); } static void AudioCallback(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount);
static void AudioCallback(void* userdata, uint8_t* stream, int len); SDL_AudioStream* m_sdl_stream = nullptr;
u32 m_device_id = 0;
}; };
} // namespace } // namespace
@ -39,7 +38,7 @@ static bool InitializeSDLAudio(Error* error)
return true; return true;
// May as well keep it alive until the process exits. // May as well keep it alive until the process exits.
if (SDL_InitSubSystem(SDL_INIT_AUDIO) != 0) if (!SDL_InitSubSystem(SDL_INIT_AUDIO))
{ {
Error::SetStringFmt(error, "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: {}", SDL_GetError()); Error::SetStringFmt(error, "SDL_InitSubSystem(SDL_INIT_AUDIO) failed: {}", SDL_GetError());
return false; return false;
@ -58,7 +57,6 @@ SDLAudioStream::SDLAudioStream(u32 sample_rate, const AudioStreamParameters& par
SDLAudioStream::~SDLAudioStream() SDLAudioStream::~SDLAudioStream()
{ {
if (IsOpen())
SDLAudioStream::CloseDevice(); SDLAudioStream::CloseDevice();
} }
@ -77,29 +75,21 @@ std::unique_ptr<AudioStream> AudioStream::CreateSDLAudioStream(u32 sample_rate,
bool SDLAudioStream::OpenDevice(Error* error) bool SDLAudioStream::OpenDevice(Error* error)
{ {
DebugAssert(!IsOpen()); DebugAssert(!m_sdl_stream);
SDL_AudioSpec spec = {}; const SDL_AudioSpec spec = {
spec.freq = m_sample_rate; .format = SDL_AUDIO_S16LE, .channels = NUM_CHANNELS, .freq = static_cast<int>(m_sample_rate)};
spec.channels = NUM_CHANNELS;
spec.format = AUDIO_S16;
spec.samples = static_cast<Uint16>(GetBufferSizeForMS(
m_sample_rate, (m_parameters.output_latency_ms == 0) ? m_parameters.buffer_ms : m_parameters.output_latency_ms));
spec.callback = AudioCallback;
spec.userdata = static_cast<void*>(this);
SDL_AudioSpec obtained_spec = {}; m_sdl_stream =
m_device_id = SDL_OpenAudioDevice(nullptr, 0, &spec, &obtained_spec, SDL_AUDIO_ALLOW_SAMPLES_CHANGE); SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, AudioCallback, static_cast<void*>(this));
if (m_device_id == 0) if (!m_sdl_stream)
{ {
Error::SetStringFmt(error, "SDL_OpenAudioDevice() failed: {}", SDL_GetError()); Error::SetStringFmt(error, "SDL_OpenAudioDeviceStream() failed: {}", SDL_GetError());
return false; return false;
} }
DEV_LOG("Requested {} frame buffer, got {} frame buffer", spec.samples, obtained_spec.samples);
BaseInitialize(); BaseInitialize();
SDL_PauseAudioDevice(m_device_id, 0); SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_sdl_stream));
return true; return true;
} }
@ -109,20 +99,31 @@ void SDLAudioStream::SetPaused(bool paused)
if (m_paused == paused) if (m_paused == paused)
return; return;
SDL_PauseAudioDevice(m_device_id, paused ? 1 : 0); paused ? SDL_PauseAudioStreamDevice(m_sdl_stream) : SDL_ResumeAudioStreamDevice(m_sdl_stream);
m_paused = paused; m_paused = paused;
} }
void SDLAudioStream::CloseDevice() void SDLAudioStream::CloseDevice()
{ {
SDL_CloseAudioDevice(m_device_id); if (m_sdl_stream)
m_device_id = 0; {
SDL_DestroyAudioStream(m_sdl_stream);
m_sdl_stream = nullptr;
}
} }
void SDLAudioStream::AudioCallback(void* userdata, uint8_t* stream, int len) void SDLAudioStream::AudioCallback(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount)
{
if (additional_amount == 0)
return;
u8* data = SDL_stack_alloc(u8, additional_amount);
if (data)
{ {
SDLAudioStream* const this_ptr = static_cast<SDLAudioStream*>(userdata); SDLAudioStream* const this_ptr = static_cast<SDLAudioStream*>(userdata);
const u32 num_frames = len / sizeof(SampleType) / NUM_CHANNELS; const u32 num_frames = static_cast<u32>(additional_amount) / (sizeof(SampleType) * NUM_CHANNELS);
this_ptr->ReadFrames(reinterpret_cast<SampleType*>(data), num_frames);
this_ptr->ReadFrames(reinterpret_cast<SampleType*>(stream), num_frames); SDL_PutAudioStreamData(stream, data, additional_amount);
SDL_stack_free(data);
}
} }

View File

@ -28,100 +28,115 @@ LOG_CHANNEL(SDL);
static constexpr const char* CONTROLLER_DB_FILENAME = "gamecontrollerdb.txt"; static constexpr const char* CONTROLLER_DB_FILENAME = "gamecontrollerdb.txt";
static constexpr std::array<const char*, SDL_CONTROLLER_AXIS_MAX> s_sdl_axis_names = {{ static constexpr std::array<const char*, SDL_GAMEPAD_AXIS_COUNT> s_sdl_axis_names = {{
"LeftX", // SDL_CONTROLLER_AXIS_LEFTX "LeftX", // SDL_GAMEPAD_AXIS_LEFTX
"LeftY", // SDL_CONTROLLER_AXIS_LEFTY "LeftY", // SDL_GAMEPAD_AXIS_LEFTY
"RightX", // SDL_CONTROLLER_AXIS_RIGHTX "RightX", // SDL_GAMEPAD_AXIS_RIGHTX
"RightY", // SDL_CONTROLLER_AXIS_RIGHTY "RightY", // SDL_GAMEPAD_AXIS_RIGHTY
"LeftTrigger", // SDL_CONTROLLER_AXIS_TRIGGERLEFT "LeftTrigger", // SDL_GAMEPAD_AXIS_LEFT_TRIGGER
"RightTrigger", // SDL_CONTROLLER_AXIS_TRIGGERRIGHT "RightTrigger", // SDL_GAMEPAD_AXIS_RIGHT_TRIGGER
}}; }};
static constexpr std::array<std::array<const char*, 2>, SDL_CONTROLLER_AXIS_MAX> s_sdl_axis_icons = {{ static constexpr std::array<std::array<const char*, 2>, SDL_GAMEPAD_AXIS_COUNT> s_sdl_axis_icons = {{
{{ICON_PF_LEFT_ANALOG_LEFT, ICON_PF_LEFT_ANALOG_RIGHT}}, // SDL_CONTROLLER_AXIS_LEFTX {{ICON_PF_LEFT_ANALOG_LEFT, ICON_PF_LEFT_ANALOG_RIGHT}}, // SDL_GAMEPAD_AXIS_LEFTX
{{ICON_PF_LEFT_ANALOG_UP, ICON_PF_LEFT_ANALOG_DOWN}}, // SDL_CONTROLLER_AXIS_LEFTY {{ICON_PF_LEFT_ANALOG_UP, ICON_PF_LEFT_ANALOG_DOWN}}, // SDL_GAMEPAD_AXIS_LEFTY
{{ICON_PF_RIGHT_ANALOG_LEFT, ICON_PF_RIGHT_ANALOG_RIGHT}}, // SDL_CONTROLLER_AXIS_RIGHTX {{ICON_PF_RIGHT_ANALOG_LEFT, ICON_PF_RIGHT_ANALOG_RIGHT}}, // SDL_GAMEPAD_AXIS_RIGHTX
{{ICON_PF_RIGHT_ANALOG_UP, ICON_PF_RIGHT_ANALOG_DOWN}}, // SDL_CONTROLLER_AXIS_RIGHTY {{ICON_PF_RIGHT_ANALOG_UP, ICON_PF_RIGHT_ANALOG_DOWN}}, // SDL_GAMEPAD_AXIS_RIGHTY
{{nullptr, ICON_PF_LEFT_TRIGGER_LT}}, // SDL_CONTROLLER_AXIS_TRIGGERLEFT {{nullptr, ICON_PF_LEFT_TRIGGER_LT}}, // SDL_GAMEPAD_AXIS_LEFT_TRIGGER
{{nullptr, ICON_PF_RIGHT_TRIGGER_RT}}, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT {{nullptr, ICON_PF_RIGHT_TRIGGER_RT}}, // SDL_GAMEPAD_AXIS_RIGHT_TRIGGER
}}; }};
static constexpr std::array<std::array<GenericInputBinding, 2>, SDL_CONTROLLER_AXIS_MAX> static constexpr std::array<std::array<GenericInputBinding, 2>, SDL_GAMEPAD_AXIS_COUNT>
s_sdl_generic_binding_axis_mapping = {{ s_sdl_generic_binding_axis_mapping = {{
{{GenericInputBinding::LeftStickLeft, GenericInputBinding::LeftStickRight}}, // SDL_CONTROLLER_AXIS_LEFTX {{GenericInputBinding::LeftStickLeft, GenericInputBinding::LeftStickRight}}, // SDL_GAMEPAD_AXIS_LEFTX
{{GenericInputBinding::LeftStickUp, GenericInputBinding::LeftStickDown}}, // SDL_CONTROLLER_AXIS_LEFTY {{GenericInputBinding::LeftStickUp, GenericInputBinding::LeftStickDown}}, // SDL_GAMEPAD_AXIS_LEFTY
{{GenericInputBinding::RightStickLeft, GenericInputBinding::RightStickRight}}, // SDL_CONTROLLER_AXIS_RIGHTX {{GenericInputBinding::RightStickLeft, GenericInputBinding::RightStickRight}}, // SDL_GAMEPAD_AXIS_RIGHTX
{{GenericInputBinding::RightStickUp, GenericInputBinding::RightStickDown}}, // SDL_CONTROLLER_AXIS_RIGHTY {{GenericInputBinding::RightStickUp, GenericInputBinding::RightStickDown}}, // SDL_GAMEPAD_AXIS_RIGHTY
{{GenericInputBinding::Unknown, GenericInputBinding::L2}}, // SDL_CONTROLLER_AXIS_TRIGGERLEFT {{GenericInputBinding::Unknown, GenericInputBinding::L2}}, // SDL_GAMEPAD_AXIS_LEFT_TRIGGER
{{GenericInputBinding::Unknown, GenericInputBinding::R2}}, // SDL_CONTROLLER_AXIS_TRIGGERRIGHT {{GenericInputBinding::Unknown, GenericInputBinding::R2}}, // SDL_GAMEPAD_AXIS_RIGHT_TRIGGER
}}; }};
static constexpr std::array<const char*, SDL_CONTROLLER_BUTTON_MAX> s_sdl_button_names = {{ static constexpr std::array<const char*, SDL_GAMEPAD_BUTTON_COUNT> s_sdl_button_names = {{
"A", // SDL_CONTROLLER_BUTTON_A "A", // SDL_GAMEPAD_BUTTON_SOUTH
"B", // SDL_CONTROLLER_BUTTON_B "B", // SDL_GAMEPAD_BUTTON_EAST
"X", // SDL_CONTROLLER_BUTTON_X "X", // SDL_GAMEPAD_BUTTON_WEST
"Y", // SDL_CONTROLLER_BUTTON_Y "Y", // SDL_GAMEPAD_BUTTON_NORTH
"Back", // SDL_CONTROLLER_BUTTON_BACK "Back", // SDL_GAMEPAD_BUTTON_BACK
"Guide", // SDL_CONTROLLER_BUTTON_GUIDE "Guide", // SDL_GAMEPAD_BUTTON_GUIDE
"Start", // SDL_CONTROLLER_BUTTON_START "Start", // SDL_GAMEPAD_BUTTON_START
"LeftStick", // SDL_CONTROLLER_BUTTON_LEFTSTICK "LeftStick", // SDL_GAMEPAD_BUTTON_LEFT_STICK
"RightStick", // SDL_CONTROLLER_BUTTON_RIGHTSTICK "RightStick", // SDL_GAMEPAD_BUTTON_RIGHT_STICK
"LeftShoulder", // SDL_CONTROLLER_BUTTON_LEFTSHOULDER "LeftShoulder", // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER
"RightShoulder", // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER "RightShoulder", // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER
"DPadUp", // SDL_CONTROLLER_BUTTON_DPAD_UP "DPadUp", // SDL_GAMEPAD_BUTTON_DPAD_UP
"DPadDown", // SDL_CONTROLLER_BUTTON_DPAD_DOWN "DPadDown", // SDL_GAMEPAD_BUTTON_DPAD_DOWN
"DPadLeft", // SDL_CONTROLLER_BUTTON_DPAD_LEFT "DPadLeft", // SDL_GAMEPAD_BUTTON_DPAD_LEFT
"DPadRight", // SDL_CONTROLLER_BUTTON_DPAD_RIGHT "DPadRight", // SDL_GAMEPAD_BUTTON_DPAD_RIGHT
"Misc1", // SDL_CONTROLLER_BUTTON_MISC1 "Misc1", // SDL_GAMEPAD_BUTTON_MISC1
"Paddle1", // SDL_CONTROLLER_BUTTON_PADDLE1 "RightPaddle1", // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1
"Paddle2", // SDL_CONTROLLER_BUTTON_PADDLE2 "LeftPaddle1", // SDL_GAMEPAD_BUTTON_LEFT_PADDLE1
"Paddle3", // SDL_CONTROLLER_BUTTON_PADDLE3 "RightPaddle2", // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2
"Paddle4", // SDL_CONTROLLER_BUTTON_PADDLE4 "LeftPaddle2", // SDL_GAMEPAD_BUTTON_LEFT_PADDLE2
"Touchpad", // SDL_CONTROLLER_BUTTON_TOUCHPAD "Touchpad", // SDL_GAMEPAD_BUTTON_TOUCHPAD
"Misc2", // SDL_GAMEPAD_BUTTON_MISC2
"Misc3", // SDL_GAMEPAD_BUTTON_MISC3
"Misc4", // SDL_GAMEPAD_BUTTON_MISC4
"Misc5", // SDL_GAMEPAD_BUTTON_MISC5
"Misc6", // SDL_GAMEPAD_BUTTON_MISC6
}}; }};
static constexpr std::array<const char*, SDL_CONTROLLER_BUTTON_MAX> s_sdl_button_icons = {{ static constexpr std::array<const char*, SDL_GAMEPAD_BUTTON_COUNT> s_sdl_button_icons = {{
ICON_PF_BUTTON_A, // SDL_CONTROLLER_BUTTON_A ICON_PF_BUTTON_A, // SDL_GAMEPAD_BUTTON_SOUTH
ICON_PF_BUTTON_B, // SDL_CONTROLLER_BUTTON_B ICON_PF_BUTTON_B, // SDL_GAMEPAD_BUTTON_EAST
ICON_PF_BUTTON_X, // SDL_CONTROLLER_BUTTON_X ICON_PF_BUTTON_X, // SDL_GAMEPAD_BUTTON_WEST
ICON_PF_BUTTON_Y, // SDL_CONTROLLER_BUTTON_Y ICON_PF_BUTTON_Y, // SDL_GAMEPAD_BUTTON_NORTH
ICON_PF_SHARE_CAPTURE, // SDL_CONTROLLER_BUTTON_BACK ICON_PF_SHARE_CAPTURE, // SDL_GAMEPAD_BUTTON_BACK
ICON_PF_XBOX, // SDL_CONTROLLER_BUTTON_GUIDE ICON_PF_XBOX, // SDL_GAMEPAD_BUTTON_GUIDE
ICON_PF_BURGER_MENU, // SDL_CONTROLLER_BUTTON_START ICON_PF_BURGER_MENU, // SDL_GAMEPAD_BUTTON_START
ICON_PF_LEFT_ANALOG_CLICK, // SDL_CONTROLLER_BUTTON_LEFTSTICK ICON_PF_LEFT_ANALOG_CLICK, // SDL_GAMEPAD_BUTTON_LEFT_STICK
ICON_PF_RIGHT_ANALOG_CLICK, // SDL_CONTROLLER_BUTTON_RIGHTSTICK ICON_PF_RIGHT_ANALOG_CLICK, // SDL_GAMEPAD_BUTTON_RIGHT_STICK
ICON_PF_LEFT_SHOULDER_LB, // SDL_CONTROLLER_BUTTON_LEFTSHOULDER ICON_PF_LEFT_SHOULDER_LB, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER
ICON_PF_RIGHT_SHOULDER_RB, // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ICON_PF_RIGHT_SHOULDER_RB, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER
ICON_PF_XBOX_DPAD_UP, // SDL_CONTROLLER_BUTTON_DPAD_UP ICON_PF_XBOX_DPAD_UP, // SDL_GAMEPAD_BUTTON_DPAD_UP
ICON_PF_XBOX_DPAD_DOWN, // SDL_CONTROLLER_BUTTON_DPAD_DOWN ICON_PF_XBOX_DPAD_DOWN, // SDL_GAMEPAD_BUTTON_DPAD_DOWN
ICON_PF_XBOX_DPAD_LEFT, // SDL_CONTROLLER_BUTTON_DPAD_LEFT ICON_PF_XBOX_DPAD_LEFT, // SDL_GAMEPAD_BUTTON_DPAD_LEFT
ICON_PF_XBOX_DPAD_RIGHT, // SDL_CONTROLLER_BUTTON_DPAD_RIGHT ICON_PF_XBOX_DPAD_RIGHT, // SDL_GAMEPAD_BUTTON_DPAD_RIGHT
nullptr, // SDL_CONTROLLER_BUTTON_MISC1 nullptr, // SDL_GAMEPAD_BUTTON_MISC1
nullptr, // SDL_CONTROLLER_BUTTON_PADDLE1 nullptr, // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1
nullptr, // SDL_CONTROLLER_BUTTON_PADDLE2 nullptr, // SDL_GAMEPAD_BUTTON_LEFT_PADDLE1
nullptr, // SDL_CONTROLLER_BUTTON_PADDLE3 nullptr, // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2
nullptr, // SDL_CONTROLLER_BUTTON_PADDLE4 nullptr, // SDL_GAMEPAD_BUTTON_LEFT_PADDLE2
ICON_PF_DUALSHOCK_TOUCHPAD, // SDL_CONTROLLER_BUTTON_TOUCHPAD ICON_PF_DUALSHOCK_TOUCHPAD, // SDL_GAMEPAD_BUTTON_TOUCHPAD
nullptr, // SDL_GAMEPAD_BUTTON_MISC2
nullptr, // SDL_GAMEPAD_BUTTON_MISC3
nullptr, // SDL_GAMEPAD_BUTTON_MISC4
nullptr, // SDL_GAMEPAD_BUTTON_MISC5
nullptr, // SDL_GAMEPAD_BUTTON_MISC6
}}; }};
static constexpr std::array<GenericInputBinding, SDL_CONTROLLER_BUTTON_MAX> s_sdl_generic_binding_button_mapping = {{ static constexpr std::array<GenericInputBinding, SDL_GAMEPAD_BUTTON_COUNT> s_sdl_generic_binding_button_mapping = {{
GenericInputBinding::Cross, // SDL_CONTROLLER_BUTTON_A GenericInputBinding::Cross, // SDL_GAMEPAD_BUTTON_SOUTH
GenericInputBinding::Circle, // SDL_CONTROLLER_BUTTON_B GenericInputBinding::Circle, // SDL_GAMEPAD_BUTTON_EAST
GenericInputBinding::Square, // SDL_CONTROLLER_BUTTON_X GenericInputBinding::Square, // SDL_GAMEPAD_BUTTON_WEST
GenericInputBinding::Triangle, // SDL_CONTROLLER_BUTTON_Y GenericInputBinding::Triangle, // SDL_GAMEPAD_BUTTON_NORTH
GenericInputBinding::Select, // SDL_CONTROLLER_BUTTON_BACK GenericInputBinding::Select, // SDL_GAMEPAD_BUTTON_BACK
GenericInputBinding::System, // SDL_CONTROLLER_BUTTON_GUIDE GenericInputBinding::System, // SDL_GAMEPAD_BUTTON_GUIDE
GenericInputBinding::Start, // SDL_CONTROLLER_BUTTON_START GenericInputBinding::Start, // SDL_GAMEPAD_BUTTON_START
GenericInputBinding::L3, // SDL_CONTROLLER_BUTTON_LEFTSTICK GenericInputBinding::L3, // SDL_GAMEPAD_BUTTON_LEFT_STICK
GenericInputBinding::R3, // SDL_CONTROLLER_BUTTON_RIGHTSTICK GenericInputBinding::R3, // SDL_GAMEPAD_BUTTON_RIGHT_STICK
GenericInputBinding::L1, // SDL_CONTROLLER_BUTTON_LEFTSHOULDER GenericInputBinding::L1, // SDL_GAMEPAD_BUTTON_LEFT_SHOULDER
GenericInputBinding::R1, // SDL_CONTROLLER_BUTTON_RIGHTSHOULDER GenericInputBinding::R1, // SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER
GenericInputBinding::DPadUp, // SDL_CONTROLLER_BUTTON_DPAD_UP GenericInputBinding::DPadUp, // SDL_GAMEPAD_BUTTON_DPAD_UP
GenericInputBinding::DPadDown, // SDL_CONTROLLER_BUTTON_DPAD_DOWN GenericInputBinding::DPadDown, // SDL_GAMEPAD_BUTTON_DPAD_DOWN
GenericInputBinding::DPadLeft, // SDL_CONTROLLER_BUTTON_DPAD_LEFT GenericInputBinding::DPadLeft, // SDL_GAMEPAD_BUTTON_DPAD_LEFT
GenericInputBinding::DPadRight, // SDL_CONTROLLER_BUTTON_DPAD_RIGHT GenericInputBinding::DPadRight, // SDL_GAMEPAD_BUTTON_DPAD_RIGHT
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_MISC1 GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_MISC1
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE1 GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE2 GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_LEFT_PADDLE1
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE3 GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_PADDLE4 GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_LEFT_PADDLE2
GenericInputBinding::Unknown, // SDL_CONTROLLER_BUTTON_TOUCHPAD GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_TOUCHPAD
GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_MISC2
GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_MISC3
GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_MISC4
GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_MISC5
GenericInputBinding::Unknown, // SDL_GAMEPAD_BUTTON_MISC6
}}; }};
static constexpr std::array<const char*, 4> s_sdl_hat_direction_names = {{ static constexpr std::array<const char*, 4> s_sdl_hat_direction_names = {{
@ -140,16 +155,17 @@ static constexpr std::array<const char*, 4> s_sdl_default_led_colors = {{
"ffff00", // SDL-3 "ffff00", // SDL-3
}}; }};
static void SetControllerRGBLED(SDL_GameController* gc, u32 color) static void SetControllerRGBLED(SDL_Gamepad* gp, u32 color)
{ {
SDL_GameControllerSetLED(gc, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff); SDL_SetGamepadLED(gp, (color >> 16) & 0xff, (color >> 8) & 0xff, color & 0xff);
} }
static void SDLLogCallback(void* userdata, int category, SDL_LogPriority priority, const char* message) static void SDLLogCallback(void* userdata, int category, SDL_LogPriority priority, const char* message)
{ {
static constexpr Log::Level priority_map[SDL_NUM_LOG_PRIORITIES] = { static constexpr Log::Level priority_map[SDL_LOG_PRIORITY_COUNT] = {
Log::Level::Debug, Log::Level::Debug, // SDL_LOG_PRIORITY_INVALID
Log::Level::Debug, // SDL_LOG_PRIORITY_VERBOSE Log::Level::Trace, // SDL_LOG_PRIORITY_TRACE
Log::Level::Verbose, // SDL_LOG_PRIORITY_VERBOSE
Log::Level::Debug, // SDL_LOG_PRIORITY_DEBUG Log::Level::Debug, // SDL_LOG_PRIORITY_DEBUG
Log::Level::Info, // SDL_LOG_PRIORITY_INFO Log::Level::Info, // SDL_LOG_PRIORITY_INFO
Log::Level::Warning, // SDL_LOG_PRIORITY_WARN Log::Level::Warning, // SDL_LOG_PRIORITY_WARN
@ -232,10 +248,10 @@ void SDLInputSource::LoadSettings(const SettingsInterface& si)
m_led_colors[i] = color; m_led_colors[i] = color;
const auto it = GetControllerDataForPlayerId(i); const auto it = GetControllerDataForPlayerId(i);
if (it == m_controllers.end() || !it->game_controller || !SDL_GameControllerHasLED(it->game_controller)) if (it == m_controllers.end() || !it->gamepad || !it->has_led)
continue; continue;
SetControllerRGBLED(it->game_controller, color); SetControllerRGBLED(it->gamepad, color);
} }
m_controller_enhanced_mode = si.GetBoolValue("InputSources", "SDLControllerEnhancedMode", false); m_controller_enhanced_mode = si.GetBoolValue("InputSources", "SDLControllerEnhancedMode", false);
@ -297,8 +313,7 @@ void SDLInputSource::SetHints()
ERROR_LOG("Controller DB not found, it should be named '{}'", CONTROLLER_DB_FILENAME); ERROR_LOG("Controller DB not found, it should be named '{}'", CONTROLLER_DB_FILENAME);
} }
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, m_controller_enhanced_mode ? "1" : "0"); SDL_SetHint(SDL_HINT_JOYSTICK_ENHANCED_REPORTS, m_controller_enhanced_mode ? "1" : "0");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, m_controller_enhanced_mode ? "1" : "0");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, m_controller_ps5_player_led ? "1" : "0"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, m_controller_ps5_player_led ? "1" : "0");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_WII, "1");
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS3, "1");
@ -316,22 +331,26 @@ void SDLInputSource::SetHints()
bool SDLInputSource::InitializeSubsystem() bool SDLInputSource::InitializeSubsystem()
{ {
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) < 0) if (!SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC))
{ {
ERROR_LOG("SDL_InitSubSystem(SDL_INIT_JOYSTICK |SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) failed"); ERROR_LOG("SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC) failed");
return false; return false;
} }
SDL_LogSetOutputFunction(SDLLogCallback, nullptr); SDL_SetLogOutputFunction(SDLLogCallback, nullptr);
#if defined(_DEBUG) || defined(_DEVEL) #if defined(_DEBUG) || defined(_DEVEL)
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_VERBOSE); SDL_SetLogPriorities(SDL_LOG_PRIORITY_DEBUG);
#else #else
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_INFO); SDL_SetLogPriorities(SDL_LOG_PRIORITY_INFO);
#endif #endif
// we should open the controllers as the connected events come in, so no need to do any more here // we should open the controllers as the connected events come in, so no need to do any more here
m_sdl_subsystem_initialized = true; m_sdl_subsystem_initialized = true;
INFO_LOG("{} controller mappings are loaded.", SDL_GameControllerNumMappings());
int mapping_count = 0;
SDL_free(SDL_GetGamepadMappings(&mapping_count));
INFO_LOG("{} controller mappings are loaded.", mapping_count);
return true; return true;
} }
@ -342,7 +361,7 @@ void SDLInputSource::ShutdownSubsystem()
if (m_sdl_subsystem_initialized) if (m_sdl_subsystem_initialized)
{ {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC); SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC);
m_sdl_subsystem_initialized = false; m_sdl_subsystem_initialized = false;
} }
} }
@ -371,7 +390,7 @@ InputManager::DeviceList SDLInputSource::EnumerateDevices()
std::string id = fmt::format("SDL-{}", cd.player_id); std::string id = fmt::format("SDL-{}", cd.player_id);
const InputBindingKey key = MakeGenericControllerDeviceKey(InputSourceType::SDL, cd.player_id); const InputBindingKey key = MakeGenericControllerDeviceKey(InputSourceType::SDL, cd.player_id);
const char* name = cd.game_controller ? SDL_GameControllerName(cd.game_controller) : SDL_JoystickName(cd.joystick); const char* name = cd.gamepad ? SDL_GetGamepadName(cd.gamepad) : SDL_GetJoystickName(cd.joystick);
if (name) if (name)
ret.emplace_back(key, std::move(id), name); ret.emplace_back(key, std::move(id), name);
else else
@ -595,20 +614,20 @@ bool SDLInputSource::IsHandledInputEvent(const SDL_Event* ev)
{ {
switch (ev->type) switch (ev->type)
{ {
case SDL_CONTROLLERDEVICEADDED: case SDL_EVENT_GAMEPAD_ADDED:
case SDL_CONTROLLERDEVICEREMOVED: case SDL_EVENT_GAMEPAD_REMOVED:
case SDL_JOYDEVICEADDED: case SDL_EVENT_GAMEPAD_AXIS_MOTION:
case SDL_JOYDEVICEREMOVED: case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_CONTROLLERAXISMOTION: case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_CONTROLLERBUTTONDOWN: case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
case SDL_CONTROLLERBUTTONUP: case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
case SDL_CONTROLLERTOUCHPADDOWN: case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
case SDL_CONTROLLERTOUCHPADUP: case SDL_EVENT_JOYSTICK_ADDED:
case SDL_CONTROLLERTOUCHPADMOTION: case SDL_EVENT_JOYSTICK_REMOVED:
case SDL_JOYAXISMOTION: case SDL_EVENT_JOYSTICK_AXIS_MOTION:
case SDL_JOYBUTTONDOWN: case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_JOYBUTTONUP: case SDL_EVENT_JOYSTICK_BUTTON_UP:
case SDL_JOYHATMOTION: case SDL_EVENT_JOYSTICK_HAT_MOTION:
return true; return true;
default: default:
@ -620,63 +639,62 @@ bool SDLInputSource::ProcessSDLEvent(const SDL_Event* event)
{ {
switch (event->type) switch (event->type)
{ {
case SDL_CONTROLLERDEVICEADDED: case SDL_EVENT_GAMEPAD_ADDED:
{ {
INFO_LOG("Controller {} inserted", event->cdevice.which); INFO_LOG("Controller {} inserted", event->gdevice.which);
OpenDevice(event->cdevice.which, true); OpenDevice(event->gdevice.which, true);
return true; return true;
} }
case SDL_CONTROLLERDEVICEREMOVED: case SDL_EVENT_GAMEPAD_REMOVED:
{ {
INFO_LOG("Controller {} removed", event->cdevice.which); INFO_LOG("Controller {} removed", event->gdevice.which);
CloseDevice(event->cdevice.which); CloseDevice(event->gdevice.which);
return true; return true;
} }
case SDL_JOYDEVICEADDED: case SDL_EVENT_JOYSTICK_ADDED:
{ {
// Let game controller handle.. well.. game controllers. // Let gamepad handle.. well.. gamepads.
if (SDL_IsGameController(event->jdevice.which)) if (SDL_IsGamepad(event->jdevice.which))
return false; return false;
INFO_LOG("Joystick {} inserted", event->jdevice.which); INFO_LOG("Joystick {} inserted", event->jdevice.which);
OpenDevice(event->cdevice.which, false); OpenDevice(event->jdevice.which, false);
return true; return true;
} }
break; break;
case SDL_JOYDEVICEREMOVED: case SDL_EVENT_JOYSTICK_REMOVED:
{ {
if (auto it = GetControllerDataForJoystickId(event->cdevice.which); if (auto it = GetControllerDataForJoystickId(event->jdevice.which); it != m_controllers.end() && it->gamepad)
it != m_controllers.end() && it->game_controller)
return false; return false;
INFO_LOG("Joystick {} removed", event->jdevice.which); INFO_LOG("Joystick {} removed", event->jdevice.which);
CloseDevice(event->cdevice.which); CloseDevice(event->jdevice.which);
return true; return true;
} }
case SDL_CONTROLLERAXISMOTION: case SDL_EVENT_GAMEPAD_AXIS_MOTION:
return HandleControllerAxisEvent(&event->caxis); return HandleGamepadAxisMotionEvent(&event->gaxis);
case SDL_CONTROLLERBUTTONDOWN: case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_CONTROLLERBUTTONUP: case SDL_EVENT_GAMEPAD_BUTTON_UP:
return HandleControllerButtonEvent(&event->cbutton); return HandleGamepadButtonEvent(&event->gbutton);
case SDL_CONTROLLERTOUCHPADDOWN: case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN:
case SDL_CONTROLLERTOUCHPADUP: case SDL_EVENT_GAMEPAD_TOUCHPAD_UP:
case SDL_CONTROLLERTOUCHPADMOTION: case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION:
return HandleControllerTouchpadEvent(&event->ctouchpad); return HandleGamepadTouchpadEvent(&event->gtouchpad);
case SDL_JOYAXISMOTION: case SDL_EVENT_JOYSTICK_AXIS_MOTION:
return HandleJoystickAxisEvent(&event->jaxis); return HandleJoystickAxisEvent(&event->jaxis);
case SDL_JOYBUTTONDOWN: case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_JOYBUTTONUP: case SDL_EVENT_JOYSTICK_BUTTON_UP:
return HandleJoystickButtonEvent(&event->jbutton); return HandleJoystickButtonEvent(&event->jbutton);
case SDL_JOYHATMOTION: case SDL_EVENT_JOYSTICK_HAT_MOTION:
return HandleJoystickHatEvent(&event->jhat); return HandleJoystickHatEvent(&event->jhat);
default: default:
@ -731,31 +749,31 @@ int SDLInputSource::GetFreePlayerId() const
bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller)
{ {
SDL_GameController* gcontroller; SDL_Gamepad* gamepad;
SDL_Joystick* joystick; SDL_Joystick* joystick;
if (is_gamecontroller) if (is_gamecontroller)
{ {
gcontroller = SDL_GameControllerOpen(index); gamepad = SDL_OpenGamepad(index);
joystick = gcontroller ? SDL_GameControllerGetJoystick(gcontroller) : nullptr; joystick = gamepad ? SDL_GetGamepadJoystick(gamepad) : nullptr;
} }
else else
{ {
gcontroller = nullptr; gamepad = nullptr;
joystick = SDL_JoystickOpen(index); joystick = SDL_OpenJoystick(index);
} }
if (!gcontroller && !joystick) if (!gamepad && !joystick)
{ {
ERROR_LOG("Failed to open controller {}", index); ERROR_LOG("Failed to open controller {}", index);
if (gcontroller) if (gamepad)
SDL_GameControllerClose(gcontroller); SDL_CloseGamepad(gamepad);
return false; return false;
} }
const int joystick_id = SDL_JoystickInstanceID(joystick); const int joystick_id = SDL_GetJoystickID(joystick);
int player_id = gcontroller ? SDL_GameControllerGetPlayerIndex(gcontroller) : SDL_JoystickGetPlayerIndex(joystick); int player_id = gamepad ? SDL_GetGamepadPlayerIndex(gamepad) : SDL_GetJoystickPlayerIndex(joystick);
if (player_id < 0 || GetControllerDataForPlayerId(player_id) != m_controllers.end()) if (player_id < 0 || GetControllerDataForPlayerId(player_id) != m_controllers.end())
{ {
const int free_player_id = GetFreePlayerId(); const int free_player_id = GetFreePlayerId();
@ -764,10 +782,12 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller)
player_id = free_player_id; player_id = free_player_id;
} }
const char* name = gcontroller ? SDL_GameControllerName(gcontroller) : SDL_JoystickName(joystick); const char* name = gamepad ? SDL_GetGamepadName(gamepad) : SDL_GetJoystickName(joystick);
if (!name) if (!name)
name = "Unknown Device"; name = "Unknown Device";
const SDL_PropertiesID properties = gamepad ? SDL_GetGamepadProperties(gamepad) : SDL_GetJoystickProperties(joystick);
VERBOSE_LOG("Opened {} {} (instance id {}, player id {}): {}", is_gamecontroller ? "game controller" : "joystick", VERBOSE_LOG("Opened {} {} (instance id {}, player id {}): {}", is_gamecontroller ? "game controller" : "joystick",
index, joystick_id, player_id, name); index, joystick_id, player_id, name);
@ -775,56 +795,94 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller)
cd.player_id = player_id; cd.player_id = player_id;
cd.joystick_id = joystick_id; cd.joystick_id = joystick_id;
cd.haptic_left_right_effect = -1; cd.haptic_left_right_effect = -1;
cd.game_controller = gcontroller; cd.gamepad = gamepad;
cd.joystick = joystick; cd.joystick = joystick;
cd.last_touch_x = 0.0f; cd.last_touch_x = 0.0f;
cd.last_touch_y = 0.0f; cd.last_touch_y = 0.0f;
if (gcontroller) const u32 num_axes = static_cast<u32>(std::max(SDL_GetNumJoystickAxes(joystick), 0));
{ const u32 num_buttons = static_cast<u32>(std::max(SDL_GetNumJoystickButtons(joystick), 0));
const int num_axes = SDL_JoystickNumAxes(joystick); const u32 num_hats = static_cast<u32>(std::max(SDL_GetNumJoystickHats(joystick), 0));
const int num_buttons = SDL_JoystickNumButtons(joystick);
cd.joy_axis_used_in_gc.resize(num_axes, false); VERBOSE_LOG("Controller {} has {} axes, {} buttons and {} hats", player_id, num_axes, num_buttons, num_hats);
cd.joy_button_used_in_gc.resize(num_buttons, false);
auto mark_bind = [&](SDL_GameControllerButtonBind bind) {
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_AXIS && bind.value.axis < num_axes)
cd.joy_axis_used_in_gc[bind.value.axis] = true;
if (bind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON && bind.value.button < num_buttons)
cd.joy_button_used_in_gc[bind.value.button] = true;
};
for (size_t i = 0; i < std::size(s_sdl_axis_names); i++)
mark_bind(SDL_GameControllerGetBindForAxis(gcontroller, static_cast<SDL_GameControllerAxis>(i)));
for (size_t i = 0; i < std::size(s_sdl_button_names); i++)
mark_bind(SDL_GameControllerGetBindForButton(gcontroller, static_cast<SDL_GameControllerButton>(i)));
VERBOSE_LOG("Controller {} has {} axes and {} buttons", player_id, num_axes, num_buttons);
}
else
{
// GC doesn't have the concept of hats, so we only need to do this for joysticks.
const int num_hats = SDL_JoystickNumHats(joystick);
if (num_hats > 0)
cd.last_hat_state.resize(static_cast<size_t>(num_hats), u8(0)); cd.last_hat_state.resize(static_cast<size_t>(num_hats), u8(0));
VERBOSE_LOG("Joystick {} has {} axes, {} buttons and {} hats", player_id, SDL_JoystickNumAxes(joystick), if (gamepad)
SDL_JoystickNumButtons(joystick), num_hats);
}
cd.use_game_controller_rumble = (gcontroller && SDL_GameControllerRumble(gcontroller, 0, 0, 0) == 0);
if (cd.use_game_controller_rumble)
{ {
VERBOSE_LOG("Rumble is supported on '{}' via gamecontroller", name); static constexpr auto map_desc = [](const SDL_GamepadBinding* binding) -> const char* {
if (binding->output_type == SDL_GAMEPAD_BINDTYPE_BUTTON &&
static_cast<u32>(binding->output.button) < SDL_GAMEPAD_BUTTON_COUNT)
{
return s_sdl_button_names[static_cast<u32>(binding->output.button)];
}
else if (binding->output_type == SDL_GAMEPAD_BINDTYPE_AXIS &&
static_cast<u32>(binding->output.axis.axis) < SDL_GAMEPAD_AXIS_COUNT)
{
return s_sdl_axis_names[static_cast<u32>(binding->output.axis.axis)];
} }
else else
{ {
SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick); return "Unknown";
}
};
// reserve the already-mapped gamepad inputs/outputs so that we don't duplicate events
cd.joy_axis_used_in_gc.resize(num_axes, false);
cd.joy_button_used_in_gc.resize(num_buttons, false);
cd.joy_hat_used_in_gc.resize(num_hats, false);
int binding_count = 0;
SDL_GamepadBinding** const bindings = SDL_GetGamepadBindings(gamepad, &binding_count);
for (int i = 0; i < binding_count; i++)
{
const SDL_GamepadBinding* binding = bindings[i];
if (binding->input_type == SDL_GAMEPAD_BINDTYPE_BUTTON)
{
const u32 joy_button_index = static_cast<u32>(binding->input.button);
if (joy_button_index < num_buttons && !cd.joy_button_used_in_gc[joy_button_index])
{
DEV_LOG("Controller {} button {} is mapped to gamepad {}", player_id, joy_button_index, map_desc(binding));
cd.joy_button_used_in_gc[joy_button_index] = true;
}
}
else if (binding->input_type == SDL_GAMEPAD_BINDTYPE_AXIS)
{
const u32 joy_axis_index = static_cast<u32>(binding->output.axis.axis);
if (joy_axis_index < num_axes && !cd.joy_axis_used_in_gc[joy_axis_index])
{
DEV_LOG("Controller {} axis {} is mapped to gamepad {}", player_id, joy_axis_index, map_desc(binding));
cd.joy_axis_used_in_gc[joy_axis_index] = true;
}
}
else if (binding->input_type == SDL_GAMEPAD_BINDTYPE_HAT)
{
const u32 joy_hat_index = static_cast<u32>(binding->input.hat.hat);
if (joy_hat_index < num_hats && !cd.joy_hat_used_in_gc[joy_hat_index])
{
DEV_LOG("Controller {} hat {} is mapped to gamepad {}", player_id, joy_hat_index, map_desc(binding));
cd.joy_hat_used_in_gc[joy_hat_index] = true;
}
}
}
SDL_free(bindings);
}
cd.use_gamepad_rumble = (gamepad && SDL_GetBooleanProperty(properties, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false));
if (cd.use_gamepad_rumble)
{
VERBOSE_LOG("Rumble is supported on '{}' via gamepad", name);
}
else
{
SDL_Haptic* haptic = SDL_OpenHapticFromJoystick(joystick);
if (haptic) if (haptic)
{ {
SDL_HapticEffect ef = {}; SDL_HapticEffect ef = {};
ef.leftright.type = SDL_HAPTIC_LEFTRIGHT; ef.leftright.type = SDL_HAPTIC_LEFTRIGHT;
ef.leftright.length = 1000; ef.leftright.length = 1000;
int ef_id = SDL_HapticNewEffect(haptic, &ef); int ef_id = SDL_CreateHapticEffect(haptic, &ef);
if (ef_id >= 0) if (ef_id >= 0)
{ {
cd.haptic = haptic; cd.haptic = haptic;
@ -833,14 +891,14 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller)
else else
{ {
ERROR_LOG("Failed to create haptic left/right effect: {}", SDL_GetError()); ERROR_LOG("Failed to create haptic left/right effect: {}", SDL_GetError());
if (SDL_HapticRumbleSupported(haptic) && SDL_HapticRumbleInit(haptic) != 0) if (SDL_HapticRumbleSupported(haptic) && SDL_InitHapticRumble(haptic) != 0)
{ {
cd.haptic = haptic; cd.haptic = haptic;
} }
else else
{ {
ERROR_LOG("No haptic rumble supported: {}", SDL_GetError()); ERROR_LOG("No haptic rumble supported: {}", SDL_GetError());
SDL_HapticClose(haptic); SDL_CloseHaptic(haptic);
} }
} }
} }
@ -849,14 +907,12 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller)
VERBOSE_LOG("Rumble is supported on '{}' via haptic", name); VERBOSE_LOG("Rumble is supported on '{}' via haptic", name);
} }
if (!cd.haptic && !cd.use_game_controller_rumble) if (!cd.haptic && !cd.use_gamepad_rumble)
VERBOSE_LOG("Rumble is not supported on '{}'", name); VERBOSE_LOG("Rumble is not supported on '{}'", name);
if (player_id >= 0 && static_cast<u32>(player_id) < MAX_LED_COLORS && gcontroller && cd.has_led = (gamepad && SDL_GetBooleanProperty(properties, SDL_PROP_GAMEPAD_CAP_RGB_LED_BOOLEAN, false));
SDL_GameControllerHasLED(gcontroller)) if (cd.has_led && player_id >= 0 && static_cast<u32>(player_id) < MAX_LED_COLORS)
{ SetControllerRGBLED(gamepad, m_led_colors[player_id]);
SetControllerRGBLED(gcontroller, m_led_colors[player_id]);
}
m_controllers.push_back(std::move(cd)); m_controllers.push_back(std::move(cd));
@ -875,12 +931,12 @@ bool SDLInputSource::CloseDevice(int joystick_index)
fmt::format("SDL-{}", it->player_id)); fmt::format("SDL-{}", it->player_id));
if (it->haptic) if (it->haptic)
SDL_HapticClose(it->haptic); SDL_CloseHaptic(it->haptic);
if (it->game_controller) if (it->gamepad)
SDL_GameControllerClose(it->game_controller); SDL_CloseGamepad(it->gamepad);
else else
SDL_JoystickClose(it->joystick); SDL_CloseJoystick(it->joystick);
m_controllers.erase(it); m_controllers.erase(it);
return true; return true;
@ -891,7 +947,7 @@ static float NormalizeS16(s16 value)
return static_cast<float>(value) / (value < 0 ? 32768.0f : 32767.0f); return static_cast<float>(value) / (value < 0 ? 32768.0f : 32767.0f);
} }
bool SDLInputSource::HandleControllerAxisEvent(const SDL_ControllerAxisEvent* ev) bool SDLInputSource::HandleGamepadAxisMotionEvent(const SDL_GamepadAxisEvent* ev)
{ {
auto it = GetControllerDataForJoystickId(ev->which); auto it = GetControllerDataForJoystickId(ev->which);
if (it == m_controllers.end()) if (it == m_controllers.end())
@ -905,7 +961,7 @@ bool SDLInputSource::HandleControllerAxisEvent(const SDL_ControllerAxisEvent* ev
return true; return true;
} }
bool SDLInputSource::HandleControllerButtonEvent(const SDL_ControllerButtonEvent* ev) bool SDLInputSource::HandleGamepadButtonEvent(const SDL_GamepadButtonEvent* ev)
{ {
auto it = GetControllerDataForJoystickId(ev->which); auto it = GetControllerDataForJoystickId(ev->which);
if (it == m_controllers.end()) if (it == m_controllers.end())
@ -915,11 +971,11 @@ bool SDLInputSource::HandleControllerButtonEvent(const SDL_ControllerButtonEvent
const GenericInputBinding generic_key = (ev->button < s_sdl_generic_binding_button_mapping.size()) ? const GenericInputBinding generic_key = (ev->button < s_sdl_generic_binding_button_mapping.size()) ?
s_sdl_generic_binding_button_mapping[ev->button] : s_sdl_generic_binding_button_mapping[ev->button] :
GenericInputBinding::Unknown; GenericInputBinding::Unknown;
InputManager::InvokeEvents(key, (ev->state == SDL_PRESSED) ? 1.0f : 0.0f, generic_key); InputManager::InvokeEvents(key, static_cast<float>(BoolToUInt32(ev->down)), generic_key);
return true; return true;
} }
bool SDLInputSource::HandleControllerTouchpadEvent(const SDL_ControllerTouchpadEvent* ev) bool SDLInputSource::HandleGamepadTouchpadEvent(const SDL_GamepadTouchpadEvent* ev)
{ {
// More than one touchpad? // More than one touchpad?
if (ev->touchpad != 0 || !m_controller_touchpad_as_pointer) if (ev->touchpad != 0 || !m_controller_touchpad_as_pointer)
@ -938,7 +994,7 @@ bool SDLInputSource::HandleControllerTouchpadEvent(const SDL_ControllerTouchpadE
if (ev->finger == 0) if (ev->finger == 0)
{ {
// If down event, reset the position. // If down event, reset the position.
if (ev->type == SDL_CONTROLLERTOUCHPADDOWN) if (ev->type == SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN)
{ {
it->last_touch_x = ev->x; it->last_touch_x = ev->x;
it->last_touch_y = ev->y; it->last_touch_y = ev->y;
@ -962,10 +1018,10 @@ bool SDLInputSource::HandleControllerTouchpadEvent(const SDL_ControllerTouchpadE
} }
// If down/up event, fire the clicked handler. // If down/up event, fire the clicked handler.
if (ev->type == SDL_CONTROLLERTOUCHPADDOWN || ev->type == SDL_CONTROLLERTOUCHPADUP) if (ev->type == SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN || ev->type == SDL_EVENT_GAMEPAD_TOUCHPAD_UP)
{ {
const InputBindingKey key(InputManager::MakePointerButtonKey(pointer_index, static_cast<u32>(ev->finger))); const InputBindingKey key(InputManager::MakePointerButtonKey(pointer_index, static_cast<u32>(ev->finger)));
InputManager::InvokeEvents(key, (ev->type == SDL_CONTROLLERTOUCHPADUP) ? 0.0f : ev->pressure); InputManager::InvokeEvents(key, (ev->type == SDL_EVENT_GAMEPAD_TOUCHPAD_UP) ? 0.0f : ev->pressure);
} }
return true; return true;
@ -994,7 +1050,7 @@ bool SDLInputSource::HandleJoystickButtonEvent(const SDL_JoyButtonEvent* ev)
const u32 button = const u32 button =
ev->button + static_cast<u32>(std::size(s_sdl_button_names)); // Ensure we don't conflict with GC buttons ev->button + static_cast<u32>(std::size(s_sdl_button_names)); // Ensure we don't conflict with GC buttons
const InputBindingKey key(MakeGenericControllerButtonKey(InputSourceType::SDL, it->player_id, button)); const InputBindingKey key(MakeGenericControllerButtonKey(InputSourceType::SDL, it->player_id, button));
InputManager::InvokeEvents(key, (ev->state == SDL_PRESSED) ? 1.0f : 0.0f); InputManager::InvokeEvents(key, static_cast<float>(BoolToUInt32(ev->down)));
return true; return true;
} }
@ -1003,6 +1059,8 @@ bool SDLInputSource::HandleJoystickHatEvent(const SDL_JoyHatEvent* ev)
auto it = GetControllerDataForJoystickId(ev->which); auto it = GetControllerDataForJoystickId(ev->which);
if (it == m_controllers.end() || ev->hat >= it->last_hat_state.size()) if (it == m_controllers.end() || ev->hat >= it->last_hat_state.size())
return false; return false;
if (ev->hat < it->joy_hat_used_in_gc.size() && it->joy_hat_used_in_gc[ev->hat])
return false; // Will get handled by GC event
const unsigned long last_direction = it->last_hat_state[ev->hat]; const unsigned long last_direction = it->last_hat_state[ev->hat];
it->last_hat_state[ev->hat] = ev->value; it->last_hat_state[ev->hat] = ev->value;
@ -1041,7 +1099,7 @@ InputManager::VibrationMotorList SDLInputSource::EnumerateVibrationMotors(std::o
key.source_index = cd.player_id; key.source_index = cd.player_id;
if (cd.use_game_controller_rumble || cd.haptic_left_right_effect) if (cd.use_gamepad_rumble || cd.haptic_left_right_effect)
{ {
// two motors // two motors
key.source_subtype = InputSubclass::ControllerMotor; key.source_subtype = InputSubclass::ControllerMotor;
@ -1075,7 +1133,7 @@ bool SDLInputSource::GetGenericBindingMapping(std::string_view device, GenericIn
if (it == m_controllers.end()) if (it == m_controllers.end())
return false; return false;
if (it->game_controller) if (it->gamepad)
{ {
// assume all buttons are present. // assume all buttons are present.
const s32 pid = player_id.value(); const s32 pid = player_id.value();
@ -1096,7 +1154,7 @@ bool SDLInputSource::GetGenericBindingMapping(std::string_view device, GenericIn
mapping->emplace_back(binding, fmt::format("SDL-{}/{}", pid, s_sdl_button_names[i])); mapping->emplace_back(binding, fmt::format("SDL-{}/{}", pid, s_sdl_button_names[i]));
} }
if (it->use_game_controller_rumble || it->haptic_left_right_effect) if (it->use_gamepad_rumble || it->haptic_left_right_effect)
{ {
mapping->emplace_back(GenericInputBinding::SmallMotor, fmt::format("SDL-{}/SmallMotor", pid)); mapping->emplace_back(GenericInputBinding::SmallMotor, fmt::format("SDL-{}/SmallMotor", pid));
mapping->emplace_back(GenericInputBinding::LargeMotor, fmt::format("SDL-{}/LargeMotor", pid)); mapping->emplace_back(GenericInputBinding::LargeMotor, fmt::format("SDL-{}/LargeMotor", pid));
@ -1155,9 +1213,9 @@ void SDLInputSource::SendRumbleUpdate(ControllerData* cd)
// we'll update before this duration is elapsed // we'll update before this duration is elapsed
static constexpr u32 DURATION = 65535; // SDL_MAX_RUMBLE_DURATION_MS static constexpr u32 DURATION = 65535; // SDL_MAX_RUMBLE_DURATION_MS
if (cd->use_game_controller_rumble) if (cd->use_gamepad_rumble)
{ {
SDL_GameControllerRumble(cd->game_controller, cd->rumble_intensity[0], cd->rumble_intensity[1], DURATION); SDL_RumbleGamepad(cd->gamepad, cd->rumble_intensity[0], cd->rumble_intensity[1], DURATION);
return; return;
} }
@ -1170,12 +1228,12 @@ void SDLInputSource::SendRumbleUpdate(ControllerData* cd)
ef.leftright.large_magnitude = cd->rumble_intensity[0]; ef.leftright.large_magnitude = cd->rumble_intensity[0];
ef.leftright.small_magnitude = cd->rumble_intensity[1]; ef.leftright.small_magnitude = cd->rumble_intensity[1];
ef.leftright.length = DURATION; ef.leftright.length = DURATION;
SDL_HapticUpdateEffect(cd->haptic, cd->haptic_left_right_effect, &ef); SDL_UpdateHapticEffect(cd->haptic, cd->haptic_left_right_effect, &ef);
SDL_HapticRunEffect(cd->haptic, cd->haptic_left_right_effect, SDL_HAPTIC_INFINITY); SDL_RunHapticEffect(cd->haptic, cd->haptic_left_right_effect, SDL_HAPTIC_INFINITY);
} }
else else
{ {
SDL_HapticStopEffect(cd->haptic, cd->haptic_left_right_effect); SDL_StopHapticEffect(cd->haptic, cd->haptic_left_right_effect);
} }
} }
else else
@ -1183,9 +1241,9 @@ void SDLInputSource::SendRumbleUpdate(ControllerData* cd)
const float strength = const float strength =
static_cast<float>(std::max(cd->rumble_intensity[0], cd->rumble_intensity[1])) * (1.0f / 65535.0f); static_cast<float>(std::max(cd->rumble_intensity[0], cd->rumble_intensity[1])) * (1.0f / 65535.0f);
if (strength > 0.0f) if (strength > 0.0f)
SDL_HapticRumblePlay(cd->haptic, strength, DURATION); SDL_PlayHapticRumble(cd->haptic, strength, DURATION);
else else
SDL_HapticRumbleStop(cd->haptic); SDL_StopHapticRumble(cd->haptic);
} }
} }
@ -1203,10 +1261,10 @@ std::unique_ptr<ForceFeedbackDevice> SDLInputSource::CreateForceFeedbackDevice(s
return nullptr; return nullptr;
} }
SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick); SDL_Haptic* haptic = SDL_OpenHapticFromJoystick(joystick);
if (!haptic) if (!haptic)
{ {
Error::SetStringFmt(error, "Haptic is not supported on {} ({})", device, SDL_JoystickName(joystick)); Error::SetStringFmt(error, "Haptic is not supported on {} ({})", device, SDL_GetJoystickName(joystick));
return nullptr; return nullptr;
} }
@ -1224,7 +1282,7 @@ SDLForceFeedbackDevice::~SDLForceFeedbackDevice()
{ {
DestroyEffects(); DestroyEffects();
SDL_HapticClose(m_haptic); SDL_CloseHaptic(m_haptic);
m_haptic = nullptr; m_haptic = nullptr;
} }
} }
@ -1233,20 +1291,20 @@ void SDLForceFeedbackDevice::CreateEffects(SDL_Joystick* joystick)
{ {
constexpr u32 length = 10000; // 10 seconds since NFS games seem to not issue new commands while rotating. constexpr u32 length = 10000; // 10 seconds since NFS games seem to not issue new commands while rotating.
const unsigned int supported = SDL_HapticQuery(m_haptic); const u32 features = SDL_GetHapticFeatures(m_haptic);
if (supported & SDL_HAPTIC_CONSTANT) if (features & SDL_HAPTIC_CONSTANT)
{ {
m_constant_effect.type = SDL_HAPTIC_CONSTANT; m_constant_effect.type = SDL_HAPTIC_CONSTANT;
m_constant_effect.constant.direction.type = SDL_HAPTIC_STEERING_AXIS; m_constant_effect.constant.direction.type = SDL_HAPTIC_STEERING_AXIS;
m_constant_effect.constant.length = length; m_constant_effect.constant.length = length;
m_constant_effect_id = SDL_HapticNewEffect(m_haptic, &m_constant_effect); m_constant_effect_id = SDL_CreateHapticEffect(m_haptic, &m_constant_effect);
if (m_constant_effect_id < 0) if (m_constant_effect_id < 0)
ERROR_LOG("SDL_HapticNewEffect() for constant failed: {}", SDL_GetError()); ERROR_LOG("SDL_HapticNewEffect() for constant failed: {}", SDL_GetError());
} }
else else
{ {
WARNING_LOG("Constant effect is not supported on '{}'", SDL_JoystickName(joystick)); WARNING_LOG("Constant effect is not supported on '{}'", SDL_GetJoystickName(joystick));
} }
} }
@ -1256,10 +1314,10 @@ void SDLForceFeedbackDevice::DestroyEffects()
{ {
if (m_constant_effect_running) if (m_constant_effect_running)
{ {
SDL_HapticStopEffect(m_haptic, m_constant_effect_id); SDL_StopHapticEffect(m_haptic, m_constant_effect_id);
m_constant_effect_running = false; m_constant_effect_running = false;
} }
SDL_HapticDestroyEffect(m_haptic, m_constant_effect_id); SDL_DestroyHapticEffect(m_haptic, m_constant_effect_id);
m_constant_effect_id = -1; m_constant_effect_id = -1;
} }
} }
@ -1285,13 +1343,13 @@ void SDLForceFeedbackDevice::SetConstantForce(s32 level)
if (m_constant_effect.constant.level != new_level) if (m_constant_effect.constant.level != new_level)
{ {
m_constant_effect.constant.level = new_level; m_constant_effect.constant.level = new_level;
if (SDL_HapticUpdateEffect(m_haptic, m_constant_effect_id, &m_constant_effect) != 0) if (SDL_UpdateHapticEffect(m_haptic, m_constant_effect_id, &m_constant_effect) != 0)
ERROR_LOG("SDL_HapticUpdateEffect() for constant failed: {}", SDL_GetError()); ERROR_LOG("SDL_HapticUpdateEffect() for constant failed: {}", SDL_GetError());
} }
if (!m_constant_effect_running) if (!m_constant_effect_running)
{ {
if (SDL_HapticRunEffect(m_haptic, m_constant_effect_id, SDL_HAPTIC_INFINITY) == 0) if (SDL_RunHapticEffect(m_haptic, m_constant_effect_id, SDL_HAPTIC_INFINITY) == 0)
m_constant_effect_running = true; m_constant_effect_running = true;
else else
ERROR_LOG("SDL_HapticRunEffect() for constant failed: {}", SDL_GetError()); ERROR_LOG("SDL_HapticRunEffect() for constant failed: {}", SDL_GetError());
@ -1306,7 +1364,7 @@ void SDLForceFeedbackDevice::DisableForce(Effect force)
{ {
if (m_constant_effect_running) if (m_constant_effect_running)
{ {
SDL_HapticStopEffect(m_haptic, m_constant_effect_id); SDL_StopHapticEffect(m_haptic, m_constant_effect_id);
m_constant_effect_running = false; m_constant_effect_running = false;
} }
} }

View File

@ -2,9 +2,10 @@
// SPDX-License-Identifier: CC-BY-NC-ND-4.0 // SPDX-License-Identifier: CC-BY-NC-ND-4.0
#pragma once #pragma once
#include "input_source.h" #include "input_source.h"
#include <SDL.h> #include <SDL3/SDL.h>
#include <array> #include <array>
#include <functional> #include <functional>
@ -58,7 +59,7 @@ private:
struct ControllerData struct ControllerData
{ {
SDL_Haptic* haptic; SDL_Haptic* haptic;
SDL_GameController* game_controller; SDL_Gamepad* gamepad;
SDL_Joystick* joystick; SDL_Joystick* joystick;
u16 rumble_intensity[2]; u16 rumble_intensity[2];
int haptic_left_right_effect; int haptic_left_right_effect;
@ -66,11 +67,13 @@ private:
int player_id; int player_id;
float last_touch_x; float last_touch_x;
float last_touch_y; float last_touch_y;
bool use_game_controller_rumble; bool use_gamepad_rumble : 1;
bool has_led : 1;
// Used to disable Joystick controls that are used in GameController inputs so we don't get double events // Used to disable Joystick controls that are used in GameController inputs so we don't get double events
std::vector<bool> joy_button_used_in_gc; std::vector<bool> joy_button_used_in_gc;
std::vector<bool> joy_axis_used_in_gc; std::vector<bool> joy_axis_used_in_gc;
std::vector<bool> joy_hat_used_in_gc;
// Track last hat state so we can send "unpressed" events. // Track last hat state so we can send "unpressed" events.
std::vector<u8> last_hat_state; std::vector<u8> last_hat_state;
@ -89,9 +92,9 @@ private:
bool OpenDevice(int index, bool is_gamecontroller); bool OpenDevice(int index, bool is_gamecontroller);
bool CloseDevice(int joystick_index); bool CloseDevice(int joystick_index);
bool HandleControllerAxisEvent(const SDL_ControllerAxisEvent* ev); bool HandleGamepadAxisMotionEvent(const SDL_GamepadAxisEvent* ev);
bool HandleControllerButtonEvent(const SDL_ControllerButtonEvent* ev); bool HandleGamepadButtonEvent(const SDL_GamepadButtonEvent* ev);
bool HandleControllerTouchpadEvent(const SDL_ControllerTouchpadEvent* ev); bool HandleGamepadTouchpadEvent(const SDL_GamepadTouchpadEvent* ev);
bool HandleJoystickAxisEvent(const SDL_JoyAxisEvent* ev); bool HandleJoystickAxisEvent(const SDL_JoyAxisEvent* ev);
bool HandleJoystickButtonEvent(const SDL_JoyButtonEvent* ev); bool HandleJoystickButtonEvent(const SDL_JoyButtonEvent* ev);
bool HandleJoystickHatEvent(const SDL_JoyHatEvent* ev); bool HandleJoystickHatEvent(const SDL_JoyHatEvent* ev);

View File

@ -22,10 +22,10 @@
<!-- Dependency linking and DLL copying --> <!-- Dependency linking and DLL copying -->
<ItemDefinitionGroup> <ItemDefinitionGroup>
<ClCompile> <ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)SDL2;$(DepsIncludeDir)spirv_cross</AdditionalIncludeDirectories> <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)spirv_cross</AdditionalIncludeDirectories>
</ClCompile> </ClCompile>
<Link> <Link>
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lunasvg.lib;SDL2.lib;soundtouch.lib;zlib.lib;zstd.lib</AdditionalDependencies> <AdditionalDependencies>%(AdditionalDependencies);freetype.lib;jpeg.lib;libpng16.lib;libwebp.lib;lunasvg.lib;SDL3.lib;soundtouch.lib;zlib.lib;zstd.lib</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
@ -40,7 +40,7 @@
<DepsDLLs Include="$(DepsBinDir)libsharpyuv.dll" /> <DepsDLLs Include="$(DepsBinDir)libsharpyuv.dll" />
<DepsDLLs Include="$(DepsBinDir)libwebp.dll" /> <DepsDLLs Include="$(DepsBinDir)libwebp.dll" />
<DepsDLLs Include="$(DepsBinDir)lunasvg.dll" /> <DepsDLLs Include="$(DepsBinDir)lunasvg.dll" />
<DepsDLLs Include="$(DepsBinDir)SDL2.dll" /> <DepsDLLs Include="$(DepsBinDir)SDL3.dll" />
<DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" /> <DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" />
<DepsDLLs Include="$(DepsBinDir)soundtouch.dll" /> <DepsDLLs Include="$(DepsBinDir)soundtouch.dll" />
<DepsDLLs Include="$(DepsBinDir)spirv-cross-c-shared.dll" /> <DepsDLLs Include="$(DepsBinDir)spirv-cross-c-shared.dll" />