WiimoteReal: Add IOHIDDevice support for OS X
This commit is contained in:
parent
3f0f3c36fa
commit
6f8a38cefb
|
@ -45,6 +45,31 @@ private:
|
||||||
IOPMAssertionID m_pm_assertion;
|
IOPMAssertionID m_pm_assertion;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class WiimoteDarwinHid final : public Wiimote
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WiimoteDarwinHid(IOHIDDeviceRef device);
|
||||||
|
~WiimoteDarwinHid() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ConnectInternal() override;
|
||||||
|
void DisconnectInternal() override;
|
||||||
|
bool IsConnected() const override;
|
||||||
|
void IOWakeup() override;
|
||||||
|
int IORead(u8* buf) override;
|
||||||
|
int IOWrite(u8 const* buf, size_t len) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void ReportCallback(void* context, IOReturn result, void* sender, IOHIDReportType type, u32 reportID, u8* report, CFIndex reportLength);
|
||||||
|
static void RemoveCallback(void* context, IOReturn result, void* sender);
|
||||||
|
void QueueBufferReport(int length);
|
||||||
|
IOHIDDeviceRef m_device;
|
||||||
|
bool m_connected;
|
||||||
|
std::atomic<bool> m_interrupted;
|
||||||
|
Report m_report_buffer;
|
||||||
|
Common::FifoQueue<Report> m_buffered_reports;
|
||||||
|
};
|
||||||
|
|
||||||
WiimoteScanner::WiimoteScanner()
|
WiimoteScanner::WiimoteScanner()
|
||||||
: m_run_thread()
|
: m_run_thread()
|
||||||
, m_want_wiimotes()
|
, m_want_wiimotes()
|
||||||
|
@ -61,65 +86,109 @@ void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimot
|
||||||
// TODO: find the device in the constructor and save it for later
|
// TODO: find the device in the constructor and save it for later
|
||||||
IOBluetoothHostController *bth;
|
IOBluetoothHostController *bth;
|
||||||
IOBluetoothDeviceInquiry *bti;
|
IOBluetoothDeviceInquiry *bti;
|
||||||
|
IOHIDManagerRef hid;
|
||||||
SearchBT *sbt;
|
SearchBT *sbt;
|
||||||
NSEnumerator *en;
|
NSEnumerator *en;
|
||||||
found_board = nullptr;
|
found_board = nullptr;
|
||||||
|
|
||||||
|
bool btFailed = false;
|
||||||
|
bool hidFailed = false;
|
||||||
|
|
||||||
bth = [[IOBluetoothHostController alloc] init];
|
bth = [[IOBluetoothHostController alloc] init];
|
||||||
if ([bth addressAsString] == nil)
|
btFailed = [bth addressAsString] == nil;
|
||||||
{
|
if (btFailed)
|
||||||
WARN_LOG(WIIMOTE, "No Bluetooth host controller");
|
WARN_LOG(WIIMOTE, "No Bluetooth host controller");
|
||||||
|
|
||||||
|
hid = IOHIDManagerCreate(NULL, kIOHIDOptionsTypeNone);
|
||||||
|
hidFailed = CFGetTypeID(hid) != IOHIDManagerGetTypeID();
|
||||||
|
if (hidFailed)
|
||||||
|
WARN_LOG(WIIMOTE, "No HID manager");
|
||||||
|
|
||||||
|
if (hidFailed && btFailed)
|
||||||
|
{
|
||||||
|
CFRelease(hid);
|
||||||
[bth release];
|
[bth release];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sbt = [[SearchBT alloc] init];
|
if (!btFailed)
|
||||||
sbt->maxDevices = 32;
|
|
||||||
bti = [[IOBluetoothDeviceInquiry alloc] init];
|
|
||||||
[bti setDelegate: sbt];
|
|
||||||
[bti setInquiryLength: 2];
|
|
||||||
|
|
||||||
if ([bti start] != kIOReturnSuccess)
|
|
||||||
{
|
{
|
||||||
ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery");
|
sbt = [[SearchBT alloc] init];
|
||||||
|
sbt->maxDevices = 32;
|
||||||
|
bti = [[IOBluetoothDeviceInquiry alloc] init];
|
||||||
|
[bti setDelegate: sbt];
|
||||||
|
[bti setInquiryLength: 2];
|
||||||
|
|
||||||
|
if ([bti start] != kIOReturnSuccess)
|
||||||
|
{
|
||||||
|
ERROR_LOG(WIIMOTE, "Unable to do Bluetooth discovery");
|
||||||
|
[bth release];
|
||||||
|
[sbt release];
|
||||||
|
btFailed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
CFRunLoopRun();
|
||||||
|
}
|
||||||
|
while (!sbt->done);
|
||||||
|
|
||||||
|
int found_devices = [[bti foundDevices] count];
|
||||||
|
|
||||||
|
if (found_devices)
|
||||||
|
NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices);
|
||||||
|
|
||||||
|
en = [[bti foundDevices] objectEnumerator];
|
||||||
|
for (int i = 0; i < found_devices; i++)
|
||||||
|
{
|
||||||
|
IOBluetoothDevice *dev = [en nextObject];
|
||||||
|
if (!IsValidBluetoothName([[dev name] UTF8String]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Wiimote* wm = new WiimoteDarwin([dev retain]);
|
||||||
|
|
||||||
|
if (IsBalanceBoardName([[dev name] UTF8String]))
|
||||||
|
{
|
||||||
|
found_board = wm;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found_wiimotes.push_back(wm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[bth release];
|
[bth release];
|
||||||
|
[bti release];
|
||||||
[sbt release];
|
[sbt release];
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
if (!hidFailed)
|
||||||
{
|
{
|
||||||
|
NSArray *criteria = @[
|
||||||
|
@{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0306 },
|
||||||
|
@{ @kIOHIDVendorIDKey: @0x057e, @kIOHIDProductIDKey: @0x0330 },
|
||||||
|
];
|
||||||
|
IOHIDManagerSetDeviceMatchingMultiple(hid, (CFArrayRef)criteria);
|
||||||
CFRunLoopRun();
|
CFRunLoopRun();
|
||||||
}
|
CFSetRef devices = IOHIDManagerCopyDevices(hid);
|
||||||
while (!sbt->done);
|
if (devices)
|
||||||
|
|
||||||
int found_devices = [[bti foundDevices] count];
|
|
||||||
|
|
||||||
if (found_devices)
|
|
||||||
NOTICE_LOG(WIIMOTE, "Found %i Bluetooth devices", found_devices);
|
|
||||||
|
|
||||||
en = [[bti foundDevices] objectEnumerator];
|
|
||||||
for (int i = 0; i < found_devices; i++)
|
|
||||||
{
|
|
||||||
IOBluetoothDevice *dev = [en nextObject];
|
|
||||||
if (!IsValidBluetoothName([[dev name] UTF8String]))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
Wiimote* wm = new WiimoteDarwin([dev retain]);
|
|
||||||
|
|
||||||
if (IsBalanceBoardName([[dev name] UTF8String]))
|
|
||||||
{
|
{
|
||||||
found_board = wm;
|
int found_devices = CFSetGetCount(devices);
|
||||||
}
|
if (found_devices)
|
||||||
else
|
{
|
||||||
{
|
NOTICE_LOG(WIIMOTE, "Found %i HID devices", found_devices);
|
||||||
found_wiimotes.push_back(wm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[bth release];
|
IOHIDDeviceRef values[found_devices];
|
||||||
[bti release];
|
CFSetGetValues(devices, reinterpret_cast<const void**>(&values));
|
||||||
[sbt release];
|
for (int i = 0; i < found_devices; i++)
|
||||||
|
{
|
||||||
|
Wiimote* wm = new WiimoteDarwinHid(values[i]);
|
||||||
|
found_wiimotes.push_back(wm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CFRelease(hid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WiimoteScanner::IsReady() const
|
bool WiimoteScanner::IsReady() const
|
||||||
|
@ -287,6 +356,118 @@ void WiimoteDarwin::DisablePowerAssertionInternal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WiimoteDarwinHid::WiimoteDarwinHid(IOHIDDeviceRef device) : m_device(device)
|
||||||
|
{
|
||||||
|
CFRetain(m_device);
|
||||||
|
m_connected = false;
|
||||||
|
m_report_buffer = Report(MAX_PAYLOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
WiimoteDarwinHid::~WiimoteDarwinHid()
|
||||||
|
{
|
||||||
|
Shutdown();
|
||||||
|
CFRelease(m_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiimoteDarwinHid::ConnectInternal()
|
||||||
|
{
|
||||||
|
IOReturn ret = IOHIDDeviceOpen(m_device, kIOHIDOptionsTypeNone);
|
||||||
|
m_connected = ret == kIOReturnSuccess;
|
||||||
|
if (m_connected)
|
||||||
|
{
|
||||||
|
IOHIDDeviceScheduleWithRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||||
|
IOHIDDeviceRegisterInputReportCallback(m_device,
|
||||||
|
m_report_buffer.data() + 1,
|
||||||
|
MAX_PAYLOAD - 1,
|
||||||
|
&WiimoteDarwinHid::ReportCallback,
|
||||||
|
this);
|
||||||
|
IOHIDDeviceRegisterRemovalCallback(m_device, &WiimoteDarwinHid::RemoveCallback, this);
|
||||||
|
NOTICE_LOG(WIIMOTE, "Connected to Wiimote %i", m_index + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ERROR_LOG(WIIMOTE, "Could not open IOHID Wiimote: %08x", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiimoteDarwinHid::DisconnectInternal()
|
||||||
|
{
|
||||||
|
IOHIDDeviceUnscheduleFromRunLoop(m_device, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||||
|
IOWakeup();
|
||||||
|
IOReturn ret = IOHIDDeviceClose(m_device, kIOHIDOptionsTypeNone);
|
||||||
|
if (ret != kIOReturnSuccess)
|
||||||
|
ERROR_LOG(WIIMOTE, "Error closing IOHID Wiimote: %08x", ret);
|
||||||
|
|
||||||
|
if (!IsConnected())
|
||||||
|
return;
|
||||||
|
|
||||||
|
NOTICE_LOG(WIIMOTE, "Disconnecting Wiimote %i", m_index + 1);
|
||||||
|
|
||||||
|
m_buffered_reports.Clear();
|
||||||
|
|
||||||
|
m_connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WiimoteDarwinHid::IsConnected() const
|
||||||
|
{
|
||||||
|
return m_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiimoteDarwinHid::IOWakeup()
|
||||||
|
{
|
||||||
|
m_interrupted.store(true);
|
||||||
|
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiimoteDarwinHid::IORead(u8* buf)
|
||||||
|
{
|
||||||
|
Report rpt;
|
||||||
|
m_interrupted.store(false);
|
||||||
|
while (m_buffered_reports.Empty() && !m_interrupted.load())
|
||||||
|
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
|
||||||
|
|
||||||
|
if (m_buffered_reports.Pop(rpt))
|
||||||
|
{
|
||||||
|
memcpy(buf, rpt.data(), rpt.size());
|
||||||
|
return rpt.size();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int WiimoteDarwinHid::IOWrite(u8 const* buf, size_t len)
|
||||||
|
{
|
||||||
|
IOReturn ret = IOHIDDeviceSetReport(m_device, kIOHIDReportTypeOutput, buf[1], buf + 1, len - 1);
|
||||||
|
if (ret != kIOReturnSuccess)
|
||||||
|
{
|
||||||
|
ERROR_LOG(WIIMOTE, "Error writing to Wiimote: %08x", ret);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiimoteDarwinHid::QueueBufferReport(int length)
|
||||||
|
{
|
||||||
|
Report rpt(m_report_buffer);
|
||||||
|
rpt[0] = 0xa1;
|
||||||
|
rpt.resize(length + 1);
|
||||||
|
m_buffered_reports.Push(std::move(rpt));
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiimoteDarwinHid::ReportCallback(void* context, IOReturn result, void*, IOHIDReportType type, u32 report_id, u8* report, CFIndex report_length)
|
||||||
|
{
|
||||||
|
WiimoteDarwinHid* wm = static_cast<WiimoteDarwinHid*>(context);
|
||||||
|
report[0] = report_id;
|
||||||
|
wm->QueueBufferReport(report_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiimoteDarwinHid::RemoveCallback(void* context, IOReturn result, void*)
|
||||||
|
{
|
||||||
|
WiimoteDarwinHid* wm = static_cast<WiimoteDarwinHid*>(context);
|
||||||
|
wm->DisconnectInternal();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@implementation SearchBT
|
@implementation SearchBT
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
// end hack
|
// end hack
|
||||||
#import <IOBluetooth/IOBluetooth.h>
|
#import <IOBluetooth/IOBluetooth.h>
|
||||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
|
#include <IOKit/hid/IOHIDManager.h>
|
||||||
#elif defined(__linux__) && HAVE_BLUEZ
|
#elif defined(__linux__) && HAVE_BLUEZ
|
||||||
#include <bluetooth/bluetooth.h>
|
#include <bluetooth/bluetooth.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue