[meego-commits] 14385: Changes to Trunk/meegotouch-inputmethodkeyboard

Peter Zhu no_reply at build.meego.com
Tue Mar 1 12:55:10 UTC 2011


Hi,
I have made the following changes to meegotouch-inputmethodkeyboard in project Trunk. Please review and accept ASAP.

Thank You,
Peter Zhu

[This message was auto-generated]

---

Request #14385:

  submit:   Trunk:Testing/meegotouch-inputmethodkeyboard(r2) -> Trunk/meegotouch-inputmethodkeyboard


Message:
    Move to Trunk

State:   new          2011-02-28T23:53:08 peter
Comment: None



changes files:
--------------
--- meegotouch-inputmethodkeyboard.changes
+++ meegotouch-inputmethodkeyboard.changes
@@ -0,0 +1,8 @@
+* Thu Feb 24 2011 Luis Araujo <luis.araujo at collabora.co.uk> - 0.5.28
+- Update to release tag 0.5.28-1 (BMC#13345, BMC#12978)
+
+* Fri Feb 04 2011 Luis Araujo <luis.araujo at collabora.co.uk> - 0.5.26
+- Update to release tag 0.5.26-1 (BMC#13233)
+- Add version dependency on framework >= 0.19.41, meegotouch >= 0.20.77
+- Update files paths
+

old:
----
  meegotouch-inputmethodkeyboard-0.5.25.tar.bz2

new:
----
  meegotouch-inputmethodkeyboard-0.5.28.tar.bz2

spec files:
-----------
--- meegotouch-inputmethodkeyboard.spec
+++ meegotouch-inputmethodkeyboard.spec
@@ -7,20 +7,17 @@
 
 Name:       meegotouch-inputmethodkeyboard
 Summary:    MeeGo Virtual Keyboard
-Version:    0.5.25
+Version:    0.5.28
 Release:    1
 Group:      System/GUI/Other
 License:    LGPLv2.1
 URL:        http://meego.gitorious.org/meegotouch/meegotouch-inputmethodkeyboard
 Source0:    %{name}-%{version}.tar.bz2
 Source100:  meegotouch-inputmethodkeyboard.yaml
-Requires(pre): GConf2
-Requires(preun): GConf2
-Requires(post): GConf2
 BuildRequires:  pkgconfig(QtGui) >= 4.6.0
 BuildRequires:  pkgconfig(MeegoImEngine) >= 0.4.1
-BuildRequires:  pkgconfig(MeegoImFramework) >= 0.19.40
-BuildRequires:  pkgconfig(meegotouch) >= 0.20
+BuildRequires:  pkgconfig(MeegoImFramework) >= 0.19.41
+BuildRequires:  pkgconfig(meegotouch) >= 0.20.77
 BuildRequires:  pkgconfig(meegotouch-feedbackreactionmaps)
 BuildRequires:  pkgconfig(x11)
 BuildRequires:  pkgconfig(xkbfile) >= 1.0.6
@@ -85,26 +82,8 @@
 # >> install post
 # << install post
 
-%pre
-if [ "$1" -gt 1 ]; then
-  export GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source`
-  gconftool-2 --makefile-uninstall-rule \
-    %{_datadir}/gconf/schemas/meego-keyboard.schemas \
-    > /dev/null || :
-fi
-
-%preun
-if [ "$1" -eq 0 ]; then
-  export GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source`
-  gconftool-2 --makefile-uninstall-rule \
-    %{_datadir}/gconf/schemas/meego-keyboard.schemas \
-    > /dev/null || :
-fi
-
-%post
-export GCONF_CONFIG_SOURCE=`gconftool-2 --get-default-source`
-gconftool-2 --makefile-install-rule \
-    %{_datadir}/gconf/schemas/meego-keyboard.schemas  > /dev/null || :
+
+
 
 
 

other changes:
--------------

++++++ meegotouch-inputmethodkeyboard-0.5.25.tar.bz2 -> meegotouch-inputmethodkeyboard-0.5.28.tar.bz2
--- debian/changelog
+++ debian/changelog
@@ -1,8 +1,28 @@
-meego-keyboard (0.5.26~1) unstable; urgency=low
+meego-keyboard (0.5.29~1) unstable; urgency=low
 
   * [UNRELEASED]
 
- -- huaming wang <huaming.wang at nokia.com>  Wed, 26 Jan 2011 10:31:42 +0200
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Thu, 24 Feb 2011 13:35:46 +0200
+
+meego-keyboard (0.5.28-1) unstable; urgency=low
+
+  * New release
+
+ -- Pekka Vuorela <pekka.ta.vuorela at nokia.com>  Thu, 24 Feb 2011 13:34:10 +0200
+
+meego-keyboard (0.5.27-1) unstable; urgency=low
+
+  * Fixes: NB#228917 - meego-keyboard provides dev package with missing dependencies
+
+ -- huaming wang <huaming.wang at nokia.com>  Wed, 23 Feb 2011 16:16:40 +0200
+
+meego-keyboard (0.5.26-1) unstable; urgency=low
+
+  * Fixes: NB#218821 - With the VKB default language as English(UK), error correction and word completion are not working
+  * Fixes: NB#222168 - libmeegotouch in can't uphold locked window orientation
+  * Fixes: unwanted long presses in case of delays in event delivery
+
+ -- huaming wang <huaming.wang at nokia.com>  Thu, 03 Feb 2011 13:18:26 +0200
 
 meego-keyboard (0.5.25-1) unstable; urgency=low
 
--- debian/control
+++ debian/control
@@ -2,7 +2,7 @@
 Section: libs
 Priority: extra
 Maintainer: Mohammad Anwari <Mohammad.Anwari at nokia.com> 
-Build-Depends: debhelper (>= 5), libqt4-dev (>= 4.6), doxygen, libmeegoimengine-dev (>= 0.4.1), libmeegoimframework-dev (>= 0.19.40~1), libmeegotouch-dev (>= 0.20), libmeegoreactionmap-dev (>= 0.14.0-1), libxkbfile-dev (>= 1.0.6)
+Build-Depends: debhelper (>= 5), libqt4-dev (>= 4.6), doxygen, libmeegoimengine-dev (>= 0.4.1), libmeegoimframework-dev (>= 0.19.41~1), libmeegotouch-dev (>= 0.20), libmeegoreactionmap-dev (>= 0.14.0-1), libxkbfile-dev (>= 1.0.6)
 Standards-Version: 3.7.2
 
 Package: meego-keyboard
@@ -21,7 +21,7 @@
 Package: meego-keyboard-dev
 Section: devel
 Architecture: all
-Depends:  meego-keyboard (= ${binary:Version}) 
+Depends:  meego-keyboard (= ${binary:Version}), libqt4-dev (>= 4.6), libmeegotouch-dev, libmeegofeedback-dev
 Description: MeegoTouch Input Method Keyboard header files 
  MeegoTouch Keyboard header files.
 
--- doc/src/layoutxml.dox
+++ doc/src/layoutxml.dox
@@ -119,10 +119,6 @@
 just keys and spacers.  A row may be empty.
 
 
-\subsection Key
-
-Key element describes a visible key on the keyboard.
-
 \subsection Spacer
 
 Spacers can be used for alignment purposes. They distribute all remaining space
@@ -130,6 +126,10 @@
 
 For instance, to get a center-aligned row, put spacer elements in the beginning and end of a row. Spacer elements are cumulative, i.e., <spacer/><spacer/> will get twice the space of a single spacer.
 
+\subsection Key
+
+Key element describes a visible key on the keyboard.
+
 Attributes:
 
 \li \c style The style type this key should use. The style type is defined in
@@ -139,6 +139,7 @@
 \li \c fixed If false, this button uses a relative width. Otherwise uses fixed
 width.
 \li \c rtl If true, this button uses RTL version of icon.
+\li \c id Unique identifier of the key, optional. Needs to exist for keys that can be customized by the application.
 
 
 \subsection Binding
--- m-keyboard/common/common.pri
+++ m-keyboard/common/common.pri
@@ -5,10 +5,12 @@
     $$COMMON_DIR/keyevent.h \
     $$COMMON_DIR/layoutdata.h \
     $$COMMON_DIR/mkeyboardcommon.h \
+    $$COMMON_DIR/reactionmappainter.h \
     $$COMMON_DIR/regiontracker.h \
 
 HEADERS += \
     $$INSTALL_HEADERS \
+    $$COMMON_DIR/reactionmappainter_p.h \
     $$COMMON_DIR/regiontracker_p.h \
     $$COMMON_DIR/keyboarddata.h \
     $$COMMON_DIR/layoutsmanager.h \
@@ -21,6 +23,8 @@
     $$COMMON_DIR/flickgesture.h \
     $$COMMON_DIR/flickgesturerecognizer.h \
     $$COMMON_DIR/keyboardmapping.h \
+    $$COMMON_DIR/simplefilelog.h \
+    $$COMMON_DIR/mimreactionmap.h \
 
 SOURCES += \
     $$COMMON_DIR/keyboarddata.cpp\
@@ -37,8 +41,9 @@
     $$COMMON_DIR/flickgesture.cpp \
     $$COMMON_DIR/flickgesturerecognizer.cpp \
     $$COMMON_DIR/keyboardmapping.cpp \
+    $$COMMON_DIR/reactionmappainter.cpp \
     $$COMMON_DIR/regiontracker.cpp \
+    $$COMMON_DIR/simplefilelog.cpp \
 
 INCLUDEPATH += $$COMMON_DIR
 DEPENDPATH += $$COMMON_DIR
-
--- m-keyboard/common/keyboarddata.cpp
+++ m-keyboard/common/keyboarddata.cpp
@@ -22,95 +22,96 @@
 #include <QDir>
 #include <QDomDocument>
 #include <QFile>
+#include <QSet>
 
 
 namespace
 {
     // TODO: Support Windows paths too.
-    const QString VKBConfigurationPath = "/usr/share/meegotouch/virtual-keyboard/layouts/";
-
-    const QString VKBTagKeyboard             = QString("keyboard");
-    const QString VKBTagVersion              = QString("version");
-    const QString VKBTagCatalog              = QString("catalog");
-    const QString VKBTagAutoCapitalization   = QString("autocapitalization");
-    const QString VKBTagLayout               = QString("layout");
-    const QString VKBTagTitle                = QString("title");
-    const QString VKBTagLanguage             = QString("language");
-    const QString VKBTagBoolTrue             = QString("true");
-    const QString VKBTagBoolFalse            = QString("false");
-    const QString VKBTagType                 = QString("type");
-    const QString VKBTagTypeGeneral          = QString("general");
-    const QString VKBTagTypeUrl              = QString("url");
-    const QString VKBTagTypeEmail            = QString("email");
-    const QString VKBTagTypeNumber           = QString("number");
-    const QString VKBTagTypePhoneNumber      = QString("phonenumber");
-    const QString VKBTagTypeCommon           = QString("common");
-    const QString VKBTagOrientation          = QString("orientation");
-    const QString VKBTagOrientationLandscape = QString("landscape");
-    const QString VKBTagOrientationPortrait  = QString("portrait");
-
-    const QString VKBTagID                   = QString("id");
-    const QString VKBTagWidth                = QString("width");
-    const QString VKBTagHeight               = QString("height");
-
-    const QString VKBTagTypeNonsloppy        = QString("non-sloppy");
-    const QString VKBTagHorizontalAlignment  = QString("horizontal_alignment");
-    const QString VKBTagVerticalAlignment    = QString("vertical_alignment");
-    const QString VKBTagAlignFull            = QString("full");
-    const QString VKBTagAlignLeft            = QString("left");
-    const QString VKBTagAlignRight           = QString("right");
-    const QString VKBTagAlignBottom          = QString("bottom");
-    const QString VKBTagAlignTop             = QString("top");
-    const QString VKBTagAlignCenter          = QString("center");
-
-    const QString VKBTagRow                  = QString("row");
-    const QString VKBTagSection              = QString("section");
-    const QString VKBTagMovable              = QString("movable");
-
-    const QString VKBTagBinding              = QString("binding");
-    const QString VKBTagKey                  = QString("key");
-    const QString VKBTagSpacer               = QString("spacer");
-
-    const QString VKBTagKeyAction            = QString("action");
-    const QString VKBTagShift                = QString("shift");
-    const QString VKBTagLabel                = QString("label");
-    const QString VKBTagSecondaryLabel       = QString("secondary_label");
-    const QString VKBTagAccents              = QString("accents");
-    const QString VKBTagAccentedLabels       = QString("accented_labels");
-    const QString VKBTagExtendedLabels       = QString("extended_labels");
-    const QString VKBTagCycleSet             = QString("cycleset");
-    const QString VKBTagDead                 = QString("dead");
-    const QString VKBTagQuickPick            = QString("quickpick");
-
-    const QString ActionStrInsert            = QString("insert");
-    const QString ActionStrShift             = QString("shift");
-    const QString ActionStrBackspace         = QString("backspace");
-    const QString ActionStrSpace             = QString("space");
-    const QString ActionStrCycle             = QString("cycle");
-    const QString ActionStrLayoutMenu        = QString("layout_menu");
-    const QString ActionStrSym               = QString("sym");
-    const QString ActionStrReturn            = QString("return");
-    const QString ActionStrDecimalSeparator  = QString("decimal_separator");
-    const QString ActionStrPlusMinusToggle   = QString("plus_minus_toggle");
-    const QString ActionStrTab               = QString("tab");
-    const QString ActionStrCommit            = QString("commit");
-    const QString ActionStrSwitch            = QString("switch");
-
-    const QString VKBTagImport               = QString("import");
-    const QString VKBTagFile                 = QString("file");
-
-    const QString RtlString                  = QString("rtl");
-    const QString RtlStringDefValue          = QString("false");
-
-    const QString StyleString                = QString("style");
-    const QString StyleStringDefValue        = QString("normal");
-    const QString WidthTypeString            = QString("width");
-    const QString WidthTypeStringDefValue    = QString("medium");
-    const QString FixedString                = QString("fixed");
-    const QString FixedStringDefValue        = QString("false");
-    const QString HeightTypeString           = QString("height");
-    const QString HeightTypeStringDefValue   = QString("medium");
+    const char * const VKBConfigurationPath = "/usr/share/meegotouch/virtual-keyboard/layouts/";
 
+    const char * const VKBTagKeyboard             = "keyboard";
+    const char * const VKBTagVersion              = "version";
+    const char * const VKBTagCatalog              = "catalog";
+    const char * const VKBTagAutoCapitalization   = "autocapitalization";
+    const char * const VKBTagLayout               = "layout";
+    const char * const VKBTagTitle                = "title";
+    const char * const VKBTagLanguage             = "language";
+    const char * const VKBTagBoolTrue             = "true";
+    const char * const VKBTagBoolFalse            = "false";
+    const char * const VKBTagType                 = "type";
+    const char * const VKBTagTypeGeneral          = "general";
+    const char * const VKBTagTypeUrl              = "url";
+    const char * const VKBTagTypeEmail            = "email";
+    const char * const VKBTagTypeNumber           = "number";
+    const char * const VKBTagTypePhoneNumber      = "phonenumber";
+    const char * const VKBTagTypeCommon           = "common";
+    const char * const VKBTagOrientation          = "orientation";
+    const char * const VKBTagOrientationLandscape = "landscape";
+    const char * const VKBTagOrientationPortrait  = "portrait";
+
+    const char * const VKBTagID                   = "id";
+    const char * const VKBTagWidth                = "width";
+    const char * const VKBTagHeight               = "height";
+
+    const char * const VKBTagTypeNonsloppy        = "non-sloppy";
+    const char * const VKBTagHorizontalAlignment  = "horizontal_alignment";
+    const char * const VKBTagVerticalAlignment    = "vertical_alignment";
+    const char * const VKBTagAlignFull            = "full";
+    const char * const VKBTagAlignLeft            = "left";
+    const char * const VKBTagAlignRight           = "right";
+    const char * const VKBTagAlignBottom          = "bottom";
+    const char * const VKBTagAlignTop             = "top";
+    const char * const VKBTagAlignCenter          = "center";
+
+    const char * const VKBTagRow                  = "row";
+    const char * const VKBTagSection              = "section";
+    const char * const VKBTagMovable              = "movable";
+
+    const char * const VKBTagBinding              = "binding";
+    const char * const VKBTagKey                  = "key";
+    const char * const VKBTagSpacer               = "spacer";
+
+    const char * const VKBTagKeyAction            = "action";
+    const char * const VKBTagShift                = "shift";
+    const char * const VKBTagLabel                = "label";
+    const char * const VKBTagSecondaryLabel       = "secondary_label";
+    const char * const VKBTagAccents              = "accents";
+    const char * const VKBTagAccentedLabels       = "accented_labels";
+    const char * const VKBTagExtendedLabels       = "extended_labels";
+    const char * const VKBTagCycleSet             = "cycleset";
+    const char * const VKBTagDead                 = "dead";
+    const char * const VKBTagQuickPick            = "quickpick";
+
+    const char * const ActionStrInsert            = "insert";
+    const char * const ActionStrShift             = "shift";
+    const char * const ActionStrBackspace         = "backspace";
+    const char * const ActionStrSpace             = "space";
+    const char * const ActionStrCycle             = "cycle";
+    const char * const ActionStrLayoutMenu        = "layout_menu";
+    const char * const ActionStrSym               = "sym";
+    const char * const ActionStrReturn            = "return";
+    const char * const ActionStrDecimalSeparator  = "decimal_separator";
+    const char * const ActionStrPlusMinusToggle   = "plus_minus_toggle";
+    const char * const ActionStrTab               = "tab";
+    const char * const ActionStrCommit            = "commit";
+    const char * const ActionStrSwitch            = "switch";
+
+    const char * const VKBTagImport               = "import";
+    const char * const VKBTagFile                 = "file";
+
+    const char * const RtlString                  = "rtl";
+    const char * const RtlStringDefValue          = "false";
+
+    const char * const StyleString                = "style";
+    const char * const StyleStringDefValue        = "normal";
+    const char * const WidthTypeString            = "width";
+    const char * const WidthTypeStringDefValue    = "medium";
+    const char * const FixedString                = "fixed";
+    const char * const FixedStringDefValue        = "false";
+    const char * const HeightTypeString           = "height";
+    const char * const HeightTypeStringDefValue   = "medium";
+    const char * const KeyIdString                = "id";
 }
 
 struct ParseParameters {
@@ -125,6 +126,9 @@
     //! Contains true if current XML tag was successfully parsed
     bool validTag;
 
+    //! Contains key identifiers for current section
+    QSet<QString> keyIds;
+
     const QString *fileName;
 
     ParseParameters();
@@ -328,8 +332,8 @@
             keyboardAutoCapsEnabled = toBoolean(root.attribute(VKBTagAutoCapitalization, "true"));
         }
 
-        parseChildren(root, params, &VKBTagImport, &KeyboardData::parseTagImport,
-                      &VKBTagLayout, &KeyboardData::parseTagLayout);
+        parseChildren(root, params, VKBTagImport, &KeyboardData::parseTagImport,
+                      VKBTagLayout, &KeyboardData::parseTagLayout);
         valid = params.validTag;
     }
 
@@ -342,7 +346,7 @@
  * change this to accept an array of (tagname, parser) structures.
  */
 void KeyboardData::parseChildren(const QDomElement &element, ParseParameters &params,
-                                 const QString *tag1, TagParser parser1, const QString *tag2,
+                                 const char * const tag1, TagParser parser1, const char * const tag2,
                                  TagParser parser2)
 {
     Q_ASSERT(tag1);
@@ -352,9 +356,9 @@
             child = child.nextSibling()) {
         if (child.isElement()) {
             const QDomElement childElement = child.toElement();
-            if (childElement.tagName() == *tag1) {
+            if (childElement.tagName() == tag1) {
                 (this->*parser1)(childElement, params);
-            } else if ((tag2 != NULL) && (childElement.tagName() == *tag2)) {
+            } else if ((tag2 != NULL) && (childElement.tagName() == tag2)) {
                 Q_ASSERT(parser2 != 0);
                 (this->*parser2)(childElement, params);
             } else {
@@ -362,9 +366,9 @@
                            << childElement.lineNumber() << "column" << childElement.columnNumber()
                            << "in layout file" << *params.fileName;
                 if (tag2) {
-                    qWarning() << "Allowed tags are" << *tag1 << "and" << *tag2;
+                    qWarning() << "Allowed tags are" << tag1 << "and" << tag2;
                 } else {
-                    qWarning() << "The only allowed tag is" << *tag1;
+                    qWarning() << "The only allowed tag is" << tag1;
                 }
                 params.validTag = false;
             }
@@ -440,7 +444,7 @@
 
     currentLayout = layoutModel;
 
-    parseChildren(element, params, &VKBTagSection, &KeyboardData::parseTagSection);
+    parseChildren(element, params, VKBTagSection, &KeyboardData::parseTagSection);
 
     currentLayout->sections = currentLayout->sectionMap.values();
 }
@@ -470,8 +474,9 @@
     section->sectionName = element.attribute(VKBTagID);
     section->sectionType = (element.attribute(VKBTagType) == VKBTagTypeNonsloppy) ? LayoutSection::NonSloppy : LayoutSection::Sloppy;
     params.currentSection = section;
+    params.keyIds.clear();
     currentLayout->sectionMap.insert(section->sectionName, section);
-    parseChildren(element, params, &VKBTagRow, &KeyboardData::parseTagRow);
+    parseChildren(element, params, VKBTagRow, &KeyboardData::parseTagRow);
 }
 
 void KeyboardData::parseTagRow(const QDomElement &element, ParseParameters &params)
@@ -482,8 +487,8 @@
     params.currentRow = row;
 
     parseChildren(element, params,
-                  &VKBTagKey, &KeyboardData::parseTagKey,
-                  &VKBTagSpacer, &KeyboardData::parseTagSpacer);
+                  VKBTagKey, &KeyboardData::parseTagKey,
+                  VKBTagSpacer, &KeyboardData::parseTagSpacer);
 
     params.currentSection->mMaxColumns = qMax(params.currentSection->maxColumns(),
                                               row->keys.size());
@@ -525,12 +530,23 @@
     MImKeyModel::WidthType widthType = toWidthType(element.attribute(WidthTypeString, WidthTypeStringDefValue));
     const bool isRtl = toBoolean(element.attribute(RtlString, RtlStringDefValue));
     const bool isFixed = toBoolean(element.attribute(FixedString, FixedStringDefValue));
+    const QString keyId = element.attribute(KeyIdString);
+
+    if (!keyId.isEmpty()) {
+        if (params.keyIds.contains(keyId)) {
+            qWarning() << "Invalid virtual keyboard layout file" << *params.fileName
+                       << "contains key id" << keyId
+                       << "more than one time. Only last key will be registered with this id.";
+        } else {
+            params.keyIds.insert(keyId);
+        }
+    }
 
-    MImKeyModel *key = new MImKeyModel(type, widthType, isFixed, isRtl);
+    MImKeyModel *key = new MImKeyModel(type, widthType, isFixed, isRtl, keyId);
     params.currentKey = key;
     params.currentRow->keys.append(key);
 
-    parseChildren(element, params, &VKBTagBinding, &KeyboardData::parseTagBinding);
+    parseChildren(element, params, VKBTagBinding, &KeyboardData::parseTagBinding);
 
     if (key->bindings[1] == NULL) {
         key->bindings[1] = key->bindings[0];
--- m-keyboard/common/keyboarddata.h
+++ m-keyboard/common/keyboarddata.h
@@ -140,7 +140,7 @@
      * \param parser2 compulsory with tag2, parser for the tag2
      */
     void parseChildren(const QDomElement &element, ParseParameters &params,
-                       const QString *tag1, TagParser parser1, const QString *tag2 = NULL,
+                       const char * const tag1, TagParser parser1, const char * const tag2 = NULL,
                        TagParser parser2 = NULL);
 
     //! Parse XML tag for import
--- m-keyboard/common/mhardwarekeyboard.cpp
+++ m-keyboard/common/mhardwarekeyboard.cpp
@@ -234,6 +234,7 @@
     }
 
     inputMethodHost.setRedirectKeys(true);
+    emit enabled();
 }
 
 
@@ -533,7 +534,7 @@
 
 bool MHardwareKeyboard::filterKeyPress(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
                                        QString text, bool autoRepeat, int count,
-                                       quint32 nativeScanCode, quint32 nativeModifiers)
+                                       quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time)
 {
     bool eaten = false;
 
@@ -620,6 +621,8 @@
             preeditFormats << preeditFormat;
             inputMethodHost.sendPreeditString(text, preeditFormats);
             preedit = text;
+            preeditTime = time; // event time is needed by long press undo
+            preeditBeforeLongPress = preedit;
             preeditScanCode = nativeScanCode;
         } else if (!eaten) {
             if (longPressTimer.isActive()) {
@@ -662,7 +665,8 @@
 
 bool MHardwareKeyboard::filterKeyRelease(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
                                          QString text,
-                                         quint32 nativeScanCode, quint32 nativeModifiers)
+                                         quint32 nativeScanCode, quint32 nativeModifiers,
+                                         unsigned long time)
 {
     bool eaten = false;
 
@@ -715,12 +719,34 @@
         eaten = true;
     } else if (!eaten && !passKeyOnPress(keyCode, text, nativeScanCode, nativeModifiers)
                && !(pressNativeModifiers & ControlMask)) {
-        const bool deadKey(preedit == deadKeyMapper.currentDeadKey());
+        bool deadKey(preedit == deadKeyMapper.currentDeadKey());
+        if (keyWasPressed) {
+            // If there are delays in passing events to us, long press timer may hit even
+            // though the real time difference between press and release actions was
+            // smaller than the long press time.  We detect that case here and undo the
+            // long press effect.
+            const bool longPressUndo((preedit != preeditBeforeLongPress)
+                                     && ((preeditTime + longPressTime) > time)
+                                     // to make unit tests easier:
+                                     && !((preeditTime == 0) && (time == 0)));
+            if (longPressUndo) {
+                Q_ASSERT(!longPressTimer.isActive());
+                preedit = preeditBeforeLongPress;
+                (void)deadKeyMapper.filterKeyPress(preedit, true);
+                deadKey = preedit == deadKeyMapper.currentDeadKey();
+            }
 
-        if (keyWasPressed && !deadKey) {
-            inputMethodHost.sendCommitString(preedit);
-            preedit.clear();
+            if (!deadKey) {
+                inputMethodHost.sendCommitString(preedit);
+                preedit.clear();
+            } else if (longPressUndo) {
+                QList<MInputMethod::PreeditTextFormat> preeditFormats;
+                MInputMethod::PreeditTextFormat preeditFormat(0, preedit.length(), MInputMethod::PreeditKeyPress);
+                preeditFormats << preeditFormat;
+                inputMethodHost.sendPreeditString(text, preeditFormats);
+            }
         }
+
         eaten = true;
 
         if (!autoCaps && !deadKey && !(pressNativeModifiers & ShiftMask)) {
@@ -753,15 +779,16 @@
 bool MHardwareKeyboard::filterKeyEvent(QEvent::Type eventType,
                                        Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
                                        const QString &text, bool autoRepeat, int count,
-                                       quint32 nativeScanCode, quint32 nativeModifiers)
+                                       quint32 nativeScanCode, quint32 nativeModifiers,
+                                       unsigned long time)
 {
     bool eaten = false;
 
     if (eventType == QEvent::KeyPress) {
         eaten = filterKeyPress(keyCode, modifiers, text, autoRepeat, count,
-                               nativeScanCode, nativeModifiers);
+                               nativeScanCode, nativeModifiers, time);
     } else {
-        eaten = filterKeyRelease(keyCode, modifiers, text, nativeScanCode, nativeModifiers);
+        eaten = filterKeyRelease(keyCode, modifiers, text, nativeScanCode, nativeModifiers, time);
     }
 
     lastEventType = eventType;
--- m-keyboard/common/mhardwarekeyboard.h
+++ m-keyboard/common/mhardwarekeyboard.h
@@ -115,7 +115,7 @@
     bool filterKeyEvent(QEvent::Type eventType, Qt::Key keyCode,
                         Qt::KeyboardModifiers modifiers, const QString &text,
                         bool autoRepeat, int count, quint32 nativeScanCode,
-                        quint32 nativeModifiers);
+                        quint32 nativeModifiers, unsigned long time);
 
     //! \return whether the symbol view is available for the current layout.
     bool symViewAvailable() const;
@@ -149,6 +149,9 @@
     //! \brief Emitted when the script is changed.
     void scriptChanged() const;
 
+    //! \brief Emitted when the hardware keyboard is enabled.
+    void enabled();
+
 private slots:
     //! Called when long press timer started on key press timeouts.
     void handleLongPressTimeout();
@@ -264,12 +267,12 @@
     //! Helper for filterKeyEvent, handles press events
     bool filterKeyPress(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
                         QString text, bool autoRepeat, int count,
-                        quint32 nativeScanCode, quint32 nativeModifiers);
+                        quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time);
 
     //! Helper for filterKeyEvent, handles release events
     bool filterKeyRelease(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
                           QString text,
-                          quint32 nativeScanCode, quint32 nativeModifiers);
+                          quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time);
 
     //! Helper for filterKeyRelease and filterKeyPress, handle arrow keys with Fn
     bool filterArrowKeys(QEvent::Type eventType, Qt::Key keyCode,
@@ -357,6 +360,10 @@
 
     //! What we've last sent as the preedit string
     QString preedit;
+    //! Preedit not touched by long press handling
+    QString preeditBeforeLongPress;
+    //! Time of press event that updated \a preedit (not changed by long press processing or similar)
+    unsigned long preeditTime;
     //! Native X keycode of the event that caused \a preedit to be set
     quint32 preeditScanCode;
 
--- m-keyboard/common/mimkeymodel.cpp
+++ m-keyboard/common/mimkeymodel.cpp
@@ -129,11 +129,16 @@
 }
 
 
-MImKeyModel::MImKeyModel(MImKeyModel::StyleType style, MImKeyModel::WidthType widthType, bool isFixed, bool isRtl)
+MImKeyModel::MImKeyModel(MImKeyModel::StyleType style,
+                         MImKeyModel::WidthType widthType,
+                         bool isFixed,
+                         bool isRtl,
+                         const QString &id)
     : mStyle(style),
       mWidthType(widthType),
       isFixed(isFixed),
-      isRtl(isRtl)
+      isRtl(isRtl),
+      keyId(id)
 {
     bindings[NoShift] = 0;
     bindings[Shift] = 0;
@@ -187,3 +192,8 @@
     return isRtl;
 }
 
+QString MImKeyModel::id() const
+{
+    return keyId;
+}
+
--- m-keyboard/common/mimkeymodel.h
+++ m-keyboard/common/mimkeymodel.h
@@ -194,7 +194,8 @@
      * \param isRtl Contains true if button should use RTL icon.
      */
     explicit MImKeyModel(StyleType type = NormalStyle, WidthType widthType = Medium,
-                        bool isFixed = false, bool isRtl = false);
+                        bool isFixed = false, bool isRtl = false,
+                        const QString &id = QString());
 
     ~MImKeyModel();
 
@@ -231,6 +232,9 @@
     //! Returns true if button uses RTL icon.
     bool rtl() const;
 
