1 /***************************************************************************
2 * *
3 * This program is free software; you can redistribute it and/or modify *
4 * it under the terms of the GNU General Public License as published by *
5 * the Free Software Foundation; either version 3 of the License, or *
6 * (at your option) any later version. *
7 * *
8 ***************************************************************************/
9
10
11 #include "ShortcutGetter.h"
12
13 #include <QLayout>
14 #include <QHash>
15 #include <QLabel>
16 #include <QString>
17 #include <QShortcut>
18 #include <QLineEdit>
19 #include <QKeyEvent>
20 #include <QPushButton>
21 #include <QDialogButtonBox>
22
23 static QHash<int, const char*> keyMap;
24
initKeyMap()25 static void initKeyMap()
26 {
27 if ( !keyMap.isEmpty() )
28 return;
29
30 /*
31 I'm a bit unsure about these one...
32 */
33 keyMap[Qt::Key_Escape] = "Escape";
34 keyMap[Qt::Key_Return] = "Return";
35 keyMap[Qt::Key_Enter] = "Enter";
36 keyMap[Qt::Key_Insert] = "Ins";
37 keyMap[Qt::Key_Delete] = "Delete";
38 keyMap[Qt::Key_Home] = "Home";
39 keyMap[Qt::Key_End] = "End";
40 keyMap[Qt::Key_Left] = "Left";
41 keyMap[Qt::Key_Up] = "Up";
42 keyMap[Qt::Key_Right] = "Right";
43 keyMap[Qt::Key_Down] = "Down";
44 keyMap[Qt::Key_PageUp] = "PgUp";
45 keyMap[Qt::Key_PageDown] = "PgDown";
46 keyMap[Qt::Key_CapsLock] = "CapsLock";
47 keyMap[Qt::Key_NumLock] = "NumLock";
48 keyMap[Qt::Key_ScrollLock] = "ScrollLock";
49
50 /*
51 These one are quite sure...
52 */
53 keyMap[Qt::Key_F1] = "F1";
54 keyMap[Qt::Key_F2] = "F2";
55 keyMap[Qt::Key_F3] = "F3";
56 keyMap[Qt::Key_F4] = "F4";
57 keyMap[Qt::Key_F5] = "F5";
58 keyMap[Qt::Key_F6] = "F6";
59 keyMap[Qt::Key_F7] = "F7";
60 keyMap[Qt::Key_F8] = "F8";
61 keyMap[Qt::Key_F9] = "F9";
62 keyMap[Qt::Key_F10] = "F10";
63 keyMap[Qt::Key_F11] = "F11";
64 keyMap[Qt::Key_F12] = "F12";
65 keyMap[Qt::Key_F13] = "F13";
66 keyMap[Qt::Key_F14] = "F14";
67 keyMap[Qt::Key_F15] = "F15";
68 keyMap[Qt::Key_F16] = "F16";
69 keyMap[Qt::Key_F17] = "F17";
70 keyMap[Qt::Key_F18] = "F18";
71 keyMap[Qt::Key_F19] = "F19";
72 keyMap[Qt::Key_F20] = "F20";
73 keyMap[Qt::Key_F21] = "F21";
74 keyMap[Qt::Key_F22] = "F22";
75 keyMap[Qt::Key_F23] = "F23";
76 keyMap[Qt::Key_F24] = "F24";
77 keyMap[Qt::Key_F25] = "F25";
78 keyMap[Qt::Key_F26] = "F26";
79 keyMap[Qt::Key_F27] = "F27";
80 keyMap[Qt::Key_F28] = "F28";
81 keyMap[Qt::Key_F29] = "F29";
82 keyMap[Qt::Key_F30] = "F30";
83 keyMap[Qt::Key_F31] = "F31";
84 keyMap[Qt::Key_F32] = "F32";
85 keyMap[Qt::Key_F33] = "F33";
86 keyMap[Qt::Key_F34] = "F34";
87 keyMap[Qt::Key_F35] = "F35";
88
89 keyMap[Qt::Key_Exclam] = "!";
90 keyMap[Qt::Key_QuoteDbl] = "\"";
91 keyMap[Qt::Key_NumberSign] = "-";
92 keyMap[Qt::Key_Dollar] = "$";
93 keyMap[Qt::Key_Percent] = "%";
94 keyMap[Qt::Key_Ampersand] = "&";
95 keyMap[Qt::Key_Apostrophe] = "\'";
96 keyMap[Qt::Key_ParenLeft] = "(";
97 keyMap[Qt::Key_ParenRight] = ")";
98 keyMap[Qt::Key_Asterisk] = "*";
99 keyMap[Qt::Key_Plus] = "+";
100 keyMap[Qt::Key_Comma] = ",";
101 keyMap[Qt::Key_Minus] = "-";
102 keyMap[Qt::Key_Period] = "Period";
103 keyMap[Qt::Key_Slash] = "/";
104
105 keyMap[Qt::Key_0] = "0";
106 keyMap[Qt::Key_1] = "1";
107 keyMap[Qt::Key_2] = "2";
108 keyMap[Qt::Key_3] = "3";
109 keyMap[Qt::Key_4] = "4";
110 keyMap[Qt::Key_5] = "5";
111 keyMap[Qt::Key_6] = "6";
112 keyMap[Qt::Key_7] = "7";
113 keyMap[Qt::Key_8] = "8";
114 keyMap[Qt::Key_9] = "9";
115
116 keyMap[Qt::Key_Colon] = ":";
117 keyMap[Qt::Key_Semicolon] = ";";
118 keyMap[Qt::Key_Less] = "<";
119 keyMap[Qt::Key_Equal] = "=";
120 keyMap[Qt::Key_Greater] = ">";
121 keyMap[Qt::Key_Question] = "?";
122 keyMap[Qt::Key_At] = "@";
123
124 keyMap[Qt::Key_A] = "A";
125 keyMap[Qt::Key_B] = "B";
126 keyMap[Qt::Key_C] = "C";
127 keyMap[Qt::Key_D] = "D";
128 keyMap[Qt::Key_E] = "E";
129 keyMap[Qt::Key_F] = "F";
130 keyMap[Qt::Key_G] = "G";
131 keyMap[Qt::Key_H] = "H";
132 keyMap[Qt::Key_I] = "I";
133 keyMap[Qt::Key_J] = "J";
134 keyMap[Qt::Key_K] = "K";
135 keyMap[Qt::Key_L] = "L";
136 keyMap[Qt::Key_M] = "M";
137 keyMap[Qt::Key_N] = "N";
138 keyMap[Qt::Key_O] = "O";
139 keyMap[Qt::Key_P] = "P";
140 keyMap[Qt::Key_Q] = "Q";
141 keyMap[Qt::Key_R] = "R";
142 keyMap[Qt::Key_S] = "S";
143 keyMap[Qt::Key_T] = "T";
144 keyMap[Qt::Key_U] = "U";
145 keyMap[Qt::Key_V] = "V";
146 keyMap[Qt::Key_W] = "W";
147 keyMap[Qt::Key_X] = "X";
148 keyMap[Qt::Key_Y] = "Y";
149 keyMap[Qt::Key_Z] = "Z";
150
151 keyMap[Qt::Key_BracketLeft] = "[";
152 keyMap[Qt::Key_Backslash] = "\\";
153 keyMap[Qt::Key_BracketRight] = "]";
154
155 keyMap[Qt::Key_Underscore] = "_";
156 keyMap[Qt::Key_BraceLeft] = "{";
157 keyMap[Qt::Key_Bar] = "|";
158 keyMap[Qt::Key_BraceRight] = "}";
159 keyMap[Qt::Key_AsciiTilde] = "~";
160
161 // Added by rvm:
162 keyMap[Qt::Key_Space] = "Space";
163 keyMap[Qt::Key_Backspace] = "Backspace";
164 keyMap[Qt::Key_MediaPlay] = "Media Play";
165 keyMap[Qt::Key_MediaStop] = "Media Stop";
166 keyMap[Qt::Key_MediaPrevious] = "Media Previous";
167 keyMap[Qt::Key_MediaNext] = "Media Next";
168 keyMap[Qt::Key_MediaRecord] = "Media Record";
169 keyMap[Qt::Key_MediaLast] = "Media Last"; // doesn't work?
170 keyMap[Qt::Key_VolumeUp] = "Volume Up";
171 keyMap[Qt::Key_VolumeDown] = "Volume Down";
172 keyMap[Qt::Key_VolumeMute] = "Volume Mute";
173 keyMap[Qt::Key_Back] = "Back";
174 keyMap[Qt::Key_Forward] = "Forward";
175 keyMap[Qt::Key_Stop] = "Stop";
176 }
177
keyToString(int k)178 static QString keyToString(int k)
179 {
180 if ( k == Qt::Key_Shift || k == Qt::Key_Control || k == Qt::Key_Meta ||
181 k == Qt::Key_Alt || k == Qt::Key_AltGr )
182 return QString::null;
183
184 initKeyMap();
185
186 return keyMap[k];
187 }
188
modToString(Qt::KeyboardModifiers k)189 static QStringList modToString(Qt::KeyboardModifiers k)
190 {
191 //qDebug("modToString: k: %x", (int) k);
192
193 QStringList l;
194
195 if ( k & Qt::ShiftModifier )
196 l << "Shift";
197 if ( k & Qt::ControlModifier )
198 l << "Ctrl";
199 if ( k & Qt::AltModifier )
200 l << "Alt";
201 if ( k & Qt::MetaModifier )
202 l << "Meta";
203 if ( k & Qt::GroupSwitchModifier )
204 ;
205 if ( k & Qt::KeypadModifier )
206 ;
207
208 return l;
209 }
210
211
ShortcutGetter(QWidget * parent)212 ShortcutGetter::ShortcutGetter(QWidget *parent) : QDialog(parent)
213 {
214 setWindowTitle(tr("Modify shortcut"));
215
216
217 QVBoxLayout *vbox = new QVBoxLayout(this);
218 vbox->setMargin(2);
219 vbox->setSpacing(4);
220
221 QLabel *l = new QLabel(this);
222 l->setText(tr("Press the key combination you want to assign"));
223 vbox->addWidget(l);
224
225 leKey = new QLineEdit(this);
226
227 leKey->installEventFilter(this);
228 vbox->addWidget(leKey);
229
230 // Change by rvm: use a QDialogButtonBox instead of QPushButtons
231 // and add a clear button
232 setCaptureKeyboard(true);
233 QDialogButtonBox * buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok |
234 QDialogButtonBox::Cancel |
235 QDialogButtonBox::Reset );
236 QPushButton * clearbutton = buttonbox->button(QDialogButtonBox::Reset);
237 clearbutton->setText( tr("Clear") );
238
239 QPushButton * captureButton = new QPushButton(tr("Capture"), this);
240 captureButton->setToolTip( tr("Capture keystrokes") );
241 captureButton->setCheckable( captureKeyboard() );
242 captureButton->setChecked( captureKeyboard() );
243 connect(captureButton, SIGNAL(toggled(bool)),
244 this, SLOT(setCaptureKeyboard(bool)));
245
246
247 buttonbox->addButton(captureButton, QDialogButtonBox::ActionRole);
248
249 connect( buttonbox, SIGNAL(accepted()), this, SLOT(accept()) );
250 connect( buttonbox, SIGNAL(rejected()), this, SLOT(reject()) );
251 connect( clearbutton, SIGNAL(clicked()), leKey, SLOT(clear()) );
252 vbox->addWidget(buttonbox);
253 }
254
setCaptureKeyboard(bool b)255 void ShortcutGetter::setCaptureKeyboard(bool b) {
256 capture = b;
257 leKey->setReadOnly(b);
258 leKey->setFocus();
259 }
260
261
exec(const QString & s)262 QString ShortcutGetter::exec(const QString& s)
263 {
264 bStop = false;
265 leKey->setText(s);
266
267 if ( QDialog::exec() == QDialog::Accepted )
268 return leKey->text();
269
270 return QString();
271 }
272
event(QEvent * e)273 bool ShortcutGetter::event(QEvent *e)
274 {
275 if (!capture) return QDialog::event(e);
276
277
278 QString key;
279 QStringList mods;
280 QKeyEvent *k = static_cast<QKeyEvent*>(e);
281
282 switch ( e->type() )
283 {
284 case QEvent::KeyPress :
285
286 if ( bStop )
287 {
288 lKeys.clear();
289 bStop = false;
290 }
291
292 key = keyToString(k->key());
293 mods = modToString(k->modifiers());
294
295 //qDebug("event: key.count: %d, mods.count: %d", key.count(), mods.count());
296
297 if ( key.count() || mods.count() )
298 {
299
300 if ( key.count() && !lKeys.contains(key) )
301 lKeys << key;
302
303 for ( const auto &key : mods ) {
304 if ( !lKeys.contains(key) )
305 lKeys << key;
306 }
307 } else {
308 key = k->text();
309
310 if ( !lKeys.contains(key) )
311 lKeys << key;
312 }
313
314 setText();
315 break;
316
317 case QEvent::KeyRelease :
318
319 bStop = true;
320 break;
321
322 /*
323 case QEvent::ShortcutOverride :
324 leKey->setText("Shortcut override");
325 break;
326 */
327
328 default:
329 return QDialog::event(e);
330 break;
331 }
332
333 return true;
334 }
335
eventFilter(QObject * o,QEvent * e)336 bool ShortcutGetter::eventFilter(QObject *o, QEvent *e)
337 {
338 if (!capture) return QDialog::eventFilter(o, e);
339
340 if ( e->type() == QEvent::KeyPress ||
341 e->type() ==QEvent::KeyRelease )
342 return event(e);
343 else
344 return QDialog::eventFilter(o, e);
345 }
346
setText()347 void ShortcutGetter::setText()
348 {
349 QStringList seq;
350
351 if ( lKeys.contains("Shift") )
352 seq << "Shift";
353
354 if ( lKeys.contains("Ctrl") )
355 seq << "Ctrl";
356
357 if ( lKeys.contains("Alt") )
358 seq << "Alt";
359
360 if ( lKeys.contains("Meta") )
361 seq << "Meta";
362
363 for (const QString &s : lKeys ) {
364 //qDebug("setText: s: '%s'", s.toUtf8().data());
365 if ( s != "Shift" && s != "Ctrl"
366 && s != "Alt" && s != "Meta" )
367 seq << s;
368 }
369
370 leKey->setText(seq.join("+"));
371 //leKey->selectAll();
372 }
373