New code style refactor

This commit is contained in:
Jack Andersen
2018-12-07 19:17:51 -10:00
parent 2c2c72bfd1
commit 058ea23a00
113 changed files with 23305 additions and 27650 deletions

View File

@@ -3,111 +3,93 @@
#include "IHIDDevice.hpp"
#include <cstdarg>
namespace boo
{
namespace boo {
DeviceBase::DeviceBase(uint64_t typeHash, DeviceToken* token)
: m_typeHash(typeHash), m_token(token)
{
DeviceBase::DeviceBase(uint64_t typeHash, DeviceToken* token) : m_typeHash(typeHash), m_token(token) {}
void DeviceBase::_deviceDisconnected() {
deviceDisconnected();
m_token = nullptr;
if (m_hidDev) {
m_hidDev->_deviceDisconnected();
m_hidDev.reset();
}
}
void DeviceBase::_deviceDisconnected()
{
deviceDisconnected();
m_token = nullptr;
if (m_hidDev)
{
m_hidDev->_deviceDisconnected();
m_hidDev.reset();
}
void DeviceBase::closeDevice() {
if (m_token)
m_token->_deviceClose();
}
void DeviceBase::closeDevice()
{
if (m_token)
m_token->_deviceClose();
void DeviceBase::deviceError(const char* error, ...) {
va_list vl;
va_start(vl, error);
vfprintf(stderr, error, vl);
va_end(vl);
}
void DeviceBase::deviceError(const char* error, ...)
{
va_list vl;
va_start(vl, error);
vfprintf(stderr, error, vl);
va_end(vl);
bool DeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
if (m_hidDev)
return m_hidDev->_sendUSBInterruptTransfer(data, length);
return false;
}
bool DeviceBase::sendUSBInterruptTransfer(const uint8_t* data, size_t length)
{
if (m_hidDev)
return m_hidDev->_sendUSBInterruptTransfer(data, length);
return false;
size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length) {
if (m_hidDev)
return m_hidDev->_receiveUSBInterruptTransfer(data, length);
return false;
}
size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length)
{
if (m_hidDev)
return m_hidDev->_receiveUSBInterruptTransfer(data, length);
return false;
unsigned DeviceBase::getVendorId() {
if (m_token)
return m_token->getVendorId();
return -1;
}
unsigned DeviceBase::getVendorId()
{
if (m_token)
return m_token->getVendorId();
return -1;
unsigned DeviceBase::getProductId() {
if (m_token)
return m_token->getProductId();
return -1;
}
unsigned DeviceBase::getProductId()
{
if (m_token)
return m_token->getProductId();
return -1;
std::string_view DeviceBase::getVendorName() {
if (m_token)
return m_token->getVendorName();
return {};
}
std::string_view DeviceBase::getVendorName()
{
if (m_token)
return m_token->getVendorName();
return {};
}
std::string_view DeviceBase::getProductName()
{
if (m_token)
return m_token->getProductName();
return {};
std::string_view DeviceBase::getProductName() {
if (m_token)
return m_token->getProductName();
return {};
}
#if _WIN32
#if !WINDOWS_STORE
const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor()
{
if (m_hidDev)
return m_hidDev->_getReportDescriptor();
return {};
const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor() {
if (m_hidDev)
return m_hidDev->_getReportDescriptor();
return {};
}
#endif
#else
std::vector<uint8_t> DeviceBase::getReportDescriptor()
{
if (m_hidDev)
return m_hidDev->_getReportDescriptor();
return {};
std::vector<uint8_t> DeviceBase::getReportDescriptor() {
if (m_hidDev)
return m_hidDev->_getReportDescriptor();
return {};
}
#endif
bool DeviceBase::sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
if (m_hidDev)
return m_hidDev->_sendHIDReport(data, length, tp, message);
return false;
bool DeviceBase::sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (m_hidDev)
return m_hidDev->_sendHIDReport(data, length, tp, message);
return false;
}
size_t DeviceBase::receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
if (m_hidDev)
return m_hidDev->_receiveHIDReport(data, length, tp, message);
return 0;
size_t DeviceBase::receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (m_hidDev)
return m_hidDev->_receiveHIDReport(data, length, tp, message);
return 0;
}
}
} // namespace boo

View File

@@ -6,68 +6,59 @@
#include <usbiodef.h>
#endif
namespace boo
{
namespace boo {
DeviceFinder* DeviceFinder::skDevFinder = nullptr;
#if _WIN32 && !WINDOWS_STORE
/* Windows-specific WM_DEVICECHANGED handler */
LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam)
{
PDEV_BROADCAST_HDR dbh = (PDEV_BROADCAST_HDR)lParam;
PDEV_BROADCAST_DEVICEINTERFACE dbhi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
DeviceFinder* finder = instance();
if (!finder)
return 0;
if (wParam == DBT_DEVICEARRIVAL)
{
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID;
if (type != DeviceType::None)
{
#ifdef UNICODE
char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024);
finder->m_listener->_extDevConnect(devPath);
#else
finder->m_listener->_extDevConnect(dbhi->dbcc_name);
#endif
}
}
}
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
{
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
{
DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID;
if (type != DeviceType::None)
{
#ifdef UNICODE
char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024);
finder->m_listener->_extDevDisconnect(devPath);
#else
finder->m_listener->_extDevDisconnect(dbhi->dbcc_name);
#endif
}
}
}
LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam) {
PDEV_BROADCAST_HDR dbh = (PDEV_BROADCAST_HDR)lParam;
PDEV_BROADCAST_DEVICEINTERFACE dbhi = (PDEV_BROADCAST_DEVICEINTERFACE)lParam;
DeviceFinder* finder = instance();
if (!finder)
return 0;
if (wParam == DBT_DEVICEARRIVAL) {
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID;
if (type != DeviceType::None) {
#ifdef UNICODE
char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024);
finder->m_listener->_extDevConnect(devPath);
#else
finder->m_listener->_extDevConnect(dbhi->dbcc_name);
#endif
}
}
} else if (wParam == DBT_DEVICEREMOVECOMPLETE) {
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
DeviceType type = DeviceType::None;
if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_USB_DEVICE)
type = DeviceType::USB;
else if (dbhi->dbcc_classguid == GUID_DEVINTERFACE_HID)
type = DeviceType::HID;
if (type != DeviceType::None) {
#ifdef UNICODE
char devPath[1024];
wcstombs(devPath, dbhi->dbcc_name, 1024);
finder->m_listener->_extDevDisconnect(devPath);
#else
finder->m_listener->_extDevDisconnect(dbhi->dbcc_name);
#endif
}
}
}
return 0;
}
#endif
}
} // namespace boo

View File

@@ -3,87 +3,75 @@
#include "boo/inputdev/GenericPad.hpp"
#include "IHIDDevice.hpp"
namespace boo
{
namespace boo {
extern const DeviceSignature BOO_DEVICE_SIGS[];
bool DeviceSignature::DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet)
{
if (token.getDeviceType() == DeviceType::HID)
{
uint64_t genPadHash = dev_typeid(GenericPad);
bool hasGenericPad = false;
for (const DeviceSignature* sig : sigSet)
{
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId() &&
sig->m_type != DeviceType::HID)
return false;
if (sig->m_typeHash == genPadHash)
hasGenericPad = true;
}
return hasGenericPad;
bool DeviceSignature::DeviceMatchToken(const DeviceToken& token, const TDeviceSignatureSet& sigSet) {
if (token.getDeviceType() == DeviceType::HID) {
uint64_t genPadHash = dev_typeid(GenericPad);
bool hasGenericPad = false;
for (const DeviceSignature* sig : sigSet) {
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId() && sig->m_type != DeviceType::HID)
return false;
if (sig->m_typeHash == genPadHash)
hasGenericPad = true;
}
for (const DeviceSignature* sig : sigSet)
{
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
return true;
}
return false;
return hasGenericPad;
}
for (const DeviceSignature* sig : sigSet) {
if (sig->m_vid == token.getVendorId() && sig->m_pid == token.getProductId())
return true;
}
return false;
}
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp);
std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token)
{
std::shared_ptr<DeviceBase> retval;
std::shared_ptr<DeviceBase> DeviceSignature::DeviceNew(DeviceToken& token) {
std::shared_ptr<DeviceBase> retval;
/* Perform signature-matching to find the appropriate device-factory */
const DeviceSignature* foundSig = nullptr;
const DeviceSignature* 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;
/* Perform signature-matching to find the appropriate device-factory */
const DeviceSignature* foundSig = nullptr;
const DeviceSignature* 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;
}
if (!foundSig)
{
/* Try Generic HID devices */
if (token.getDeviceType() == DeviceType::HID)
{
retval = std::make_shared<GenericPad>(&token);
if (!retval)
return nullptr;
retval->m_hidDev = IHIDDeviceNew(token, retval);
if (!retval->m_hidDev)
return nullptr;
retval->m_hidDev->_startThread();
return retval;
}
++sigIter;
}
if (!foundSig) {
/* Try Generic HID devices */
if (token.getDeviceType() == DeviceType::HID) {
retval = std::make_shared<GenericPad>(&token);
if (!retval)
return nullptr;
retval->m_hidDev = IHIDDeviceNew(token, retval);
if (!retval->m_hidDev)
return nullptr;
retval->m_hidDev->_startThread();
return retval;
}
if (foundSig->m_type != DeviceType::None && foundSig->m_type != token.getDeviceType())
return nullptr;
retval = foundSig->m_factory(&token);
if (!retval)
return nullptr;
retval->m_hidDev = IHIDDeviceNew(token, retval);
if (!retval->m_hidDev)
return nullptr;
retval->m_hidDev->_startThread();
return retval;
return nullptr;
}
if (foundSig->m_type != DeviceType::None && foundSig->m_type != token.getDeviceType())
return nullptr;
retval = foundSig->m_factory(&token);
if (!retval)
return nullptr;
retval->m_hidDev = IHIDDeviceNew(token, retval);
if (!retval->m_hidDev)
return nullptr;
retval->m_hidDev->_startThread();
return retval;
}
}
} // namespace boo

View File