+    //! Returns key's identifier
+    QString id() const;
+
 private:
     enum  {
         NoShift = 0,
@@ -252,6 +256,9 @@
     //! Contains true if button uses RTL icon.
     bool isRtl;
 
+    //! Contains key's identifier
+    QString keyId;
+
     friend class KeyboardData;
     friend class Ut_MImKeyModel;
     friend class Ut_MImKey;
--- m-keyboard/common/mimreactionmap.h
+++ m-keyboard/common/mimreactionmap.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef MIMREACTIONMAP_H
+#define MIMREACTIONMAP_H
+
+#include <QString>
+
+namespace MImReactionMap
+{
+const static QString Press = "vkb-press";
+const static QString Release = "vkb-release";
+};
+
+#endif
--- m-keyboard/common/reactionmappainter.cpp
+++ m-keyboard/common/reactionmappainter.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "reactionmappainter.h"
+#include "reactionmappainter_p.h"
+
+#include <mplainwindow.h>
+#include <mreactionmap.h>
+#include <mscene.h>
+
+#include "reactionmappaintable.h"
+
+// ReactionMapPainterPrivate......................................................
+
+ReactionMapPainterPrivate::ReactionMapPainterPrivate()
+{
+    repaintTimer.setSingleShot(true);
+    connect(&repaintTimer, SIGNAL(timeout()), this, SLOT(repaint()));
+}
+
+void ReactionMapPainterPrivate::addWidget(ReactionMapPaintable &widget)
+{
+    connect(&widget.signalForwarder, SIGNAL(requestRepaint()),
+            this, SLOT(requestRepaint()), Qt::UniqueConnection);
+    connect(&widget.signalForwarder, SIGNAL(requestClear()),
+            this, SLOT(clear()), Qt::UniqueConnection);
+    widgets.push_back(&widget);
+}
+
+void ReactionMapPainterPrivate::removeWidget(const ReactionMapPaintable &widget)
+{
+    const int pos(widgets.indexOf(const_cast<ReactionMapPaintable*>(&widget)));
+
+    if (pos >= 0) {
+        widgets.remove(pos);
+    }
+}
+
+void ReactionMapPainterPrivate::clear()
+{
+    const QList<QGraphicsView *> views = MPlainWindow::instance()->scene()->views();
+
+    // Draw invisible color to all reaction maps
+    foreach (QGraphicsView *view, views) {
+        MReactionMap *reactionMap = MReactionMap::instance(view);
+
+        if (reactionMap) {
+            reactionMap->setDrawingValue(MReactionMap::Transparent, MReactionMap::Transparent);
+            reactionMap->setTransform(QTransform());
+            reactionMap->fillRectangle(0, 0, reactionMap->width(), reactionMap->height());
+        }
+    }
+}
+
+
+void ReactionMapPainterPrivate::requestRepaint()
+{
+    if (repaintTimer.isActive())
+        return;
+
+    // The reaction map painting is queued because if it is scheduled too early then
+    // the widget geometries are not ready yet and wrong reaction maps will be
+    // painted.
+    repaintTimer.start(30);
+}
+
+void ReactionMapPainterPrivate::repaint()
+{
+    const QList<QGraphicsView *> views = MPlainWindow::instance()->scene()->views();
+
+    clear();
+    // Draw all reaction maps
+    foreach (QGraphicsView *view, views) {
+        MReactionMap *reactionMap = MReactionMap::instance(view);
+
+        if (!reactionMap) {
+            continue;
+        }
+
+        // Draw the first full-screen and paintable widget and go to the
+        // next reaction map
+        bool fullScreenWidget = false;
+
+        foreach (ReactionMapPaintable *widget, widgets) {
+
+            if (widget->isFullScreen() && widget->isPaintable())
+            {
+                widget->paintReactionMap(reactionMap, view);
+                fullScreenWidget = true;
+                break;
+            }
+        }
+        // Don't draw non-fullscreen widgets and go to the next reaction map
+        if (fullScreenWidget)
+            continue;
+        // Draw the non-fullscreen and paintable widgets
+        foreach (ReactionMapPaintable *widget, widgets) {
+
+            if (widget->isPaintable()) {
+                widget->paintReactionMap(reactionMap, view);
+            }
+        }
+    }
+}
+
+
+// ReactionMapPainter.............................................................
+
+ReactionMapPainter *ReactionMapPainter::singleton = 0;
+
+ReactionMapPainter::ReactionMapPainter()
+    : d_ptr(new ReactionMapPainterPrivate)
+{
+}
+
+ReactionMapPainter::~ReactionMapPainter()
+{
+    delete d_ptr;
+}
+
+void ReactionMapPainter::createInstance()
+{
+    Q_ASSERT(!singleton);
+    if (!singleton) {
+        singleton = new ReactionMapPainter();
+    }
+}
+
+void ReactionMapPainter::destroyInstance()
+{
+    Q_ASSERT(singleton);
+    delete singleton;
+    singleton = 0;
+}
+
+void ReactionMapPainter::addWidget(ReactionMapPaintable &widget)
+{
+    Q_D(ReactionMapPainter);
+    d->addWidget(widget);
+}
+
+void ReactionMapPainter::removeWidget(const ReactionMapPaintable &widget)
+{
+    Q_D(ReactionMapPainter);
+    d->removeWidget(widget);
+}
+
+void ReactionMapPainter::clear()
+{
+    Q_D(ReactionMapPainter);
+    d->clear();
+}
+
+void ReactionMapPainter::repaint()
+{
+    Q_D(ReactionMapPainter);
+    d->requestRepaint();
+}
--- m-keyboard/common/reactionmappainter.h
+++ m-keyboard/common/reactionmappainter.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef REACTIONMAPPAINTER_H
+#define REACTIONMAPPAINTER_H
+
+#include <QObject>
+
+class ReactionMapPainterPrivate;
+class ReactionMapPaintable;
+
+//! \brief A class that does the job of the centralised reaction map painting.
+//!
+//! This class is public and can be used by pop-up plug-ins.
+class ReactionMapPainter : public QObject
+{
+    Q_OBJECT
+
+    //! \brief Constructor.
+    ReactionMapPainter();
+
+public:
+    //! Destructor
+    virtual ~ReactionMapPainter();
+
+    //! \brief Get singleton instance
+    //! \return singleton instance
+    static ReactionMapPainter &instance();
+
+    //! \brief Create singleton
+    static void createInstance();
+
+    //! \brief Destroy singleton
+    static void destroyInstance();
+
+    //! \brief Add \a widget to the reaction map painter
+    void addWidget(ReactionMapPaintable &widget);
+
+    //! \brief Remove \a widget from the reaction map painter
+    void removeWidget(const ReactionMapPaintable &widget);
+
+public slots:
+    //! \brief Clear the reaction maps
+    void clear();
+
+    //! \brief Repaint the reaction maps
+    void repaint();
+private:
+    //! Singleton instance
+    static ReactionMapPainter *singleton;
+
+    ReactionMapPainterPrivate *const d_ptr;
+
+    Q_DECLARE_PRIVATE(ReactionMapPainter)
+};
+
+inline ReactionMapPainter &ReactionMapPainter::instance()
+{
+    Q_ASSERT(singleton);
+    return *singleton;
+}
+
+#endif
--- m-keyboard/common/reactionmappainter_p.h
+++ m-keyboard/common/reactionmappainter_p.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef REACTIONMAPPAINTER_P_H
+#define REACTIONMAPPAINTER_P_H
+
+#include <QObject>
+#include <QTimer>
+#include <QVector>
+
+class ReactionMapPainter;
+class ReactionMapPaintable;
+
+class ReactionMapPainterPrivate : public QObject
+{
+    Q_OBJECT
+    friend class ReactionMapPainter;
+
+public:
+    ReactionMapPainterPrivate();
+
+private:
+    //! \brief Add \a widget to the reaction map painter
+    void addWidget(ReactionMapPaintable &widget);
+
+    //! \brief Remove \a widget from the reaction map painter
+    void removeWidget(const ReactionMapPaintable &widget);
+
+private slots:
+    //! \brief Clear the reaction maps
+    void clear();
+
+    //! \brief Request repainting the reaction maps
+    void requestRepaint();
+
+    //! \brief Repaint the reaction maps
+    void repaint();
+
+private:
+    //! List of paintable widgets
+    QVector<ReactionMapPaintable*> widgets;
+    //! Timer for repainting
+    QTimer repaintTimer;
+
+    Q_DISABLE_COPY(ReactionMapPainterPrivate)
+};
+
+#endif
--- m-keyboard/common/regiontracker.cpp
+++ m-keyboard/common/regiontracker.cpp
@@ -40,8 +40,10 @@
     if (!regions.contains(&widget)) {
         return;
     }
-    regions[&widget] = region;
-    dirty = true;
+    if (!(regions[&widget] ^ region).isEmpty()) {
+        regions[&widget] = region;
+        dirty = true;
+    }
     maybeNotify();
 }
 
