summaryrefslogtreecommitdiff
path: root/src/common/input.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/input.h')
-rw-r--r--src/common/input.h372
1 files changed, 372 insertions, 0 deletions
diff --git a/src/common/input.h b/src/common/input.h
new file mode 100644
index 000000000..eaee0bdea
--- /dev/null
+++ b/src/common/input.h
@@ -0,0 +1,372 @@
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(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 return;
241 }
242
243 // Force input device to update data regardless of the current state
244 virtual void ForceUpdate() {
245 return;
246 }
247
248 // Sets the function to be triggered when input changes
249 void SetCallback(InputCallback callback_) {
250 callback = std::move(callback_);
251 }
252
253 // Triggers the function set in the callback
254 void TriggerOnChange(CallbackStatus status) {
255 if (callback.on_change) {
256 callback.on_change(status);
257 }
258 }
259
260private:
261 InputCallback callback;
262};
263
264/// An abstract class template for an output device (rumble, LED pattern, polling mode).
265class OutputDevice {
266public:
267 virtual ~OutputDevice() = default;
268
269 virtual void SetLED([[maybe_unused]] LedStatus led_status) {
270 return;
271 }
272
273 virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) {
274 return VibrationError::NotSupported;
275 }
276
277 virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) {
278 return PollingError::NotSupported;
279 }
280};
281
282/// An abstract class template for a factory that can create input devices.
283template <typename InputDeviceType>
284class Factory {
285public:
286 virtual ~Factory() = default;
287 virtual std::unique_ptr<InputDeviceType> Create(const Common::ParamPackage&) = 0;
288};
289
290namespace Impl {
291
292template <typename InputDeviceType>
293using FactoryListType = std::unordered_map<std::string, std::shared_ptr<Factory<InputDeviceType>>>;
294
295template <typename InputDeviceType>
296struct FactoryList {
297 static FactoryListType<InputDeviceType> list;
298};
299
300template <typename InputDeviceType>
301FactoryListType<InputDeviceType> FactoryList<InputDeviceType>::list;
302
303} // namespace Impl
304
305/**
306 * Registers an input device factory.
307 * @tparam InputDeviceType the type of input devices the factory can create
308 * @param name the name of the factory. Will be used to match the "engine" parameter when creating
309 * a device
310 * @param factory the factory object to register
311 */
312template <typename InputDeviceType>
313void RegisterFactory(const std::string& name, std::shared_ptr<Factory<InputDeviceType>> factory) {
314 auto pair = std::make_pair(name, std::move(factory));
315 if (!Impl::FactoryList<InputDeviceType>::list.insert(std::move(pair)).second) {
316 LOG_ERROR(Input, "Factory '{}' already registered", name);
317 }
318}
319
320/**
321 * Unregisters an input device factory.
322 * @tparam InputDeviceType the type of input devices the factory can create
323 * @param name the name of the factory to unregister
324 */
325template <typename InputDeviceType>
326void UnregisterFactory(const std::string& name) {
327 if (Impl::FactoryList<InputDeviceType>::list.erase(name) == 0) {
328 LOG_ERROR(Input, "Factory '{}' not registered", name);
329 }
330}
331
332/**
333 * Create an input device from given paramters.
334 * @tparam InputDeviceType the type of input devices to create
335 * @param params a serialized ParamPackage string that contains all parameters for creating the
336 * device
337 */
338template <typename InputDeviceType>
339std::unique_ptr<InputDeviceType> CreateDeviceFromString(const std::string& params) {
340 const Common::ParamPackage package(params);
341 const std::string engine = package.Get("engine", "null");
342 const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
343 const auto pair = factory_list.find(engine);
344 if (pair == factory_list.end()) {
345 if (engine != "null") {
346 LOG_ERROR(Input, "Unknown engine name: {}", engine);
347 }
348 return std::make_unique<InputDeviceType>();
349 }
350 return pair->second->Create(package);
351}
352
353/**
354 * Create an input device from given paramters.
355 * @tparam InputDeviceType the type of input devices to create
356 * @param A ParamPackage that contains all parameters for creating the device
357 */
358template <typename InputDeviceType>
359std::unique_ptr<InputDeviceType> CreateDevice(const Common::ParamPackage package) {
360 const std::string engine = package.Get("engine", "null");
361 const auto& factory_list = Impl::FactoryList<InputDeviceType>::list;
362 const auto pair = factory_list.find(engine);
363 if (pair == factory_list.end()) {
364 if (engine != "null") {
365 LOG_ERROR(Input, "Unknown engine name: {}", engine);
366 }
367 return std::make_unique<InputDeviceType>();
368 }
369 return pair->second->Create(package);
370}
371
372} // namespace Common::Input