diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp index 6f037019e7..91ed7d8d56 100644 --- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp +++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp @@ -308,8 +308,17 @@ void WiimoteScannerWindows::FindAndAuthenticateWiimotes() { // The sync button method conveniently makes remotes seek reconnection on button press. // I think the 1+2 method is effectively pointless? - const auto pair_count = - DiscoverAndPairWiimotes(DEFAULT_INQUIRY_LENGTH, AuthenticationMethod::SyncButton); + static constexpr auto auth_method = AuthenticationMethod::SyncButton; + + // Windows isn't so cooperative. This helps one button click actually able to pair a remote. + constexpr int ITERATION_COUNT = 3; + + RemoveUnusableWiimoteBluetoothDevices(); + + auto pair_count = 0; + for (int i = 0; i != ITERATION_COUNT; ++i) + pair_count += DiscoverAndPairWiimotes(DEFAULT_INQUIRY_LENGTH, auth_method); + NOTICE_LOG_FMT(WIIMOTE, "Successfully paired Wiimotes: {}", pair_count); } diff --git a/Source/Core/DolphinQt/Config/WiimoteControllersWidget.cpp b/Source/Core/DolphinQt/Config/WiimoteControllersWidget.cpp index 1d78196907..9f7d4cdc49 100644 --- a/Source/Core/DolphinQt/Config/WiimoteControllersWidget.cpp +++ b/Source/Core/DolphinQt/Config/WiimoteControllersWidget.cpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -39,6 +41,10 @@ #include "DolphinQt/Settings.h" #include "DolphinQt/Settings/USBDevicePicker.h" +#if defined(_WIN32) +#include "Core/HW//WiimoteReal/IOWin.h" +#endif + WiimoteControllersWidget::WiimoteControllersWidget(QWidget* parent) : QWidget(parent) { CreateLayout(); @@ -191,7 +197,31 @@ void WiimoteControllersWidget::CreateLayout() m_bluetooth_adapters_refresh = new NonDefaultQPushButton(tr("Refresh")); m_wiimote_sync = new NonDefaultQPushButton(tr("Sync")); m_wiimote_reset = new NonDefaultQPushButton(tr("Reset")); - m_wiimote_refresh = new NonDefaultQPushButton(tr("Refresh")); + + m_wiimote_refresh_indicator = new QLabel{}; + m_wiimote_refresh_indicator->hide(); + m_wiimote_refresh = new QToolButton(); + auto* const wiimote_refresh_action = new QAction(tr("Refresh"), m_wiimote_refresh); + m_wiimote_refresh->setDefaultAction(wiimote_refresh_action); + connect(wiimote_refresh_action, &QAction::triggered, this, + &WiimoteControllersWidget::OnWiimoteRefreshPressed); + m_wiimote_refresh->setPopupMode(QToolButton::ToolButtonPopupMode::MenuButtonPopup); + +#if defined(_WIN32) + m_wiimote_refresh_indicator->setPixmap( + style()->standardIcon(QStyle::SP_BrowserReload).pixmap(16, 16)); + + auto* const wiimote_sync_action = new QAction(tr("Sync"), m_wiimote_refresh); + m_wiimote_refresh->addAction(wiimote_sync_action); + connect(wiimote_sync_action, &QAction::triggered, this, + &WiimoteControllersWidget::TriggerHostWiimoteSync); + + auto* const wiimote_reset_action = new QAction(tr("Reset"), m_wiimote_refresh); + m_wiimote_refresh->addAction(wiimote_reset_action); + connect(wiimote_reset_action, &QAction::triggered, this, + &WiimoteControllersWidget::TriggerHostWiimoteReset); +#endif + m_wiimote_pt_labels[0] = new QLabel(tr("Sync real Wii Remotes and pair them")); m_wiimote_pt_labels[1] = new QLabel(tr("Reset all saved Wii Remote pairings")); m_wiimote_emu = new QRadioButton(tr("Emulate the Wii's Bluetooth adapter")); @@ -245,7 +275,13 @@ void WiimoteControllersWidget::CreateLayout() m_wiimote_layout->addWidget(m_wiimote_ciface, m_wiimote_layout->rowCount(), 0, 1, -1); int continuous_scanning_row = m_wiimote_layout->rowCount(); - m_wiimote_layout->addWidget(m_wiimote_continuous_scanning, continuous_scanning_row, 0, 1, 3); + + auto* const left_of_refresh_button_layout = new QHBoxLayout; + left_of_refresh_button_layout->addWidget(m_wiimote_continuous_scanning); + left_of_refresh_button_layout->addStretch(1); + left_of_refresh_button_layout->addWidget(m_wiimote_refresh_indicator); + + m_wiimote_layout->addLayout(left_of_refresh_button_layout, continuous_scanning_row, 0, 1, 3); m_wiimote_layout->addWidget(m_wiimote_refresh, continuous_scanning_row, 3); m_bluetooth_unavailable = new QLabel(tr("A supported Bluetooth device could not be found.\n" @@ -287,8 +323,6 @@ void WiimoteControllersWidget::ConnectWidgets() &WiimoteControllersWidget::OnBluetoothPassthroughSyncPressed); connect(m_wiimote_reset, &QPushButton::clicked, this, &WiimoteControllersWidget::OnBluetoothPassthroughResetPressed); - connect(m_wiimote_refresh, &QPushButton::clicked, this, - &WiimoteControllersWidget::OnWiimoteRefreshPressed); for (size_t i = 0; i < m_wiimote_groups.size(); i++) { @@ -503,3 +537,40 @@ void WiimoteControllersWidget::SaveSettings() SConfig::GetInstance().SaveSettings(); } + +#if defined(_WIN32) +void WiimoteControllersWidget::AsyncRefreshActionHelper(std::invocable<> auto func) +{ + m_wiimote_refresh->setEnabled(false); + m_wiimote_refresh_indicator->show(); + + auto result = std::async(std::launch::async, std::move(func)); + + auto* const animation = new QTimer{this}; + connect(animation, &QTimer::timeout, this, [this, animation, result = std::move(result)] { + // Spin the refresh indicator. + m_wiimote_refresh_indicator->setPixmap( + m_wiimote_refresh_indicator->pixmap().transformed(QTransform().rotate(90))); + + if (result.wait_for(std::chrono::seconds{}) != std::future_status::ready) + return; + + // When the async task is done, re-enable the button and hide the indicator. + animation->deleteLater(); + m_wiimote_refresh_indicator->hide(); + m_wiimote_refresh->setEnabled(true); + }); + + animation->start(250); +} + +void WiimoteControllersWidget::TriggerHostWiimoteSync() +{ + AsyncRefreshActionHelper(WiimoteReal::WiimoteScannerWindows::FindAndAuthenticateWiimotes); +} + +void WiimoteControllersWidget::TriggerHostWiimoteReset() +{ + AsyncRefreshActionHelper(WiimoteReal::WiimoteScannerWindows::RemoveRememberedWiimotes); +} +#endif diff --git a/Source/Core/DolphinQt/Config/WiimoteControllersWidget.h b/Source/Core/DolphinQt/Config/WiimoteControllersWidget.h index ef75fbbcbb..b2a082b3e2 100644 --- a/Source/Core/DolphinQt/Config/WiimoteControllersWidget.h +++ b/Source/Core/DolphinQt/Config/WiimoteControllersWidget.h @@ -10,10 +10,12 @@ #include "Common/WorkQueueThread.h" #include "Core/USBUtils.h" +class QAction; class QCheckBox; class QComboBox; class QHBoxLayout; class QGridLayout; +class QToolButton; class QGroupBox; class QLabel; class QPushButton; @@ -48,6 +50,12 @@ private: void ConnectWidgets(); void LoadSettings(Core::State state); +#if defined(_WIN32) + void AsyncRefreshActionHelper(std::invocable<> auto); + void TriggerHostWiimoteSync(); + void TriggerHostWiimoteReset(); +#endif + QGroupBox* m_wiimote_box; QGridLayout* m_wiimote_layout; std::array m_wiimote_labels; @@ -70,6 +78,7 @@ private: QCheckBox* m_wiimote_real_balance_board; QCheckBox* m_wiimote_speaker_data; QCheckBox* m_wiimote_ciface; - QPushButton* m_wiimote_refresh; + QToolButton* m_wiimote_refresh; + QLabel* m_wiimote_refresh_indicator; QLabel* m_bluetooth_unavailable; };