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,
76static 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},
117 {0x0483, 0x5720, InputDevice::DeviceClass::flight_stick, 0},
127EvdevInputDevice(LinuxInputDeviceManager *manager,
size_t index) :
138 _dpad_left_button(-1),
145 sprintf(path,
"/dev/input/event%zd", index);
147 _fd = open(path, O_RDWR | O_NONBLOCK);
152 _fd = open(path, O_RDONLY | O_NONBLOCK);
158 _is_connected =
false;
160 <<
"Opening raw input device: " << strerror(errno) <<
" " << path <<
"\n";
172 do_set_vibration(0, 0);
173 ioctl(_fd, EVIOCRMFF, _ff_id);
187void EvdevInputDevice::
188do_set_vibration(
double strong,
double weak) {
189 if (_fd == -1 || !_can_write) {
193 int strong_level = strong * 0xffff;
194 int weak_level = weak * 0xffff;
196 if (strong_level == _ff_strong && weak_level == _ff_weak) {
204 struct ff_effect effect;
205 effect.type = FF_RUMBLE;
207 effect.direction = 0;
208 effect.trigger.button = 0;
209 effect.trigger.interval = 0;
210 effect.replay.length = 0;
211 effect.replay.delay = 0;
212 effect.u.rumble.strong_magnitude = strong_level;
213 effect.u.rumble.weak_magnitude = weak_level;
215 if (ioctl(_fd, EVIOCSFF, &effect) < 0) {
219 _ff_strong = strong_level;
220 _ff_weak = weak_level;
228 struct input_event play;
233 if (write(_fd, &play,
sizeof(play)) < 0) {
235 <<
"Failed to write force-feedback event: " << strerror(errno) <<
"\n";
246bool EvdevInputDevice::
247reactivate_steam_controller() {
249 if (!_is_connected && (_quirks & QB_steam_controller) != 0) {
253 _is_connected =
true;
265void EvdevInputDevice::
267 if (_fd != -1 && process_events()) {
268 while (process_events()) {}
271 if (!_is_connected && _fd != -1) {
272 _is_connected =
true;
273 if (_manager !=
nullptr) {
274 _manager->add_device(
this);
283bool EvdevInputDevice::
287 nassertr(_fd >= 0,
false);
291 uint8_t evtypes[(EV_MAX + 8) >> 3] = {0};
293 if (ioctl(_fd, EVIOCGNAME(
sizeof(name)), name) < 0 ||
294 ioctl(_fd, EVIOCGBIT(0,
sizeof(evtypes)), evtypes) < 0) {
297 _is_connected =
false;
298 device_cat.error() <<
"Opening raw input device: ioctl failed\n";
306 if (ioctl(_fd, EVIOCGID, &
id) >= 0) {
307 _vendor_id =
id.vendor;
308 _product_id =
id.product;
311 bool all_values_zero =
true;
312 bool emulate_dpad =
true;
313 bool have_analog_triggers =
false;
315 bool has_keys =
false;
316 bool has_axes =
false;
318 uint8_t keys[(KEY_MAX + 8) >> 3] = {0};
319 if (test_bit(EV_KEY, evtypes)) {
321 ioctl(_fd, EVIOCGBIT(EV_KEY,
sizeof(keys)), keys);
324 if (test_bit(KEY_A, keys) && test_bit(KEY_Z, keys)) {
325 enable_feature(Feature::keyboard);
330 uint8_t axes[(ABS_MAX + 8) >> 3] = {0};
331 if (test_bit(EV_ABS, evtypes)) {
333 int result = ioctl(_fd, EVIOCGBIT(EV_ABS,
sizeof(axes)), axes);
337 for (
int i = ABS_MAX; i >= 0; --i) {
338 if (test_bit(i, axes)) {
347 num_bits = result << 3;
354 const DeviceMapping *mapping = mapping_presets;
355 while (mapping->vendor != 0) {
356 if (_vendor_id == mapping->vendor && _product_id == mapping->product) {
357 _device_class = mapping->device_class;
358 quirks = mapping->quirks;
365 if (quirks & QB_steam_controller) {
366 if (test_bit(BTN_GAMEPAD, keys)) {
367 _device_class = DeviceClass::gamepad;
373 if (_manager->has_virtual_device(0x28de, 0x11ff)) {
375 <<
"Detected Steam virtual gamepad, disabling Steam Controller\n";
376 quirks |= QB_connect_if_nonzero;
383 if (_device_class == DeviceClass::unknown) {
384 int device_scores[(size_t)DeviceClass::digitizer + 1] = {0};
387 if (test_bit(BTN_GAMEPAD, keys) && test_bit(ABS_X, axes) && test_bit(ABS_RX, axes)) {
388 device_scores[(size_t)DeviceClass::gamepad] += 5;
389 device_scores[(size_t)DeviceClass::steering_wheel] += 5;
390 device_scores[(size_t)DeviceClass::flight_stick] += 5;
393 if (test_bit(ABS_WHEEL, axes) && test_bit(ABS_GAS, axes) && test_bit(ABS_BRAKE, axes)) {
394 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
396 if (test_bit(BTN_GEAR_DOWN, keys) && test_bit(BTN_GEAR_UP, keys)) {
397 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
399 if (test_bit(BTN_JOYSTICK, keys) && test_bit(ABS_X, axes)) {
400 device_scores[(size_t)DeviceClass::flight_stick] += 10;
402 if (test_bit(BTN_MOUSE, keys) && test_bit(EV_REL, evtypes)) {
403 device_scores[(size_t)DeviceClass::mouse] += 20;
405 if (test_bit(BTN_DIGI, keys) && test_bit(EV_ABS, evtypes)) {
406 device_scores[(size_t)DeviceClass::digitizer] += 20;
408 uint8_t unknown_keys[] = {KEY_POWER};
409 for (
int i = 0; i < 1; i++) {
410 if (test_bit(unknown_keys[i], keys)) {
411 if (unknown_keys[i] == KEY_POWER) {
413 device_scores[(size_t)DeviceClass::unknown] += 20;
416 if (_features & (
unsigned int)Feature::keyboard) {
417 device_scores[(size_t)DeviceClass::keyboard] += 20;
421 string lowercase_name = _name;
422 for(
size_t x = 0; x < _name.length(); ++x) {
423 lowercase_name[x] = tolower(lowercase_name[x]);
425 if (lowercase_name.find(
"gamepad") != string::npos) {
426 device_scores[(size_t)DeviceClass::gamepad] += 10;
428 if (lowercase_name.find(
"wheel") != string::npos) {
429 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
431 if (lowercase_name.find(
"mouse") != string::npos || lowercase_name.find(
"touchpad") != string::npos) {
432 device_scores[(size_t)DeviceClass::mouse] += 10;
434 if (lowercase_name.find(
"keyboard") != string::npos) {
435 device_scores[(size_t)DeviceClass::keyboard] += 10;
438 string unknown_names[] = {
"video bus",
"power button",
"sleep button"};
439 for(
int i = 0; i < 3; i++) {
440 if (lowercase_name.find(unknown_names[i]) != string::npos) {
441 device_scores[(size_t)DeviceClass::unknown] += 20;
446 int highest_score = 0;
447 for (
size_t i = 0; i <= (size_t)DeviceClass::digitizer; i++) {
448 if (device_scores[i] > highest_score) {
449 highest_score = device_scores[i];
450 _device_class = (DeviceClass)i;
458 uint8_t states[(KEY_MAX + 8) >> 3] = {0};
459 ioctl(_fd, EVIOCGKEY(
sizeof(states)), states);
461 for (
int i = 0; i <= KEY_MAX; ++i) {
462 if (test_bit(i, keys)) {
464 button.handle = map_button(i, _device_class, quirks);
466 int button_index = (int)_buttons.size();
467 if (button.handle == ButtonHandle::none()) {
468 if (device_cat.is_debug()) {
469 device_cat.debug() <<
"Unmapped /dev/input/event" << _index
470 <<
" button " << button_index <<
": 0x" << std::hex << i << std::dec <<
"\n";
474 if (test_bit(i, states)) {
475 button._state = S_down;
476 all_values_zero =
false;
478 button._state = S_up;
480 if (button.handle == GamepadButton::dpad_left()) {
481 emulate_dpad =
false;
482 }
else if (button.handle == GamepadButton::ltrigger()) {
484 }
else if (button.handle == GamepadButton::rtrigger()) {
488 _buttons.push_back(button);
489 if ((
size_t)i >= _button_indices.size()) {
490 _button_indices.resize(i + 1, -1);
492 _button_indices[i] = button_index;
498 _axis_indices.resize(num_bits, -1);
500 for (
int i = 0; i < num_bits; ++i) {
501 if (test_bit(i, axes)) {
502 Axis axis = Axis::none;
505 if (_device_class == DeviceClass::gamepad) {
506 axis = InputDevice::Axis::left_x;
507 }
else if (_device_class == DeviceClass::flight_stick) {
508 axis = InputDevice::Axis::roll;
510 axis = InputDevice::Axis::x;
514 if (_device_class == DeviceClass::gamepad) {
515 axis = InputDevice::Axis::left_y;
516 }
else if (_device_class == DeviceClass::flight_stick) {
517 axis = InputDevice::Axis::pitch;
519 axis = InputDevice::Axis::y;
523 if (quirks & QB_rstick_from_z) {
524 if (quirks & QB_right_axes_swapped) {
525 axis = InputDevice::Axis::right_y;
527 axis = InputDevice::Axis::right_x;
529 }
else if (_device_class == DeviceClass::gamepad) {
530 if ((quirks & QB_no_analog_triggers) == 0) {
531 axis = InputDevice::Axis::left_trigger;
532 have_analog_triggers =
true;
534 }
else if (_device_class == DeviceClass::spatial_mouse) {
535 axis = InputDevice::Axis::z;
537 axis = InputDevice::Axis::throttle;
541 if (_device_class == DeviceClass::spatial_mouse) {
542 axis = InputDevice::Axis::pitch;
543 }
else if ((quirks & QB_rstick_from_z) == 0) {
544 axis = InputDevice::Axis::right_x;
548 if (_device_class == DeviceClass::spatial_mouse) {
549 axis = InputDevice::Axis::roll;
550 }
else if ((quirks & QB_rstick_from_z) == 0) {
551 axis = InputDevice::Axis::right_y;
555 if (quirks & QB_rstick_from_z) {
556 if (quirks & QB_right_axes_swapped) {
557 axis = InputDevice::Axis::right_x;
559 axis = InputDevice::Axis::right_y;
561 }
else if (_device_class == DeviceClass::gamepad) {
562 if ((quirks & QB_no_analog_triggers) == 0) {
563 axis = InputDevice::Axis::right_trigger;
564 have_analog_triggers =
true;
567 axis = InputDevice::Axis::right_y;
570 axis = InputDevice::Axis::yaw;
574 if (quirks & QB_rudder_from_throttle) {
575 axis = InputDevice::Axis::rudder;
577 axis = InputDevice::Axis::throttle;
581 axis = InputDevice::Axis::rudder;
584 axis = InputDevice::Axis::wheel;
587 if (_device_class == DeviceClass::gamepad) {
588 if ((quirks & QB_no_analog_triggers) == 0) {
589 axis = InputDevice::Axis::right_trigger;
590 have_analog_triggers =
true;
593 axis = InputDevice::Axis::accelerator;
597 if (_device_class == DeviceClass::gamepad) {
598 axis = InputDevice::Axis::left_trigger;
599 have_analog_triggers =
true;
601 axis = InputDevice::Axis::brake;
607 _dpad_left_button = (int)_buttons.size();
608 if (_device_class == DeviceClass::gamepad) {
609 _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
610 _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
612 _buttons.push_back(ButtonState(GamepadButton::hat_left()));
613 _buttons.push_back(ButtonState(GamepadButton::hat_right()));
615 _buttons[_dpad_left_button]._state = S_up;
616 _buttons[_dpad_left_button+1]._state = S_up;
622 _dpad_up_button = (int)_buttons.size();
623 if (_device_class == DeviceClass::gamepad) {
624 _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
625 _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
627 _buttons.push_back(ButtonState(GamepadButton::hat_up()));
628 _buttons.push_back(ButtonState(GamepadButton::hat_down()));
630 _buttons[_dpad_up_button]._state = S_up;
631 _buttons[_dpad_up_button+1]._state = S_up;
635 if (quirks & QB_steam_controller) {
636 axis = InputDevice::Axis::right_trigger;
637 have_analog_triggers =
true;
641 if (quirks & QB_steam_controller) {
642 axis = InputDevice::Axis::left_trigger;
643 have_analog_triggers =
true;
647 axis = InputDevice::Axis::pressure;
652 struct input_absinfo absinfo;
653 if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) {
658 if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y ||
659 (axis == Axis::throttle && (quirks & QB_reversed_throttle) != 0) ||
660 (_device_class == DeviceClass::spatial_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll)) ||
661 (_device_class == DeviceClass::digitizer && axis == Axis::y)) {
662 std::swap(absinfo.maximum, absinfo.minimum);
664 if (axis == Axis::throttle && (quirks & QB_centered_throttle) != 0) {
665 index = add_axis(axis, absinfo.minimum, absinfo.maximum,
true);
667 index = add_axis(axis, absinfo.minimum, absinfo.maximum);
669 axis_changed(index, absinfo.value);
670 _axis_indices[i] = index;
672 if (absinfo.value != 0) {
673 all_values_zero =
false;
680 if (test_bit(EV_REL, evtypes)) {
681 enable_feature(Feature::pointer);
682 add_pointer(PointerType::unknown, 0);
685 if (test_bit(EV_FF, evtypes)) {
686 uint8_t effects[(FF_MAX + 8) >> 3] = {0};
687 ioctl(_fd, EVIOCGBIT(EV_FF,
sizeof(effects)), effects);
689 if (test_bit(FF_RUMBLE, effects)) {
691 enable_feature(Feature::vibration);
695 <<
"/dev/input/event" << _index <<
" is not writable, vibration "
696 <<
"effects will be unavailable.\n";
701 if (_ltrigger_code >= 0 && _rtrigger_code >= 0 && !have_analog_triggers) {
703 _ltrigger_axis = (int)_axes.size();
704 add_axis(Axis::left_trigger, 0, 1,
false);
705 add_axis(Axis::right_trigger, 0, 1,
false);
714 const char *parent =
"";
715 sprintf(path,
"/sys/class/input/event%zd/device/device/../product", _index);
716 FILE *f = fopen(path,
"r");
719 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../product", _index, parent);
720 f = fopen(path,
"r");
723 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
724 buffer[strcspn(buffer,
"\r\n")] = 0;
725 if (buffer[0] != 0) {
726 _name.assign(buffer);
731 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../manufacturer", _index, parent);
732 f = fopen(path,
"r");
734 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
735 buffer[strcspn(buffer,
"\r\n")] = 0;
736 _manufacturer.assign(buffer);
740 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../serial", _index, parent);
741 f = fopen(path,
"r");
743 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
744 buffer[strcspn(buffer,
"\r\n")] = 0;
745 _serial_number.assign(buffer);
754 if (all_values_zero && (quirks & QB_connect_if_nonzero) != 0) {
755 _is_connected =
false;
757 _is_connected =
true;
766bool EvdevInputDevice::
769 struct input_event events[8];
771 int n_read = read(_fd, events,
sizeof(events));
773 if (errno == EAGAIN || errno == EWOULDBLOCK) {
776 }
else if (errno == ENODEV || errno == EINVAL) {
786 device_cat.error() <<
"read: " << strerror(errno) <<
"\n";
795 n_read /=
sizeof(
struct input_event);
804 if (n_read == 1 && events[0].code == EV_SYN) {
808 for (
int i = 0; i < n_read; ++i) {
809 int code = events[i].code;
811 switch (events[i].type) {
816 if (code == REL_X) rel_x += events[i].value;
817 if (code == REL_Y) rel_y += events[i].value;
821 if (code == _dpad_x_axis) {
822 button_changed(_dpad_left_button, events[i].value < 0);
823 button_changed(_dpad_left_button+1, events[i].value > 0);
824 }
else if (code == _dpad_y_axis) {
825 button_changed(_dpad_up_button, events[i].value < 0);
826 button_changed(_dpad_up_button+1, events[i].value > 0);
828 if (code >= 0 && (
size_t)code < _axis_indices.size()) {
829 index = _axis_indices[code];
831 axis_changed(index, events[i].value);
834 else if (device_cat.is_debug()) {
836 <<
"Ignoring EV_ABS event with unknown code " << code <<
"\n";
841 if (code >= 0 && (
size_t)code < _button_indices.size()) {
842 index = _button_indices[code];
844 button_changed(index, events[i].value != 0);
846 if (code == _ltrigger_code) {
847 axis_changed(_ltrigger_axis, events[i].value);
848 }
else if (code == _rtrigger_code) {
849 axis_changed(_ltrigger_axis + 1, events[i].value);
852 else if (device_cat.is_debug()) {
854 <<
"Ignoring EV_KEY event with unknown code " << code <<
"\n";
864 if (rel_x != 0 || rel_y != 0) {
865 pointer_moved(0, rel_x, rel_y, time);
875map_button(
int code, DeviceClass device_class,
int quirks) {
876 if (code >= 0 && code < 0x80) {
879 ButtonHandle::none(),
880 KeyboardButton::escape(),
893 KeyboardButton::backspace(),
894 KeyboardButton::tab(),
907 KeyboardButton::enter(),
908 KeyboardButton::lcontrol(),
921 KeyboardButton::lshift(),
933 KeyboardButton::rshift(),
935 KeyboardButton::lalt(),
936 KeyboardButton::space(),
937 KeyboardButton::caps_lock(),
938 KeyboardButton::f1(),
939 KeyboardButton::f2(),
940 KeyboardButton::f3(),
941 KeyboardButton::f4(),
942 KeyboardButton::f5(),
943 KeyboardButton::f6(),
944 KeyboardButton::f7(),
945 KeyboardButton::f8(),
946 KeyboardButton::f9(),
947 KeyboardButton::f10(),
948 KeyboardButton::num_lock(),
949 KeyboardButton::scroll_lock(),
963 ButtonHandle::none(),
964 ButtonHandle::none(),
966 KeyboardButton::f11(),
967 KeyboardButton::f12(),
968 ButtonHandle::none(),
969 ButtonHandle::none(),
970 ButtonHandle::none(),
971 ButtonHandle::none(),
972 ButtonHandle::none(),
973 ButtonHandle::none(),
974 ButtonHandle::none(),
975 KeyboardButton::enter(),
976 KeyboardButton::rcontrol(),
978 KeyboardButton::print_screen(),
979 KeyboardButton::ralt(),
980 ButtonHandle::none(),
981 KeyboardButton::home(),
982 KeyboardButton::up(),
983 KeyboardButton::page_up(),
984 KeyboardButton::left(),
985 KeyboardButton::right(),
986 KeyboardButton::end(),
987 KeyboardButton::down(),
988 KeyboardButton::page_down(),
989 KeyboardButton::insert(),
990 KeyboardButton::del(),
991 ButtonHandle::none(),
992 ButtonHandle::none(),
993 ButtonHandle::none(),
994 ButtonHandle::none(),
995 ButtonHandle::none(),
996 ButtonHandle::none(),
997 ButtonHandle::none(),
998 KeyboardButton::pause(),
999 ButtonHandle::none(),
1000 ButtonHandle::none(),
1001 ButtonHandle::none(),
1002 ButtonHandle::none(),
1003 ButtonHandle::none(),
1004 KeyboardButton::lmeta(),
1005 KeyboardButton::rmeta(),
1006 KeyboardButton::menu(),
1008 return keyboard_map[code];
1010 }
else if (code == KEY_BACK) {
1012 return GamepadButton::back();
1014 }
else if (code == KEY_SEARCH) {
1016 return GamepadButton::guide();
1018 }
else if (code < 0x100) {
1019 return ButtonHandle::none();
1021 }
else if ((code & 0xfff0) == BTN_MOUSE) {
1023 if (code == BTN_RIGHT) {
1025 }
else if (code == BTN_MIDDLE) {
1031 }
else if ((code & 0xfff0) == BTN_JOYSTICK) {
1032 if (quirks & QB_steam_controller) {
1034 return ButtonHandle::none();
1036 }
else if (device_class == DeviceClass::gamepad &&
1037 (quirks & QB_alt_button_mapping) != 0) {
1039 GamepadButton::face_y(),
1040 GamepadButton::face_b(),
1041 GamepadButton::face_a(),
1042 GamepadButton::face_x(),
1043 GamepadButton::lshoulder(),
1044 GamepadButton::rshoulder(),
1045 GamepadButton::ltrigger(),
1046 GamepadButton::rtrigger(),
1047 GamepadButton::back(),
1048 GamepadButton::start(),
1049 GamepadButton::lstick(),
1050 GamepadButton::rstick(),
1052 if ((code & 0xf) < 12) {
1053 return mapping[code & 0xf];
1056 }
else if (device_class == DeviceClass::gamepad) {
1059 GamepadButton::face_x(),
1060 GamepadButton::face_y(),
1061 GamepadButton::face_a(),
1062 GamepadButton::face_b(),
1063 GamepadButton::lshoulder(),
1064 GamepadButton::ltrigger(),
1065 GamepadButton::rshoulder(),
1066 GamepadButton::rtrigger(),
1067 GamepadButton::back(),
1068 GamepadButton::start(),
1069 GamepadButton::lstick(),
1070 GamepadButton::rstick(),
1072 if ((code & 0xf) < 12) {
1073 return mapping[code & 0xf];
1082 return GamepadButton::face_a();
1085 return GamepadButton::face_b();
1088 return GamepadButton::face_c();
1091 return GamepadButton::face_x();
1094 return GamepadButton::face_y();
1097 return GamepadButton::face_z();
1100 return GamepadButton::lshoulder();
1103 return GamepadButton::rshoulder();
1106 return GamepadButton::ltrigger();
1109 return GamepadButton::rtrigger();
1112 return GamepadButton::face_1();
1115 return GamepadButton::face_2();
1119 return GamepadButton::back();
1123 return GamepadButton::start();
1126 return GamepadButton::guide();
1129 return GamepadButton::lstick();
1132 return GamepadButton::rstick();
1135 case BTN_TRIGGER_HAPPY1:
1136 return GamepadButton::dpad_left();
1138 case BTN_DPAD_RIGHT:
1139 case BTN_TRIGGER_HAPPY2:
1140 return GamepadButton::dpad_right();
1143 case BTN_TRIGGER_HAPPY3:
1144 return GamepadButton::dpad_up();
1147 case BTN_TRIGGER_HAPPY4:
1148 return GamepadButton::dpad_down();
1152 return GamepadButton::lgrip();
1155 return GamepadButton::rgrip();
1158 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.