1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the QtTest module of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:LGPL$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** GNU Lesser General Public License Usage 18 ** Alternatively, this file may be used under the terms of the GNU Lesser 19 ** General Public License version 3 as published by the Free Software 20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 ** packaging of this file. Please review the following information to 22 ** ensure the GNU Lesser General Public License version 3 requirements 23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 ** 25 ** GNU General Public License Usage 26 ** Alternatively, this file may be used under the terms of the GNU 27 ** General Public License version 2.0 or (at your option) the GNU General 28 ** Public license version 3 or any later version approved by the KDE Free 29 ** Qt Foundation. The licenses are as published by the Free Software 30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 ** included in the packaging of this file. Please review the following 32 ** information to ensure the GNU General Public License requirements will 33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 ** https://www.gnu.org/licenses/gpl-3.0.html. 35 ** 36 ** $QT_END_LICENSE$ 37 ** 38 ****************************************************************************/ 39 40 #ifndef QTESTKEYBOARD_H 41 #define QTESTKEYBOARD_H 42 43 #if 0 44 // inform syncqt 45 #pragma qt_no_master_include 46 #endif 47 48 #include <QtTest/qtestassert.h> 49 #include <QtTest/qttestglobal.h> 50 #include <QtTest/qtestsystem.h> 51 #include <QtTest/qtestspontaneevent.h> 52 53 #include <QtCore/qpointer.h> 54 #include <QtGui/qguiapplication.h> 55 #include <QtGui/qwindow.h> 56 #include <QtGui/qevent.h> 57 #include <QtGui/qkeysequence.h> 58 59 #ifdef QT_WIDGETS_LIB 60 #include <QtWidgets/qwidget.h> 61 #include <QtWidgets/qapplication.h> 62 #endif 63 64 QT_BEGIN_NAMESPACE 65 66 Q_GUI_EXPORT void qt_handleKeyEvent(QWindow *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1); 67 Q_GUI_EXPORT bool qt_sendShortcutOverrideEvent(QObject *o, ulong timestamp, int k, Qt::KeyboardModifiers mods, const QString &text = QString(), bool autorep = false, ushort count = 1); 68 69 namespace QTest 70 { 71 enum KeyAction { Press, Release, Click, Shortcut }; 72 73 static void simulateEvent(QWindow *window, bool press, int code, 74 Qt::KeyboardModifiers modifier, QString text, bool repeat, int delay=-1) 75 { 76 QEvent::Type type; 77 type = press ? QEvent::KeyPress : QEvent::KeyRelease; 78 qt_handleKeyEvent(window, type, code, modifier, text, repeat, delay); 79 qApp->processEvents(); 80 } 81 82 static void sendKeyEvent(KeyAction action, QWindow *window, Qt::Key code, 83 QString text, Qt::KeyboardModifiers modifier, int delay=-1) 84 { 85 QTEST_ASSERT(qApp); 86 87 if (!window) 88 window = QGuiApplication::focusWindow(); 89 90 QTEST_ASSERT(window); 91 92 93 if (action == Click) { 94 sendKeyEvent(Press, window, code, text, modifier, delay); 95 sendKeyEvent(Release, window, code, text, modifier, delay); 96 return; 97 } 98 99 bool repeat = false; 100 101 if (action == Shortcut) { 102 int timestamp = 0; 103 qt_sendShortcutOverrideEvent(window, timestamp, code, modifier, text, repeat); 104 return; 105 } 106 107 if (action == Press) { 108 if (modifier & Qt::ShiftModifier) 109 simulateEvent(window, true, Qt::Key_Shift, Qt::KeyboardModifiers(), QString(), false, delay); 110 111 if (modifier & Qt::ControlModifier) 112 simulateEvent(window, true, Qt::Key_Control, modifier & Qt::ShiftModifier, QString(), false, delay); 113 114 if (modifier & Qt::AltModifier) 115 simulateEvent(window, true, Qt::Key_Alt, 116 modifier & (Qt::ShiftModifier | Qt::ControlModifier), QString(), false, delay); 117 if (modifier & Qt::MetaModifier) 118 simulateEvent(window, true, Qt::Key_Meta, modifier & (Qt::ShiftModifier 119 | Qt::ControlModifier | Qt::AltModifier), QString(), false, delay); 120 simulateEvent(window, true, code, modifier, text, repeat, delay); 121 } else if (action == Release) { 122 simulateEvent(window, false, code, modifier, text, repeat, delay); 123 124 if (modifier & Qt::MetaModifier) 125 simulateEvent(window, false, Qt::Key_Meta, modifier, QString(), false, delay); 126 if (modifier & Qt::AltModifier) 127 simulateEvent(window, false, Qt::Key_Alt, modifier & 128 (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier), QString(), false, delay); 129 130 if (modifier & Qt::ControlModifier) 131 simulateEvent(window, false, Qt::Key_Control, 132 modifier & (Qt::ShiftModifier | Qt::ControlModifier), QString(), false, delay); 133 134 if (modifier & Qt::ShiftModifier) 135 simulateEvent(window, false, Qt::Key_Shift, modifier & Qt::ShiftModifier, QString(), false, delay); 136 } 137 } 138 139 // Convenience function 140 static void sendKeyEvent(KeyAction action, QWindow *window, Qt::Key code, 141 char ascii, Qt::KeyboardModifiers modifier, int delay=-1) 142 { 143 QString text; 144 if (ascii) 145 text = QString(QChar::fromLatin1(ascii)); 146 sendKeyEvent(action, window, code, text, modifier, delay); 147 } 148 149 inline static void keyEvent(KeyAction action, QWindow *window, char ascii, 150 Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 151 { sendKeyEvent(action, window, asciiToKey(ascii), ascii, modifier, delay); } 152 inline static void keyEvent(KeyAction action, QWindow *window, Qt::Key key, 153 Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 154 { sendKeyEvent(action, window, key, keyToAscii(key), modifier, delay); } 155 156 Q_DECL_UNUSED inline static void keyClick(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 157 { keyEvent(Click, window, key, modifier, delay); } 158 Q_DECL_UNUSED inline static void keyClick(QWindow *window, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 159 { keyEvent(Click, window, key, modifier, delay); } 160 Q_DECL_UNUSED inline static void keyRelease(QWindow *window, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 161 { keyEvent(Release, window, key, modifier, delay); } 162 Q_DECL_UNUSED inline static void keyRelease(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 163 { keyEvent(Release, window, key, modifier, delay); } 164 Q_DECL_UNUSED inline static void keyPress(QWindow *window, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 165 { keyEvent(Press, window, key, modifier, delay); } 166 Q_DECL_UNUSED inline static void keyPress(QWindow *window, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 167 { keyEvent(Press, window, key, modifier, delay); } 168 169 #if QT_CONFIG(shortcut) keySequence(QWindow * window,const QKeySequence & keySequence)170 Q_DECL_UNUSED inline static void keySequence(QWindow *window, const QKeySequence &keySequence) 171 { 172 for (int i = 0; i < keySequence.count(); ++i) { 173 const Qt::Key key = Qt::Key(keySequence[i] & ~Qt::KeyboardModifierMask); 174 const Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keySequence[i] & Qt::KeyboardModifierMask); 175 keyClick(window, key, modifiers); 176 } 177 } 178 #endif 179 180 #ifdef QT_WIDGETS_LIB 181 static void simulateEvent(QWidget *widget, bool press, int code, 182 Qt::KeyboardModifiers modifier, QString text, bool repeat, int delay=-1) 183 { 184 QTEST_ASSERT(widget); 185 extern int Q_TESTLIB_EXPORT defaultKeyDelay(); 186 187 if (delay == -1 || delay < defaultKeyDelay()) 188 delay = defaultKeyDelay(); 189 if (delay > 0) 190 QTest::qWait(delay); 191 192 QKeyEvent a(press ? QEvent::KeyPress : QEvent::KeyRelease, code, modifier, text, repeat); 193 QSpontaneKeyEvent::setSpontaneous(&a); 194 195 if (press && qt_sendShortcutOverrideEvent(widget, a.timestamp(), code, modifier, text, repeat)) 196 return; 197 if (!qApp->notify(widget, &a)) 198 QTest::qWarn("Keyboard event not accepted by receiving widget"); 199 } 200 201 static void sendKeyEvent(KeyAction action, QWidget *widget, Qt::Key code, 202 QString text, Qt::KeyboardModifiers modifier, int delay=-1) 203 { 204 QTEST_ASSERT(qApp); 205 206 if (!widget) 207 widget = QWidget::keyboardGrabber(); 208 if (!widget) { 209 // Popup widgets stealthily steal the keyboard grab 210 if (QWidget *apw = QApplication::activePopupWidget()) 211 widget = apw->focusWidget() ? apw->focusWidget() : apw; 212 } 213 if (!widget) { 214 QWindow *window = QGuiApplication::focusWindow(); 215 if (window) { 216 sendKeyEvent(action, window, code, text, modifier, delay); 217 return; 218 } 219 } 220 if (!widget) 221 widget = QApplication::focusWidget(); 222 if (!widget) 223 widget = QApplication::activeWindow(); 224 225 QTEST_ASSERT(widget); 226 227 if (action == Click) { 228 QPointer<QWidget> ptr(widget); 229 sendKeyEvent(Press, widget, code, text, modifier, delay); 230 if (!ptr) { 231 // if we send key-events to embedded widgets, they might be destroyed 232 // when the user presses Return 233 return; 234 } 235 sendKeyEvent(Release, widget, code, text, modifier, delay); 236 return; 237 } 238 239 bool repeat = false; 240 241 if (action == Press) { 242 if (modifier & Qt::ShiftModifier) 243 simulateEvent(widget, true, Qt::Key_Shift, Qt::KeyboardModifiers(), QString(), false, delay); 244 245 if (modifier & Qt::ControlModifier) 246 simulateEvent(widget, true, Qt::Key_Control, modifier & Qt::ShiftModifier, QString(), false, delay); 247 248 if (modifier & Qt::AltModifier) 249 simulateEvent(widget, true, Qt::Key_Alt, 250 modifier & (Qt::ShiftModifier | Qt::ControlModifier), QString(), false, delay); 251 if (modifier & Qt::MetaModifier) 252 simulateEvent(widget, true, Qt::Key_Meta, modifier & (Qt::ShiftModifier 253 | Qt::ControlModifier | Qt::AltModifier), QString(), false, delay); 254 simulateEvent(widget, true, code, modifier, text, repeat, delay); 255 } else if (action == Release) { 256 simulateEvent(widget, false, code, modifier, text, repeat, delay); 257 258 if (modifier & Qt::MetaModifier) 259 simulateEvent(widget, false, Qt::Key_Meta, modifier, QString(), false, delay); 260 if (modifier & Qt::AltModifier) 261 simulateEvent(widget, false, Qt::Key_Alt, modifier & 262 (Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier), QString(), false, delay); 263 264 if (modifier & Qt::ControlModifier) 265 simulateEvent(widget, false, Qt::Key_Control, 266 modifier & (Qt::ShiftModifier | Qt::ControlModifier), QString(), false, delay); 267 268 if (modifier & Qt::ShiftModifier) 269 simulateEvent(widget, false, Qt::Key_Shift, modifier & Qt::ShiftModifier, QString(), false, delay); 270 } 271 } 272 273 // Convenience function 274 static void sendKeyEvent(KeyAction action, QWidget *widget, Qt::Key code, 275 char ascii, Qt::KeyboardModifiers modifier, int delay=-1) 276 { 277 QString text; 278 if (ascii) 279 text = QString(QChar::fromLatin1(ascii)); 280 sendKeyEvent(action, widget, code, text, modifier, delay); 281 } 282 283 inline static void keyEvent(KeyAction action, QWidget *widget, char ascii, 284 Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 285 { sendKeyEvent(action, widget, asciiToKey(ascii), ascii, modifier, delay); } 286 inline static void keyEvent(KeyAction action, QWidget *widget, Qt::Key key, 287 Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 288 { sendKeyEvent(action, widget, key, keyToAscii(key), modifier, delay); } 289 290 inline static void keyClicks(QWidget *widget, const QString &sequence, 291 Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 292 { 293 for (int i=0; i < sequence.length(); i++) 294 keyEvent(Click, widget, sequence.at(i).toLatin1(), modifier, delay); 295 } 296 297 inline static void keyPress(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 298 { keyEvent(Press, widget, key, modifier, delay); } 299 inline static void keyRelease(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 300 { keyEvent(Release, widget, key, modifier, delay); } 301 inline static void keyClick(QWidget *widget, char key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 302 { keyEvent(Click, widget, key, modifier, delay); } 303 inline static void keyPress(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 304 { keyEvent(Press, widget, key, modifier, delay); } 305 inline static void keyRelease(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 306 { keyEvent(Release, widget, key, modifier, delay); } 307 inline static void keyClick(QWidget *widget, Qt::Key key, Qt::KeyboardModifiers modifier = Qt::NoModifier, int delay=-1) 308 { keyEvent(Click, widget, key, modifier, delay); } 309 310 #if QT_CONFIG(shortcut) keySequence(QWidget * widget,const QKeySequence & keySequence)311 inline static void keySequence(QWidget *widget, const QKeySequence &keySequence) 312 { 313 for (int i = 0; i < keySequence.count(); ++i) { 314 const Qt::Key key = Qt::Key(keySequence[i] & ~Qt::KeyboardModifierMask); 315 const Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(keySequence[i] & Qt::KeyboardModifierMask); 316 keyClick(widget, key, modifiers); 317 } 318 } 319 #endif 320 321 #endif // QT_WIDGETS_LIB 322 323 } 324 325 QT_END_NAMESPACE 326 327 #endif // QTESTKEYBOARD_H 328