@@ -3,8 +3,7 @@
#include <cstdio>
#include <cstring>
namespace boo
{
namespace boo {
/*
* Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c
*/
@@ -14,134 +13,118 @@ DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token)
DolphinSmashAdapter::~DolphinSmashAdapter() {}
static inline EDolphinControllerType parseType(unsigned char status)
{
EDolphinControllerType type =
EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird);
switch (type)
{
case EDolphinControllerType::Normal:
case EDolphinControllerType::Wavebird:
return type;
default:
return EDolphinControllerType::None;
}
}
static inline EDolphinControllerType parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble)
{
memset(stateOut, 0, sizeof(DolphinControllerState));
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];
static inline EDolphinControllerType parseType(unsigned char status) {
EDolphinControllerType type =
EDolphinControllerType(status) & (EDolphinControllerType::Normal | EDolphinControllerType::Wavebird);
switch (type) {
case EDolphinControllerType::Normal:
case EDolphinControllerType::Wavebird:
return type;
default:
return EDolphinControllerType::None;
}
}
void DolphinSmashAdapter::initialCycle()
{
uint8_t handshakePayload[] = {0x13};
sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload));
static inline EDolphinControllerType parseState(DolphinControllerState* stateOut, uint8_t* payload, bool& rumble) {
memset(stateOut, 0, sizeof(DolphinControllerState));
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 DolphinSmashAdapter::transferCycle()
{
uint8_t payload[37];
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 37 || payload[0] != 0x21)
return;
void DolphinSmashAdapter::initialCycle() {
uint8_t handshakePayload[] = {0x13};
sendUSBInterruptTransfer(handshakePayload, sizeof(handshakePayload));
}
// printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
void DolphinSmashAdapter::transferCycle() {
uint8_t payload[37];
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 37 || payload[0] != 0x21)
return;
std::lock_guard<std::mutex> lk(m_callbackLock);
if (!m_callback)
return;
// printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
/* Parse controller states */
uint8_t* controller = &payload[1];
uint8_t rumbleMask = 0;
for (uint32_t i = 0; i < 4; i++, controller += 9)
{
DolphinControllerState state;
bool rumble = false;
EDolphinControllerType type = parseState(&state, controller, rumble);
if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i))
{
m_leftStickCal[0] = state.m_leftStick[0];
m_leftStickCal[1] = state.m_leftStick[1];
m_rightStickCal[0] = state.m_rightStick[0];
m_rightStickCal[1] = state.m_rightStick[1];
m_triggersCal[0] = state.m_analogTriggers[0];
m_triggersCal[1] = state.m_analogTriggers[1];
m_knownControllers |= 1 << i;
m_callback->controllerConnected(i, type);
}
else if (type == EDolphinControllerType::None && (m_knownControllers & 1 << i))
{
m_knownControllers &= ~(1 << i);
m_callback->controllerDisconnected(i);
}
if (m_knownControllers & 1 << i)
{
state.m_leftStick[0] = state.m_leftStick[0] - m_leftStickCal[0];
state.m_leftStick[1] = state.m_leftStick[1] - m_leftStickCal[1];
state.m_rightStick[0] = state.m_rightStick[0] - m_rightStickCal[0];
state.m_rightStick[1] = state.m_rightStick[1] - m_rightStickCal[1];
state.m_analogTriggers[0] = state.m_analogTriggers[0] - m_triggersCal[0];
state.m_analogTriggers[1] = state.m_analogTriggers[1] - m_triggersCal[1];
m_callback->controllerUpdate(i, type, state);
}
rumbleMask |= rumble ? 1 << i : 0;
std::lock_guard<std::mutex> lk(m_callbackLock);
if (!m_callback)
return;
/* Parse controller states */
uint8_t* controller = &payload[1];
uint8_t rumbleMask = 0;
for (uint32_t i = 0; i < 4; i++, controller += 9) {
DolphinControllerState state;
bool rumble = false;
EDolphinControllerType type = parseState(&state, controller, rumble);
if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i)) {
m_leftStickCal[0] = state.m_leftStick[0];
m_leftStickCal[1] = state.m_leftStick[1];
m_rightStickCal[0] = state.m_rightStick[0];
m_rightStickCal[1] = state.m_rightStick[1];
m_triggersCal[0] = state.m_analogTriggers[0];
m_triggersCal[1] = state.m_analogTriggers[1];
m_knownControllers |= 1 << i;
m_callback->controllerConnected(i, type);
} else if (type == EDolphinControllerType::None && (m_knownControllers & 1 << i)) {
m_knownControllers &= ~(1 << i);
m_callback->controllerDisconnected(i);
}
if (m_knownControllers & 1 << i) {
state.m_leftStick[0] = state.m_leftStick[0] - m_leftStickCal[0];
state.m_leftStick[1] = state.m_leftStick[1] - m_leftStickCal[1];
state.m_rightStick[0] = state.m_rightStick[0] - m_rightStickCal[0];
state.m_rightStick[1] = state.m_rightStick[1] - m_rightStickCal[1];
state.m_analogTriggers[0] = state.m_analogTriggers[0] - m_triggersCal[0];
state.m_analogTriggers[1] = state.m_analogTriggers[1] - m_triggersCal[1];
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 if (m_hardStop[i])
rumbleMessage[i + 1] = 2;
else
rumbleMessage[i + 1] = 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 if (m_hardStop[i])
rumbleMessage[i + 1] = 2;
else
rumbleMessage[i + 1] = 0;
}
sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
m_rumbleState = rumbleReq;
}
}
void DolphinSmashAdapter::finalCycle()
{
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
m_rumbleState = rumbleReq;
}
}
void DolphinSmashAdapter::deviceDisconnected()
{
for (uint32_t i = 0; i < 4; i++)
{
if (m_knownControllers & 1 << i)
{
m_knownControllers &= ~(1 << i);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected(i);
}
void DolphinSmashAdapter::finalCycle() {
uint8_t rumbleMessage[5] = {0x11, 0, 0, 0, 0};
sendUSBInterruptTransfer(rumbleMessage, sizeof(rumbleMessage));
}
void DolphinSmashAdapter::deviceDisconnected() {
for (uint32_t i = 0; i < 4; i++) {
if (m_knownControllers & 1 << i) {
m_knownControllers &= ~(1 << i);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected(i);
}
}
}
/* The following code is derived from pad.c in libogc
@@ -170,98 +153,79 @@ void DolphinSmashAdapter::deviceDisconnected()
static int16_t pad_clampregion[8] = {30, 180, 15, 72, 40, 15, 59, 31};
static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, int16_t min)
{
int x = px;
int y = py;
int signX;
int signY;
int d;
static void pad_clampstick(int16_t& px, int16_t& py, int16_t max, int16_t xy, int16_t min) {
int x = px;
int y = py;
int signX;
int signY;
int d;
if (x > 0)
{
signX = 1;
}
else
{
signX = -1;
x = -x;
}
if (x > 0) {
signX = 1;
} else {
signX = -1;
x = -x;
}
if (y > 0)
{
signY = 1;
}
else
{
signY = -1;
y = -y;
}
if (y > 0) {
signY = 1;
} else {
signY = -1;
y = -y;
}
if (x <= min)
x = 0;
else
x -= min;
if (x <= min)
x = 0;
else
x -= min;
if (y <= min)
{
y = 0;
}
else
{
y -= min;
}
if (y <= min) {
y = 0;
} else {
y -= min;
}
if (x == 0 && y == 0)
{
px = py = 0;
return;
}
if (x == 0 && y == 0) {
px = py = 0;
return;
}
if (xy * y <= xy * x)
{
d = xy * x + (max - xy) * y;
if (xy * max < d)
{
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
}
if (xy * y <= xy * x) {
d = xy * x + (max - xy) * y;
if (xy * max < d) {
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
}
else
{
d = xy * y + (max - xy) * x;
if (xy * max < d)
{
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
}
} else {
d = xy * y + (max - xy) * x;
if (xy * max < d) {
x = int16_t(xy * max * x / d);
y = int16_t(xy * max * y / d);
}
}
px = int16_t(signX * x);
py = int16_t(signY * y);
px = int16_t(signX * x);
py = int16_t(signY * y);
}
static void pad_clamptrigger(int16_t& trigger)
{
int16_t min, max;
static void pad_clamptrigger(int16_t& trigger) {
int16_t min, max;
min = pad_clampregion[0];
max = pad_clampregion[1];
if (min > trigger)
trigger = 0;
else
{
if (max < trigger)
trigger = max;
trigger -= min;
}
min = pad_clampregion[0];
max = pad_clampregion[1];
if (min > trigger)
trigger = 0;
else {
if (max < trigger)
trigger = max;
trigger -= min;
}
}
void DolphinControllerState::clamp()
{
pad_clampstick(m_leftStick[0], m_leftStick[1], pad_clampregion[3], pad_clampregion[4], pad_clampregion[2]);
pad_clampstick(m_rightStick[0], m_rightStick[1], pad_clampregion[6], pad_clampregion[7], pad_clampregion[5]);
pad_clamptrigger(m_analogTriggers[0]);
pad_clamptrigger(m_analogTriggers[1]);
}
void DolphinControllerState::clamp() {
pad_clampstick(m_leftStick[0], m_leftStick[1], pad_clampregion[3], pad_clampregion[4], pad_clampregion[2]);
pad_clampstick(m_rightStick[0], m_rightStick[1], pad_clampregion[6], pad_clampregion[7], pad_clampregion[5]);
pad_clamptrigger(m_analogTriggers[0]);
pad_clamptrigger(m_analogTriggers[1]);
}
} // namespace boo

View File

@@ -7,54 +7,40 @@
#include <memory.h>
#ifdef _WIN32
static inline uint16_t bswap16(uint16_t val) {return _byteswap_ushort(val);}
static inline uint16_t bswap16(uint16_t val) { return _byteswap_ushort(val); }
#elif __GNUC__ && !defined(__FreeBSD__)
static inline uint16_t bswap16(uint16_t val) {return __builtin_bswap16(val); }
static inline uint16_t bswap16(uint16_t val) { return __builtin_bswap16(val); }
#elif !defined(__FreeBSD__)
static inline uint16_t bswap16(uint16_t val) {return __builtin_byteswap(val);}
static inline uint16_t bswap16(uint16_t val) { return __builtin_byteswap(val); }
#endif
#ifndef M_PIF
#define M_PIF 3.14159265358979323846f /* pi */
#endif
#define RAD_TO_DEG (180.f/M_PIF)
#define RAD_TO_DEG (180.f / M_PIF)
namespace boo
{
static const uint8_t defaultReport[49] = {
0x01,
0x01, 0xff, 0x00, 0xff, 0x00,
0xff, 0x80, 0x00, 0x00, 0x00,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
};
namespace boo {
static const uint8_t defaultReport[49] = {0x01, 0x01, 0xff, 0x00, 0xff, 0x00, 0xff, 0x80, 0x00, 0x00, 0x00, 0xff,
0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0xff, 0x27, 0x10,
0x00, 0x32, 0xff, 0x27, 0x10, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00};
DualshockPad::DualshockPad(DeviceToken* token)
: TDeviceBase<IDualshockPadCallback>(dev_typeid(DualshockPad), token),
m_rumbleRequest(EDualshockMotor::None),
m_rumbleState(EDualshockMotor::None)
{
memcpy(m_report.buf, defaultReport, 49);
: TDeviceBase<IDualshockPadCallback>(dev_typeid(DualshockPad), token)
, m_rumbleRequest(EDualshockMotor::None)
, m_rumbleState(EDualshockMotor::None) {
memcpy(m_report.buf, defaultReport, 49);
}
DualshockPad::~DualshockPad()
{
DualshockPad::~DualshockPad() {}
void DualshockPad::deviceDisconnected() {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void DualshockPad::deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void DualshockPad::initialCycle()
{
void DualshockPad::initialCycle() {
#if 0
uint8_t setupCommand[5] = {0xF4, 0x42, 0x0c, 0x00, 0x00}; //Tells controller to start sending changes on in pipe
if (!sendHIDReport(setupCommand, 5, HIDReportType::Feature, 0xF4))
@@ -69,77 +55,64 @@ void DualshockPad::initialCycle()
#endif
}
void DualshockPad::transferCycle()
{
void DualshockPad::transferCycle() {}
void DualshockPad::finalCycle() {
m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0;
m_report.rumble.rightDuration = 0;
m_report.rumble.rightOn = false;
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
}
void DualshockPad::finalCycle()
{
m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0;
m_report.rumble.rightDuration = 0;
m_report.rumble.rightOn = false;
void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (message != 1 || length != 49 || tp != HIDReportType::Input)
return;
DualshockPadState state = *reinterpret_cast<const DualshockPadState*>(data);
for (int i = 0; i < 3; i++)
state.m_accelerometer[i] = bswap16(state.m_accelerometer[i]);
state.m_gyrometerZ = bswap16(state.m_gyrometerZ);
const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V);
float accXval = -((double)state.m_accelerometer[0] - zeroG);
float accYval = -((double)state.m_accelerometer[1] - zeroG);
float accZval = -((double)state.m_accelerometer[2] - zeroG);
state.accPitch = (atan2(accYval, accZval) + M_PIF) * RAD_TO_DEG;
state.accYaw = (atan2(accXval, accZval) + M_PIF) * RAD_TO_DEG;
state.gyroZ = (state.m_gyrometerZ / 1023.f);
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerUpdate(*this, state);
}
if (m_rumbleRequest != m_rumbleState) {
if ((m_rumbleRequest & EDualshockMotor::Left) != EDualshockMotor::None) {
m_report.rumble.leftDuration = m_rumbleDuration[0];
m_report.rumble.leftForce = m_rumbleIntensity[0];
} else {
m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0;
}
if ((m_rumbleRequest & EDualshockMotor::Right) != EDualshockMotor::None) {
m_report.rumble.rightDuration = m_rumbleDuration[1];
m_report.rumble.rightOn = m_rumbleIntensity[1] > 0;
} else {
m_report.rumble.rightDuration = 0;
m_report.rumble.rightOn = false;
}
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
m_rumbleState = m_rumbleRequest;
} else {
if (state.m_reserved5[8] & 0x80)
m_rumbleRequest &= ~EDualshockMotor::Right;
if (state.m_reserved5[7] & 0x01)
m_rumbleRequest &= ~EDualshockMotor::Left;
m_rumbleState = m_rumbleRequest;
}
}
void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
if (message != 1 || length != 49 || tp != HIDReportType::Input)
return;
DualshockPadState state = *reinterpret_cast<const DualshockPadState*>(data);
for (int i = 0; i < 3; i++)
state.m_accelerometer[i] = bswap16(state.m_accelerometer[i]);
state.m_gyrometerZ = bswap16(state.m_gyrometerZ);
const double zeroG = 511.5; // 1.65/3.3*1023 (1,65V);
float accXval = -((double)state.m_accelerometer[0] - zeroG);
float accYval = -((double)state.m_accelerometer[1] - zeroG);
float accZval = -((double)state.m_accelerometer[2] - zeroG);
state.accPitch = (atan2(accYval, accZval) + M_PIF) * RAD_TO_DEG;
state.accYaw = (atan2(accXval, accZval) + M_PIF) * RAD_TO_DEG;
state.gyroZ = (state.m_gyrometerZ / 1023.f);
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerUpdate(*this, state);
}
if (m_rumbleRequest != m_rumbleState)
{
if ((m_rumbleRequest & EDualshockMotor::Left) != EDualshockMotor::None)
{
m_report.rumble.leftDuration = m_rumbleDuration[0];
m_report.rumble.leftForce = m_rumbleIntensity[0];
}
else
{
m_report.rumble.leftDuration = 0;
m_report.rumble.leftForce = 0;
}
if ((m_rumbleRequest & EDualshockMotor::Right) != EDualshockMotor::None)
{
m_report.rumble.rightDuration = m_rumbleDuration[1];
m_report.rumble.rightOn = m_rumbleIntensity[1] > 0;
}
else
{
m_report.rumble.rightDuration = 0;
m_report.rumble.rightOn = false;
}
sendHIDReport(m_report.buf, sizeof(m_report), HIDReportType::Output, 0x01);
m_rumbleState = m_rumbleRequest;
}
else
{
if (state.m_reserved5[8] & 0x80)
m_rumbleRequest &= ~EDualshockMotor::Right;
if (state.m_reserved5[7] & 0x01)
m_rumbleRequest &= ~EDualshockMotor::Left;
m_rumbleState = m_rumbleRequest;
}
}
} // boo
} // namespace boo

View File

@@ -1,57 +1,46 @@
#include "boo/inputdev/GenericPad.hpp"
#include "boo/inputdev/DeviceToken.hpp"
namespace boo
{
namespace boo {
GenericPad::GenericPad(DeviceToken* token)
: TDeviceBase<IGenericPadCallback>(dev_typeid(GenericPad), token)
{
}
GenericPad::GenericPad(DeviceToken* token) : TDeviceBase<IGenericPadCallback>(dev_typeid(GenericPad), token) {}
GenericPad::~GenericPad() {}
void GenericPad::deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
void GenericPad::deviceDisconnected() {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void GenericPad::initialCycle()
{
void GenericPad::initialCycle() {
#if _WIN32
#if !WINDOWS_STORE
const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor();
m_parser.Parse(reportDesc);
const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor();
m_parser.Parse(reportDesc);
#endif
#else
std::vector<uint8_t> reportDesc = getReportDescriptor();
m_parser.Parse(reportDesc.data(), reportDesc.size());
std::vector<uint8_t> reportDesc = getReportDescriptor();
m_parser.Parse(reportDesc.data(), reportDesc.size());
#endif
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerConnected();
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerConnected();
}
void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (length == 0 || tp != HIDReportType::Input || !m_callback)
return;
std::function<bool(const HIDMainItem&, int32_t)> func =
[this](const HIDMainItem& item, int32_t value)
{
m_callback->valueUpdate(item, value);
return true;
};
m_parser.ScanValues(func, data, length);
void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (length == 0 || tp != HIDReportType::Input || !m_callback)
return;
std::function<bool(const HIDMainItem&, int32_t)> func = [this](const HIDMainItem& item, int32_t value) {
m_callback->valueUpdate(item, value);
return true;
};
m_parser.ScanValues(func, data, length);
}
void GenericPad::enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const
{
m_parser.EnumerateValues(valueCB);
void GenericPad::enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const {
m_parser.EnumerateValues(valueCB);
}
}
} // namespace boo

View File

@@ -1,31 +1,21 @@
#include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
namespace boo {
namespace boo
{
class HIDListenerBSD final : public IHIDListener {
DeviceFinder& m_finder;
class HIDListenerBSD final : public IHIDListener
{
DeviceFinder& m_finder;
public:
HIDListenerBSD(DeviceFinder& finder)
: m_finder(finder)
{
}
HIDListenerBSD(DeviceFinder& finder) : m_finder(finder) {}
~HIDListenerBSD()
{
}
~HIDListenerBSD() {}
bool startScanning() { return false; }
bool stopScanning() { return false; }
bool startScanning() { return false; }
bool stopScanning() { return false; }
bool scanNow() { return false; }
bool scanNow() { return false; }
};
IHIDListener* IHIDListenerNew(DeviceFinder &finder)
{
return new HIDListenerBSD(finder);
}
}
IHIDListener* IHIDListenerNew(DeviceFinder& finder) { return new HIDListenerBSD(finder); }
} // namespace boo

View File

@@ -5,380 +5,320 @@
#include "IOKitPointer.hpp"
#include <thread>
namespace boo
{
namespace boo {
class HIDDeviceIOKit : public IHIDDevice
{
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
class HIDDeviceIOKit : public IHIDDevice {
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
IUnknownPointer<IOUSBInterfaceInterface> m_usbIntf;
uint8_t m_usbIntfInPipe = 0;
uint8_t m_usbIntfOutPipe = 0;
CFPointer<IOHIDDeviceRef> m_hidIntf;
bool m_runningTransferLoop = false;
bool m_isBt = false;
IUnknownPointer<IOUSBInterfaceInterface> m_usbIntf;
uint8_t m_usbIntfInPipe = 0;
uint8_t m_usbIntfOutPipe = 0;
CFPointer<IOHIDDeviceRef> m_hidIntf;
bool m_runningTransferLoop = false;
bool m_isBt = false;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)
{
if (m_usbIntf)
{
IOReturn res = m_usbIntf->WritePipe(m_usbIntf.storage(), m_usbIntfOutPipe, (void*)data, length);
return res == kIOReturnSuccess;
}
return false;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
if (m_usbIntf) {
IOReturn res = m_usbIntf->WritePipe(m_usbIntf.storage(), m_usbIntfOutPipe, (void*)data, length);
return res == kIOReturnSuccess;
}
return false;
}
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)
{
if (m_usbIntf)
{
UInt32 readSize = length;
IOReturn res = m_usbIntf->ReadPipe(m_usbIntf.storage(), m_usbIntfInPipe, data, &readSize);
if (res != kIOReturnSuccess)
return 0;
return readSize;
}
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) {
if (m_usbIntf) {
UInt32 readSize = length;
IOReturn res = m_usbIntf->ReadPipe(m_usbIntf.storage(), m_usbIntfInPipe, data, &readSize);
if (res != kIOReturnSuccess)
return 0;
return readSize;
}
return 0;
}
std::vector<uint8_t> _getReportDescriptor()
{
if (m_hidIntf)
{
if (CFTypeRef desc = IOHIDDeviceGetProperty(m_hidIntf.get(), CFSTR(kIOHIDReportDescriptorKey)))
{
CFIndex len = CFDataGetLength(CFDataRef(desc));
std::vector<uint8_t> ret(len, '\0');
CFDataGetBytes(CFDataRef(desc), CFRangeMake(0, len), &ret[0]);
return ret;
}
}
return {};
std::vector<uint8_t> _getReportDescriptor() {
if (m_hidIntf) {
if (CFTypeRef desc = IOHIDDeviceGetProperty(m_hidIntf.get(), CFSTR(kIOHIDReportDescriptorKey))) {
CFIndex len = CFDataGetLength(CFDataRef(desc));
std::vector<uint8_t> ret(len, '\0');
CFDataGetBytes(CFDataRef(desc), CFRangeMake(0, len), &ret[0]);
return ret;
}
}
return {};
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
/* HACK: A bug in IOBluetoothGamepadHIDDriver prevents raw output report transmission
* USB driver appears to work correctly */
if (m_hidIntf && !m_isBt)
{
IOReturn res = IOHIDDeviceSetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, length);
return res == kIOReturnSuccess;
}
return false;
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
/* HACK: A bug in IOBluetoothGamepadHIDDriver prevents raw output report transmission
* USB driver appears to work correctly */
if (m_hidIntf && !m_isBt) {
IOReturn res = IOHIDDeviceSetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, length);
return res == kIOReturnSuccess;
}
return false;
}
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
if (m_hidIntf)
{
CFIndex readSize = length;
IOReturn res = IOHIDDeviceGetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, &readSize);
if (res != kIOReturnSuccess)
return 0;
return readSize;
}
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (m_hidIntf) {
CFIndex readSize = length;
IOReturn res = IOHIDDeviceGetReport(m_hidIntf.get(), IOHIDReportType(tp), message, data, &readSize);
if (res != kIOReturnSuccess)
return 0;
return readSize;
}
return 0;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceIOKit> device) {
char thrName[128];
snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data());
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) */
IOObjectPointer<io_iterator_t> devIter;
IOObjectPointer<io_registry_entry_t> devEntry =
IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data());
IOObjectPointer<io_object_t> interfaceEntry;
IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter);
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter.get())) {
if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName)) {
interfaceEntry = obj;
break;
}
}
if (!interfaceEntry) {
snprintf(errStr, 256, "Unable to find interface for %s@%s\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceIOKit> device)
{
char thrName[128];
snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data());
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) */
IOObjectPointer<io_iterator_t> devIter;
IOObjectPointer<io_registry_entry_t> devEntry = IORegistryEntryFromPath(kIOMasterPortDefault,
device->m_devPath.data());
IOObjectPointer<io_object_t> interfaceEntry;
IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter);
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter.get()))
{
if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName))
{
interfaceEntry = obj;
break;
}
}
if (!interfaceEntry)
{
snprintf(errStr, 256, "Unable to find interface for %s@%s\n",
device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* IOKit Plugin COM interface (WTF Apple???) */
IOCFPluginPointer iodev;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(interfaceEntry.get(),
kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID,
&iodev,
&score);
if (err)
{
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* USB interface function-pointer table */
IUnknownPointer<IOUSBInterfaceInterface> intf;
err = iodev.As(&intf, kIOUSBInterfaceInterfaceID);
if (err)
{
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Obtain exclusive lock on device */
device->m_usbIntf = intf;
err = intf->USBInterfaceOpen(intf.storage());
if (err != kIOReturnSuccess)
{
if (err == kIOReturnExclusiveAccess)
{
snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr);
}
else
{
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr);
}
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Determine pipe indices for interrupt I/O */
UInt8 numEndpoints = 0;
err = intf->GetNumEndpoints(intf.storage(), &numEndpoints);
for (int i=1 ; i<numEndpoints+1 ; ++i)
{
UInt8 dir, num, tType, interval;
UInt16 mPacketSz;
err = intf->GetPipeProperties(intf.storage(), 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.storage());
device->m_usbIntf = nullptr;
/* IOKit Plugin COM interface (WTF Apple???) */
IOCFPluginPointer iodev;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(interfaceEntry.get(), kIOUSBInterfaceUserClientTypeID,
kIOCFPlugInInterfaceID, &iodev, &score);
if (err) {
snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
static void _threadProcBTLL(std::shared_ptr<HIDDeviceIOKit> 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();
/* USB interface function-pointer table */
IUnknownPointer<IOUSBInterfaceInterface> intf;
err = iodev.As(&intf, kIOUSBInterfaceInterfaceID);
if (err) {
snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
static void _hidRemoveCb(void * _Nullable context,
IOReturn result,
void * _Nullable sender)
{
reinterpret_cast<HIDDeviceIOKit*>(context)->m_runningTransferLoop = false;
/* Obtain exclusive lock on device */
device->m_usbIntf = intf;
err = intf->USBInterfaceOpen(intf.storage());
if (err != kIOReturnSuccess) {
if (err == kIOReturnExclusiveAccess) {
snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
} else {
snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
}
lk.unlock();
device->m_initCond.notify_one();
return;
}
static void _hidReportCb(void * _Nullable context,
IOReturn,
void * _Nullable,
IOHIDReportType type,
uint32_t reportID,
uint8_t * report,
CFIndex reportLength)
{
reinterpret_cast<DeviceBase*>(context)->receivedHIDReport(report, reportLength, HIDReportType(type), reportID);
/* Determine pipe indices for interrupt I/O */
UInt8 numEndpoints = 0;
err = intf->GetNumEndpoints(intf.storage(), &numEndpoints);
for (int i = 1; i < numEndpoints + 1; ++i) {
UInt8 dir, num, tType, interval;
UInt16 mPacketSz;
err = intf->GetPipeProperties(intf.storage(), i, &dir, &num, &tType, &mPacketSz, &interval);
if (tType == kUSBInterrupt) {
if (dir == kUSBIn)
device->m_usbIntfInPipe = num;
else if (dir == kUSBOut)
device->m_usbIntfOutPipe = num;
}
}
static void _threadProcHID(std::shared_ptr<HIDDeviceIOKit> device)
{
char thrName[128];
snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data());
pthread_setname_np(thrName);
char errStr[256];
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();
/* Get the HID element's object (HID device interface) */
IOObjectPointer<io_service_t> interfaceEntry =
IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data());
if (!IOObjectConformsTo(interfaceEntry.get(), "IOHIDDevice"))
{
snprintf(errStr, 256, "Unable to find interface for %s@%s\n",
device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
device->m_hidIntf = IOHIDDeviceCreate(nullptr, interfaceEntry.get());
if (!device->m_hidIntf)
{
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Cleanup */
intf->USBInterfaceClose(intf.storage());
device->m_usbIntf = nullptr;
}
/* Open device */
IOReturn err = IOHIDDeviceOpen(device->m_hidIntf.get(), kIOHIDOptionsTypeNone);
if (err != kIOReturnSuccess)
{
if (err == kIOReturnExclusiveAccess)
{
snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr);
}
else
{
snprintf(errStr, 256, "Unable to open %s@%s\n",
device->m_token.getProductName().data(), device->m_devPath.data());
device->m_devImp->deviceError(errStr);
}
lk.unlock();
device->m_initCond.notify_one();
return;
}
static void _threadProcBTLL(std::shared_ptr<HIDDeviceIOKit> device) {
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Register removal callback */
IOHIDDeviceRegisterRemovalCallback(device->m_hidIntf.get(), _hidRemoveCb, device.get());
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Make note if device uses bluetooth driver */
if (CFTypeRef transport = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDTransportKey)))
device->m_isBt = CFStringCompare(CFStringRef(transport), CFSTR(kIOHIDTransportBluetoothValue), 0) == kCFCompareEqualTo;
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
device->m_devImp->finalCycle();
}
/* Register input buffer */
std::unique_ptr<uint8_t[]> buffer;
int bufSize = 0;
if (CFTypeRef maxSize = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDMaxInputReportSizeKey)))
CFNumberGetValue(CFNumberRef(maxSize), kCFNumberIntType, &bufSize);
if (bufSize)
{
buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufSize]);
IOHIDDeviceRegisterInputReportCallback(device->m_hidIntf.get(), buffer.get(), bufSize,
_hidReportCb, device->m_devImp.get());
IOHIDDeviceScheduleWithRunLoop(device->m_hidIntf.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
static void _hidRemoveCb(void* _Nullable context, IOReturn result, void* _Nullable sender) {
reinterpret_cast<HIDDeviceIOKit*>(context)->m_runningTransferLoop = false;
}
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
static void _hidReportCb(void* _Nullable context, IOReturn, void* _Nullable, IOHIDReportType type, uint32_t reportID,
uint8_t* report, CFIndex reportLength) {
reinterpret_cast<DeviceBase*>(context)->receivedHIDReport(report, reportLength, HIDReportType(type), reportID);
}
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
{
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.010, true);
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
static void _threadProcHID(std::shared_ptr<HIDDeviceIOKit> device) {
char thrName[128];
snprintf(thrName, 128, "%s Transfer Thread", device->m_token.getProductName().data());
pthread_setname_np(thrName);
char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* Cleanup */
IOHIDDeviceClose(device->m_hidIntf.get(), kIOHIDOptionsTypeNone);
device->m_hidIntf.reset();
/* Get the HID element's object (HID device interface) */
IOObjectPointer<io_service_t> interfaceEntry =
IORegistryEntryFromPath(kIOMasterPortDefault, device->m_devPath.data());
if (!IOObjectConformsTo(interfaceEntry.get(), "IOHIDDevice")) {
snprintf(errStr, 256, "Unable to find interface for %s@%s\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
void _deviceDisconnected()
{
m_runningTransferLoop = false;
device->m_hidIntf = IOHIDDeviceCreate(nullptr, interfaceEntry.get());
if (!device->m_hidIntf) {
snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Open device */
IOReturn err = IOHIDDeviceOpen(device->m_hidIntf.get(), kIOHIDOptionsTypeNone);
if (err != kIOReturnSuccess) {
if (err == kIOReturnExclusiveAccess) {
snprintf(errStr, 256, "Unable to open %s@%s: someone else using it\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
} else {
snprintf(errStr, 256, "Unable to open %s@%s\n", device->m_token.getProductName().data(),
device->m_devPath.data());
device->m_devImp->deviceError(errStr);
}
lk.unlock();
device->m_initCond.notify_one();
return;
}
/* Register removal callback */
IOHIDDeviceRegisterRemovalCallback(device->m_hidIntf.get(), _hidRemoveCb, device.get());
/* Make note if device uses bluetooth driver */
if (CFTypeRef transport = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDTransportKey)))
device->m_isBt =
CFStringCompare(CFStringRef(transport), CFSTR(kIOHIDTransportBluetoothValue), 0) == kCFCompareEqualTo;
/* Register input buffer */
std::unique_ptr<uint8_t[]> buffer;
int bufSize = 0;
if (CFTypeRef maxSize = IOHIDDeviceGetProperty(device->m_hidIntf.get(), CFSTR(kIOHIDMaxInputReportSizeKey)))
CFNumberGetValue(CFNumberRef(maxSize), kCFNumberIntType, &bufSize);
if (bufSize) {
buffer = std::unique_ptr<uint8_t[]>(new uint8_t[bufSize]);
IOHIDDeviceRegisterInputReportCallback(device->m_hidIntf.get(), buffer.get(), bufSize, _hidReportCb,
device->m_devImp.get());
IOHIDDeviceScheduleWithRunLoop(device->m_hidIntf.get(), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
}
/* 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) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.010, true);
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
/* Cleanup */
IOHIDDeviceClose(device->m_hidIntf.get(), kIOHIDOptionsTypeNone);
device->m_hidIntf.reset();
}
void _deviceDisconnected() { m_runningTransferLoop = false; }
public:
HIDDeviceIOKit(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
HIDDeviceIOKit(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token),
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
void _startThread() {
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else {
fprintf(stderr, "invalid token supplied to device constructor\n");
return;
}
m_initCond.wait(lk);
}
void _startThread()
{
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceIOKit>(shared_from_this()));
else
{
fprintf(stderr, "invalid token supplied to device constructor\n");
return;
}
m_initCond.wait(lk);
}
~HIDDeviceIOKit()
{
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
~HIDDeviceIOKit() {
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
{
return std::make_shared<HIDDeviceIOKit>(token, devImp);
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceIOKit>(token, devImp);
}
}
} // namespace boo

View File

@@ -1,34 +1,27 @@
#include "IHIDDevice.hpp"
namespace boo
{
namespace boo {
class HIDDeviceNX : public IHIDDevice
{
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
std::string_view m_devPath;
class HIDDeviceNX : public IHIDDevice {
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
std::string_view m_devPath;
public:
HIDDeviceNX(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token),
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
}
HIDDeviceNX(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
std::vector<uint8_t> _getReportDescriptor() { return {}; }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; }
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return 0; }
void _startThread() {}
void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
std::vector<uint8_t> _getReportDescriptor() { return {}; }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; }
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return 0; }
void _startThread() {}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
{
return std::make_shared<HIDDeviceNX>(token, devImp);
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceNX>(token, devImp);
}
}
} // namespace boo

View File

@@ -3,28 +3,22 @@
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp"
namespace boo
{
namespace boo {
class HIDDeviceUWP : public IHIDDevice
{
class HIDDeviceUWP : public IHIDDevice {
public:
HIDDeviceUWP(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
{
HIDDeviceUWP(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {}
}
void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; }
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; }
void _startThread() {}
void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; }
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) { return false; }
void _startThread() {}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
{
return std::make_shared<HIDDeviceUWP>(token, devImp);
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceUWP>(token, devImp);
}
}
} // namespace boo

View File

@@ -18,8 +18,7 @@
#include <cstring>
#include "boo/inputdev/HIDParser.hpp"
namespace boo
{
namespace boo {
udev* GetUdev();
@@ -27,331 +26,270 @@ udev* GetUdev();
* Reference: http://tali.admingilde.org/linux-docbook/usb/ch07s06.html
*/
class HIDDeviceUdev final : public IHIDDevice
{
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
class HIDDeviceUdev final : public IHIDDevice {
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
int m_devFd = 0;
unsigned m_usbIntfInPipe = 0;
unsigned m_usbIntfOutPipe = 0;
bool m_runningTransferLoop = false;
int m_devFd = 0;
unsigned m_usbIntfInPipe = 0;
unsigned m_usbIntfOutPipe = 0;
bool m_runningTransferLoop = false;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)
{
if (m_devFd)
{
usbdevfs_bulktransfer xfer =
{
m_usbIntfOutPipe | USB_DIR_OUT,
(unsigned)length,
30,
(void*)data
};
int ret = ioctl(m_devFd, USBDEVFS_BULK, &xfer);
if (ret != (int)length)
return false;
return true;
}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) {
if (m_devFd) {
usbdevfs_bulktransfer xfer = {m_usbIntfOutPipe | USB_DIR_OUT, (unsigned)length, 30, (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* data, size_t length) {
if (m_devFd) {
usbdevfs_bulktransfer xfer = {m_usbIntfInPipe | USB_DIR_IN, (unsigned)length, 30, data};
return ioctl(m_devFd, USBDEVFS_BULK, &xfer);
}
return 0;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceUdev> device) {
int 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.data());
/* Get device file */
const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR);
if (fd < 0) {
snprintf(errStr, 256, "Unable to open %s@%s: %s\n", device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
return;
}
device->m_devFd = fd;
usb_device_descriptor devDesc = {};
read(fd, &devDesc, 1);
read(fd, &devDesc.bDescriptorType, devDesc.bLength - 1);
if (devDesc.bNumConfigurations) {
usb_config_descriptor confDesc = {};
read(fd, &confDesc, 1);
read(fd, &confDesc.bDescriptorType, confDesc.bLength - 1);
if (confDesc.bNumInterfaces) {
usb_interface_descriptor intfDesc = {};
read(fd, &intfDesc, 1);
read(fd, &intfDesc.bDescriptorType, intfDesc.bLength - 1);
for (i = 0; i < intfDesc.bNumEndpoints + 1; ++i) {
usb_endpoint_descriptor endpDesc = {};
read(fd, &endpDesc, 1);
read(fd, &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;
}
}
}
}
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)
{
if (m_devFd)
{
usbdevfs_bulktransfer xfer =
{
m_usbIntfInPipe | USB_DIR_IN,
(unsigned)length,
30,
data
};
return ioctl(m_devFd, USBDEVFS_BULK, &xfer);
}
return 0;
/* Request that kernel disconnects existing driver */
usbdevfs_ioctl disconnectReq = {0, USBDEVFS_DISCONNECT, NULL};
ioctl(fd, 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(fd);
device->m_devFd = 0;
udev_device_unref(udevDev);
}
static void _threadProcBTLL(std::shared_ptr<HIDDeviceUdev> device) {
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
/* 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(std::shared_ptr<HIDDeviceUdev> device) {
char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
/* Get device file */
const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR | O_NONBLOCK);
if (fd < 0) {
snprintf(errStr, 256, "Unable to open %s@%s: %s\n", device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
return;
}
device->m_devFd = fd;
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) {
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESCSIZE) %s@%s: %s\n", device->m_token.getProductName().data(),
dp, strerror(errno));
device->m_devImp->deviceError(errStr);
close(fd);
return;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceUdev> device)
{
int 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.data());
/* Get device file */
const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR);
if (fd < 0)
{
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
return;
}
device->m_devFd = fd;
usb_device_descriptor devDesc = {};
read(fd, &devDesc, 1);
read(fd, &devDesc.bDescriptorType, devDesc.bLength-1);
if (devDesc.bNumConfigurations)
{
usb_config_descriptor confDesc = {};
read(fd, &confDesc, 1);
read(fd, &confDesc.bDescriptorType, confDesc.bLength-1);
if (confDesc.bNumInterfaces)
{
usb_interface_descriptor intfDesc = {};
read(fd, &intfDesc, 1);
read(fd, &intfDesc.bDescriptorType, intfDesc.bLength-1);
for (i=0 ; i<intfDesc.bNumEndpoints+1 ; ++i)
{
usb_endpoint_descriptor endpDesc = {};
read(fd, &endpDesc, 1);
read(fd, &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(fd, 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(fd);
device->m_devFd = 0;
udev_device_unref(udevDev);
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) {
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESC) %s@%s: %s\n", device->m_token.getProductName().data(), dp,
strerror(errno));
device->m_devImp->deviceError(errStr);
close(fd);
return;
}
size_t readSz = HIDParser::CalculateMaxInputReportSize(reportDesc.value, reportDesc.size);
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[readSz]);
static void _threadProcBTLL(std::shared_ptr<HIDDeviceUdev> device)
{
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
/* 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(std::shared_ptr<HIDDeviceUdev> device)
{
char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex);
udev_device* udevDev = udev_device_new_from_syspath(GetUdev(), device->m_devPath.data());
/* Get device file */
const char* dp = udev_device_get_devnode(udevDev);
int fd = open(dp, O_RDWR | O_NONBLOCK);
if (fd < 0)
{
snprintf(errStr, 256, "Unable to open %s@%s: %s\n",
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
udev_device_unref(udevDev);
return;
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) {
fd_set readset;
FD_ZERO(&readset);
FD_SET(fd, &readset);
struct timeval timeout = {0, 10000};
if (select(fd + 1, &readset, nullptr, nullptr, &timeout) > 0) {
while (true) {
ssize_t sz = read(fd, readBuf.get(), readSz);
if (sz < 0)
break;
device->m_devImp->receivedHIDReport(readBuf.get(), sz, HIDReportType::Input, readBuf[0]);
}
device->m_devFd = fd;
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
{
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESCSIZE) %s@%s: %s\n",
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
close(fd);
return;
}
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1)
{
snprintf(errStr, 256, "Unable to ioctl(HIDIOCGRDESC) %s@%s: %s\n",
device->m_token.getProductName().data(), dp, strerror(errno));
device->m_devImp->deviceError(errStr);
close(fd);
return;
}
size_t readSz = HIDParser::CalculateMaxInputReportSize(reportDesc.value, reportDesc.size);
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[readSz]);
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
{
fd_set readset;
FD_ZERO(&readset);
FD_SET(fd, &readset);
struct timeval timeout = {0, 10000};
if (select(fd + 1, &readset, nullptr, nullptr, &timeout) > 0)
{
while (true)
{
ssize_t sz = read(fd, readBuf.get(), readSz);
if (sz < 0)
break;
device->m_devImp->receivedHIDReport(readBuf.get(), sz,
HIDReportType::Input, readBuf[0]);
}
}
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
/* Cleanup */
close(fd);
device->m_devFd = 0;
udev_device_unref(udevDev);
}
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
void _deviceDisconnected()
{
m_runningTransferLoop = false;
/* Cleanup */
close(fd);
device->m_devFd = 0;
udev_device_unref(udevDev);
}
void _deviceDisconnected() { m_runningTransferLoop = false; }
std::vector<uint8_t> _getReportDescriptor() {
/* Report descriptor size */
int reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
return {};
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESC, &reportDesc) == -1)
return {};
std::vector<uint8_t> ret(reportDesc.size, '\0');
memmove(ret.data(), reportDesc.value, reportDesc.size);
return ret;
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (m_devFd) {
if (tp == HIDReportType::Feature) {
int ret = ioctl(m_devFd, HIDIOCSFEATURE(length), data);
if (ret < 0)
return false;
return true;
} else if (tp == HIDReportType::Output) {
ssize_t ret = write(m_devFd, data, length);
if (ret < 0)
return false;
return true;
}
}
return false;
}
std::vector<uint8_t> _getReportDescriptor()
{
/* Report descriptor size */
int reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
return {};
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(m_devFd, HIDIOCGRDESC, &reportDesc) == -1)
return {};
std::vector<uint8_t> ret(reportDesc.size, '\0');
memmove(ret.data(), reportDesc.value, reportDesc.size);
return ret;
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
if (m_devFd)
{
if (tp == HIDReportType::Feature)
{
int ret = ioctl(m_devFd, HIDIOCSFEATURE(length), data);
if (ret < 0)
return false;
return true;
}
else if (tp == HIDReportType::Output)
{
ssize_t ret = write(m_devFd, data, length);
if (ret < 0)
return false;
return true;
}
}
return false;
}
size_t _receiveHIDReport(uint8_t *data, size_t length, HIDReportType tp, uint32_t message)
{
if (m_devFd)
{
if (tp == HIDReportType::Feature)
{
data[0] = message;
int ret = ioctl(m_devFd, HIDIOCGFEATURE(length), data);
if (ret < 0)
return 0;
return length;
}
}
return 0;
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
if (m_devFd) {
if (tp == HIDReportType::Feature) {
data[0] = message;
int ret = ioctl(m_devFd, HIDIOCGFEATURE(length), data);
if (ret < 0)
return 0;
return length;
}
}
return 0;
}
public:
HIDDeviceUdev(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
HIDDeviceUdev(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token),
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
void _startThread() {
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else {
fprintf(stderr, "invalid token supplied to device constructor");
abort();
}
m_initCond.wait(lk);
}
void _startThread()
{
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceUdev>(shared_from_this()));
else
{
fprintf(stderr, "invalid token supplied to device constructor");
abort();
}
m_initCond.wait(lk);
}
~HIDDeviceUdev()
{
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
~HIDDeviceUdev() {
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
{
return std::make_shared<HIDDeviceUdev>(token, devImp);
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceUdev>(token, devImp);
}
}
} // namespace boo

View File

@@ -21,378 +21,311 @@
#undef min
#undef max
namespace boo
{
namespace boo {
class HIDDeviceWinUSB final : public IHIDDevice
{
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
class HIDDeviceWinUSB final : public IHIDDevice {
DeviceToken& m_token;
std::shared_ptr<DeviceBase> m_devImp;
HANDLE m_devHandle = 0;
HANDLE m_hidHandle = 0;
WINUSB_INTERFACE_HANDLE m_usbHandle = nullptr;
unsigned m_usbIntfInPipe = 0;
unsigned m_usbIntfOutPipe = 0;
bool m_runningTransferLoop = false;
HANDLE m_devHandle = 0;
HANDLE m_hidHandle = 0;
WINUSB_INTERFACE_HANDLE m_usbHandle = nullptr;
unsigned m_usbIntfInPipe = 0;
unsigned m_usbIntfOutPipe = 0;
bool m_runningTransferLoop = false;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
std::string_view m_devPath;
std::mutex m_initMutex;
std::condition_variable m_initCond;
std::thread m_thread;
bool _sendUSBInterruptTransfer(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;
}
bool _sendUSBInterruptTransfer(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* 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(std::shared_ptr<HIDDeviceWinUSB> 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.data(), 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().data(),
device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
size_t _receiveUSBInterruptTransfer(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;
if (!WinUsb_Initialize(device->m_devHandle, &device->m_usbHandle)) {
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(),
device->m_devPath.data(), 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().data(),
device->m_devPath.data(), 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(std::shared_ptr<HIDDeviceWinUSB> 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();
}
size_t m_minFeatureSz = 0;
size_t m_minInputSz = 0;
size_t m_minOutputSz = 0;
PHIDP_PREPARSED_DATA m_preparsedData = nullptr;
static void _threadProcHID(std::shared_ptr<HIDDeviceWinUSB> device) {
char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* POSIX.. who needs it?? -MS */
device->m_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
device->m_hidHandle =
CreateFileA(device->m_devPath.data(), 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_hidHandle) {
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n", device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData)) {
_snprintf(errStr, 256, "Unable get preparsed data of %s@%s: %d\n", device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
HIDP_CAPS caps;
HidP_GetCaps(device->m_preparsedData, &caps);
device->m_minFeatureSz = caps.FeatureReportByteLength;
device->m_minInputSz = caps.InputReportByteLength;
device->m_minOutputSz = caps.OutputReportByteLength;
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Allocate read buffer */
size_t inBufferSz = device->m_minInputSz;
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[inBufferSz]);
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop) {
device->ReadCycle(readBuf.get(), inBufferSz);
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
/* Cleanup */
CloseHandle(device->m_overlapped.hEvent);
CloseHandle(device->m_hidHandle);
HidD_FreePreparsedData(device->m_preparsedData);
device->m_hidHandle = nullptr;
}
void _deviceDisconnected() { m_runningTransferLoop = false; }
std::vector<uint8_t> m_sendBuf;
std::vector<uint8_t> m_recvBuf;
const PHIDP_PREPARSED_DATA _getReportDescriptor() { return m_preparsedData; }
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
size_t maxOut = std::max(m_minFeatureSz, std::max(m_minOutputSz, length));
if (m_sendBuf.size() < maxOut)
m_sendBuf.resize(maxOut);
if (maxOut > length)
memset(m_sendBuf.data() + length, 0, maxOut - length);
memmove(m_sendBuf.data(), data, length);
if (tp == HIDReportType::Output) {
DWORD useLength = DWORD(std::max(length, m_minOutputSz));
DWORD BytesWritten;
OVERLAPPED Overlapped;
ZeroMemory(&Overlapped, sizeof(Overlapped));
BOOL Result = WriteFile(m_hidHandle, m_sendBuf.data(), useLength, &BytesWritten, &Overlapped);
if (!Result) {
DWORD Error = GetLastError();
if (Error == ERROR_INVALID_USER_BUFFER) {
// std::cout << "Falling back to SetOutputReport" << std::endl;
if (!HidD_SetOutputReport(m_hidHandle, (PVOID)m_sendBuf.data(), useLength))
return false;
}
if (Error != ERROR_IO_PENDING) {
fprintf(stderr, "Write Failed %08X\n", int(Error));
return false;
}
}
if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE)) {
DWORD Error = GetLastError();
fprintf(stderr, "Write Failed %08X\n", int(Error));
return false;
}
} else if (tp == HIDReportType::Feature) {
DWORD useLength = DWORD(std::max(length, m_minFeatureSz));
if (!HidD_SetFeature(m_hidHandle, (PVOID)m_sendBuf.data(), useLength)) {
// int error = GetLastError();
return false;
}
}
return true;
}
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {
size_t maxIn = std::max(m_minFeatureSz, std::max(m_minInputSz, length));
if (m_recvBuf.size() < maxIn)
m_recvBuf.resize(maxIn);
memset(m_recvBuf.data(), 0, length);
m_recvBuf[0] = message;
if (tp == HIDReportType::Input) {
if (!HidD_GetInputReport(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minInputSz, length))))
return 0;
} else if (tp == HIDReportType::Feature) {
if (!HidD_GetFeature(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minFeatureSz, length))))
return 0;
}
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceWinUSB> 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.data(),
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().data(),
device->m_devPath.data(), 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().data(),
device->m_devPath.data(), 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().data(),
device->m_devPath.data(), 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(std::shared_ptr<HIDDeviceWinUSB> 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();
}
size_t m_minFeatureSz = 0;
size_t m_minInputSz = 0;
size_t m_minOutputSz = 0;
PHIDP_PREPARSED_DATA m_preparsedData = nullptr;
static void _threadProcHID(std::shared_ptr<HIDDeviceWinUSB> device)
{
char errStr[256];
std::unique_lock<std::mutex> lk(device->m_initMutex);
/* POSIX.. who needs it?? -MS */
device->m_overlapped.hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
device->m_hidHandle = CreateFileA(device->m_devPath.data(),
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_hidHandle)
{
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
if (!HidD_GetPreparsedData(device->m_hidHandle, &device->m_preparsedData))
{
_snprintf(errStr, 256, "Unable get preparsed data of %s@%s: %d\n",
device->m_token.getProductName().data(),
device->m_devPath.data(), GetLastError());
device->m_devImp->deviceError(errStr);
lk.unlock();
device->m_initCond.notify_one();
return;
}
HIDP_CAPS caps;
HidP_GetCaps(device->m_preparsedData, &caps);
device->m_minFeatureSz = caps.FeatureReportByteLength;
device->m_minInputSz = caps.InputReportByteLength;
device->m_minOutputSz = caps.OutputReportByteLength;
/* Return control to main thread */
device->m_runningTransferLoop = true;
lk.unlock();
device->m_initCond.notify_one();
/* Allocate read buffer */
size_t inBufferSz = device->m_minInputSz;
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[inBufferSz]);
/* Start transfer loop */
device->m_devImp->initialCycle();
while (device->m_runningTransferLoop)
{
device->ReadCycle(readBuf.get(), inBufferSz);
if (device->m_runningTransferLoop)
device->m_devImp->transferCycle();
}
device->m_devImp->finalCycle();
/* Cleanup */
CloseHandle(device->m_overlapped.hEvent);
CloseHandle(device->m_hidHandle);
HidD_FreePreparsedData(device->m_preparsedData);
device->m_hidHandle = nullptr;
}
void _deviceDisconnected()
{
m_runningTransferLoop = false;
}
std::vector<uint8_t> m_sendBuf;
std::vector<uint8_t> m_recvBuf;
const PHIDP_PREPARSED_DATA _getReportDescriptor()
{
return m_preparsedData;
}
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
size_t maxOut = std::max(m_minFeatureSz, std::max(m_minOutputSz, length));
if (m_sendBuf.size() < maxOut)
m_sendBuf.resize(maxOut);
if (maxOut > length)
memset(m_sendBuf.data() + length, 0, maxOut - length);
memmove(m_sendBuf.data(), data, length);
if (tp == HIDReportType::Output)
{
DWORD useLength = DWORD(std::max(length, m_minOutputSz));
DWORD BytesWritten;
OVERLAPPED Overlapped;
ZeroMemory(&Overlapped, sizeof(Overlapped));
BOOL Result = WriteFile(m_hidHandle, m_sendBuf.data(), useLength, &BytesWritten, &Overlapped);
if (!Result)
{
DWORD Error = GetLastError();
if (Error == ERROR_INVALID_USER_BUFFER)
{
//std::cout << "Falling back to SetOutputReport" << std::endl;
if (!HidD_SetOutputReport(m_hidHandle, (PVOID)m_sendBuf.data(), useLength))
return false;
}
if (Error != ERROR_IO_PENDING)
{
fprintf(stderr, "Write Failed %08X\n", int(Error));
return false;
}
}
if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE))
{
DWORD Error = GetLastError();
fprintf(stderr, "Write Failed %08X\n", int(Error));
return false;
}
}
else if (tp == HIDReportType::Feature)
{
DWORD useLength = DWORD(std::max(length, m_minFeatureSz));
if (!HidD_SetFeature(m_hidHandle, (PVOID)m_sendBuf.data(), useLength))
{
//int error = GetLastError();
return false;
}
}
return true;
}
size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
size_t maxIn = std::max(m_minFeatureSz, std::max(m_minInputSz, length));
if (m_recvBuf.size() < maxIn)
m_recvBuf.resize(maxIn);
memset(m_recvBuf.data(), 0, length);
m_recvBuf[0] = message;
if (tp == HIDReportType::Input)
{
if (!HidD_GetInputReport(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minInputSz, length))))
return 0;
}
else if (tp == HIDReportType::Feature)
{
if (!HidD_GetFeature(m_hidHandle, m_recvBuf.data(), ULONG(std::max(m_minFeatureSz, length))))
return 0;
}
memmove(data, m_recvBuf.data(), length);
return length;
}
memmove(data, m_recvBuf.data(), length);
return length;
}
public:
HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token), m_devImp(devImp), m_devPath(token.getDevicePath()) {}
HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
: m_token(token),
m_devImp(devImp),
m_devPath(token.getDevicePath())
{
}
void _startThread() {
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else
throw std::runtime_error("invalid token supplied to device constructor");
m_initCond.wait(lk);
}
void _startThread()
{
std::unique_lock<std::mutex> lk(m_initMutex);
DeviceType dType = m_token.getDeviceType();
if (dType == DeviceType::USB)
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::Bluetooth)
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else if (dType == DeviceType::HID)
m_thread = std::thread(_threadProcHID, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
else
throw std::runtime_error("invalid token supplied to device constructor");
m_initCond.wait(lk);
}
~HIDDeviceWinUSB() {
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
}
~HIDDeviceWinUSB()
{
OVERLAPPED m_overlapped = {};
void ReadCycle(uint8_t* inBuffer, size_t inBufferSz) {
ResetEvent(m_overlapped.hEvent);
ZeroMemory(inBuffer, inBufferSz);
DWORD BytesRead = 0;
BOOL Result = ReadFile(m_hidHandle, inBuffer, DWORD(inBufferSz), &BytesRead, &m_overlapped);
if (!Result) {
DWORD Error = GetLastError();
if (Error == ERROR_DEVICE_NOT_CONNECTED) {
m_runningTransferLoop = false;
if (m_thread.joinable())
m_thread.detach();
return;
} else if (Error != ERROR_IO_PENDING) {
fprintf(stderr, "Read Failed: %08X\n", int(Error));
return;
} else if (!GetOverlappedResultEx(m_hidHandle, &m_overlapped, &BytesRead, 10, TRUE)) {
return;
}
}
OVERLAPPED m_overlapped = {};
void ReadCycle(uint8_t* inBuffer, size_t inBufferSz)
{
ResetEvent(m_overlapped.hEvent);
ZeroMemory(inBuffer, inBufferSz);
DWORD BytesRead = 0;
BOOL Result = ReadFile(m_hidHandle, inBuffer, DWORD(inBufferSz), &BytesRead, &m_overlapped);
if (!Result)
{
DWORD Error = GetLastError();
if (Error == ERROR_DEVICE_NOT_CONNECTED)
{
m_runningTransferLoop = false;
return;
}
else if (Error != ERROR_IO_PENDING)
{
fprintf(stderr, "Read Failed: %08X\n", int(Error));
return;
}
else if (!GetOverlappedResultEx(m_hidHandle, &m_overlapped, &BytesRead, 10, TRUE))
{
return;
}
}
m_devImp->receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]);
}
m_devImp->receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]);
}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
{
return std::make_shared<HIDDeviceWinUSB>(token, devImp);
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceWinUSB>(token, devImp);
}
}
} // namespace boo

