CMake integration and refactor

This commit is contained in:
Jack Andersen
2015-08-18 08:00:24 -10:00
parent cf9e12c650
commit 3d1e6a554a
50 changed files with 82 additions and 331 deletions

View File

@@ -0,0 +1 @@
#include "inputdev/CafeProPad.hpp"

View File

@@ -0,0 +1,57 @@
#include "inputdev/DeviceBase.hpp"
#include "inputdev/DeviceToken.hpp"
#include "IHIDDevice.hpp"
namespace boo
{
CDeviceBase::CDeviceBase(CDeviceToken* token)
: m_token(token), m_hidDev(NULL)
{
}
CDeviceBase::~CDeviceBase()
{
delete m_hidDev;
}
void CDeviceBase::_deviceDisconnected()
{
deviceDisconnected();
m_token = NULL;
if (m_hidDev)
{
m_hidDev->_deviceDisconnected();
delete m_hidDev;
m_hidDev = NULL;
}
}
void CDeviceBase::closeDevice()
{
if (m_token)
m_token->_deviceClose();
}
bool CDeviceBase::sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)
{
if (m_hidDev)
return m_hidDev->_sendUSBInterruptTransfer(pipe, data, length);
return false;
}
size_t CDeviceBase::receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
{
if (m_hidDev)
return m_hidDev->_receiveUSBInterruptTransfer(pipe, data, length);
return false;
}
bool CDeviceBase::sendHIDReport(const uint8_t* data, size_t length)
{
if (m_hidDev)
return m_hidDev->_sendHIDReport(data, length);
return false;
}
}

View File

@@ -0,0 +1,78 @@
#include "inputdev/DeviceSignature.hpp"
#include "inputdev/DeviceToken.hpp"
#include "inputdev/GenericPad.hpp"
#include "IHIDDevice.hpp"
namespace boo
{
extern const SDeviceSignature BOO_DEVICE_SIGS[];
bool SDeviceSignature::DeviceMatchToken(const CDeviceToken& token, const TDeviceSignatureSet& sigSet)
{
if (token.getDeviceType() == CDeviceToken::DEVTYPE_GENERICHID)
return true;
for (const SDeviceSignature* sig : sigSet)
{
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
return true;
}
return false;
}
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp);
CDeviceBase* SDeviceSignature::DeviceNew(CDeviceToken& token)
{
CDeviceBase* retval = NULL;
/* Early-return for generic HID devices */
if (token.getDeviceType() == CDeviceToken::DEVTYPE_GENERICHID)
{
retval = new CGenericPad(&token);
if (!retval)
return NULL;
IHIDDevice* newDev = IHIDDeviceNew(token, *retval);
if (!newDev)
{
delete retval;
return NULL;
}
return retval;
}
/* Otherwise perform signature-matching to find the appropriate device-factory */
const SDeviceSignature* foundSig = NULL;
const SDeviceSignature* sigIter = BOO_DEVICE_SIGS;
unsigned targetVid = token.getVendorId();
unsigned targetPid = token.getProductId();
while (sigIter->m_name)
{
if (sigIter->m_vid == targetVid && sigIter->m_pid == targetPid)
{
foundSig = sigIter;
break;
}
++sigIter;
}
if (!foundSig)
return NULL;
retval = foundSig->m_factory(&token);
if (!retval)
return NULL;
IHIDDevice* newDev = IHIDDeviceNew(token, *retval);
if (!newDev)
{
delete retval;
return NULL;
}
return retval;
}
}

View File

