@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,466 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+ #include <functional>
5
+ #include <inputtino/result.hpp>
6
+ #include <map>
7
+ #include <memory>
8
+ #include <optional>
9
+ #include <random>
10
+ #include <string>
11
+ #include <thread>
12
+ #include <vector>
13
+
14
+ namespace inputtino {
15
+
16
+ class VirtualDevice {
17
+ public:
18
+ virtual std::vector<std::string> get_nodes() const = 0;
19
+ virtual ~VirtualDevice() = default;
20
+ };
21
+
22
+ struct DeviceDefinition {
23
+ std::string name;
24
+ uint16_t vendor_id;
25
+ uint16_t product_id;
26
+ uint16_t version;
27
+
28
+ std::string device_phys = "";
29
+ std::string device_uniq = "";
30
+ };
31
+
32
+ /**
33
+ * A virtual mouse device
34
+ */
35
+ class Mouse : public VirtualDevice {
36
+ public:
37
+ static Result<Mouse>
38
+ create(const DeviceDefinition &device = {
39
+ .name = "Wolf mouse virtual device", .vendor_id = 0xAB00, .product_id = 0xAB01, .version = 0xAB00});
40
+
41
+ Mouse(Mouse &&j) noexcept : _state(nullptr) {
42
+ std::swap(j._state, _state);
43
+ }
44
+ ~Mouse() override;
45
+ std::vector<std::string> get_nodes() const override;
46
+
47
+ void move(int delta_x, int delta_y);
48
+
49
+ void move_abs(int x, int y, int screen_width, int screen_height);
50
+
51
+ enum MOUSE_BUTTON {
52
+ LEFT,
53
+ MIDDLE,
54
+ RIGHT,
55
+ SIDE,
56
+ EXTRA
57
+ };
58
+
59
+ void press(MOUSE_BUTTON button);
60
+
61
+ void release(MOUSE_BUTTON button);
62
+
63
+ /**
64
+ *
65
+ * A value that is a fraction of ±120 indicates a wheel movement less than
66
+ * one logical click, a caller should either scroll by the respective
67
+ * fraction of the normal scroll distance or accumulate that value until a
68
+ * multiple of 120 is reached.
69
+ *
70
+ * The magic number 120 originates from the
71
+ * <a href="http://download.microsoft.com/download/b/d/1/bd1f7ef4-7d72-419e-bc5c-9f79ad7bb66e/wheel.docx">
72
+ * Windows Vista Mouse Wheel design document
73
+ * </a>.
74
+ *
75
+ * Positive numbers will scroll down, negative numbers will scroll up
76
+ *
77
+ * @param high_res_distance The distance in high resolution
78
+ */
79
+ void vertical_scroll(int high_res_distance);
80
+
81
+ /**
82
+ *
83
+ * A value that is a fraction of ±120 indicates a wheel movement less than
84
+ * one logical click, a caller should either scroll by the respective
85
+ * fraction of the normal scroll distance or accumulate that value until a
86
+ * multiple of 120 is reached.
87
+ *
88
+ * The magic number 120 originates from the
89
+ * <a href="http://download.microsoft.com/download/b/d/1/bd1f7ef4-7d72-419e-bc5c-9f79ad7bb66e/wheel.docx">
90
+ * Windows Vista Mouse Wheel design document
91
+ * </a>.
92
+ *
93
+ * Positive numbers will scroll right, negative numbers will scroll left
94
+ *
95
+ * @param high_res_distance The distance in high resolution
96
+ */
97
+ void horizontal_scroll(int high_res_distance);
98
+
99
+ protected:
100
+ typedef struct MouseState MouseState;
101
+ std::shared_ptr<MouseState> _state;
102
+
103
+ private:
104
+ Mouse(); // use Mouse::create() instead
105
+ };
106
+
107
+ /**
108
+ * A virtual trackpad
109
+ *
110
+ * implements a pure multi-touch touchpad as defined in libinput
111
+ * https://wayland.freedesktop.org/libinput/doc/latest/touchpads.html
112
+ */
113
+ class Trackpad : public VirtualDevice {
114
+ public:
115
+ static Result<Trackpad>
116
+ create(const DeviceDefinition &device = {
117
+ .name = "Wolf (virtual) touchpad", .vendor_id = 0xAB00, .product_id = 0xAB02, .version = 0xAB00});
118
+ Trackpad(Trackpad &&j) noexcept : _state(nullptr) {
119
+ std::swap(j._state, _state);
120
+ }
121
+ ~Trackpad() override;
122
+ std::vector<std::string> get_nodes() const override;
123
+
124
+ /**
125
+ * We expect (x,y) to be in the range [0.0, 1.0]; x and y values are normalised device coordinates
126
+ * from the top-left corner (0.0, 0.0) to bottom-right corner (1.0, 1.0)
127
+ *
128
+ * @param finger_nr
129
+ * @param pressure A value between 0 and 1
130
+ * @param orientation A value between -90 and 90
131
+ */
132
+ void place_finger(int finger_nr, float x, float y, float pressure, int orientation);
133
+
134
+ void release_finger(int finger_nr);
135
+
136
+ void set_left_btn(bool pressed);
137
+
138
+ protected:
139
+ typedef struct TrackpadState TrackpadState;
140
+ std::shared_ptr<TrackpadState> _state;
141
+
142
+ private:
143
+ Trackpad(); // use Trackpad::create() instead
144
+ };
145
+
146
+ /**
147
+ * A virtual touchscreen
148
+ */
149
+ class TouchScreen : public VirtualDevice {
150
+
151
+ public:
152
+ static Result<TouchScreen>
153
+ create(const DeviceDefinition &device = {
154
+ .name = "Wolf (virtual) touchscreen", .vendor_id = 0xAB00, .product_id = 0xAB03, .version = 0xAB00});
155
+ TouchScreen(TouchScreen &&j) noexcept : _state(nullptr) {
156
+ std::swap(j._state, _state);
157
+ }
158
+ ~TouchScreen() override;
159
+ std::vector<std::string> get_nodes() const override;
160
+
161
+ /**
162
+ * We expect (x,y) to be in the range [0.0, 1.0]; x and y values are normalised device coordinates
163
+ * from the top-left corner (0.0, 0.0) to bottom-right corner (1.0, 1.0)
164
+ *
165
+ * @param finger_nr
166
+ * @param pressure A value between 0 and 1
167
+ */
168
+ void place_finger(int finger_nr, float x, float y, float pressure, int orientation);
169
+
170
+ void release_finger(int finger_nr);
171
+
172
+ protected:
173
+ typedef struct TouchScreenState TouchScreenState;
174
+ std::shared_ptr<TouchScreenState> _state;
175
+
176
+ private:
177
+ TouchScreen();
178
+ };
179
+
180
+ /**
181
+ * A virtual pen tablet
182
+ *
183
+ * implements a pen tablet as defined in libinput
184
+ * https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html
185
+ */
186
+ class PenTablet : public VirtualDevice {
187
+ public:
188
+ static Result<PenTablet>
189
+ create(const DeviceDefinition &device = {
190
+ .name = "Wolf (virtual) pen tablet", .vendor_id = 0xAB00, .product_id = 0xAB04, .version = 0xAB00});
191
+ PenTablet(PenTablet &&j) : _state(nullptr) {
192
+ std::swap(j._state, _state);
193
+ }
194
+ ~PenTablet() override;
195
+ std::vector<std::string> get_nodes() const override;
196
+
197
+ enum TOOL_TYPE {
198
+ PEN,
199
+ ERASER,
200
+ BRUSH,
201
+ PENCIL,
202
+ AIRBRUSH,
203
+ TOUCH,
204
+ SAME_AS_BEFORE /* Real devices don't need to report the tool type when it's still the same */
205
+ };
206
+
207
+ enum BTN_TYPE {
208
+ PRIMARY,
209
+ SECONDARY,
210
+ TERTIARY
211
+ };
212
+
213
+ /**
214
+ * x,y,pressure and distance should be normalized in the range [0.0, 1.0].
215
+ * Passing a negative value will discard that value; this is used to report pressure instead of distance
216
+ * (they should never be both positive).
217
+ *
218
+ * tilt_x and tilt_y are in the range [-90.0, 90.0] degrees.
219
+ *
220
+ * Refer to the libinput docs to better understand what each param means:
221
+ * https://wayland.freedesktop.org/libinput/doc/latest/tablet-support.html#special-axes-on-tablet-tools
222
+ */
223
+ void place_tool(TOOL_TYPE tool_type, float x, float y, float pressure, float distance, float tilt_x, float tilt_y);
224
+
225
+ void set_btn(BTN_TYPE btn, bool pressed);
226
+
227
+ protected:
228
+ typedef struct PenTabletState PenTabletState;
229
+ std::shared_ptr<PenTabletState> _state;
230
+
231
+ private:
232
+ PenTablet();
233
+ };
234
+
235
+ /**
236
+ * A virtual keyboard device
237
+ *
238
+ * Key codes are Win32 Virtual Key (VK) codes
239
+ * Users of this class can expect that if a key is pressed, it'll be re-pressed every
240
+ * time_repress_key until it's released.
241
+ */
242
+ class Keyboard : public VirtualDevice {
243
+ public:
244
+ static Result<Keyboard> create(const DeviceDefinition &device = {.name = "Wolf (virtual) keyboard",
245
+ .vendor_id = 0xAB00,
246
+ .product_id = 0xAB05,
247
+ .version = 0xAB00},
248
+ int millis_repress_key = 50);
249
+ Keyboard(Keyboard &&j) noexcept : _state(nullptr) {
250
+ std::swap(j._state, _state);
251
+ }
252
+ ~Keyboard() override;
253
+ std::vector<std::string> get_nodes() const override;
254
+
255
+ void press(short key_code);
256
+
257
+ void release(short key_code);
258
+
259
+ protected:
260
+ typedef struct KeyboardState KeyboardState;
261
+ std::shared_ptr<KeyboardState> _state;
262
+
263
+ private:
264
+ Keyboard();
265
+ };
266
+
267
+ /**
268
+ * Base class for all joypads, they at the very least have to implement buttons and triggers
269
+ */
270
+ class Joypad : public VirtualDevice {
271
+ public:
272
+ enum CONTROLLER_BTN : unsigned int {
273
+ DPAD_UP = 0x0001,
274
+ DPAD_DOWN = 0x0002,
275
+ DPAD_LEFT = 0x0004,
276
+ DPAD_RIGHT = 0x0008,
277
+
278
+ START = 0x0010,
279
+ BACK = 0x0020,
280
+ HOME = 0x0400,
281
+
282
+ LEFT_STICK = 0x0040,
283
+ RIGHT_STICK = 0x0080,
284
+ LEFT_BUTTON = 0x0100,
285
+ RIGHT_BUTTON = 0x0200,
286
+
287
+ SPECIAL_FLAG = 0x0400,
288
+ PADDLE1_FLAG = 0x010000,
289
+ PADDLE2_FLAG = 0x020000,
290
+ PADDLE3_FLAG = 0x040000,
291
+ PADDLE4_FLAG = 0x080000,
292
+ TOUCHPAD_FLAG = 0x100000, // Touchpad buttons on Sony controllers
293
+ MISC_FLAG = 0x200000, // Share/Mic/Capture/Mute buttons on various controllers
294
+
295
+ A = 0x1000,
296
+ B = 0x2000,
297
+ X = 0x4000,
298
+ Y = 0x8000
299
+ };
300
+
301
+ enum STICK_POSITION {
302
+ RS,
303
+ LS
304
+ };
305
+
306
+ /**
307
+ * Given the nature of joypads we (might) have to simultaneously press and release multiple buttons.
308
+ * In order to implement this, you can pass a single short: button_flags which represent the currently pressed
309
+ * buttons in the joypad.
310
+ * This class will keep an internal state of the joypad and will automatically release buttons that are no
311
+ * longer pressed.
312
+ *
313
+ * Example: previous state had `DPAD_UP` and `A` -> user release `A` -> new state only has `DPAD_UP`
314
+ */
315
+ virtual void set_pressed_buttons(unsigned int newly_pressed) = 0;
316
+
317
+ virtual void set_triggers(int16_t left, int16_t right) = 0;
318
+
319
+ virtual void set_stick(STICK_POSITION stick_type, short x, short y) = 0;
320
+ };
321
+
322
+ class XboxOneJoypad : public Joypad {
323
+ public:
324
+ static Result<XboxOneJoypad>
325
+ create(const DeviceDefinition &device = {
326
+ .name = "Wolf X-Box One (virtual) pad",
327
+ // https://github.com/torvalds/linux/blob/master/drivers/input/joystick/xpad.c#L147
328
+ .vendor_id = 0x045E,
329
+ .product_id = 0x02EA,
330
+ .version = 0x0408});
331
+ XboxOneJoypad(XboxOneJoypad &&j) noexcept : _state(nullptr) {
332
+ std::swap(j._state, _state);
333
+ }
334
+ ~XboxOneJoypad() override;
335
+
336
+ std::vector<std::string> get_nodes() const override;
337
+
338
+ void set_pressed_buttons(unsigned int newly_pressed) override;
339
+ void set_triggers(int16_t left, int16_t right) override;
340
+ void set_stick(STICK_POSITION stick_type, short x, short y) override;
341
+ void set_on_rumble(const std::function<void(int low_freq, int high_freq)> &callback);
342
+
343
+ protected:
344
+ typedef struct XboxOneJoypadState XboxOneJoypadState;
345
+ std::shared_ptr<XboxOneJoypadState> _state;
346
+
347
+ private:
348
+ XboxOneJoypad();
349
+ };
350
+
351
+ class SwitchJoypad : public Joypad {
352
+ public:
353
+ static Result<SwitchJoypad> create(const DeviceDefinition &device = {
354
+ .name = "Wolf Nintendo (virtual) pad",
355
+ // https://github.com/torvalds/linux/blob/master/drivers/hid/hid-ids.h#L981
356
+ .vendor_id = 0x057e,
357
+ .product_id = 0x2009,
358
+ .version = 0x8111});
359
+ SwitchJoypad(SwitchJoypad &&j) : _state(nullptr) {
360
+ std::swap(j._state, _state);
361
+ }
362
+ ~SwitchJoypad() override;
363
+
364
+ std::vector<std::string> get_nodes() const override;
365
+
366
+ void set_pressed_buttons(unsigned int newly_pressed) override;
367
+ void set_triggers(int16_t left, int16_t right) override;
368
+ void set_stick(STICK_POSITION stick_type, short x, short y) override;
369
+ void set_on_rumble(const std::function<void(int low_freq, int high_freq)> &callback);
370
+
371
+ protected:
372
+ typedef struct XboxOneJoypadState SwitchJoypadState;
373
+ std::shared_ptr<SwitchJoypadState> _state;
374
+
375
+ private:
376
+ SwitchJoypad();
377
+ };
378
+
379
+ class PS5Joypad : public Joypad {
380
+ public:
381
+ static Result<PS5Joypad>
382
+ create(const DeviceDefinition &device = {
383
+ .name = "Wolf DualSense (virtual) pad", .vendor_id = 0x054C, .product_id = 0x0CE6, .version = 0x8111});
384
+ PS5Joypad(PS5Joypad &&j) noexcept : _state(nullptr) {
385
+ std::swap(j._state, _state);
386
+ }
387
+ ~PS5Joypad() override;
388
+
389
+ std::vector<std::string> get_nodes() const override;
390
+
391
+ std::string get_mac_address() const;
392
+
393
+ std::vector<std::string> get_sys_nodes() const;
394
+
395
+ void set_pressed_buttons(unsigned int newly_pressed) override;
396
+ void set_triggers(int16_t left, int16_t right) override;
397
+ void set_stick(STICK_POSITION stick_type, short x, short y) override;
398
+ void set_on_rumble(const std::function<void(int low_freq, int high_freq)> &callback);
399
+
400
+ static constexpr int touchpad_width = 1920;
401
+ static constexpr int touchpad_height = 1080;
402
+ void place_finger(int finger_nr, uint16_t x, uint16_t y);
403
+ void release_finger(int finger_nr);
404
+
405
+ enum MOTION_TYPE : uint8_t {
406
+ ACCELERATION = 0x01,
407
+ GYROSCOPE = 0x02
408
+ };
409
+
410
+ /**
411
+ * Acceleration should report data in m/s^2 (inclusive of gravitational acceleration).
412
+ * Gyroscope should report data in deg/s.
413
+ *
414
+ * The x/y/z axis assignments follow SDL's convention documented here:
415
+ * https://github.com/libsdl-org/SDL/blob/96720f335002bef62115e39327940df454d78f6c/include/SDL3/SDL_sensor.h#L80-L124
416
+ */
417
+ void set_motion(MOTION_TYPE type, float x, float y, float z);
418
+
419
+ enum BATTERY_STATE : uint8_t {
420
+ BATTERY_DISCHARGING = 0x0,
421
+ BATTERY_CHARGHING = 0x1,
422
+ BATTERY_FULL = 0x2,
423
+ VOLTAGE_OR_TEMPERATURE_OUT_OF_RANGE = 0xA,
424
+ TEMPERATURE_ERROR = 0xB,
425
+ CHARGHING_ERROR = 0xF
426
+ };
427
+
428
+ void set_battery(BATTERY_STATE state, int percentage);
429
+
430
+ void set_on_led(const std::function<void(int r, int g, int b)> &callback);
431
+
432
+ /**
433
+ * This is an opaque blob that is sent to the controller.
434
+ * There is some reversed engineered information here:
435
+ * https://gist.github.com/Nielk1/6d54cc2c00d2201ccb8c2720ad7538db
436
+ */
437
+ struct TriggerEffect {
438
+ /**
439
+ * 0x04 - Right trigger
440
+ * 0x08 - Left trigger
441
+ */
442
+ uint8_t event_flags;
443
+ uint8_t type_left;
444
+ uint8_t type_right;
445
+ std::array<uint8_t, 10> left = {};
446
+ std::array<uint8_t, 10> right = {};
447
+ };
448
+
449
+ void set_on_trigger_effect(const std::function<void(const TriggerEffect &)> &callback);
450
+
451
+ protected:
452
+ typedef struct PS5JoypadState PS5JoypadState;
453
+ std::shared_ptr<PS5JoypadState> _state;
454
+
455
+ private:
456
+ std::thread _send_input_thread;
457
+
458
+ static std::array<unsigned char, 6> generate_mac_address() {
459
+ auto rand = std::bind(std::uniform_int_distribution<unsigned char>{0, 0xFF},
460
+ std::default_random_engine{std::random_device()()});
461
+ return {rand(), rand(), rand(), rand(), rand(), rand()};
462
+ };
463
+
464
+ PS5Joypad(uint16_t vendor_id, std::array<unsigned char, 6> mac_address = generate_mac_address());
465
+ };
466
+ } // namespace inputtino
@@ -0,0 +1,37 @@
1
+ #pragma once
2
+ #include <string>
3
+ #include <variant>
4
+
5
+ namespace inputtino {
6
+
7
+ struct Error {
8
+ explicit Error(std::string s) : msg(std::move(s)) {}
9
+ std::string msg;
10
+ };
11
+
12
+ template <typename T> class Result {
13
+ public:
14
+ Result(const Error &errorString) : contents(errorString) {}
15
+
16
+ Result(T &&value) : contents(std::move(value)) {}
17
+
18
+ explicit operator bool() const {
19
+ return contents.index() == 0;
20
+ }
21
+
22
+ const T &operator*() const {
23
+ return std::get<T>(contents);
24
+ }
25
+
26
+ T &operator*() {
27
+ return std::get<T>(contents);
28
+ }
29
+
30
+ std::string getErrorMessage() {
31
+ return std::get<Error>(contents).msg;
32
+ }
33
+
34
+ private:
35
+ std::variant<T, Error> contents;
36
+ };
37
+ } // namespace inputtino
@@ -0,0 +1,17 @@
1
+ prefix=@CMAKE_INSTALL_PREFIX@
2
+ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/@PROJECT_NAME@
3
+
4
+ prefix=@CMAKE_INSTALL_PREFIX@
5
+ exec_prefix=@CMAKE_INSTALL_PREFIX@
6
+ libdir=@INSTALL_LIB_DIR@
7
+ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/@PROJECT_NAME@
8
+
9
+ Name: libinputtino
10
+ Description: @PROJECT_DESCRIPTION@
11
+ URL: @PROJECT_HOMEPAGE_URL@
12
+ Version: @PROJECT_VERSION@
13
+
14
+ Requires:
15
+ Libs: -L${libdir} -llibevdev
16
+ Cflags: -I${includedir}
17
+
@@ -0,0 +1,19 @@
1
+ #pragma once
2
+
3
+ #include <cstring>
4
+ #include <inputtino/input.hpp>
5
+
6
+ static char **c_get_nodes(void *device, int *num_nodes) {
7
+ char **nodes = nullptr;
8
+ *num_nodes = 0;
9
+ if (device) {
10
+ auto devices = reinterpret_cast<inputtino::VirtualDevice *>(device)->get_nodes();
11
+ *num_nodes = devices.size();
12
+ nodes = new char *[devices.size()];
13
+ for (int index = 0; index < devices.size(); index++) {
14
+ nodes[index] = new char[devices[index].size() + 1];
15
+ strcpy(nodes[index], devices[index].c_str());
16
+ }
17
+ }
18
+ return nodes;
19
+ }
@@ -0,0 +1,115 @@
1
+ #include "helpers.hpp"
2
+ #include <inputtino/input.h>
3
+
4
+ InputtinoPS5Joypad *inputtino_joypad_ps5_create(const InputtinoDeviceDefinition *device,
5
+ const InputtinoErrorHandler *eh) {
6
+ auto joypad_ = inputtino::PS5Joypad::create({
7
+ .name = device->name ? device->name : "Inputtino virtual device",
8
+ .vendor_id = device->vendor_id,
9
+ .product_id = device->product_id,
10
+ .version = device->version,
11
+ .device_phys = device->device_phys ? device->device_phys : "00:11:22:33:44:55",
12
+ .device_uniq = device->device_uniq ? device->device_uniq : "00:11:22:33:44:55",
13
+ });
14
+ if (joypad_) {
15
+ return reinterpret_cast<InputtinoPS5Joypad *>(new inputtino::PS5Joypad(std::move(*joypad_)));
16
+ } else {
17
+ eh->eh(joypad_.getErrorMessage().c_str(), eh->user_data);
18
+ return nullptr;
19
+ }
20
+ }
21
+
22
+ char **inputtino_joypad_ps5_get_nodes(InputtinoPS5Joypad *joypad, int *num_nodes) {
23
+ return c_get_nodes(joypad, num_nodes);
24
+ }
25
+
26
+ void inputtino_joypad_ps5_set_pressed_buttons(InputtinoPS5Joypad *joypad, int newly_pressed) {
27
+ if (joypad) {
28
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_pressed_buttons(newly_pressed);
29
+ }
30
+ }
31
+
32
+ void inputtino_joypad_ps5_set_triggers(InputtinoPS5Joypad *joypad, short left_trigger, short right_trigger) {
33
+ if (joypad) {
34
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_triggers(left_trigger, right_trigger);
35
+ }
36
+ }
37
+
38
+ void inputtino_joypad_ps5_set_stick(InputtinoPS5Joypad *joypad,
39
+ enum INPUTTINO_JOYPAD_STICK_POSITION stick_type,
40
+ short x,
41
+ short y) {
42
+ if (joypad) {
43
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_stick(inputtino::Joypad::STICK_POSITION(stick_type), x, y);
44
+ }
45
+ }
46
+
47
+ void inputtino_joypad_ps5_set_on_rumble(InputtinoPS5Joypad *joypad,
48
+ InputtinoJoypadRumbleFn rumble_fn,
49
+ void *user_data) {
50
+ if (joypad) {
51
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_on_rumble(
52
+ [user_data, rumble_fn](short left, short right) { rumble_fn(left, right, user_data); });
53
+ }
54
+ }
55
+
56
+ void inputtino_joypad_ps5_place_finger(InputtinoPS5Joypad *joypad, int finger_nr, unsigned short x, unsigned short y) {
57
+ if (joypad) {
58
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->place_finger(finger_nr, x, y);
59
+ }
60
+ }
61
+
62
+ void inputtino_joypad_ps5_release_finger(InputtinoPS5Joypad *joypad, int finger_nr) {
63
+ if (joypad) {
64
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->release_finger(finger_nr);
65
+ }
66
+ }
67
+
68
+ void inputtino_joypad_ps5_set_motion(
69
+ InputtinoPS5Joypad *joypad, enum INPUTTINO_JOYPAD_MOTION_TYPE motion_type, float x, float y, float z) {
70
+ if (joypad) {
71
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_motion(inputtino::PS5Joypad::MOTION_TYPE(motion_type),
72
+ x,
73
+ y,
74
+ z);
75
+ }
76
+ }
77
+
78
+ void inputtino_joypad_ps5_set_battery(InputtinoPS5Joypad *joypad,
79
+ enum BATTERY_STATE battery_state,
80
+ unsigned short level) {
81
+ if (joypad) {
82
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_battery(inputtino::PS5Joypad::BATTERY_STATE(battery_state),
83
+ level);
84
+ }
85
+ }
86
+
87
+ void inputtino_joypad_ps5_set_on_led(InputtinoPS5Joypad *joypad, InputtinoJoypadLEDFn led_fn, void *user_data) {
88
+ if (joypad) {
89
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_on_led(
90
+ [user_data, led_fn](unsigned char r, unsigned char g, unsigned char b) { led_fn(r, g, b, user_data); });
91
+ }
92
+ }
93
+
94
+ void inputtino_joypad_ps5_set_on_trigger_effect(InputtinoPS5Joypad *joypad,
95
+ InputtinoJoypadTriggerFn trigger_effect_fn,
96
+ void *user_data) {
97
+ if (joypad) {
98
+ reinterpret_cast<inputtino::PS5Joypad *>(joypad)->set_on_trigger_effect(
99
+ [user_data, trigger_effect_fn](const inputtino::PS5Joypad::TriggerEffect &effect) {
100
+ trigger_effect_fn(effect.event_flags,
101
+ effect.type_left,
102
+ effect.type_right,
103
+ effect.left.data(),
104
+ effect.right.data(),
105
+ user_data);
106
+ });
107
+ }
108
+ }
109
+
110
+ void inputtino_joypad_ps5_destroy(InputtinoPS5Joypad *joypad) {
111
+ if (joypad) {
112
+ auto joypad_ptr = reinterpret_cast<inputtino::PS5Joypad *>(joypad);
113
+ delete joypad_ptr;
114
+ }
115
+ }