Panda3D

ioKitInputDevice.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 ioKitInputDevice.cxx
10 * @author rdb
11 * @date 2017-12-21
12 */
13
14 #include "ioKitInputDevice.h"
15
16 #if defined(__APPLE__) && !defined(CPPPARSER)
17
18 #include <IOKit/hid/IOHIDElement.h>
19
20 #include "keyboardButton.h"
21 #include "gamepadButton.h"
22 #include "mouseButton.h"
23
24 /**
25 * Protected constructor.
26 */
27 IOKitInputDevice::
28 IOKitInputDevice(IOHIDDeviceRef device) :
29 _device(device),
30 _hat_element(nullptr),
31 _pointer_x(nullptr),
32 _pointer_y(nullptr),
33 _scroll_wheel(nullptr),
34 _pointer_x_timestamp(0),
35 _pointer_y_timestamp(0),
36 _scroll_wheel_timestamp(0) {
37 nassertv(device);
38
39 char buffer[4096];
40
41 CFStringRef name = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
42 if (name) {
43 buffer[0] = 0;
44 CFStringGetCString(name, buffer, sizeof(buffer), kCFStringEncodingUTF8);
45
46 // Strip trailing spaces.
47 size_t len = strlen(buffer);
48 while (isspace(buffer[len - 1])) {
49 --len;
50 }
51 _name.assign(buffer, len);
52 }
53
54 CFStringRef mfg = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDManufacturerKey));
55 if (mfg) {
56 CFStringGetCString(mfg, buffer, sizeof(buffer), kCFStringEncodingUTF8);
57 _manufacturer = buffer;
58 }
59
60 CFStringRef serial = (CFStringRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDSerialNumberKey));
61 if (serial) {
62 CFStringGetCString(serial, buffer, sizeof(buffer), kCFStringEncodingUTF8);
63 _serial_number = buffer;
64 }
65
66 CFNumberRef vendor = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDVendorIDKey));
67 if (vendor) {
68 int32_t value = 0;
69 CFNumberGetValue(vendor, kCFNumberSInt32Type, &value);
70 _vendor_id = (unsigned short)value;
71 }
72
73 CFNumberRef product = (CFNumberRef)IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductIDKey));
74 if (product) {
75 int32_t value = 0;
76 CFNumberGetValue(product, kCFNumberSInt32Type, &value);
77 _product_id = (unsigned short)value;
78 }
79
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) {
91 // T.Flight Hotas X
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)) {
101 // 3Dconnexion SpaceNavigator and friends.
102 _device_class = DeviceClass::spatial_mouse;
103 } else if (_name == "usb gamepad") {
104 _device_class = DeviceClass::gamepad;
105 }
106
107 CFArrayRef elements = IOHIDDeviceCopyMatchingElements(device, nullptr, 0);
108 if (elements) {
109 CFIndex count = CFArrayGetCount(elements);
110 for (CFIndex i = 0; i < count; ++i) {
111 IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
112 parse_element(element);
113 }
114 CFRelease(elements);
115 }
116
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()));
123 }
124
125 if (_pointer_x != nullptr && _pointer_y != nullptr) {
126 enable_feature(Feature::pointer);
127 add_pointer(PointerType::unknown, 0);
128 }
129
130 _is_connected = true;
131 }
132
133 /**
134 *
135 */
136 IOKitInputDevice::
137 ~IOKitInputDevice() {
138 }
139
140 /**
141 *
142 */
143 void IOKitInputDevice::
144 parse_element(IOHIDElementRef element) {
145 ButtonHandle handle = ButtonHandle::none();
146 Axis axis = Axis::none;
147 uint32_t page = IOHIDElementGetUsagePage(element);
148 uint32_t usage = IOHIDElementGetUsage(element);
149
150 switch (IOHIDElementGetType(element)) {
151 case kIOHIDElementTypeInput_Misc:
152 switch (page) {
153 case kHIDPage_GenericDesktop:
154 switch (usage) {
155 case kHIDUsage_GD_X:
156 if (_device_class == DeviceClass::gamepad) {
157 axis = Axis::left_x;
158 } else if (_device_class == DeviceClass::flight_stick) {
159 axis = Axis::roll;
160 } else if (_device_class == DeviceClass::mouse) {
161 _pointer_x = element;
162 return;
163 } else {
164 axis = Axis::x;
165 }
166 break;
167 case kHIDUsage_GD_Y:
168 if (_device_class == DeviceClass::gamepad) {
169 axis = Axis::left_y;
170 } else if (_device_class == DeviceClass::flight_stick) {
171 axis = Axis::pitch;
172 } else if (_device_class == DeviceClass::mouse) {
173 _pointer_y = element;
174 return;
175 } else {
176 axis = Axis::y;
177 }
178 break;
179 case kHIDUsage_GD_Z:
180 if (_device_class == DeviceClass::gamepad) {
181 axis = Axis::left_trigger;
182 } else if (_device_class == DeviceClass::flight_stick) {
183 axis = Axis::throttle;
184 } else {
185 axis = Axis::z;
186 }
187 break;
188 case kHIDUsage_GD_Rx:
189 if (_device_class == DeviceClass::gamepad) {
190 axis = Axis::right_x;
191 } else {
192 axis = Axis::pitch;
193 }
194 break;
195 case kHIDUsage_GD_Ry:
196 if (_device_class == DeviceClass::gamepad) {
197 axis = Axis::right_y;
198 } else {
199 axis = Axis::roll;
200 }
201 break;
202 case kHIDUsage_GD_Rz:
203 if (_device_class == DeviceClass::gamepad) {
204 axis = Axis::right_trigger;
205 } else {
206 axis = Axis::yaw;
207 }
208 break;
209 case kHIDUsage_GD_Slider:
210 axis = Axis::rudder;
211 break;
212 case kHIDUsage_GD_Dial:
213 break;
214 case kHIDUsage_GD_Wheel:
215 _scroll_wheel = element;
216 return;
217 case kHIDUsage_GD_Hatswitch:
218 _hat_element = element;
219 return;
220 case kHIDUsage_GD_DPadUp:
221 handle = GamepadButton::dpad_up();
222 break;
223 case kHIDUsage_GD_DPadDown:
224 handle = GamepadButton::dpad_down();
225 break;
226 case kHIDUsage_GD_DPadRight:
227 handle = GamepadButton::dpad_right();
228 break;
229 case kHIDUsage_GD_DPadLeft:
230 handle = GamepadButton::dpad_left();
231 break;
232 case 0xffffffffu:
233 return;
234 default:
235 break;
236 }
237 break;
238
239 case kHIDPage_Simulation:
240 switch (usage) {
241 case kHIDUsage_Sim_Rudder:
242 axis = Axis::rudder;
243 break;
244 case kHIDUsage_Sim_Throttle:
245 axis = Axis::throttle;
246 break;
247 case kHIDUsage_Sim_Accelerator:
248 axis = Axis::accelerator;
249 break;
250 case kHIDUsage_Sim_Brake:
251 axis = Axis::brake;
252 break;
253 }
254 break;
255 }
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) {
260 // T.Flight Hotas X throttle is reversed and can go backwards.
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))) {
264 // We'd like to reverse the Y axis to match the XInput behavior.
265 // We also reverse yaw to obey the right-hand rule.
266 add_axis(axis, max, min);
267 } else {
268 add_axis(axis, min, max);
269 }
270
271 _analog_elements.push_back(element);
272 }
273 break;
274
275 case kIOHIDElementTypeInput_Button:
276 switch (page) {
277 case kHIDPage_GenericDesktop:
278 switch (usage) {
279 case kHIDUsage_GD_DPadUp:
280 handle = GamepadButton::dpad_up();
281 break;
282 case kHIDUsage_GD_DPadDown:
283 handle = GamepadButton::dpad_down();
284 break;
285 case kHIDUsage_GD_DPadRight:
286 handle = GamepadButton::dpad_right();
287 break;
288 case kHIDUsage_GD_DPadLeft:
289 handle = GamepadButton::dpad_left();
290 break;
291 default:
292 break;
293 }
294 break;
295
296 case kHIDPage_KeyboardOrKeypad:
297 switch (usage) {
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:
324 handle = KeyboardButton::ascii_key('a' + (usage - kHIDUsage_KeyboardA));
325 break;
326 case kHIDUsage_Keyboard1:
327 handle = KeyboardButton::ascii_key('1');
328 break;
329 case kHIDUsage_Keyboard2:
330 handle = KeyboardButton::ascii_key('2');
331 break;
332 case kHIDUsage_Keyboard3:
333 handle = KeyboardButton::ascii_key('3');
334 break;
335 case kHIDUsage_Keyboard4:
336 handle = KeyboardButton::ascii_key('4');
337 break;
338 case kHIDUsage_Keyboard5:
339 handle = KeyboardButton::ascii_key('5');
340 break;
341 case kHIDUsage_Keyboard6:
342 handle = KeyboardButton::ascii_key('6');
343 break;
344 case kHIDUsage_Keyboard7:
345 handle = KeyboardButton::ascii_key('7');
346 break;
347 case kHIDUsage_Keyboard8:
348 handle = KeyboardButton::ascii_key('8');
349 break;
350 case kHIDUsage_Keyboard9:
351 handle = KeyboardButton::ascii_key('9');
352 break;
353 case kHIDUsage_Keyboard0:
354 handle = KeyboardButton::ascii_key('0');
355 break;
356 case kHIDUsage_KeyboardReturnOrEnter:
357 handle = KeyboardButton::enter();
358 break;
359 case kHIDUsage_KeyboardEscape:
360 handle = KeyboardButton::escape();
361 break;
362 case kHIDUsage_KeyboardDeleteOrBackspace:
363 handle = KeyboardButton::backspace();
364 break;
365 case kHIDUsage_KeyboardTab:
366 handle = KeyboardButton::tab();
367 break;
368 case kHIDUsage_KeyboardSpacebar:
369 handle = KeyboardButton::ascii_key(' ');
370 break;
371 case kHIDUsage_KeyboardHyphen:
372 handle = KeyboardButton::ascii_key('-');
373 break;
374 case kHIDUsage_KeyboardEqualSign:
375 handle = KeyboardButton::ascii_key('=');
376 break;
377 case kHIDUsage_KeyboardOpenBracket:
378 handle = KeyboardButton::ascii_key('[');
379 break;
380 case kHIDUsage_KeyboardCloseBracket:
381 handle = KeyboardButton::ascii_key(']');
382 break;
383 case kHIDUsage_KeyboardBackslash:
384 handle = KeyboardButton::ascii_key('\\');
385 break;
386 case kHIDUsage_KeyboardNonUSPound:
387 handle = KeyboardButton::ascii_key('$');
388 break;
389 case kHIDUsage_KeyboardSemicolon:
390 handle = KeyboardButton::ascii_key(';');
391 break;
392 case kHIDUsage_KeyboardQuote:
393 handle = KeyboardButton::ascii_key('\'');
394 break;
395 case kHIDUsage_KeyboardGraveAccentAndTilde:
396 handle = KeyboardButton::ascii_key('`');
397 break;
398 case kHIDUsage_KeyboardComma:
399 handle = KeyboardButton::ascii_key(',');
400 break;
401 case kHIDUsage_KeyboardPeriod:
402 handle = KeyboardButton::ascii_key('.');
403 break;
404 case kHIDUsage_KeyboardSlash:
405 handle = KeyboardButton::ascii_key('/');
406 break;
407 case kHIDUsage_KeyboardCapsLock:
408 handle = KeyboardButton::caps_lock();
409 break;
410 case kHIDUsage_KeyboardF1:
411 handle = KeyboardButton::f1();
412 break;
413 case kHIDUsage_KeyboardF2:
414 handle = KeyboardButton::f2();
415 break;
416 case kHIDUsage_KeyboardF3:
417 handle = KeyboardButton::f3();
418 break;
419 case kHIDUsage_KeyboardF4:
420 handle = KeyboardButton::f4();
421 break;
422 case kHIDUsage_KeyboardF5:
423 handle = KeyboardButton::f5();
424 break;
425 case kHIDUsage_KeyboardF6:
426 handle = KeyboardButton::f6();
427 break;
428 case kHIDUsage_KeyboardF7:
429 handle = KeyboardButton::f7();
430 break;
431 case kHIDUsage_KeyboardF8:
432 handle = KeyboardButton::f8();
433 break;
434 case kHIDUsage_KeyboardF9:
435 handle = KeyboardButton::f9();
436 break;
437 case kHIDUsage_KeyboardF10:
438 handle = KeyboardButton::f10();
439 break;
440 case kHIDUsage_KeyboardF11:
441 handle = KeyboardButton::f11();
442 break;
443 case kHIDUsage_KeyboardF12:
444 handle = KeyboardButton::f12();
445 break;
446 case kHIDUsage_KeyboardPrintScreen:
447 handle = KeyboardButton::print_screen();
448 break;
449 case kHIDUsage_KeyboardScrollLock:
450 handle = KeyboardButton::scroll_lock();
451 break;
452 case kHIDUsage_KeyboardPause:
453 handle = KeyboardButton::pause();
454 break;
455 case kHIDUsage_KeyboardInsert:
456 handle = KeyboardButton::insert();
457 break;
458 case kHIDUsage_KeyboardHome:
459 handle = KeyboardButton::home();
460 break;
461 case kHIDUsage_KeyboardPageUp:
462 handle = KeyboardButton::page_up();
463 break;
464 case kHIDUsage_KeyboardDeleteForward:
465 handle = KeyboardButton::del();
466 break;
467 case kHIDUsage_KeyboardEnd:
468 handle = KeyboardButton::end();
469 break;
470 case kHIDUsage_KeyboardPageDown:
471 handle = KeyboardButton::page_down();
472 break;
473 case kHIDUsage_KeyboardRightArrow:
474 handle = KeyboardButton::right();
475 break;
476 case kHIDUsage_KeyboardLeftArrow:
477 handle = KeyboardButton::left();
478 break;
479 case kHIDUsage_KeyboardDownArrow:
480 handle = KeyboardButton::down();
481 break;
482 case kHIDUsage_KeyboardUpArrow:
483 handle = KeyboardButton::up();
484 break;
485 case kHIDUsage_KeypadNumLock:
486 handle = KeyboardButton::num_lock();
487 break;
488 case kHIDUsage_KeypadSlash:
489 handle = KeyboardButton::ascii_key('/');
490 break;
491 case kHIDUsage_KeypadAsterisk:
492 handle = KeyboardButton::ascii_key('*');
493 break;
494 case kHIDUsage_KeypadHyphen:
495 handle = KeyboardButton::ascii_key('-');
496 break;
497 case kHIDUsage_KeypadPlus:
498 handle = KeyboardButton::ascii_key('+');
499 break;
500 case kHIDUsage_KeypadEnter:
501 handle = KeyboardButton::enter();
502 break;
503 case kHIDUsage_Keypad1:
504 handle = KeyboardButton::ascii_key('1');
505 break;
506 case kHIDUsage_Keypad2:
507 handle = KeyboardButton::ascii_key('2');
508 break;
509 case kHIDUsage_Keypad3:
510 handle = KeyboardButton::ascii_key('3');
511 break;
512 case kHIDUsage_Keypad4:
513 handle = KeyboardButton::ascii_key('4');
514 break;
515 case kHIDUsage_Keypad5:
516 handle = KeyboardButton::ascii_key('5');
517 break;
518 case kHIDUsage_Keypad6:
519 handle = KeyboardButton::ascii_key('6');
520 break;
521 case kHIDUsage_Keypad7:
522 handle = KeyboardButton::ascii_key('7');
523 break;
524 case kHIDUsage_Keypad8:
525 handle = KeyboardButton::ascii_key('8');
526 break;
527 case kHIDUsage_Keypad9:
528 handle = KeyboardButton::ascii_key('9');
529 break;
530 case kHIDUsage_Keypad0:
531 handle = KeyboardButton::ascii_key('0');
532 break;
533 case kHIDUsage_KeypadPeriod:
534 handle = KeyboardButton::ascii_key('.');
535 break;
536 case kHIDUsage_KeyboardNonUSBackslash:
537 handle = KeyboardButton::ascii_key('\\');
538 break;
539 case kHIDUsage_KeypadEqualSign:
540 handle = KeyboardButton::ascii_key('=');
541 break;
542 case kHIDUsage_KeyboardF13:
543 handle = KeyboardButton::f13();
544 break;
545 case kHIDUsage_KeyboardF14:
546 handle = KeyboardButton::f14();
547 break;
548 case kHIDUsage_KeyboardF15:
549 handle = KeyboardButton::f15();
550 break;
551 case kHIDUsage_KeyboardF16:
552 handle = KeyboardButton::f16();
553 break;
554 case kHIDUsage_KeyboardExecute:
555 break;
556 case kHIDUsage_KeyboardHelp:
557 handle = KeyboardButton::help();
558 break;
559 case kHIDUsage_KeyboardMenu:
560 handle = KeyboardButton::menu();
561 break;
562 case kHIDUsage_KeypadComma:
563 handle = KeyboardButton::ascii_key(',');
564 break;
565 case kHIDUsage_KeypadEqualSignAS400:
566 handle = KeyboardButton::ascii_key('=');
567 break;
568 case kHIDUsage_KeyboardReturn:
569 handle = KeyboardButton::enter();
570 break;
571 case kHIDUsage_KeyboardLeftControl:
572 handle = KeyboardButton::lcontrol();
573 break;
574 case kHIDUsage_KeyboardLeftShift:
575 handle = KeyboardButton::lshift();
576 break;
577 case kHIDUsage_KeyboardLeftAlt:
578 handle = KeyboardButton::lalt();
579 break;
580 case kHIDUsage_KeyboardLeftGUI:
581 handle = KeyboardButton::lmeta();
582 break;
583 case kHIDUsage_KeyboardRightControl:
584 handle = KeyboardButton::rcontrol();
585 break;
586 case kHIDUsage_KeyboardRightShift:
587 handle = KeyboardButton::rshift();
588 break;
589 case kHIDUsage_KeyboardRightAlt:
590 handle = KeyboardButton::ralt();
591 break;
592 case kHIDUsage_KeyboardRightGUI:
593 handle = KeyboardButton::rmeta();
594 break;
595 default:
596 break;
597 }
598 break;
599
600 case kHIDPage_Button:
601 if (_device_class == DeviceClass::gamepad) {
602 if (_vendor_id == 0x0810 && _product_id == 0xe501) {
603 // SNES-style USB gamepad
604 static const ButtonHandle gamepad_buttons[] = {
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(),
616 };
617 if (usage < sizeof(gamepad_buttons) / sizeof(ButtonHandle)) {
618 handle = gamepad_buttons[usage];
619 }
620 } else {
621 // These seem to be the button mappings exposed by the 360Controller
622 // driver. I don't know if other drivers do the same thing at all.
623 static const ButtonHandle gamepad_buttons[] = {
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(),
640 };
641 if (usage < sizeof(gamepad_buttons) / sizeof(ButtonHandle)) {
642 handle = gamepad_buttons[usage];
643 }
644 }
645 } else if (_device_class == DeviceClass::flight_stick) {
646 if (usage > 0) {
647 handle = GamepadButton::joystick(usage - 1);
648 }
649 } else if (_device_class == DeviceClass::mouse) {
650 // In Panda, wheel and right button are flipped around...
651 int button = (usage == 2 || usage == 3) ? (4 - usage) : (usage - 1);
652 handle = MouseButton::button(button);
653 }
654 break;
655 }
656 _buttons.push_back(ButtonState(handle));
657 _button_elements.push_back(element);
658 break;
659
660 case kIOHIDElementTypeInput_Axis:
661 break;
662
663 case kIOHIDElementTypeInput_ScanCodes:
664 break;
665
666 case kIOHIDElementTypeOutput:
667 break;
668
669 case kIOHIDElementTypeFeature:
670 break;
671
672 case kIOHIDElementTypeCollection:
673 {
674 // This doesn't seem to be necessary and instead leads to duplication of
675 // axes and buttons.
676 /*
677 CFArrayRef children = IOHIDElementGetChildren(element);
678 CFIndex count = CFArrayGetCount(children);
679 for (CFIndex i = 0; i < count; ++i) {
680 IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(children, i);
681 parse_element(element, depth + 2);
682 }*/
683 }
684 break;
685 }
686 }
687
688 /**
689 * Polls the input device for new activity, to ensure it contains the latest
690 * events. This will only have any effect for some types of input devices;
691 * others may be updated automatically, and this method will be a no-op.
692 */
693 void IOKitInputDevice::
694 do_poll() {
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);
701 }
702 }
703
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);
709 }
710 }
711
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); // left
717 button_changed(_hat_left_button + 1, value >= 1 && value <= 3); // right
718 button_changed(_hat_left_button + 2, value >= 3 && value <= 5); // down
719 button_changed(_hat_left_button + 3, value == 7 || value == 0 || value == 1); // up
720 }
721 }
722
723 int x = 0, y = 0;
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;
731 }
732 }
733 }
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;
741 }
742 }
743 }
744 if (x != 0 || y != 0) {
745 pointer_moved(0, x, y, ClockObject::get_global_clock()->get_frame_time());
746 }
747
748 // Do we have a scroll wheel axis?
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);
755 if (value != 0) {
756 // Just fire off a rapid down/up event.
757 double time = ClockObject::get_global_clock()->get_frame_time();
758 ButtonHandle handle = (value > 0) ? MouseButton::wheel_up() : MouseButton::wheel_down();
759 _button_events->add_event(ButtonEvent(handle, ButtonEvent::T_down, time));
760 _button_events->add_event(ButtonEvent(handle, ButtonEvent::T_up, time));
761 }
762 _scroll_wheel_timestamp = timestamp;
763 }
764 }
765 }
766 }
767
768 #endif // __APPLE__
ButtonEvent
Records a button event of some kind.
Definition: buttonEvent.h:46
ButtonHandle
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
ClockObject::get_frame_time
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Definition: clockObject.h:91
ClockObject::get_global_clock
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
GamepadButton::joystick
static ButtonHandle joystick(int button_number)
Returns the ButtonHandle associated with the particular numbered joystick button (zero-based),...
Definition: gamepadButton.cxx:64
KeyboardButton::ascii_key
static ButtonHandle ascii_key(char ascii_equivalent)
Returns the ButtonHandle associated with the particular ASCII character, if there is one,...
Definition: keyboardButton.cxx:24
MouseButton::button
static ButtonHandle button(int button_number)
Returns the ButtonHandle associated with the particular numbered mouse button (zero-based),...
Definition: mouseButton.cxx:32
MouseButton::wheel_up
static ButtonHandle wheel_up()
Returns the ButtonHandle generated when the mouse wheel is rolled one notch upwards.
Definition: mouseButton.cxx:84
MouseButton::wheel_down
static ButtonHandle wheel_down()
Returns the ButtonHandle generated when the mouse wheel is rolled one notch downwards.
Definition: mouseButton.cxx:93
gamepadButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ioKitInputDevice.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
keyboardButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
mouseButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.