summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorJMC47 <JMC4789@gmail.com>2025-10-21 19:49:22 -0400
committerGitHub <noreply@github.com>2025-10-21 19:49:22 -0400
commitbe131ddc5974dda67e597195437a9e65034853fa (patch)
treefd1ef64cfc8ebf242e746aadd4f56bc6a027c400 /Source
parent5f5cfda5ad98f63ce213323b2ac99a3854501cc3 (diff)
parent26c5b2f57a2f0aec357448523c205b0970a5b9c3 (diff)
Merge pull request #13984 from jordan-woyak/wmreal-quick-connect-and-disconnect
WiimoteReal: Quickly connect and disconnect Wii remotes with hidapi / Android.
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp44
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOAndroid.h14
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IODummy.h1
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOLinux.cpp31
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOLinux.h5
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOWin.cpp23
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOWin.h8
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp12
-rw-r--r--Source/Core/Core/HW/WiimoteReal/IOhidapi.h4
-rw-r--r--Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp26
-rw-r--r--Source/Core/Core/HW/WiimoteReal/WiimoteReal.h17
11 files changed, 125 insertions, 60 deletions
diff --git a/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp b/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp
index 84d9c2615a..bdc0a6fc42 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp
+++ b/Source/Core/Core/HW/WiimoteReal/IOAndroid.cpp
@@ -5,6 +5,8 @@
#include <jni.h>
+#include <fmt/format.h>
+
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/Flag.h"
@@ -20,11 +22,9 @@ namespace WiimoteReal
// Java classes
static jclass s_adapter_class;
-void WiimoteScannerAndroid::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
- Wiimote*& found_board)
+auto WiimoteScannerAndroid::FindAttachedWiimotes() -> FindResults
{
- found_wiimotes.clear();
- found_board = nullptr;
+ FindResults results;
NOTICE_LOG_FMT(WIIMOTE, "Finding Wiimotes");
@@ -37,8 +37,23 @@ void WiimoteScannerAndroid::FindWiimotes(std::vector<Wiimote*>& found_wiimotes,
env->CallStaticBooleanMethod(s_adapter_class, openadapter_func))
{
for (int i = 0; i < MAX_WIIMOTES; ++i)
- found_wiimotes.emplace_back(new WiimoteAndroid(i));
+ {
+ if (!IsNewWiimote(WiimoteAndroid::GetIdFromDolphinBarIndex(i)))
+ continue;
+
+ auto wiimote = std::make_unique<WiimoteAndroid>(i);
+
+ if (!wiimote->ConnectInternal())
+ continue;
+
+ // TODO: We make no attempt to differentiate balance boards here.
+ // wiimote->IsBalanceBoard() would probably be enough to do that.
+
+ results.wii_remotes.emplace_back(std::move(wiimote));
+ }
}
+
+ return results;
}
WiimoteAndroid::WiimoteAndroid(int index) : Wiimote(), m_mayflash_index(index)
@@ -50,9 +65,22 @@ WiimoteAndroid::~WiimoteAndroid()
Shutdown();
}
+std::string WiimoteAndroid::GetId() const
+{
+ return GetIdFromDolphinBarIndex(m_mayflash_index);
+}
+
+std::string WiimoteAndroid::GetIdFromDolphinBarIndex(int index)
+{
+ return fmt::format("Android {}", index);
+}
+
// Connect to a Wiimote with a known address.
bool WiimoteAndroid::ConnectInternal()
{
+ if (IsConnected())
+ return true;
+
auto* const env = IDCache::GetEnvForThread();
jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "wiimotePayload", "[[B");
@@ -64,6 +92,12 @@ bool WiimoteAndroid::ConnectInternal()
m_input_func = env->GetStaticMethodID(s_adapter_class, "input", "(I)I");
m_output_func = env->GetStaticMethodID(s_adapter_class, "output", "(I[BI)I");
+ // Test a write to see if a remote is actually connected to the DolphinBar.
+ constexpr u8 report[] = {WR_SET_REPORT | BT_OUTPUT,
+ u8(WiimoteCommon::OutputReportID::RequestStatus), 0};
+ if (IOWrite(report, sizeof(report)) <= 0)
+ return false;
+
is_connected = true;
return true;
diff --git a/Source/Core/Core/HW/WiimoteReal/IOAndroid.h b/Source/Core/Core/HW/WiimoteReal/IOAndroid.h
index 7581a6dbd1..fc257a8ad6 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOAndroid.h
+++ b/Source/Core/Core/HW/WiimoteReal/IOAndroid.h
@@ -12,12 +12,18 @@
namespace WiimoteReal
{
+class WiimoteScannerAndroid;
+
class WiimoteAndroid final : public Wiimote
{
+ friend WiimoteScannerAndroid;
+
public:
WiimoteAndroid(int index);
~WiimoteAndroid() override;
- std::string GetId() const override { return "Android " + std::to_string(m_mayflash_index); }
+
+ std::string GetId() const override;
+ static std::string GetIdFromDolphinBarIndex(int index);
protected:
bool ConnectInternal() override;
@@ -29,7 +35,7 @@ protected:
private:
int m_mayflash_index;
- bool is_connected = true;
+ bool is_connected = false;
jmethodID m_input_func;
jmethodID m_output_func;
@@ -43,7 +49,9 @@ public:
WiimoteScannerAndroid() = default;
~WiimoteScannerAndroid() override = default;
bool IsReady() const override { return true; }
- void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
+
+ FindResults FindAttachedWiimotes() override;
+
void Update() override {}
void RequestStopSearching() override {}
};
diff --git a/Source/Core/Core/HW/WiimoteReal/IODummy.h b/Source/Core/Core/HW/WiimoteReal/IODummy.h
index 2df8e6fb5c..2fe6e9a71f 100644
--- a/Source/Core/Core/HW/WiimoteReal/IODummy.h
+++ b/Source/Core/Core/HW/WiimoteReal/IODummy.h
@@ -13,7 +13,6 @@ public:
WiimoteScannerDummy() = default;
~WiimoteScannerDummy() override = default;
bool IsReady() const override { return false; }
- void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override {}
void Update() override {}
void RequestStopSearching() override {}
};
diff --git a/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp b/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp
index 3fe5f09403..fef4f3f4df 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp
+++ b/Source/Core/Core/HW/WiimoteReal/IOLinux.cpp
@@ -31,8 +31,10 @@ namespace WiimoteReal
constexpr u16 L2CAP_PSM_HID_CNTL = 0x0011;
constexpr u16 L2CAP_PSM_HID_INTR = 0x0013;
-static void AddAutoConnectAddresses(std::vector<Wiimote*>& found_wiimotes)
+static auto GetAutoConnectAddresses()
{
+ std::vector<std::unique_ptr<Wiimote>> wii_remotes;
+
std::string entries = Config::Get(Config::MAIN_WIIMOTE_AUTO_CONNECT_ADDRESSES);
for (auto& bt_address_str : SplitString(entries, ','))
{
@@ -47,9 +49,11 @@ static void AddAutoConnectAddresses(std::vector<Wiimote*>& found_wiimotes)
if (!IsNewWiimote(bt_address_str))
continue;
- found_wiimotes.push_back(new WiimoteLinux(*bt_addr));
+ wii_remotes.emplace_back(std::make_unique<WiimoteLinux>(*bt_addr));
NOTICE_LOG_FMT(WIIMOTE, "Added Wiimote with fixed address ({}).", bt_address_str);
}
+
+ return wii_remotes;
}
WiimoteScannerLinux::WiimoteScannerLinux()
@@ -134,7 +138,8 @@ static int HciInquiry(int device_socket, InquiryRequest* request)
// Signal doneness to `poll`.
u64 val = 1;
- write(done_event, &val, sizeof(val));
+ if (write(done_event, &val, sizeof(val)) != sizeof(val))
+ ERROR_LOG_FMT(WIIMOTE, "failed to write to eventfd: {}", Common::LastStrerrorString());
}};
Common::ScopeGuard join_guard([&] { pthread_join(hci_inquiry_thread.handle, nullptr); });
@@ -157,14 +162,14 @@ static int HciInquiry(int device_socket, InquiryRequest* request)
return hci_inquiry_errorno;
}
-void WiimoteScannerLinux::FindWiimotes(std::vector<Wiimote*>& found_wiimotes, Wiimote*& found_board)
+auto WiimoteScannerLinux::FindNewWiimotes() -> FindResults
{
- found_board = nullptr;
+ FindResults results;
if (!Open())
- return;
+ return results;
- AddAutoConnectAddresses(found_wiimotes);
+ results.wii_remotes = GetAutoConnectAddresses();
InquiryRequest request{};
request.dev_id = m_device_id;
@@ -186,7 +191,7 @@ void WiimoteScannerLinux::FindWiimotes(std::vector<Wiimote*>& found_wiimotes, Wi
default:
ERROR_LOG_FMT(WIIMOTE, "Error searching for Bluetooth devices: {}",
Common::StrerrorString(hci_inquiry_result));
- return;
+ return results;
}
DEBUG_LOG_FMT(WIIMOTE, "Found {} Bluetooth device(s).", request.num_rsp);
@@ -197,8 +202,8 @@ void WiimoteScannerLinux::FindWiimotes(std::vector<Wiimote*>& found_wiimotes, Wi
BluetoothAddressToString(std::bit_cast<Common::BluetoothAddress>(scan_info.bdaddr));
// Did AddAutoConnectAddresses already add this remote?
- const auto eq_this_bdaddr = [&](auto* wm) { return wm->GetId() == bdaddr_str; };
- if (std::ranges::any_of(found_wiimotes, eq_this_bdaddr))
+ const auto eq_this_bdaddr = [&](auto& wm) { return wm->GetId() == bdaddr_str; };
+ if (std::ranges::any_of(results.wii_remotes, eq_this_bdaddr))
continue;
if (!IsNewWiimote(bdaddr_str))
@@ -233,15 +238,17 @@ void WiimoteScannerLinux::FindWiimotes(std::vector<Wiimote*>& found_wiimotes, Wi
std::make_unique<WiimoteLinux>(std::bit_cast<Common::BluetoothAddress>(scan_info.bdaddr));
if (IsBalanceBoardName(name))
{
- delete std::exchange(found_board, wm.release());
+ results.balance_boards.emplace_back(std::move(wm));
NOTICE_LOG_FMT(WIIMOTE, "Found balance board ({}).", bdaddr_str);
}
else
{
- found_wiimotes.push_back(wm.release());
+ results.wii_remotes.emplace_back(std::move(wm));
NOTICE_LOG_FMT(WIIMOTE, "Found Wiimote ({}).", bdaddr_str);
}
}
+
+ return results;
}
void WiimoteScannerLinux::Update()
diff --git a/Source/Core/Core/HW/WiimoteReal/IOLinux.h b/Source/Core/Core/HW/WiimoteReal/IOLinux.h
index 9f03dbd066..7f88ac89b8 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOLinux.h
+++ b/Source/Core/Core/HW/WiimoteReal/IOLinux.h
@@ -42,7 +42,10 @@ public:
~WiimoteScannerLinux() override;
bool IsReady() const override;
- void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
+
+ // FYI: This backend only supports connecting remotes just found via Bluetooth inquiry.
+ FindResults FindNewWiimotes() override;
+
void Update() override;
void RequestStopSearching() override;
diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
index 91ed7d8d56..af442355cd 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
+++ b/Source/Core/Core/HW/WiimoteReal/IOWin.cpp
@@ -576,9 +576,10 @@ int WiimoteWindows::IOWrite(const u8* buf, size_t len)
return write_result;
}
-void WiimoteScannerWindows::FindWiimoteHIDDevices(std::vector<Wiimote*>& found_wiimotes,
- Wiimote*& found_board)
+auto WiimoteScannerWindows::FindWiimoteHIDDevices() -> FindResults
{
+ FindResults results;
+
// Enumerate connected HID interfaces IDs.
auto class_guid = GUID_DEVINTERFACE_HID;
constexpr ULONG flags = CM_GET_DEVICE_INTERFACE_LIST_PRESENT;
@@ -591,7 +592,7 @@ void WiimoteScannerWindows::FindWiimoteHIDDevices(std::vector<Wiimote*>& found_w
if (list_result != CR_SUCCESS)
{
ERROR_LOG_FMT(WIIMOTE, "CM_Get_Device_Interface_List: {}", list_result);
- return;
+ return results;
}
for (const WCHAR* hid_iface = buffer.get(); *hid_iface != L'\0';
@@ -678,26 +679,26 @@ void WiimoteScannerWindows::FindWiimoteHIDDevices(std::vector<Wiimote*>& found_w
is_balance_board = wiimote->IsBalanceBoard();
if (*is_balance_board)
- delete std::exchange(found_board, wiimote.release());
+ results.balance_boards.emplace_back(std::move(wiimote));
else
- found_wiimotes.push_back(wiimote.release());
+ results.wii_remotes.emplace_back(std::move(wiimote));
}
+
+ return results;
}
-void WiimoteScannerWindows::FindWiimotes(std::vector<Wiimote*>&, Wiimote*&)
+auto WiimoteScannerWindows::FindNewWiimotes() -> FindResults
{
// Ideally we'd only enumerate the radios once.
RemoveUnusableWiimoteBluetoothDevices();
DiscoverAndPairWiimotes(DEFAULT_INQUIRY_LENGTH);
- // Kinda odd that we never return any remotes here. The scanner interface is odd.
- // We return all the results in FindAlreadyConnectedWiimote.
+ return FindWiimoteHIDDevices();
}
-void WiimoteScannerWindows::FindAttachedDevices(std::vector<Wiimote*>& found_wiimotes,
- Wiimote*& found_board)
+auto WiimoteScannerWindows::FindAttachedWiimotes() -> FindResults
{
- FindWiimoteHIDDevices(found_wiimotes, found_board);
+ return FindWiimoteHIDDevices();
}
bool WiimoteScannerWindows::IsReady() const
diff --git a/Source/Core/Core/HW/WiimoteReal/IOWin.h b/Source/Core/Core/HW/WiimoteReal/IOWin.h
index 12c577f950..b8bc29a86f 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOWin.h
+++ b/Source/Core/Core/HW/WiimoteReal/IOWin.h
@@ -52,8 +52,10 @@ class WiimoteScannerWindows final : public WiimoteScannerBackend
public:
WiimoteScannerWindows();
bool IsReady() const override;
- void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
- void FindAttachedDevices(std::vector<Wiimote*>&, Wiimote*&) override;
+
+ FindResults FindNewWiimotes() override;
+ FindResults FindAttachedWiimotes() override;
+
void Update() override;
void RequestStopSearching() override {}
@@ -61,7 +63,7 @@ public:
static void RemoveRememberedWiimotes();
private:
- void FindWiimoteHIDDevices(std::vector<Wiimote*>&, Wiimote*&);
+ FindResults FindWiimoteHIDDevices();
};
} // namespace WiimoteReal
diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp
index 7a70b09409..4f38c4a949 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp
+++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.cpp
@@ -108,8 +108,10 @@ bool WiimoteScannerHidapi::IsReady() const
return true;
}
-void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& wiimotes, Wiimote*& board)
+auto WiimoteScannerHidapi::FindAttachedWiimotes() -> FindResults
{
+ FindResults results;
+
hid_device_info* list = hid_enumerate(0x0, 0x0); // FYI: 0 for all VID/PID.
for (hid_device_info* device = list; device != nullptr; device = device->next)
{
@@ -123,12 +125,12 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& wiimotes, Wiimote
LogLinuxDriverName(device->path);
#endif
- auto* wiimote = new WiimoteHidapi(device->path);
+ auto wiimote = std::make_unique<WiimoteHidapi>(device->path);
const bool is_balance_board = IsBalanceBoardName(name) || wiimote->IsBalanceBoard();
if (is_balance_board)
- board = wiimote;
+ results.balance_boards.emplace_back(std::move(wiimote));
else
- wiimotes.push_back(wiimote);
+ results.wii_remotes.emplace_back(std::move(wiimote));
NOTICE_LOG_FMT(WIIMOTE, "Found {} at {}: {} {} ({:04x}:{:04x})",
is_balance_board ? "balance board" : "Wiimote", device->path,
@@ -136,6 +138,8 @@ void WiimoteScannerHidapi::FindWiimotes(std::vector<Wiimote*>& wiimotes, Wiimote
WStringToUTF8(device->product_string), device->vendor_id, device->product_id);
}
hid_free_enumeration(list);
+
+ return results;
}
WiimoteHidapi::WiimoteHidapi(std::string device_path) : m_device_path(std::move(device_path))
diff --git a/Source/Core/Core/HW/WiimoteReal/IOhidapi.h b/Source/Core/Core/HW/WiimoteReal/IOhidapi.h
index f4340e3bc2..16cb6c858d 100644
--- a/Source/Core/Core/HW/WiimoteReal/IOhidapi.h
+++ b/Source/Core/Core/HW/WiimoteReal/IOhidapi.h
@@ -36,7 +36,9 @@ public:
WiimoteScannerHidapi();
~WiimoteScannerHidapi() override;
bool IsReady() const override;
- void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) override;
+
+ FindResults FindAttachedWiimotes() override;
+
void Update() override {} // not needed for hidapi
void RequestStopSearching() override {} // not needed for hidapi
};
diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp
index cdf477d8be..603ad9ed0f 100644
--- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp
+++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.cpp
@@ -716,40 +716,36 @@ void WiimoteScanner::ThreadFunc()
auto scan_mode = WiimoteScanMode::SCAN_ONCE;
m_scan_mode.compare_exchange_strong(scan_mode, WiimoteScanMode::DO_NOT_SCAN);
+ // When not scanning we still look for already attached devices.
+ // This allows Windows, hidapi, and DolphinBar remotes to be quickly discovered.
+ const bool should_perform_inquiry = scan_mode != WiimoteScanMode::DO_NOT_SCAN;
+
for (const auto& backend : m_backends)
{
- std::vector<Wiimote*> found_wiimotes;
- Wiimote* found_board = nullptr;
-
- // When not scanning we still look for already attached devices.
- // This allows Windows and DolphinBar remotes to be quickly discovered.
- if (scan_mode == WiimoteScanMode::DO_NOT_SCAN)
- backend->FindAttachedDevices(found_wiimotes, found_board);
- else
- backend->FindWiimotes(found_wiimotes, found_board);
-
+ auto results =
+ should_perform_inquiry ? backend->FindNewWiimotes() : backend->FindAttachedWiimotes();
{
std::unique_lock wm_lk(g_wiimotes_mutex);
- for (auto* wiimote : found_wiimotes)
+ for (auto& wiimote : results.wii_remotes)
{
{
std::lock_guard lk(s_known_ids_mutex);
s_known_ids.insert(wiimote->GetId());
}
- AddWiimoteToPool(std::unique_ptr<Wiimote>(wiimote));
+ AddWiimoteToPool(std::move(wiimote));
g_controller_interface.PlatformPopulateDevices([] { ProcessWiimotePool(); });
}
- if (found_board)
+ for (auto& bboard : results.balance_boards)
{
{
std::lock_guard lk(s_known_ids_mutex);
- s_known_ids.insert(found_board->GetId());
+ s_known_ids.insert(bboard->GetId());
}
- TryToConnectBalanceBoard(std::unique_ptr<Wiimote>(found_board));
+ TryToConnectBalanceBoard(std::move(bboard));
}
}
}
diff --git a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h
index dd0f699aed..940eedeab1 100644
--- a/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h
+++ b/Source/Core/Core/HW/WiimoteReal/WiimoteReal.h
@@ -184,15 +184,24 @@ public:
// Note: Invoked from UI thread.
virtual bool IsReady() const = 0;
- virtual void FindWiimotes(std::vector<Wiimote*>&, Wiimote*&) = 0;
// function called when not looking for more Wiimotes
virtual void Update() = 0;
// requests the backend to stop scanning if FindWiimotes is blocking
virtual void RequestStopSearching() = 0;
- // Used by Windows to search for HID interfaces of already connected Wii remotes.
- // hidapi should probably implement the equivalent.
- virtual void FindAttachedDevices(std::vector<Wiimote*>&, Wiimote*&) {}
+ struct FindResults
+ {
+ std::vector<std::unique_ptr<Wiimote>> wii_remotes;
+ std::vector<std::unique_ptr<Wiimote>> balance_boards;
+ };
+
+ // Implementations are expected to perform a new inquiry if possible.
+ // Only not-yet-in-use remotes shall be returned.
+ virtual FindResults FindNewWiimotes() { return FindAttachedWiimotes(); }
+
+ // Implementations shall return not-not-in-use already connected remotes.
+ // e.g. DolphinBar interfaces would be found here.
+ virtual FindResults FindAttachedWiimotes() { return {}; }
};
enum class WiimoteScanMode