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