aboutsummaryrefslogtreecommitdiff
path: root/src/input_common/drivers/sdl_driver.h
blob: c826325069e10d3af6220c215f0012c41c8dbc0f (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
// Copyright 2018 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <atomic>
#include <mutex>
#include <thread>
#include <unordered_map>

#include <SDL.h>

#include "common/common_types.h"
#include "common/threadsafe_queue.h"
#include "input_common/input_engine.h"

union SDL_Event;
using SDL_GameController = struct _SDL_GameController;
using SDL_Joystick = struct _SDL_Joystick;
using SDL_JoystickID = s32;

namespace InputCommon {

class SDLJoystick;

using ButtonBindings =
    std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 18>;
using ZButtonBindings =
    std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;

class SDLDriver : public InputEngine {
public:
    /// Initializes and registers SDL device factories
    explicit SDLDriver(std::string input_engine_);

    /// Unregisters SDL device factories and shut them down.
    ~SDLDriver() override;

    /// Handle SDL_Events for joysticks from SDL_PollEvent
    void HandleGameControllerEvent(const SDL_Event& event);

    /// Get the nth joystick with the corresponding GUID
    std::shared_ptr<SDLJoystick> GetSDLJoystickBySDLID(SDL_JoystickID sdl_id);

    /**
     * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so
     * tie it to a SDLJoystick with the same guid and that port
     */
    std::shared_ptr<SDLJoystick> GetSDLJoystickByGUID(const std::string& guid, int port);

    std::vector<Common::ParamPackage> GetInputDevices() const override;

    ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
    AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
    MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override;
    Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override;

    std::string GetHatButtonName(u8 direction_value) const override;
    u8 GetHatButtonId(const std::string& direction_name) const override;

    bool IsStickInverted(const Common::ParamPackage& params) override;

    Common::Input::VibrationError SetRumble(
        const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override;

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

    void InitJoystick(int joystick_index);
    void CloseJoystick(SDL_Joystick* sdl_joystick);

    /// Needs to be called before SDL_QuitSubSystem.
    void CloseJoysticks();

    /// Takes all vibrations from the queue and sends the command to the controller
    void SendVibrations();

    Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
                                                          float value = 0.1f) const;
    Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid,
                                                          s32 button) const;

    Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat,
                                                       u8 value) const;

    Common::ParamPackage BuildMotionParam(int port, std::string guid) const;

    Common::ParamPackage BuildParamPackageForBinding(
        int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const;

    Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x,
                                                    int axis_y, float offset_x,
                                                    float offset_y) const;

    /// Returns the default button bindings list for generic controllers
    ButtonBindings GetDefaultButtonBinding() const;

    /// Returns the default button bindings list for nintendo controllers
    ButtonBindings GetNintendoButtonBinding(const std::shared_ptr<SDLJoystick>& joystick) const;

    /// Returns the button mappings from a single controller
    ButtonMapping GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
                                             const ButtonBindings& switch_to_sdl_button,
                                             const ZButtonBindings& switch_to_sdl_axis) const;

    /// Returns the button mappings from two different controllers
    ButtonMapping GetDualControllerMapping(const std::shared_ptr<SDLJoystick>& joystick,
                                           const std::shared_ptr<SDLJoystick>& joystick2,
                                           const ButtonBindings& switch_to_sdl_button,
                                           const ZButtonBindings& switch_to_sdl_axis) const;

    /// Returns true if the button is on the left joycon
    bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const;

    /// Queue of vibration request to controllers
    Common::SPSCQueue<VibrationRequest> vibration_queue;

    /// Map of GUID of a list of corresponding virtual Joysticks
    std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
    std::mutex joystick_map_mutex;

    bool start_thread = false;
    std::atomic<bool> initialized = false;

    std::thread poll_thread;
};
} // namespace InputCommon