summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Zach Hilman2018-11-01 22:07:46 -0400
committerGravatar Zach Hilman2018-11-18 23:22:36 -0500
commit2e1dd9c64939a1af43d0a77c63340e88d19f7e61 (patch)
treebd54a5dad907a43bdd77d67c4b117aaa1b54715d /src
parentconfigure_input: Add support for multiplayer and controller types (diff)
downloadyuzu-2e1dd9c64939a1af43d0a77c63340e88d19f7e61.tar.gz
yuzu-2e1dd9c64939a1af43d0a77c63340e88d19f7e61.tar.xz
yuzu-2e1dd9c64939a1af43d0a77c63340e88d19f7e61.zip
qt: Add UI to configure mouse buttons
Supports setting the five mouse buttons to any valid controller button/keyboard key (Left, Right, Middle, Foward, Back)
Diffstat (limited to 'src')
-rw-r--r--src/yuzu/CMakeLists.txt3
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp211
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.h67
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.ui261
4 files changed, 542 insertions, 0 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index f9ca2948e..36714f55e 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -27,6 +27,8 @@ add_executable(yuzu
27 configuration/configure_graphics.h 27 configuration/configure_graphics.h
28 configuration/configure_input.cpp 28 configuration/configure_input.cpp
29 configuration/configure_input.h 29 configuration/configure_input.h
30 configuration/configure_mouse_advanced.cpp
31 configuration/configure_mouse_advanced.h
30 configuration/configure_system.cpp 32 configuration/configure_system.cpp
31 configuration/configure_system.h 33 configuration/configure_system.h
32 configuration/configure_web.cpp 34 configuration/configure_web.cpp
@@ -76,6 +78,7 @@ set(UIS
76 configuration/configure_general.ui 78 configuration/configure_general.ui
77 configuration/configure_graphics.ui 79 configuration/configure_graphics.ui
78 configuration/configure_input.ui 80 configuration/configure_input.ui
81 configuration/configure_mouse_advanced.ui
79 configuration/configure_system.ui 82 configuration/configure_system.ui
80 configuration/configure_web.ui 83 configuration/configure_web.ui
81 hotkeys.ui 84 hotkeys.ui
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
new file mode 100644
index 000000000..8cfcd1679
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -0,0 +1,211 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <memory>
7#include <utility>
8#include <QKeyEvent>
9#include <QMenu>
10#include <QMessageBox>
11#include <QTimer>
12#include "common/assert.h"
13#include "common/param_package.h"
14#include "input_common/main.h"
15#include "ui_configure_mouse_advanced.h"
16#include "yuzu/configuration/config.h"
17#include "yuzu/configuration/configure_mouse_advanced.h"
18
19static QString getKeyName(int key_code) {
20 switch (key_code) {
21 case Qt::Key_Shift:
22 return QObject::tr("Shift");
23 case Qt::Key_Control:
24 return QObject::tr("Ctrl");
25 case Qt::Key_Alt:
26 return QObject::tr("Alt");
27 case Qt::Key_Meta:
28 return "";
29 default:
30 return QKeySequence(key_code).toString();
31 }
32}
33
34static QString ButtonToText(const Common::ParamPackage& param) {
35 if (!param.Has("engine")) {
36 return QObject::tr("[not set]");
37 } else if (param.Get("engine", "") == "keyboard") {
38 return getKeyName(param.Get("code", 0));
39 } else if (param.Get("engine", "") == "sdl") {
40 if (param.Has("hat")) {
41 return QString(QObject::tr("Hat %1 %2"))
42 .arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
43 }
44 if (param.Has("axis")) {
45 return QString(QObject::tr("Axis %1%2"))
46 .arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
47 }
48 if (param.Has("button")) {
49 return QString(QObject::tr("Button %1")).arg(param.Get("button", "").c_str());
50 }
51 return QString();
52 } else {
53 return QObject::tr("[unknown]");
54 }
55}
56
57ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
58 : QDialog(parent), ui(std::make_unique<Ui::ConfigureMouseAdvanced>()),
59 timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
60 ui->setupUi(this);
61 setFocusPolicy(Qt::ClickFocus);
62
63 button_map = {
64 ui->left_button, ui->right_button, ui->middle_button, ui->forward_button, ui->back_button,
65 };
66
67 for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
68 if (!button_map[button_id])
69 continue;
70 button_map[button_id]->setContextMenuPolicy(Qt::CustomContextMenu);
71 connect(button_map[button_id], &QPushButton::released, [=]() {
72 handleClick(
73 button_map[button_id],
74 [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
75 InputCommon::Polling::DeviceType::Button);
76 });
77 connect(button_map[button_id], &QPushButton::customContextMenuRequested,
78 [=](const QPoint& menu_location) {
79 QMenu context_menu;
80 context_menu.addAction(tr("Clear"), [&] {
81 buttons_param[button_id].Clear();
82 button_map[button_id]->setText(tr("[not set]"));
83 });
84 context_menu.addAction(tr("Restore Default"), [&] {
85 buttons_param[button_id] =
86 Common::ParamPackage{InputCommon::GenerateKeyboardParam(
87 Config::default_mouse_buttons[button_id])};
88 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
89 });
90 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
91 });
92 }
93
94 connect(ui->buttonClearAll, &QPushButton::released, [this] { ClearAll(); });
95 connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
96
97 timeout_timer->setSingleShot(true);
98 connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
99
100 connect(poll_timer.get(), &QTimer::timeout, [this]() {
101 Common::ParamPackage params;
102 for (auto& poller : device_pollers) {
103 params = poller->GetNextInput();
104 if (params.Has("engine")) {
105 setPollingResult(params, false);
106 return;
107 }
108 }
109 });
110
111 loadConfiguration();
112 resize(0, 0);
113}
114
115void ConfigureMouseAdvanced::applyConfiguration() {
116 std::transform(buttons_param.begin(), buttons_param.end(),
117 Settings::values.mouse_buttons.begin(),
118 [](const Common::ParamPackage& param) { return param.Serialize(); });
119}
120
121void ConfigureMouseAdvanced::loadConfiguration() {
122 std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
123 buttons_param.begin(),
124 [](const std::string& str) { return Common::ParamPackage(str); });
125 updateButtonLabels();
126}
127
128void ConfigureMouseAdvanced::restoreDefaults() {
129 for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) {
130 buttons_param[button_id] = Common::ParamPackage{
131 InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
132 }
133
134 updateButtonLabels();
135}
136
137void ConfigureMouseAdvanced::ClearAll() {
138 for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
139 if (button_map[i] && button_map[i]->isEnabled())
140 buttons_param[i].Clear();
141 }
142
143 updateButtonLabels();
144}
145
146void ConfigureMouseAdvanced::updateButtonLabels() {
147 for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) {
148 button_map[button]->setText(ButtonToText(buttons_param[button]));
149 }
150}
151
152void ConfigureMouseAdvanced::handleClick(
153 QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
154 InputCommon::Polling::DeviceType type) {
155 button->setText(tr("[press key]"));
156 button->setFocus();
157
158 const auto iter = std::find(button_map.begin(), button_map.end(), button);
159 ASSERT(iter != button_map.end());
160 const auto index = std::distance(button_map.begin(), iter);
161 ASSERT(index < Settings::NativeButton::NumButtons && index >= 0);
162
163 input_setter = new_input_setter;
164
165 device_pollers = InputCommon::Polling::GetPollers(type);
166
167 // Keyboard keys can only be used as button devices
168 want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
169
170 for (auto& poller : device_pollers) {
171 poller->Start();
172 }
173
174 grabKeyboard();
175 grabMouse();
176 timeout_timer->start(5000); // Cancel after 5 seconds
177 poll_timer->start(200); // Check for new inputs every 200ms
178}
179
180void ConfigureMouseAdvanced::setPollingResult(const Common::ParamPackage& params, bool abort) {
181 releaseKeyboard();
182 releaseMouse();
183 timeout_timer->stop();
184 poll_timer->stop();
185 for (auto& poller : device_pollers) {
186 poller->Stop();
187 }
188
189 if (!abort) {
190 (*input_setter)(params);
191 }
192
193 updateButtonLabels();
194 input_setter = boost::none;
195}
196
197void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
198 if (!input_setter || !event)
199 return;
200
201 if (event->key() != Qt::Key_Escape) {
202 if (want_keyboard_keys) {
203 setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
204 false);
205 } else {
206 // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
207 return;
208 }
209 }
210 setPollingResult({}, true);
211}
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h
new file mode 100644
index 000000000..f897d9044
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.h
@@ -0,0 +1,67 @@
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 <memory>
8#include <QDialog>
9#include <QWidget>
10#include <boost/optional.hpp>
11#include "core/settings.h"
12
13class QCheckBox;
14class QPushButton;
15class QTimer;
16
17namespace Ui {
18class ConfigureMouseAdvanced;
19}
20
21class ConfigureMouseAdvanced : public QDialog {
22 Q_OBJECT
23
24public:
25 explicit ConfigureMouseAdvanced(QWidget* parent);
26
27 void applyConfiguration();
28
29private:
30 std::unique_ptr<Ui::ConfigureMouseAdvanced> ui;
31
32 /// This will be the the setting function when an input is awaiting configuration.
33 boost::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
34
35 std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map;
36 std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param;
37
38 std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
39
40 std::unique_ptr<QTimer> timeout_timer;
41 std::unique_ptr<QTimer> poll_timer;
42
43 /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
44 /// keyboard events are ignored.
45 bool want_keyboard_keys = false;
46
47 /// Load configuration settings.
48 void loadConfiguration();
49 /// Restore all buttons to their default values.
50 void restoreDefaults();
51 /// Clear all input configuration
52 void ClearAll();
53
54 /// Update UI to reflect current configuration.
55 void updateButtonLabels();
56
57 /// Called when the button was pressed.
58 void handleClick(QPushButton* button,
59 std::function<void(const Common::ParamPackage&)> new_input_setter,
60 InputCommon::Polling::DeviceType type);
61
62 /// Finish polling and configure input using the input_setter
63 void setPollingResult(const Common::ParamPackage& params, bool abort);
64
65 /// Handle key press events.
66 void keyPressEvent(QKeyEvent* event) override;
67};
diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui
new file mode 100644
index 000000000..08245ecf0
--- /dev/null
+++ b/src/yuzu/configuration/configure_mouse_advanced.ui
@@ -0,0 +1,261 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<ui version="4.0">
3 <class>ConfigureMouseAdvanced</class>
4 <widget class="QDialog" name="ConfigureMouseAdvanced">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>250</width>
10 <height>261</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Configure Mouse</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
18 <widget class="QGroupBox" name="gridGroupBox">
19 <property name="title">
20 <string>Mouse Buttons</string>
21 </property>
22 <layout class="QGridLayout" name="gridLayout">
23 <item row="0" column="4">
24 <spacer name="horizontalSpacer_2">
25 <property name="orientation">
26 <enum>Qt::Horizontal</enum>
27 </property>
28 <property name="sizeType">
29 <enum>QSizePolicy::Fixed</enum>
30 </property>
31 <property name="sizeHint" stdset="0">
32 <size>
33 <width>20</width>
34 <height>20</height>
35 </size>
36 </property>
37 </spacer>
38 </item>
39 <item row="0" column="3">
40 <layout class="QVBoxLayout" name="verticalLayout_4">
41 <item>
42 <layout class="QHBoxLayout" name="horizontalLayout_3">
43 <item>
44 <widget class="QLabel" name="label_3">
45 <property name="text">
46 <string>Right:</string>
47 </property>
48 </widget>
49 </item>
50 </layout>
51 </item>
52 <item>
53 <widget class="QPushButton" name="right_button">
54 <property name="minimumSize">
55 <size>
56 <width>75</width>
57 <height>0</height>
58 </size>
59 </property>
60 <property name="text">
61 <string/>
62 </property>
63 </widget>
64 </item>
65 </layout>
66 </item>
67 <item row="0" column="0">
68 <spacer name="horizontalSpacer">
69 <property name="orientation">
70 <enum>Qt::Horizontal</enum>
71 </property>
72 <property name="sizeType">
73 <enum>QSizePolicy::Fixed</enum>
74 </property>
75 <property name="sizeHint" stdset="0">
76 <size>
77 <width>20</width>
78 <height>20</height>
79 </size>
80 </property>
81 </spacer>
82 </item>
83 <item row="2" column="1">
84 <layout class="QVBoxLayout" name="verticalLayout_3">
85 <item>
86 <layout class="QHBoxLayout" name="horizontalLayout_2">
87 <item>
88 <widget class="QLabel" name="label_2">
89 <property name="text">
90 <string>Middle:</string>
91 </property>
92 </widget>
93 </item>
94 </layout>
95 </item>
96 <item>
97 <widget class="QPushButton" name="middle_button">
98 <property name="text">
99 <string/>
100 </property>
101 </widget>
102 </item>
103 </layout>
104 </item>
105 <item row="3" column="1">
106 <layout class="QVBoxLayout" name="verticalLayout_5">
107 <item>
108 <layout class="QHBoxLayout" name="horizontalLayout_4">
109 <item>
110 <widget class="QLabel" name="label_4">
111 <property name="minimumSize">
112 <size>
113 <width>54</width>
114 <height>0</height>
115 </size>
116 </property>
117 <property name="text">
118 <string>Back:</string>
119 </property>
120 </widget>
121 </item>
122 </layout>
123 </item>
124 <item>
125 <widget class="QPushButton" name="back_button">
126 <property name="text">
127 <string/>
128 </property>
129 </widget>
130 </item>
131 </layout>
132 </item>
133 <item row="0" column="1">
134 <layout class="QVBoxLayout" name="verticalLayout_2">
135 <item>
136 <layout class="QHBoxLayout" name="horizontalLayout">
137 <item>
138 <widget class="QLabel" name="label">
139 <property name="text">
140 <string>Left:</string>
141 </property>
142 </widget>
143 </item>
144 </layout>
145 </item>
146 <item>
147 <widget class="QPushButton" name="left_button">
148 <property name="minimumSize">
149 <size>
150 <width>75</width>
151 <height>0</height>
152 </size>
153 </property>
154 <property name="text">
155 <string/>
156 </property>
157 </widget>
158 </item>
159 </layout>
160 </item>
161 <item row="3" column="3">
162 <layout class="QVBoxLayout" name="verticalLayout_6">
163 <item>
164 <layout class="QHBoxLayout" name="horizontalLayout_5">
165 <item>
166 <widget class="QLabel" name="label_5">
167 <property name="text">
168 <string>Forward:</string>
169 </property>
170 </widget>
171 </item>
172 </layout>
173 </item>
174 <item>
175 <widget class="QPushButton" name="forward_button">
176 <property name="text">
177 <string/>
178 </property>
179 </widget>
180 </item>
181 </layout>
182 </item>
183 </layout>
184 </widget>
185 </item>
186 <item>
187 <layout class="QHBoxLayout" name="horizontalLayout_6">
188 <item>
189 <widget class="QPushButton" name="buttonClearAll">
190 <property name="text">
191 <string>Clear All</string>
192 </property>
193 </widget>
194 </item>
195 <item>
196 <widget class="QPushButton" name="buttonRestoreDefaults">
197 <property name="text">
198 <string>Restore Defaults</string>
199 </property>
200 </widget>
201 </item>
202 <item>
203 <spacer name="horizontalSpacer_3">
204 <property name="orientation">
205 <enum>Qt::Horizontal</enum>
206 </property>
207 <property name="sizeHint" stdset="0">
208 <size>
209 <width>40</width>
210 <height>20</height>
211 </size>
212 </property>
213 </spacer>
214 </item>
215 </layout>
216 </item>
217 <item>
218 <widget class="QDialogButtonBox" name="buttonBox">
219 <property name="standardButtons">
220 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
221 </property>
222 </widget>
223 </item>
224 </layout>
225 </widget>
226 <resources/>
227 <connections>
228 <connection>
229 <sender>buttonBox</sender>
230 <signal>accepted()</signal>
231 <receiver>ConfigureMouseAdvanced</receiver>
232 <slot>accept()</slot>
233 <hints>
234 <hint type="sourcelabel">
235 <x>124</x>
236 <y>266</y>
237 </hint>
238 <hint type="destinationlabel">
239 <x>124</x>
240 <y>143</y>
241 </hint>
242 </hints>
243 </connection>
244 <connection>
245 <sender>buttonBox</sender>
246 <signal>rejected()</signal>
247 <receiver>ConfigureMouseAdvanced</receiver>
248 <slot>reject()</slot>
249 <hints>
250 <hint type="sourcelabel">
251 <x>124</x>
252 <y>266</y>
253 </hint>
254 <hint type="destinationlabel">
255 <x>124</x>
256 <y>143</y>
257 </hint>
258 </hints>
259 </connection>
260 </connections>
261</ui>