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;
|
||||
}
|
||||
|
||||
hid_overlap = OVERLAPPED();
|
||||
hid_overlap.hEvent = CreateEvent(NULL, 1, 1, _T(""));
|
||||
hid_overlap.Offset = 0;
|
||||
hid_overlap.OffsetHigh = 0;
|
||||
#if 0
|
||||
HIDD_ATTRIBUTES attr;
|
||||
attr.Size = sizeof(attr);
|
||||
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
|
||||
// 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);
|
||||
dev_handle = 0;
|
||||
|
||||
CloseHandle(hid_overlap.hEvent);
|
||||
CloseHandle(hid_overlap_read.hEvent);
|
||||
CloseHandle(hid_overlap_write.hEvent);
|
||||
}
|
||||
|
||||
bool Wiimote::IsConnected() const
|
||||
|
@ -307,20 +320,20 @@ bool Wiimote::IsConnected() const
|
|||
// positive = read packet
|
||||
// negative = didn't read packet
|
||||
// zero = error
|
||||
int Wiimote::IORead(unsigned char* buf)
|
||||
int Wiimote::IORead(u8* buf)
|
||||
{
|
||||
// used below for a warning
|
||||
*buf = 0;
|
||||
|
||||
DWORD bytes;
|
||||
ResetEvent(hid_overlap.hEvent);
|
||||
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap))
|
||||
ResetEvent(hid_overlap_read.hEvent);
|
||||
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
|
||||
{
|
||||
auto const err = GetLastError();
|
||||
|
||||
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)
|
||||
{
|
||||
// Timeout - cancel and continue
|
||||
|
@ -338,7 +351,7 @@ int Wiimote::IORead(unsigned char* buf)
|
|||
}
|
||||
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);
|
||||
bytes = 0;
|
||||
|
@ -380,70 +393,76 @@ int Wiimote::IORead(unsigned char* buf)
|
|||
|
||||
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)
|
||||
{
|
||||
case MSBT_STACK_UNKNOWN:
|
||||
{
|
||||
// Try to auto-detect the stack type
|
||||
|
||||
auto i = WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap);
|
||||
if (i)
|
||||
stack = MSBT_STACK_BLUESOLEIL;
|
||||
if (IOWrite(buf, len))
|
||||
return 1;
|
||||
|
||||
stack = MSBT_STACK_MS;
|
||||
if (IOWrite(buf, len))
|
||||
{
|
||||
// Bluesoleil will always return 1 here, even if it's not connected
|
||||
stack = MSBT_STACK_BLUESOLEIL;
|
||||
return i;
|
||||
// Don't mind me, just a random sleep to fix stuff on Windows
|
||||
SLEEP(1000);
|
||||
return 1;
|
||||
}
|
||||
|
||||
i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1);
|
||||
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;
|
||||
}
|
||||
stack = MSBT_STACK_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
case MSBT_STACK_MS:
|
||||
{
|
||||
auto i = HidD_SetOutputReport(dev_handle, (unsigned char*) buf + 1, len - 1);
|
||||
auto dw = GetLastError();
|
||||
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
|
||||
//FlushFileBuffers(dev_handle);
|
||||
|
||||
if (dw == 121)
|
||||
if (!result)
|
||||
{
|
||||
// Semaphore timeout
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
|
||||
return 0;
|
||||
auto err = GetLastError();
|
||||
if (err == 121)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -555,6 +574,7 @@ bool ForgetWiimote(HANDLE, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
|
|||
// We don't want "remembered" devices.
|
||||
// SetServiceState seems to just fail with them.
|
||||
// Make Windows forget about them.
|
||||
// This is also required to detect a disconnect for some reason..
|
||||
NOTICE_LOG(WIIMOTE, "Removing remembered wiimote.");
|
||||
Bth_BluetoothRemoveDevice(&btdi.Address);
|
||||
|
||||
|
|
|
@ -232,6 +232,12 @@ Report Wiimote::ProcessReadQueue()
|
|||
|
||||
void Wiimote::Update()
|
||||
{
|
||||
if (!IsConnected())
|
||||
{
|
||||
HandleWiimoteDisconnect(index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Pop through the queued reports
|
||||
Report const rpt = ProcessReadQueue();
|
||||
|
||||
|
@ -252,18 +258,17 @@ bool Wiimote::Prepare(int _index)
|
|||
// core buttons, no continuous reporting
|
||||
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30};
|
||||
|
||||
// Set the active LEDs.
|
||||
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index)};
|
||||
// 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) | 0x1};
|
||||
|
||||
// Rumble briefly
|
||||
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 1};
|
||||
// Turn off rumble
|
||||
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0};
|
||||
|
||||
// TODO: request status and check for sane response?
|
||||
|
||||
return (IOWrite(mode_report, sizeof(mode_report))
|
||||
&& IOWrite(led_report, sizeof(led_report))
|
||||
&& IOWrite(rumble_report, sizeof(rumble_report))
|
||||
&& (rumble_report[2] = 0, SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))));
|
||||
&& (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report))));
|
||||
}
|
||||
|
||||
void Wiimote::EmuStart()
|
||||
|
@ -375,6 +380,8 @@ void Wiimote::ThreadFunc()
|
|||
{
|
||||
Common::SetCurrentThreadName("Wiimote Device Thread");
|
||||
|
||||
Host_ConnectWiimote(index, true);
|
||||
|
||||
// main loop
|
||||
while (m_run_thread && IsConnected())
|
||||
{
|
||||
|
@ -408,13 +415,13 @@ void LoadSettings()
|
|||
|
||||
void Initialize()
|
||||
{
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||
|
||||
if (g_real_wiimotes_initialized)
|
||||
return;
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
|
||||
|
||||
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
|
||||
|
||||
g_wiimote_scanner.StartScanning();
|
||||
|
@ -423,9 +430,7 @@ void Initialize()
|
|||
}
|
||||
|
||||
void Shutdown(void)
|
||||
{
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
|
||||
|
||||
{
|
||||
g_wiimote_scanner.StopScanning();
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||
|
@ -433,6 +438,8 @@ void Shutdown(void)
|
|||
if (!g_real_wiimotes_initialized)
|
||||
return;
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
|
||||
|
||||
g_real_wiimotes_initialized = false;
|
||||
|
||||
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
|
||||
|
@ -466,8 +473,6 @@ void TryToConnectWiimote(Wiimote* wm)
|
|||
g_wiimotes[i] = wm;
|
||||
|
||||
wm->StartThread();
|
||||
|
||||
Host_ConnectWiimote(i, true);
|
||||
|
||||
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);
|
||||
|
||||
Host_ConnectWiimote(index, false);
|
||||
|
||||
if (g_wiimotes[index])
|
||||
{
|
||||
delete g_wiimotes[index];
|
||||
|
@ -511,12 +514,24 @@ void Refresh()
|
|||
{
|
||||
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
|
||||
|
||||
CheckForDisconnectedWiimotes();
|
||||
std::vector<Wiimote*> found_wiimotes;
|
||||
|
||||
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();
|
||||
|
@ -546,8 +561,13 @@ void Update(int _WiimoteNumber)
|
|||
|
||||
if (g_wiimotes[_WiimoteNumber])
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void StateChange(EMUSTATE_CHANGE newState)
|
||||
|
|
|
@ -96,7 +96,7 @@ public:
|
|||
std::string devicepath; // Unique wiimote reference
|
||||
//ULONGLONG btaddr; // Bluetooth address
|
||||
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
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue