// Connect to a Wiimote with a known device path. bool WiimoteWindows::ConnectInternal() { if (IsConnected()) return true; if (!IsNewWiimote(UTF16ToUTF8(m_devicepath))) return false; auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE; m_dev_handle = CreateFile(m_devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, open_flags, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); if (m_dev_handle == INVALID_HANDLE_VALUE) { m_dev_handle = nullptr; return false; } #if 0 TCHAR name[128] = {}; pHidD_GetProductString(dev_handle, name, 128); //ERROR_LOG(WIIMOTE, "Product string: %s", TStrToUTF8(name).c_str()); if (!IsValidBluetoothName(TStrToUTF8(name))) { CloseHandle(dev_handle); dev_handle = 0; return false; } #endif #if 0 HIDD_ATTRIBUTES attr; attr.Size = sizeof(attr); if (!pHidD_GetAttributes(dev_handle, &attr)) { CloseHandle(dev_handle); dev_handle = 0; return false; } #endif // 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 // reside is normal priority. Needed for keeping audio reports at a decent rate /* if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL)) { ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority"); } */ return true; }
// Connect to a Wiimote with a known device path. bool WiimoteWindows::ConnectInternal() { if (IsConnected()) return false; #ifdef SHARE_WRITE_WIIMOTES std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock); if (g_connected_wiimotes.count(m_devicepath) != 0) return false; auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE; #else // Having no FILE_SHARE_WRITE disallows us from connecting to the same Wiimote twice. // (And disallows using Wiimotes in use by other programs) // This is what "WiiYourself" does. // Apparently this doesn't work for everyone. It might be their fault. auto const open_flags = FILE_SHARE_READ; #endif m_dev_handle = CreateFile(m_devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, open_flags, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); if (m_dev_handle == INVALID_HANDLE_VALUE) { m_dev_handle = 0; return false; } #if 0 TCHAR name[128] = {}; pHidD_GetProductString(dev_handle, name, 128); //ERROR_LOG(WIIMOTE, "Product string: %s", TStrToUTF8(name).c_str()); if (!IsValidBluetoothName(TStrToUTF8(name))) { CloseHandle(dev_handle); dev_handle = 0; return false; } #endif #if 0 HIDD_ATTRIBUTES attr; attr.Size = sizeof(attr); if (!pHidD_GetAttributes(dev_handle, &attr)) { CloseHandle(dev_handle); dev_handle = 0; return false; } #endif // 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 // reside is normal priority. Needed for keeping audio reports at a decent rate /* if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL)) { ERROR_LOG(WIIMOTE, "Failed to set Wiimote thread priority"); } */ #ifdef SHARE_WRITE_WIIMOTES g_connected_wiimotes.insert(m_devicepath); #endif return true; }
// A convoluted way of checking if a device is a Wii Balance Board and if it is a connectible Wiimote. // Because nothing on Windows should be easy. // (We can't seem to easily identify the Bluetooth device an HID device belongs to...) void WiimoteScanner::CheckDeviceType(std::basic_string<TCHAR> &devicepath, bool &real_wiimote, bool &is_bb) { real_wiimote = false; is_bb = false; #ifdef SHARE_WRITE_WIIMOTES std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock); if (g_connected_wiimotes.count(devicepath) != 0) return; #endif HANDLE dev_handle = CreateFile(devicepath.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, nullptr); if (dev_handle == INVALID_HANDLE_VALUE) return; // enable to only check for official nintendo wiimotes/bb's bool check_vidpid = false; HIDD_ATTRIBUTES attrib; attrib.Size = sizeof(attrib); if (!check_vidpid || (pHidD_GetAttributes(dev_handle, &attrib) && (attrib.VendorID == 0x057e) && (attrib.ProductID == 0x0306))) { // max_cycles insures we are never stuck here due to bad coding... int max_cycles = 20; u8 buf[MAX_PAYLOAD] = {0}; u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0}; // The new way to initialize the extension is by writing 0x55 to 0x(4)A400F0, then writing 0x00 to 0x(4)A400FB // 52 16 04 A4 00 F0 01 55 // 52 16 04 A4 00 FB 01 00 u8 const disable_enc_pt1_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55}; u8 const disable_enc_pt2_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00}; CheckDeviceType_Write(dev_handle, disable_enc_pt1_report, sizeof(disable_enc_pt1_report), 1); CheckDeviceType_Write(dev_handle, disable_enc_pt2_report, sizeof(disable_enc_pt2_report), 1); int rc = CheckDeviceType_Write(dev_handle, req_status_report, sizeof(req_status_report), 1); while (rc > 0 && --max_cycles > 0) { if ((rc = CheckDeviceType_Read(dev_handle, buf, 1)) <= 0) { // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Read failed..."); break; } switch (buf[1]) { case WM_STATUS_REPORT: { real_wiimote = true; // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Status Report"); wm_status_report * wsr = (wm_status_report*)&buf[2]; if (wsr->extension) { // Wiimote with extension, we ask it what kind. u8 read_ext[MAX_PAYLOAD] = {0}; read_ext[0] = WM_SET_REPORT | WM_BT_OUTPUT; read_ext[1] = WM_READ_DATA; // Extension type register. *(u32*)&read_ext[2] = Common::swap32(0x4a400fa); // Size. *(u16*)&read_ext[6] = Common::swap16(6); rc = CheckDeviceType_Write(dev_handle, read_ext, 8, 1); } else { // Normal Wiimote, exit while and be happy. rc = -1; } break; } case WM_ACK_DATA: { real_wiimote = true; //wm_acknowledge * wm = (wm_acknowledge*)&buf[2]; //DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Ack Error: %X ReportID: %X", wm->errorID, wm->reportID); break; } case WM_READ_DATA_REPLY: { // DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Data Reply"); wm_read_data_reply * wrdr = (wm_read_data_reply*)&buf[2]; // Check if it has returned what we asked. if (Common::swap16(wrdr->address) == 0x00fa) { real_wiimote = true; // 0x020420A40000ULL means balance board. u64 ext_type = (*(u64*)&wrdr->data[0]); // DEBUG_LOG(WIIMOTE, // "CheckDeviceType: GOT EXT TYPE %llX", // ext_type); is_bb = (ext_type == 0x020420A40000ULL); } else { ERROR_LOG(WIIMOTE, "CheckDeviceType: GOT UNREQUESTED ADDRESS %X", Common::swap16(wrdr->address)); } // force end rc = -1; break; } default: { // We let read try again incase there is another packet waiting. // DEBUG_LOG(WIIMOTE, "CheckDeviceType: GOT UNKNOWN REPLY: %X", buf[1]); break; } } } } CloseHandle(dev_handle); }