@desklink/host 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +44 -0
  3. package/README.md +266 -0
  4. package/bin/desklink-host.mjs +113 -0
  5. package/dist/bridge.d.ts +57 -0
  6. package/dist/bridge.d.ts.map +1 -0
  7. package/dist/bridge.js +208 -0
  8. package/dist/bridge.js.map +1 -0
  9. package/dist/engineProcess.d.ts +82 -0
  10. package/dist/engineProcess.d.ts.map +1 -0
  11. package/dist/engineProcess.js +243 -0
  12. package/dist/engineProcess.js.map +1 -0
  13. package/dist/index.d.ts +12 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +12 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/protocol.d.ts +169 -0
  18. package/dist/protocol.d.ts.map +1 -0
  19. package/dist/protocol.js +18 -0
  20. package/dist/protocol.js.map +1 -0
  21. package/dist/resolveEngine.d.ts +34 -0
  22. package/dist/resolveEngine.d.ts.map +1 -0
  23. package/dist/resolveEngine.js +103 -0
  24. package/dist/resolveEngine.js.map +1 -0
  25. package/docs/BOUNDARY.md +145 -0
  26. package/docs/PROTOCOL.md +363 -0
  27. package/engine/Cargo.lock +3077 -0
  28. package/engine/Cargo.toml +37 -0
  29. package/engine/build.rs +107 -0
  30. package/engine/native/inputtino_shim.cpp +11 -0
  31. package/engine/native/vpx_shim.c +184 -0
  32. package/engine/native/wrapper.h +7 -0
  33. package/engine/src/capture.rs +510 -0
  34. package/engine/src/clipboard.rs +132 -0
  35. package/engine/src/convert.rs +299 -0
  36. package/engine/src/encoder.rs +204 -0
  37. package/engine/src/input.rs +355 -0
  38. package/engine/src/keymap.rs +338 -0
  39. package/engine/src/main.rs +614 -0
  40. package/engine/src/peer.rs +775 -0
  41. package/engine/src/portal.rs +115 -0
  42. package/engine/src/protocol.rs +331 -0
  43. package/engine/src/session.rs +2159 -0
  44. package/engine/src/x11.rs +244 -0
  45. package/engine/vendor/inputtino/.clang-format +166 -0
  46. package/engine/vendor/inputtino/.clang-tidy +30 -0
  47. package/engine/vendor/inputtino/.dockerignore +11 -0
  48. package/engine/vendor/inputtino/.github/workflows/mirror-repo.yml +14 -0
  49. package/engine/vendor/inputtino/.github/workflows/python-lint-format-test-typecheck.yml +124 -0
  50. package/engine/vendor/inputtino/.github/workflows/python-test-install.yaml +49 -0
  51. package/engine/vendor/inputtino/.github/workflows/rust.yml +40 -0
  52. package/engine/vendor/inputtino/CMakeLists.txt +187 -0
  53. package/engine/vendor/inputtino/LICENSE +21 -0
  54. package/engine/vendor/inputtino/README.md +110 -0
  55. package/engine/vendor/inputtino/bindings/python/.devcontainer/Dockerfile +23 -0
  56. package/engine/vendor/inputtino/bindings/python/.devcontainer/devcontainer.json +28 -0
  57. package/engine/vendor/inputtino/bindings/python/.python-version +1 -0
  58. package/engine/vendor/inputtino/bindings/python/CMakeLists.txt +23 -0
  59. package/engine/vendor/inputtino/bindings/python/CPPLINT.cfg +2 -0
  60. package/engine/vendor/inputtino/bindings/python/Makefile +49 -0
  61. package/engine/vendor/inputtino/bindings/python/README.md +215 -0
  62. package/engine/vendor/inputtino/bindings/python/pyproject.toml +178 -0
  63. package/engine/vendor/inputtino/bindings/python/src/inputtino/__init__.py +43 -0
  64. package/engine/vendor/inputtino/bindings/python/src/inputtino/_core.pyi +533 -0
  65. package/engine/vendor/inputtino/bindings/python/src/inputtino/base.py +63 -0
  66. package/engine/vendor/inputtino/bindings/python/src/inputtino/joypad.py +248 -0
  67. package/engine/vendor/inputtino/bindings/python/src/inputtino/keyboard.py +256 -0
  68. package/engine/vendor/inputtino/bindings/python/src/inputtino/mouse.py +106 -0
  69. package/engine/vendor/inputtino/bindings/python/src/inputtino/pentablet.py +73 -0
  70. package/engine/vendor/inputtino/bindings/python/src/inputtino/py.typed +0 -0
  71. package/engine/vendor/inputtino/bindings/python/src/inputtino/touchscreen.py +61 -0
  72. package/engine/vendor/inputtino/bindings/python/src/inputtino/trackpad.py +74 -0
  73. package/engine/vendor/inputtino/bindings/python/src/main.cpp +217 -0
  74. package/engine/vendor/inputtino/bindings/python/tests/__init__.py +0 -0
  75. package/engine/vendor/inputtino/bindings/python/tests/helpers.py +3 -0
  76. package/engine/vendor/inputtino/bindings/python/tests/test_base.py +60 -0
  77. package/engine/vendor/inputtino/bindings/python/tests/test_inputtino.py +5 -0
  78. package/engine/vendor/inputtino/bindings/python/tests/test_joypad.py +332 -0
  79. package/engine/vendor/inputtino/bindings/python/tests/test_keyboard.py +164 -0
  80. package/engine/vendor/inputtino/bindings/python/tests/test_mouse.py +185 -0
  81. package/engine/vendor/inputtino/bindings/python/tests/test_pentablet.py +198 -0
  82. package/engine/vendor/inputtino/bindings/python/tests/test_touchscreen.py +144 -0
  83. package/engine/vendor/inputtino/bindings/python/tests/test_trackpad.py +146 -0
  84. package/engine/vendor/inputtino/bindings/python/uv.lock +390 -0
  85. package/engine/vendor/inputtino/bindings/rust/Cargo.toml +6 -0
  86. package/engine/vendor/inputtino/bindings/rust/inputtino/.dockerignore +1 -0
  87. package/engine/vendor/inputtino/bindings/rust/inputtino/Cargo.toml +18 -0
  88. package/engine/vendor/inputtino/bindings/rust/inputtino/examples/keyboard.rs +33 -0
  89. package/engine/vendor/inputtino/bindings/rust/inputtino/examples/mouse.rs +17 -0
  90. package/engine/vendor/inputtino/bindings/rust/inputtino/src/common.rs +116 -0
  91. package/engine/vendor/inputtino/bindings/rust/inputtino/src/error.rs +17 -0
  92. package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad.rs +74 -0
  93. package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_nintendo.rs +135 -0
  94. package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_ps5.rs +280 -0
  95. package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_xbox.rs +134 -0
  96. package/engine/vendor/inputtino/bindings/rust/inputtino/src/keyboard.rs +76 -0
  97. package/engine/vendor/inputtino/bindings/rust/inputtino/src/lib.rs +32 -0
  98. package/engine/vendor/inputtino/bindings/rust/inputtino/src/mouse.rs +178 -0
  99. package/engine/vendor/inputtino/bindings/rust/inputtino/tests/common.rs +38 -0
  100. package/engine/vendor/inputtino/bindings/rust/inputtino/tests/joypads.rs +150 -0
  101. package/engine/vendor/inputtino/bindings/rust/inputtino/tests/keyboard.rs +73 -0
  102. package/engine/vendor/inputtino/bindings/rust/inputtino/tests/mouse.rs +139 -0
  103. package/engine/vendor/inputtino/bindings/rust/inputtino-sys/.dockerignore +1 -0
  104. package/engine/vendor/inputtino/bindings/rust/inputtino-sys/Cargo.toml +12 -0
  105. package/engine/vendor/inputtino/bindings/rust/inputtino-sys/build.rs +48 -0
  106. package/engine/vendor/inputtino/bindings/rust/inputtino-sys/src/lib.rs +5 -0
  107. package/engine/vendor/inputtino/bindings/rust/inputtino-sys/wrapper.h +1 -0
  108. package/engine/vendor/inputtino/cmake/utils.cmake +9 -0
  109. package/engine/vendor/inputtino/docker/Dockerfile +70 -0
  110. package/engine/vendor/inputtino/include/inputtino/input.h +324 -0
  111. package/engine/vendor/inputtino/include/inputtino/input.hpp +466 -0
  112. package/engine/vendor/inputtino/include/inputtino/result.hpp +37 -0
  113. package/engine/vendor/inputtino/share/pkgconfig/libinputtino.pc.in +17 -0
  114. package/engine/vendor/inputtino/src/c-bindings/helpers.hpp +19 -0
  115. package/engine/vendor/inputtino/src/c-bindings/joypad_ps5.cpp +115 -0
  116. package/engine/vendor/inputtino/src/c-bindings/joypad_switch.cpp +63 -0
  117. package/engine/vendor/inputtino/src/c-bindings/joypad_xone.cpp +62 -0
  118. package/engine/vendor/inputtino/src/c-bindings/keyboard.cpp +42 -0
  119. package/engine/vendor/inputtino/src/c-bindings/mouse.cpp +67 -0
  120. package/engine/vendor/inputtino/src/c-bindings/pen_tablet.cpp +50 -0
  121. package/engine/vendor/inputtino/src/c-bindings/touchscreen.cpp +43 -0
  122. package/engine/vendor/inputtino/src/c-bindings/trackpad.cpp +49 -0
  123. package/engine/vendor/inputtino/src/uhid/README.adoc +63 -0
  124. package/engine/vendor/inputtino/src/uhid/include/crc32.hpp +38 -0
  125. package/engine/vendor/inputtino/src/uhid/include/uhid/protected_types.hpp +36 -0
  126. package/engine/vendor/inputtino/src/uhid/include/uhid/ps5.hpp +550 -0
  127. package/engine/vendor/inputtino/src/uhid/include/uhid/uhid.hpp +168 -0
  128. package/engine/vendor/inputtino/src/uhid/joypad_ps5.cpp +580 -0
  129. package/engine/vendor/inputtino/src/uinput/include/inputtino/keyboard.hpp +84 -0
  130. package/engine/vendor/inputtino/src/uinput/include/inputtino/protected_ps5_types.hpp +7 -0
  131. package/engine/vendor/inputtino/src/uinput/include/inputtino/protected_types.hpp +110 -0
  132. package/engine/vendor/inputtino/src/uinput/joypad_nintendo.cpp +190 -0
  133. package/engine/vendor/inputtino/src/uinput/joypad_ps.cpp +203 -0
  134. package/engine/vendor/inputtino/src/uinput/joypad_utils.hpp +246 -0
  135. package/engine/vendor/inputtino/src/uinput/joypad_xbox.cpp +190 -0
  136. package/engine/vendor/inputtino/src/uinput/keyboard.cpp +120 -0
  137. package/engine/vendor/inputtino/src/uinput/mouse.cpp +199 -0
  138. package/engine/vendor/inputtino/src/uinput/pentablet.cpp +162 -0
  139. package/engine/vendor/inputtino/src/uinput/touchscreen.cpp +140 -0
  140. package/engine/vendor/inputtino/src/uinput/trackpad.cpp +192 -0
  141. package/examples/reference-client.html +428 -0
  142. package/package.json +38 -0