View File

@@ -2,33 +2,25 @@
#include "boo/inputdev/DeviceToken.hpp"
#include "boo/inputdev/DeviceBase.hpp"
namespace boo
{
namespace boo {
class HIDDeviceBSD final : public IHIDDevice
{
DeviceToken& m_token;
DeviceBase& m_devImp;
class HIDDeviceBSD final : public IHIDDevice {
DeviceToken& m_token;
DeviceBase& m_devImp;
void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message) { return false; }
size_t _recieveReport(const uint8_t* data, size_t length, uint16_t message) { return 0; }
void _deviceDisconnected() {}
bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) { return false; }
size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) { return 0; }
bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message) { return false; }
size_t _recieveReport(const uint8_t* data, size_t length, uint16_t message) {return 0; }
public:
HIDDeviceBSD(DeviceToken& token, DeviceBase& devImp)
: m_token(token),
m_devImp(devImp)
{
}
HIDDeviceBSD(DeviceToken& token, DeviceBase& devImp) : m_token(token), m_devImp(devImp) {}
~HIDDeviceBSD()
{
}
~HIDDeviceBSD() {}
};
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
{
return std::make_shared<HIDDeviceBSD>(token, devImp);
}
std::shared_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp) {
return std::make_shared<HIDDeviceBSD>(token, devImp);
}
} // namespace boo

View File

@@ -11,326 +11,285 @@
#include "IOKitPointer.hpp"
#include "../CFPointer.hpp"
namespace boo
{
namespace boo {
/*
* Reference: http://oroboro.com/usb-serial-number-osx/
*/
static bool getUSBStringDescriptor(const IUnknownPointer<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.storage(), &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.
if (request.wLenDone == 0)
return false;
static bool getUSBStringDescriptor(const IUnknownPointer<IOUSBDeviceInterface182>& usbDevice, UInt8 idx, char* out) {
UInt16 buffer[128];
unsigned count = (request.wLenDone - 1) / 2;
unsigned i;
for (i=0 ; i<count ; ++i)
out[i] = buffer[i+1];
out[i] = '\0';
return true;
// 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.storage(), &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.
if (request.wLenDone == 0)
return false;
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 HIDListenerIOKit : public IHIDListener
{
DeviceFinder& m_finder;
CFRunLoopRef m_listenerRunLoop;
IONotificationPortRef m_llPort;
IOObjectPointer<io_iterator_t> m_llAddNotif, m_llRemoveNotif;
IOObjectPointer<io_iterator_t> m_hidAddNotif, m_hidRemoveNotif;
const char* m_usbClass;
bool m_scanningEnabled;
static void devicesConnectedUSBLL(HIDListenerIOKit* listener,
io_iterator_t iterator)
{
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator))
{
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
class HIDListenerIOKit : public IHIDListener {
DeviceFinder& m_finder;
if (!listener->m_scanningEnabled ||
listener->m_finder._hasToken(devPath))
continue;
UInt16 vid, pid;
char vstr[128] = {0};
char pstr[128] = {0};
{
IOCFPluginPointer devServ;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(obj.get(), kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &devServ, &score);
if (err != kIOReturnSuccess)
{
fprintf(stderr, "unable to open IOKit plugin interface\n");
continue;
}
CFRunLoopRef m_listenerRunLoop;
IONotificationPortRef m_llPort;
IOObjectPointer<io_iterator_t> m_llAddNotif, m_llRemoveNotif;
IOObjectPointer<io_iterator_t> m_hidAddNotif, m_hidRemoveNotif;
const char* m_usbClass;
bool m_scanningEnabled;
IUnknownPointer<IOUSBDeviceInterface182> dev;
err = devServ.As(&dev, kIOUSBDeviceInterfaceID182);
if (err != kIOReturnSuccess)
{
fprintf(stderr, "unable to open IOKit device interface\n");
continue;
}
static void devicesConnectedUSBLL(HIDListenerIOKit* listener, io_iterator_t iterator) {
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
dev->GetDeviceVendor(dev.storage(), &vid);
dev->GetDeviceProduct(dev.storage(), &pid);
if (!listener->m_scanningEnabled || listener->m_finder._hasToken(devPath))
continue;
UInt8 vstridx, pstridx;
dev->USBGetManufacturerStringIndex(dev.storage(), &vstridx);
dev->USBGetProductStringIndex(dev.storage(), &pstridx);
getUSBStringDescriptor(dev, vstridx, vstr);
getUSBStringDescriptor(dev, pstridx, pstr);
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB,
vid, pid, vstr, pstr, devPath));
//printf("ADDED %08X %s\n", obj.get(), devPath);
UInt16 vid, pid;
char vstr[128] = {0};
char pstr[128] = {0};
{
IOCFPluginPointer devServ;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(obj.get(), kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID,
&devServ, &score);
if (err != kIOReturnSuccess) {
fprintf(stderr, "unable to open IOKit plugin interface\n");
continue;
}
IUnknownPointer<IOUSBDeviceInterface182> dev;
err = devServ.As(&dev, kIOUSBDeviceInterfaceID182);
if (err != kIOReturnSuccess) {
fprintf(stderr, "unable to open IOKit device interface\n");
continue;
}
dev->GetDeviceVendor(dev.storage(), &vid);
dev->GetDeviceProduct(dev.storage(), &pid);
UInt8 vstridx, pstridx;
dev->USBGetManufacturerStringIndex(dev.storage(), &vstridx);
dev->USBGetProductStringIndex(dev.storage(), &pstridx);
getUSBStringDescriptor(dev, vstridx, vstr);
getUSBStringDescriptor(dev, pstridx, pstr);
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB, vid, pid, vstr, pstr, devPath));
// printf("ADDED %08X %s\n", obj.get(), devPath);
}
static void devicesDisconnectedUSBLL(HIDListenerIOKit* listener,
io_iterator_t iterator)
{
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop)
{
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode, ^{
devicesDisconnectedUSBLL(listener, iterator);
});
CFRunLoopWakeUp(listener->m_listenerRunLoop);
return;
}
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator))
{
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
listener->m_finder._removeToken(devPath);
//printf("REMOVED %08X %s\n", obj.get(), devPath);
}
}
static void devicesDisconnectedUSBLL(HIDListenerIOKit* listener, io_iterator_t iterator) {
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) {
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode,
^{ devicesDisconnectedUSBLL(listener, iterator); });
CFRunLoopWakeUp(listener->m_listenerRunLoop);
return;
}
static void devicesConnectedHID(HIDListenerIOKit* listener,
io_iterator_t iterator)
{
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator))
{
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
if (!listener->m_scanningEnabled ||
listener->m_finder._hasToken(devPath))
continue;
unsigned vidv, pidv;
char vstr[128] = {0};
char pstr[128] = {0};
{
IOCFPluginPointer devServ;
SInt32 score;
IOReturn err;
err = IOCreatePlugInInterfaceForService(obj.get(), kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &devServ, &score);
if (err != kIOReturnSuccess)
{
fprintf(stderr, "unable to open IOKit plugin interface\n");
continue;
}
IUnknownPointer<IOHIDDeviceDeviceInterface> dev;
err = devServ.As(&dev, kIOHIDDeviceDeviceInterfaceID);
if (err != kIOReturnSuccess)
{
fprintf(stderr, "unable to open IOKit device interface\n");
continue;
}
/* Game controllers only */
CFPointer<CFNumberRef> usagePage;
dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsagePageKey), (CFTypeRef*)&usagePage);
CFPointer<CFNumberRef> usage;
dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsageKey), (CFTypeRef*)&usage);
int usagePageV, usageV;
CFNumberGetValue(usagePage.get(), kCFNumberIntType, &usagePageV);
CFNumberGetValue(usage.get(), kCFNumberIntType, &usageV);
if (usagePageV == kHIDPage_GenericDesktop)
{
if (usageV != kHIDUsage_GD_Joystick && usageV != kHIDUsage_GD_GamePad)
continue;
}
else
{
continue;
}
CFPointer<CFNumberRef> vid, pid;
dev->getProperty(dev.storage(), CFSTR(kIOHIDVendorIDKey), (CFTypeRef*)&vid);
dev->getProperty(dev.storage(), CFSTR(kIOHIDProductIDKey), (CFTypeRef*)&pid);
CFNumberGetValue(vid.get(), kCFNumberIntType, &vidv);
CFNumberGetValue(pid.get(), kCFNumberIntType, &pidv);
CFPointer<CFStringRef> vstridx, pstridx;
dev->getProperty(dev.storage(), CFSTR(kIOHIDManufacturerKey), (CFTypeRef*)&vstridx);
dev->getProperty(dev.storage(), CFSTR(kIOHIDProductKey), (CFTypeRef*)&pstridx);
if (vstridx)
CFStringGetCString(vstridx.get(), vstr, 128, kCFStringEncodingUTF8);
if (pstridx)
CFStringGetCString(pstridx.get(), pstr, 128, kCFStringEncodingUTF8);
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID,
vidv, pidv, vstr, pstr, devPath));
//printf("ADDED %08X %s\n", obj, devPath);
}
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
listener->m_finder._removeToken(devPath);
// printf("REMOVED %08X %s\n", obj.get(), devPath);
}
}
static void devicesDisconnectedHID(HIDListenerIOKit* listener,
io_iterator_t iterator)
{
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop)
{
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode, ^{
devicesDisconnectedHID(listener, iterator);
});
CFRunLoopWakeUp(listener->m_listenerRunLoop);
return;
static void devicesConnectedHID(HIDListenerIOKit* listener, io_iterator_t iterator) {
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
if (!listener->m_scanningEnabled || listener->m_finder._hasToken(devPath))
continue;
unsigned vidv, pidv;
char vstr[128] = {0};
char pstr[128] = {0};
{
IOCFPluginPointer devServ;
SInt32 score;
IOReturn err;
err =
IOCreatePlugInInterfaceForService(obj.get(), kIOHIDDeviceTypeID, kIOCFPlugInInterfaceID, &devServ, &score);
if (err != kIOReturnSuccess) {
fprintf(stderr, "unable to open IOKit plugin interface\n");
continue;
}
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator))
{
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
listener->m_finder._removeToken(devPath);
//printf("REMOVED %08X %s\n", obj, devPath);
IUnknownPointer<IOHIDDeviceDeviceInterface> dev;
err = devServ.As(&dev, kIOHIDDeviceDeviceInterfaceID);
if (err != kIOReturnSuccess) {
fprintf(stderr, "unable to open IOKit device interface\n");
continue;
}
/* Game controllers only */
CFPointer<CFNumberRef> usagePage;
dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsagePageKey), (CFTypeRef*)&usagePage);
CFPointer<CFNumberRef> usage;
dev->getProperty(dev.storage(), CFSTR(kIOHIDPrimaryUsageKey), (CFTypeRef*)&usage);
int usagePageV, usageV;
CFNumberGetValue(usagePage.get(), kCFNumberIntType, &usagePageV);
CFNumberGetValue(usage.get(), kCFNumberIntType, &usageV);
if (usagePageV == kHIDPage_GenericDesktop) {
if (usageV != kHIDUsage_GD_Joystick && usageV != kHIDUsage_GD_GamePad)
continue;
} else {
continue;
}
CFPointer<CFNumberRef> vid, pid;
dev->getProperty(dev.storage(), CFSTR(kIOHIDVendorIDKey), (CFTypeRef*)&vid);
dev->getProperty(dev.storage(), CFSTR(kIOHIDProductIDKey), (CFTypeRef*)&pid);
CFNumberGetValue(vid.get(), kCFNumberIntType, &vidv);
CFNumberGetValue(pid.get(), kCFNumberIntType, &pidv);
CFPointer<CFStringRef> vstridx, pstridx;
dev->getProperty(dev.storage(), CFSTR(kIOHIDManufacturerKey), (CFTypeRef*)&vstridx);
dev->getProperty(dev.storage(), CFSTR(kIOHIDProductKey), (CFTypeRef*)&pstridx);
if (vstridx)
CFStringGetCString(vstridx.get(), vstr, 128, kCFStringEncodingUTF8);
if (pstridx)
CFStringGetCString(pstridx.get(), pstr, 128, kCFStringEncodingUTF8);
}
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::HID, vidv, pidv, vstr, pstr, devPath));
// printf("ADDED %08X %s\n", obj, devPath);
}
}
static void devicesDisconnectedHID(HIDListenerIOKit* listener, io_iterator_t iterator) {
if (CFRunLoopGetCurrent() != listener->m_listenerRunLoop) {
CFRunLoopPerformBlock(listener->m_listenerRunLoop, kCFRunLoopDefaultMode,
^{ devicesDisconnectedHID(listener, iterator); });
CFRunLoopWakeUp(listener->m_listenerRunLoop);
return;
}
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator)) {
io_string_t devPath;
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
continue;
listener->m_finder._removeToken(devPath);
// printf("REMOVED %08X %s\n", obj, devPath);
}
}
public:
HIDListenerIOKit(DeviceFinder& finder)
: m_finder(finder)
HIDListenerIOKit(DeviceFinder& finder) : m_finder(finder) {
struct utsname kernInfo;
uname(&kernInfo);
int release = atoi(kernInfo.release);
m_usbClass = release >= 15 ? "IOUSBHostDevice" : kIOUSBDeviceClassName;
m_listenerRunLoop = CFRunLoopGetMain();
m_llPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopSourceRef rlSrc = IONotificationPortGetRunLoopSource(m_llPort);
CFRunLoopAddSource(m_listenerRunLoop, rlSrc, kCFRunLoopDefaultMode);
m_scanningEnabled = true;
/* Register HID Matcher */
{
struct utsname kernInfo;
uname(&kernInfo);
int release = atoi(kernInfo.release);
m_usbClass = release >= 15 ? "IOUSBHostDevice" : kIOUSBDeviceClassName;
CFMutableDictionaryRef matchDict = IOServiceMatching("IOHIDDevice");
CFRetain(matchDict);
m_listenerRunLoop = CFRunLoopGetMain();
m_llPort = IONotificationPortCreate(kIOMasterPortDefault);
CFRunLoopSourceRef rlSrc = IONotificationPortGetRunLoopSource(m_llPort);
CFRunLoopAddSource(m_listenerRunLoop, rlSrc, kCFRunLoopDefaultMode);
m_scanningEnabled = true;
kern_return_t hidRet =
IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict,
(IOServiceMatchingCallback)devicesConnectedHID, this, &m_hidAddNotif);
if (hidRet == kIOReturnSuccess)
devicesConnectedHID(this, m_hidAddNotif.get());
/* Register HID Matcher */
{
CFMutableDictionaryRef matchDict = IOServiceMatching("IOHIDDevice");
CFRetain(matchDict);
kern_return_t hidRet =
IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict,
(IOServiceMatchingCallback)devicesConnectedHID, this, &m_hidAddNotif);
if (hidRet == kIOReturnSuccess)
devicesConnectedHID(this, m_hidAddNotif.get());
hidRet =
IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict,
(IOServiceMatchingCallback)devicesDisconnectedHID, this, &m_hidRemoveNotif);
if (hidRet == kIOReturnSuccess)
devicesDisconnectedHID(this, m_hidRemoveNotif.get());
}
/* Register Low-Level USB Matcher */
{
CFMutableDictionaryRef matchDict = IOServiceMatching(m_usbClass);
CFRetain(matchDict);
kern_return_t llRet =
IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict,
(IOServiceMatchingCallback)devicesConnectedUSBLL, this, &m_llAddNotif);
if (llRet == kIOReturnSuccess)
devicesConnectedUSBLL(this, m_llAddNotif.get());
llRet =
IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict,
(IOServiceMatchingCallback)devicesDisconnectedUSBLL, this, &m_llRemoveNotif);
if (llRet == kIOReturnSuccess)
devicesDisconnectedUSBLL(this, m_llRemoveNotif.get());
}
m_scanningEnabled = false;
hidRet =
IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict,
(IOServiceMatchingCallback)devicesDisconnectedHID, this, &m_hidRemoveNotif);
if (hidRet == kIOReturnSuccess)
devicesDisconnectedHID(this, m_hidRemoveNotif.get());
}
~HIDListenerIOKit()
/* Register Low-Level USB Matcher */
{
//CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode);
IONotificationPortDestroy(m_llPort);
CFMutableDictionaryRef matchDict = IOServiceMatching(m_usbClass);
CFRetain(matchDict);
kern_return_t llRet =
IOServiceAddMatchingNotification(m_llPort, kIOMatchedNotification, matchDict,
(IOServiceMatchingCallback)devicesConnectedUSBLL, this, &m_llAddNotif);
if (llRet == kIOReturnSuccess)
devicesConnectedUSBLL(this, m_llAddNotif.get());
llRet =
IOServiceAddMatchingNotification(m_llPort, kIOTerminatedNotification, matchDict,
(IOServiceMatchingCallback)devicesDisconnectedUSBLL, this, &m_llRemoveNotif);
if (llRet == kIOReturnSuccess)
devicesDisconnectedUSBLL(this, m_llRemoveNotif.get());
}
/* Automatic device scanning */
bool startScanning()
{
m_scanningEnabled = true;
return true;
m_scanningEnabled = false;
}
~HIDListenerIOKit() {
// CFRunLoopRemoveSource(m_listenerRunLoop, IONotificationPortGetRunLoopSource(m_llPort), kCFRunLoopDefaultMode);
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() {
IOObjectPointer<io_iterator_t> iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess) {
devicesConnectedUSBLL(this, iter.get());
}
bool stopScanning()
{
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow()
{
IOObjectPointer<io_iterator_t> iter;
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess)
{
devicesConnectedUSBLL(this, iter.get());
}
return true;
}
return true;
}
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
{
return std::make_unique<HIDListenerIOKit>(finder);
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
return std::make_unique<HIDListenerIOKit>(finder);
}
}
} // namespace boo

