summaryrefslogtreecommitdiffstats
path: root/old/libqtuitest/qinputgenerator_qws.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'old/libqtuitest/qinputgenerator_qws.cpp')
-rw-r--r--old/libqtuitest/qinputgenerator_qws.cpp333
1 files changed, 333 insertions, 0 deletions
diff --git a/old/libqtuitest/qinputgenerator_qws.cpp b/old/libqtuitest/qinputgenerator_qws.cpp
new file mode 100644
index 0000000..657f34e
--- /dev/null
+++ b/old/libqtuitest/qinputgenerator_qws.cpp
@@ -0,0 +1,333 @@
+/****************************************************************************
+**
+** 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 <QCopChannel>
+#include <QDebug>
+#include <QKeySequence>
+#include <QScreen>
+#include <QWSServer>
+#include <QWidget>
+
+#include "qtuitestnamespace.h"
+
+#ifdef QTOPIA_TARGET
+# include <qtopialog.h>
+# define QINPUTGENERATOR_DEBUG() qLog(QtUitest)
+#else
+# define QINPUTGENERATOR_DEBUG() if (1); else qDebug() << "QInputGenerator:"
+#endif
+
+#define QINPUTGENERATOR_QCOP "QtUiTest/QInputGenerator"
+#define QINPUTGENERATOR_QCOP_KEYEVENT "keyEvent(int,int,int,bool)"
+#define QINPUTGENERATOR_QCOP_VERSION QDataStream::Qt_4_0
+
+struct QInputGeneratorPrivate
+{
+ QInputGeneratorPrivate();
+ QInputGenerator* q;
+
+ enum KeyEventType { KeyPress, KeyRelease, KeyClick };
+ enum MouseEventType { MousePress, MouseRelease, MouseClick };
+
+ void keyEvent (Qt::Key, Qt::KeyboardModifiers, KeyEventType, bool = false);
+ void mouseEvent(QPoint const&, Qt::MouseButtons, MouseEventType);
+
+ void ensureModifiers(Qt::KeyboardModifiers);
+
+ Qt::KeyboardModifiers currentModifiers;
+};
+
+struct QInputGeneratorService : public QCopChannel
+{
+ QInputGeneratorService(QInputGeneratorPrivate*,QObject* =0);
+
+ virtual void receive(QString const&,QByteArray const&);
+
+ QInputGeneratorPrivate* d;
+};
+
+QInputGeneratorService::QInputGeneratorService(QInputGeneratorPrivate* _d, QObject* parent)
+ : QCopChannel(QINPUTGENERATOR_QCOP, parent),
+ d(_d)
+{
+ Q_ASSERT(qApp->type() == qApp->GuiServer);
+}
+
+void QInputGeneratorService::receive(QString const& message, QByteArray const& data)
+{
+ if (message == QLatin1String(QINPUTGENERATOR_QCOP_KEYEVENT)) {
+ int key = 0;
+ int mod = 0;
+ int type = 0;
+ bool autoRepeat = false;
+
+ QByteArray copy(data);
+ QDataStream ds(&copy, QIODevice::ReadOnly);
+ ds.setVersion(QINPUTGENERATOR_QCOP_VERSION);
+ ds >> key >> mod >> type >> autoRepeat;
+
+ if (ds.status() != QDataStream::Ok) {
+ qWarning() << "QtUitest: error deserializing " QINPUTGENERATOR_QCOP_KEYEVENT
+ " message, a key event might be lost.";
+ } else {
+ Qt::KeyboardModifiers qtMod(mod);
+ d->ensureModifiers(qtMod);
+ d->keyEvent(Qt::Key(key), qtMod, static_cast<QInputGeneratorPrivate::KeyEventType>(type), autoRepeat);
+ }
+ } else {
+ qWarning() << "QtUitest: QInputGenerator received unknown message" << message;
+ }
+}
+
+QInputGeneratorPrivate::QInputGeneratorPrivate()
+ : q(0)
+ , currentModifiers(0)
+{}
+
+QInputGenerator::QInputGenerator(QObject* parent)
+ : QObject(parent),
+ d(new QInputGeneratorPrivate)
+{
+ d->q = this;
+ if (qApp->type() == qApp->GuiServer) {
+ new QInputGeneratorService(d, this);
+ }
+}
+
+QInputGenerator::~QInputGenerator()
+{
+ d->ensureModifiers(0);
+ d->q = 0;
+ delete d;
+ d = 0;
+}
+
+void QInputGeneratorPrivate::keyEvent(Qt::Key key, Qt::KeyboardModifiers mod, KeyEventType type, bool autoRepeat)
+{
+ if (qApp->type() != qApp->GuiServer) {
+ QByteArray data;
+ {
+ QDataStream ds(&data,QIODevice::WriteOnly);
+ ds.setVersion(QINPUTGENERATOR_QCOP_VERSION);
+ ds << int(key) << int(mod) << int(type) << autoRepeat;
+ if (ds.status() != QDataStream::Ok) {
+ qWarning() << "QtUitest: error serializing " QINPUTGENERATOR_QCOP_KEYEVENT
+ " message, a key event might be lost.";
+ }
+ }
+ if (!QCopChannel::send(QINPUTGENERATOR_QCOP, QINPUTGENERATOR_QCOP_KEYEVENT, data)) {
+ qWarning() << "QtUitest: error sending " QINPUTGENERATOR_QCOP_KEYEVENT
+ " message, a key event might be lost.";
+ }
+ return;
+ }
+
+ QINPUTGENERATOR_DEBUG() << "about to simulate key"
+ << ((type==KeyPress) ? "press" : ((type==KeyRelease) ? "release" : "click"))
+ << QKeySequence(key|mod).toString() << "autorepeat" << QString("%1").arg(autoRepeat);
+
+ ushort unicode = 0;
+ if (key <= 0xff) {
+ QChar ch(key);
+ // FIXME this should be less of a hack. The case should not implicitly depend on mod.
+ if (mod & Qt::ShiftModifier) ch = ch.toUpper();
+ else ch = ch.toLower();
+ unicode = ch.unicode();
+ }
+
+ /*
+ The screensaver may consume key events.
+ There is no way to query the server to determine if the next key event will be consumed,
+ or even if the screensaver is currently active. All we can do is force the screensaver
+ (if any) to wake up before every key event to ensure none of them are consumed.
+ */
+ if (!QMetaObject::invokeMethod(QWSServer::instance(), "_q_screenSaverWake"))
+ Q_ASSERT(0);
+
+ QWSServer::processKeyEvent(unicode, key, mod, (type != KeyRelease), autoRepeat);
+
+ if (type == KeyClick) {
+ // Key press/release should not occur in same millisecond
+ QtUiTest::wait(10);
+ QWSServer::processKeyEvent(unicode, key, mod, false, autoRepeat);
+ }
+
+ QINPUTGENERATOR_DEBUG() << "simulated key"
+ << ((type==KeyPress) ? "press" : ((type==KeyRelease) ? "release" : "click"))
+ << QKeySequence(key|mod).toString() << "autorepeat" << QString("%1").arg(autoRepeat);
+}
+
+void QInputGenerator::keyPress(Qt::Key key, Qt::KeyboardModifiers mod, bool autoRepeat)
+{
+ if (qApp->type() == qApp->GuiServer) {
+ d->ensureModifiers(mod);
+ }
+ d->keyEvent(key, mod, d->KeyPress, autoRepeat);
+}
+
+void QInputGenerator::keyRelease(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ if (qApp->type() == qApp->GuiServer) {
+ d->ensureModifiers(mod);
+ }
+ d->keyEvent(key, mod, d->KeyRelease);
+}
+
+void QInputGenerator::keyClick(Qt::Key key, Qt::KeyboardModifiers mod)
+{
+ if (qApp->type() == qApp->GuiServer) {
+ d->ensureModifiers(mod);
+ }
+ d->keyEvent(key, mod, d->KeyClick);
+}
+
+void QInputGeneratorPrivate::mouseEvent(QPoint const& local, Qt::MouseButtons state, MouseEventType type)
+{
+ QPoint pos(q->mapFromActiveWindow(local));
+
+ QINPUTGENERATOR_DEBUG() << "about to simulate mouse"
+ << ((type==MousePress) ? "press" : ((type==MouseRelease) ? "release" : "click"));
+
+ Q_ASSERT(pos.x() >= 0 && pos.x() < QScreen::instance()->width()
+ && pos.y() >= 0 && pos.y() < QScreen::instance()->height());
+
+ // When a mouse click occurs while an input method is currently active,
+ // and the click goes to a non-qpe window, there's a fair chance it will
+ // cause the current IM to change.
+ // We'd better wait for it, because it can cause widgets to be resized
+ // and hence screw up subsequent clicks.
+ struct InputMethods {
+ static QWidget* widget()
+ {
+ static QWidget* inputMethods = 0;
+ if (!inputMethods) {
+ QWidgetList wl(QApplication::topLevelWidgets());
+ foreach (QWidget *w, wl) {
+ inputMethods = w->findChild<QWidget*>("InputMethods");
+ if (inputMethods) break;
+ }
+ }
+ return inputMethods;
+ }
+
+ static QString current()
+ {
+ QString ret;
+ if (InputMethods::widget()) {
+ QMetaObject::invokeMethod(InputMethods::widget(), "currentShown",
+ Qt::DirectConnection, Q_RETURN_ARG(QString, ret));
+ }
+ return ret;
+
+ }
+ };
+
+ QWSWindow *win = QWSServer::instance()->windowAt(pos);
+ QString client_before_click = (win ? win->client()->identity() : QString());
+ QString im_before_click = InputMethods::current();
+
+ QWSServer::sendMouseEvent(pos, (MouseRelease == type) ? Qt::MouseButtons(0) : state, 0);
+
+ if (type == MouseClick) {
+ // This wait is to avoid the mouse press and release occurring in
+ // the same millisecond, which surely won't happen with real
+ // hardware and wouldn't be unlikely to confuse some apps.
+ QtUiTest::wait(10);
+ QWSServer::sendMouseEvent(pos, 0, 0);
+ }
+
+ if (type == MouseClick && client_before_click != "qpe"
+ && !im_before_click.isEmpty()) {
+ for (int i = 0;
+ i < 500 && InputMethods::current() == im_before_click;
+ i += 50, QtUiTest::wait(50)) {}
+ }
+
+ QINPUTGENERATOR_DEBUG() << "simulated mouse"
+ << ((type==MousePress) ? "press" : ((type==MouseRelease) ? "release" : "click"));
+}
+
+void QInputGenerator::mousePress(QPoint const& pos, Qt::MouseButtons state)
+{ d->mouseEvent(pos, state, d->MousePress); }
+
+void QInputGenerator::mouseRelease(QPoint const& pos, Qt::MouseButtons state)
+{ d->mouseEvent(pos, state, d->MouseRelease); }
+
+void QInputGenerator::mouseClick(QPoint const& pos, Qt::MouseButtons state)
+{ d->mouseEvent(pos, state, d->MouseClick); }
+
+void QInputGeneratorPrivate::ensureModifiers(Qt::KeyboardModifiers desiredMod)
+{
+ if (currentModifiers == desiredMod) return;
+
+ Qt::KeyboardModifiers incrementalMod = 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) && !(currentModifiers & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Enabling modifier" << (void*)thisMod << "by press";
+ incrementalMod |= thisMod;
+ keyEvent(q->modifierToKey(thisMod), incrementalMod, KeyPress, false);
+ } else if (!(desiredMod & thisMod) && (currentModifiers & thisMod)) {
+ QINPUTGENERATOR_DEBUG() << "Disabling modifier" << (void*)thisMod << "by release";
+ incrementalMod &= ~thisMod;
+ keyEvent(q->modifierToKey(thisMod), incrementalMod, KeyRelease, false);
+ }
+ }
+
+ /*
+ On QWS, we cannot check if QApplication::keyboardModifiers() changes to the desired
+ state. That function returns whatever modifiers were set on the last spontaneous
+ input event, and the modifiers set on input events are the modifiers _before_ the
+ event occurred (e.g. the Shift key press event does not have the Shift modifier set,
+ but the next key event does).
+
+ So QApplication::keyboardModifiers() is off-by-one and thus can't be checked until
+ the next event occurs - we're just assuming success.
+ */
+ currentModifiers = desiredMod;
+
+}
+
+