mirror of https://github.com/AxioDL/boo.git
macOS IOKit interface fixes; callback-change mutex for controllers
This commit is contained in:
parent
cb99c05284
commit
e0aa15610b
|
@ -6,6 +6,7 @@
|
|||
#include <stdio.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include "boo/System.hpp"
|
||||
|
||||
#if _WIN32
|
||||
|
@ -33,10 +34,10 @@ class DeviceBase : public std::enable_shared_from_this<DeviceBase>
|
|||
class DeviceToken* m_token;
|
||||
std::shared_ptr<IHIDDevice> m_hidDev;
|
||||
void _deviceDisconnected();
|
||||
|
||||
|
||||
public:
|
||||
DeviceBase(DeviceToken* token);
|
||||
virtual ~DeviceBase();
|
||||
virtual ~DeviceBase() = default;
|
||||
void closeDevice();
|
||||
|
||||
/* Callbacks */
|
||||
|
@ -63,6 +64,21 @@ public:
|
|||
virtual void receivedHIDReport(const uint8_t* /*data*/, size_t /*length*/, HIDReportType /*tp*/, uint32_t /*message*/) {}
|
||||
};
|
||||
|
||||
template <class CB>
|
||||
class TDeviceBase : public DeviceBase
|
||||
{
|
||||
protected:
|
||||
std::mutex m_callbackLock;
|
||||
CB* m_callback = nullptr;
|
||||
public:
|
||||
TDeviceBase(DeviceToken* token) : DeviceBase(token) {}
|
||||
void setCallback(CB* cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
m_callback = cb;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CDEVICEBASE
|
||||
|
|
|
@ -112,7 +112,7 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
~DeviceFinder()
|
||||
virtual ~DeviceFinder()
|
||||
{
|
||||
if (m_listener)
|
||||
m_listener->stopScanning();
|
||||
|
|
|
@ -60,9 +60,10 @@ struct IDolphinSmashAdapterCallback
|
|||
const DolphinControllerState& state) {(void)idx;(void)type;(void)state;}
|
||||
};
|
||||
|
||||
class DolphinSmashAdapter final : public DeviceBase
|
||||
class DolphinSmashAdapter final : public TDeviceBase<IDolphinSmashAdapterCallback>
|
||||
{
|
||||
IDolphinSmashAdapterCallback* m_callback = nullptr;
|
||||
int16_t m_leftStickCal[2] = {0x7f};
|
||||
int16_t m_rightStickCal[2] = {0x7f};
|
||||
uint8_t m_knownControllers = 0;
|
||||
uint8_t m_rumbleRequest = 0;
|
||||
bool m_hardStop[4] = {false};
|
||||
|
@ -76,7 +77,10 @@ public:
|
|||
~DolphinSmashAdapter();
|
||||
|
||||
void setCallback(IDolphinSmashAdapterCallback* cb)
|
||||
{m_callback = cb; m_knownControllers = 0;}
|
||||
{
|
||||
TDeviceBase<IDolphinSmashAdapterCallback>::setCallback(cb);
|
||||
m_knownControllers = 0;
|
||||
}
|
||||
void startRumble(unsigned idx)
|
||||
{if (idx >= 4) return; m_rumbleRequest |= 1<<idx;}
|
||||
void stopRumble(unsigned idx, bool hard=false)
|
||||
|
|
|
@ -122,9 +122,8 @@ struct IDualshockPadCallback
|
|||
virtual void controllerUpdate(DualshockPad&, const DualshockPadState&) {}
|
||||
};
|
||||
|
||||
class DualshockPad final : public DeviceBase
|
||||
class DualshockPad final : public TDeviceBase<IDualshockPadCallback>
|
||||
{
|
||||
IDualshockPadCallback* m_callback;
|
||||
EDualshockMotor m_rumbleRequest;
|
||||
EDualshockMotor m_rumbleState;
|
||||
uint8_t m_rumbleDuration[2];
|
||||
|
@ -140,8 +139,6 @@ public:
|
|||
DualshockPad(DeviceToken* token);
|
||||
~DualshockPad();
|
||||
|
||||
void setCallback(IDualshockPadCallback* cb) { m_callback = cb; }
|
||||
|
||||
void startRumble(EDualshockMotor motor, uint8_t duration = 254, uint8_t intensity=255)
|
||||
{
|
||||
m_rumbleRequest |= motor;
|
||||
|
|
|
@ -16,15 +16,13 @@ struct IGenericPadCallback
|
|||
virtual void valueUpdate(const HIDMainItem& item, int32_t value) {}
|
||||
};
|
||||
|
||||
class GenericPad final : public DeviceBase
|
||||
class GenericPad final : public TDeviceBase<IGenericPadCallback>
|
||||
{
|
||||
HIDParser m_parser;
|
||||
IGenericPadCallback* m_cb = nullptr;
|
||||
public:
|
||||
GenericPad(DeviceToken* token);
|
||||
~GenericPad();
|
||||
|
||||
void setCallback(IGenericPadCallback* cb) { m_cb = cb; }
|
||||
void deviceDisconnected();
|
||||
void initialCycle();
|
||||
void receivedHIDReport(const uint8_t* data, size_t length, HIDReportType tp, uint32_t message);
|
||||
|
|
|
@ -37,9 +37,8 @@ struct INintendoPowerACallback
|
|||
virtual void controllerUpdate(const NintendoPowerAState& state) {}
|
||||
};
|
||||
|
||||
class NintendoPowerA final : public DeviceBase
|
||||
class NintendoPowerA final : public TDeviceBase<INintendoPowerACallback>
|
||||
{
|
||||
INintendoPowerACallback* m_callback = nullptr;
|
||||
NintendoPowerAState m_last;
|
||||
void deviceDisconnected();
|
||||
void initialCycle();
|
||||
|
@ -49,8 +48,6 @@ class NintendoPowerA final : public DeviceBase
|
|||
public:
|
||||
NintendoPowerA(DeviceToken*);
|
||||
~NintendoPowerA();
|
||||
|
||||
void setCallback(INintendoPowerACallback* cb) { m_callback = cb; }
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -33,17 +33,16 @@ struct IXInputPadCallback
|
|||
virtual void controllerUpdate(XInputPad& pad, const XInputPadState&) {}
|
||||
};
|
||||
|
||||
class XInputPad final : public DeviceBase
|
||||
class XInputPad final : public TDeviceBase<IXInputPadCallback>
|
||||
{
|
||||
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; }
|
||||
XInputPad(DeviceToken* token) : TDeviceBase<IXInputPadCallback>(token) {}
|
||||
void deviceDisconnected()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
if (m_callback)
|
||||
m_callback->controllerDisconnected();
|
||||
}
|
||||
|
|
|
@ -11,10 +11,6 @@ DeviceBase::DeviceBase(DeviceToken* token)
|
|||
{
|
||||
}
|
||||
|
||||
DeviceBase::~DeviceBase()
|
||||
{
|
||||
}
|
||||
|
||||
void DeviceBase::_deviceDisconnected()
|
||||
{
|
||||
deviceDisconnected();
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace boo
|
|||
* Reference: https://github.com/ToadKing/wii-u-gc-adapter/blob/master/wii-u-gc-adapter.c
|
||||
*/
|
||||
|
||||
DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token) : DeviceBase(token) {}
|
||||
DolphinSmashAdapter::DolphinSmashAdapter(DeviceToken* token) : TDeviceBase<IDolphinSmashAdapterCallback>(token) {}
|
||||
|
||||
DolphinSmashAdapter::~DolphinSmashAdapter() {}
|
||||
|
||||
|
@ -61,6 +61,7 @@ void DolphinSmashAdapter::transferCycle()
|
|||
|
||||
// printf("RECEIVED DATA %zu %02X\n", recvSz, payload[0]);
|
||||
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
if (!m_callback)
|
||||
return;
|
||||
|
||||
|
@ -74,6 +75,10 @@ void DolphinSmashAdapter::transferCycle()
|
|||
EDolphinControllerType type = parseState(&state, controller, rumble);
|
||||
if (type != EDolphinControllerType::None && !(m_knownControllers & 1 << i))
|
||||
{
|
||||
m_leftStickCal[0] = reinterpret_cast<uint8_t&>(state.m_leftStick[0]);
|
||||
m_leftStickCal[1] = reinterpret_cast<uint8_t&>(state.m_leftStick[1]);
|
||||
m_rightStickCal[0] = reinterpret_cast<uint8_t&>(state.m_rightStick[0]);
|
||||
m_rightStickCal[1] = reinterpret_cast<uint8_t&>(state.m_rightStick[1]);
|
||||
m_knownControllers |= 1 << i;
|
||||
m_callback->controllerConnected(i, type);
|
||||
}
|
||||
|
@ -83,7 +88,13 @@ void DolphinSmashAdapter::transferCycle()
|
|||
m_callback->controllerDisconnected(i);
|
||||
}
|
||||
if (m_knownControllers & 1 << i)
|
||||
{
|
||||
state.m_leftStick[0] = int8_t(reinterpret_cast<uint8_t&>(state.m_leftStick[0]) - m_leftStickCal[0]);
|
||||
state.m_leftStick[1] = int8_t(reinterpret_cast<uint8_t&>(state.m_leftStick[1]) - m_leftStickCal[1]);
|
||||
state.m_rightStick[0] = int8_t(reinterpret_cast<uint8_t&>(state.m_rightStick[0]) - m_rightStickCal[0]);
|
||||
state.m_rightStick[1] = int8_t(reinterpret_cast<uint8_t&>(state.m_rightStick[1]) - m_rightStickCal[1]);
|
||||
m_callback->controllerUpdate(i, type, state);
|
||||
}
|
||||
rumbleMask |= rumble ? 1 << i : 0;
|
||||
}
|
||||
|
||||
|
@ -115,14 +126,14 @@ void DolphinSmashAdapter::finalCycle()
|
|||
|
||||
void DolphinSmashAdapter::deviceDisconnected()
|
||||
{
|
||||
if (!m_callback)
|
||||
return;
|
||||
for (uint32_t i = 0; i < 4; i++)
|
||||
{
|
||||
if (m_knownControllers & 1 << i)
|
||||
{
|
||||
m_knownControllers &= ~(1 << i);
|
||||
m_callback->controllerDisconnected(i);
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
if (m_callback)
|
||||
m_callback->controllerDisconnected(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ static const uint8_t defaultReport[49] = {
|
|||
};
|
||||
|
||||
DualshockPad::DualshockPad(DeviceToken* token)
|
||||
: DeviceBase(token),
|
||||
m_callback(nullptr),
|
||||
: TDeviceBase<IDualshockPadCallback>(token),
|
||||
m_rumbleRequest(EDualshockMotor::None),
|
||||
m_rumbleState(EDualshockMotor::None)
|
||||
{
|
||||
|
@ -44,6 +43,7 @@ DualshockPad::~DualshockPad()
|
|||
|
||||
void DualshockPad::deviceDisconnected()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
if (m_callback)
|
||||
m_callback->controllerDisconnected();
|
||||
}
|
||||
|
@ -95,8 +95,11 @@ void DualshockPad::receivedHIDReport(const uint8_t* data, size_t length, HIDRepo
|
|||
state.accYaw = (atan2(accXval, accZval) + M_PI) * RAD_TO_DEG;
|
||||
state.gyroZ = (state.m_gyrometerZ / 1023.f);
|
||||
|
||||
if (m_callback)
|
||||
m_callback->controllerUpdate(*this, state);
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
if (m_callback)
|
||||
m_callback->controllerUpdate(*this, state);
|
||||
}
|
||||
|
||||
if (m_rumbleRequest != m_rumbleState)
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace boo
|
|||
{
|
||||
|
||||
GenericPad::GenericPad(DeviceToken* token)
|
||||
: DeviceBase(token)
|
||||
: TDeviceBase<IGenericPadCallback>(token)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -14,8 +14,9 @@ GenericPad::~GenericPad() {}
|
|||
|
||||
void GenericPad::deviceDisconnected()
|
||||
{
|
||||
if (m_cb)
|
||||
m_cb->controllerDisconnected();
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
if (m_callback)
|
||||
m_callback->controllerDisconnected();
|
||||
}
|
||||
|
||||
void GenericPad::initialCycle()
|
||||
|
@ -29,18 +30,20 @@ void GenericPad::initialCycle()
|
|||
std::vector<uint8_t> reportDesc = getReportDescriptor();
|
||||
m_parser.Parse(reportDesc.data(), reportDesc.size());
|
||||
#endif
|
||||
if (m_cb)
|
||||
m_cb->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)
|
||||
{
|
||||
if (length == 0 || tp != HIDReportType::Input || !m_cb)
|
||||
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_cb->valueUpdate(item, value);
|
||||
m_callback->valueUpdate(item, value);
|
||||
return true;
|
||||
};
|
||||
m_parser.ScanValues(func, data, length);
|
||||
|
|
|
@ -100,14 +100,15 @@ class HIDDeviceIOKit : public IHIDDevice
|
|||
IOObjectPointer<io_iterator_t> devIter;
|
||||
IOObjectPointer<io_registry_entry_t> devEntry = IORegistryEntryFromPath(kIOMasterPortDefault,
|
||||
device->m_devPath.data());
|
||||
IORegistryEntryGetChildIterator(devEntry, kIOServicePlane, &devIter);
|
||||
IOObjectPointer<io_object_t> interfaceEntry;
|
||||
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter))
|
||||
IORegistryEntryGetChildIterator(devEntry.get(), kIOServicePlane, &devIter);
|
||||
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(devIter.get()))
|
||||
{
|
||||
if (IOObjectConformsTo(obj, kIOUSBInterfaceClassName))
|
||||
if (IOObjectConformsTo(obj.get(), kIOUSBInterfaceClassName))
|
||||
{
|
||||
interfaceEntry = obj;
|
||||
else
|
||||
IOObjectRelease(obj);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!interfaceEntry)
|
||||
{
|
||||
|
@ -124,7 +125,7 @@ class HIDDeviceIOKit : public IHIDDevice
|
|||
IOCFPluginPointer iodev;
|
||||
SInt32 score;
|
||||
IOReturn err;
|
||||
err = IOCreatePlugInInterfaceForService(interfaceEntry,
|
||||
err = IOCreatePlugInInterfaceForService(interfaceEntry.get(),
|
||||
kIOUSBInterfaceUserClientTypeID,
|
||||
kIOCFPlugInInterfaceID,
|
||||
&iodev,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/usb/IOUSBLib.h>
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
#include <sys/utsname.h>
|
||||
#include "IOKitPointer.hpp"
|
||||
#include "CFPointer.hpp"
|
||||
|
||||
|
@ -67,10 +68,11 @@ class HIDListenerIOKit : public IHIDListener
|
|||
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)
|
||||
io_iterator_t iterator)
|
||||
{
|
||||
while (IOObjectPointer<io_service_t> obj = IOIteratorNext(iterator))
|
||||
{
|
||||
|
@ -118,7 +120,7 @@ class HIDListenerIOKit : public IHIDListener
|
|||
listener->m_finder._insertToken(std::make_unique<DeviceToken>(DeviceType::USB,
|
||||
vid, pid, vstr, pstr, devPath));
|
||||
|
||||
//printf("ADDED %08X %s\n", obj, devPath);
|
||||
//printf("ADDED %08X %s\n", obj.get(), devPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,7 +141,7 @@ class HIDListenerIOKit : public IHIDListener
|
|||
if (IORegistryEntryGetPath(obj.get(), kIOServicePlane, devPath) != 0)
|
||||
continue;
|
||||
listener->m_finder._removeToken(devPath);
|
||||
//printf("REMOVED %08X %s\n", obj, devPath);
|
||||
//printf("REMOVED %08X %s\n", obj.get(), devPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,6 +246,11 @@ public:
|
|||
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);
|
||||
|
@ -270,7 +277,7 @@ public:
|
|||
|
||||
/* Register Low-Level USB Matcher */
|
||||
{
|
||||
CFMutableDictionaryRef matchDict = IOServiceMatching(kIOUSBDeviceClassName);
|
||||
CFMutableDictionaryRef matchDict = IOServiceMatching(m_usbClass);
|
||||
CFRetain(matchDict);
|
||||
|
||||
kern_return_t llRet =
|
||||
|
@ -312,7 +319,7 @@ public:
|
|||
{
|
||||
IOObjectPointer<io_iterator_t> iter;
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||
IOServiceMatching(kIOUSBDeviceClassName), &iter) == kIOReturnSuccess)
|
||||
IOServiceMatching(m_usbClass), &iter) == kIOReturnSuccess)
|
||||
{
|
||||
devicesConnectedUSBLL(this, iter.get());
|
||||
}
|
||||
|
|
|
@ -218,6 +218,7 @@ class HIDListenerWinUSB final : public IHIDListener
|
|||
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));
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace boo
|
||||
{
|
||||
NintendoPowerA::NintendoPowerA(DeviceToken* token)
|
||||
: DeviceBase(token)
|
||||
: TDeviceBase<INintendoPowerACallback>(token)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ NintendoPowerA::~NintendoPowerA()
|
|||
|
||||
void NintendoPowerA::deviceDisconnected()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(m_callbackLock);
|
||||
if (m_callback)
|
||||
m_callback->controllerDisconnected();
|
||||
}
|
||||
|
@ -29,6 +30,7 @@ void NintendoPowerA::transferCycle()
|
|||
|
||||
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;
|
||||
|
|
Loading…
Reference in New Issue