Try to improve real wiimotes on Windows.
This commit is contained in:
parent
b8fd5c0c30
commit
c2d2fb8c7c
|
@ -270,10 +270,22 @@ bool Wiimote::Connect()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
hid_overlap = OVERLAPPED();
|
#if 0
|
||||||
hid_overlap.hEvent = CreateEvent(NULL, 1, 1, _T(""));
|
HIDD_ATTRIBUTES attr;
|
||||||
hid_overlap.Offset = 0;
|
attr.Size = sizeof(attr);
|
||||||
hid_overlap.OffsetHigh = 0;
|
if (!HidD_GetAttributes(dev_handle, &attr))
|
||||||
|
{
|
||||||
|
CloseHandle(dev_handle);
|
||||||
|
dev_handle = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
hid_overlap_read = OVERLAPPED();
|
||||||
|
hid_overlap_read.hEvent = CreateEvent(NULL, true, false, NULL);
|
||||||
|
|
||||||
|
hid_overlap_write = OVERLAPPED();
|
||||||
|
hid_overlap_write.hEvent = CreateEvent(NULL, true, false, NULL);
|
||||||
|
|
||||||
// TODO: thread isn't started here now, do this elsewhere
|
// TODO: thread isn't started here now, do this elsewhere
|
||||||
// This isn't as drastic as it sounds, since the process in which the threads
|
// This isn't as drastic as it sounds, since the process in which the threads
|
||||||
|
@ -296,7 +308,8 @@ void Wiimote::Disconnect()
|
||||||
CloseHandle(dev_handle);
|
CloseHandle(dev_handle);
|
||||||
dev_handle = 0;
|
dev_handle = 0;
|
||||||
|
|
||||||
CloseHandle(hid_overlap.hEvent);
|
CloseHandle(hid_overlap_read.hEvent);
|
||||||
|
CloseHandle(hid_overlap_write.hEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wiimote::IsConnected() const
|
bool Wiimote::IsConnected() const
|
||||||
|
@ -307,20 +320,20 @@ bool Wiimote::IsConnected() const
|
||||||
// positive = read packet
|
// positive = read packet
|
||||||
// negative = didn't read packet
|
// negative = didn't read packet
|
||||||
// zero = error
|
// zero = error
|
||||||
int Wiimote::IORead(unsigned char* buf)
|
int Wiimote::IORead(u8* buf)
|
||||||
{
|
{
|
||||||
// used below for a warning
|
// used below for a warning
|
||||||
*buf = 0;
|
*buf = 0;
|
||||||
|
|
||||||
DWORD bytes;
|
DWORD bytes;
|
||||||
ResetEvent(hid_overlap.hEvent);
|
ResetEvent(hid_overlap_read.hEvent);
|
||||||
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap))
|
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
|
||||||
{
|
{
|
||||||
auto const err = GetLastError();
|
auto const err = GetLastError();
|
||||||
|
|
||||||
if (ERROR_IO_PENDING == err)
|
if (ERROR_IO_PENDING == err)
|
||||||
{
|
{
|
||||||
auto const r = WaitForSingleObject(hid_overlap.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
auto const r = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
||||||
if (WAIT_TIMEOUT == r)
|
if (WAIT_TIMEOUT == r)
|
||||||
{
|
{
|
||||||
// Timeout - cancel and continue
|
// Timeout - cancel and continue
|
||||||
|
@ -338,7 +351,7 @@ int Wiimote::IORead(unsigned char* buf)
|
||||||
}
|
}
|
||||||
else if (WAIT_OBJECT_0 == r)
|
else if (WAIT_OBJECT_0 == r)
|
||||||
{
|
{
|
||||||
if (!GetOverlappedResult(dev_handle, &hid_overlap, &bytes, TRUE))
|
if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE))
|
||||||
{
|
{
|
||||||
WARN_LOG(WIIMOTE, "GetOverlappedResult failed on wiimote %i.", index + 1);
|
WARN_LOG(WIIMOTE, "GetOverlappedResult failed on wiimote %i.", index + 1);
|
||||||
bytes = 0;
|
bytes = 0;
|
||||||
|
@ -380,70 +393,76 @@ int Wiimote::IORead(unsigned char* buf)
|
||||||
|
|
||||||
int Wiimote::IOWrite(const u8* buf, int len)
|
int Wiimote::IOWrite(const u8* buf, int len)
|
||||||
{
|
{
|
||||||
u8 big_buf[MAX_PAYLOAD];
|
|
||||||
if (len < MAX_PAYLOAD)
|
|
||||||
{
|
|
||||||
std::copy(buf, buf + len, big_buf);
|
|
||||||
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
|
|
||||||
buf = big_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD bytes = 0;
|
|
||||||
switch (stack)
|
switch (stack)
|
||||||
{
|
{
|
||||||
case MSBT_STACK_UNKNOWN:
|
case MSBT_STACK_UNKNOWN:
|
||||||
{
|
{
|
||||||
// Try to auto-detect the stack type
|
// Try to auto-detect the stack type
|
||||||
|
stack = MSBT_STACK_BLUESOLEIL;
|
||||||
auto i = WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap);
|
if (IOWrite(buf, len))
|
||||||
if (i)
|
return 1;
|
||||||
|
|
||||||
|
stack = MSBT_STACK_MS;
|
||||||
|
if (IOWrite(buf, len))
|
||||||
{
|
{
|
||||||
// Bluesoleil will always return 1 here, even if it's not connected
|
// Don't mind me, just a random sleep to fix stuff on Windows
|
||||||
stack = MSBT_STACK_BLUESOLEIL;
|
SLEEP(1000);
|
||||||
return i;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1);
|
stack = MSBT_STACK_UNKNOWN;
|
||||||
if (i)
|
|
||||||
{
|
|
||||||
stack = MSBT_STACK_MS;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const dw = GetLastError();
|
|
||||||
// Checking for 121 = timeout on semaphore/device off/disconnected to
|
|
||||||
// avoid trouble with other stacks toshiba/widcomm
|
|
||||||
if (dw == 121)
|
|
||||||
{
|
|
||||||
NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: Timeout");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: ERROR: %08x", dw);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSBT_STACK_MS:
|
case MSBT_STACK_MS:
|
||||||
{
|
{
|
||||||
auto i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1);
|
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
|
||||||
auto dw = GetLastError();
|
//FlushFileBuffers(dev_handle);
|
||||||
|
|
||||||
if (dw == 121)
|
if (!result)
|
||||||
{
|
{
|
||||||
// Semaphore timeout
|
auto err = GetLastError();
|
||||||
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
|
if (err == 121)
|
||||||
return 0;
|
{
|
||||||
|
// Semaphore timeout
|
||||||
|
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case MSBT_STACK_BLUESOLEIL:
|
case MSBT_STACK_BLUESOLEIL:
|
||||||
return WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap);
|
{
|
||||||
|
u8 big_buf[MAX_PAYLOAD];
|
||||||
|
if (len < MAX_PAYLOAD)
|
||||||
|
{
|
||||||
|
std::copy(buf, buf + len, big_buf);
|
||||||
|
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
|
||||||
|
buf = big_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResetEvent(hid_overlap_write.hEvent);
|
||||||
|
DWORD bytes = 0;
|
||||||
|
if (WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_write))
|
||||||
|
{
|
||||||
|
// WriteFile always returns true with bluesoleil.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto const err = GetLastError();
|
||||||
|
if (ERROR_IO_PENDING == err)
|
||||||
|
{
|
||||||
|
CancelIo(dev_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -555,6 +574,7 @@ bool ForgetWiimote(HANDLE, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
|
||||||
// We don't want "remembered" devices.
|
// We don't want "remembered" devices.
|
||||||
// SetServiceState seems to just fail with them.
|
// SetServiceState seems to just fail with them.
|
||||||
// Make Windows forget about them.
|
// Make Windows forget about them.
|
||||||
|
// This is also required to detect a disconnect for some reason..
|
||||||
NOTICE_LOG(WIIMOTE, "Removing remembered wiimote.");
|
NOTICE_LOG(WIIMOTE, "Removing remembered wiimote.");
|
||||||
Bth_BluetoothRemoveDevice(&btdi.Address);
|
Bth_BluetoothRemoveDevice(&btdi.Address);
|
||||||
|
|
||||||
|
|
|
@ -232,6 +232,12 @@ Report Wiimote::ProcessReadQueue()
|
||||||
|
|
||||||
void Wiimote::Update()
|
void Wiimote::Update()
|
||||||
{
|
{
|
||||||
|
if (!IsConnected())
|
||||||
|
{
|
||||||
|
HandleWiimoteDisconnect(index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Pop through the queued reports
|
// Pop through the queued reports
|
||||||
Report const rpt = ProcessReadQueue();
|
Report const rpt = ProcessReadQueue();
|
||||||
|
|
||||||
|
@ -252,18 +258,17 @@ bool Wiimote::Prepare(int _index)
|
||||||
// core buttons, no continuous reporting
|
// core buttons, no continuous reporting
|
||||||
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30};
|
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30};
|
||||||
|
|
||||||
// Set the active LEDs.
|
// Set the active LEDs and turn on rumble.
|
||||||
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index)};
|
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index) | 0x1};
|
||||||
|
|
||||||
// Rumble briefly
|
// Turn off rumble
|
||||||
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 1};
|
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0};
|
||||||
|
|
||||||
// TODO: request status and check for sane response?
|
// TODO: request status and check for sane response?
|
||||||
|
|
||||||
return (IOWrite(mode_report, sizeof(mode_report))
|
return (IOWrite(mode_report, sizeof(mode_report))
|
||||||
&& IOWrite(led_report, sizeof(led_report))
|
&& IOWrite(led_report, sizeof(led_report))
|
||||||
&& IOWrite(rumble_report, sizeof(rumble_report))
|
&& (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))));
|
||||||
&& (rumble_report[2] = 0, SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::EmuStart()
|
void Wiimote::EmuStart()
|
||||||
|
@ -375,6 +380,8 @@ void Wiimote::ThreadFunc()
|
||||||
{
|
{
|
||||||
Common::SetCurrentThreadName("Wiimote Device Thread");
|
Common::SetCurrentThreadName("Wiimote Device Thread");
|
||||||
|
|
||||||
|
Host_ConnectWiimote(index, true);
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
while (m_run_thread && IsConnected())
|
while (m_run_thread && IsConnected())
|
||||||
{
|
{
|
||||||
|
@ -408,13 +415,13 @@ void LoadSettings()
|
||||||
|
|
||||||
void Initialize()
|
void Initialize()
|
||||||
{
|
{
|
||||||
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
|
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||||
|
|
||||||
if (g_real_wiimotes_initialized)
|
if (g_real_wiimotes_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
|
||||||
|
|
||||||
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
|
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
|
||||||
|
|
||||||
g_wiimote_scanner.StartScanning();
|
g_wiimote_scanner.StartScanning();
|
||||||
|
@ -423,9 +430,7 @@ void Initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown(void)
|
void Shutdown(void)
|
||||||
{
|
{
|
||||||
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
|
|
||||||
|
|
||||||
g_wiimote_scanner.StopScanning();
|
g_wiimote_scanner.StopScanning();
|
||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||||
|
@ -433,6 +438,8 @@ void Shutdown(void)
|
||||||
if (!g_real_wiimotes_initialized)
|
if (!g_real_wiimotes_initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
|
||||||
|
|
||||||
g_real_wiimotes_initialized = false;
|
g_real_wiimotes_initialized = false;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
||||||
|
@ -466,8 +473,6 @@ void TryToConnectWiimote(Wiimote* wm)
|
||||||
g_wiimotes[i] = wm;
|
g_wiimotes[i] = wm;
|
||||||
|
|
||||||
wm->StartThread();
|
wm->StartThread();
|
||||||
|
|
||||||
Host_ConnectWiimote(i, true);
|
|
||||||
|
|
||||||
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1);
|
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1);
|
||||||
|
|
||||||
|
@ -485,8 +490,6 @@ void HandleWiimoteDisconnect(int index)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||||
|
|
||||||
Host_ConnectWiimote(index, false);
|
|
||||||
|
|
||||||
if (g_wiimotes[index])
|
if (g_wiimotes[index])
|
||||||
{
|
{
|
||||||
delete g_wiimotes[index];
|
delete g_wiimotes[index];
|
||||||
|
@ -511,12 +514,24 @@ void Refresh()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||||
|
|
||||||
CheckForDisconnectedWiimotes();
|
std::vector<Wiimote*> found_wiimotes;
|
||||||
|
|
||||||
if (0 != CalculateWantedWiimotes())
|
if (0 != CalculateWantedWiimotes())
|
||||||
{
|
{
|
||||||
HandleFoundWiimotes(g_wiimote_scanner.FindWiimotes());
|
found_wiimotes = g_wiimote_scanner.FindWiimotes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckForDisconnectedWiimotes();
|
||||||
|
|
||||||
|
// Brief rumble for already connected wiimotes.
|
||||||
|
for (int i = 0; i != MAX_WIIMOTES; ++i)
|
||||||
|
{
|
||||||
|
// kinda sloppy
|
||||||
|
if (g_wiimotes[i])
|
||||||
|
g_wiimotes[i]->Prepare(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
HandleFoundWiimotes(found_wiimotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_wiimote_scanner.StartScanning();
|
g_wiimote_scanner.StartScanning();
|
||||||
|
@ -546,8 +561,13 @@ void Update(int _WiimoteNumber)
|
||||||
|
|
||||||
if (g_wiimotes[_WiimoteNumber])
|
if (g_wiimotes[_WiimoteNumber])
|
||||||
g_wiimotes[_WiimoteNumber]->Update();
|
g_wiimotes[_WiimoteNumber]->Update();
|
||||||
else
|
|
||||||
|
// Wiimote::Update() may remove the wiimote if it was disconnected.
|
||||||
|
if (!g_wiimotes[_WiimoteNumber])
|
||||||
|
{
|
||||||
|
NOTICE_LOG(WIIMOTE, "Emulating disconnect of wiimote %d.", _WiimoteNumber + 1);
|
||||||
Host_ConnectWiimote(_WiimoteNumber, false);
|
Host_ConnectWiimote(_WiimoteNumber, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateChange(EMUSTATE_CHANGE newState)
|
void StateChange(EMUSTATE_CHANGE newState)
|
||||||
|
|
|
@ -96,7 +96,7 @@ public:
|
||||||
std::string devicepath; // Unique wiimote reference
|
std::string devicepath; // Unique wiimote reference
|
||||||
//ULONGLONG btaddr; // Bluetooth address
|
//ULONGLONG btaddr; // Bluetooth address
|
||||||
HANDLE dev_handle; // HID handle
|
HANDLE dev_handle; // HID handle
|
||||||
OVERLAPPED hid_overlap; // Overlap handle
|
OVERLAPPED hid_overlap_read, hid_overlap_write; // Overlap handle
|
||||||
enum win_bt_stack_t stack; // Type of bluetooth stack to use
|
enum win_bt_stack_t stack; // Type of bluetooth stack to use
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue