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 static const struct DeviceMapping {
68 unsigned short vendor;
69 unsigned short product;
70 InputDevice::DeviceClass device_class;
72 } mapping_presets[] = {
74 {0x0955, 0x7214, InputDevice::DeviceClass::gamepad, QB_rstick_from_z},
76 {0x044f, 0xb108, InputDevice::DeviceClass::flight_stick, QB_centered_throttle | QB_reversed_throttle | QB_rudder_from_throttle},
78 {0x045e, 0x0719, InputDevice::DeviceClass::gamepad, QB_connect_if_nonzero},
80 {0x28de, 0x1102, InputDevice::DeviceClass::unknown, QB_steam_controller},
82 {0x28de, 0x1142, InputDevice::DeviceClass::unknown, QB_steam_controller},
84 {0x0f30, 0x0111, InputDevice::DeviceClass::gamepad, 0},
86 {0x0079, 0x0006, InputDevice::DeviceClass::gamepad, 0},
88 {0x046d, 0xc623, InputDevice::DeviceClass::spatial_mouse, 0},
90 {0x046d, 0xc625, InputDevice::DeviceClass::spatial_mouse, 0},
92 {0x046d, 0xc626, InputDevice::DeviceClass::spatial_mouse, 0},
94 {0x046d, 0xc627, InputDevice::DeviceClass::spatial_mouse, 0},
96 {0x046d, 0xc628, InputDevice::DeviceClass::spatial_mouse, 0},
98 {0x046d, 0xc629, InputDevice::DeviceClass::spatial_mouse, 0},
100 {0x046d, 0xc62b, InputDevice::DeviceClass::spatial_mouse, 0},
110 EvdevInputDevice(LinuxInputDeviceManager *manager,
size_t index) :
121 _dpad_left_button(-1),
128 sprintf(path,
"/dev/input/event%zd", index);
130 _fd = open(path, O_RDWR | O_NONBLOCK);
135 _fd = open(path, O_RDONLY | O_NONBLOCK);
141 _is_connected =
false;
143 <<
"Opening raw input device: " << strerror(errno) <<
" " << path <<
"\n";
151 ~EvdevInputDevice() {
155 do_set_vibration(0, 0);
156 ioctl(_fd, EVIOCRMFF, _ff_id);
170 void EvdevInputDevice::
171 do_set_vibration(
double strong,
double weak) {
172 if (_fd == -1 || !_can_write) {
176 int strong_level = strong * 0xffff;
177 int weak_level = weak * 0xffff;
179 if (strong_level == _ff_strong && weak_level == _ff_weak) {
187 struct ff_effect effect;
188 effect.type = FF_RUMBLE;
190 effect.direction = 0;
191 effect.trigger.button = 0;
192 effect.trigger.interval = 0;
193 effect.replay.length = 0;
194 effect.replay.delay = 0;
195 effect.u.rumble.strong_magnitude = strong_level;
196 effect.u.rumble.weak_magnitude = weak_level;
198 if (ioctl(_fd, EVIOCSFF, &effect) < 0) {
202 _ff_strong = strong_level;
203 _ff_weak = weak_level;
211 struct input_event play;
216 if (write(_fd, &play,
sizeof(play)) < 0) {
218 <<
"Failed to write force-feedback event: " << strerror(errno) <<
"\n";
229 bool EvdevInputDevice::
230 reactivate_steam_controller() {
232 if (!_is_connected && (_quirks & QB_steam_controller) != 0) {
236 _is_connected =
true;
248 void EvdevInputDevice::
250 if (_fd != -1 && process_events()) {
251 while (process_events()) {}
254 if (!_is_connected && _fd != -1) {
255 _is_connected =
true;
256 if (_manager !=
nullptr) {
257 _manager->add_device(
this);
266 bool EvdevInputDevice::
270 nassertr(_fd >= 0,
false);
274 uint8_t evtypes[(EV_MAX + 8) >> 3] = {0};
276 if (ioctl(_fd, EVIOCGNAME(
sizeof(name)), name) < 0 ||
277 ioctl(_fd, EVIOCGBIT(0,
sizeof(evtypes)), evtypes) < 0) {
280 _is_connected =
false;
281 device_cat.error() <<
"Opening raw input device: ioctl failed\n";
289 if (ioctl(_fd, EVIOCGID, &
id) >= 0) {
290 _vendor_id =
id.vendor;
291 _product_id =
id.product;
294 bool all_values_zero =
true;
295 bool emulate_dpad =
true;
296 bool have_analog_triggers =
false;
298 bool has_keys =
false;
299 bool has_axes =
false;
301 uint8_t keys[(KEY_MAX + 8) >> 3] = {0};
302 if (test_bit(EV_KEY, evtypes)) {
304 ioctl(_fd, EVIOCGBIT(EV_KEY,
sizeof(keys)), keys);
307 if (test_bit(KEY_A, keys) && test_bit(KEY_Z, keys)) {
308 enable_feature(Feature::keyboard);
313 uint8_t axes[(ABS_MAX + 8) >> 3] = {0};
314 if (test_bit(EV_ABS, evtypes)) {
316 num_bits = ioctl(_fd, EVIOCGBIT(EV_ABS,
sizeof(axes)), axes) << 3;
322 const DeviceMapping *mapping = mapping_presets;
323 while (mapping->vendor != 0) {
324 if (_vendor_id == mapping->vendor && _product_id == mapping->product) {
325 _device_class = mapping->device_class;
326 quirks = mapping->quirks;
333 if (quirks & QB_steam_controller) {
334 if (test_bit(BTN_GAMEPAD, keys)) {
335 _device_class = DeviceClass::gamepad;
341 if (_manager->has_virtual_device(0x28de, 0x11ff)) {
343 <<
"Detected Steam virtual gamepad, disabling Steam Controller\n";
344 quirks |= QB_connect_if_nonzero;
351 if (_device_class == DeviceClass::unknown) {
352 int device_scores[(size_t)DeviceClass::spatial_mouse] = {0};
355 if (test_bit(BTN_GAMEPAD, keys) && test_bit(ABS_X, axes) && test_bit(ABS_RX, axes)) {
356 device_scores[(size_t)DeviceClass::gamepad] += 5;
357 device_scores[(size_t)DeviceClass::steering_wheel] += 5;
358 device_scores[(size_t)DeviceClass::flight_stick] += 5;
361 if (test_bit(ABS_WHEEL, axes) && test_bit(ABS_GAS, axes) && test_bit(ABS_BRAKE, axes)) {
362 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
364 if (test_bit(BTN_GEAR_DOWN, keys) && test_bit(BTN_GEAR_UP, keys)) {
365 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
367 if (test_bit(BTN_JOYSTICK, keys) && test_bit(ABS_X, axes)) {
368 device_scores[(size_t)DeviceClass::flight_stick] += 10;
370 if (test_bit(BTN_MOUSE, keys) && test_bit(EV_REL, evtypes)) {
371 device_scores[(size_t)DeviceClass::mouse] += 20;
373 uint8_t unknown_keys[] = {KEY_POWER};
374 for (
int i = 0; i < 1; i++) {
375 if (test_bit(unknown_keys[i], keys)) {
376 if (unknown_keys[i] == KEY_POWER) {
378 device_scores[(size_t)DeviceClass::unknown] += 20;
381 if (_features & (
unsigned int)Feature::keyboard) {
382 device_scores[(size_t)DeviceClass::keyboard] += 20;
386 string lowercase_name = _name;
387 for(
size_t x = 0; x < _name.length(); ++x) {
388 lowercase_name[x] = tolower(lowercase_name[x]);
390 if (lowercase_name.find(
"gamepad") != string::npos) {
391 device_scores[(size_t)DeviceClass::gamepad] += 10;
393 if (lowercase_name.find(
"wheel") != string::npos) {
394 device_scores[(size_t)DeviceClass::steering_wheel] += 10;
396 if (lowercase_name.find(
"mouse") != string::npos || lowercase_name.find(
"touchpad") != string::npos) {
397 device_scores[(size_t)DeviceClass::mouse] += 10;
399 if (lowercase_name.find(
"keyboard") != string::npos) {
400 device_scores[(size_t)DeviceClass::keyboard] += 10;
403 string unknown_names[] = {
"video bus",
"power button",
"sleep button"};
404 for(
int i = 0; i < 3; i++) {
405 if (lowercase_name.find(unknown_names[i]) != string::npos) {
406 device_scores[(size_t)DeviceClass::unknown] += 20;
411 int highest_score = 0;
412 for (
size_t i = 0; i < (size_t)DeviceClass::spatial_mouse; i++) {
413 if (device_scores[i] > highest_score) {
414 highest_score = device_scores[i];
415 _device_class = (DeviceClass)i;
423 uint8_t states[(KEY_MAX + 8) >> 3] = {0};
424 ioctl(_fd, EVIOCGKEY(
sizeof(states)), states);
426 for (
int i = 0; i <= KEY_MAX; ++i) {
427 if (test_bit(i, keys)) {
429 button.handle = map_button(i, _device_class, quirks);
431 int button_index = (int)_buttons.size();
432 if (button.handle == ButtonHandle::none()) {
433 if (device_cat.is_debug()) {
434 device_cat.debug() <<
"Unmapped /dev/input/event" << _index
435 <<
" button " << button_index <<
": 0x" << std::hex << i << std::dec <<
"\n";
439 if (test_bit(i, states)) {
440 button._state = S_down;
441 all_values_zero =
false;
443 button._state = S_up;
445 if (button.handle == GamepadButton::dpad_left()) {
446 emulate_dpad =
false;
447 }
else if (button.handle == GamepadButton::ltrigger()) {
449 }
else if (button.handle == GamepadButton::rtrigger()) {
453 _buttons.push_back(button);
454 if ((
size_t)i >= _button_indices.size()) {
455 _button_indices.resize(i + 1, -1);
457 _button_indices[i] = button_index;
463 _axis_indices.resize(num_bits, -1);
465 for (
int i = 0; i < num_bits; ++i) {
466 if (test_bit(i, axes)) {
467 Axis axis = Axis::none;
470 if (_device_class == DeviceClass::gamepad) {
471 axis = InputDevice::Axis::left_x;
472 }
else if (_device_class == DeviceClass::flight_stick) {
473 axis = InputDevice::Axis::roll;
475 axis = InputDevice::Axis::x;
479 if (_device_class == DeviceClass::gamepad) {
480 axis = InputDevice::Axis::left_y;
481 }
else if (_device_class == DeviceClass::flight_stick) {
482 axis = InputDevice::Axis::pitch;
484 axis = InputDevice::Axis::y;
488 if (quirks & QB_rstick_from_z) {
489 axis = InputDevice::Axis::right_x;
490 }
else if (_device_class == DeviceClass::gamepad) {
491 axis = InputDevice::Axis::left_trigger;
492 have_analog_triggers =
true;
493 }
else if (_device_class == DeviceClass::spatial_mouse) {
494 axis = InputDevice::Axis::z;
496 axis = InputDevice::Axis::throttle;
500 if (_device_class == DeviceClass::spatial_mouse) {
501 axis = InputDevice::Axis::pitch;
502 }
else if ((quirks & QB_rstick_from_z) == 0) {
503 axis = InputDevice::Axis::right_x;
507 if (_device_class == DeviceClass::spatial_mouse) {
508 axis = InputDevice::Axis::roll;
509 }
else if ((quirks & QB_rstick_from_z) == 0) {
510 axis = InputDevice::Axis::right_y;
514 if (quirks & QB_rstick_from_z) {
515 axis = InputDevice::Axis::right_y;
516 }
else if (_device_class == DeviceClass::gamepad) {
517 axis = InputDevice::Axis::right_trigger;
518 have_analog_triggers =
true;
520 axis = InputDevice::Axis::yaw;
524 if (quirks & QB_rudder_from_throttle) {
525 axis = InputDevice::Axis::rudder;
527 axis = InputDevice::Axis::throttle;
531 axis = InputDevice::Axis::rudder;
534 axis = InputDevice::Axis::wheel;
537 if (_device_class == DeviceClass::gamepad) {
538 axis = InputDevice::Axis::right_trigger;
539 have_analog_triggers =
true;
541 axis = InputDevice::Axis::accelerator;
545 if (_device_class == DeviceClass::gamepad) {
546 axis = InputDevice::Axis::left_trigger;
547 have_analog_triggers =
true;
549 axis = InputDevice::Axis::brake;
555 _dpad_left_button = (int)_buttons.size();
556 if (_device_class == DeviceClass::gamepad) {
557 _buttons.push_back(ButtonState(GamepadButton::dpad_left()));
558 _buttons.push_back(ButtonState(GamepadButton::dpad_right()));
560 _buttons.push_back(ButtonState(GamepadButton::hat_left()));
561 _buttons.push_back(ButtonState(GamepadButton::hat_right()));
568 _dpad_up_button = (int)_buttons.size();
569 if (_device_class == DeviceClass::gamepad) {
570 _buttons.push_back(ButtonState(GamepadButton::dpad_up()));
571 _buttons.push_back(ButtonState(GamepadButton::dpad_down()));
573 _buttons.push_back(ButtonState(GamepadButton::hat_up()));
574 _buttons.push_back(ButtonState(GamepadButton::hat_down()));
579 if (quirks & QB_steam_controller) {
580 axis = InputDevice::Axis::right_trigger;
581 have_analog_triggers =
true;
585 if (quirks & QB_steam_controller) {
586 axis = InputDevice::Axis::left_trigger;
587 have_analog_triggers =
true;
593 struct input_absinfo absinfo;
594 if (ioctl(_fd, EVIOCGABS(i), &absinfo) >= 0) {
599 if (axis == Axis::yaw || axis == Axis::rudder || axis == Axis::left_y || axis == Axis::right_y ||
600 (axis == Axis::throttle && (quirks & QB_reversed_throttle) != 0) ||
601 (_device_class == DeviceClass::spatial_mouse && (axis == Axis::y || axis == Axis::z || axis == Axis::roll))) {
602 std::swap(absinfo.maximum, absinfo.minimum);
604 if (axis == Axis::throttle && (quirks & QB_centered_throttle) != 0) {
605 index = add_axis(axis, absinfo.minimum, absinfo.maximum,
true);
607 index = add_axis(axis, absinfo.minimum, absinfo.maximum);
609 axis_changed(index, absinfo.value);
610 _axis_indices[i] = index;
612 if (absinfo.value != 0) {
613 all_values_zero =
false;
620 if (test_bit(EV_REL, evtypes)) {
621 enable_feature(Feature::pointer);
622 add_pointer(PointerType::unknown, 0);
625 if (test_bit(EV_FF, evtypes)) {
626 uint8_t effects[(FF_MAX + 8) >> 3] = {0};
627 ioctl(_fd, EVIOCGBIT(EV_FF,
sizeof(effects)), effects);
629 if (test_bit(FF_RUMBLE, effects)) {
631 enable_feature(Feature::vibration);
635 <<
"/dev/input/event" << _index <<
" is not writable, vibration " 636 <<
"effects will be unavailable.\n";
641 if (_ltrigger_code >= 0 && _rtrigger_code >= 0 && !have_analog_triggers) {
643 _ltrigger_axis = (int)_axes.size();
644 add_axis(Axis::left_trigger, 0, 1,
false);
645 add_axis(Axis::right_trigger, 0, 1,
false);
653 const char *parent =
"";
654 sprintf(path,
"/sys/class/input/event%zd/device/device/../product", _index);
655 FILE *f = fopen(path,
"r");
658 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../product", _index, parent);
659 f = fopen(path,
"r");
662 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
663 buffer[strcspn(buffer,
"\r\n")] = 0;
664 if (buffer[0] != 0) {
665 _name.assign(buffer);
670 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../manufacturer", _index, parent);
671 f = fopen(path,
"r");
673 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
674 buffer[strcspn(buffer,
"\r\n")] = 0;
675 _manufacturer.assign(buffer);
679 sprintf(path,
"/sys/class/input/event%zd/device/device/%s../serial", _index, parent);
680 f = fopen(path,
"r");
682 if (fgets(buffer,
sizeof(buffer), f) !=
nullptr) {
683 buffer[strcspn(buffer,
"\r\n")] = 0;
684 _serial_number.assign(buffer);
692 if (all_values_zero && (quirks & QB_connect_if_nonzero) != 0) {
693 _is_connected =
false;
695 _is_connected =
true;
704 bool EvdevInputDevice::
707 struct input_event events[8];
709 int n_read = read(_fd, events,
sizeof(events));
711 if (errno == EAGAIN || errno == EWOULDBLOCK) {
714 }
else if (errno == ENODEV || errno == EINVAL) {
724 device_cat.error() <<
"read: " << strerror(errno) <<
"\n";
733 n_read /=
sizeof(
struct input_event);
742 if (n_read == 1 && events[0].code == EV_SYN) {
746 for (
int i = 0; i < n_read; ++i) {
747 int code = events[i].code;
749 switch (events[i].type) {
754 if (code == REL_X) rel_x += events[i].value;
755 if (code == REL_Y) rel_y += events[i].value;
759 if (code == _dpad_x_axis) {
760 button_changed(_dpad_left_button, events[i].value < 0);
761 button_changed(_dpad_left_button+1, events[i].value > 0);
762 }
else if (code == _dpad_y_axis) {
763 button_changed(_dpad_up_button, events[i].value < 0);
764 button_changed(_dpad_up_button+1, events[i].value > 0);
766 nassertd(code >= 0 && (
size_t)code < _axis_indices.size())
break;
767 index = _axis_indices[code];
769 axis_changed(index, events[i].value);
774 nassertd(code >= 0 && (
size_t)code < _button_indices.size())
break;
775 index = _button_indices[code];
777 button_changed(index, events[i].value != 0);
779 if (code == _ltrigger_code) {
780 axis_changed(_ltrigger_axis, events[i].value);
781 }
else if (code == _rtrigger_code) {
782 axis_changed(_ltrigger_axis + 1, events[i].value);
792 if (rel_x != 0 || rel_y != 0) {
793 pointer_moved(0, rel_x, rel_y, time);
803 map_button(
int code, DeviceClass device_class,
int quirks) {
804 if (code >= 0 && code < 0x80) {
807 ButtonHandle::none(),
808 KeyboardButton::escape(),
821 KeyboardButton::backspace(),
822 KeyboardButton::tab(),
835 KeyboardButton::enter(),
836 KeyboardButton::lcontrol(),
849 KeyboardButton::lshift(),
861 KeyboardButton::rshift(),
863 KeyboardButton::lalt(),
864 KeyboardButton::space(),
865 KeyboardButton::caps_lock(),
866 KeyboardButton::f1(),
867 KeyboardButton::f2(),
868 KeyboardButton::f3(),
869 KeyboardButton::f4(),
870 KeyboardButton::f5(),
871 KeyboardButton::f6(),
872 KeyboardButton::f7(),
873 KeyboardButton::f8(),
874 KeyboardButton::f9(),
875 KeyboardButton::f10(),
876 KeyboardButton::num_lock(),
877 KeyboardButton::scroll_lock(),
891 ButtonHandle::none(),
892 ButtonHandle::none(),
893 ButtonHandle::none(),
894 KeyboardButton::f11(),
895 KeyboardButton::f12(),
896 ButtonHandle::none(),
897 ButtonHandle::none(),
898 ButtonHandle::none(),
899 ButtonHandle::none(),
900 ButtonHandle::none(),
901 ButtonHandle::none(),
902 ButtonHandle::none(),
903 KeyboardButton::enter(),
904 KeyboardButton::rcontrol(),
906 KeyboardButton::print_screen(),
907 KeyboardButton::ralt(),
908 ButtonHandle::none(),
909 KeyboardButton::home(),
910 KeyboardButton::up(),
911 KeyboardButton::page_up(),
912 KeyboardButton::left(),
913 KeyboardButton::right(),
914 KeyboardButton::end(),
915 KeyboardButton::down(),
916 KeyboardButton::page_down(),
917 KeyboardButton::insert(),
918 KeyboardButton::del(),
919 ButtonHandle::none(),
920 ButtonHandle::none(),
921 ButtonHandle::none(),
922 ButtonHandle::none(),
923 ButtonHandle::none(),
924 ButtonHandle::none(),
925 ButtonHandle::none(),
926 KeyboardButton::pause(),
927 ButtonHandle::none(),
928 ButtonHandle::none(),
929 ButtonHandle::none(),
930 ButtonHandle::none(),
931 ButtonHandle::none(),
932 KeyboardButton::lmeta(),
933 KeyboardButton::rmeta(),
934 KeyboardButton::menu(),
936 return keyboard_map[code];
938 }
else if (code == KEY_BACK) {
940 return GamepadButton::back();
942 }
else if (code == KEY_SEARCH) {
944 return GamepadButton::guide();
946 }
else if (code < 0x100) {
947 return ButtonHandle::none();
949 }
else if ((code & 0xfff0) == BTN_MOUSE) {
951 if (code == BTN_RIGHT) {
953 }
else if (code == BTN_MIDDLE) {
959 }
else if ((code & 0xfff0) == BTN_JOYSTICK) {
960 if (quirks & QB_steam_controller) {
962 return ButtonHandle::none();
964 }
else if (device_class == DeviceClass::gamepad) {
967 GamepadButton::face_x(),
968 GamepadButton::face_y(),
969 GamepadButton::face_a(),
970 GamepadButton::face_b(),
971 GamepadButton::lshoulder(),
972 GamepadButton::ltrigger(),
973 GamepadButton::rshoulder(),
974 GamepadButton::rtrigger(),
975 GamepadButton::back(),
976 GamepadButton::start(),
977 GamepadButton::lstick(),
978 GamepadButton::rstick(),
980 if ((code & 0xf) < 12) {
981 return mapping[code & 0xf];
990 return GamepadButton::face_a();
993 return GamepadButton::face_b();
996 return GamepadButton::face_c();
999 return GamepadButton::face_x();
1002 return GamepadButton::face_y();
1005 return GamepadButton::face_z();
1008 return GamepadButton::lshoulder();
1011 return GamepadButton::rshoulder();
1014 return GamepadButton::ltrigger();
1017 return GamepadButton::rtrigger();
1020 return GamepadButton::face_1();
1023 return GamepadButton::face_2();
1027 return GamepadButton::back();
1031 return GamepadButton::start();
1034 return GamepadButton::guide();
1037 return GamepadButton::lstick();
1040 return GamepadButton::rstick();
1043 case BTN_TRIGGER_HAPPY1:
1044 return GamepadButton::dpad_left();
1046 case BTN_DPAD_RIGHT:
1047 case BTN_TRIGGER_HAPPY2:
1048 return GamepadButton::dpad_right();
1051 case BTN_TRIGGER_HAPPY3:
1052 return GamepadButton::dpad_up();
1055 case BTN_TRIGGER_HAPPY4:
1056 return GamepadButton::dpad_down();
1060 return GamepadButton::lgrip();
1063 return GamepadButton::rgrip();
1066 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.