1 // Copyright 2016 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <array> 8 #include <functional> 9 #include <memory> 10 #include <optional> 11 #include <string> 12 #include <vector> 13 14 #include <QWidget> 15 16 #include "common/param_package.h" 17 #include "core/settings.h" 18 #include "ui_configure_input.h" 19 20 class QCheckBox; 21 class QKeyEvent; 22 class QLabel; 23 class QPushButton; 24 class QSlider; 25 class QSpinBox; 26 class QString; 27 class QTimer; 28 class QWidget; 29 30 class InputProfiles; 31 32 namespace InputCommon { 33 class InputSubsystem; 34 } 35 36 namespace InputCommon::Polling { 37 class DevicePoller; 38 enum class DeviceType; 39 } // namespace InputCommon::Polling 40 41 namespace Ui { 42 class ConfigureInputPlayer; 43 } 44 45 class ConfigureInputPlayer : public QWidget { 46 Q_OBJECT 47 48 public: 49 explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, 50 InputCommon::InputSubsystem* input_subsystem_, 51 InputProfiles* profiles_, bool debug = false); 52 ~ConfigureInputPlayer() override; 53 54 /// Save all button configurations to settings file. 55 void ApplyConfiguration(); 56 57 /// Set the connection state checkbox (used to sync state). 58 void ConnectPlayer(bool connected); 59 60 /// Update the input devices combobox. 61 void UpdateInputDeviceCombobox(); 62 63 /// Updates the list of controller profiles. 64 void UpdateInputProfiles(); 65 66 /// Restore all buttons to their default values. 67 void RestoreDefaults(); 68 69 /// Clear all input configuration. 70 void ClearAll(); 71 72 signals: 73 /// Emitted when this controller is connected by the user. 74 void Connected(bool connected); 75 /// Emitted when the Handheld mode is selected (undocked with dual joycons attached). 76 void HandheldStateChanged(bool is_handheld); 77 /// Emitted when the input devices combobox is being refreshed. 78 void RefreshInputDevices(); 79 /** 80 * Emitted when the input profiles combobox is being refreshed. 81 * The player_index represents the current player's index, and the profile combobox 82 * will not be updated for this index as they are already updated by other mechanisms. 83 */ 84 void RefreshInputProfiles(std::size_t player_index); 85 86 protected: 87 void showEvent(QShowEvent* event) override; 88 89 private: 90 void changeEvent(QEvent* event) override; 91 void RetranslateUI(); 92 93 /// Load configuration settings. 94 void LoadConfiguration(); 95 96 /// Called when the button was pressed. 97 void HandleClick(QPushButton* button, 98 std::function<void(const Common::ParamPackage&)> new_input_setter, 99 InputCommon::Polling::DeviceType type); 100 101 /// Finish polling and configure input using the input_setter. 102 void SetPollingResult(const Common::ParamPackage& params, bool abort); 103 104 /// Checks whether a given input can be accepted. 105 bool IsInputAcceptable(const Common::ParamPackage& params) const; 106 107 /// Handle mouse button press events. 108 void mousePressEvent(QMouseEvent* event) override; 109 110 /// Handle key press events. 111 void keyPressEvent(QKeyEvent* event) override; 112 113 /// Update UI to reflect current configuration. 114 void UpdateUI(); 115 116 /// Sets the available controllers. 117 void SetConnectableControllers(); 118 119 /// Gets the Controller Type for a given controller combobox index. 120 Settings::ControllerType GetControllerTypeFromIndex(int index) const; 121 122 /// Gets the controller combobox index for a given Controller Type. 123 int GetIndexFromControllerType(Settings::ControllerType type) const; 124 125 /// Update the available input devices. 126 void UpdateInputDevices(); 127 128 /// Update the current controller icon. 129 void UpdateControllerIcon(); 130 131 /// Hides and disables controller settings based on the current controller type. 132 void UpdateControllerAvailableButtons(); 133 134 /// Shows or hides motion groupboxes based on the current controller type. 135 void UpdateMotionButtons(); 136 137 /// Gets the default controller mapping for this device and auto configures the input to match. 138 void UpdateMappingWithDefaults(); 139 140 /// Creates a controller profile. 141 void CreateProfile(); 142 143 /// Deletes the selected controller profile. 144 void DeleteProfile(); 145 146 /// Loads the selected controller profile. 147 void LoadProfile(); 148 149 /// Saves the current controller configuration into a selected controller profile. 150 void SaveProfile(); 151 152 std::unique_ptr<Ui::ConfigureInputPlayer> ui; 153 154 std::size_t player_index; 155 bool debug; 156 157 InputCommon::InputSubsystem* input_subsystem; 158 159 InputProfiles* profiles; 160 161 std::unique_ptr<QTimer> timeout_timer; 162 std::unique_ptr<QTimer> poll_timer; 163 164 /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. 165 std::vector<std::pair<int, Settings::ControllerType>> index_controller_type_pairs; 166 167 static constexpr int PLAYER_COUNT = 8; 168 std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox; 169 170 /// This will be the the setting function when an input is awaiting configuration. 171 std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; 172 173 std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param; 174 std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param; 175 std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions> motions_param; 176 177 static constexpr int ANALOG_SUB_BUTTONS_NUM = 4; 178 179 /// Each button input is represented by a QPushButton. 180 std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map; 181 182 /// A group of four QPushButtons represent one analog input. The buttons each represent up, 183 /// down, left, right, respectively. 184 std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> 185 analog_map_buttons; 186 187 /// Each motion input is represented by a QPushButton. 188 std::array<QPushButton*, Settings::NativeMotion::NumMotions> motion_map; 189 190 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label; 191 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_slider; 192 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_groupbox; 193 std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_button; 194 std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_label; 195 std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_slider; 196 std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_groupbox; 197 std::array<QSpinBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_spinbox; 198 199 static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; 200 201 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; 202 203 /// A flag to indicate that the "Map Analog Stick" pop-up has been shown and accepted once. 204 bool map_analog_stick_accepted{}; 205 206 /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, 207 /// keyboard events are ignored. 208 bool want_keyboard_mouse{}; 209 210 /// List of physical devices users can map with. If a SDL backed device is selected, then you 211 /// can use this device to get a default mapping. 212 std::vector<Common::ParamPackage> input_devices; 213 214 /// Bottom row is where console wide settings are held, and its "owned" by the parent 215 /// ConfigureInput widget. On show, add this widget to the main layout. This will change the 216 /// parent of the widget to this widget (but thats fine). 217 QWidget* bottom_row; 218 }; 219