Panda3D
Loading...
Searching...
No Matches
ioKitInputDeviceManager.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file ioKitInputDeviceManager.cxx
10 * @author rdb
11 * @date 2018-02-04
12 */
13
15#include "ioKitInputDevice.h"
16
17#if defined(__APPLE__) && !defined(CPPPARSER)
18
19static ConfigVariableBool iokit_scan_mouse_devices
20("iokit-scan-mouse-devices", false,
21 PRC_DESC("Set this to true to enable capturing raw mouse data via IOKit on "
22 "macOS. This is disabled by default because newer macOS versions "
23 "will prompt the user explicitly for permissions when this is on."));
24
25static ConfigVariableBool iokit_scan_keyboard_devices
26("iokit-scan-keyboard-devices", false,
27 PRC_DESC("Set this to true to enable capturing raw keyboard data via IOKit on "
28 "macOS. This is disabled by default because newer macOS versions "
29 "will prompt the user explicitly for permissions when this is on."));
30
31/**
32 * Initializes the input device manager by scanning which devices are currently
33 * connected and setting up any platform-dependent structures necessary for
34 * listening for future device connect events.
35 */
36IOKitInputDeviceManager::
37IOKitInputDeviceManager() {
38 _hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
39 if (!_hid_manager) {
40 device_cat.error()
41 << "Failed to create an IOHIDManager.\n";
42 return;
43 }
44
45 // The types of devices we're interested in.
46 int page = kHIDPage_GenericDesktop;
47 int usages[] = {kHIDUsage_GD_GamePad,
48 kHIDUsage_GD_Joystick,
49 kHIDUsage_GD_MultiAxisController,
50 0, 0, 0};
51
52 int num_usages = 3;
53 if (iokit_scan_mouse_devices) {
54 usages[num_usages++] = kHIDUsage_GD_Mouse;
55 }
56 if (iokit_scan_keyboard_devices) {
57 usages[num_usages++] = kHIDUsage_GD_Keyboard;
58 }
59
60 // This giant mess is necessary to create an array of match dictionaries
61 // that will match the devices we're interested in.
62 CFMutableArrayRef match = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
63 nassertv(match);
64 int *usage = usages;
65 while (*usage) {
66 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
67 CFNumberRef page_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &page);
68 CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsagePageKey), page_ref);
69 CFRelease(page_ref);
70 CFNumberRef usage_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, usage);
71 CFDictionarySetValue(dict, CFSTR(kIOHIDDeviceUsageKey), usage_ref);
72 CFRelease(usage_ref);
73 CFArrayAppendValue(match, dict);
74 CFRelease(dict);
75 ++usage;
76 }
77 IOHIDManagerSetDeviceMatchingMultiple(_hid_manager, match);
78 CFRelease(match);
79
80 IOHIDManagerRegisterDeviceMatchingCallback(_hid_manager, on_match_device, this);
81 IOHIDManagerRegisterDeviceRemovalCallback(_hid_manager, on_remove_device, this);
82 IOHIDManagerScheduleWithRunLoop(_hid_manager, CFRunLoopGetMain(), kCFRunLoopCommonModes);
83 IOHIDManagerOpen(_hid_manager, kIOHIDOptionsTypeNone);
84}
85
86/**
87 * Closes any resources that the device manager was using to listen for events.
88 */
89IOKitInputDeviceManager::
90~IOKitInputDeviceManager() {
91 IOHIDManagerUnscheduleFromRunLoop(_hid_manager, CFRunLoopGetMain(), kCFRunLoopCommonModes);
92 IOHIDManagerClose(_hid_manager, kIOHIDOptionsTypeNone);
93 CFRelease(_hid_manager);
94}
95
96/**
97 * Called by IOKit when an input device matching our filters has been found.
98 */
99void IOKitInputDeviceManager::
100on_match_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device) {
101 IOKitInputDeviceManager *mgr = (IOKitInputDeviceManager *)ctx;
102 nassertv(mgr != nullptr);
103 nassertv(device);
104
105 IOKitInputDevice *input_device = new IOKitInputDevice(device);
106 if (device_cat.is_debug()) {
107 device_cat.debug()
108 << "Discovered input device " << *input_device << "\n";
109 }
110 mgr->add_device(input_device);
111 mgr->_devices_by_hidref[device] = input_device;
112}
113
114/**
115 * Called by IOKit when an input device has disappeared.
116 */
117void IOKitInputDeviceManager::
118on_remove_device(void *ctx, IOReturn result, void *sender, IOHIDDeviceRef device) {
119 IOKitInputDeviceManager *mgr = (IOKitInputDeviceManager *)ctx;
120 nassertv(mgr != nullptr);
121 nassertv(device);
122
123 auto it = mgr->_devices_by_hidref.find(device);
124 nassertv(it != mgr->_devices_by_hidref.end());
125 IOKitInputDevice *input_device = it->second;
126
127 input_device->set_connected(false);
128
129 mgr->_devices_by_hidref.erase(device);
130
131 IOHIDDeviceClose(device, kIOHIDOptionsTypeNone);
132
133 if (device_cat.is_debug()) {
134 device_cat.debug()
135 << "Removed input device " << *input_device << "\n";
136 }
137
138 mgr->remove_device(input_device);
139}
140#endif
This is a convenience class to specialize ConfigVariable as a boolean type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.