open_toontown_panda3d/panda/src/device/ioKitInputDeviceManager.cxx

141 lines
4.9 KiB
C++

/**
* PANDA 3D SOFTWARE
* Copyright (c) Carnegie Mellon University. All rights reserved.
*
* All use of this software is subject to the terms of the revised BSD
* license. You should have received a copy of this license along
* with this source code in a file named "LICENSE."
*
* @file ioKitInputDeviceManager.cxx
* @author rdb
* @date 2018-02-04
*/
#include "ioKitInputDeviceManager.h"
#include "ioKitInputDevice.h"
#if defined(__APPLE__) && !defined(CPPPARSER)
static ConfigVariableBool iokit_scan_mouse_devices
("iokit-scan-mouse-devices", false,
PRC_DESC("Set this to true to enable capturing raw mouse data via IOKit on "
"macOS. This is disabled by default because newer macOS versions "
"will prompt the user explicitly for permissions when this is on."));
static ConfigVariableBool iokit_scan_keyboard_devices
("iokit-scan-keyboard-devices", false,
PRC_DESC("Set this to true to enable capturing raw keyboard data via IOKit on "
"macOS. This is disabled by default because newer macOS versions "
"will prompt the user explicitly for permissions when this is on."));
/**
* Initializes the input device manager by scanning which devices are currently
* connected and setting up any platform-dependent structures necessary for
* listening for future device connect events.
*/
IOKitInputDeviceManager::
IOKitInputDeviceManager() {
_hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
if (!_hid_manager) {
device_cat.error()
<< "Failed to create an IOHIDManager.\n";
return;
}
// The types of devices we're interested in.
int page = kHIDPage_GenericDesktop;
int usages[] = {kHIDUsage_GD_GamePad,
kHIDUsage_GD_Joystick,
kHIDUsage_GD_MultiAxisController,
0, 0, 0};
int num_usages = 3;
if (iokit_scan_mouse_devices) {
usages[num_usages++] = kHIDUsage_GD_Mouse;
}
if (iokit_scan_keyboard_devices) {
usages[num_usages++] = kHIDUsage_GD_Keyboard;
}
// This giant mess is necessary to create an array of match dictionaries
// that will match the devices we're interested in.
CFMutableArrayRef match = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
nassertv(match);
int *usage = usages;
while (*usage) {
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFNumberRef page_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), page_ref);
CFRelease(page_ref);
CFNumberRef usage_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, usage);
CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), usage_ref);
CFRelease(usage_ref);
CFArrayAppendValue(match, dict);
CFRelease(dict);
++usage;
}
IOHIDManagerSetDeviceMatchingMultiple(_hid_manager, match);
CFRelease(match);
IOHIDManagerRegisterDeviceMatchingCallback(_hid_manager, on_match_device, this);
IOHIDManagerRegisterDeviceRemovalCallback(_hid_manager, on_remove_device, this);
IOHIDManagerScheduleWithRunLoop(_hid_manager, CFRunLoopGetMain(), kCFRunLoopCommonModes);
IOHIDManagerOpen(_hid_manager, kIOHIDOptionsTypeNone);
}
/**
* Closes any resources that the device manager was using to listen for events.
*/
IOKitInputDeviceManager::
~IOKitInputDeviceManager() {
IOHIDManagerUnscheduleFromRunLoop(_hid_manager, CFRunLoopGetMain(), kCFRunLoopCommonModes);
IOHIDManagerClose(_hid_manager, kIOHIDOptionsTypeNone);
CFRelease(_hid_manager);
}
/**
* Called by IOKit when an input device matching our filters has been found.
*/
void IOKitInputDeviceManager::
on_match_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device) {
IOKitInputDeviceManager *mgr = (IOKitInputDeviceManager *)ctx;
nassertv(mgr != nullptr);
nassertv(device);
IOKitInputDevice *input_device = new IOKitInputDevice(device);
if (device_cat.is_debug()) {
device_cat.debug()
<< "Discovered input device " << *input_device << "\n";
}
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