@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.
- package/LICENSE +202 -0
- package/NOTICE +44 -0
- package/README.md +266 -0
- package/bin/desklink-host.mjs +113 -0
- package/dist/bridge.d.ts +57 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +208 -0
- package/dist/bridge.js.map +1 -0
- package/dist/engineProcess.d.ts +82 -0
- package/dist/engineProcess.d.ts.map +1 -0
- package/dist/engineProcess.js +243 -0
- package/dist/engineProcess.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +169 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +18 -0
- package/dist/protocol.js.map +1 -0
- package/dist/resolveEngine.d.ts +34 -0
- package/dist/resolveEngine.d.ts.map +1 -0
- package/dist/resolveEngine.js +103 -0
- package/dist/resolveEngine.js.map +1 -0
- package/docs/BOUNDARY.md +145 -0
- package/docs/PROTOCOL.md +363 -0
- package/engine/Cargo.lock +3077 -0
- package/engine/Cargo.toml +37 -0
- package/engine/build.rs +107 -0
- package/engine/native/inputtino_shim.cpp +11 -0
- package/engine/native/vpx_shim.c +184 -0
- package/engine/native/wrapper.h +7 -0
- package/engine/src/capture.rs +510 -0
- package/engine/src/clipboard.rs +132 -0
- package/engine/src/convert.rs +299 -0
- package/engine/src/encoder.rs +204 -0
- package/engine/src/input.rs +355 -0
- package/engine/src/keymap.rs +338 -0
- package/engine/src/main.rs +614 -0
- package/engine/src/peer.rs +775 -0
- package/engine/src/portal.rs +115 -0
- package/engine/src/protocol.rs +331 -0
- package/engine/src/session.rs +2159 -0
- package/engine/src/x11.rs +244 -0
- package/engine/vendor/inputtino/.clang-format +166 -0
- package/engine/vendor/inputtino/.clang-tidy +30 -0
- package/engine/vendor/inputtino/.dockerignore +11 -0
- package/engine/vendor/inputtino/.github/workflows/mirror-repo.yml +14 -0
- package/engine/vendor/inputtino/.github/workflows/python-lint-format-test-typecheck.yml +124 -0
- package/engine/vendor/inputtino/.github/workflows/python-test-install.yaml +49 -0
- package/engine/vendor/inputtino/.github/workflows/rust.yml +40 -0
- package/engine/vendor/inputtino/CMakeLists.txt +187 -0
- package/engine/vendor/inputtino/LICENSE +21 -0
- package/engine/vendor/inputtino/README.md +110 -0
- package/engine/vendor/inputtino/bindings/python/.devcontainer/Dockerfile +23 -0
- package/engine/vendor/inputtino/bindings/python/.devcontainer/devcontainer.json +28 -0
- package/engine/vendor/inputtino/bindings/python/.python-version +1 -0
- package/engine/vendor/inputtino/bindings/python/CMakeLists.txt +23 -0
- package/engine/vendor/inputtino/bindings/python/CPPLINT.cfg +2 -0
- package/engine/vendor/inputtino/bindings/python/Makefile +49 -0
- package/engine/vendor/inputtino/bindings/python/README.md +215 -0
- package/engine/vendor/inputtino/bindings/python/pyproject.toml +178 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/__init__.py +43 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/_core.pyi +533 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/base.py +63 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/joypad.py +248 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/keyboard.py +256 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/mouse.py +106 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/pentablet.py +73 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/py.typed +0 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/touchscreen.py +61 -0
- package/engine/vendor/inputtino/bindings/python/src/inputtino/trackpad.py +74 -0
- package/engine/vendor/inputtino/bindings/python/src/main.cpp +217 -0
- package/engine/vendor/inputtino/bindings/python/tests/__init__.py +0 -0
- package/engine/vendor/inputtino/bindings/python/tests/helpers.py +3 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_base.py +60 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_inputtino.py +5 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_joypad.py +332 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_keyboard.py +164 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_mouse.py +185 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_pentablet.py +198 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_touchscreen.py +144 -0
- package/engine/vendor/inputtino/bindings/python/tests/test_trackpad.py +146 -0
- package/engine/vendor/inputtino/bindings/python/uv.lock +390 -0
- package/engine/vendor/inputtino/bindings/rust/Cargo.toml +6 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/.dockerignore +1 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/Cargo.toml +18 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/examples/keyboard.rs +33 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/examples/mouse.rs +17 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/common.rs +116 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/error.rs +17 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad.rs +74 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_nintendo.rs +135 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_ps5.rs +280 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/joypad_xbox.rs +134 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/keyboard.rs +76 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/lib.rs +32 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/src/mouse.rs +178 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/common.rs +38 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/joypads.rs +150 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/keyboard.rs +73 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino/tests/mouse.rs +139 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/.dockerignore +1 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/Cargo.toml +12 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/build.rs +48 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/src/lib.rs +5 -0
- package/engine/vendor/inputtino/bindings/rust/inputtino-sys/wrapper.h +1 -0
- package/engine/vendor/inputtino/cmake/utils.cmake +9 -0
- package/engine/vendor/inputtino/docker/Dockerfile +70 -0
- package/engine/vendor/inputtino/include/inputtino/input.h +324 -0
- package/engine/vendor/inputtino/include/inputtino/input.hpp +466 -0
- package/engine/vendor/inputtino/include/inputtino/result.hpp +37 -0
- package/engine/vendor/inputtino/share/pkgconfig/libinputtino.pc.in +17 -0
- package/engine/vendor/inputtino/src/c-bindings/helpers.hpp +19 -0
- package/engine/vendor/inputtino/src/c-bindings/joypad_ps5.cpp +115 -0
- package/engine/vendor/inputtino/src/c-bindings/joypad_switch.cpp +63 -0
- package/engine/vendor/inputtino/src/c-bindings/joypad_xone.cpp +62 -0
- package/engine/vendor/inputtino/src/c-bindings/keyboard.cpp +42 -0
- package/engine/vendor/inputtino/src/c-bindings/mouse.cpp +67 -0
- package/engine/vendor/inputtino/src/c-bindings/pen_tablet.cpp +50 -0
- package/engine/vendor/inputtino/src/c-bindings/touchscreen.cpp +43 -0
- package/engine/vendor/inputtino/src/c-bindings/trackpad.cpp +49 -0
- package/engine/vendor/inputtino/src/uhid/README.adoc +63 -0
- package/engine/vendor/inputtino/src/uhid/include/crc32.hpp +38 -0
- package/engine/vendor/inputtino/src/uhid/include/uhid/protected_types.hpp +36 -0
- package/engine/vendor/inputtino/src/uhid/include/uhid/ps5.hpp +550 -0
- package/engine/vendor/inputtino/src/uhid/include/uhid/uhid.hpp +168 -0
- package/engine/vendor/inputtino/src/uhid/joypad_ps5.cpp +580 -0
- package/engine/vendor/inputtino/src/uinput/include/inputtino/keyboard.hpp +84 -0
- package/engine/vendor/inputtino/src/uinput/include/inputtino/protected_ps5_types.hpp +7 -0
- package/engine/vendor/inputtino/src/uinput/include/inputtino/protected_types.hpp +110 -0
- package/engine/vendor/inputtino/src/uinput/joypad_nintendo.cpp +190 -0
- package/engine/vendor/inputtino/src/uinput/joypad_ps.cpp +203 -0
- package/engine/vendor/inputtino/src/uinput/joypad_utils.hpp +246 -0
- package/engine/vendor/inputtino/src/uinput/joypad_xbox.cpp +190 -0
- package/engine/vendor/inputtino/src/uinput/keyboard.cpp +120 -0
- package/engine/vendor/inputtino/src/uinput/mouse.cpp +199 -0
- package/engine/vendor/inputtino/src/uinput/pentablet.cpp +162 -0
- package/engine/vendor/inputtino/src/uinput/touchscreen.cpp +140 -0
- package/engine/vendor/inputtino/src/uinput/trackpad.cpp +192 -0
- package/examples/reference-client.html +428 -0
- package/package.json +38 -0
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
#include <algorithm>
|
|
2
|
+
#include <climits>
|
|
3
|
+
#include <cmath>
|
|
4
|
+
#include <crc32.hpp>
|
|
5
|
+
#include <endian.h>
|
|
6
|
+
#include <filesystem>
|
|
7
|
+
#include <fstream>
|
|
8
|
+
#include <inputtino/input.hpp>
|
|
9
|
+
#include <iomanip>
|
|
10
|
+
#include <random>
|
|
11
|
+
#include <uhid/protected_types.hpp>
|
|
12
|
+
#include <uhid/ps5.hpp>
|
|
13
|
+
#include <uhid/uhid.hpp>
|
|
14
|
+
|
|
15
|
+
namespace inputtino {
|
|
16
|
+
|
|
17
|
+
static uint32_t sign_crc32(uint32_t seed, const unsigned char *buffer, size_t length) {
|
|
18
|
+
auto crc = CRC32(buffer, length, seed);
|
|
19
|
+
crc = htole32(crc); // Convert to little endian
|
|
20
|
+
return crc;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static void send_report(PS5JoypadState &state) {
|
|
24
|
+
{ // setup timestamp and increase seq_number
|
|
25
|
+
state.current_state.seq_number++;
|
|
26
|
+
if (state.current_state.seq_number >= 255) {
|
|
27
|
+
state.current_state.seq_number = 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Seems that the timestamp is little endian and 0.33us units
|
|
31
|
+
// see:
|
|
32
|
+
// https://github.com/torvalds/linux/blob/305230142ae0637213bf6e04f6d9f10bbcb74af8/drivers/hid/hid-playstation.c#L1409-L1410
|
|
33
|
+
auto now = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now().time_since_epoch())
|
|
34
|
+
.count();
|
|
35
|
+
state.current_state.sensor_timestamp = htole32(now / 333);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
struct uhid_event ev{};
|
|
39
|
+
{
|
|
40
|
+
ev.type = UHID_INPUT2;
|
|
41
|
+
|
|
42
|
+
std::size_t header_size;
|
|
43
|
+
if (state.is_bluetooth) {
|
|
44
|
+
auto header = uhid::dualsense_input_report_bt_header{};
|
|
45
|
+
header_size = sizeof(header);
|
|
46
|
+
std::copy(reinterpret_cast<unsigned char *>(&header),
|
|
47
|
+
reinterpret_cast<unsigned char *>(&header) + header_size,
|
|
48
|
+
&ev.u.input2.data[0]);
|
|
49
|
+
} else {
|
|
50
|
+
auto header = uhid::dualsense_input_report_usb_header{};
|
|
51
|
+
header_size = sizeof(header);
|
|
52
|
+
std::copy(reinterpret_cast<unsigned char *>(&header),
|
|
53
|
+
reinterpret_cast<unsigned char *>(&header) + header_size,
|
|
54
|
+
&ev.u.input2.data[0]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
unsigned char *data = (unsigned char *)&state.current_state;
|
|
58
|
+
std::copy(data, data + sizeof(state.current_state), &ev.u.input2.data[header_size]);
|
|
59
|
+
|
|
60
|
+
ev.u.input2.size = header_size + sizeof(state.current_state);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (state.is_bluetooth) { // CRC32 encode the data and append it to the reply
|
|
64
|
+
ev.u.input2.size += uhid::PS_INPUT_REPORT_BT_OFFSET;
|
|
65
|
+
|
|
66
|
+
auto end_of_msg = ev.u.input2.size - 4; // (Last 4 bytes contains crc32)
|
|
67
|
+
auto crc = sign_crc32(uhid::PS_INPUT_CRC32, &ev.u.input2.data[0], end_of_msg);
|
|
68
|
+
std::copy(reinterpret_cast<unsigned char *>(&crc),
|
|
69
|
+
reinterpret_cast<unsigned char *>(&crc) + 4,
|
|
70
|
+
&ev.u.input2.data[end_of_msg]);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
state.dev->send(ev);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static void on_uhid_event(std::shared_ptr<PS5JoypadState> state, uhid_event ev, int fd) {
|
|
77
|
+
switch (ev.type) {
|
|
78
|
+
case UHID_GET_REPORT: {
|
|
79
|
+
uhid_event answer{};
|
|
80
|
+
answer.type = UHID_GET_REPORT_REPLY;
|
|
81
|
+
answer.u.get_report_reply.id = ev.u.get_report.id;
|
|
82
|
+
answer.u.get_report_reply.err = 0;
|
|
83
|
+
switch (ev.u.get_report.rnum) {
|
|
84
|
+
case uhid::PS5_REPORT_TYPES::CALIBRATION: {
|
|
85
|
+
std::copy(&uhid::ps5_calibration_info[0],
|
|
86
|
+
&uhid::ps5_calibration_info[0] + sizeof(uhid::ps5_calibration_info),
|
|
87
|
+
&answer.u.get_report_reply.data[0]);
|
|
88
|
+
answer.u.get_report_reply.size = sizeof(uhid::ps5_calibration_info);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case uhid::PS5_REPORT_TYPES::PAIRING_INFO: {
|
|
92
|
+
std::copy(&uhid::ps5_pairing_info[0],
|
|
93
|
+
&uhid::ps5_pairing_info[0] + sizeof(uhid::ps5_pairing_info),
|
|
94
|
+
&answer.u.get_report_reply.data[0]);
|
|
95
|
+
|
|
96
|
+
// Copy MAC address data
|
|
97
|
+
std::reverse_copy(&state->mac_address[0],
|
|
98
|
+
&state->mac_address[0] + sizeof(state->mac_address),
|
|
99
|
+
&answer.u.get_report_reply.data[1]);
|
|
100
|
+
|
|
101
|
+
answer.u.get_report_reply.size = sizeof(uhid::ps5_pairing_info);
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case uhid::PS5_REPORT_TYPES::FIRMWARE_INFO: {
|
|
105
|
+
std::copy(&uhid::ps5_firmware_info[0],
|
|
106
|
+
&uhid::ps5_firmware_info[0] + sizeof(uhid::ps5_firmware_info),
|
|
107
|
+
&answer.u.get_report_reply.data[0]);
|
|
108
|
+
answer.u.get_report_reply.size = sizeof(uhid::ps5_firmware_info);
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
default:
|
|
112
|
+
answer.u.get_report_reply.err = -EINVAL;
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (state->is_bluetooth) {
|
|
117
|
+
// CRC32 encode the data and append it to the reply
|
|
118
|
+
auto end_of_msg = answer.u.get_report_reply.size - 4; // (Last 4 bytes contains crc32)
|
|
119
|
+
auto crc = sign_crc32(uhid::PS_FEATURE_CRC32, &answer.u.get_report_reply.data[0], end_of_msg);
|
|
120
|
+
std::copy(reinterpret_cast<unsigned char *>(&crc),
|
|
121
|
+
reinterpret_cast<unsigned char *>(&crc) + 4,
|
|
122
|
+
&answer.u.get_report_reply.data[end_of_msg]);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
auto res = uhid::uhid_write(fd, &answer);
|
|
126
|
+
// TODO: signal error somehow
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
case UHID_OUTPUT: { // This is sent if the HID device driver wants to send raw data to the device
|
|
130
|
+
// Here is where we'll get Rumble and LED events
|
|
131
|
+
// Check the first byte to see if it's a USB or BT report
|
|
132
|
+
uint8_t report_type = ev.u.output.data[0];
|
|
133
|
+
uhid::dualsense_output_report_common report;
|
|
134
|
+
if (report_type == uhid::DS_OUTPUT_REPORT_USB) {
|
|
135
|
+
auto report_usb = (uhid::dualsense_output_report_usb *)ev.u.output.data;
|
|
136
|
+
report = report_usb->common;
|
|
137
|
+
} else {
|
|
138
|
+
uhid::dualsense_output_report_bt *report_bt = (uhid::dualsense_output_report_bt *)ev.u.output.data;
|
|
139
|
+
/*
|
|
140
|
+
* SDL2 sets the EnableHID flag and will send the output report straight after
|
|
141
|
+
* https://github.com/libsdl-org/SDL/blob/c8c4c9772758de2ae466d27f13eb3ed4233e3f32/src/joystick/hidapi/SDL_hidapi_ps5.c#L788-L789
|
|
142
|
+
*
|
|
143
|
+
* The Linux kernel instead, sets this as 0, properly set the SeqNo and adds a hardcoded `tag` field before the
|
|
144
|
+
* actual output report
|
|
145
|
+
* https://github.com/torvalds/linux/blob/305230142ae0637213bf6e04f6d9f10bbcb74af8/drivers/hid/hid-playstation.c#L1184-L1192
|
|
146
|
+
*/
|
|
147
|
+
if (report_bt->EnableHID == 0) {
|
|
148
|
+
report_bt = (uhid::dualsense_output_report_bt *)&ev.u.output.data[1]; // Skip the tag field
|
|
149
|
+
}
|
|
150
|
+
report = report_bt->common;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
* RUMBLE
|
|
155
|
+
* The PS5 joypad seems to report values in the range 0-255,
|
|
156
|
+
* we'll turn those into 0-0xFFFF
|
|
157
|
+
*/
|
|
158
|
+
if (report.valid_flag0 & uhid::MOTOR_OR_COMPATIBLE_VIBRATION || report.valid_flag2 & uhid::COMPATIBLE_VIBRATION) {
|
|
159
|
+
auto left = (report.motor_left / 255.0f) * 0xFFFF;
|
|
160
|
+
auto right = (report.motor_right / 255.0f) * 0xFFFF;
|
|
161
|
+
if (state->on_rumble) {
|
|
162
|
+
(*state->on_rumble)(left, right);
|
|
163
|
+
}
|
|
164
|
+
} else if (report.valid_flag0 == 0 && report.valid_flag1 == 0 && report.valid_flag2 == 0) {
|
|
165
|
+
// Seems to be a special stop rumble event, let's propagate it
|
|
166
|
+
if (state->on_rumble) {
|
|
167
|
+
(*state->on_rumble)(0, 0);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Trigger effects
|
|
173
|
+
*/
|
|
174
|
+
bool right_trigger = report.valid_flag0 & uhid::RIGHT_TRIGGER_EFFECT;
|
|
175
|
+
bool left_trigger = report.valid_flag0 & uhid::LEFT_TRIGGER_EFFECT;
|
|
176
|
+
if ((right_trigger || left_trigger) && state->on_trigger_effect) {
|
|
177
|
+
auto left_array_start = std::begin(report.left_trigger_effect);
|
|
178
|
+
auto left_array_end = std::end(report.left_trigger_effect);
|
|
179
|
+
auto right_array_start = std::begin(report.right_trigger_effect);
|
|
180
|
+
auto right_array_end = std::end(report.right_trigger_effect);
|
|
181
|
+
// We have to cache these values because these flags will be set as long as the effect is active
|
|
182
|
+
uint32_t left_trigger_hash = std::accumulate(left_array_start, left_array_end, 0ul);
|
|
183
|
+
uint32_t right_trigger_hash = std::accumulate(right_array_start, right_array_end, 0ul);
|
|
184
|
+
if ((left_trigger && state->last_left_trigger_event != left_trigger_hash) ||
|
|
185
|
+
(right_trigger && state->last_right_trigger_event != right_trigger_hash)) {
|
|
186
|
+
// First, update the cache
|
|
187
|
+
if (left_trigger)
|
|
188
|
+
state->last_left_trigger_event = left_trigger_hash;
|
|
189
|
+
if (right_trigger)
|
|
190
|
+
state->last_right_trigger_event = right_trigger_hash;
|
|
191
|
+
|
|
192
|
+
// Then, trigger the event
|
|
193
|
+
uint8_t event_flags = (report.valid_flag0 & uhid::LEFT_TRIGGER_EFFECT) |
|
|
194
|
+
(report.valid_flag0 & uhid::RIGHT_TRIGGER_EFFECT);
|
|
195
|
+
PS5Joypad::TriggerEffect effect = {.event_flags = event_flags,
|
|
196
|
+
.type_left = report.left_trigger_effect_type,
|
|
197
|
+
.type_right = report.right_trigger_effect_type};
|
|
198
|
+
std::copy(left_array_start, left_array_end, std::begin(effect.left));
|
|
199
|
+
std::copy(right_array_start, right_array_end, std::begin(effect.right));
|
|
200
|
+
(*state->on_trigger_effect)(effect);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/*
|
|
205
|
+
* LED
|
|
206
|
+
*/
|
|
207
|
+
if (report.valid_flag1 & uhid::LIGHTBAR_ENABLE) {
|
|
208
|
+
if (state->on_led) {
|
|
209
|
+
// TODO: should we blend brightness?
|
|
210
|
+
(*state->on_led)(report.lightbar_red, report.lightbar_green, report.lightbar_blue);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
default:
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
PS5Joypad::PS5Joypad(uint16_t vendor_id, std::array<unsigned char, 6> mac_address)
|
|
220
|
+
: _state(std::make_shared<PS5JoypadState>()) {
|
|
221
|
+
std::copy(mac_address.begin(), mac_address.end(), this->_state->mac_address);
|
|
222
|
+
this->_state->vendor_id = vendor_id;
|
|
223
|
+
// Set touchpad as not pressed
|
|
224
|
+
this->_state->current_state.points[0].contact = 1;
|
|
225
|
+
this->_state->current_state.points[1].contact = 1;
|
|
226
|
+
// Set the battery to 100% (so that if the client doesn't report it we don't trigger annoying low battery warnings)
|
|
227
|
+
this->_state->current_state.battery_charge = 10;
|
|
228
|
+
this->_state->current_state.battery_status = BATTERY_FULL;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
PS5Joypad::~PS5Joypad() {
|
|
232
|
+
if (this->_state && this->_state->dev) {
|
|
233
|
+
this->_state->stop_repeat_thread = true;
|
|
234
|
+
if (this->_send_input_thread.joinable()) {
|
|
235
|
+
this->_send_input_thread.join();
|
|
236
|
+
}
|
|
237
|
+
this->_state->dev->stop_thread();
|
|
238
|
+
this->_state->dev.reset(); // Will trigger ~Device and ultimately destroy the device
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
Result<PS5Joypad> PS5Joypad::create(const DeviceDefinition &device) {
|
|
243
|
+
bool use_bluetooth = true; // TODO: expose this
|
|
244
|
+
|
|
245
|
+
auto def = uhid::DeviceDefinition{
|
|
246
|
+
.name = device.name,
|
|
247
|
+
.phys = device.device_phys,
|
|
248
|
+
.uniq = device.device_uniq,
|
|
249
|
+
.bus = BUS_BLUETOOTH,
|
|
250
|
+
.vendor = static_cast<uint32_t>(device.vendor_id),
|
|
251
|
+
.product = static_cast<uint32_t>(device.product_id),
|
|
252
|
+
.version = static_cast<uint32_t>(device.version),
|
|
253
|
+
.country = 0,
|
|
254
|
+
.report_description = {&uhid::ps5_rdesc_bt[0], &uhid::ps5_rdesc_bt[0] + sizeof(uhid::ps5_rdesc_bt)}};
|
|
255
|
+
|
|
256
|
+
if (!use_bluetooth) {
|
|
257
|
+
def.bus = BUS_USB;
|
|
258
|
+
def.report_description = {&uhid::ps5_rdesc[0], &uhid::ps5_rdesc[0] + sizeof(uhid::ps5_rdesc)};
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
std::array<unsigned char, 6> mac_address = {};
|
|
262
|
+
if (def.uniq.empty()) {
|
|
263
|
+
mac_address = generate_mac_address();
|
|
264
|
+
} else {
|
|
265
|
+
// Assuming we have in input a MAC address in the format of xx:xx:xx:xx:xx:xx
|
|
266
|
+
std::stringstream ss(def.uniq);
|
|
267
|
+
for (int i = 0; i < 6; ++i) {
|
|
268
|
+
unsigned int value;
|
|
269
|
+
ss >> std::hex >> value;
|
|
270
|
+
mac_address[i] = static_cast<unsigned char>(value);
|
|
271
|
+
if (i < 5)
|
|
272
|
+
ss.ignore(1, ':');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
auto joypad = PS5Joypad(device.vendor_id, mac_address);
|
|
276
|
+
|
|
277
|
+
if (def.phys.empty()) {
|
|
278
|
+
def.phys = "INPUTTINO_BT_LINK";
|
|
279
|
+
}
|
|
280
|
+
if (def.uniq.empty()) {
|
|
281
|
+
def.uniq = joypad.get_mac_address();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
auto dev =
|
|
285
|
+
uhid::Device::create(def, [state = joypad._state](uhid_event ev, int fd) { on_uhid_event(state, ev, fd); });
|
|
286
|
+
if (dev) {
|
|
287
|
+
joypad._state->is_bluetooth = use_bluetooth;
|
|
288
|
+
joypad._state->dev = std::make_shared<uhid::Device>(std::move(*dev));
|
|
289
|
+
|
|
290
|
+
// Readers will expect frequent events event if the state hasn't changed
|
|
291
|
+
joypad._send_input_thread = std::thread([state = joypad._state]() {
|
|
292
|
+
while (!state->stop_repeat_thread) {
|
|
293
|
+
send_report(*state);
|
|
294
|
+
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
joypad._send_input_thread.detach();
|
|
298
|
+
|
|
299
|
+
return joypad;
|
|
300
|
+
}
|
|
301
|
+
return Error(dev.getErrorMessage());
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
static int scale_value(int input, int input_start, int input_end, int output_start, int output_end) {
|
|
305
|
+
auto slope = 1.0 * (output_end - output_start) / (input_end - input_start);
|
|
306
|
+
return output_start + std::round(slope * (input - input_start));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
template <typename T> std::string to_hex(T i) {
|
|
310
|
+
std::stringstream stream;
|
|
311
|
+
stream << std::hex << std::uppercase << i;
|
|
312
|
+
return stream.str();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
std::string PS5Joypad::get_mac_address() const {
|
|
316
|
+
std::stringstream stream;
|
|
317
|
+
stream << std::hex << std::setfill('0') << std::setw(2) << (unsigned int)_state->mac_address[0] << ":" << std::setw(2)
|
|
318
|
+
<< (unsigned int)_state->mac_address[1] << ":" << std::setw(2) << (unsigned int)_state->mac_address[2] << ":"
|
|
319
|
+
<< std::setw(2) << (unsigned int)_state->mac_address[3] << ":" << std::setw(2)
|
|
320
|
+
<< (unsigned int)_state->mac_address[4] << ":" << std::setw(2) << (unsigned int)_state->mac_address[5];
|
|
321
|
+
return stream.str();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* The trick here is to match the devices under /sys/devices/virtual/misc/uhid/
|
|
326
|
+
* with the MAC address that we've set for the current device
|
|
327
|
+
*
|
|
328
|
+
* @returns a list of paths to the created input devices ex:
|
|
329
|
+
* /sys/devices/virtual/misc/uhid/0003:054C:0CE6.000D/input/input58/
|
|
330
|
+
*/
|
|
331
|
+
std::vector<std::string> PS5Joypad::get_sys_nodes() const {
|
|
332
|
+
std::vector<std::string> nodes;
|
|
333
|
+
auto base_path = "/sys/devices/virtual/misc/uhid/";
|
|
334
|
+
auto target_mac = get_mac_address();
|
|
335
|
+
if (std::filesystem::exists(base_path)) {
|
|
336
|
+
auto uhid_entries = std::filesystem::directory_iterator{base_path};
|
|
337
|
+
for (auto uhid_entry : uhid_entries) {
|
|
338
|
+
// Here we are looking for a directory that has a name like {BUS_ID}:{VENDOR_ID}:{PRODUCT_ID}.xxxx
|
|
339
|
+
// (ex: 0003:054C:0CE6.000D)
|
|
340
|
+
auto uhid_candidate_path = uhid_entry.path().filename().string();
|
|
341
|
+
auto target_id = to_hex(this->_state->vendor_id);
|
|
342
|
+
if (uhid_entry.is_directory() && uhid_candidate_path.find(target_id) != std::string::npos) {
|
|
343
|
+
// Found a match! Let's scan the input devices in that directory
|
|
344
|
+
if (std::filesystem::exists(uhid_entry.path() / "input")) {
|
|
345
|
+
// ex: /sys/devices/virtual/misc/uhid/0003:054C:0CE6.000D/input/
|
|
346
|
+
auto dev_entries = std::filesystem::directory_iterator{uhid_entry.path() / "input"};
|
|
347
|
+
for (auto dev_entry : dev_entries) {
|
|
348
|
+
// Here we only have a match if the "uniq" file inside contains the same MAC address that we've set
|
|
349
|
+
if (dev_entry.is_directory()) {
|
|
350
|
+
// ex: /sys/devices/virtual/misc/uhid/0003:054C:0CE6.000D/input/input58/uniq
|
|
351
|
+
auto dev_uniq_path = dev_entry.path() / "uniq";
|
|
352
|
+
if (std::filesystem::exists(dev_uniq_path)) {
|
|
353
|
+
std::ifstream dev_uniq_file{dev_uniq_path};
|
|
354
|
+
std::string line;
|
|
355
|
+
std::getline(dev_uniq_file, line);
|
|
356
|
+
if (line == target_mac) {
|
|
357
|
+
nodes.push_back(dev_entry.path().string());
|
|
358
|
+
}
|
|
359
|
+
} else {
|
|
360
|
+
fprintf(stderr, "Unable to get joypad nodes, path %s does not exist\n", dev_uniq_path.string().c_str());
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
} else {
|
|
365
|
+
fprintf(stderr, "Unable to get joypad nodes, path %s does not exist\n", uhid_entry.path().string().c_str());
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
} else {
|
|
370
|
+
fprintf(stderr, "Unable to get joypad nodes, path %s does not exist\n", base_path);
|
|
371
|
+
}
|
|
372
|
+
return nodes;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
std::vector<std::string> PS5Joypad::get_nodes() const {
|
|
376
|
+
std::vector<std::string> nodes;
|
|
377
|
+
|
|
378
|
+
auto sys_nodes = get_sys_nodes();
|
|
379
|
+
for (const auto dev_entry : sys_nodes) {
|
|
380
|
+
auto dev_nodes = std::filesystem::directory_iterator{dev_entry};
|
|
381
|
+
for (auto dev_node : dev_nodes) {
|
|
382
|
+
if (dev_node.is_directory() && (dev_node.path().filename().string().rfind("event", 0) == 0 ||
|
|
383
|
+
dev_node.path().filename().string().rfind("js", 0) == 0)) {
|
|
384
|
+
nodes.push_back(("/dev/input/" / dev_node.path().filename()).string());
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
return nodes;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
void PS5Joypad::set_pressed_buttons(unsigned int pressed) {
|
|
393
|
+
{ // First reset everything to non-pressed
|
|
394
|
+
this->_state->current_state.buttons[0] = 0;
|
|
395
|
+
// Don't reset L2 and R2, these are handled in set_triggers
|
|
396
|
+
this->_state->current_state.buttons[1] &= (uhid::L2 | uhid::R2);
|
|
397
|
+
this->_state->current_state.buttons[2] = 0;
|
|
398
|
+
this->_state->current_state.buttons[3] = 0;
|
|
399
|
+
}
|
|
400
|
+
{
|
|
401
|
+
if (DPAD_UP & pressed) { // Pressed UP
|
|
402
|
+
if (DPAD_LEFT & pressed) { // NW
|
|
403
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_NW;
|
|
404
|
+
} else if (DPAD_RIGHT & pressed) { // NE
|
|
405
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_NE;
|
|
406
|
+
} else { // N
|
|
407
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_N;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (DPAD_DOWN & pressed) { // Pressed DOWN
|
|
412
|
+
if (DPAD_LEFT & pressed) { // SW
|
|
413
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_SW;
|
|
414
|
+
} else if (DPAD_RIGHT & pressed) { // SE
|
|
415
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_SE;
|
|
416
|
+
} else { // S
|
|
417
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_S;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
if (DPAD_LEFT & pressed) { // Pressed LEFT
|
|
422
|
+
if (!(DPAD_UP & pressed) && !(DPAD_DOWN & pressed)) { // Pressed only LEFT
|
|
423
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_W;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
if (DPAD_RIGHT & pressed) { // Pressed RIGHT
|
|
428
|
+
if (!(DPAD_UP & pressed) && !(DPAD_DOWN & pressed)) { // Pressed only RIGHT
|
|
429
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_E;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (!(DPAD_UP & pressed) && !(DPAD_DOWN & pressed) && !(DPAD_LEFT & pressed) && !(DPAD_RIGHT & pressed)) {
|
|
434
|
+
this->_state->current_state.buttons[0] |= uhid::HAT_NEUTRAL;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// TODO: L2/R2 ??
|
|
438
|
+
|
|
439
|
+
if (X & pressed)
|
|
440
|
+
this->_state->current_state.buttons[0] |= uhid::SQUARE;
|
|
441
|
+
if (Y & pressed)
|
|
442
|
+
this->_state->current_state.buttons[0] |= uhid::TRIANGLE;
|
|
443
|
+
if (A & pressed)
|
|
444
|
+
this->_state->current_state.buttons[0] |= uhid::CROSS;
|
|
445
|
+
if (B & pressed)
|
|
446
|
+
this->_state->current_state.buttons[0] |= uhid::CIRCLE;
|
|
447
|
+
if (LEFT_BUTTON & pressed)
|
|
448
|
+
this->_state->current_state.buttons[1] |= uhid::L1;
|
|
449
|
+
if (RIGHT_BUTTON & pressed)
|
|
450
|
+
this->_state->current_state.buttons[1] |= uhid::R1;
|
|
451
|
+
if (LEFT_STICK & pressed)
|
|
452
|
+
this->_state->current_state.buttons[1] |= uhid::L3;
|
|
453
|
+
if (RIGHT_STICK & pressed)
|
|
454
|
+
this->_state->current_state.buttons[1] |= uhid::R3;
|
|
455
|
+
if (START & pressed)
|
|
456
|
+
this->_state->current_state.buttons[1] |= uhid::OPTIONS;
|
|
457
|
+
if (BACK & pressed)
|
|
458
|
+
this->_state->current_state.buttons[1] |= uhid::CREATE;
|
|
459
|
+
if (TOUCHPAD_FLAG & pressed)
|
|
460
|
+
this->_state->current_state.buttons[2] |= uhid::TOUCHPAD;
|
|
461
|
+
if (HOME & pressed)
|
|
462
|
+
this->_state->current_state.buttons[2] |= uhid::PS_HOME;
|
|
463
|
+
if (MISC_FLAG & pressed)
|
|
464
|
+
this->_state->current_state.buttons[2] |= uhid::MIC_MUTE;
|
|
465
|
+
}
|
|
466
|
+
send_report(*this->_state);
|
|
467
|
+
}
|
|
468
|
+
void PS5Joypad::set_triggers(int16_t left, int16_t right) {
|
|
469
|
+
this->_state->current_state.z = scale_value(left, 0, 255, uhid::PS5_AXIS_MIN, uhid::PS5_AXIS_MAX);
|
|
470
|
+
this->_state->current_state.rz = scale_value(right, 0, 255, uhid::PS5_AXIS_MIN, uhid::PS5_AXIS_MAX);
|
|
471
|
+
|
|
472
|
+
if (left == 0)
|
|
473
|
+
this->_state->current_state.buttons[1] &= ~uhid::L2;
|
|
474
|
+
else
|
|
475
|
+
this->_state->current_state.buttons[1] |= uhid::L2;
|
|
476
|
+
|
|
477
|
+
if (right == 0)
|
|
478
|
+
this->_state->current_state.buttons[1] &= ~uhid::R2;
|
|
479
|
+
else
|
|
480
|
+
this->_state->current_state.buttons[1] |= uhid::R2;
|
|
481
|
+
|
|
482
|
+
send_report(*this->_state);
|
|
483
|
+
}
|
|
484
|
+
void PS5Joypad::set_stick(Joypad::STICK_POSITION stick_type, short x, short y) {
|
|
485
|
+
switch (stick_type) {
|
|
486
|
+
case RS: {
|
|
487
|
+
this->_state->current_state.rx = scale_value(x, -32768, 32767, uhid::PS5_AXIS_MIN, uhid::PS5_AXIS_MAX);
|
|
488
|
+
this->_state->current_state.ry = scale_value(-y, -32768, 32767, uhid::PS5_AXIS_MIN, uhid::PS5_AXIS_MAX);
|
|
489
|
+
send_report(*this->_state);
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
case LS: {
|
|
493
|
+
this->_state->current_state.x = scale_value(x, -32768, 32767, uhid::PS5_AXIS_MIN, uhid::PS5_AXIS_MAX);
|
|
494
|
+
this->_state->current_state.y = scale_value(-y, -32768, 32767, uhid::PS5_AXIS_MIN, uhid::PS5_AXIS_MAX);
|
|
495
|
+
send_report(*this->_state);
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
void PS5Joypad::set_on_rumble(const std::function<void(int, int)> &callback) {
|
|
501
|
+
this->_state->on_rumble = callback;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* For a rationale behind this, see: https://github.com/LizardByte/Sunshine/issues/3247#issuecomment-2428065349
|
|
506
|
+
*/
|
|
507
|
+
static __le16 to_le_signed(float original, float value) {
|
|
508
|
+
value = std::clamp(value, static_cast<float>(SHRT_MIN), static_cast<float>(SHRT_MAX));
|
|
509
|
+
return htole16(value);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
void PS5Joypad::set_motion(PS5Joypad::MOTION_TYPE type, float x, float y, float z) {
|
|
513
|
+
switch (type) {
|
|
514
|
+
case ACCELERATION: {
|
|
515
|
+
this->_state->current_state.accel[0] = to_le_signed(x, (x * uhid::SDL_STANDARD_GRAVITY_CONST * 100));
|
|
516
|
+
this->_state->current_state.accel[1] = to_le_signed(y, (y * uhid::SDL_STANDARD_GRAVITY_CONST * 100));
|
|
517
|
+
this->_state->current_state.accel[2] = to_le_signed(z, (z * uhid::SDL_STANDARD_GRAVITY_CONST * 100));
|
|
518
|
+
|
|
519
|
+
send_report(*this->_state);
|
|
520
|
+
break;
|
|
521
|
+
}
|
|
522
|
+
case GYROSCOPE: {
|
|
523
|
+
this->_state->current_state.gyro[0] = to_le_signed(x, x * uhid::gyro_resolution);
|
|
524
|
+
this->_state->current_state.gyro[1] = to_le_signed(y, y * uhid::gyro_resolution);
|
|
525
|
+
this->_state->current_state.gyro[2] = to_le_signed(z, z * uhid::gyro_resolution);
|
|
526
|
+
|
|
527
|
+
send_report(*this->_state);
|
|
528
|
+
break;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
void PS5Joypad::set_battery(PS5Joypad::BATTERY_STATE state, int percentage) {
|
|
534
|
+
/*
|
|
535
|
+
* Each unit of battery data corresponds to 10%
|
|
536
|
+
* 0 = 0-9%, 1 = 10-19%, .. and 10 = 100%
|
|
537
|
+
*/
|
|
538
|
+
this->_state->current_state.battery_charge = std::lround((percentage / 10));
|
|
539
|
+
this->_state->current_state.battery_status = state;
|
|
540
|
+
send_report(*this->_state);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
void PS5Joypad::set_on_led(const std::function<void(int, int, int)> &callback) {
|
|
544
|
+
this->_state->on_led = callback;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
void PS5Joypad::set_on_trigger_effect(const std::function<void(const TriggerEffect &)> &callback) {
|
|
548
|
+
this->_state->on_trigger_effect = callback;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
void PS5Joypad::place_finger(int finger_nr, uint16_t x, uint16_t y) {
|
|
552
|
+
if (finger_nr <= 1) {
|
|
553
|
+
// If this finger was previously unpressed, we should increase the touch id
|
|
554
|
+
if (this->_state->current_state.points[finger_nr].contact == 1) {
|
|
555
|
+
this->_state->current_state.points[finger_nr].id = ++this->_state->last_touch_id;
|
|
556
|
+
}
|
|
557
|
+
this->_state->current_state.points[finger_nr].contact = 0;
|
|
558
|
+
|
|
559
|
+
this->_state->current_state.points[finger_nr].x_lo = static_cast<uint8_t>(x & 0x00FF);
|
|
560
|
+
this->_state->current_state.points[finger_nr].x_hi = static_cast<uint8_t>((x & 0x0F00) >> 8);
|
|
561
|
+
|
|
562
|
+
this->_state->current_state.points[finger_nr].y_lo = static_cast<uint8_t>(y & 0x000F);
|
|
563
|
+
this->_state->current_state.points[finger_nr].y_hi = static_cast<uint8_t>((y & 0x0FF0) >> 4);
|
|
564
|
+
|
|
565
|
+
send_report(*this->_state);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
void PS5Joypad::release_finger(int finger_nr) {
|
|
570
|
+
if (finger_nr <= 1) {
|
|
571
|
+
// if it goes above 0x7F we should reset it to 0
|
|
572
|
+
if (this->_state->last_touch_id >= 0x7E) {
|
|
573
|
+
this->_state->last_touch_id = 0;
|
|
574
|
+
}
|
|
575
|
+
this->_state->current_state.points[finger_nr].contact = 1;
|
|
576
|
+
send_report(*this->_state);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
} // namespace inputtino
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#include <linux/input-event-codes.h>
|
|
2
|
+
#include <map>
|
|
3
|
+
|
|
4
|
+
namespace inputtino::keyboard {
|
|
5
|
+
|
|
6
|
+
struct KEY_MAP {
|
|
7
|
+
int linux_code;
|
|
8
|
+
int scan_code;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
constexpr auto UNKNOWN = 0;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A map of [Moonlight keyboard code] -> {linux_code, scan_code}
|
|
15
|
+
*/
|
|
16
|
+
static const std::map<short, KEY_MAP> key_mappings = {
|
|
17
|
+
{0x08, {KEY_BACKSPACE, 0x7002A}}, {0x09, {KEY_TAB, 0x7002B}},
|
|
18
|
+
{0x0C, {KEY_CLEAR, UNKNOWN}}, {0x0D, {KEY_ENTER, 0x70028}},
|
|
19
|
+
{0x10, {KEY_LEFTSHIFT, 0x700E1}}, {0x11, {KEY_LEFTCTRL, 0x700E0}},
|
|
20
|
+
{0x12, {KEY_LEFTALT, UNKNOWN}}, {0x13, {KEY_PAUSE, UNKNOWN}},
|
|
21
|
+
{0x14, {KEY_CAPSLOCK, 0x70039}}, {0x15, {KEY_KATAKANAHIRAGANA, UNKNOWN}},
|
|
22
|
+
{0x16, {KEY_HANGEUL, UNKNOWN}}, {0x17, {KEY_HANJA, UNKNOWN}},
|
|
23
|
+
{0x19, {KEY_KATAKANA, UNKNOWN}}, {0x1B, {KEY_ESC, 0x70029}},
|
|
24
|
+
{0x20, {KEY_SPACE, 0x7002C}}, {0x21, {KEY_PAGEUP, 0x7004B}},
|
|
25
|
+
{0x22, {KEY_PAGEDOWN, 0x7004E}}, {0x23, {KEY_END, 0x7004D}},
|
|
26
|
+
{0x24, {KEY_HOME, 0x7004A}}, {0x25, {KEY_LEFT, 0x70050}},
|
|
27
|
+
{0x26, {KEY_UP, 0x70052}}, {0x27, {KEY_RIGHT, 0x7004F}},
|
|
28
|
+
{0x28, {KEY_DOWN, 0x70051}}, {0x29, {KEY_SELECT, UNKNOWN}},
|
|
29
|
+
{0x2A, {KEY_PRINT, UNKNOWN}}, {0x2C, {KEY_SYSRQ, 0x70046}},
|
|
30
|
+
{0x2D, {KEY_INSERT, 0x70049}}, {0x2E, {KEY_DELETE, 0x7004C}},
|
|
31
|
+
{0x2F, {KEY_HELP, UNKNOWN}}, {0x30, {KEY_0, 0x70027}},
|
|
32
|
+
{0x31, {KEY_1, 0x7001E}}, {0x32, {KEY_2, 0x7001F}},
|
|
33
|
+
{0x33, {KEY_3, 0x70020}}, {0x34, {KEY_4, 0x70021}},
|
|
34
|
+
{0x35, {KEY_5, 0x70022}}, {0x36, {KEY_6, 0x70023}},
|
|
35
|
+
{0x37, {KEY_7, 0x70024}}, {0x38, {KEY_8, 0x70025}},
|
|
36
|
+
{0x39, {KEY_9, 0x70026}}, {0x41, {KEY_A, 0x70004}},
|
|
37
|
+
{0x42, {KEY_B, 0x70005}}, {0x43, {KEY_C, 0x70006}},
|
|
38
|
+
{0x44, {KEY_D, 0x70007}}, {0x45, {KEY_E, 0x70008}},
|
|
39
|
+
{0x46, {KEY_F, 0x70009}}, {0x47, {KEY_G, 0x7000A}},
|
|
40
|
+
{0x48, {KEY_H, 0x7000B}}, {0x49, {KEY_I, 0x7000C}},
|
|
41
|
+
{0x4A, {KEY_J, 0x7000D}}, {0x4B, {KEY_K, 0x7000E}},
|
|
42
|
+
{0x4C, {KEY_L, 0x7000F}}, {0x4D, {KEY_M, 0x70010}},
|
|
43
|
+
{0x4E, {KEY_N, 0x70011}}, {0x4F, {KEY_O, 0x70012}},
|
|
44
|
+
{0x50, {KEY_P, 0x70013}}, {0x51, {KEY_Q, 0x70014}},
|
|
45
|
+
{0x52, {KEY_R, 0x70015}}, {0x53, {KEY_S, 0x70016}},
|
|
46
|
+
{0x54, {KEY_T, 0x70017}}, {0x55, {KEY_U, 0x70018}},
|
|
47
|
+
{0x56, {KEY_V, 0x70019}}, {0x57, {KEY_W, 0x7001A}},
|
|
48
|
+
{0x58, {KEY_X, 0x7001B}}, {0x59, {KEY_Y, 0x7001C}},
|
|
49
|
+
{0x5A, {KEY_Z, 0x7001D}}, {0x5B, {KEY_LEFTMETA, 0x700E3}},
|
|
50
|
+
{0x5C, {KEY_RIGHTMETA, 0x700E7}}, {0x5D, {KEY_COMPOSE, UNKNOWN}},
|
|
51
|
+
{0x5F, {KEY_SLEEP, UNKNOWN}},
|
|
52
|
+
{0x60, {KEY_KP0, 0x70062}}, {0x61, {KEY_KP1, 0x70059}},
|
|
53
|
+
{0x62, {KEY_KP2, 0x7005A}}, {0x63, {KEY_KP3, 0x7005B}},
|
|
54
|
+
{0x64, {KEY_KP4, 0x7005C}}, {0x65, {KEY_KP5, 0x7005D}},
|
|
55
|
+
{0x66, {KEY_KP6, 0x7005E}}, {0x67, {KEY_KP7, 0x7005F}},
|
|
56
|
+
{0x68, {KEY_KP8, 0x70060}}, {0x69, {KEY_KP9, 0x70061}},
|
|
57
|
+
{0x6A, {KEY_KPASTERISK, 0x70055}}, {0x6B, {KEY_KPPLUS, 0x70057}},
|
|
58
|
+
{0x6C, {KEY_KPCOMMA, UNKNOWN}}, {0x6D, {KEY_KPMINUS, 0x70056}},
|
|
59
|
+
{0x6E, {KEY_KPDOT, 0x70063}}, {0x6F, {KEY_KPSLASH, 0x70054}},
|
|
60
|
+
{0x70, {KEY_F1, 0x70059}}, {0x71, {KEY_F2, 0x70060}},
|
|
61
|
+
{0x72, {KEY_F3, 0x70061}}, {0x73, {KEY_F4, 0x70062}},
|
|
62
|
+
{0x74, {KEY_F5, 0x70063}}, {0x75, {KEY_F6, 0x70064}},
|
|
63
|
+
{0x76, {KEY_F7, 0x70065}}, {0x77, {KEY_F8, 0x70066}},
|
|
64
|
+
{0x78, {KEY_F9, 0x70067}}, {0x79, {KEY_F10, 0x70068}},
|
|
65
|
+
{0x7A, {KEY_F11, 70044}}, {0x7B, {KEY_F12, 70045}},
|
|
66
|
+
{0x7C, {KEY_F13, 0x70068}}, {0x7D, {KEY_F14, 0x70069}},
|
|
67
|
+
{0x7E, {KEY_F15, 0x7006a}}, {0x7F, {KEY_F16, 0x7006b}},
|
|
68
|
+
{0x80, {KEY_F17, 0x7006c}}, {0x81, {KEY_F18, 0x7006d}},
|
|
69
|
+
{0x82, {KEY_F19, 0x7006e}}, {0x83, {KEY_F20, 0x7006f}},
|
|
70
|
+
{0x84, {KEY_F21, 0x70070}}, {0x85, {KEY_F22, 0x70071}},
|
|
71
|
+
{0x86, {KEY_F23, 0x70072}}, {0x87, {KEY_F24, 0x70073}},
|
|
72
|
+
{0x90, {KEY_NUMLOCK, 0x70053}}, {0x91, {KEY_SCROLLLOCK, 0x70047}},
|
|
73
|
+
{0xA0, {KEY_LEFTSHIFT, 0x700E1}}, {0xA1, {KEY_RIGHTSHIFT, 0x700E5}},
|
|
74
|
+
{0xA2, {KEY_LEFTCTRL, 0x700E0}}, {0xA3, {KEY_RIGHTCTRL, 0x700E4}},
|
|
75
|
+
{0xA4, {KEY_LEFTALT, 0x7002E}}, {0xA5, {KEY_RIGHTALT, 0x700E6}},
|
|
76
|
+
{0xBA, {KEY_SEMICOLON, 0x70033}}, {0xBB, {KEY_EQUAL, 0x7002E}},
|
|
77
|
+
{0xBC, {KEY_COMMA, 0x70036}}, {0xBD, {KEY_MINUS, 0x7002D}},
|
|
78
|
+
{0xBE, {KEY_DOT, 0x70037}}, {0xBF, {KEY_SLASH, 0x70038}},
|
|
79
|
+
{0xC0, {KEY_GRAVE, 0x70035}}, {0xDB, {KEY_LEFTBRACE, 0x7002F}},
|
|
80
|
+
{0xDC, {KEY_BACKSLASH, 0x70031}}, {0xDD, {KEY_RIGHTBRACE, 0x70030}},
|
|
81
|
+
{0xDE, {KEY_APOSTROPHE, 0x70034}}, {0xE2, {KEY_102ND, 0x70064}},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
} // namespace wolf::core::input::keyboard
|