PairingDialog: Implement 'pairing' for bluez, reformat file

This commit is contained in:
capitalistspz 2024-09-26 02:50:02 +01:00
parent 0d4176aab0
commit 00ff45d66b
3 changed files with 214 additions and 168 deletions

View file

@ -4,233 +4,279 @@
#if BOOST_OS_WINDOWS #if BOOST_OS_WINDOWS
#include <bluetoothapis.h> #include <bluetoothapis.h>
#endif #endif
#if BOOST_OS_LINUX
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <input/api/Wiimote/l2cap/L2CapWiimote.h>
#endif
wxDECLARE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent); wxDECLARE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent);
wxDEFINE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent); wxDEFINE_EVENT(wxEVT_PROGRESS_PAIR, wxCommandEvent);
PairingDialog::PairingDialog(wxWindow* parent) PairingDialog::PairingDialog(wxWindow* parent)
: wxDialog(parent, wxID_ANY, _("Pairing..."), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX) : wxDialog(parent, wxID_ANY, _("Pairing..."), wxDefaultPosition, wxDefaultSize, wxCAPTION | wxMINIMIZE_BOX | wxSYSTEM_MENU | wxTAB_TRAVERSAL | wxCLOSE_BOX)
{ {
auto* sizer = new wxBoxSizer(wxVERTICAL); auto* sizer = new wxBoxSizer(wxVERTICAL);
m_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(350, 20), wxGA_HORIZONTAL); m_gauge = new wxGauge(this, wxID_ANY, 100, wxDefaultPosition, wxSize(350, 20), wxGA_HORIZONTAL);
m_gauge->SetValue(0); m_gauge->SetValue(0);
sizer->Add(m_gauge, 0, wxALL | wxEXPAND, 5); sizer->Add(m_gauge, 0, wxALL | wxEXPAND, 5);
auto* rows = new wxFlexGridSizer(0, 2, 0, 0); auto* rows = new wxFlexGridSizer(0, 2, 0, 0);
rows->AddGrowableCol(1); rows->AddGrowableCol(1);
m_text = new wxStaticText(this, wxID_ANY, _("Searching for controllers...")); m_text = new wxStaticText(this, wxID_ANY, _("Searching for controllers..."));
rows->Add(m_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); rows->Add(m_text, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
{ {
auto* right_side = new wxBoxSizer(wxHORIZONTAL); auto* right_side = new wxBoxSizer(wxHORIZONTAL);
m_cancelButton = new wxButton(this, wxID_ANY, _("Cancel")); m_cancelButton = new wxButton(this, wxID_ANY, _("Cancel"));
m_cancelButton->Bind(wxEVT_BUTTON, &PairingDialog::OnCancelButton, this); m_cancelButton->Bind(wxEVT_BUTTON, &PairingDialog::OnCancelButton, this);
right_side->Add(m_cancelButton, 0, wxALL, 5); right_side->Add(m_cancelButton, 0, wxALL, 5);
rows->Add(right_side, 1, wxALIGN_RIGHT, 5); rows->Add(right_side, 1, wxALIGN_RIGHT, 5);
} }
sizer->Add(rows, 0, wxALL | wxEXPAND, 5); sizer->Add(rows, 0, wxALL | wxEXPAND, 5);
SetSizerAndFit(sizer); SetSizerAndFit(sizer);
Centre(wxBOTH); Centre(wxBOTH);
Bind(wxEVT_CLOSE_WINDOW, &PairingDialog::OnClose, this); Bind(wxEVT_CLOSE_WINDOW, &PairingDialog::OnClose, this);
Bind(wxEVT_PROGRESS_PAIR, &PairingDialog::OnGaugeUpdate, this); Bind(wxEVT_PROGRESS_PAIR, &PairingDialog::OnGaugeUpdate, this);
m_thread = std::thread(&PairingDialog::WorkerThread, this); m_thread = std::thread(&PairingDialog::WorkerThread, this);
} }
PairingDialog::~PairingDialog() PairingDialog::~PairingDialog()
{ {
Unbind(wxEVT_CLOSE_WINDOW, &PairingDialog::OnClose, this); Unbind(wxEVT_CLOSE_WINDOW, &PairingDialog::OnClose, this);
} }
void PairingDialog::OnClose(wxCloseEvent& event) void PairingDialog::OnClose(wxCloseEvent& event)
{ {
event.Skip(); event.Skip();
m_threadShouldQuit = true; m_threadShouldQuit = true;
if (m_thread.joinable()) if (m_thread.joinable())
m_thread.join(); m_thread.join();
} }
void PairingDialog::OnCancelButton(const wxCommandEvent& event) void PairingDialog::OnCancelButton(const wxCommandEvent& event)
{ {
Close(); Close();
} }
void PairingDialog::OnGaugeUpdate(wxCommandEvent& event) void PairingDialog::OnGaugeUpdate(wxCommandEvent& event)
{ {
PairingState state = (PairingState)event.GetInt(); PairingState state = (PairingState)event.GetInt();
switch (state) switch (state)
{ {
case PairingState::Pairing: case PairingState::Pairing:
{ {
m_text->SetLabel(_("Found controller. Pairing...")); m_text->SetLabel(_("Found controller. Pairing..."));
m_gauge->SetValue(50); m_gauge->SetValue(50);
break; break;
} }
case PairingState::Finished: case PairingState::Finished:
{ {
m_text->SetLabel(_("Successfully paired the controller.")); m_text->SetLabel(_("Successfully paired the controller."));
m_gauge->SetValue(100); m_gauge->SetValue(100);
m_cancelButton->SetLabel(_("Close")); m_cancelButton->SetLabel(_("Close"));
break; break;
} }
case PairingState::NoBluetoothAvailable: case PairingState::NoBluetoothAvailable:
{ {
m_text->SetLabel(_("Failed to find a suitable Bluetooth radio.")); m_text->SetLabel(_("Failed to find a suitable Bluetooth radio."));
m_gauge->SetValue(0); m_gauge->SetValue(0);
m_cancelButton->SetLabel(_("Close")); m_cancelButton->SetLabel(_("Close"));
break; break;
} }
case PairingState::BluetoothFailed: case PairingState::SearchFailed:
{ {
m_text->SetLabel(_("Failed to search for controllers.")); m_text->SetLabel(_("Failed to find controllers."));
m_gauge->SetValue(0); m_gauge->SetValue(0);
m_cancelButton->SetLabel(_("Close")); m_cancelButton->SetLabel(_("Close"));
break; break;
} }
case PairingState::PairingFailed: case PairingState::PairingFailed:
{ {
m_text->SetLabel(_("Failed to pair with the found controller.")); m_text->SetLabel(_("Failed to pair with the found controller."));
m_gauge->SetValue(0); m_gauge->SetValue(0);
m_cancelButton->SetLabel(_("Close")); m_cancelButton->SetLabel(_("Close"));
break; break;
} }
case PairingState::BluetoothUnusable: case PairingState::BluetoothUnusable:
{ {
m_text->SetLabel(_("Please use your system's Bluetooth manager instead.")); m_text->SetLabel(_("Please use your system's Bluetooth manager instead."));
m_gauge->SetValue(0); m_gauge->SetValue(0);
m_cancelButton->SetLabel(_("Close")); m_cancelButton->SetLabel(_("Close"));
break; break;
} }
default:
default: {
{ break;
break; }
} }
}
} }
void PairingDialog::WorkerThread()
{
const std::wstring wiimoteName = L"Nintendo RVL-CNT-01";
const std::wstring wiiUProControllerName = L"Nintendo RVL-CNT-01-UC";
#if BOOST_OS_WINDOWS #if BOOST_OS_WINDOWS
const GUID bthHidGuid = {0x00001124,0x0000,0x1000,{0x80,0x00,0x00,0x80,0x5F,0x9B,0x34,0xFB}}; void PairingDialog::WorkerThread()
{
const std::wstring wiimoteName = L"Nintendo RVL-CNT-01";
const std::wstring wiiUProControllerName = L"Nintendo RVL-CNT-01-UC";
const BLUETOOTH_FIND_RADIO_PARAMS radioFindParams = const GUID bthHidGuid = {0x00001124, 0x0000, 0x1000, {0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB}};
{
.dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS)
};
HANDLE radio = INVALID_HANDLE_VALUE; const BLUETOOTH_FIND_RADIO_PARAMS radioFindParams =
HBLUETOOTH_RADIO_FIND radioFind = BluetoothFindFirstRadio(&radioFindParams, &radio); {
if (radioFind == nullptr) .dwSize = sizeof(BLUETOOTH_FIND_RADIO_PARAMS)};
{
UpdateCallback(PairingState::NoBluetoothAvailable);
return;
}
BluetoothFindRadioClose(radioFind); HANDLE radio = INVALID_HANDLE_VALUE;
HBLUETOOTH_RADIO_FIND radioFind = BluetoothFindFirstRadio(&radioFindParams, &radio);
if (radioFind == nullptr)
{
UpdateCallback(PairingState::NoBluetoothAvailable);
return;
}
BLUETOOTH_RADIO_INFO radioInfo = BluetoothFindRadioClose(radioFind);
{
.dwSize = sizeof(BLUETOOTH_RADIO_INFO)
};
DWORD result = BluetoothGetRadioInfo(radio, &radioInfo); BLUETOOTH_RADIO_INFO radioInfo =
if (result != ERROR_SUCCESS) {
{ .dwSize = sizeof(BLUETOOTH_RADIO_INFO)};
UpdateCallback(PairingState::NoBluetoothAvailable);
return;
}
const BLUETOOTH_DEVICE_SEARCH_PARAMS searchParams = DWORD result = BluetoothGetRadioInfo(radio, &radioInfo);
{ if (result != ERROR_SUCCESS)
.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS), {
UpdateCallback(PairingState::NoBluetoothAvailable);
return;
}
.fReturnAuthenticated = FALSE, const BLUETOOTH_DEVICE_SEARCH_PARAMS searchParams =
.fReturnRemembered = FALSE, {
.fReturnUnknown = TRUE, .dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS),
.fReturnConnected = FALSE,
.fIssueInquiry = TRUE, .fReturnAuthenticated = FALSE,
.cTimeoutMultiplier = 5, .fReturnRemembered = FALSE,
.fReturnUnknown = TRUE,
.fReturnConnected = FALSE,
.hRadio = radio .fIssueInquiry = TRUE,
}; .cTimeoutMultiplier = 5,
BLUETOOTH_DEVICE_INFO info = .hRadio = radio};
{
.dwSize = sizeof(BLUETOOTH_DEVICE_INFO)
};
while (!m_threadShouldQuit) BLUETOOTH_DEVICE_INFO info =
{ {
HBLUETOOTH_DEVICE_FIND deviceFind = BluetoothFindFirstDevice(&searchParams, &info); .dwSize = sizeof(BLUETOOTH_DEVICE_INFO)};
if (deviceFind == nullptr)
{
UpdateCallback(PairingState::BluetoothFailed);
return;
}
while (!m_threadShouldQuit) while (!m_threadShouldQuit)
{ {
if (info.szName == wiimoteName || info.szName == wiiUProControllerName) HBLUETOOTH_DEVICE_FIND deviceFind = BluetoothFindFirstDevice(&searchParams, &info);
{ if (deviceFind == nullptr)
BluetoothFindDeviceClose(deviceFind); {
UpdateCallback(PairingState::BluetoothFailed);
return;
}
UpdateCallback(PairingState::Pairing); while (!m_threadShouldQuit)
{
if (info.szName == wiimoteName || info.szName == wiiUProControllerName)
{
BluetoothFindDeviceClose(deviceFind);
wchar_t passwd[6] = { radioInfo.address.rgBytes[0], radioInfo.address.rgBytes[1], radioInfo.address.rgBytes[2], radioInfo.address.rgBytes[3], radioInfo.address.rgBytes[4], radioInfo.address.rgBytes[5] }; UpdateCallback(PairingState::Pairing);
DWORD bthResult = BluetoothAuthenticateDevice(nullptr, radio, &info, passwd, 6);
if (bthResult != ERROR_SUCCESS)
{
UpdateCallback(PairingState::PairingFailed);
return;
}
bthResult = BluetoothSetServiceState(radio, &info, &bthHidGuid, BLUETOOTH_SERVICE_ENABLE); wchar_t passwd[6] = {radioInfo.address.rgBytes[0], radioInfo.address.rgBytes[1], radioInfo.address.rgBytes[2], radioInfo.address.rgBytes[3], radioInfo.address.rgBytes[4], radioInfo.address.rgBytes[5]};
if (bthResult != ERROR_SUCCESS) DWORD bthResult = BluetoothAuthenticateDevice(nullptr, radio, &info, passwd, 6);
{ if (bthResult != ERROR_SUCCESS)
UpdateCallback(PairingState::PairingFailed); {
return; UpdateCallback(PairingState::PairingFailed);
} return;
}
UpdateCallback(PairingState::Finished); bthResult = BluetoothSetServiceState(radio, &info, &bthHidGuid, BLUETOOTH_SERVICE_ENABLE);
return; if (bthResult != ERROR_SUCCESS)
} {
UpdateCallback(PairingState::PairingFailed);
return;
}
BOOL nextDevResult = BluetoothFindNextDevice(deviceFind, &info); UpdateCallback(PairingState::Finished);
if (nextDevResult == FALSE) return;
{ }
break;
}
}
BluetoothFindDeviceClose(deviceFind); BOOL nextDevResult = BluetoothFindNextDevice(deviceFind, &info);
} if (nextDevResult == FALSE)
#else {
UpdateCallback(PairingState::BluetoothUnusable); break;
#endif }
}
BluetoothFindDeviceClose(deviceFind);
}
} }
#elif BOOST_OS_LINUX
void PairingDialog::WorkerThread()
{
constexpr static uint8_t liacLap[] = {0x00, 0x8b, 0x9e};
constexpr static auto isWiimoteName = [](std::string_view name) {
return name == "Nintendo RVL-CNT-01" || name == "Nintendo RVL-CNT-01-TR";
};
// Get default BT device
const auto hostId = hci_get_route(nullptr);
if (hostId < 0)
{
UpdateCallback(PairingState::NoBluetoothAvailable);
return;
}
// Search for device
inquiry_info* info = nullptr;
const auto respCount = hci_inquiry(hostId, 5, 1, liacLap, &info, IREQ_CACHE_FLUSH);
if (respCount <= 0)
{
UpdateCallback(PairingState::SearchFailed);
return;
}
//! Open dev to read name
const auto hostDesc = hci_open_dev(hostId);
char nameBuffer[HCI_MAX_NAME_LENGTH] = {};
// Get device name and compare. Would use product and vendor id from SDP, but many third-party Wiimotes don't store them
auto& addr = info->bdaddr;
if (hci_read_remote_name(hostDesc, &addr, HCI_MAX_NAME_LENGTH, nameBuffer,
2000) != 0 || !isWiimoteName(nameBuffer))
{
UpdateCallback(PairingState::SearchFailed);
return;
}
cemuLog_log(LogType::Force, "Pairing Dialog: Found '{}' with address {:02x}", nameBuffer, fmt::join(addr.b, ":"));
UpdateCallback(PairingState::Finished);
L2CapWiimote::AddCandidateAddress(addr);
}
#else
void PairingDialog::WorkerThread()
{
UpdateCallback(PairingState::BluetoothUnusable);
}
#endif
void PairingDialog::UpdateCallback(PairingState state) void PairingDialog::UpdateCallback(PairingState state)
{ {
auto* event = new wxCommandEvent(wxEVT_PROGRESS_PAIR); auto* event = new wxCommandEvent(wxEVT_PROGRESS_PAIR);
event->SetInt((int)state); event->SetInt((int)state);
wxQueueEvent(this, event); wxQueueEvent(this, event);
} }

View file

@ -17,7 +17,7 @@ private:
Pairing, Pairing,
Finished, Finished,
NoBluetoothAvailable, NoBluetoothAvailable,
BluetoothFailed, SearchFailed,
PairingFailed, PairingFailed,
BluetoothUnusable BluetoothUnusable
}; };

View file

@ -1,5 +1,5 @@
#pragma once #pragma once
#include <api/Wiimote/WiimoteDevice.h> #include <input/api/Wiimote/WiimoteDevice.h>
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>
class L2CapWiimote : public WiimoteDevice class L2CapWiimote : public WiimoteDevice
@ -12,7 +12,7 @@ class L2CapWiimote : public WiimoteDevice
std::optional<std::vector<uint8>> read_data() override; std::optional<std::vector<uint8>> read_data() override;
bool operator==(WiimoteDevice& o) const override; bool operator==(WiimoteDevice& o) const override;
static void AddCandidateAddresses(const std::vector<bdaddr_t>& addrs); static void AddCandidateAddress(bdaddr_t addr);
static std::vector<WiimoteDevicePtr> get_devices(); static std::vector<WiimoteDevicePtr> get_devices();
private: private:
int m_recvFd; int m_recvFd;