diff --git a/include/inputdev/CDeviceBase.hpp b/include/inputdev/CDeviceBase.hpp index fc84027..392802f 100644 --- a/include/inputdev/CDeviceBase.hpp +++ b/include/inputdev/CDeviceBase.hpp @@ -13,7 +13,7 @@ class CDeviceBase friend class CDeviceToken; friend class CHIDDeviceIOKit; friend class CHIDDeviceUdev; - friend class CHIDDeviceWin32; + friend class CHIDDeviceWinUSB; class CDeviceToken* m_token; class IHIDDevice* m_hidDev; diff --git a/include/inputdev/CDeviceFinder.hpp b/include/inputdev/CDeviceFinder.hpp index cec1660..7878d01 100644 --- a/include/inputdev/CDeviceFinder.hpp +++ b/include/inputdev/CDeviceFinder.hpp @@ -19,7 +19,7 @@ class CDeviceFinder public: friend class CHIDListenerIOKit; friend class CHIDListenerUdev; - friend class CHIDListenerWin32; + friend class CHIDListenerWinUSB; static inline CDeviceFinder* instance() {return skDevFinder;} private: diff --git a/include/inputdev/CDeviceToken.hpp b/include/inputdev/CDeviceToken.hpp index 2753081..2908130 100644 --- a/include/inputdev/CDeviceToken.hpp +++ b/include/inputdev/CDeviceToken.hpp @@ -69,7 +69,7 @@ public: inline const std::string& getVendorName() const {return m_vendorName;} inline const std::string& getProductName() const {return m_productName;} inline const std::string& getDevicePath() const {return m_devPath;} - inline bool isDeviceOpen() const {return m_connectedDev;} + inline bool isDeviceOpen() const {return (m_connectedDev != NULL);} inline CDeviceBase* openAndGetDevice() { if (!m_connectedDev) diff --git a/libBoo.pri b/libBoo.pri index 752282a..66e92a2 100644 --- a/libBoo.pri +++ b/libBoo.pri @@ -31,7 +31,9 @@ SOURCES += \ $$PWD/src/inputdev/CDualshockPad.cpp \ $$PWD/src/inputdev/CGenericPad.cpp \ $$PWD/src/inputdev/CDeviceBase.cpp \ - $$PWD/src/inputdev/SDeviceSignature.cpp + $$PWD/src/inputdev/SDeviceSignature.cpp \ + $$PWD/src/inputdev/CHIDListenerWinUSB.cpp \ + $$PWD/src/inputdev/CHIDDeviceWinUSB.cpp unix:!macx { HEADERS += \ @@ -66,9 +68,7 @@ win32 { HEADERS += \ $$PWD/include/win/CWGLContext.hpp SOURCES += \ - $$PWD/src/win/CWGLContext.cpp \ - $$PWD/src/inputdev/CHIDDeviceWin32.cpp \ - $$PWD/src/inputdev/CHIDListenerWin32.cpp + $$PWD/src/win/CWGLContext.cpp } INCLUDEPATH += $$PWD/include diff --git a/libBoo.pro b/libBoo.pro index d1460c1..496ad73 100644 --- a/libBoo.pro +++ b/libBoo.pro @@ -5,14 +5,7 @@ CONFIG += console unix:QMAKE_CXXFLAGS += -stdlib=libc++ unix:LIBS += -std=c++11 -stdlib=libc++ -lc++abi -win32:INCLUDEPATH += $$PWD/extern/libwdi -win32:LIBS += \ - Shell32.lib \ - Ole32.lib \ - Setupapi.lib \ - Advapi32.lib \ - User32.lib \ - $$PWD/extern/libwdi/x64/Debug/lib/libwdi.lib +win32:LIBS += Setupapi.lib winusb.lib User32.lib #unix:!macx:CONFIG += link_pkgconfig #unix:!macx:PKGCONFIG += x11 diff --git a/src/inputdev/CHIDDeviceIOKit.cpp b/src/inputdev/CHIDDeviceIOKit.cpp index a7bd0dd..95b115a 100644 --- a/src/inputdev/CHIDDeviceIOKit.cpp +++ b/src/inputdev/CHIDDeviceIOKit.cpp @@ -6,8 +6,6 @@ #include #include -#define MAX_REPORT_SIZE 65536 - namespace boo { @@ -54,6 +52,7 @@ class CHIDDeviceIOKit final : public IHIDDevice char thrName[128]; snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().c_str()); pthread_setname_np(thrName); + char errStr[256]; std::unique_lock lk(device->m_initMutex); /* Get the HID element's parent (USB interrupt transfer-interface) */ @@ -70,7 +69,10 @@ class CHIDDeviceIOKit final : public IHIDDevice } if (!interfaceEntry) { - throw std::runtime_error("unable to find device interface"); + snprintf(errStr, 256, "Unable to find interface for %s@%s\n", + device->m_token.getProductName().c_str(), + device->m_devPath.c_str()); + device->m_devImp.deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); return; @@ -88,7 +90,9 @@ class CHIDDeviceIOKit final : public IHIDDevice IOObjectRelease(interfaceEntry); if (err) { - throw std::runtime_error("unable to obtain IOKit plugin service"); + snprintf(errStr, 256, "Unable to open %s@%s\n", + device->m_token.getProductName().c_str(), device->m_devPath.c_str()); + device->m_devImp.deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); return; @@ -101,7 +105,9 @@ class CHIDDeviceIOKit final : public IHIDDevice (LPVOID*)&intf); if (err) { - throw std::runtime_error("unable to query IOKit USB interface"); + snprintf(errStr, 256, "Unable to open %s@%s\n", + device->m_token.getProductName().c_str(), device->m_devPath.c_str()); + device->m_devImp.deviceError(errStr); lk.unlock(); device->m_initCond.notify_one(); IODestroyPlugInInterface(iodev); @@ -114,9 +120,17 @@ class CHIDDeviceIOKit final : public IHIDDevice if (err != kIOReturnSuccess) { if (err == kIOReturnExclusiveAccess) - throw std::runtime_error("unable to open IOKit USB interface; someone else using it"); + { + snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", + device->m_token.getProductName().c_str(), device->m_devPath.c_str()); + device->m_devImp.deviceError(errStr); + } else - throw std::runtime_error("unable to open IOKit USB interface"); + { + snprintf(errStr, 256, "Unable to open %s@%s\n", + device->m_token.getProductName().c_str(), device->m_devPath.c_str()); + device->m_devImp.deviceError(errStr); + } lk.unlock(); device->m_initCond.notify_one(); (*intf)->Release(intf); diff --git a/src/inputdev/CHIDDeviceUdev.cpp b/src/inputdev/CHIDDeviceUdev.cpp index c4a8111..48aaa11 100644 --- a/src/inputdev/CHIDDeviceUdev.cpp +++ b/src/inputdev/CHIDDeviceUdev.cpp @@ -19,8 +19,6 @@ namespace boo udev* GetUdev(); -#define MAX_REPORT_SIZE 65536 - /* * Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html */ @@ -78,15 +76,15 @@ class CHIDDeviceUdev final : public IHIDDevice static void _threadProcUSBLL(CHIDDeviceUdev* device) { unsigned i; + char errStr[256]; std::unique_lock lk(device->m_initMutex); udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str()); - /* Get the HID element's parent (USB interrupt transfer-interface) */ + /* Get device file */ const char* dp = udev_device_get_devnode(udevDev); device->m_devFd = open(dp, O_RDWR); if (device->m_devFd < 0) { - char errStr[256]; snprintf(errStr, 256, "Unable to open %s@%s: %s\n", device->m_token.getProductName().c_str(), dp, strerror(errno)); device->m_devImp.deviceError(errStr); diff --git a/src/inputdev/CHIDDeviceWin32.cpp b/src/inputdev/CHIDDeviceWin32.cpp deleted file mode 100644 index 4984fa0..0000000 --- a/src/inputdev/CHIDDeviceWin32.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include "IHIDDevice.hpp" -#include "inputdev/CDeviceToken.hpp" -#include "inputdev/CDeviceBase.hpp" -#include -#include -#include -#include - -namespace boo -{ - -#if 0 - -udev* GetUdev(); - -#define MAX_REPORT_SIZE 65536 - -/* - * Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html - */ - -class CHIDDeviceUdev final : public IHIDDevice -{ - CDeviceToken& m_token; - CDeviceBase& m_devImp; - - int m_devFd = 0; - unsigned m_usbIntfInPipe = 0; - unsigned m_usbIntfOutPipe = 0; - bool m_runningTransferLoop = false; - - const std::string& m_devPath; - std::mutex m_initMutex; - std::condition_variable m_initCond; - std::thread* m_thread; - - bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) - { - if (m_devFd) - { - usbdevfs_bulktransfer xfer = - { - m_usbIntfOutPipe | USB_DIR_OUT, - (unsigned)length, - 0, - (void*)data - }; - int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer); - if (ret != (int)length) - return false; - return true; - } - return false; - } - - size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) - { - if (m_devFd) - { - usbdevfs_bulktransfer xfer = - { - m_usbIntfInPipe | USB_DIR_IN, - (unsigned)length, - 0, - data - }; - return ioctl(m_devFd, USBDEVFS_BULK, &xfer); - } - return 0; - } - - static void _threadProcUSBLL(CHIDDeviceUdev* device) - { - unsigned i; - std::unique_lock lk(device->m_initMutex); - udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str()); - - /* Get the HID element's parent (USB interrupt transfer-interface) */ - const char* dp = udev_device_get_devnode(udevDev); - device->m_devFd = open(dp, O_RDWR); - if (device->m_devFd < 0) - { - char errStr[256]; - snprintf(errStr, 256, "Unable to open %s@%s: %s\n", - device->m_token.getProductName().c_str(), dp, strerror(errno)); - device->m_devImp.deviceError(errStr); - lk.unlock(); - device->m_initCond.notify_one(); - udev_device_unref(udevDev); - return; - } - usb_device_descriptor devDesc = {0}; - read(device->m_devFd, &devDesc, 1); - read(device->m_devFd, &devDesc.bDescriptorType, devDesc.bLength-1); - if (devDesc.bNumConfigurations) - { - usb_config_descriptor confDesc = {0}; - read(device->m_devFd, &confDesc, 1); - read(device->m_devFd, &confDesc.bDescriptorType, confDesc.bLength-1); - if (confDesc.bNumInterfaces) - { - usb_interface_descriptor intfDesc = {0}; - read(device->m_devFd, &intfDesc, 1); - read(device->m_devFd, &intfDesc.bDescriptorType, intfDesc.bLength-1); - for (i=0 ; im_devFd, &endpDesc, 1); - read(device->m_devFd, &endpDesc.bDescriptorType, endpDesc.bLength-1); - if ((endpDesc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) - { - if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) - device->m_usbIntfInPipe = endpDesc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - else if ((endpDesc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) - device->m_usbIntfOutPipe = endpDesc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - } - } - } - } - - /* Request that kernel disconnects existing driver */ - usbdevfs_ioctl disconnectReq = { - 0, - USBDEVFS_DISCONNECT, - NULL - }; - ioctl(device->m_devFd, USBDEVFS_IOCTL, &disconnectReq); - - /* Return control to main thread */ - device->m_runningTransferLoop = true; - lk.unlock(); - device->m_initCond.notify_one(); - - /* Start transfer loop */ - device->m_devImp.initialCycle(); - while (device->m_runningTransferLoop) - device->m_devImp.transferCycle(); - device->m_devImp.finalCycle(); - - /* Cleanup */ - close(device->m_devFd); - device->m_devFd = 0; - udev_device_unref(udevDev); - - } - - static void _threadProcBTLL(CHIDDeviceUdev* device) - { - std::unique_lock lk(device->m_initMutex); - udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str()); - - /* Return control to main thread */ - device->m_runningTransferLoop = true; - lk.unlock(); - device->m_initCond.notify_one(); - - /* Start transfer loop */ - device->m_devImp.initialCycle(); - while (device->m_runningTransferLoop) - device->m_devImp.transferCycle(); - device->m_devImp.finalCycle(); - - udev_device_unref(udevDev); - } - - static void _threadProcHID(CHIDDeviceUdev* device) - { - std::unique_lock lk(device->m_initMutex); - udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str()); - - /* Return control to main thread */ - device->m_runningTransferLoop = true; - lk.unlock(); - device->m_initCond.notify_one(); - - /* Start transfer loop */ - device->m_devImp.initialCycle(); - while (device->m_runningTransferLoop) - device->m_devImp.transferCycle(); - device->m_devImp.finalCycle(); - - udev_device_unref(udevDev); - } - - void _deviceDisconnected() - { - m_runningTransferLoop = false; - } - - bool _sendHIDReport(const uint8_t* data, size_t length) - { - return false; - } - -public: - - CHIDDeviceUdev(CDeviceToken& token, CDeviceBase& devImp) - : m_token(token), - m_devImp(devImp), - m_devPath(token.getDevicePath()) - { - devImp.m_hidDev = this; - std::unique_lock lk(m_initMutex); - CDeviceToken::TDeviceType dType = token.getDeviceType(); - if (dType == CDeviceToken::DEVTYPE_USB) - m_thread = new std::thread(_threadProcUSBLL, this); - else if (dType == CDeviceToken::DEVTYPE_BLUETOOTH) - m_thread = new std::thread(_threadProcBTLL, this); - else if (dType == CDeviceToken::DEVTYPE_GENERICHID) - m_thread = new std::thread(_threadProcHID, this); - else - throw std::runtime_error("invalid token supplied to device constructor"); - m_initCond.wait(lk); - } - - ~CHIDDeviceUdev() - { - m_runningTransferLoop = false; - m_thread->join(); - delete m_thread; - } - - -}; - -#endif - -IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp) -{ - //return new CHIDDeviceUdev(token, devImp); - return nullptr; -} - -} diff --git a/src/inputdev/CHIDDeviceWinUSB.cpp b/src/inputdev/CHIDDeviceWinUSB.cpp new file mode 100644 index 0000000..f1811ed --- /dev/null +++ b/src/inputdev/CHIDDeviceWinUSB.cpp @@ -0,0 +1,194 @@ +#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */ +#include "IHIDDevice.hpp" +#include "inputdev/CDeviceToken.hpp" +#include "inputdev/CDeviceBase.hpp" +#include +#include +#include +#include +#include + +#define _WIN32_LEAN_AND_MEAN 1 +#include +#include + +namespace boo +{ + +class CHIDDeviceWinUSB final : public IHIDDevice +{ + CDeviceToken& m_token; + CDeviceBase& m_devImp; + + HANDLE m_devHandle = 0; + WINUSB_INTERFACE_HANDLE m_usbHandle = NULL; + unsigned m_usbIntfInPipe = 0; + unsigned m_usbIntfOutPipe = 0; + bool m_runningTransferLoop = false; + + const std::string& m_devPath; + std::mutex m_initMutex; + std::condition_variable m_initCond; + std::thread* m_thread; + + bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length) + { + if (m_usbHandle) + { + ULONG lengthTransferred = 0; + if (!WinUsb_WritePipe(m_usbHandle, m_usbIntfOutPipe, (PUCHAR)data, + (ULONG)length, &lengthTransferred, NULL) + || lengthTransferred != length) + return false; + return true; + } + return false; + } + + size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length) + { + if (m_usbHandle) + { + ULONG lengthTransferred = 0; + if (!WinUsb_ReadPipe(m_usbHandle, m_usbIntfInPipe, (PUCHAR)data, + (ULONG)length, &lengthTransferred, NULL)) + return 0; + return lengthTransferred; + } + return 0; + } + + static void _threadProcUSBLL(CHIDDeviceWinUSB* device) + { + unsigned i; + char errStr[256]; + std::unique_lock lk(device->m_initMutex); + + /* POSIX.. who needs it?? -MS */ + device->m_devHandle = CreateFileA(device->m_devPath.c_str(), + GENERIC_WRITE | GENERIC_READ, + FILE_SHARE_WRITE | FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, + NULL); + if (INVALID_HANDLE_VALUE == device->m_devHandle) { + _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", + device->m_token.getProductName().c_str(), + device->m_devPath, GetLastError()); + device->m_devImp.deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + return; + } + + if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) { + _snprintf(errStr, 256, "Unable to open %s@%s: %d\n", + device->m_token.getProductName().c_str(), + device->m_devPath, GetLastError()); + device->m_devImp.deviceError(errStr); + lk.unlock(); + device->m_initCond.notify_one(); + CloseHandle(device->m_devHandle); + return; + } + + /* Return control to main thread */ + device->m_runningTransferLoop = true; + lk.unlock(); + device->m_initCond.notify_one(); + + /* Start transfer loop */ + device->m_devImp.initialCycle(); + while (device->m_runningTransferLoop) + device->m_devImp.transferCycle(); + device->m_devImp.finalCycle(); + + /* Cleanup */ + WinUsb_Free(device->m_usbHandle); + CloseHandle(device->m_devHandle); + device->m_devHandle = 0; + + } + + static void _threadProcBTLL(CHIDDeviceWinUSB* device) + { + std::unique_lock lk(device->m_initMutex); + + /* Return control to main thread */ + device->m_runningTransferLoop = true; + lk.unlock(); + device->m_initCond.notify_one(); + + /* Start transfer loop */ + device->m_devImp.initialCycle(); + while (device->m_runningTransferLoop) + device->m_devImp.transferCycle(); + device->m_devImp.finalCycle(); + + } + + static void _threadProcHID(CHIDDeviceWinUSB* device) + { + std::unique_lock lk(device->m_initMutex); + + /* Return control to main thread */ + device->m_runningTransferLoop = true; + lk.unlock(); + device->m_initCond.notify_one(); + + /* Start transfer loop */ + device->m_devImp.initialCycle(); + while (device->m_runningTransferLoop) + device->m_devImp.transferCycle(); + device->m_devImp.finalCycle(); + + } + + void _deviceDisconnected() + { + m_runningTransferLoop = false; + } + + bool _sendHIDReport(const uint8_t* data, size_t length) + { + return false; + } + +public: + + CHIDDeviceWinUSB(CDeviceToken& token, CDeviceBase& devImp) + : m_token(token), + m_devImp(devImp), + m_devPath(token.getDevicePath()) + { + devImp.m_hidDev = this; + std::unique_lock lk(m_initMutex); + CDeviceToken::TDeviceType dType = token.getDeviceType(); + if (dType == CDeviceToken::DEVTYPE_USB) + m_thread = new std::thread(_threadProcUSBLL, this); + else if (dType == CDeviceToken::DEVTYPE_BLUETOOTH) + m_thread = new std::thread(_threadProcBTLL, this); + else if (dType == CDeviceToken::DEVTYPE_GENERICHID) + m_thread = new std::thread(_threadProcHID, this); + else + throw std::runtime_error("invalid token supplied to device constructor"); + m_initCond.wait(lk); + } + + ~CHIDDeviceWinUSB() + { + m_runningTransferLoop = false; + m_thread->join(); + delete m_thread; + } + + +}; + +IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp) +{ + return new CHIDDeviceWinUSB(token, devImp); +} + +} diff --git a/src/inputdev/CHIDListenerWin32.cpp b/src/inputdev/CHIDListenerWin32.cpp deleted file mode 100644 index 7398249..0000000 --- a/src/inputdev/CHIDListenerWin32.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include "inputdev/IHIDListener.hpp" -#include "inputdev/CDeviceFinder.hpp" -#include -#include - -#define _WIN32_LEAN_AND_MEAN 1 -#include - -namespace boo -{ - -#if 0 - -static udev* UDEV_INST = NULL; -udev* GetUdev() -{ - if (!UDEV_INST) - UDEV_INST = udev_new(); - return UDEV_INST; -} - -class CHIDListenerWin32 final : public IHIDListener -{ - CDeviceFinder& m_finder; - - udev_monitor* m_udevMon; - std::thread* m_udevThread; - bool m_udevRunning; - bool m_scanningEnabled; - - static void deviceConnected(CHIDListenerWin32* listener, - udev_device* device) - { - if (!listener->m_scanningEnabled) - return; - - /* Filter to USB/BT */ - const char* dt = udev_device_get_devtype(device); - CDeviceToken::TDeviceType type; - if (!strcmp(dt, "usb_device")) - type = CDeviceToken::DEVTYPE_USB; - else if (!strcmp(dt, "bluetooth_device")) - type = CDeviceToken::DEVTYPE_BLUETOOTH; - else - return; - - /* Prevent redundant registration */ - const char* devPath = udev_device_get_syspath(device); - if (listener->m_finder._hasToken(devPath)) - return; - - int vid = 0, pid = 0; - udev_list_entry* attrs = udev_device_get_properties_list_entry(device); -#if 0 - udev_list_entry* att = NULL; - udev_list_entry_foreach(att, attrs) - { - const char* name = udev_list_entry_get_name(att); - const char* val = udev_list_entry_get_value(att); - fprintf(stderr, "%s %s\n", name, val); - } - fprintf(stderr, "\n\n"); -#endif - - udev_list_entry* vide = udev_list_entry_get_by_name(attrs, "ID_VENDOR_ID"); - if (vide) - vid = strtol(udev_list_entry_get_value(vide), NULL, 16); - - udev_list_entry* pide = udev_list_entry_get_by_name(attrs, "ID_MODEL_ID"); - if (pide) - pid = strtol(udev_list_entry_get_value(pide), NULL, 16); - - const char* manuf = NULL; - udev_list_entry* manufe = udev_list_entry_get_by_name(attrs, "ID_VENDOR"); - if (manufe) - manuf = udev_list_entry_get_value(manufe); - - const char* product = NULL; - udev_list_entry* producte = udev_list_entry_get_by_name(attrs, "ID_MODEL"); - if (producte) - product = udev_list_entry_get_value(producte); - - if (!listener->m_finder._insertToken(CDeviceToken(type, vid, pid, manuf, product, devPath))) - { - /* Matched-insertion failed; see if generic HID interface is available */ - udev_list_entry* devInterfaces = NULL; - if (type == CDeviceToken::DEVTYPE_USB) - devInterfaces = udev_list_entry_get_by_name(attrs, "ID_USB_INTERFACES"); - else if (type == CDeviceToken::DEVTYPE_BLUETOOTH) - devInterfaces = udev_list_entry_get_by_name(attrs, "ID_BLUETOOTH_INTERFACES"); - if (devInterfaces) - { - const char* interfacesStr = udev_list_entry_get_value(devInterfaces); - if (strstr(interfacesStr, ":030104") || /* HID / GenericDesktop / Joystick */ - strstr(interfacesStr, ":030105")) /* HID / GenericDesktop / Gamepad */ - { - udev_enumerate* hidEnum = udev_enumerate_new(UDEV_INST); - udev_enumerate_add_match_parent(hidEnum, device); - udev_enumerate_add_match_subsystem(hidEnum, "hid"); - udev_enumerate_scan_devices(hidEnum); - udev_list_entry* hidEnt = udev_enumerate_get_list_entry(hidEnum); - if (hidEnt) - { - const char* hidPath = udev_list_entry_get_name(hidEnt); - if (!listener->m_finder._hasToken(hidPath)) - listener->m_finder._insertToken(CDeviceToken(CDeviceToken::DEVTYPE_GENERICHID, - vid, pid, manuf, product, hidPath)); - } - udev_enumerate_unref(hidEnum); - } - } - } - } - - static void deviceDisconnected(CHIDListenerWin32* listener, - udev_device* device) - { - const char* devPath = udev_device_get_syspath(device); - listener->m_finder._removeToken(devPath); - } - - static void _udevProc(CHIDListenerWin32* listener) - { - udev_monitor_enable_receiving(listener->m_udevMon); - int fd = udev_monitor_get_fd(listener->m_udevMon); - while (listener->m_udevRunning) - { - fd_set fds; - FD_ZERO(&fds); - FD_SET(fd, &fds); - select(fd+1, &fds, NULL, NULL, NULL); - udev_device* dev = udev_monitor_receive_device(listener->m_udevMon); - if (dev) - { - const char* action = udev_device_get_action(dev); - if (!strcmp(action, "add")) - deviceConnected(listener, dev); - else if (!strcmp(action, "remove")) - deviceDisconnected(listener, dev); - udev_device_unref(dev); - } - } - } - -public: - CHIDListenerWin32(CDeviceFinder& finder) - : m_finder(finder) - { - - /* Setup hotplug events */ - m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev"); - if (!m_udevMon) - throw std::runtime_error("unable to init udev_monitor"); - udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "usb", "usb_device"); - udev_monitor_filter_add_match_subsystem_devtype(m_udevMon, "bluetooth", "bluetooth_device"); - udev_monitor_filter_update(m_udevMon); - - /* Initial HID Device Add */ - m_scanningEnabled = true; - scanNow(); - m_scanningEnabled = false; - - /* Start hotplug thread */ - m_udevRunning = true; - m_udevThread = new std::thread(_udevProc, this); - - } - - ~CHIDListenerWin32() - { - m_udevRunning = false; - m_udevThread->join(); - delete m_udevThread; - udev_monitor_unref(m_udevMon); - } - - /* Automatic device scanning */ - bool startScanning() - { - m_scanningEnabled = true; - return true; - } - bool stopScanning() - { - m_scanningEnabled = false; - return true; - } - - /* Manual device scanning */ - bool scanNow() - { - udev_enumerate* uenum = udev_enumerate_new(GetUdev()); - udev_enumerate_add_match_subsystem(uenum, "usb"); - udev_enumerate_add_match_property(uenum, "DEVTYPE", "usb_device"); - udev_enumerate_add_match_subsystem(uenum, "bluetooth"); - udev_enumerate_add_match_property(uenum, "DEVTYPE", "bluetooth_device"); - udev_enumerate_scan_devices(uenum); - udev_list_entry* uenumList = udev_enumerate_get_list_entry(uenum); - udev_list_entry* uenumItem; - udev_list_entry_foreach(uenumItem, uenumList) - { - const char* devPath = udev_list_entry_get_name(uenumItem); - udev_device* dev = udev_device_new_from_syspath(UDEV_INST, devPath); - if (dev) - deviceConnected(this, dev); - udev_device_unref(dev); - } - udev_enumerate_unref(uenum); - return true; - } - -}; - -#endif - -IHIDListener* IHIDListenerNew(CDeviceFinder& finder) -{ - // return new CHIDListenerWin32(finder); - return nullptr; -} - -} diff --git a/src/inputdev/CHIDListenerWinUSB.cpp b/src/inputdev/CHIDListenerWinUSB.cpp new file mode 100644 index 0000000..667b81c --- /dev/null +++ b/src/inputdev/CHIDListenerWinUSB.cpp @@ -0,0 +1,203 @@ +#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */ +#include "inputdev/IHIDListener.hpp" +#include "inputdev/CDeviceFinder.hpp" +#include +#include + +#define _WIN32_LEAN_AND_MEAN 1 +#include + +#include +#include +#include +#include +#include + +namespace boo +{ + +class CHIDListenerWinUSB final : public IHIDListener +{ + CDeviceFinder& m_finder; + + std::thread* m_setupThread; + bool m_setupRunning; + bool m_scanningEnabled; + + /* + * Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c + */ + + void _pollDevices() + { + + /* Don't ask */ + static const LPCSTR arPrefix[3] = {"VID_", "PID_", "MI_"}; + unsigned i, j; + CONFIGRET r; + ULONG devpropType; + DWORD reg_type; + HDEVINFO hDevInfo = 0; + SP_DEVINFO_DATA DeviceInfoData = {0}; + DeviceInfoData.cbSize = sizeof(DeviceInfoData); + SP_DEVICE_INTERFACE_DATA DeviceInterfaceData = {0}; + DeviceInterfaceData.cbSize = sizeof(DeviceInterfaceData); + union { + SP_DEVICE_INTERFACE_DETAIL_DATA_A wtf; + CHAR alloc[2048]; + } DeviceInterfaceDetailData; /* Stack allocation should be fine for this */ + DeviceInterfaceDetailData.wtf.cbSize = sizeof(DeviceInterfaceDetailData); + CHAR szDeviceInstanceID[MAX_DEVICE_ID_LEN]; + LPSTR pszToken, pszNextToken; + CHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN]; + + /* List all connected USB devices */ + hDevInfo = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE); + if (hDevInfo == INVALID_HANDLE_VALUE) + return; + + for (i=0 ; ; ++i) + { + + if (!SetupDiEnumDeviceInterfaces(hDevInfo, + NULL, + &GUID_DEVINTERFACE_USB_DEVICE, + i, + &DeviceInterfaceData)) + break; + + DeviceInterfaceDetailData.wtf.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + if (!SetupDiGetDeviceInterfaceDetailA(hDevInfo, + &DeviceInterfaceData, + &DeviceInterfaceDetailData.wtf, + sizeof(DeviceInterfaceDetailData), + NULL, + &DeviceInfoData)) + continue; + + r = CM_Get_Device_IDA(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0); + if (r != CR_SUCCESS) + continue; + + /* Retreive the device description as reported by the device itself */ + pszToken = strtok_s(szDeviceInstanceID , "\\#&", &pszNextToken); + szVid[0] = '\0'; + szPid[0] = '\0'; + szMi[0] = '\0'; + while (pszToken != NULL) + { + for (j=0 ; j<3 ; ++j) + { + if (strncmp(pszToken, arPrefix[j], 4) == 0) + { + switch (j) + { + case 0: + strcpy_s(szVid, MAX_DEVICE_ID_LEN, pszToken); + break; + case 1: + strcpy_s(szPid, MAX_DEVICE_ID_LEN, pszToken); + break; + case 2: + strcpy_s(szMi, MAX_DEVICE_ID_LEN, pszToken); + break; + default: + break; + } + } + } + pszToken = strtok_s(NULL, "\\#&", &pszNextToken); + } + + if (!szVid[0] || !szPid[0]) + continue; + + unsigned vid = strtol(szVid+4, NULL, 16); + unsigned pid = strtol(szPid+4, NULL, 16); + + WCHAR productW[1024] = {0}; + CHAR product[1024] = {0}; + DWORD productSz = 0; + if (!SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, + &devpropType, (BYTE*)productW, 1024, &productSz, 0)) { + /* fallback to SPDRP_DEVICEDESC (USB hubs still use it) */ + SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC, + ®_type, (BYTE*)productW, 1024, &productSz); + } + wcstombs(product, productW, productSz / 2); + + WCHAR manufW[1024] = L"Someone"; /* Windows Vista and earlier will use this as the vendor */ + CHAR manuf[1024] = {0}; + DWORD manufSz = 0; + SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer, + &devpropType, (BYTE*)manufW, 1024, &manufSz, 0); + wcstombs(manuf, manufW, manufSz / 2); + + /* Whew!! that's a single device enumerated!! */ + if (!m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath)) + m_finder._insertToken(CDeviceToken(CDeviceToken::DEVTYPE_USB, + vid, pid, manuf, product, + DeviceInterfaceDetailData.wtf.DevicePath)); + + } + + SetupDiDestroyDeviceInfoList(hDevInfo); + + } + + static void _setupProc(CHIDListenerWinUSB* listener) + { + while (listener->m_setupRunning) + { + if (listener->m_scanningEnabled) + listener->_pollDevices(); + + /* Due to NT derpiness, this needs to be a periodic poll */ + Sleep(1000); + } + } + +public: + CHIDListenerWinUSB(CDeviceFinder& finder) + : m_finder(finder) + { + + /* Initial HID Device Add */ + _pollDevices(); + + } + + ~CHIDListenerWinUSB() + { + m_setupRunning = false; + m_setupThread->join(); + delete m_setupThread; + } + + /* Automatic device scanning */ + bool startScanning() + { + m_scanningEnabled = true; + return true; + } + bool stopScanning() + { + m_scanningEnabled = false; + return true; + } + + /* Manual device scanning */ + bool scanNow() + { + _pollDevices(); + return true; + } + +}; + +IHIDListener* IHIDListenerNew(CDeviceFinder& finder) +{ + return new CHIDListenerWinUSB(finder); +} + +} diff --git a/test/Win32Elevatedlauncher.c b/test/Win32Elevatedlauncher.c deleted file mode 100644 index 3f4445d..0000000 --- a/test/Win32Elevatedlauncher.c +++ /dev/null @@ -1,37 +0,0 @@ - -#define _WIN32_LEAN_AND_MEAN 1 -#include -#include - -int genWin32ShellExecute(const wchar_t* AppFullPath, - const wchar_t* Verb, - const wchar_t* Params, - bool ShowAppWindow, - bool WaitToFinish) -{ - int Result = 0; - - // Setup the required structure - SHELLEXECUTEINFO ShExecInfo; - memset(&ShExecInfo, 0, sizeof(SHELLEXECUTEINFO)); - ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); - ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; - ShExecInfo.hwnd = NULL; - ShExecInfo.lpVerb = Verb; - ShExecInfo.lpFile = AppFullPath; - ShExecInfo.lpParameters = Params; - ShExecInfo.lpDirectory = NULL; - ShExecInfo.nShow = (ShowAppWindow ? SW_SHOW : SW_HIDE); - ShExecInfo.hInstApp = NULL; - - // Spawn the process - if (ShellExecuteEx(&ShExecInfo) == FALSE) - { - Result = -1; // Failed to execute process - } else if (WaitToFinish) - { - WaitForSingleObject(ShExecInfo.hProcess, INFINITE); - } - - return Result; -} diff --git a/test/main.cpp b/test/main.cpp index faa1202..ba16599 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -8,6 +8,9 @@ #if _WIN32 #define _WIN32_LEAN_AND_MEAN 1 #include +#include +#include +#include #else #include #endif @@ -58,70 +61,8 @@ public: } -#if _WIN32 -static int genWin32ShellExecute(const wchar_t* AppFullPath, - const wchar_t* Verb, - const wchar_t* Params, - bool ShowAppWindow, - bool WaitToFinish) -{ - int Result = 0; - - // Setup the required structure - SHELLEXECUTEINFO ShExecInfo; - memset(&ShExecInfo, 0, sizeof(SHELLEXECUTEINFO)); - ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); - ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; - ShExecInfo.hwnd = NULL; - ShExecInfo.lpVerb = Verb; - ShExecInfo.lpFile = AppFullPath; - ShExecInfo.lpParameters = Params; - ShExecInfo.lpDirectory = NULL; - ShExecInfo.nShow = (ShowAppWindow ? SW_SHOW : SW_HIDE); - ShExecInfo.hInstApp = NULL; - - // Spawn the process - if (ShellExecuteEx(&ShExecInfo) == FALSE) - { - Result = -1; // Failed to execute process - } else if (WaitToFinish) - { - WaitForSingleObject(ShExecInfo.hProcess, INFINITE); - } - - return Result; -} - -#include -static void scanWinUSB() -{ - struct wdi_device_info *device, *list; - struct wdi_options_create_list WDI_LIST_OPTS = - { - true, false, true - }; - int err = wdi_create_list(&list, &WDI_LIST_OPTS); - if (err == WDI_SUCCESS) - { - for (device = list; device != NULL; device = device->next) - { - if (device->vid == 0x57E && device->pid == 0x337 && - !strcmp(device->driver, "HidUsb")) - { - printf("GC adapter detected; installing driver\n"); - genWin32ShellExecute(L"WinUsbInstaller.exe", L"", L"", false, true); - } - } - wdi_destroy_list(list); - } -} -#endif - int main(int argc, char** argv) { -#if _WIN32 - scanWinUSB(); -#endif boo::CTestDeviceFinder finder; finder.startScanning(); @@ -137,7 +78,35 @@ int main(int argc, char** argv) #if __APPLE__ CFRunLoopRun(); #elif _WIN32 - while (true) {Sleep(1000);} + + /* Register hotplug notification with windows */ + DEV_BROADCAST_DEVICEINTERFACE_A hotplugConf = + { + sizeof(DEV_BROADCAST_DEVICEINTERFACE_A), + DBT_DEVTYP_DEVICEINTERFACE, + 0, + GUID_DEVINTERFACE_USB_DEVICE + }; + HWND consoleWnd = GetConsoleWindow(); + HDEVNOTIFY notHandle = RegisterDeviceNotificationA(consoleWnd, &hotplugConf, DEVICE_NOTIFY_WINDOW_HANDLE); + + MSG recvMsg; + while (GetMessage(&recvMsg, consoleWnd, 0, 0)) + { + printf("MSG: %d\n", recvMsg.message); + switch (recvMsg.message) + { + case WM_DEVICECHANGE: + printf("DEVICECHANGE!!\n"); + break; + + default: + TranslateMessage(&recvMsg); + DispatchMessage(&recvMsg); + break; + } + } + #else while (true) {sleep(1);} #endif diff --git a/test/test.pri b/test/test.pri index 07e0ac2..872e5fb 100644 --- a/test/test.pri +++ b/test/test.pri @@ -1,5 +1,4 @@ SOURCES += \ - $$PWD/main.cpp \ - $$PWD/Win32Elevatedlauncher.c + $$PWD/main.cpp win32:SOURCES +=