summaryrefslogtreecommitdiffstats
path: root/old/libqtuitest/qinputgenerator_win.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'old/libqtuitest/qinputgenerator_win.cpp')
-rw-r--r--old/libqtuitest/qinputgenerator_win.cpp496
1 files changed, 496 insertions, 0 deletions
diff --git a/old/libqtuitest/qinputgenerator_win.cpp b/old/libqtuitest/qinputgenerator_win.cpp
new file mode 100644
index 0000000..991755b
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_win.cpp
@@ -0,0 +1,496 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of QtUiTest.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qinputgenerator_p.h"
+
+#include <QtCore>
+#include <QtGui>
+
+#include <qt_windows.h>
+#include <windows.h>
+#ifdef __GNUC__
+ #include <winable.h>
+#endif
+
+#include "qtuitestnamespace.h"
+
+#define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+
+enum WindowsNativeModifiers {
+ ShiftLeft = 0x00000001,
+ ControlLeft = 0x00000002,
+ AltLeft = 0x00000004,
+ MetaLeft = 0x00000008,
+ ShiftRight = 0x00000010,
+ ControlRight = 0x00000020,
+ AltRight = 0x00000040,
+ MetaRight = 0x00000080,
+ CapsLock = 0x00000100,
+ NumLock = 0x00000200,
+ ScrollLock = 0x00000400,
+ ExtendedKey = 0x01000000,
+
+ // Convenience mappings
+ ShiftAny = 0x00000011,
+ ControlAny = 0x00000022,
+ AltAny = 0x00000044,
+ MetaAny = 0x00000088,
+ LockAny = 0x00000700
+};
+
+QMap<int,int> qt_key_to_win_vk_make()
+{
+ QMap<int,int> m;
+
+ m.insert( Qt::Key_Escape, VK_ESCAPE );
+ m.insert( Qt::Key_Tab, VK_TAB );
+ m.insert( Qt::Key_Backspace, VK_BACK );
+ m.insert( Qt::Key_Return, VK_RETURN );
+ m.insert( Qt::Key_Enter, VK_RETURN );
+ m.insert( Qt::Key_Insert, VK_INSERT );
+ m.insert( Qt::Key_Delete, VK_DELETE );
+ m.insert( Qt::Key_Pause, VK_PAUSE );
+ m.insert( Qt::Key_Print, VK_SNAPSHOT );
+ m.insert( Qt::Key_Mode_switch, VK_MODECHANGE );
+ m.insert( Qt::Key_PageUp, VK_PRIOR );
+ m.insert( Qt::Key_PageDown, VK_NEXT );
+ m.insert( Qt::Key_End, VK_END );
+ m.insert( Qt::Key_Home, VK_HOME );
+ m.insert( Qt::Key_Sleep, VK_SLEEP );
+ m.insert( Qt::Key_Left, VK_LEFT );
+ m.insert( Qt::Key_Up, VK_UP );
+ m.insert( Qt::Key_Right, VK_RIGHT );
+ m.insert( Qt::Key_Down, VK_DOWN );
+ m.insert( Qt::Key_Select, VK_SELECT );
+ m.insert( Qt::Key_Printer, VK_PRINT );
+ m.insert( Qt::Key_Execute, VK_EXECUTE );
+ m.insert( Qt::Key_CapsLock, VK_CAPITAL );
+ m.insert( Qt::Key_NumLock, VK_NUMLOCK );
+ m.insert( Qt::Key_ScrollLock, VK_SCROLL );
+ m.insert( Qt::Key_F1, VK_F1 );
+ m.insert( Qt::Key_F2, VK_F2 );
+ m.insert( Qt::Key_F3, VK_F3 );
+ m.insert( Qt::Key_F4, VK_F4 );
+ m.insert( Qt::Key_F5, VK_F5 );
+ m.insert( Qt::Key_F6, VK_F6 );
+ m.insert( Qt::Key_F7, VK_F7 );
+ m.insert( Qt::Key_F8, VK_F8 );
+ m.insert( Qt::Key_F9, VK_F9 );
+ m.insert( Qt::Key_F10, VK_F10 );
+ m.insert( Qt::Key_F11, VK_F11 );
+ m.insert( Qt::Key_F12, VK_F12 );
+ m.insert( Qt::Key_F13, VK_F13 );
+ m.insert( Qt::Key_F14, VK_F14 );
+ m.insert( Qt::Key_F15, VK_F15 );
+ m.insert( Qt::Key_F16, VK_F16 );
+ m.insert( Qt::Key_F17, VK_F17 );
+ m.insert( Qt::Key_F18, VK_F18 );
+ m.insert( Qt::Key_F19, VK_F19 );
+ m.insert( Qt::Key_F20, VK_F20 );
+ m.insert( Qt::Key_F21, VK_F21 );
+ m.insert( Qt::Key_F22, VK_F22 );
+ m.insert( Qt::Key_F23, VK_F23 );
+ m.insert( Qt::Key_F24, VK_F24 );
+ m.insert( Qt::Key_Menu, VK_APPS );
+ m.insert( Qt::Key_Help, VK_HELP );
+ m.insert( Qt::Key_Cancel, VK_CANCEL );
+ m.insert( Qt::Key_Clear, VK_CLEAR );
+ m.insert( Qt::Key_Play, VK_PLAY );
+ m.insert( Qt::Key_Zoom, VK_ZOOM );
+
+#if (_WIN32_WINNT >= 0x0500)
+#if !defined(VK_OEM_BACKTAB)
+# define VK_OEM_BACKTAB 0xF5
+#endif
+ m.insert( Qt::Key_Backtab, VK_OEM_BACKTAB );
+ m.insert( Qt::Key_Back, VK_BROWSER_BACK );
+ m.insert( Qt::Key_Forward, VK_BROWSER_FORWARD );
+ m.insert( Qt::Key_Refresh, VK_BROWSER_REFRESH );
+ m.insert( Qt::Key_Stop, VK_BROWSER_STOP );
+ m.insert( Qt::Key_Search, VK_BROWSER_SEARCH );
+ m.insert( Qt::Key_Favorites, VK_BROWSER_FAVORITES );
+ m.insert( Qt::Key_HomePage, VK_BROWSER_HOME );
+ m.insert( Qt::Key_VolumeMute, VK_VOLUME_MUTE );
+ m.insert( Qt::Key_VolumeDown, VK_VOLUME_DOWN );
+ m.insert( Qt::Key_VolumeUp, VK_VOLUME_UP );
+ m.insert( Qt::Key_MediaNext, VK_MEDIA_NEXT_TRACK );
+ m.insert( Qt::Key_MediaPrevious, VK_MEDIA_PREV_TRACK );
+ m.insert( Qt::Key_MediaStop, VK_MEDIA_STOP );
+ m.insert( Qt::Key_MediaPlay, VK_MEDIA_PLAY_PAUSE );
+ m.insert( Qt::Key_LaunchMail, VK_LAUNCH_MAIL );
+ m.insert( Qt::Key_LaunchMedia, VK_LAUNCH_MEDIA_SELECT );
+ m.insert( Qt::Key_Launch0, VK_LAUNCH_APP1 );
+ m.insert( Qt::Key_Launch1, VK_LAUNCH_APP2 );
+#endif
+
+
+ // Modifiers
+ m.insert( Qt::ShiftModifier, VK_SHIFT );
+ m.insert( Qt::Key_Shift, VK_SHIFT );
+ m.insert( Qt::ControlModifier, VK_CONTROL );
+ m.insert( Qt::Key_Control, VK_CONTROL );
+ m.insert( Qt::AltModifier, VK_MENU );
+ m.insert( Qt::Key_Alt, VK_MENU );
+ m.insert( Qt::MetaModifier, VK_LWIN );
+ m.insert( Qt::Key_Meta, VK_LWIN );
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_win_button_down_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, MOUSEEVENTF_LEFTDOWN );
+ m.insert( Qt::MidButton, MOUSEEVENTF_MIDDLEDOWN );
+ m.insert( Qt::RightButton, MOUSEEVENTF_RIGHTDOWN );
+
+#if (_WIN32_WINNT >= 0x0500)
+ m.insert( Qt::XButton1, MOUSEEVENTF_XDOWN );
+ m.insert( Qt::XButton2, MOUSEEVENTF_XDOWN );
+#endif
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_win_button_up_make()
+{
+ QMap<int,uint> m;
+
+ m.insert( Qt::LeftButton, MOUSEEVENTF_LEFTUP );
+ m.insert( Qt::MidButton, MOUSEEVENTF_MIDDLEUP );
+ m.insert( Qt::RightButton, MOUSEEVENTF_RIGHTUP );
+
+#if (_WIN32_WINNT >= 0x0500)
+ m.insert( Qt::XButton1, MOUSEEVENTF_XUP );
+ m.insert( Qt::XButton2, MOUSEEVENTF_XUP );
+#endif
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_win_mousedata_make()
+{
+ QMap<int,uint> m;
+
+#if (_WIN32_WINNT >= 0x0500)
+ m.insert( Qt::XButton1, XBUTTON1 );
+ m.insert( Qt::XButton2, XBUTTON2 );
+#endif
+
+ return m;
+}
+
+class QInputGeneratorPrivate
+{
+public:
+ QInputGeneratorPrivate();
+ QInputGenerator* q;
+
+ void keyEvent(Qt::Key, bool);
+ void mouseEvent(QPoint const&, Qt::MouseButtons);
+
+ void ensureModifiers(Qt::KeyboardModifiers);
+ Qt::KeyboardModifiers currentModifiers() const;
+
+ QMap<int,int> const keyMap;
+ QMap<int,uint> const buttonDownMap;
+ QMap<int,uint> const buttonUpMap;
+ QMap<int,uint> const buttonMouseDataMap;
+
+ QPoint currentPos;
+ Qt::MouseButtons currentButtons;
+};
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : keyMap(qt_key_to_win_vk_make()),
+ buttonDownMap(qt_button_to_win_button_down_make()),
+ buttonUpMap(qt_button_to_win_button_up_make()),
+ buttonMouseDataMap(qt_button_to_win_mousedata_make()),
+ currentPos(),
+ currentButtons(0)
+{}
+
+QInputGenerator::QInputGenerator(QObject* parent)
+ : QObject(parent),
+ d(new QInputGeneratorPrivate)
+{
+ d->q = this;
+ QINPUTGENERATOR_DEBUG() << "constructor";
+}
+
+QInputGenerator::~QInputGenerator()
+{
+ QINPUTGENERATOR_DEBUG() << "destructor";
+
+ /*
+ Restore all keyboard modifiers to off.
+ Note that there is no guarantee this code actually gets run.
+ */
+ d->ensureModifiers(0);
+ if (d->currentButtons) {
+ d->mouseEvent(d->currentPos, 0);
+ }
+
+ d->q = 0;
+ delete d;
+ d = 0;
+}
+
+/*
+ Returns the Qt keyboard modifiers which are currently pressed.
+*/
+Qt::KeyboardModifiers QInputGeneratorPrivate::currentModifiers() const
+{
+ quint32 nModifiers = 0;
+
+ if (QSysInfo::WindowsVersion < QSysInfo::WV_NT || QSysInfo::WindowsVersion & QSysInfo::WV_CE_based) {
+ nModifiers |= (GetKeyState(VK_SHIFT ) < 0 ? ShiftAny : 0);
+ nModifiers |= (GetKeyState(VK_CONTROL) < 0 ? ControlAny : 0);
+ nModifiers |= (GetKeyState(VK_MENU ) < 0 ? AltAny : 0);
+ nModifiers |= (GetKeyState(VK_LWIN ) < 0 ? MetaLeft : 0);
+ nModifiers |= (GetKeyState(VK_RWIN ) < 0 ? MetaRight : 0);
+ } else {
+ // Map native modifiers to some bit representation
+ nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ? ShiftLeft : 0);
+ nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ? ShiftRight : 0);
+ nModifiers |= (GetKeyState(VK_LCONTROL) & 0x80 ? ControlLeft : 0);
+ nModifiers |= (GetKeyState(VK_RCONTROL) & 0x80 ? ControlRight : 0);
+ nModifiers |= (GetKeyState(VK_LMENU ) & 0x80 ? AltLeft : 0);
+ nModifiers |= (GetKeyState(VK_RMENU ) & 0x80 ? AltRight : 0);
+ nModifiers |= (GetKeyState(VK_LWIN ) & 0x80 ? MetaLeft : 0);
+ nModifiers |= (GetKeyState(VK_RWIN ) & 0x80 ? MetaRight : 0);
+ // Add Lock keys to the same bits
+ nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ? CapsLock : 0);
+ nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ? NumLock : 0);
+ nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ? ScrollLock : 0);
+ }
+
+ int state = 0;
+ state |= (nModifiers & ShiftAny ? Qt::ShiftModifier : 0);
+ state |= (nModifiers & ControlAny ? Qt::ControlModifier : 0);
+ state |= (nModifiers & AltAny ? Qt::AltModifier : 0);
+ state |= (nModifiers & MetaAny ? Qt::MetaModifier : 0);
+
+ return Qt::KeyboardModifier(state);
+}
+
+void QInputGeneratorPrivate::ensureModifiers(Qt::KeyboardModifiers desiredMod)
+{
+ Qt::KeyboardModifiers currentMod = currentModifiers();
+
+ // For each modifier..
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ // If the modifier is currently disabled but we want it enabled, or vice-versa...
+ if ((desiredMod & thisMod) && !(currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Enabling modifier" << (void*)thisMod << "by press";
+ // press to enable
+ keyEvent(q->modifierToKey(thisMod), true);
+ } else if (!(desiredMod & thisMod) && (currentMod & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Disabling modifier" << (void*)thisMod << "by release";
+ // release to disable
+ keyEvent(q->modifierToKey(thisMod), false);
+ }
+ }
+
+ if (currentMod != desiredMod) {
+ currentMod = desiredMod;
+ for (int i = 0;
+ i < 1000 && QApplication::keyboardModifiers() != desiredMod;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (QApplication::keyboardModifiers() != desiredMod)
+ qWarning() << "QtUitest: couldn't set all modifiers to desired state! "
+ "Current state:" << (void*)(int)QApplication::keyboardModifiers() <<
+ "Desired:" << (void*)(int)desiredMod;
+ }
+
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, bool is_press)
+{
+ int sym = 0;
+ Qt::KeyboardModifiers mod = 0;
+
+ do {
+ if (key >= Qt::Key_0 && key <= Qt::Key_9 ||
+ key >= Qt::Key_A && key <= Qt::Key_Z) {
+ sym = QChar(key).toUpper().toAscii();
+ break;
+ }
+
+ if (key >= Qt::Key_Space && key <= Qt::Key_AsciiTilde) {
+ sym = VkKeyScan(QChar(key).toAscii());
+ if (sym & 0x0100) mod |= Qt::ShiftModifier;
+ if (sym & 0x0200) mod |= Qt::ControlModifier;
+ if (sym & 0x0400) mod |= Qt::AltModifier;
+ break;
+ }
+
+ QMap<int,int>::const_iterator found = keyMap.find(key);
+ if (found != keyMap.end()) {
+ sym = *found;
+ break;
+ }
+
+ qWarning() << "QInputGenerator: don't know how to translate Qt key"
+ << (void*)key << "into Windows virtual key";
+ return;
+
+ } while(0);
+
+ if (mod) {
+ ensureModifiers(mod);
+ }
+
+ QINPUTGENERATOR_DEBUG() << (is_press ? "press" : "release") << sym;
+
+ KEYBDINPUT kbi = {0};
+ INPUT input = {0};
+
+ kbi.wVk = sym;
+ if (!is_press) kbi.dwFlags = KEYEVENTF_KEYUP;
+
+ input.ki = kbi;
+ input.type = INPUT_KEYBOARD;
+ SendInput(1, &input, sizeof(input));
+}
+
+void QInputGenerator::keyPress(Qt::Key key, Qt::KeyboardModifiers mod, bool autoRepeat)
+{
+ Q_UNUSED(autoRepeat);
+ d->ensureModifiers(mod);
+ d->keyEvent(key, true);
+}
+
+void QInputGenerator::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ d->ensureModifiers(mod);
+ d->keyEvent(key, false);
+}
+
+void QInputGenerator::keyClick(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ keyPress(key,mod);
+ keyRelease(key,mod);
+}
+
+void QInputGeneratorPrivate::mouseEvent(QPoint const& pos, Qt::MouseButtons state)
+{
+ if (currentPos != pos) {
+ currentPos = pos;
+
+ MOUSEINPUT mi = {0};
+ INPUT input = {0};
+
+ QRect rect = QApplication::desktop()->screenGeometry(); // FIXME: Uses default screen for now
+
+ mi.dx = LONG(pos.x() * 65535.0 / rect.width() + 8);
+ mi.dy = LONG(pos.y() * 65535.0 / rect.height() + 8);
+ mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
+ input.mi = mi;
+ input.type = INPUT_MOUSE;
+ SendInput(1, &input, sizeof(input));
+
+ for (int i = 0;
+ i < 1000 && QCursor::pos() != pos;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (QCursor::pos() != pos)
+ qWarning() << "QtUitest: couldn't move cursor to desired point! "
+ "Current position:" << QCursor::pos() <<
+ "Desired:" << pos;
+
+ }
+
+ typedef QPair<uint,uint> ButtonEvent;
+ QList<ButtonEvent> buttonEvents;
+
+ foreach (int button, buttonDownMap.keys()) {
+ bool desired = button & state;
+ bool current = button & currentButtons;
+
+ // Do we need to release?
+ if (!desired && current) {
+ buttonEvents << qMakePair(buttonUpMap[button], buttonMouseDataMap[button]);
+ }
+
+ // Do we need to press?
+ if (desired && !current) {
+ buttonEvents << qMakePair(buttonDownMap[button], buttonMouseDataMap[button]);
+ }
+ }
+
+ foreach (ButtonEvent const& event, buttonEvents) {
+ MOUSEINPUT mi = {0};
+ INPUT input = {0};
+
+ mi.dwFlags = event.first;
+ mi.mouseData = event.second;
+ input.mi = mi;
+ input.type = INPUT_MOUSE;
+ SendInput(1, &input, sizeof(input));
+ }
+
+ currentButtons = state;
+}
+
+void QInputGenerator::mousePress(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse press" << pos << (void*)(int)state;
+ d->mouseEvent(pos, d->currentButtons | state);
+}
+
+void QInputGenerator::mouseRelease(QPoint const& pos, Qt::MouseButtons state)
+{
+ QINPUTGENERATOR_DEBUG() << "Mouse release" << pos << (void*)(int)(d->currentButtons & ~state);
+ d->mouseEvent(pos, d->currentButtons & ~state);
+}
+
+void QInputGenerator::mouseClick(QPoint const& pos, Qt::MouseButtons state)
+{
+ mousePress (pos,state);
+ mouseRelease(pos,state);
+}
+