summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/hid/controllers/npad.h
blob: 80cfcb2bbbbf56004a09428d4ab3cab73aca5fa3 (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
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <atomic>
#include <mutex>
#include <span>

#include "common/common_types.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/controllers/types/npad_types.h"

namespace Core::HID {
class EmulatedController;
enum class ControllerTriggerType;
} // namespace Core::HID

namespace Kernel {
class KEvent;
class KReadableEvent;
} // namespace Kernel

namespace Service::KernelHelpers {
class ServiceContext;
} // namespace Service::KernelHelpers

union Result;

namespace Service::HID {
class AppletResource;
struct NpadInternalState;
struct NpadSixAxisSensorLifo;
struct NpadSharedMemoryFormat;

class NPad final : public ControllerBase {
public:
    explicit NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
    ~NPad() override;

    // Called when the controller is initialized
    void OnInit() override;

    // When the controller is released
    void OnRelease() override;

    // When the controller is requesting an update for the shared memory
    void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;

    void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
    Core::HID::NpadStyleTag GetSupportedStyleSet() const;

    Result SetSupportedNpadIdTypes(std::span<const u8> data);
    void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
    std::size_t GetSupportedNpadIdTypesSize() const;

    void SetHoldType(NpadJoyHoldType joy_hold_type);
    NpadJoyHoldType GetHoldType() const;

    void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
    NpadHandheldActivationMode GetNpadHandheldActivationMode() const;

    void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
    NpadCommunicationMode GetNpadCommunicationMode() const;

    bool SetNpadMode(Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
                     NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);

    bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
                                  const Core::HID::VibrationValue& vibration_value);

    void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle,
                           const Core::HID::VibrationValue& vibration_value);

    void VibrateControllers(
        std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
        std::span<const Core::HID::VibrationValue> vibration_values);

    Core::HID::VibrationValue GetLastVibration(
        const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;

    void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);

    void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index);

    void SetPermitVibrationSession(bool permit_vibration_session);

    bool IsVibrationDeviceMounted(
        const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;

    Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id);
    void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const;

    // Adds a new controller at an index.
    void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id);
    // Adds a new controller at an index with connection status.
    void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id,
                            bool connected);

    Result DisconnectNpad(Core::HID::NpadIdType npad_id);

    Result IsFirmwareUpdateAvailableForSixAxisSensor(
        const Core::HID::SixAxisSensorHandle& sixaxis_handle, bool& is_firmware_available) const;
    Result ResetIsSixAxisSensorDeviceNewlyAssigned(
        const Core::HID::SixAxisSensorHandle& sixaxis_handle);

    Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
    Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
                                                        bool& is_enabled) const;
    Result SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
                                                         Core::HID::NpadIdType npad_id);
    void SetAnalogStickUseCenterClamp(bool use_center_clamp);
    void ClearAllConnectedControllers();
    void DisconnectAllConnectedControllers();
    void ConnectAllDisconnectedControllers();
    void ClearAllControllers();

    Result MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1,
                                   Core::HID::NpadIdType npad_id_2);
    void StartLRAssignmentMode();
    void StopLRAssignmentMode();
    Result SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);

    // Logical OR for all buttons presses on all controllers
    // Specifically for cheat engine and other features.
    Core::HID::NpadButton GetAndResetPressState();

    void ApplyNpadSystemCommonPolicy();

    AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);

private:
    struct VibrationData {
        bool device_mounted{};
        Core::HID::VibrationValue latest_vibration_value{};
        std::chrono::steady_clock::time_point last_vibration_timepoint{};
    };

    struct NpadControllerData {
        Kernel::KEvent* styleset_changed_event{};
        NpadInternalState* shared_memory = nullptr;
        Core::HID::EmulatedController* device = nullptr;

        std::array<VibrationData, 2> vibration{};
        bool unintended_home_button_input_protection{};
        bool is_connected{};

        // Dual joycons can have only one side connected
        bool is_dual_left_connected{true};
        bool is_dual_right_connected{true};

        // Current pad state
        NPadGenericState npad_pad_state{};
        NPadGenericState npad_libnx_state{};
        NpadGcTriggerState npad_trigger_state{};
        int callback_key{};
    };

    void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
    void InitNewlyAddedController(Core::HID::NpadIdType npad_id);
    bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const;
    void RequestPadStateUpdate(Core::HID::NpadIdType npad_id);
    void WriteEmptyEntry(NpadInternalState* npad);

    NpadControllerData& GetControllerFromHandle(
        const Core::HID::VibrationDeviceHandle& device_handle);
    const NpadControllerData& GetControllerFromHandle(
        const Core::HID::VibrationDeviceHandle& device_handle) const;
    NpadControllerData& GetControllerFromHandle(
        const Core::HID::SixAxisSensorHandle& device_handle);
    const NpadControllerData& GetControllerFromHandle(
        const Core::HID::SixAxisSensorHandle& device_handle) const;
    NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
    const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;

    Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
        const Core::HID::SixAxisSensorHandle& device_handle);
    const Core::HID::SixAxisSensorProperties& GetSixaxisProperties(
        const Core::HID::SixAxisSensorHandle& device_handle) const;

    std::atomic<u64> press_state{};

    std::array<NpadControllerData, NpadCount> controller_data{};
    KernelHelpers::ServiceContext& service_context;
    std::mutex mutex;
    std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
    NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical};
    NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
    NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
    bool permit_vibration_session_enabled{false};
    bool analog_stick_use_center_clamp{false};
    bool is_in_lr_assignment_mode{false};
    bool is_controller_initialized{false};
};
} // namespace Service::HID