summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/ControllerInterface
diff options
context:
space:
mode:
authorMichael Maltese <michaeljosephmaltese@gmail.com>2016-10-17 23:00:11 -0700
committerMichael Maltese <michaeljosephmaltese@gmail.com>2016-11-30 22:27:46 -0800
commit7ed8fb95c553d876a717089ca8808bd2c5adf575 (patch)
tree87ccf59fea68b0590117334afe252a54f2251ba5 /Source/Core/InputCommon/ControllerInterface
parenta3d2dead76f9fe46163a20f6b7cc6ac7b2b66f29 (diff)
ControllerInterface: enable hotplugging on macOS
Diffstat (limited to 'Source/Core/InputCommon/ControllerInterface')
-rw-r--r--Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm76
-rw-r--r--Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h1
-rw-r--r--Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm5
-rw-r--r--Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h1
-rw-r--r--Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm5
-rw-r--r--Source/Core/InputCommon/ControllerInterface/OSX/RunLoopStopper.h45
6 files changed, 117 insertions, 16 deletions
diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm
index e575260a89..c69d2c3af2 100644
--- a/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm
+++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSX.mm
@@ -2,23 +2,29 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
+#include <thread>
+
#include <Cocoa/Cocoa.h>
#include <Foundation/Foundation.h>
#include <IOKit/hid/IOHIDLib.h>
+#include "Common/Logging/Log.h"
#include "Common/StringUtil.h"
+#include "Common/Thread.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "InputCommon/ControllerInterface/OSX/OSX.h"
#include "InputCommon/ControllerInterface/OSX/OSXJoystick.h"
#include "InputCommon/ControllerInterface/OSX/OSXKeyboard.h"
-
-#include <map>
+#include "InputCommon/ControllerInterface/OSX/RunLoopStopper.h"
namespace ciface
{
namespace OSX
{
+constexpr CFTimeInterval FOREVER = 1e20;
+static std::thread s_hotplug_thread;
+static RunLoopStopper s_stopper;
static IOHIDManagerRef HIDManager = nullptr;
static CFStringRef OurRunLoop = CFSTR("DolphinOSXInput");
@@ -134,13 +140,36 @@ static void DeviceDebugPrint(IOHIDDeviceRef device)
static void* g_window;
-static void DeviceMatching_callback(void* inContext, IOReturn inResult, void* inSender,
- IOHIDDeviceRef inIOHIDDeviceRef)
+static std::string GetDeviceRefName(IOHIDDeviceRef inIOHIDDeviceRef)
+{
+ const NSString* name = reinterpret_cast<const NSString*>(
+ IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductKey)));
+ return (name != nullptr) ? StripSpaces([name UTF8String]) : "Unknown device";
+}
+
+static void DeviceRemovalCallback(void* inContext, IOReturn inResult, void* inSender,
+ IOHIDDeviceRef inIOHIDDeviceRef)
{
- NSString* pName = (NSString*)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDProductKey));
- std::string name = (pName != nullptr) ? StripSpaces([pName UTF8String]) : "Unknown device";
+ g_controller_interface.RemoveDevice([&inIOHIDDeviceRef](const auto* device) {
+ const Joystick* joystick = dynamic_cast<const Joystick*>(device);
+ if (joystick && joystick->IsSameDevice(inIOHIDDeviceRef))
+ return true;
+
+ const Keyboard* keyboard = dynamic_cast<const Keyboard*>(device);
+ if (keyboard && keyboard->IsSameDevice(inIOHIDDeviceRef))
+ return true;
+
+ return false;
+ });
+ g_controller_interface.InvokeHotplugCallbacks();
+ NOTICE_LOG(SERIALINTERFACE, "Removed device: %s", GetDeviceRefName(inIOHIDDeviceRef).c_str());
+}
+static void DeviceMatchingCallback(void* inContext, IOReturn inResult, void* inSender,
+ IOHIDDeviceRef inIOHIDDeviceRef)
+{
DeviceDebugPrint(inIOHIDDeviceRef);
+ std::string name = GetDeviceRefName(inIOHIDDeviceRef);
// Add a device if it's of a type we want
if (IOHIDDeviceConformsTo(inIOHIDDeviceRef, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard))
@@ -151,39 +180,54 @@ static void DeviceMatching_callback(void* inContext, IOReturn inResult, void* in
#endif
else
g_controller_interface.AddDevice(std::make_shared<Joystick>(inIOHIDDeviceRef, name));
+
+ NOTICE_LOG(SERIALINTERFACE, "Added device: %s", name.c_str());
+ g_controller_interface.InvokeHotplugCallbacks();
}
void Init(void* window)
{
HIDManager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
if (!HIDManager)
- NSLog(@"Failed to create HID Manager reference");
+ ERROR_LOG(SERIALINTERFACE, "Failed to create HID Manager reference");
g_window = window;
IOHIDManagerSetDeviceMatching(HIDManager, nullptr);
+ if (IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
+ ERROR_LOG(SERIALINTERFACE, "Failed to open HID Manager");
// Callbacks for acquisition or loss of a matching device
- IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, DeviceMatching_callback, nullptr);
+ IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, DeviceMatchingCallback, nullptr);
+ IOHIDManagerRegisterDeviceRemovalCallback(HIDManager, DeviceRemovalCallback, nullptr);
// Match devices that are plugged in right now
IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
- if (IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone) != kIOReturnSuccess)
- NSLog(@"Failed to open HID Manager");
-
- // Wait while current devices are initialized
while (CFRunLoopRunInMode(OurRunLoop, 0, TRUE) == kCFRunLoopRunHandledSource)
{
};
-
- // Things should be configured now
- // Disable hotplugging and other scheduling
- IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, nullptr, nullptr);
IOHIDManagerUnscheduleFromRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
+
+ // Enable hotplugging
+ s_hotplug_thread = std::thread([] {
+ Common::SetCurrentThreadName("IOHIDManager Hotplug Thread");
+ NOTICE_LOG(SERIALINTERFACE, "IOHIDManager hotplug thread started");
+
+ IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
+ s_stopper.AddToRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
+ CFRunLoopRunInMode(OurRunLoop, FOREVER, FALSE);
+ s_stopper.RemoveFromRunLoop(CFRunLoopGetCurrent(), OurRunLoop);
+ IOHIDManagerUnscheduleFromRunLoop(HIDManager, CFRunLoopGetCurrent(), OurRunLoop);
+
+ NOTICE_LOG(SERIALINTERFACE, "IOHIDManager hotplug thread stopped");
+ });
}
void DeInit()
{
+ s_stopper.Signal();
+ s_hotplug_thread.join();
+
// This closes all devices as well
IOHIDManagerClose(HIDManager, kIOHIDOptionsTypeNone);
CFRelease(HIDManager);
diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h
index 41ea7c8365..dbe6a725c1 100644
--- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h
+++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.h
@@ -78,6 +78,7 @@ public:
std::string GetName() const override;
std::string GetSource() const override;
+ bool IsSameDevice(const IOHIDDeviceRef) const;
private:
const IOHIDDeviceRef m_device;
diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm
index 19aa9e23b7..e8595153f2 100644
--- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm
+++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXJoystick.mm
@@ -276,5 +276,10 @@ std::string Joystick::Hat::GetName() const
{
return m_name;
}
+
+bool Joystick::IsSameDevice(const IOHIDDeviceRef other_device) const
+{
+ return m_device == other_device;
+}
}
}
diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h
index d73243259e..3d2dccfb79 100644
--- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h
+++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.h
@@ -64,6 +64,7 @@ public:
std::string GetName() const override;
std::string GetSource() const override;
+ bool IsSameDevice(const IOHIDDeviceRef) const;
private:
struct
diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm
index 8fb6ebe80d..a4e4bd9312 100644
--- a/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm
+++ b/Source/Core/InputCommon/ControllerInterface/OSX/OSXKeyboard.mm
@@ -263,5 +263,10 @@ std::string Keyboard::Key::GetName() const
{
return m_name;
}
+
+bool Keyboard::IsSameDevice(const IOHIDDeviceRef other_device) const
+{
+ return m_device == other_device;
+}
}
}
diff --git a/Source/Core/InputCommon/ControllerInterface/OSX/RunLoopStopper.h b/Source/Core/InputCommon/ControllerInterface/OSX/RunLoopStopper.h
new file mode 100644
index 0000000000..298dcd4a80
--- /dev/null
+++ b/Source/Core/InputCommon/ControllerInterface/OSX/RunLoopStopper.h
@@ -0,0 +1,45 @@
+// Copyright 2016 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <Foundation/Foundation.h>
+
+namespace ciface
+{
+namespace OSX
+{
+class RunLoopStopper
+{
+ CFRunLoopSourceRef m_source;
+ CFRunLoopRef m_runloop = nullptr;
+
+public:
+ RunLoopStopper()
+ {
+ CFRunLoopSourceContext ctx = {.version = 0,
+ .perform = [](void*) { CFRunLoopStop(CFRunLoopGetCurrent()); }};
+ m_source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &ctx);
+ }
+ ~RunLoopStopper() { CFRelease(m_source); }
+ void Signal()
+ {
+ CFRunLoopSourceSignal(m_source);
+ if (m_runloop != nullptr)
+ CFRunLoopWakeUp(m_runloop);
+ }
+ void AddToRunLoop(CFRunLoopRef runloop, CFStringRef mode)
+ {
+ m_runloop = runloop;
+ CFRunLoopAddSource(runloop, m_source, mode);
+ }
+ void RemoveFromRunLoop(CFRunLoopRef runloop, CFStringRef mode)
+ {
+ m_runloop = nullptr;
+ CFRunLoopRemoveSource(runloop, m_source, mode);
+ }
+};
+
+} // namespace ciface
+} // namespace OSX