tests/auto/qinputcontext/tst_qinputcontext.cpp
changeset 37 758a864f9613
parent 18 2f34d5167611
--- a/tests/auto/qinputcontext/tst_qinputcontext.cpp	Fri Sep 17 08:34:18 2010 +0300
+++ b/tests/auto/qinputcontext/tst_qinputcontext.cpp	Mon Oct 04 01:19:32 2010 +0300
@@ -48,17 +48,27 @@
 #include <qlayout.h>
 #include <qradiobutton.h>
 #include <qwindowsstyle.h>
+#include <qdesktopwidget.h>
+#include <qpushbutton.h>
+
+#ifdef Q_OS_SYMBIAN
+#include <private/qt_s60_p.h>
+#include <private/qcoefepinputcontext_p.h>
+
+#include <w32std.h>
+#include <coecntrl.h>
+#endif
 
 class tst_QInputContext : public QObject
 {
 Q_OBJECT
 
 public:
-    tst_QInputContext() {}
+    tst_QInputContext() : m_phoneIsQwerty(false) {}
     virtual ~tst_QInputContext() {}
 
 public slots:
-    void initTestCase() {}
+    void initTestCase();
     void cleanupTestCase() {}
     void init() {}
     void cleanup() {}
@@ -69,8 +79,178 @@
     void closeSoftwareInputPanel();
     void selections();
     void focusProxy();
+    void symbianTestCoeFepInputContext_data();
+    void symbianTestCoeFepInputContext();
+    void symbianTestCoeFepAutoCommit_data();
+    void symbianTestCoeFepAutoCommit();
+
+private:
+    bool m_phoneIsQwerty;
 };
 
