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.
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
mouseButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ButtonHandle
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
ClockObject::get_global_clock
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
keyboardButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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
GamepadButton::joystick
static ButtonHandle joystick(int button_number)
Returns the ButtonHandle associated with the particular numbered joystick button (zero-based),...
Definition: gamepadButton.cxx:64
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
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
ioKitInputDevice.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
gamepadButton.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.