mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-03-11 16:05:23 +01:00
Wiimote to GunCon3: rework disconnect/reconnect logic
This commit is contained in:
parent
f50ed8752c
commit
81bc25d3b4
|
|
@ -248,6 +248,13 @@ void usb_device_guncon3::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint,
|
|||
if (my_wiimote_index >= 0 && static_cast<size_t>(my_wiimote_index) < states.size())
|
||||
{
|
||||
const auto& ws = states[my_wiimote_index];
|
||||
if (!ws.connected)
|
||||
{
|
||||
// Disconnected Wiimote, provide default neutral state for this GunCon
|
||||
std::memcpy(buf, &gc, std::min<usz>(buf_size, sizeof(gc)));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto map = wm->get_mapping();
|
||||
|
||||
auto is_pressed = [&](wiimote_button btn) { return (ws.buttons & static_cast<u16>(btn)) != 0; };
|
||||
|
|
|
|||
|
|
@ -16,38 +16,57 @@ static constexpr u16 VID_MAYFLASH = 0x0079;
|
|||
static constexpr u16 PID_DOLPHINBAR_START = 0x1800;
|
||||
static constexpr u16 PID_DOLPHINBAR_END = 0x1803;
|
||||
|
||||
wiimote_device::wiimote_device(hid_device_info* info)
|
||||
: m_path(info->path)
|
||||
, m_serial(info->serial_number ? info->serial_number : L"")
|
||||
wiimote_device::wiimote_device()
|
||||
{
|
||||
m_state.connected = false;
|
||||
}
|
||||
|
||||
wiimote_device::~wiimote_device()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
bool wiimote_device::open(hid_device_info* info)
|
||||
{
|
||||
if (m_handle) return false;
|
||||
|
||||
m_path = info->path;
|
||||
m_serial = info->serial_number ? info->serial_number : L"";
|
||||
m_handle = hid_open_path(info->path);
|
||||
|
||||
if (m_handle)
|
||||
{
|
||||
// 1. Connectivity Test (Matching wiimote_test)
|
||||
u8 status_req[] = { 0x15, 0x00 };
|
||||
if (hid_write(m_handle, status_req, sizeof(status_req)) < 0)
|
||||
{
|
||||
hid_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
return;
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// 2. Full Initialization
|
||||
if (initialize_ir())
|
||||
{
|
||||
m_state.connected = true;
|
||||
m_last_update = std::chrono::steady_clock::now();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
hid_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
}
|
||||
|
||||
close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
wiimote_device::~wiimote_device()
|
||||
void wiimote_device::close()
|
||||
{
|
||||
if (m_handle) hid_close(m_handle);
|
||||
if (m_handle)
|
||||
{
|
||||
hid_close(m_handle);
|
||||
m_handle = nullptr;
|
||||
}
|
||||
m_state = {}; // Reset state including connected = false
|
||||
m_path.clear();
|
||||
m_serial.clear();
|
||||
}
|
||||
|
||||
bool wiimote_device::initialize_ir()
|
||||
|
|
@ -101,11 +120,13 @@ bool wiimote_device::update()
|
|||
|
||||
u8 buf[22];
|
||||
int res;
|
||||
bool received = false;
|
||||
|
||||
// Fully drain the buffer until empty to ensure we have the most recent data.
|
||||
// This avoids getting stuck behind a backlog of old reports (e.g. from before IR was enabled).
|
||||
while ((res = hid_read_timeout(m_handle, buf, sizeof(buf), 0)) > 0)
|
||||
{
|
||||
received = true;
|
||||
// All data reports (0x30-0x3F) carry buttons in the same location (first 2 bytes).
|
||||
// We mask out accelerometer LSBs (bits 5,6 of both bytes).
|
||||
if ((buf[0] & 0xF0) == 0x30)
|
||||
|
|
@ -133,7 +154,22 @@ bool wiimote_device::update()
|
|||
}
|
||||
|
||||
// hid_read_timeout returns -1 on error (e.g. device disconnected).
|
||||
if (res < 0) return false;
|
||||
if (res < 0)
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (received)
|
||||
{
|
||||
m_last_update = std::chrono::steady_clock::now();
|
||||
}
|
||||
else if (std::chrono::steady_clock::now() - m_last_update > std::chrono::seconds(2))
|
||||
{
|
||||
// No data for 2 seconds. Likely disconnected or powered off.
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -219,7 +255,11 @@ wiimote_manager::wiimote_manager()
|
|||
if (!s_instance)
|
||||
s_instance = this;
|
||||
|
||||
|
||||
// Pre-initialize 4 Wiimote slots (standard for DolphinBar and typical local multiplayer)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
m_devices.push_back(std::make_unique<wiimote_device>());
|
||||
}
|
||||
|
||||
load_config();
|
||||
}
|
||||
|
|
@ -300,36 +340,53 @@ void wiimote_manager::thread_proc()
|
|||
auto scan_and_add = [&](u16 vid, u16 pid_start, u16 pid_end)
|
||||
{
|
||||
hid_device_info* devs = hid_enumerate(vid, 0);
|
||||
hid_device_info* cur = devs;
|
||||
|
||||
while (cur)
|
||||
for (hid_device_info* cur = devs; cur; cur = cur->next)
|
||||
{
|
||||
if (cur->product_id >= pid_start && cur->product_id <= pid_end)
|
||||
{
|
||||
bool already_owned = false;
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
||||
// 1. Check if this physical device is already connected to any slot
|
||||
bool already_connected = false;
|
||||
for (const auto& d : m_devices)
|
||||
{
|
||||
std::shared_lock lock(m_mutex);
|
||||
for (const auto& d : m_devices)
|
||||
if (d->get_state().connected && d->get_path() == cur->path)
|
||||
{
|
||||
if (d->get_path() == cur->path)
|
||||
already_connected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (already_connected) continue;
|
||||
|
||||
// 2. Determine target slot
|
||||
int slot_idx = -1;
|
||||
if (vid == VID_MAYFLASH)
|
||||
{
|
||||
// DolphinBar Mode 4: PIDs 0x1800-0x1803 correspond to Players 1-4
|
||||
slot_idx = cur->product_id - PID_DOLPHINBAR_START;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generic Wiimote: Find first available slot
|
||||
for (size_t i = 0; i < m_devices.size(); i++)
|
||||
{
|
||||
if (!m_devices[i]->get_state().connected)
|
||||
{
|
||||
already_owned = true;
|
||||
slot_idx = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!already_owned)
|
||||
// 3. Connect to slot
|
||||
if (slot_idx >= 0 && slot_idx < static_cast<int>(m_devices.size()))
|
||||
{
|
||||
auto dev = std::make_unique<wiimote_device>(cur);
|
||||
if (dev->get_state().connected)
|
||||
if (!m_devices[slot_idx]->get_state().connected)
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
m_devices.push_back(std::move(dev));
|
||||
m_devices[slot_idx]->open(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
hid_free_enumeration(devs);
|
||||
};
|
||||
|
|
@ -339,17 +396,19 @@ void wiimote_manager::thread_proc()
|
|||
// Wiimote Plus
|
||||
scan_and_add(VID_NINTENDO, PID_WIIMOTE_PLUS, PID_WIIMOTE_PLUS);
|
||||
// Mayflash DolphinBar Mode 4 (Custom VID/PIDs)
|
||||
// Supports up to 4 players (1800, 1801, 1802, 1803)
|
||||
scan_and_add(VID_MAYFLASH, PID_DOLPHINBAR_START, PID_DOLPHINBAR_END);
|
||||
}
|
||||
|
||||
// Update all devices at 100Hz
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
m_devices.erase(std::remove_if(m_devices.begin(), m_devices.end(), [](const auto& d)
|
||||
for (auto& d : m_devices)
|
||||
{
|
||||
return !const_cast<wiimote_device&>(*d).update();
|
||||
}), m_devices.end());
|
||||
if (d->get_state().connected)
|
||||
{
|
||||
d->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
|
|
|||
|
|
@ -62,9 +62,12 @@ struct wiimote_state
|
|||
class wiimote_device
|
||||
{
|
||||
public:
|
||||
wiimote_device(hid_device_info* info);
|
||||
wiimote_device();
|
||||
~wiimote_device();
|
||||
|
||||
bool open(hid_device_info* info);
|
||||
void close();
|
||||
|
||||
bool update();
|
||||
const wiimote_state& get_state() const { return m_state; }
|
||||
std::string get_path() const { return m_path; }
|
||||
|
|
@ -75,6 +78,7 @@ private:
|
|||
std::string m_path;
|
||||
std::wstring m_serial;
|
||||
wiimote_state m_state;
|
||||
std::chrono::steady_clock::time_point m_last_update;
|
||||
|
||||
bool initialize_ir();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -244,9 +244,12 @@ void wiimote_settings_dialog::update_list()
|
|||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
auto states = wm->get_states();
|
||||
for (size_t i = 0; i < states.size(); i++)
|
||||
{
|
||||
ui->wiimoteList->addItem(tr("Wiimote #%1").arg(i + 1));
|
||||
QString label = tr("Wiimote #%1").arg(i + 1);
|
||||
if (!states[i].connected) label += " (" + tr("Disconnected") + ")";
|
||||
ui->wiimoteList->addItem(label);
|
||||
}
|
||||
ui->wiimoteList->setCurrentRow(0);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue