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 num_bits = ioctl(_fd, EVIOCGBIT(EV_ABS,
sizeof(axes)), axes) << 3;
337 const DeviceMapping *mapping = mapping_presets;
338 while (mapping->vendor != 0) {
339 if (_vendor_id == mapping->vendor && _product_id == mapping->product) {
340 _device_class = mapping->device_class;
341 quirks = mapping->quirks;
348 if (quirks & QB_steam_controller) {
349 if (test_bit(BTN_GAMEPAD, keys)) {
350 _device_class = DeviceClass::gamepad;
356 if (_manager->has_virtual_device(0x28de, 0x11ff)) {
358 <<
"Detected Steam virtual gamepad, disabling Steam Controller\n";
359 quirks |= QB_connect_if_nonzero;
366 if (_device_class == DeviceClass::unknown) {
367 int device_scores[(size_t)DeviceClass::spatial_mouse] = {0};
370 if (test_bit(BTN_GAMEPAD, keys) && test_bit(ABS_X, axes) && test_bit(ABS_RX, axes)) {
371 device_scores[(size_t)DeviceClass::gamepad] += 5;
372 device_scores[(size_t)DeviceClass::steering_wheel] += 5;
373 device_scores[(size_t)DeviceClass::flight_stick] += 5;
376 if (test_bit(ABS_WHEEL, axes) && test_bit(ABS_GAS, axes) && test_bit(ABS_BRAKE, axes)) {
377 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
379 if (test_bit(BTN_GEAR_DOWN, keys) && test_bit(BTN_GEAR_UP, keys)) {
380 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
382 if (test_bit(BTN_JOYSTICK, keys) && test_bit(ABS_X, axes)) {
383 device_scores[(size_t)DeviceClass::flight_stick] += 10;
385 if (test_bit(BTN_MOUSE, keys) && test_bit(EV_REL, evtypes)) {
386 device_scores[(size_t)DeviceClass::mouse] += 20;
388 uint8_t unknown_keys[] = {KEY_POWER};
389 for (
int i = 0; i < 1; i++) {
390 if (test_bit(unknown_keys[i], keys)) {
391 if (unknown_keys[i] == KEY_POWER) {
393 device_scores[(size_t)DeviceClass::unknown] += 20;
396 if (_features & (
unsigned int)Feature::keyboard) {
397 device_scores[(size_t)DeviceClass::keyboard] += 20;
401 string lowercase_name = _name;
402 for(
size_t x = 0; x < _name.length(); ++x) {
403 lowercase_name[x] = tolower(lowercase_name[x]);
405 if (lowercase_name.find(
"gamepad") != string::npos) {
406 device_scores[(size_t)DeviceClass::gamepad] += 10;
408 if (lowercase_name.find(
"wheel") != string::npos) {
409 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
411 if (lowercase_name.find(
"mouse") != string::npos || lowercase_name.find(
"touchpad") != string::npos) {
412 device_scores[(size_t)DeviceClass::mouse] += 10;
414 if (lowercase_name.find(
"keyboard") != string::npos) {
415 device_scores[(size_t)DeviceClass::keyboard] += 10;
418 string unknown_names[] = {
"video bus",
"power button",
"sleep button"};
419 for(
int i = 0; i < 3; i++) {
420 if (lowercase_name.find(unknown_names[i]) != string::npos) {
421 device_scores[(size_t)DeviceClass::unknown] += 20;
426 int highest_score = 0;
427 for (
size_t i = 0; i < (size_t)DeviceClass::spatial_mouse; i++) {
428 if (device_scores[i] > highest_score) {
429 highest_score = device_scores[i];
430 _device_class = (DeviceClass)i;
438 uint8_t states[(KEY_MAX + 8) >> 3] = {0};
439 ioctl(_fd, EVIOCGKEY(
sizeof(states)), states);
441 for (
int i = 0; i <= KEY_MAX; ++i) {
442 if (test_bit(i, keys)) {
444 button.handle = map_button(i, _device_class, quirks);
446 int button_index = (int)_buttons.size();
447 if (button.handle == ButtonHandle::none()) {
448 if (device_cat.is_debug()) {
449 device_cat.debug() <<
"Unmapped /dev/input/event" << _index
450 <<
" button " << button_index <<
": 0x" << std::hex << i << std::dec <<
"\n";
454 if (test_bit(i, states)) {
455 button._state = S_down;
456 all_values_zero =
false;
458 button._state = S_up;
460 if (button.handle == GamepadButton::dpad_left()) {
461 emulate_dpad =
false;
462 }
else if (button.handle == GamepadButton::ltrigger()) {
464 }
else if (button.handle == GamepadButton::rtrigger()) {
468 _buttons.push_back(button);
469 if ((
size_t)i >= _button_indices.size()) {
470 _button_indices.resize(i + 1, -1);
472 _button_indices[i] = button_index;
478 _axis_indices.resize(num_bits, -1);
480 for (
int i = 0; i < num_bits; ++i) {
481 if (test_bit(i, axes)) {
482 Axis axis = Axis::none;
485 if (_device_class == DeviceClass::gamepad) {
486 axis = InputDevice::Axis::left_x;
487 }
else if (_device_class == DeviceClass::flight_stick) {
488 axis = InputDevice::Axis::roll;
490 axis = InputDevice::Axis::x;
494 if (_device_class == DeviceClass::gamepad) {
495 axis = InputDevice::Axis::left_y;
496 }
else if (_device_class == DeviceClass::flight_stick) {
497 axis = InputDevice::Axis::pitch;
499 axis = InputDevice::Axis::y;
503 if (quirks & QB_rstick_from_z) {
504 if (quirks & QB_right_axes_swapped) {
505 axis = InputDevice::Axis::right_y;
507 axis = InputDevice::Axis::right_x;
509 }
else if (_device_class == DeviceClass::gamepad) {
510 if ((quirks & QB_no_analog_triggers) == 0) {
511 axis = InputDevice::Axis::left_trigger;
512 have_analog_triggers =
true;
514 }
else if (_device_class == DeviceClass::spatial_mouse) {
515 axis = InputDevice::Axis::z;
517 axis = InputDevice::Axis::throttle;
521 if (_device_class == DeviceClass::spatial_mouse) {
522 axis = InputDevice::Axis::pitch;
523 }
else if ((quirks & QB_rstick_from_z) == 0) {
524 axis = InputDevice::Axis::right_x;
528 if (_device_class == DeviceClass::spatial_mouse) {
529 axis = InputDevice::Axis::roll;
530 }
else if ((quirks & QB_rstick_from_z) == 0) {
531 axis = InputDevice::Axis::right_y;
535 if (quirks & QB_rstick_from_z) {
536 if (quirks & QB_right_axes_swapped) {
537 axis = InputDevice::Axis::right_x;
539 axis = InputDevice::Axis::right_y;
541 }
else if (_device_class == DeviceClass::gamepad) {
542 if ((quirks & QB_no_analog_triggers) == 0) {
543 axis = InputDevice::Axis::right_trigger;
544 have_analog_triggers =
true;
547 axis = InputDevice::Axis::right_y;
550 axis = InputDevice::Axis::yaw;
554 if (quirks & QB_rudder_from_throttle) {
555 axis = InputDevice::Axis::rudder;
557 axis = InputDevice::Axis::throttle;
561 axis = InputDevice::Axis::rudder;
564 axis = InputDevice::Axis::wheel;
567 if (_device_class == DeviceClass::gamepad) {
568 if ((quirks & QB_no_analog_triggers) == 0) {
569 axis = InputDevice::Axis::right_trigger;
570 have_analog_triggers =
true;
573 axis = InputDevice::Axis::accelerator;
577 if (_device_class == DeviceClass::gamepad) {
578 axis = InputDevice::Axis::left_trigger;
579 have_analog_triggers =
true;
581 axis = InputDevice::Axis::brake;
587 _dpad_left_button = (int)_buttons.size();
588 if (_device_class == DeviceClass::gamepad) {
589 _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
590 _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
592 _buttons.push_back(ButtonState(GamepadButton::hat_left()));
593 _buttons.push_back(ButtonState(GamepadButton::hat_right()));
600 _dpad_up_button = (int)_buttons.size();
601 if (_device_class == DeviceClass::gamepad) {
602 _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
603 _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
605 _buttons.push_back(ButtonState(GamepadButton::hat_up()));
606 _buttons.push_back(ButtonState(GamepadButton::hat_down()));
611 if (quirks & QB_steam_controller) {
612 axis = InputDevice::Axis::right_trigger;
613 have_analog_triggers =
true;
617 if (quirks & QB_steam_controller) {
618 axis = InputDevice::Axis::left_trigger;
619 have_analog_triggers =
true;
625 struct input_absinfo absinfo;
626 if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) {
631 if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y ||
632 (axis == Axis::throttle && (quirks & QB_reversed_throttle) != 0) ||
633 (_device_class == DeviceClass::spatial_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll))) {
634 std::swap(absinfo.maximum, absinfo.minimum);
636 if (axis == Axis::throttle && (quirks & QB_centered_throttle) != 0) {
637 index = add_axis(axis, absinfo.minimum, absinfo.maximum,
true);
639 index = add_axis(axis, absinfo.minimum, absinfo.maximum);
641 axis_changed(index, absinfo.value);
642 _axis_indices[i] = index;
644 if (absinfo.value != 0) {
645 all_values_zero =
false;
652 if (test_bit(EV_REL, evtypes)) {
653 enable_feature(Feature::pointer);
654 add_pointer(PointerType::unknown, 0);
657 if (test_bit(EV_FF, evtypes)) {
658 uint8_t effects[(FF_MAX + 8) >> 3] = {0};
659 ioctl(_fd, EVIOCGBIT(EV_FF,
sizeof(effects)), effects);
661 if (test_bit(FF_RUMBLE, effects)) {
663 enable_feature(Feature::vibration);
667 <<
"/dev/input/event" << _index <<
" is not writable, vibration " 668 <<
"effects will be unavailable.\n";
673 if (_ltrigger_code >= 0 && _rtrigger_code >= 0 && !have_analog_triggers) {
675 _ltrigger_axis = (int)_axes.size();
676 add_axis(Axis::left_trigger, 0, 1,
false);
677 add_axis(Axis::right_trigger, 0, 1,
false);
685 const char *parent =
"";
686 sprintf(path,
"/sys/class/input/event%zd/device/device/../product", _index);
687 FILE *f = fopen(path,
"r");
690 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../product", _index, parent);
691 f = fopen(path,
"r");
694 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
695 buffer[strcspn(buffer,
"\r\n")] = 0;
696 if (buffer[0] != 0) {
697 _name.assign(buffer);
702 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../manufacturer", _index, parent);
703 f = fopen(path,
"r");
705 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
706 buffer[strcspn(buffer,
"\r\n")] = 0;
707 _manufacturer.assign(buffer);
711 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../serial", _index, parent);
712 f = fopen(path,
"r");
714 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
715 buffer[strcspn(buffer,
"\r\n")] = 0;
716 _serial_number.assign(buffer);
724 if (all_values_zero && (quirks & QB_connect_if_nonzero) != 0) {
725 _is_connected =
false;
727 _is_connected =
true;
736 bool EvdevInputDevice::
739 struct input_event events[8];
741 int n_read = read(_fd, events,
sizeof(events));
743 if (errno == EAGAIN || errno == EWOULDBLOCK) {
746 }
else if (errno == ENODEV || errno == EINVAL) {
756 device_cat.error() <<
"read: " << strerror(errno) <<
"\n";
765 n_read /=
sizeof(
struct input_event);
774 if (n_read == 1 && events[0].code == EV_SYN) {
778 for (
int i = 0; i < n_read; ++i) {
779 int code = events[i].code;
781 switch (events[i].type) {
786 if (code == REL_X) rel_x += events[i].value;
787 if (code == REL_Y) rel_y += events[i].value;
791 if (code == _dpad_x_axis) {
792 button_changed(_dpad_left_button, events[i].value < 0);
793 button_changed(_dpad_left_button+1, events[i].value > 0);
794 }
else if (code == _dpad_y_axis) {
795 button_changed(_dpad_up_button, events[i].value < 0);
796 button_changed(_dpad_up_button+1, events[i].value > 0);
798 nassertd(code >= 0 && (
size_t)code < _axis_indices.size())
break;
799 index = _axis_indices[code];
801 axis_changed(index, events[i].value);
806 nassertd(code >= 0 && (
size_t)code < _button_indices.size())
break;
807 index = _button_indices[code];
809 button_changed(index, events[i].value != 0);
811 if (code == _ltrigger_code) {
812 axis_changed(_ltrigger_axis, events[i].value);
813 }
else if (code == _rtrigger_code) {
814 axis_changed(_ltrigger_axis + 1, events[i].value);
824 if (rel_x != 0 || rel_y != 0) {
825 pointer_moved(0, rel_x, rel_y, time);
835 map_button(
int code, DeviceClass device_class,
int quirks) {
836 if (code >= 0 && code < 0x80) {
839 ButtonHandle::none(),
840 KeyboardButton::escape(),
853 KeyboardButton::backspace(),
854 KeyboardButton::tab(),
867 KeyboardButton::enter(),
868 KeyboardButton::lcontrol(),
881 KeyboardButton::lshift(),
893 KeyboardButton::rshift(),
895 KeyboardButton::lalt(),
896 KeyboardButton::space(),
897 KeyboardButton::caps_lock(),
898 KeyboardButton::f1(),
899 KeyboardButton::f2(),
900 KeyboardButton::f3(),
901 KeyboardButton::f4(),
902 KeyboardButton::f5(),
903 KeyboardButton::f6(),
904 KeyboardButton::f7(),
905 KeyboardButton::f8(),
906 KeyboardButton::f9(),
907 KeyboardButton::f10(),
908 KeyboardButton::num_lock(),
909 KeyboardButton::scroll_lock(),
923 ButtonHandle::none(),
924 ButtonHandle::none(),
925 ButtonHandle::none(),
926 KeyboardButton::f11(),
927 KeyboardButton::f12(),
928 ButtonHandle::none(),
929 ButtonHandle::none(),
930 ButtonHandle::none(),
931 ButtonHandle::none(),
932 ButtonHandle::none(),
933 ButtonHandle::none(),
934 ButtonHandle::none(),
935 KeyboardButton::enter(),
936 KeyboardButton::rcontrol(),
938 KeyboardButton::print_screen(),
939 KeyboardButton::ralt(),
940 ButtonHandle::none(),
941 KeyboardButton::home(),
942 KeyboardButton::up(),
943 KeyboardButton::page_up(),
944 KeyboardButton::left(),
945 KeyboardButton::right(),
946 KeyboardButton::end(),
947 KeyboardButton::down(),
948 KeyboardButton::page_down(),
949 KeyboardButton::insert(),
950 KeyboardButton::del(),
951 ButtonHandle::none(),
952 ButtonHandle::none(),
953 ButtonHandle::none(),
954 ButtonHandle::none(),
955 ButtonHandle::none(),
956 ButtonHandle::none(),
957 ButtonHandle::none(),
958 KeyboardButton::pause(),
959 ButtonHandle::none(),
960 ButtonHandle::none(),
961 ButtonHandle::none(),
962 ButtonHandle::none(),
963 ButtonHandle::none(),
964 KeyboardButton::lmeta(),
965 KeyboardButton::rmeta(),
966 KeyboardButton::menu(),
968 return keyboard_map[code];
970 }
else if (code == KEY_BACK) {
972 return GamepadButton::back();
974 }
else if (code == KEY_SEARCH) {
976 return GamepadButton::guide();
978 }
else if (code < 0x100) {
979 return ButtonHandle::none();
981 }
else if ((code & 0xfff0) == BTN_MOUSE) {
983 if (code == BTN_RIGHT) {
985 }
else if (code == BTN_MIDDLE) {
991 }
else if ((code & 0xfff0) == BTN_JOYSTICK) {
992 if (quirks & QB_steam_controller) {
994 return ButtonHandle::none();
996 }
else if (device_class == DeviceClass::gamepad &&
997 (quirks & QB_alt_button_mapping) != 0) {
999 GamepadButton::face_y(),
1000 GamepadButton::face_b(),
1001 GamepadButton::face_a(),
1002 GamepadButton::face_x(),
1003 GamepadButton::lshoulder(),
1004 GamepadButton::rshoulder(),
1005 GamepadButton::ltrigger(),
1006 GamepadButton::rtrigger(),
1007 GamepadButton::back(),
1008 GamepadButton::start(),
1009 GamepadButton::lstick(),
1010 GamepadButton::rstick(),
1012 if ((code & 0xf) < 12) {
1013 return mapping[code & 0xf];
1016 }
else if (device_class == DeviceClass::gamepad) {
1019 GamepadButton::face_x(),
1020 GamepadButton::face_y(),
1021 GamepadButton::face_a(),
1022 GamepadButton::face_b(),
1023 GamepadButton::lshoulder(),
1024 GamepadButton::ltrigger(),
1025 GamepadButton::rshoulder(),
1026 GamepadButton::rtrigger(),
1027 GamepadButton::back(),
1028 GamepadButton::start(),
1029 GamepadButton::lstick(),
1030 GamepadButton::rstick(),
1032 if ((code & 0xf) < 12) {
1033 return mapping[code & 0xf];
1042 return GamepadButton::face_a();
1045 return GamepadButton::face_b();
1048 return GamepadButton::face_c();
1051 return GamepadButton::face_x();
1054 return GamepadButton::face_y();
1057 return GamepadButton::face_z();
1060 return GamepadButton::lshoulder();
1063 return GamepadButton::rshoulder();
1066 return GamepadButton::ltrigger();
1069 return GamepadButton::rtrigger();
1072 return GamepadButton::face_1();
1075 return GamepadButton::face_2();
1079 return GamepadButton::back();
1083 return GamepadButton::start();
1086 return GamepadButton::guide();
1089 return GamepadButton::lstick();
1092 return GamepadButton::rstick();
1095 case BTN_TRIGGER_HAPPY1:
1096 return GamepadButton::dpad_left();
1098 case BTN_DPAD_RIGHT:
1099 case BTN_TRIGGER_HAPPY2:
1100 return GamepadButton::dpad_right();
1103 case BTN_TRIGGER_HAPPY3:
1104 return GamepadButton::dpad_up();
1107 case BTN_TRIGGER_HAPPY4:
1108 return GamepadButton::dpad_down();
1112 return GamepadButton::lgrip();
1115 return GamepadButton::rgrip();
1118 return ButtonHandle::none();
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
get_frame_time
Returns the time in seconds as of the last time tick() was called (typically, this will be as of the ...
Similar to MutexHolder, but for a light mutex.
TypeHandle is the identifier used to differentiate C++ class types.