@@ -0,0 +1,127 @@
#include "inputdev/DolphinSmashAdapter.hpp"
#include <stdio.h>
#include <string.h>
namespace boo
{
/*
* Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c
*/
CDolphinSmashAdapter::CDolphinSmashAdapter(CDeviceToken* token)
: CDeviceBase(token),
m_callback(NULL),
m_knownControllers(0),
m_rumbleRequest(0),
m_rumbleState(0)
{
}
CDolphinSmashAdapter::~CDolphinSmashAdapter()
{
}
static inline EDolphinControllerType parseType(unsigned char status)
{
unsigned char type = status & (DOL_TYPE_NORMAL | DOL_TYPE_WAVEBIRD);
switch (type)
{
case DOL_TYPE_NORMAL:
case DOL_TYPE_WAVEBIRD:
return (EDolphinControllerType)type;
default:
return DOL_TYPE_NONE;
}
}
static inline EDolphinControllerType
parseState(SDolphinControllerState* stateOut, uint8_t* payload, bool& rumble)
{
memset(stateOut, 0, sizeof(SDolphinControllerState));
unsigned char status = payload[0];
EDolphinControllerType type = parseType(status);
rumble = ((status & 0x04) != 0) ? true : false;
stateOut->m_btns = (uint16_t)payload[1] << 8 | (uint16_t)payload[2];
stateOut->m_leftStick[0] = payload[3];
stateOut->m_leftStick[1] = payload[4];
stateOut->m_rightStick[0] = payload[5];
stateOut->m_rightStick[1] = payload[6];
stateOut->m_analogTriggers[0] = payload[7];
stateOut->m_analogTriggers[1] = payload[8];
return type;
}
void CDolphinSmashAdapter::initialCycle()
{
uint8_t handshakePayload[] = {0x13};
sendUSBInterruptTransfer(0, handshakePayload, sizeof(handshakePayload));
}
void CDolphinSmashAdapter::transferCycle()
{
uint8_t payload[37];
size_t recvSz = receiveUSBInterruptTransfer(0, payload, sizeof(payload));
if (recvSz != 37 || payload[0] != 0x21)
return;
//printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
if (!m_callback)
return;
/* Parse controller states */
uint8_t* controller = &payload[1];
uint8_t rumbleMask = 0;
for (int i=0 ; i<4 ; i++, controller += 9)
{
SDolphinControllerState state;
bool rumble = false;
EDolphinControllerType type = parseState(&state, controller, rumble);
if (type && !(m_knownControllers & 1<<i))
{
m_knownControllers |= 1<<i;
m_callback->controllerConnected(i, type);
}
else if (!type && (m_knownControllers & 1<<i))
{
m_knownControllers &= ~(1<<i);
m_callback->controllerDisconnected(i, type);
}
if (m_knownControllers & 1<<i)
m_callback->controllerUpdate(i, type, state);
rumbleMask |= rumble ? 1<<i : 0;
}
/* Send rumble message (if needed) */
uint8_t rumbleReq = m_rumbleRequest & rumbleMask;
if (rumbleReq != m_rumbleState)
{
uint8_t rumbleMessage[5] = {0x11};
for (int i=0 ; i<4 ; ++i)
{
if (rumbleReq & 1<<i)
rumbleMessage[i+1] = 1;
else
rumbleMessage[i+1] = 0;
}
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
m_rumbleState = rumbleReq;
}
}
void CDolphinSmashAdapter::finalCycle()
{
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
sendUSBInterruptTransfer(0, rumbleMessage, sizeof(rumbleMessage));
}
void CDolphinSmashAdapter::deviceDisconnected()
{
}
}

View File

@@ -0,0 +1 @@
#include "inputdev/DualshockPad.hpp"

View File

@@ -0,0 +1,23 @@
#include "inputdev/GenericPad.hpp"
#include "inputdev/DeviceToken.hpp"
namespace boo
{
CGenericPad::CGenericPad(CDeviceToken* token)
: CDeviceBase(token)
{
}
CGenericPad::~CGenericPad()
{
}
void CGenericPad::deviceDisconnected()
{
}
}

View File