+#ifdef Q_OS_SYMBIAN
+class KeyEvent : public TWsEvent
+{
+public:
+    KeyEvent(QWidget *w, TInt type, TInt scanCode, TUint code, TUint modifiers, TInt repeats) {
+        iHandle = w->effectiveWinId()->DrawableWindow()->WindowGroupId();
+        iType = type;
+        SetTimeNow();
+        TKeyEvent *keyEvent = reinterpret_cast<TKeyEvent *>(iEventData);
+        keyEvent->iScanCode = scanCode;
+        keyEvent->iCode = code;
+        keyEvent->iModifiers = modifiers;
+        keyEvent->iRepeats = repeats;
+    }
+};
+
+class FepReplayEvent
+{
+public:
+    enum Type {
+        Pause,
+        Key,
+        CompleteKey
+    };
+
+    FepReplayEvent(int msecsToPause)
+        : m_type(Pause)
+        , m_msecsToPause(msecsToPause)
+    {
+    }
+
+    FepReplayEvent(TInt keyType, TInt scanCode, TUint code, TUint modifiers, TInt repeats)
+        : m_type(Key)
+        , m_keyType(keyType)
+        , m_scanCode(scanCode)
+        , m_code(code)
+        , m_modifiers(modifiers)
+        , m_repeats(repeats)
+    {
+    }
+
+    FepReplayEvent(TInt scanCode, TUint code, TUint modifiers, TInt repeats)
+        : m_type(CompleteKey)
+        , m_scanCode(scanCode)
+        , m_code(code)
+        , m_modifiers(modifiers)
+        , m_repeats(repeats)
+    {
+    }
+
+    void sendEvent(QWidget *w, TInt type, TInt scanCode, TUint code, TUint modifiers, TInt repeats)
+    {
+        KeyEvent event(w, type, scanCode, code, modifiers, repeats);
+        S60->wsSession().SendEventToWindowGroup(w->effectiveWinId()->DrawableWindow()->WindowGroupId(), event);
+    }
+
+    void pause(int msecs)
+    {
+        // Don't use qWait here. The polling nature of that function screws up the test.
+        QTimer timer;
+        QEventLoop loop;
+        QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
+        timer.setSingleShot(true);
+        timer.start(msecs);
+        loop.exec();
+    }
+
+    // For some reason, the test fails if using processEvents instead of an event loop
+    // with a zero timer to quit it, so use the timer.
+#define KEY_WAIT 0
+
+    void replay(QWidget *w)
+    {
+        if (m_type == Pause) {
+            pause(m_msecsToPause);
+        } else if (m_type == Key) {
+            sendEvent(w, m_keyType, m_scanCode, m_code, m_modifiers, m_repeats);
+            if (m_keyType != EEventKeyDown)
+                // EEventKeyDown events should have no pause before the EEventKey event.
+                pause(KEY_WAIT);
+        } else if (m_type == CompleteKey) {
+            sendEvent(w, EEventKeyDown, m_scanCode, 0, m_modifiers, m_repeats);
+            // EEventKeyDown events should have no pause before the EEventKey event.
+            sendEvent(w, EEventKey, m_scanCode, m_code, m_modifiers, m_repeats);
+            pause(KEY_WAIT);
+            sendEvent(w, EEventKeyUp, m_scanCode, 0, m_modifiers, m_repeats);
+            pause(KEY_WAIT);
+        }
+    }
+
+private:
+    Type m_type;
+    int m_msecsToPause;
+    TInt m_keyType;
+    TInt m_scanCode;
+    TUint m_code;
+    TUint m_modifiers;
+    TInt m_repeats;
+};
+
+Q_DECLARE_METATYPE(QList<FepReplayEvent>)
+Q_DECLARE_METATYPE(Qt::InputMethodHints)
+Q_DECLARE_METATYPE(QLineEdit::EchoMode);
+
+#endif // Q_OS_SYMBIAN
+
+void tst_QInputContext::initTestCase()
+{
+#ifdef Q_OS_SYMBIAN
+    // Sanity test. Checks FEP for:
+    // - T9 mode is default (it will attempt to fix this)
+    // - Language is English (it cannot fix this; bail out if not correct)
+    QWidget w;
+    QLayout *layout = new QVBoxLayout;
+    w.setLayout(layout);
+    QLineEdit *lineedit = new QLineEdit;
+    layout->addWidget(lineedit);
+    lineedit->setFocus();
+#ifdef QT_KEYPAD_NAVIGATION
+    lineedit->setEditFocus(true);
+#endif
+    w.show();
+
+    QDesktopWidget desktop;
+    QRect screenSize = desktop.screenGeometry(&w);
+    if (screenSize.width() > screenSize.height()) {
+        // Crude way of finding out we are running on a qwerty phone.
+        m_phoneIsQwerty = true;
+        return;
+    }
+
+    for (int iterations = 0; iterations < 16; iterations++) {
+        QTest::qWait(500);
+
+        QList<FepReplayEvent> keyEvents;
+
+        keyEvents << FepReplayEvent('9', '9', 0, 0);
+        keyEvents << FepReplayEvent('6', '6', 0, 0);
+        keyEvents << FepReplayEvent('8', '8', 0, 0);
+        keyEvents << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0);
+
+        foreach(FepReplayEvent event, keyEvents) {
+            event.replay(lineedit);
+        }
+
+        QApplication::processEvents();
+
+        if (lineedit->text().endsWith("you", Qt::CaseInsensitive)) {
+            // Success!
+            return;
+        }
+
+        // Try changing modes.
+        // After 8 iterations, try to press the mode switch twice before typing.
+        for (int c = 0; c <= iterations / 8; c++) {
+            FepReplayEvent(EStdKeyHash, '#', 0, 0).replay(lineedit);
+        }
+    }
+
+    QFAIL("FEP sanity test failed. Either the phone is not set to English, or the test was unable to enable T9");
+#endif
+}
+
 void tst_QInputContext::maximumTextLength()
 {
     QLineEdit le;
@@ -271,7 +451,6 @@
 
     QInputContext *gic = qApp->inputContext();
     QVERIFY(gic);
-    qDebug() << gic->focusWidget() << &proxy;
     QCOMPARE(gic->focusWidget(), &proxy);
 
     // then change the focus proxy and check that input context is valid
@@ -285,5 +464,601 @@
     QCOMPARE(gic->focusWidget(), &proxy);
 }
 
