summaryrefslogtreecommitdiff
path: root/src/common/input.h
diff options
context:
space:
mode:
authorGravatar Feng Chen2021-12-18 13:57:14 +0800
committerGravatar GitHub2021-12-18 13:57:14 +0800
commite49184e6069a9d791d2df3c1958f5c4b1187e124 (patch)
treeb776caf722e0be0e680f67b0ad0842628162ef1c /src/common/input.h
parentImplement convert legacy to generic (diff)
parentMerge pull request #7570 from ameerj/favorites-expanded (diff)
downloadyuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.tar.gz
yuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.tar.xz
yuzu-e49184e6069a9d791d2df3c1958f5c4b1187e124.zip
Merge branch 'yuzu-emu:master' into convert_legacy
Diffstat (limited to 'src/common/input.h')
-rw-r--r--src/common/input.h366
1 files changed, 366 insertions, 0 deletions
diff --git a/src/common/input.h b/src/common/input.h
new file mode 100644
index 000000000..f775a4c01
--- /dev/null
+++ b/src/common/input.h
@@ -0,0 +1,366 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <functional>
8#include <memory>
9#include <string>
10#include <unordered_map>
11#include <utility>
12#include "common/logging/log.h"
13#include "common/param_package.h"
14#include "common/uuid.h"
15
16namespace Common::Input {
17
18// Type of data that is expected to recieve or send
19enum class InputType {
20 None,
21 Battery,
22 Button,
23 Stick,
24 Analog,
25 Trigger,
26 Motion,
27 Touch,
28 Color,
29 Vibration,
30 Nfc,
31 Ir,
32};
33
34// Internal battery charge level
35enum class BatteryLevel : u32 {
36 None,
37 Empty,
38 Critical,
39 Low,
40 Medium,
41 Full,
42 Charging,
43};
44
45enum class PollingMode {
46 // Constant polling of buttons, analogs and motion data
47 Active,
48 // Only update on button change, digital analogs
49 Pasive,
50 // Enable near field communication polling
51 NFC,
52 // Enable infrared camera polling
53 IR,
54};
55
56// Vibration reply from the controller
57enum class VibrationError {
58 None,
59 NotSupported,
60 Disabled,
61 Unknown,
62};
63
64// Polling mode reply from the controller
65enum class PollingError {
66 None,
67 NotSupported,
68 Unknown,
69};
70
71// Hint for amplification curve to be used
72enum class VibrationAmplificationType {
73 Linear,
74 Exponential,
75};
76
77// Analog properties for calibration
78struct AnalogProperties {
79 // Anything below this value will be detected as zero
80 float deadzone{};
81 // Anyting above this values will be detected as one
82 float range{1.0f};
83 // Minimum value to be detected as active
84 float threshold{0.5f};
85 // Drift correction applied to the raw data
86 float offset{};
87 // Invert direction of the sensor data
88 bool inverted{};
89};
90
91// Single analog sensor data
92struct AnalogStatus {
93 float value{};
94 float raw_value{};
95 AnalogProperties properties{};
96};
97
98// Button data
99struct ButtonStatus {
100 Common::UUID uuid{};
101 bool value{};
102 bool inverted{};
103 bool toggle{};
104 bool locked{};
105};
106
107// Internal battery data
108using BatteryStatus = BatteryLevel;
109
110// Analog and digital joystick data
111struct StickStatus {
112 Common::UUID uuid{};
113 AnalogStatus x{};
114 AnalogStatus y{};
115 bool left{};
116 bool right{};
117 bool up{};
118 bool down{};
119};
120
121// Analog and digital trigger data
122struct TriggerStatus {
123 Common::UUID uuid{};
124 AnalogStatus analog{};
125 ButtonStatus pressed{};
126};
127
128// 3D vector representing motion input
129struct MotionSensor {
130 AnalogStatus x{};
131 AnalogStatus y{};
132 AnalogStatus z{};
133};
134
135// Motion data used to calculate controller orientation
136struct MotionStatus {
137 // Gyroscope vector measurement in radians/s.
138 MotionSensor gyro{};
139 // Acceleration vector measurement in G force
140 MotionSensor accel{};
141 // Time since last measurement in microseconds
142 u64 delta_timestamp{};
143 // Request to update after reading the value
144 bool force_update{};
145};
146
147// Data of a single point on a touch screen
148struct TouchStatus {
149 ButtonStatus pressed{};
150 AnalogStatus x{};
151 AnalogStatus y{};
152 int id{};
153};
154
155// Physical controller color in RGB format
156struct BodyColorStatus {
157 u32 body{};
158 u32 buttons{};
159};
160
161// HD rumble data
162struct VibrationStatus {
163 f32 low_amplitude{};
164 f32 low_frequency{};
165 f32 high_amplitude{};
166 f32 high_frequency{};
167 VibrationAmplificationType type;
168};
169
170// Physical controller LED pattern
171struct LedStatus {
172 bool led_1{};
173 bool led_2{};
174 bool led_3{};
175 bool led_4{};
176};
177
178// List of buttons to be passed to Qt that can be translated
179enum class ButtonNames {
180 Undefined,
181 Invalid,
182 // This will display the engine name instead of the button name
183 Engine,
184 // This will display the button by value instead of the button name
185 Value,
186 ButtonLeft,
187 ButtonRight,
188 ButtonDown,
189 ButtonUp,
190 TriggerZ,
191 TriggerR,
192 TriggerL,
193 ButtonA,
194 ButtonB,
195 ButtonX,
196 ButtonY,
197 ButtonStart,
198
199 // DS4 button names
200 L1,
201 L2,
202 L3,
203 R1,
204 R2,
205 R3,
206 Circle,
207 Cross,
208 Square,
209 Triangle,
210 Share,
211 Options,
212};
213
214// Callback data consisting of an input type and the equivalent data status
215struct CallbackStatus {
216 InputType type{InputType::None};
217 ButtonStatus button_status{};
218 StickStatus stick_status{};
219 AnalogStatus analog_status{};
220 TriggerStatus trigger_status{};
221 MotionStatus motion_status{};
222 TouchStatus touch_status{};
223 BodyColorStatus color_status{};
224 BatteryStatus battery_status{};
225 VibrationStatus vibration_status{};
226};
227
228// Triggered once every input change
229struct InputCallback {
230 std::function<void(const CallbackStatus&)> on_change;
231};
232
233/// An abstract class template for an input device (a button, an analog input, etc.).
234class InputDevice {
235public:
236 virtual ~InputDevice() = default;
237
238 // Request input device to update if necessary
239 virtual void SoftUpdate() {}
240
241 // Force input device to update data regardless of the current state
242 virtual void ForceUpdate() {}
243
244 // Sets the function to be triggered when input changes
245 void SetCallback(InputCallback callback_) {
246 callback = std::move(callback_);
247 }
248
249 // Triggers the function set in the callback
250 void TriggerOnChange(const CallbackStatus& status) {
251 if (callback.on_change) {
252 callback.on_change(status);
253 }
254 }
255
256private:
257 InputCallback callback;
258};
259
260/// An abstract class template for an output device (rumble, LED pattern, polling mode).
261class OutputDevice {
262public:
263 virtual ~OutputDevice() = default;
264
265 virtual void SetLED([[maybe_unused]] const LedStatus& led_status) {}
266
267 virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) {
268 return VibrationError::NotSupported;
269 }
270
271 virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
272 return PollingError::NotSupported;
273 }
274};
275
276/// An abstract class template for a factory that can create input devices.
277template <typename InputDeviceType>
278class Factory {
279public:
280 virtual ~Factory() = default;
281 virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
282};
283
284namespace Impl {
285
286template <typename InputDeviceType>
287using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
288
289template <typename InputDeviceType>
290struct FactoryList {
291 static FactoryListType<InputDeviceType> list;
292};
293
294template <typename InputDeviceType>
295FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
296
297} // namespace Impl
298
299/**
300 * Registers an input device factory.
301 * @tparam InputDeviceType the type of input devices the factory can create
302 * @param name the name of the factory. Will be used to match the "engine" parameter when creating
303 * a device
304 * @param factory the factory object to register
305 */
306template <typename InputDeviceType>
307void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
308 auto pair = std::make_pair(name, std::move(factory));
309 if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
310 LOG_ERROR(Input, "Factory '{}' already registered", name);
311 }
312}
313
314/**
315 * Unregisters an input device factory.
316 * @tparam InputDeviceType the type of input devices the factory can create
317 * @param name the name of the factory to unregister
318 */
319template <typename InputDeviceType>
320void UnregisterFactory(const std::string& name) {
321 if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
322 LOG_ERROR(Input, "Factory '{}' not registered", name);
323 }
324}
325
326/**
327 * Create an input device from given paramters.
328 * @tparam InputDeviceType the type of input devices to create
329 * @param params a serialized ParamPackage string that contains all parameters for creating the
330 * device
331 */
332template <typename InputDeviceType>
333std::unique_ptr<InputDeviceType> CreateDeviceFromString(const std::string& params) {
334 const Common::ParamPackage package(params);
335 const std::string engine = package.Get("engine", "null");
336 const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
337 const auto pair = factory_list.find(engine);
338 if (pair == factory_list.end()) {
339 if (engine != "null") {
340 LOG_ERROR(Input, "Unknown engine name: {}", engine);
341 }
342 return std::make_unique<InputDeviceType>();
343 }
344 return pair->second->Create(package);
345}
346
347/**
348 * Create an input device from given paramters.
349 * @tparam InputDeviceType the type of input devices to create
350 * @param A ParamPackage that contains all parameters for creating the device
351 */
352template <typename InputDeviceType>
353std::unique_ptr<InputDeviceType> CreateDevice(const Common::ParamPackage package) {
354 const std::string engine = package.Get("engine", "null");
355 const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
356 const auto pair = factory_list.find(engine);
357 if (pair == factory_list.end()) {
358 if (engine != "null") {
359 LOG_ERROR(Input, "Unknown engine name: {}", engine);
360 }
361 return std::make_unique<InputDeviceType>();
362 }
363 return pair->second->Create(package);
364}
365
366} // namespace Common::Input