@@ -49,7 +51,7 @@
 {
     if (enabled && dirty) {
         const QRegion newRegion(combineRegions());
-        if (newRegion != lastRegion) {
+        if (!(newRegion ^ lastRegion).isEmpty()) {
             lastRegion = newRegion;
             emit regionChanged(newRegion);
         }
@@ -60,8 +62,13 @@
 QRegion RegionStore::combineRegions() const
 {
     QRegion combinedRegion;
-    foreach (const QRegion &partialRegion, regions) {
-        combinedRegion |= partialRegion;
+
+    for (RegionMap::iterator i(regions.begin()); i != regions.end(); ++i) {
+        const QGraphicsWidget &widget(dynamic_cast<const QGraphicsWidget &>(*i.key()));
+        const QRegion region(widget.isVisible() ? widget.mapRectToScene(widget.rect()).toRect()
+                             : QRect());
+        combinedRegion |= region;
+        i.value() = region;
     }
 
     return combinedRegion;
@@ -94,17 +101,17 @@
 {
     changeGeometry(widget);
     connect(&widget, SIGNAL(geometryChanged()),
-            this, SLOT(handleGeometryChange()), Qt::UniqueConnection);
+            this, SLOT(handleGeometryChange()), Qt::QueuedConnection);
     connect(&widget, SIGNAL(destroyed(QObject *)),
             this, SLOT(handleDestroy(QObject *)), Qt::UniqueConnection);
     connect(&widget, SIGNAL(visibleChanged()),
-            this, SLOT(handleVisibilityChange()), Qt::UniqueConnection);
+            this, SLOT(handleVisibilityChange()), Qt::QueuedConnection);
 }
 
 void RegionTrackerPrivate::handleGeometryChange()
 {
     const QGraphicsWidget *widget(dynamic_cast<const QGraphicsWidget *>(QObject::sender()));
-    if (!widget->isVisible()) {
+    if (!widget || !widget->isVisible()) {
         return;
     }
     changeGeometry(*widget);
@@ -128,6 +135,9 @@
 void RegionTrackerPrivate::handleVisibilityChange()
 {
     const QGraphicsWidget *widget(dynamic_cast<const QGraphicsWidget *>(QObject::sender()));
+    if (!widget) {
+        return;
+    }
     changeGeometry(*widget);
 }
 
@@ -146,8 +156,6 @@
             this, SIGNAL(regionChanged(const QRegion &)));
     connect(&d->inputMethodAreaWidgetRegions, SIGNAL(regionChanged(const QRegion &)),
             this, SIGNAL(inputMethodAreaChanged(const QRegion &)));
-    connect(this, SIGNAL(regionChanged(const QRegion &)),
-            this, SIGNAL(reactionMapUpdateNeeded()));
 }
 
 RegionTracker::~RegionTracker()
@@ -196,11 +204,6 @@
     return wasEnabled;
 }
 
-void RegionTracker::requestReactionMapUpdate()
-{
-    emit reactionMapUpdateNeeded();
-}
-
 void RegionTracker::sendInputMethodAreaEstimate(const QRegion &region)
 {
     Q_D(RegionTracker);
--- m-keyboard/common/regiontracker.h
+++ m-keyboard/common/regiontracker.h
@@ -62,9 +62,6 @@
     //! signaled if \a flush is true.
     bool enableSignals(bool newEnabled, bool flush = true);
 
-    //! \brief Request \a reactionMapUpdateNeeded to be emitted.
-    void requestReactionMapUpdate();
-
     //! \brief Request given \a region to be emitted via \a inputMethodAreaChanged
     //! regardless of signals being enabled or disabled
     void sendInputMethodAreaEstimate(const QRegion &region);
@@ -80,12 +77,6 @@
     //! \brief Screen area covered by widgets registered with \a addInputMethodArea was changed
     void inputMethodAreaChanged(const QRegion &region);
 
-    //! \brief Emitted whenever reaction map update is needed.
-    //!
-    //! \a regionChanged emission implies \a reactionMapUpdateNeeded emission, but not the
-    //! other way around.
-    void reactionMapUpdateNeeded();
-
 private:
     //! \brief Constructor.
     RegionTracker();
--- m-keyboard/common/simplefilelog.cpp
+++ m-keyboard/common/simplefilelog.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "simplefilelog.h"
+
+#include <QDir>
+#include <QCoreApplication>
+
+namespace {
+    const char *const MImUserDirectory = ".meego-im";
+}
+
+SimpleFileLog::SimpleFileLog(const QString &fileName)
+    : mFile()
+    ,  mStream(&mFile)
+{
+    QString logFilePath = QString("%1/%2/%3-%4").arg(QDir::homePath())
+                          .arg(MImUserDirectory)
+                          .arg(QCoreApplication::applicationPid())
+                          .arg(fileName);
+    mFile.setFileName(logFilePath);
+
+    mStream.setCodec("utf-8");
+
+    if (!QDir::home().exists(MImUserDirectory)) {
+        QDir::home().mkdir(MImUserDirectory);
+    }
+    mFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+}
+
+QTextStream & SimpleFileLog::stream()
+{
+    return mStream;
+}
+
+void SimpleFileLog::flush()
+{
+    mStream << "\n";
+    mStream.flush();
+}
--- m-keyboard/common/simplefilelog.h
+++ m-keyboard/common/simplefilelog.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef SIMPLEFILELOG_H
+#define SIMPLEFILELOG_H
+
+#include <QFile>
+#include <QTextStream>
+
+//! \internal
+class SimpleFileLog
+{
+public:
+    //! \brief Constructor. File will be opened under the meego-im home directory,
+    //! and be prefixed with the current PID. Ex: /home/user/.meego-im/4912-file.cvs
+    explicit SimpleFileLog(const QString &fileName);
+
+    //! \brief The stream to log to.
+    QTextStream & stream();
+
+    //! \brief Insert a marker (\n), and flush the textstream to file.
+    void flush();
+
+private:
+    QFile mFile;
+    QTextStream mStream;
+};
+
+#endif // SIMPLEFILELOG_H
--- m-keyboard/layouts/VirtualKeyboardLayout.dtd
+++ m-keyboard/layouts/VirtualKeyboardLayout.dtd
@@ -34,7 +34,9 @@
   style (normal | special | deadkey) "normal"
   width (small | medium | large | x-large | xx-large | stretched) "medium"
   fixed (true | false) "false"
-  rtl (true | false) "false">
+  rtl (true | false) "false"
+  id CDATA #IMPLIED
+>
 
 <!ATTLIST binding
   action (insert | shift | backspace | space | cycle | layout_menu | sym
--- m-keyboard/layouts/ar.xml
+++ m-keyboard/layouts/ar.xml
@@ -117,8 +117,8 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
         <key><binding label="ذ"/></key>
@@ -131,7 +131,7 @@
         <key><binding label="."/></key>
         <key><binding label="ط"/></key>
 
-        <key style="special" width="x-large" rtl="false">
+        <key style="special" width="x-large" rtl="false" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/layouts/cs.xml
+++ m-keyboard/layouts/cs.xml
@@ -86,7 +86,8 @@
         <key>
           <binding label="ů"/>
           <binding shift="true" label="Ů"/>
-        </key>
+        </key>		
+
       </row>
 
       <row>
@@ -121,7 +122,7 @@
           <binding label="m"/>
           <binding shift="true" label="M"/>
         </key>
-        <key>
+		<key>
             <binding dead="true" label="´"/>
         </key>
         <key style="special">
@@ -130,22 +131,22 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
         <key><binding label=","/></key>
+       <key><binding label="."/></key>
 
         <key width="xx-large">
           <binding action="space" label=""/>
         </key>
 
-        <key><binding label="."/></key>
-        <key>
+         <key>
           <binding dead="true" label="ˇ"/>
         </key>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return" label=""/>
         </key>
       </row>
@@ -153,5 +154,5 @@
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/da.xml
+++ m-keyboard/layouts/da.xml
@@ -133,28 +133,28 @@
       </row>
 
       <row>
-      <key style="special" width="x-large">
-        <binding action="sym" label="SYM"/>
+      <key style="special" width="large">
+        <binding action="sym" label="?123"/>
       </key>
 
       <key><binding label=","/></key>
+      <key><binding label="."/></key>
 
       <key width="xx-large">
         <binding action="space" label=""/>
       </key>
 
-      <key><binding label="."/></key>
       <key>
         <binding label="ø" extended_labels="ö"/>
         <binding shift="true" label="Ø" extended_labels="Ö"/>
       </key>
 
-      <key style="special" width="x-large">
+      <key style="special" width="x-large" id="actionKey">
         <binding action="return" label=""/>
       </key>
     </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/de.xml
+++ m-keyboard/layouts/de.xml
@@ -133,28 +133,28 @@
       </row>
 
       <row>
-      <key style="special" width="x-large">
-        <binding action="sym" label="SYM"/>
+      <key style="special" width="large">
+        <binding action="sym" label="?123"/>
       </key>
 
       <key><binding label=","/></key>
+      <key><binding label="."/></key>
 
       <key width="xx-large">
         <binding action="space" label=""/>
       </key>
 
-      <key><binding label="."/></key>
       <key>
         <binding label="ö"/>
         <binding shift="true" label="Ö"/>
       </key>
 
-      <key style="special" width="x-large">
+      <key style="special" width="x-large" id="actionKey">
         <binding action="return" label=""/>
       </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/en_gb_default.xml
+++ m-keyboard/layouts/en_gb_default.xml
@@ -134,18 +134,18 @@
 
       <row>
         <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+          <binding action="sym" label="?123"/>
         </key>
 
         <spacer/>
 
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
+        <key><binding label="."/></key>
 
         <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/layouts/es.xml
+++ m-keyboard/layouts/es.xml
@@ -133,32 +133,28 @@
       </row>
 
       <row>
-      <key style="special" width="x-large">
-        <binding action="sym" label="CAR"/>
+      <key style="special" width="large">
+        <binding action="sym" label="?123"/>
       </key>
 
-      <key>
-        <binding dead="true" label="´"/>
-        <binding shift="true" dead="true" label="´"/>
-      </key>
+      <key><binding label=","/></key>
+      <key><binding label="."/></key>
 
       <key width="xx-large">
         <binding action="space" label=""/>
       </key>
 
       <key>
-        <binding label=","/>
-      </key>
-      <key>
-        <binding label="."/>
+        <binding dead="true" label="´"/>
+        <binding shift="true" dead="true" label="´"/>
       </key>
 
-      <key style="special" width="x-large">
+      <key style="special" width="x-large" id="actionKey">
         <binding action="return" label=""/>
       </key>
       </row>
     </section>
   </layout>
   
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/fi.xml
+++ m-keyboard/layouts/fi.xml
@@ -132,28 +132,28 @@
       </row>
 
       <row>
-      <key style="special" width="x-large">
-        <binding action="sym" label="SYM"/>
+      <key style="special" width="large">
+        <binding action="sym" label="?123"/>
       </key>
 
       <key><binding label=","/></key>
+      <key><binding label="."/></key>
 
       <key width="xx-large">
         <binding action="space" label=""/>
       </key>
 
-      <key><binding label="."/></key>
       <key>
         <binding label="å"/>
         <binding shift="true" label="Å"/>
       </key>
 
-      <key style="special" width="x-large">
+      <key style="special" width="x-large" id="actionKey">
         <binding action="return" label=""/>
       </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/fr.xml
+++ m-keyboard/layouts/fr.xml
@@ -148,24 +148,20 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <spacer/>
-
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
-
-        <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-38.xml"/>
 </keyboard>
--- m-keyboard/layouts/fr_ca.xml
+++ m-keyboard/layouts/fr_ca.xml
@@ -148,19 +148,15 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <spacer/>
-
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
         <key width="xx-large"><binding action="space" label=""/></key>
-        <key width="large"><binding label="."/></key>
-
-        <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return" label=""/>
         </key>
       </row>
@@ -168,5 +164,5 @@
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-38.xml"/>
 </keyboard>
--- m-keyboard/layouts/hu.xml
+++ m-keyboard/layouts/hu.xml
@@ -132,31 +132,25 @@
       </row>
 
       <row>
-       <key style="special" width="x-large">
-        <binding action="sym" label="SYM"/>
+       <key style="special" width="large">
+        <binding action="sym" label="?123"/>
        </key>
 
-       <key>
-        <binding label=","/>
-       </key>
+       <key><binding label=","/></key>
+       <key><binding label="."/></key>
 
        <key width="xx-large">
         <binding action="space" label=""/>
        </key>
 
-       <key>
-        <binding label="."/>
-       </key>
-       <key>
-        <binding dead="true" label="¨"/>
-       </key>
+       <key><binding dead="true" label="¨"/></key>
 
-       <key style="special" width="x-large">
+       <key style="special" width="x-large" id="actionKey">
         <binding action="return" label=""/>
        </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/id.xml
+++ m-keyboard/layouts/id.xml
@@ -134,18 +134,18 @@
 
       <row>
         <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+          <binding action="sym" label="?123"/>
         </key>
 
         <spacer/>
 
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
+        <key><binding label="."/></key>
 
         <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/layouts/it.xml
+++ m-keyboard/layouts/it.xml
@@ -133,24 +133,21 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <spacer/>
-
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
-
-        <spacer/>
+        <key><binding label="&#x0027;"/></key>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/ms.xml
+++ m-keyboard/layouts/ms.xml
@@ -134,18 +134,18 @@
 
       <row>
         <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+          <binding action="sym" label="?123"/>
         </key>
 
         <spacer/>
 
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
+        <key><binding label="."/></key>
 
         <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/layouts/nl.xml
+++ m-keyboard/layouts/nl.xml
@@ -128,18 +128,18 @@
 
       <row>
         <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+          <binding action="sym" label="?123"/>
         </key>
 
         <spacer/>
 
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
+        <key><binding label="."/></key>
 
         <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/layouts/no.xml
+++ m-keyboard/layouts/no.xml
@@ -133,27 +133,23 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <key>
-          <binding label=","/>
-        </key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
 
         <key width="xx-large">
           <binding action="space" label=""/>
         </key>
 
         <key>
-          <binding label="."/>
-        </key>
-        <key>
           <binding label="ø" extended_labels="ö"/>
           <binding shift="true" label="Ø" extended_labels="Ö"/>
         </key>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return" label=""/>
         </key>
       </row>
@@ -161,5 +157,5 @@
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/number.xml
+++ m-keyboard/layouts/number.xml
@@ -92,10 +92,10 @@
 
       <row>
         <key>
-          <binding label="0"/>
+          <binding label="&#x002B;&#x002F;&#x002D;" action="plus_minus_toggle"/>
         </key>
         <key>
-          <binding label="&#x002B;&#x002F;&#x002D;" action="plus_minus_toggle"/>
+          <binding label="0"/>
         </key>
         <key>
           <binding action="decimal_separator"/>
--- m-keyboard/layouts/number_ar.xml
+++ m-keyboard/layouts/number_ar.xml
@@ -91,10 +91,10 @@
 
       <row>
         <key>
-          <binding label="&#x0660;"/>
+          <binding label="&#x002B;&#x002F;&#x002D;" action="plus_minus_toggle"/>
         </key>
         <key>
-          <binding label="&#x002B;&#x002F;&#x002D;" action="plus_minus_toggle"/>
+          <binding label="&#x0660;"/>
         </key>
         <key>
           <binding action="decimal_separator"/>
--- m-keyboard/layouts/phonenumber.xml
+++ m-keyboard/layouts/phonenumber.xml
@@ -92,10 +92,10 @@
 
       <row>
         <key>
-          <binding label="0"/>
+          <binding label="&#x002A;&#x002B;" cycleset="&#x002A;&#x002B;p" action="cycle"/>
         </key>
         <key>
-          <binding label="&#x002A;&#x002B;" cycleset="&#x002A;&#x002B;p" action="cycle"/>
+          <binding label="0"/>
         </key>
         <key>
           <binding label="&#x0023;"/>
--- m-keyboard/layouts/phonenumber_ar.xml
+++ m-keyboard/layouts/phonenumber_ar.xml
@@ -92,10 +92,10 @@
 
       <row> 
         <key>
-          <binding label="&#x0660;"/>
+          <binding label="&#x002A;&#x002B;" cycleset="&#x002A;&#x002B;p" action="cycle"/>
         </key>
         <key>
-          <binding label="&#x002A;&#x002B;" cycleset="&#x002A;&#x002B;p" action="cycle"/>
+          <binding label="&#x0660;"/>
         </key>
         <key>
           <binding label="&#x0023;"/>
--- m-keyboard/layouts/phonenumber_ru.xml
+++ m-keyboard/layouts/phonenumber_ru.xml
@@ -92,10 +92,10 @@
 
       <row>
         <key>
-          <binding label="0"/>
+          <binding label="&#x002A;&#x002B;" cycleset="&#x002A;&#x002B;p" action="cycle"/>
         </key>
         <key>
-          <binding label="&#x002A;&#x002B;" cycleset="&#x002A;&#x002B;p" action="cycle"/>
+          <binding label="0"/>
         </key>
         <key>
           <binding label="&#x0023;"/>
--- m-keyboard/layouts/pl.xml
+++ m-keyboard/layouts/pl.xml
@@ -146,24 +146,20 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <spacer/>
-
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
-
-        <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-38.xml"/>
 </keyboard>
--- m-keyboard/layouts/pt.xml
+++ m-keyboard/layouts/pt.xml
@@ -148,24 +148,20 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="CAR"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <spacer/>
-
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
         <key width="xx-large"><binding action="space" label=""/></key>
-        <key width="large"><binding label="."/></key>
-
-        <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-38.xml"/>
 </keyboard>
--- m-keyboard/layouts/pt_br.xml
+++ m-keyboard/layouts/pt_br.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard title="Português-Brazil" version="1.0" catalog="pt_br" language="pt_br">
+<keyboard title="Português- Brasil" version="1.0" catalog="pt_br" language="pt_br">
     <import file="pt.xml"/>
 </keyboard>
--- m-keyboard/layouts/ro.xml
+++ m-keyboard/layouts/ro.xml
@@ -145,24 +145,20 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <spacer/>
-
-        <key width="large"><binding label=","/></key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="."/></key>
-
-        <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-38.xml"/>
 </keyboard>
--- m-keyboard/layouts/ru.xml
+++ m-keyboard/layouts/ru.xml
@@ -21,8 +21,8 @@
           <binding shift="true" label="К"/>
         </key>
         <key>
-          <binding label="е" extended_labels="ë"/>
-          <binding shift="true" label="Е" extended_labels="Ë"/>
+          <binding label="е" extended_labels="&#x0451;"/>
+          <binding shift="true" label="Е" extended_labels="&#x0401;"/>
         </key>
         <key>
           <binding label="н"/>
@@ -145,25 +145,24 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
         <key><binding label=","/></key>
+        <key><binding label="."/></key>
 
         <key width="xx-large">
           <binding action="space" label=""/>
         </key>
 
-        <key>
-          <binding label="."/>
-        </key>
+        <key><binding label="-"/></key>
         <key>
           <binding label="ъ"/>
           <binding shift="true" label="Ъ"/>
         </key>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/layouts/sk.xml
+++ m-keyboard/layouts/sk.xml
@@ -133,33 +133,25 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
-        </key>
-        <key>
-          <binding dead="true" label="´"/>
-        </key>
-        <key>
-          <binding dead="true" label="ˇ"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
 
         <key width="xx-large">
           <binding action="space" label=""/>
         </key>
 
-        <key>
-          <binding label=","/>
-        </key>
-        <key>
-          <binding label="."/>
-        </key>
+        <key><binding dead="true" label="´"/></key>
+        <key><binding dead="true" label="ˇ"/></key>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-36.xml"/>
 </keyboard>
--- m-keyboard/layouts/symbols-36.xml
+++ m-keyboard/layouts/symbols-36.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
+<keyboard version="1.0" catalog="symbols">
+  <layout type="general">
+    <section id="symbols0" type="non-sloppy">
+      <row>
+        <key>
+          <binding label="1"/>
+        </key>
+        <key>
+          <binding label="2"/>
+        </key>
+        <key>
+          <binding label="3"/>
+        </key>
+        <key>
+          <binding label="4"/>
+        </key>
+        <key>
+          <binding label="5"/>
+        </key>
+        <key>
+          <binding label="6"/>
+        </key>
+        <key>
+          <binding label="7"/>
+        </key>
+        <key>
+          <binding label="8"/>
+        </key>
+        <key>
+          <binding label="9"/>
+        </key>
+        <key>
+          <binding label="0"/>
+        </key>
+      </row>
+
+      <row>
+        <key>
+          <binding label="*"/>
+        </key>
+        <key>
+          <binding label="#"/>
+        </key>
+        <key>
+          <binding label="+"/>
+        </key>
+        <key>
+          <binding label="-"/>
+        </key>
+        <key>
+          <binding label="_"/>
+        </key>
+        <key>
+          <binding label="="/>
+        </key>
+        <key>
+          <binding label="("/>
+        </key>
+        <key>
+          <binding label=")"/>
+        </key>
+        <key>
+          <binding label="<"/>
+        </key>
+        <key>
+          <binding label=">"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special">
+          <binding action="switch" label="1/2"/>
+        </key>
+        <key>
+          <binding label="@" quickpick="true"/>
+        </key>
+        <key>
+          <binding label="~"/>
+        </key>
+        <key>
+          <binding label="/"/>
+        </key>
+        <key>
+          <binding label="\"/>
+        </key>
+        <key>
+          <binding label="&#x0027;" quickpick="true"/>
+        </key>
+        <key>
+          <binding label="&#x0022;"/>
+        </key>
+        <key>
+          <binding label="&#x0026;"/>
+        </key>
+        <key>
+          <binding label="!"/>
+        </key>
+        <key style="special">
+          <binding action="backspace"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special" width="large">
+          <binding action="sym" label="ABC"/>
+        </key>
+        
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
+        
+        <key width="xx-large">
+          <binding action="space"/>
+        </key>
+        
+        <key><binding label="?"/></key>
+        
+        <key style="special" width="x-large" id="actionKey">
+          <binding action="return"/>
+        </key>
+
+      </row>
+    </section>
+
+    <section id="symbols1" type="non-sloppy">
+      <row>
+        <key>
+          <binding label="1"/>
+        </key>
+        <key>
+          <binding label="2"/>
+        </key>
+        <key>
+          <binding label="3"/>
+        </key>
+        <key>
+          <binding label="4"/>
+        </key>
+        <key>
+          <binding label="5"/>
+        </key>
+        <key>
+          <binding label="6"/>
+        </key>
+        <key>
+          <binding label="7"/>
+        </key>
+        <key>
+          <binding label="8"/>
+        </key>
+        <key>
+          <binding label="9"/>
+        </key>
+        <key>
+          <binding label="0"/>
+        </key>
+      </row>
+
+      <row>
+        <key>
+          <binding label="&#x20AC;"/>
+        </key>
+        <key>
+          <binding label="&#x00A3;"/>
+        </key>
+        <key>
+          <binding label="&#x0024;"/>
+        </key>
+        <key>
+          <binding label="&#x00A5;"/>
+        </key>
+        <key>
+          <binding label="&#x00A7;"/>
+        </key>
+        <key>
+          <binding label="&#x0025;"/>
+        </key>
+        <key>
+          <binding label="&#x005B;"/>
+        </key>
+        <key>
+          <binding label="&#x005D;"/>
+        </key>
+        <key>
+          <binding label="&#x00AB;"/>
+        </key>
+        <key>
+          <binding label="&#x00BB;"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special">
+          <binding action="switch" label="2/2"/>
+        </key>
+        <key>
+          <binding label="&#x0060;"/>
+        </key>
+        <key>
+          <binding label="&#x005E;"/>
+        </key>
+        <key>
+          <binding label="&#x007C;"/>
+        </key>
+        <key>
+          <binding label="&#x00B0;"/>
+        </key>
+        <key>
+          <binding label="&#x201C;"/>
+        </key>
+        <key>
+          <binding label="&#x201D;"/>
+        </key>
+        <key>
+          <binding label="&#x201E;"/>
+        </key>
+        <key>
+          <binding label="&#x00A1;"/>
+        </key>
+        <key style="special">
+          <binding action="backspace"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special" width="large">
+          <binding action="sym" label="ABC"/>
+        </key>
+        
+        <key><binding label="&#x003B;"/></key>
+        <key><binding label="&#x003A;"/></key>
+        
+        <key width="xx-large">
+          <binding action="space"/>
+        </key>
+        
+        <key><binding label="&#x00BF;"/></key>
+        
+        <key style="special" width="x-large" id="actionKey">
+          <binding action="return"/>
+        </key>
+      </row>
+    </section>
+  </layout>
+</keyboard>
--- m-keyboard/layouts/symbols-38.xml
+++ m-keyboard/layouts/symbols-38.xml
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
+<keyboard version="1.0" catalog="symbols">
+  <layout type="general">
+    <section id="symbols0" type="non-sloppy">
+      <row>
+        <key>
+          <binding label="1"/>
+        </key>
+        <key>
+          <binding label="2"/>
+        </key>
+        <key>
+          <binding label="3"/>
+        </key>
+        <key>
+          <binding label="4"/>
+        </key>
+        <key>
+          <binding label="5"/>
+        </key>
+        <key>
+          <binding label="6"/>
+        </key>
+        <key>
+          <binding label="7"/>
+        </key>
+        <key>
+          <binding label="8"/>
+        </key>
+        <key>
+          <binding label="9"/>
+        </key>
+        <key>
+          <binding label="0"/>
+        </key>
+        <key>
+          <binding label="%"/>
+        </key>
+      </row>
+
+      <row>
+        <key>
+          <binding label="*"/>
+        </key>
+        <key>
+          <binding label="#"/>
+        </key>
+        <key>
+          <binding label="+"/>
+        </key>
+        <key>
+          <binding label="-"/>
+        </key>
+        <key>
+          <binding label="_"/>
+        </key>
+        <key>
+          <binding label="="/>
+        </key>
+        <key>
+          <binding label="&#x0026;"/>
+        </key>
+        <key>
+          <binding label="("/>
+        </key>
+        <key>
+          <binding label=")"/>
+        </key>
+        <key>
+          <binding label="<"/>
+        </key>
+        <key>
+          <binding label=">"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special">
+          <binding action="switch" label="1/2"/>
+        </key>
+        <key>
+          <binding label="@" quickpick="true"/>
+        </key>
+        <key>
+          <binding label="~"/>
+        </key>
+        <key>
+          <binding label="/"/>
+        </key>
+        <key>
+          <binding label="\"/>
+        </key>
+        <key>
+          <binding label="&#x0027;" quickpick="true"/>
+        </key>
+        <key>
+          <binding label="&#x0022;"/>
+        </key>
+        <key>
+          <binding label="&#x00B0;"/>
+        </key>
+        <key>
+          <binding label="?"/>
+        </key>
+        <key>
+          <binding label="!"/>
+        </key>
+        <key style="special">
+          <binding action="backspace"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special" width="large">
+          <binding action="sym" label="ABC"/>
+        </key>
+        
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
+        
+        <key width="xx-large">
+          <binding action="space"/>
+        </key>
+        
+        <key style="special" width="x-large" id="actionKey">
+          <binding action="return"/>
+        </key>
+
+      </row>
+    </section>
+
+    <section id="symbols1" type="non-sloppy">
+      <row>
+        <key>
+          <binding label="1"/>
+        </key>
+        <key>
+          <binding label="2"/>
+        </key>
+        <key>
+          <binding label="3"/>
+        </key>
+        <key>
+          <binding label="4"/>
+        </key>
+        <key>
+          <binding label="5"/>
+        </key>
+        <key>
+          <binding label="6"/>
+        </key>
+        <key>
+          <binding label="7"/>
+        </key>
+        <key>
+          <binding label="8"/>
+        </key>
+        <key>
+          <binding label="9"/>
+        </key>
+        <key>
+          <binding label="0"/>
+        </key>
+        <key>
+          <binding label="&#x2030;"/>
+        </key>
+      </row>
+
+      <row>
+        <key>
+          <binding label="&#x20AC;"/>
+        </key>
+        <key>
+          <binding label="&#x00A3;"/>
+        </key>
+        <key>
+          <binding label="&#x0024;"/>
+        </key>
+        <key>
+          <binding label="&#x00A5;"/>
+        </key>
+        <key>
+          <binding label="&#x00A7;"/>
+        </key>
+        <key>
+          <binding label="&#x007B;"/>
+        </key>
+        <key>
+          <binding label="&#x007D;"/>
+        </key>
+        <key>
+          <binding label="&#x005B;"/>
+        </key>
+        <key>
+          <binding label="&#x005D;"/>
+        </key>
+        <key>
+          <binding label="&#x00AB;"/>
+        </key>
+        <key>
+          <binding label="&#x00BB;"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special">
+          <binding action="switch" label="2/2"/>
+        </key>
+        <key>
+          <binding label="&#x0060;"/>
+        </key>
+        <key>
+          <binding label="&#x005E;"/>
+        </key>
+        <key>
+          <binding label="&#x007C;"/>
+        </key>
+        <key>
+          <binding label="&#x201C;"/>
+        </key>
+        <key>
+          <binding label="&#x201D;"/>
+        </key>
+        <key>
+          <binding label="&#x201E;"/>
+        </key>
+        <key>
+          <binding label="&#x00A9;"/>
+        </key>
+        <key>
+          <binding label="&#x00BF;"/>
+        </key>
+        <key>
+          <binding label="&#x00A1;"/>
+        </key>
+        <key style="special">
+          <binding action="backspace"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special" width="large">
+          <binding action="sym" label="ABC"/>
+        </key>
+        
+        <key><binding label="&#x003B;"/></key>
+        <key><binding label="&#x003A;"/></key>
+        
+        <key width="xx-large">
+          <binding action="space"/>
+        </key>
+        
+        <key style="special" width="x-large" id="actionKey">
+          <binding action="return"/>
+        </key>
+      </row>
+    </section>
+  </layout>
+</keyboard>
--- m-keyboard/layouts/symbols.xml
+++ m-keyboard/layouts/symbols.xml
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
-<keyboard version="1.0" catalog="symbols">
-  <layout type="general">
-    <section id="symbols0" type="non-sloppy">
-      <row>
-        <key>
-          <binding label="1" quickpick="true"/>
-        </key>
-        <key>
-          <binding label="2"/>
-        </key>
-        <key>
-          <binding label="3"/>
-        </key>
-        <key>
-          <binding label="4"/>
-        </key>
-        <key>
-          <binding label="5"/>
-        </key>
-        <key>
-          <binding label="6"/>
-        </key>
-        <key>
-          <binding label="7"/>
-        </key>
-        <key>
-          <binding label="8"/>
-        </key>
-        <key>
-          <binding label="9"/>
-        </key>
-        <key>
-          <binding label="0"/>
-        </key>
-      </row>
-
-      <row>
-        <key>
-          <binding label="*"/>
-        </key>
-        <key>
-          <binding label="#"/>
-        </key>
-        <key>
-          <binding label="+"/>
-        </key>
-        <key>
-          <binding label="-"/>
-        </key>
-        <key>
-          <binding label="_"/>
-        </key>
-        <key>
-          <binding label="="/>
-        </key>
-        <key>
-          <binding label="("/>
-        </key>
-        <key>
-          <binding label=")"/>
-        </key>
-        <key>
-          <binding label=";"/>
-        </key>
-        <key>
-          <binding label=":"/>
-        </key>
-      </row>
-
-      <row>
-        <key style="special">
-          <binding action="switch" label="1/2"/>
-        </key>
-        <key>
-          <binding label="@" quickpick="true"/>
-        </key>
-        <key>
-          <binding label="~"/>
-        </key>
-        <key>
-          <binding label="/"/>
-        </key>
-        <key>
-          <binding label="\"/>
-        </key>
-        <key>
-          <binding label="&#x0027;" quickpick="true"/>
-        </key>
-        <key>
-          <binding label="&#x0022;"/>
-        </key>
-        <key>
-          <binding label="&#x003F;"/>
-        </key>
-        <key>
-          <binding label="&#x0021;"/>
-        </key>
-        <key style="special">
-          <binding action="backspace"/>
-        </key>
-      </row>
-
-      <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="ABC"/>
-        </key>
-
-        <spacer/>
-
-        <key width="large"><binding label="&#x002C;"/></key>
-        <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="&#x002E;"/></key>
-
-        <spacer/>
-
-        <key style="special" width="x-large">
-          <binding action="return"/>
-        </key>
-
-      </row>
-    </section>
-
-    <section id="symbols1" type="non-sloppy">
-      <row>
-        <key>
-          <binding label="1"/>
-        </key>
-        <key>
-          <binding label="2"/>
-        </key>
-        <key>
-          <binding label="3"/>
-        </key>
-        <key>
-          <binding label="4"/>
-        </key>
-        <key>
-          <binding label="5"/>
-        </key>
-        <key>
-          <binding label="6"/>
-        </key>
-        <key>
-          <binding label="7"/>
-        </key>
-        <key>
-          <binding label="8"/>
-        </key>
-        <key>
-          <binding label="9"/>
-        </key>
-        <key>
-          <binding label="0"/>
-        </key>
-      </row>
-
-      <row>
-        <key>
-          <binding label="&#x20AC;"/>
-        </key>
-        <key>
-          <binding label="&#x00A3;"/>
-        </key>
-        <key>
-          <binding label="&#x0024;"/>
-        </key>
-        <key>
-          <binding label="&#x00A5;"/>
-        </key>
-        <key>
-          <binding label="&#x00A7;"/>
-        </key>
-        <key>
-          <binding label="&#x0025;"/>
-        </key>
-        <key>
-          <binding label="&#x005B;"/>
-        </key>
-        <key>
-          <binding label="&#x005D;"/>
-        </key>
-        <key>
-          <binding label="&#x003C;"/>
-        </key>
-        <key>
-          <binding label="&#x003E;"/>
-        </key>
-      </row>
-
-      <row>
-        <key style="special">
-          <binding action="switch" label="2/2"/>
-        </key>
-        <key>
-          <binding label="&#x0060;"/>
-        </key>
-        <key>
-          <binding label="&#x005E;"/>
-        </key>
-        <key>
-          <binding label="&#x007C;"/>
-        </key>
-        <key>
-          <binding label="&#x0026;"/>
-        </key>
-        <key>
-          <binding label="&#x201D;"/>
-        </key>
-        <key>
-          <binding label="&#x201E;"/>
-        </key>
-        <key>
-          <binding label="&#x00BF;"/>
-        </key>
-        <key>
-          <binding label="&#x00A1;"/>
-        </key>
-        <key style="special">
-          <binding action="backspace"/>
-        </key>
-      </row>
-
-      <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="ABC"/>
-        </key>
-
-        <spacer/>
-
-        <key width="large"><binding label="&#x00AB;"/></key>
-        <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="&#x00BB;"/></key>
-
-        <spacer/>
-
-        <key style="special" width="x-large">
-          <binding action="return"/>
-        </key>
-      </row>
-    </section>
-  </layout>
-</keyboard>
--- m-keyboard/layouts/symbols_ar.xml
+++ m-keyboard/layouts/symbols_ar.xml
@@ -1,266 +1,266 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
 <keyboard version="1.0" catalog="symbols">
-    <layout type="general">
-        <section id="symbols0" type="non-sloppy">
-          <row>
-            <key>
-              <binding label="1"/>
-            </key>
-            <key>
-              <binding label="2"/>
-            </key>
-            <key>
-              <binding label="3"/>
-            </key>
-            <key>
-              <binding label="4"/>
-            </key>
-            <key>
-              <binding label="5"/>
-            </key>
-            <key>
-              <binding label="6"/>
-            </key>
-            <key>
-              <binding label="7"/>
-            </key>
-            <key>
-              <binding label="8"/>
-            </key>
-            <key>
-              <binding label="9"/>
-            </key>
-            <key>
-              <binding label="0"/>
-            </key>
-          </row>
-
-          <row>
-            <key>
-              <binding label="*"/>
-            </key>
-            <key>
-              <binding label="#"/>
-            </key>
-            <key>
-              <binding label="+"/>
-            </key>
-            <key>
-              <binding label="-"/>
-            </key>
-            <key>
-              <binding label="_"/>
-            </key>
-            <key>
-              <binding label="%"/>
-            </key>
-            <key>
-              <binding label="="/>
-            </key>
-            <key>
-              <binding label="&#x0026;"/>
-            </key>
-            <key>
-              <binding label="("/>
-            </key>
-            <key>
-              <binding label=")"/>
-            </key>
-          </row>
-
-          <row>
-            <key style="special">
-              <binding action="switch" label="1/2"/>
-            </key>
-
-            <key>
-              <binding label="&#x0040;" quickpick="true"/>
-            </key>
-            <key>
-              <binding label="&#x007E;"/>
-            </key>
-            <key>
-              <binding label="&#x002F;"/>
-            </key>
-            <key>
-              <binding label="&#x005C;"/>
-            </key>
-            <key>
-              <binding label="&#x0027;" quickpick="true"/>
-            </key>
-            <key>
-              <binding label="&#x0022;"/>
-            </key>
-            <key>
-              <binding label="&#x061F;"/>
-            </key>
-            <key>
-              <binding label="&#x0021;"/>
-            </key>
-            <key style="special" rtl="true">
-              <binding action="backspace"/>
-            </key>
-          </row>
-
-          <row>
-            <key style="special" width="xx-large">
-              <binding action="sym" label="&#x0627;&#x200C;&#x0628;&#x200C;&#x062A;"/>
-            </key>
-
-            <key>
-              <binding label="&#x061B;"/>
-            </key>
-            <key>
-              <binding label="&#x002C;"/>
-            </key>
-
-            <key width="xx-large">
-              <binding action="space"/>
-            </key>
-
-            <key>
-              <binding label="&#x002E;"/>
-            </key>
-            <key>
-              <binding label="&#x003A;"/>
-            </key>
-
-            <key style="special" width="xx-large" rtl="false">
-              <binding action="return"/>
-            </key>
-          </row>
-        </section>
-
-        <section id="symbols1" type="non-sloppy">
-          <row>
-            <key>
-              <binding label="&#x0661;"/>
-            </key>
-            <key>
-              <binding label="&#x0662;"/>
-            </key>
-            <key>
-              <binding label="&#x0663;"/>
-            </key>
-            <key>
-              <binding label="&#x0664;"/>
-            </key>
-            <key>
-              <binding label="&#x0665;"/>
-            </key>
-            <key>
-              <binding label="&#x0666;"/>
-            </key>
-            <key>
-              <binding label="&#x0667;"/>
-            </key>
-            <key>
-              <binding label="&#x0668;"/>
-            </key>
-            <key>
-              <binding label="&#x0669;"/>
-            </key>
-            <key>
-              <binding label="&#x0660;"/>
-            </key>
-          </row>
-
-          <row>
-            <key>
-              <binding label="&#x20AC;"/>
-            </key>
-            <key>
-              <binding label="&#x00A3;"/>
-            </key>
-            <key>
-              <binding label="&#x0024;"/>
-            </key>
-            <key>
-              <binding label="&#x00A5;"/>
-            </key>
-            <key>
-              <binding label="&#x00A7;"/>
-            </key>
-            <key>
-              <binding label="&#x066A;"/>
-            </key>
-            <key>
-              <binding label="&#x003C;"/>
-            </key>
-            <key>
-              <binding label="&#x003E;"/>
-            </key>
-            <key>
-              <binding label="&#x005B;"/>
-            </key>
-            <key>
-              <binding label="&#x005D;"/>
-            </key>
-          </row>
-
-          <row>
-            <key style="special">
-              <binding action="switch" label="2/2"/>
-            </key>
-
-            <key>
-              <binding label="&#x0060;"/>
-            </key>
-            <key>
-              <binding label="&#x005E;"/>
-            </key>
-            <key>
-              <binding label="&#x007C;"/>
-            </key>
-            <key>
-              <binding label="&#x201C;"/>
-            </key>
-            <key>
-              <binding label="&#x201D;"/>
-            </key>
-            <key>
-              <binding label="&#x201E;"/>
-            </key>
-            <key>
-              <binding label="&#x066B;"/>
-            </key>
-            <key>
-              <binding label="&#x066C;"/>
-            </key>
-            <key style="special" rtl="true">
-              <binding action="backspace"/>
-            </key>
-          </row>
-
-          <row>
-            <key style="special" width="xx-large">
-              <binding action="sym" label="&#x0627;&#x200C;&#x0628;&#x200C;&#x062A;"/>
-            </key>
-
-            <key>
-              <binding label="&#x00AB;"/>
-            </key>
-            <key>
-              <binding label="&#x060C;"/>
-            </key>
-
-            <key width="xx-large">
-              <binding action="space"/>
-            </key>
-
-            <key>
-              <binding label="&#x002E;"/>
-            </key>
-            <key>
-              <binding label="&#x00BB;"/>
-            </key>
-
-            <key style="special" width="xx-large" rtl="false">
-              <binding action="return"/>
-            </key>
-          </row>
-        </section>
-    </layout>
+  <layout type="general">
+    <section id="symbols0" type="non-sloppy">
+      <row>
+        <key>
+          <binding label="&#x0661;"/>
+        </key>
+        <key>
+          <binding label="&#x0662;"/>
+        </key>
+        <key>
+          <binding label="&#x0663;"/>
+        </key>
+        <key>
+          <binding label="&#x0664;"/>
+        </key>
+        <key>
+          <binding label="&#x0665;"/>
+        </key>
+        <key>
+          <binding label="&#x0666;"/>
+        </key>
+        <key>
+          <binding label="&#x0667;"/>
+        </key>
+        <key>
+          <binding label="&#x0668;"/>
+        </key>
+        <key>
+          <binding label="&#x0669;"/>
+        </key>
+        <key>
+          <binding label="&#x0660;"/>
+        </key>
+        <key>
+          <binding label="%"/>
+        </key>
+      </row>
+
+      <row>
+        <key>
+          <binding label="*"/>
+        </key>
+        <key>
+          <binding label="#"/>
+        </key>
+        <key>
+          <binding label="+"/>
+        </key>
+        <key>
+          <binding label="-"/>
+        </key>
+        <key>
+          <binding label="_"/>
+        </key>
+        <key>
+          <binding label="="/>
+        </key>
+        <key>
+          <binding label="&#x0026;"/>
+        </key>
+        <key>
+          <binding label="("/>
+        </key>
+        <key>
+          <binding label=")"/>
+        </key>
+        <key>
+          <binding label="<"/>
+        </key>
+        <key>
+          <binding label=">"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special">
+          <binding action="switch" label="1/2"/>
+        </key>
+        <key>
+          <binding label="@" quickpick="true"/>
+        </key>
+        <key>
+          <binding label="~"/>
+        </key>
+        <key>
+          <binding label="/"/>
+        </key>
+        <key>
+          <binding label="\"/>
+        </key>
+        <key>
+          <binding label="&#x0027;" quickpick="true"/>
+        </key>
+        <key>
+          <binding label="&#x0022;"/>
+        </key>
+        <key>
+          <binding label="?"/>
+        </key>
+        <key>
+          <binding label="!"/>
+        </key>
+        <key>
+          <binding label="&#x00B0;"/>
+        </key>
+        <key style="special" rtl="true">
+          <binding action="backspace"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special" width="large">
+          <binding action="sym" label="&#x0627;&#x200C;&#x0628;&#x200C;&#x062A;"/>
+        </key>
+        
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
+        
+        <key width="xx-large">
+          <binding action="space"/>
+        </key>
+        
+        <key><binding label=";"/></key>
+        <key><binding label=":"/></key>
+        
+        <key style="special" width="x-large" id="actionKey">
+          <binding action="return"/>
+        </key>
+
+      </row>
+    </section>
+
+    <section id="symbols1" type="non-sloppy">
+      <row>
+        <key>
+          <binding label="1"/>
+        </key>
+        <key>
+          <binding label="2"/>
+        </key>
+        <key>
+          <binding label="3"/>
+        </key>
+        <key>
+          <binding label="4"/>
+        </key>
+        <key>
+          <binding label="5"/>
+        </key>
+        <key>
+          <binding label="6"/>
+        </key>
+        <key>
+          <binding label="7"/>
+        </key>
+        <key>
+          <binding label="8"/>
+        </key>
+        <key>
+          <binding label="9"/>
+        </key>
+        <key>
+          <binding label="0"/>
+        </key>
+        <key>
+          <binding label="&#x2030;"/>
+        </key>
+      </row>
+
+      <row>
+        <key>
+          <binding label="&#x20AC;"/>
+        </key>
+        <key>
+          <binding label="&#x00A3;"/>
+        </key>
+        <key>
+          <binding label="&#x0024;"/>
+        </key>
+        <key>
+          <binding label="&#x00A5;"/>
+        </key>
+        <key>
+          <binding label="&#x00A7;"/>
+        </key>
+        <key>
+          <binding label="&#x007B;"/>
+        </key>
+        <key>
+          <binding label="&#x007D;"/>
+        </key>
+        <key>
+          <binding label="&#x005B;"/>
+        </key>
+        <key>
+          <binding label="&#x005D;"/>
+        </key>
+        <key>
+          <binding label="&#x00AB;"/>
+        </key>
+        <key>
+          <binding label="&#x00BB;"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special">
+          <binding action="switch" label="2/2"/>
+        </key>
+        <key>
+          <binding label="&#x0060;"/>
+        </key>
+        <key>
+          <binding label="&#x005E;"/>
+        </key>
+        <key>
+          <binding label="&#x007C;"/>
+        </key>
+        <key>
+          <binding label="&#x201C;"/>
+        </key>
+        <key>
+          <binding label="&#x201D;"/>
+        </key>
+        <key>
+          <binding label="&#x201E;"/>
+        </key>
+        <key>
+          <binding label="&#x2116;"/>
+        </key>
+        <key>
+          <binding label="&#x00A9;"/>
+        </key>
+        <key>
+          <binding label="&#x00AE;"/>
+        </key>
+        <key style="special" rtl="true">
+          <binding action="backspace"/>
+        </key>
+      </row>
+
+      <row>
+        <key style="special" width="large">
+          <binding action="sym" label="&#x0627;&#x200C;&#x0628;&#x200C;&#x062A;"/>
+        </key>
+        
+        <key><binding label="&#x003B;"/></key>
+        <key><binding label="&#x003A;"/></key>
+        
+        <key width="xx-large">
+          <binding action="space"/>
+        </key>
+		
+        <key><binding label=";"/></key>
+        <key><binding label=":"/></key>
+        
+        <key style="special" width="x-large" id="actionKey">
+          <binding action="return"/>
+        </key>
+      </row>
+    </section>
+  </layout>
 </keyboard>
-
--- m-keyboard/layouts/symbols_en.xml
+++ m-keyboard/layouts/symbols_en.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!DOCTYPE keyboard SYSTEM 'VirtualKeyboardLayout.dtd'>
 <keyboard version="1.0" catalog="symbols">
-  <layout type="general" orientation="landscape">
+  <layout type="general">
     <section id="symbols0" type="non-sloppy">
       <row>
         <key>
@@ -55,10 +55,10 @@
           <binding label="="/>
         </key>
         <key>
-          <binding label="&#x0028;"/>
+          <binding label="("/>
         </key>
         <key>
-          <binding label="&#x0029;"/>
+          <binding label=")"/>
         </key>
         <key>
           <binding label="?"/>
@@ -94,10 +94,10 @@
           <binding label="&#x0027;" quickpick="true"/>
         </key>
         <key>
-          <binding label="&#x003B;"/>
+          <binding label=";"/>
         </key>
         <key>
-          <binding label="&#x003A;"/>
+          <binding label=":"/>
         </key>
 
         <spacer/>
@@ -114,13 +114,13 @@
 
         <spacer/>
 
-        <key width="large"><binding label="&#x002C;"/></key>
+        <key><binding label=","/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="&#x002E;"/></key>
+        <key><binding label="."/></key>
 
         <spacer/>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
 
@@ -238,261 +238,13 @@
 
         <spacer/>
 
-        <key width="large"><binding label="&#x002C;"/></key>
+        <key><binding label=","/></key>
         <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="&#x002E;"/></key>
-
-        <spacer/>
-
-        <key style="special" width="x-large">
-          <binding action="return"/>
-        </key>
-      </row>
-    </section>
-  </layout>
-
-  <layout type="general" orientation="portrait">
-    <section id="symbols0" type="non-sloppy">
-      <row>
-        <key>
-          <binding label="1"/>
-        </key>
-        <key>
-          <binding label="2"/>
-        </key>
-        <key>
-          <binding label="3"/>
-        </key>
-        <key>
-          <binding label="4"/>
-        </key>
-        <key>
-          <binding label="5"/>
-        </key>
-        <key>
-          <binding label="6"/>
-        </key>
-        <key>
-          <binding label="7"/>
-        </key>
-        <key>
-          <binding label="8"/>
-        </key>
-        <key>
-          <binding label="9"/>
-        </key>
-        <key>
-          <binding label="0"/>
-        </key>
-      </row>
+        <key><binding label="."/></key>
 
-      <row>
         <spacer/>
 
-        <key>
-          <binding label="*"/>
-        </key>
-        <key>
-          <binding label="#"/>
-        </key>
-        <key>
-          <binding label="+"/>
-        </key>
-        <key>
-          <binding label="-"/>
-        </key>
-        <key>
-          <binding label="="/>
-        </key>
-        <key>
-          <binding label="&#x0028;"/>
-        </key>
-        <key>
-          <binding label="&#x0029;"/>
-        </key>
-        <key>
-          <binding label="?"/>
-        </key>
-        <key>
-          <binding label="!"/>
-        </key>
-
-        <spacer/>
-      </row>
-
-      <row>
-        <key style="special" width="large">
-          <binding action="switch" label="1/2"/>
-        </key>
-
-        <spacer/>
-
-        <key>
-          <binding label="@"/>
-        </key>
-        <key>
-          <binding label="~"/>
-        </key>
-        <key>
-          <binding label="/"/>
-        </key>
-        <key>
-          <binding label="\"/>
-        </key>
-        <key>
-          <binding label="&#x0027;"/>
-        </key>
-        <key>
-          <binding label="&#x003B;"/>
-        </key>
-        <key>
-          <binding label="&#x003A;"/>
-        </key>
-
-        <spacer/>
-
-        <key style="special" width="large">
-          <binding action="backspace"/>
-        </key>
-      </row>
-
-      <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="ABC"/>
-        </key>
-
-        <spacer/>
-
-        <key width="large"><binding label="&#x002C;"/></key>
-        <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="&#x002E;"/></key>
-
-        <spacer/>
-
-        <key style="special" width="x-large">
-          <binding action="return"/>
-        </key>
-      </row>
-    </section>
-
-    <section id="symbols1" type="non-sloppy">
-      <row>
-        <key>
-          <binding label="&#x20AC;"/>
-        </key>
-        <key>
-          <binding label="&#x00A3;"/>
-        </key>
-        <key>
-          <binding label="&#x0024;"/>
-        </key>
-        <key>
-          <binding label="&#x00A5;"/>
-        </key>
-        <key>
-          <binding label="&#x0025;"/>
-        </key>
-        <key>
-          <binding label="&#x2030;"/>
-        </key>
-        <key>
-          <binding label="&#x003C;"/>
-        </key>
-        <key>
-          <binding label="&#x003E;"/>
-        </key>
-        <key>
-          <binding label="&#x005B;"/>
-        </key>
-        <key>
-          <binding label="&#x005D;"/>
-        </key>
-      </row>
-
-      <row>
-        <spacer/>
-
-         <key>
-          <binding label="&#x0060;"/>
-        </key>
-        <key>
-          <binding label="&#x005E;"/>
-        </key>
-        <key>
-          <binding label="&#x007C;"/>
-        </key>
-        <key>
-          <binding label="&#x005F;"/>
-        </key>
-        <key>
-          <binding label="&#x00A7;"/>
-        </key>
-        <key>
-          <binding label="&#x007B;"/>
-        </key>
-        <key>
-          <binding label="&#x007D;"/>
-        </key>
-        <key>
-          <binding label="&#x00BF;"/>
-        </key>
-        <key>
-          <binding label="&#x00A1;"/>
-        </key>
-
-        <spacer/>
-      </row>
-
-      <row>
-        <key style="special" width="large">
-          <binding action="switch" label="2/2"/>
-        </key>
-
-        <spacer/>
-
-        <key>
-          <binding label="&#x00AB;"/>
-        </key>
-        <key>
-          <binding label="&#x00BB;"/>
-        </key>
-        <key>
-          <binding label="&#x0022;"/>
-        </key>
-        <key>
-          <binding label="&#x201C;"/>
-        </key>
-        <key>
-          <binding label="&#x201D;"/>
-        </key>
-        <key>
-          <binding label="&#x201E;"/>
-        </key>
-        <key>
-          <binding label="&#x0026;"/>
-        </key>
-
-        <spacer/>
-
-        <key style="special" width="large">
-          <binding action="backspace"/>
-        </key>
-      </row>
-
-      <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="ABC"/>
-        </key>
-
-        <spacer/>
-
-        <key width="large"><binding label="&#x002C;"/></key>
-        <key width="xx-large"><binding action="space"/></key>
-        <key width="large"><binding label="&#x002E;"/></key>
-
-        <spacer/>
-
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/layouts/symbols_ru_uk.xml
+++ m-keyboard/layouts/symbols_ru_uk.xml
@@ -34,6 +34,9 @@
         <key>
           <binding label="0"/>
         </key>
+        <key>
+          <binding label="%"/>
+        </key>
       </row>
 
       <row>
@@ -53,10 +56,7 @@
           <binding label="_"/>
         </key>
         <key>
-          <binding label="&#x0025;"/>
-        </key>
-        <key>
-          <binding label="&#x003D;"/>
+          <binding label="="/>
         </key>
         <key>
           <binding label="&#x0026;"/>
@@ -67,6 +67,12 @@
         <key>
           <binding label=")"/>
         </key>
+        <key>
+          <binding label="<"/>
+        </key>
+        <key>
+          <binding label=">"/>
+        </key>
       </row>
 
       <row>
@@ -92,10 +98,13 @@
           <binding label="&#x0022;"/>
         </key>
         <key>
-          <binding label="&#x003F;"/>
+          <binding label="?"/>
+        </key>
+        <key>
+          <binding label="!"/>
         </key>
         <key>
-          <binding label="&#x0021;"/>
+          <binding label="&#x00B0;"/>
         </key>
         <key style="special">
           <binding action="backspace"/>
@@ -103,29 +112,21 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="&#x0410;&#x0411;&#x0412;"/>
-        </key>
-
-        <key>
-          <binding label="&#x003B;"/>
+        <key style="special" width="large">
+          <binding action="sym" label="АБВ"/>
         </key>
-        <key>
-          <binding label="&#x002C;"/>
-        </key>
-
+        
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
+        
         <key width="xx-large">
           <binding action="space"/>
         </key>
-
-        <key>
-          <binding label="&#x002E;"/>
-        </key>
-        <key>
-          <binding label="&#x003A;"/>
-        </key>
-
-        <key style="special" width="x-large">
+        
+        <key><binding label=";"/></key>
+        <key><binding label=":"/></key>
+        
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
 
@@ -164,6 +165,9 @@
         <key>
           <binding label="0"/>
         </key>
+        <key>
+          <binding label="&#x2030;"/>
+        </key>
       </row>
 
       <row>
@@ -183,13 +187,10 @@
           <binding label="&#x00A7;"/>
         </key>
         <key>
-          <binding label="&#x2030;"/>
-        </key>
-        <key>
-          <binding label="&#x003C;"/>
+          <binding label="&#x007B;"/>
         </key>
         <key>
-          <binding label="&#x003E;"/>
+          <binding label="&#x007D;"/>
         </key>
         <key>
           <binding label="&#x005B;"/>
@@ -197,6 +198,12 @@
         <key>
           <binding label="&#x005D;"/>
         </key>
+        <key>
+          <binding label="&#x00AB;"/>
+        </key>
+        <key>
+          <binding label="&#x00BB;"/>
+        </key>
       </row>
 
       <row>
@@ -227,38 +234,33 @@
         <key>
           <binding label="&#x00A9;"/>
         </key>
+        <key>
+          <binding label="&#x00AE;"/>
+        </key>
         <key style="special">
           <binding action="backspace"/>
         </key>
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="&#x0410;&#x0411;&#x0412;"/>
+        <key style="special" width="large">
+          <binding action="sym" label="АБВ"/>
         </key>
-        <key>
-          <binding label="&#x00AB;"/>
-        </key>
-        <key>
-          <binding label="&#x002C;"/>
-        </key>
-
+        
+        <key><binding label="&#x003B;"/></key>
+        <key><binding label="&#x003A;"/></key>
+        
         <key width="xx-large">
           <binding action="space"/>
         </key>
-
-        <key>
-          <binding label="&#x002E;"/>
-        </key>
-        <key>
-          <binding label="&#x00BB;"/>
-        </key>
-
-        <key style="special" width="x-large">
+		
+        <key><binding label=";"/></key>
+        <key><binding label=":"/></key>
+        
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 </keyboard>
-
--- m-keyboard/layouts/tr.xml
+++ m-keyboard/layouts/tr.xml
@@ -145,28 +145,28 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
         <key><binding label=","/></key>
+        <key><binding label="."/></key>
 
         <key width="xx-large">
           <binding action="space" label=""/>
         </key>
 
-        <key><binding label="."/></key>
         <key>
           <binding label="ğ"/>
           <binding shift="true" label="Ğ"/>
         </key>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
     </section>
   </layout>
 
-  <import file="symbols.xml"/>
+  <import file="symbols-38.xml"/>
 </keyboard>
--- m-keyboard/layouts/uk.xml
+++ m-keyboard/layouts/uk.xml
@@ -145,16 +145,12 @@
       </row>
 
       <row>
-        <key style="special" width="x-large">
-          <binding action="sym" label="SYM"/>
+        <key style="special" width="large">
+          <binding action="sym" label="?123"/>
         </key>
 
-        <key>
-          <binding label=","/>
-        </key>
-        <key>
-          <binding label="."/>
-        </key>
+        <key><binding label=","/></key>
+        <key><binding label="."/></key>
 
         <key width="xx-large">
           <binding action="space" label=""/>
@@ -169,7 +165,7 @@
           <binding shift="true" label="Ї"/>
         </key>
 
-        <key style="special" width="x-large">
+        <key style="special" width="x-large" id="actionKey">
           <binding action="return"/>
         </key>
       </row>
--- m-keyboard/mkeyboardhost.cpp
+++ m-keyboard/mkeyboardhost.cpp
@@ -27,7 +27,9 @@
 #include "symbolview.h"
 #include "mimtoolbar.h"
 #include "sharedhandlearea.h"
+#include "reactionmappainter.h"
 #include "regiontracker.h"
+#include "simplefilelog.h"
 
 #include <mimenginefactory.h>
 #include <mabstractinputmethodhost.h>
@@ -37,11 +39,9 @@
 
 #include <QDebug>
 #include <QKeyEvent>
-#include <QFile>
 #include <QRegExp>
 #include <QEasingCurve>
 
-#include <mreactionmap.h>
 #include <MScene>
 #include <MSceneManager>
 #include <MSceneWindow>
@@ -56,7 +56,9 @@
     const QString DefaultInputLanguage("en_GB");
     // TODO: check that these paths still hold
     const QString CorrectionSetting("/meegotouch/inputmethods/virtualkeyboard/correctionenabled");
+    const QString CorrectionSettingWithSpace("/meegotouch/inputmethods/virtualkeyboard/correctwithspace");
     const bool DefaultCorrectionSettingOption = true;
+    const bool DefaultCorrectionSettingAcceptedWithSpaceOption = true;
     const QString InputMethodCorrectionEngine("/meegotouch/inputmethods/correctionengine");
     const QRegExp AutoCapsTrigger("[.?!¡¿] +$");
     const QString AutoPunctuationTriggers(".,?!");
@@ -72,9 +74,10 @@
     const char * const NotificationObjectName = "ModifierLockNotification";
     const int KeysRequiredForFastTypingMode = 3;
     const int FastTypingTimeout = 700; //! Milliseconds to idle before leaving fast typing mode.
+    MKeyboardHost *currentInstance = 0;
+    const char *const MImTouchPointsLogfile = "touchpoints.csv";
 }
 
-
 MKeyboardHost::SlideUpAnimation::SlideUpAnimation(QObject *parent)
     : QPropertyAnimation(parent)
 {
@@ -187,8 +190,11 @@
       symbolView(0),
       imCorrectionEngine(0),
       inputMethodCorrectionSettings(new MGConfItem(CorrectionSetting)),
+      inputMethodCorrectionSettingsSpace(new MGConfItem(CorrectionSettingWithSpace)),
       inputMethodCorrectionEngine(new MGConfItem(InputMethodCorrectionEngine)),
+      rotationInProgress(false),
       correctionEnabled(false),
+      correctionAcceptedWithSpaceEnabled(false),
       autoCapsEnabled(true),
       autoCapsTriggered(false),
       cursorPos(-1),
@@ -196,7 +202,6 @@
       hasSelection(false),
       inputMethodMode(M::InputMethodModeNormal),
       backspaceTimer(),
-      rotationTimer(),
       shiftHeldDown(false),
       activeState(MInputMethod::OnScreen),
       modifierLockOnBanner(0),
@@ -212,16 +217,17 @@
       fastTypingKeyCount(0),
       fastTypingEnabled(false),
       vkbFadeInAnimation(*new QPropertyAnimation(this)),
-      toolbarFadeInAnimation(*new QPropertyAnimation(this))
+      toolbarFadeInAnimation(*new QPropertyAnimation(this)),
+      touchPointLogHandle(0)
 {
     RegionTracker::createInstance();
     connect(&RegionTracker::instance(), SIGNAL(regionChanged(const QRegion &)),
             imHost, SLOT(setScreenRegion(const QRegion &)));
     connect(&RegionTracker::instance(), SIGNAL(inputMethodAreaChanged(const QRegion &)),
             imHost, SLOT(setInputMethodArea(const QRegion &)));
-    connect(&RegionTracker::instance(), SIGNAL(reactionMapUpdateNeeded()),
-            this, SLOT(updateReactionMaps()));
-    RegionTracker::instance().enableSignals(false);
+
+    // Create the reaction map painter
+    ReactionMapPainter::createInstance();
 
     displayHeight = MPlainWindow::instance()->visibleSceneSize(M::Landscape).height();
     displayWidth  = MPlainWindow::instance()->visibleSceneSize(M::Landscape).width();
@@ -229,8 +235,10 @@
     sceneWindow = new MSceneWindow;
     sceneWindow->setManagedManually(true); // we want the scene window to remain in origin
 
-    // Enforcing full viewport updates helps to paint correctly in software mode.
-    MPlainWindow::instance()->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+    MPlainWindow::instance()->setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate);
+
+    // our paint methods are accurate enough, so we can disable painter saving
+    MPlainWindow::instance()->setOptimizationFlags(QGraphicsView::DontSavePainterState);
 
     // Because we set vkbWidget as a child of sceneWindow the vkb
     // will always be in correct orientation. However the animation will be
@@ -276,6 +284,8 @@
     hardwareKeyboard = new MHardwareKeyboard(*imHost, this);
     connect(hardwareKeyboard, SIGNAL(symbolKeyClicked()),
             this, SLOT(handleSymbolKeyClick()));
+    // Trigger a reaction map when the hardware keyboard is opened
+    connect(hardwareKeyboard, SIGNAL(enabled()), &ReactionMapPainter::instance(), SLOT(repaint()));
 
     bool ok = connect(vkbWidget, SIGNAL(copyPasteClicked(CopyPasteState)),
                       this, SLOT(sendCopyPaste(CopyPasteState)));
@@ -305,10 +315,8 @@
 
     // Set z value below default level (0.0) so popup will be on top of shared handle area.
     sharedHandleArea->setZValue(-1.0);
-
     sharedHandleArea->watchOnWidget(vkbWidget);
 
-
     createCorrectionCandidateWidget();
 
     // Don't listen to device orientation.  Applications can be in different orientation
@@ -352,6 +360,8 @@
             initializeInputEngine();
             connect(inputMethodCorrectionSettings, SIGNAL(valueChanged()),
                     this, SLOT(synchronizeCorrectionSetting()));
+            connect(inputMethodCorrectionSettingsSpace, SIGNAL(valueChanged()),
+                    this, SLOT(synchronizeCorrectionSettingSpace()));
         } else {
             qDebug() << __PRETTY_FUNCTION__ << "Failed to load correction engine"
                      << inputMethodCorrectionEngine->value().toString();
@@ -361,9 +371,6 @@
     backspaceTimer.setSingleShot(true);
     connect(&backspaceTimer, SIGNAL(timeout()), this, SLOT(autoBackspace()));
 
-    rotationTimer.setSingleShot(true);
-    connect(&rotationTimer, SIGNAL(timeout()), this, SLOT(finalizeOrientationChange()));
-
     fastTypingTimeout.setSingleShot(true);
     fastTypingTimeout.setInterval(FastTypingTimeout);
     connect(&fastTypingTimeout, SIGNAL(timeout()),
@@ -393,8 +400,12 @@
 
     connect(&slideUpAnimation, SIGNAL(finished()), this, SLOT(handleAnimationFinished()));
     connect(&toolbarAndVkbFadeInAnimation, SIGNAL(finished()), this, SLOT(handleAnimationFinished()));
+    // Trigger a reaction map update
+    connect(&slideUpAnimation, SIGNAL(finished()), &ReactionMapPainter::instance(), SLOT(repaint()));
+    connect(&toolbarAndVkbFadeInAnimation, SIGNAL(finished()), &ReactionMapPainter::instance(), SLOT(repaint()));
 
-    RegionTracker::instance().enableSignals(true, false);
+    Q_ASSERT(currentInstance == 0); // Several instances of this class is invalid.
+    currentInstance = this;
 }
 
 MKeyboardHost::~MKeyboardHost()
@@ -415,17 +426,27 @@
     sceneWindow = 0;
     delete vkbStyleContainer;
     vkbStyleContainer = 0;
+    delete inputMethodCorrectionSettingsSpace;
+    inputMethodCorrectionSettingsSpace = 0;
     delete inputMethodCorrectionSettings;
     inputMethodCorrectionSettings = 0;
+    delete touchPointLogHandle;
+    touchPointLogHandle = 0;
     if (imCorrectionEngine) {
         MImEngineFactory::instance()->deleteEngine(imCorrectionEngine);
         imCorrectionEngine = 0;
     }
     backspaceMode = NormalBackspaceMode;
     backspaceTimer.stop();
-    rotationTimer.stop();
     LayoutsManager::destroyInstance();
+    ReactionMapPainter::destroyInstance();
     RegionTracker::destroyInstance();
+    currentInstance = 0;
+}
+
+MKeyboardHost* MKeyboardHost::instance()
+{
+    return currentInstance;
 }
 
 void MKeyboardHost::createCorrectionCandidateWidget()
@@ -437,6 +458,13 @@
             this, SLOT(commitString(const QString &)));
 }
 
+QTextStream &MKeyboardHost::touchPointLog()
+{
+    if (!touchPointLogHandle) {
+        touchPointLogHandle = new SimpleFileLog(MImTouchPointsLogfile);
+    }
+    return touchPointLogHandle->stream();
+}
 
 // TODO: it would seem that application focus state is passed to all plugins by
 // MInputContextGlibDBusConnection::updateWidgetInformation, including nonactive ones.  If
@@ -472,14 +500,27 @@
     // something else changes during the animation.  But normally the region should be
     // the same as the one we send now.
 
-    QRectF vkbRect(vkbWidget->rect());
-    vkbRect.translate(0, -vkbRect.y()
-                      + MPlainWindow::instance()->visibleSceneSize().height()
-                      - vkbRect.height());
-    QRectF toolbarRect(sharedHandleArea->rect());
-    toolbarRect.translate(0, -toolbarRect.y() + vkbRect.y() - toolbarRect.height());
+    // Region is calculated from widget geometries so this method assumes relevant layouts
+    // to have been activated beforehand. A QGraphicsItem::show() will do, for example.
+
+    QRectF stackedRects(0.0f, MPlainWindow::instance()->visibleSceneSize().height(),
+                        0.0f, 0.0f);
+
+    // Add vkb rect if vkb is visible.
+    if (vkbWidget->isVisible()) {
+        QRectF vkbRect(vkbWidget->rect());
+        vkbRect.moveBottom(stackedRects.top());
+        stackedRects |= vkbRect;
+    }
+
+    // Add toolbar rect if it is visible.
+    if (sharedHandleArea->isVisible()) {
+        QRectF toolbarRect(sharedHandleArea->rect());
+        toolbarRect.moveBottom(stackedRects.top());
+        stackedRects |= toolbarRect;
+    }
 
-    const QRegion region((sceneWindow->mapRectToScene(vkbRect) | sceneWindow->mapRectToScene(toolbarRect)).toRect());
+    const QRegion region(sceneWindow->mapRectToScene(stackedRects).toRect());
 
     RegionTracker::instance().sendInputMethodAreaEstimate(region);
     RegionTracker::instance().sendRegionEstimate(region);
@@ -512,8 +553,21 @@
     updateEngineKeyboardLayout();
     updateCorrectionState();
 
-    sharedHandleArea->show();
+    if (imToolbar->currentToolbarData())
+        sharedHandleArea->show();
+
+    prepareHideShowAnimation();
+    if (activeState == MInputMethod::OnScreen) {
+        vkbWidget->show();
+    }
+    sendRegionEstimate();
+    slideUpAnimation.setDirection(QAbstractAnimation::Forward);
+    slideUpAnimation.start();
+}
+
 