@@ -0,0 +1,256 @@
#include "IHIDDevice.hpp"
#include "inputdev/CDeviceToken.hpp"
#include "inputdev/CDeviceBase.hpp"
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <thread>
namespace boo
{
class CHIDDeviceIOKit final : public IHIDDevice
{
CDeviceToken& m_token;
CDeviceBase& m_devImp;
IOUSBInterfaceInterface** m_usbIntf = NULL;
uint8_t m_usbIntfInPipe = 0;
uint8_t 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_usbIntf)
{
IOReturn res = (*m_usbIntf)->WritePipe(m_usbIntf, m_usbIntfOutPipe, (void*)data, length);
return res == kIOReturnSuccess;
}
return false;
}
size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)
{
if (m_usbIntf)
{
UInt32 readSize = length;
IOReturn res = (*m_usbIntf)->ReadPipe(m_usbIntf, m_usbIntfInPipe, data, &readSize);
if (res != kIOReturnSuccess)
return 0;
return readSize;
}
return 0;
}
static void _threadProcUSBLL(CHIDDeviceIOKit* device)
{
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<std::mutex> lk(device->m_initMutex);
/* Get the HID element's parent (USB interrupt transfer-interface) */
io_iterator_t devIter;
io_registry_entry_t devEntry = IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.c_str());
IORegistryEntryGetChildIterator(devEntry, kIOServicePlane, &devIter);
io_object_t obj, interfaceEntry = 0;
while ((obj = IOIteratorNext(devIter)))
{
if (IOObjectConformsTo(obj, kIOUSBInterfaceClassName))
interfaceEntry = obj;
else
IOObjectRelease(obj);
}
if (!interfaceEntry)
{
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;
}
/* IOKit Plugin COM interface (WTF Apple???) */
IOCFPlugInInterface **iodev;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(interfaceEntry,
kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID,
&iodev,
&score);
IOObjectRelease(interfaceEntry);
if (err)
{
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;
}
/* USB interface function-pointer table */
IOUSBInterfaceInterface** intf = NULL;
err = (*iodev)->QueryInterface(iodev,
CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID),
(LPVOID*)&intf);
if (err)
{
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);
return;
}
/* Obtain exclusive lock on device */
device->m_usbIntf = intf;
err = (*intf)->USBInterfaceOpen(intf);
if (err != kIOReturnSuccess)
{
if (err == kIOReturnExclusiveAccess)
{
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
{
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);
IODestroyPlugInInterface(iodev);
return;
}
/* Determine pipe indices for interrupt I/O */
UInt8 numEndpoints = 0;
err = (*intf)->GetNumEndpoints(intf, &numEndpoints);
for (int i=1 ; i<numEndpoints+1 ; ++i)
{
UInt8 dir, num, tType, interval;
UInt16 mPacketSz;
err = (*intf)->GetPipeProperties(intf, i, &dir, &num, &tType, &mPacketSz, &interval);
if (tType == kUSBInterrupt)
{
if (dir == kUSBIn)
device->m_usbIntfInPipe = num;
else if (dir == kUSBOut)
device->m_usbIntfOutPipe = num;
}
}
/* 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 */
(*intf)->USBInterfaceClose(intf);
(*intf)->Release(intf);
IODestroyPlugInInterface(iodev);
device->m_usbIntf = NULL;
}
static void _threadProcBTLL(CHIDDeviceIOKit* device)
{
std::unique_lock<std::mutex> 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(CHIDDeviceIOKit* device)
{
std::unique_lock<std::mutex> 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:
CHIDDeviceIOKit(CDeviceToken& token, CDeviceBase& devImp)
: m_token(token),
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
devImp.m_hidDev = this;
std::unique_lock<std::mutex> 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);
}
~CHIDDeviceIOKit()
{
m_runningTransferLoop = false;
m_thread->join();
delete m_thread;
}
};
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp)
{
return new CHIDDeviceIOKit(token, devImp);
}
}

View File

@@ -0,0 +1,239 @@
#include "IHIDDevice.hpp"
#include "inputdev/DeviceToken.hpp"
#include "inputdev/DeviceBase.hpp"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <stdio.h>
#include <libudev.h>
#include <stropts.h>
#include <linux/usb/ch9.h>
#include <linux/usbdevice_fs.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <string.h>
namespace boo
{
udev* GetUdev();
/*
* 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;
char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.c_str());
/* Get device file */
const char* dp = udev_device_get_devnode(udevDev);
device->m_devFd = open(dp, O_RDWR);
if (device->m_devFd < 0)
{
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 ; i<intfDesc.bNumEndpoints+1 ; ++i)
{
usb_endpoint_descriptor endpDesc = {0};
read(device->m_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<std::mutex> 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<std::mutex> 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<std::mutex> 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
{
fprintf(stderr, "invalid token supplied to device constructor");
abort();
}
m_initCond.wait(lk);
}
~CHIDDeviceUdev()
{
m_runningTransferLoop = false;
m_thread->join();
delete m_thread;
}
};
IHIDDevice* IHIDDeviceNew(CDeviceToken& token, CDeviceBase& devImp)
{
return new CHIDDeviceUdev(token, devImp);
}
}

