16 #if defined(__APPLE__) && !defined(CPPPARSER)
18 #include <IOKit/hid/IOHIDElement.h>
28 IOKitInputDevice(IOHIDDeviceRef device) :
30 _hat_element(nullptr),
33 _scroll_wheel(nullptr),
34 _pointer_x_timestamp(0),
35 _pointer_y_timestamp(0),
36 _scroll_wheel_timestamp(0) {
41 CFStringRef name = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
44 CFStringGetCString(name, buffer,
sizeof(buffer), kCFStringEncodingUTF8);
47 size_t len = strlen(buffer);
48 while (isspace(buffer[len - 1])) {
51 _name.assign(buffer, len);
54 CFStringRef mfg = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDManufacturerKey));
56 CFStringGetCString(mfg, buffer,
sizeof(buffer), kCFStringEncodingUTF8);
57 _manufacturer = buffer;
60 CFStringRef serial = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDSerialNumberKey));
62 CFStringGetCString(serial, buffer,
sizeof(buffer), kCFStringEncodingUTF8);
63 _serial_number = buffer;
66 CFNumberRef vendor = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
69 CFNumberGetValue(vendor, kCFNumberSInt32Type, &value);
70 _vendor_id = (
unsigned short)value;
73 CFNumberRef product = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
76 CFNumberGetValue(product, kCFNumberSInt32Type, &value);
77 _product_id = (
unsigned short)value;
80 if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse)) {
81 _device_class = DeviceClass::mouse;
82 }
else if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard)) {
83 _device_class = DeviceClass::keyboard;
84 }
else if (IOHIDDeviceConformsTo(device, kHIDPage_GenericDesktop, kHIDUsage_GD_GamePad)) {
85 _device_class = DeviceClass::gamepad;
86 }
else if (IOHIDDeviceConformsTo(device, kHIDPage_Simulation, kHIDUsage_Sim_FlightStick)) {
87 _device_class = DeviceClass::flight_stick;
88 }
else if (IOHIDDeviceConformsTo(device, kHIDPage_Simulation, kHIDUsage_GD_Joystick)) {
89 _device_class = DeviceClass::flight_stick;
90 }
else if (_vendor_id == 0x044f && _product_id == 0xb108) {
92 _device_class = DeviceClass::flight_stick;
93 }
else if (_vendor_id == 0x046d &&
94 (_product_id == 0xc623 ||
95 _product_id == 0xc625 ||
96 _product_id == 0xc626 ||
97 _product_id == 0xc627 ||
98 _product_id == 0xc628 ||
99 _product_id == 0xc629 ||
100 _product_id == 0xc62b)) {
102 _device_class = DeviceClass::spatial_mouse;
103 }
else if (_name ==
"usb gamepad") {
104 _device_class = DeviceClass::gamepad;
107 CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device,
nullptr, 0);
109 CFIndex count = CFArrayGetCount(elements);
110 for (CFIndex i = 0; i < count; ++i) {
111 IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
112 parse_element(element);
117 if (_hat_element !=
nullptr) {
118 _hat_left_button = (int)_buttons.size();
119 _buttons.push_back(ButtonState(GamepadButton::hat_left()));
120 _buttons.push_back(ButtonState(GamepadButton::hat_right()));
121 _buttons.push_back(ButtonState(GamepadButton::hat_down()));
122 _buttons.push_back(ButtonState(GamepadButton::hat_up()));
125 if (_pointer_x !=
nullptr && _pointer_y !=
nullptr) {
126 enable_feature(Feature::pointer);
127 add_pointer(PointerType::unknown, 0);
130 _is_connected =
true;
137 ~IOKitInputDevice() {
143 void IOKitInputDevice::
144 parse_element(IOHIDElementRef element) {
146 Axis axis = Axis::none;
147 uint32_t page = IOHIDElementGetUsagePage(element);
148 uint32_t usage = IOHIDElementGetUsage(element);
150 switch (IOHIDElementGetType(element)) {
151 case kIOHIDElementTypeInput_Misc:
153 case kHIDPage_GenericDesktop:
156 if (_device_class == DeviceClass::gamepad) {
158 }
else if (_device_class == DeviceClass::flight_stick) {
160 }
else if (_device_class == DeviceClass::mouse) {
161 _pointer_x = element;
168 if (_device_class == DeviceClass::gamepad) {
170 }
else if (_device_class == DeviceClass::flight_stick) {
172 }
else if (_device_class == DeviceClass::mouse) {
173 _pointer_y = element;
180 if (_device_class == DeviceClass::gamepad) {
181 axis = Axis::left_trigger;
182 }
else if (_device_class == DeviceClass::flight_stick) {
183 axis = Axis::throttle;
188 case kHIDUsage_GD_Rx:
189 if (_device_class == DeviceClass::gamepad) {
190 axis = Axis::right_x;
195 case kHIDUsage_GD_Ry:
196 if (_device_class == DeviceClass::gamepad) {
197 axis = Axis::right_y;
202 case kHIDUsage_GD_Rz:
203 if (_device_class == DeviceClass::gamepad) {
204 axis = Axis::right_trigger;
209 case kHIDUsage_GD_Slider:
212 case kHIDUsage_GD_Dial:
214 case kHIDUsage_GD_Wheel:
215 _scroll_wheel = element;
217 case kHIDUsage_GD_Hatswitch:
218 _hat_element = element;
220 case kHIDUsage_GD_DPadUp:
221 handle = GamepadButton::dpad_up();
223 case kHIDUsage_GD_DPadDown:
224 handle = GamepadButton::dpad_down();
226 case kHIDUsage_GD_DPadRight:
227 handle = GamepadButton::dpad_right();
229 case kHIDUsage_GD_DPadLeft:
230 handle = GamepadButton::dpad_left();
239 case kHIDPage_Simulation:
241 case kHIDUsage_Sim_Rudder:
244 case kHIDUsage_Sim_Throttle:
245 axis = Axis::throttle;
247 case kHIDUsage_Sim_Accelerator:
248 axis = Axis::accelerator;
250 case kHIDUsage_Sim_Brake:
256 if (axis != Axis::none) {
257 int min = IOHIDElementGetLogicalMin(element);
258 int max = IOHIDElementGetLogicalMax(element);
259 if (_vendor_id == 0x044f && _product_id == 0xb108 && axis == Axis::throttle) {
261 add_axis(axis, max, min,
true);
262 }
else if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y ||
263 (_device_class == DeviceClass::spatial_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll))) {
266 add_axis(axis, max, min);
268 add_axis(axis, min, max);
271 _analog_elements.push_back(element);
275 case kIOHIDElementTypeInput_Button:
277 case kHIDPage_GenericDesktop:
279 case kHIDUsage_GD_DPadUp:
280 handle = GamepadButton::dpad_up();
282 case kHIDUsage_GD_DPadDown:
283 handle = GamepadButton::dpad_down();
285 case kHIDUsage_GD_DPadRight:
286 handle = GamepadButton::dpad_right();
288 case kHIDUsage_GD_DPadLeft:
289 handle = GamepadButton::dpad_left();
296 case kHIDPage_KeyboardOrKeypad:
298 case kHIDUsage_KeyboardA:
299 case kHIDUsage_KeyboardB:
300 case kHIDUsage_KeyboardC:
301 case kHIDUsage_KeyboardD:
302 case kHIDUsage_KeyboardE:
303 case kHIDUsage_KeyboardF:
304 case kHIDUsage_KeyboardG:
305 case kHIDUsage_KeyboardH:
306 case kHIDUsage_KeyboardI:
307 case kHIDUsage_KeyboardJ:
308 case kHIDUsage_KeyboardK:
309 case kHIDUsage_KeyboardL:
310 case kHIDUsage_KeyboardM:
311 case kHIDUsage_KeyboardN:
312 case kHIDUsage_KeyboardO:
313 case kHIDUsage_KeyboardP:
314 case kHIDUsage_KeyboardQ:
315 case kHIDUsage_KeyboardR:
316 case kHIDUsage_KeyboardS:
317 case kHIDUsage_KeyboardT:
318 case kHIDUsage_KeyboardU:
319 case kHIDUsage_KeyboardV:
320 case kHIDUsage_KeyboardW:
321 case kHIDUsage_KeyboardX:
322 case kHIDUsage_KeyboardY:
323 case kHIDUsage_KeyboardZ:
326 case kHIDUsage_Keyboard1:
329 case kHIDUsage_Keyboard2:
332 case kHIDUsage_Keyboard3:
335 case kHIDUsage_Keyboard4:
338 case kHIDUsage_Keyboard5:
341 case kHIDUsage_Keyboard6:
344 case kHIDUsage_Keyboard7:
347 case kHIDUsage_Keyboard8:
350 case kHIDUsage_Keyboard9:
353 case kHIDUsage_Keyboard0:
356 case kHIDUsage_KeyboardReturnOrEnter:
357 handle = KeyboardButton::enter();
359 case kHIDUsage_KeyboardEscape:
360 handle = KeyboardButton::escape();
362 case kHIDUsage_KeyboardDeleteOrBackspace:
363 handle = KeyboardButton::backspace();
365 case kHIDUsage_KeyboardTab:
366 handle = KeyboardButton::tab();
368 case kHIDUsage_KeyboardSpacebar:
371 case kHIDUsage_KeyboardHyphen:
374 case kHIDUsage_KeyboardEqualSign:
377 case kHIDUsage_KeyboardOpenBracket:
380 case kHIDUsage_KeyboardCloseBracket:
383 case kHIDUsage_KeyboardBackslash:
386 case kHIDUsage_KeyboardNonUSPound:
389 case kHIDUsage_KeyboardSemicolon:
392 case kHIDUsage_KeyboardQuote:
395 case kHIDUsage_KeyboardGraveAccentAndTilde:
398 case kHIDUsage_KeyboardComma:
401 case kHIDUsage_KeyboardPeriod:
404 case kHIDUsage_KeyboardSlash:
407 case kHIDUsage_KeyboardCapsLock:
408 handle = KeyboardButton::caps_lock();
410 case kHIDUsage_KeyboardF1:
411 handle = KeyboardButton::f1();
413 case kHIDUsage_KeyboardF2:
414 handle = KeyboardButton::f2();
416 case kHIDUsage_KeyboardF3:
417 handle = KeyboardButton::f3();
419 case kHIDUsage_KeyboardF4:
420 handle = KeyboardButton::f4();
422 case kHIDUsage_KeyboardF5:
423 handle = KeyboardButton::f5();
425 case kHIDUsage_KeyboardF6:
426 handle = KeyboardButton::f6();
428 case kHIDUsage_KeyboardF7:
429 handle = KeyboardButton::f7();
431 case kHIDUsage_KeyboardF8:
432 handle = KeyboardButton::f8();
434 case kHIDUsage_KeyboardF9:
435 handle = KeyboardButton::f9();
437 case kHIDUsage_KeyboardF10:
438 handle = KeyboardButton::f10();
440 case kHIDUsage_KeyboardF11:
441 handle = KeyboardButton::f11();
443 case kHIDUsage_KeyboardF12:
444 handle = KeyboardButton::f12();
446 case kHIDUsage_KeyboardPrintScreen:
447 handle = KeyboardButton::print_screen();
449 case kHIDUsage_KeyboardScrollLock:
450 handle = KeyboardButton::scroll_lock();
452 case kHIDUsage_KeyboardPause:
453 handle = KeyboardButton::pause();
455 case kHIDUsage_KeyboardInsert:
456 handle = KeyboardButton::insert();
458 case kHIDUsage_KeyboardHome:
459 handle = KeyboardButton::home();
461 case kHIDUsage_KeyboardPageUp:
462 handle = KeyboardButton::page_up();
464 case kHIDUsage_KeyboardDeleteForward:
465 handle = KeyboardButton::del();
467 case kHIDUsage_KeyboardEnd:
468 handle = KeyboardButton::end();
470 case kHIDUsage_KeyboardPageDown:
471 handle = KeyboardButton::page_down();
473 case kHIDUsage_KeyboardRightArrow:
474 handle = KeyboardButton::right();
476 case kHIDUsage_KeyboardLeftArrow:
477 handle = KeyboardButton::left();
479 case kHIDUsage_KeyboardDownArrow:
480 handle = KeyboardButton::down();
482 case kHIDUsage_KeyboardUpArrow:
483 handle = KeyboardButton::up();
485 case kHIDUsage_KeypadNumLock:
486 handle = KeyboardButton::num_lock();
488 case kHIDUsage_KeypadSlash:
491 case kHIDUsage_KeypadAsterisk:
494 case kHIDUsage_KeypadHyphen:
497 case kHIDUsage_KeypadPlus:
500 case kHIDUsage_KeypadEnter:
501 handle = KeyboardButton::enter();
503 case kHIDUsage_Keypad1:
506 case kHIDUsage_Keypad2:
509 case kHIDUsage_Keypad3:
512 case kHIDUsage_Keypad4:
515 case kHIDUsage_Keypad5:
518 case kHIDUsage_Keypad6:
521 case kHIDUsage_Keypad7:
524 case kHIDUsage_Keypad8:
527 case kHIDUsage_Keypad9:
530 case kHIDUsage_Keypad0:
533 case kHIDUsage_KeypadPeriod:
536 case kHIDUsage_KeyboardNonUSBackslash:
539 case kHIDUsage_KeypadEqualSign:
542 case kHIDUsage_KeyboardF13:
543 handle = KeyboardButton::f13();
545 case kHIDUsage_KeyboardF14:
546 handle = KeyboardButton::f14();
548 case kHIDUsage_KeyboardF15:
549 handle = KeyboardButton::f15();
551 case kHIDUsage_KeyboardF16:
552 handle = KeyboardButton::f16();
554 case kHIDUsage_KeyboardExecute:
556 case kHIDUsage_KeyboardHelp:
557 handle = KeyboardButton::help();
559 case kHIDUsage_KeyboardMenu:
560 handle = KeyboardButton::menu();
562 case kHIDUsage_KeypadComma:
565 case kHIDUsage_KeypadEqualSignAS400:
568 case kHIDUsage_KeyboardReturn:
569 handle = KeyboardButton::enter();
571 case kHIDUsage_KeyboardLeftControl:
572 handle = KeyboardButton::lcontrol();
574 case kHIDUsage_KeyboardLeftShift:
575 handle = KeyboardButton::lshift();
577 case kHIDUsage_KeyboardLeftAlt:
578 handle = KeyboardButton::lalt();
580 case kHIDUsage_KeyboardLeftGUI:
581 handle = KeyboardButton::lmeta();
583 case kHIDUsage_KeyboardRightControl:
584 handle = KeyboardButton::rcontrol();
586 case kHIDUsage_KeyboardRightShift:
587 handle = KeyboardButton::rshift();
589 case kHIDUsage_KeyboardRightAlt:
590 handle = KeyboardButton::ralt();
592 case kHIDUsage_KeyboardRightGUI:
593 handle = KeyboardButton::rmeta();
600 case kHIDPage_Button:
601 if (_device_class == DeviceClass::gamepad) {
602 if (_vendor_id == 0x0810 && _product_id == 0xe501) {
605 ButtonHandle::none(),
606 GamepadButton::face_x(),
607 GamepadButton::face_a(),
608 GamepadButton::face_b(),
609 GamepadButton::face_y(),
610 GamepadButton::lshoulder(),
611 GamepadButton::rshoulder(),
612 ButtonHandle::none(),
613 ButtonHandle::none(),
614 GamepadButton::back(),
615 GamepadButton::start(),
617 if (usage <
sizeof(gamepad_buttons) /
sizeof(
ButtonHandle)) {
618 handle = gamepad_buttons[usage];
624 ButtonHandle::none(),
625 GamepadButton::face_a(),
626 GamepadButton::face_b(),
627 GamepadButton::face_x(),
628 GamepadButton::face_y(),
629 GamepadButton::lshoulder(),
630 GamepadButton::rshoulder(),
631 GamepadButton::lstick(),
632 GamepadButton::rstick(),
633 GamepadButton::start(),
634 GamepadButton::back(),
635 GamepadButton::guide(),
636 GamepadButton::dpad_up(),
637 GamepadButton::dpad_down(),
638 GamepadButton::dpad_left(),
639 GamepadButton::dpad_right(),
641 if (usage <
sizeof(gamepad_buttons) /
sizeof(
ButtonHandle)) {
642 handle = gamepad_buttons[usage];
645 }
else if (_device_class == DeviceClass::flight_stick) {
649 }
else if (_device_class == DeviceClass::mouse) {
651 int button = (usage == 2 || usage == 3) ? (4 - usage) : (usage - 1);
656 _buttons.push_back(ButtonState(handle));
657 _button_elements.push_back(element);
660 case kIOHIDElementTypeInput_Axis:
663 case kIOHIDElementTypeInput_ScanCodes:
666 case kIOHIDElementTypeOutput:
669 case kIOHIDElementTypeFeature:
672 case kIOHIDElementTypeCollection:
693 void IOKitInputDevice::
695 for (
size_t i = 0; i < _button_elements.size(); ++i) {
696 IOHIDValueRef value_ref;
697 if (!_button_elements[i])
continue;
698 if (IOHIDDeviceGetValue(_device, _button_elements[i], &value_ref) == kIOReturnSuccess) {
699 int value = IOHIDValueGetIntegerValue(value_ref);
700 button_changed(i, value != 0);
704 for (
size_t i = 0; i < _analog_elements.size(); ++i) {
705 IOHIDValueRef value_ref;
706 if (IOHIDDeviceGetValue(_device, _analog_elements[i], &value_ref) == kIOReturnSuccess) {
707 int value = IOHIDValueGetIntegerValue(value_ref);
708 axis_changed(i, value);
712 if (_hat_element !=
nullptr) {
713 IOHIDValueRef value_ref;
714 if (IOHIDDeviceGetValue(_device, _hat_element, &value_ref) == kIOReturnSuccess) {
715 int value = IOHIDValueGetIntegerValue(value_ref);
716 button_changed(_hat_left_button + 0, value >= 5 && value <= 7);
717 button_changed(_hat_left_button + 1, value >= 1 && value <= 3);
718 button_changed(_hat_left_button + 2, value >= 3 && value <= 5);
719 button_changed(_hat_left_button + 3, value == 7 || value == 0 || value == 1);
724 if (_pointer_x !=
nullptr) {
725 IOHIDValueRef value_ref;
726 if (IOHIDDeviceGetValue(_device, _pointer_x, &value_ref) == kIOReturnSuccess) {
727 uint64_t timestamp = IOHIDValueGetTimeStamp(value_ref);
728 if (timestamp != _pointer_x_timestamp) {
729 x = IOHIDValueGetIntegerValue(value_ref);
730 _pointer_x_timestamp = timestamp;
734 if (_pointer_y !=
nullptr) {
735 IOHIDValueRef value_ref;
736 if (IOHIDDeviceGetValue(_device, _pointer_y, &value_ref) == kIOReturnSuccess) {
737 uint64_t timestamp = IOHIDValueGetTimeStamp(value_ref);
738 if (timestamp != _pointer_y_timestamp) {
739 y = IOHIDValueGetIntegerValue(value_ref);
740 _pointer_y_timestamp = timestamp;
744 if (x != 0 || y != 0) {
749 if (_scroll_wheel !=
nullptr) {
750 IOHIDValueRef value_ref;
751 if (IOHIDDeviceGetValue(_device, _scroll_wheel, &value_ref) == kIOReturnSuccess) {
752 uint64_t timestamp = IOHIDValueGetTimeStamp(value_ref);
753 if (timestamp != _scroll_wheel_timestamp) {
754 int value = IOHIDValueGetIntegerValue(value_ref);
759 _button_events->add_event(
ButtonEvent(handle, ButtonEvent::T_down, time));
760 _button_events->add_event(
ButtonEvent(handle, ButtonEvent::T_up, time));
762 _scroll_wheel_timestamp = timestamp;
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.