summaryrefslogtreecommitdiffstats
path: root/src/core/hid/emulated_console.h
blob: 79114bb6d06633fa882d0eccf3db5ae15eff53dc (plain) (blame)
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
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <functional>
#include <memory>
#include <mutex>
#include <optional>
#include <unordered_map>

#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/input.h"
#include "common/param_package.h"
#include "common/point.h"
#include "common/quaternion.h"
#include "common/vector_math.h"
#include "core/hid/hid_types.h"
#include "core/hid/motion_input.h"

namespace Core::HID {
static constexpr std::size_t MaxTouchDevices = 32;
static constexpr std::size_t MaxActiveTouchInputs = 16;

struct ConsoleMotionInfo {
    Common::Input::MotionStatus raw_status{};
    MotionInput emulated{};
};

using ConsoleMotionDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 2>;
using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>;

using ConsoleMotionParams = std::array<Common::ParamPackage, 2>;
using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>;

using ConsoleMotionValues = ConsoleMotionInfo;
using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>;

struct TouchFinger {
    u64 last_touch{};
    Common::Point<float> position{};
    u32 id{};
    TouchAttribute attribute{};
    bool pressed{};
};

// Contains all motion related data that is used on the services
struct ConsoleMotion {
    Common::Vec3f accel{};
    Common::Vec3f gyro{};
    Common::Vec3f rotation{};
    std::array<Common::Vec3f, 3> orientation{};
    Common::Quaternion<f32> quaternion{};
    Common::Vec3f gyro_bias{};
    f32 verticalization_error{};
    bool is_at_rest{};
};

using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>;

struct ConsoleStatus {
    // Data from input_common
    ConsoleMotionValues motion_values{};
    TouchValues touch_values{};

    // Data for HID services
    ConsoleMotion motion_state{};
    TouchFingerState touch_state{};
};

enum class ConsoleTriggerType {
    Motion,
    Touch,
    All,
};

struct ConsoleUpdateCallback {
    std::function<void(ConsoleTriggerType)> on_change;
};

class EmulatedConsole {
public:
    /**
     * Contains all input data within the emulated switch console tablet such as touch and motion
     */
    explicit EmulatedConsole();
    ~EmulatedConsole();

    YUZU_NON_COPYABLE(EmulatedConsole);
    YUZU_NON_MOVEABLE(EmulatedConsole);

    /// Removes all callbacks created from input devices
    void UnloadInput();

    /**
     * Sets the emulated console into configuring mode
     * This prevents the modification of the HID state of the emulated console by input commands
     */
    void EnableConfiguration();

    /// Returns the emulated console into normal mode, allowing the modification of the HID state
    void DisableConfiguration();

    /// Returns true if the emulated console is in configuring mode
    bool IsConfiguring() const;

    /// Reload all input devices
    void ReloadInput();

    /// Overrides current mapped devices with the stored configuration and reloads all input devices
    void ReloadFromSettings();

    /// Saves the current mapped configuration
    void SaveCurrentConfig();

    /// Reverts any mapped changes made that weren't saved
    void RestoreConfig();

    // Returns the current mapped motion device
    Common::ParamPackage GetMotionParam() const;

    /**
     * Updates the current mapped motion device
     * @param param ParamPackage with controller data to be mapped
     */
    void SetMotionParam(Common::ParamPackage param);

    /// Returns the latest status of motion input from the console with parameters
    ConsoleMotionValues GetMotionValues() const;

    /// Returns the latest status of touch input from the console with parameters
    TouchValues GetTouchValues() const;

    /// Returns the latest status of motion input from the console
    ConsoleMotion GetMotion() const;

    /// Returns the latest status of touch input from the console
    TouchFingerState GetTouch() const;

    /**
     * Adds a callback to the list of events
     * @param update_callback A ConsoleUpdateCallback that will be triggered
     * @return an unique key corresponding to the callback index in the list
     */
    int SetCallback(ConsoleUpdateCallback update_callback);

    /**
     * Removes a callback from the list stopping any future events to this object
     * @param key Key corresponding to the callback index in the list
     */
    void DeleteCallback(int key);

private:
    /// Creates and stores the touch params
    void SetTouchParams();

    /**
     * Updates the motion status of the console
     * @param callback A CallbackStatus containing gyro and accelerometer data
     */
    void SetMotion(const Common::Input::CallbackStatus& callback);

    /**
     * Updates the touch status of the console
     * @param callback A CallbackStatus containing the touch position
     * @param index Finger ID to be updated
     */
    void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index);

    std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const;

    std::optional<std::size_t> GetNextFreeIndex() const;

    /**
     * Triggers a callback that something has changed on the console status
     * @param type Input type of the event to trigger
     */
    void TriggerOnChange(ConsoleTriggerType type);

    bool is_configuring{false};
    f32 motion_sensitivity{0.01f};

    ConsoleMotionParams motion_params;
    TouchParams touch_params;

    ConsoleMotionDevices motion_devices;
    TouchDevices touch_devices;

    mutable std::mutex mutex;
    mutable std::mutex callback_mutex;
    std::unordered_map<int, ConsoleUpdateCallback> callback_list;
    int last_callback_key = 0;

    // Stores the current status of all console input
    ConsoleStatus console;
};

} // namespace Core::HID