aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/input_common/input_engine.h
blob: 3e328509b13d89b88d43281e3ef36ee677f96906 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>
#include <mutex>
#include <unordered_map>

#include "common/common_types.h"
#include "common/input.h"
#include "common/param_package.h"
#include "common/uuid.h"
#include "input_common/main.h"

// Pad Identifier of data source
struct PadIdentifier {
    Common::UUID guid{};
    std::size_t port{};
    std::size_t pad{};

    friend constexpr bool operator==(const PadIdentifier&, const PadIdentifier&) = default;
};

// Basic motion data containing data from the sensors and a timestamp in microseconds
struct BasicMotion {
    float gyro_x{};
    float gyro_y{};
    float gyro_z{};
    float accel_x{};
    float accel_y{};
    float accel_z{};
    u64 delta_timestamp{};
};

// Types of input that are stored in the engine
enum class EngineInputType {
    None,
    Analog,
    Battery,
    Button,
    Camera,
    Color,
    HatButton,
    Motion,
    Nfc,
};

struct VibrationRequest {
    PadIdentifier identifier;
    Common::Input::VibrationStatus vibration;
};

namespace std {
// Hash used to create lists from PadIdentifier data
template <>
struct hash<PadIdentifier> {
    size_t operator()(const PadIdentifier& pad_id) const noexcept {
        u64 hash_value = pad_id.guid.Hash();
        hash_value ^= (static_cast<u64>(pad_id.port) << 32);
        hash_value ^= static_cast<u64>(pad_id.pad);
        return static_cast<size_t>(hash_value);
    }
};

} // namespace std

namespace InputCommon {

// Data from the engine and device needed for creating a ParamPackage
struct MappingData {
    std::string engine{};
    PadIdentifier pad{};
    EngineInputType type{};
    int index{};
    bool button_value{};
    std::string hat_name{};
    f32 axis_value{};
    BasicMotion motion_value{};
};

// Triggered if data changed on the controller
struct UpdateCallback {
    std::function<void()> on_change;
};

// Triggered if data changed on the controller and the engine is on configuring mode
struct MappingCallback {
    std::function<void(const MappingData&)> on_data;
};

// Input Identifier of data source
struct InputIdentifier {
    PadIdentifier identifier;
    EngineInputType type;
    int index;
    UpdateCallback callback;
};

class InputEngine {
public:
    explicit InputEngine(std::string input_engine_) : input_engine{std::move(input_engine_)} {}

    virtual ~InputEngine() = default;

    // Enable configuring mode for mapping
    void BeginConfiguration();

    // Disable configuring mode for mapping
    void EndConfiguration();

    // Sets a led pattern for a controller
    virtual Common::Input::DriverResult SetLeds(
        [[maybe_unused]] const PadIdentifier& identifier,
        [[maybe_unused]] const Common::Input::LedStatus& led_status) {
        return Common::Input::DriverResult::NotSupported;
    }

    // Sets rumble to a controller
    virtual Common::Input::DriverResult SetVibration(
        [[maybe_unused]] const PadIdentifier& identifier,
        [[maybe_unused]] const Common::Input::VibrationStatus& vibration) {
        return Common::Input::DriverResult::NotSupported;
    }

    // Returns true if device supports vibrations
    virtual bool IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) {
        return false;
    }

    // Sets polling mode to a controller
    virtual Common::Input::DriverResult SetPollingMode(
        [[maybe_unused]] const PadIdentifier& identifier,
        [[maybe_unused]] const Common::Input::PollingMode polling_mode) {
        return Common::Input::DriverResult::NotSupported;
    }

    // Sets camera format to a controller
    virtual Common::Input::DriverResult SetCameraFormat(
        [[maybe_unused]] const PadIdentifier& identifier,
        [[maybe_unused]] Common::Input::CameraFormat camera_format) {
        return Common::Input::DriverResult::NotSupported;
    }

    // Returns success if nfc is supported
    virtual Common::Input::NfcState SupportsNfc(
        [[maybe_unused]] const PadIdentifier& identifier) const {
        return Common::Input::NfcState::NotSupported;
    }

    // Start scanning for nfc tags
    virtual Common::Input::NfcState StartNfcPolling(
        [[maybe_unused]] const PadIdentifier& identifier_) {
        return Common::Input::NfcState::NotSupported;
    }

    // Start scanning for nfc tags
    virtual Common::Input::NfcState StopNfcPolling(
        [[maybe_unused]] const PadIdentifier& identifier_) {
        return Common::Input::NfcState::NotSupported;
    }

    // Reads data from amiibo tag
    virtual Common::Input::NfcState ReadAmiiboData(
        [[maybe_unused]] const PadIdentifier& identifier_,
        [[maybe_unused]] std::vector<u8>& out_data) {
        return Common::Input::NfcState::NotSupported;
    }

    // Writes data to an nfc tag
    virtual Common::Input::NfcState WriteNfcData([[maybe_unused]] const PadIdentifier& identifier,
                                                 [[maybe_unused]] const std::vector<u8>& data) {
        return Common::Input::NfcState::NotSupported;
    }

    // Reads data from mifare tag
    virtual Common::Input::NfcState ReadMifareData(
        [[maybe_unused]] const PadIdentifier& identifier_,
        [[maybe_unused]] const Common::Input::MifareRequest& request,
        [[maybe_unused]] Common::Input::MifareRequest& out_data) {
        return Common::Input::NfcState::NotSupported;
    }