View File

@@ -1,25 +1,18 @@
#include "boo/inputdev/IHIDListener.hpp"
namespace boo
{
namespace boo {
class HIDListenerNX : public IHIDListener
{
DeviceFinder& m_finder;
class HIDListenerNX : public IHIDListener {
DeviceFinder& m_finder;
public:
HIDListenerNX(DeviceFinder& finder)
: m_finder(finder)
{}
HIDListenerNX(DeviceFinder& finder) : m_finder(finder) {}
bool startScanning() { return false; }
bool stopScanning() { return false; }
bool scanNow() { return false; }
bool startScanning() { return false; }
bool stopScanning() { return false; }
bool scanNow() { return false; }
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
{
return std::make_unique<HIDListenerNX>(finder);
}
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) { return std::make_unique<HIDListenerNX>(finder); }
}
} // namespace boo

View File

@@ -2,25 +2,20 @@
#include "boo/inputdev/IHIDListener.hpp"
#include "boo/inputdev/DeviceFinder.hpp"
namespace boo
{
namespace boo {
class HIDListenerUWP : public IHIDListener
{
class HIDListenerUWP : public IHIDListener {
public:
HIDListenerUWP(DeviceFinder& finder) {}
HIDListenerUWP(DeviceFinder& finder) {}
/* Automatic device scanning */
bool startScanning() { return false; }
bool stopScanning() { return false; }
/* Automatic device scanning */
bool startScanning() { return false; }
bool stopScanning() { return false; }
/* Manual device scanning */
bool scanNow() { return false; }
/* Manual device scanning */
bool scanNow() { return false; }
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
{
return std::make_unique<HIDListenerUWP>(finder);
}
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) { return std::make_unique<HIDListenerUWP>(finder); }
}
} // namespace boo

View File

@@ -12,122 +12,110 @@
#include <unistd.h>
#include <thread>
namespace boo
{
namespace boo {
static udev* UDEV_INST = nullptr;
udev* GetUdev()
{
if (!UDEV_INST)
UDEV_INST = udev_new();
return UDEV_INST;
udev* GetUdev() {
if (!UDEV_INST)
UDEV_INST = udev_new();
return UDEV_INST;
}
class HIDListenerUdev final : public IHIDListener
{
DeviceFinder& m_finder;
class HIDListenerUdev final : public IHIDListener {
DeviceFinder& m_finder;
udev_monitor* m_udevMon;
std::thread m_udevThread;
bool m_scanningEnabled;
udev_monitor* m_udevMon;
std::thread m_udevThread;
bool m_scanningEnabled;
void deviceConnected(udev_device* device)
{
if (!m_scanningEnabled)
return;
void deviceConnected(udev_device* device) {
if (!m_scanningEnabled)
return;
/* Prevent redundant registration */
const char* devPath = udev_device_get_syspath(device);
if (m_finder._hasToken(devPath))
return;
/* Prevent redundant registration */
const char* devPath = udev_device_get_syspath(device);
if (m_finder._hasToken(devPath))
return;
/* Filter to USB/BT */
const char* dt = udev_device_get_devtype(device);
DeviceType type;
int vid = 0, pid = 0;
const char* manuf = nullptr;
const char* product = nullptr;
if (dt)
{
if (!strcmp(dt, "usb_device"))
type = DeviceType::USB;
else if (!strcmp(dt, "bluetooth_device"))
type = DeviceType::Bluetooth;
else
return;
/* Filter to USB/BT */
const char* dt = udev_device_get_devtype(device);
DeviceType type;
int vid = 0, pid = 0;
const char* manuf = nullptr;
const char* product = nullptr;
if (dt) {
if (!strcmp(dt, "usb_device"))
type = DeviceType::USB;
else if (!strcmp(dt, "bluetooth_device"))
type = DeviceType::Bluetooth;
else
return;
udev_list_entry* attrs = udev_device_get_properties_list_entry(device);
udev_list_entry* vide = udev_list_entry_get_by_name(attrs, "ID_VENDOR_ID");
if (vide)
vid = strtol(udev_list_entry_get_value(vide), nullptr, 16);
udev_list_entry* attrs = udev_device_get_properties_list_entry(device);
udev_list_entry* vide = udev_list_entry_get_by_name(attrs, "ID_VENDOR_ID");
if (vide)
vid = strtol(udev_list_entry_get_value(vide), nullptr, 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), nullptr, 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), nullptr, 16);
udev_list_entry* manufe = udev_list_entry_get_by_name(attrs, "ID_VENDOR");
if (manufe)
manuf = udev_list_entry_get_value(manufe);
udev_list_entry* manufe = udev_list_entry_get_by_name(attrs, "ID_VENDOR");
if (manufe)
manuf = udev_list_entry_get_value(manufe);
udev_list_entry* producte = udev_list_entry_get_by_name(attrs, "ID_MODEL");
if (producte)
product = udev_list_entry_get_value(producte);
}
else if (!strcmp(udev_device_get_subsystem(device), "hidraw"))
{
type = DeviceType::HID;
udev_device* parent = udev_device_get_parent(device);
udev_list_entry* attrs = udev_device_get_properties_list_entry(parent);
udev_list_entry* producte = udev_list_entry_get_by_name(attrs, "ID_MODEL");
if (producte)
product = udev_list_entry_get_value(producte);
} else if (!strcmp(udev_device_get_subsystem(device), "hidraw")) {
type = DeviceType::HID;
udev_device* parent = udev_device_get_parent(device);
udev_list_entry* attrs = udev_device_get_properties_list_entry(parent);
udev_list_entry* hidide = udev_list_entry_get_by_name(attrs, "HID_ID");
if (hidide)
{
const char* hidid = udev_list_entry_get_value(hidide);
const char* vids = strchr(hidid, ':') + 1;
const char* pids = strchr(vids, ':') + 1;
vid = strtol(vids, nullptr, 16);
pid = strtol(pids, nullptr, 16);
}
udev_list_entry* hidide = udev_list_entry_get_by_name(attrs, "HID_ID");
if (hidide) {
const char* hidid = udev_list_entry_get_value(hidide);
const char* vids = strchr(hidid, ':') + 1;
const char* pids = strchr(vids, ':') + 1;
vid = strtol(vids, nullptr, 16);
pid = strtol(pids, nullptr, 16);
}
udev_list_entry* hidnamee = udev_list_entry_get_by_name(attrs, "HID_NAME");
if (hidnamee)
{
product = udev_list_entry_get_value(hidnamee);
manuf = product;
}
udev_list_entry* hidnamee = udev_list_entry_get_by_name(attrs, "HID_NAME");
if (hidnamee) {
product = udev_list_entry_get_value(hidnamee);
manuf = product;
}
/* Get device file */
const char* dp = udev_device_get_devnode(device);
int fd = open(dp, O_RDWR);
if (fd < 0)
return;
/* Get device file */
const char* dp = udev_device_get_devnode(device);
int fd = open(dp, O_RDWR);
if (fd < 0)
return;
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1)
{
//const char* err = strerror(errno);
close(fd);
return;
}
/* Report descriptor size */
int reportDescSize;
if (ioctl(fd, HIDIOCGRDESCSIZE, &reportDescSize) == -1) {
// const char* err = strerror(errno);
close(fd);
return;
}
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1)
{
//const char* err = strerror(errno);
close(fd);
return;
}
close(fd);
/* Get report descriptor */
hidraw_report_descriptor reportDesc;
reportDesc.size = reportDescSize;
if (ioctl(fd, HIDIOCGRDESC, &reportDesc) == -1) {
// const char* err = strerror(errno);
close(fd);
return;
}
close(fd);
std::pair<HIDUsagePage, HIDUsage> usage =
HIDParser::GetApplicationUsage(reportDesc.value, reportDesc.size);
if (usage.first != HIDUsagePage::GenericDesktop ||
(usage.second != HIDUsage::Joystick && usage.second != HIDUsage::GamePad))
return;
}
std::pair<HIDUsagePage, HIDUsage> usage = HIDParser::GetApplicationUsage(reportDesc.value, reportDesc.size);
if (usage.first != HIDUsagePage::GenericDesktop ||
(usage.second != HIDUsage::Joystick && usage.second != HIDUsage::GamePad))
return;
}
#if 0
udev_list_entry* att = nullptr;
@@ -140,120 +128,105 @@ class HIDListenerUdev final : public IHIDListener
fprintf(stderr, "\n\n");
#endif
m_finder._insertToken(std::make_unique<DeviceToken>(type, vid, pid, manuf, product, devPath));
}
m_finder._insertToken(std::make_unique<DeviceToken>(type, vid, pid, manuf, product, devPath));
}
void deviceDisconnected(udev_device* device)
{
const char* devPath = udev_device_get_syspath(device);
m_finder._removeToken(devPath);
}
void deviceDisconnected(udev_device* device) {
const char* devPath = udev_device_get_syspath(device);
m_finder._removeToken(devPath);
}
void _udevProc()
{
logvisor::RegisterThreadName("Boo udev");
udev_monitor_enable_receiving(m_udevMon);
int fd = udev_monitor_get_fd(m_udevMon);
while (true)
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (pselect(fd+1, &fds, nullptr, nullptr, nullptr, nullptr) < 0)
{
/* SIGTERM handled here */
if (errno == EINTR)
break;
}
int oldtype;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype);
udev_device* dev = udev_monitor_receive_device(m_udevMon);
if (dev)
{
const char* action = udev_device_get_action(dev);
if (!strcmp(action, "add"))
deviceConnected(dev);
else if (!strcmp(action, "remove"))
deviceDisconnected(dev);
udev_device_unref(dev);
}
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldtype);
pthread_testcancel();
}
void _udevProc() {
logvisor::RegisterThreadName("Boo udev");
udev_monitor_enable_receiving(m_udevMon);
int fd = udev_monitor_get_fd(m_udevMon);
while (true) {
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
if (pselect(fd + 1, &fds, nullptr, nullptr, nullptr, nullptr) < 0) {
/* SIGTERM handled here */
if (errno == EINTR)
break;
}
int oldtype;
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype);
udev_device* dev = udev_monitor_receive_device(m_udevMon);
if (dev) {
const char* action = udev_device_get_action(dev);
if (!strcmp(action, "add"))
deviceConnected(dev);
else if (!strcmp(action, "remove"))
deviceDisconnected(dev);
udev_device_unref(dev);
}
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldtype);
pthread_testcancel();
}
}
public:
HIDListenerUdev(DeviceFinder& 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_add_match_subsystem_devtype(m_udevMon, "hidraw", nullptr);
udev_monitor_filter_update(m_udevMon);
/* Initial HID Device Add */
m_scanningEnabled = true;
scanNow();
m_scanningEnabled = false;
/* Start hotplug thread */
m_udevThread = std::thread(std::bind(&HIDListenerUdev::_udevProc, this), this);
HIDListenerUdev(DeviceFinder& 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_add_match_subsystem_devtype(m_udevMon, "hidraw", nullptr);
udev_monitor_filter_update(m_udevMon);
~HIDListenerUdev()
{
pthread_cancel(m_udevThread.native_handle());
if (m_udevThread.joinable())
m_udevThread.join();
udev_monitor_unref(m_udevMon);
}
/* Initial HID Device Add */
m_scanningEnabled = true;
scanNow();
m_scanningEnabled = false;
/* Automatic device scanning */
bool startScanning()
{
m_scanningEnabled = true;
return true;
}
bool stopScanning()
{
m_scanningEnabled = false;
return true;
}
/* Start hotplug thread */
m_udevThread = std::thread(std::bind(&HIDListenerUdev::_udevProc, this), this);
}
/* Manual device scanning */
bool scanNow()
{
udev_enumerate* uenum = udev_enumerate_new(GetUdev());
udev_enumerate_add_match_subsystem(uenum, "usb");
udev_enumerate_add_match_subsystem(uenum, "bluetooth");
udev_enumerate_add_match_subsystem(uenum, "hidraw");
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(dev);
udev_device_unref(dev);
}
udev_enumerate_unref(uenum);
return true;
}
~HIDListenerUdev() {
pthread_cancel(m_udevThread.native_handle());
if (m_udevThread.joinable())
m_udevThread.join();
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_subsystem(uenum, "bluetooth");
udev_enumerate_add_match_subsystem(uenum, "hidraw");
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(dev);
udev_device_unref(dev);
}
udev_enumerate_unref(uenum);
return true;
}
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
{
return std::make_unique<HIDListenerUdev>(finder);
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
return std::make_unique<HIDListenerUdev>(finder);
}
}
} // namespace boo

