mirror of
https://github.com/AxioDL/boo.git
synced 2025-05-14 19:31:20 +00:00
Win32 input device refinements and XInput support
This commit is contained in:
parent
aa272fe7b9
commit
ff89a9cccf
@ -65,7 +65,7 @@ if(WIN32)
|
|||||||
|
|
||||||
list(APPEND _BOO_SYS_DEFINES -DUNICODE -D_UNICODE)
|
list(APPEND _BOO_SYS_DEFINES -DUNICODE -D_UNICODE)
|
||||||
|
|
||||||
list(APPEND _BOO_SYS_LIBS Winusb opengl32 Setupapi Imm32 Winmm Shlwapi)
|
list(APPEND _BOO_SYS_LIBS Winusb opengl32 Setupapi Imm32 Winmm Shlwapi Hid Xinput)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
list(APPEND PLAT_SRCS
|
list(APPEND PLAT_SRCS
|
||||||
lib/mac/ApplicationCocoa.mm
|
lib/mac/ApplicationCocoa.mm
|
||||||
@ -214,6 +214,7 @@ add_library(boo
|
|||||||
lib/inputdev/RevolutionPad.cpp include/boo/inputdev/RevolutionPad.hpp
|
lib/inputdev/RevolutionPad.cpp include/boo/inputdev/RevolutionPad.hpp
|
||||||
lib/inputdev/DolphinSmashAdapter.cpp include/boo/inputdev/DolphinSmashAdapter.hpp
|
lib/inputdev/DolphinSmashAdapter.cpp include/boo/inputdev/DolphinSmashAdapter.hpp
|
||||||
lib/inputdev/DualshockPad.cpp include/boo/inputdev/DualshockPad.hpp
|
lib/inputdev/DualshockPad.cpp include/boo/inputdev/DualshockPad.hpp
|
||||||
|
include/boo/inputdev/XInputPad.hpp
|
||||||
lib/inputdev/GenericPad.cpp include/boo/inputdev/GenericPad.hpp
|
lib/inputdev/GenericPad.cpp include/boo/inputdev/GenericPad.hpp
|
||||||
lib/inputdev/DeviceSignature.cpp include/boo/inputdev/DeviceSignature.hpp
|
lib/inputdev/DeviceSignature.cpp include/boo/inputdev/DeviceSignature.hpp
|
||||||
lib/inputdev/DeviceFinder.cpp include/boo/inputdev/DeviceFinder.hpp
|
lib/inputdev/DeviceFinder.cpp include/boo/inputdev/DeviceFinder.hpp
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "boo/inputdev/DeviceSignature.hpp"
|
#include "boo/inputdev/DeviceSignature.hpp"
|
||||||
#include "boo/inputdev/DolphinSmashAdapter.hpp"
|
#include "boo/inputdev/DolphinSmashAdapter.hpp"
|
||||||
#include "boo/inputdev/DualshockPad.hpp"
|
#include "boo/inputdev/DualshockPad.hpp"
|
||||||
|
#include "boo/inputdev/XInputPad.hpp"
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
@ -9,6 +10,7 @@ const DeviceSignature BOO_DEVICE_SIGS[] =
|
|||||||
{
|
{
|
||||||
DEVICE_SIG(DolphinSmashAdapter, 0x57e, 0x337, DeviceType::USB),
|
DEVICE_SIG(DolphinSmashAdapter, 0x57e, 0x337, DeviceType::USB),
|
||||||
DEVICE_SIG(DualshockPad, 0x54c, 0x268, DeviceType::HID),
|
DEVICE_SIG(DualshockPad, 0x54c, 0x268, DeviceType::HID),
|
||||||
|
DEVICE_SIG(XInputPad, 0, 0, DeviceType::XInput),
|
||||||
DEVICE_SIG_SENTINEL()
|
DEVICE_SIG_SENTINEL()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ private:
|
|||||||
|
|
||||||
/* Platform-specific USB event registration
|
/* Platform-specific USB event registration
|
||||||
* (for auto-scanning, NULL if not registered) */
|
* (for auto-scanning, NULL if not registered) */
|
||||||
IHIDListener* m_listener;
|
std::unique_ptr<IHIDListener> m_listener;
|
||||||
|
|
||||||
/* Set of presently-connected device tokens */
|
/* Set of presently-connected device tokens */
|
||||||
TDeviceTokens m_tokens;
|
TDeviceTokens m_tokens;
|
||||||
@ -95,7 +95,6 @@ public:
|
|||||||
|
|
||||||
/* Application must specify its interested device-types */
|
/* Application must specify its interested device-types */
|
||||||
DeviceFinder(std::unordered_set<std::type_index> types)
|
DeviceFinder(std::unordered_set<std::type_index> types)
|
||||||
: m_listener(NULL)
|
|
||||||
{
|
{
|
||||||
if (skDevFinder)
|
if (skDevFinder)
|
||||||
{
|
{
|
||||||
@ -118,7 +117,6 @@ public:
|
|||||||
{
|
{
|
||||||
if (m_listener)
|
if (m_listener)
|
||||||
m_listener->stopScanning();
|
m_listener->stopScanning();
|
||||||
delete m_listener;
|
|
||||||
skDevFinder = NULL;
|
skDevFinder = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
@ -13,7 +14,8 @@ enum class DeviceType
|
|||||||
None = 0,
|
None = 0,
|
||||||
USB = 1,
|
USB = 1,
|
||||||
Bluetooth = 2,
|
Bluetooth = 2,
|
||||||
HID = 3
|
HID = 3,
|
||||||
|
XInput = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeviceToken;
|
class DeviceToken;
|
||||||
|
@ -11,6 +11,7 @@ namespace boo
|
|||||||
class DeviceToken
|
class DeviceToken
|
||||||
{
|
{
|
||||||
friend struct DeviceSignature;
|
friend struct DeviceSignature;
|
||||||
|
friend class HIDListenerWinUSB;
|
||||||
DeviceType m_devType;
|
DeviceType m_devType;
|
||||||
unsigned m_vendorId;
|
unsigned m_vendorId;
|
||||||
unsigned m_productId;
|
unsigned m_productId;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "DeviceBase.hpp"
|
#include "DeviceBase.hpp"
|
||||||
#include "../System.hpp"
|
#include "boo/System.hpp"
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
@ -117,9 +117,8 @@ struct DualshockPadState
|
|||||||
class DualshockPad;
|
class DualshockPad;
|
||||||
struct IDualshockPadCallback
|
struct IDualshockPadCallback
|
||||||
{
|
{
|
||||||
DualshockPad* ctrl = nullptr;
|
|
||||||
virtual void controllerDisconnected() {}
|
virtual void controllerDisconnected() {}
|
||||||
virtual void controllerUpdate(const DualshockPadState&) {}
|
virtual void controllerUpdate(DualshockPad&, const DualshockPadState&) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DualshockPad final : public DeviceBase
|
class DualshockPad final : public DeviceBase
|
||||||
@ -141,8 +140,7 @@ public:
|
|||||||
DualshockPad(DeviceToken* token);
|
DualshockPad(DeviceToken* token);
|
||||||
~DualshockPad();
|
~DualshockPad();
|
||||||
|
|
||||||
void setCallback(IDualshockPadCallback* cb)
|
void setCallback(IDualshockPadCallback* cb) { m_callback = cb; }
|
||||||
{ m_callback = cb; if (m_callback) m_callback->ctrl = this; }
|
|
||||||
|
|
||||||
void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity=255)
|
void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity=255)
|
||||||
{
|
{
|
||||||
@ -159,9 +157,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopRumble(int motor)
|
void stopRumble(EDualshockMotor motor)
|
||||||
{
|
{
|
||||||
m_rumbleRequest &= ~EDualshockMotor(motor);
|
m_rumbleRequest &= ~motor;
|
||||||
}
|
}
|
||||||
|
|
||||||
EDualshockLED getLED()
|
EDualshockLED getLED()
|
||||||
|
@ -33,7 +33,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Platform-specific constructor */
|
/* Platform-specific constructor */
|
||||||
IHIDListener* IHIDListenerNew(DeviceFinder& finder);
|
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
include/boo/inputdev/XInputPad.hpp
Normal file
68
include/boo/inputdev/XInputPad.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#ifndef XINPUTPAD_HPP
|
||||||
|
#define XINPUTPAD_HPP
|
||||||
|
|
||||||
|
#include "DeviceBase.hpp"
|
||||||
|
#include "boo/System.hpp"
|
||||||
|
|
||||||
|
namespace boo
|
||||||
|
{
|
||||||
|
|
||||||
|
struct XInputPadState
|
||||||
|
{
|
||||||
|
uint16_t wButtons;
|
||||||
|
uint8_t bLeftTrigger;
|
||||||
|
uint8_t bRightTrigger;
|
||||||
|
int16_t sThumbLX;
|
||||||
|
int16_t sThumbLY;
|
||||||
|
int16_t sThumbRX;
|
||||||
|
int16_t sThumbRY;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class EXInputMotor : uint8_t
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Right = 1<<0,
|
||||||
|
Left = 1<<1,
|
||||||
|
};
|
||||||
|
ENABLE_BITWISE_ENUM(EXInputMotor)
|
||||||
|
|
||||||
|
class XInputPad;
|
||||||
|
struct IXInputPadCallback
|
||||||
|
{
|
||||||
|
virtual void controllerDisconnected() {}
|
||||||
|
virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class XInputPad final : public DeviceBase
|
||||||
|
{
|
||||||
|
friend class HIDListenerWinUSB;
|
||||||
|
IXInputPadCallback* m_callback;
|
||||||
|
uint16_t m_rumbleRequest[2] = {};
|
||||||
|
uint16_t m_rumbleState[2] = {};
|
||||||
|
public:
|
||||||
|
XInputPad(DeviceToken* token) : DeviceBase(token) {}
|
||||||
|
void setCallback(IXInputPadCallback* cb) { m_callback = cb; }
|
||||||
|
void deviceDisconnected()
|
||||||
|
{
|
||||||
|
if (m_callback)
|
||||||
|
m_callback->controllerDisconnected();
|
||||||
|
}
|
||||||
|
void startRumble(EXInputMotor motors, uint16_t intensity)
|
||||||
|
{
|
||||||
|
if ((motors & EXInputMotor::Left) != EXInputMotor::None)
|
||||||
|
m_rumbleRequest[0] = intensity;
|
||||||
|
if ((motors & EXInputMotor::Right) != EXInputMotor::None)
|
||||||
|
m_rumbleRequest[1] = intensity;
|
||||||
|
}
|
||||||
|
void stopRumble(EXInputMotor motors)
|
||||||
|
{
|
||||||
|
if ((motors & EXInputMotor::Left) != EXInputMotor::None)
|
||||||
|
m_rumbleRequest[0] = 0;
|
||||||
|
if ((motors & EXInputMotor::Right) != EXInputMotor::None)
|
||||||
|
m_rumbleRequest[1] = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // XINPUTPAD_HPP
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#if _WIN32
|
#if _WIN32
|
||||||
#include <Dbt.h>
|
#include <Dbt.h>
|
||||||
|
#include <hidclass.h>
|
||||||
|
#include <usbiodef.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
@ -21,26 +23,44 @@ LRESULT DeviceFinder::winDevChangedHandler(WPARAM wParam, LPARAM lParam)
|
|||||||
{
|
{
|
||||||
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
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
|
#ifdef UNICODE
|
||||||
char devPath[1024];
|
char devPath[1024];
|
||||||
wcstombs(devPath, dbhi->dbcc_name, 1024);
|
wcstombs(devPath, dbhi->dbcc_name, 1024);
|
||||||
finder->m_listener->_extDevConnect(devPath);
|
finder->m_listener->_extDevConnect(devPath);
|
||||||
#else
|
#else
|
||||||
finder->m_listener->_extDevConnect(dbhi->dbcc_name);
|
finder->m_listener->_extDevConnect(dbhi->dbcc_name);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
|
else if (wParam == DBT_DEVICEREMOVECOMPLETE)
|
||||||
{
|
{
|
||||||
if (dbh->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE)
|
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
|
#ifdef UNICODE
|
||||||
char devPath[1024];
|
char devPath[1024];
|
||||||
wcstombs(devPath, dbhi->dbcc_name, 1024);
|
wcstombs(devPath, dbhi->dbcc_name, 1024);
|
||||||
finder->m_listener->_extDevDisconnect(devPath);
|
finder->m_listener->_extDevDisconnect(devPath);
|
||||||
#else
|
#else
|
||||||
finder->m_listener->_extDevDisconnect(dbhi->dbcc_name);
|
finder->m_listener->_extDevDisconnect(dbhi->dbcc_name);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDRepo
|
|||||||
|
|
||||||
state.m_gyrometerZ = bswap16(state.m_gyrometerZ);
|
state.m_gyrometerZ = bswap16(state.m_gyrometerZ);
|
||||||
if (m_callback)
|
if (m_callback)
|
||||||
m_callback->controllerUpdate(state);
|
m_callback->controllerUpdate(*this, state);
|
||||||
|
|
||||||
if (m_rumbleRequest != m_rumbleState)
|
if (m_rumbleRequest != m_rumbleState)
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
#define WIN32_LEAN_AND_MEAN 1
|
#define WIN32_LEAN_AND_MEAN 1
|
||||||
@ -15,6 +16,10 @@
|
|||||||
#include <winusb.h>
|
#include <winusb.h>
|
||||||
#include <usb100.h>
|
#include <usb100.h>
|
||||||
#include <Winusbio.h>
|
#include <Winusbio.h>
|
||||||
|
#include <hidsdi.h>
|
||||||
|
|
||||||
|
#undef min
|
||||||
|
#undef max
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
@ -25,7 +30,8 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
|||||||
DeviceBase& m_devImp;
|
DeviceBase& m_devImp;
|
||||||
|
|
||||||
HANDLE m_devHandle = 0;
|
HANDLE m_devHandle = 0;
|
||||||
WINUSB_INTERFACE_HANDLE m_usbHandle = NULL;
|
HANDLE m_hidHandle = 0;
|
||||||
|
WINUSB_INTERFACE_HANDLE m_usbHandle = nullptr;
|
||||||
unsigned m_usbIntfInPipe = 0;
|
unsigned m_usbIntfInPipe = 0;
|
||||||
unsigned m_usbIntfOutPipe = 0;
|
unsigned m_usbIntfOutPipe = 0;
|
||||||
bool m_runningTransferLoop = false;
|
bool m_runningTransferLoop = false;
|
||||||
@ -140,7 +146,6 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
|||||||
WinUsb_Free(device->m_usbHandle);
|
WinUsb_Free(device->m_usbHandle);
|
||||||
CloseHandle(device->m_devHandle);
|
CloseHandle(device->m_devHandle);
|
||||||
device->m_devHandle = 0;
|
device->m_devHandle = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _threadProcBTLL(HIDDeviceWinUSB* device)
|
static void _threadProcBTLL(HIDDeviceWinUSB* device)
|
||||||
@ -157,24 +162,76 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
|||||||
while (device->m_runningTransferLoop)
|
while (device->m_runningTransferLoop)
|
||||||
device->m_devImp.transferCycle();
|
device->m_devImp.transferCycle();
|
||||||
device->m_devImp.finalCycle();
|
device->m_devImp.finalCycle();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t m_minFeatureSz = 0;
|
||||||
|
size_t m_minInputSz = 0;
|
||||||
|
size_t m_minOutputSz = 0;
|
||||||
|
|
||||||
static void _threadProcHID(HIDDeviceWinUSB* device)
|
static void _threadProcHID(HIDDeviceWinUSB* device)
|
||||||
{
|
{
|
||||||
|
char errStr[256];
|
||||||
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
std::unique_lock<std::mutex> lk(device->m_initMutex);
|
||||||
|
|
||||||
|
/* POSIX.. who needs it?? -MS */
|
||||||
|
device->m_hidHandle = CreateFileA(device->m_devPath.c_str(),
|
||||||
|
GENERIC_WRITE | GENERIC_READ,
|
||||||
|
FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||||||
|
NULL,
|
||||||
|
OPEN_EXISTING,
|
||||||
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
|
||||||
|
NULL);
|
||||||
|
if (INVALID_HANDLE_VALUE == device->m_hidHandle)
|
||||||
|
{
|
||||||
|
_snprintf(errStr, 256, "Unable to open %s@%s: %d\n",
|
||||||
|
device->m_token.getProductName().c_str(),
|
||||||
|
device->m_devPath.c_str(), GetLastError());
|
||||||
|
device->m_devImp.deviceError(errStr);
|
||||||
|
lk.unlock();
|
||||||
|
device->m_initCond.notify_one();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PHIDP_PREPARSED_DATA preparsedData;
|
||||||
|
if (!HidD_GetPreparsedData(device->m_hidHandle, &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);
|
||||||
|
lk.unlock();
|
||||||
|
device->m_initCond.notify_one();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HIDP_CAPS caps;
|
||||||
|
HidP_GetCaps(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 */
|
/* Return control to main thread */
|
||||||
device->m_runningTransferLoop = true;
|
device->m_runningTransferLoop = true;
|
||||||
lk.unlock();
|
lk.unlock();
|
||||||
device->m_initCond.notify_one();
|
device->m_initCond.notify_one();
|
||||||
|
|
||||||
|
/* Allocate read buffer */
|
||||||
|
size_t inBufferSz = std::max(device->m_minInputSz, device->m_devImp.getInputBufferSize());
|
||||||
|
std::unique_ptr<uint8_t[]> readBuf(new uint8_t[inBufferSz]);
|
||||||
|
|
||||||
/* Start transfer loop */
|
/* Start transfer loop */
|
||||||
device->m_devImp.initialCycle();
|
device->m_devImp.initialCycle();
|
||||||
while (device->m_runningTransferLoop)
|
while (device->m_runningTransferLoop)
|
||||||
|
{
|
||||||
|
device->ReadCycle(readBuf.get(), inBufferSz);
|
||||||
device->m_devImp.transferCycle();
|
device->m_devImp.transferCycle();
|
||||||
|
}
|
||||||
device->m_devImp.finalCycle();
|
device->m_devImp.finalCycle();
|
||||||
|
|
||||||
|
/* Cleanup */
|
||||||
|
CloseHandle(device->m_hidHandle);
|
||||||
|
device->m_hidHandle = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _deviceDisconnected()
|
void _deviceDisconnected()
|
||||||
@ -182,9 +239,84 @@ class HIDDeviceWinUSB final : public IHIDDevice
|
|||||||
m_runningTransferLoop = false;
|
m_runningTransferLoop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _sendHIDReport(const uint8_t* data, size_t length, uint16_t message)
|
std::vector<uint8_t> m_sendBuf;
|
||||||
|
std::vector<uint8_t> m_recvBuf;
|
||||||
|
|
||||||
|
bool _sendHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message)
|
||||||
{
|
{
|
||||||
return false;
|
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", Error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetOverlappedResult(m_hidHandle, &Overlapped, &BytesWritten, TRUE))
|
||||||
|
{
|
||||||
|
DWORD Error = GetLastError();
|
||||||
|
fprintf(stderr, "Write Failed %08X\n", 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -194,14 +326,13 @@ public:
|
|||||||
m_devImp(devImp),
|
m_devImp(devImp),
|
||||||
m_devPath(token.getDevicePath())
|
m_devPath(token.getDevicePath())
|
||||||
{
|
{
|
||||||
devImp.m_hidDev = this;
|
|
||||||
std::unique_lock<std::mutex> lk(m_initMutex);
|
std::unique_lock<std::mutex> lk(m_initMutex);
|
||||||
DeviceToken::DeviceType dType = token.getDeviceType();
|
DeviceType dType = token.getDeviceType();
|
||||||
if (dType == DeviceToken::DeviceType::USB)
|
if (dType == DeviceType::USB)
|
||||||
m_thread = std::thread(_threadProcUSBLL, this);
|
m_thread = std::thread(_threadProcUSBLL, this);
|
||||||
else if (dType == DeviceToken::DeviceType::Bluetooth)
|
else if (dType == DeviceType::Bluetooth)
|
||||||
m_thread = std::thread(_threadProcBTLL, this);
|
m_thread = std::thread(_threadProcBTLL, this);
|
||||||
else if (dType == DeviceToken::DeviceType::GenericHID)
|
else if (dType == DeviceType::HID)
|
||||||
m_thread = std::thread(_threadProcHID, this);
|
m_thread = std::thread(_threadProcHID, this);
|
||||||
else
|
else
|
||||||
throw std::runtime_error("invalid token supplied to device constructor");
|
throw std::runtime_error("invalid token supplied to device constructor");
|
||||||
@ -214,12 +345,55 @@ public:
|
|||||||
m_thread.join();
|
m_thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OVERLAPPED m_overlapped = {};
|
||||||
|
|
||||||
|
void ReadCycle(uint8_t* inBuffer, size_t inBufferSz)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
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_IO_PENDING)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Read Failed: %08X\n", Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!GetOverlappedResult(m_hidHandle, &m_overlapped, &BytesRead, TRUE))
|
||||||
|
{
|
||||||
|
Error = GetLastError();
|
||||||
|
if (Error == ERROR_IO_INCOMPLETE)
|
||||||
|
return;
|
||||||
|
fprintf(stderr, "Read Failed: %08X\n", Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_overlapped.Internal == STATUS_PENDING)
|
||||||
|
{
|
||||||
|
//std::cout << "Read Interrupted" << std::endl;
|
||||||
|
if(!CancelIo(m_hidHandle))
|
||||||
|
{
|
||||||
|
Error = GetLastError();
|
||||||
|
fprintf(stderr, "Cancel IO Failed: %08X\n", Error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_devImp.receivedHIDReport(inBuffer, BytesRead, HIDReportType::Input, inBuffer[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
IHIDDevice* IHIDDeviceNew(DeviceToken& token, DeviceBase& devImp)
|
std::unique_ptr<IHIDDevice> IHIDDeviceNew(DeviceToken& token, DeviceBase& devImp)
|
||||||
{
|
{
|
||||||
return new HIDDeviceWinUSB(token, devImp);
|
return std::make_unique<HIDDeviceWinUSB>(token, devImp);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -329,9 +329,9 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IHIDListener* IHIDListenerNew(DeviceFinder& finder)
|
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
|
||||||
{
|
{
|
||||||
return new HIDListenerIOKit(finder);
|
return std::make_unique<HIDListenerIOKit>(finder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
|
#define _CRT_SECURE_NO_WARNINGS 1 /* STFU MSVC */
|
||||||
#include "boo/inputdev/IHIDListener.hpp"
|
#include "boo/inputdev/IHIDListener.hpp"
|
||||||
#include "boo/inputdev/DeviceFinder.hpp"
|
#include "boo/inputdev/DeviceFinder.hpp"
|
||||||
|
#include "boo/inputdev/XInputPad.hpp"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@ -14,6 +15,8 @@
|
|||||||
#include <Cfgmgr32.h>
|
#include <Cfgmgr32.h>
|
||||||
#include <Usbiodef.h>
|
#include <Usbiodef.h>
|
||||||
#include <Devpkey.h>
|
#include <Devpkey.h>
|
||||||
|
#include <hidclass.h>
|
||||||
|
#include <Xinput.h>
|
||||||
|
|
||||||
namespace boo
|
namespace boo
|
||||||
{
|
{
|
||||||
@ -28,9 +31,8 @@ class HIDListenerWinUSB final : public IHIDListener
|
|||||||
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
|
* Reference: https://github.com/pbatard/libwdi/blob/master/libwdi/libwdi.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void _pollDevices(const char* pathFilter)
|
void _enumerate(DeviceType type, CONST GUID* TypeGUID, const char* pathFilter)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* Don't ask */
|
/* Don't ask */
|
||||||
static const LPCSTR arPrefix[3] = {"VID_", "PID_", "MI_"};
|
static const LPCSTR arPrefix[3] = {"VID_", "PID_", "MI_"};
|
||||||
unsigned i, j;
|
unsigned i, j;
|
||||||
@ -51,17 +53,16 @@ class HIDListenerWinUSB final : public IHIDListener
|
|||||||
LPSTR pszToken, pszNextToken;
|
LPSTR pszToken, pszNextToken;
|
||||||
CHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN];
|
CHAR szVid[MAX_DEVICE_ID_LEN], szPid[MAX_DEVICE_ID_LEN], szMi[MAX_DEVICE_ID_LEN];
|
||||||
|
|
||||||
/* List all connected USB devices */
|
/* List all connected HID devices */
|
||||||
hDevInfo = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
|
hDevInfo = SetupDiGetClassDevs(NULL, 0, 0, DIGCF_PRESENT | DIGCF_ALLCLASSES | DIGCF_DEVICEINTERFACE);
|
||||||
if (hDevInfo == INVALID_HANDLE_VALUE)
|
if (hDevInfo == INVALID_HANDLE_VALUE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (i=0 ; ; ++i)
|
for (i=0 ; ; ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!SetupDiEnumDeviceInterfaces(hDevInfo,
|
if (!SetupDiEnumDeviceInterfaces(hDevInfo,
|
||||||
NULL,
|
NULL,
|
||||||
&GUID_DEVINTERFACE_USB_DEVICE,
|
TypeGUID,
|
||||||
i,
|
i,
|
||||||
&DeviceInterfaceData))
|
&DeviceInterfaceData))
|
||||||
break;
|
break;
|
||||||
@ -75,7 +76,7 @@ class HIDListenerWinUSB final : public IHIDListener
|
|||||||
&DeviceInfoData))
|
&DeviceInfoData))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = CM_Get_Device_IDA(DeviceInfoData.DevInst, szDeviceInstanceID , MAX_PATH, 0);
|
r = CM_Get_Device_IDA(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0);
|
||||||
if (r != CR_SUCCESS)
|
if (r != CR_SUCCESS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -115,8 +116,8 @@ class HIDListenerWinUSB final : public IHIDListener
|
|||||||
unsigned vid = strtol(szVid+4, NULL, 16);
|
unsigned vid = strtol(szVid+4, NULL, 16);
|
||||||
unsigned pid = strtol(szPid+4, NULL, 16);
|
unsigned pid = strtol(szPid+4, NULL, 16);
|
||||||
|
|
||||||
WCHAR productW[1024] = {0};
|
CHAR productW[1024] = {0};
|
||||||
CHAR product[1024] = {0};
|
//CHAR product[1024] = {0};
|
||||||
DWORD productSz = 0;
|
DWORD productSz = 0;
|
||||||
if (!SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
|
if (!SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc,
|
||||||
&devpropType, (BYTE*)productW, 1024, &productSz, 0)) {
|
&devpropType, (BYTE*)productW, 1024, &productSz, 0)) {
|
||||||
@ -124,14 +125,15 @@ class HIDListenerWinUSB final : public IHIDListener
|
|||||||
SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC,
|
SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData, SPDRP_DEVICEDESC,
|
||||||
®_type, (BYTE*)productW, 1024, &productSz);
|
®_type, (BYTE*)productW, 1024, &productSz);
|
||||||
}
|
}
|
||||||
wcstombs(product, productW, productSz / 2);
|
/* 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 */
|
WCHAR manufW[1024] = L"Someone"; /* Windows Vista and earlier will use this as the vendor */
|
||||||
CHAR manuf[1024] = {0};
|
CHAR manuf[1024] = {0};
|
||||||
DWORD manufSz = 0;
|
DWORD manufSz = 0;
|
||||||
SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer,
|
SetupDiGetDevicePropertyW(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_Manufacturer,
|
||||||
&devpropType, (BYTE*)manufW, 1024, &manufSz, 0);
|
&devpropType, (BYTE*)manufW, 1024, &manufSz, 0);
|
||||||
wcstombs(manuf, manufW, manufSz / 2);
|
WideCharToMultiByte(CP_UTF8, 0, manufW, -1, manuf, 1024, nullptr, nullptr);
|
||||||
|
|
||||||
/* Store as a shouting string (to keep hash-lookups consistent) */
|
/* Store as a shouting string (to keep hash-lookups consistent) */
|
||||||
CharUpperA(DeviceInterfaceDetailData.wtf.DevicePath);
|
CharUpperA(DeviceInterfaceDetailData.wtf.DevicePath);
|
||||||
@ -140,16 +142,86 @@ class HIDListenerWinUSB final : public IHIDListener
|
|||||||
if (pathFilter && strcmp(pathFilter, DeviceInterfaceDetailData.wtf.DevicePath))
|
if (pathFilter && strcmp(pathFilter, DeviceInterfaceDetailData.wtf.DevicePath))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Whew!! that's a single device enumerated!! */
|
if (!m_scanningEnabled || m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
|
||||||
if (!m_finder._hasToken(DeviceInterfaceDetailData.wtf.DevicePath))
|
continue;
|
||||||
m_finder._insertToken(DeviceToken(DeviceToken::DeviceType::USB,
|
|
||||||
vid, pid, manuf, product,
|
|
||||||
DeviceInterfaceDetailData.wtf.DevicePath));
|
|
||||||
|
|
||||||
|
/* Whew!! that's a single device enumerated!! */
|
||||||
|
m_finder._insertToken(std::make_unique<DeviceToken>(
|
||||||
|
type, vid, pid, manuf, productW,
|
||||||
|
DeviceInterfaceDetailData.wtf.DevicePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
SetupDiDestroyDeviceInfoList(hDevInfo);
|
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);
|
||||||
|
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:
|
public:
|
||||||
@ -157,11 +229,25 @@ public:
|
|||||||
: m_finder(finder)
|
: m_finder(finder)
|
||||||
{
|
{
|
||||||
/* Initial HID Device Add */
|
/* Initial HID Device Add */
|
||||||
_pollDevices(NULL);
|
_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~HIDListenerWinUSB()
|
~HIDListenerWinUSB()
|
||||||
{}
|
{
|
||||||
|
m_xinputRunning = false;
|
||||||
|
if (m_xinputThread.joinable())
|
||||||
|
m_xinputThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
/* Automatic device scanning */
|
/* Automatic device scanning */
|
||||||
bool startScanning()
|
bool startScanning()
|
||||||
@ -178,7 +264,7 @@ public:
|
|||||||
/* Manual device scanning */
|
/* Manual device scanning */
|
||||||
bool scanNow()
|
bool scanNow()
|
||||||
{
|
{
|
||||||
_pollDevices(NULL);
|
_pollDevices(nullptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,12 +286,11 @@ public:
|
|||||||
m_finder._removeToken(upperPath);
|
m_finder._removeToken(upperPath);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
IHIDListener* IHIDListenerNew(DeviceFinder& finder)
|
std::unique_ptr<IHIDListener> IHIDListenerNew(DeviceFinder& finder)
|
||||||
{
|
{
|
||||||
return new HIDListenerWinUSB(finder);
|
return std::make_unique<HIDListenerWinUSB>(finder);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -528,7 +528,7 @@ static const DEV_BROADCAST_DEVICEINTERFACE HOTPLUG_CONF =
|
|||||||
sizeof(DEV_BROADCAST_DEVICEINTERFACE),
|
sizeof(DEV_BROADCAST_DEVICEINTERFACE),
|
||||||
DBT_DEVTYP_DEVICEINTERFACE,
|
DBT_DEVTYP_DEVICEINTERFACE,
|
||||||
0,
|
0,
|
||||||
GUID_DEVINTERFACE_USB_DEVICE
|
0
|
||||||
};
|
};
|
||||||
static bool HOTPLUG_REGISTERED = false;
|
static bool HOTPLUG_REGISTERED = false;
|
||||||
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
@ -536,7 +536,8 @@ static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM l
|
|||||||
if (!HOTPLUG_REGISTERED && uMsg == WM_CREATE)
|
if (!HOTPLUG_REGISTERED && uMsg == WM_CREATE)
|
||||||
{
|
{
|
||||||
/* Register hotplug notification with windows */
|
/* Register hotplug notification with windows */
|
||||||
RegisterDeviceNotification(hwnd, (LPVOID)&HOTPLUG_CONF, DEVICE_NOTIFY_WINDOW_HANDLE);
|
RegisterDeviceNotification(hwnd, (LPVOID)&HOTPLUG_CONF,
|
||||||
|
DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
|
||||||
HOTPLUG_REGISTERED = true;
|
HOTPLUG_REGISTERED = true;
|
||||||
}
|
}
|
||||||
return static_cast<boo::ApplicationWin32*>(boo::APP)->winHwndHandler(hwnd, uMsg, wParam, lParam);
|
return static_cast<boo::ApplicationWin32*>(boo::APP)->winHwndHandler(hwnd, uMsg, wParam, lParam);
|
||||||
|
@ -38,7 +38,7 @@ class DualshockPadCallback : public IDualshockPadCallback
|
|||||||
{
|
{
|
||||||
printf("CONTROLLER DISCONNECTED\n");
|
printf("CONTROLLER DISCONNECTED\n");
|
||||||
}
|
}
|
||||||
void controllerUpdate(const DualshockPadState& state)
|
void controllerUpdate(DualshockPad& pad, const DualshockPadState& state)
|
||||||
{
|
{
|
||||||
static time_t timeTotal;
|
static time_t timeTotal;
|
||||||
static time_t lastTime = 0;
|
static time_t lastTime = 0;
|
||||||
@ -59,8 +59,8 @@ class DualshockPadCallback : public IDualshockPadCallback
|
|||||||
{
|
{
|
||||||
if (timeDif >= 1) // wait 30 seconds before issuing another rumble event
|
if (timeDif >= 1) // wait 30 seconds before issuing another rumble event
|
||||||
{
|
{
|
||||||
ctrl->startRumble(EDualshockMotor::Left);
|
pad.startRumble(EDualshockMotor::Left);
|
||||||
ctrl->startRumble(EDualshockMotor::Right, 100);
|
pad.startRumble(EDualshockMotor::Right, 100);
|
||||||
lastTime = timeTotal;
|
lastTime = timeTotal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user