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__
Records a button event of some kind.
Definition: buttonEvent.h:46
A ButtonHandle represents a single button from any device, including keyboard buttons and mouse butto...
Definition: buttonHandle.h:26
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
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
static ButtonHandle joystick(int button_number)
Returns the ButtonHandle associated with the particular numbered joystick button (zero-based),...
static ButtonHandle ascii_key(char ascii_equivalent)
Returns the ButtonHandle associated with the particular ASCII character, if there is one,...
static ButtonHandle button(int button_number)
Returns the ButtonHandle associated with the particular numbered mouse button (zero-based),...
Definition: mouseButton.cxx:32
static ButtonHandle wheel_up()
Returns the ButtonHandle generated when the mouse wheel is rolled one notch upwards.
Definition: mouseButton.cxx:84
static ButtonHandle wheel_down()
Returns the ButtonHandle generated when the mouse wheel is rolled one notch downwards.
Definition: mouseButton.cxx:93
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.