mirror of https://github.com/PCSX2/pcsx2.git
Deps: Update to SDL3 (#12311)
Co-authored-by: TheTechnician27 <TheTechnician27@users.noreply.github.com>
This commit is contained in:
parent
582bba6c91
commit
ac1a6d3348
|
@ -19,7 +19,7 @@ LIBJPEG=9f
|
|||
LIBPNG=1.6.45
|
||||
LIBWEBP=1.5.0
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
SDL=SDL2-2.30.12
|
||||
SDL=SDL3-3.2.6
|
||||
QT=6.8.2
|
||||
ZSTD=1.5.7
|
||||
|
||||
|
@ -37,7 +37,7 @@ fd6f417fe9e3a071cf1424a5152d926a34c4a3c5070745470be6cf12a404ed79 $LIBBACKTRACE.
|
|||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c libwebp-$LIBWEBP.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $SDL.tar.gz
|
||||
096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
012043ce6d411e6e8a91fdc4e05e6bedcfa10fcb1347d3c33908f7fdd10dfe05 qtbase-everywhere-src-$QT.tar.xz
|
||||
d2a1bbb84707b8a0aec29227b170be00f04383fbf2361943596d09e7e443c8e1 qtimageformats-everywhere-src-$QT.tar.xz
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "sdl2",
|
||||
"name": "sdl3",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"builddir": true,
|
||||
"config-opts": [
|
||||
|
@ -14,8 +14,8 @@
|
|||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://libsdl.org/release/SDL2-2.30.12.tar.gz",
|
||||
"sha256": "ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea"
|
||||
"url": "https://libsdl.org/release/SDL3-3.2.6.tar.gz",
|
||||
"sha256": "096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a"
|
||||
}
|
||||
],
|
||||
"cleanup": [
|
|
@ -26,7 +26,7 @@
|
|||
],
|
||||
"modules": [
|
||||
"modules/10-libpcap.json",
|
||||
"modules/20-sdl2.json",
|
||||
"modules/20-sdl3.json",
|
||||
"modules/21-libbacktrace.json",
|
||||
"modules/22-shaderc.json",
|
||||
{
|
||||
|
|
|
@ -40,7 +40,7 @@ fi
|
|||
|
||||
FREETYPE=2.13.3
|
||||
HARFBUZZ=10.0.1
|
||||
SDL=SDL2-2.30.12
|
||||
SDL=SDL3-3.2.6
|
||||
ZSTD=1.5.7
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.45
|
||||
|
@ -76,7 +76,7 @@ CMAKE_ARCH_UNIVERSAL=-DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"
|
|||
cat > SHASUMS <<EOF
|
||||
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $SDL.tar.gz
|
||||
096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
|
|
|
@ -22,7 +22,7 @@ fi
|
|||
|
||||
FREETYPE=2.13.3
|
||||
HARFBUZZ=10.0.1
|
||||
SDL=SDL2-2.30.12
|
||||
SDL=SDL3-3.2.6
|
||||
ZSTD=1.5.7
|
||||
LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
LIBPNG=1.6.45
|
||||
|
@ -56,7 +56,7 @@ CMAKE_COMMON=(
|
|||
cat > SHASUMS <<EOF
|
||||
0550350666d427c74daeb85d5ac7bb353acba5f76956395995311a9c6f063289 freetype-$FREETYPE.tar.xz
|
||||
e7358ea86fe10fb9261931af6f010d4358dac64f7074420ca9bc94aae2bdd542 harfbuzz-$HARFBUZZ.tar.gz
|
||||
ac356ea55e8b9dd0b2d1fa27da40ef7e238267ccf9324704850d5d47375b48ea $SDL.tar.gz
|
||||
096a0b843dd1124afda41c24bd05034af75af37e9a1b9d205cc0a70193b27e1a $SDL.tar.gz
|
||||
eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3 zstd-$ZSTD.tar.gz
|
||||
0728800155f3ed0a0c87e03addbd30ecbe374f7b080678bbca1506051d50dec3 $LZ4.tar.gz
|
||||
926485350139ffb51ef69760db35f78846c805fef3d59bfdcb2fba704663f370 libpng-$LIBPNG.tar.xz
|
||||
|
|
|
@ -49,7 +49,7 @@ set LIBPNG=1645
|
|||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.8.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.12
|
||||
set SDL=SDL3-3.2.6
|
||||
set WEBP=1.5.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
|
@ -66,7 +66,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
|
|||
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" aa2808d0f2dc6b383c6689bf6d166e2de62db4d58be989e4b052acb31df0fba3 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 665e5aa2a613affe099a38d61257ecc5ef4bf38b109d915147aa8b005399d68a || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
|
||||
|
@ -179,7 +179,7 @@ cd "%SDL%" || 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 --build build --parallel || 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
|
||||
|
||||
if %DEBUG%==1 (
|
||||
|
|
|
@ -47,7 +47,7 @@ set LIBPNG=1645
|
|||
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
|
||||
set QT=6.8.2
|
||||
set QTMINOR=6.8
|
||||
set SDL=SDL2-2.30.12
|
||||
set SDL=SDL3-3.2.6
|
||||
set WEBP=1.5.0
|
||||
set ZLIB=1.3.1
|
||||
set ZLIBSHORT=131
|
||||
|
@ -64,7 +64,7 @@ call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lp
|
|||
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
|
||||
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 7d6fab70cf844bf6769077bd5d7a74893f8ffd4dfb42861745750c63c2a5c92c || goto error
|
||||
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" aa2808d0f2dc6b383c6689bf6d166e2de62db4d58be989e4b052acb31df0fba3 || goto error
|
||||
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 665e5aa2a613affe099a38d61257ecc5ef4bf38b109d915147aa8b005399d68a || goto error
|
||||
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 44087aec0caa4aa81437e787917d29d97536484a682a5d51ec035878e57c0b5c || goto error
|
||||
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 83c72b5dfad04854acf61d592e3f9cdc2ed894779aab8d0470d966715266caaf || goto error
|
||||
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 144d55e4d199793a76c53f19872633a79aec0314039f6f99b6a10b5be7a78fbf || goto error
|
||||
|
@ -176,7 +176,7 @@ cd "%SDL%" || 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 --build build --parallel || 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
|
||||
|
||||
if %DEBUG%==1 (
|
||||
|
|
|
@ -17,7 +17,7 @@ find_package(ZLIB REQUIRED) # v1.3, but Mac uses the SDK version.
|
|||
find_package(Zstd 1.5.5 REQUIRED)
|
||||
find_package(LZ4 REQUIRED)
|
||||
find_package(WebP REQUIRED) # v1.3.2, spews an error on Linux because no pkg-config.
|
||||
find_package(SDL2 2.30.4 REQUIRED)
|
||||
find_package(SDL3 3.2.6 REQUIRED)
|
||||
find_package(Freetype 2.11.1 REQUIRED)
|
||||
|
||||
if(USE_VULKAN)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<ItemDefinitionGroup>
|
||||
<Link>
|
||||
<AdditionalLibraryDirectories>$(DepsLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;libjpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL2.lib;zlib.lib;zstd.lib</AdditionalDependencies>
|
||||
<AdditionalDependencies>%(AdditionalDependencies);freetype.lib;libjpeg.lib;libpng16.lib;libwebp.lib;lz4.lib;SDL3.lib;zlib.lib;zstd.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -15,7 +15,7 @@
|
|||
<DepsDLLs Include="$(DepsBinDir)libsharpyuv.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)libwebp.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)lz4.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)SDL2.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)SDL3.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)shaderc_shared.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)zlib1.dll" />
|
||||
<DepsDLLs Include="$(DepsBinDir)zstd.dll" />
|
||||
|
|
|
@ -174,6 +174,14 @@ std::unique_ptr<ProgressCallback> Host::CreateHostProgressCallback()
|
|||
return ProgressCallback::CreateNullProgressCallback();
|
||||
}
|
||||
|
||||
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
if (!title.empty() && !message.empty())
|
||||
INFO_LOG("ReportInfoAsync: {}: {}", title, message);
|
||||
else if (!message.empty())
|
||||
INFO_LOG("ReportInfoAsync: {}", message);
|
||||
}
|
||||
|
||||
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
if (!title.empty() && !message.empty())
|
||||
|
|
|
@ -1221,6 +1221,11 @@ void MainWindow::cancelGameListRefresh()
|
|||
m_game_list_widget->cancelRefresh();
|
||||
}
|
||||
|
||||
void MainWindow::reportInfo(const QString& title, const QString& message)
|
||||
{
|
||||
QMessageBox::information(this, title, message);
|
||||
}
|
||||
|
||||
void MainWindow::reportError(const QString& title, const QString& message)
|
||||
{
|
||||
QMessageBox::critical(this, title, message);
|
||||
|
|
|
@ -109,6 +109,7 @@ public Q_SLOTS:
|
|||
void checkForUpdates(bool display_message, bool force_check);
|
||||
void refreshGameList(bool invalidate_cache);
|
||||
void cancelGameListRefresh();
|
||||
void reportInfo(const QString& title, const QString& message);
|
||||
void reportError(const QString& title, const QString& message);
|
||||
bool confirmMessage(const QString& title, const QString& message);
|
||||
void onStatusMessage(const QString& message);
|
||||
|
|
|
@ -1612,6 +1612,18 @@ bool QtHost::DownloadFile(QWidget* parent, const QString& title, std::string url
|
|||
return true;
|
||||
}
|
||||
|
||||
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
if (!title.empty() && !message.empty())
|
||||
INFO_LOG("ReportInfoAsync: {}: {}", title, message);
|
||||
else if (!message.empty())
|
||||
INFO_LOG("ReportInfoAsync: {}", message);
|
||||
|
||||
QMetaObject::invokeMethod(g_main_window, "reportInfo", Qt::QueuedConnection,
|
||||
Q_ARG(const QString&, title.empty() ? QString() : QString::fromUtf8(title.data(), title.size())),
|
||||
Q_ARG(const QString&, message.empty() ? QString() : QString::fromUtf8(message.data(), message.size())));
|
||||
}
|
||||
|
||||
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
if (!title.empty() && !message.empty())
|
||||
|
|
|
@ -19,7 +19,7 @@ ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent,
|
|||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", true);
|
||||
connect(m_ui.enableSDLSource, &QCheckBox::checkStateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
|
||||
connect(m_ui.ledSettings, &QToolButton::clicked, this, &ControllerGlobalSettingsWidget::ledSettingsClicked);
|
||||
|
||||
|
@ -146,7 +146,7 @@ ControllerLEDSettingsDialog::ControllerLEDSettingsDialog(QWidget* parent, Contro
|
|||
|
||||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources", "SDLPS5PlayerLED", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.enableSDLPS5PlayerLED, "InputSources", "SDLPS5PlayerLED", true);
|
||||
connect(m_ui.buttonBox->button(QDialogButtonBox::Close), &QPushButton::clicked, this, &QDialog::accept);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,13 +16,14 @@
|
|||
#include <bit>
|
||||
|
||||
InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name,
|
||||
std::string key_name, std::vector<std::string> bindings, QWidget* parent)
|
||||
std::string key_name, std::vector<std::string> bindings_settings, std::vector<std::string> bindings_ui, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_sif(sif)
|
||||
, m_bind_type(bind_type)
|
||||
, m_section_name(std::move(section_name))
|
||||
, m_key_name(std::move(key_name))
|
||||
, m_bindings(std::move(bindings))
|
||||
, m_bindings_settings(std::move(bindings_settings))
|
||||
, m_bindings_ui(std::move(bindings_ui))
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
m_ui.title->setText(tr("Bindings for %1 %2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name)));
|
||||
|
@ -32,6 +33,8 @@ InputBindingDialog::InputBindingDialog(SettingsInterface* sif, InputBindingInfo:
|
|||
connect(m_ui.removeBinding, &QPushButton::clicked, this, &InputBindingDialog::onRemoveBindingButtonClicked);
|
||||
connect(m_ui.clearBindings, &QPushButton::clicked, this, &InputBindingDialog::onClearBindingsButtonClicked);
|
||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, [this]() { done(0); });
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &InputBindingDialog::onInputDeviceConnected);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &InputBindingDialog::onInputDeviceDisconnected);
|
||||
updateList();
|
||||
|
||||
// Only show the sensitivity controls for binds where it's applicable.
|
||||
|
@ -210,11 +213,17 @@ void InputBindingDialog::addNewBinding()
|
|||
const std::string new_binding(InputManager::ConvertInputBindingKeysToString(m_bind_type, m_new_bindings.data(), m_new_bindings.size()));
|
||||
if (!new_binding.empty())
|
||||
{
|
||||
if (std::find(m_bindings.begin(), m_bindings.end(), new_binding) != m_bindings.end())
|
||||
if (std::find(m_bindings_settings.begin(), m_bindings_settings.end(), new_binding) != m_bindings_settings.end())
|
||||
return;
|
||||
|
||||
m_ui.bindingList->addItem(QString::fromStdString(new_binding));
|
||||
m_bindings.push_back(std::move(new_binding));
|
||||
m_bindings_settings.push_back(std::move(new_binding));
|
||||
|
||||
SmallString new_binding_temp{std::string_view{new_binding}};
|
||||
InputManager::PrettifyInputBinding(new_binding_temp, false);
|
||||
std::string new_binding_ui{new_binding_temp};
|
||||
|
||||
m_bindings_ui.push_back(new_binding_ui);
|
||||
m_ui.bindingList->addItem(QString::fromStdString(new_binding_ui));
|
||||
saveListToSettings();
|
||||
}
|
||||
}
|
||||
|
@ -230,17 +239,19 @@ void InputBindingDialog::onAddBindingButtonClicked()
|
|||
void InputBindingDialog::onRemoveBindingButtonClicked()
|
||||
{
|
||||
const int row = m_ui.bindingList->currentRow();
|
||||
if (row < 0 || static_cast<size_t>(row) >= m_bindings.size())
|
||||
if (row < 0 || static_cast<size_t>(row) >= m_bindings_ui.size())
|
||||
return;
|
||||
|
||||
m_bindings.erase(m_bindings.begin() + row);
|
||||
m_bindings_settings.erase(m_bindings_settings.begin() + row);
|
||||
m_bindings_ui.erase(m_bindings_ui.begin() + row);
|
||||
delete m_ui.bindingList->takeItem(row);
|
||||
saveListToSettings();
|
||||
}
|
||||
|
||||
void InputBindingDialog::onClearBindingsButtonClicked()
|
||||
{
|
||||
m_bindings.clear();
|
||||
m_bindings_settings.clear();
|
||||
m_bindings_ui.clear();
|
||||
m_ui.bindingList->clear();
|
||||
saveListToSettings();
|
||||
}
|
||||
|
@ -248,7 +259,7 @@ void InputBindingDialog::onClearBindingsButtonClicked()
|
|||
void InputBindingDialog::updateList()
|
||||
{
|
||||
m_ui.bindingList->clear();
|
||||
for (const std::string& binding : m_bindings)
|
||||
for (const std::string& binding : m_bindings_ui)
|
||||
m_ui.bindingList->addItem(QString::fromStdString(binding));
|
||||
}
|
||||
|
||||
|
@ -256,8 +267,8 @@ void InputBindingDialog::saveListToSettings()
|
|||
{
|
||||
if (m_sif)
|
||||
{
|
||||
if (!m_bindings.empty())
|
||||
m_sif->SetStringList(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
|
||||
if (!m_bindings_settings.empty())
|
||||
m_sif->SetStringList(m_section_name.c_str(), m_key_name.c_str(), m_bindings_settings);
|
||||
else
|
||||
m_sif->DeleteValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
m_sif->Save();
|
||||
|
@ -265,8 +276,8 @@ void InputBindingDialog::saveListToSettings()
|
|||
}
|
||||
else
|
||||
{
|
||||
if (!m_bindings.empty())
|
||||
Host::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
|
||||
if (!m_bindings_settings.empty())
|
||||
Host::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings_settings);
|
||||
else
|
||||
Host::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
Host::CommitBaseSettingChanges();
|
||||
|
@ -337,6 +348,16 @@ void InputBindingDialog::onDeadzoneChanged(int value)
|
|||
m_ui.deadzoneValue->setText(tr("%1%").arg(value));
|
||||
}
|
||||
|
||||
void InputBindingDialog::onInputDeviceConnected(const QString& identifier, const QString& device_name)
|
||||
{
|
||||
ReloadBindNames();
|
||||
}
|
||||
|
||||
void InputBindingDialog::onInputDeviceDisconnected(const QString& identifier)
|
||||
{
|
||||
ReloadBindNames();
|
||||
}
|
||||
|
||||
void InputBindingDialog::hookInputManager()
|
||||
{
|
||||
InputManager::SetHook([this](InputBindingKey key, float value) {
|
||||
|
@ -349,3 +370,17 @@ void InputBindingDialog::unhookInputManager()
|
|||
{
|
||||
InputManager::RemoveHook();
|
||||
}
|
||||
|
||||
void InputBindingDialog::ReloadBindNames()
|
||||
{
|
||||
m_bindings_ui.clear();
|
||||
m_bindings_ui.reserve(m_bindings_settings.size());
|
||||
for (int i = 0; i < m_bindings_settings.size(); i++)
|
||||
{
|
||||
SmallString binding{std::string_view{m_bindings_settings[i]}};
|
||||
InputManager::PrettifyInputBinding(binding, false);
|
||||
m_bindings_ui.push_back(std::string{binding});
|
||||
}
|
||||
|
||||
updateList();
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ class InputBindingDialog : public QDialog
|
|||
|
||||
public:
|
||||
InputBindingDialog(SettingsInterface* sif, InputBindingInfo::Type bind_type, std::string section_name, std::string key_name,
|
||||
std::vector<std::string> bindings, QWidget* parent);
|
||||
std::vector<std::string> bindings_settings, std::vector<std::string> bindings_ui, QWidget* parent);
|
||||
~InputBindingDialog();
|
||||
|
||||
protected Q_SLOTS:
|
||||
|
@ -35,6 +35,9 @@ protected Q_SLOTS:
|
|||
void onSensitivityChanged(int value);
|
||||
void onDeadzoneChanged(int value);
|
||||
|
||||
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
|
||||
void onInputDeviceDisconnected(const QString& identifier);
|
||||
|
||||
protected:
|
||||
enum : u32
|
||||
{
|
||||
|
@ -55,13 +58,16 @@ protected:
|
|||
void hookInputManager();
|
||||
void unhookInputManager();
|
||||
|
||||
void ReloadBindNames();
|
||||
|
||||
Ui::InputBindingDialog m_ui;
|
||||
|
||||
SettingsInterface* m_sif;
|
||||
InputBindingInfo::Type m_bind_type;
|
||||
std::string m_section_name;
|
||||
std::string m_key_name;
|
||||
std::vector<std::string> m_bindings;
|
||||
std::vector<std::string> m_bindings_settings;
|
||||
std::vector<std::string> m_bindings_ui;
|
||||
std::vector<InputBindingKey> m_new_bindings;
|
||||
std::vector<std::pair<InputBindingKey, std::pair<float, float>>> m_value_ranges;
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ InputBindingWidget::InputBindingWidget(QWidget* parent)
|
|||
: QPushButton(parent)
|
||||
{
|
||||
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &InputBindingWidget::onInputDeviceConnected);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &InputBindingWidget::onInputDeviceDisconnected);
|
||||
}
|
||||
|
||||
InputBindingWidget::InputBindingWidget(
|
||||
|
@ -33,6 +35,8 @@ InputBindingWidget::InputBindingWidget(
|
|||
setMaximumWidth(225);
|
||||
|
||||
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &InputBindingWidget::onInputDeviceConnected);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceDisconnected, this, &InputBindingWidget::onInputDeviceDisconnected);
|
||||
|
||||
initialize(sif, bind_type, std::move(section_name), std::move(key_name));
|
||||
}
|
||||
|
@ -62,20 +66,20 @@ void InputBindingWidget::updateText()
|
|||
const QString binding_tip(tr("\n\nLeft click to assign a new button\nShift + left click for additional bindings"));
|
||||
const QString binding_clear_tip(tr("\nRight click to clear binding"));
|
||||
|
||||
if (m_bindings.empty())
|
||||
if (m_bindings_ui.empty())
|
||||
{
|
||||
setText(QString());
|
||||
|
||||
setToolTip(tr("No bindings registered") + binding_tip);
|
||||
}
|
||||
else if (m_bindings.size() > 1)
|
||||
else if (m_bindings_ui.size() > 1)
|
||||
{
|
||||
setText(tr("%n bindings", "", static_cast<int>(m_bindings.size())));
|
||||
setText(tr("%n bindings", "", static_cast<int>(m_bindings_ui.size())));
|
||||
|
||||
// keep the full thing for the tooltip
|
||||
std::stringstream ss;
|
||||
bool first = true;
|
||||
for (const std::string& binding : m_bindings)
|
||||
for (const std::string& binding : m_bindings_ui)
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
|
@ -87,7 +91,7 @@ void InputBindingWidget::updateText()
|
|||
}
|
||||
else
|
||||
{
|
||||
QString binding_text(QString::fromStdString(m_bindings[0]));
|
||||
QString binding_text(QString::fromStdString(m_bindings_ui[0]));
|
||||
setToolTip(binding_text + binding_tip + binding_clear_tip);
|
||||
|
||||
// fix up accelerators, and if it's too long, ellipsise it
|
||||
|
@ -232,13 +236,12 @@ void InputBindingWidget::setNewBinding()
|
|||
}
|
||||
}
|
||||
|
||||
m_bindings.clear();
|
||||
m_bindings.push_back(std::move(new_binding));
|
||||
m_bindings_ui.clear();
|
||||
m_bindings_ui.push_back(std::move(new_binding));
|
||||
}
|
||||
|
||||
void InputBindingWidget::clearBinding()
|
||||
{
|
||||
m_bindings.clear();
|
||||
if (m_sif)
|
||||
{
|
||||
m_sif->DeleteValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
|
@ -256,14 +259,24 @@ void InputBindingWidget::clearBinding()
|
|||
|
||||
void InputBindingWidget::reloadBinding()
|
||||
{
|
||||
m_bindings = m_sif ? m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) :
|
||||
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
|
||||
m_bindings_settings = m_sif ? m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) :
|
||||
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
|
||||
|
||||
m_bindings_ui.clear();
|
||||
m_bindings_ui.reserve(m_bindings_settings.size());
|
||||
for (int i = 0; i < m_bindings_settings.size(); i++)
|
||||
{
|
||||
SmallString binding{std::string_view{m_bindings_settings[i]}};
|
||||
InputManager::PrettifyInputBinding(binding, false);
|
||||
m_bindings_ui.push_back(std::string{binding});
|
||||
}
|
||||
|
||||
updateText();
|
||||
}
|
||||
|
||||
void InputBindingWidget::onClicked()
|
||||
{
|
||||
if (m_bindings.size() > 1)
|
||||
if (m_bindings_ui.size() > 1)
|
||||
{
|
||||
openDialog();
|
||||
return;
|
||||
|
@ -376,6 +389,16 @@ void InputBindingWidget::inputManagerHookCallback(InputBindingKey key, float val
|
|||
}
|
||||
}
|
||||
|
||||
void InputBindingWidget::onInputDeviceConnected(const QString& identifier, const QString& device_name)
|
||||
{
|
||||
reloadBinding();
|
||||
}
|
||||
|
||||
void InputBindingWidget::onInputDeviceDisconnected(const QString& identifier)
|
||||
{
|
||||
reloadBinding();
|
||||
}
|
||||
|
||||
void InputBindingWidget::hookInputManager()
|
||||
{
|
||||
InputManager::SetHook([this](InputBindingKey key, float value) {
|
||||
|
@ -391,7 +414,7 @@ void InputBindingWidget::unhookInputManager()
|
|||
|
||||
void InputBindingWidget::openDialog()
|
||||
{
|
||||
InputBindingDialog binding_dialog(m_sif, m_bind_type, m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this));
|
||||
InputBindingDialog binding_dialog(m_sif, m_bind_type, m_section_name, m_key_name, m_bindings_settings, m_bindings_ui, QtUtils::GetRootWidget(this));
|
||||
binding_dialog.exec();
|
||||
reloadBinding();
|
||||
}
|
||||
|
@ -422,6 +445,12 @@ void InputVibrationBindingWidget::setKey(ControllerSettingsWindow* dialog, std::
|
|||
m_section_name = std::move(section_name);
|
||||
m_key_name = std::move(key_name);
|
||||
m_binding = Host::GetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
|
||||
SmallString binding{std::string_view{m_binding}};
|
||||
|
||||
if (InputManager::PrettifyInputBinding(binding, false))
|
||||
m_binding = binding;
|
||||
|
||||
setText(QString::fromStdString(m_binding));
|
||||
}
|
||||
|
||||
|
@ -440,12 +469,22 @@ void InputVibrationBindingWidget::onClicked()
|
|||
|
||||
const QString full_key(QStringLiteral("%1/%2").arg(QString::fromStdString(m_section_name)).arg(QString::fromStdString(m_key_name)));
|
||||
const QString current(QString::fromStdString(m_binding));
|
||||
QStringList input_options(m_dialog->getVibrationMotors());
|
||||
if (!current.isEmpty() && input_options.indexOf(current) < 0)
|
||||
QStringList input_setting_options(m_dialog->getVibrationMotors());
|
||||
QStringList input_ui_options;
|
||||
input_ui_options.reserve(input_setting_options.count());
|
||||
|
||||
for (QString motor : input_setting_options)
|
||||
{
|
||||
input_options.append(current);
|
||||
SmallStringBase motor_ui(motor.toStdString());
|
||||
InputManager::PrettifyInputBinding(motor_ui, false);
|
||||
input_ui_options.push_back(QString(motor_ui));
|
||||
}
|
||||
else if (input_options.isEmpty())
|
||||
|
||||
if (!current.isEmpty() && input_ui_options.indexOf(current) < 0)
|
||||
{
|
||||
input_setting_options.append(current);
|
||||
}
|
||||
else if (input_setting_options.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"), tr("No devices with vibration motors were detected."));
|
||||
return;
|
||||
|
@ -457,16 +496,25 @@ void InputVibrationBindingWidget::onClicked()
|
|||
input_dialog.setInputMode(QInputDialog::TextInput);
|
||||
input_dialog.setOptions(QInputDialog::UseListViewForComboBoxItems);
|
||||
input_dialog.setComboBoxEditable(false);
|
||||
input_dialog.setComboBoxItems(std::move(input_options));
|
||||
input_dialog.setComboBoxItems(std::move(input_ui_options));
|
||||
input_dialog.setTextValue(current);
|
||||
if (input_dialog.exec() == 0)
|
||||
return;
|
||||
|
||||
const QString new_value(input_dialog.textValue());
|
||||
m_binding = new_value.toStdString();
|
||||
Host::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_binding.c_str());
|
||||
Host::CommitBaseSettingChanges();
|
||||
setText(new_value);
|
||||
// If a controller is unplugged, we won't have the setting string to save
|
||||
// Skip saving if selected is an existing bind from an unplugged controller
|
||||
const int selected = input_setting_options.indexOf(input_dialog.textValue());
|
||||
if (selected >= 0)
|
||||
{
|
||||
// Update config
|
||||
const std::string new_setting_value(input_setting_options[selected].toStdString());
|
||||
Host::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), new_setting_value.c_str());
|
||||
Host::CommitBaseSettingChanges();
|
||||
// Update ui
|
||||
const QString new_ui_value(input_dialog.textValue());
|
||||
m_binding = new_ui_value.toStdString();
|
||||
setText(new_ui_value);
|
||||
}
|
||||
}
|
||||
|
||||
void InputVibrationBindingWidget::mouseReleaseEvent(QMouseEvent* e)
|
||||
|
|
|
@ -39,6 +39,9 @@ protected Q_SLOTS:
|
|||
void onInputListenTimerTimeout();
|
||||
void inputManagerHookCallback(InputBindingKey key, float value);
|
||||
|
||||
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
|
||||
void onInputDeviceDisconnected(const QString& identifier);
|
||||
|
||||
protected:
|
||||
enum : u32
|
||||
{
|
||||
|
@ -65,7 +68,8 @@ protected:
|
|||
InputBindingInfo::Type m_bind_type = InputBindingInfo::Type::Unknown;
|
||||
std::string m_section_name;
|
||||
std::string m_key_name;
|
||||
std::vector<std::string> m_bindings;
|
||||
std::vector<std::string> m_bindings_settings;
|
||||
std::vector<std::string> m_bindings_ui;
|
||||
std::vector<InputBindingKey> m_new_bindings;
|
||||
std::vector<std::pair<InputBindingKey, std::pair<float, float>>> m_value_ranges;
|
||||
QTimer* m_input_listen_timer = nullptr;
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL2</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL3</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\lzma\include</AdditionalIncludeDirectories>
|
||||
|
|
|
@ -1146,7 +1146,7 @@ target_link_libraries(PCSX2_FLAGS INTERFACE
|
|||
discord-rpc
|
||||
simpleini
|
||||
freesurround
|
||||
SDL2::SDL2
|
||||
SDL3::SDL3
|
||||
ZLIB::ZLIB
|
||||
LZ4::LZ4
|
||||
SoundTouch::SoundTouch
|
||||
|
@ -1282,7 +1282,7 @@ function(setup_main_executable target)
|
|||
|
||||
# Copy dependency libraries.
|
||||
set(DEPS_BINDIR "${CMAKE_SOURCE_DIR}/deps/bin")
|
||||
set(DEPS_TO_COPY freetype.dll harfbuzz.dll libjpeg.dll libpng16.dll libsharpyuv.dll libwebp.dll lz4.dll SDL2.dll shaderc_shared.dll zlib1.dll zstd.dll)
|
||||
set(DEPS_TO_COPY freetype.dll harfbuzz.dll libjpeg.dll libpng16.dll libsharpyuv.dll libwebp.dll lz4.dll SDL3.dll shaderc_shared.dll zlib1.dll zstd.dll)
|
||||
foreach(DEP_TO_COPY ${DEPS_TO_COPY})
|
||||
install(FILES "${DEPS_BINDIR}/${DEP_TO_COPY}" DESTINATION "${CMAKE_SOURCE_DIR}/bin")
|
||||
endforeach()
|
||||
|
|
|
@ -138,6 +138,15 @@ void Host::ClearTranslationCache()
|
|||
s_translation_string_mutex.unlock();
|
||||
}
|
||||
|
||||
void Host::ReportFormattedInfoAsync(const std::string_view title, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
va_start(ap, format);
|
||||
std::string message(StringUtil::StdStringFromFormatV(format, ap));
|
||||
va_end(ap);
|
||||
ReportInfoAsync(title, message);
|
||||
}
|
||||
|
||||
void Host::ReportFormattedErrorAsync(const std::string_view title, const char* format, ...)
|
||||
{
|
||||
std::va_list ap;
|
||||
|
|
|
@ -55,6 +55,10 @@ namespace Host
|
|||
void RemoveKeyedOSDMessage(std::string key);
|
||||
void ClearOSDMessages();
|
||||
|
||||
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
|
||||
void ReportInfoAsync(const std::string_view title, const std::string_view message);
|
||||
void ReportFormattedInfoAsync(const std::string_view title, const char* format, ...);
|
||||
|
||||
/// Displays an asynchronous error on the UI thread, i.e. doesn't block the caller.
|
||||
void ReportErrorAsync(const std::string_view title, const std::string_view message);
|
||||
void ReportFormattedErrorAsync(const std::string_view title, const char* format, ...);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#include "common/Console.h"
|
||||
#include "common/Error.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -23,11 +23,11 @@ namespace
|
|||
void CloseDevice();
|
||||
|
||||
protected:
|
||||
__fi bool IsOpen() const { return (m_device_id != 0); }
|
||||
__fi bool IsOpen() const { return (m_stream != nullptr); }
|
||||
|
||||
static void AudioCallback(void* userdata, uint8_t* stream, int len);
|
||||
static void AudioCallback(void* userdata, SDL_AudioStream* stream, int additional_amount, int total_amount);
|
||||
|
||||
u32 m_device_id = 0;
|
||||
SDL_AudioStream* m_stream = nullptr;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -41,7 +41,7 @@ static bool InitializeSDLAudio(Error* error)
|
|||
SDL_SetHint("SDL_AUDIO_DEVICE_APP_NAME", "PCSX2");
|
||||
|
||||
// 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());
|
||||
return false;
|
||||
|
@ -102,27 +102,24 @@ bool SDLAudioStream::OpenDevice(bool stretch_enabled, Error* error)
|
|||
READ_CHANNEL_REAR_LEFT, READ_CHANNEL_REAR_RIGHT>,
|
||||
}};
|
||||
|
||||
SDL_AudioSpec spec = {};
|
||||
spec.freq = m_sample_rate;
|
||||
spec.channels = m_output_channels;
|
||||
spec.format = AUDIO_S16;
|
||||
spec.samples = static_cast<Uint16>(GetBufferSizeForMS(
|
||||
m_sample_rate, (m_parameters.minimal_output_latency) ? m_parameters.buffer_ms : m_parameters.output_latency_ms));
|
||||
spec.callback = AudioCallback;
|
||||
spec.userdata = static_cast<void*>(this);
|
||||
uint samples = GetBufferSizeForMS(
|
||||
m_sample_rate, (m_parameters.minimal_output_latency) ? m_parameters.buffer_ms : m_parameters.output_latency_ms);
|
||||
|
||||
SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, fmt::format("{}", samples).c_str());
|
||||
|
||||
const SDL_AudioSpec spec = {SDL_AUDIO_S16LE, m_output_channels, static_cast<int>(m_sample_rate)};
|
||||
m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, AudioCallback, static_cast<void*>(this));
|
||||
|
||||
SDL_AudioSpec obtained_spec = {};
|
||||
m_device_id = SDL_OpenAudioDevice(nullptr, 0, &spec, &obtained_spec, SDL_AUDIO_ALLOW_SAMPLES_CHANGE);
|
||||
if (m_device_id == 0)
|
||||
{
|
||||
Error::SetStringFmt(error, "SDL_OpenAudioDevice() failed: {}", SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
int obtained_samples = 0;
|
||||
|
||||
DEV_LOG("Requested {} frame buffer, got {} frame buffer", spec.samples, obtained_spec.samples);
|
||||
if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &obtained_spec, &obtained_samples))
|
||||
DEV_LOG("Requested {} frame buffer, got {} frame buffer", samples, obtained_samples);
|
||||
else
|
||||
DEV_LOG("SDL_GetAudioDeviceFormat() failed {}", SDL_GetError());
|
||||
|
||||
BaseInitialize(sample_readers[static_cast<size_t>(m_parameters.expansion_mode)], stretch_enabled);
|
||||
SDL_PauseAudioDevice(m_device_id, 0);
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -132,20 +129,33 @@ void SDLAudioStream::SetPaused(bool paused)
|
|||
if (m_paused == paused)
|
||||
return;
|
||||
|
||||
SDL_PauseAudioDevice(m_device_id, paused ? 1 : 0);
|
||||
if (paused)
|
||||
SDL_PauseAudioDevice(SDL_GetAudioStreamDevice(m_stream));
|
||||
else
|
||||
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream));
|
||||
|
||||
m_paused = paused;
|
||||
}
|
||||
|
||||
void SDLAudioStream::CloseDevice()
|
||||
{
|
||||
SDL_CloseAudioDevice(m_device_id);
|
||||
m_device_id = 0;
|
||||
SDL_DestroyAudioStream(m_stream);
|
||||
m_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)
|
||||
{
|
||||
SDLAudioStream* const this_ptr = static_cast<SDLAudioStream*>(userdata);
|
||||
const u32 num_frames = len / sizeof(SampleType) / this_ptr->m_output_channels;
|
||||
if (additional_amount > 0)
|
||||
{
|
||||
SDLAudioStream* const this_ptr = static_cast<SDLAudioStream*>(userdata);
|
||||
|
||||
this_ptr->ReadFrames(reinterpret_cast<SampleType*>(stream), num_frames);
|
||||
const u32 num_frames = additional_amount / sizeof(SampleType) / this_ptr->m_output_channels;
|
||||
SampleType* buffer = SDL_stack_alloc(SampleType, additional_amount / sizeof(SampleType));
|
||||
if (buffer)
|
||||
{
|
||||
this_ptr->ReadFrames(buffer, num_frames);
|
||||
SDL_PutAudioStreamData(stream, buffer, additional_amount);
|
||||
SDL_stack_free(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1589,7 +1589,9 @@ void FullscreenUI::DrawInputBindingButton(
|
|||
return;
|
||||
|
||||
if (oneline)
|
||||
InputManager::PrettifyInputBinding(value);
|
||||
InputManager::PrettifyInputBinding(value, true);
|
||||
else
|
||||
InputManager::PrettifyInputBinding(value, false);
|
||||
|
||||
if (show_type)
|
||||
{
|
||||
|
@ -4461,11 +4463,11 @@ void FullscreenUI::DrawControllerSettingsPage()
|
|||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COG, "Enable SDL Input Source"),
|
||||
FSUI_CSTR("The SDL input source supports most controllers."), "InputSources", "SDL", true, true, false);
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_WIFI, "SDL DualShock 4 / DualSense Enhanced Mode"),
|
||||
FSUI_CSTR("Provides vibration and LED control support over Bluetooth."), "InputSources", "SDLControllerEnhancedMode", false,
|
||||
FSUI_CSTR("Provides vibration and LED control support over Bluetooth."), "InputSources", "SDLControllerEnhancedMode", true,
|
||||
bsi->GetBoolValue("InputSources", "SDL", true), false);
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LIGHTBULB, "SDL DualSense Player LED"),
|
||||
FSUI_CSTR("Enable/Disable the Player LED on DualSense controllers."), "InputSources", "SDLPS5PlayerLED", false,
|
||||
bsi->GetBoolValue("InputSources", "SDLControllerEnhancedMode", true), false);
|
||||
FSUI_CSTR("Enable/Disable the Player LED on DualSense controllers."), "InputSources", "SDLPS5PlayerLED", true,
|
||||
bsi->GetBoolValue("InputSources", "SDLControllerEnhancedMode", true), true);
|
||||
#ifdef _WIN32
|
||||
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_COG, "SDL Raw Input"), FSUI_CSTR("Allow SDL to use raw access to input devices."),
|
||||
"InputSources", "SDLRawInput", false, bsi->GetBoolValue("InputSources", "SDL", true), false);
|
||||
|
|
|
@ -489,7 +489,7 @@ bool ImGuiManager::AddIconFonts(float size)
|
|||
{
|
||||
// clang-format off
|
||||
static constexpr ImWchar range_fa[] = { 0xe06f,0xe06f,0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf023,0xf025,0xf028,0xf02b,0xf02b,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03e,0xf04b,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf05a,0xf05a,0xf05e,0xf05e,0xf063,0xf063,0xf067,0xf067,0xf06a,0xf06a,0xf06e,0xf06e,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf084,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c8,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf11b,0xf11c,0xf120,0xf121,0xf129,0xf12a,0xf140,0xf140,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf187,0xf188,0xf191,0xf192,0xf1b3,0xf1b3,0xf1de,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf21e,0xf21e,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2bd,0xf2bd,0xf2db,0xf2db,0xf2f2,0xf2f2,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf462,0xf462,0xf466,0xf466,0xf4e2,0xf4e2,0xf51f,0xf51f,0xf545,0xf545,0xf54c,0xf54c,0xf553,0xf553,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf70e,0xf70e,0xf756,0xf756,0xf780,0xf780,0xf794,0xf794,0xf815,0xf815,0xf84c,0xf84c,0xf8cc,0xf8cc,0x0,0x0 };
|
||||
static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a3,0x21b0,0x21b3,0x21ba,0x21c3,0x21ce,0x21ce,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x235e,0x2360,0x2361,0x2364,0x2367,0x237a,0x237b,0x237d,0x237d,0x237f,0x237f,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243d,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24fd,0x24ff,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xe001,0xe001,0xff21,0xff3a,0x0,0x0 };
|
||||
static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a7,0x21b0,0x21b3,0x21ba,0x21c3,0x21ce,0x21ce,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21e6,0x21e8,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x2206,0x2208,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x235e,0x2360,0x2361,0x2364,0x2367,0x237a,0x237b,0x237d,0x237d,0x237f,0x237f,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243d,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24fd,0x24ff,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xe000,0xe001,0xff21,0xff3a,0x0,0x0 };
|
||||
// clang-format on
|
||||
|
||||
{
|
||||
|
|
|
@ -45,6 +45,17 @@ std::string DInputSource::GetDeviceIdentifier(u32 index)
|
|||
return fmt::format("DInput-{}", index);
|
||||
}
|
||||
|
||||
static constexpr const char* s_dinput_axis_names[] = {
|
||||
"X Axis",
|
||||
"Y Axis",
|
||||
"Z Axis",
|
||||
"Z Rotation",
|
||||
"X Rotation",
|
||||
"Y Rotation",
|
||||
"Slider 1",
|
||||
"Slider 2",
|
||||
};
|
||||
|
||||
static constexpr std::array<const char*, DInputSource::NUM_HAT_DIRECTIONS> s_hat_directions = {{"Up", "Down", "Left", "Right"}};
|
||||
|
||||
bool DInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock)
|
||||
|
@ -150,6 +161,15 @@ void DInputSource::Shutdown()
|
|||
GetDeviceIdentifier(index));
|
||||
m_controllers.pop_back();
|
||||
}
|
||||
|
||||
m_toplevel_window = nullptr;
|
||||
m_dinput.reset();
|
||||
m_dinput_module.reset();
|
||||
}
|
||||
|
||||
bool DInputSource::IsInitialized()
|
||||
{
|
||||
return m_toplevel_window;
|
||||
}
|
||||
|
||||
bool DInputSource::AddDevice(ControllerData& cd, const std::string& name)
|
||||
|
@ -379,7 +399,7 @@ std::optional<InputBindingKey> DInputSource::ParseKeyString(const std::string_vi
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
TinyString DInputSource::ConvertKeyToString(InputBindingKey key)
|
||||
TinyString DInputSource::ConvertKeyToString(InputBindingKey key, bool display, bool migration)
|
||||
{
|
||||
TinyString ret;
|
||||
|
||||
|
@ -387,18 +407,33 @@ TinyString DInputSource::ConvertKeyToString(InputBindingKey key)
|
|||
{
|
||||
if (key.source_subtype == InputSubclass::ControllerAxis)
|
||||
{
|
||||
const char* modifier = (key.modifier == InputModifier::FullAxis ? "Full" : (key.modifier == InputModifier::Negate ? "-" : "+"));
|
||||
ret.format("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), (key.invert && !ShouldIgnoreInversion()) ? "~" : "");
|
||||
const char* modifier = (key.modifier == InputModifier::FullAxis ? (display ? "Full " : "Full") : (key.modifier == InputModifier::Negate ? "-" : "+"));
|
||||
if (display)
|
||||
{
|
||||
if (key.data < std::size(s_dinput_axis_names))
|
||||
ret.format("DInput-{} {}{}{}", u32(key.source_index), modifier, s_dinput_axis_names[key.data], key.invert ? "~" : "");
|
||||
else
|
||||
ret.format("DInput-{} {}Axis {}{}", u32(key.source_index), modifier, u32(key.data) + 1, key.invert ? "~" : "");
|
||||
}
|
||||
else
|
||||
ret.format("DInput-{}/{}Axis{}{}", u32(key.source_index), modifier, u32(key.data), (key.invert && (migration || !ShouldIgnoreInversion())) ? "~" : "");
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerButton && key.data >= MAX_NUM_BUTTONS)
|
||||
{
|
||||
// Note, hats currently get mapped to buttons
|
||||
const u32 hat_num = (key.data - MAX_NUM_BUTTONS) / NUM_HAT_DIRECTIONS;
|
||||
const u32 hat_dir = (key.data - MAX_NUM_BUTTONS) % NUM_HAT_DIRECTIONS;
|
||||
ret.format("DInput-{}/Hat{}{}", u32(key.source_index), hat_num, s_hat_directions[hat_dir]);
|
||||
if (display)
|
||||
ret.format("DInput-{} Hat {} {}", u32(key.source_index), hat_num + 1, s_hat_directions[hat_dir]);
|
||||
else
|
||||
ret.format("DInput-{}/Hat{}{}", u32(key.source_index), hat_num, s_hat_directions[hat_dir]);
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerButton)
|
||||
{
|
||||
ret.format("DInput-{}/Button{}", u32(key.source_index), u32(key.data));
|
||||
if (display)
|
||||
ret.format("DInput-{} Button {}", u32(key.source_index), u32(key.data) + 1);
|
||||
else
|
||||
ret.format("DInput-{}/Button{}", u32(key.source_index), u32(key.data));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||
bool ReloadDevices() override;
|
||||
void Shutdown() override;
|
||||
bool IsInitialized() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
|
@ -47,7 +48,7 @@ public:
|
|||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
|
||||
|
||||
std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) override;
|
||||
TinyString ConvertKeyToString(InputBindingKey key) override;
|
||||
TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) override;
|
||||
TinyString ConvertKeyToIcon(InputBindingKey key) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "SIO/Sio.h"
|
||||
#include "USB/USB.h"
|
||||
#include "VMManager.h"
|
||||
#include "LayeredSettingsInterface.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
|
@ -92,10 +93,15 @@ namespace InputManager
|
|||
static std::optional<InputBindingKey> ParseHostKeyboardKey(const std::string_view source, const std::string_view sub_binding);
|
||||
static std::optional<InputBindingKey> ParsePointerKey(const std::string_view source, const std::string_view sub_binding);
|
||||
|
||||
static TinyString ConvertKeyboardKeyToString(InputBindingKey key, bool display = false);
|
||||
static TinyString ConvertPointerKeyToString(InputBindingKey key, bool display = false);
|
||||
|
||||
static bool SplitBinding(const std::string_view binding, std::string_view* source, std::string_view* sub_binding);
|
||||
static void PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed);
|
||||
static void AddBinding(const std::string_view binding, const InputEventHandler& handler);
|
||||
static void AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler);
|
||||
static void PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed, bool use_icons);
|
||||
static std::shared_ptr<InputBinding> AddBinding(const std::string_view binding, const InputEventHandler& handler);
|
||||
// Will also apply SDL2-SDL3 migrations and update the provided section & key
|
||||
static void AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler,
|
||||
InputBindingInfo::Type binding_type, SettingsInterface& si, const char* section, const char* key);
|
||||
static bool ParseBindingAndGetSource(const std::string_view binding, InputBindingKey* key, InputSource** source);
|
||||
|
||||
static bool IsAxisHandler(const InputEventHandler& handler);
|
||||
|
@ -142,9 +148,12 @@ static const HotkeyInfo* const s_hotkey_list[] = {g_common_hotkeys, g_gs_hotkeys
|
|||
// Tracking host mouse movement and turning into relative events
|
||||
// 4 axes: pointer left/right, wheel vertical/horizontal. Last/Next/Normalized.
|
||||
// ------------------------------------------------------------------------
|
||||
static constexpr const std::array<const char*, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_names = {
|
||||
static constexpr const std::array<const char*, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_setting_names = {
|
||||
{"X", "Y", "WheelX", "WheelY"}};
|
||||
static constexpr const std::array<const char*, 3> s_pointer_button_names = {{"LeftButton", "RightButton", "MiddleButton"}};
|
||||
static constexpr const std::array<const char*, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_names = {
|
||||
{"X", "Y", "Wheel X", "Wheel Y"}};
|
||||
static constexpr const std::array<const char*, 3> s_pointer_button_setting_names = {{"LeftButton", "RightButton", "MiddleButton"}};
|
||||
static constexpr const std::array<const char*, 3> s_pointer_button_names = {{"Left Button", "Right Button", "Middle Button"}};
|
||||
|
||||
struct PointerAxisState
|
||||
{
|
||||
|
@ -232,7 +241,7 @@ std::optional<InputBindingKey> InputManager::ParseInputBindingKey(const std::str
|
|||
{
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
{
|
||||
std::optional<InputBindingKey> key = s_input_sources[i]->ParseKeyString(source, sub_binding);
|
||||
if (key.has_value())
|
||||
|
@ -252,7 +261,7 @@ bool InputManager::ParseBindingAndGetSource(const std::string_view binding, Inpu
|
|||
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
{
|
||||
std::optional<InputBindingKey> parsed_key = s_input_sources[i]->ParseKeyString(source_string, sub_binding);
|
||||
if (parsed_key.has_value())
|
||||
|
@ -267,7 +276,62 @@ bool InputManager::ParseBindingAndGetSource(const std::string_view binding, Inpu
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key)
|
||||
TinyString InputManager::ConvertKeyboardKeyToString(InputBindingKey key, bool display)
|
||||
{
|
||||
TinyString ret;
|
||||
|
||||
if (key.source_type == InputSourceType::Keyboard)
|
||||
{
|
||||
const std::optional<std::string> str(ConvertHostKeyboardCodeToString(key.data));
|
||||
if (str.has_value() && !str->empty())
|
||||
if (display)
|
||||
// Keyboard keys arn't spaced out for display yet
|
||||
ret.format("Keyboard {}", str->c_str());
|
||||
else
|
||||
ret.format("Keyboard/{}", str->c_str());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
TinyString InputManager::ConvertPointerKeyToString(InputBindingKey key, bool display)
|
||||
{
|
||||
TinyString ret;
|
||||
|
||||
if (key.source_type == InputSourceType::Pointer)
|
||||
{
|
||||
if (key.source_subtype == InputSubclass::PointerButton)
|
||||
{
|
||||
if (display)
|
||||
{
|
||||
if (key.data < s_pointer_button_setting_names.size())
|
||||
ret.format("Pointer-{} {}", u32{key.source_index}, s_pointer_button_names[key.data]);
|
||||
else
|
||||
ret.format("Pointer-{} Button{}", u32{key.source_index}, key.data + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (key.data < s_pointer_button_setting_names.size())
|
||||
ret.format("Pointer-{}/{}", u32{key.source_index}, s_pointer_button_setting_names[key.data]);
|
||||
else
|
||||
ret.format("Pointer-{}/Button{}", u32{key.source_index}, key.data);
|
||||
}
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::PointerAxis)
|
||||
{
|
||||
if (display)
|
||||
ret.format("Pointer-{} {}{:c}", u32{key.source_index}, s_pointer_axis_setting_names[key.data],
|
||||
key.modifier == InputModifier::Negate ? '-' : '+');
|
||||
else
|
||||
ret.format("Pointer-{}/{}{:c}", u32{key.source_index}, s_pointer_axis_setting_names[key.data],
|
||||
key.modifier == InputModifier::Negate ? '-' : '+');
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key, bool migration)
|
||||
{
|
||||
if (binding_type == InputBindingInfo::Type::Pointer || binding_type == InputBindingInfo::Type::Device)
|
||||
{
|
||||
|
@ -294,48 +358,35 @@ std::string InputManager::ConvertInputBindingKeyToString(InputBindingInfo::Type
|
|||
{
|
||||
if (key.source_type == InputSourceType::Keyboard)
|
||||
{
|
||||
const std::optional<std::string> str(ConvertHostKeyboardCodeToString(key.data));
|
||||
if (str.has_value() && !str->empty())
|
||||
return fmt::format("Keyboard/{}", str->c_str());
|
||||
return std::string(ConvertKeyboardKeyToString(key));
|
||||
}
|
||||
else if (key.source_type == InputSourceType::Pointer)
|
||||
{
|
||||
if (key.source_subtype == InputSubclass::PointerButton)
|
||||
{
|
||||
if (key.data < s_pointer_button_names.size())
|
||||
return fmt::format("Pointer-{}/{}", u32{key.source_index}, s_pointer_button_names[key.data]);
|
||||
else
|
||||
return fmt::format("Pointer-{}/Button{}", u32{key.source_index}, key.data);
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::PointerAxis)
|
||||
{
|
||||
return fmt::format("Pointer-{}/{}{:c}", u32{key.source_index}, s_pointer_axis_names[key.data],
|
||||
key.modifier == InputModifier::Negate ? '-' : '+');
|
||||
}
|
||||
return std::string(ConvertPointerKeyToString(key));
|
||||
}
|
||||
else if (key.source_type < InputSourceType::Count && s_input_sources[static_cast<u32>(key.source_type)])
|
||||
{
|
||||
return std::string(s_input_sources[static_cast<u32>(key.source_type)]->ConvertKeyToString(key));
|
||||
return std::string(s_input_sources[static_cast<u32>(key.source_type)]->ConvertKeyToString(key, false, migration));
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys)
|
||||
std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys, bool migration)
|
||||
{
|
||||
// can't have a chord of devices/pointers
|
||||
if (binding_type == InputBindingInfo::Type::Pointer || binding_type == InputBindingInfo::Type::Device)
|
||||
{
|
||||
// so only take the first
|
||||
if (num_keys > 0)
|
||||
return ConvertInputBindingKeyToString(binding_type, keys[0]);
|
||||
return ConvertInputBindingKeyToString(binding_type, keys[0], migration);
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
for (size_t i = 0; i < num_keys; i++)
|
||||
{
|
||||
const std::string keystr(ConvertInputBindingKeyToString(binding_type, keys[i]));
|
||||
const std::string keystr(ConvertInputBindingKeyToString(binding_type, keys[i], migration));
|
||||
if (keystr.empty())
|
||||
return std::string();
|
||||
|
||||
|
@ -348,7 +399,7 @@ std::string InputManager::ConvertInputBindingKeysToString(InputBindingInfo::Type
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
|
||||
bool InputManager::PrettifyInputBinding(SmallStringBase& binding, bool use_icons)
|
||||
{
|
||||
if (binding.empty())
|
||||
return false;
|
||||
|
@ -369,7 +420,7 @@ bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
|
|||
{
|
||||
if (!ret.empty())
|
||||
ret.append(" + ");
|
||||
PrettifyInputBindingPart(part, ret, changed);
|
||||
PrettifyInputBindingPart(part, ret, changed, use_icons);
|
||||
}
|
||||
}
|
||||
last = next + 1;
|
||||
|
@ -381,7 +432,7 @@ bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
|
|||
{
|
||||
if (!ret.empty())
|
||||
ret.append(" + ");
|
||||
PrettifyInputBindingPart(part, ret, changed);
|
||||
PrettifyInputBindingPart(part, ret, changed, use_icons);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,7 +442,7 @@ bool InputManager::PrettifyInputBinding(SmallStringBase& binding)
|
|||
return changed;
|
||||
}
|
||||
|
||||
void InputManager::PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed)
|
||||
void InputManager::PrettifyInputBindingPart(const std::string_view binding, SmallString& ret, bool& changed, bool use_icons)
|
||||
{
|
||||
std::string_view source, sub_binding;
|
||||
if (!SplitBinding(binding, &source, &sub_binding))
|
||||
|
@ -401,12 +452,30 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
|
|||
if (source.starts_with("Keyboard"))
|
||||
{
|
||||
std::optional<InputBindingKey> key = ParseHostKeyboardKey(source, sub_binding);
|
||||
const char* icon = key.has_value() ? ConvertHostKeyboardCodeToIcon(key->data) : nullptr;
|
||||
if (icon)
|
||||
if (key.has_value())
|
||||
{
|
||||
ret.append(icon);
|
||||
changed = true;
|
||||
return;
|
||||
if (use_icons)
|
||||
{
|
||||
const char* icon = ConvertHostKeyboardCodeToIcon(key->data);
|
||||
if (icon)
|
||||
{
|
||||
ret.append(icon);
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(ConvertKeyboardKeyToString(key.value(), true));
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(ConvertKeyboardKeyToString(key.value(), true));
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (source.starts_with("Pointer"))
|
||||
|
@ -414,7 +483,7 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
|
|||
const std::optional<InputBindingKey> key = ParsePointerKey(source, sub_binding);
|
||||
if (key.has_value())
|
||||
{
|
||||
if (key->source_subtype == InputSubclass::PointerButton)
|
||||
if (use_icons && key->source_subtype == InputSubclass::PointerButton)
|
||||
{
|
||||
static constexpr const char* button_icons[] = {
|
||||
ICON_PF_MOUSE_BUTTON_1,
|
||||
|
@ -424,32 +493,41 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
|
|||
ICON_PF_MOUSE_BUTTON_5,
|
||||
};
|
||||
if (key->data < std::size(button_icons))
|
||||
{
|
||||
ret.append(button_icons[key->data]);
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
ret.append(ConvertPointerKeyToString(key.value(), true));
|
||||
}
|
||||
else
|
||||
ret.append(ConvertPointerKeyToString(key.value(), true));
|
||||
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
// We call ConvertKeyToIcon/String() even on disabled sources
|
||||
// This ensures consistant appearance between enabled and disabled sources
|
||||
if (s_input_sources[i])
|
||||
{
|
||||
std::optional<InputBindingKey> key = s_input_sources[i]->ParseKeyString(source, sub_binding);
|
||||
if (key.has_value())
|
||||
{
|
||||
const TinyString icon = s_input_sources[i]->ConvertKeyToIcon(key.value());
|
||||
if (!icon.empty())
|
||||
if (use_icons)
|
||||
{
|
||||
ret.append(icon);
|
||||
changed = true;
|
||||
return;
|
||||
const TinyString icon = s_input_sources[i]->ConvertKeyToIcon(key.value());
|
||||
if (!icon.empty())
|
||||
ret.append(icon);
|
||||
else
|
||||
ret.append(s_input_sources[i]->ConvertKeyToString(key.value(), true));
|
||||
}
|
||||
else
|
||||
ret.append(s_input_sources[i]->ConvertKeyToString(key.value(), true));
|
||||
|
||||
break;
|
||||
changed = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -459,7 +537,7 @@ void InputManager::PrettifyInputBindingPart(const std::string_view binding, Smal
|
|||
}
|
||||
|
||||
|
||||
void InputManager::AddBinding(const std::string_view binding, const InputEventHandler& handler)
|
||||
std::shared_ptr<InputBinding> InputManager::AddBinding(const std::string_view binding, const InputEventHandler& handler)
|
||||
{
|
||||
std::shared_ptr<InputBinding> ibinding;
|
||||
const std::vector<std::string_view> chord_bindings(SplitChord(binding));
|
||||
|
@ -493,17 +571,65 @@ void InputManager::AddBinding(const std::string_view binding, const InputEventHa
|
|||
}
|
||||
|
||||
if (!ibinding)
|
||||
return;
|
||||
return nullptr;
|
||||
|
||||
// plop it in the input map for all the keys
|
||||
for (u32 i = 0; i < ibinding->num_keys; i++)
|
||||
s_binding_map.emplace(ibinding->keys[i].MaskDirection(), ibinding);
|
||||
|
||||
return ibinding;
|
||||
}
|
||||
|
||||
void InputManager::AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler)
|
||||
void InputManager::AddBindings(const std::vector<std::string>& bindings, const InputEventHandler& handler,
|
||||
InputBindingInfo::Type binding_type, SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
std::vector<std::shared_ptr<InputBinding>> ibindings;
|
||||
|
||||
bool migrate = false;
|
||||
for (const std::string& binding : bindings)
|
||||
AddBinding(binding, handler);
|
||||
{
|
||||
std::shared_ptr<InputBinding> ibinding = AddBinding(binding, handler);
|
||||
ibindings.push_back(ibinding);
|
||||
|
||||
if (ibinding)
|
||||
{
|
||||
// Check for SDL2-3 migrations
|
||||
for (u32 i = 0; i < ibinding->num_keys; i++)
|
||||
{
|
||||
if (ibinding->keys[i].needs_migration)
|
||||
migrate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save migrations
|
||||
if (migrate)
|
||||
{
|
||||
std::vector<std::string> new_bindings;
|
||||
new_bindings.reserve(bindings.size());
|
||||
|
||||
for (int i = 0; i < bindings.size(); i++)
|
||||
{
|
||||
if (ibindings[i])
|
||||
new_bindings.push_back(ConvertInputBindingKeysToString(binding_type, ibindings[i]->keys, ibindings[i]->num_keys, true));
|
||||
else
|
||||
// Retain invalid bindings as is
|
||||
new_bindings.push_back(bindings[i]);
|
||||
}
|
||||
|
||||
// Need to find where our binding came from
|
||||
LayeredSettingsInterface& lsi = static_cast<LayeredSettingsInterface&>(si);
|
||||
for (int i = 0; i < LayeredSettingsInterface::NUM_LAYERS; i++)
|
||||
{
|
||||
SettingsInterface* layer = lsi.GetLayer(static_cast<LayeredSettingsInterface::Layer>(i));
|
||||
if (layer && layer->GetStringList(section, key) == bindings)
|
||||
{
|
||||
// Layer found, update settings
|
||||
layer->SetStringList(section, key, new_bindings);
|
||||
layer->Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
@ -631,14 +757,14 @@ std::optional<InputBindingKey> InputManager::ParsePointerKey(const std::string_v
|
|||
return key;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < s_pointer_axis_names.size(); i++)
|
||||
for (u32 i = 0; i < s_pointer_axis_setting_names.size(); i++)
|
||||
{
|
||||
if (sub_binding.starts_with(s_pointer_axis_names[i]))
|
||||
if (sub_binding.starts_with(s_pointer_axis_setting_names[i]))
|
||||
{
|
||||
key.source_subtype = InputSubclass::PointerAxis;
|
||||
key.data = i;
|
||||
|
||||
const std::string_view dir_part(sub_binding.substr(std::strlen(s_pointer_axis_names[i])));
|
||||
const std::string_view dir_part(sub_binding.substr(std::strlen(s_pointer_axis_setting_names[i])));
|
||||
if (dir_part == "+")
|
||||
key.modifier = InputModifier::None;
|
||||
else if (dir_part == "-")
|
||||
|
@ -650,9 +776,9 @@ std::optional<InputBindingKey> InputManager::ParsePointerKey(const std::string_v
|
|||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < s_pointer_button_names.size(); i++)
|
||||
for (u32 i = 0; i < s_pointer_button_setting_names.size(); i++)
|
||||
{
|
||||
if (sub_binding == s_pointer_button_names[i])
|
||||
if (sub_binding == s_pointer_button_setting_names[i])
|
||||
{
|
||||
key.source_subtype = InputSubclass::PointerButton;
|
||||
key.data = i;
|
||||
|
@ -711,7 +837,7 @@ void InputManager::AddHotkeyBindings(SettingsInterface& si)
|
|||
if (bindings.empty())
|
||||
continue;
|
||||
|
||||
AddBindings(bindings, InputButtonEventHandler{hotkey->handler});
|
||||
AddBindings(bindings, InputButtonEventHandler{hotkey->handler}, InputBindingInfo::Type::Button, si, "Hotkeys", hotkey->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -753,7 +879,8 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index)
|
|||
AddBindings(
|
||||
bindings, InputAxisEventHandler{[pad_index, bind_index = bi.bind_index, sensitivity, deadzone](InputBindingKey key, float value) {
|
||||
Pad::SetControllerState(pad_index, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||
}});
|
||||
}},
|
||||
bi.bind_type, si, section.c_str(), bi.name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -771,10 +898,12 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index)
|
|||
if (!bindings.empty())
|
||||
{
|
||||
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("Macro{}Deadzone", macro_button_index + 1).c_str(), 0.0f);
|
||||
AddBindings(bindings, InputAxisEventHandler{[pad_index, macro_button_index, deadzone](InputBindingKey key, float value) {
|
||||
const bool state = (value > deadzone);
|
||||
Pad::SetMacroButtonState(key, pad_index, macro_button_index, state);
|
||||
}});
|
||||
AddBindings(
|
||||
bindings, InputAxisEventHandler{[pad_index, macro_button_index, deadzone](InputBindingKey key, float value) {
|
||||
const bool state = (value > deadzone);
|
||||
Pad::SetMacroButtonState(key, pad_index, macro_button_index, state);
|
||||
}},
|
||||
InputBindingInfo::Type::Macro, si, section.c_str(), fmt::format("Macro{}", macro_button_index + 1).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -835,9 +964,11 @@ void InputManager::AddUSBBindings(SettingsInterface& si, u32 port)
|
|||
{
|
||||
const float sensitivity = si.GetFloatValue(section.c_str(), fmt::format("{}Scale", bi.name).c_str(), 1.0f);
|
||||
const float deadzone = si.GetFloatValue(section.c_str(), fmt::format("{}Deadzone", bi.name).c_str(), 0.0f);
|
||||
AddBindings(bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index, sensitivity, deadzone](InputBindingKey key, float value) {
|
||||
USB::SetDeviceBindValue(port, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||
}});
|
||||
AddBindings(
|
||||
bindings, InputAxisEventHandler{[port, bind_index = bi.bind_index, sensitivity, deadzone](InputBindingKey key, float value) {
|
||||
USB::SetDeviceBindValue(port, bind_index, ApplySingleBindingScale(sensitivity, deadzone, value));
|
||||
}},
|
||||
bi.bind_type, si, section.c_str(), bind_name.c_str());
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -1414,10 +1545,10 @@ void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& bind
|
|||
constexpr float pointer_sensitivity = 0.05f;
|
||||
for (u32 axis = 0; axis <= static_cast<u32>(InputPointerAxis::Y); axis++)
|
||||
{
|
||||
s_pointer_axis_speed[axis] = si.GetFloatValue("Pad", fmt::format("Pointer{}Speed", s_pointer_axis_names[axis]).c_str(), 40.0f) /
|
||||
s_pointer_axis_speed[axis] = si.GetFloatValue("Pad", fmt::format("Pointer{}Speed", s_pointer_axis_setting_names[axis]).c_str(), 40.0f) /
|
||||
ui_ctrl_range * pointer_sensitivity;
|
||||
s_pointer_axis_dead_zone[axis] = std::min(
|
||||
si.GetFloatValue("Pad", fmt::format("Pointer{}DeadZone", s_pointer_axis_names[axis]).c_str(), 20.0f) / ui_ctrl_range, 1.0f);
|
||||
si.GetFloatValue("Pad", fmt::format("Pointer{}DeadZone", s_pointer_axis_setting_names[axis]).c_str(), 20.0f) / ui_ctrl_range, 1.0f);
|
||||
s_pointer_axis_range[axis] = 1.0f - s_pointer_axis_dead_zone[axis];
|
||||
}
|
||||
s_pointer_inertia = si.GetFloatValue("Pad", "PointerInertia", 10.0f) / ui_ctrl_range;
|
||||
|
@ -1461,7 +1592,7 @@ bool InputManager::ReloadDevices()
|
|||
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
changed |= s_input_sources[i]->ReloadDevices();
|
||||
}
|
||||
|
||||
|
@ -1472,11 +1603,11 @@ void InputManager::CloseSources()
|
|||
{
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
{
|
||||
s_input_sources[i]->Shutdown();
|
||||
s_input_sources[i].reset();
|
||||
}
|
||||
s_input_sources[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1484,7 +1615,7 @@ void InputManager::PollSources()
|
|||
{
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
s_input_sources[i]->PollEvents();
|
||||
}
|
||||
|
||||
|
@ -1504,7 +1635,7 @@ std::vector<std::pair<std::string, std::string>> InputManager::EnumerateDevices(
|
|||
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> devs(s_input_sources[i]->EnumerateDevices());
|
||||
if (ret.empty())
|
||||
|
@ -1523,7 +1654,7 @@ std::vector<InputBindingKey> InputManager::EnumerateMotors()
|
|||
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i])
|
||||
if (s_input_sources[i]->IsInitialized())
|
||||
{
|
||||
std::vector<InputBindingKey> devs(s_input_sources[i]->EnumerateMotors());
|
||||
if (ret.empty())
|
||||
|
@ -1583,7 +1714,7 @@ InputManager::GenericInputBindingMapping InputManager::GetGenericBindingMapping(
|
|||
{
|
||||
for (u32 i = FIRST_EXTERNAL_INPUT_SOURCE; i < LAST_EXTERNAL_INPUT_SOURCE; i++)
|
||||
{
|
||||
if (s_input_sources[i] && s_input_sources[i]->GetGenericBindingMapping(device, &mapping))
|
||||
if (s_input_sources[i]->IsInitialized() && s_input_sources[i]->GetGenericBindingMapping(device, &mapping))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1599,34 +1730,34 @@ bool InputManager::IsInputSourceEnabled(SettingsInterface& si, InputSourceType t
|
|||
template <typename T>
|
||||
void InputManager::UpdateInputSourceState(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock, InputSourceType type)
|
||||
{
|
||||
if (!s_input_sources[static_cast<u32>(type)])
|
||||
{
|
||||
std::unique_ptr<InputSource> source = std::make_unique<T>();
|
||||
if (!source->Initialize(si, settings_lock))
|
||||
Console.Error("(InputManager) Source '%s' failed to initialize.", InputSourceToString(type));
|
||||
|
||||
s_input_sources[static_cast<u32>(type)] = std::move(source);
|
||||
}
|
||||
|
||||
const bool enabled = IsInputSourceEnabled(si, type);
|
||||
if (enabled)
|
||||
{
|
||||
if (s_input_sources[static_cast<u32>(type)])
|
||||
if (s_input_sources[static_cast<u32>(type)]->IsInitialized())
|
||||
{
|
||||
s_input_sources[static_cast<u32>(type)]->UpdateSettings(si, settings_lock);
|
||||
}
|
||||
else
|
||||
else if (!s_input_sources[static_cast<u32>(type)]->Initialize(si, settings_lock))
|
||||
{
|
||||
std::unique_ptr<InputSource> source = std::make_unique<T>();
|
||||
if (!source->Initialize(si, settings_lock))
|
||||
{
|
||||
Console.Error("(InputManager) Source '%s' failed to initialize.", InputSourceToString(type));
|
||||
return;
|
||||
}
|
||||
|
||||
s_input_sources[static_cast<u32>(type)] = std::move(source);
|
||||
Console.Error("(InputManager) Source '%s' failed to initialize.", InputSourceToString(type));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_input_sources[static_cast<u32>(type)])
|
||||
if (s_input_sources[static_cast<u32>(type)]->IsInitialized())
|
||||
{
|
||||
settings_lock.unlock();
|
||||
s_input_sources[static_cast<u32>(type)]->Shutdown();
|
||||
settings_lock.lock();
|
||||
|
||||
s_input_sources[static_cast<u32>(type)].reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,7 +63,8 @@ union InputBindingKey
|
|||
InputSubclass source_subtype : 3; ///< if 1, binding is for an axis and not a button (used for controllers)
|
||||
InputModifier modifier : 2;
|
||||
u32 invert : 1; ///< if 1, value is inverted prior to being sent to the sink
|
||||
u32 unused : 14;
|
||||
u32 needs_migration : 1; //< Used for SDL2-3 Migration, binding should be saved to complete migration
|
||||
u32 unused : 13;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
|
@ -80,6 +81,7 @@ union InputBindingKey
|
|||
r.bits = bits;
|
||||
r.modifier = InputModifier::None;
|
||||
r.invert = 0;
|
||||
r.needs_migration = false;
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
@ -203,13 +205,13 @@ namespace InputManager
|
|||
std::optional<InputBindingKey> ParseInputBindingKey(const std::string_view binding);
|
||||
|
||||
/// Converts a input key to a string.
|
||||
std::string ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key);
|
||||
std::string ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key, bool migration = false);
|
||||
|
||||
/// Converts a chord of binding keys to a string.
|
||||
std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys);
|
||||
std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys, size_t num_keys, bool migration = false);
|
||||
|
||||
/// Represents a binding with icon fonts, if available.
|
||||
bool PrettifyInputBinding(SmallStringBase& binding);
|
||||
bool PrettifyInputBinding(SmallStringBase& binding, bool use_icons = true);
|
||||
|
||||
/// Splits a chord into individual bindings.
|
||||
std::vector<std::string_view> SplitChord(const std::string_view binding);
|
||||
|
|
|
@ -24,11 +24,13 @@ public:
|
|||
virtual void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) = 0;
|
||||
virtual bool ReloadDevices() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual bool IsInitialized() = 0;
|
||||
|
||||
virtual void PollEvents() = 0;
|
||||
|
||||
/// InputBinding functions can be called while uninitialized
|
||||
virtual std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) = 0;
|
||||
virtual TinyString ConvertKeyToString(InputBindingKey key) = 0;
|
||||
virtual TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) = 0;
|
||||
virtual TinyString ConvertKeyToIcon(InputBindingKey key) = 0;
|
||||
|
||||
/// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "Input/InputSource.h"
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
|
@ -26,6 +26,7 @@ public:
|
|||
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||
bool ReloadDevices() override;
|
||||
void Shutdown() override;
|
||||
bool IsInitialized() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
|
@ -35,7 +36,7 @@ public:
|
|||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
|
||||
|
||||
std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) override;
|
||||
TinyString ConvertKeyToString(InputBindingKey key) override;
|
||||
TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) override;
|
||||
TinyString ConvertKeyToIcon(InputBindingKey key) override;
|
||||
|
||||
bool ProcessSDLEvent(const SDL_Event* event);
|
||||
|
@ -50,17 +51,17 @@ private:
|
|||
struct ControllerData
|
||||
{
|
||||
SDL_Haptic* haptic;
|
||||
SDL_GameController* game_controller;
|
||||
SDL_Gamepad* gamepad;
|
||||
SDL_Joystick* joystick;
|
||||
u16 rumble_intensity[2];
|
||||
int haptic_left_right_effect;
|
||||
int joystick_id;
|
||||
SDL_JoystickID joystick_id;
|
||||
int player_id;
|
||||
bool use_game_controller_rumble;
|
||||
bool use_gamepad_rumble;
|
||||
|
||||
// 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_axis_used_in_gc;
|
||||
// Used to disable Joystick controls that are used in Gamepad inputs so we don't get double events
|
||||
std::vector<bool> joy_button_used_in_pad;
|
||||
std::vector<bool> joy_axis_used_in_pad;
|
||||
|
||||
// Track last hat state so we can send "unpressed" events.
|
||||
std::vector<u8> last_hat_state;
|
||||
|
@ -77,10 +78,10 @@ private:
|
|||
ControllerDataVector::iterator GetControllerDataForPlayerId(int id);
|
||||
int GetFreePlayerId() const;
|
||||
|
||||
bool OpenDevice(int index, bool is_gamecontroller);
|
||||
bool OpenDevice(int index, bool is_gamepad);
|
||||
bool CloseDevice(int joystick_index);
|
||||
bool HandleControllerAxisEvent(const SDL_ControllerAxisEvent* ev);
|
||||
bool HandleControllerButtonEvent(const SDL_ControllerButtonEvent* ev);
|
||||
bool HandleGamepadAxisEvent(const SDL_GamepadAxisEvent* ev);
|
||||
bool HandleGamepadButtonEvent(const SDL_GamepadButtonEvent* ev);
|
||||
bool HandleJoystickAxisEvent(const SDL_JoyAxisEvent* ev);
|
||||
bool HandleJoystickButtonEvent(const SDL_JoyButtonEvent* ev);
|
||||
bool HandleJoystickHatEvent(const SDL_JoyHatEvent* ev);
|
||||
|
@ -88,13 +89,22 @@ private:
|
|||
|
||||
ControllerDataVector m_controllers;
|
||||
|
||||
// ConvertKeyToString and ConvertKeyToIcon can inspect the
|
||||
// currently connected gamepad to provide matching labels
|
||||
// ParseKeyString can also inspect the gamepad for migrations
|
||||
// Those functions can be called on the main thread, while
|
||||
// gamepad addition/removal is done on the CPU thread
|
||||
std::mutex m_controllers_key_mutex;
|
||||
|
||||
std::vector<u32> m_gamepads_needing_migration;
|
||||
|
||||
std::array<u32, MAX_LED_COLORS> m_led_colors{};
|
||||
std::vector<std::pair<std::string, std::string>> m_sdl_hints;
|
||||
|
||||
bool m_sdl_subsystem_initialized = false;
|
||||
bool m_controller_enhanced_mode = false;
|
||||
bool m_controller_raw_mode = false;
|
||||
bool m_controller_ps5_player_led = false;
|
||||
bool m_enable_enhanced_reports = false;
|
||||
bool m_use_raw_input = false;
|
||||
bool m_enable_ps5_player_leds = false;
|
||||
|
||||
#ifdef __APPLE__
|
||||
bool m_enable_iokit_driver = false;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include <cmath>
|
||||
|
||||
static const char* s_axis_names[XInputSource::NUM_AXES] = {
|
||||
static const char* s_axis_setting_names[XInputSource::NUM_AXES] = {
|
||||
"LeftX", // AXIS_LEFTX
|
||||
"LeftY", // AXIS_LEFTY
|
||||
"RightX", // AXIS_RIGHTX
|
||||
|
@ -22,6 +22,14 @@ static const char* s_axis_names[XInputSource::NUM_AXES] = {
|
|||
"LeftTrigger", // AXIS_TRIGGERLEFT
|
||||
"RightTrigger", // AXIS_TRIGGERRIGHT
|
||||
};
|
||||
static const char* s_axis_names[XInputSource::NUM_AXES] = {
|
||||
"Left X", // AXIS_LEFTX
|
||||
"Left Y", // AXIS_LEFTY
|
||||
"Right X", // AXIS_RIGHTX
|
||||
"Right Y", // AXIS_RIGHTY
|
||||
"Left Trigger", // AXIS_TRIGGERLEFT
|
||||
"Right Trigger", // AXIS_TRIGGERRIGHT
|
||||
};
|
||||
static constexpr const char* s_axis_icons[][2] = {
|
||||
{ICON_PF_LEFT_ANALOG_LEFT, ICON_PF_LEFT_ANALOG_RIGHT}, // AXIS_LEFTX
|
||||
{ICON_PF_LEFT_ANALOG_UP, ICON_PF_LEFT_ANALOG_DOWN}, // AXIS_LEFTY
|
||||
|
@ -39,7 +47,7 @@ static const GenericInputBinding s_xinput_generic_binding_axis_mapping[][2] = {
|
|||
{GenericInputBinding::Unknown, GenericInputBinding::R2}, // AXIS_TRIGGERRIGHT
|
||||
};
|
||||
|
||||
static const char* s_button_names[XInputSource::NUM_BUTTONS] = {
|
||||
static const char* s_button_setting_names[XInputSource::NUM_BUTTONS] = {
|
||||
"DPadUp", // XINPUT_GAMEPAD_DPAD_UP
|
||||
"DPadDown", // XINPUT_GAMEPAD_DPAD_DOWN
|
||||
"DPadLeft", // XINPUT_GAMEPAD_DPAD_LEFT
|
||||
|
@ -56,6 +64,24 @@ static const char* s_button_names[XInputSource::NUM_BUTTONS] = {
|
|||
"Y", // XINPUT_GAMEPAD_Y
|
||||
"Guide", // XINPUT_GAMEPAD_GUIDE
|
||||
};
|
||||
static const char* s_button_names[XInputSource::NUM_BUTTONS] = {
|
||||
"D-Pad Up", // XINPUT_GAMEPAD_DPAD_UP
|
||||
"D-Pad Down", // XINPUT_GAMEPAD_DPAD_DOWN
|
||||
"D-Pad Left", // XINPUT_GAMEPAD_DPAD_LEFT
|
||||
"D-Pad Right", // XINPUT_GAMEPAD_DPAD_RIGHT
|
||||
"Start", // XINPUT_GAMEPAD_START
|
||||
"Back", // XINPUT_GAMEPAD_BACK
|
||||
"Left Stick", // XINPUT_GAMEPAD_LEFT_THUMB
|
||||
"Right Stick", // XINPUT_GAMEPAD_RIGHT_THUMB
|
||||
"Left Shoulder", // XINPUT_GAMEPAD_LEFT_SHOULDER
|
||||
"Right Shoulder", // XINPUT_GAMEPAD_RIGHT_SHOULDER
|
||||
"A", // XINPUT_GAMEPAD_A
|
||||
"B", // XINPUT_GAMEPAD_B
|
||||
"X", // XINPUT_GAMEPAD_X
|
||||
"Y", // XINPUT_GAMEPAD_Y
|
||||
"Guide", // XINPUT_GAMEPAD_GUIDE
|
||||
};
|
||||
|
||||
static const u16 s_button_masks[XInputSource::NUM_BUTTONS] = {
|
||||
XINPUT_GAMEPAD_DPAD_UP, XINPUT_GAMEPAD_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_RIGHT, XINPUT_GAMEPAD_START,
|
||||
XINPUT_GAMEPAD_BACK, XINPUT_GAMEPAD_LEFT_THUMB, XINPUT_GAMEPAD_RIGHT_THUMB, XINPUT_GAMEPAD_LEFT_SHOULDER, XINPUT_GAMEPAD_RIGHT_SHOULDER,
|
||||
|
@ -133,6 +159,8 @@ bool XInputSource::Initialize(SettingsInterface& si, std::unique_lock<std::mutex
|
|||
if (!m_xinput_get_state || !m_xinput_set_state || !m_xinput_get_capabilities)
|
||||
{
|
||||
Console.Error("Failed to get XInput function pointers.");
|
||||
FreeLibrary(m_xinput_module);
|
||||
m_xinput_module = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -196,6 +224,11 @@ void XInputSource::Shutdown()
|
|||
m_xinput_get_extended = nullptr;
|
||||
}
|
||||
|
||||
bool XInputSource::IsInitialized()
|
||||
{
|
||||
return m_xinput_module;
|
||||
}
|
||||
|
||||
void XInputSource::PollEvents()
|
||||
{
|
||||
for (u32 i = 0; i < NUM_CONTROLLERS; i++)
|
||||
|
@ -287,9 +320,9 @@ std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_vi
|
|||
{
|
||||
// likely an axis
|
||||
const std::string_view axis_name(binding.substr(1));
|
||||
for (u32 i = 0; i < std::size(s_axis_names); i++)
|
||||
for (u32 i = 0; i < std::size(s_axis_setting_names); i++)
|
||||
{
|
||||
if (axis_name == s_axis_names[i])
|
||||
if (axis_name == s_axis_setting_names[i])
|
||||
{
|
||||
// found an axis!
|
||||
key.source_subtype = InputSubclass::ControllerAxis;
|
||||
|
@ -302,9 +335,9 @@ std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_vi
|
|||
else
|
||||
{
|
||||
// must be a button
|
||||
for (u32 i = 0; i < std::size(s_button_names); i++)
|
||||
for (u32 i = 0; i < std::size(s_button_setting_names); i++)
|
||||
{
|
||||
if (binding == s_button_names[i])
|
||||
if (binding == s_button_setting_names[i])
|
||||
{
|
||||
key.source_subtype = InputSubclass::ControllerButton;
|
||||
key.data = i;
|
||||
|
@ -317,24 +350,33 @@ std::optional<InputBindingKey> XInputSource::ParseKeyString(const std::string_vi
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
TinyString XInputSource::ConvertKeyToString(InputBindingKey key)
|
||||
TinyString XInputSource::ConvertKeyToString(InputBindingKey key, bool display, bool migration)
|
||||
{
|
||||
TinyString ret;
|
||||
|
||||
if (key.source_type == InputSourceType::XInput)
|
||||
{
|
||||
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < std::size(s_axis_names))
|
||||
if (key.source_subtype == InputSubclass::ControllerAxis && key.data < std::size(s_axis_setting_names))
|
||||
{
|
||||
const char modifier = key.modifier == InputModifier::Negate ? '-' : '+';
|
||||
ret.format("XInput-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_axis_names[key.data]);
|
||||
if (display)
|
||||
ret.format("XInput-{} {}{}", static_cast<u32>(key.source_index), modifier, s_axis_names[key.data]);
|
||||
else
|
||||
ret.format("XInput-{}/{}{}", static_cast<u32>(key.source_index), modifier, s_axis_setting_names[key.data]);
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerButton && key.data < std::size(s_button_names))
|
||||
else if (key.source_subtype == InputSubclass::ControllerButton && key.data < std::size(s_button_setting_names))
|
||||
{
|
||||
ret.format("XInput-{}/{}", static_cast<u32>(key.source_index), s_button_names[key.data]);
|
||||
if (display)
|
||||
ret.format("XInput-{} {}", static_cast<u32>(key.source_index), s_button_names[key.data]);
|
||||
else
|
||||
ret.format("XInput-{}/{}", static_cast<u32>(key.source_index), s_button_setting_names[key.data]);
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::ControllerMotor)
|
||||
{
|
||||
ret.format("XInput-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
|
||||
if (display)
|
||||
ret.format("XInput-{} {} Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
|
||||
else
|
||||
ret.format("XInput-{}/{}Motor", static_cast<u32>(key.source_index), key.data ? "Large" : "Small");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,16 +446,16 @@ bool XInputSource::GetGenericBindingMapping(const std::string_view device, Input
|
|||
const GenericInputBinding negative = s_xinput_generic_binding_axis_mapping[i][0];
|
||||
const GenericInputBinding positive = s_xinput_generic_binding_axis_mapping[i][1];
|
||||
if (negative != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(negative, fmt::format("XInput-{}/-{}", pid, s_axis_names[i]));
|
||||
mapping->emplace_back(negative, fmt::format("XInput-{}/-{}", pid, s_axis_setting_names[i]));
|
||||
|
||||
if (positive != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(positive, fmt::format("XInput-{}/+{}", pid, s_axis_names[i]));
|
||||
mapping->emplace_back(positive, fmt::format("XInput-{}/+{}", pid, s_axis_setting_names[i]));
|
||||
}
|
||||
for (u32 i = 0; i < std::size(s_xinput_generic_binding_button_mapping); i++)
|
||||
{
|
||||
const GenericInputBinding binding = s_xinput_generic_binding_button_mapping[i];
|
||||
if (binding != GenericInputBinding::Unknown)
|
||||
mapping->emplace_back(binding, fmt::format("XInput-{}/{}", pid, s_button_names[i]));
|
||||
mapping->emplace_back(binding, fmt::format("XInput-{}/{}", pid, s_button_setting_names[i]));
|
||||
}
|
||||
|
||||
if (m_controllers[pid].has_small_motor)
|
||||
|
|
|
@ -75,6 +75,7 @@ public:
|
|||
void UpdateSettings(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock) override;
|
||||
bool ReloadDevices() override;
|
||||
void Shutdown() override;
|
||||
bool IsInitialized() override;
|
||||
|
||||
void PollEvents() override;
|
||||
std::vector<std::pair<std::string, std::string>> EnumerateDevices() override;
|
||||
|
@ -84,7 +85,7 @@ public:
|
|||
void UpdateMotorState(InputBindingKey large_key, InputBindingKey small_key, float large_intensity, float small_intensity) override;
|
||||
|
||||
std::optional<InputBindingKey> ParseKeyString(const std::string_view device, const std::string_view binding) override;
|
||||
TinyString ConvertKeyToString(InputBindingKey key) override;
|
||||
TinyString ConvertKeyToString(InputBindingKey key, bool display = false, bool migration = false) override;
|
||||
TinyString ConvertKeyToIcon(InputBindingKey key) override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -167,8 +167,8 @@ void Pad::SetDefaultControllerConfig(SettingsInterface& si)
|
|||
InputManager::InputSourceToString(static_cast<InputSourceType>(i)),
|
||||
InputManager::GetInputSourceDefaultEnabled(static_cast<InputSourceType>(i)));
|
||||
}
|
||||
si.SetBoolValue("InputSources", "SDLControllerEnhancedMode", false);
|
||||
si.SetBoolValue("InputSources", "SDLPS5PlayerLED", false);
|
||||
si.SetBoolValue("InputSources", "SDLControllerEnhancedMode", true);
|
||||
si.SetBoolValue("InputSources", "SDLPS5PlayerLED", true);
|
||||
si.SetBoolValue("Pad", "MultitapPort1", false);
|
||||
si.SetBoolValue("Pad", "MultitapPort2", false);
|
||||
si.SetFloatValue("Pad", "PointerXScale", 8.0f);
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace usb_pad
|
|||
{
|
||||
DestroyEffects();
|
||||
|
||||
SDL_HapticClose(m_haptic);
|
||||
SDL_CloseHaptic(m_haptic);
|
||||
m_haptic = nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ namespace usb_pad
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
SDL_Haptic* haptic = SDL_HapticOpenFromJoystick(joystick);
|
||||
SDL_Haptic* haptic = SDL_OpenHapticFromJoystick(joystick);
|
||||
if (!haptic)
|
||||
{
|
||||
Console.Error(fmt::format("Haptic is not supported on {}.", device));
|
||||
|
@ -77,16 +77,16 @@ namespace usb_pad
|
|||
// - Simagic Alpha Mini: Does NOT implement infinite durations (stops after some time, seeking hard numbers)
|
||||
constexpr u32 length = SDL_HAPTIC_INFINITY;
|
||||
|
||||
const unsigned int supported = SDL_HapticQuery(m_haptic);
|
||||
const unsigned int supported = SDL_GetHapticFeatures(m_haptic);
|
||||
if (supported & SDL_HAPTIC_CONSTANT)
|
||||
{
|
||||
m_constant_effect.type = SDL_HAPTIC_CONSTANT;
|
||||
m_constant_effect.constant.direction.type = SDL_HAPTIC_STEERING_AXIS;
|
||||
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)
|
||||
Console.Error("SDL_HapticNewEffect() for constant failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_CreateHapticEffect() for constant failed: %s", SDL_GetError());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -99,9 +99,9 @@ namespace usb_pad
|
|||
m_spring_effect.condition.direction.type = SDL_HAPTIC_STEERING_AXIS;
|
||||
m_spring_effect.condition.length = length;
|
||||
|
||||
m_spring_effect_id = SDL_HapticNewEffect(m_haptic, &m_spring_effect);
|
||||
m_spring_effect_id = SDL_CreateHapticEffect(m_haptic, &m_spring_effect);
|
||||
if (m_spring_effect_id < 0)
|
||||
Console.Error("SDL_HapticNewEffect() for spring failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_CreateHapticEffect() for spring failed: %s", SDL_GetError());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -114,9 +114,9 @@ namespace usb_pad
|
|||
m_damper_effect.condition.direction.type = SDL_HAPTIC_STEERING_AXIS;
|
||||
m_damper_effect.condition.length = length;
|
||||
|
||||
m_damper_effect_id = SDL_HapticNewEffect(m_haptic, &m_damper_effect);
|
||||
m_damper_effect_id = SDL_CreateHapticEffect(m_haptic, &m_damper_effect);
|
||||
if (m_damper_effect_id < 0)
|
||||
Console.Error("SDL_HapticNewEffect() for damper failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_CreateHapticEffect() for damper failed: %s", SDL_GetError());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -129,9 +129,9 @@ namespace usb_pad
|
|||
m_friction_effect.condition.direction.type = SDL_HAPTIC_STEERING_AXIS;
|
||||
m_friction_effect.condition.length = length;
|
||||
|
||||
m_friction_effect_id = SDL_HapticNewEffect(m_haptic, &m_friction_effect);
|
||||
m_friction_effect_id = SDL_CreateHapticEffect(m_haptic, &m_friction_effect);
|
||||
if (m_friction_effect_id < 0)
|
||||
Console.Error("SDL_HapticNewEffect() for friction failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_CreateHapticEffect() for friction failed: %s", SDL_GetError());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -149,10 +149,10 @@ namespace usb_pad
|
|||
{
|
||||
if (m_friction_effect_running)
|
||||
{
|
||||
SDL_HapticStopEffect(m_haptic, m_friction_effect_id);
|
||||
SDL_StopHapticEffect(m_haptic, m_friction_effect_id);
|
||||
m_friction_effect_running = false;
|
||||
}
|
||||
SDL_HapticDestroyEffect(m_haptic, m_friction_effect_id);
|
||||
SDL_DestroyHapticEffect(m_haptic, m_friction_effect_id);
|
||||
m_friction_effect_id = -1;
|
||||
}
|
||||
|
||||
|
@ -160,10 +160,10 @@ namespace usb_pad
|
|||
{
|
||||
if (m_damper_effect_running)
|
||||
{
|
||||
SDL_HapticStopEffect(m_haptic, m_damper_effect_id);
|
||||
SDL_StopHapticEffect(m_haptic, m_damper_effect_id);
|
||||
m_damper_effect_running = false;
|
||||
}
|
||||
SDL_HapticDestroyEffect(m_haptic, m_damper_effect_id);
|
||||
SDL_DestroyHapticEffect(m_haptic, m_damper_effect_id);
|
||||
m_damper_effect_id = -1;
|
||||
}
|
||||
|
||||
|
@ -171,10 +171,10 @@ namespace usb_pad
|
|||
{
|
||||
if (m_spring_effect_running)
|
||||
{
|
||||
SDL_HapticStopEffect(m_haptic, m_spring_effect_id);
|
||||
SDL_StopHapticEffect(m_haptic, m_spring_effect_id);
|
||||
m_spring_effect_running = false;
|
||||
}
|
||||
SDL_HapticDestroyEffect(m_haptic, m_spring_effect_id);
|
||||
SDL_DestroyHapticEffect(m_haptic, m_spring_effect_id);
|
||||
m_spring_effect_id = -1;
|
||||
}
|
||||
|
||||
|
@ -182,10 +182,10 @@ namespace usb_pad
|
|||
{
|
||||
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;
|
||||
}
|
||||
SDL_HapticDestroyEffect(m_haptic, m_constant_effect_id);
|
||||
SDL_DestroyHapticEffect(m_haptic, m_constant_effect_id);
|
||||
m_constant_effect_id = -1;
|
||||
}
|
||||
}
|
||||
|
@ -199,8 +199,8 @@ namespace usb_pad
|
|||
if (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)
|
||||
Console.Warning("SDL_HapticUpdateEffect() for constant failed: %s", SDL_GetError());
|
||||
if (!SDL_UpdateHapticEffect(m_haptic, m_constant_effect_id, &m_constant_effect))
|
||||
Console.Warning("SDL_UpdateHapticEffect() for constant failed: %s", SDL_GetError());
|
||||
}
|
||||
|
||||
// Avoid re-running already-running effects by default. Re-running a running effect
|
||||
|
@ -217,10 +217,10 @@ namespace usb_pad
|
|||
// This is the reason for use_ffb_dropout_workaround.
|
||||
if (!m_constant_effect_running || use_ffb_dropout_workaround)
|
||||
{
|
||||
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))
|
||||
m_constant_effect_running = true;
|
||||
else
|
||||
Console.Error("SDL_HapticRunEffect() for constant failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_RunHapticEffect() for constant failed: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,15 +248,15 @@ namespace usb_pad
|
|||
m_spring_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband);
|
||||
m_spring_effect.condition.center[0] = ClampS16(ff.u.condition.center);
|
||||
|
||||
if (SDL_HapticUpdateEffect(m_haptic, m_spring_effect_id, &m_spring_effect) != 0)
|
||||
Console.Warning("SDL_HapticUpdateEffect() for spring failed: %s", SDL_GetError());
|
||||
if (!SDL_UpdateHapticEffect(m_haptic, m_spring_effect_id, &m_spring_effect))
|
||||
Console.Warning("SDL_UpdateHapticEffect() for spring failed: %s", SDL_GetError());
|
||||
|
||||
if (!m_spring_effect_running)
|
||||
{
|
||||
if (SDL_HapticRunEffect(m_haptic, m_spring_effect_id, SDL_HAPTIC_INFINITY) == 0)
|
||||
if (SDL_RunHapticEffect(m_haptic, m_spring_effect_id, SDL_HAPTIC_INFINITY))
|
||||
m_spring_effect_running = true;
|
||||
else
|
||||
Console.Error("SDL_HapticRunEffect() for spring failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_RunHapticEffect() for spring failed: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -272,15 +272,15 @@ namespace usb_pad
|
|||
m_damper_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband);
|
||||
m_damper_effect.condition.center[0] = ClampS16(ff.u.condition.center);
|
||||
|
||||
if (SDL_HapticUpdateEffect(m_haptic, m_damper_effect_id, &m_damper_effect) != 0)
|
||||
Console.Warning("SDL_HapticUpdateEffect() for damper failed: %s", SDL_GetError());
|
||||
if (!SDL_UpdateHapticEffect(m_haptic, m_damper_effect_id, &m_damper_effect))
|
||||
Console.Warning("SDL_UpdateHapticEffect() for damper failed: %s", SDL_GetError());
|
||||
|
||||
if (!m_damper_effect_running)
|
||||
{
|
||||
if (SDL_HapticRunEffect(m_haptic, m_damper_effect_id, SDL_HAPTIC_INFINITY) == 0)
|
||||
if (SDL_RunHapticEffect(m_haptic, m_damper_effect_id, SDL_HAPTIC_INFINITY))
|
||||
m_damper_effect_running = true;
|
||||
else
|
||||
Console.Error("SDL_HapticRunEffect() for damper failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_RunHapticEffect() for damper failed: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -296,12 +296,12 @@ namespace usb_pad
|
|||
m_friction_effect.condition.deadband[0] = ClampU16(ff.u.condition.deadband);
|
||||
m_friction_effect.condition.center[0] = ClampS16(ff.u.condition.center);
|
||||
|
||||
if (SDL_HapticUpdateEffect(m_haptic, m_friction_effect_id, &m_friction_effect) != 0)
|
||||
if (!SDL_UpdateHapticEffect(m_haptic, m_friction_effect_id, &m_friction_effect))
|
||||
{
|
||||
if (!m_friction_effect_running && SDL_HapticRunEffect(m_haptic, m_friction_effect_id, SDL_HAPTIC_INFINITY) == 0)
|
||||
if (!m_friction_effect_running && SDL_RunHapticEffect(m_haptic, m_friction_effect_id, SDL_HAPTIC_INFINITY))
|
||||
m_friction_effect_running = true;
|
||||
else
|
||||
Console.Error("SDL_HapticUpdateEffect() for friction failed: %s", SDL_GetError());
|
||||
Console.Error("SDL_UpdateHapticEffect() for friction failed: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -309,8 +309,8 @@ namespace usb_pad
|
|||
{
|
||||
if (m_autocenter_supported)
|
||||
{
|
||||
if (SDL_HapticSetAutocenter(m_haptic, value) != 0)
|
||||
Console.Warning("SDL_HapticSetAutocenter() failed: %s", SDL_GetError());
|
||||
if (!SDL_SetHapticAutocenter(m_haptic, value))
|
||||
Console.Warning("SDL_SetHapticAutocenter() failed: %s", SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,7 @@ namespace usb_pad
|
|||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -332,7 +332,7 @@ namespace usb_pad
|
|||
{
|
||||
if (m_spring_effect_running)
|
||||
{
|
||||
SDL_HapticStopEffect(m_haptic, m_spring_effect_id);
|
||||
SDL_StopHapticEffect(m_haptic, m_spring_effect_id);
|
||||
m_spring_effect_running = false;
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +342,7 @@ namespace usb_pad
|
|||
{
|
||||
if (m_damper_effect_running)
|
||||
{
|
||||
SDL_HapticStopEffect(m_haptic, m_damper_effect_id);
|
||||
SDL_StopHapticEffect(m_haptic, m_damper_effect_id);
|
||||
m_damper_effect_running = false;
|
||||
}
|
||||
}
|
||||
|
@ -352,7 +352,7 @@ namespace usb_pad
|
|||
{
|
||||
if (m_friction_effect_running)
|
||||
{
|
||||
SDL_HapticStopEffect(m_haptic, m_friction_effect_id);
|
||||
SDL_StopHapticEffect(m_haptic, m_friction_effect_id);
|
||||
m_friction_effect_running = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -624,10 +624,10 @@ void VMManager::ReloadInputSources()
|
|||
LoadInputBindings(*si, lock);
|
||||
}
|
||||
|
||||
void VMManager::ReloadInputBindings()
|
||||
void VMManager::ReloadInputBindings(bool force)
|
||||
{
|
||||
// skip loading bindings if we're not running, since it'll get done on startup anyway
|
||||
if (!HasValidVM())
|
||||
if (!force && !HasValidVM())
|
||||
return;
|
||||
|
||||
FPControlRegisterBackup fpcr_backup(FPControlRegister::GetDefault());
|
||||
|
|
|
@ -114,7 +114,8 @@ namespace VMManager
|
|||
void ReloadInputSources();
|
||||
|
||||
/// Reloads input bindings.
|
||||
void ReloadInputBindings();
|
||||
/// Can be forced to load even when there is not an active virtual machine.
|
||||
void ReloadInputBindings(bool force = false);
|
||||
|
||||
/// Returns the save state filename for the given game serial/crc.
|
||||
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL2</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(DepsIncludeDir)\SDL3</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\fmt\include</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)3rdparty\winwil\include</AdditionalIncludeDirectories>
|
||||
|
|
|
@ -60,16 +60,16 @@ else()
|
|||
target_sources(core_test PRIVATE ${multi_isa_sources})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND TARGET SDL2::SDL2)
|
||||
# Copy SDL2 DLL to binary directory.
|
||||
if(WIN32 AND TARGET SDL3::SDL3)
|
||||
# Copy SDL3 DLL to binary directory.
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
get_property(SDL2_DLL_PATH TARGET SDL2::SDL2 PROPERTY IMPORTED_LOCATION_DEBUG)
|
||||
get_property(SDL3_DLL_PATH TARGET SDL3::SDL3 PROPERTY IMPORTED_LOCATION_DEBUG)
|
||||
else()
|
||||
get_property(SDL2_DLL_PATH TARGET SDL2::SDL2 PROPERTY IMPORTED_LOCATION_RELEASE)
|
||||
get_property(SDL3_DLL_PATH TARGET SDL3::SDL3 PROPERTY IMPORTED_LOCATION_RELEASE)
|
||||
endif()
|
||||
if(SDL2_DLL_PATH)
|
||||
if(SDL3_DLL_PATH)
|
||||
add_custom_command(TARGET core_test POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:core_test>"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SDL2_DLL_PATH}" "$<TARGET_FILE_DIR:core_test>")
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SDL3_DLL_PATH}" "$<TARGET_FILE_DIR:core_test>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
@ -39,6 +39,10 @@ std::unique_ptr<ProgressCallback> Host::CreateHostProgressCallback()
|
|||
return ProgressCallback::CreateNullProgressCallback();
|
||||
}
|
||||
|
||||
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue