duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

input_manager.h (14378B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>
      2 // SPDX-License-Identifier: (GPL-3.0 OR PolyForm-Strict-1.0.0)
      3 
      4 #pragma once
      5 
      6 #include <functional>
      7 #include <mutex>
      8 #include <optional>
      9 #include <string_view>
     10 #include <utility>
     11 #include <variant>
     12 
     13 #include "common/settings_interface.h"
     14 #include "common/types.h"
     15 
     16 #include "core/input_types.h"
     17 #include "window_info.h"
     18 
     19 class SmallStringBase;
     20 
     21 /// Class, or source of an input event.
     22 enum class InputSourceType : u32
     23 {
     24   Keyboard,
     25   Pointer,
     26   Sensor,
     27 #ifdef _WIN32
     28   DInput,
     29   XInput,
     30 #endif
     31 #ifndef __ANDROID__
     32   SDL,
     33   RawInput,
     34 #else
     35   Android,
     36 #endif
     37   Count,
     38 };
     39 
     40 /// Subtype of a key for an input source.
     41 enum class InputSubclass : u32
     42 {
     43   None = 0,
     44 
     45   PointerButton = 0,
     46   PointerAxis = 1,
     47 
     48   ControllerButton = 0,
     49   ControllerAxis = 1,
     50   ControllerHat = 2,
     51   ControllerMotor = 3,
     52   ControllerHaptic = 4,
     53 
     54   SensorAccelerometer = 0,
     55 };
     56 
     57 enum class InputModifier : u32
     58 {
     59   None = 0,
     60   Negate,   ///< Input * -1, gets the negative side of the axis
     61   FullAxis, ///< (Input * 0.5) + 0.5, uses both the negative and positive side of the axis together
     62 };
     63 
     64 /// A composite type representing a full input key which is part of an event.
     65 union InputBindingKey
     66 {
     67   struct
     68   {
     69     InputSourceType source_type : 4;
     70     u32 source_index : 8;             ///< controller number
     71     InputSubclass source_subtype : 3; ///< if 1, binding is for an axis and not a button (used for controllers)
     72     InputModifier modifier : 2;
     73     u32 invert : 1; ///< if 1, value is inverted prior to being sent to the sink
     74     u32 unused : 14;
     75     u32 data;
     76   };
     77 
     78   u64 bits;
     79 
     80   bool operator==(const InputBindingKey& k) const { return bits == k.bits; }
     81   bool operator!=(const InputBindingKey& k) const { return bits != k.bits; }
     82 
     83   /// Removes the direction bit from the key, which is used to look up the bindings for it.
     84   /// This is because negative bindings should still fire when they reach zero again.
     85   InputBindingKey MaskDirection() const
     86   {
     87     InputBindingKey r;
     88     r.bits = bits;
     89     r.modifier = InputModifier::None;
     90     r.invert = 0;
     91     return r;
     92   }
     93 };
     94 static_assert(sizeof(InputBindingKey) == sizeof(u64), "Input binding key is 64 bits");
     95 
     96 /// Hashability for InputBindingKey
     97 struct InputBindingKeyHash
     98 {
     99   std::size_t operator()(const InputBindingKey& k) const { return std::hash<u64>{}(k.bits); }
    100 };
    101 
    102 /// Callback type for a binary event. Usually used for hotkeys.
    103 using InputButtonEventHandler = std::function<void(s32 value)>;
    104 
    105 /// Callback types for a normalized event. Usually used for pads.
    106 using InputAxisEventHandler = std::function<void(float value)>;
    107 
    108 /// ------------------------------------------------------------------------
    109 /// Event Handler Type
    110 /// ------------------------------------------------------------------------
    111 /// This class acts as an adapter to convert from normalized values to
    112 /// binary values when the callback is a binary/button handler. That way
    113 /// you don't need to convert float->bool in your callbacks.
    114 using InputEventHandler = std::variant<InputAxisEventHandler, InputButtonEventHandler>;
    115 
    116 /// Input monitoring for external access.
    117 struct InputInterceptHook
    118 {
    119   enum class CallbackResult
    120   {
    121     StopProcessingEvent,
    122     ContinueProcessingEvent,
    123     RemoveHookAndStopProcessingEvent,
    124     RemoveHookAndContinueProcessingEvent,
    125   };
    126 
    127   using Callback = std::function<CallbackResult(InputBindingKey key, float value)>;
    128 };
    129 
    130 /// Hotkeys are actions (e.g. toggle frame limit) which can be bound to keys or chords.
    131 /// The handler is called with an integer representing the key state, where 0 means that
    132 /// one or more keys were released, 1 means all the keys were pressed, and -1 means that
    133 /// the hotkey was cancelled due to a chord with more keys being activated.
    134 struct HotkeyInfo
    135 {
    136   const char* name;
    137   const char* category;
    138   const char* display_name;
    139   void (*handler)(s32 pressed);
    140 };
    141 #define DECLARE_HOTKEY_LIST(name) extern const HotkeyInfo name[]
    142 #define BEGIN_HOTKEY_LIST(name) const HotkeyInfo name[] = {
    143 #define DEFINE_HOTKEY(name, category, display_name, handler) {(name), (category), (display_name), (handler)},
    144 #define END_HOTKEY_LIST()                                                                                              \
    145   {                                                                                                                    \
    146     nullptr, nullptr, nullptr, nullptr                                                                                 \
    147   }                                                                                                                    \
    148   }                                                                                                                    \
    149   ;
    150 
    151 DECLARE_HOTKEY_LIST(g_common_hotkeys);
    152 DECLARE_HOTKEY_LIST(g_host_hotkeys);
    153 
    154 /// Generic input bindings. These roughly match a DualShock 4 or XBox One controller.
    155 /// They are used for automatic binding to PS2 controller types, and for big picture mode navigation.
    156 enum class GenericInputBinding : u8;
    157 using GenericInputBindingMapping = std::vector<std::pair<GenericInputBinding, std::string>>;
    158 
    159 /// Host mouse relative axes are X, Y, wheel horizontal, wheel vertical.
    160 enum class InputPointerAxis : u8
    161 {
    162   X,
    163   Y,
    164   WheelX,
    165   WheelY,
    166   Count
    167 };
    168 
    169 /// External input source class.
    170 class InputSource;
    171 
    172 namespace InputManager {
    173 /// Minimum interval between vibration updates when the effect is continuous.
    174 static constexpr double VIBRATION_UPDATE_INTERVAL_SECONDS = 0.5; // 500ms
    175 
    176 /// Maximum number of host mouse devices.
    177 static constexpr u32 MAX_POINTER_DEVICES = 8;
    178 static constexpr u32 MAX_POINTER_BUTTONS = 3;
    179 
    180 /// Maximum number of software cursors. We allocate an extra two for controllers with
    181 /// positioning data from the controller instead of a mouse.
    182 static constexpr u32 MAX_SOFTWARE_CURSORS = MAX_POINTER_DEVICES + 2;
    183 
    184 /// Number of macro buttons per controller.
    185 static constexpr u32 NUM_MACRO_BUTTONS_PER_CONTROLLER = 4;
    186 
    187 /// Returns a pointer to the external input source class, if present.
    188 InputSource* GetInputSourceInterface(InputSourceType type);
    189 
    190 /// Converts an input class to a string.
    191 const char* InputSourceToString(InputSourceType clazz);
    192 
    193 /// Returns the default state for an input source.
    194 bool GetInputSourceDefaultEnabled(InputSourceType type);
    195 
    196 /// Parses an input class string.
    197 std::optional<InputSourceType> ParseInputSourceString(std::string_view str);
    198 
    199 /// Parses a pointer device string, i.e. tells you which pointer is specified.
    200 std::optional<u32> GetIndexFromPointerBinding(std::string_view str);
    201 
    202 /// Returns the device name for a pointer index (e.g. Pointer-0).
    203 std::string GetPointerDeviceName(u32 pointer_index);
    204 
    205 /// Converts a key code from a human-readable string to an identifier.
    206 std::optional<u32> ConvertHostKeyboardStringToCode(std::string_view str);
    207 
    208 /// Converts a key code from an identifier to a human-readable string.
    209 std::optional<std::string> ConvertHostKeyboardCodeToString(u32 code);
    210 
    211 /// Converts a key code from an identifier to an icon which can be drawn.
    212 const char* ConvertHostKeyboardCodeToIcon(u32 code);
    213 
    214 /// Creates a key for a host-specific key code.
    215 InputBindingKey MakeHostKeyboardKey(u32 key_code);
    216 
    217 /// Creates a key for a host-specific button.
    218 InputBindingKey MakePointerButtonKey(u32 index, u32 button_index);
    219 
    220 /// Creates a key for a host-specific mouse relative event
    221 /// (axis 0 = horizontal, 1 = vertical, 2 = wheel horizontal, 3 = wheel vertical).
    222 InputBindingKey MakePointerAxisKey(u32 index, InputPointerAxis axis);
    223 
    224 /// Creates a key for a host-specific sensor.
    225 InputBindingKey MakeSensorAxisKey(InputSubclass sensor, u32 axis);
    226 
    227 /// Parses an input binding key string.
    228 std::optional<InputBindingKey> ParseInputBindingKey(std::string_view binding);
    229 
    230 /// Converts a input key to a string.
    231 std::string ConvertInputBindingKeyToString(InputBindingInfo::Type binding_type, InputBindingKey key);
    232 
    233 /// Converts a chord of binding keys to a string.
    234 std::string ConvertInputBindingKeysToString(InputBindingInfo::Type binding_type, const InputBindingKey* keys,
    235                                             size_t num_keys);
    236 
    237 /// Represents a binding with icon fonts, if available.
    238 bool PrettifyInputBinding(SmallStringBase& binding);
    239 
    240 /// Returns a list of all hotkeys.
    241 std::vector<const HotkeyInfo*> GetHotkeyList();
    242 
    243 /// Enumerates available devices. Returns a pair of the prefix (e.g. SDL-0) and the device name.
    244 std::vector<std::pair<std::string, std::string>> EnumerateDevices();
    245 
    246 /// Enumerates available vibration motors at the time of call.
    247 std::vector<InputBindingKey> EnumerateMotors();
    248 
    249 /// Retrieves bindings that match the generic bindings for the specified device.
    250 GenericInputBindingMapping GetGenericBindingMapping(std::string_view device);
    251 
    252 /// Returns true if the specified input source is enabled.
    253 bool IsInputSourceEnabled(SettingsInterface& si, InputSourceType type);
    254 
    255 /// Re-parses the config and registers all hotkey and pad bindings.
    256 void ReloadBindings(SettingsInterface& si, SettingsInterface& hotkey_binding_si);
    257 
    258 /// Re-parses the sources part of the config and initializes any backends.
    259 void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);
    260 
    261 /// Called when a device change is triggered by the system (DBT_DEVNODES_CHANGED on Windows).
    262 /// Returns true if any device changes are detected.
    263 bool ReloadDevices();
    264 
    265 /// Shuts down any enabled input sources.
    266 void CloseSources();
    267 
    268 /// Polls input sources for events (e.g. external controllers).
    269 void PollSources();
    270 
    271 /// Returns true if any bindings exist for the specified key.
    272 /// Can be safely called on another thread.
    273 bool HasAnyBindingsForKey(InputBindingKey key);
    274 
    275 /// Returns true if any bindings exist for the specified source + index.
    276 /// Can be safely called on another thread.
    277 bool HasAnyBindingsForSource(InputBindingKey key);
    278 
    279 /// Parses a string binding into its components. Use with external AddBinding().
    280 bool ParseBindingAndGetSource(std::string_view binding, InputBindingKey* key, InputSource** source);
    281 
    282 /// Externally adds a fixed binding. Be sure to call *after* ReloadBindings() otherwise it will be lost.
    283 void AddBinding(std::string_view binding, const InputEventHandler& handler);
    284 
    285 /// Adds an external vibration binding.
    286 void AddVibrationBinding(u32 pad_index, const InputBindingKey* motor_0_binding, InputSource* motor_0_source,
    287                          const InputBindingKey* motor_1_binding, InputSource* motor_1_source);
    288 
    289 /// Updates internal state for any binds for this key, and fires callbacks as needed.
    290 /// Returns true if anything was bound to this key, otherwise false.
    291 bool InvokeEvents(InputBindingKey key, float value, GenericInputBinding generic_key = GenericInputBinding::Unknown);
    292 
    293 /// Clears internal state for any binds with a matching source/index.
    294 void ClearBindStateFromSource(InputBindingKey key);
    295 
    296 /// Sets a hook which can be used to intercept events before they're processed by the normal bindings.
    297 /// This is typically used when binding new controls to detect what gets pressed.
    298 void SetHook(InputInterceptHook::Callback callback);
    299 
    300 /// Removes any currently-active interception hook.
    301 void RemoveHook();
    302 
    303 /// Returns true if there is an interception hook present.
    304 bool HasHook();
    305 
    306 /// Internal method used by pads to dispatch vibration updates to input sources.
    307 /// Intensity is normalized from 0 to 1.
    308 void SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensity, float small_motor_intensity);
    309 
    310 /// Zeros all vibration intensities. Call when pausing.
    311 /// The pad vibration state will internally remain, so that when emulation is unpaused, the effect resumes.
    312 void PauseVibration();
    313 
    314 /// Returns the number of currently-connected pointer devices.
    315 u32 GetPointerCount();
    316 
    317 /// Reads absolute pointer position.
    318 std::pair<float, float> GetPointerAbsolutePosition(u32 index);
    319 
    320 /// Updates absolute pointer position. Can call from UI thread, use when the host only reports absolute coordinates.
    321 void UpdatePointerAbsolutePosition(u32 index, float x, float y);
    322 
    323 /// Updates relative pointer position. Can call from the UI thread, use when host supports relative coordinate
    324 /// reporting.
    325 void UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input = false);
    326 
    327 /// Updates host mouse mode (relative/cursor hiding).
    328 void UpdateRelativeMouseMode();
    329 void UpdateHostMouseMode();
    330 
    331 /// Sets the state of the specified macro button.
    332 void SetMacroButtonState(u32 pad, u32 index, bool state);
    333 
    334 /// Returns true if the raw input source is being used.
    335 bool IsUsingRawInput();
    336 
    337 /// Updates InputManager's view of the window size, used for clamping raw input coordinates.
    338 void SetDisplayWindowSize(float width, float height);
    339 
    340 /// Restores default configuration.
    341 void SetDefaultSourceConfig(SettingsInterface& si);
    342 
    343 /// Clears all bindings for a given port.
    344 void ClearPortBindings(SettingsInterface& si, u32 port);
    345 
    346 /// Copies pad configuration from one interface (ini) to another.
    347 void CopyConfiguration(SettingsInterface* dest_si, const SettingsInterface& src_si, bool copy_pad_config = true,
    348                        bool copy_pad_bindings = true, bool copy_hotkey_bindings = true);
    349 
    350 /// Performs automatic controller mapping with the provided list of generic mappings.
    351 bool MapController(SettingsInterface& si, u32 controller,
    352                    const std::vector<std::pair<GenericInputBinding, std::string>>& mapping);
    353 
    354 /// Returns a list of input profiles available.
    355 std::vector<std::string> GetInputProfileNames();
    356 
    357 /// Called when a new input device is connected.
    358 void OnInputDeviceConnected(std::string_view identifier, std::string_view device_name);
    359 
    360 /// Called when an input device is disconnected.
    361 void OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier);
    362 } // namespace InputManager
    363 
    364 namespace Host {
    365 /// Adds any fixed bindings from the host.
    366 void AddFixedInputBindings(SettingsInterface& si);
    367 
    368 /// Called when a new input device is connected.
    369 void OnInputDeviceConnected(std::string_view identifier, std::string_view device_name);
    370 
    371 /// Called when an input device is disconnected.
    372 void OnInputDeviceDisconnected(InputBindingKey key, std::string_view identifier);
    373 
    374 /// Enables "relative" mouse mode, locking the cursor position and returning relative coordinates.
    375 void SetMouseMode(bool relative, bool hide_cursor);
    376 } // namespace Host