src/platform/qt/input/InputIndex.cpp (view raw)
1/* Copyright (c) 2013-2017 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "InputIndex.h"
7
8#include "ConfigController.h"
9
10using namespace QGBA;
11
12void InputIndex::setConfigController(ConfigController* controller) {
13 m_config = controller;
14 for (auto& item : m_items) {
15 loadShortcuts(item);
16 }
17}
18
19void InputIndex::clone(InputIndex* root, bool actions) {
20 if (!actions) {
21 clone(const_cast<const InputIndex*>(root));
22 } else {
23 qDeleteAll(m_items);
24 m_items.clear();
25 for (auto& item : root->m_items) {
26 InputItem* newItem = new InputItem(*item);
27 m_items.append(newItem);
28 itemAdded(newItem);
29 }
30 }
31 rebuild();
32}
33
34void InputIndex::clone(const InputIndex* root) {
35 qDeleteAll(m_items);
36 m_items.clear();
37 for (auto& item : root->m_items) {
38 InputItem* newItem = new InputItem(*item);
39 m_items.append(newItem);
40 itemAdded(newItem);
41 }
42 rebuild();
43}
44
45void InputIndex::rebuild(const InputIndex* root) {
46 if (!root) {
47 root = this;
48 }
49
50 m_names.clear();
51 m_menus.clear();
52 m_shortcuts.clear();
53 m_buttons.clear();
54 m_axes.clear();
55
56 for (auto& item : root->m_items) {
57 InputItem* newItem = nullptr;
58 for (auto &iter : m_items) {
59 if (*iter == *item) {
60 newItem = iter;
61 break;
62 }
63 }
64 if (!newItem) {
65 continue;
66 }
67 if (item->hasShortcut()) {
68 newItem->setShortcut(item->shortcut());
69 }
70 if (item->hasButton()) {
71 newItem->setButton(item->button());
72 }
73 if (item->hasAxis()) {
74 newItem->setAxis(item->axis(), item->direction());
75 }
76
77 itemAdded(newItem);
78 }
79}
80
81InputItem* InputIndex::itemAt(const QString& name) {
82 return m_names[name];
83}
84
85const InputItem* InputIndex::itemAt(const QString& name) const {
86 return m_names[name];
87}
88
89InputItem* InputIndex::itemForMenu(const QMenu* menu) {
90 InputItem* item = m_menus[menu];
91 return item;
92}
93
94const InputItem* InputIndex::itemForMenu(const QMenu* menu) const {
95 const InputItem* item = m_menus[menu];
96 return item;
97}
98
99InputItem* InputIndex::itemForShortcut(int shortcut) {
100 return m_shortcuts[shortcut];
101}
102
103InputItem* InputIndex::itemForButton(int button) {
104 return m_buttons[button];
105}
106
107InputItem* InputIndex::itemForAxis(int axis, GamepadAxisEvent::Direction direction) {
108 return m_axes[qMakePair(axis, direction)];
109}
110
111bool InputIndex::loadShortcuts(InputItem* item) {
112 if (item->name().isNull()) {
113 return false;
114 }
115 loadGamepadShortcuts(item);
116 QVariant shortcut = m_config->getQtOption(item->name(), KEY_SECTION);
117 if (!shortcut.isNull()) {
118 if (shortcut.toString().endsWith("+")) {
119 item->setShortcut(toModifierShortcut(shortcut.toString()));
120 } else {
121 item->setShortcut(QKeySequence(shortcut.toString())[0]);
122 }
123 return true;
124 }
125 return false;
126}
127
128void InputIndex::loadGamepadShortcuts(InputItem* item) {
129 if (item->name().isNull()) {
130 return;
131 }
132 QVariant button = m_config->getQtOption(item->name(), BUTTON_SECTION);
133 if (!button.isNull()) {
134 item->setButton(button.toInt());
135 }
136
137 QVariant axis = m_config->getQtOption(item->name(), AXIS_SECTION);
138 int oldAxis = item->axis();
139 if (oldAxis >= 0) {
140 item->setAxis(-1, GamepadAxisEvent::NEUTRAL);
141 }
142 if (!axis.isNull()) {
143 QString axisDesc = axis.toString();
144 if (axisDesc.size() >= 2) {
145 GamepadAxisEvent::Direction direction = GamepadAxisEvent::NEUTRAL;
146 if (axisDesc[0] == '-') {
147 direction = GamepadAxisEvent::NEGATIVE;
148 }
149 if (axisDesc[0] == '+') {
150 direction = GamepadAxisEvent::POSITIVE;
151 }
152 bool ok;
153 int axis = axisDesc.mid(1).toInt(&ok);
154 if (ok) {
155 item->setAxis(axis, direction);
156 }
157 }
158 }
159}
160
161int InputIndex::toModifierShortcut(const QString& shortcut) {
162 // Qt doesn't seem to work with raw modifier shortcuts!
163 QStringList modifiers = shortcut.split('+');
164 int value = 0;
165 for (const auto& mod : modifiers) {
166 if (mod == QLatin1String("Shift")) {
167 value |= Qt::ShiftModifier;
168 continue;
169 }
170 if (mod == QLatin1String("Ctrl")) {
171 value |= Qt::ControlModifier;
172 continue;
173 }
174 if (mod == QLatin1String("Alt")) {
175 value |= Qt::AltModifier;
176 continue;
177 }
178 if (mod == QLatin1String("Meta")) {
179 value |= Qt::MetaModifier;
180 continue;
181 }
182 }
183 return value;
184}
185
186void InputIndex::itemAdded(InputItem* child) {
187 const QMenu* menu = child->menu();
188 if (menu) {
189 m_menus[menu] = child;
190 }
191 m_names[child->name()] = child;
192
193 if (child->shortcut() > 0) {
194 m_shortcuts[child->shortcut()] = child;
195 }
196 if (child->button() >= 0) {
197 m_buttons[child->button()] = child;
198 }
199 if (child->direction() != GamepadAxisEvent::NEUTRAL) {
200 m_axes[qMakePair(child->axis(), child->direction())] = child;
201 }
202}
203
204bool InputIndex::isModifierKey(int key) {
205 switch (key) {
206 case Qt::Key_Shift:
207 case Qt::Key_Control:
208 case Qt::Key_Alt:
209 case Qt::Key_Meta:
210 return true;
211 default:
212 return false;
213 }
214}
215
216int InputIndex::toModifierKey(int key) {
217 int modifiers = key & (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier);
218 key ^= modifiers;
219 switch (key) {
220 case Qt::Key_Shift:
221 modifiers |= Qt::ShiftModifier;
222 break;
223 case Qt::Key_Control:
224 modifiers |= Qt::ControlModifier;
225 break;
226 case Qt::Key_Alt:
227 modifiers |= Qt::AltModifier;
228 break;
229 case Qt::Key_Meta:
230 modifiers |= Qt::MetaModifier;
231 break;
232 default:
233 break;
234 }
235 return modifiers;
236}
237
238void InputIndex::saveConfig() {
239 for (auto& item : m_items) {
240 if (item->hasShortcut()) {
241 m_config->setQtOption(item->name(), QKeySequence(item->shortcut()).toString(), KEY_SECTION);
242 }
243 if (item->hasButton()) {
244 m_config->setQtOption(item->name(), item->button(), BUTTON_SECTION);
245 }
246 if (item->hasAxis()) {
247 m_config->setQtOption(item->name(), QString("%1%2").arg(GamepadAxisEvent::POSITIVE ? '+' : '-').arg(item->axis()), AXIS_SECTION);
248 }
249 }
250}