    // Write data to mifare tag
    virtual Common::Input::NfcState WriteMifareData(
        [[maybe_unused]] const PadIdentifier& identifier_,
        [[maybe_unused]] const Common::Input::MifareRequest& request) {
        return Common::Input::NfcState::NotSupported;
    }

    // Returns the engine name
    [[nodiscard]] const std::string& GetEngineName() const;

    /// Used for automapping features
    virtual std::vector<Common::ParamPackage> GetInputDevices() const {
        return {};
    }

    /// Retrieves the button mappings for the given device
    virtual ButtonMapping GetButtonMappingForDevice(
        [[maybe_unused]] const Common::ParamPackage& params) {
        return {};
    }

    /// Retrieves the analog mappings for the given device
    virtual AnalogMapping GetAnalogMappingForDevice(
        [[maybe_unused]] const Common::ParamPackage& params) {
        return {};
    }

    /// Retrieves the motion mappings for the given device
    virtual MotionMapping GetMotionMappingForDevice(
        [[maybe_unused]] const Common::ParamPackage& params) {
        return {};
    }

    /// Retrieves the name of the given input.
    virtual Common::Input::ButtonNames GetUIName(
        [[maybe_unused]] const Common::ParamPackage& params) const {
        return Common::Input::ButtonNames::Engine;
    }

    /// Retrieves the index number of the given hat button direction
    virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const {
        return 0;
    }

    /// Returns true if axis of a stick aren't mapped in the correct direction
    virtual bool IsStickInverted([[maybe_unused]] const Common::ParamPackage& params) {
        return false;
    }

    void PreSetController(const PadIdentifier& identifier);
    void PreSetButton(const PadIdentifier& identifier, int button);
    void PreSetHatButton(const PadIdentifier& identifier, int button);
    void PreSetAxis(const PadIdentifier& identifier, int axis);
    void PreSetMotion(const PadIdentifier& identifier, int motion);
    void ResetButtonState();
    void ResetAnalogState();

    bool GetButton(const PadIdentifier& identifier, int button) const;
    bool GetHatButton(const PadIdentifier& identifier, int button, u8 direction) const;
    f32 GetAxis(const PadIdentifier& identifier, int axis) const;
    Common::Input::BatteryLevel GetBattery(const PadIdentifier& identifier) const;
    Common::Input::BodyColorStatus GetColor(const PadIdentifier& identifier) const;
    BasicMotion GetMotion(const PadIdentifier& identifier, int motion) const;
    Common::Input::CameraStatus GetCamera(const PadIdentifier& identifier) const;
    Common::Input::NfcStatus GetNfc(const PadIdentifier& identifier) const;

    int SetCallback(InputIdentifier input_identifier);
    void SetMappingCallback(MappingCallback callback);
    void DeleteCallback(int key);

protected:
    void SetButton(const PadIdentifier& identifier, int button, bool value);
    void SetHatButton(const PadIdentifier& identifier, int button, u8 value);
    void SetAxis(const PadIdentifier& identifier, int axis, f32 value);
    void SetBattery(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
    void SetColor(const PadIdentifier& identifier, Common::Input::BodyColorStatus value);
    void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value);
    void SetCamera(const PadIdentifier& identifier, const Common::Input::CameraStatus& value);
    void SetNfc(const PadIdentifier& identifier, const Common::Input::NfcStatus& value);

    virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const {
        return "Unknown";
    }

private:
    struct ControllerData {
        std::unordered_map<int, bool> buttons;
        std::unordered_map<int, u8> hat_buttons;
        std::unordered_map<int, float> axes;
        std::unordered_map<int, BasicMotion> motions;
        Common::Input::BatteryLevel battery{};
        Common::Input::BodyColorStatus color{};
        Common::Input::CameraStatus camera{};
        Common::Input::NfcStatus nfc{};
    };

    void TriggerOnButtonChange(const PadIdentifier& identifier, int button, bool value);
    void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value);
    void TriggerOnAxisChange(const PadIdentifier& identifier, int axis, f32 value);
    void TriggerOnBatteryChange(const PadIdentifier& identifier, Common::Input::BatteryLevel value);
    void TriggerOnColorChange(const PadIdentifier& identifier,
                              Common::Input::BodyColorStatus value);
    void TriggerOnMotionChange(const PadIdentifier& identifier, int motion,
                               const BasicMotion& value);
    void TriggerOnCameraChange(const PadIdentifier& identifier,
                               const Common::Input::CameraStatus& value);
    void TriggerOnNfcChange(const PadIdentifier& identifier, const Common::Input::NfcStatus& value);

    bool IsInputIdentifierEqual(const InputIdentifier& input_identifier,
                                const PadIdentifier& identifier, EngineInputType type,
                                int index) const;

    mutable std::mutex mutex;
    mutable std::mutex mutex_callback;
    bool configuring{false};
    const std::string input_engine;
    int last_callback_key = 0;
    std::unordered_map<PadIdentifier, ControllerData> controller_list;
    std::unordered_map<int, InputIdentifier> callback_list;
    MappingCallback mapping_callback;
};

} // namespace InputCommon