+void MKeyboardHost::prepareHideShowAnimation()
+{
     if (activeState == MInputMethod::Hardware) {
         slideUpAnimation.setDuration(HardwareAnimationTime);
         vkbFadeInAnimation.setDuration(HardwareAnimationTime);
@@ -529,11 +583,7 @@
         slideUpAnimation.setTargetObject(vkbWidget);
         slideUpAnimation.setStartValue(QPointF(0, MPlainWindow::instance()->visibleSceneSize().height()
                                                + sharedHandleArea->size().height()));
-        vkbWidget->show();
     }
-    sendRegionEstimate();
-    slideUpAnimation.setDirection(QAbstractAnimation::Forward);
-    slideUpAnimation.start();
 }
 
 
@@ -545,10 +595,15 @@
     correctionHost->hideCorrectionWidget();
     symbolView->hideSymbolView(); // TODO: transition?
 
+    prepareHideShowAnimation();
     slideUpAnimation.setDirection(QAbstractAnimation::Backward);
     slideUpAnimation.start();
 
     sipRequested = false;
+
+    if (touchPointLogHandle) {
+        touchPointLogHandle->flush();
+    }
 }
 
 
@@ -567,7 +622,6 @@
     }
 
     RegionTracker::instance().enableSignals(true);
-    updateReactionMaps();
 }
 
 
@@ -777,23 +831,23 @@
 
 void MKeyboardHost::prepareOrientationChange()
 {
-    if (rotationTimer.isActive()) {
+    if (rotationInProgress) {
         return;
     }
+    rotationInProgress = true;
+
     // Saves states then hide
     symbolView->prepareToOrientationChange();
     vkbWidget->prepareToOrientationChange();
     correctionHost->prepareToOrientationChange();
     MPlainWindow::instance()->sceneManager()->disappearSceneWindowNow(sceneWindow);
-
-    // TODO: this is only a workaround for fixing the orientaton change bug.
-    // The correct fix need a notification from application, to tell keyboard
-    // when the orientation is finished for calling finalizeOrientationChange.
-    rotationTimer.start(1000);
 }
 
 void MKeyboardHost::finalizeOrientationChange()
 {
+    if (!rotationInProgress)
+        return;
+
     MPlainWindow::instance()->sceneManager()->appearSceneWindowNow(sceneWindow);
 
     if (imToolbar) {
@@ -805,6 +859,9 @@
     symbolView->finalizeOrientationChange();
     if (sharedHandleArea) {
         sharedHandleArea->finalizeOrientationChange();
+        if (activeState == MInputMethod::Hardware) {
+            sharedHandleArea->setPos(0, MPlainWindow::instance()->visibleSceneSize().height() - sharedHandleArea->size().height());
+        }
     }
 
     // Finalize candidate list after so its region will apply.
@@ -827,7 +884,7 @@
     if (vkbWidget->isVisible()) {
         updateEngineKeyboardLayout();
     }
-    rotationTimer.stop();
+    rotationInProgress = false;
 }
 
 void MKeyboardHost::handleMouseClickOnPreedit(const QPoint &mousePos, const QRect &preeditRect)
@@ -853,24 +910,19 @@
 
     // TODO: hide/show by fading?
     if (sipRequested) {
-        const bool wasEnabled(RegionTracker::instance().enableSignals(false));
         if (priority) {
             MPlainWindow::instance()->sceneManager()->disappearSceneWindowNow(sceneWindow);
         } else {
             MPlainWindow::instance()->sceneManager()->appearSceneWindowNow(sceneWindow);
         }
-        RegionTracker::instance().enableSignals(wasEnabled);
     }
 }
 
-
-void MKeyboardHost::handleAppOrientationChange(int angle)
+void MKeyboardHost::handleAppOrientationAboutToChange(int angle)
 {
     if (MPlainWindow::instance()->sceneManager()->orientationAngle()== static_cast<M::OrientationAngle>(angle))
         return;
-    if (rotationTimer.isActive()) {
-        rotationTimer.stop();
-    }
+
     // The application receiving input has changed its orientation. Let's change ours.
     // Disable  the transition animation for rotation.
     MPlainWindow::instance()->sceneManager()->setOrientationAngle(static_cast<M::OrientationAngle>(angle),
@@ -878,6 +930,16 @@
     prepareOrientationChange();
 }
 
+void MKeyboardHost::handleAppOrientationChanged(int angle)
+{
+    const M::OrientationAngle orientationAngle = static_cast<M::OrientationAngle>(angle);
+    if (orientationAngle != MPlainWindow::instance()->orientationAngle()) {
+        handleAppOrientationAboutToChange(angle);
+    }
+
+    finalizeOrientationChange();
+}
+
 
 void MKeyboardHost::commitString(const QString &updatedString)
 {
@@ -965,11 +1027,13 @@
 
 void MKeyboardHost::handleKeyPress(const KeyEvent &event)
 {
+#if 0 // Disabled because of bug NB#223996.
     // update fast typing mode
     if (++fastTypingKeyCount >= KeysRequiredForFastTypingMode) {
         turnOnFastTyping();
     }
     fastTypingTimeout.start(); // restart
+#endif
 
     if (event.qtKey() == Qt::Key_Shift) {
         if (shiftHeldDown) {
@@ -1037,62 +1101,6 @@
     }
 }
 
-void MKeyboardHost::updateReactionMaps()
-{
-    if (rotationTimer.isActive()) {
-        return;
-    }
-
-    // Start by making everything transparent
-    clearReactionMaps(MReactionMap::Transparent);
-
-    QList<QGraphicsView *> views = MPlainWindow::instance()->scene()->views();
-    foreach (QGraphicsView *view, views) {
-        MReactionMap *reactionMap = MReactionMap::instance(view);
-
-        if (!reactionMap) {
-            continue;
-        }
-
-        // Candidates widget
-        if (correctionHost && correctionHost->isActive()) {
-            correctionHost->paintReactionMap(reactionMap, view);
-
-            // Correction candidate widget occupies whole screen when it is WordListMode.
-            if (correctionHost->candidateMode() == MImCorrectionHost::WordListMode)
-                continue;
-        }
-
-        // Paint either symview or vkb widget reactive areas.
-        if (symbolView && symbolView->isVisible()) {
-            symbolView->paintReactionMap(reactionMap, view);
-        } else if (vkbWidget && vkbWidget->isVisible()) {
-            vkbWidget->paintReactionMap(reactionMap, view);
-        }
-
-        // Toolbar
-        if (imToolbar && imToolbar->isVisible()) {
-            imToolbar->paintReactionMap(reactionMap, view);
-        }
-    }
-}
-
-void MKeyboardHost::clearReactionMaps(const QString &clearValue)
-{
-    if (!MPlainWindow::instance()->scene()) {
-        return;
-    }
-
-    foreach (QGraphicsView *view, MPlainWindow::instance()->scene()->views()) {
-        MReactionMap *reactionMap = MReactionMap::instance(view);
-        if (reactionMap) {
-            reactionMap->setDrawingValue(clearValue, clearValue);
-            reactionMap->setTransform(QTransform()); // Identity
-            reactionMap->fillRectangle(0, 0, reactionMap->width(), reactionMap->height());
-        }
-    }
-}
-
 void MKeyboardHost::handleKeyClick(const KeyEvent &event)
 {
     // Don't need send key events for Direct input mode here.
@@ -1103,9 +1111,9 @@
         // modifiers may not be correct (depending on the current hwkbd modifier
         // state) but that doesn't matter.
         processKeyEvent(QEvent::KeyPress, event.qtKey(), event.modifiers(),
-                        event.text(), false, 1, 0, 0);
+                        event.text(), false, 1, 0, 0, 0);
         processKeyEvent(QEvent::KeyRelease, event.qtKey(), event.modifiers(),
-                        event.text(), false, 1, 0, 0);
+                        event.text(), false, 1, 0, 0, 0);
     } else if ((inputMethodMode != M::InputMethodModeDirect)) {
         handleTextInputKeyClick(event);
     }
@@ -1269,7 +1277,8 @@
         // or ignore it if correction widget is visible and with suggestionlist mode
         // otherwise commit preedit
         if (event.qtKey() == Qt::Key_Space
-            && correctionHost->isActive()) {
+            && correctionHost->isActive()
+            && correctionAcceptedWithSpaceEnabled) {
             if (correctionHost->candidateMode() == MImCorrectionHost::WordTrackerMode) {
                 wordTrackerSuggestionAcceptedWithSpace = true;
                 inputMethodHost()->sendCommitString(correctionHost->suggestion());
@@ -1286,10 +1295,7 @@
                                                   && preeditCursorPos != preedit.length()
                                                   && inputMethodHost()->surroundingText(surroundingText, cursorPos)
                                                   && (cursorPos >= 0);
-                inputMethodHost()->sendCommitString(preedit);
-                if (needRepositionCursor) {
-                    inputMethodHost()->setSelection(cursorPos + preeditCursorPos, 0);
-                }
+                inputMethodHost()->sendCommitString(preedit, 0, 0, needRepositionCursor ? (cursorPos + preeditCursorPos) : -1);
             }
         }
 
@@ -1382,6 +1388,7 @@
         engineLayoutDirty = true;
         updateEngineKeyboardLayout();
         synchronizeCorrectionSetting();
+        synchronizeCorrectionSettingSpace();
         imCorrectionEngine->disablePrediction();
         imCorrectionEngine->setMaximumCandidates(MaximumErrorCorrectionCandidate);
         imCorrectionEngine->setExactWordPositionInList(MImEngine::ExactInListFirst);
@@ -1403,6 +1410,11 @@
     updateCorrectionState();
 }
 
+void MKeyboardHost::synchronizeCorrectionSettingSpace()
+{
+    correctionAcceptedWithSpaceEnabled
+        = inputMethodCorrectionSettingsSpace->value(DefaultCorrectionSettingAcceptedWithSpaceOption).toBool();
+}
 
 void MKeyboardHost::updateCorrectionState()
 {
@@ -1415,14 +1427,28 @@
             correctionEnabled = false;
             return;
         }
-        bool val = false;
-        bool enabled = inputMethodHost()->correctionEnabled(val);
-        if (val)
-            correctionEnabled = enabled && imCorrectionEngine->correctionEnabled()
-                                && imCorrectionEngine->completionEnabled();
-        else
-            correctionEnabled = imCorrectionEngine->correctionEnabled()
-                                && imCorrectionEngine->completionEnabled();
+
+        // Don't use correction for certain types.
+        bool enabledByContent = true, ctValid;
+        int contentType = inputMethodHost()->contentType(ctValid);
+        if (ctValid && (contentType == M::NumberContentType
+                        || contentType == M::PhoneNumberContentType
+                        || contentType == M::EmailContentType
+                        || contentType == M::UrlContentType)) {
+            enabledByContent = false;
+        }
+
+        // Enable correction if correction is enabled from MTextEdit and prediction
+        // is not disabled (Qt::ImhNoPredictiveText hint not set). Ignore either
+        // value if value is not set.
+        bool ecValid = false, pValid = false;
+        bool ecEnabled = inputMethodHost()->correctionEnabled(ecValid);
+        bool pEnabled = inputMethodHost()->predictionEnabled(pValid);
+        correctionEnabled = enabledByContent
+                            && (!ecValid || ecEnabled)
+                            && (!pValid || pEnabled)
+                            && imCorrectionEngine->correctionEnabled()
+                            && imCorrectionEngine->completionEnabled();
 
         // info context the global correction option
         // TODO: should not put setGlobalCorrectionEnabled here, it will send correction setting
@@ -1493,21 +1519,30 @@
 void MKeyboardHost::setToolbar(QSharedPointer<const MToolbarData> toolbar)
 {
     if (toolbar && toolbar->isVisible()) {
+        const MToolbarData *oldToolbar = imToolbar->currentToolbarData();
+        sharedHandleArea->show();
         imToolbar->showToolbarWidget(toolbar);
+        // if current is in Hardware state, and no toolbar being visible before,
+        // start animation to show new toolbar.
+        if (!oldToolbar && activeState == MInputMethod::Hardware) {
+            prepareHideShowAnimation();
+            slideUpAnimation.start();
+        }
     } else {
         imToolbar->hideToolbarWidget();
+        sharedHandleArea->hide();
     }
 }
 
 void MKeyboardHost::processKeyEvent(QEvent::Type keyType, Qt::Key keyCode,
                                     Qt::KeyboardModifiers modifiers, const QString &text,
                                     bool autoRepeat, int count, quint32 nativeScanCode,
-                                    quint32 nativeModifiers)
+                                    quint32 nativeModifiers, unsigned long time)
 {
     if ((activeState != MInputMethod::Hardware) ||
         !hardwareKeyboard->filterKeyEvent(keyType, keyCode, modifiers, text,
                                           autoRepeat, count, nativeScanCode,
-                                          nativeModifiers)) {
+                                          nativeModifiers, time)) {
         inputMethodHost()->sendKeyEvent(QKeyEvent(keyType, keyCode, modifiers, text,
                                                   autoRepeat, count),
                                         MInputMethod::EventRequestEventOnly);
@@ -1564,8 +1599,8 @@
         }
         if (sipRequested) {
             slideUpAnimation.stop();
-            vkbWidget->show();
             vkbWidget->setPos(0, MPlainWindow::instance()->visibleSceneSize().height() - vkbWidget->size().height());
+            vkbWidget->show();
         }
     } else {
         currentIndicatorDeadKey = false;
@@ -1603,9 +1638,6 @@
         return;
     }
 
-    // TODO: make RegionTracker do this kind of optimization automatically
-    const bool wasEnabled(RegionTracker::instance().enableSignals(false));
-
     // Toggle SymbolView.
     if (!symbolView->isVisible()) {
         symbolView->setPos(0, MPlainWindow::instance()->visibleSceneSize().height() - symbolView->size().height());
@@ -1615,8 +1647,6 @@
     } else {
         symbolView->hideSymbolView();
     }
-
-    RegionTracker::instance().enableSignals(wasEnabled);
 }
 
 void MKeyboardHost::updateSymbolViewLevel()
@@ -1635,13 +1665,10 @@
 
 void MKeyboardHost::showSymbolView()
 {
-    // TODO: make RegionTracker do this kind of optimization automatically
-    const bool wasEnabled(RegionTracker::instance().enableSignals(false));
     symbolView->setPos(0, MPlainWindow::instance()->visibleSceneSize().height() - symbolView->size().height());
     symbolView->showSymbolView(SymbolView::FollowMouseShowMode);
     //give the symbolview right shift level(for hardware state)
     updateSymbolViewLevel();
-    RegionTracker::instance().enableSignals(wasEnabled);
 }
 
 MInputMethod::InputModeIndicator MKeyboardHost::deadKeyToIndicator(const QChar &key)
--- m-keyboard/mkeyboardhost.h
+++ m-keyboard/mkeyboardhost.h
@@ -28,6 +28,7 @@
 #include <QPropertyAnimation>
 #include <QSequentialAnimationGroup>
 #include <QParallelAnimationGroup>
+#include <QTextStream>
 
 class MGConfItem;
 class MImCorrectionHost;
@@ -42,7 +43,7 @@
 class SharedHandleArea;
 class MImToolbar;
 class MAbstractInputMethodHost;
-
+class SimpleFileLog;
 
 //! Logic class for virtual keyboard
 class MKeyboardHost: public MAbstractInputMethod
@@ -53,6 +54,11 @@
     MKeyboardHost(MAbstractInputMethodHost *imHost, QObject *parent = 0);
     virtual ~MKeyboardHost();
 
+    //! \brief Return the current instance, or 0 if none.
+    static MKeyboardHost* instance();
+    //! \brief Return the logger for touchpoints. Created if neccesary.
+    QTextStream &touchPointLog();
+
     //! reimp
     virtual void handleFocusChange(bool focusIn);
     virtual void show();
@@ -65,13 +71,14 @@
     virtual void reset();
     virtual void handleMouseClickOnPreedit(const QPoint &mousePos, const QRect &preeditRect);
     virtual void handleVisualizationPriorityChange(bool priority);
-    virtual void handleAppOrientationChange(int angle);
+    virtual void handleAppOrientationAboutToChange(int angle);
+    virtual void handleAppOrientationChanged(int angle);
     virtual void setToolbar(QSharedPointer<const MToolbarData> toolbar);
     virtual void setState(const QSet<MInputMethod::HandlerState> &state);
     virtual void processKeyEvent(QEvent::Type keyType, Qt::Key keyCode,
                                  Qt::KeyboardModifiers modifiers,
                                  const QString &text, bool autoRepeat, int count,
-                                 quint32 nativeScanCode, quint32 nativeModifiers);
+                                 quint32 nativeScanCode, quint32 nativeModifiers, unsigned long time);
     virtual void handleClientChange();
     virtual void switchContext(MInputMethod::SwitchDirection direction, bool enableAnimation);
     virtual QList<MAbstractInputMethod::MInputMethodSubView> subViews(MInputMethod::HandlerState state
@@ -116,9 +123,6 @@
      */
     void handleLongKeyPress(const KeyEvent &event);
 
-    //! \brief Draws reaction maps for the topmost widget.
-    void updateReactionMaps();
-
     /*!
      * \brief Commits \a string.
      *
@@ -141,6 +145,9 @@
     //! Synchronize correction setting
     void synchronizeCorrectionSetting();
 
+    //! Synchronize the correction setting whether the correction suggestion should be accepted by space.
+    void synchronizeCorrectionSettingSpace();
+
     //! handles user initiated hiding of the keyboard
     void userHide();
 
@@ -197,6 +204,9 @@
     void handleAnimationFinished();
 
 private:
+    //! Configures the parts that may change dynamically.
+    void prepareHideShowAnimation();
+
     void sendRegionEstimate();
 
     //! \brief Reset internal state, used by reset() and others
@@ -241,11 +251,6 @@
      */
     void handleTextInputKeyClick(const KeyEvent &event);
 
-    /*! \brief Clears reaction maps with given MReactionMap color value.
-     *  \param clearValue A MReactionMap color value such as MReactionMap::Inactive.
-     */
-    void clearReactionMaps(const QString &clearValue);
-
     //! initialize input engine
     void initializeInputEngine();
 
@@ -331,6 +336,7 @@
     MImEngineWordsInterface *imCorrectionEngine;
     //! default input method error correction setting
     MGConfItem *inputMethodCorrectionSettings;
+    MGConfItem *inputMethodCorrectionSettingsSpace;
     MGConfItem *inputMethodCorrectionEngine;
 
     QStringList candidates;
@@ -338,8 +344,11 @@
     int displayWidth;
     int displayHeight;
 
+    bool rotationInProgress;
+
     //! error correction flag
     bool correctionEnabled;
+    bool correctionAcceptedWithSpaceEnabled;
 
     //! FIXME: should we provide such a flag to on/off auto caps
     bool autoCapsEnabled;
@@ -354,8 +363,6 @@
 
     QTimer backspaceTimer;
 
-    QTimer rotationTimer;
-
     KeyEvent lastClickEvent;
 
     //! Keeps track of shift up/down status.
@@ -407,6 +414,8 @@
     QPropertyAnimation& toolbarFadeInAnimation;
     QParallelAnimationGroup toolbarAndVkbFadeInAnimation;
 
+    SimpleFileLog *touchPointLogHandle;
+
 #ifdef UNIT_TEST
     friend class Ut_MKeyboardHost;
 #endif
--- m-keyboard/theme/haptic-press
+++ m-keyboard/theme/haptic-press
+(directory)
--- m-keyboard/theme/haptic-press/haptic-press.pri
+++ m-keyboard/theme/haptic-press/haptic-press.pri
+
+haptic_press_data.path = /usr/share/themes/base/meegotouch/meego-im-uiserver/feedbacks/vkb-press
+haptic_press_data.files = theme/haptic-press/vibra.ivt
+
+INSTALLS += \
+    haptic_press_data \
--- m-keyboard/theme/haptic-release
+++ m-keyboard/theme/haptic-release
+(directory)
--- m-keyboard/theme/haptic-release/haptic-release.pri
+++ m-keyboard/theme/haptic-release/haptic-release.pri
+
+haptic_release_data.path = /usr/share/themes/base/meegotouch/meego-im-uiserver/feedbacks/vkb-release
+haptic_release_data.files = theme/haptic-release/vibra.ivt
+
+INSTALLS += \
+    haptic_release_data \
--- m-keyboard/theme/libmeego-keyboard.css
+++ m-keyboard/theme/libmeego-keyboard.css
@@ -30,7 +30,7 @@
 MImAbstractKeyAreaStyle {
     /*** Font Settings ***/
     font: $FONT_KEYBOARD;
-    font-color: $COLOR_FOREGROUND;
+    font-color: $FONT_COLOR_KEYBOARD;
     secondary-font: $FONT_SMALL;
 
     /*** Graphical assets ***/
@@ -46,7 +46,7 @@
     key-background-special-pressed-selected: "meegotouch-keyboard-function-key-pressed-selected" 15 15 15 15;
 
     key-background-deadkey: "meegotouch-keyboard-key" 15 15 15 15;
-    key-background-deadkey-pressed: "meegotouch-keyboard-pressed" 15 15 15 15;
+    key-background-deadkey-pressed: "meegotouch-keyboard-key-pressed" 15 15 15 15;
     key-background-deadkey-selected: "meegotouch-keyboard-key-selected" 15 15 15 15;
     key-background-deadkey-pressed-selected: "meegotouch-keyboard-key-pressed-selected" 15 15 15 15;
 
@@ -76,6 +76,8 @@
     flick-gesture-timeout: 500;
     flick-gesture-threshold-ratio: 0.5;
 
+    touchpoint-vertical-offset: 0mm;
+
     /*** Key Geometry ***/
     use-fixed-key-width: false;
     key-width-small: 0.5;
@@ -117,27 +119,27 @@
 
     /*** Key Geometry ***/
     key-height-small: -1; /* unused */
-    key-height-medium: 48px;
+    key-height-medium: 46px;
     key-height-large: 66px;
     key-height-x-large: 82px;
     key-height-xx-large: -1; /* unused */
 
     key-width-small-fixed: -1; /* unused */
     key-width-medium-fixed: 76px;
-    key-width-large-fixed: 94px;
-    key-width-x-large-fixed: 160px;
+    key-width-large-fixed: 93px;
+    key-width-x-large-fixed: 178px;
     key-width-xx-large-fixed: 244px;
     key-width-stretched-fixed: -1; /* unused */
     
     key-margin-left: 4px;
     key-margin-top: 0px;
     key-margin-right: 4px;
-    key-margin-bottom: 8px;
+    key-margin-bottom: 12px;
 
     padding-left: 11px;
-    padding-top: 12px;
+    padding-top: 8px;
     padding-right: 11px;
-    padding-bottom: 12px;
+    padding-bottom: 8px;
 
     /*** Key Area Geometry ***/
     size: 854 -1;
@@ -153,6 +155,8 @@
     touchpoint-horizontal-gravity: 17px;
     touchpoint-vertical-gravity: 26px;
 
+    touchpoint-vertical-offset: 1.7mm;
+
     /*** Key Geometry ***/
     key-height-small: -1; /* unused */
     key-height-medium: 62px;
@@ -161,21 +165,21 @@
     key-height-xx-large: -1; /* unused */
 
     key-width-small-fixed: -1; /* unused */
-    key-width-medium-fixed: 46px;
-    key-width-large-fixed: 70px;
-    key-width-x-large-fixed: 94px;
-    key-width-xx-large-fixed: 142px;
+    key-width-medium-fixed: 40px;
+    key-width-large-fixed: 56px;
+    key-width-x-large-fixed: 104px;
+    key-width-xx-large-fixed: 136px;
     key-width-stretched-fixed: -1; /* unused */
    
-    key-margin-left: 1px;
+    key-margin-left: 4px;
     key-margin-top: 0px;
-    key-margin-right: 1px;
-    key-margin-bottom: 16px;
+    key-margin-right: 4px;
+    key-margin-bottom: 18px;
 
-    padding-left: 1px;
-    padding-top: 12px;
-    padding-right: 1px;
-    padding-bottom: 12px;
+    padding-left: 4px;
+    padding-top: 8px;
+    padding-right: 4px;
+    padding-bottom: 8px;
 
     /*** Key Area Geometry ***/
     size: 480 -1;
@@ -204,31 +208,35 @@
     use-fixed-key-width: true;
 }
 
-MImAbstractKeyAreaStyle.Landscape:keys35 {
-    use-fixed-key-width: true;
-}
-
-MImAbstractKeyAreaStyle.Portrait:keys35 {
-    use-fixed-key-width: true;
-}
-
 MImAbstractKeyAreaStyle.Landscape:keys36 {
     use-fixed-key-width: true;
+    
+    key-width-large-fixed: 118px;
+    key-width-x-large-fixed: 160px;
+    key-width-xx-large-fixed: 286px;
 }
 
 MImAbstractKeyAreaStyle.Portrait:keys36 {
     use-fixed-key-width: true;
+
+    key-width-large-fixed: 88px;
+    key-width-x-large-fixed: 112px;
+    key-width-xx-large-fixed: 112px;
 }
 
 MImAbstractKeyAreaStyle.Landscape:keys37 {
     use-fixed-key-width: true;
 
-    key-width-xx-large-fixed: 160px;
+    key-width-large-fixed: 118px;
+    key-width-x-large-fixed: 160px;
+    key-width-xx-large-fixed: 202px;
 }
 
 MImAbstractKeyAreaStyle.Portrait:keys37 {
     use-fixed-key-width: true;
 
+    key-width-large-fixed: 64px;
+    key-width-x-large-fixed: 112px;
     key-width-xx-large-fixed: 88px;
 }
 
@@ -236,9 +244,9 @@
     use-fixed-key-width: true;
 
     key-width-medium-fixed: 72px;
-    key-width-large-fixed: 87px;
+    key-width-large-fixed: 150px;
     key-width-x-large-fixed: 150px;
-    key-width-xx-large-fixed: 306px;
+    key-width-xx-large-fixed: 384px;
     
     key-margin-left: 3px;
     key-margin-right: 3px;
@@ -250,25 +258,25 @@
 MImAbstractKeyAreaStyle.Portrait:keys38 {
     use-fixed-key-width: true;
 
-    key-width-medium-fixed: 42px;
-    key-width-large-fixed: 66px;
-    key-width-x-large-fixed: 85px;
+    key-width-medium-fixed: 38px;
+    key-width-large-fixed: 82px;
+    key-width-x-large-fixed: 126px;
     key-width-xx-large-fixed: 170px;
    
-    key-margin-left: 1px;
-    key-margin-right: 1px;
+    key-margin-left: 3px;
+    key-margin-right: 3px;
 
-    padding-left: 0px;
-    padding-right: 0px;
+    padding-left: 1px;
+    padding-right: 1px;
 }
 
 MImAbstractKeyAreaStyle.Landscape:keys39 {
     use-fixed-key-width: true;
 
     key-width-medium-fixed: 72px;
-    key-width-large-fixed: 87px;
+    key-width-large-fixed: 111px;
     key-width-x-large-fixed: 150px;
-    key-width-xx-large-fixed: 306px;
+    key-width-xx-large-fixed: 345px;
     
     key-margin-left: 3px;
     key-margin-right: 3px;
@@ -280,25 +288,25 @@
 MImAbstractKeyAreaStyle.Portrait:keys39 {
     use-fixed-key-width: true;
 
-    key-width-medium-fixed: 42px;
-    key-width-large-fixed: 66px;
-    key-width-x-large-fixed: 85px;
-    key-width-xx-large-fixed: 174px;
+    key-width-medium-fixed: 38px;
+    key-width-large-fixed: 82px;
+    key-width-x-large-fixed: 126px;
+    key-width-xx-large-fixed: 126px;
    
-    key-margin-left: 1px;
-    key-margin-right: 1px;
+    key-margin-left: 3px;
+    key-margin-right: 3px;
 
-    padding-left: 0px;
-    padding-right: 0px;
+    padding-left: 1px;
+    padding-right: 1px;
 }
 
 MImAbstractKeyAreaStyle.Landscape:keys40 {
     use-fixed-key-width: true;
 
     key-width-medium-fixed: 72px;
-    key-width-large-fixed: 87px;
+    key-width-large-fixed: 111px;
     key-width-x-large-fixed: 150px;
-    key-width-xx-large-fixed: 228px;
+    key-width-xx-large-fixed: 267px;
     
     key-margin-left: 3px;
     key-margin-right: 3px;
@@ -310,16 +318,16 @@
 MImAbstractKeyAreaStyle.Portrait:keys40 {
     use-fixed-key-width: true;
 
-    key-width-medium-fixed: 42px;
-    key-width-large-fixed: 66px;
-    key-width-x-large-fixed: 85px;
-    key-width-xx-large-fixed: 130px;
+    key-width-medium-fixed: 38px;
+    key-width-large-fixed: 60px;
+    key-width-x-large-fixed: 126px;
+    key-width-xx-large-fixed: 104px;
    
-    key-margin-left: 1px;
-    key-margin-right: 1px;
+    key-margin-left: 3px;
+    key-margin-right: 3px;
 
-    padding-left: 0px;
-    padding-right: 0px;
+    padding-left: 1px;
+    padding-right: 1px;
 }
 
 #InvisibleHandle.Portrait {
@@ -329,25 +337,9 @@
 }
 
 #InvisibleHandle.Landscape {
-    preferred-size: 864 2.5mm;
+    preferred-size: 854 2.5mm;
     minimum-size:   480 2.5mm;
-    maximum-size:   864 2.5mm;
-}
-
-#KeyboardToolbarHandle {
-    background-image: "meegotouch-keyboard-border-top";
-}
-
-#KeyboardToolbarHandle.Portrait {
-    preferred-size: 480 0.6mm;
-    minimum-size: 480 0.6mm;
-    maximum-size: 480 0.6mm;
-}
-
-#KeyboardToolbarHandle.Landscape {
-    preferred-size: 864 0.6mm;
-    minimum-size: 480 0.6mm;
-    maximum-size: 864 0.6mm;
+    maximum-size:   854 2.5mm;
 }
 
 #KeyboardHandle {