View File

@@ -0,0 +1,224 @@
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#include "IHIDDevice.hpp"
#include "inputdev/CDeviceToken.hpp"
#include "inputdev/CDeviceBase.hpp"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <string.h>
#include <stdio.h>
#define _WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <winusb.h>
#include <usb100.h>
#include <Winusbio.h>
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<std::mutex> 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.c_str(), 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.c_str(), GetLastError());
device->m_devImp.deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
CloseHandle(device->m_devHandle);
return;
}
/* Enumerate device pipes */
USB_INTERFACE_DESCRIPTOR ifDesc = {0};
if (!WinUsb_QueryInterfaceSettings(device->m_usbHandle, 0, &ifDesc))
{
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
device->m_token.getProductName().c_str(),
device->m_devPath.c_str(), GetLastError());
device->m_devImp.deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
CloseHandle(device->m_devHandle);
return;
}
for (i=0 ; i<ifDesc.bNumEndpoints ; ++i)
{
WINUSB_PIPE_INFORMATION pipeDesc;
WinUsb_QueryPipe(device->m_usbHandle, 0, i, &pipeDesc);
if (pipeDesc.PipeType == UsbdPipeTypeInterrupt)
{
if (USB_ENDPOINT_DIRECTION_IN(pipeDesc.PipeId))
device->m_usbIntfInPipe = pipeDesc.PipeId;
else
device->m_usbIntfOutPipe = pipeDesc.PipeId;
}
}
/* 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<std::mutex> 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<std::mutex> 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<std::mutex> 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);
}
}

View File

@@ -0,0 +1,217 @@
#include "IHIDListener.hpp"
#include "inputdev/CDeviceFinder.hpp"
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/hid/IOHIDLib.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/IOCFPlugIn.h>
namespace boo
{
/*
* Reference: http://oroboro.com/usb-serial-number-osx/
*/
static bool getUSBStringDescriptor(IOUSBDeviceInterface182** usbDevice, UInt8 idx, char* out)
{
UInt16 buffer[128];
// wow... we're actually forced to make hard coded bus requests. Its like
// hard disk programming in the 80's!
IOUSBDevRequest request;
request.bmRequestType = USBmakebmRequestType(kUSBIn,
kUSBStandard,
kUSBDevice);
request.bRequest = kUSBRqGetDescriptor;
request.wValue = (kUSBStringDesc << 8) | idx;
request.wIndex = 0x409; // english
request.wLength = sizeof(buffer);
request.pData = buffer;
kern_return_t err = (*usbDevice)->DeviceRequest(usbDevice, &request);
if (err != 0)
{
// the request failed... fairly uncommon for the USB disk driver, but not
// so uncommon for other devices. This can also be less reliable if your
// disk is mounted through an external USB hub. At this level we actually
// have to worry about hardware issues like this.
return false;
}
// we're mallocing this string just as an example. But you probably will want
// to do something smarter, like pre-allocated buffers in the info class, or
// use a string class.
unsigned count = (request.wLenDone - 1) / 2;
unsigned i;
for (i=0 ; i<count ; ++i)
out[i] = buffer[i+1];
out[i] = '\0';
return true;
}
class CHIDListenerIOKit final : public IHIDListener
{
CDeviceFinder& m_finder;
CFRunLoopRef m_listenerRunLoop;
IONotificationPortRef m_llPort;
io_iterator_t m_llAddNotif, m_llRemoveNotif;
bool m_scanningEnabled;
static void devicesConnectedUSBLL(CHIDListenerIOKit* listener,
io_iterator_t iterator)
{
io_object_t obj;
while ((obj = IOIteratorNext(iterator)))
{
io_string_t devPath;
if (IORegistryEntryGetPath(obj, kIOServicePlane, devPath) != 0)
continue;
if (!listener->m_scanningEnabled ||
listener->m_finder._hasToken(devPath))
{
IOObjectRelease(obj);
continue;
}
IOCFPlugInInterface** devServ;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(obj, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &devServ, &score);
if (err != kIOReturnSuccess)
throw std::runtime_error("unable to open IOKit plugin interface");
IOUSBDeviceInterface182 **dev;
err = (*devServ)->QueryInterface(devServ,
CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID182),
(LPVOID*)&dev);
if (err != kIOReturnSuccess)
throw std::runtime_error("unable to open IOKit device interface");
UInt16 vid, pid;
(*dev)->GetDeviceVendor(dev, &vid);
(*dev)->GetDeviceProduct(dev, &pid);
UInt8 vstridx, pstridx;
(*dev)->USBGetManufacturerStringIndex(dev, &vstridx);
(*dev)->USBGetProductStringIndex(dev, &pstridx);
char vstr[128] = {0};
char pstr[128] = {0};
getUSBStringDescriptor(dev, vstridx, vstr);
getUSBStringDescriptor(dev, pstridx, pstr);
if (!listener->m_finder._insertToken(CDeviceToken(CDeviceToken::DEVTYPE_USB,
vid, pid, vstr, pstr, devPath)))
{
/* Matched-insertion failed; see if generic HID interface is available */
/* TODO: Do */
}
//printf("ADDED %08X %s\n", obj, devPath);
(*dev)->Release(dev);
IODestroyPlugInInterface(devServ);
IOObjectRelease(obj);
}
}
static void devicesDisconnectedUSBLL(CHIDListenerIOKit* listener,
io_iterator_t iterator)
{
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop)
{
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode, ^{
devicesDisconnectedUSBLL(listener, iterator);
});
CFRunLoopWakeUp(listener->m_listenerRunLoop);
return;
}
io_object_t obj;
while ((obj = IOIteratorNext(iterator)))
{
io_string_t devPath;
if (IORegistryEntryGetPath(obj, kIOServicePlane, devPath) != 0)
continue;
listener->m_finder._removeToken(devPath);
//printf("REMOVED %08X %s\n", obj, devPath);
IOObjectRelease(obj);
}
}
public:
CHIDListenerIOKit(CDeviceFinder& finder)
: m_finder(finder)
{
/* Register Low-Level USB Matcher */
m_listenerRunLoop = CFRunLoopGetCurrent();
m_llPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopSourceRef rlSrc = IONotificationPortGetRunLoopSource(m_llPort);
CFRunLoopAddSource(m_listenerRunLoop, rlSrc, kCFRunLoopDefaultMode);
CFMutableDictionaryRef matchDict = IOServiceMatching(kIOUSBDeviceClassName);
CFRetain(matchDict);
m_scanningEnabled = true;
kern_return_t llRet =
IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict,
(IOServiceMatchingCallback)devicesConnectedUSBLL, this, &m_llAddNotif);
if (llRet == kIOReturnSuccess)
devicesConnectedUSBLL(this, m_llAddNotif);
llRet =
IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict,
(IOServiceMatchingCallback)devicesDisconnectedUSBLL, this, &m_llRemoveNotif);
if (llRet == kIOReturnSuccess)
devicesDisconnectedUSBLL(this, m_llRemoveNotif);
m_scanningEnabled = false;
}
~CHIDListenerIOKit()
{
CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode);
IOObjectRelease(m_llAddNotif);
IOObjectRelease(m_llRemoveNotif);
IONotificationPortDestroy(m_llPort);
}
/* Automatic device scanning */
bool startScanning()
{
m_scanningEnabled = true;
return true;
}
bool stopScanning()
{
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow()
{
io_iterator_t iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching(kIOUSBDeviceClassName), &iter) == kIOReturnSuccess)
{
devicesConnectedUSBLL(this, iter);
IOObjectRelease(iter);
}
return true;
}
};
IHIDListener* IHIDListenerNew(CDeviceFinder& finder)
{
return new CHIDListenerIOKit(finder);
}
}