View File

@@ -18,306 +18,257 @@
#include <hidclass.h>
#include <Xinput.h>
namespace boo
{
namespace boo {
class HIDListenerWinUSB final : public IHIDListener
{
DeviceFinder& m_finder;
class HIDListenerWinUSB final : public IHIDListener {
DeviceFinder& m_finder;
bool m_scanningEnabled;
bool m_scanningEnabled;
/*
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
*/
/*
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
*/
void _enumerate(DeviceType type, CONST GUID* TypeGUID, 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];
void _enumerate(DeviceType type, CONST GUID* TypeGUID, 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 HID devices */
hDevInfo = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
if (hDevInfo == INVALID_HANDLE_VALUE)
return;
/* List all connected HID 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,
TypeGUID,
i,
&DeviceInterfaceData))
break;
for (i = 0;; ++i) {
if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, TypeGUID, i, &DeviceInterfaceData))
break;
DeviceInterfaceDetailData.wtf.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (!SetupDiGetDeviceInterfaceDetailA(hDevInfo,
&DeviceInterfaceData,
&DeviceInterfaceDetailData.wtf,
sizeof(DeviceInterfaceDetailData),
NULL,
&DeviceInfoData))
continue;
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;
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);
/* 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;
}
if (!szVid[0] || !szPid[0])
continue;
unsigned vid = strtol(szVid+4, NULL, 16);
unsigned pid = strtol(szPid+4, NULL, 16);
CHAR 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);
}
/* DAFUQ??? Why isn't this really WCHAR??? */
//WideCharToMultiByte(CP_UTF8, 0, productW, -1, product, 1024, nullptr, nullptr);
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);
WideCharToMultiByte(CP_UTF8, 0, manufW, -1, manuf, 1024, nullptr, nullptr);
if (type == DeviceType::HID)
{
HANDLE devHnd = CreateFileA(DeviceInterfaceDetailData.wtf.DevicePath,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
if (INVALID_HANDLE_VALUE == devHnd)
continue;
PHIDP_PREPARSED_DATA preparsedData;
if (!HidD_GetPreparsedData(devHnd, &preparsedData))
{
CloseHandle(devHnd);
continue;
}
HIDP_CAPS caps;
HidP_GetCaps(preparsedData, &caps);
HidD_FreePreparsedData(preparsedData);
CloseHandle(devHnd);
/* Filter non joysticks and gamepads */
if (caps.UsagePage != 1 || (caps.Usage != 4 && caps.Usage != 5))
continue;
}
/* 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;
if (!m_scanningEnabled || m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
continue;
/* Whew!! that's a single device enumerated!! */
m_finder._insertToken(std::make_unique<DeviceToken>(
type, vid, pid, manuf, productW,
DeviceInterfaceDetailData.wtf.DevicePath));
}
}
pszToken = strtok_s(NULL, "\\#&", &pszNextToken);
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
if (!szVid[0] || !szPid[0])
continue;
void _pollDevices(const char* pathFilter)
{
_enumerate(DeviceType::HID, &GUID_DEVINTERFACE_HID, pathFilter);
_enumerate(DeviceType::USB, &GUID_DEVINTERFACE_USB_DEVICE, pathFilter);
}
unsigned vid = strtol(szVid + 4, NULL, 16);
unsigned pid = strtol(szPid + 4, NULL, 16);
static XInputPadState ConvertXInputState(const XINPUT_GAMEPAD& pad)
{
return {pad.wButtons, pad.bLeftTrigger, pad.bRightTrigger,
pad.sThumbLX, pad.sThumbLY, pad.sThumbLY, pad.sThumbRY};
}
CHAR 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);
}
/* DAFUQ??? Why isn't this really WCHAR??? */
// WideCharToMultiByte(CP_UTF8, 0, productW, -1, product, 1024, nullptr, nullptr);
std::thread m_xinputThread;
bool m_xinputRunning = true;
DWORD m_xinputPackets[4] = {DWORD(-1), DWORD(-1), DWORD(-1), DWORD(-1)};
std::vector<DeviceToken> m_xinputTokens;
void _xinputProc()
{
m_xinputTokens.reserve(4);
for (int i=0 ; i<4 ; ++i)
m_xinputTokens.emplace_back(DeviceType::XInput, 0, i, "", "", "");
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);
WideCharToMultiByte(CP_UTF8, 0, manufW, -1, manuf, 1024, nullptr, nullptr);
while (m_xinputRunning)
{
for (int i=0 ; i<4 ; ++i)
{
DeviceToken& tok = m_xinputTokens[i];
XINPUT_STATE state;
if (XInputGetState(i, &state) == ERROR_SUCCESS)
{
if (state.dwPacketNumber != m_xinputPackets[i])
{
if (m_xinputPackets[i] == -1)
m_finder.deviceConnected(tok);
m_xinputPackets[i] = state.dwPacketNumber;
if (tok.m_connectedDev)
{
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
std::lock_guard<std::mutex> lk(pad.m_callbackLock);
if (pad.m_callback)
pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad));
}
}
if (tok.m_connectedDev)
{
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
if (pad.m_rumbleRequest[0] != pad.m_rumbleState[0] ||
pad.m_rumbleRequest[1] != pad.m_rumbleState[1])
{
pad.m_rumbleState[0] = pad.m_rumbleRequest[0];
pad.m_rumbleState[1] = pad.m_rumbleRequest[1];
XINPUT_VIBRATION vibe = {pad.m_rumbleRequest[0], pad.m_rumbleRequest[1]};
XInputSetState(i, &vibe);
}
}
}
else if (m_xinputPackets[i] != -1)
{
m_xinputPackets[i] = -1;
if (tok.m_connectedDev)
{
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
pad.deviceDisconnected();
}
m_finder.deviceDisconnected(tok, tok.m_connectedDev.get());
}
}
Sleep(10);
if (type == DeviceType::HID) {
HANDLE devHnd = CreateFileA(DeviceInterfaceDetailData.wtf.DevicePath, GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (INVALID_HANDLE_VALUE == devHnd)
continue;
PHIDP_PREPARSED_DATA preparsedData;
if (!HidD_GetPreparsedData(devHnd, &preparsedData)) {
CloseHandle(devHnd);
continue;
}
HIDP_CAPS caps;
HidP_GetCaps(preparsedData, &caps);
HidD_FreePreparsedData(preparsedData);
CloseHandle(devHnd);
/* Filter non joysticks and gamepads */
if (caps.UsagePage != 1 || (caps.Usage != 4 && caps.Usage != 5))
continue;
}
/* 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;
if (!m_scanningEnabled || m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
continue;
/* Whew!! that's a single device enumerated!! */
m_finder._insertToken(
std::make_unique<DeviceToken>(type, vid, pid, manuf, productW, DeviceInterfaceDetailData.wtf.DevicePath));
}
SetupDiDestroyDeviceInfoList(hDevInfo);
}
void _pollDevices(const char* pathFilter) {
_enumerate(DeviceType::HID, &GUID_DEVINTERFACE_HID, pathFilter);
_enumerate(DeviceType::USB, &GUID_DEVINTERFACE_USB_DEVICE, pathFilter);
}
static XInputPadState ConvertXInputState(const XINPUT_GAMEPAD& pad) {
return {pad.wButtons, pad.bLeftTrigger, pad.bRightTrigger, pad.sThumbLX, pad.sThumbLY, pad.sThumbLY, pad.sThumbRY};
}
std::thread m_xinputThread;
bool m_xinputRunning = true;
DWORD m_xinputPackets[4] = {DWORD(-1), DWORD(-1), DWORD(-1), DWORD(-1)};
std::vector<DeviceToken> m_xinputTokens;
void _xinputProc() {
m_xinputTokens.reserve(4);
for (int i = 0; i < 4; ++i)
m_xinputTokens.emplace_back(DeviceType::XInput, 0, i, "", "", "");
while (m_xinputRunning) {
for (int i = 0; i < 4; ++i) {
DeviceToken& tok = m_xinputTokens[i];
XINPUT_STATE state;
if (XInputGetState(i, &state) == ERROR_SUCCESS) {
if (state.dwPacketNumber != m_xinputPackets[i]) {
if (m_xinputPackets[i] == -1)
m_finder.deviceConnected(tok);
m_xinputPackets[i] = state.dwPacketNumber;
if (tok.m_connectedDev) {
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
std::lock_guard<std::mutex> lk(pad.m_callbackLock);
if (pad.m_callback)
pad.m_callback->controllerUpdate(pad, ConvertXInputState(state.Gamepad));
}
}
if (tok.m_connectedDev) {
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
if (pad.m_rumbleRequest[0] != pad.m_rumbleState[0] || pad.m_rumbleRequest[1] != pad.m_rumbleState[1]) {
pad.m_rumbleState[0] = pad.m_rumbleRequest[0];
pad.m_rumbleState[1] = pad.m_rumbleRequest[1];
XINPUT_VIBRATION vibe = {pad.m_rumbleRequest[0], pad.m_rumbleRequest[1]};
XInputSetState(i, &vibe);
}
}
} else if (m_xinputPackets[i] != -1) {
m_xinputPackets[i] = -1;
if (tok.m_connectedDev) {
XInputPad& pad = static_cast<XInputPad&>(*tok.m_connectedDev);
pad.deviceDisconnected();
}
m_finder.deviceDisconnected(tok, tok.m_connectedDev.get());
}
}
Sleep(10);
}
}
public:
HIDListenerWinUSB(DeviceFinder& finder)
: m_finder(finder)
{
/* Initial HID Device Add */
_pollDevices(nullptr);
HIDListenerWinUSB(DeviceFinder& finder) : m_finder(finder) {
/* Initial HID Device Add */
_pollDevices(nullptr);
/* XInput arbitration thread */
for (const DeviceSignature* sig : m_finder.getTypes())
{
if (sig->m_type == DeviceType::XInput)
{
m_xinputThread = std::thread(std::bind(&HIDListenerWinUSB::_xinputProc, this));
break;
}
}
/* XInput arbitration thread */
for (const DeviceSignature* sig : m_finder.getTypes()) {
if (sig->m_type == DeviceType::XInput) {
m_xinputThread = std::thread(std::bind(&HIDListenerWinUSB::_xinputProc, this));
break;
}
}
}
~HIDListenerWinUSB()
{
m_xinputRunning = false;
if (m_xinputThread.joinable())
m_xinputThread.join();
}
~HIDListenerWinUSB() {
m_xinputRunning = false;
if (m_xinputThread.joinable())
m_xinputThread.join();
}
/* Automatic device scanning */
bool startScanning()
{
m_scanningEnabled = true;
return true;
}
bool stopScanning()
{
m_scanningEnabled = false;
return true;
}
/* Automatic device scanning */
bool startScanning() {
m_scanningEnabled = true;
return true;
}
bool stopScanning() {
m_scanningEnabled = false;
return true;
}
/* Manual device scanning */
bool scanNow()
{
_pollDevices(nullptr);
return true;
}
/* Manual device scanning */
bool scanNow() {
_pollDevices(nullptr);
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 _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;
}
bool _extDevDisconnect(const char* path) {
char upperPath[1024];
strcpy_s(upperPath, 1024, path);
CharUpperA(upperPath);
m_finder._removeToken(upperPath);
return true;
}
};
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
{
return std::make_unique<HIDListenerWinUSB>(finder);
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder) {
return std::make_unique<HIDListenerWinUSB>(finder);
}
}
} // namespace boo