@@ -355,9 +347,9 @@
 }
 
 #KeyboardHandle.Landscape {
-    preferred-size: 864 0;
+    preferred-size: 854 0;
     minimum-size: 480 0;
-    maximum-size: 864 0;
+    maximum-size: 854 0;
 }
 
 #KeyboardHandle.Portrait {
@@ -366,34 +358,6 @@
     maximum-size: 480 0;
 }
 
-#MenuToggleButton {
-    background-image: "Toggle-btn-normal" 0 0 0 0;
-    background-opacity: 1.0;
-    background-color: #000000;
-    text-color: #FFFFFF;
-}
-
-
-#MenuToggleButton:pressed {
-    background-image: "Toggle-btn-selected" 0 0 0 0;
-    background-opacity: 1.0;
-    background-color: #F9A427;
-    text-color: #555555;    
-}
-
-
-#MenuLanguageList {
-    background-image: "Single-line-input-field" 0 0 0 0;
-    text-left-offset: 12;
-    text-right-offset: 12;
-
-    font: $FONT_SMALL_REGULAR;
-    text-color: $COLOR_FOREGROUND;
-
-    preferred-size: 414 56;
-    minimum-size: 414 56;
-    maximum-size: 414 56;
-}
 
 MToolbarLabelStyle {
     margin-left: 0;
--- m-keyboard/theme/theme.pri
+++ m-keyboard/theme/theme.pri
@@ -1,3 +1,7 @@
+
+include(haptic-press/haptic-press.pri)
+include(haptic-release/haptic-release.pri)
+
 IMAGES_DATA = theme/meegotouch-keyboard.svg
 images_data.path = /usr/share/themes/base/meegotouch/svg
 images_data.files = $$IMAGES_DATA
@@ -9,4 +13,3 @@
 INSTALLS += \
     images_data \
     css_data \
-
--- m-keyboard/widgets/mimabstractkey.h
+++ m-keyboard/widgets/mimabstractkey.h
@@ -25,6 +25,7 @@
 class QRect;
 class QPainter;
 class MImAbstractKey;
+class MScalableImage;
 
 //! Visitor interface that can be used for MImAbstractKey::visitActiveKeys
 class MImAbstractKeyVisitor
@@ -114,6 +115,9 @@
     //! \brief Returns whether gravity is active.
     virtual bool isGravityActive() const = 0;
 
+    //! \brief Return background image according to current mode and style.
+    virtual const MScalableImage *backgroundImage() const = 0;
+
     //! \brief Returns most recent key that became active, and wasn't released yet.
     //!        If no key is active, returns 0.
     static MImAbstractKey* lastActiveKey();
--- m-keyboard/widgets/mimabstractkeyarea.cpp
+++ m-keyboard/widgets/mimabstractkeyarea.cpp
@@ -18,8 +18,10 @@
 #include "flickgesturerecognizer.h"
 #include "mimabstractkeyarea.h"
 #include "mimkeyvisitor.h"
+#include "mimreactionmap.h"
 #include "popupbase.h"
 #include "popupfactory.h"
+#include "mkeyboardhost.h"
 
 #include <MFeedback>
 #include <MGConfItem>
@@ -45,9 +47,6 @@
     // This GConf item defines whether multitouch is enabled or disabled
     const char *const MultitouchSettings = "/meegotouch/inputmethods/multitouch/enabled";
 
-    const char *const MImUserDirectory = ".meego-im";
-    const char *const MImTouchPointsLogfile = "touchpoints.csv";
-
     // Minimal distance (in px) for touch point from key button edge.
     const int CorrectionDistanceThreshold = 2;
 
@@ -72,41 +71,6 @@
         return pos;
     }
 
-    //! Handles destruction order of internal QFile and QTextStream correctly
-    //! and extends lifetime of QFile to QTextStream.
-    class StreamHandle
-    {
-    public:
-        explicit StreamHandle(const QString &fileName)
-            : mFile(fileName)
-            , mStream(&mFile)
-        {
-            mStream.setCodec("utf-8");
-            lastAccess.start();
-        }
-
-        QFile &file()
-        {
-            return mFile;
-        }
-
-        QTextStream &stream()
-        {
-            // Just make sure we don't lose too much in case of a uiserver crash:
-            if (lastAccess.elapsed() > 10000) {
-                mStream.flush();
-                lastAccess.restart();
-            }
-
-            return mStream;
-        }
-
-    private:
-        QFile mFile;
-        QTextStream mStream;
-        QTime lastAccess;
-    };
-
     QString toString(const QPointF &p, const QString &separator = ", ")
     {
         return QString("%1%2%3").arg(p.x())
@@ -167,8 +131,7 @@
       mPopup(usePopup ? PopupFactory::instance()->createPopup(this) : 0),
       wasGestureTriggered(false),
       enableMultiTouch(MGConfItem(MultitouchSettings).value().toBool()),
-      feedbackPress(MFeedback::Press),
-      feedbackCancel(MFeedback::Cancel),
+      feedbackSliding(MImReactionMap::Release),
       section(newSection)
 {
     // By default multi-touch is disabled
@@ -253,11 +216,11 @@
 void
 MImAbstractKeyArea::handleVisibilityChanged(bool visible)
 {
-    if (mPopup) {
-        mPopup->setVisible(visible);
-    }
-
     if (!visible) {
+        if (mPopup) {
+            mPopup->setVisible(false);
+        }
+
         MImKeyVisitor::SpecialKeyFinder finder(MImKeyVisitor::SpecialKeyFinder::FindDeadKey);
         MImAbstractKey::visitActiveKeys(&finder);
 
@@ -533,7 +496,7 @@
         ungrabGesture(FlickGestureRecognizer::sharedGestureType());
     }
 
-    const QPoint pos = mapFromScene(tp.scenePos()).toPoint();
+    const QPoint pos = correctedTouchPoint(tp.scenePos());
     MImAbstractKey *key = keyAt(pos);
 
 
@@ -596,9 +559,8 @@
 
     mTimestamp("MImAbstractKeyArea", "start");
 
-    const QPoint pos = mapFromScene(tp.scenePos()).toPoint();
-    const QPoint lastPos = mapFromScene(tp.lastScenePos()).toPoint();
-    const QPoint startPos = mapFromScene(tp.startScenePos()).toPoint();
+    const QPoint pos = correctedTouchPoint(tp.scenePos());
+    const QPoint lastPos = correctedTouchPoint(tp.lastScenePos());
 
     const GravitationalLookupResult lookup = gravitationalKeyAt(pos, lastPos);
     MImKeyVisitor::SpecialKeyFinder finder;
@@ -616,7 +578,7 @@
                 // Reaction map cannot discover when we move from one key
                 // (= reactive area) to another
                 // slot is called asynchronously to get screen update as fast as possible
-                QMetaObject::invokeMethod(&feedbackPress, "play", Qt::QueuedConnection);
+                QMetaObject::invokeMethod(&feedbackSliding, "play", Qt::QueuedConnection);
                 longPressTimer.start(style()->longPressTimeout());
                 emit keyPressed(lookup.key,
                                 (finder.deadKey() ? finder.deadKey()->label() : QString()),
@@ -627,10 +589,6 @@
         if (lookup.lastKey
             && lookup.lastKey->decreaseTouchPointCount()
             && lookup.lastKey->touchPointCount() == 0) {
-            // Reaction map cannot discover when we move from one key
-            // (= reactive area) to another
-            // slot is called asynchronously to get screen update as fast as possible
-            QMetaObject::invokeMethod(&feedbackCancel, "play", Qt::QueuedConnection);
             emit keyReleased(lookup.lastKey,
                              (finder.deadKey() ? finder.deadKey()->label() : QString()),
                              hasActiveShiftKeys || level() % 2);
@@ -656,9 +614,8 @@
 
     idleVkbTimer.start(style()->idleVkbTimeout());
 
-    const QPoint pos = mapFromScene(tp.scenePos()).toPoint();
-    const QPoint lastPos = mapFromScene(tp.lastScenePos()).toPoint();
-    const QPoint startPos = mapFromScene(tp.startScenePos()).toPoint();
+    const QPoint pos = correctedTouchPoint(tp.scenePos());
+    const QPoint lastPos = correctedTouchPoint(tp.lastScenePos());
 
     const GravitationalLookupResult lookup = gravitationalKeyAt(pos, lastPos);
     MImKeyVisitor::SpecialKeyFinder finder;
@@ -779,20 +736,10 @@
                                        const MImAbstractKey *key,
                                        const MImAbstractKey *lastKey) const
 {
-    if (!QDir::home().exists(MImUserDirectory)) {
-        QDir::home().mkdir(MImUserDirectory);
-    }
-
-    static StreamHandle handle(QString("%1/%2/%3-%4").arg(QDir::homePath())
-                                                     .arg(MImUserDirectory)
-                                                     .arg(QCoreApplication::applicationPid())
-                                                     .arg(MImTouchPointsLogfile));
+    static bool headerWritten = false;
+    QTextStream &out = MKeyboardHost::instance()->touchPointLog();
 
-    QFile &file = handle.file();
-    QTextStream &out = handle.stream();
-
-    if (!file.isOpen()) {
-        file.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
+    if (!headerWritten) {
         out << "time (sec.msec)\t"
             << "tp_id\t"
             << "tp_state\t"
@@ -804,6 +751,7 @@
             << "label\t"
             << "label_last\t"
             << "br_x\t" << "br_y\t" << "br_w\t" << "br_h\n";
+        headerWritten = true;
     }
 
     out << timeStamp() << "\t"
@@ -987,3 +935,30 @@
     }
     update();
 }
+
+QPoint MImAbstractKeyArea::correctedTouchPoint(const QPointF &scenePos) const
+{
+    QPointF pos = mapFromScene(scenePos);
+
+    if (pos.y() >= baseStyle()->touchpointVerticalOffset()) {
+        pos.ry() -= baseStyle()->touchpointVerticalOffset();
+    }
+
+    return pos.toPoint();
+}
+
+QRectF MImAbstractKeyArea::correctedReactionRect(const QRectF &originalRect) const
+{
+    QRectF rect = originalRect;
+    const qreal offset = baseStyle()->touchpointVerticalOffset();
+
+    if (rect.top() >= offset) {
+        rect.setTop(rect.top() + offset);
+    }
+    const qreal newBottom(rect.bottom() + offset);
+    if (newBottom <= size().height()) {
+        rect.setBottom(newBottom);
+    }
+
+    return rect;
+}
--- m-keyboard/widgets/mimabstractkeyarea.h
+++ m-keyboard/widgets/mimabstractkeyarea.h
@@ -72,6 +72,9 @@
     //! \brief Returns all keys from this key area.
     virtual QList<const MImAbstractKey *> keys() const = 0;
 
+    //! \brief Returns key with given \a id
+    virtual MImAbstractKey * findKey(const QString &id) = 0;
+
     //! \brief Notification for derived classes about button modifier change.
     //!
     //! Derived classes should not change the level of selected dead keys. This is to
@@ -192,9 +195,6 @@
     //! \param visible the new visbility status
     virtual void handleVisibilityChanged(bool visible);
 
-    //! \brief Invalidates the current background cache.
-    virtual void invalidateBackgroundCache() = 0;
-
     //! Shows popup and updates its content and position.
     //! \param key current key
     void updatePopup(MImAbstractKey *key = 0);
@@ -236,6 +236,16 @@
     qreal mRelativeKeyBaseWidth; //!< Relative key base width in currently active layout
     bool debugTouchPoints; //!< Whether touch point debugging is enabled
 
+    //! Correct the vertical offset of a touchpoint
+    //! \param scenePos Input position in scene coordinates.
+    //! \returns the corrected position in item coordinates.
+    QPoint correctedTouchPoint(const QPointF &scenePos) const;
+
+    //! Correct the reaction rects for the vertical offset of a touchpoint
+    //! \param originalRect Original rectangle in item coordinates.
+    //! \returns the corrected rectangle in item coordinates.
+    QRectF correctedReactionRect(const QRectF &originalRect) const;
+
 protected slots:
     //! Update background images, text layouts, etc. when the theme changed.
     virtual void onThemeChangeCompleted();
@@ -314,8 +324,7 @@
     QList<QStringList> accentLabels; //!< list of accent labels
     bool wasGestureTriggered; //!< whether a gesture was already triggered for any active touch point
     bool enableMultiTouch; //!< whether this key area operates in multitouch mode
-    MFeedback feedbackPress; //!< Press feedback
-    MFeedback feedbackCancel; //!< Cancel feedback
+    MFeedback feedbackSliding; //!< Sliding feedback
     const LayoutData::SharedLayoutSection section; //!< layout section shown by this key area
     static M::InputMethodMode InputMethodMode; //!< used input method mode (same for all key areas)
     QTimer longPressTimer; //!< used to recognize long press
--- m-keyboard/widgets/mimabstractkeyareastyle.h
+++ m-keyboard/widgets/mimabstractkeyareastyle.h
@@ -42,6 +42,7 @@
     M_STYLE_ATTRIBUTE(qreal, flickGestureThresholdRatio, FlickGestureThresholdRatio)
     M_STYLE_ATTRIBUTE(qreal, touchpointHorizontalGravity, TouchpointHorizontalGravity)
     M_STYLE_ATTRIBUTE(qreal, touchpointVerticalGravity, TouchpointVerticalGravity)
+    M_STYLE_ATTRIBUTE(qreal, touchpointVerticalOffset, TouchpointVerticalOffset)
 
     M_STYLE_ATTRIBUTE(QSize, size, Size)
     M_STYLE_ATTRIBUTE(qreal, keyHeightSmall, KeyHeightSmall)
--- m-keyboard/widgets/mimcorrectionhost.cpp
+++ m-keyboard/widgets/mimcorrectionhost.cpp
@@ -23,6 +23,7 @@
 
 MImCorrectionHost::MImCorrectionHost(MSceneWindow *parentWindow)
     : QObject(parentWindow),
+      ReactionMapPaintable(),
       rotationInProgress(false),
       currentMode(MImCorrectionHost::WordTrackerMode),
       pendingCandidatesUpdate(false),
@@ -31,8 +32,17 @@
 {
     connect(wordTracker, SIGNAL(candidateClicked(QString)), this, SLOT(handleCandidateClicked(QString)));
     connect(wordTracker, SIGNAL(longTapped()), this, SLOT(longTap()));
+    // The word tracker changed -> Repaint the reaction maps
+    // TODO: The reaction map repainting can be optimized here to clear/repaint only the
+    // reaction map of the word tracker.
+    connect(wordTracker, SIGNAL(geometryChanged()), &signalForwarder, SIGNAL(requestRepaint()));
+    connect(wordTracker, SIGNAL(displayExited()), &signalForwarder, SIGNAL(requestRepaint()));
 
     connect(wordList, SIGNAL(candidateClicked(QString)), this, SLOT(handleCandidateClicked(QString)));
+    // The word list goes on top -> Clear the reaction maps
+    connect(wordList, SIGNAL(displayEntered()), &signalForwarder, SIGNAL(requestClear()));
+    // The word list disappears -> Repaint the reaction maps
+    connect(wordList, SIGNAL(displayExited()), &signalForwarder, SIGNAL(requestRepaint()));
 }
 
 
@@ -176,6 +186,17 @@
     hideCorrectionWidget();
 }
 
+bool MImCorrectionHost::isPaintable() const
+{
+    return isActive();
+}
+
+bool MImCorrectionHost::isFullScreen() const
+{
+    // Correction candidate widget occupies whole screen when it is WordListMode.
+    return candidateMode() == MImCorrectionHost::WordListMode;
+}
+
 void MImCorrectionHost::longTap()
 {
     qDebug() << __PRETTY_FUNCTION__;
--- m-keyboard/widgets/mimcorrectionhost.h
+++ m-keyboard/widgets/mimcorrectionhost.h
@@ -17,6 +17,8 @@
 #ifndef MIMCORRECTIONHOST_H
 #define MIMCORRECTIONHOST_H
 
+#include "reactionmappaintable.h"
+
 #include <QObject>
 #include <QString>
 #include <QStringList>
@@ -34,7 +36,7 @@
   \brief The MImCorrectionHost class is used to show error correction
   candidate word tracker or word list.
 */
-class MImCorrectionHost : public QObject
+class MImCorrectionHost : public QObject, public ReactionMapPaintable
 {
     Q_OBJECT
 
@@ -113,6 +115,10 @@
     //! Clear stored suggestion and hide candidate widget.
     void reset();
 
+    /*! \reimp */
+    bool isPaintable() const;
+    bool isFullScreen() const;
+    /*! \reimp_end */
 signals:
     //! Updates the preedit word
     void candidateClicked(const QString &);
--- m-keyboard/widgets/mimkey.cpp
+++ m-keyboard/widgets/mimkey.cpp
@@ -21,8 +21,12 @@
 #include "mvirtualkeyboardstyle.h"
 #include "getcssproperty.h"
 
+#include <mplainwindow.h>
+
 #include <MTheme>
-#include <QGraphicsItem>
+#include <MScalableImage>
+#include <MTimestamp>
+
 #include <QPainter>
 
 namespace {
@@ -31,6 +35,46 @@
         const qreal scaling = qMax<qreal>(0.0, newScaling);
         return ((scaling * unit) + (qMax<qreal>(0.0, scaling - 1) * spacing));
     }
+
+    // Modify font to make text fit into boundingRect
+    // TODO: Could be optimized to use a binary search.
+    void scaleDownFont(QFont *font, const QString& text, const QRect& boundingRect)
+    {
+        // Fonts can either be specified in points or pixels
+        int fontSize = font->pixelSize();
+        const bool usesPixelSize = (fontSize == -1) ? false : true;
+
+        if (!usesPixelSize) {
+            fontSize = font->pointSize();
+            Q_ASSERT(fontSize != -1);
+        }
+
+        // Minimum font size is 1
+        while (fontSize > 1) {
+            if (usesPixelSize) {
+                font->setPixelSize(fontSize);
+            }
+            else {
+                font->setPointSize(fontSize);
+            }
+
+            const QFontMetrics fontMetrics(*font);
+            const QRect textBounds = fontMetrics.boundingRect(text);
+
+            if (textBounds.width() <= boundingRect.width()
+                && textBounds.height() <= boundingRect.height()) {
+                break;
+            }
+            --fontSize;
+        }
+
+    }
+}
+
+MImKey::StylingCache::StylingCache()
+    : primary(QFont()),
+    secondary(QFont())
+{
 }
 
 MImKey::IconInfo::IconInfo()
@@ -46,8 +90,7 @@
 }
 
 MImKey::Geometry::Geometry()
-    : pos()
-    , width(0.0)
+    : width(0.0)
     , height(0.0)
     , marginLeft(0.0)
     , marginTop(0.0)
@@ -55,15 +98,13 @@
     , marginBottom(0.0)
 {}
 
-MImKey::Geometry::Geometry(const QPointF &newPos,
-                           qreal newWidth,
+MImKey::Geometry::Geometry(qreal newWidth,
                            qreal newHeight,
                            qreal newMarginLeft,
                            qreal newMarginTop,
                            qreal newMarginRight,
                            qreal newMarginBottom)
-    : pos(newPos)
-    , width(newWidth)
+    : width(newWidth)
     , height(newHeight)
     , marginLeft(newMarginLeft)
     , marginTop(newMarginTop)
@@ -73,8 +114,10 @@
 
 MImKey::MImKey(const MImKeyModel &newModel,
                const MImAbstractKeyAreaStyleContainer &style,
-               QGraphicsItem &parent)
-    : width(0),
+               QGraphicsItem &parent,
+               const QSharedPointer<StylingCache> &newStylingCache)
+    : QGraphicsItem(&parent),
+      width(0),
       mModel(newModel),
       shift(false),
       currentLabel(mModel.binding(false)->label()),
@@ -83,7 +126,9 @@
       styleContainer(style),
       parentItem(parent),
       currentTouchPointCount(0),
-      hasGravity(false)
+      hasGravity(false),
+      rowHasSecondaryLabel(false),
+      stylingCache(newStylingCache)
 {
     if (mModel.binding(false)) {
         loadIcon(false);
@@ -91,6 +136,11 @@
     if (mModel.binding(true)) {
         loadIcon(true);
     }
+
+    labelFont = style->font();
+    hide();
+
+    //label position should be computed later, when geometry will be known
 }
 
 MImKey::~MImKey()
@@ -117,16 +167,83 @@
     return cachedButtonBoundingRect;
 }
 
-void MImKey::updateButtonRects()
+void MImKey::updateGeometryCache()
 {
     const Geometry &g = currentGeometry;
-    cachedButtonBoundingRect = QRectF(g.pos.x(), g.pos.y(),
+    cachedButtonBoundingRect = QRectF(pos().x(), pos().y(),
                                       g.width + g.marginLeft + g.marginRight,
                                       g.height + g.marginTop + g.marginBottom);
     cachedButtonRect = cachedButtonBoundingRect.adjusted( g.marginLeft,   g.marginTop,
                                                          -g.marginRight, -g.marginBottom);
 }
 
+void MImKey::invalidateLabelPos()
+{
+    labelArea = QRectF();
+    secondaryLabelArea = QRectF();
+
+    updateLabelFont();
+}
+
+void MImKey::updateLabelFont()
+{
+    // Use a maximum label rectangle that is a bit smaller than the button
+    const QRect maximumLabelRect = buttonRect().adjusted(0, 0, -10, -5).toRect();
+    labelFont = styleContainer->font();
+    scaleDownFont(&labelFont, label(), maximumLabelRect);
+}
+
+void MImKey::updateLabelPos() const
+{
+    const QRectF paintingArea(currentGeometry.marginLeft,
+                              currentGeometry.marginTop,
+                              currentGeometry.width,
+                              currentGeometry.height);
+
+    if (!rowHasSecondaryLabel) {
+        labelArea = paintingArea;
+    } else {
+        const int labelHeight = stylingCache->primary.height();
+        const int secondaryLabelHeight = stylingCache->secondary.height();
+        const int topMargin = styleContainer->labelMarginTop();
+        const int labelLeftWithSecondary = styleContainer->labelMarginLeftWithSecondary();
+        const int secondarySeparation = styleContainer->secondaryLabelSeparation();
+        const bool landscape = (MPlainWindow::instance()->orientation() == M::Landscape);
+
+        // In landscape the secondary labels are below the primary ones. In portrait,
+        // secondary labels are horizontally next to primary labels.
+        if (landscape) {
+            // primary label: horizontally centered, top margin defines y
+            // secondary: horizontally centered, primary bottom + separation margin defines y
+            const int primaryY = paintingArea.top() + topMargin;
+            labelArea = QRectF(paintingArea.left(),
+                               primaryY,
+                               paintingArea.width(),
+                               labelHeight);
+            if (!secondaryLabel().isEmpty()) {
+                secondaryLabelArea = QRectF(paintingArea.left(),
+                                            labelArea.bottom() + secondarySeparation,
+                                            paintingArea.width(),
+                                            secondaryLabelHeight);
+            }
+        } else {
+            // primary label: horizontally according to left margin, vertically centered
+            // secondary: horizontally on right of primary + separation margin, vertically centered
+            const int primaryX = paintingArea.left() + labelLeftWithSecondary;
+            labelArea = QRectF(primaryX,
+                               paintingArea.top(),
+                               stylingCache->primary.width(label()),
+                               paintingArea.height());
+            if (!secondaryLabel().isEmpty()) {
+                secondaryLabelArea = QRectF(labelArea.right() + secondarySeparation,
+                                            paintingArea.top(),
+                                            stylingCache->secondary.width(secondaryLabel()),
+                                            paintingArea.height());
+            }
+        }
+    }
+}
+
 void MImKey::setModifiers(bool shift, QChar accent)
 {
     if (this->shift != shift || this->accent != accent) {
@@ -134,6 +251,7 @@
         this->accent = accent;
         currentLabel = binding().accented(accent);
 
+        invalidateLabelPos();
         update();
     }
 }
@@ -160,7 +278,7 @@
             hasGravity = false;
         }
 
-        update();
+        setVisible(currentState != Normal);
     }
 }
 
@@ -265,6 +383,104 @@
     return hasGravity;
 }
 
