mirror of
https://github.com/AxioDL/boo.git
synced 2025-05-14 19:31:20 +00:00
HID Parser for Win32
This commit is contained in:
parent
0f2a838bfb
commit
1f14cc09a1
@ -5,6 +5,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "boo/System.hpp"
|
||||
|
||||
#if _WIN32
|
||||
#include <hidsdi.h>
|
||||
#endif
|
||||
|
||||
namespace boo
|
||||
{
|
||||
@ -45,7 +51,11 @@ public:
|
||||
size_t receiveUSBInterruptTransfer(uint8_t* data, size_t length);
|
||||
|
||||
/* High-Level API */
|
||||
#if _WIN32
|
||||
const PHIDP_PREPARSED_DATA getReportDescriptor();
|
||||
#else
|
||||
std::vector<uint8_t> getReportDescriptor();
|
||||
#endif
|
||||
bool sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message=0);
|
||||
size_t receiveHIDReport(uint8_t* data, size_t length, HIDReportType tp, uint32_t message=0); // Prefer callback version
|
||||
virtual void receivedHIDReport(const uint8_t* /*data*/, size_t /*length*/, HIDReportType /*tp*/, uint32_t /*message*/) {}
|
||||
|
@ -20,8 +20,6 @@
|
||||
namespace boo
|
||||
{
|
||||
|
||||
static class DeviceFinder* skDevFinder = NULL;
|
||||
|
||||
class DeviceFinder
|
||||
{
|
||||
public:
|
||||
@ -31,6 +29,7 @@ public:
|
||||
static inline DeviceFinder* instance() {return skDevFinder;}
|
||||
|
||||
private:
|
||||
static class DeviceFinder* skDevFinder;
|
||||
|
||||
/* Types this finder is interested in (immutable) */
|
||||
DeviceSignature::TDeviceSignatureSet m_types;
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
void initialCycle();
|
||||
void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message);
|
||||
|
||||
void enumerateValues(std::function<bool(const HIDMainItem& item)>& valueCB) const;
|
||||
void enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,11 @@
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#if _WIN32
|
||||
#include <hidsdi.h>
|
||||
#endif
|
||||
|
||||
namespace boo
|
||||
{
|
||||
@ -157,6 +162,8 @@ struct HIDMainItem
|
||||
|
||||
HIDMainItem() = default;
|
||||
HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t reportIdx);
|
||||
HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage,
|
||||
HIDRange logicalRange, int32_t reportSize);
|
||||
const char* GetUsagePageName() const;
|
||||
const char* GetUsageName() const;
|
||||
};
|
||||
@ -171,22 +178,35 @@ public:
|
||||
Error
|
||||
};
|
||||
private:
|
||||
|
||||
ParserStatus m_status = ParserStatus::OK;
|
||||
#if _WIN32
|
||||
std::vector<HIDMainItem> m_itemPool;
|
||||
mutable std::vector<HIDP_DATA> m_dataList;
|
||||
PHIDP_PREPARSED_DATA m_descriptorData = nullptr;
|
||||
#else
|
||||
std::unique_ptr<HIDMainItem[]> m_itemPool;
|
||||
using Report = std::pair<uint32_t, std::pair<uint32_t, uint32_t>>;
|
||||
std::unique_ptr<Report[]> m_reportPool;
|
||||
std::pair<uint32_t, uint32_t> m_inputReports = {};
|
||||
std::pair<uint32_t, uint32_t> m_outputReports = {};
|
||||
std::pair<uint32_t, uint32_t> m_featureReports = {};
|
||||
ParserStatus m_status = ParserStatus::OK;
|
||||
bool m_multipleReports = false;
|
||||
ParserStatus ParseItem(HIDReports& reportsOut,
|
||||
std::stack<HIDItemState>& stateStack, std::stack<HIDCollectionItem>& collectionStack,
|
||||
std::stack<HIDItemState>& stateStack,
|
||||
std::stack<HIDCollectionItem>& collectionStack,
|
||||
const uint8_t*& it, const uint8_t* end);
|
||||
#endif
|
||||
|
||||
public:
|
||||
#if _WIN32
|
||||
ParserStatus Parse(const PHIDP_PREPARSED_DATA descriptorData);
|
||||
#else
|
||||
ParserStatus Parse(const uint8_t* descriptorData, size_t len);
|
||||
#endif
|
||||
operator bool() const { return m_status == ParserStatus::Done; }
|
||||
void EnumerateValues(std::function<bool(uint32_t rep, const HIDMainItem& item)>& valueCB) const;
|
||||
void ScanValues(std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
|
||||
void EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const;
|
||||
void ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
|
||||
const uint8_t* data, size_t len) const;
|
||||
};
|
||||
|
||||
|
@ -54,12 +54,21 @@ size_t DeviceBase::receiveUSBInterruptTransfer(uint8_t* data, size_t length)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if _WIN32
|
||||
const PHIDP_PREPARSED_DATA DeviceBase::getReportDescriptor()
|
||||
{
|
||||
if (m_hidDev)
|
||||
return m_hidDev->_getReportDescriptor();
|
||||
return {};
|
||||
}
|
||||
#else
|
||||
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)
|
||||
{
|
||||
|
@ -9,6 +9,8 @@
|
||||
namespace boo
|
||||
{
|
||||
|
||||
DeviceFinder* DeviceFinder::skDevFinder = nullptr;
|
||||
|
||||
#if _WIN32
|
||||
/* Windows-specific WM_DEVICECHANGED handler */
|
||||
LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam)
|
||||
|
@ -20,8 +20,13 @@ void GenericPad::deviceDisconnected()
|
||||
|
||||
void GenericPad::initialCycle()
|
||||
{
|
||||
#if _WIN32
|
||||
const PHIDP_PREPARSED_DATA reportDesc = getReportDescriptor();
|
||||
m_parser.Parse(reportDesc);
|
||||
#else
|
||||
std::vector<uint8_t> reportDesc = getReportDescriptor();
|
||||
m_parser.Parse(reportDesc.data(), reportDesc.size());
|
||||
#endif
|
||||
if (m_cb)
|
||||
m_cb->controllerConnected();
|
||||
}
|
||||
@ -39,11 +44,9 @@ void GenericPad::receivedHIDReport(const uint8_t* data, size_t length, HIDReport
|
||||
m_parser.ScanValues(func, data, length);
|
||||
}
|
||||
|
||||
void GenericPad::enumerateValues(std::function<bool(const HIDMainItem& item)>& valueCB) const
|
||||
void GenericPad::enumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const
|
||||
{
|
||||
std::function<bool(uint32_t, const HIDMainItem&)> func =
|
||||
[&](uint32_t rep, const HIDMainItem& item) { return valueCB(item); };
|
||||
m_parser.EnumerateValues(func);
|
||||
m_parser.EnumerateValues(valueCB);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace boo
|
||||
class HIDDeviceWinUSB final : public IHIDDevice
|
||||
{
|
||||
DeviceToken& m_token;
|
||||
DeviceBase& m_devImp;
|
||||
std::shared_ptr<DeviceBase> m_devImp;
|
||||
|
||||
HANDLE m_devHandle = 0;
|
||||
HANDLE m_hidHandle = 0;
|
||||
@ -68,7 +68,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _threadProcUSBLL(HIDDeviceWinUSB* device)
|
||||
static void _threadProcUSBLL(std::shared_ptr<HIDDeviceWinUSB> device)
|
||||
{
|
||||
unsigned i;
|
||||
char errStr[256];
|
||||
@ -87,7 +87,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||
device->m_token.getProductName().c_str(),
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
device->m_devImp->deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
return;
|
||||
@ -98,7 +98,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||
device->m_token.getProductName().c_str(),
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
device->m_devImp->deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
CloseHandle(device->m_devHandle);
|
||||
@ -112,7 +112,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||
device->m_token.getProductName().c_str(),
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
device->m_devImp->deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
CloseHandle(device->m_devHandle);
|
||||
@ -137,10 +137,10 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
device->m_initCond.notify_one();
|
||||
|
||||
/* Start transfer loop */
|
||||
device->m_devImp.initialCycle();
|
||||
device->m_devImp->initialCycle();
|
||||
while (device->m_runningTransferLoop)
|
||||
device->m_devImp.transferCycle();
|
||||
device->m_devImp.finalCycle();
|
||||
device->m_devImp->transferCycle();
|
||||
device->m_devImp->finalCycle();
|
||||
|
||||
/* Cleanup */
|
||||
WinUsb_Free(device->m_usbHandle);
|
||||
@ -148,7 +148,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
device->m_devHandle = 0;
|
||||
}
|
||||
|
||||
static void _threadProcBTLL(HIDDeviceWinUSB* device)
|
||||
static void _threadProcBTLL(std::shared_ptr<HIDDeviceWinUSB> device)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
||||
|
||||
@ -158,17 +158,19 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
device->m_initCond.notify_one();
|
||||
|
||||
/* Start transfer loop */
|
||||
device->m_devImp.initialCycle();
|
||||
device->m_devImp->initialCycle();
|
||||
while (device->m_runningTransferLoop)
|
||||
device->m_devImp.transferCycle();
|
||||
device->m_devImp.finalCycle();
|
||||
device->m_devImp->transferCycle();
|
||||
device->m_devImp->finalCycle();
|
||||
}
|
||||
|
||||
size_t m_minFeatureSz = 0;
|
||||
size_t m_minInputSz = 0;
|
||||
size_t m_minOutputSz = 0;
|
||||
|
||||
static void _threadProcHID(HIDDeviceWinUSB* device)
|
||||
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);
|
||||
@ -187,30 +189,28 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||
device->m_token.getProductName().c_str(),
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
device->m_devImp->deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
return;
|
||||
}
|
||||
|
||||
PHIDP_PREPARSED_DATA preparsedData;
|
||||
if (!HidD_GetPreparsedData(device->m_hidHandle, &preparsedData))
|
||||
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().c_str(),
|
||||
device->m_devPath.c_str(), GetLastError());
|
||||
device->m_devImp.deviceError(errStr);
|
||||
device->m_devImp->deviceError(errStr);
|
||||
lk.unlock();
|
||||
device->m_initCond.notify_one();
|
||||
return;
|
||||
}
|
||||
|
||||
HIDP_CAPS caps;
|
||||
HidP_GetCaps(preparsedData, &caps);
|
||||
HidP_GetCaps(device->m_preparsedData, &caps);
|
||||
device->m_minFeatureSz = caps.FeatureReportByteLength;
|
||||
device->m_minInputSz = caps.InputReportByteLength;
|
||||
device->m_minOutputSz = caps.OutputReportByteLength;
|
||||
HidD_FreePreparsedData(preparsedData);
|
||||
|
||||
/* Return control to main thread */
|
||||
device->m_runningTransferLoop = true;
|
||||
@ -218,21 +218,23 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
device->m_initCond.notify_one();
|
||||
|
||||
/* Allocate read buffer */
|
||||
size_t inBufferSz = std::max(device->m_minInputSz, device->m_devImp.getInputBufferSize());
|
||||
size_t inBufferSz = device->m_minInputSz;
|
||||
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[inBufferSz]);
|
||||
|
||||
/* Start transfer loop */
|
||||
device->m_devImp.initialCycle();
|
||||
device->m_devImp->initialCycle();
|
||||
while (device->m_runningTransferLoop)
|
||||
{
|
||||
device->ReadCycle(readBuf.get(), inBufferSz);
|
||||
device->m_devImp.transferCycle();
|
||||
if (device->m_runningTransferLoop)
|
||||
device->m_devImp->transferCycle();
|
||||
}
|
||||
device->m_devImp.finalCycle();
|
||||
device->m_devImp->finalCycle();
|
||||
|
||||
/* Cleanup */
|
||||
CloseHandle(device->m_overlapped.hEvent);
|
||||
CloseHandle(device->m_hidHandle);
|
||||
HidD_FreePreparsedData(device->m_preparsedData);
|
||||
device->m_hidHandle = nullptr;
|
||||
}
|
||||
|
||||
@ -244,6 +246,11 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
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));
|
||||
@ -323,7 +330,7 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
||||
|
||||
public:
|
||||
|
||||
HIDDeviceWinUSB(DeviceToken& token, DeviceBase& devImp)
|
||||
HIDDeviceWinUSB(DeviceToken& token, const std::shared_ptr<DeviceBase>& devImp)
|
||||
: m_token(token),
|
||||
m_devImp(devImp),
|
||||
m_devPath(token.getDevicePath())
|
||||
@ -335,11 +342,11 @@ public:
|
||||
std::unique_lock<std::mutex> lk(m_initMutex);
|
||||
DeviceType dType = m_token.getDeviceType();
|
||||
if (dType == DeviceType::USB)
|
||||
m_thread = std::thread(_threadProcUSBLL, this);
|
||||
m_thread = std::thread(_threadProcUSBLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
|
||||
else if (dType == DeviceType::Bluetooth)
|
||||
m_thread = std::thread(_threadProcBTLL, this);
|
||||
m_thread = std::thread(_threadProcBTLL, std::static_pointer_cast<HIDDeviceWinUSB>(shared_from_this()));
|
||||
else if (dType == DeviceType::HID)
|
||||
m_thread = std::thread(_threadProcHID, this);
|
||||
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);
|
||||
@ -348,7 +355,8 @@ public:
|
||||
~HIDDeviceWinUSB()
|
||||
{
|
||||
m_runningTransferLoop = false;
|
||||
m_thread.join();
|
||||
if (m_thread.joinable())
|
||||
m_thread.detach();
|
||||
}
|
||||
|
||||
OVERLAPPED m_overlapped = {};
|
||||
@ -362,7 +370,12 @@ public:
|
||||
if (!Result)
|
||||
{
|
||||
DWORD Error = GetLastError();
|
||||
if (Error != ERROR_IO_PENDING)
|
||||
if (Error == ERROR_DEVICE_NOT_CONNECTED)
|
||||
{
|
||||
m_runningTransferLoop = false;
|
||||
return;
|
||||
}
|
||||
else if (Error != ERROR_IO_PENDING)
|
||||
{
|
||||
fprintf(stderr, "Read Failed: %08X\n", Error);
|
||||
return;
|
||||
@ -373,7 +386,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
m_devImp.receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]);
|
||||
m_devImp->receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -135,6 +135,32 @@ class HIDListenerWinUSB final : public IHIDListener
|
||||
&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);
|
||||
|
||||
|
@ -1,5 +1,9 @@
|
||||
#include "boo/inputdev/HIDParser.hpp"
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
namespace boo
|
||||
{
|
||||
@ -289,6 +293,12 @@ HIDMainItem::HIDMainItem(uint32_t flags, const HIDItemState& state, uint32_t rep
|
||||
m_reportSize = state.m_reportSize;
|
||||
}
|
||||
|
||||
HIDMainItem::HIDMainItem(uint32_t flags, HIDUsagePage usagePage, HIDUsage usage,
|
||||
HIDRange logicalRange, int32_t reportSize)
|
||||
: m_flags(uint16_t(flags)), m_usagePage(usagePage), m_usage(usage),
|
||||
m_logicalRange(logicalRange), m_reportSize(reportSize)
|
||||
{}
|
||||
|
||||
const char* HIDMainItem::GetUsagePageName() const
|
||||
{
|
||||
if (int(m_usagePage) >= std::extent<decltype(UsagePageNames)>::value)
|
||||
@ -385,9 +395,92 @@ struct HIDReports
|
||||
void AddFeatureItem(uint32_t flags, const HIDItemState& state) { _AddItem(m_featureReports, flags, state); }
|
||||
};
|
||||
|
||||
#if _WIN32
|
||||
HIDParser::ParserStatus HIDParser::Parse(const PHIDP_PREPARSED_DATA descriptorData)
|
||||
{
|
||||
/* User mode HID report descriptor isn't available on Win32.
|
||||
* Opaque preparsed data must be enumerated and sorted into
|
||||
* iterable items.
|
||||
*
|
||||
* Wine's implementation has a good illustration of what's
|
||||
* going on here:
|
||||
* https://github.com/wine-mirror/wine/blob/master/dlls/hidclass.sys/descriptor.c
|
||||
*
|
||||
* (Thanks for this pointless pain-in-the-ass Microsoft)
|
||||
*/
|
||||
|
||||
m_descriptorData = descriptorData;
|
||||
HIDP_CAPS caps;
|
||||
HidP_GetCaps(descriptorData, &caps);
|
||||
m_dataList.resize(HidP_MaxDataListLength(HidP_Input, descriptorData));
|
||||
|
||||
std::map<uint32_t, HIDMainItem> inputItems;
|
||||
|
||||
{
|
||||
/* First enumerate buttons */
|
||||
USHORT length = caps.NumberInputButtonCaps;
|
||||
std::vector<HIDP_BUTTON_CAPS> bCaps(caps.NumberInputButtonCaps, HIDP_BUTTON_CAPS());
|
||||
HidP_GetButtonCaps(HidP_Input, bCaps.data(), &length, descriptorData);
|
||||
for (const HIDP_BUTTON_CAPS& caps : bCaps)
|
||||
{
|
||||
if (caps.IsRange)
|
||||
{
|
||||
int usage = caps.Range.UsageMin;
|
||||
for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage)
|
||||
{
|
||||
inputItems.insert(std::make_pair(i,
|
||||
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage),
|
||||
HIDUsage(usage), std::make_pair(0, 1), 1)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inputItems.insert(std::make_pair(caps.NotRange.DataIndex,
|
||||
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage),
|
||||
HIDUsage(caps.NotRange.Usage), std::make_pair(0, 1), 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
/* Now enumerate values */
|
||||
USHORT length = caps.NumberInputValueCaps;
|
||||
std::vector<HIDP_VALUE_CAPS> vCaps(caps.NumberInputValueCaps, HIDP_VALUE_CAPS());
|
||||
HidP_GetValueCaps(HidP_Input, vCaps.data(), &length, descriptorData);
|
||||
for (const HIDP_VALUE_CAPS& caps : vCaps)
|
||||
{
|
||||
if (caps.IsRange)
|
||||
{
|
||||
int usage = caps.Range.UsageMin;
|
||||
for (int i=caps.Range.DataIndexMin ; i<=caps.Range.DataIndexMax ; ++i, ++usage)
|
||||
{
|
||||
inputItems.insert(std::make_pair(i,
|
||||
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(usage),
|
||||
std::make_pair(caps.LogicalMin, caps.LogicalMax), caps.BitSize)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inputItems.insert(std::make_pair(caps.NotRange.DataIndex,
|
||||
HIDMainItem(caps.BitField, HIDUsagePage(caps.UsagePage), HIDUsage(caps.NotRange.Usage),
|
||||
HIDRange(caps.LogicalMin, caps.LogicalMax), caps.BitSize)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_itemPool.reserve(inputItems.size());
|
||||
for (const auto& item : inputItems)
|
||||
m_itemPool.push_back(item.second);
|
||||
|
||||
m_status = ParserStatus::Done;
|
||||
return ParserStatus::Done;
|
||||
}
|
||||
#else
|
||||
|
||||
HIDParser::ParserStatus
|
||||
HIDParser::ParseItem(HIDReports& reportsOut,
|
||||
std::stack<HIDItemState>& stateStack, std::stack<HIDCollectionItem>& collectionStack,
|
||||
std::stack<HIDItemState>& stateStack,
|
||||
std::stack<HIDCollectionItem>& collectionStack,
|
||||
const uint8_t*& it, const uint8_t* end)
|
||||
{
|
||||
ParserStatus status = ParserStatus::OK;
|
||||
@ -567,8 +660,24 @@ HIDParser::ParserStatus HIDParser::Parse(const uint8_t* descriptorData, size_t l
|
||||
|
||||
return m_status;
|
||||
}
|
||||
#endif
|
||||
|
||||
void HIDParser::EnumerateValues(std::function<bool(uint32_t rep, const HIDMainItem& item)>& valueCB) const
|
||||
#if _WIN32
|
||||
void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const
|
||||
{
|
||||
if (m_status != ParserStatus::Done)
|
||||
return;
|
||||
|
||||
for (const HIDMainItem& item : m_itemPool)
|
||||
{
|
||||
if (item.IsConstant())
|
||||
continue;
|
||||
if (!valueCB(item))
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void HIDParser::EnumerateValues(const std::function<bool(const HIDMainItem& item)>& valueCB) const
|
||||
{
|
||||
if (m_status != ParserStatus::Done)
|
||||
return;
|
||||
@ -579,11 +688,50 @@ void HIDParser::EnumerateValues(std::function<bool(uint32_t rep, const HIDMainIt
|
||||
for (uint32_t j=rep.second.first ; j<rep.second.second ; ++j)
|
||||
{
|
||||
const HIDMainItem& item = m_itemPool[j];
|
||||
if (!valueCB(rep.first, item))
|
||||
if (item.IsConstant())
|
||||
continue;
|
||||
if (!valueCB(item))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
|
||||
const uint8_t* data, size_t len) const
|
||||
{
|
||||
if (m_status != ParserStatus::Done)
|
||||
return;
|
||||
|
||||
ULONG dataLen = m_dataList.size();
|
||||
if (HidP_GetData(HidP_Input, m_dataList.data(), &dataLen,
|
||||
m_descriptorData, PCHAR(data), len) != HIDP_STATUS_SUCCESS)
|
||||
return;
|
||||
|
||||
int idx = 0;
|
||||
auto it = m_dataList.begin();
|
||||
auto end = m_dataList.begin() + dataLen;
|
||||
for (const HIDMainItem& item : m_itemPool)
|
||||
{
|
||||
if (item.IsConstant())
|
||||
continue;
|
||||
int32_t value = 0;
|
||||
if (it != end)
|
||||
{
|
||||
const HIDP_DATA& data = *it;
|
||||
if (data.DataIndex == idx)
|
||||
{
|
||||
value = data.RawValue;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (!valueCB(item, value))
|
||||
return;
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
class BitwiseIterator
|
||||
{
|
||||
@ -618,7 +766,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void HIDParser::ScanValues(std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
|
||||
void HIDParser::ScanValues(const std::function<bool(const HIDMainItem& item, int32_t value)>& valueCB,
|
||||
const uint8_t* data, size_t len) const
|
||||
{
|
||||
if (m_status != ParserStatus::Done)
|
||||
@ -646,11 +794,14 @@ void HIDParser::ScanValues(std::function<bool(const HIDMainItem& item, int32_t v
|
||||
int32_t val = bitIt.GetUnsignedValue(item.m_reportSize, status);
|
||||
if (status == ParserStatus::Error)
|
||||
return;
|
||||
if (item.IsConstant())
|
||||
continue;
|
||||
if (!valueCB(item, val))
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,10 @@
|
||||
#include "boo/inputdev/DeviceBase.hpp"
|
||||
#include <memory>
|
||||
|
||||
#if _WIN32
|
||||
#include <hidsdi.h>
|
||||
#endif
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
@ -15,7 +19,11 @@ class IHIDDevice : public std::enable_shared_from_this<IHIDDevice>
|
||||
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
|
||||
virtual const PHIDP_PREPARSED_DATA _getReportDescriptor()=0;
|
||||
#else
|
||||
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;
|
||||
|
@ -316,11 +316,11 @@ public:
|
||||
/* Lookup boo window instance */
|
||||
auto search = m_allWindows.find(hwnd);
|
||||
if (search == m_allWindows.end())
|
||||
return 0;
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);;
|
||||
|
||||
std::shared_ptr<IWindow> window = search->second.lock();
|
||||
if (!window)
|
||||
return 0;
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
@ -527,7 +527,7 @@ int ApplicationRun(IApplication::EPlatformType platform,
|
||||
};
|
||||
wndClass.hIcon = LoadIconW(wndClass.hInstance, MAKEINTRESOURCEW(101));
|
||||
wndClass.hCursor = WIN32_CURSORS.m_arrow;
|
||||
RegisterClassW(&wndClass);
|
||||
ATOM a = RegisterClassW(&wndClass);
|
||||
|
||||
APP = new ApplicationWin32(cb, uniqueName, friendlyName, pname, args, singleInstance);
|
||||
return APP->run();
|
||||
|
Loading…
x
Reference in New Issue
Block a user