16 #ifdef PHAVE_LINUX_INPUT_H
24 #include <linux/input.h>
27 #define BTN_DPAD_UP 0x220
28 #define BTN_DPAD_DOWN 0x221
29 #define BTN_DPAD_LEFT 0x222
30 #define BTN_DPAD_RIGHT 0x223
35 #ifndef BTN_TRIGGER_HAPPY
36 #define BTN_TRIGGER_HAPPY 0x2c0
37 #define BTN_TRIGGER_HAPPY1 0x2c0
38 #define BTN_TRIGGER_HAPPY2 0x2c1
39 #define BTN_TRIGGER_HAPPY3 0x2c2
40 #define BTN_TRIGGER_HAPPY4 0x2c3
43 #define test_bit(bit, array) ((array)[(bit)>>3] & (1<<((bit)&7)))
50 QB_centered_throttle = 2,
53 QB_reversed_throttle = 4,
56 QB_connect_if_nonzero = 8,
59 QB_rudder_from_throttle = 16,
64 QB_steam_controller = 32,
67 QB_right_axes_swapped = 64,
70 QB_no_analog_triggers = 128,
73 QB_alt_button_mapping = 256,
76 static const struct DeviceMapping {
77 unsigned short vendor;
78 unsigned short product;
79 InputDevice::DeviceClass device_class;
81 } mapping_presets[] = {
83 {0x0955, 0x7214, InputDevice::DeviceClass::gamepad, QB_rstick_from_z},
85 {0x044f, 0xb108, InputDevice::DeviceClass::flight_stick, QB_centered_throttle | QB_reversed_throttle | QB_rudder_from_throttle},
87 {0x045e, 0x0719, InputDevice::DeviceClass::gamepad, QB_connect_if_nonzero},
89 {0x28de, 0x1102, InputDevice::DeviceClass::unknown, QB_steam_controller},
91 {0x28de, 0x1142, InputDevice::DeviceClass::unknown, QB_steam_controller},
93 {0x0f30, 0x0111, InputDevice::DeviceClass::gamepad, QB_rstick_from_z | QB_right_axes_swapped},
95 {0x0079, 0x0006, InputDevice::DeviceClass::gamepad, QB_no_analog_triggers | QB_alt_button_mapping},
97 {0x2dc8, 0x9001, InputDevice::DeviceClass::gamepad, QB_rstick_from_z},
99 {0x0810, 0x0001, InputDevice::DeviceClass::gamepad, QB_no_analog_triggers | QB_alt_button_mapping | QB_rstick_from_z | QB_right_axes_swapped},
101 {0x0810, 0xe501, InputDevice::DeviceClass::gamepad, QB_no_analog_triggers | QB_alt_button_mapping},
103 {0x046d, 0xc623, InputDevice::DeviceClass::spatial_mouse, 0},
105 {0x046d, 0xc625, InputDevice::DeviceClass::spatial_mouse, 0},
107 {0x046d, 0xc626, InputDevice::DeviceClass::spatial_mouse, 0},
109 {0x046d, 0xc627, InputDevice::DeviceClass::spatial_mouse, 0},
111 {0x046d, 0xc628, InputDevice::DeviceClass::spatial_mouse, 0},
113 {0x046d, 0xc629, InputDevice::DeviceClass::spatial_mouse, 0},
115 {0x046d, 0xc62b, InputDevice::DeviceClass::spatial_mouse, 0},
125 EvdevInputDevice(LinuxInputDeviceManager *manager,
size_t index) :
136 _dpad_left_button(-1),
143 sprintf(path,
"/dev/input/event%zd", index);
145 _fd = open(path, O_RDWR | O_NONBLOCK);
150 _fd = open(path, O_RDONLY | O_NONBLOCK);
156 _is_connected =
false;
158 <<
"Opening raw input device: " << strerror(errno) <<
" " << path <<
"\n";
166 ~EvdevInputDevice() {
170 do_set_vibration(0, 0);
171 ioctl(_fd, EVIOCRMFF, _ff_id);
185 void EvdevInputDevice::
186 do_set_vibration(
double strong,
double weak) {
187 if (_fd == -1 || !_can_write) {
191 int strong_level = strong * 0xffff;
192 int weak_level = weak * 0xffff;
194 if (strong_level == _ff_strong && weak_level == _ff_weak) {
202 struct ff_effect effect;
203 effect.type = FF_RUMBLE;
205 effect.direction = 0;
206 effect.trigger.button = 0;
207 effect.trigger.interval = 0;
208 effect.replay.length = 0;
209 effect.replay.delay = 0;
210 effect.u.rumble.strong_magnitude = strong_level;
211 effect.u.rumble.weak_magnitude = weak_level;
213 if (ioctl(_fd, EVIOCSFF, &effect) < 0) {
217 _ff_strong = strong_level;
218 _ff_weak = weak_level;
226 struct input_event play;
231 if (write(_fd, &play,
sizeof(play)) < 0) {
233 <<
"Failed to write force-feedback event: " << strerror(errno) <<
"\n";
244 bool EvdevInputDevice::
245 reactivate_steam_controller() {
247 if (!_is_connected && (_quirks & QB_steam_controller) != 0) {
251 _is_connected =
true;
263 void EvdevInputDevice::
265 if (_fd != -1 && process_events()) {
266 while (process_events()) {}
269 if (!_is_connected && _fd != -1) {
270 _is_connected =
true;
271 if (_manager !=
nullptr) {
272 _manager->add_device(
this);
281 bool EvdevInputDevice::
285 nassertr(_fd >= 0,
false);
289 uint8_t evtypes[(EV_MAX + 8) >> 3] = {0};
291 if (ioctl(_fd, EVIOCGNAME(
sizeof(name)), name) < 0 ||
292 ioctl(_fd, EVIOCGBIT(0,
sizeof(evtypes)), evtypes) < 0) {
295 _is_connected =
false;
296 device_cat.error() <<
"Opening raw input device: ioctl failed\n";
304 if (ioctl(_fd, EVIOCGID, &
id) >= 0) {
305 _vendor_id =
id.vendor;
306 _product_id =
id.product;
309 bool all_values_zero =
true;
310 bool emulate_dpad =
true;
311 bool have_analog_triggers =
false;
313 bool has_keys =
false;
314 bool has_axes =
false;
316 uint8_t keys[(KEY_MAX + 8) >> 3] = {0};
317 if (test_bit(EV_KEY, evtypes)) {
319 ioctl(_fd, EVIOCGBIT(EV_KEY,
sizeof(keys)), keys);
322 if (test_bit(KEY_A, keys) && test_bit(KEY_Z, keys)) {
323 enable_feature(Feature::keyboard);
328 uint8_t axes[(ABS_MAX + 8) >> 3] = {0};
329 if (test_bit(EV_ABS, evtypes)) {
331 int result = ioctl(_fd, EVIOCGBIT(EV_ABS,
sizeof(axes)), axes);
335 for (
int i = ABS_MAX; i >= 0; --i) {
336 if (test_bit(i, axes)) {
345 num_bits = result << 3;
352 const DeviceMapping *mapping = mapping_presets;
353 while (mapping->vendor != 0) {
354 if (_vendor_id == mapping->vendor && _product_id == mapping->product) {
355 _device_class = mapping->device_class;
356 quirks = mapping->quirks;
363 if (quirks & QB_steam_controller) {
364 if (test_bit(BTN_GAMEPAD, keys)) {
365 _device_class = DeviceClass::gamepad;
371 if (_manager->has_virtual_device(0x28de, 0x11ff)) {
373 <<
"Detected Steam virtual gamepad, disabling Steam Controller\n";
374 quirks |= QB_connect_if_nonzero;
381 if (_device_class == DeviceClass::unknown) {
382 int device_scores[(size_t)DeviceClass::digitizer + 1] = {0};
385 if (test_bit(BTN_GAMEPAD, keys) && test_bit(ABS_X, axes) && test_bit(ABS_RX, axes)) {
386 device_scores[(size_t)DeviceClass::gamepad] += 5;
387 device_scores[(size_t)DeviceClass::steering_wheel] += 5;
388 device_scores[(size_t)DeviceClass::flight_stick] += 5;
391 if (test_bit(ABS_WHEEL, axes) && test_bit(ABS_GAS, axes) && test_bit(ABS_BRAKE, axes)) {
392 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
394 if (test_bit(BTN_GEAR_DOWN, keys) && test_bit(BTN_GEAR_UP, keys)) {
395 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
397 if (test_bit(BTN_JOYSTICK, keys) && test_bit(ABS_X, axes)) {
398 device_scores[(size_t)DeviceClass::flight_stick] += 10;
400 if (test_bit(BTN_MOUSE, keys) && test_bit(EV_REL, evtypes)) {
401 device_scores[(size_t)DeviceClass::mouse] += 20;
403 if (test_bit(BTN_DIGI, keys) && test_bit(EV_ABS, evtypes)) {
404 device_scores[(size_t)DeviceClass::digitizer] += 20;
406 uint8_t unknown_keys[] = {KEY_POWER};
407 for (
int i = 0; i < 1; i++) {
408 if (test_bit(unknown_keys[i], keys)) {
409 if (unknown_keys[i] == KEY_POWER) {
411 device_scores[(size_t)DeviceClass::unknown] += 20;
414 if (_features & (
unsigned int)Feature::keyboard) {
415 device_scores[(size_t)DeviceClass::keyboard] += 20;
419 string lowercase_name = _name;
420 for(
size_t x = 0; x < _name.length(); ++x) {
421 lowercase_name[x] = tolower(lowercase_name[x]);
423 if (lowercase_name.find(
"gamepad") != string::npos) {
424 device_scores[(size_t)DeviceClass::gamepad] += 10;
426 if (lowercase_name.find(
"wheel") != string::npos) {
427 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
429 if (lowercase_name.find(
"mouse") != string::npos || lowercase_name.find(
"touchpad") != string::npos) {
430 device_scores[(size_t)DeviceClass::mouse] += 10;
432 if (lowercase_name.find(
"keyboard") != string::npos) {
433 device_scores[(size_t)DeviceClass::keyboard] += 10;
436 string unknown_names[] = {
"video bus",
"power button",
"sleep button"};
437 for(
int i = 0; i < 3; i++) {
438 if (lowercase_name.find(unknown_names[i]) != string::npos) {
439 device_scores[(size_t)DeviceClass::unknown] += 20;
444 int highest_score = 0;
445 for (
size_t i = 0; i <= (size_t)DeviceClass::digitizer; i++) {
446 if (device_scores[i] > highest_score) {
447 highest_score = device_scores[i];
448 _device_class = (DeviceClass)i;
456 uint8_t states[(KEY_MAX + 8) >> 3] = {0};
457 ioctl(_fd, EVIOCGKEY(
sizeof(states)), states);
459 for (
int i = 0; i <= KEY_MAX; ++i) {
460 if (test_bit(i, keys)) {
462 button.handle = map_button(i, _device_class, quirks);
464 int button_index = (int)_buttons.size();
465 if (button.handle == ButtonHandle::none()) {
466 if (device_cat.is_debug()) {
467 device_cat.debug() <<
"Unmapped /dev/input/event" << _index
468 <<
" button " << button_index <<
": 0x" << std::hex << i << std::dec <<
"\n";
472 if (test_bit(i, states)) {
473 button._state = S_down;
474 all_values_zero =
false;
476 button._state = S_up;
478 if (button.handle == GamepadButton::dpad_left()) {
479 emulate_dpad =
false;
480 }
else if (button.handle == GamepadButton::ltrigger()) {
482 }
else if (button.handle == GamepadButton::rtrigger()) {
486 _buttons.push_back(button);
487 if ((
size_t)i >= _button_indices.size()) {
488 _button_indices.resize(i + 1, -1);
490 _button_indices[i] = button_index;
496 _axis_indices.resize(num_bits, -1);
498 for (
int i = 0; i < num_bits; ++i) {
499 if (test_bit(i, axes)) {
500 Axis axis = Axis::none;
503 if (_device_class == DeviceClass::gamepad) {
504 axis = InputDevice::Axis::left_x;
505 }
else if (_device_class == DeviceClass::flight_stick) {
506 axis = InputDevice::Axis::roll;
508 axis = InputDevice::Axis::x;
512 if (_device_class == DeviceClass::gamepad) {
513 axis = InputDevice::Axis::left_y;
514 }
else if (_device_class == DeviceClass::flight_stick) {
515 axis = InputDevice::Axis::pitch;
517 axis = InputDevice::Axis::y;
521 if (quirks & QB_rstick_from_z) {
522 if (quirks & QB_right_axes_swapped) {
523 axis = InputDevice::Axis::right_y;
525 axis = InputDevice::Axis::right_x;
527 }
else if (_device_class == DeviceClass::gamepad) {
528 if ((quirks & QB_no_analog_triggers) == 0) {
529 axis = InputDevice::Axis::left_trigger;
530 have_analog_triggers =
true;
532 }
else if (_device_class == DeviceClass::spatial_mouse) {
533 axis = InputDevice::Axis::z;
535 axis = InputDevice::Axis::throttle;
539 if (_device_class == DeviceClass::spatial_mouse) {
540 axis = InputDevice::Axis::pitch;
541 }
else if ((quirks & QB_rstick_from_z) == 0) {
542 axis = InputDevice::Axis::right_x;
546 if (_device_class == DeviceClass::spatial_mouse) {
547 axis = InputDevice::Axis::roll;
548 }
else if ((quirks & QB_rstick_from_z) == 0) {
549 axis = InputDevice::Axis::right_y;
553 if (quirks & QB_rstick_from_z) {
554 if (quirks & QB_right_axes_swapped) {
555 axis = InputDevice::Axis::right_x;
557 axis = InputDevice::Axis::right_y;
559 }
else if (_device_class == DeviceClass::gamepad) {
560 if ((quirks & QB_no_analog_triggers) == 0) {
561 axis = InputDevice::Axis::right_trigger;
562 have_analog_triggers =
true;
565 axis = InputDevice::Axis::right_y;
568 axis = InputDevice::Axis::yaw;
572 if (quirks & QB_rudder_from_throttle) {
573 axis = InputDevice::Axis::rudder;
575 axis = InputDevice::Axis::throttle;
579 axis = InputDevice::Axis::rudder;
582 axis = InputDevice::Axis::wheel;
585 if (_device_class == DeviceClass::gamepad) {
586 if ((quirks & QB_no_analog_triggers) == 0) {
587 axis = InputDevice::Axis::right_trigger;
588 have_analog_triggers =
true;
591 axis = InputDevice::Axis::accelerator;
595 if (_device_class == DeviceClass::gamepad) {
596 axis = InputDevice::Axis::left_trigger;
597 have_analog_triggers =
true;
599 axis = InputDevice::Axis::brake;
605 _dpad_left_button = (int)_buttons.size();
606 if (_device_class == DeviceClass::gamepad) {
607 _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
608 _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
610 _buttons.push_back(ButtonState(GamepadButton::hat_left()));
611 _buttons.push_back(ButtonState(GamepadButton::hat_right()));
613 _buttons[_dpad_left_button]._state = S_up;
614 _buttons[_dpad_left_button+1]._state = S_up;
620 _dpad_up_button = (int)_buttons.size();
621 if (_device_class == DeviceClass::gamepad) {
622 _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
623 _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
625 _buttons.push_back(ButtonState(GamepadButton::hat_up()));
626 _buttons.push_back(ButtonState(GamepadButton::hat_down()));
628 _buttons[_dpad_up_button]._state = S_up;
629 _buttons[_dpad_up_button+1]._state = S_up;
633 if (quirks & QB_steam_controller) {
634 axis = InputDevice::Axis::right_trigger;
635 have_analog_triggers =
true;
639 if (quirks & QB_steam_controller) {
640 axis = InputDevice::Axis::left_trigger;
641 have_analog_triggers =
true;
645 axis = InputDevice::Axis::pressure;
650 struct input_absinfo absinfo;
651 if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) {
656 if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y ||
657 (axis == Axis::throttle && (quirks & QB_reversed_throttle) != 0) ||
658 (_device_class == DeviceClass::spatial_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll)) ||
659 (_device_class == DeviceClass::digitizer && axis == Axis::y)) {
660 std::swap(absinfo.maximum, absinfo.minimum);
662 if (axis == Axis::throttle && (quirks & QB_centered_throttle) != 0) {
663 index = add_axis(axis, absinfo.minimum, absinfo.maximum,
true);
665 index = add_axis(axis, absinfo.minimum, absinfo.maximum);
667 axis_changed(index, absinfo.value);
668 _axis_indices[i] = index;
670 if (absinfo.value != 0) {
671 all_values_zero =
false;
678 if (test_bit(EV_REL, evtypes)) {
679 enable_feature(Feature::pointer);
680 add_pointer(PointerType::unknown, 0);
683 if (test_bit(EV_FF, evtypes)) {
684 uint8_t effects[(FF_MAX + 8) >> 3] = {0};
685 ioctl(_fd, EVIOCGBIT(EV_FF,
sizeof(effects)), effects);
687 if (test_bit(FF_RUMBLE, effects)) {
689 enable_feature(Feature::vibration);
693 <<
"/dev/input/event" << _index <<
" is not writable, vibration "
694 <<
"effects will be unavailable.\n";
699 if (_ltrigger_code >= 0 && _rtrigger_code >= 0 && !have_analog_triggers) {
701 _ltrigger_axis = (int)_axes.size();
702 add_axis(Axis::left_trigger, 0, 1,
false);
703 add_axis(Axis::right_trigger, 0, 1,
false);
712 const char *parent =
"";
713 sprintf(path,
"/sys/class/input/event%zd/device/device/../product", _index);
714 FILE *f = fopen(path,
"r");
717 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../product", _index, parent);
718 f = fopen(path,
"r");
721 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
722 buffer[strcspn(buffer,
"\r\n")] = 0;
723 if (buffer[0] != 0) {
724 _name.assign(buffer);
729 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../manufacturer", _index, parent);
730 f = fopen(path,
"r");
732 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
733 buffer[strcspn(buffer,
"\r\n")] = 0;
734 _manufacturer.assign(buffer);
738 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../serial", _index, parent);
739 f = fopen(path,
"r");
741 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
742 buffer[strcspn(buffer,
"\r\n")] = 0;
743 _serial_number.assign(buffer);
752 if (all_values_zero && (quirks & QB_connect_if_nonzero) != 0) {
753 _is_connected =
false;
755 _is_connected =
true;
764 bool EvdevInputDevice::
767 struct input_event events[8];
769 int n_read = read(_fd, events,
sizeof(events));
771 if (errno == EAGAIN || errno == EWOULDBLOCK) {
774 }
else if (errno == ENODEV || errno == EINVAL) {
784 device_cat.error() <<
"read: " << strerror(errno) <<
"\n";
793 n_read /=
sizeof(
struct input_event);
802 if (n_read == 1 && events[0].code == EV_SYN) {
806 for (
int i = 0; i < n_read; ++i) {
807 int code = events[i].code;
809 switch (events[i].type) {
814 if (code == REL_X) rel_x += events[i].value;
815 if (code == REL_Y) rel_y += events[i].value;
819 if (code == _dpad_x_axis) {
820 button_changed(_dpad_left_button, events[i].value < 0);
821 button_changed(_dpad_left_button+1, events[i].value > 0);
822 }
else if (code == _dpad_y_axis) {
823 button_changed(_dpad_up_button, events[i].value < 0);
824 button_changed(_dpad_up_button+1, events[i].value > 0);
826 if (code >= 0 && (
size_t)code < _axis_indices.size()) {
827 index = _axis_indices[code];
829 axis_changed(index, events[i].value);
832 else if (device_cat.is_debug()) {
834 <<
"Ignoring EV_ABS event with unknown code " << code <<
"\n";
839 if (code >= 0 && (
size_t)code < _button_indices.size()) {
840 index = _button_indices[code];
842 button_changed(index, events[i].value != 0);
844 if (code == _ltrigger_code) {
845 axis_changed(_ltrigger_axis, events[i].value);
846 }
else if (code == _rtrigger_code) {
847 axis_changed(_ltrigger_axis + 1, events[i].value);
850 else if (device_cat.is_debug()) {
852 <<
"Ignoring EV_KEY event with unknown code " << code <<
"\n";
862 if (rel_x != 0 || rel_y != 0) {
863 pointer_moved(0, rel_x, rel_y, time);
873 map_button(
int code, DeviceClass device_class,
int quirks) {
874 if (code >= 0 && code < 0x80) {
877 ButtonHandle::none(),
878 KeyboardButton::escape(),
891 KeyboardButton::backspace(),
892 KeyboardButton::tab(),
905 KeyboardButton::enter(),
906 KeyboardButton::lcontrol(),
919 KeyboardButton::lshift(),
931 KeyboardButton::rshift(),
933 KeyboardButton::lalt(),
934 KeyboardButton::space(),
935 KeyboardButton::caps_lock(),
936 KeyboardButton::f1(),
937 KeyboardButton::f2(),
938 KeyboardButton::f3(),
939 KeyboardButton::f4(),
940 KeyboardButton::f5(),
941 KeyboardButton::f6(),
942 KeyboardButton::f7(),
943 KeyboardButton::f8(),
944 KeyboardButton::f9(),
945 KeyboardButton::f10(),
946 KeyboardButton::num_lock(),
947 KeyboardButton::scroll_lock(),
961 ButtonHandle::none(),
962 ButtonHandle::none(),
963 ButtonHandle::none(),
964 KeyboardButton::f11(),
965 KeyboardButton::f12(),
966 ButtonHandle::none(),
967 ButtonHandle::none(),
968 ButtonHandle::none(),
969 ButtonHandle::none(),
970 ButtonHandle::none(),
971 ButtonHandle::none(),
972 ButtonHandle::none(),
973 KeyboardButton::enter(),
974 KeyboardButton::rcontrol(),
976 KeyboardButton::print_screen(),
977 KeyboardButton::ralt(),
978 ButtonHandle::none(),
979 KeyboardButton::home(),
980 KeyboardButton::up(),
981 KeyboardButton::page_up(),
982 KeyboardButton::left(),
983 KeyboardButton::right(),
984 KeyboardButton::end(),
985 KeyboardButton::down(),
986 KeyboardButton::page_down(),
987 KeyboardButton::insert(),
988 KeyboardButton::del(),
989 ButtonHandle::none(),
990 ButtonHandle::none(),
991 ButtonHandle::none(),
992 ButtonHandle::none(),
993 ButtonHandle::none(),
994 ButtonHandle::none(),
995 ButtonHandle::none(),
996 KeyboardButton::pause(),
997 ButtonHandle::none(),
998 ButtonHandle::none(),
999 ButtonHandle::none(),
1000 ButtonHandle::none(),
1001 ButtonHandle::none(),
1002 KeyboardButton::lmeta(),
1003 KeyboardButton::rmeta(),
1004 KeyboardButton::menu(),
1006 return keyboard_map[code];
1008 }
else if (code == KEY_BACK) {
1010 return GamepadButton::back();
1012 }
else if (code == KEY_SEARCH) {
1014 return GamepadButton::guide();
1016 }
else if (code < 0x100) {
1017 return ButtonHandle::none();
1019 }
else if ((code & 0xfff0) == BTN_MOUSE) {
1021 if (code == BTN_RIGHT) {
1023 }
else if (code == BTN_MIDDLE) {
1029 }
else if ((code & 0xfff0) == BTN_JOYSTICK) {
1030 if (quirks & QB_steam_controller) {
1032 return ButtonHandle::none();
1034 }
else if (device_class == DeviceClass::gamepad &&
1035 (quirks & QB_alt_button_mapping) != 0) {
1037 GamepadButton::face_y(),
1038 GamepadButton::face_b(),
1039 GamepadButton::face_a(),
1040 GamepadButton::face_x(),
1041 GamepadButton::lshoulder(),
1042 GamepadButton::rshoulder(),
1043 GamepadButton::ltrigger(),
1044 GamepadButton::rtrigger(),
1045 GamepadButton::back(),
1046 GamepadButton::start(),
1047 GamepadButton::lstick(),
1048 GamepadButton::rstick(),
1050 if ((code & 0xf) < 12) {
1051 return mapping[code & 0xf];
1054 }
else if (device_class == DeviceClass::gamepad) {
1057 GamepadButton::face_x(),
1058 GamepadButton::face_y(),
1059 GamepadButton::face_a(),
1060 GamepadButton::face_b(),
1061 GamepadButton::lshoulder(),
1062 GamepadButton::ltrigger(),
1063 GamepadButton::rshoulder(),
1064 GamepadButton::rtrigger(),
1065 GamepadButton::back(),
1066 GamepadButton::start(),
1067 GamepadButton::lstick(),
1068 GamepadButton::rstick(),
1070 if ((code & 0xf) < 12) {
1071 return mapping[code & 0xf];
1080 return GamepadButton::face_a();
1083 return GamepadButton::face_b();
1086 return GamepadButton::face_c();
1089 return GamepadButton::face_x();
1092 return GamepadButton::face_y();
1095 return GamepadButton::face_z();
1098 return GamepadButton::lshoulder();
1101 return GamepadButton::rshoulder();
1104 return GamepadButton::ltrigger();
1107 return GamepadButton::rtrigger();
1110 return GamepadButton::face_1();
1113 return GamepadButton::face_2();
1117 return GamepadButton::back();
1121 return GamepadButton::start();
1124 return GamepadButton::guide();
1127 return GamepadButton::lstick();
1130 return GamepadButton::rstick();
1133 case BTN_TRIGGER_HAPPY1:
1134 return GamepadButton::dpad_left();
1136 case BTN_DPAD_RIGHT:
1137 case BTN_TRIGGER_HAPPY2:
1138 return GamepadButton::dpad_right();
1141 case BTN_TRIGGER_HAPPY3:
1142 return GamepadButton::dpad_up();
1145 case BTN_TRIGGER_HAPPY4:
1146 return GamepadButton::dpad_down();
1150 return GamepadButton::lgrip();
1153 return GamepadButton::rgrip();
1156 return ButtonHandle::none();
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.
Similar to MutexHolder, but for a light mutex.
TypeHandle is the identifier used to differentiate C++ class types.