+const MScalableImage * MImKey::backgroundImage() const
+{
+    const MScalableImage *background = 0;
+
+    switch (state()) {
+
+        case MImAbstractKey::Normal:
+            switch (model().style()) {
+                case MImKeyModel::SpecialStyle:
+                    background = styleContainer->keyBackgroundSpecial();
+                    break;
+                case MImKeyModel::DeadkeyStyle:
+                    background = styleContainer->keyBackgroundDeadkey();
+                    break;
+                case MImKeyModel::NormalStyle:
+                default:
+                    background = styleContainer->keyBackground();
+                    break;
+            }
+            break;
+
+        case MImAbstractKey::Pressed:
+            switch (model().style()) {
+                case MImKeyModel::SpecialStyle:
+                    background = styleContainer->keyBackgroundSpecialPressed();
+                    break;
+                case MImKeyModel::DeadkeyStyle:
+                    background = styleContainer->keyBackgroundDeadkeyPressed();
+                    break;
+                case MImKeyModel::NormalStyle:
+                default:
+                    background = styleContainer->keyBackgroundPressed();
+                    break;
+            }
+            break;
+
+        case MImAbstractKey::Selected:
+            switch (model().style()) {
+                case MImKeyModel::SpecialStyle:
+                    background = styleContainer->keyBackgroundSpecialSelected();
+                    break;
+                case MImKeyModel::DeadkeyStyle:
+                    background = styleContainer->keyBackgroundDeadkeySelected();
+                    break;
+                case MImKeyModel::NormalStyle:
+                default:
+                    background = styleContainer->keyBackgroundSelected();
+                    break;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    return background;
+}
+
+QRectF MImKey::boundingRect() const
+{
+    return QRectF(QPointF(), buttonBoundingRect().size());
+}
+
+void MImKey::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
+{
+    mTimestamp("MImKey", "start");
+
+    // We use QGraphicsView::DontSavePainterState, so save/restore state manually
+    // Not strictly needed at the moment, but prevents subtle breakage later
+    painter->save();
+    const MScalableImage *background = backgroundImage();
+    const QRectF paintingArea(currentGeometry.marginLeft,
+                              currentGeometry.marginTop,
+                              currentGeometry.width,
+                              currentGeometry.height);
+    const QPixmap *iconPixmap(icon());
+
+    if (background) {
+        background->draw(paintingArea, painter);
+    }
+
+    if (iconPixmap) {
+        QPointF iconPos(paintingArea.left() + (paintingArea.width() - iconPixmap->width()) / 2,
+                        paintingArea.top() + (paintingArea.height() - iconPixmap->height()) / 2);
+        painter->drawPixmap(iconPos, *iconPixmap);
+    } else {
+        painter->setFont(font());
+        painter->setPen(styleContainer->fontColor());
+        painter->drawText(labelArea, Qt::AlignCenter, label());
+        if (!secondaryLabel().isEmpty()) {
+            painter->setFont(styleContainer->secondaryFont());
+            painter->drawText(secondaryLabelArea, Qt::AlignCenter, secondaryLabel());
+        }
+    }
+    painter->restore();
+    mTimestamp("MImKey", "end");
+}
+
 const QPixmap *MImKey::icon() const
 {
     return iconInfo().pixmap;
@@ -287,12 +503,6 @@
     }
 }
 
-void MImKey::update()
-{
-    // Invalidate this button's area.
-    parentItem.update(buttonRect());
-}
-
 int MImKey::preferredFixedWidth() const
 {
     switch(mModel.width()) {
@@ -373,25 +583,20 @@
 void MImKey::setGeometry(const MImKey::Geometry &geometry)
 {
     currentGeometry = geometry;
-    updateButtonRects();
-}
-
-void MImKey::setPos(const QPointF &pos)
-{
-    currentGeometry.pos = pos;
-    updateButtonRects();
+    updateGeometryCache();
+    invalidateLabelPos();
 }
 
 void MImKey::setWidth(qreal width)
 {
     currentGeometry.width = width;
-    updateButtonRects();
+    updateGeometryCache();
 }
 
 void MImKey::setHeight(qreal height)
 {
     currentGeometry.height = height;
-    updateButtonRects();
+    updateGeometryCache();
 }
 
 void MImKey::setMargins(qreal left,
@@ -403,7 +608,33 @@
     currentGeometry.marginTop = top;
     currentGeometry.marginRight = right;
     currentGeometry.marginBottom = bottom;
-    updateButtonRects();
+    updateGeometryCache();
+}
+
+void MImKey::setSecondaryLabelEnabled(bool enable)
+{
+    if (rowHasSecondaryLabel != enable) {
+        rowHasSecondaryLabel = enable;
+        invalidateLabelPos();
+    }
+}
+
+const QRectF & MImKey::labelRect() const
+{
+    if (labelArea.isNull()) {
+        updateLabelPos();
+    }
+
+    return labelArea;
+}
+
+const QRectF & MImKey::secondaryLabelRect() const
+{
+    if (labelArea.isNull()) {
+        updateLabelPos();
+    }
+
+    return secondaryLabelArea;
 }
 
 void MImKey::loadIcon(bool shift)
@@ -458,3 +689,7 @@
     return (shift ? upperCaseIcon : lowerCaseIcon);
 }
 
+const QFont &MImKey::font() const
+{
+    return labelFont;
+}
--- m-keyboard/widgets/mimkey.h
+++ m-keyboard/widgets/mimkey.h
@@ -16,23 +16,36 @@
 
 
 
-#ifndef SINGLEWIDGETBUTTON_H
-#define SINGLEWIDGETBUTTON_H
+#ifndef MIMKEY_H
+#define MIMKEY_H
 
 #include "mimabstractkey.h"
 #include <QPointF>
+#include <QGraphicsItem>
+#include <QRectF>
+#include <QFontMetrics>
+#include <QSharedPointer>
 
 class MImAbstractKeyAreaStyleContainer;
-class QGraphicsItem;
 class MImKeyArea;
+class MScalableImage;
 
 //! Represents a key model with the key's current binding state, and also contains its visible area.
 class MImKey
-    : public MImAbstractKey
+    : public QGraphicsItem,
+      public MImAbstractKey
 {
 public:
+    //! Contains cached font information for current style
+    struct StylingCache
+    {
+        QFontMetrics primary;
+        QFontMetrics secondary;
+
+        StylingCache();
+    };
+
     struct Geometry {
-        QPointF pos;
         qreal width;
         qreal height;
         qreal marginLeft;
@@ -41,8 +54,7 @@
         qreal marginBottom;
 
         Geometry();
-        Geometry(const QPointF &newPos,
-                 qreal newWidth,
+        Geometry(qreal newWidth,
                  qreal newHeight,
                  qreal newMarginLeft,
                  qreal newMarginTop,
@@ -52,7 +64,8 @@
 
     explicit MImKey(const MImKeyModel &mModel,
                     const MImAbstractKeyAreaStyleContainer &style,
-                    QGraphicsItem &parent);
+                    QGraphicsItem &parent,
+                    const QSharedPointer<StylingCache> &newStylingCache);
 
     virtual ~MImKey();
 
@@ -78,6 +91,9 @@
     virtual int touchPointCount() const;
     virtual void activateGravity();
     virtual bool isGravityActive() const;
+    virtual const MScalableImage *backgroundImage() const;
+    virtual QRectF boundingRect() const;
+    virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem *option, QWidget *widget = 0);
     //! \reimp_end
 
     //! Return limit for active touchpoints
@@ -91,8 +107,6 @@
 
     //! \brief Draws the icon of this key, if available.
     virtual void drawIcon(QPainter *painter) const;
-    //! \brief Calls parent item's QGraphicsItem::update() who actually draws the button.
-    void update();
 
     //! Returns preferred fixed witdth
     int preferredFixedWidth() const;
@@ -111,10 +125,6 @@
     //! \param geometry the new geometry
     void setGeometry(const MImKey::Geometry &geometry);
 
-    //! \brief Set position (relative to parent item).
-    //! \param pos the new position
-    void setPos(const QPointF &pos);
-
     //! \brief Set the key width.
     //! \param width the new width
     void setWidth(qreal width);
@@ -133,11 +143,33 @@
                     qreal right,
                     qreal bottom);
 
+    //! \brief This parameter defines text alignment: we use primary label only if \a enable is false
+    //! and both primary and secondary labels if \a enable is false.
+    void setSecondaryLabelEnabled(bool enable);
+
+    //! \brief Return rectangle where we should draw primary label
+    const QRectF & labelRect() const;
+
+    //! \brief Return rectangle where we should draw secondary label.
+    const QRectF & secondaryLabelRect() const;
+
+    //! \brief Invalidates cached position, so next call to getter will calculate it again
+    void invalidateLabelPos();
+
+    //! \brief Updates cached geometry.
+    //! This method must be called when position or size of this key is changed.
+    void updateGeometryCache();
+
+    //! \brief Return the font of this key.
+    const QFont &font() const;
+
     //! The width for this button. Not managed by this class.
     //! It is used by MImKeyArea to store the correct button size.
     qreal width;
 
 private:
+    Q_DISABLE_COPY(MImKey);
+
     //! Contains information about icon
     struct IconInfo
     {
@@ -152,7 +184,10 @@
 
     void loadIcon(bool shift);
     const IconInfo &iconInfo() const;
-    void updateButtonRects();
+    //! \brief Update cached label position.
+    void updateLabelPos() const;
+    //! \brief Update label font.
+    void updateLabelFont();
 
     const MImKeyModel &mModel;
 
@@ -178,7 +213,20 @@
     QRectF cachedButtonBoundingRect;
 
     bool hasGravity;
+
+    //! Some key in the same row has secondary label
+    bool rowHasSecondaryLabel;
+
+    //! Cached position of primary label
+    mutable QRectF labelArea;
+    //! Cached position of secondary label
+    mutable QRectF secondaryLabelArea;
+
+    //! Primary label font
+    QFont labelFont;
+
+    const QSharedPointer<StylingCache> stylingCache;
 };
 
-#endif // SINGLEWIDGETBUTTON_H
+#endif // MIMKEY_H
 
--- m-keyboard/widgets/mimkeyarea.cpp
+++ m-keyboard/widgets/mimkeyarea.cpp
@@ -28,6 +28,8 @@
 #include <mreactionmap.h>
 #include <MTimestamp>
 
+#include "mimreactionmap.h"
+
 namespace {
     template<class T>
     int binaryRangeFind(T value,
@@ -63,7 +65,7 @@
         //! PaintMode can be used to optimize drawing for HW acceleration
         enum PaintMode {
             PaintBackground, //!< Only draw background of given keys, fills up iconKeys
-            PaintBackgroundAndIcon  //!< Draw both, background and icon, in one go
+            PaintBackgroundAndIcon //!< Draw both, background and icon, in one go
         };
 
     private:
@@ -138,58 +140,7 @@
                 return;
             }
 
-            const MScalableImage *background = 0;
-
-            switch (key->state()) {
-
-            case MImAbstractKey::Normal:
-                switch (key->model().style()) {
-                case MImKeyModel::SpecialStyle:
-                    background = keyArea->baseStyle()->keyBackgroundSpecial();
-                    break;
-                case MImKeyModel::DeadkeyStyle:
-                    background = keyArea->baseStyle()->keyBackgroundDeadkey();
-                    break;
-                case MImKeyModel::NormalStyle:
-                default:
-                    background = keyArea->baseStyle()->keyBackground();
-                    break;
-                }
-                break;
-
-            case MImAbstractKey::Pressed:
-                switch (key->model().style()) {
-                case MImKeyModel::SpecialStyle:
-                    background = keyArea->baseStyle()->keyBackgroundSpecialPressed();
-                    break;
-                case MImKeyModel::DeadkeyStyle:
-                    background = keyArea->baseStyle()->keyBackgroundDeadkeyPressed();
-                    break;
-                case MImKeyModel::NormalStyle:
-                default:
-                    background = keyArea->baseStyle()->keyBackgroundPressed();
-                    break;
-                }
-                break;
-
-            case MImAbstractKey::Selected:
-                switch (key->model().style()) {
-                case MImKeyModel::SpecialStyle:
-                    background = keyArea->baseStyle()->keyBackgroundSpecialSelected();
-                    break;
-                case MImKeyModel::DeadkeyStyle:
-                    background = keyArea->baseStyle()->keyBackgroundDeadkeySelected();
-                    break;
-                case MImKeyModel::NormalStyle:
-                default:
-                    background = keyArea->baseStyle()->keyBackgroundSelected();
-                    break;
-                }
-                break;
-
-            default:
-                break;
-            }
+            const MScalableImage *background = key->backgroundImage();
 
             if (background) {
                 background->draw(key->buttonRect().toRect(), painter);
@@ -360,6 +311,7 @@
 
             foreach (MImKey *const key, row) {
                 key->setPos(currentPos);
+                key->updateGeometryCache();
 
                 const qreal nextPosX = currentPos.x() + key->buttonBoundingRect().width();
                 mKeyOffsets.append(QPair<qreal, qreal>(currentPos.x(), nextPosX));
@@ -380,16 +332,15 @@
       cachedWidgetHeight(computeWidgetHeight()),
       mMaxNormalizedWidth(computeMaxNormalizedWidth()),
       shiftKey(0),
-      textDirty(false),
-      cachedBackgroundDirty(true),
-      hasCachedBackground(false),
       equalWidthKeys(true),
-      WidthCorrection(0)
+      WidthCorrection(0),
+      stylingCache(new MImKey::StylingCache)
 {
-    textLayout.setCacheEnabled(true);
     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
 
     loadKeys();
+
+    setCacheMode(QGraphicsItem::DeviceCoordinateCache);
 }
 
 MImKeyArea::~MImKeyArea()
@@ -398,6 +349,7 @@
         qDeleteAll(rowIter->keys);
         rowIter->keys.clear();
     }
+    clearKeyIds();
 }
 
 QSizeF MImKeyArea::sizeHint(Qt::SizeHint which,
@@ -416,12 +368,28 @@
                                    QGraphicsView *view)
 {
     reactionMap->setTransform(this, view);
-    reactionMap->setReactiveDrawingValue();
+    reactionMap->setDrawingValue(MImReactionMap::Press, MImReactionMap::Release);
 
     foreach (const KeyRow &row, rowList) {
+        // 'area' is used for key bounding rect coalescing, to improve
+        // downsampling to reaction map resolution (usually display_size / 4).
+        QRectF area;
+        qreal lastRightBorder = 0.0f;
+
         foreach (const MImKey *const key, row.keys) {
-            reactionMap->fillRectangle(key->buttonBoundingRect());
+            const QRectF rect = correctedReactionRect(key->buttonBoundingRect());
+
+            // Check for spacers. If found, we draw the accummulated area and start from scratch.
+            if (lastRightBorder < rect.left()) {
+                reactionMap->fillRectangle(area);
+                area = QRectF();
+            }
+
+            area |= rect;
+            lastRightBorder = rect.right();
         }
+
+        reactionMap->fillRectangle(area);
     }
 }
 
@@ -438,7 +406,11 @@
         for (int col = 0; col < numColumns; ++col) {
             // Parameters to fetch from base class.
             MImKeyModel *dataKey = sectionModel()->keyModel(row, col);
-            MImKey *key = new MImKey(*dataKey, baseStyle(), *this);
+            MImKey *key = new MImKey(*dataKey, baseStyle(), *this, stylingCache);
+
+            if (!key->model().id().isEmpty()) {
+                registerKeyId(key);
+            }
 
             // Temporary, dirty workaround-hack to detect Arabic layouts
             // because the QTextLayout rendering is broken with Arabic characters and
@@ -467,153 +439,6 @@
     updateGeometry();
 }
 
-void MImKeyArea::buildTextLayout()
-{
-    textDirty = false;
-
-    textLayout.clearLayout();
-
-    QList<QTextLayout::FormatRange> formatList;
-    QTextCharFormat secondaryFormat;
-    secondaryFormat.setFont(baseStyle()->secondaryFont());
-
-    // QTextLayout requires text content to be set before creating QTextLines.
-    // While concatenating the text, also build 'additional formats' used for secondary
-    // labels. This must be done before QTextLayout::beginLayout().
-    QString labelContent;
-
-    foreach (const KeyRow &row, rowList) {
-        foreach (const MImKey *key, row.keys) {
-            // primary label
-            QString label = key->label();
-
-            if (!label.isEmpty()) {
-                // Add whitespace for QTextLine to be able to cut.
-                labelContent += label + " ";
-
-                // try secondary label
-                label = key->secondaryLabel();
-
-                if (!label.isEmpty()) {
-                    // Add formatting for this secondary label.
-                    QTextLayout::FormatRange formatRange = {labelContent.length(),
-                                                            label.length(),
-                                                            secondaryFormat};
-                    formatList.append(formatRange);
-                    labelContent += label + " ";
-                }
-            }
-        }
-    }
-
-    // Apply the formats
-    if (!formatList.isEmpty()) {
-        textLayout.setAdditionalFormats(formatList);
-    }
-
-    QFontMetrics fm(baseStyle()->font());
-    QFontMetrics secondaryFm(secondaryFormat.font());
-    const int labelHeight = fm.height();
-    const int secondaryLabelHeight = secondaryFm.height();
-    const int topMargin = baseStyle()->labelMarginTop();
-    const int labelLeftWithSecondary = baseStyle()->labelMarginLeftWithSecondary();
-    const int secondarySeparation = baseStyle()->secondaryLabelSeparation();
-    const bool landscape = (MPlainWindow::instance()->orientation() == M::Landscape);
-
-    textLayout.setFont(baseStyle()->font());
-    textLayout.setText(labelContent);
-
-    textLayout.beginLayout();
-
-    for (RowIterator row(rowList.begin()); row != rowList.end(); ++row) {
-        // rowHasSecondaryLabel is needed for the vertical alignment of
-        // secondary label purposes.
-        bool rowHasSecondaryLabel = false;
-
-        foreach (const MImKey *key, row->keys) {
-            if (!key->secondaryLabel().isEmpty()) {
-                rowHasSecondaryLabel = true;
-            }
-        }
-
-        foreach (const MImKey *key, row->keys) {
-            const QString &label(key->label());
-            const QString &secondary(key->secondaryLabel());
-            QPoint labelPos;
-            QPoint secondaryLabelPos;
-
-            // We must not create a new QTextLine if there is no label.
-            if (label.isEmpty()) {
-                continue;
-            }
-
-            const QRectF &keyRect = key->buttonRect();
-
-            if (!rowHasSecondaryLabel) {
-                // All horizontally centered.
-                labelPos = fm.boundingRect(keyRect.x(),
-                                           keyRect.y(),
-                                           keyRect.width(),
-                                           keyRect.height(),
-                                           Qt::AlignCenter,
-                                           label).topLeft();
-            } else {
-                // Calculate position for both primary and secondary label.
-                // We only have secondary labels in phone number layouts (with sym being exception)
-                // so this follows their styling.
-
-                // In landscape the secondary labels are below the primary ones. In portrait,
-                // secondary labels are horizontally next to primary labels.
-                if (landscape) {
-                    // primary label: horizontally centered, top margin defines y
-                    // secondary: horizontally centered, primary bottom + separation margin defines y
-                    const int primaryY = keyRect.top() + topMargin;
-                    labelPos.setX(keyRect.center().x() - fm.width(label) / 2);
-                    labelPos.setY(primaryY);
-                    if (!secondary.isEmpty()) {
-                        secondaryLabelPos.setX(keyRect.center().x() - secondaryFm.width(secondary) / 2);
-                        secondaryLabelPos.setY(primaryY + labelHeight + secondarySeparation);
-                    }
-                } else {
-                    // primary label: horizontally according to left margin, vertically centered
-                    // secondary: horizontally on right of primary + separation margin, vertically centered
-                    const int primaryX = keyRect.left() + labelLeftWithSecondary;
-                    labelPos.setX(primaryX);
-                    labelPos.setY(keyRect.center().y() - labelHeight / 2);
-                    if (!secondary.isEmpty()) {
-                        secondaryLabelPos.setX(primaryX + fm.width(label) + secondarySeparation);
-                        secondaryLabelPos.setY(keyRect.center().y() - secondaryLabelHeight / 2);
-                    }
-                }
-            }
-
-            // We now have positions, let's create some QTextLines.
-
-            // Create the primary label
-            QTextLine line = textLayout.createLine();
-            if (!line.isValid()) {
-                // We are getting out of sync anyway so no point in continuing.
-                goto endLayout;
-            }
-            line.setNumColumns(label.length()); // will be seeked forward until next whitespace
-            line.setPosition(labelPos);
-
-            // Same for secondary label
-            if (!secondary.isEmpty()) {
-                line = textLayout.createLine();
-                if (!line.isValid()) {
-                    goto endLayout;
-                }
-                line.setNumColumns(secondary.length());
-                line.setPosition(secondaryLabelPos);
-            }
-        }
-    }
-
-endLayout:
-    textLayout.endLayout();
-}
-
 qreal MImKeyArea::computeWidgetHeight() const
 {
     qreal height = baseStyle()->size().height();
@@ -632,79 +457,77 @@
     return qMax<qreal>(0.0, height);
 }
 
-void MImKeyArea::paint(QPainter *onScreenPainter,
+void MImKeyArea::paint(QPainter *painter,
                        const QStyleOptionGraphicsItem *,
                        QWidget *)
 {
     mTimestamp("MImKeyArea", "start");
     const MImAbstractKeyAreaStyleContainer &style(baseStyle());
 
-    // Key areas are disabled during animations. Once we are animated, it
-    // makes no sense to maintain the offscreen cache (especially when
-    // HW-accelerated). Therefore, we draw directly to the screen.
-    // However, we need to remember whether we drew a current version of the
-    // key area to the offscreen cache at all (that's what hasCachedBackground
-    // is for).
-    QPainter *currentPainter = onScreenPainter;
-    if (cachedBackgroundDirty
-        || !isEnabled()
-        || !hasCachedBackground) {
+    const MScalableImage *background = style->backgroundImage();
 
-        // TODO: find out why size()'s height is incorrect for popup.
-        initCachedBackground(QSize(size().width(), cachedWidgetHeight));
-        QPainter offScreenPainter(cachedBackground.get());
+    if (background) {
+        background->draw(boundingRect().toRect(), painter);
+    }
 
-        if (isEnabled()) {
-            currentPainter = &offScreenPainter;
-            hasCachedBackground = true;
-        }
+    const bool drawButtonBoundingRects(style->drawButtonBoundingRects());
+    const bool drawButtonRects(style->drawButtonRects());
 
-        const MScalableImage *background = style->backgroundImage();
+    // In case of HW acceleration, we want to avoid switching between textures, if possible
+    // Draw backgrounds first, icons later:
+    const KeyPainter kp(this, painter, KeyPainter::PaintBackground);
 
-        if (background) {
-            background->draw(boundingRect().toRect(), currentPainter);
+    foreach (const KeyRow &row, rowList) {
+        foreach (const MImKey *key, row.keys) {
+            kp(key);
+            drawDebugRects(painter, key,
+                    drawButtonBoundingRects,
+                    drawButtonRects);
         }
+    }
 
-        const bool drawButtonBoundingRects(style->drawButtonBoundingRects());
-        const bool drawButtonRects(style->drawButtonRects());
+    kp.drawIcons();
 
-        // In case of HW acceleration, we want to avoid switching between textures, if possible
-        // Draw backgrounds first, icons later:
-        const KeyPainter kp(this, currentPainter, KeyPainter::PaintBackground);
+    if (style->drawReactiveAreas()) {
+        drawDebugReactiveAreas(painter);
+    }
 
-        foreach (const KeyRow &row, rowList) {
-            foreach (const MImKey *key, row.keys) {
-                kp(key);
-                drawDebugRects(currentPainter, key,
-                               drawButtonBoundingRects,
-                               drawButtonRects);
+    // Draw text next.
+    // We use QGraphicsView::DontSavePainterState, so save/restore state manually
+    // Not strictly needed at the moment, but prevents subtle breakage later
+    painter->save();
+    painter->setPen(style->fontColor());
+    foreach (const KeyRow &row, rowList) {
+        // rowHasSecondaryLabel is needed for the vertical alignment of
+        // secondary label purposes.
+        bool rowHasSecondaryLabel = false;
+        foreach (const MImKey *key, row.keys) {
+            if (!key->secondaryLabel().isEmpty()) {
+                rowHasSecondaryLabel = true;
+                break;
             }
         }
 
-        kp.drawIcons();
+        foreach (MImKey *key, row.keys) {
+            painter->setFont(key->font());
+            key->setSecondaryLabelEnabled(rowHasSecondaryLabel);
 
-        if (style->drawReactiveAreas()) {
-            drawDebugReactiveAreas(currentPainter);
+            QRectF rect = mapFromItem(key, key->labelRect()).boundingRect();
+            painter->drawText(rect, Qt::AlignCenter, key->label());
         }
     }
 
-    if (hasCachedBackground) {
-        onScreenPainter->drawPixmap(boundingRect().toRect(), *cachedBackground.get());
-    }
-
-    KeyPainter kp(this, onScreenPainter, KeyPainter::PaintBackground);
-    MImAbstractKey::visitActiveKeys(&kp);
-    kp.drawIcons();
-
-    if (textDirty) {
-        buildTextLayout();
+    painter->setFont(style->secondaryFont());
+    foreach (const KeyRow &row, rowList) {
+        foreach (const MImKey *key, row.keys) {
+            if (!key->secondaryLabel().isEmpty()) {
+                QRectF rect = mapFromItem(key, key->secondaryLabelRect()).boundingRect();
+                painter->drawText(rect, Qt::AlignCenter, key->secondaryLabel());
+            }
+        }
     }
+    painter->restore();
 
-    // Draw text next.
-    onScreenPainter->setPen(style->fontColor());
-    textLayout.draw(onScreenPainter, QPoint(WidthCorrection, 0));
-
-    cachedBackgroundDirty = false;
     mTimestamp("MImKeyArea", "end");
 }
 
@@ -740,44 +563,23 @@
 {
     painter->save();
 
-    for (int rowIdx = 0; rowIdx < rowList.size(); ++rowIdx) {
-        QPair<qreal, qreal> rowPair = rowOffsets[rowIdx];
-        painter->setPen(Qt::darkMagenta);
-        painter->drawLine(QPointF(0, rowPair.first),
-                          QPointF(size().width(), rowPair.first));
-
-        painter->setPen(Qt::magenta);
-        painter->drawLine(QPointF(0, rowPair.second),
-                          QPointF(size().width(), rowPair.second));
+    foreach (const KeyRow &row, rowList) {
+        foreach (const MImKey *const key, row.keys) {
+            const QRectF rect = correctedReactionRect(key->buttonBoundingRect());
 
-        const QVector<QPair<qreal, qreal> > &keyOffsets = rowList[rowIdx].keyOffsets;
+            painter->setPen(Qt::magenta);
+            painter->drawLine(rect.topLeft(), rect.topRight());
+            painter->drawLine(rect.bottomLeft(), rect.bottomRight());
 
-        for(int colIdx = 0; colIdx < keyOffsets.size(); ++colIdx) {
-            QPair<qreal, qreal> colPair = keyOffsets[colIdx];
             painter->setPen(Qt::cyan);
-            painter->drawLine(QPointF(colPair.first, rowPair.first),
-                              QPointF(colPair.first, rowPair.second));
-
-            painter->setPen(Qt::darkCyan);
-            painter->drawLine(QPointF(colPair.second, rowPair.first),
-                              QPointF(colPair.second, rowPair.second));
+            painter->drawLine(rect.topLeft(), rect.bottomLeft());
+            painter->drawLine(rect.topRight(), rect.bottomRight());
         }
     }
 
     painter->restore();
 }
 
-void MImKeyArea::initCachedBackground(const QSize &newSize)
-{
-    if (cachedBackground.get() && newSize == cachedBackground->size()) {
-        return; // already initialized
-    }
-
-    cachedBackground.reset(new QPixmap(newSize));
-    cachedBackground->fill(Qt::transparent);
-    hasCachedBackground = false;
-}
-
 MImAbstractKey *MImKeyArea::keyAt(const QPoint &pos) const
 {
     const int numRows = rowList.count();
@@ -823,7 +625,7 @@
         }
     }
 
-    textDirty = true;
+    update();
 }
 
 void MImKeyArea::updateKeyGeometries(const int newAvailableWidth)
@@ -838,7 +640,6 @@
                                                                       : newAvailableWidth);
 
     cachedWidgetHeight = computeWidgetHeight();
-    initCachedBackground(QSize(effectiveWidth, cachedWidgetHeight));
 
     KeyGeometryUpdater updater = KeyGeometryUpdater(baseStyle(), effectiveWidth,
                                                     computeMaxNormalizedWidth());
@@ -868,7 +669,7 @@
     mRelativeKeyBaseWidth = updater.relativeKeyWidth();
 
     // Positions may have changed, rebuild text layout.
-    textDirty = true;
+    update();
 }
 
 QRectF MImKeyArea::boundingRect() const
@@ -953,20 +754,25 @@
 {
     mMaxNormalizedWidth = computeMaxNormalizedWidth();
     cachedWidgetHeight = computeWidgetHeight();
+    stylingCache->primary   = QFontMetrics(baseStyle()->font());
+    stylingCache->secondary = QFontMetrics(baseStyle()->secondaryFont());
 
-    MImAbstractKeyArea::onThemeChangeCompleted();
-    buildTextLayout();
-}
+    foreach (const KeyRow &row, rowList) {
+        foreach (MImKey *key, row.keys) {
+            if (key) {
+                key->invalidateLabelPos();
+            }
+        }
+    }
 
-void MImKeyArea::handleVisibilityChanged(bool)
-{
-    invalidateBackgroundCache();
+    MImAbstractKeyArea::onThemeChangeCompleted();
+    update();
 }
 
-void MImKeyArea::invalidateBackgroundCache()
+void MImKeyArea::applyStyle()
 {
-    cachedBackgroundDirty = true;
-    hasCachedBackground = false;
+    stylingCache->primary   = QFontMetrics(baseStyle()->font());
+    stylingCache->secondary = QFontMetrics(baseStyle()->secondaryFont());
 }
 
 QList<const MImAbstractKey *> MImKeyArea::keys() const
@@ -981,3 +787,38 @@
 
     return keyList;
 }
+
+MImAbstractKey * MImKeyArea::findKey(const QString &id)
+{
+    MImKey *key = 0;
+
+    for (QList<MImKey *>::const_iterator iterator = idToKey.begin();
+         iterator != idToKey.end();
+         ++iterator) {
+        if ((*iterator)->model().id() == id) {
+            key = *iterator;
+            break;
+        }
+    }
+
+    return key;
+}
+
+void MImKeyArea::clearKeyIds()
+{
+    idToKey.clear();
+}
+
+void MImKeyArea::registerKeyId(MImKey *key)
+{
+    for (QList<MImKey *>::iterator iterator = idToKey.begin();
+         iterator != idToKey.end();
+         ++iterator) {
+        if ((*iterator)->model().id() == key->model().id()) {
+            *iterator = key;
+            return;
+        }
+    }
+    idToKey.append(key);
+}
+
--- m-keyboard/widgets/mimkeyarea.h
+++ m-keyboard/widgets/mimkeyarea.h
@@ -20,10 +20,9 @@
 #include "mimabstractkeyarea.h"
 #include "mimkey.h"
 
-#include <QTextLayout>
-#include <QPixmap>
 #include <QSize>
-#include <memory>
+#include <QFontMetrics>
+#include <QSharedPointer>
 
 //! \brief MImKeyArea reimplements MImAbstractKeyArea and is optimized for drawing.
 class MImKeyArea
@@ -49,6 +48,7 @@
     virtual QRectF boundingRect() const;
     virtual void setShiftState(ModifierState newShiftState);
     virtual QList<const MImAbstractKey *> keys() const;
+    virtual MImAbstractKey * findKey(const QString &id);
     //! \reimp_end
 
 protected:
@@ -60,17 +60,13 @@
     virtual void updateKeyGeometries(int availableWidth);
     virtual MImAbstractKey *keyAt(const QPoint &pos) const;
     virtual void onThemeChangeCompleted();
-    virtual void handleVisibilityChanged(bool visible);
-    virtual void invalidateBackgroundCache();
+    virtual void applyStyle();
     //! \reimp_end
 
 private:
     //! \brief Creates buttons for key data models.
     void loadKeys();
 
-    //! \brief Builds QTextLayout representation of current button labels for faster drawing.
-    void buildTextLayout();
-
     //! \brief Returns the new height of the key area.
     qreal computeWidgetHeight() const;
 
@@ -99,9 +95,12 @@
     //! \param painter the painter to be used
     void drawDebugReactiveAreas(QPainter *painter);
 
-    //! \brief Initializes the pixmap used for background caching
-    //! \param size the new size
-    void initCachedBackground(const QSize &size);
+    //! \brief Clears all information about key identifiers
+    void clearKeyIds();
+
+    //! \brief Register new key having identifier
+    //! \param key Pointer to key which id should be registered
+    void registerKeyId(MImKey *key);
 
     //! \brief Helper struct to store a row of keys.
     struct KeyRow {
@@ -118,13 +117,10 @@
     qreal mMaxNormalizedWidth; //!< maximal normalized width, for all rows
     QVector<QPair<qreal, qreal> > rowOffsets; //!< cached offsets for faster key lookups
     MImKey *shiftKey; //!< stores shift key, if available in this key area
-    QTextLayout textLayout; //!< used to draw key labels onto key area
-    bool textDirty; //!< dirty text cache flag
-    std::auto_ptr<QPixmap> cachedBackground; //!< cached background, containing all keys in inactive state
-    bool cachedBackgroundDirty; //!< dirty background cache flag
-    bool hasCachedBackground; //!< stores whether we already cached the background
     bool equalWidthKeys; //!< whether to assume equal width for all keys
     int WidthCorrection; //!< width correction for Arabic layouts
+    QSharedPointer<MImKey::StylingCache> stylingCache; //!< Cached information about current styling
+    QList<MImKey *> idToKey; //!< Contains information about keys which have identifiers
 
 #ifdef UNIT_TEST
     friend class Ut_MImAbstractKeyArea;
--- m-keyboard/widgets/mimtoolbar.cpp
+++ m-keyboard/widgets/mimtoolbar.cpp
@@ -19,6 +19,7 @@
 #include "mimtoolbar.h"
 #include "mtoolbarbutton.h"
 #include "mtoolbarlabel.h"
+#include "mimreactionmap.h"
 
 #include <mtoolbardata.h>
 #include <mtoolbaritem.h>
@@ -42,6 +43,7 @@
 
 MImToolbar::MImToolbar(QGraphicsWidget *parent)
     : MStylableWidget(parent),
+      ReactionMapPaintable(),
       textSelected(false),
       leftBar(this),
       rightBar(this),
@@ -59,6 +61,9 @@
     connect(this, SIGNAL(visibleChanged()), this, SLOT(arrangeWidgets()));
     connect(MTheme::instance(), SIGNAL(themeChangeCompleted()),
             this, SLOT(updateFromStyle()));
+
+    // Request a reaction map painting if it appears
+    connect(this, SIGNAL(displayEntered()), &signalForwarder, SIGNAL(requestRepaint()));
 }
 
 MImToolbar::~MImToolbar()
@@ -193,19 +198,20 @@
 
     const M::Orientation orientation = MPlainWindow::instance()->sceneManager()->orientation();
     QSharedPointer<const MToolbarLayout> layout = currentToolbar->layout(orientation);
-    QGraphicsLinearLayout *mainLayout = static_cast<QGraphicsLinearLayout*>(this->layout());
 
-    if (!mainLayout) {
-        qCritical() << __PRETTY_FUNCTION__ << "Layout does not exist";
+    if (layout.isNull()) {
+        qWarning() << __PRETTY_FUNCTION__
+                   << "Could not find layout in current toolbar. Orientation was:"
+                   << orientation;
+        return;
     }
 
-
     foreach (QSharedPointer<MToolbarItem> item, layout->items()) {
         createAndAppendWidget(item);
     }
 }
 
-void MImToolbar::createAndAppendWidget(QSharedPointer<MToolbarItem> item)
+void MImToolbar::createAndAppendWidget(const QSharedPointer<MToolbarItem> &item)
 {
     MWidget *widget = 0;
     WidgetBar *sidebar = 0;
@@ -229,6 +235,13 @@
         widget = new MToolbarLabel(item, sidebar);
     }
     customWidgets.append(widget);
+    // We should update the reaction map if the custom toolbar elements are changing.
+    connect(widget, SIGNAL(geometryChanged()),
+            &signalForwarder, SIGNAL(requestRepaint()), Qt::UniqueConnection);
+    connect(widget, SIGNAL(displayEntered()),
+            &signalForwarder, SIGNAL(requestRepaint()), Qt::UniqueConnection);
+    connect(widget, SIGNAL(displayExited()),
+            &signalForwarder, SIGNAL(requestRepaint()), Qt::UniqueConnection);
     if (sidebar->count() == 0) {
         // must be done before appending so that isVisible() tells the truth
         sidebar->show();
@@ -238,12 +251,6 @@
 
 void MImToolbar::unloadCustomWidgets()
 {
-    QGraphicsLinearLayout *mainLayout = static_cast<QGraphicsLinearLayout*>(layout());
-
-    if (!mainLayout) {
-        qCritical() << __PRETTY_FUNCTION__ << "Layout does not exist";
-    }
-
     qDeleteAll(customWidgets);
     customWidgets.clear();
     leftBar.cleanup();
@@ -363,8 +370,11 @@
     currentToolbar = toolbar;
     loadCustomWidgets();
 
-    if (isVisible())
+    if (isVisible()) {
         updateVisibility();
+        // The content has been changed -> Repaint the reaction maps
+        signalForwarder.emitRequestRepaint();
+    }
     arrangeWidgets();
 }
 
@@ -388,7 +398,7 @@
     reactionMap->fillRectangle(boundingRect());
 
     // Draw all widgets geometries.
-    reactionMap->setReactiveDrawingValue();
+    reactionMap->setDrawingValue(MImReactionMap::Press, MImReactionMap::Release);
 
     QGraphicsLinearLayout *mainLayout = static_cast<QGraphicsLinearLayout*>(layout());
 
@@ -407,7 +417,7 @@
         // Buttons sometimes require this.
         sidebar->layout()->activate();
 
-        reactionMap->setReactiveDrawingValue();
+        reactionMap->setDrawingValue(MImReactionMap::Press, MImReactionMap::Release);
 
         for (int i = 0; i < sidebar->count(); ++i) {
             QGraphicsWidget *widget = sidebar->widgetAt(i);
@@ -443,3 +453,12 @@
                   size().height() + style()->marginTop() + style()->marginBottom());
 }
 
+bool MImToolbar::isPaintable() const
+{
+    return isVisible();
+}
+
+const MToolbarData *MImToolbar::currentToolbarData() const
+{
+    return currentToolbar.data();
+}
--- m-keyboard/widgets/mimtoolbar.h
+++ m-keyboard/widgets/mimtoolbar.h
@@ -23,6 +23,7 @@
 #include "widgetbar.h"
 #include "mkeyboardcommon.h"
 #include "mimtoolbarstyle.h"
+#include "reactionmappaintable.h"
 
 #include <QPointer>
 #include <QSharedPointer>
@@ -48,7 +49,7 @@
   will be placed into left or right side WidgetBar widget. Toolbar
   takes all available space horizontally.
 */
-class MImToolbar : public MStylableWidget
+class MImToolbar : public MStylableWidget, public ReactionMapPaintable
 {
     Q_OBJECT
 
@@ -69,14 +70,19 @@
     QRegion region() const;
 
     /*!
-     * \brief Shows a custom toolbar with unique \a id.
-     * Loads a custom toolbar according \a id, if successfuly loads,
+     * \brief Shows a custom toolbar with toolbar definition \a toolbar.
+     * Loads a custom toolbar according \a toolbar, if successfuly loads,
      * the toolbar will be visible when show().
-     * \param id      Unique identifier of the custom toolbar.
+     * \param toolbar      The pointer of toolbar definition.
      */
     void showToolbarWidget(QSharedPointer<const MToolbarData> toolbar);
 
     /*!
+     * \brief Returns the pointer of current toolbar definition.
+     */
+    const MToolbarData *currentToolbarData() const;
+
+    /*!
      * \brief Hides all custom toolbars, this also means they are removed from visible virtual keyboard.
      */
     void hideToolbarWidget();
@@ -94,6 +100,7 @@
 
     //! \reimp
     virtual QRectF boundingRect() const;
+    bool isPaintable() const;
     //! \reimp_end
 
 public slots:
@@ -165,7 +172,7 @@
 
     Qt::KeyboardModifiers keyModifiers(int key) const;
 
-    void createAndAppendWidget(QSharedPointer<MToolbarItem> item);
+    void createAndAppendWidget(const QSharedPointer<MToolbarItem> &item);
 
     bool textSelected;
 
--- m-keyboard/widgets/mimwordlist.cpp
+++ m-keyboard/widgets/mimwordlist.cpp
@@ -18,17 +18,11 @@
 #include "regiontracker.h"
 #include "mimwordlist.h"
 #include "mimwordlistitem.h"
-#include <mplainwindow.h>
 
 #include <QGraphicsLinearLayout>
 #include <QDebug>
 #include <QString>
 
-#include <MSceneManager>
-#include <MScene>
-#include <MGConfItem>
-#include <MContentItem>
-#include <MTheme>
 #include <mreactionmap.h>
 
 #include <mwidgetcreator.h>
@@ -39,39 +33,11 @@
     const char * const WordListObjectName = "CorrectionWordList";
 };
 
-MIMWordListWindow::MIMWordListWindow(MImWordList *widget)
-    : MImOverlay(),
-      listWidget(widget)
-{
-    setVisible(false);
-}
-
-bool MIMWordListWindow::sceneEvent(QEvent *e)
-{
-    // TODO: below hiding list widget could be removed when meegotouch
-    // decide not hiding dialog when tap outside.
-    if (e->type() == QEvent::GraphicsSceneMouseRelease) {
-        listWidget->disappear();
-    }
-    return MImOverlay::sceneEvent(e);
-}
-
-void MIMWordListWindow::handleListAppeared()
-{
-    setVisible(true);
-    listWidget->setParentItem(this);
-}
-
-void MIMWordListWindow::handleListDisappeared()
-{
-    setVisible(false);
-}
 
 MImWordList::MImWordList()
-    : MDialog(),
-      parentWindow(new MIMWordListWindow(this))
+    : MDialog()
 {
-   RegionTracker::instance().addRegion(*this);
+    RegionTracker::instance().addRegion(*this);
     // for MATTI
     setObjectName(WordListObjectName);
 
@@ -89,18 +55,10 @@
     }
     setCentralWidget(contentWidget);
     hide();
-
-    connect(this, SIGNAL(appeared()),
-            parentWindow, SLOT(handleListAppeared()));
-    connect(this, SIGNAL(disappeared()),
-            parentWindow, SLOT(handleListDisappeared()));
 }
 
 MImWordList::~MImWordList()
 {
-    setParentItem(0);
-    delete parentWindow;
-    parentWindow = 0;
 }
 
 void MImWordList::setCandidates(const QStringList &candidates)
--- m-keyboard/widgets/mimwordlist.h
+++ m-keyboard/widgets/mimwordlist.h
@@ -19,48 +19,12 @@
 #define MIMWORDLIST_H
 
 #include <MDialog>
-#include "mimoverlay.h" 
 
 class QGraphicsLinearLayout;
-class MContentItem;
 class MImWordListItem;
-class MImWordList;
 class MReactionMap;
 
 /*!
- * \brief MIMWordListWindow is used as the plain translucent parent window for word list dialog.
- *
-  * MIMWordListWindow prevents mouse and touch events from reaching the virtual keyboard or the application.
-  * \sa MImOverlay.
- */
-class MIMWordListWindow : public MImOverlay
-{
-    Q_OBJECT
-public:
-    //! Constructor
-    explicit MIMWordListWindow(MImWordList *widget);
-
-public slots:
-    /*
-     * \brief This slot is connected with word list widget's appeared() signal.
-     */
-    void handleListAppeared();
-
-    /*
-     * \brief This slot is connected with word list widget's disappeared() signal.
-     */
-    void handleListDisappeared();
-
-protected:
-    /*! \reimp */
-    virtual bool sceneEvent(QEvent *event);
-    /*! \reimp_end */
-
-private:
-    MImWordList *listWidget;
-};
-
-/*!
  * \brief MIMWordList is used for word list dialog.
  *
  * MImWordList shows a dialog which list the suggested candidates.
@@ -116,7 +80,6 @@
     QStringList mCandidates;
     QGraphicsLinearLayout *mainLayout;
     MImWordListItem *candidateItems[MaxCandidateCount];
-    MIMWordListWindow *parentWindow;
 };
 
 #endif
--- m-keyboard/widgets/mimwordtracker.cpp
+++ m-keyboard/widgets/mimwordtracker.cpp
@@ -19,6 +19,7 @@
 #include "regiontracker.h"
 #include "mimwordtracker.h"
 #include "mimcorrectioncandidateitem.h"
+#include "mimreactionmap.h"
 
 #include <QGraphicsLinearLayout>
 #include <QDebug>
@@ -280,6 +281,6 @@
     reactionMap->fillRectangle(geometry());
 
     // Draw the actual word tracker area.
-    reactionMap->setReactiveDrawingValue();
+    reactionMap->setDrawingValue(MImReactionMap::Press, MImReactionMap::Release);
     reactionMap->fillRectangle(geometry());
 }
--- m-keyboard/widgets/mkeyboardsettingswidget.cpp
+++ m-keyboard/widgets/mkeyboardsettingswidget.cpp
@@ -154,10 +154,10 @@
     correctionSpaceSwitch->setViewType(MButton::switchType);
     correctionSpaceSwitch->setCheckable(true);
     correctionSpaceContentItem = new MContentItem(MContentItem::TwoTextLabels, this);
-    //% "Select with space"
-    correctionSpaceContentItem->setTitle(qtTrId("qtn_txts_select_with_space"));
-    //% "Select with space description"
-    correctionSpaceContentItem->setSubtitle(qtTrId("qtn_txts_select_with_space_description"));
+    //% "Insert with space"
+    correctionSpaceContentItem->setTitle(qtTrId("qtn_txts_insert_with_space"));
+    //% "Insert with space description"
+    correctionSpaceContentItem->setSubtitle(qtTrId("qtn_txts_insert_with_space_description"));
     QGraphicsLinearLayout *wCLayout = new QGraphicsLinearLayout(Qt::Horizontal);
     wCLayout->addItem(correctionSpaceContentItem);
     wCLayout->addItem(correctionSpaceSwitch);
@@ -186,8 +186,8 @@
 
     errorCorrectionContentItem->setTitle(qtTrId("qtn_txts_error_correction"));
     errorCorrectionContentItem->setSubtitle(qtTrId("qtn_txts_error_correction_description"));
-    correctionSpaceContentItem->setTitle(qtTrId("qtn_txts_select_with_space"));
-    correctionSpaceContentItem->setSubtitle(qtTrId("qtn_txts_select_with_space_description"));
+    correctionSpaceContentItem->setTitle(qtTrId("qtn_txts_insert_with_space"));
+    correctionSpaceContentItem->setSubtitle(qtTrId("qtn_txts_insert_with_space_description"));
     QStringList keyboards = settingsObject->selectedKeyboards().values();
     //% "Installed keyboards (%1)"
     QString title = qtTrId("qtn_txts_installed_keyboards")
@@ -228,18 +228,25 @@
     connect(settingsObject, SIGNAL(correctionSpaceChanged()),
             this, SLOT(syncCorrectionSpaceState()));
     connect(settingsObject, SIGNAL(selectedKeyboardsChanged()),
-            this, SLOT(updateTitle()));
-    connect(settingsObject, SIGNAL(selectedKeyboardsChanged()),
             this, SLOT(updateKeyboardSelectionModel()));
 }
 
 void MKeyboardSettingsWidget::showKeyboardList()
 {
-    if (!settingsObject || !keyboardDialog) {
-        QStringList keyboards = settingsObject->selectedKeyboards().values();
-        QString keyboardTitle = qtTrId("qtn_txts_installed_keyboards")
-                                       .arg(keyboards.count());
-        keyboardDialog = new MDialog(keyboardTitle, M::NoStandardButton);
+    if (!settingsObject)
+        return;
+
+    QStringList keyboards = settingsObject->selectedKeyboards().values();
+
+    // This is the ugly hack to avoid the crash of the VKB settings since the
+    // toolkit fixes and releases NB#230358.
+    // The basic problem is that the model selection update crashes second time
+    // when we try to reuse the same keyboard list to show the dialog again.
+    delete keyboardDialog;
+    keyboardDialog = 0;
+
+    if (!keyboardDialog) {
+        keyboardDialog = new MDialog();
 
         keyboardList = new MList(keyboardDialog);
         MKeyboardCellCreator *cellCreator = new MKeyboardCellCreator;
@@ -250,11 +257,19 @@
         keyboardList->setSelectionMode(MList::MultiSelection);
         keyboardList->setSelectionModel(new QItemSelectionModel(model, this));
         keyboardDialog->setCentralWidget(keyboardList);
+        keyboardDialog->addButton(M::DoneButton);
 
         connect(keyboardList, SIGNAL(itemClicked(const QModelIndex &)),
                 this, SLOT(updateSelectedKeyboards(const QModelIndex &)));
+        connect(keyboardDialog, SIGNAL(accepted()),
+                this, SLOT(selectKeyboards()));
     }
     updateKeyboardModel();
+    // We need to update the title every time because probably the dialog was
+    // cancelled/closed without tapping on the Done button.
+    QString keyboardTitle = qtTrId("qtn_txts_installed_keyboards")
+                                   .arg(keyboards.count());
+    keyboardDialog->setTitle(keyboardTitle);
     keyboardDialog->exec();
 }
 
@@ -296,18 +311,35 @@
 
 void MKeyboardSettingsWidget::updateSelectedKeyboards(const QModelIndex &index)
 {
-    if (!settingsObject || !index.isValid() || !keyboardList
+    if (!index.isValid() || !keyboardDialog || !keyboardList
         || !keyboardList->selectionModel())
         return;
 
+    QModelIndexList indexList = keyboardList->selectionModel()->selectedIndexes();
+
+    // Update the dialog title
+    QString title = qtTrId("qtn_txts_installed_keyboards")
+                            .arg(indexList.size());
+
+    keyboardDialog->setTitle(title);
+}
+
+void MKeyboardSettingsWidget::selectKeyboards()
+{
+    if (!settingsObject || !keyboardDialog)
+        return;
+
     QStringList updatedKeyboardLayouts;
-    foreach (const QModelIndex &i, keyboardList->selectionModel()->selectedIndexes()) {
+    QModelIndexList indexList = keyboardList->selectionModel()->selectedIndexes();
+
+    foreach (const QModelIndex &i, indexList) {
         updatedKeyboardLayouts << i.data(MKeyboardLayoutRole).toString();
     }
-    if (updatedKeyboardLayouts.isEmpty()) {
+    settingsObject->setSelectedKeyboards(updatedKeyboardLayouts);
+    // "No keyboard is selected" notification
+    if (indexList.isEmpty()) {
         notifyNoKeyboards();
     }
-    settingsObject->setSelectedKeyboards(updatedKeyboardLayouts);
     //update titles
     retranslateUi();
 }
--- m-keyboard/widgets/mkeyboardsettingswidget.h
+++ m-keyboard/widgets/mkeyboardsettingswidget.h
@@ -48,6 +48,7 @@
     void updateTitle();
     void updateKeyboardSelectionModel();
     void updateSelectedKeyboards(const QModelIndex &);
+    void selectKeyboards();
     void setErrorCorrectionState(bool enabled);
     void syncErrorCorrectionState();
     void setCorrectionSpaceState(bool enabled);
--- m-keyboard/widgets/mvirtualkeyboard.cpp
+++ m-keyboard/widgets/mvirtualkeyboard.cpp
@@ -28,6 +28,7 @@
 #include "mimabstractkey.h"
 #include "keyevent.h"
 #include "grip.h"
+#include "reactionmappainter.h"
 #include "regiontracker.h"
 
 #include <mtoolbardata.h>
@@ -60,6 +61,7 @@
                                    const MVirtualKeyboardStyleContainer *styleContainer,
                                    QGraphicsWidget *parent)
     : MWidget(parent),
+      ReactionMapPaintable(),
       styleContainer(styleContainer),
       mainLayout(new QGraphicsLinearLayout(Qt::Vertical, this)),
       currentLevel(0),
@@ -123,6 +125,9 @@
     keyboardsReset(); // creates keyboard widgets
 
     organizeContent(currentOrientation);
+
+    // Request a reaction map painting if it appears
+    connect(this, SIGNAL(displayEntered()), &signalForwarder, SIGNAL(requestRepaint()));
 }
 
 
@@ -249,6 +254,10 @@
     return MWidget::itemChange(change, value);
 }
 
+bool MVirtualKeyboard::isPaintable() const
+{
+    return isVisible();
+}
 
 void MVirtualKeyboard::resetState()
 {
@@ -481,9 +490,6 @@
 void MVirtualKeyboard::onSectionSwitched(QGraphicsWidget */*previous*/, QGraphicsWidget */*current*/)
 {
     organizeContent(currentOrientation);
-    // We (probably) need to redraw reaction map even if the region doesn't
-    // change, buttons may be positioned differently
-    RegionTracker::instance().requestReactionMapUpdate();
 }
 
 
@@ -501,6 +507,9 @@
             this, SLOT(onSectionSwitchStarting(int, int)));
     connect(mainKeyboardSwitcher, SIGNAL(switchDone(QGraphicsWidget *, QGraphicsWidget *)),
             this, SLOT(onSectionSwitched(QGraphicsWidget *, QGraphicsWidget *)));
+    // Repaint the reaction maps if the keyboard is changed
+    connect(mainKeyboardSwitcher, SIGNAL(switchDone(QGraphicsWidget *, QGraphicsWidget *)),
+            &signalForwarder, SIGNAL(requestRepaint()));
 }
 
 
@@ -725,6 +734,13 @@
 
     // resize and update keyboards if needed
     organizeContent(currentOrientation);
+
+    // Request a reaction map repainting when the first keyboard is loaded or
+    // the keyboard is changed between normal, phone and number layouts.
+    if (previousWidget != newWidget) {
+        signalForwarder.emitRequestRepaint();
+    }
+
 }
 
 QList<MImEngine::KeyboardLayoutKey> MVirtualKeyboard::mainLayoutKeys() const
--- m-keyboard/widgets/mvirtualkeyboard.h
+++ m-keyboard/widgets/mvirtualkeyboard.h
@@ -23,6 +23,7 @@
 #include "mkeyboardcommon.h"
 #include "mimkeyarea.h"
 #include "layoutdata.h"
+#include "reactionmappaintable.h"
 
 #include <minputmethodnamespace.h>
 #include <MWidget>
@@ -61,7 +62,7 @@
    It also provides interfaces to get keystatus
 
 */
-class MVirtualKeyboard : public MWidget
+class MVirtualKeyboard : public MWidget, public ReactionMapPaintable
 {
     Q_OBJECT
     Q_PROPERTY(QString layoutLanguage READ layoutLanguage)
@@ -147,6 +148,7 @@
 
     //! reimp
     QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+    bool isPaintable() const;
     //! reimp_end
 
     //! \return region occupied by keyboard in scene coordinates
@@ -376,8 +378,8 @@
 
     Notification *notification;
 
-    QGraphicsWidget *numberKeyboard;
-    QGraphicsWidget *phoneNumberKeyboard;
+    MImAbstractKeyArea *numberKeyboard;
+    MImAbstractKeyArea *phoneNumberKeyboard;
 
     QSharedPointer<QPixmap> backgroundPixmap;
 
--- m-keyboard/widgets/popupfactory.cpp
+++ m-keyboard/widgets/popupfactory.cpp
@@ -28,15 +28,15 @@
 }
 
 // dummy popup to be used if no plugin is found
-class DummyPopup: public PopupBase
+class MockPopup: public PopupBase
 {
 public:
-    explicit DummyPopup(MImAbstractKeyArea *mainArea)
+    explicit MockPopup(MImAbstractKeyArea *mainArea)
         : PopupBase(mainArea),
           visible(false)
     {}
 
-    virtual ~DummyPopup()
+    virtual ~MockPopup()
     {}
 
     //! \reimp
@@ -86,8 +86,12 @@
 
 PopupBase *PopupFactory::createPopup(MImAbstractKeyArea *mainArea) const
 {
+#ifdef UNIT_TEST
+    return new MockPopup(mainArea);
+#else
     return (plugin ? plugin->createPopup(mainArea)
-                   : new DummyPopup(mainArea));
+                   : new MockPopup(mainArea));
+#endif
 }
 
 PopupFactory::PopupFactory()
--- m-keyboard/widgets/reactionmappaintable.cpp
+++ m-keyboard/widgets/reactionmappaintable.cpp
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#include "reactionmappaintable.h"
+
+#include "reactionmappainter.h"
+
+void ReactionMapPaintableSignaler::emitRequestRepaint()
+{
+    emit requestRepaint();
+}
+
+ReactionMapPaintable::ReactionMapPaintable()
+{
+    ReactionMapPainter::instance().addWidget(*this);
+}
+
+ReactionMapPaintable::~ReactionMapPaintable()
+{
+    ReactionMapPainter::instance().removeWidget(*this);
+}
+
+bool ReactionMapPaintable::isFullScreen() const
+{
+    // Most of the widgets do not occupy the full screen.
+    return false;
+};
--- m-keyboard/widgets/reactionmappaintable.h
+++ m-keyboard/widgets/reactionmappaintable.h
+/* * This file is part of meego-keyboard *
+ *
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ * All rights reserved.
+ * Contact: Nokia Corporation (directui at nokia.com)
+ *
+ * If you have questions regarding the use of this file, please contact
+ * Nokia at directui at nokia.com.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it 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.
+ */
+
+#ifndef REACTIONMAPPAINTABLE_H
+#define REACTIONMAPPAINTABLE_H
+
+#include <QObject>
+
+class MReactionMap;
+class QGraphicsView;
+
+//! \brief A helper class for reaction map painting to enable signals in ReactionMapPaintable
+class ReactionMapPaintableSignaler : public QObject
+{
+    Q_OBJECT
+
+public:
+    //! \brief Emit a request for reaction map repainting
+    void emitRequestRepaint();
+
+signals:
+    //! \brief Request a reaction map repainting
+    void requestRepaint();
+
+    //! \brief Request a reaction map clearing
+    void requestClear();
+};
+
+//! \brief A class for widgets with reaction map painting
+class ReactionMapPaintable
+{
+public:
+    //! \brief Ctor
+    ReactionMapPaintable();
+    //! \brief Dtor
+    virtual ~ReactionMapPaintable();
+
+    //! \brief Paint the reaction map of the widget
+    virtual void paintReactionMap(MReactionMap *, QGraphicsView *) = 0;
+
+    //! \brief Is the widget paintable
+    virtual bool isPaintable() const = 0;
+
+    //! \brief Is the widget full screen
+    virtual bool isFullScreen() const;
+
+    ReactionMapPaintableSignaler signalForwarder;
+};
+
+#endif
--- m-keyboard/widgets/sharedhandlearea.cpp
+++ m-keyboard/widgets/sharedhandlearea.cpp
@@ -55,7 +55,6 @@
     mainLayout.addItem(&toolbar);
     mainLayout.setAlignment(&toolbar, Qt::AlignCenter);
 
-    connect(&toolbar, SIGNAL(regionUpdated()), this, SLOT(updatePosition()));
     connect(this, SIGNAL(visibleChanged()), this, SLOT(updatePosition()));
 }
 
@@ -147,3 +146,12 @@
     updatePosition();
 }
 
+bool SharedHandleArea::event(QEvent *e)
+{
+    if (e->type() == QEvent::GraphicsSceneResize) {
+        // when share handler area is resized,need to call updatePosition
+        // to make sure the toolbar in the proper position.
+        updatePosition();
+    }
+    return MWidget::event(e);
+}
--- m-keyboard/widgets/sharedhandlearea.h
+++ m-keyboard/widgets/sharedhandlearea.h
@@ -69,6 +69,11 @@
     void flickLeft(const FlickGesture &gesture);
     void flickRight(const FlickGesture &gesture);
 
+protected:
+    // \reimp
+    virtual bool event(QEvent *);
+    // \reimp_end
+
 private:
     //! Connect signals from a \a handle widget
     void connectHandle(const Handle &handle);
--- m-keyboard/widgets/symbolview.cpp
+++ m-keyboard/widgets/symbolview.cpp
@@ -22,6 +22,8 @@
 #include "symbolview.h"
 #include "grip.h"
 #include "mimkeyarea.h"
+#include "reactionmappainter.h"
+#include "mimreactionmap.h"
 #include "regiontracker.h"
 
 #include <MSceneManager>
@@ -46,6 +48,7 @@
 SymbolView::SymbolView(const LayoutsManager &layoutsManager, const MVirtualKeyboardStyleContainer *style,
                        const QString &layout, QGraphicsWidget *parent)
     : MWidget(parent),
+      ReactionMapPaintable(),
       styleContainer(style),
       sceneManager(*MPlainWindow::instance()->sceneManager()),
       activity(Inactive),
@@ -83,6 +86,9 @@
     hide();
     setupLayout();
     reloadContent();
+
+    // Request a reaction map painting if it appears
+    connect(this, SIGNAL(displayEntered()), &signalForwarder, SIGNAL(requestRepaint()));
 }
 
 
