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] = "&amp;";
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