summaryrefslogtreecommitdiffstats
path: root/old/libqtuitest/qinputgenerator_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'old/libqtuitest/qinputgenerator_x11.cpp')
-rw-r--r--old/libqtuitest/qinputgenerator_x11.cpp514
1 files changed, 514 insertions, 0 deletions
diff --git a/old/libqtuitest/qinputgenerator_x11.cpp b/old/libqtuitest/qinputgenerator_x11.cpp
new file mode 100644
index 0000000..11bb7e1
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_x11.cpp
@@ -0,0 +1,514 @@
+/****************************************************************************
+**
+** 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 <QX11Info>
+#include <X11/extensions/XTest.h>
+#include <X11/keysym.h>
+
+#include "qtuitestnamespace.h"
+
+#define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+
+
+QMap<int,int> qt_key_to_keysym_make()
+{
+ QMap<int,int> m;
+
+#define QT_K(Qt,X) m.insert(Qt,X)
+ QT_K( '\n', XK_Return );
+ QT_K( Qt::Key_Escape, XK_Escape );
+ QT_K( Qt::Key_Tab, XK_Tab );
+ QT_K( Qt::Key_Backtab, XK_ISO_Left_Tab );
+ QT_K( Qt::Key_Backspace, XK_BackSpace );
+ QT_K( Qt::Key_Return, XK_Return );
+ QT_K( Qt::Key_Enter, XK_KP_Enter );
+ QT_K( Qt::Key_Insert, XK_Insert );
+ QT_K( Qt::Key_Delete, XK_Delete );
+ QT_K( Qt::Key_Pause, XK_Pause );
+ QT_K( Qt::Key_Print, XK_Print );
+ QT_K( Qt::Key_SysReq, XK_Sys_Req );
+ QT_K( Qt::Key_Home, XK_Home );
+ QT_K( Qt::Key_End, XK_End );
+ QT_K( Qt::Key_Left, XK_Left );
+ QT_K( Qt::Key_Up, XK_Up );
+ QT_K( Qt::Key_Right, XK_Right );
+ QT_K( Qt::Key_Down, XK_Down );
+ QT_K( Qt::Key_CapsLock, XK_Caps_Lock );
+ QT_K( Qt::Key_NumLock, XK_Num_Lock );
+ QT_K( Qt::Key_ScrollLock, XK_Scroll_Lock );
+ QT_K( Qt::Key_F1, XK_F1 );
+ QT_K( Qt::Key_F2, XK_F2 );
+ QT_K( Qt::Key_F3, XK_F3 );
+ QT_K( Qt::Key_F4, XK_F4 );
+ QT_K( Qt::Key_F5, XK_F5 );
+ QT_K( Qt::Key_F6, XK_F6 );
+ QT_K( Qt::Key_F7, XK_F7 );
+ QT_K( Qt::Key_F8, XK_F8 );
+ QT_K( Qt::Key_F9, XK_F9 );
+ QT_K( Qt::Key_F10, XK_F10 );
+ QT_K( Qt::Key_F11, XK_F11 );
+ QT_K( Qt::Key_F12, XK_F12 );
+ QT_K( Qt::Key_F13, XK_F13 );
+ QT_K( Qt::Key_F14, XK_F14 );
+ QT_K( Qt::Key_F15, XK_F15 );
+ QT_K( Qt::Key_F16, XK_F16 );
+ QT_K( Qt::Key_F17, XK_F17 );
+ QT_K( Qt::Key_F18, XK_F18 );
+ QT_K( Qt::Key_F19, XK_F19 );
+ QT_K( Qt::Key_F20, XK_F20 );
+ QT_K( Qt::Key_F21, XK_F21 );
+ QT_K( Qt::Key_F22, XK_F22 );
+ QT_K( Qt::Key_F23, XK_F23 );
+ QT_K( Qt::Key_F24, XK_F24 );
+ QT_K( Qt::Key_F25, XK_F25 );
+ QT_K( Qt::Key_F26, XK_F26 );
+ QT_K( Qt::Key_F27, XK_F27 );
+ QT_K( Qt::Key_F28, XK_F28 );
+ QT_K( Qt::Key_F29, XK_F29 );
+ QT_K( Qt::Key_F30, XK_F30 );
+ QT_K( Qt::Key_F31, XK_F31 );
+ QT_K( Qt::Key_F32, XK_F32 );
+ QT_K( Qt::Key_F33, XK_F33 );
+ QT_K( Qt::Key_F34, XK_F34 );
+ QT_K( Qt::Key_F35, XK_F35 );
+ QT_K( Qt::Key_Super_L, XK_Super_L );
+ QT_K( Qt::Key_Super_R, XK_Super_R );
+ QT_K( Qt::Key_Menu, XK_Menu );
+ QT_K( Qt::Key_Hyper_L, XK_Hyper_L );
+ QT_K( Qt::Key_Hyper_R, XK_Hyper_R );
+ QT_K( Qt::Key_Help, XK_Help );
+ QT_K( '/', XK_KP_Divide );
+// QT_K( '*', XK_KP_Multiply );
+ QT_K( '-', XK_KP_Subtract );
+ QT_K( '+', XK_KP_Add );
+ QT_K( Qt::Key_Return, XK_KP_Enter );
+ QT_K( Qt::Key_Kanji, XK_Kanji );
+ QT_K( Qt::Key_Muhenkan, XK_Muhenkan );
+ QT_K( Qt::Key_Henkan, XK_Henkan );
+ QT_K( Qt::Key_Romaji, XK_Romaji );
+ QT_K( Qt::Key_Hiragana, XK_Hiragana );
+ QT_K( Qt::Key_Katakana, XK_Katakana );
+ QT_K( Qt::Key_Hiragana_Katakana, XK_Hiragana_Katakana );
+ QT_K( Qt::Key_Zenkaku, XK_Zenkaku );
+ QT_K( Qt::Key_Hankaku, XK_Hankaku );
+ QT_K( Qt::Key_Zenkaku_Hankaku, XK_Zenkaku_Hankaku );
+ QT_K( Qt::Key_Touroku, XK_Touroku );
+ QT_K( Qt::Key_Massyo, XK_Massyo );
+ QT_K( Qt::Key_Kana_Lock, XK_Kana_Lock );
+ QT_K( Qt::Key_Kana_Shift, XK_Kana_Shift );
+ QT_K( Qt::Key_Eisu_Shift, XK_Eisu_Shift );
+ QT_K( Qt::Key_Eisu_toggle,XK_Eisu_toggle );
+ QT_K( Qt::Key_Hangul, XK_Hangul );
+ QT_K( Qt::Key_Hangul_Start, XK_Hangul_Start );
+ QT_K( Qt::Key_Hangul_End, XK_Hangul_End );
+ QT_K( Qt::Key_Hangul_Hanja, XK_Hangul_Hanja );
+ QT_K( Qt::Key_Hangul_Jamo, XK_Hangul_Jamo );
+ QT_K( Qt::Key_Hangul_Romaja, XK_Hangul_Romaja );
+ QT_K( Qt::Key_Hangul_Jeonja, XK_Hangul_Jeonja );
+ QT_K( Qt::Key_Hangul_Banja, XK_Hangul_Banja );
+ QT_K( Qt::Key_Hangul_PreHanja, XK_Hangul_PreHanja );
+ QT_K( Qt::Key_Hangul_PostHanja,XK_Hangul_PostHanja );
+ QT_K( Qt::Key_Hangul_Special, XK_Hangul_Special );
+
+ // Modifiers
+ QT_K( Qt::ShiftModifier, XK_Shift_L );
+ QT_K( Qt::Key_Shift, XK_Shift_L );
+ QT_K( Qt::ControlModifier,XK_Control_L );
+ QT_K( Qt::Key_Control, XK_Control_L );
+// QT_K( Qt::AltModifier, XK_Alt_L );
+// QT_K( Qt::Key_Alt, XK_Alt_L );
+ QT_K( Qt::MetaModifier, XK_Meta_L );
+ QT_K( Qt::Key_Meta, XK_Meta_L );
+
+ QT_K( Qt::AltModifier, XK_ISO_Level3_Shift );
+ QT_K( Qt::Key_Alt, XK_ISO_Level3_Shift );
+ // FIXME support Qt::KeypadModifier
+
+#undef QT_K
+
+ return m;
+}
+
+QMap<int,uint> qt_button_to_x_button_make()
+{
+ QMap<int,uint> m;
+
+ m.insert(Qt::LeftButton, 1);
+ m.insert(Qt::MidButton, 2);
+ m.insert(Qt::RightButton, 3);
+
+ return m;
+}
+
+QMap<int,int> qt_modifier_to_x_modmask_make()
+{
+ QMap<int,int> m;
+
+ m.insert( Qt::ShiftModifier, ShiftMask );
+ m.insert( Qt::ControlModifier, ControlMask );
+// m.insert( Qt::AltModifier, Mod1Mask );
+ m.insert( Qt::MetaModifier, Mod4Mask );
+ m.insert( Qt::AltModifier, Mod5Mask );
+
+ return m;
+}
+
+struct QInputGeneratorPrivate
+{
+ 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 buttonmap;
+
+ QPoint currentPos;
+ Qt::MouseButtons currentButtons;
+};
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : keymap(qt_key_to_keysym_make()),
+ buttonmap(qt_button_to_x_button_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.
+ If we don't do this, the current modifiers stay activated for the current X server
+ even when this application is closed.
+ 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
+{
+ Display* dpy = QX11Info::display();
+ if (!dpy) {
+ /* No X connection */
+ return 0;
+ }
+
+ Window root = 0;
+ Window child = 0;
+ int root_x = 0;
+ int root_y = 0;
+ int win_x = 0;
+ int win_y = 0;
+ uint buttons = 0;
+
+ // Grab all of the pointer info, though all we really care about is the modifiers.
+ bool ok = false;
+ for (int i = 0; i < ScreenCount(dpy) && !ok; ++i) {
+ if (XQueryPointer(dpy, (Window)QX11Info::appRootWindow(i), &root, &child, &root_x, &root_y,
+ &win_x, &win_y, &buttons))
+ ok = true;
+ }
+
+ if (!ok) {
+ qWarning() <<
+ "QInputGenerator: could not determine current state of keyboard modifiers. "
+ "Simulated key events may be incorrect.";
+ return 0;
+ }
+
+ // Convert to Qt::KeyboardModifiers.
+ static const QMap<int,int> modmap = qt_modifier_to_x_modmask_make();
+
+ Qt::KeyboardModifiers ret(0);
+ for (unsigned i = 0; i < sizeof(q->AllModifiers)/sizeof(Qt::KeyboardModifier); ++i) {
+ Qt::KeyboardModifier thisMod = q->AllModifiers[i];
+ int mask = modmap.value(thisMod);
+ if (buttons & mask) {
+ QINPUTGENERATOR_DEBUG() << "mod enabled:" << (void*)(int)thisMod << (void*)mask;
+ ret |= thisMod;
+ }
+ }
+
+ QINPUTGENERATOR_DEBUG() << "current modifiers:" << (void*)buttons << (void*)(int)ret;
+
+ return ret;
+}
+
+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;
+// }
+ if (currentMod != desiredMod) {
+ currentMod = desiredMod;
+ for (int i = 0;
+ i < 1000 && currentModifiers() != desiredMod;
+ i += 50, QtUiTest::wait(50))
+ {}
+
+ if (currentModifiers() != desiredMod)
+ qWarning() << "QtUitest: couldn't set all modifiers to desired state! "
+ "Current state:" << (void*)(int)currentModifiers() <<
+ "Desired:" << (void*)(int)desiredMod;
+ }
+
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, bool is_press)
+{
+ Display* dpy = QX11Info::display();
+ if (!dpy) {
+ /* No X connection */
+ return;
+ }
+
+ KeySym sym = 0;
+
+ do {
+// if ((key >= Qt::Key_0 && key <= Qt::Key_9) ||
+// (key >= Qt::Key_A && key <= Qt::Key_Z)) {
+// sym = QChar(key).toLower().unicode();
+// break;
+// }
+
+ if (key >= Qt::Key_A && key <= Qt::Key_Z) {
+ sym = QChar(key).toLower().unicode();
+ break;
+ }
+
+
+ QMap<int,int>::const_iterator found = keymap.find(key);
+ if (found != keymap.end()) {
+ sym = *found;
+ break;
+ }
+
+ if ((key < 0x1000 && key >= 0x20 )|| (key >= Qt::Key_0 && key <= Qt::Key_9) ){
+ sym = QChar(key).unicode();
+ KeyCode kc = XKeysymToKeycode(dpy, sym);
+ int syms_per_keycode;
+ KeySym *keymap = XGetKeyboardMapping(dpy, kc, 1, &syms_per_keycode);
+ for(int i=0; i<syms_per_keycode;i++)
+ {
+ QINPUTGENERATOR_DEBUG()<<"keymap["<<i<<"]is:"<<XKeysymToString(keymap[i]);
+ }
+
+ if (sym == keymap[1] && sym != keymap[0]) {
+ ensureModifiers(Qt::ShiftModifier);
+ }
+
+ else if (sym == keymap[4]) {
+ ensureModifiers(Qt::AltModifier);
+ }
+
+ XFree(keymap);
+ break;
+ }
+
+ qWarning() << "QInputGenerator: don't know how to translate Qt key"
+ << (void*)key << "into X11 keysym";
+ return;
+
+ } while(0);
+
+ QINPUTGENERATOR_DEBUG() << (is_press ? "press" : "release") << XKeysymToString(sym);
+
+ XTestFakeKeyEvent(
+ dpy,
+ XKeysymToKeycode(dpy, sym),
+ is_press,
+ 0
+ );
+}
+
+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)
+{
+ Display* dpy = QX11Info::display();
+ if (!dpy) {
+ /* No X connection */
+ return;
+ }
+
+ if (currentPos != pos) {
+ currentPos = pos;
+
+ XTestFakeMotionEvent(
+ dpy,
+ QX11Info::appScreen(),
+ pos.x(),
+ pos.y(),
+ 0
+ );
+
+ 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,bool> ButtonEvent;
+ QList<ButtonEvent> buttonEvents;
+
+ foreach (int button, buttonmap.keys()) {
+ bool desired = button & state;
+ bool current = button & currentButtons;
+
+ // Do we need to press?
+ if (desired && !current) {
+ buttonEvents << qMakePair(buttonmap[button], true);
+ }
+
+ // Do we need to release?
+ if (!desired && current) {
+ buttonEvents << qMakePair(buttonmap[button], false);
+ }
+ }
+
+ foreach (ButtonEvent const& event, buttonEvents) {
+ QINPUTGENERATOR_DEBUG() << "Button event at" << pos << ":" << event.first << event.second;
+ XTestFakeButtonEvent(
+ dpy,
+ event.first,
+ event.second,
+ 0
+ );
+ }
+
+ 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);
+}
+