+void tst_QInputContext::symbianTestCoeFepInputContext_data()
+{
+#ifdef Q_OS_SYMBIAN
+    QTest::addColumn<bool>                   ("inputMethodEnabled");
+    QTest::addColumn<Qt::InputMethodHints>   ("inputMethodHints");
+    QTest::addColumn<int>                    ("maxLength"); // Zero for no limit
+    QTest::addColumn<QLineEdit::EchoMode>    ("echoMode");
+    QTest::addColumn<QList<FepReplayEvent> > ("keyEvents");
+    QTest::addColumn<QString>                ("finalString");
+    QTest::addColumn<QString>                ("preeditString");
+    QList<FepReplayEvent> events;
+
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    events << FepReplayEvent('5', '5', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('6', '6', 0, 0);
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    events << FepReplayEvent('1', '1', 0, 0);
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    events << FepReplayEvent('2', '2', 0, 0);
+    events << FepReplayEvent('1', '1', 0, 0);
+    QTest::newRow("Numbers (no FEP)")
+            << false
+            << Qt::InputMethodHints(Qt::ImhNone)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("521")
+            << QString("");
+    QTest::newRow("Numbers and password mode (no FEP)")
+            << false
+            << Qt::InputMethodHints(Qt::ImhNone)
+            << 0
+            << QLineEdit::Password
+            << events
+            << QString("521")
+            << QString("");
+    QTest::newRow("Numbers")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("521")
+            << QString("");
+    QTest::newRow("Numbers max length (no FEP)")
+            << false
+            << Qt::InputMethodHints(Qt::ImhNone)
+            << 2
+            << QLineEdit::Normal
+            << events
+            << QString("21")
+            << QString("");
+    QTest::newRow("Numbers max length")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 2
+            << QLineEdit::Normal
+            << events
+            << QString("21")
+            << QString("");
+    events.clear();
+
+    events << FepReplayEvent(EEventKeyDown, '5', 0, 0, 0);
+    events << FepReplayEvent(EEventKey, '5', '5', 0, 0);
+    events << FepReplayEvent(EEventKey, '5', '5', 0, 1);
+    events << FepReplayEvent(EEventKey, '5', '5', 0, 1);
+    events << FepReplayEvent(EEventKeyUp, '5', 0, 0, 0);
+    QTest::newRow("Numbers and autorepeat (no FEP)")
+            << false
+            << Qt::InputMethodHints(Qt::ImhNone)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("555")
+            << QString("");
+    events.clear();
+
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    events << FepReplayEvent('2', '2', 0, 0);
+    events << FepReplayEvent('3', '3', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('5', '5', 0, 0);
+    events << FepReplayEvent('5', '5', 0, 0);
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    QTest::newRow("Multitap")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("Adh")
+            << QString("");
+    QTest::newRow("Multitap with no auto uppercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("adh")
+            << QString("");
+    QTest::newRow("Multitap with uppercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferUppercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("ADH")
+            << QString("");
+    QTest::newRow("Multitap with lowercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("adh")
+            << QString("");
+    QTest::newRow("Multitap with forced uppercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhUppercaseOnly)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("ADH")
+            << QString("");
+    QTest::newRow("Multitap with forced lowercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhLowercaseOnly)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("adh")
+            << QString("");
+    events.clear();
+
+    events << FepReplayEvent(EStdKeyHash, '#', 0, 0);
+    events << FepReplayEvent('2', '2', 0, 0);
+    events << FepReplayEvent('2', '2', 0, 0);
+    events << FepReplayEvent('3', '3', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('5', '5', 0, 0);
+    events << FepReplayEvent('5', '5', 0, 0);
+    events << FepReplayEvent(EStdKeyBackspace, EKeyBackspace, 0, 0);
+    QTest::newRow("Multitap with mode switch")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("bdh")
+            << QString("");
+    events.clear();
+
+    events << FepReplayEvent('7', '7', 0, 0);
+    events << FepReplayEvent('7', '7', 0, 0);
+    events << FepReplayEvent('8', '8', 0, 0);
+    events << FepReplayEvent('9', '9', 0, 0);
+    events << FepReplayEvent('9', '9', 0, 0);
+    QTest::newRow("Multitap with unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("Qt")
+            << QString("x");
+    events << FepReplayEvent(2000);
+    QTest::newRow("Multitap with committed text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("Qtx")
+            << QString("");
+    events.clear();
+
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    // Simulate holding down hash key.
+    events << FepReplayEvent(EEventKeyDown, EStdKeyHash, 0, 0, 0);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 0);
+    events << FepReplayEvent(500);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1);
+    events << FepReplayEvent(EEventKeyUp, EStdKeyHash, 0, 0, 0);
+    events << FepReplayEvent('7', '7', 0, 0);
+    events << FepReplayEvent('7', '7', 0, 0);
+    events << FepReplayEvent('8', '8', 0, 0);
+    // QTBUG-9867: Switch back as well to make sure we don't get extra symbols
+    events << FepReplayEvent(EEventKeyDown, EStdKeyHash, 0, 0, 0);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 0);
+    events << FepReplayEvent(500);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1);
+    events << FepReplayEvent(EEventKey, EStdKeyHash, '#', 0, 1);
+    events << FepReplayEvent(EEventKeyUp, EStdKeyHash, 0, 0, 0);
+    events << FepReplayEvent('9', '9', 0, 0);
+    events << FepReplayEvent('6', '6', 0, 0);
+    events << FepReplayEvent('8', '8', 0, 0);
+    events << FepReplayEvent(2000);
+    events << FepReplayEvent(EStdKeyDevice3, EKeyDevice3, 0, 0); // Select key
+    QTest::newRow("Multitap and numbers")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("H778wmt")
+            << QString("");
+    QTest::newRow("T9 and numbers")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("hi778you")
+            << QString("");
+    events.clear();
+
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent(EStdKeyDevice3, EKeyDevice3, 0, 0); // Select key
+    QTest::newRow("T9")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("hi")
+            << QString("");
+    QTest::newRow("T9 with uppercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferUppercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("HI")
+            << QString("");
+    QTest::newRow("T9 with forced lowercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhLowercaseOnly)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("hi")
+            << QString("");
+    QTest::newRow("T9 with forced uppercase")
+            << true
+            << Qt::InputMethodHints(Qt::ImhUppercaseOnly)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("HI")
+            << QString("");
+    QTest::newRow("T9 with maxlength")
+            << true
+            << Qt::InputMethodHints(Qt::ImhLowercaseOnly)
+            << 1
+            << QLineEdit::Normal
+            << events
+            << QString("i")
+            << QString("");
+    events.clear();
+
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent(EStdKeyLeftArrow, EKeyLeftArrow, 0, 0);
+    events << FepReplayEvent(EStdKeyLeftArrow, EKeyLeftArrow, 0, 0);
+    events << FepReplayEvent('9', '9', 0, 0);
+    events << FepReplayEvent('6', '6', 0, 0);
+    events << FepReplayEvent('8', '8', 0, 0);
+    events << FepReplayEvent('0', '0', 0, 0);
+    events << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0);
+    events << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0);
+    events << FepReplayEvent('8', '8', 0, 0);
+    events << FepReplayEvent('8', '8', 0, 0);
+    QTest::newRow("T9 with movement and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("you hi")
+            << QString("tv");
+    QTest::newRow("T9 with movement, password and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Password
+            << events
+            << QString("wmt h")
+            << QString("u");
+    QTest::newRow("T9 with movement, maxlength, password and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 2
+            << QLineEdit::Password
+            << events
+            << QString("wh")
+            << QString("");
+    QTest::newRow("T9 with movement, maxlength and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 2
+            << QLineEdit::Normal
+            << events
+            << QString("hi")
+            << QString("");
+    QTest::newRow("Multitap with movement and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("wmt h")
+            << QString("u");
+    QTest::newRow("Multitap with movement, maxlength and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase)
+            << 2
+            << QLineEdit::Normal
+            << events
+            << QString("wh")
+            << QString("");
+    QTest::newRow("Numbers with movement")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("96804488")
+            << QString("");
+    QTest::newRow("Numbers with movement and maxlength")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 2
+            << QLineEdit::Normal
+            << events
+            << QString("44")
+            << QString("");
+    QTest::newRow("Numbers with movement, password and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 0
+            << QLineEdit::Password
+            << events
+            << QString("9680448")
+            << QString("8");
+    QTest::newRow("Numbers with movement, maxlength, password and unfinished text")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 2
+            << QLineEdit::Password
+            << events
+            << QString("44")
+            << QString("");
+    events << FepReplayEvent(EStdKeyRightArrow, EKeyRightArrow, 0, 0);
+    QTest::newRow("T9 with movement")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("you htvi")
+            << QString("");
+    QTest::newRow("T9 with movement and password")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Password
+            << events
+            << QString("wmt hu")
+            << QString("");
+    QTest::newRow("T9 with movement, maxlength and password")
+            << true
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << 2
+            << QLineEdit::Password
+            << events
+            << QString("wh")
+            << QString("");
+    QTest::newRow("Multitap with movement")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase)
+            << 0
+            << QLineEdit::Normal
+            << events
+            << QString("wmt hu")
+            << QString("");
+    QTest::newRow("Multitap with movement and maxlength")
+            << true
+            << Qt::InputMethodHints(Qt::ImhNoPredictiveText | Qt::ImhPreferLowercase)
+            << 2
+            << QLineEdit::Normal
+            << events
+            << QString("wh")
+            << QString("");
+    QTest::newRow("Numbers with movement and password")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 0
+            << QLineEdit::Password
+            << events
+            << QString("96804488")
+            << QString("");
+    QTest::newRow("Numbers with movement, maxlength and password")
+            << true
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << 2
+            << QLineEdit::Password
+            << events
+            << QString("44")
+            << QString("");
+    events.clear();
+#endif
+}
+
+void tst_QInputContext::symbianTestCoeFepInputContext()
+{
+#ifndef Q_OS_SYMBIAN
+    QSKIP("This is a Symbian-only test", SkipAll);
+#else
+    QCoeFepInputContext *ic = qobject_cast<QCoeFepInputContext *>(qApp->inputContext());
+    if (!ic) {
+        QSKIP("coefep is not the active input context; skipping test", SkipAll);
+    }
+
+    QFETCH(bool,                  inputMethodEnabled);
+    QFETCH(Qt::InputMethodHints,  inputMethodHints);
+    QFETCH(int,                   maxLength);
+    QFETCH(QLineEdit::EchoMode,   echoMode);
+    QFETCH(QList<FepReplayEvent>, keyEvents);
+    QFETCH(QString,               finalString);
+    QFETCH(QString,               preeditString);
+
+    if (inputMethodEnabled && m_phoneIsQwerty) {
+        QSKIP("Skipping advanced input method tests on QWERTY phones", SkipSingle);
+    }
+
+    QWidget w;
+    QLayout *layout = new QVBoxLayout;
+    w.setLayout(layout);
+    QLineEdit *lineedit = new QLineEdit;
+    layout->addWidget(lineedit);
+    lineedit->setFocus();
+#ifdef QT_KEYPAD_NAVIGATION
+    lineedit->setEditFocus(true);
+#endif
+    w.show();
+
+    lineedit->setAttribute(Qt::WA_InputMethodEnabled, inputMethodEnabled);
+    lineedit->setInputMethodHints(inputMethodHints);
+    if (maxLength > 0)
+        lineedit->setMaxLength(maxLength);
+    lineedit->setEchoMode(echoMode);
+
+    QTest::qWait(200);
+
+    foreach(FepReplayEvent event, keyEvents) {
+        event.replay(lineedit);
+    }
+
+    QApplication::processEvents();
+
+    QCOMPARE(lineedit->text(), finalString);
+    QCOMPARE(ic->m_preeditString, preeditString);
+#endif
+}
+
+void tst_QInputContext::symbianTestCoeFepAutoCommit_data()
+{
+#ifdef Q_OS_SYMBIAN
+    QTest::addColumn<Qt::InputMethodHints>   ("inputMethodHints");
+    QTest::addColumn<QLineEdit::EchoMode>    ("echoMode");
+    QTest::addColumn<QList<FepReplayEvent> > ("keyEvents");
+    QTest::addColumn<QString>                ("finalString");
+
+    QList<FepReplayEvent> events;
+
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('4', '4', 0, 0);
+    events << FepReplayEvent('0', '0', 0, 0);
+    events << FepReplayEvent('9', '9', 0, 0);
+    events << FepReplayEvent('6', '6', 0, 0);
+    events << FepReplayEvent('8', '8', 0, 0);
+    QTest::newRow("Numbers")
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << QLineEdit::Normal
+            << events
+            << QString("440968");
+    QTest::newRow("Numbers and password")
+            << Qt::InputMethodHints(Qt::ImhDigitsOnly)
+            << QLineEdit::Password
+            << events
+            << QString("440968");
+    QTest::newRow("Multitap")
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase | Qt::ImhNoPredictiveText)
+            << QLineEdit::Normal
+            << events
+            << QString("h wmt");
+    QTest::newRow("T9")
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << QLineEdit::Normal
+            << events
+            << QString("hi you");
+    QTest::newRow("Multitap with password")
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase | Qt::ImhNoPredictiveText)
+            << QLineEdit::Password
+            << events
+            << QString("h wmt");
+    QTest::newRow("T9 with password")
+            << Qt::InputMethodHints(Qt::ImhPreferLowercase)
+            << QLineEdit::Password
+            << events
+            << QString("h wmt");
+#endif
+}
+
+void tst_QInputContext::symbianTestCoeFepAutoCommit()
+{
+#ifndef Q_OS_SYMBIAN
+    QSKIP("This is a Symbian-only test", SkipAll);
+#else
+    QCoeFepInputContext *ic = qobject_cast<QCoeFepInputContext *>(qApp->inputContext());
+    if (!ic) {
+        QSKIP("coefep is not the active input context; skipping test", SkipAll);
+    }
+
+    QFETCH(Qt::InputMethodHints,  inputMethodHints);
+    QFETCH(QLineEdit::EchoMode,   echoMode);
+    QFETCH(QList<FepReplayEvent>, keyEvents);
+    QFETCH(QString,               finalString);
+
+    if (m_phoneIsQwerty) {
+        QSKIP("Skipping advanced input method tests on QWERTY phones", SkipSingle);
+    }
+
+    QWidget w;
+    QLayout *layout = new QVBoxLayout;
+    w.setLayout(layout);
+    QLineEdit *lineedit = new QLineEdit;
+    layout->addWidget(lineedit);
+    lineedit->setFocus();
+#ifdef QT_KEYPAD_NAVIGATION
+    lineedit->setEditFocus(true);
+#endif
+    QPushButton *pushButton = new QPushButton("Done");
+    layout->addWidget(pushButton);
+    QAction softkey("Done", &w);
+    softkey.setSoftKeyRole(QAction::PositiveSoftKey);
+    w.addAction(&softkey);
+    w.show();
+
+    lineedit->setInputMethodHints(inputMethodHints);
+    lineedit->setEchoMode(echoMode);
+
+    QTest::qWait(200);
+    foreach(FepReplayEvent event, keyEvents) {
+        event.replay(lineedit);
+    }
+    QApplication::processEvents();
+
+    QTest::mouseClick(pushButton, Qt::LeftButton);
+
+    QCOMPARE(lineedit->text(), finalString);
+    QVERIFY(ic->m_preeditString.isEmpty());
+
+#ifdef Q_WS_S60
+    lineedit->inputContext()->reset();
+    lineedit->clear();
+    lineedit->setFocus();
+#ifdef QT_KEYPAD_NAVIGATION
+    lineedit->setEditFocus(true);
+#endif
+
+    QTest::qWait(200);
+    foreach(FepReplayEvent event, keyEvents) {
+        event.replay(lineedit);
+    }
+    QApplication::processEvents();
+
+    FepReplayEvent(EStdKeyDevice0, EKeyDevice0, 0, 0).replay(lineedit); // Left softkey
+
+    QCOMPARE(lineedit->text(), finalString);
+    QVERIFY(ic->m_preeditString.isEmpty());
+
+#endif // Q_WS_S60
+#endif // Q_OS_SYMBIAN
+}
+
 QTEST_MAIN(tst_QInputContext)
 #include "tst_qinputcontext.moc"