From f084e76f3620c96f362d70a6f2d8e8df3ea9085e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 15 May 2024 07:42:19 +1000 Subject: [PATCH] Qt: Add option to pause when controller is disconnected --- pcsx2-gsrunner/Main.cpp | 4 +- pcsx2-qt/MainWindow.cpp | 14 +++-- pcsx2-qt/MainWindow.h | 3 +- pcsx2-qt/QtHost.cpp | 42 +++++++++++++-- pcsx2-qt/QtHost.h | 4 +- pcsx2-qt/Settings/InterfaceSettingsWidget.cpp | 9 ++-- pcsx2-qt/Settings/InterfaceSettingsWidget.ui | 53 +++++++++++-------- pcsx2/ImGui/FullscreenUI.cpp | 10 ++-- pcsx2/Input/DInputSource.cpp | 8 ++- pcsx2/Input/InputManager.cpp | 6 +-- pcsx2/Input/InputManager.h | 8 +-- pcsx2/Input/SDLInputSource.cpp | 30 ++++++----- pcsx2/Input/XInputSource.cpp | 18 ++++--- tests/ctest/core/StubHost.cpp | 4 +- 14 files changed, 135 insertions(+), 78 deletions(-) diff --git a/pcsx2-gsrunner/Main.cpp b/pcsx2-gsrunner/Main.cpp index c6ddb0c2bd..e51acea6b8 100644 --- a/pcsx2-gsrunner/Main.cpp +++ b/pcsx2-gsrunner/Main.cpp @@ -218,11 +218,11 @@ std::optional Host::GetTopLevelWindowInfo() return GSRunner::GetPlatformWindowInfo(); } -void Host::OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name) +void Host::OnInputDeviceConnected(const std::string_view identifier, const std::string_view device_name) { } -void Host::OnInputDeviceDisconnected(const std::string_view& identifier) +void Host::OnInputDeviceDisconnected(const InputBindingKey key, const std::string_view identifier) { } diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index c23f12e42f..9885320422 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -424,6 +424,7 @@ void MainWindow::connectSignals() void MainWindow::connectVMThreadSignals(EmuThread* thread) { connect(thread, &EmuThread::messageConfirmed, this, &MainWindow::confirmMessage, Qt::BlockingQueuedConnection); + connect(thread, &EmuThread::statusMessage, this, &MainWindow::onStatusMessage); connect(thread, &EmuThread::onAcquireRenderWindowRequested, this, &MainWindow::acquireRenderWindow, Qt::BlockingQueuedConnection); connect(thread, &EmuThread::onReleaseRenderWindowRequested, this, &MainWindow::releaseRenderWindow, Qt::BlockingQueuedConnection); connect(thread, &EmuThread::onResizeRenderWindowRequested, this, &MainWindow::displayResizeRequested); @@ -438,7 +439,6 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread) connect(thread, &EmuThread::onCaptureStarted, this, &MainWindow::onCaptureStarted); connect(thread, &EmuThread::onCaptureStopped, this, &MainWindow::onCaptureStopped); connect(thread, &EmuThread::onAchievementsLoginRequested, this, &MainWindow::onAchievementsLoginRequested); - connect(thread, &EmuThread::onAchievementsLoginSucceeded, this, &MainWindow::onAchievementsLoginSucceeded); connect(thread, &EmuThread::onAchievementsHardcoreModeChanged, this, &MainWindow::onAchievementsHardcoreModeChanged); connect(thread, &EmuThread::onCoverDownloaderOpenRequested, this, &MainWindow::onToolsCoverDownloaderTriggered); connect(thread, &EmuThread::onCreateMemoryCardOpenRequested, this, &MainWindow::onCreateMemoryCardOpenRequested); @@ -763,13 +763,6 @@ void MainWindow::onAchievementsLoginRequested(Achievements::LoginRequestReason r dlg.exec(); } -void MainWindow::onAchievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points, quint32 unread_messages) -{ - const QString message = - tr("RA: Logged in as %1 (%2 pts, softcore: %3 pts). %4 unread messages.").arg(display_name).arg(points).arg(sc_points).arg(unread_messages); - m_ui.statusBar->showMessage(message); -} - void MainWindow::onAchievementsHardcoreModeChanged(bool enabled) { // disable debugger while hardcore mode is active @@ -1143,6 +1136,11 @@ bool MainWindow::confirmMessage(const QString& title, const QString& message) return (QMessageBox::question(this, title, message) == QMessageBox::Yes); } +void MainWindow::onStatusMessage(const QString& message) +{ + m_ui.statusBar->showMessage(message); +} + void MainWindow::runOnUIThread(const std::function& func) { func(); diff --git a/pcsx2-qt/MainWindow.h b/pcsx2-qt/MainWindow.h index 04d5347dc8..2e0bb06fb2 100644 --- a/pcsx2-qt/MainWindow.h +++ b/pcsx2-qt/MainWindow.h @@ -110,6 +110,8 @@ public Q_SLOTS: void cancelGameListRefresh(); void reportError(const QString& title, const QString& message); bool confirmMessage(const QString& title, const QString& message); + void onStatusMessage(const QString& message); + void runOnUIThread(const std::function& func); void requestReset(); bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true); @@ -190,7 +192,6 @@ private Q_SLOTS: void onCaptureStopped(); void onAchievementsLoginRequested(Achievements::LoginRequestReason reason); - void onAchievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points, quint32 unread_messages); void onAchievementsHardcoreModeChanged(bool enabled); protected: diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index a9089abd65..9223d0f6b3 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -1107,7 +1107,14 @@ void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason) void Host::OnAchievementsLoginSuccess(const char* username, u32 points, u32 sc_points, u32 unread_messages) { - emit g_emu_thread->onAchievementsLoginSucceeded(QString::fromUtf8(username), points, sc_points, unread_messages); + const QString message = + qApp->translate("QtHost", "RA: Logged in as %1 (%2 pts, softcore: %3 pts). %4 unread messages.") + .arg(QString::fromUtf8(username)) + .arg(points) + .arg(sc_points) + .arg(unread_messages); + + emit g_emu_thread->statusMessage(message); } void Host::OnAchievementsRefreshed() @@ -1671,15 +1678,44 @@ std::optional Host::GetTopLevelWindowInfo() return ret; } -void Host::OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name) +void Host::OnInputDeviceConnected(const std::string_view identifier, const std::string_view device_name) { emit g_emu_thread->onInputDeviceConnected(identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size()), device_name.empty() ? QString() : QString::fromUtf8(device_name.data(), device_name.size())); + + + if (VMManager::HasValidVM() || g_emu_thread->isRunningFullscreenUI()) + { + Host::AddIconOSDMessage(fmt::format("controller_connected_{}", identifier), ICON_FA_GAMEPAD, + fmt::format(TRANSLATE_FS("QtHost", "Controller {} connected."), identifier), + Host::OSD_INFO_DURATION); + } } -void Host::OnInputDeviceDisconnected(const std::string_view& identifier) +void Host::OnInputDeviceDisconnected(const InputBindingKey key, const std::string_view identifier) { emit g_emu_thread->onInputDeviceDisconnected(identifier.empty() ? QString() : QString::fromUtf8(identifier.data(), identifier.size())); + + if (VMManager::GetState() == VMState::Running && Host::GetBoolSettingValue("UI", "PauseOnControllerDisconnection", false) && + InputManager::HasAnyBindingsForSource(key)) + { + std::string message = + fmt::format(TRANSLATE_FS("QtHost", "System paused because controller {} was disconnected."), identifier); + Host::RunOnCPUThread([message = QString::fromStdString(message)]() { + VMManager::SetPaused(true); + + // has to be done after pause, otherwise pause message takes precedence + emit g_emu_thread->statusMessage(message); + }); + Host::AddIconOSDMessage(fmt::format("controller_connected_{}", identifier), ICON_FA_GAMEPAD, std::move(message), + Host::OSD_WARNING_DURATION); + } + else if (VMManager::HasValidVM() || g_emu_thread->isRunningFullscreenUI()) + { + Host::AddIconOSDMessage(fmt::format("controller_connected_{}", identifier), ICON_FA_GAMEPAD, + fmt::format(TRANSLATE_FS("QtHost", "Controller {} disconnected."), identifier), + Host::OSD_INFO_DURATION); + } } void Host::SetMouseMode(bool relative_mode, bool hide_cursor) diff --git a/pcsx2-qt/QtHost.h b/pcsx2-qt/QtHost.h index a79f2a8ecb..fc74e6ec27 100644 --- a/pcsx2-qt/QtHost.h +++ b/pcsx2-qt/QtHost.h @@ -117,6 +117,7 @@ public Q_SLOTS: Q_SIGNALS: bool messageConfirmed(const QString& title, const QString& message); + void statusMessage(const QString& message); std::optional onAcquireRenderWindowRequested(bool recreate_window, bool fullscreen, bool render_to_main, bool surfaceless); void onResizeRenderWindowRequested(qint32 width, qint32 height); @@ -161,9 +162,6 @@ Q_SIGNALS: /// Called when achievements login is requested. void onAchievementsLoginRequested(Achievements::LoginRequestReason reason); - /// Called when achievements login succeeds. Also happens on startup. - void onAchievementsLoginSucceeded(const QString& display_name, quint32 points, quint32 sc_points, quint32 unread_messages); - /// Called when achievements are reloaded/refreshed (e.g. game change, login, option change). void onAchievementsRefreshed(quint32 id, const QString& game_info_string); diff --git a/pcsx2-qt/Settings/InterfaceSettingsWidget.cpp b/pcsx2-qt/Settings/InterfaceSettingsWidget.cpp index 794b30c453..56ffab1e35 100644 --- a/pcsx2-qt/Settings/InterfaceSettingsWidget.cpp +++ b/pcsx2-qt/Settings/InterfaceSettingsWidget.cpp @@ -10,7 +10,7 @@ const char* InterfaceSettingsWidget::THEME_NAMES[] = { QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Native"), - //: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated. +//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated. #ifdef _WIN32 QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Classic Windows"), #endif @@ -75,6 +75,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* dialog, QWidget SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.confirmShutdown, "UI", "ConfirmShutdown", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveStateOnShutdown, "EmuCore", "SaveStateOnShutdown", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "UI", "PauseOnFocusLoss", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnControllerDisconnection, "UI", "PauseOnControllerDisconnection", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.backupSaveStates, "EmuCore", "BackupSavestate", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.discordPresence, "EmuCore", "EnableDiscordPresence", false); @@ -147,6 +148,8 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* dialog, QWidget dialog->registerWidgetHelp(m_ui.pauseOnFocusLoss, tr("Pause On Focus Loss"), tr("Unchecked"), tr("Pauses the emulator when you minimize the window or switch to another application, " "and unpauses when you switch back.")); + dialog->registerWidgetHelp(m_ui.pauseOnControllerDisconnection, tr("Pause On Controller Disconnection"), + tr("Unchecked"), tr("Pauses the emulator when a controller with bindings is disconnected.")); dialog->registerWidgetHelp(m_ui.backupSaveStates, tr("Create Save State Backups"), tr("Checked"), //: Do not translate the ".backup" extension. tr("Creates a backup copy of a save state if it already exists when the save is created. The backup copy has a .backup suffix.")); @@ -164,10 +167,10 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsWindow* dialog, QWidget m_ui.discordPresence, tr("Enable Discord Presence"), tr("Unchecked"), tr("Shows the game you are currently playing as part of your profile in Discord.")); dialog->registerWidgetHelp( - m_ui.doubleClickTogglesFullscreen, tr("Double-Click Toggles Fullscreen"), tr("Checked"), + m_ui.doubleClickTogglesFullscreen, tr("Double-Click Toggles Fullscreen"), tr("Checked"), tr("Allows switching in and out of fullscreen mode by double-clicking the game window.")); dialog->registerWidgetHelp( - m_ui.disableWindowResizing, tr("Disable Window Resizing"), tr("Unchecked"), + m_ui.disableWindowResizing, tr("Disable Window Resizing"), tr("Unchecked"), tr("Prevents the main window from being resized.")); onRenderToSeparateWindowChanged(); diff --git a/pcsx2-qt/Settings/InterfaceSettingsWidget.ui b/pcsx2-qt/Settings/InterfaceSettingsWidget.ui index 3d4b677295..f59ba668ae 100644 --- a/pcsx2-qt/Settings/InterfaceSettingsWidget.ui +++ b/pcsx2-qt/Settings/InterfaceSettingsWidget.ui @@ -29,28 +29,28 @@ Behaviour - - - - Pause On Focus Loss - - - - - - - Inhibit Screensaver - - - - + Save State On Shutdown - + + + + Inhibit Screensaver + + + + + + + Confirm Shutdown + + + + Pause On Start @@ -58,26 +58,33 @@ - + - Confirm Shutdown + Pause On Focus Loss - - + + - Create Save State Backups + Pause On Controller Disconnection - + Enable Discord Presence + + + + Create Save State Backups + + + @@ -215,7 +222,7 @@ - Qt::Vertical + Qt::Orientation::Vertical diff --git a/pcsx2/ImGui/FullscreenUI.cpp b/pcsx2/ImGui/FullscreenUI.cpp index befec14cb6..f876ed2b64 100644 --- a/pcsx2/ImGui/FullscreenUI.cpp +++ b/pcsx2/ImGui/FullscreenUI.cpp @@ -3101,6 +3101,8 @@ void FullscreenUI::DrawInterfaceSettingsPage() DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_EYE, "Pause On Focus Loss"), FSUI_CSTR("Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back."), "UI", "PauseOnFocusLoss", false); + DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_GAMEPAD, "Pause On Controller Disconnection"), + FSUI_CSTR("Pauses the emulator when a controller with bindings is disconnected."), "UI", "PauseOnControllerDisconnection", false); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_LIST_ALT, "Pause On Menu"), FSUI_CSTR("Pauses the emulator when you open the quick menu, and unpauses when you close it."), "UI", "PauseOnMenu", true); DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_POWER_OFF, "Confirm Shutdown"), @@ -6898,6 +6900,7 @@ TRANSLATE_NOOP("FullscreenUI", "Prevents the screen saver from activating and th TRANSLATE_NOOP("FullscreenUI", "Shows the game you are currently playing as part of your profile on Discord."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a game is started."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you minimize the window or switch to another application, and unpauses when you switch back."); +TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when a controller with bindings is disconnected."); TRANSLATE_NOOP("FullscreenUI", "Pauses the emulator when you open the quick menu, and unpauses when you close it."); TRANSLATE_NOOP("FullscreenUI", "Determines whether a prompt will be displayed to confirm shutting down the emulator/game when the hotkey is pressed."); TRANSLATE_NOOP("FullscreenUI", "Automatically saves the emulator state when powering down or exiting. You can then resume directly from where you left off next time."); @@ -7140,10 +7143,11 @@ TRANSLATE_NOOP("FullscreenUI", "Synchronization"); TRANSLATE_NOOP("FullscreenUI", "Changes when SPU samples are generated relative to system emulation."); TRANSLATE_NOOP("FullscreenUI", "Buffer Size"); TRANSLATE_NOOP("FullscreenUI", "Determines the amount of audio buffered before being pulled by the host API."); -TRANSLATE_NOOP("FullscreenUI", "Minimal Output Latency"); -TRANSLATE_NOOP("FullscreenUI", "When enabled, the minimum supported output latency will be used for the host API."); +TRANSLATE_NOOP("FullscreenUI", "%d ms"); TRANSLATE_NOOP("FullscreenUI", "Output Latency"); TRANSLATE_NOOP("FullscreenUI", "Determines how much latency there is between the audio being picked up by the host API, and played through speakers."); +TRANSLATE_NOOP("FullscreenUI", "Minimal Output Latency"); +TRANSLATE_NOOP("FullscreenUI", "When enabled, the minimum supported output latency will be used for the host API."); TRANSLATE_NOOP("FullscreenUI", "Settings and Operations"); TRANSLATE_NOOP("FullscreenUI", "Creates a new memory card file or folder."); TRANSLATE_NOOP("FullscreenUI", "Simulates a larger memory card by filtering saves only to the current game."); @@ -7561,6 +7565,7 @@ TRANSLATE_NOOP("FullscreenUI", "Inhibit Screensaver"); TRANSLATE_NOOP("FullscreenUI", "Enable Discord Presence"); TRANSLATE_NOOP("FullscreenUI", "Pause On Start"); TRANSLATE_NOOP("FullscreenUI", "Pause On Focus Loss"); +TRANSLATE_NOOP("FullscreenUI", "Pause On Controller Disconnection"); TRANSLATE_NOOP("FullscreenUI", "Pause On Menu"); TRANSLATE_NOOP("FullscreenUI", "Confirm Shutdown"); TRANSLATE_NOOP("FullscreenUI", "Save State On Shutdown"); @@ -7683,6 +7688,5 @@ TRANSLATE_NOOP("FullscreenUI", "Game not loaded or no RetroAchievements availabl TRANSLATE_NOOP("FullscreenUI", "Card Enabled"); TRANSLATE_NOOP("FullscreenUI", "Card Name"); TRANSLATE_NOOP("FullscreenUI", "Eject Card"); -TRANSLATE_NOOP("FullscreenUI", "%d ms"); // TRANSLATION-STRING-AREA-END #endif diff --git a/pcsx2/Input/DInputSource.cpp b/pcsx2/Input/DInputSource.cpp index 80755ccade..4d680b0f3b 100644 --- a/pcsx2/Input/DInputSource.cpp +++ b/pcsx2/Input/DInputSource.cpp @@ -145,7 +145,9 @@ void DInputSource::Shutdown() { while (!m_controllers.empty()) { - InputManager::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(m_controllers.size() - 1))); + const u32 index = static_cast(m_controllers.size() - 1); + InputManager::OnInputDeviceDisconnected({{.source_type = InputSourceType::DInput, .source_index = index}}, + GetDeviceIdentifier(index)); m_controllers.pop_back(); } } @@ -245,7 +247,9 @@ void DInputSource::PollEvents() if (hr != DI_OK) { - InputManager::OnInputDeviceDisconnected(GetDeviceIdentifier(static_cast(i))); + InputManager::OnInputDeviceDisconnected( + {{.source_type = InputSourceType::DInput, .source_index = static_cast(i)}}, + GetDeviceIdentifier(static_cast(i))); m_controllers.erase(m_controllers.begin() + i); continue; } diff --git a/pcsx2/Input/InputManager.cpp b/pcsx2/Input/InputManager.cpp index 7017e84861..ef1b853f5e 100644 --- a/pcsx2/Input/InputManager.cpp +++ b/pcsx2/Input/InputManager.cpp @@ -1199,7 +1199,7 @@ void InputManager::UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, ImGuiManager::UpdateMousePosition(s_host_pointer_positions[0][0], s_host_pointer_positions[0][1]); } -void InputManager::OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name) +void InputManager::OnInputDeviceConnected(const std::string_view identifier, const std::string_view device_name) { if (VMManager::HasValidVM()) USB::InputDeviceConnected(identifier); @@ -1207,12 +1207,12 @@ void InputManager::OnInputDeviceConnected(const std::string_view& identifier, co Host::OnInputDeviceConnected(identifier, device_name); } -void InputManager::OnInputDeviceDisconnected(const std::string_view& identifier) +void InputManager::OnInputDeviceDisconnected(const InputBindingKey key, const std::string_view identifier) { if (VMManager::HasValidVM()) USB::InputDeviceDisconnected(identifier); - Host::OnInputDeviceDisconnected(identifier); + Host::OnInputDeviceDisconnected(key, identifier); } // ------------------------------------------------------------------------ diff --git a/pcsx2/Input/InputManager.h b/pcsx2/Input/InputManager.h index f4899d4610..c3ffb06b79 100644 --- a/pcsx2/Input/InputManager.h +++ b/pcsx2/Input/InputManager.h @@ -289,10 +289,10 @@ namespace InputManager void UpdateHostMouseMode(); /// Called when a new input device is connected. - void OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name); + void OnInputDeviceConnected(const std::string_view identifier, const std::string_view device_name); /// Called when an input device is disconnected. - void OnInputDeviceDisconnected(const std::string_view& identifier); + void OnInputDeviceDisconnected(const InputBindingKey key, const std::string_view identifier); } // namespace InputManager namespace Host @@ -301,10 +301,10 @@ namespace Host std::optional GetTopLevelWindowInfo(); /// Called when a new input device is connected. - void OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name); + void OnInputDeviceConnected(const std::string_view identifier, const std::string_view device_name); /// Called when an input device is disconnected. - void OnInputDeviceDisconnected(const std::string_view& identifier); + void OnInputDeviceDisconnected(const InputBindingKey key, const std::string_view identifier); /// Enables relative mouse mode in the host, and/or hides the cursor. void SetMouseMode(bool relative_mode, bool hide_cursor); diff --git a/pcsx2/Input/SDLInputSource.cpp b/pcsx2/Input/SDLInputSource.cpp index 168c9be735..95ad2232bf 100644 --- a/pcsx2/Input/SDLInputSource.cpp +++ b/pcsx2/Input/SDLInputSource.cpp @@ -657,7 +657,7 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) if (!gcontroller && !joystick) { - Console.Error("(SDLInputSource) Failed to open controller %d", index); + ERROR_LOG("(SDLInputSource) Failed to open controller {}", index); return false; } @@ -667,7 +667,7 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) { if (it->joystick_id == joystick_id) { - Console.Error("(SDLInputSource) Controller %d, instance %d, player %d already connected, ignoring.", index, joystick_id, player_id); + ERROR_LOG("(SDLInputSource) Controller {}, instance {}, player {} already connected, ignoring.", index, joystick_id, player_id); if (gcontroller) SDL_GameControllerClose(gcontroller); else @@ -680,8 +680,8 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) if (player_id < 0 || GetControllerDataForPlayerId(player_id) != m_controllers.end()) { const int free_player_id = GetFreePlayerId(); - Console.Warning("(SDLInputSource) Controller %d (joystick %d) returned player ID %d, which is invalid or in " - "use. Using ID %d instead.", + WARNING_LOG("(SDLInputSource) Controller {} (joystick {}) returned player ID {}, which is invalid or in " + "use. Using ID {} instead.", index, joystick_id, player_id, free_player_id); player_id = free_player_id; } @@ -690,7 +690,7 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) if (!name) name = "Unknown Device"; - Console.WriteLn("(SDLInputSource) Opened %s %d (instance id %d, player id %d): %s", is_gamecontroller ? "game controller" : "joystick", + INFO_LOG("(SDLInputSource) Opened {} {} (instance id {}, player id {}): {}", is_gamecontroller ? "game controller" : "joystick", index, joystick_id, player_id, name); ControllerData cd = {}; @@ -717,7 +717,7 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) for (size_t i = 0; i < std::size(s_sdl_button_names); i++) mark_bind(SDL_GameControllerGetBindForButton(gcontroller, static_cast(i))); - Console.WriteLn("(SDLInputSource) Controller %d has %d axes and %d buttons", player_id, num_axes, num_buttons); + INFO_LOG("(SDLInputSource) Controller {} has {} axes and {} buttons", player_id, num_axes, num_buttons); } else { @@ -726,14 +726,14 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) if (num_hats > 0) cd.last_hat_state.resize(static_cast(num_hats), u8(0)); - Console.WriteLn("(SDLInputSource) Joystick %d has %d axes, %d buttons and %d hats", player_id, + INFO_LOG("(SDLInputSource) Joystick {} has {} axes, {} buttons and {} hats", player_id, SDL_JoystickNumAxes(joystick), SDL_JoystickNumButtons(joystick), num_hats); } cd.use_game_controller_rumble = (gcontroller && SDL_GameControllerRumble(gcontroller, 0, 0, 0) == 0); if (cd.use_game_controller_rumble) { - Console.WriteLn("(SDLInputSource) Rumble is supported on '%s' via gamecontroller", name); + INFO_LOG("(SDLInputSource) Rumble is supported on '{}' via gamecontroller", name); } else { @@ -752,25 +752,25 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) } else { - Console.Error("(SDLInputSource) Failed to create haptic left/right effect: %s", SDL_GetError()); + ERROR_LOG("(SDLInputSource) Failed to create haptic left/right effect: {}", SDL_GetError()); if (SDL_HapticRumbleSupported(haptic) && SDL_HapticRumbleInit(haptic) != 0) { cd.haptic = haptic; } else { - Console.Error("(SDLInputSource) No haptic rumble supported: %s", SDL_GetError()); + ERROR_LOG("(SDLInputSource) No haptic rumble supported: {}", SDL_GetError()); SDL_HapticClose(haptic); } } } if (cd.haptic) - Console.WriteLn("(SDLInputSource) Rumble is supported on '%s' via haptic", name); + INFO_LOG("(SDLInputSource) Rumble is supported on '{}' via haptic", name); } if (!cd.haptic && !cd.use_game_controller_rumble) - Console.Warning("(SDLInputSource) Rumble is not supported on '%s'", name); + WARNING_LOG("(SDLInputSource) Rumble is not supported on '{}'", name); if (player_id >= 0 && static_cast(player_id) < MAX_LED_COLORS && gcontroller && SDL_GameControllerHasLED(gcontroller)) { @@ -779,7 +779,7 @@ bool SDLInputSource::OpenDevice(int index, bool is_gamecontroller) m_controllers.push_back(std::move(cd)); - InputManager::OnInputDeviceConnected(StringUtil::StdStringFromFormat("SDL-%d", player_id), name); + InputManager::OnInputDeviceConnected(fmt::format("SDL-{}", player_id), name); return true; } @@ -789,7 +789,9 @@ bool SDLInputSource::CloseDevice(int joystick_index) if (it == m_controllers.end()) return false; - InputManager::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("SDL-%d", it->player_id)); + InputManager::OnInputDeviceDisconnected( + {{.source_type = InputSourceType::SDL, .source_index = static_cast(it->player_id)}}, + fmt::format("SDL-{}", it->player_id)); if (it->haptic) SDL_HapticClose(it->haptic); diff --git a/pcsx2/Input/XInputSource.cpp b/pcsx2/Input/XInputSource.cpp index a0894d31b8..923037146e 100644 --- a/pcsx2/Input/XInputSource.cpp +++ b/pcsx2/Input/XInputSource.cpp @@ -226,7 +226,7 @@ void XInputSource::PollEvents() else { if (result != ERROR_DEVICE_NOT_CONNECTED) - Console.Warning("XInputGetState(%u) failed: 0x%08X / 0x%08X", i, result, GetLastError()); + WARNING_LOG("XInputGetState({}) failed: 0x{:08X} / 0x{:08X}", i, result, GetLastError()); if (was_connected) HandleControllerDisconnection(i); @@ -424,11 +424,11 @@ bool XInputSource::GetGenericBindingMapping(const std::string_view& device, Inpu void XInputSource::HandleControllerConnection(u32 index) { - Console.WriteLn("XInput controller %u connected.", index); + INFO_LOG("XInput controller {} connected.", index); XINPUT_CAPABILITIES caps = {}; if (m_xinput_get_capabilities(index, 0, &caps) != ERROR_SUCCESS) - Console.Warning("Failed to get XInput capabilities for controller %u", index); + WARNING_LOG("Failed to get XInput capabilities for controller {}", index); ControllerData& cd = m_controllers[index]; cd.connected = true; @@ -438,13 +438,17 @@ void XInputSource::HandleControllerConnection(u32 index) cd.last_state_scp = {}; InputManager::OnInputDeviceConnected( - StringUtil::StdStringFromFormat("XInput-%u", index), StringUtil::StdStringFromFormat("XInput Controller %u", index)); + fmt::format("XInput-{}", index), fmt::format("XInput Controller {}", index)); } void XInputSource::HandleControllerDisconnection(u32 index) { - Console.WriteLn("XInput controller %u disconnected.", index); - InputManager::OnInputDeviceDisconnected(StringUtil::StdStringFromFormat("XInput-%u", index)); + INFO_LOG("XInput controller {} disconnected.", index); + InputManager::OnInputDeviceDisconnected({{ + .source_type = InputSourceType::XInput, + .source_index = index, + }}, + fmt::format("XInput-{}", index)); m_controllers[index] = {}; } @@ -485,7 +489,7 @@ void XInputSource::CheckForStateChanges(u32 index, const XINPUT_STATE& new_state { const GenericInputBinding generic_key = (button < std::size(s_xinput_generic_binding_button_mapping)) ? s_xinput_generic_binding_button_mapping[button] : - GenericInputBinding::Unknown; + GenericInputBinding::Unknown; const float value = ((new_button_bits & button_mask) != 0) ? 1.0f : 0.0f; InputManager::InvokeEvents(MakeGenericControllerButtonKey(InputSourceType::XInput, index, button), value, generic_key); } diff --git a/tests/ctest/core/StubHost.cpp b/tests/ctest/core/StubHost.cpp index 677b4d8684..7d23593c2d 100644 --- a/tests/ctest/core/StubHost.cpp +++ b/tests/ctest/core/StubHost.cpp @@ -64,11 +64,11 @@ std::optional Host::GetTopLevelWindowInfo() return std::nullopt; } -void Host::OnInputDeviceConnected(const std::string_view& identifier, const std::string_view& device_name) +void Host::OnInputDeviceConnected(const std::string_view identifier, const std::string_view device_name) { } -void Host::OnInputDeviceDisconnected(const std::string_view& identifier) +void Host::OnInputDeviceDisconnected(const InputBindingKey key, const std::string_view identifier) { }