@@ -0,0 +1,110 @@
1
+ #pragma once
2
+
3
+ #include <cstring>
4
+ #include <inputtino/input.hpp>
5
+ #include <iostream>
6
+ #include <libevdev/libevdev-uinput.h>
7
+ #include <libevdev/libevdev.h>
8
+ #include <thread>
9
+ #include <unistd.h>
10
+
11
+ namespace inputtino {
12
+
13
+ using libevdev_uinput_ptr = std::shared_ptr<libevdev_uinput>;
14
+ using libevdev_event_ptr = std::shared_ptr<input_event>;
15
+
16
+ /**
17
+ * Given a uinput fd will read all queued events available at this time up to max_events
18
+ */
19
+ static std::vector<libevdev_event_ptr> fetch_events(int uinput_fd, int max_events = 50) {
20
+ std::vector<libevdev_event_ptr> events = {};
21
+ struct input_event ev {};
22
+ int ret, read_events = 0;
23
+ while (read_events < max_events && (ret = read(uinput_fd, &ev, sizeof(ev))) == sizeof(ev)) {
24
+ events.push_back(std::make_shared<input_event>(ev));
25
+ read_events++;
26
+ }
27
+ if (ret < 0 && errno != EAGAIN) {
28
+ std::cerr << "Failed reading uinput fd; ret=" << strerror(errno);
29
+ } else if (ret > 0) {
30
+ std::cerr << "Uinput incorrect read size of " << ret;
31
+ }
32
+
33
+ return events;
34
+ }
35
+
36
+ struct PenTabletState {
37
+ libevdev_uinput_ptr pen_tablet = nullptr;
38
+ PenTablet::TOOL_TYPE last_tool = PenTablet::SAME_AS_BEFORE;
39
+ };
40
+
41
+ struct BaseJoypadState {
42
+ libevdev_uinput_ptr joy = nullptr;
43
+ int currently_pressed_btns = 0;
44
+
45
+ bool stop_listening_events = false;
46
+ std::thread events_thread;
47
+
48
+ std::optional<std::function<void(int low_freq, int high_freq)>> on_rumble = std::nullopt;
49
+ };
50
+
51
+ struct XboxOneJoypadState : BaseJoypadState {};
52
+ struct SwitchJoypadState : BaseJoypadState {};
53
+
54
+ struct KeyboardState {
55
+ std::thread repeat_press_t;
56
+ bool stop_repeat_thread = false;
57
+ libevdev_uinput_ptr kb = nullptr;
58
+ std::vector<short> cur_press_keys = {};
59
+ };
60
+
61
+ struct MouseState {
62
+ libevdev_uinput_ptr mouse_rel = nullptr;
63
+ libevdev_uinput_ptr mouse_abs = nullptr;
64
+ };
65
+
66
+ struct TouchScreenState {
67
+ libevdev_uinput_ptr touch_screen = nullptr;
68
+
69
+ /**
70
+ * Multi touch protocol type B is stateful; see: https://docs.kernel.org/input/multi-touch-protocol.html
71
+ * Slots are numbered starting from 0 up to <number of currently connected fingers> (max: 4)
72
+ *
73
+ * The way it works:
74
+ * - first time a new finger_id arrives we'll create a new slot and call MT_TRACKING_ID = slot_number
75
+ * - we can keep updating ABS_X and ABS_Y as long as the finger_id stays the same
76
+ * - if we want to update a different finger we'll have to call ABS_MT_SLOT = slot_number
77
+ * - when a finger is released we'll call ABS_MT_SLOT = slot_number && MT_TRACKING_ID = -1
78
+ *
79
+ * The other thing that needs to be kept in sync is the EV_KEY.
80
+ * EX: enabling BTN_TOOL_DOUBLETAP will result in scrolling instead of moving the mouse
81
+ */
82
+ /* The MT_SLOT we are currently updating */
83
+ int current_slot = -1;
84
+ /* A map of finger_id to MT_SLOT */
85
+ std::map<int /* finger_id */, int /* MT_SLOT */> fingers;
86
+ };
87
+
88
+ struct TrackpadState {
89
+ libevdev_uinput_ptr trackpad = nullptr;
90
+
91
+ /**
92
+ * Multi touch protocol type B is stateful; see: https://docs.kernel.org/input/multi-touch-protocol.html
93
+ * Slots are numbered starting from 0 up to <number of currently connected fingers> (max: 4)
94
+ *
95
+ * The way it works:
96
+ * - first time a new finger_id arrives we'll create a new slot and call MT_TRACKING_ID = slot_number
97
+ * - we can keep updating ABS_X and ABS_Y as long as the finger_id stays the same
98
+ * - if we want to update a different finger we'll have to call ABS_MT_SLOT = slot_number
99
+ * - when a finger is released we'll call ABS_MT_SLOT = slot_number && MT_TRACKING_ID = -1
100
+ *
101
+ * The other thing that needs to be kept in sync is the EV_KEY.
102
+ * EX: enabling BTN_TOOL_DOUBLETAP will result in scrolling instead of moving the mouse
103
+ */
104
+ /* The MT_SLOT we are currently updating */
105
+ int current_slot = -1;
106
+ /* A map of finger_id to MT_SLOT */
107
+ std::map<int /* finger_id */, int /* MT_SLOT */> fingers;
108
+ };
109
+
110
+ } // namespace inputtino
@@ -0,0 +1,190 @@
1
+ #include "joypad_utils.hpp"
2
+ #include <cstring>
3
+ #include <fcntl.h>
4
+ #include <inputtino/input.hpp>
5
+ #include <inputtino/protected_types.hpp>
6
+ #include <iostream>
7
+ #include <linux/input.h>
8
+ #include <optional>
9
+ #include <thread>
10
+
11
+ namespace inputtino {
12
+
13
+ std::vector<std::string> SwitchJoypad::get_nodes() const {
14
+ std::vector<std::string> nodes;
15
+
16
+ if (auto joy = _state->joy.get()) {
17
+ auto additional_nodes = get_child_dev_nodes(joy);
18
+ nodes.insert(nodes.end(), additional_nodes.begin(), additional_nodes.end());
19
+ }
20
+
21
+ return nodes;
22
+ }
23
+
24
+ Result<libevdev_uinput_ptr> create_nintendo_controller(const DeviceDefinition &device) {
25
+ libevdev *dev = libevdev_new();
26
+ libevdev_uinput *uidev;
27
+
28
+ libevdev_set_name(dev, device.name.c_str());
29
+ libevdev_set_id_vendor(dev, device.vendor_id);
30
+ libevdev_set_id_product(dev, device.product_id);
31
+ libevdev_set_id_version(dev, device.version);
32
+ libevdev_set_id_bustype(dev, BUS_USB);
33
+
34
+ libevdev_enable_event_type(dev, EV_KEY);
35
+ libevdev_enable_event_code(dev, EV_KEY, BTN_WEST, nullptr);
36
+ libevdev_enable_event_code(dev, EV_KEY, BTN_EAST, nullptr);
37
+ libevdev_enable_event_code(dev, EV_KEY, BTN_NORTH, nullptr);
38
+ libevdev_enable_event_code(dev, EV_KEY, BTN_SOUTH, nullptr);
39
+ libevdev_enable_event_code(dev, EV_KEY, BTN_THUMBL, nullptr);
40
+ libevdev_enable_event_code(dev, EV_KEY, BTN_THUMBR, nullptr);
41
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TR, nullptr);
42
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TL, nullptr);
43
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TR2, nullptr);
44
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TL2, nullptr);
45
+ libevdev_enable_event_code(dev, EV_KEY, BTN_Z, nullptr); // Capture btn
46
+ libevdev_enable_event_code(dev, EV_KEY, BTN_SELECT, nullptr);
47
+ libevdev_enable_event_code(dev, EV_KEY, BTN_MODE, nullptr);
48
+ libevdev_enable_event_code(dev, EV_KEY, BTN_START, nullptr);
49
+
50
+ libevdev_enable_event_type(dev, EV_ABS);
51
+
52
+ input_absinfo dpad{0, -1, 1, 0, 0, 0};
53
+ libevdev_enable_event_code(dev, EV_ABS, ABS_HAT0Y, &dpad);
54
+ libevdev_enable_event_code(dev, EV_ABS, ABS_HAT0X, &dpad);
55
+
56
+ // see: https://github.com/games-on-whales/wolf/issues/56
57
+ input_absinfo stick{0, -32768, 32767, 250, 500, 0};
58
+ libevdev_enable_event_code(dev, EV_ABS, ABS_X, &stick);
59
+ libevdev_enable_event_code(dev, EV_ABS, ABS_RX, &stick);
60
+ libevdev_enable_event_code(dev, EV_ABS, ABS_Y, &stick);
61
+ libevdev_enable_event_code(dev, EV_ABS, ABS_RY, &stick);
62
+
63
+ // On Nintendo L2/R2 are just buttons!
64
+
65
+ libevdev_enable_event_type(dev, EV_FF);
66
+ libevdev_enable_event_code(dev, EV_FF, FF_RUMBLE, nullptr);
67
+ libevdev_enable_event_code(dev, EV_FF, FF_CONSTANT, nullptr);
68
+ libevdev_enable_event_code(dev, EV_FF, FF_PERIODIC, nullptr);
69
+ libevdev_enable_event_code(dev, EV_FF, FF_SINE, nullptr);
70
+ libevdev_enable_event_code(dev, EV_FF, FF_RAMP, nullptr);
71
+ libevdev_enable_event_code(dev, EV_FF, FF_GAIN, nullptr);
72
+
73
+ auto err = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
74
+ libevdev_free(dev);
75
+ if (err != 0) {
76
+ return Error(strerror(-err));
77
+ }
78
+
79
+ return libevdev_uinput_ptr{uidev, ::libevdev_uinput_destroy};
80
+ }
81
+
82
+ SwitchJoypad::SwitchJoypad() : _state(std::make_shared<SwitchJoypadState>()) {}
83
+
84
+ SwitchJoypad::~SwitchJoypad() {
85
+ if (_state) {
86
+ _state->stop_listening_events = true;
87
+ if (_state->joy.get() != nullptr && _state->events_thread.joinable()) {
88
+ _state->events_thread.join();
89
+ }
90
+ }
91
+ }
92
+
93
+ Result<SwitchJoypad> SwitchJoypad::create(const DeviceDefinition &device) {
94
+ auto joy_el = create_nintendo_controller(device);
95
+ if (!joy_el) {
96
+ return Error(joy_el.getErrorMessage());
97
+ }
98
+
99
+ SwitchJoypad joypad;
100
+ joypad._state->joy = std::move(*joy_el);
101
+
102
+ auto event_thread = std::thread(event_listener, joypad._state);
103
+ joypad._state->events_thread = std::move(event_thread);
104
+ joypad._state->events_thread.detach();
105
+
106
+ return joypad;
107
+ }
108
+
109
+ void SwitchJoypad::set_pressed_buttons(unsigned int newly_pressed) {
110
+ // Button flags that have been changed between current and prev
111
+ auto bf_changed = newly_pressed ^ this->_state->currently_pressed_btns;
112
+ // Button flags that are only part of the new packet
113
+ auto bf_new = newly_pressed;
114
+ if (auto controller = this->_state->joy.get()) {
115
+
116
+ if (bf_changed) {
117
+ if ((DPAD_UP | DPAD_DOWN) & bf_changed) {
118
+ int button_state = bf_new & DPAD_UP ? -1 : (bf_new & DPAD_DOWN ? 1 : 0);
119
+
120
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_HAT0Y, button_state);
121
+ }
122
+
123
+ if ((DPAD_LEFT | DPAD_RIGHT) & bf_changed) {
124
+ int button_state = bf_new & DPAD_LEFT ? -1 : (bf_new & DPAD_RIGHT ? 1 : 0);
125
+
126
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_HAT0X, button_state);
127
+ }
128
+
129
+ if (START & bf_changed)
130
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_START, bf_new & START ? 1 : 0);
131
+ if (BACK & bf_changed)
132
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_SELECT, bf_new & BACK ? 1 : 0);
133
+ if (LEFT_STICK & bf_changed)
134
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_THUMBL, bf_new & LEFT_STICK ? 1 : 0);
135
+ if (RIGHT_STICK & bf_changed)
136
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_THUMBR, bf_new & RIGHT_STICK ? 1 : 0);
137
+ if (LEFT_BUTTON & bf_changed)
138
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_TL, bf_new & LEFT_BUTTON ? 1 : 0);
139
+ if (RIGHT_BUTTON & bf_changed)
140
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_TR, bf_new & RIGHT_BUTTON ? 1 : 0);
141
+ if (HOME & bf_changed)
142
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_MODE, bf_new & HOME ? 1 : 0);
143
+ if (MISC_FLAG & bf_changed) {
144
+ // Capture button
145
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_Z, bf_new & MISC_FLAG ? 1 : 0);
146
+ }
147
+ if (A & bf_changed)
148
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_EAST, bf_new & A ? 1 : 0);
149
+ if (B & bf_changed)
150
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_SOUTH, bf_new & B ? 1 : 0);
151
+ if (X & bf_changed)
152
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_NORTH, bf_new & X ? 1 : 0);
153
+ if (Y & bf_changed)
154
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_WEST, bf_new & Y ? 1 : 0);
155
+ }
156
+
157
+ libevdev_uinput_write_event(controller, EV_SYN, SYN_REPORT, 0);
158
+ }
159
+ this->_state->currently_pressed_btns = bf_new;
160
+ }
161
+
162
+ void SwitchJoypad::set_stick(Joypad::STICK_POSITION stick_type, short x, short y) {
163
+ if (auto controller = this->_state->joy.get()) {
164
+ if (stick_type == LS) {
165
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_X, x);
166
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_Y, -y);
167
+ } else {
168
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_RX, x);
169
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_RY, -y);
170
+ }
171
+
172
+ libevdev_uinput_write_event(controller, EV_SYN, SYN_REPORT, 0);
173
+ }
174
+ }
175
+
176
+ void SwitchJoypad::set_triggers(int16_t left, int16_t right) {
177
+ if (auto controller = this->_state->joy.get()) {
178
+ // Nintendo ZL and ZR are just buttons (EV_KEY)
179
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_TL2, left > 0 ? 1 : 0);
180
+ libevdev_uinput_write_event(controller, EV_SYN, SYN_REPORT, 0);
181
+
182
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_TR2, right > 0 ? 1 : 0);
183
+ libevdev_uinput_write_event(controller, EV_SYN, SYN_REPORT, 0);
184
+ }
185
+ }
186
+
187
+ void SwitchJoypad::set_on_rumble(const std::function<void(int, int)> &callback) {
188
+ this->_state->on_rumble = callback;
189
+ }
190
+ } // namespace inputtino
@@ -0,0 +1,203 @@
1
+ #include "joypad_utils.hpp"
2
+ #include <cstring>
3
+ #include <fcntl.h>
4
+ #include <inputtino/input.hpp>
5
+ #include <inputtino/protected_ps5_types.hpp>
6
+ #include <linux/input.h>
7
+ #include <optional>
8
+ #include <thread>
9
+
10
+ namespace inputtino {
11
+
12
+ std::vector<std::string> PS5Joypad::get_nodes() const {
13
+ std::vector<std::string> nodes;
14
+
15
+ if (auto joy = _state->joy.get()) {
16
+ auto additional_nodes = get_child_dev_nodes(joy);
17
+ nodes.insert(nodes.end(), additional_nodes.begin(), additional_nodes.end());
18
+ }
19
+
20
+ return nodes;
21
+ }
22
+
23
+ Result<libevdev_uinput_ptr> create_ps_controller(const DeviceDefinition &device) {
24
+ libevdev *dev = libevdev_new();
25
+ libevdev_uinput *uidev;
26
+
27
+ libevdev_set_name(dev, device.name.c_str());
28
+ libevdev_set_id_vendor(dev, device.vendor_id);
29
+ libevdev_set_id_product(dev, device.product_id);
30
+ libevdev_set_id_version(dev, device.version);
31
+ libevdev_set_id_bustype(dev, BUS_USB);
32
+
33
+ libevdev_enable_event_type(dev, EV_KEY);
34
+ libevdev_enable_event_code(dev, EV_KEY, BTN_WEST, nullptr);
35
+ libevdev_enable_event_code(dev, EV_KEY, BTN_EAST, nullptr);
36
+ libevdev_enable_event_code(dev, EV_KEY, BTN_NORTH, nullptr);
37
+ libevdev_enable_event_code(dev, EV_KEY, BTN_SOUTH, nullptr);
38
+ libevdev_enable_event_code(dev, EV_KEY, BTN_THUMBL, nullptr);
39
+ libevdev_enable_event_code(dev, EV_KEY, BTN_THUMBR, nullptr);
40
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TR, nullptr);
41
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TL, nullptr);
42
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TR2, nullptr);
43
+ libevdev_enable_event_code(dev, EV_KEY, BTN_TL2, nullptr);
44
+ libevdev_enable_event_code(dev, EV_KEY, BTN_SELECT, nullptr);
45
+ libevdev_enable_event_code(dev, EV_KEY, BTN_MODE, nullptr);
46
+ libevdev_enable_event_code(dev, EV_KEY, BTN_START, nullptr);
47
+
48
+ libevdev_enable_event_type(dev, EV_ABS);
49
+
50
+ input_absinfo dpad{0, -1, 1, 0, 0, 0};
51
+ libevdev_enable_event_code(dev, EV_ABS, ABS_HAT0Y, &dpad);
52
+ libevdev_enable_event_code(dev, EV_ABS, ABS_HAT0X, &dpad);
53
+
54
+ // see: https://github.com/games-on-whales/wolf/issues/56
55
+ input_absinfo stick{0, -32768, 32767, 16, 128, 0};
56
+ libevdev_enable_event_code(dev, EV_ABS, ABS_X, &stick);
57
+ libevdev_enable_event_code(dev, EV_ABS, ABS_RX, &stick);
58
+ libevdev_enable_event_code(dev, EV_ABS, ABS_Y, &stick);
59
+ libevdev_enable_event_code(dev, EV_ABS, ABS_RY, &stick);
60
+
61
+ input_absinfo trigger{0, 0, 255, 0, 0, 0};
62
+ libevdev_enable_event_code(dev, EV_ABS, ABS_Z, &trigger);
63
+ libevdev_enable_event_code(dev, EV_ABS, ABS_RZ, &trigger);
64
+
65
+ libevdev_enable_event_type(dev, EV_FF);
66
+ libevdev_enable_event_code(dev, EV_FF, FF_RUMBLE, nullptr);
67
+ libevdev_enable_event_code(dev, EV_FF, FF_CONSTANT, nullptr);
68
+ libevdev_enable_event_code(dev, EV_FF, FF_PERIODIC, nullptr);
69
+ libevdev_enable_event_code(dev, EV_FF, FF_SINE, nullptr);
70
+ libevdev_enable_event_code(dev, EV_FF, FF_RAMP, nullptr);
71
+ libevdev_enable_event_code(dev, EV_FF, FF_GAIN, nullptr);
72
+
73
+ auto err = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
74
+ libevdev_free(dev);
75
+ if (err != 0) {
76
+ return Error(strerror(-err));
77
+ }
78
+
79
+ return libevdev_uinput_ptr{uidev, ::libevdev_uinput_destroy};
80
+ }
81
+
82
+ PS5Joypad::PS5Joypad(uint16_t vendor_id, std::array<unsigned char, 6> mac_address) : _state(std::make_shared<PS5JoypadState>()) {
83
+ }
84
+
85
+ PS5Joypad::~PS5Joypad() {
86
+ if (_state) {
87
+ _state->stop_listening_events = true;
88
+ if (_state->joy.get() != nullptr && _state->events_thread.joinable()) {
89
+ _state->events_thread.join();
90
+ }
91
+ }
92
+ }
93
+
94
+ Result<PS5Joypad> PS5Joypad::create(const DeviceDefinition &device) {
95
+ auto joy_el = create_ps_controller(device);
96
+ if (!joy_el) {
97
+ return Error(joy_el.getErrorMessage());
98
+ }
99
+
100
+ PS5Joypad joypad(0);
101
+ joypad._state->joy = std::move(*joy_el);
102
+
103
+ auto event_thread = std::thread(event_listener, joypad._state);
104
+ joypad._state->events_thread = std::move(event_thread);
105
+ joypad._state->events_thread.detach();
106
+
107
+ return joypad;
108
+ }
109
+
110
+ void PS5Joypad::set_pressed_buttons(unsigned int newly_pressed) {
111
+ // Button flags that have been changed between current and prev
112
+ auto bf_changed = newly_pressed ^ this->_state->currently_pressed_btns;
113
+ // Button flags that are only part of the new packet
114
+ auto bf_new = newly_pressed;
115
+ if (auto controller = this->_state->joy.get()) {
116
+
117
+ if (bf_changed) {
118
+ if ((DPAD_UP | DPAD_DOWN) & bf_changed) {
119
+ int button_state = bf_new & DPAD_UP ? -1 : (bf_new & DPAD_DOWN ? 1 : 0);
120
+
121
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_HAT0Y, button_state);
122
+ }
123
+
124
+ if ((DPAD_LEFT | DPAD_RIGHT) & bf_changed) {
125
+ int button_state = bf_new & DPAD_LEFT ? -1 : (bf_new & DPAD_RIGHT ? 1 : 0);
126
+
127
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_HAT0X, button_state);
128
+ }
129
+
130
+ if (START & bf_changed)
131
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_START, bf_new & START ? 1 : 0);
132
+ if (BACK & bf_changed)
133
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_SELECT, bf_new & BACK ? 1 : 0);
134
+ if (LEFT_STICK & bf_changed)
135
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_THUMBL, bf_new & LEFT_STICK ? 1 : 0);
136
+ if (RIGHT_STICK & bf_changed)
137
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_THUMBR, bf_new & RIGHT_STICK ? 1 : 0);
138
+ if (LEFT_BUTTON & bf_changed)
139
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_TL, bf_new & LEFT_BUTTON ? 1 : 0);
140
+ if (RIGHT_BUTTON & bf_changed)
141
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_TR, bf_new & RIGHT_BUTTON ? 1 : 0);
142
+ if (HOME & bf_changed)
143
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_MODE, bf_new & HOME ? 1 : 0);
144
+ if (A & bf_changed)
145
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_SOUTH, bf_new & A ? 1 : 0);
146
+ if (B & bf_changed)
147
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_EAST, bf_new & B ? 1 : 0);
148
+ if (X & bf_changed)
149
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_WEST, bf_new & X ? 1 : 0);
150
+ if (Y & bf_changed)
151
+ libevdev_uinput_write_event(controller, EV_KEY, BTN_NORTH, bf_new & Y ? 1 : 0);
152
+ }
153
+
154
+ libevdev_uinput_write_event(controller, EV_SYN, SYN_REPORT, 0);
155
+ }
156
+ this->_state->currently_pressed_btns = bf_new;
157
+ }
158
+
159
+ void PS5Joypad::set_stick(Joypad::STICK_POSITION stick_type, short x, short y) {
160
+ if (auto controller = this->_state->joy.get()) {
161
+ if (stick_type == LS) {
162
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_X, x);
163
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_Y, -y);
164
+ } else {
165
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_RX, x);
166
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_RY, -y);
167
+ }
168
+
169
+ libevdev_uinput_write_event(controller, EV_SYN, SYN_REPORT, 0);
170
+ }
171
+ }
172
+
173
+ void PS5Joypad::set_triggers(int16_t left, int16_t right) {
174
+ if (auto controller = this->_state->joy.get()) {
175
+ if (left > 0) {
176
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_Z, left);
177
+ } else {
178
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_Z, left);
179
+ }
180
+
181
+ if (right > 0) {
182
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_RZ, right);
183
+ } else {
184
+ libevdev_uinput_write_event(controller, EV_ABS, ABS_RZ, right);
185
+ }
186
+
187
+ libevdev_uinput_write_event(controller, EV_SYN, SYN_REPORT, 0);
188
+ }
189
+ }
190
+
191
+ void PS5Joypad::set_on_rumble(const std::function<void(int, int)> &callback) {
192
+ this->_state->on_rumble = callback;
193
+ }
194
+
195
+ // Followings aren't supported when not using the UHID implementation
196
+ void PS5Joypad::place_finger(int finger_nr, uint16_t x, uint16_t y) {}
197
+ void PS5Joypad::release_finger(int finger_nr) {}
198
+ void PS5Joypad::set_motion(MOTION_TYPE type, float x, float y, float z) {}
199
+ void PS5Joypad::set_battery(BATTERY_STATE state, int percentage) {}
200
+ void PS5Joypad::set_on_led(const std::function<void(int r, int g, int b)> &callback) {}
201
+ void PS5Joypad::set_on_trigger_effect(const std::function<void(const TriggerEffect &)> &callback) {}
202
+
203
+ } // namespace inputtino