File diff suppressed because it is too large Load Diff

View File

@@ -8,29 +8,27 @@
#include <hidsdi.h>
#endif
namespace boo
{
namespace boo {
class IHIDDevice : public std::enable_shared_from_this<IHIDDevice>
{
friend class DeviceBase;
friend struct DeviceSignature;
virtual void _deviceDisconnected()=0;
virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length)=0;
virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length)=0;
class IHIDDevice : public std::enable_shared_from_this<IHIDDevice> {
friend class DeviceBase;
friend struct DeviceSignature;
virtual void _deviceDisconnected() = 0;
virtual bool _sendUSBInterruptTransfer(const uint8_t* data, size_t length) = 0;
virtual size_t _receiveUSBInterruptTransfer(uint8_t* data, size_t length) = 0;
#if _WIN32
#if !WINDOWS_STORE
virtual const PHIDP_PREPARSED_DATA _getReportDescriptor()=0;
virtual const PHIDP_PREPARSED_DATA _getReportDescriptor() = 0;
#endif
#else
virtual std::vector<uint8_t> _getReportDescriptor()=0;
virtual std::vector<uint8_t> _getReportDescriptor() = 0;
#endif
virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0;
virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message)=0;
virtual void _startThread()=0;
virtual bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0;
virtual size_t _receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message) = 0;
virtual void _startThread() = 0;
public:
virtual ~IHIDDevice() = default;
virtual ~IHIDDevice() = default;
};
}
} // namespace boo

