mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 16:20:11 -04:00
device: Fix 10.15 segfault on USB hotplug
For some reason, IOHIDDeviceRegisterRemovalCallback() no longer works on 10.15+, so an app will crash once trying to poll a device that doesn't exist anymore. Thankfully, there is the alternative solution of using IOHIDManagerRegisterDeviceRemovalCallback(). This just required a little rearranging of the callback code, as well as keeping track of the connection between IOHIDDeviceRefs and IOKitInputDevices so we actually know which device to remove. Closes #847
This commit is contained in:
parent
8222255b3b
commit
17dddeedc4
@ -21,15 +21,6 @@
|
|||||||
#include "gamepadButton.h"
|
#include "gamepadButton.h"
|
||||||
#include "mouseButton.h"
|
#include "mouseButton.h"
|
||||||
|
|
||||||
static void removal_callback(void *ctx, IOReturn result, void *sender) {
|
|
||||||
// We need to hold a reference to this because it may otherwise be destroyed
|
|
||||||
// during the call to on_remove().
|
|
||||||
PT(IOKitInputDevice) input_device = (IOKitInputDevice *)ctx;
|
|
||||||
nassertv(input_device != nullptr);
|
|
||||||
nassertv(input_device->test_ref_count_integrity());
|
|
||||||
input_device->on_remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Protected constructor.
|
* Protected constructor.
|
||||||
*/
|
*/
|
||||||
@ -137,7 +128,6 @@ IOKitInputDevice(IOHIDDeviceRef device) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
_is_connected = true;
|
_is_connected = true;
|
||||||
IOHIDDeviceRegisterRemovalCallback(device, removal_callback, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -147,31 +137,6 @@ IOKitInputDevice::
|
|||||||
~IOKitInputDevice() {
|
~IOKitInputDevice() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The nonstatic version of on_remove_device.
|
|
||||||
*/
|
|
||||||
void IOKitInputDevice::
|
|
||||||
on_remove() {
|
|
||||||
{
|
|
||||||
LightMutexHolder holder(_lock);
|
|
||||||
if (!_is_connected) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_is_connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (device_cat.is_debug()) {
|
|
||||||
device_cat.debug()
|
|
||||||
<< "Removed input device " << *this << "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
IOHIDDeviceClose(_device, kIOHIDOptionsTypeNone);
|
|
||||||
|
|
||||||
InputDeviceManager *mgr = InputDeviceManager::get_global_ptr();
|
|
||||||
nassertv(mgr != nullptr);
|
|
||||||
mgr->remove_device(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -30,8 +30,6 @@ public:
|
|||||||
IOKitInputDevice(IOHIDDeviceRef device);
|
IOKitInputDevice(IOHIDDeviceRef device);
|
||||||
~IOKitInputDevice();
|
~IOKitInputDevice();
|
||||||
|
|
||||||
void on_remove();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parse_element(IOHIDElementRef element);
|
void parse_element(IOHIDElementRef element);
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ IOKitInputDeviceManager() {
|
|||||||
CFRelease(match);
|
CFRelease(match);
|
||||||
|
|
||||||
IOHIDManagerRegisterDeviceMatchingCallback(_hid_manager, on_match_device, this);
|
IOHIDManagerRegisterDeviceMatchingCallback(_hid_manager, on_match_device, this);
|
||||||
|
IOHIDManagerRegisterDeviceRemovalCallback(_hid_manager, on_remove_device, this);
|
||||||
IOHIDManagerScheduleWithRunLoop(_hid_manager, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
IOHIDManagerScheduleWithRunLoop(_hid_manager, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||||
IOHIDManagerOpen(_hid_manager, kIOHIDOptionsTypeNone);
|
IOHIDManagerOpen(_hid_manager, kIOHIDOptionsTypeNone);
|
||||||
}
|
}
|
||||||
@ -78,16 +79,43 @@ IOKitInputDeviceManager::
|
|||||||
*/
|
*/
|
||||||
void IOKitInputDeviceManager::
|
void IOKitInputDeviceManager::
|
||||||
on_match_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device) {
|
on_match_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device) {
|
||||||
InputDeviceManager *mgr = (InputDeviceManager *)ctx;
|
IOKitInputDeviceManager *mgr = (IOKitInputDeviceManager *)ctx;
|
||||||
nassertv(mgr != nullptr);
|
nassertv(mgr != nullptr);
|
||||||
nassertv(device);
|
nassertv(device);
|
||||||
|
|
||||||
PT(InputDevice) input_device = new IOKitInputDevice(device);
|
IOKitInputDevice *input_device = new IOKitInputDevice(device);
|
||||||
if (device_cat.is_debug()) {
|
if (device_cat.is_debug()) {
|
||||||
device_cat.debug()
|
device_cat.debug()
|
||||||
<< "Discovered input device " << *input_device << "\n";
|
<< "Discovered input device " << *input_device << "\n";
|
||||||
}
|
}
|
||||||
mgr->add_device(input_device);
|
mgr->add_device(input_device);
|
||||||
|
mgr->_devices_by_hidref[device] = input_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by IOKit when an input device has disappeared.
|
||||||
|
*/
|
||||||
|
void IOKitInputDeviceManager::
|
||||||
|
on_remove_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device) {
|
||||||
|
IOKitInputDeviceManager *mgr = (IOKitInputDeviceManager *)ctx;
|
||||||
|
nassertv(mgr != nullptr);
|
||||||
|
nassertv(device);
|
||||||
|
|
||||||
|
auto it = mgr->_devices_by_hidref.find(device);
|
||||||
|
nassertv(it != mgr->_devices_by_hidref.end());
|
||||||
|
IOKitInputDevice *input_device = it->second;
|
||||||
|
|
||||||
|
input_device->set_connected(false);
|
||||||
|
|
||||||
|
mgr->_devices_by_hidref.erase(device);
|
||||||
|
|
||||||
|
IOHIDDeviceClose(device, kIOHIDOptionsTypeNone);
|
||||||
|
|
||||||
|
if (device_cat.is_debug()) {
|
||||||
|
device_cat.debug()
|
||||||
|
<< "Removed input device " << *input_device << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
mgr->remove_device(input_device);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#if defined(__APPLE__) && !defined(CPPPARSER)
|
#if defined(__APPLE__) && !defined(CPPPARSER)
|
||||||
#include <IOKit/hid/IOHIDManager.h>
|
#include <IOKit/hid/IOHIDManager.h>
|
||||||
|
|
||||||
|
class IOKitInputDevice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The macOS implementation of InputDeviceManager.
|
* The macOS implementation of InputDeviceManager.
|
||||||
*/
|
*/
|
||||||
@ -30,7 +32,16 @@ protected:
|
|||||||
protected:
|
protected:
|
||||||
IOHIDManagerRef _hid_manager;
|
IOHIDManagerRef _hid_manager;
|
||||||
|
|
||||||
|
// The device removal callback method we need to use requires us to remember
|
||||||
|
// which IOKitInputDevice corresponds to which IOHIDDeviceRef. This is the
|
||||||
|
// same strategy used by winInputDevice and friends.
|
||||||
|
//
|
||||||
|
// We can make this a mapping to raw pointers since we know _devices will be
|
||||||
|
// holding a reference until remove_device is called.
|
||||||
|
pmap<IOHIDDeviceRef, IOKitInputDevice *> _devices_by_hidref;
|
||||||
|
|
||||||
static void on_match_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device);
|
static void on_match_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device);
|
||||||
|
static void on_remove_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device);
|
||||||
|
|
||||||
friend class InputDeviceManager;
|
friend class InputDeviceManager;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user