View File

@@ -0,0 +1,219 @@
#include "inputdev/IHIDListener.hpp"
#include "inputdev/DeviceFinder.hpp"
#include <libudev.h>
#include <string.h>
#include <stdio.h>
#include <thread>
namespace boo
{
static udev* UDEV_INST = NULL;
udev* GetUdev()
{
if (!UDEV_INST)
UDEV_INST = udev_new();
return UDEV_INST;
}
class CHIDListenerUdev final : public IHIDListener
{
CDeviceFinder& m_finder;
udev_monitor* m_udevMon;
std::thread* m_udevThread;
bool m_udevRunning;
bool m_scanningEnabled;
static void deviceConnected(CHIDListenerUdev* 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(CHIDListenerUdev* listener,
udev_device* device)
{
const char* devPath = udev_device_get_syspath(device);
listener->m_finder._removeToken(devPath);
}
static void _udevProc(CHIDListenerUdev* 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:
CHIDListenerUdev(CDeviceFinder& finder)
: m_finder(finder)
{
/* Setup hotplug events */
m_udevMon = udev_monitor_new_from_netlink(GetUdev(), "udev");
if (!m_udevMon)
{
fprintf(stderr, "unable to init udev_monitor");
abort();
}
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);
}
~CHIDListenerUdev()
{
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;
}
};
IHIDListener* IHIDListenerNew(CDeviceFinder& finder)
{
return new CHIDListenerUdev(finder);
}
}

View File

@@ -0,0 +1,209 @@
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
#include "inputdev/IHIDListener.hpp"
#include "inputdev/CDeviceFinder.hpp"
#include <string.h>
#include <thread>
#define _WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <initguid.h>
#include <SetupAPI.h>
#include <Cfgmgr32.h>
#include <Usbiodef.h>
#include <Devpkey.h>
namespace boo
{
class CHIDListenerWinUSB final : public IHIDListener
{
CDeviceFinder& m_finder;
bool m_scanningEnabled;
/*
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
*/
void _pollDevices(const char* pathFilter)
{
/* 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,
&reg_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);
/* Store as a shouting string (to keep hash-lookups consistent) */
CharUpperA(DeviceInterfaceDetailData.wtf.DevicePath);
/* Filter to specific device (provided by hotplug event) */
if (pathFilter && strcmp(pathFilter, DeviceInterfaceDetailData.wtf.DevicePath))
continue;
/* 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);
}
public:
CHIDListenerWinUSB(CDeviceFinder& finder)
: m_finder(finder)
{
/* Initial HID Device Add */
_pollDevices(NULL);
}
~CHIDListenerWinUSB()
{}
/* Automatic device scanning */
bool startScanning()
{
m_scanningEnabled = true;
return true;
}
bool stopScanning()
{
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow()
{
_pollDevices(NULL);
return true;
}
bool _extDevConnect(const char* path)
{
char upperPath[1024];
strcpy_s(upperPath, 1024, path);
CharUpperA(upperPath);
if (m_scanningEnabled && !m_finder._hasToken(upperPath))
_pollDevices(upperPath);
return true;
}
bool _extDevDisconnect(const char* path)
{
char upperPath[1024];
strcpy_s(upperPath, 1024, path);
CharUpperA(upperPath);
m_finder._removeToken(upperPath);
return true;
}
};
IHIDListener* IHIDListenerNew(CDeviceFinder& finder)
{
return new CHIDListenerWinUSB(finder);
}
}

View File

@@ -0,0 +1,22 @@
#ifndef IHIDDEVICE_HPP
#define IHIDDEVICE_HPP
#include "inputdev/DeviceToken.hpp"
namespace boo
{
class IHIDDevice
{
friend class CDeviceBase;
virtual void _deviceDisconnected()=0;
virtual bool _sendUSBInterruptTransfer(uint8_t pipe, const uint8_t* data, size_t length)=0;
virtual size_t _receiveUSBInterruptTransfer(uint8_t pipe, uint8_t* data, size_t length)=0;
virtual bool _sendHIDReport(const uint8_t* data, size_t length)=0;
public:
inline virtual ~IHIDDevice() {}
};
}
#endif // IHIDDEVICE_HPP

View File

@@ -0,0 +1 @@
#include "inputdev/RevolutionPad.hpp"