summaryrefslogtreecommitdiff
path: root/src/core/hid/input_converter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hid/input_converter.cpp')
-rw-r--r--src/core/hid/input_converter.cpp436
1 files changed, 0 insertions, 436 deletions
diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp
deleted file mode 100644
index a05716fd8..000000000
--- a/src/core/hid/input_converter.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
1// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include <algorithm>
5#include <random>
6
7#include "common/input.h"
8#include "core/hid/input_converter.h"
9
10namespace Core::HID {
11
12Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback) {
13 Common::Input::BatteryStatus battery{Common::Input::BatteryStatus::None};
14 switch (callback.type) {
15 case Common::Input::InputType::Analog:
16 case Common::Input::InputType::Trigger: {
17 const auto value = TransformToTrigger(callback).analog.value;
18 battery = Common::Input::BatteryLevel::Empty;
19 if (value > 0.2f) {
20 battery = Common::Input::BatteryLevel::Critical;
21 }
22 if (value > 0.4f) {
23 battery = Common::Input::BatteryLevel::Low;
24 }
25 if (value > 0.6f) {
26 battery = Common::Input::BatteryLevel::Medium;
27 }
28 if (value > 0.8f) {
29 battery = Common::Input::BatteryLevel::Full;
30 }
31 if (value >= 0.95f) {
32 battery = Common::Input::BatteryLevel::Charging;
33 }
34 break;
35 }
36 case Common::Input::InputType::Button:
37 battery = callback.button_status.value ? Common::Input::BatteryLevel::Charging
38 : Common::Input::BatteryLevel::Critical;
39 break;
40 case Common::Input::InputType::Battery:
41 battery = callback.battery_status;
42 break;
43 default:
44 LOG_ERROR(Input, "Conversion from type {} to battery not implemented", callback.type);
45 break;
46 }
47
48 return battery;
49}
50
51Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback) {
52 Common::Input::ButtonStatus status{};
53 switch (callback.type) {
54 case Common::Input::InputType::Analog:
55 status.value = TransformToTrigger(callback).pressed.value;
56 status.toggle = callback.analog_status.properties.toggle;
57 status.inverted = callback.analog_status.properties.inverted_button;
58 break;
59 case Common::Input::InputType::Trigger:
60 status.value = TransformToTrigger(callback).pressed.value;
61 break;
62 case Common::Input::InputType::Button:
63 status = callback.button_status;
64 break;
65 case Common::Input::InputType::Motion:
66 status.value = std::abs(callback.motion_status.gyro.x.raw_value) > 1.0f;
67 break;
68 default:
69 LOG_ERROR(Input, "Conversion from type {} to button not implemented", callback.type);
70 break;
71 }
72
73 if (status.inverted) {
74 status.value = !status.value;
75 }
76
77 return status;
78}
79
80Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback) {
81 Common::Input::MotionStatus status{};
82 switch (callback.type) {
83 case Common::Input::InputType::Button: {
84 Common::Input::AnalogProperties properties{
85 .deadzone = 0.0f,
86 .range = 1.0f,
87 .offset = 0.0f,
88 };
89 status.delta_timestamp = 1000;
90 status.force_update = true;
91 status.accel.x = {
92 .value = 0.0f,
93 .raw_value = 0.0f,
94 .properties = properties,
95 };
96 status.accel.y = {
97 .value = 0.0f,
98 .raw_value = 0.0f,
99 .properties = properties,
100 };
101 status.accel.z = {
102 .value = 0.0f,
103 .raw_value = -1.0f,
104 .properties = properties,
105 };
106 status.gyro.x = {
107 .value = 0.0f,
108 .raw_value = 0.0f,
109 .properties = properties,
110 };
111 status.gyro.y = {
112 .value = 0.0f,
113 .raw_value = 0.0f,
114 .properties = properties,
115 };
116 status.gyro.z = {
117 .value = 0.0f,
118 .raw_value = 0.0f,
119 .properties = properties,
120 };
121 if (TransformToButton(callback).value) {
122 std::random_device device;
123 std::mt19937 gen(device());
124 std::uniform_int_distribution<s16> distribution(-5000, 5000);
125 status.accel.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
126 status.accel.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
127 status.accel.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
128 status.gyro.x.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
129 status.gyro.y.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
130 status.gyro.z.raw_value = static_cast<f32>(distribution(gen)) * 0.001f;
131 }
132 break;
133 }
134 case Common::Input::InputType::Motion:
135 status = callback.motion_status;
136 break;
137 default:
138 LOG_ERROR(Input, "Conversion from type {} to motion not implemented", callback.type);
139 break;
140 }
141 SanitizeAnalog(status.accel.x, false);
142 SanitizeAnalog(status.accel.y, false);
143 SanitizeAnalog(status.accel.z, false);
144 SanitizeAnalog(status.gyro.x, false);
145 SanitizeAnalog(status.gyro.y, false);
146 SanitizeAnalog(status.gyro.z, false);
147
148 return status;
149}
150
151Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback) {
152 Common::Input::StickStatus status{};
153
154 switch (callback.type) {
155 case Common::Input::InputType::Stick:
156 status = callback.stick_status;
157 break;
158 default:
159 LOG_ERROR(Input, "Conversion from type {} to stick not implemented", callback.type);
160 break;
161 }
162
163 SanitizeStick(status.x, status.y, true);
164 const auto& properties_x = status.x.properties;
165 const auto& properties_y = status.y.properties;
166 const float x = status.x.value;
167 const float y = status.y.value;
168
169 // Set directional buttons
170 status.right = x > properties_x.threshold;
171 status.left = x < -properties_x.threshold;
172 status.up = y > properties_y.threshold;
173 status.down = y < -properties_y.threshold;
174
175 return status;
176}
177
178Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback) {
179 Common::Input::TouchStatus status{};
180
181 switch (callback.type) {
182 case Common::Input::InputType::Touch:
183 status = callback.touch_status;
184 break;
185 case Common::Input::InputType::Stick:
186 status.x = callback.stick_status.x;
187 status.y = callback.stick_status.y;
188 break;
189 default:
190 LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type);
191 break;
192 }
193
194 SanitizeAnalog(status.x, true);
195 SanitizeAnalog(status.y, true);
196 float& x = status.x.value;
197 float& y = status.y.value;
198
199 // Adjust if value is inverted
200 x = status.x.properties.inverted ? 1.0f + x : x;
201 y = status.y.properties.inverted ? 1.0f + y : y;
202
203 // clamp value
204 x = std::clamp(x, 0.0f, 1.0f);
205 y = std::clamp(y, 0.0f, 1.0f);
206
207 if (status.pressed.inverted) {
208 status.pressed.value = !status.pressed.value;
209 }
210
211 return status;
212}
213
214Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback) {
215 Common::Input::TriggerStatus status{};
216 float& raw_value = status.analog.raw_value;
217 bool calculate_button_value = true;
218
219 switch (callback.type) {
220 case Common::Input::InputType::Analog:
221 status.analog.properties = callback.analog_status.properties;
222 raw_value = callback.analog_status.raw_value;
223 break;
224 case Common::Input::InputType::Button:
225 status.analog.properties.range = 1.0f;
226 status.analog.properties.inverted = callback.button_status.inverted;
227 raw_value = callback.button_status.value ? 1.0f : 0.0f;
228 break;
229 case Common::Input::InputType::Trigger:
230 status = callback.trigger_status;
231 calculate_button_value = false;
232 break;
233 case Common::Input::InputType::Motion:
234 status.analog.properties.range = 1.0f;
235 raw_value = callback.motion_status.accel.x.raw_value;
236 break;
237 default:
238 LOG_ERROR(Input, "Conversion from type {} to trigger not implemented", callback.type);
239 break;
240 }
241
242 SanitizeAnalog(status.analog, true);
243 const auto& properties = status.analog.properties;
244 float& value = status.analog.value;
245
246 // Set button status
247 if (calculate_button_value) {
248 status.pressed.value = value > properties.threshold;
249 }
250
251 // Adjust if value is inverted
252 value = properties.inverted ? 1.0f + value : value;
253
254 // clamp value
255 value = std::clamp(value, 0.0f, 1.0f);
256
257 return status;
258}
259
260Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback) {
261 Common::Input::AnalogStatus status{};
262
263 switch (callback.type) {
264 case Common::Input::InputType::Analog:
265 status.properties = callback.analog_status.properties;
266 status.raw_value = callback.analog_status.raw_value;
267 break;
268 default:
269 LOG_ERROR(Input, "Conversion from type {} to analog not implemented", callback.type);
270 break;
271 }
272
273 SanitizeAnalog(status, false);
274
275 // Adjust if value is inverted
276 status.value = status.properties.inverted ? -status.value : status.value;
277
278 return status;
279}
280
281Common::Input::CameraStatus TransformToCamera(const Common::Input::CallbackStatus& callback) {
282 Common::Input::CameraStatus camera{};
283 switch (callback.type) {
284 case Common::Input::InputType::IrSensor:
285 camera = {
286 .format = callback.camera_status,
287 .data = callback.raw_data,
288 };
289 break;
290 default:
291 LOG_ERROR(Input, "Conversion from type {} to camera not implemented", callback.type);
292 break;
293 }
294
295 return camera;
296}
297
298Common::Input::NfcStatus TransformToNfc(const Common::Input::CallbackStatus& callback) {
299 Common::Input::NfcStatus nfc{};
300 switch (callback.type) {
301 case Common::Input::InputType::Nfc:
302 return callback.nfc_status;
303 default:
304 LOG_ERROR(Input, "Conversion from type {} to NFC not implemented", callback.type);
305 break;
306 }
307
308 return nfc;
309}
310
311Common::Input::BodyColorStatus TransformToColor(const Common::Input::CallbackStatus& callback) {
312 switch (callback.type) {
313 case Common::Input::InputType::Color:
314 return callback.color_status;
315 break;
316 default:
317 LOG_ERROR(Input, "Conversion from type {} to color not implemented", callback.type);
318 return {};
319 break;
320 }
321}
322
323void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
324 const auto& properties = analog.properties;
325 float& raw_value = analog.raw_value;
326 float& value = analog.value;
327
328 if (!std::isnormal(raw_value)) {
329 raw_value = 0;
330 }
331
332 // Apply center offset
333 raw_value -= properties.offset;
334
335 // Set initial values to be formatted
336 value = raw_value;
337
338 // Calculate vector size
339 const float r = std::abs(value);
340
341 // Return zero if value is smaller than the deadzone
342 if (r <= properties.deadzone || properties.deadzone == 1.0f) {
343 analog.value = 0;
344 return;
345 }
346
347 // Adjust range of value
348 const float deadzone_factor =
349 1.0f / r * (r - properties.deadzone) / (1.0f - properties.deadzone);
350 value = value * deadzone_factor / properties.range;
351
352 // Invert direction if needed
353 if (properties.inverted) {
354 value = -value;
355 }
356
357 // Clamp value
358 if (clamp_value) {
359 value = std::clamp(value, -1.0f, 1.0f);
360 }
361}
362
363void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y,
364 bool clamp_value) {
365 const auto& properties_x = analog_x.properties;
366 const auto& properties_y = analog_y.properties;
367 float& raw_x = analog_x.raw_value;
368 float& raw_y = analog_y.raw_value;
369 float& x = analog_x.value;
370 float& y = analog_y.value;
371
372 if (!std::isnormal(raw_x)) {
373 raw_x = 0;
374 }
375 if (!std::isnormal(raw_y)) {
376 raw_y = 0;
377 }
378
379 // Apply center offset
380 raw_x += properties_x.offset;
381 raw_y += properties_y.offset;
382
383 // Apply X scale correction from offset
384 if (std::abs(properties_x.offset) < 0.75f) {
385 if (raw_x > 0) {
386 raw_x /= 1 + properties_x.offset;
387 } else {
388 raw_x /= 1 - properties_x.offset;
389 }
390 }
391
392 // Apply Y scale correction from offset
393 if (std::abs(properties_y.offset) < 0.75f) {
394 if (raw_y > 0) {
395 raw_y /= 1 + properties_y.offset;
396 } else {
397 raw_y /= 1 - properties_y.offset;
398 }
399 }
400
401 // Invert direction if needed
402 raw_x = properties_x.inverted ? -raw_x : raw_x;
403 raw_y = properties_y.inverted ? -raw_y : raw_y;
404
405 // Set initial values to be formatted
406 x = raw_x;
407 y = raw_y;
408
409 // Calculate vector size
410 float r = x * x + y * y;
411 r = std::sqrt(r);
412
413 // TODO(German77): Use deadzone and range of both axis
414
415 // Return zero if values are smaller than the deadzone
416 if (r <= properties_x.deadzone || properties_x.deadzone >= 1.0f) {
417 x = 0;
418 y = 0;
419 return;
420 }
421
422 // Adjust range of joystick
423 const float deadzone_factor =
424 1.0f / r * (r - properties_x.deadzone) / (1.0f - properties_x.deadzone);
425 x = x * deadzone_factor / properties_x.range;
426 y = y * deadzone_factor / properties_x.range;
427 r = r * deadzone_factor / properties_x.range;
428
429 // Normalize joystick
430 if (clamp_value && r > 1.0f) {
431 x /= r;
432 y /= r;
433 }
434}
435
436} // namespace Core::HID