View File

@@ -7,113 +7,97 @@
#include <utility>
/// A smart pointer that can manage the lifecycle of IOKit objects.
template<typename T>
template <typename T>
class IOObjectPointer {
public:
IOObjectPointer() : storage(0) { }
IOObjectPointer() : storage(0) {}
IOObjectPointer(T pointer) : storage(toStorageType(pointer)) {
if (storage) {
IOObjectRetain(storage);
}
IOObjectPointer(T pointer) : storage(toStorageType(pointer)) {
if (storage) {
IOObjectRetain(storage);
}
}
IOObjectPointer(const IOObjectPointer & other) : storage(other.storage) {
if (io_object_t ptr = storage) {
IOObjectRetain(ptr);
}
IOObjectPointer(const IOObjectPointer& other) : storage(other.storage) {
if (io_object_t ptr = storage) {
IOObjectRetain(ptr);
}
IOObjectPointer& operator=(const IOObjectPointer & other) {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
storage = other.storage;
if (io_object_t ptr = storage) {
IOObjectRetain(ptr);
}
return *this;
}
IOObjectPointer& operator=(const IOObjectPointer& other) {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
storage = other.storage;
if (io_object_t ptr = storage) {
IOObjectRetain(ptr);
}
return *this;
}
IOObjectPointer(IOObjectPointer && other) : storage(std::exchange(other.storage, 0)) { }
IOObjectPointer(IOObjectPointer&& other) : storage(std::exchange(other.storage, 0)) {}
~IOObjectPointer() {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
~IOObjectPointer() {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
}
static inline IOObjectPointer<T> adopt(T ptr) {
return IOObjectPointer<T>(ptr, IOObjectPointer<T>::Adopt);
}
static inline IOObjectPointer<T> adopt(T ptr) { return IOObjectPointer<T>(ptr, IOObjectPointer<T>::Adopt); }
T get() const {
return fromStorageType(storage);
T get() const { return fromStorageType(storage); }
io_object_t* operator&() {
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
io_object_t* operator&()
{
if (io_object_t pointer = storage) {
IOObjectRelease(pointer);
}
return &storage;
}
operator bool() const { return storage != 0; }
return &storage;
}
operator bool() const { return storage != 0; }
private:
io_object_t storage;
io_object_t storage;
enum AdoptTag { Adopt };
IOObjectPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) { }
enum AdoptTag { Adopt };
IOObjectPointer(T ptr, AdoptTag) : storage(toStorageType(ptr)) {}
inline io_object_t toStorageType(io_object_t ptr) const {
return (io_object_t)ptr;
}
inline io_object_t toStorageType(io_object_t ptr) const { return (io_object_t)ptr; }
inline T fromStorageType(io_object_t pointer) const {
return (T)pointer;
}
inline T fromStorageType(io_object_t pointer) const { return (T)pointer; }
void swap(IOObjectPointer &other) {
std::swap(storage, other.storage);
}
void swap(IOObjectPointer& other) { std::swap(storage, other.storage); }
};
/// A smart pointer that can manage the lifecycle of IOKit plugin objects.
class IOCFPluginPointer {
public:
IOCFPluginPointer() : _storage(nullptr) { }
IOCFPluginPointer() : _storage(nullptr) {}
IOCFPluginPointer(const IOCFPluginPointer & other) = delete;
IOCFPluginPointer(const IOCFPluginPointer& other) = delete;
IOCFPluginPointer(IOCFPluginPointer && other) : _storage(std::exchange(other._storage, nullptr)) { }
IOCFPluginPointer(IOCFPluginPointer&& other) : _storage(std::exchange(other._storage, nullptr)) {}
~IOCFPluginPointer() {
if (IOCFPlugInInterface** pointer = _storage) {
IODestroyPlugInInterface(pointer);
}
~IOCFPluginPointer() {
if (IOCFPlugInInterface** pointer = _storage) {
IODestroyPlugInInterface(pointer);
}
}
IOCFPlugInInterface*** operator&()
{
if (IOCFPlugInInterface** pointer = _storage) {
IODestroyPlugInInterface(pointer);
}
return &_storage;
IOCFPlugInInterface*** operator&() {
if (IOCFPlugInInterface** pointer = _storage) {
IODestroyPlugInInterface(pointer);
}
return &_storage;
}
HRESULT As(LPVOID* p, CFUUIDRef uuid) const
{
(*_storage)->AddRef(_storage); // Needed for some reason
return (*_storage)->QueryInterface(_storage, CFUUIDGetUUIDBytes(uuid), p);
}
HRESULT As(LPVOID* p, CFUUIDRef uuid) const {
(*_storage)->AddRef(_storage); // Needed for some reason
return (*_storage)->QueryInterface(_storage, CFUUIDGetUUIDBytes(uuid), p);
}
operator bool() const { return _storage != nullptr; }
operator bool() const { return _storage != nullptr; }
IOCFPlugInInterface** storage() const { return _storage; }
IOCFPlugInInterface** storage() const { return _storage; }
private:
IOCFPlugInInterface** _storage;
void swap(IOCFPluginPointer &other) {
std::swap(_storage, other._storage);
}
IOCFPlugInInterface** _storage;
void swap(IOCFPluginPointer& other) { std::swap(_storage, other._storage); }
};

View File

@@ -1,56 +1,44 @@
#include "boo/inputdev/NintendoPowerA.hpp"
#include "boo/inputdev/DeviceSignature.hpp"
#include <memory.h>
namespace boo
{
namespace boo {
NintendoPowerA::NintendoPowerA(DeviceToken* token)
: TDeviceBase<INintendoPowerACallback>(dev_typeid(NintendoPowerA), token)
{
: TDeviceBase<INintendoPowerACallback>(dev_typeid(NintendoPowerA), token) {}
}
NintendoPowerA::~NintendoPowerA() {}
NintendoPowerA::~NintendoPowerA()
{
}
void NintendoPowerA::deviceDisconnected()
{
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
void NintendoPowerA::deviceDisconnected() {
std::lock_guard<std::mutex> lk(m_callbackLock);
if (m_callback)
m_callback->controllerDisconnected();
}
void NintendoPowerA::initialCycle() {}
void NintendoPowerA::transferCycle()
{
uint8_t payload[8];
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 8)
return;
void NintendoPowerA::transferCycle() {
uint8_t payload[8];
size_t recvSz = receiveUSBInterruptTransfer(payload, sizeof(payload));
if (recvSz != 8)
return;
NintendoPowerAState state = *reinterpret_cast<NintendoPowerAState*>(&payload);
NintendoPowerAState state = *reinterpret_cast<NintendoPowerAState*>(&payload);
std::lock_guard<std::mutex> lk(m_callbackLock);
if (state != m_last && m_callback)
m_callback->controllerUpdate(state);
m_last = state;
std::lock_guard<std::mutex> lk(m_callbackLock);
if (state != m_last && m_callback)
m_callback->controllerUpdate(state);
m_last = state;
}
void NintendoPowerA::finalCycle() {}
void NintendoPowerA::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
{
void NintendoPowerA::receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message) {}
bool NintendoPowerAState::operator==(const NintendoPowerAState& other) {
return !memcmp(this, &other, sizeof(NintendoPowerAState));
}
bool NintendoPowerAState::operator==(const NintendoPowerAState &other)
{
return !memcmp(this, &other, sizeof(NintendoPowerAState));
bool NintendoPowerAState::operator!=(const NintendoPowerAState& other) {
return memcmp(this, &other, sizeof(NintendoPowerAState));
}
bool NintendoPowerAState::operator!=(const NintendoPowerAState &other)
{
return memcmp(this, &other, sizeof(NintendoPowerAState));
}
}
} // namespace boo