@@ -358,11 +364,8 @@
 void SymbolView::organizeContent()
 {
     const M::Orientation orientation(sceneManager.orientation());
-    const int sceneWidth = sceneManager.visibleSceneSize().width();
 
-    setPreferredWidth(sceneWidth);
-    setMaximumWidth(sceneWidth);
-    setMinimumWidth(sceneWidth);
+    resize(sceneManager.visibleSceneSize().width(), size().height());
 
     if (currentOrientation != orientation) {
         currentOrientation = orientation;
@@ -452,7 +455,7 @@
     // after we've been hidden.
     if (isVisible()) {
         layout()->activate();
-        RegionTracker::instance().requestReactionMapUpdate();
+        signalForwarder.emitRequestRepaint();
     }
     if (pageSwitcher) {
         activePage = pageSwitcher->current();
@@ -493,7 +496,7 @@
         reactionMap->fillRectangle(mapRectFromScene(rect));
     }
 
-    reactionMap->setReactiveDrawingValue();
+    reactionMap->setDrawingValue(MImReactionMap::Press, MImReactionMap::Release);
 
     // Draw current character view.
     if (pageSwitcher->currentWidget()) {
@@ -549,6 +552,11 @@
     }
 }
 
+bool SymbolView::isPaintable() const
+{
+    return isVisible();
+}
+
 void SymbolView::resetCurrentKeyArea(bool resetCapsLock)
 {
     MImAbstractKeyArea *mainKba = static_cast<MImAbstractKeyArea *>(pageSwitcher->currentWidget());
--- m-keyboard/widgets/symbolview.h
+++ m-keyboard/widgets/symbolview.h
@@ -20,6 +20,7 @@
 #include "keyeventhandler.h"
 #include "mkeyboardcommon.h"
 #include "layoutdata.h"
+#include "reactionmappaintable.h"
 
 #include <minputmethodnamespace.h>
 #include <MWidget>
@@ -39,7 +40,7 @@
 /*!
  * \brief SymbolView is used to show different layouts symbols/upper case/lower case
  */
-class SymbolView : public MWidget
+class SymbolView : public MWidget, public ReactionMapPaintable
 {
     Q_OBJECT
 
@@ -95,6 +96,10 @@
      */
     void setTemporarilyHidden(bool hidden);
 
+    /*! \reimp */
+    bool isPaintable() const;
+    /*! \reimp_end */
+
 public slots:
     /*!
      * Handler to show the page.
--- m-keyboard/widgets/widgets.pri
+++ m-keyboard/widgets/widgets.pri
@@ -9,6 +9,7 @@
     $$WIDGETS_DIR/mimkeyvisitor.h \
     $$WIDGETS_DIR/mimkey.h \
     $$WIDGETS_DIR/mimkeyarea.h \
+    $$WIDGETS_DIR/reactionmappaintable.h \
 
 PUBLIC_STYLE_HEADERS += \
     $$WIDGETS_DIR/mvirtualkeyboardstyle.h \
@@ -81,6 +82,7 @@
     $$WIDGETS_DIR/mkeyboardsettingswidget.cpp \
     $$WIDGETS_DIR/mimoverlay.cpp \
     $$WIDGETS_DIR/mtoolbarlabelview.cpp \
+    $$WIDGETS_DIR/reactionmappaintable.cpp \
 
 INCLUDEPATH += $$WIDGETS_DIR
 DEPENDPATH += $$WIDGETS_DIR
--- tests/ut_mhardwarekeyboard/ut_mhardwarekeyboard.cpp
+++ tests/ut_mhardwarekeyboard/ut_mhardwarekeyboard.cpp
@@ -210,18 +210,20 @@
 
 bool Ut_MHardwareKeyboard::filterKeyRelease(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
                                             const QString &text,
-                                            quint32 nativeScanCode, quint32 nativeModifiers) const
+                                            quint32 nativeScanCode, quint32 nativeModifiers,
+                                            unsigned long time) const
 {
     return m_hkb->filterKeyEvent(QEvent::KeyRelease, keyCode, modifiers, text, false, 1, nativeScanCode,
-                                 nativeModifiers);
+                                 nativeModifiers, time);
 }
 
 bool Ut_MHardwareKeyboard::filterKeyPress(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
                                           const QString &text,
-                                          quint32 nativeScanCode, quint32 nativeModifiers) const
+                                          quint32 nativeScanCode, quint32 nativeModifiers,
+                                          unsigned long time) const
 {
     return m_hkb->filterKeyEvent(QEvent::KeyPress, keyCode, modifiers, text, false, 1, nativeScanCode,
-                                 nativeModifiers);
+                                 nativeModifiers, time);
 }
 
 bool Ut_MHardwareKeyboard::checkLatchedState(const unsigned int mask, const unsigned int value) const
@@ -1045,6 +1047,7 @@
     QCOMPARE(inputMethodHost->lastPreeditString(), QString("1"));
     QCOMPARE(inputMethodHost->lastCommitString().length(), 0);
     m_hkb->handleLongPressTimeout();
+    m_hkb->longPressTimer.stop();
     QCOMPARE(inputMethodHost->lastPreeditString().length(), 1);
     QCOMPARE(inputMethodHost->lastPreeditString(), QString("1"));
     QVERIFY(filterKeyRelease(Qt::Key_Q, Qt::GroupSwitchModifier, "1", KeycodeCharacter1, FnModifierMask));
@@ -1067,6 +1070,7 @@
     QCOMPARE(inputMethodHost->lastPreeditString().length(), 1);
     QCOMPARE(inputMethodHost->lastPreeditString(), QString("1"));
     m_hkb->handleLongPressTimeout();
+    m_hkb->longPressTimer.stop();
     QCOMPARE(inputMethodHost->lastPreeditString().length(), 1);
     QCOMPARE(inputMethodHost->lastPreeditString(), QString("1"));
     QVERIFY(filterKeyRelease(Qt::Key_Q, Qt::GroupSwitchModifier, "1", KeycodeCharacter1, FnModifierMask));
@@ -1090,6 +1094,7 @@
     QCOMPARE(inputMethodHost->lastPreeditString().length(), 1);
     QCOMPARE(inputMethodHost->lastPreeditString(), QString("0"));
     m_hkb->handleLongPressTimeout();
+    m_hkb->longPressTimer.stop();
     QCOMPARE(inputMethodHost->lastPreeditString().length(), 1);
     QCOMPARE(inputMethodHost->lastPreeditString(), QString("p"));
     QVERIFY(filterKeyRelease(Qt::Key_P, Qt::GroupSwitchModifier, "1", KeycodeCharacter0, FnModifierMask));
@@ -1460,4 +1465,23 @@
     QCOMPARE(inputMethodHost->lastCommitString(), QString("1"));
 }
 
+
+void Ut_MHardwareKeyboard::testLongPressUndo()
+{
+    // Simulate press and release actions/events at times 0 and 100 (the last parameter),
+    // which implies a time difference less than the long press time (so the end result
+    // must be "f"), but with a delivery time difference of 1500ms, which is more than the
+    // long press time (so long press processing is done and we temporarily get "1" as the
+    // pre-edit).
+    QVERIFY(filterKeyPress(Qt::Key_F, Qt::NoModifier, "f", KeycodeCharacterF, 0, 0));
+    QCOMPARE(inputMethodHost->lastPreeditString().length(), 1);
+    QCOMPARE(inputMethodHost->lastPreeditString(), QString("f"));
+    QTest::qWait(1500);         // more than long press time
+    QCOMPARE(inputMethodHost->lastPreeditString().length(), 1);
+    QCOMPARE(inputMethodHost->lastPreeditString(), QString("1"));
+    QVERIFY(filterKeyRelease(Qt::Key_F, Qt::NoModifier, "f", KeycodeCharacterF, 0, 100));
+    QCOMPARE(inputMethodHost->lastCommitString().length(), 1);
+    QCOMPARE(inputMethodHost->lastCommitString(), QString("f"));
+}
+
 QTEST_APPLESS_MAIN(Ut_MHardwareKeyboard);
--- tests/ut_mhardwarekeyboard/ut_mhardwarekeyboard.h
+++ tests/ut_mhardwarekeyboard/ut_mhardwarekeyboard.h
@@ -80,6 +80,8 @@
     void testPressTwoKeys();
     void testPressTwoKeysWithLatch();
 
+    void testLongPressUndo();
+
 private:
     bool checkLatchedState(unsigned int mask, unsigned int value) const;
     bool checkLockedState(unsigned int mask, unsigned int value) const;
@@ -87,9 +89,11 @@
 
     // Wrappers for MHardwareKeyboard::filterKeyEvent() to make calls shorter
     bool filterKeyRelease(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
-                          const QString &text, quint32 nativeScanCode, quint32 nativeModifiers) const;
+                          const QString &text, quint32 nativeScanCode, quint32 nativeModifiers,
+                          unsigned long time = 0) const;
     bool filterKeyPress(Qt::Key keyCode, Qt::KeyboardModifiers modifiers,
-                        const QString &text, quint32 nativeScanCode, quint32 nativeModifiers) const;
+                        const QString &text, quint32 nativeScanCode, quint32 nativeModifiers,
+                        unsigned long time = 0) const;
 };
 
 #endif
--- tests/ut_mimabstractkeyarea/layouts/test-layout.xml
+++ tests/ut_mimabstractkeyarea/layouts/test-layout.xml
@@ -42,7 +42,7 @@
               <binding accented_labels="óö" accents="´¨" label="o"/>
               <binding shift="true" accented_labels="ÓÖ" accents="´¨" label="O"/>
             </key>
-            <key>
+            <key id="actionKey">
               <binding label="p"/>
               <binding shift="true" label="P"/>
             </key>
@@ -153,7 +153,7 @@
               <binding label="."/>
               <binding shift="true" label=","/>
             </key>
-            <key>
+            <key id="actionKey">
               <binding action="return" label=""/>
             </key>
           </row>
--- tests/ut_mimabstractkeyarea/ut_mimabstractkeyarea.cpp
+++ tests/ut_mimabstractkeyarea/ut_mimabstractkeyarea.cpp
@@ -77,6 +77,7 @@
     {
         return new MImKeyArea(section, usePopup, parent);
     }
+
 }
 
 void Ut_MImAbstractKeyArea::initTestCase()
@@ -510,6 +511,27 @@
     QCOMPARE(eKey->model().binding(true)->extendedLabels(), QString("%1%2").arg(QChar(0xca)).arg(QChar(0xc8)));
 }
 
+void Ut_MImAbstractKeyArea::testKeyId()
+{
+    keyboard = new KeyboardData;
+    QVERIFY(keyboard->loadNokiaKeyboard("test-layout.xml"));
+    subject = createKeyArea(keyboard->layout(LayoutData::General, M::Landscape)->section(LayoutData::mainSection),
+                                              false, 0);
+
+    const MImAbstractKey *enterKey(keyAt(3, 6));
+    QCOMPARE(enterKey->model().binding(false)->action(), MImKeyBinding::ActionReturn);
+    QCOMPARE(enterKey->model().id(), QString("actionKey"));
+
+    const MImAbstractKey *dotKey(keyAt(3, 5));
+    QCOMPARE(dotKey->model().id(), QString());
+
+    MImAbstractKey *found = subject->findKey("invalid-id");
+    QVERIFY(found == 0);
+
+    found = subject->findKey("actionKey");
+    QVERIFY(found == enterKey);
+}
+
 void Ut_MImAbstractKeyArea::testImportedLayouts_data()
 {
     QTest::addColumn<KBACreator>("createKba");
@@ -876,7 +898,7 @@
 {
     const int margin = 5;
     const QSize size(50, 50);
-    subject = Ut_MImAbstractKeyArea::createArea(false, "Q", size, QSize(size.width() - 2 * margin,
+    subject = Ut_MImAbstractKeyArea::createArea("Q", size, QSize(size.width() - 2 * margin,
                                                                  size.height() - 2 * margin));
 
     MImAbstractKeyAreaStyle *s = const_cast<MImAbstractKeyAreaStyle *>(subject->style().operator->());
@@ -1062,7 +1084,7 @@
     QFETCH(TpList, touchPoints);
     QFETCH(TpButtonStateMatrix, expectedStates);
 
-    subject = Ut_MImAbstractKeyArea::createArea(false, labels, kbaSize);
+    subject = Ut_MImAbstractKeyArea::createArea(labels, kbaSize);
     QSignalSpy spy(subject, SIGNAL(keyClicked(const MImAbstractKey*, QString, bool, QPoint)));
 
     ButtonList tracedButtons;
@@ -1103,8 +1125,9 @@
 {
     const int margin = 5;
     const QSize size(50, 50);
-    subject = Ut_MImAbstractKeyArea::createArea(true, "Q", size, QSize(size.width() - 2 * margin,
-                                                                 size.height() - 2 * margin));
+    subject = Ut_MImAbstractKeyArea::createArea("Q", size, QSize(size.width() - 2 * margin,
+                                                                 size.height() - 2 * margin),
+                                                true);
 
     TpCreator createTp = &MImAbstractKeyArea::createTouchPoint;
 
@@ -1126,11 +1149,6 @@
 
     subject->reset();
     QCOMPARE(key->touchPointCount(), 0);
-    // FIXME: the timeout for popup become invisible after cancel
-    // depends on popop implementation. And if we use dummpy popup,
-    // the popup will become invisible immediately. But here we don't
-    // know what the popup plugin is used.
-    QTest::qWait(200);
     QVERIFY(!subject->popup().isVisible());
 }
 
@@ -1169,10 +1187,10 @@
     return key;
 }
 
-MImAbstractKeyArea *Ut_MImAbstractKeyArea::createArea(bool usePopup,
-                                                      const QString &labels,
+MImAbstractKeyArea *Ut_MImAbstractKeyArea::createArea(const QString &labels,
                                                       const QSize &size,
-                                                      const QSize &fixedNormalKeySize)
+                                                      const QSize &fixedNormalKeySize,
+                                                      bool usePopup)
 {
     LayoutData::SharedLayoutSection section;
     section = LayoutData::SharedLayoutSection(new LayoutSection(labels));
--- tests/ut_mimabstractkeyarea/ut_mimabstractkeyarea.h
+++ tests/ut_mimabstractkeyarea/ut_mimabstractkeyarea.h
@@ -60,6 +60,7 @@
     void testTwoDeadInOne_data();
     void testTwoDeadInOne();
     void testExtendedLabels();
+    void testKeyId();
     void testImportedLayouts_data();
     void testImportedLayouts();
     void testPopup_data();
@@ -85,10 +86,10 @@
     MImAbstractKey *keyAt(unsigned int row,
                       unsigned int column) const;
 
-    static MImAbstractKeyArea *createArea(bool usePopup,
-                                          const QString &labels,
+    static MImAbstractKeyArea *createArea(const QString &labels,
                                           const QSize &size,
-                                          const QSize &fixedNormalKeySize = QSize(48, 48));
+                                          const QSize &fixedNormalKeySize = QSize(48, 48),
+                                          bool usePopup = false);
 
 public:
     enum TestOperation {
--- tests/ut_mimabstractkeyarea/ut_mimabstractkeyarea.pro
+++ tests/ut_mimabstractkeyarea/ut_mimabstractkeyarea.pro
@@ -10,8 +10,13 @@
 
 
 # Input
-HEADERS += ut_mimabstractkeyarea.h
-SOURCES += ut_mimabstractkeyarea.cpp
+HEADERS += ut_mimabstractkeyarea.h \
+           ../../m-keyboard/widgets/popupfactory.h \
+           ../../m-keyboard/widgets/mimabstractkeyarea.h \
+
+SOURCES += ut_mimabstractkeyarea.cpp \
+           ../../m-keyboard/widgets/popupfactory.cpp \
+           ../../m-keyboard/widgets/mimabstractkeyarea.cpp \
 
 VKB_TEST_DATA = layouts/*.xml
 vkb_test_data.path = /usr/share/meegotouch/virtual-keyboard/layouts
--- tests/ut_mimcorrectionhost/ut_mimcorrectionhost.cpp
+++ tests/ut_mimcorrectionhost/ut_mimcorrectionhost.cpp
@@ -19,8 +19,10 @@
 #include "ut_mimcorrectionhost.h"
 #include "mimwordtracker.h"
 #include "mimwordlist.h"
-#include <mplainwindow.h>
+#include "reactionmappainter.h"
 #include "utils.h"
+
+#include <mplainwindow.h>
 #include <QtTest/QTest>
 #include <QObject>
 #include <QDebug>
@@ -40,6 +42,7 @@
     disableQtPlugins();
     app = new MApplication(dummyArgc, dummyArgv);
     RegionTracker::createInstance();
+    ReactionMapPainter::createInstance();
 
     // MImCorrectionHost uses this internally
     new MPlainWindow;
@@ -75,6 +78,7 @@
     delete parentWindow;
     delete MPlainWindow::instance();
     RegionTracker::destroyInstance();
+    ReactionMapPainter::destroyInstance();
     delete app;
     app = 0;
 }
--- tests/ut_mimkey/ut_mimkey.cpp
+++ tests/ut_mimkey/ut_mimkey.cpp
@@ -30,6 +30,8 @@
 #include <QSignalSpy>
 #include <QDebug>
 
+#include <memory>
+
 Q_DECLARE_METATYPE(QList<Ut_MImKey::DirectionPair>)
 Q_DECLARE_METATYPE(Ut_MImKey::KeyList)
 Q_DECLARE_METATYPE(QList<Ut_MImKey::KeyTriple>)
@@ -83,6 +85,10 @@
     style = new MImAbstractKeyAreaStyleContainer;
     style->initialize("", "", 0);
 
+    stylingCache = QSharedPointer<MImKey::StylingCache>(new MImKey::StylingCache);
+    stylingCache->primary   = QFontMetrics((*style)->font());
+    stylingCache->secondary = QFontMetrics((*style)->secondaryFont());
+
     parent = new QGraphicsWidget;
     dataKey = createKeyModel();
 }
@@ -98,7 +104,7 @@
 
 void Ut_MImKey::init()
 {
-    subject = new MImKey(*dataKey, *style, *parent);
+    subject = new MImKey(*dataKey, *style, *parent, stylingCache);
 }
 
 void Ut_MImKey::cleanup()
@@ -158,7 +164,7 @@
     MImKeyBinding *binding = new MImKeyBinding;
     key->bindings[MImKeyModel::NoShift] = binding;
 
-    MImAbstractKey *subject = new MImKey(*key, *style, *parent);
+    MImAbstractKey *subject = new MImKey(*key, *style, *parent, stylingCache);
 
     for (int i = 0; i < 2; ++i) {
         bool isDead = (i != 0);
@@ -341,7 +347,7 @@
     b->keyAction = MImKeyBinding::ActionShift;
     MImKeyModel *model = new MImKeyModel;
     model->bindings[MImKeyModel::NoShift] = b;
-    MImKey *shift = new MImKey(*model, *style, *parent);
+    MImKey *shift = new MImKey(*model, *style, *parent, stylingCache);
     shift->setDownState(true);
     keys << shift;
 
@@ -359,6 +365,7 @@
 
     const QPointF topLeft(50, 50);
     key->setPos(topLeft);
+    key->updateGeometryCache();
     QCOMPARE(key->buttonRect().topLeft(), topLeft);
     QCOMPARE(key->buttonBoundingRect().topLeft(), topLeft);
 
@@ -384,7 +391,9 @@
     QCOMPARE(key->buttonBoundingRect(), expectedBoundingRect);
 
     key.reset(createKey());
-    key->setGeometry(MImKey::Geometry(topLeft, width, height, margin0, margin1, margin1, margin0));
+    key->setGeometry(MImKey::Geometry(width, height, margin0, margin1, margin1, margin0));
+    key->setPos(topLeft);
+    key->updateGeometryCache();
     QCOMPARE(key->buttonRect(), expectedRect);
     QCOMPARE(key->buttonBoundingRect(), expectedBoundingRect);
 }
@@ -405,7 +414,7 @@
 
 MImKey *Ut_MImKey::createKey(bool state)
 {
-    MImKey *key = new MImKey(*dataKey, *style, *parent);
+    MImKey *key = new MImKey(*dataKey, *style, *parent, stylingCache);
     key->setDownState(state);
     return key;
 }
--- tests/ut_mimkey/ut_mimkey.h
+++ tests/ut_mimkey/ut_mimkey.h
@@ -20,6 +20,7 @@
 #define UT_MIMKEY_H
 
 #include <mimabstractkey.h>
+#include <mimkey.h>
 
 #include <QtTest/QTest>
 #include <QObject>
@@ -102,6 +103,7 @@
 private:
     MImKey *createKey(bool state = false);
     MImKeyModel *createKeyModel();
+    QSharedPointer<MImKey::StylingCache> stylingCache;
 };
 
 Q_DECLARE_METATYPE(Ut_MImKey::DirectionPair)
--- tests/ut_mimtoolbar/ut_mimtoolbar.cpp
+++ tests/ut_mimtoolbar/ut_mimtoolbar.cpp
@@ -25,6 +25,7 @@
 #include "layoutsmanager.h"
 #include "mreactionmaptester.h"
 #include "utils.h"
+#include "reactionmappainter.h"
 #include <mplainwindow.h>
 #include <mtoolbardata.h>
 #include <mtoolbarlayout.h>
@@ -78,6 +79,7 @@
 
     disableQtPlugins();
     app = new MApplication(dummyArgc, dummyArgv);
+    ReactionMapPainter::createInstance();
 
     qRegisterMetaType<CopyPasteState>("CopyPasteState");
     LayoutsManager::createInstance();
@@ -113,6 +115,7 @@
 {
     toolbarData.clear();
     LayoutsManager::destroyInstance();
+    ReactionMapPainter::destroyInstance();
     delete sceneWindow;
     delete MPlainWindow::instance();
     delete app;
--- tests/ut_mkeyboardhost/minputmethodhoststub.cpp
+++ tests/ut_mkeyboardhost/minputmethodhoststub.cpp
@@ -22,7 +22,9 @@
 MInputMethodHostStub::MInputMethodHostStub()
 {
     clear();
+    predictionValid_ = true;
     predictionEnabled_ = true;
+    correctionValid_ = true;
     correctionEnabled_ = true;
     autoCapitalizationEnabled_ = true;
     contentType_ = 0;
@@ -117,13 +119,13 @@
 
 bool MInputMethodHostStub::correctionEnabled(bool &val)
 {
-    val = true;
+    val = correctionValid_;
     return correctionEnabled_;
 }
 
 bool MInputMethodHostStub::predictionEnabled(bool &val)
 {
-    val = true;
+    val = predictionValid_;
     return predictionEnabled_;
 }
 
--- tests/ut_mkeyboardhost/minputmethodhoststub.h
+++ tests/ut_mkeyboardhost/minputmethodhoststub.h
@@ -94,7 +94,9 @@
     int setInputMethodAreaCalls;
     QList<QRegion> inputMethodAreas;
 
+    bool predictionValid_;
     bool predictionEnabled_;
+    bool correctionValid_;
     bool correctionEnabled_;
     bool autoCapitalizationEnabled_;
     int contentType_;
--- tests/ut_mkeyboardhost/ut_mkeyboardhost.cpp
+++ tests/ut_mkeyboardhost/ut_mkeyboardhost.cpp
@@ -56,6 +56,7 @@
     const char * const XkbVariantSettingName("/meegotouch/inputmethods/hwkeyboard/variant");
 
     const QString CorrectionSetting("/meegotouch/inputmethods/virtualkeyboard/correctionenabled");
+    const QString CorrectionSettingWithSpace("/meegotouch/inputmethods/virtualkeyboard/correctwithspace");
     const QString InputMethodCorrectionEngine("/meegotouch/inputmethods/correctionengine");
     const int SceneRotationTime = 1400; // in ms
     bool gAutoCapsEnabled = true;
@@ -362,6 +363,7 @@
 {
     subject->show();
     MGConfItem configCorrection(CorrectionSetting);
+    MGConfItem configCorrectionSpace(CorrectionSettingWithSpace);
 
     QVERIFY(subject->imCorrectionEngine != 0);
 
@@ -379,7 +381,117 @@
     QCOMPARE(subject->imCorrectionEngine->completionEnabled(), false);
     QCOMPARE(subject->correctionEnabled, false);
 
+    // Test the correction accepted with space option
+    configCorrectionSpace.set(QVariant(true));
+    QTest::qWait(100);
+    QCOMPARE(subject->correctionAcceptedWithSpaceEnabled, true);
+    configCorrectionSpace.set(QVariant(false));
+    QTest::qWait(100);
+    QCOMPARE(subject->correctionAcceptedWithSpaceEnabled, false);
+
+    subject->hide();
+}
+
+void Ut_MKeyboardHost::testCorrectionSettings_data()
+{
+    QTest::addColumn<bool>("correctionValid");
+    QTest::addColumn<bool>("correctionEnabled");
+    QTest::addColumn<bool>("predictionValid");
+    QTest::addColumn<bool>("predictionEnabled");
+    QTest::addColumn<bool>("result");
+
+    QTest::newRow("Correction and prediction invalid")
+            << false << false << false << false << true;
+    QTest::newRow("Correction invalid, prediction enabled")
+            << false << false << true << true << true;
+    QTest::newRow("Correction invalid, prediction disabled")
+            << false << false << true << false << false;
+    QTest::newRow("Correction enabled, prediction invalid")
+            << true << true << false << false << true;
+    QTest::newRow("Correction disabled, prediction invalid")
+            << true << false << false << false << false;
+    QTest::newRow("Correction disabled, prediction disabled")
+            << true << false << true << false << false;
+    QTest::newRow("Correction disabled, prediction enabled")
+            << true << false << true << true << false;
+    QTest::newRow("Correction enabled, prediction disabled")
+            << true << true << true << false << false;
+    QTest::newRow("Correction enabled, prediction enabled")
+            << true << true << true << true << true;
+}
+
+void Ut_MKeyboardHost::testCorrectionSettings()
+{
+    QFETCH(bool, correctionValid);
+    QFETCH(bool, correctionEnabled);
+    QFETCH(bool, predictionValid);
+    QFETCH(bool, predictionEnabled);
+    QFETCH(bool, result);
+
+    DummyDriverMkh *engine(new DummyDriverMkh);
+    subject->imCorrectionEngine = engine;
+    engine->enableCompletion();
+    engine->enableCorrection();
+
+    subject->show();
+
+    QVERIFY(subject->imCorrectionEngine != 0);
+
+    // Correction comes from MTextEdit inputMethodCorrectionEnabled property.
+    // Prediction comes from Qt::InputMethodHint: Qt::ImhNoPredictiveText.
+    inputMethodHost->correctionValid_ = correctionValid;
+    inputMethodHost->correctionEnabled_ = correctionEnabled;
+    inputMethodHost->predictionValid_ = predictionValid;
+    inputMethodHost->predictionEnabled_ = predictionEnabled;
+    subject->updateCorrectionState();
+    QCOMPARE(subject->correctionEnabled, result);
+
+    subject->hide();
+    delete engine;
+    subject->imCorrectionEngine = 0;
+}
+
+void Ut_MKeyboardHost::testCorrectionContentTypes_data()
+{
+    QTest::addColumn<M::TextContentType>("contentType");
+    QTest::addColumn<bool>("result");
+
+    QTest::newRow("Number field")
+            << M::NumberContentType << false;
+    QTest::newRow("Phone number field")
+            << M::PhoneNumberContentType << false;
+    QTest::newRow("Email field")
+            << M::EmailContentType << false;
+    QTest::newRow("URL field")
+            << M::UrlContentType << false;
+    QTest::newRow("Free text field")
+            << M::FreeTextContentType << true;
+    QTest::newRow("Custom field")
+            << M::CustomContentType << true;
+
+}
+
+void Ut_MKeyboardHost::testCorrectionContentTypes()
+{
+    QFETCH(M::TextContentType, contentType);
+    QFETCH(bool, result);
+
+    DummyDriverMkh *engine(new DummyDriverMkh);
+    subject->imCorrectionEngine = engine;
+    engine->enableCompletion();
+    engine->enableCorrection();
+
+    subject->show();
+
+    QVERIFY(subject->imCorrectionEngine != 0);
+
+    inputMethodHost->contentType_ = contentType;
+    subject->updateCorrectionState();
+    QCOMPARE(subject->correctionEnabled, result);
+
     subject->hide();
+    delete engine;
+    subject->imCorrectionEngine = 0;
 }
 
 void Ut_MKeyboardHost::testAutoCaps()
@@ -628,7 +740,7 @@
 
     for (int i = 0; i < 5; ++i) {
         M::OrientationAngle currentAngle = angles[i % 4];
-        im->handleAppOrientationChange(static_cast<int>(currentAngle));
+        im->handleAppOrientationChanged(static_cast<int>(currentAngle));
         QTest::qWait(1500);
         QCOMPARE(currentAngle, MPlainWindow::instance()->orientationAngle());
     }
@@ -779,11 +891,13 @@
     subject->correctionHost->setCandidates((QStringList() << "abc" << "def"));
     subject->correctionHost->showCorrectionWidget();
     ++c1;
+    qApp->processEvents();
     QCOMPARE(inputMethodHost->setScreenRegionCalls, c1);
     QCOMPARE(inputMethodHost->setInputMethodAreaCalls, c2);
 
     subject->correctionHost->hideCorrectionWidget();
     ++c1;
+    qApp->processEvents();
     QCOMPARE(inputMethodHost->setScreenRegionCalls, c1);
     QCOMPARE(inputMethodHost->setInputMethodAreaCalls, c2);
     QCOMPARE(region(ScreenRegion, c1 - 1), region(InputMethodArea, c2 - 1));
@@ -891,6 +1005,109 @@
 #endif
 }
 
+void Ut_MKeyboardHost::testOptimizedRegionCallCounts_data()
+{
+    QTest::addColumn<MInputMethod::HandlerState>("beforeShowState");
+    QTest::addColumn<MInputMethod::HandlerState>("afterShowState");
+
+    // Use -1 to not to care (yet to be optimized).
+    QTest::addColumn<int>("imAreaUpdatesAfterShow");
+    QTest::addColumn<int>("regionUpdatesAfterShow");
+    QTest::addColumn<int>("imAreaUpdatesAfterStateChange");
+    QTest::addColumn<int>("regionUpdatesAfterStateChange");
+
+    QTest::newRow("onscreen -> hardware produces only one update")
+            << MInputMethod::OnScreen
+            << MInputMethod::Hardware
+            << -1 << -1
+            << 1 << 1;
+
+    QTest::newRow("hardware -> onscreen produces only one update")
+            << MInputMethod::OnScreen
+            << MInputMethod::Hardware
+            << -1 << -1
+            << 1 << 1;
+
+    // This basically tests that the region estimate sent is correct and final.
+    QTest::newRow("onscreen state show produces only one update")
+            << MInputMethod::OnScreen
+            << MInputMethod::OnScreen
+            << 1 << 1
+            << -1 << -1;
+
+    QTest::newRow("hardware state show produces only one update")
+            << MInputMethod::Hardware
+            << MInputMethod::Hardware
+            << 1 << 1
+            << -1 << -1;
+}
+
+void Ut_MKeyboardHost::testOptimizedRegionCallCounts()
+{
+    QFETCH(MInputMethod::HandlerState, beforeShowState);
+    QFETCH(MInputMethod::HandlerState, afterShowState);
+    QFETCH(int, imAreaUpdatesAfterShow);
+    QFETCH(int, regionUpdatesAfterShow);
+    QFETCH(int, imAreaUpdatesAfterStateChange);
+    QFETCH(int, regionUpdatesAfterStateChange);
+
+    // This test does not test validity of regions. It tests only
+    // that unnecessary region or input method area updates are not
+    // triggered and forwarded to input method host.
+
+    // On state change we basically have two components affecting region,
+    // vkb widget and shared handle area.
+    // Set minimum height for both so they will affect region.
+    subject->sharedHandleArea->setMinimumHeight(10);
+    subject->vkbWidget->setMinimumHeight(10);
+
+    // Set to inital state.
+    QSet<MInputMethod::HandlerState> state;
+    state << beforeShowState;
+    subject->setState(state);
+
+    inputMethodHost->setInputMethodAreaCalls = 0;
+    inputMethodHost->setScreenRegionCalls = 0;
+
+    // Show plugin in OnScreen state.
+    // Skip animation and update positions directly.
+    subject->show();
+
+    // Speed things up.. animation has to be run because it updates widget positions.
+    subject->slideUpAnimation.pause();
+    subject->slideUpAnimation.setDuration(0);
+    subject->slideUpAnimation.resume();
+    // We need to wait here 200 ms otherwise the test case can fail in lower delays (e.g. 100 ms).
+    QTest::qWait(200);
+    QVERIFY(subject->slideUpAnimation.state() == QAbstractAnimation::Stopped);
+
+    // Check call counts.
+    if (imAreaUpdatesAfterShow >= 0) {
+        QCOMPARE(inputMethodHost->setInputMethodAreaCalls, imAreaUpdatesAfterShow);
+    }
+    if (regionUpdatesAfterShow >= 0) {
+        QCOMPARE(inputMethodHost->setScreenRegionCalls, regionUpdatesAfterShow);
+    }
+
+    // Clear call counts.
+    inputMethodHost->setInputMethodAreaCalls = 0;
+    inputMethodHost->setScreenRegionCalls = 0;
+
+    // Switch to final state.
+    state.clear();
+    state << afterShowState;
+    subject->setState(state);
+
+    // Check call counts.
+    qApp->processEvents();
+    if (imAreaUpdatesAfterStateChange >= 0) {
+        QCOMPARE(inputMethodHost->setInputMethodAreaCalls, imAreaUpdatesAfterStateChange);
+    }
+    if (regionUpdatesAfterStateChange >= 0) {
+        QCOMPARE(inputMethodHost->setScreenRegionCalls, regionUpdatesAfterStateChange);
+    }
+}
+
 void Ut_MKeyboardHost::testSetState_data()
 {
     QSet<MInputMethod::HandlerState> state;
@@ -971,20 +1188,20 @@
     spy.clear();
     //! first shift key press+release will latch the shift modifier, and then switch the symbolview level to 1
     // Note that the native modifier parameters are not correct but that doesn't matter for this test.
-    subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0);
-    subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0);
+    subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0, 0);
+    subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0, 0);
     QCOMPARE(spy.count(), 1);
     QCOMPARE(subject->hardwareKeyboard->modifierState(Qt::ShiftModifier), ModifierLatchedState);
     QCOMPARE(subject->symbolView->currentLevel(), 1);
     // second shift key press+release will lock the shift modifier, shift state changes but symbolview level stays 1
-    subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0);
-    subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0);
+    subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0, 0);
+    subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0, 0);
     QCOMPARE(spy.count(), 3);
     QCOMPARE(subject->hardwareKeyboard->modifierState(Qt::ShiftModifier), ModifierLockedState);
     QCOMPARE(subject->symbolView->currentLevel(), 1);
     //! third shift key press+release will clear the shift modifier, and switch the symbolview level back to 0
-    subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0);
-    subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0);
+    subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0, 0);
+    subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0, 0);
     QCOMPARE(spy.count(), 4);
     QCOMPARE(subject->hardwareKeyboard->modifierState(Qt::ShiftModifier), ModifierClearState);
     QCOMPARE(subject->symbolView->currentLevel(), 0);
@@ -1324,7 +1541,7 @@
 
 void Ut_MKeyboardHost::rotateToAngle(M::OrientationAngle angle)
 {
-    subject->handleAppOrientationChange(angle);
+    subject->handleAppOrientationChanged(angle);
     QTest::qWait(SceneRotationTime); // wait until rotation animation is finished
 }
 
@@ -1459,13 +1676,13 @@
     gShowLockOnInfoBannerCallCount = 0;
 
     for (int i = 0; i < shiftClickedCount;  i++) {
-        subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0);
-        subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0);
+        subject->processKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier, QString(""), false, 1, 0, 0, 0);
+        subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_Shift, Qt::ShiftModifier, QString(""), false, 1, 0, 0, 0);
     }
 
     for (int i = 0; i < fnClickedCount;  i++) {
-        subject->processKeyEvent(QEvent::KeyPress, FnLevelKey, Qt::NoModifier, QString(""), false, 1, 0, 0);
-        subject->processKeyEvent(QEvent::KeyRelease, FnLevelKey, FnLevelModifier, QString(""), false, 1, 0, 0);
+        subject->processKeyEvent(QEvent::KeyPress, FnLevelKey, Qt::NoModifier, QString(""), false, 1, 0, 0, 0);
+        subject->processKeyEvent(QEvent::KeyRelease, FnLevelKey, FnLevelModifier, QString(""), false, 1, 0, 0, 0);
     }
 
     if (deadKeyCharacterCode) {
@@ -1475,9 +1692,9 @@
         variantConfig.set(xkbVariant);
 
         subject->processKeyEvent(QEvent::KeyPress, Qt::Key_unknown, Qt::NoModifier,
-                                 QString(QChar(deadKeyCharacterCode)), false, 1, 0, 0);
+                                 QString(QChar(deadKeyCharacterCode)), false, 1, 0, 0, 0);
         subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_unknown, Qt::NoModifier,
-                                 QString(QChar(deadKeyCharacterCode)), false, 1, 0, 0);
+                                 QString(QChar(deadKeyCharacterCode)), false, 1, 0, 0, 0);
     }
 
     QCOMPARE(inputMethodHost->indicator, expectIndicator);
@@ -1486,9 +1703,9 @@
     if (deadKeyCharacterCode) {
         // When state is changed from locked -> dead key -> locked, we don't want a notification
         subject->processKeyEvent(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier,
-                                 QString("A"), false, 1, 0, 0);
+                                 QString("A"), false, 1, 0, 0, 0);
         subject->processKeyEvent(QEvent::KeyRelease, Qt::Key_A, Qt::NoModifier,
-                                 QString("A"), false, 1, 0, 0);
+                                 QString("A"), false, 1, 0, 0, 0);
         QCOMPARE(inputMethodHost->indicator, MInputMethod::LatinLockedIndicator);
         QCOMPARE(gShowLockOnInfoBannerCallCount, 1);
     }
@@ -1651,6 +1868,20 @@
 
 void Ut_MKeyboardHost::testAutoPunctuation()
 {
+    MGConfItem configCorrection(CorrectionSetting);
+    MGConfItem configCorrectionSpace(CorrectionSettingWithSpace);
+
+    QVERIFY(subject->imCorrectionEngine != 0);
+
+    // We need to be sure that the correction is enabled before the test
+    configCorrection.set(QVariant(true));
+    configCorrectionSpace.set(QVariant(true));
+    QTest::qWait(100);
+    QVERIFY(subject->imCorrectionEngine->correctionEnabled());
+    QVERIFY(subject->imCorrectionEngine->completionEnabled());
+    QVERIFY(subject->correctionAcceptedWithSpaceEnabled);
+
+    // Real test case
     QFETCH(QChar, character);
     QFETCH(bool, autopunctuated);
 
@@ -1689,6 +1920,9 @@
 
 void Ut_MKeyboardHost::testFastTypingState()
 {
+    QSKIP("Skipping fast typing test because the feature is disabled",
+          SkipSingle);
+
     // Set timeout to zero for easier testing.
     subject->fastTypingTimeout.setInterval(0);
 
@@ -1702,5 +1936,21 @@
     QCOMPARE(inputMethodHost->orientationAngleLocked, false);
 }
 
-QTEST_APPLESS_MAIN(Ut_MKeyboardHost);
+void Ut_MKeyboardHost::testToolbarPosition()
+{
+    // Position after portrait vkb -> hwkb (landscape) transition
 
+    rotateToAngle(M::Angle90);
+    subject->show();
+
+    QSet<MInputMethod::HandlerState> states;
+    states << MInputMethod::Hardware;
+    subject->setState(states);
+
+    rotateToAngle(M::Angle0);
+    QCOMPARE(subject->sharedHandleArea->pos(),
+             QPointF(0, (MPlainWindow::instance()->visibleSceneSize().height()
+                         - subject->sharedHandleArea->size().height())));
+}
+
+QTEST_APPLESS_MAIN(Ut_MKeyboardHost);
--- tests/ut_mkeyboardhost/ut_mkeyboardhost.h
+++ tests/ut_mkeyboardhost/ut_mkeyboardhost.h
@@ -52,6 +52,10 @@
     void testDirectMode();
     void testNotCrash();
     void testCorrectionOptions();
+    void testCorrectionSettings_data();
+    void testCorrectionSettings();
+    void testCorrectionContentTypes_data();
+    void testCorrectionContentTypes();
 
     void testAutoCaps();
     void testApplicationOrientationChanged();
@@ -63,6 +67,8 @@
     void testSendStringFromToolbar();
 
     void testRegionSignals();
+    void testOptimizedRegionCallCounts_data();
+    void testOptimizedRegionCallCounts();
 
     void testSetState_data();
     void testSetState();
@@ -107,6 +113,8 @@
 
     void testFastTypingState();
 
+    void testToolbarPosition();
+
 private:
     void rotateToAngle(M::OrientationAngle);
     void triggerAutoCaps();
--- tests/ut_mkeyboardhost/ut_mkeyboardhost.pro
+++ tests/ut_mkeyboardhost/ut_mkeyboardhost.pro
@@ -17,11 +17,15 @@
            dummydriver_mkh.h \
            ../stubs/mgconfitem_stub.h \
            ../stubs/fakegconf.h \
+           $$WIDGETS_DIR/popupfactory.h \
 
+# PopupFactory needs to be compiled to have a mocked functionality
+# otherwise the unit test crashes
 SOURCES += ut_mkeyboardhost.cpp \
            minputmethodhoststub.cpp \
            dummydriver_mkh.cpp \
            ../stubs/fakegconf.cpp \
+           $$WIDGETS_DIR/popupfactory.cpp \
 
 target.files += $$TARGET \
                 toolbar1.xml \
--- tests/ut_mkeyboardsettingswidget/ut_mkeyboardsettingswidget.cpp
+++ tests/ut_mkeyboardsettingswidget/ut_mkeyboardsettingswidget.cpp
@@ -106,6 +106,18 @@
     bool firstItemIsSelected = subject->keyboardList->selectionModel()->selectedRows().contains(subject->keyboardList->itemModel()->index(0,0));
     subject->keyboardList->selectItem(subject->keyboardList->itemModel()->index(0,0));
     QMap<QString, QString> newSelectedKeyboards = settingsObject->selectedKeyboards();
+    // The changes are not committed if the dialog is rejected
+    QCOMPARE(newSelectedKeyboards.count(), selectedKeyboards.count());
+    subject->keyboardDialog->reject();
+    newSelectedKeyboards = settingsObject->selectedKeyboards();
+    QCOMPARE(newSelectedKeyboards.count(), selectedKeyboards.count());
+    // Open the dialog again
+    subject->selectedKeyboardsItem->click();
+    // Select the item again
+    subject->keyboardList->selectItem(subject->keyboardList->itemModel()->index(0,0));
+    // Accept the dialog content
+    subject->keyboardDialog->accept();
+    newSelectedKeyboards = settingsObject->selectedKeyboards();
     if (firstItemIsSelected) {
         QCOMPARE(newSelectedKeyboards.count(), selectedKeyboards.count() - 1);
     } else {
--- tests/ut_mvirtualkeyboard/ut_mvirtualkeyboard.cpp
+++ tests/ut_mvirtualkeyboard/ut_mvirtualkeyboard.cpp
@@ -30,6 +30,7 @@
 #include "mplainwindow.h"
 #include "utils.h"
 #include "regiontracker.h"
+#include "reactionmappainter.h"
 
 #include <minputmethodnamespace.h>
 #include <MScene>
@@ -93,6 +94,7 @@
 
     app = new MApplication(argc, argv);
     RegionTracker::createInstance();
+    ReactionMapPainter::createInstance();
 
     QString InputMethodSetting(InputMethodSettingName);
     MGConfItem item1(InputMethodSetting);
@@ -131,6 +133,7 @@
     delete app;
     app = 0;
     RegionTracker::destroyInstance();
+    ReactionMapPainter::destroyInstance();
 }
 
 void Ut_MVirtualKeyboard::init()
@@ -776,13 +779,13 @@
     QVERIFY(tester.testChildButtonReactiveAreas(view, m_vkb));
 
     // Switch layout, the chosen kb layouts are all different in terms of reaction maps they generate.
-    QSignalSpy updateSignal(&RegionTracker::instance(), SIGNAL(reactionMapUpdateNeeded()));
+    QSignalSpy updateSignal(&m_vkb->signalForwarder, SIGNAL(requestRepaint()));
     m_vkb->setLayout(1);
     QTest::qWait(600);
 
     // Currently updating is done via kbhost when it receives region updates.
     // Kbhost is not present so we paint reaction map explicitly.
-    QVERIFY(updateSignal.count() > 0);
+    QVERIFY(updateSignal.count() == 1);
     m_vkb->paintReactionMap(MReactionMap::instance(view), view);
 
     QVERIFY(tester.testReactionMapGrid(view, 40, 50, m_vkb->mapRectToScene(m_vkb->rect()).toRect(), m_vkb));
--- tests/ut_notification/test.css
+++ tests/ut_notification/test.css
-MVirtualKeyboardStyle {
-    background-image: "keyboard-qwerty-background" 0 0 0 0;
-    divider: "keyboard-divider-vertical";
-    font: "Nokia Sans Light" 24;
-    font-opacity: 0.9;
-    font-color: #FFFFFF;
-    secondaryFont: "Nokia Sans Light" 14;
-
-    sym-background : "keyboard-sym-background";
-    sym-highlight-opacity: 0.6;
-    sym-highlight-color: #505050;
-
-    accurate-background:"keyboard-acc-thumb";
-
-    candidate-background:"textinput-candidates-background";
-    candidate-highlight-opacity: 1.0;
-    candidate-highlight-color:#BA55D3;
-
-    close-button-margin : 10;
-
-    notification-font: $FONT_KEYBOARD;
-    notification-font-size: 42;
-    notification-border-color: #00FF00;
-    notification-background-color: #FF0000;
-    notification-text-color: #0000FF;
-    notification-opacity: 1.0;
-}
-
-MVirtualKeyboardStyle.Portrait {
-    size: 280 864;
-    left-margin:6;
-    top-margin:4;
-    divider-width:4;
-    divider-height:58;
-    spacebar-width:91;
-
-    keyboard-area-size: 480 280;
-    layout-size: 480 210;
-
-    tab-button-size: 91 70;
-    function-button-size: 96 70;
-    sym-size: 480 425;
-
-    menu-size: 470 342;
-    baseline-margin:19;
-
-    menu-margin: 20;
-    menu-margin-box: 10;
-    menu-max-opacity-frame: 500;
-    menu-max-title-text-width: 200;
-}
-
-MVirtualKeyboardStyle.Landscape {
-    size: 864 280;
-    left-margin: 6;
-    top-margin: 4;
-    divider-width: 4;
-    divider-height: 58;
-    spacebar-width: 216;
-
-    keyboard-area-size: 864 280;
-    layout-size: 864 210;
-
-    function-button-size: 108 70;
-    tab-button-size: 108 70;
-    sym-size: 864 355;
-
-    menu-size: 790 342;
-    baseline-margin:19;
-
-    menu-margin: 20;
-    menu-margin-box: 10;
-    menu-max-opacity-frame: 500;
-    menu-max-title-text-width: 200;
-}
-
--- tests/ut_notification/ut_notification.cpp
+++ tests/ut_notification/ut_notification.cpp
@@ -64,13 +64,6 @@
     disableQtPlugins();
     app = new MApplication(argc, app_name);
 
-    QString cssFile("./test.css");
-    if (!QFile::exists(cssFile)) {
-        cssFile = "/usr/share/meego-keyboard-tests/ut_notification/test.css";
-        QVERIFY(QFile::exists(cssFile));
-    }
-    QVERIFY(MTheme::instance()->loadCSS(cssFile));
-
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 
@@ -146,15 +139,5 @@
     QVERIFY(!subject->isVisible());
 }
 
-//This test depends on values in test.css
-void Ut_Notification::testCSS()
-{
-    QCOMPARE(subject->background, QColor(Qt::red));
-    QCOMPARE(subject->border, QColor(Qt::green));
-    QCOMPARE(subject->textColor, QColor(Qt::blue));
-    QCOMPARE(subject->opacity, 1.0);
-    QCOMPARE(subject->font.pixelSize(), 42);
-}
-
 QTEST_APPLESS_MAIN(Ut_Notification);
 
--- tests/ut_notification/ut_notification.h
+++ tests/ut_notification/ut_notification.h
@@ -44,7 +44,6 @@
     void testCreate();
     void testSetMessageAndGeometry();
     void testFadeInFadeOut();
-    void testCSS();
 };
 
 #endif
--- tests/ut_notification/ut_notification.pro
+++ tests/ut_notification/ut_notification.pro
@@ -12,10 +12,3 @@
 SOURCES += ut_notification.cpp
 
 include(../common_check.pri)
-
-CSS_DATA = test.css
-css_data.path = /usr/share/meego-keyboard-tests/ut_notification/
-css_data.files = $$CSS_DATA
-
-INSTALLS += css_data
-
--- tests/ut_sharedhandlearea/ut_sharedhandlearea.cpp
+++ tests/ut_sharedhandlearea/ut_sharedhandlearea.cpp
@@ -15,6 +15,8 @@
  */
 
 #include "ut_sharedhandlearea.h"
+
+#include "reactionmappainter.h"
 #include <utils.h>
 #include <sharedhandlearea.h>
 #include <mgconfitem_stub.h>
@@ -42,6 +44,7 @@
     disableQtPlugins();
     app = new MApplication(dummyArgc, dummyArgv);
     RegionTracker::createInstance();
+    ReactionMapPainter::createInstance();
 
     sceneWindow = createMSceneWindow(new MPlainWindow); // also create singleton
 
@@ -55,6 +58,7 @@
     delete sceneWindow;
     delete MPlainWindow::instance();
     RegionTracker::destroyInstance();
+    ReactionMapPainter::destroyInstance();
     delete app;
 }
 
--- tests/ut_symbolview/ut_symbolview.cpp
+++ tests/ut_symbolview/ut_symbolview.cpp
@@ -26,6 +26,7 @@
 #include "mimabstractkeyarea.h"
 #include "layoutsmanager.h"
 #include "regiontracker.h"
+#include "reactionmappainter.h"
 #include "symbolview.h"
 #include "ut_symbolview.h"
 #include "mplainwindow.h"
@@ -83,6 +84,8 @@
     style = new MVirtualKeyboardStyleContainer;
     style->initialize("MVirtualKeyboard", "MVirtualKeyboardView", 0);
 
+    ReactionMapPainter::createInstance();
+
     MGConfItem inputMethodSetting(InputMethodSettingName);
 
     QStringList langlist;
@@ -100,6 +103,7 @@
 void Ut_SymbolView::cleanupTestCase()
 {
     RegionTracker::destroyInstance();
+    ReactionMapPainter::destroyInstance();
     delete MPlainWindow::instance();
     LayoutsManager::destroyInstance();
     delete style;
@@ -164,13 +168,9 @@
     QVERIFY(tester.testChildButtonReactiveAreas(view, subject));
 
     // Test the next tab also.
-    QSignalSpy reactionMapUpdate(&RegionTracker::instance(),
-                                 SIGNAL(reactionMapUpdateNeeded()));
     subject->switchToNextPage();
     QTest::qWait(600);
     QVERIFY(!subject->pageSwitcher->isRunning());
-    // After the switch the reactive areas should be updated.
-    QVERIFY(reactionMapUpdate.count() >= 1);
 
     // However since we don't have MKeyboardHost here we call this directly again.
     gMReactionMapStub->setTransparentDrawingValue();
--- tests/ut_symbolview/ut_symbolview.pro
+++ tests/ut_symbolview/ut_symbolview.pro
@@ -11,11 +11,15 @@
            ../stubs/mgconfitem_stub.h \
            ../stubs/fakegconf.h \
            ../stubs/mreactionmaptester.h \
-           $$WIDGETS_DIR/symbolview.h
+           $$WIDGETS_DIR/popupfactory.h \
+           $$WIDGETS_DIR/symbolview.h \
 
+# PopupFactory needs to be compiled to have a mocked functionality
+# otherwise the unit test crashes
 SOURCES += ut_symbolview.cpp \
            ../stubs/fakegconf.cpp \
-           $$WIDGETS_DIR/symbolview.cpp
+           $$WIDGETS_DIR/popupfactory.cpp \
+           $$WIDGETS_DIR/symbolview.cpp \
 
 include(../common_check.pri)
 

++++++ meegotouch-inputmethodkeyboard.yaml
--- meegotouch-inputmethodkeyboard.yaml
+++ meegotouch-inputmethodkeyboard.yaml
@@ -1,6 +1,6 @@
 Name: meegotouch-inputmethodkeyboard
 Summary: MeeGo Virtual Keyboard
-Version: 0.5.25
+Version: 0.5.28
 Release: 1
 Group: System/GUI/Other
 License: LGPLv2.1
@@ -12,8 +12,8 @@
 PkgConfigBR:
     - QtGui >= 4.6.0
     - MeegoImEngine >= 0.4.1
-    - MeegoImFramework >= 0.19.40
-    - meegotouch >= 0.20
+    - MeegoImFramework >= 0.19.41
+    - meegotouch >= 0.20.77
     - meegotouch-feedbackreactionmaps
     - x11
     - xkbfile >= 1.0.6



More information about the MeeGo-commits mailing list