summaryrefslogtreecommitdiffstats
path: root/src/gui/inputmethod
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/gui/inputmethod
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/gui/inputmethod')
-rw-r--r--src/gui/inputmethod/inputmethod.pri31
-rw-r--r--src/gui/inputmethod/qcoefepinputcontext_p.h176
-rw-r--r--src/gui/inputmethod/qcoefepinputcontext_s60.cpp1200
-rw-r--r--src/gui/inputmethod/qinputcontext.cpp500
-rw-r--r--src/gui/inputmethod/qinputcontext.h139
-rw-r--r--src/gui/inputmethod/qinputcontext_p.h94
-rw-r--r--src/gui/inputmethod/qinputcontextfactory.cpp354
-rw-r--r--src/gui/inputmethod/qinputcontextfactory.h88
-rw-r--r--src/gui/inputmethod/qinputcontextplugin.cpp178
-rw-r--r--src/gui/inputmethod/qinputcontextplugin.h106
-rw-r--r--src/gui/inputmethod/qmacinputcontext_mac.cpp378
-rw-r--r--src/gui/inputmethod/qmacinputcontext_p.h97
-rw-r--r--src/gui/inputmethod/qwininputcontext_p.h111
-rw-r--r--src/gui/inputmethod/qwininputcontext_win.cpp847
-rw-r--r--src/gui/inputmethod/qwsinputcontext_p.h97
-rw-r--r--src/gui/inputmethod/qwsinputcontext_qws.cpp246
-rw-r--r--src/gui/inputmethod/qximinputcontext_p.h142
-rw-r--r--src/gui/inputmethod/qximinputcontext_x11.cpp885
18 files changed, 5669 insertions, 0 deletions
diff --git a/src/gui/inputmethod/inputmethod.pri b/src/gui/inputmethod/inputmethod.pri
new file mode 100644
index 0000000000..d4394380dc
--- /dev/null
+++ b/src/gui/inputmethod/inputmethod.pri
@@ -0,0 +1,31 @@
+# Qt inputmethod module
+
+HEADERS +=inputmethod/qinputcontextfactory.h \
+ inputmethod/qinputcontextplugin.h \
+ inputmethod/qinputcontext_p.h \
+ inputmethod/qinputcontext.h
+SOURCES +=inputmethod/qinputcontextfactory.cpp \
+ inputmethod/qinputcontextplugin.cpp \
+ inputmethod/qinputcontext.cpp
+x11 {
+ HEADERS += inputmethod/qximinputcontext_p.h
+ SOURCES += inputmethod/qximinputcontext_x11.cpp
+}
+win32 {
+ HEADERS += inputmethod/qwininputcontext_p.h
+ SOURCES += inputmethod/qwininputcontext_win.cpp
+}
+embedded {
+ HEADERS += inputmethod/qwsinputcontext_p.h
+ SOURCES += inputmethod/qwsinputcontext_qws.cpp
+}
+mac:!embedded:!qpa {
+ HEADERS += inputmethod/qmacinputcontext_p.h
+ SOURCES += inputmethod/qmacinputcontext_mac.cpp
+}
+symbian:contains(QT_CONFIG, s60) {
+ HEADERS += inputmethod/qcoefepinputcontext_p.h
+ SOURCES += inputmethod/qcoefepinputcontext_s60.cpp
+ LIBS += -lfepbase -lakninputlanguage
+}
+
diff --git a/src/gui/inputmethod/qcoefepinputcontext_p.h b/src/gui/inputmethod/qcoefepinputcontext_p.h
new file mode 100644
index 0000000000..de3577f1a6
--- /dev/null
+++ b/src/gui/inputmethod/qcoefepinputcontext_p.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOEFEPINPUTCONTEXT_P_H
+#define QCOEFEPINPUTCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QT_NO_IM
+
+#include "qinputcontext.h"
+#include <qhash.h>
+#include <qtimer.h>
+#include <private/qcore_symbian_p.h>
+#include <private/qt_s60_p.h>
+
+#include <fepbase.h>
+#include <aknedsts.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_AUTOTEST_EXPORT QCoeFepInputContext : public QInputContext,
+ public MCoeFepAwareTextEditor,
+ public MCoeFepAwareTextEditor_Extension1,
+ public MObjectProvider
+{
+ Q_OBJECT
+
+public:
+ QCoeFepInputContext(QObject *parent = 0);
+ ~QCoeFepInputContext();
+
+ QString identifierName() { return QLatin1String("coefep"); }
+ QString language();
+
+ void reset();
+ void update();
+
+ bool filterEvent(const QEvent *event);
+ bool symbianFilterEvent(QWidget *keyWidget, const QSymbianEvent *event);
+ void mouseHandler( int x, QMouseEvent *event);
+ bool isComposing() const { return !m_preeditString.isEmpty(); }
+
+ void setFocusWidget(QWidget * w);
+ void widgetDestroyed(QWidget *w);
+
+ TCoeInputCapabilities inputCapabilities();
+
+ void resetSplitViewWidget(bool keepInputWidget = false);
+ void ensureFocusWidgetVisible(QWidget *widget);
+
+protected:
+ void timerEvent(QTimerEvent *timerEvent);
+
+private:
+ void commitCurrentString(bool cancelFepTransaction);
+ void updateHints(bool mustUpdateInputCapabilities);
+ void applyHints(Qt::InputMethodHints hints);
+ void applyFormat(QList<QInputMethodEvent::Attribute> *attributes);
+ void queueInputCapabilitiesChanged();
+ bool needsInputPanel();
+ void commitTemporaryPreeditString();
+ bool isWidgetVisible(QWidget *widget, int offset = 0);
+
+private Q_SLOTS:
+ void ensureInputCapabilitiesChanged();
+ void translateInputWidget();
+
+ // From MCoeFepAwareTextEditor
+public:
+ void StartFepInlineEditL(const TDesC& aInitialInlineText, TInt aPositionOfInsertionPointInInlineText,
+ TBool aCursorVisibility, const MFormCustomDraw* aCustomDraw,
+ MFepInlineTextFormatRetriever& aInlineTextFormatRetriever,
+ MFepPointerEventHandlerDuringInlineEdit& aPointerEventHandlerDuringInlineEdit);
+ void UpdateFepInlineTextL(const TDesC& aNewInlineText, TInt aPositionOfInsertionPointInInlineText);
+ void SetInlineEditingCursorVisibilityL(TBool aCursorVisibility);
+ void CancelFepInlineEdit();
+ TInt DocumentLengthForFep() const;
+ TInt DocumentMaximumLengthForFep() const;
+ void SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection);
+ void GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const;
+ void GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, TInt aLengthToRetrieve) const;
+ void GetFormatForFep(TCharFormat& aFormat, TInt aDocumentPosition) const;
+ void GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLine, TInt& aHeight, TInt& aAscent,
+ TInt aDocumentPosition) const;
+private:
+ void DoCommitFepInlineEditL();
+ MCoeFepAwareTextEditor_Extension1* Extension1(TBool& aSetToTrue);
+ void ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateEvent aEventType);
+
+ // From MCoeFepAwareTextEditor_Extension1
+public:
+ void SetStateTransferingOwnershipL(MCoeFepAwareTextEditor_Extension1::CState* aState, TUid aTypeSafetyUid);
+ MCoeFepAwareTextEditor_Extension1::CState* State(TUid aTypeSafetyUid);
+
+ // From MObjectProvider
+public:
+ TTypeUid::Ptr MopSupplyObject(TTypeUid id);
+ MObjectProvider *MopNext();
+
+private:
+ QSymbianControl *m_parent;
+ CAknEdwinState *m_fepState;
+ QString m_preeditString;
+ Qt::InputMethodHints m_lastImHints;
+ TUint m_textCapabilities;
+ bool m_inDestruction;
+ bool m_pendingInputCapabilitiesChanged;
+ int m_cursorVisibility;
+ int m_inlinePosition;
+ MFepInlineTextFormatRetriever *m_formatRetriever;
+ MFepPointerEventHandlerDuringInlineEdit *m_pointerHandler;
+ QBasicTimer m_tempPreeditStringTimeout;
+ bool m_hasTempPreeditString;
+
+ int m_splitViewResizeBy;
+ Qt::WindowStates m_splitViewPreviousWindowStates;
+ QRectF m_transformation;
+
+ friend class tst_QInputContext;
+};
+
+Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable);
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_IM
+
+#endif // QCOEFEPINPUTCONTEXT_P_H
diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
new file mode 100644
index 0000000000..06dc25c708
--- /dev/null
+++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp
@@ -0,0 +1,1200 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT_NO_IM
+
+#include "qcoefepinputcontext_p.h"
+#include <qapplication.h>
+#include <qtextformat.h>
+#include <qgraphicsview.h>
+#include <qgraphicsscene.h>
+#include <qgraphicswidget.h>
+#include <qsymbianevent.h>
+#include <qlayout.h>
+#include <qdesktopwidget.h>
+#include <private/qcore_symbian_p.h>
+
+#include <fepitfr.h>
+#include <hal.h>
+
+#include <limits.h>
+// You only find these enumerations on SDK 5 onwards, so we need to provide our own
+// to remain compatible with older releases. They won't be called by pre-5.0 SDKs.
+
+// MAknEdStateObserver::EAknCursorPositionChanged
+#define QT_EAknCursorPositionChanged MAknEdStateObserver::EAknEdwinStateEvent(6)
+// MAknEdStateObserver::EAknActivatePenInputRequest
+#define QT_EAknActivatePenInputRequest MAknEdStateObserver::EAknEdwinStateEvent(7)
+
+// EAknEditorFlagSelectionVisible is only valid from 3.2 onwards.
+// Sym^3 AVKON FEP manager expects that this flag is used for FEP-aware editors
+// that support text selection.
+#define QT_EAknEditorFlagSelectionVisible 0x100000
+
+// EAknEditorFlagEnablePartialScreen is only valid from Sym^3 onwards.
+#define QT_EAknEditorFlagEnablePartialScreen 0x200000
+
+QT_BEGIN_NAMESPACE
+
+Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable)
+{
+ S60->partial_keyboard = enable;
+
+ QInputContext *ic = 0;
+ if (QApplication::focusWidget()) {
+ ic = QApplication::focusWidget()->inputContext();
+ } else if (qApp && qApp->inputContext()) {
+ ic = qApp->inputContext();
+ }
+ if (ic)
+ ic->update();
+}
+
+QCoeFepInputContext::QCoeFepInputContext(QObject *parent)
+ : QInputContext(parent),
+ m_fepState(q_check_ptr(new CAknEdwinState)), // CBase derived object needs check on new
+ m_lastImHints(Qt::ImhNone),
+ m_textCapabilities(TCoeInputCapabilities::EAllText),
+ m_inDestruction(false),
+ m_pendingInputCapabilitiesChanged(false),
+ m_cursorVisibility(1),
+ m_inlinePosition(0),
+ m_formatRetriever(0),
+ m_pointerHandler(0),
+ m_hasTempPreeditString(false),
+ m_splitViewResizeBy(0),
+ m_splitViewPreviousWindowStates(Qt::WindowNoState)
+{
+ m_fepState->SetObjectProvider(this);
+ int defaultFlags = EAknEditorFlagDefault;
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) {
+ if (S60->partial_keyboard) {
+ defaultFlags |= QT_EAknEditorFlagEnablePartialScreen;
+ }
+ defaultFlags |= QT_EAknEditorFlagSelectionVisible;
+ }
+ m_fepState->SetFlags(defaultFlags);
+ m_fepState->SetDefaultInputMode( EAknEditorTextInputMode );
+ m_fepState->SetPermittedInputModes( EAknEditorAllInputModes );
+ m_fepState->SetDefaultCase( EAknEditorTextCase );
+ m_fepState->SetPermittedCases( EAknEditorAllCaseModes );
+ m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG);
+ m_fepState->SetNumericKeymap(EAknEditorAlphanumericNumberModeKeymap);
+}
+
+QCoeFepInputContext::~QCoeFepInputContext()
+{
+ m_inDestruction = true;
+
+ // This is to make sure that the FEP manager "forgets" about us,
+ // otherwise we may get callbacks even after we're destroyed.
+ // The call below is essentially equivalent to InputCapabilitiesChanged(),
+ // but is synchronous, rather than asynchronous.
+ CCoeEnv::Static()->SyncNotifyFocusObserversOfChangeInFocus();
+
+ if (m_fepState)
+ delete m_fepState;
+}
+
+void QCoeFepInputContext::reset()
+{
+ commitCurrentString(true);
+}
+
+void QCoeFepInputContext::ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateEvent aEventType)
+{
+ QT_TRAP_THROWING(m_fepState->ReportAknEdStateEventL(aEventType));
+}
+
+void QCoeFepInputContext::update()
+{
+ updateHints(false);
+
+ // For pre-5.0 SDKs, we don't do text updates on S60 side.
+ if (QSysInfo::s60Version() < QSysInfo::SV_S60_5_0) {
+ return;
+ }
+
+ // Don't be fooled (as I was) by the name of this enumeration.
+ // What it really does is tell the virtual keyboard UI that the text has been
+ // updated and it should be reflected in the internal display of the VK.
+ ReportAknEdStateEvent(QT_EAknCursorPositionChanged);
+}
+
+void QCoeFepInputContext::setFocusWidget(QWidget *w)
+{
+ commitCurrentString(true);
+
+ QInputContext::setFocusWidget(w);
+
+ updateHints(true);
+}
+
+void QCoeFepInputContext::widgetDestroyed(QWidget *w)
+{
+ // Make sure that the input capabilities of whatever new widget got focused are queried.
+ CCoeControl *ctrl = w->effectiveWinId();
+ if (ctrl->IsFocused()) {
+ queueInputCapabilitiesChanged();
+ }
+}
+
+QString QCoeFepInputContext::language()
+{
+ TLanguage lang = m_fepState->LocalLanguage();
+ const QByteArray localeName = qt_symbianLocaleName(lang);
+ if (!localeName.isEmpty()) {
+ return QString::fromLatin1(localeName);
+ } else {
+ return QString::fromLatin1("C");
+ }
+}
+
+bool QCoeFepInputContext::needsInputPanel()
+{
+ switch (QSysInfo::s60Version()) {
+ case QSysInfo::SV_S60_3_1:
+ case QSysInfo::SV_S60_3_2:
+ // There are no touch phones for pre-5.0 SDKs.
+ return false;
+#ifdef Q_CC_NOKIAX86
+ default:
+ // For emulator we assume that we need an input panel, since we can't
+ // separate between phone types.
+ return true;
+#else
+ case QSysInfo::SV_S60_5_0: {
+ // For SDK == 5.0, we need phone specific detection, since the HAL API
+ // is no good on most phones. However, all phones at the time of writing use the
+ // input panel, except N97 in landscape mode, but in this mode it refuses to bring
+ // up the panel anyway, so we don't have to care.
+ return true;
+ }
+ default:
+ // For unknown/newer types, we try to use the HAL API.
+ int keyboardEnabled;
+ int keyboardType;
+ int err[2];
+ err[0] = HAL::Get(HAL::EKeyboard, keyboardType);
+ err[1] = HAL::Get(HAL::EKeyboardState, keyboardEnabled);
+ if (err[0] == KErrNone && err[1] == KErrNone
+ && keyboardType != 0 && keyboardEnabled)
+ // Means that we have some sort of keyboard.
+ return false;
+
+ // Fall back to using the input panel.
+ return true;
+#endif // !Q_CC_NOKIAX86
+ }
+}
+
+bool QCoeFepInputContext::filterEvent(const QEvent *event)
+{
+ // The CloseSoftwareInputPanel event is not handled here, because the VK will automatically
+ // close when it discovers that the underlying widget does not have input capabilities.
+
+ if (!focusWidget())
+ return false;
+
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ // Alphanumeric keypad doesn't like it when we click and text is still getting displayed
+ // It ignores the mouse event, so we need to commit and send a selection event (which will get triggered
+ // after the commit)
+ if (!m_preeditString.isEmpty()) {
+ commitCurrentString(true);
+
+ int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+
+ QList<QInputMethodEvent::Attribute> selectAttributes;
+ selectAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos, 0, QVariant());
+ QInputMethodEvent selectEvent(QLatin1String(""), selectAttributes);
+ sendEvent(selectEvent);
+ }
+ break;
+ case QEvent::KeyPress:
+ commitTemporaryPreeditString();
+ // fall through intended
+ case QEvent::KeyRelease:
+ const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
+ //If proxy exists, always use hints from proxy.
+ QWidget *proxy = focusWidget()->focusProxy();
+ Qt::InputMethodHints currentHints = proxy ? proxy->inputMethodHints() : focusWidget()->inputMethodHints();
+
+ switch (keyEvent->key()) {
+ case Qt::Key_F20:
+ Q_ASSERT(m_lastImHints == currentHints);
+ if (m_lastImHints & Qt::ImhHiddenText) {
+ // Special case in Symbian. On editors with secret text, F20 is for some reason
+ // considered to be a backspace.
+ QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(),
+ keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count());
+ QApplication::sendEvent(focusWidget(), &modifiedEvent);
+ return true;
+ }
+ break;
+ case Qt::Key_Select:
+ if (!m_preeditString.isEmpty()) {
+ commitCurrentString(true);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ QString widgetText = focusWidget()->inputMethodQuery(Qt::ImSurroundingText).toString();
+ bool validLength;
+ int maxLength = focusWidget()->inputMethodQuery(Qt::ImMaximumTextLength).toInt(&validLength);
+ if (!keyEvent->text().isEmpty() && validLength
+ && widgetText.size() + m_preeditString.size() >= maxLength) {
+ // Don't send key events with string content if the widget is "full".
+ return true;
+ }
+
+ if (keyEvent->type() == QEvent::KeyPress
+ && currentHints & Qt::ImhHiddenText
+ && !keyEvent->text().isEmpty()) {
+ // Send some temporary preedit text in order to make text visible for a moment.
+ m_preeditString = keyEvent->text();
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent imEvent(m_preeditString, attributes);
+ sendEvent(imEvent);
+ m_tempPreeditStringTimeout.start(1000, this);
+ m_hasTempPreeditString = true;
+ update();
+ return true;
+ }
+ break;
+ }
+
+ if (!needsInputPanel())
+ return false;
+
+ if (event->type() == QEvent::RequestSoftwareInputPanel) {
+ // Notify S60 that we want the virtual keyboard to show up.
+ QSymbianControl *sControl;
+ sControl = focusWidget()->effectiveWinId()->MopGetObject(sControl);
+ Q_ASSERT(sControl);
+
+ // The FEP UI temporarily steals focus when it shows up the first time, causing
+ // all sorts of weird effects on the focused widgets. Since it will immediately give
+ // back focus to us, we temporarily disable focus handling until the job's done.
+ if (sControl) {
+ sControl->setIgnoreFocusChanged(true);
+ }
+
+ ensureInputCapabilitiesChanged();
+ m_fepState->ReportAknEdStateEventL(MAknEdStateObserver::QT_EAknActivatePenInputRequest);
+
+ if (sControl) {
+ sControl->setIgnoreFocusChanged(false);
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool QCoeFepInputContext::symbianFilterEvent(QWidget *keyWidget, const QSymbianEvent *event)
+{
+ Q_UNUSED(keyWidget);
+ if (event->type() == QSymbianEvent::CommandEvent)
+ // A command basically means the same as a button being pushed. With Qt buttons
+ // that would normally result in a reset of the input method due to the focus change.
+ // This should also happen for commands.
+ reset();
+
+ if (event->type() == QSymbianEvent::WindowServerEvent
+ && event->windowServerEvent()
+ && event->windowServerEvent()->Type() == EEventWindowVisibilityChanged
+ && S60->splitViewLastWidget) {
+
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(S60->splitViewLastWidget);
+ const bool alwaysResize = (gv && gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff);
+
+ if (alwaysResize) {
+ TUint visibleFlags = event->windowServerEvent()->VisibilityChanged()->iFlags;
+ if (visibleFlags & TWsVisibilityChangedEvent::EPartiallyVisible)
+ ensureFocusWidgetVisible(S60->splitViewLastWidget);
+ if (visibleFlags & TWsVisibilityChangedEvent::ENotVisible)
+ resetSplitViewWidget(true);
+ }
+ }
+
+ return false;
+}
+
+void QCoeFepInputContext::timerEvent(QTimerEvent *timerEvent)
+{
+ if (timerEvent->timerId() == m_tempPreeditStringTimeout.timerId())
+ commitTemporaryPreeditString();
+}
+
+void QCoeFepInputContext::commitTemporaryPreeditString()
+{
+ if (m_tempPreeditStringTimeout.isActive())
+ m_tempPreeditStringTimeout.stop();
+
+ if (!m_hasTempPreeditString)
+ return;
+
+ commitCurrentString(false);
+}
+
+void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event)
+{
+ Q_ASSERT(focusWidget());
+
+ if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) {
+ commitCurrentString(true);
+ int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos + x, 0, QVariant());
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ sendEvent(event);
+ }
+}
+
+TCoeInputCapabilities QCoeFepInputContext::inputCapabilities()
+{
+ if (m_inDestruction || !focusWidget()) {
+ return TCoeInputCapabilities(TCoeInputCapabilities::ENone, 0, 0);
+ }
+
+ return TCoeInputCapabilities(m_textCapabilities, this, 0);
+}
+
+void QCoeFepInputContext::resetSplitViewWidget(bool keepInputWidget)
+{
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(S60->splitViewLastWidget);
+
+ if (!gv) {
+ return;
+ }
+
+ QSymbianControl *symControl = static_cast<QSymbianControl*>(gv->effectiveWinId());
+ symControl->CancelLongTapTimer();
+
+ const bool alwaysResize = (gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff);
+ QWidget *windowToMove = gv->window();
+
+ bool userResize = gv->testAttribute(Qt::WA_Resized);
+
+ windowToMove->setUpdatesEnabled(false);
+
+ if (!alwaysResize) {
+ if (gv->scene()) {
+ if (gv->scene()->focusItem()) {
+ // Check if the widget contains cursorPositionChanged signal and disconnect from it.
+ QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged()));
+ int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1));
+ if (index != -1)
+ disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget()));
+ }
+
+ QGraphicsItem *rootItem = 0;
+ foreach (QGraphicsItem *item, gv->scene()->items()) {
+ if (!item->parentItem()) {
+ rootItem = item;
+ break;
+ }
+ }
+ if (rootItem)
+ rootItem->resetTransform();
+ }
+ } else {
+ if (m_splitViewResizeBy)
+ gv->resize(gv->rect().width(), m_splitViewResizeBy);
+ }
+ // Resizing might have led to widget losing its original windowstate.
+ // Restore previous window state.
+
+ if (m_splitViewPreviousWindowStates != windowToMove->windowState())
+ windowToMove->setWindowState(m_splitViewPreviousWindowStates);
+
+ windowToMove->setUpdatesEnabled(true);
+
+ gv->setAttribute(Qt::WA_Resized, userResize); //not a user resize
+
+ m_splitViewResizeBy = 0;
+ if (!keepInputWidget) {
+ m_splitViewPreviousWindowStates = Qt::WindowNoState;
+ S60->splitViewLastWidget = 0;
+ }
+}
+
+// Checks if a given widget is visible in the splitview rect. The offset
+// parameter can be used to validate if moving widget upwards or downwards
+// by the offset would make a difference for the visibility.
+
+bool QCoeFepInputContext::isWidgetVisible(QWidget *widget, int offset)
+{
+ bool visible = false;
+ if (widget) {
+ QRect splitViewRect = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+ QWidget *window = QApplication::activeWindow();
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(widget);
+ if (gv && window) {
+ if (QGraphicsScene *scene = gv->scene()) {
+ if (QGraphicsItem *focusItem = scene->focusItem()) {
+ QPoint cursorPos = window->mapToGlobal(focusItem->cursor().pos());
+ cursorPos.setY(cursorPos.y() + offset);
+ if (splitViewRect.contains(cursorPos)) {
+ visible = true;
+ }
+ }
+ }
+ }
+ }
+ return visible;
+}
+
+// Ensure that the input widget is visible in the splitview rect.
+
+void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget)
+{
+ // Native side opening and closing its virtual keyboard when it changes the keyboard layout,
+ // has an adverse impact on long tap timer. Cancel the timer when splitview opens to avoid this.
+ QSymbianControl *symControl = static_cast<QSymbianControl*>(widget->effectiveWinId());
+ symControl->CancelLongTapTimer();
+
+ // Graphicsviews that have vertical scrollbars should always be resized to the splitview area.
+ // Graphicsviews without scrollbars should be translated.
+
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(widget);
+ if (!gv)
+ return;
+
+ const bool alwaysResize = (gv && gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff);
+ const bool moveWithinVisibleArea = (S60->splitViewLastWidget != 0);
+
+ QWidget *windowToMove = gv ? gv : symControl->widget();
+ if (!windowToMove->isWindow())
+ windowToMove = windowToMove->window();
+ if (!windowToMove) {
+ return;
+ }
+
+ // When opening the keyboard (not moving within the splitview area), save the original
+ // window state. In some cases, ensuring input widget visibility might lead to window
+ // states getting changed.
+
+ if (!moveWithinVisibleArea) {
+ // Check if the widget contains cursorPositionChanged signal and connect to it.
+ QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged()));
+ if (gv->scene() && gv->scene()->focusItem()) {
+ int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1));
+ if (index != -1)
+ connect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget()));
+ }
+ S60->splitViewLastWidget = widget;
+ m_splitViewPreviousWindowStates = windowToMove->windowState();
+ }
+
+ int windowTop = widget->window()->pos().y();
+
+ const bool userResize = widget->testAttribute(Qt::WA_Resized);
+
+ QRect splitViewRect = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+
+
+ // When resizing a window widget, it will lose its maximized window state.
+ // Native applications hide statuspane in splitview state, so lets move to
+ // fullscreen mode. This makes available area slightly bigger, which helps usability
+ // and greatly reduces event passing in orientation switch cases,
+ // as the statuspane size is not changing.
+
+ if (alwaysResize)
+ windowToMove->setUpdatesEnabled(false);
+
+ if (!(windowToMove->windowState() & Qt::WindowFullScreen)) {
+ windowToMove->setWindowState(
+ (windowToMove->windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen)) | Qt::WindowFullScreen);
+ }
+
+ if (alwaysResize) {
+ if (!moveWithinVisibleArea) {
+ m_splitViewResizeBy = widget->height();
+ windowTop = widget->geometry().top();
+ widget->resize(widget->width(), splitViewRect.height() - windowTop);
+ }
+
+ if (gv->scene()) {
+ const QRectF microFocusRect = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+ gv->ensureVisible(microFocusRect);
+ }
+ } else {
+ translateInputWidget();
+ }
+
+ if (alwaysResize)
+ windowToMove->setUpdatesEnabled(true);
+
+ widget->setAttribute(Qt::WA_Resized, userResize); //not a user resize
+}
+
+static QTextCharFormat qt_TCharFormat2QTextCharFormat(const TCharFormat &cFormat, bool validStyleColor)
+{
+ QTextCharFormat qFormat;
+
+ if (validStyleColor) {
+ QBrush foreground(QColor(cFormat.iFontPresentation.iTextColor.Internal()));
+ qFormat.setForeground(foreground);
+ }
+
+ qFormat.setFontStrikeOut(cFormat.iFontPresentation.iStrikethrough == EStrikethroughOn);
+ qFormat.setFontUnderline(cFormat.iFontPresentation.iUnderline == EUnderlineOn);
+
+ return qFormat;
+}
+
+void QCoeFepInputContext::updateHints(bool mustUpdateInputCapabilities)
+{
+ QWidget *w = focusWidget();
+ if (w) {
+ QWidget *proxy = w->focusProxy();
+ Qt::InputMethodHints hints = proxy ? proxy->inputMethodHints() : w->inputMethodHints();
+
+ // Since splitview support works like an input method hint, yet it is private flag,
+ // we need to update its state separately.
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) {
+ TInt currentFlags = m_fepState->Flags();
+ if (S60->partial_keyboard)
+ currentFlags |= QT_EAknEditorFlagEnablePartialScreen;
+ else
+ currentFlags &= ~QT_EAknEditorFlagEnablePartialScreen;
+ if (currentFlags != m_fepState->Flags())
+ m_fepState->SetFlags(currentFlags);
+ }
+
+ if (hints != m_lastImHints) {
+ m_lastImHints = hints;
+ applyHints(hints);
+ } else if (!mustUpdateInputCapabilities) {
+ // Optimization. Return immediately if there was no change.
+ return;
+ }
+ }
+ queueInputCapabilitiesChanged();
+}
+
+void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints)
+{
+ using namespace Qt;
+
+ commitTemporaryPreeditString();
+
+ const bool anynumbermodes = hints & (ImhDigitsOnly | ImhFormattedNumbersOnly | ImhDialableCharactersOnly);
+ const bool anytextmodes = hints & (ImhUppercaseOnly | ImhLowercaseOnly | ImhEmailCharactersOnly | ImhUrlCharactersOnly);
+ const bool numbersOnly = anynumbermodes && !anytextmodes;
+ const bool noOnlys = !(hints & ImhExclusiveInputMask);
+ // if alphanumeric input, or if multiple incompatible number modes are selected;
+ // then make all symbols available in numeric mode too.
+ const bool needsCharMap= !numbersOnly || ((hints & ImhFormattedNumbersOnly) && (hints & ImhDialableCharactersOnly));
+ TInt flags;
+ Qt::InputMethodHints oldHints = hints;
+
+ // Some sanity checking. Make sure that only one preference is set.
+ InputMethodHints prefs = ImhPreferNumbers | ImhPreferUppercase | ImhPreferLowercase;
+ prefs &= hints;
+ if (prefs != ImhPreferNumbers && prefs != ImhPreferUppercase && prefs != ImhPreferLowercase) {
+ hints &= ~prefs;
+ }
+ if (!noOnlys) {
+ // Make sure that the preference is within the permitted set.
+ if (hints & ImhPreferNumbers && !anynumbermodes) {
+ hints &= ~ImhPreferNumbers;
+ } else if (hints & ImhPreferUppercase && !(hints & ImhUppercaseOnly)) {
+ hints &= ~ImhPreferUppercase;
+ } else if (hints & ImhPreferLowercase && !(hints & ImhLowercaseOnly)) {
+ hints &= ~ImhPreferLowercase;
+ }
+ // If there is no preference, set it to something within the permitted set.
+ if (!(hints & ImhPreferNumbers || hints & ImhPreferUppercase || hints & ImhPreferLowercase)) {
+ if (hints & ImhLowercaseOnly) {
+ hints |= ImhPreferLowercase;
+ } else if (hints & ImhUppercaseOnly) {
+ hints |= ImhPreferUppercase;
+ } else if (numbersOnly) {
+ hints |= ImhPreferNumbers;
+ }
+ }
+ }
+
+ if (hints & ImhPreferNumbers) {
+ m_fepState->SetDefaultInputMode(EAknEditorNumericInputMode);
+ m_fepState->SetCurrentInputMode(EAknEditorNumericInputMode);
+ } else {
+ m_fepState->SetDefaultInputMode(EAknEditorTextInputMode);
+ m_fepState->SetCurrentInputMode(EAknEditorTextInputMode);
+ }
+ flags = 0;
+ if (noOnlys || (anynumbermodes && anytextmodes)) {
+ flags = EAknEditorAllInputModes;
+ }
+ else if (anynumbermodes) {
+ flags |= EAknEditorNumericInputMode;
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0
+ && ((hints & ImhFormattedNumbersOnly) || (hints & ImhDialableCharactersOnly))) {
+ //workaround - the * key does not launch the symbols menu, making it impossible to use these modes unless text mode is enabled.
+ flags |= EAknEditorTextInputMode;
+ }
+ }
+ else if (anytextmodes) {
+ flags |= EAknEditorTextInputMode;
+ }
+ else {
+ flags = EAknEditorAllInputModes;
+ }
+ m_fepState->SetPermittedInputModes(flags);
+ ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateInputModeUpdate);
+
+ if (hints & ImhPreferLowercase) {
+ m_fepState->SetDefaultCase(EAknEditorLowerCase);
+ m_fepState->SetCurrentCase(EAknEditorLowerCase);
+ } else if (hints & ImhPreferUppercase) {
+ m_fepState->SetDefaultCase(EAknEditorUpperCase);
+ m_fepState->SetCurrentCase(EAknEditorUpperCase);
+ } else if (hints & ImhNoAutoUppercase) {
+ m_fepState->SetDefaultCase(EAknEditorLowerCase);
+ m_fepState->SetCurrentCase(EAknEditorLowerCase);
+ } else {
+ m_fepState->SetDefaultCase(EAknEditorTextCase);
+ m_fepState->SetCurrentCase(EAknEditorTextCase);
+ }
+ flags = 0;
+ if (hints & ImhUppercaseOnly) {
+ flags |= EAknEditorUpperCase;
+ }
+ if (hints & ImhLowercaseOnly) {
+ flags |= EAknEditorLowerCase;
+ }
+ if (flags == 0) {
+ flags = EAknEditorAllCaseModes;
+ if (hints & ImhNoAutoUppercase) {
+ flags &= ~EAknEditorTextCase;
+ }
+ }
+ m_fepState->SetPermittedCases(flags);
+ ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateCaseModeUpdate);
+
+ flags = 0;
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) {
+ if (S60->partial_keyboard)
+ flags |= QT_EAknEditorFlagEnablePartialScreen;
+ flags |= QT_EAknEditorFlagSelectionVisible;
+ }
+ if (hints & ImhUppercaseOnly && !(hints & ImhLowercaseOnly)
+ || hints & ImhLowercaseOnly && !(hints & ImhUppercaseOnly)) {
+ flags |= EAknEditorFlagFixedCase;
+ }
+ // Using T9 and hidden text together may actually crash the FEP, so check for hidden text too.
+ if (hints & ImhNoPredictiveText || hints & ImhHiddenText) {
+ flags |= EAknEditorFlagNoT9;
+ }
+ if (needsCharMap)
+ flags |= EAknEditorFlagUseSCTNumericCharmap;
+ m_fepState->SetFlags(flags);
+ ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateFlagsUpdate);
+
+ if (hints & ImhDialableCharactersOnly) {
+ // This is first, because if (ImhDialableCharactersOnly | ImhFormattedNumbersOnly)
+ // is specified, this one is more natural (# key enters a #)
+ flags = EAknEditorStandardNumberModeKeymap;
+ } else if (hints & ImhFormattedNumbersOnly) {
+ // # key enters decimal point
+ flags = EAknEditorCalculatorNumberModeKeymap;
+ } else if (hints & ImhDigitsOnly) {
+ // This is last, because it is most restrictive (# key is inactive)
+ flags = EAknEditorPlainNumberModeKeymap;
+ } else {
+ flags = EAknEditorStandardNumberModeKeymap;
+ }
+ m_fepState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(flags));
+
+ if (hints & ImhUrlCharactersOnly) {
+ // URL characters is everything except space, so a superset of the other restrictions
+ m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_URL_SPECIAL_CHARACTER_TABLE_DIALOG);
+ } else if (hints & ImhEmailCharactersOnly) {
+ m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_EMAIL_ADDR_SPECIAL_CHARACTER_TABLE_DIALOG);
+ } else if (needsCharMap) {
+ m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG);
+ } else if ((hints & ImhFormattedNumbersOnly) || (hints & ImhDialableCharactersOnly)) {
+ m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG);
+ } else {
+ m_fepState->SetSpecialCharacterTableResourceId(0);
+ }
+
+ if (hints & ImhHiddenText) {
+ m_textCapabilities = TCoeInputCapabilities::EAllText | TCoeInputCapabilities::ESecretText;
+ } else {
+ m_textCapabilities = TCoeInputCapabilities::EAllText;
+ }
+}
+
+void QCoeFepInputContext::applyFormat(QList<QInputMethodEvent::Attribute> *attributes)
+{
+ TCharFormat cFormat;
+ QColor styleTextColor;
+ if (QWidget *focused = focusWidget()) {
+ QGraphicsView *gv = qobject_cast<QGraphicsView*>(focused);
+ if (!gv) // could be either the QGV or its viewport that has focus
+ gv = qobject_cast<QGraphicsView*>(focused->parentWidget());
+ if (gv) {
+ if (QGraphicsScene *scene = gv->scene()) {
+ if (QGraphicsItem *focusItem = scene->focusItem()) {
+ if (focusItem->isWidget()) {
+ styleTextColor = static_cast<QGraphicsWidget*>(focusItem)->palette().text().color();
+ }
+ }
+ }
+ } else {
+ styleTextColor = focused->palette().text().color();
+ }
+ } else {
+ styleTextColor = QApplication::palette("QLineEdit").text().color();
+ }
+
+ if (styleTextColor.isValid()) {
+ const TLogicalRgb fontColor(TRgb(styleTextColor.red(), styleTextColor.green(), styleTextColor.blue(), styleTextColor.alpha()));
+ cFormat.iFontPresentation.iTextColor = fontColor;
+ }
+
+ TInt numChars = 0;
+ TInt charPos = 0;
+ int oldSize = attributes->size();
+ while (m_formatRetriever) {
+ m_formatRetriever->GetFormatOfFepInlineText(cFormat, numChars, charPos);
+ if (numChars <= 0) {
+ // This shouldn't happen according to S60 docs, but apparently does sometimes.
+ break;
+ }
+ attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ charPos,
+ numChars,
+ QVariant(qt_TCharFormat2QTextCharFormat(cFormat, styleTextColor.isValid()))));
+ charPos += numChars;
+ if (charPos >= m_preeditString.size()) {
+ break;
+ }
+ }
+
+ if (attributes->size() == oldSize) {
+ // S60 didn't provide any format, so let's give our own instead.
+ attributes->append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ 0,
+ m_preeditString.size(),
+ standardFormat(PreeditFormat)));
+ }
+}
+
+void QCoeFepInputContext::queueInputCapabilitiesChanged()
+{
+ if (m_pendingInputCapabilitiesChanged)
+ return;
+
+ // Call ensureInputCapabilitiesChanged asynchronously. This is done to improve performance
+ // by not updating input capabilities too often. The reason we don't call the Symbian
+ // asynchronous version of InputCapabilitiesChanged is because we need to ensure that it
+ // is synchronous in some specific cases. Those will call ensureInputCapabilitesChanged.
+ QMetaObject::invokeMethod(this, "ensureInputCapabilitiesChanged", Qt::QueuedConnection);
+ m_pendingInputCapabilitiesChanged = true;
+}
+
+void QCoeFepInputContext::ensureInputCapabilitiesChanged()
+{
+ if (!m_pendingInputCapabilitiesChanged)
+ return;
+
+ // The call below is essentially equivalent to InputCapabilitiesChanged(),
+ // but is synchronous, rather than asynchronous.
+ CCoeEnv::Static()->SyncNotifyFocusObserversOfChangeInFocus();
+ m_pendingInputCapabilitiesChanged = false;
+}
+
+void QCoeFepInputContext::translateInputWidget()
+{
+ QGraphicsView *gv = qobject_cast<QGraphicsView *>(S60->splitViewLastWidget);
+ QRect splitViewRect = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+
+ QRectF cursor = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF();
+ QPolygon cursorP = gv->mapFromScene(cursor);
+ QRectF vkbRect = QRectF(splitViewRect.bottomLeft(), qApp->desktop()->rect().bottomRight());
+ if (cursor.isEmpty() || vkbRect.isEmpty())
+ return;
+
+ // Fetch root item (i.e. graphicsitem with no parent)
+ QGraphicsItem *rootItem = 0;
+ foreach (QGraphicsItem *item, gv->scene()->items()) {
+ if (!item->parentItem()) {
+ rootItem = item;
+ break;
+ }
+ }
+ if (!rootItem)
+ return;
+
+ m_transformation = (rootItem->transform().isTranslating()) ? QRectF(0,0, gv->width(), rootItem->transform().dy()) : QRectF();
+
+ // Do nothing if the cursor is visible in the splitview area.
+ if (splitViewRect.contains(cursorP.boundingRect()))
+ return;
+
+ // New Y position should be ideally at the center of the splitview area.
+ // If that would expose unpainted canvas, limit the tranformation to the visible scene bottom.
+
+ const qreal maxY = gv->sceneRect().bottom() - splitViewRect.bottom() + m_transformation.height();
+ qreal dy = -(qMin(maxY, (cursor.bottom() - vkbRect.top() / 2)));
+
+ // Do not allow transform above screen top.
+ if (m_transformation.height() + dy > 0)
+ return;
+
+ rootItem->setTransform(QTransform::fromTranslate(0, dy), true);
+}
+
+void QCoeFepInputContext::StartFepInlineEditL(const TDesC& aInitialInlineText,
+ TInt aPositionOfInsertionPointInInlineText, TBool aCursorVisibility, const MFormCustomDraw* /*aCustomDraw*/,
+ MFepInlineTextFormatRetriever& aInlineTextFormatRetriever,
+ MFepPointerEventHandlerDuringInlineEdit& aPointerEventHandlerDuringInlineEdit)
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ commitTemporaryPreeditString();
+
+ QList<QInputMethodEvent::Attribute> attributes;
+
+ m_cursorVisibility = aCursorVisibility ? 1 : 0;
+ m_inlinePosition = aPositionOfInsertionPointInInlineText;
+ m_preeditString = qt_TDesC2QString(aInitialInlineText);
+
+ m_formatRetriever = &aInlineTextFormatRetriever;
+ m_pointerHandler = &aPointerEventHandlerDuringInlineEdit;
+
+ // With T9 aInitialInlineText is typically empty when StartFepInlineEditL is called,
+ // but FEP requires that selected text is always removed at StartFepInlineEditL.
+ // Let's remove the selected text if aInitialInlineText is empty and there is selected text
+ if (m_preeditString.isEmpty()) {
+ int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt();
+ int cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt();
+ int replacementLength = qAbs(cursorPos-anchor);
+ if (replacementLength > 0) {
+ int replacementStart = cursorPos < anchor ? 0 : -replacementLength;
+ QList<QInputMethodEvent::Attribute> clearSelectionAttributes;
+ QInputMethodEvent clearSelectionEvent(QLatin1String(""), clearSelectionAttributes);
+ clearSelectionEvent.setCommitString(QLatin1String(""), replacementStart, replacementLength);
+ sendEvent(clearSelectionEvent);
+ }
+ }
+
+ applyFormat(&attributes);
+
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
+ m_inlinePosition,
+ m_cursorVisibility,
+ QVariant()));
+ QInputMethodEvent event(m_preeditString, attributes);
+ sendEvent(event);
+}
+
+void QCoeFepInputContext::UpdateFepInlineTextL(const TDesC& aNewInlineText,
+ TInt aPositionOfInsertionPointInInlineText)
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ commitTemporaryPreeditString();
+
+ m_inlinePosition = aPositionOfInsertionPointInInlineText;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ applyFormat(&attributes);
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
+ m_inlinePosition,
+ m_cursorVisibility,
+ QVariant()));
+ QString newPreeditString = qt_TDesC2QString(aNewInlineText);
+ QInputMethodEvent event(newPreeditString, attributes);
+ if (newPreeditString.isEmpty() && m_preeditString.isEmpty()) {
+ // In Symbian world this means "erase last character".
+ event.setCommitString(QLatin1String(""), -1, 1);
+ }
+ m_preeditString = newPreeditString;
+ sendEvent(event);
+}
+
+void QCoeFepInputContext::SetInlineEditingCursorVisibilityL(TBool aCursorVisibility)
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ m_cursorVisibility = aCursorVisibility ? 1 : 0;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
+ m_inlinePosition,
+ m_cursorVisibility,
+ QVariant()));
+ QInputMethodEvent event(m_preeditString, attributes);
+ sendEvent(event);
+}
+
+void QCoeFepInputContext::CancelFepInlineEdit()
+{
+ // We are not supposed to ever have a tempPreeditString and a real preedit string
+ // from S60 at the same time, so it should be safe to rely on this test to determine
+ // whether we should honor S60's request to clear the text or not.
+ if (m_hasTempPreeditString)
+ return;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(QLatin1String(""), 0, 0);
+ m_preeditString.clear();
+ m_inlinePosition = 0;
+ sendEvent(event);
+}
+
+TInt QCoeFepInputContext::DocumentLengthForFep() const
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return 0;
+
+ QVariant variant = w->inputMethodQuery(Qt::ImSurroundingText);
+ return variant.value<QString>().size() + m_preeditString.size();
+}
+
+TInt QCoeFepInputContext::DocumentMaximumLengthForFep() const
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return 0;
+
+ QVariant variant = w->inputMethodQuery(Qt::ImMaximumTextLength);
+ int size;
+ if (variant.isValid()) {
+ size = variant.toInt();
+ } else {
+ size = INT_MAX; // Sensible default for S60.
+ }
+ return size;
+}
+
+void QCoeFepInputContext::SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection)
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ commitTemporaryPreeditString();
+
+ int pos = aCursorSelection.iAnchorPos;
+ int length = aCursorSelection.iCursorPos - pos;
+
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos, length, QVariant());
+ QInputMethodEvent event(m_preeditString, attributes);
+ sendEvent(event);
+}
+
+void QCoeFepInputContext::GetCursorSelectionForFep(TCursorSelection& aCursorSelection) const
+{
+ QWidget *w = focusWidget();
+ if (!w) {
+ aCursorSelection.SetSelection(0,0);
+ return;
+ }
+
+ int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + m_preeditString.size();
+ int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt() + m_preeditString.size();
+ QString text = w->inputMethodQuery(Qt::ImSurroundingText).value<QString>();
+ int combinedSize = text.size() + m_preeditString.size();
+ if (combinedSize < anchor || combinedSize < cursor) {
+ // ### TODO! FIXME! QTBUG-5050
+ // This is a hack to prevent crashing in 4.6 with QLineEdits that use input masks.
+ // The root problem is that cursor position is relative to displayed text instead of the
+ // actual text we get.
+ //
+ // To properly fix this we would need to know the displayText of QLineEdits instead
+ // of just the text, which on itself should be a trivial change. The difficulties start
+ // when we need to commit the changes back to the QLineEdit, which would have to be somehow
+ // able to handle displayText, too.
+ //
+ // Until properly fixed, the cursor and anchor positions will not reflect correct positions
+ // for masked QLineEdits, unless all the masked positions are filled in order so that
+ // cursor position relative to the displayed text matches position relative to actual text.
+ aCursorSelection.iAnchorPos = combinedSize;
+ aCursorSelection.iCursorPos = combinedSize;
+ } else {
+ aCursorSelection.iAnchorPos = anchor;
+ aCursorSelection.iCursorPos = cursor;
+ }
+}
+
+void QCoeFepInputContext::GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition,
+ TInt aLengthToRetrieve) const
+{
+ QWidget *w = focusWidget();
+ if (!w) {
+ aEditorContent.FillZ(aLengthToRetrieve);
+ return;
+ }
+
+ QString text = w->inputMethodQuery(Qt::ImSurroundingText).value<QString>();
+ // FEP expects the preedit string to be part of the editor content, so let's mix it in.
+ int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt();
+ text.insert(cursor, m_preeditString);
+ aEditorContent.Copy(qt_QString2TPtrC(text.mid(aDocumentPosition, aLengthToRetrieve)));
+}
+
+void QCoeFepInputContext::GetFormatForFep(TCharFormat& aFormat, TInt /* aDocumentPosition */) const
+{
+ QWidget *w = focusWidget();
+ if (!w) {
+ aFormat = TCharFormat();
+ return;
+ }
+
+ QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>();
+ QFontMetrics metrics(font);
+ //QString name = font.rawName();
+ QString name = font.defaultFamily(); // TODO! FIXME! Should be the above.
+ QHBufC hBufC(name);
+ aFormat = TCharFormat(hBufC->Des(), metrics.height());
+}
+
+void QCoeFepInputContext::GetScreenCoordinatesForFepL(TPoint& aLeftSideOfBaseLine, TInt& aHeight,
+ TInt& aAscent, TInt /* aDocumentPosition */) const
+{
+ QWidget *w = focusWidget();
+ if (!w) {
+ aLeftSideOfBaseLine = TPoint(0,0);
+ aHeight = 0;
+ aAscent = 0;
+ return;
+ }
+
+ QRect rect = w->inputMethodQuery(Qt::ImMicroFocus).value<QRect>();
+ aLeftSideOfBaseLine.iX = rect.left();
+ aLeftSideOfBaseLine.iY = rect.bottom();
+
+ QFont font = w->inputMethodQuery(Qt::ImFont).value<QFont>();
+ QFontMetrics metrics(font);
+ aHeight = metrics.height();
+ aAscent = metrics.ascent();
+}
+
+void QCoeFepInputContext::DoCommitFepInlineEditL()
+{
+ commitCurrentString(false);
+ if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0)
+ ReportAknEdStateEvent(QT_EAknCursorPositionChanged);
+
+}
+
+void QCoeFepInputContext::commitCurrentString(bool cancelFepTransaction)
+{
+ QList<QInputMethodEvent::Attribute> attributes;
+ QInputMethodEvent event(QLatin1String(""), attributes);
+ event.setCommitString(m_preeditString, 0, 0);
+ m_preeditString.clear();
+ m_inlinePosition = 0;
+ sendEvent(event);
+
+ m_hasTempPreeditString = false;
+
+ if (cancelFepTransaction) {
+ CCoeFep* fep = CCoeEnv::Static()->Fep();
+ if (fep)
+ fep->CancelTransaction();
+ }
+}
+
+MCoeFepAwareTextEditor_Extension1* QCoeFepInputContext::Extension1(TBool& aSetToTrue)
+{
+ aSetToTrue = ETrue;
+ return this;
+}
+
+void QCoeFepInputContext::SetStateTransferingOwnershipL(MCoeFepAwareTextEditor_Extension1::CState* aState,
+ TUid /*aTypeSafetyUid*/)
+{
+ // Note: The S60 docs are wrong! See the State() function.
+ if (m_fepState)
+ delete m_fepState;
+ m_fepState = static_cast<CAknEdwinState *>(aState);
+}
+
+MCoeFepAwareTextEditor_Extension1::CState* QCoeFepInputContext::State(TUid /*aTypeSafetyUid*/)
+{
+ // Note: The S60 docs are horribly wrong when describing the
+ // SetStateTransferingOwnershipL function and this function. They say that the former
+ // sets a CState object identified by the TUid, and the latter retrieves it.
+ // In reality, the CState is expected to always be a CAknEdwinState (even if it was not
+ // previously set), and the TUid is ignored. All in all, there is a single CAknEdwinState
+ // per QCoeFepInputContext, which should be deleted if the SetStateTransferingOwnershipL
+ // function is used to set a new one.
+ return m_fepState;
+}
+
+TTypeUid::Ptr QCoeFepInputContext::MopSupplyObject(TTypeUid /*id*/)
+{
+ return TTypeUid::Null();
+}
+
+MObjectProvider *QCoeFepInputContext::MopNext()
+{
+ QWidget *w = focusWidget();
+ if (w)
+ return w->effectiveWinId();
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_IM
diff --git a/src/gui/inputmethod/qinputcontext.cpp b/src/gui/inputmethod/qinputcontext.cpp
new file mode 100644
index 0000000000..f083e51981
--- /dev/null
+++ b/src/gui/inputmethod/qinputcontext.cpp
@@ -0,0 +1,500 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Implementation of QInputContext class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+//#define QT_NO_IM_PREEDIT_RELOCATION
+
+#include "qinputcontext.h"
+#include "qinputcontext_p.h"
+
+#ifndef QT_NO_IM
+
+#include "qplatformdefs.h"
+
+#include "qapplication.h"
+#include "qmenu.h"
+#include "qtextformat.h"
+#include "qpalette.h"
+
+#include <stdlib.h>
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QInputContext
+ \brief The QInputContext class abstracts the input method dependent data and composing state.
+
+ \ingroup i18n
+
+ An input method is responsible for inputting complex text that cannot
+ be inputted via simple keymap. It converts a sequence of input
+ events (typically key events) into a text string through the input
+ method specific converting process. The class of the processes are
+ widely ranging from simple finite state machine to complex text
+ translator that pools a whole paragraph of a text with text
+ editing capability to perform grammar and semantic analysis.
+
+ To abstract such different input method specific intermediate
+ information, Qt offers the QInputContext as base class. The
+ concept is well known as 'input context' in the input method
+ domain. An input context is created for a text widget in response
+ to a demand. It is ensured that an input context is prepared for
+ an input method before input to a text widget.
+
+ Multiple input contexts that belong to a single input method
+ may concurrently coexist. Suppose multi-window text editor. Each
+ text widget of window A and B holds different QInputContext
+ instance which contains different state information such as
+ partially composed text.
+
+ \section1 Groups of Functions
+
+ \table
+ \header \o Context \o Functions
+
+ \row \o Receiving information \o
+ x11FilterEvent(),
+ filterEvent(),
+ mouseHandler()
+
+ \row \o Sending back composed text \o
+ sendEvent()
+
+ \row \o State change notification \o
+ setFocusWidget(),
+ reset()
+
+ \row \o Context information \o
+ identifierName(),
+ language(),
+ font(),
+ isComposing()
+
+ \endtable
+
+ \section1 Licensing Information
+
+ \legalese
+ Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+
+ This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+ license. You may use this file under your Qt license. Following
+ description is copied from their original file headers. Contact
+ immodule-qt@freedesktop.org if any conditions of this licensing are
+ not clear to you.
+ \endlegalese
+
+ \sa QInputContextPlugin, QInputContextFactory, QApplication::setInputContext()
+*/
+
+/*!
+ Constructs an input context with the given \a parent.
+*/
+QInputContext::QInputContext(QObject* parent)
+ : QObject(*new QInputContextPrivate, parent)
+{
+}
+
+
+/*!
+ Destroys the input context.
+*/
+QInputContext::~QInputContext()
+{
+}
+
+/*!
+ Returns the widget that has an input focus for this input
+ context.
+
+ The return value may differ from holderWidget() if the input
+ context is shared between several text widgets.
+
+ \warning To ensure platform independence and support flexible
+ configuration of widgets, ordinary input methods should not call
+ this function directly.
+
+ \sa setFocusWidget()
+*/
+QWidget *QInputContext::focusWidget() const
+{
+ Q_D(const QInputContext);
+ return d->focusWidget;
+}
+
+
+/*!
+ Sets the \a widget that has an input focus for this input context.
+
+ \warning Ordinary input methods must not call this function
+ directly.
+
+ \sa focusWidget()
+*/
+void QInputContext::setFocusWidget(QWidget *widget)
+{
+ Q_ASSERT(!widget || widget->testAttribute(Qt::WA_InputMethodEnabled));
+ Q_D(QInputContext);
+ d->focusWidget = widget;
+}
+
+/*!
+ \fn bool QInputContext::isComposing() const
+
+ This function indicates whether InputMethodStart event had been
+ sent to the current focus widget. It is ensured that an input
+ context can send InputMethodCompose or InputMethodEnd event safely
+ if this function returned true.
+
+ The state is automatically being tracked through sendEvent().
+
+ \sa sendEvent()
+*/
+
+/*!
+ This function can be reimplemented in a subclass to filter input
+ events.
+
+ Return true if the \a event has been consumed. Otherwise, the
+ unfiltered \a event will be forwarded to widgets as ordinary
+ way. Although the input events have accept() and ignore()
+ methods, leave it untouched.
+
+ \a event is currently restricted to events of these types:
+
+ \list
+ \i CloseSoftwareInputPanel
+ \i KeyPress
+ \i KeyRelease
+ \i MouseButtonDblClick
+ \i MouseButtonPress
+ \i MouseButtonRelease
+ \i MouseMove
+ \i RequestSoftwareInputPanel
+ \endlist
+
+ But some input method related events such as QWheelEvent or
+ QTabletEvent may be added in future.
+
+ The filtering opportunity is always given to the input context as
+ soon as possible. It has to be taken place before any other key
+ event consumers such as eventfilters and accelerators because some
+ input methods require quite various key combination and
+ sequences. It often conflicts with accelerators and so on, so we
+ must give the input context the filtering opportunity first to
+ ensure all input methods work properly regardless of application
+ design.
+
+ Ordinary input methods require discrete key events to work
+ properly, so Qt's key compression is always disabled for any input
+ contexts.
+
+ \sa QKeyEvent, x11FilterEvent()
+*/
+bool QInputContext::filterEvent(const QEvent * /*event*/)
+{
+ return false;
+}
+
+/*!
+ Sends an input method event specified by \a event to the current focus
+ widget. Implementations of QInputContext should call this method to
+ send the generated input method events and not
+ QApplication::sendEvent(), as the events might have to get dispatched
+ to a different application on some platforms.
+
+ Some complex input methods route the handling to several child
+ contexts (e.g. to enable language switching). To account for this,
+ QInputContext will check if the parent object is a QInputContext. If
+ yes, it will call the parents sendEvent() implementation instead of
+ sending the event directly.
+
+ \sa QInputMethodEvent
+*/
+void QInputContext::sendEvent(const QInputMethodEvent &event)
+{
+ // route events over input context parents to make chaining possible.
+ QInputContext *p = qobject_cast<QInputContext *>(parent());
+ if (p) {
+ p->sendEvent(event);
+ return;
+ }
+
+ QWidget *focus = focusWidget();
+ if (!focus)
+ return;
+
+ QInputMethodEvent e(event);
+ QApplication::sendEvent(focus, &e);
+}
+
+
+/*!
+ This function can be reimplemented in a subclass to handle mouse
+ press, release, double-click, and move events within the preedit
+ text. You can use the function to implement mouse-oriented user
+ interface such as text selection or popup menu for candidate
+ selection.
+
+ The \a x parameter is the offset within the string that was sent
+ with the InputMethodCompose event. The alteration boundary of \a
+ x is ensured as character boundary of preedit string accurately.
+
+ The \a event parameter is the event that was sent to the editor
+ widget. The event type is QEvent::MouseButtonPress,
+ QEvent::MouseButtonRelease, QEvent::MouseButtonDblClick or
+ QEvent::MouseMove. The event's button and state indicate
+ the kind of operation that was performed.
+*/
+void QInputContext::mouseHandler(int /*x*/, QMouseEvent *event)
+{
+ // Default behavior for simple ephemeral input contexts. Some
+ // complex input contexts should not be reset here.
+ if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick)
+ reset();
+}
+
+
+/*!
+ Returns the font of the current input widget
+*/
+QFont QInputContext::font() const
+{
+ Q_D(const QInputContext);
+ if (!d->focusWidget)
+ return QApplication::font();
+
+ return qvariant_cast<QFont>(d->focusWidget->inputMethodQuery(Qt::ImFont));
+}
+
+/*!
+ This virtual function is called when a state in the focus widget
+ has changed. QInputContext can then use
+ QWidget::inputMethodQuery() to query the new state of the widget.
+*/
+void QInputContext::update()
+{
+}
+
+/*!
+ This virtual function is called when the specified \a widget is
+ destroyed. The \a widget is a widget on which this input context
+ is installed.
+*/
+void QInputContext::widgetDestroyed(QWidget *widget)
+{
+ Q_D(QInputContext);
+ if (widget == d->focusWidget)
+ setFocusWidget(0);
+}
+
+/*!
+ \fn void QInputContext::reset()
+
+ This function can be reimplemented in a subclass to reset the
+ state of the input method.
+
+ This function is called by several widgets to reset input
+ state. For example, a text widget call this function before
+ inserting a text to make widget ready to accept a text.
+
+ Default implementation is sufficient for simple input method. You
+ can override this function to reset external input method engines
+ in complex input method. In the case, call QInputContext::reset()
+ to ensure proper termination of inputting.
+
+ In a reimplementation of reset(), you must not send any
+ QInputMethodEvent containing preedit text. You can only commit
+ string and attributes; otherwise, you risk breaking input state
+ consistency.
+*/
+
+
+/*!
+ \fn QString QInputContext::identifierName()
+
+ This function must be implemented in any subclasses to return the
+ identifier name of the input method.
+
+ Return value is the name to identify and specify input methods for
+ the input method switching mechanism and so on. The name has to be
+ consistent with QInputContextPlugin::keys(). The name has to
+ consist of ASCII characters only.
+
+ There are two different names with different responsibility in the
+ input method domain. This function returns one of them. Another
+ name is called 'display name' that stands for the name for
+ endusers appeared in a menu and so on.
+
+ \sa QInputContextPlugin::keys(), QInputContextPlugin::displayName()
+*/
+
+
+/*!
+ \fn QString QInputContext::language()
+
+ This function must be implemented in any subclasses to return a
+ language code (e.g. "zh_CN", "zh_TW", "zh_HK", "ja", "ko", ...)
+ of the input context. If the input context can handle multiple
+ languages, return the currently used one. The name has to be
+ consistent with QInputContextPlugin::language().
+
+ This information will be used by language tagging feature in
+ QInputMethodEvent. It is required to distinguish unified han characters
+ correctly. It enables proper font and character code
+ handling. Suppose CJK-awared multilingual web browser
+ (that automatically modifies fonts in CJK-mixed text) and XML editor
+ (that automatically inserts lang attr).
+*/
+
+
+/*!
+ This is a preliminary interface for Qt 4.
+*/
+QList<QAction *> QInputContext::actions()
+{
+ return QList<QAction *>();
+}
+
+/*!
+ \enum QInputContext::StandardFormat
+
+ \value PreeditFormat The preedit text.
+ \value SelectionFormat The selection text.
+
+ \sa standardFormat()
+*/
+
+/*!
+ Returns a QTextFormat object that specifies the format for
+ component \a s.
+*/
+QTextFormat QInputContext::standardFormat(StandardFormat s) const
+{
+ QWidget *focus = focusWidget();
+ const QPalette &pal = focus ? focus->palette() : QApplication::palette();
+
+ QTextCharFormat fmt;
+ QColor bg;
+ switch (s) {
+ case QInputContext::PreeditFormat: {
+ fmt.setUnderlineStyle(QTextCharFormat::DashUnderline);
+ break;
+ }
+ case QInputContext::SelectionFormat: {
+ bg = pal.text().color();
+ fmt.setBackground(QBrush(bg));
+ fmt.setForeground(pal.background());
+ break;
+ }
+ }
+ return fmt;
+}
+
+#ifdef Q_WS_X11
+/*!
+ This function may be overridden only if input method is depending
+ on X11 and you need raw XEvent. Otherwise, this function must not.
+
+ This function is designed to filter raw key events for XIM, but
+ other input methods may use this to implement some special
+ features such as distinguishing Shift_L and Shift_R.
+
+ Return true if the \a event has been consumed. Otherwise, the
+ unfiltered \a event will be translated into QEvent and forwarded
+ to filterEvent(). Filtering at both x11FilterEvent() and
+ filterEvent() in single input method is allowed.
+
+ \a keywidget is a client widget into which a text is inputted. \a
+ event is inputted XEvent.
+
+ \sa filterEvent()
+*/
+bool QInputContext::x11FilterEvent(QWidget * /*keywidget*/, XEvent * /*event*/)
+{
+ return false;
+}
+#endif // Q_WS_X11
+
+#ifdef Q_OS_SYMBIAN
+/*!
+ \since 4.6
+
+ This function may be overridden only if input method is depending
+ on Symbian and you need raw Symbian events. Otherwise, this function must not.
+
+ This function is designed to filter raw key events on Symbian, but
+ other input methods may use this to implement some special
+ features.
+
+ Return true if the \a event has been consumed. Otherwise, the
+ unfiltered \a event will be translated into QEvent and forwarded
+ to filterEvent(). Filtering at both symbianFilterEvent() and
+ filterEvent() in single input method is allowed.
+
+ \a keywidget is a client widget into which a text is inputted. \a
+ event is inputted QSymbianEvent.
+
+ \sa filterEvent()
+*/
+bool QInputContext::symbianFilterEvent(QWidget * /*keywidget*/, const QSymbianEvent * /*event*/)
+{
+ return false;
+}
+#endif // Q_OS_SYMBIAN
+
+QT_END_NAMESPACE
+
+#endif //Q_NO_IM
diff --git a/src/gui/inputmethod/qinputcontext.h b/src/gui/inputmethod/qinputcontext.h
new file mode 100644
index 0000000000..089e6cdb9a
--- /dev/null
+++ b/src/gui/inputmethod/qinputcontext.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Definition of QInputContext class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#ifndef QINPUTCONTEXT_H
+#define QINPUTCONTEXT_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtGui/qevent.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+#include <QtGui/qaction.h>
+
+#ifndef QT_NO_IM
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QWidget;
+class QFont;
+class QPopupMenu;
+class QInputContextPrivate;
+#ifdef Q_OS_SYMBIAN
+class QSymbianEvent;
+#endif
+
+class Q_GUI_EXPORT QInputContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QInputContext)
+public:
+ explicit QInputContext(QObject* parent = 0);
+ virtual ~QInputContext();
+
+ virtual QString identifierName() = 0;
+ virtual QString language() = 0;
+
+ virtual void reset() = 0;
+ virtual void update();
+
+ virtual void mouseHandler( int x, QMouseEvent *event);
+ virtual QFont font() const;
+ virtual bool isComposing() const = 0;
+
+ QWidget *focusWidget() const;
+ virtual void setFocusWidget( QWidget *w );
+
+ virtual void widgetDestroyed(QWidget *w);
+
+ virtual QList<QAction *> actions();
+
+#if defined(Q_WS_X11)
+ virtual bool x11FilterEvent( QWidget *keywidget, XEvent *event );
+#endif // Q_WS_X11
+#if defined(Q_OS_SYMBIAN)
+ virtual bool symbianFilterEvent( QWidget *keywidget, const QSymbianEvent *event );
+#endif // Q_OS_SYMBIAN
+ virtual bool filterEvent( const QEvent *event );
+
+ void sendEvent(const QInputMethodEvent &event);
+
+ enum StandardFormat {
+ PreeditFormat,
+ SelectionFormat
+ };
+ QTextFormat standardFormat(StandardFormat s) const;
+private:
+ friend class QWidget;
+ friend class QWidgetPrivate;
+ friend class QInputContextFactory;
+ friend class QApplication;
+private: // Disabled copy constructor and operator=
+ QInputContext( const QInputContext & );
+ QInputContext &operator=( const QInputContext & );
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif //Q_NO_IM
+
+#endif // QINPUTCONTEXT_H
diff --git a/src/gui/inputmethod/qinputcontext_p.h b/src/gui/inputmethod/qinputcontext_p.h
new file mode 100644
index 0000000000..be4c141d05
--- /dev/null
+++ b/src/gui/inputmethod/qinputcontext_p.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+/****************************************************************************
+**
+** Implementation of QInputContext class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#ifndef QINPUTCONTEXT_P_H
+#define QINPUTCONTEXT_P_H
+
+#include "private/qobject_p.h"
+#include "qwidget.h"
+#include "qinputcontext.h"
+
+#ifndef QT_NO_IM
+
+QT_BEGIN_NAMESPACE
+
+class QInputContextPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QInputContext)
+public:
+ QInputContextPrivate()
+ : focusWidget(0)
+ {}
+
+ QWidget *focusWidget;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
+#endif
+
diff --git a/src/gui/inputmethod/qinputcontextfactory.cpp b/src/gui/inputmethod/qinputcontextfactory.cpp
new file mode 100644
index 0000000000..636e9d5c52
--- /dev/null
+++ b/src/gui/inputmethod/qinputcontextfactory.cpp
@@ -0,0 +1,354 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Implementation of QInputContextFactory class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#include "qinputcontextfactory.h"
+
+#ifndef QT_NO_IM
+
+#include "qcoreapplication.h"
+#include "qinputcontext.h"
+#include "qinputcontextplugin.h"
+
+#ifdef Q_WS_X11
+#include "private/qt_x11_p.h"
+#include "qximinputcontext_p.h"
+#endif
+#ifdef Q_WS_WIN
+#include "qwininputcontext_p.h"
+#endif
+#ifdef Q_WS_MAC
+#include "qmacinputcontext_p.h"
+#endif
+#ifdef Q_WS_S60
+#include "qcoefepinputcontext_p.h"
+#include "AknInputLanguageInfo.h"
+#endif
+
+#include "private/qfactoryloader_p.h"
+#include "qmutex.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QInputContextFactoryInterface_iid, QLatin1String("/inputmethods")))
+#endif
+
+/*!
+ \class QInputContextFactory
+ \brief The QInputContextFactory class creates QInputContext objects.
+
+
+ The input context factory creates a QInputContext object for a
+ given key with QInputContextFactory::create().
+
+ The input contexts are either built-in or dynamically loaded from
+ an input context plugin (see QInputContextPlugin).
+
+ keys() returns a list of valid keys. The
+ keys are the names used, for example, to identify and specify
+ input methods for the input method switching mechanism. The names
+ have to be consistent with QInputContext::identifierName(), and
+ may only contain ASCII characters.
+
+ A key can be used to retrieve the associated input context's
+ supported languages using languages(). You
+ can retrieve the input context's description using
+ description() and finally you can get a user
+ friendly internationalized name of the QInputContext object
+ specified by the key using displayName().
+
+ \legalese
+ Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+
+ This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+ license. You may use this file under your Qt license. Following
+ description is copied from their original file headers. Contact
+ immodule-qt@freedesktop.org if any conditions of this licensing are
+ not clear to you.
+ \endlegalese
+
+ \sa QInputContext, QInputContextPlugin
+*/
+
+/*!
+ Creates and returns a QInputContext object for the input context
+ specified by \a key with the given \a parent. Keys are case
+ sensitive.
+
+ \sa keys()
+*/
+QInputContext *QInputContextFactory::create( const QString& key, QObject *parent )
+{
+ QInputContext *result = 0;
+#if defined(Q_WS_X11) && !defined(QT_NO_XIM)
+ if (key == QLatin1String("xim")) {
+ result = new QXIMInputContext;
+ }
+#endif
+#if defined(Q_WS_WIN)
+ if (key == QLatin1String("win")) {
+ result = new QWinInputContext;
+ }
+#endif
+#if defined(Q_WS_MAC)
+ if (key == QLatin1String("mac")) {
+ result = new QMacInputContext;
+ }
+#endif
+#if defined(Q_WS_S60)
+ if (key == QLatin1String("coefep")) {
+ result = new QCoeFepInputContext;
+ }
+#endif
+#ifdef QT_NO_LIBRARY
+ Q_UNUSED(key);
+#else
+ if (QInputContextFactoryInterface *factory =
+ qobject_cast<QInputContextFactoryInterface*>(loader()->instance(key))) {
+ result = factory->create(key);
+ }
+#endif
+ if (result)
+ result->setParent(parent);
+ return result;
+}
+
+
+/*!
+ Returns the list of keys this factory can create input contexts
+ for.
+
+ The keys are the names used, for example, to identify and specify
+ input methods for the input method switching mechanism. The names
+ have to be consistent with QInputContext::identifierName(), and
+ may only contain ASCII characters.
+
+ \sa create(), displayName(), QInputContext::identifierName()
+*/
+QStringList QInputContextFactory::keys()
+{
+ QStringList result;
+#if defined(Q_WS_X11) && !defined(QT_NO_XIM)
+ result << QLatin1String("xim");
+#endif
+#if defined(Q_WS_WIN) && !defined(QT_NO_XIM)
+ result << QLatin1String("win");
+#endif
+#if defined(Q_WS_MAC)
+ result << QLatin1String("mac");
+#endif
+#if defined(Q_WS_S60)
+ result << QLatin1String("coefep");
+#endif
+#ifndef QT_NO_LIBRARY
+ result += loader()->keys();
+#endif // QT_NO_LIBRARY
+ return result;
+}
+
+#if defined(Q_WS_S60)
+/*!
+ \internal
+
+ This function contains pure Symbian exception handling code for
+ getting S60 language list.
+ Returned object ownership is transferred to caller.
+*/
+static CAknInputLanguageList* s60LangListL()
+{
+ CAknInputLanguageInfo *langInfo = AknInputLanguageInfoFactory::CreateInputLanguageInfoL();
+ CleanupStack::PushL(langInfo);
+ // In rare phone there is more than 7 languages installed -> use 7 as an array granularity
+ CAknInputLanguageList *langList = new (ELeave) CAknInputLanguageList(7);
+ CleanupStack::PushL(langList);
+ langInfo->AppendAvailableLanguagesL(langList);
+ CleanupStack::Pop(langList);
+ CleanupStack::PopAndDestroy(langInfo);
+ return langList;
+}
+
+/*!
+ \internal
+
+ This function utility function return S60 language list.
+ Returned object ownership is transferred to caller.
+*/
+static CAknInputLanguageList* s60LangList()
+{
+ CAknInputLanguageList *langList = NULL;
+ TRAP_IGNORE(langList = s60LangListL());
+ q_check_ptr(langList);
+ return langList;
+}
+#endif
+
+/*!
+ Returns the languages supported by the QInputContext object
+ specified by \a key.
+
+ The languages are expressed as language code (e.g. "zh_CN",
+ "zh_TW", "zh_HK", "ja", "ko", ...). An input context that supports
+ multiple languages can return all supported languages as a
+ QStringList. The name has to be consistent with
+ QInputContext::language().
+
+ This information may be used to optimize a user interface.
+
+ \sa keys(), QInputContext::language(), QLocale
+*/
+QStringList QInputContextFactory::languages( const QString &key )
+{
+ QStringList result;
+#if defined(Q_WS_X11) && !defined(QT_NO_XIM)
+ if (key == QLatin1String("xim"))
+ return QStringList(QString());
+#endif
+#if defined(Q_WS_WIN)
+ if (key == QLatin1String("win"))
+ return QStringList(QString());
+#endif
+#if defined(Q_WS_MAC)
+ if (key == QLatin1String("mac"))
+ return QStringList(QString());
+#endif
+#if defined(Q_WS_S60)
+ if (key == QLatin1String("coefep"))
+ {
+ CAknInputLanguageList *langList = s60LangList();
+ int count = langList->Count();
+ for (int i = 0; i < count; ++i)
+ {
+ result.append(QString(qt_symbianLocaleName(langList->At(i)->LanguageCode())));
+ }
+ delete langList;
+ }
+#endif
+#if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
+ Q_UNUSED(key);
+#else
+ if (QInputContextFactoryInterface *factory =
+ qobject_cast<QInputContextFactoryInterface*>(loader()->instance(key)))
+ result = factory->languages(key);
+#endif // QT_NO_LIBRARY
+ return result;
+}
+
+/*!
+ Returns a user friendly internationalized name of the
+ QInputContext object specified by \a key. You can, for example,
+ use this name in a menu.
+
+ \sa keys(), QInputContext::identifierName()
+*/
+QString QInputContextFactory::displayName( const QString &key )
+{
+ QString result;
+#if defined(Q_WS_X11) && !defined(QT_NO_XIM)
+ if (key == QLatin1String("xim"))
+ return QInputContext::tr( "XIM" );
+#endif
+#ifdef Q_WS_S60
+ if (key == QLatin1String("coefep"))
+ return QInputContext::tr( "FEP" );
+#endif
+#if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
+ Q_UNUSED(key);
+#else
+ if (QInputContextFactoryInterface *factory =
+ qobject_cast<QInputContextFactoryInterface*>(loader()->instance(key)))
+ return factory->displayName(key);
+#endif // QT_NO_LIBRARY
+ return QString();
+}
+
+/*!
+ Returns an internationalized brief description of the QInputContext
+ object specified by \a key. You can, for example, use this
+ description in a user interface.
+
+ \sa keys(), displayName()
+*/
+QString QInputContextFactory::description( const QString &key )
+{
+#if defined(Q_WS_X11) && !defined(QT_NO_XIM)
+ if (key == QLatin1String("xim"))
+ return QInputContext::tr( "XIM input method" );
+#endif
+#if defined(Q_WS_WIN) && !defined(QT_NO_XIM)
+ if (key == QLatin1String("win"))
+ return QInputContext::tr( "Windows input method" );
+#endif
+#if defined(Q_WS_MAC)
+ if (key == QLatin1String("mac"))
+ return QInputContext::tr( "Mac OS X input method" );
+#endif
+#if defined(Q_WS_S60)
+ if (key == QLatin1String("coefep"))
+ return QInputContext::tr( "S60 FEP input method" );
+#endif
+#if defined(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS)
+ Q_UNUSED(key);
+#else
+ if (QInputContextFactoryInterface *factory =
+ qobject_cast<QInputContextFactoryInterface*>(loader()->instance(key)))
+ return factory->description(key);
+#endif // QT_NO_LIBRARY
+ return QString();
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_IM
diff --git a/src/gui/inputmethod/qinputcontextfactory.h b/src/gui/inputmethod/qinputcontextfactory.h
new file mode 100644
index 0000000000..2382857ae1
--- /dev/null
+++ b/src/gui/inputmethod/qinputcontextfactory.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Definition of QInputContextFactory class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#ifndef QINPUTCONTEXTFACTORY_H
+#define QINPUTCONTEXTFACTORY_H
+
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#ifndef QT_NO_IM
+
+class QInputContext;
+class QWidget;
+
+class Q_GUI_EXPORT QInputContextFactory
+{
+public:
+ static QStringList keys();
+ static QInputContext *create( const QString &key, QObject *parent ); // should be a toplevel widget
+ static QStringList languages( const QString &key );
+ static QString displayName( const QString &key );
+ static QString description( const QString &key );
+};
+
+#endif // QT_NO_IM
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QINPUTCONTEXTFACTORY_H
diff --git a/src/gui/inputmethod/qinputcontextplugin.cpp b/src/gui/inputmethod/qinputcontextplugin.cpp
new file mode 100644
index 0000000000..a83359324a
--- /dev/null
+++ b/src/gui/inputmethod/qinputcontextplugin.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Implementation of QInputContext class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#include "qinputcontextplugin.h"
+
+#ifndef QT_NO_IM
+#ifndef QT_NO_LIBRARY
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QInputContextPlugin
+ \brief The QInputContextPlugin class provides an abstract base for custom QInputContext plugins.
+
+ \reentrant
+ \ingroup plugins
+
+ The input context plugin is a simple plugin interface that makes it
+ easy to create custom input contexts that can be loaded dynamically
+ into applications.
+
+ To create an input context plugin you subclass this base class,
+ reimplement the pure virtual functions keys(), create(),
+ languages(), displayName(), and description(), and export the
+ class with the Q_EXPORT_PLUGIN2() macro.
+
+ \legalese
+ Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+
+ This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+ license. You may use this file under your Qt license. Following
+ description is copied from their original file headers. Contact
+ immodule-qt@freedesktop.org if any conditions of this licensing are
+ not clear to you.
+ \endlegalese
+
+ \sa QInputContext, {How to Create Qt Plugins}
+*/
+
+/*!
+ \fn QStringList QInputContextPlugin::keys() const
+
+ Returns the list of QInputContext keys this plugin provides.
+
+ These keys are usually the class names of the custom input context
+ that are implemented in the plugin. The names are used, for
+ example, to identify and specify input methods for the input
+ method switching mechanism. They have to be consistent with
+ QInputContext::identifierName(), and may only contain ASCII
+ characters.
+
+ \sa create(), displayName(), QInputContext::identifierName()
+*/
+
+/*!
+ \fn QInputContext* QInputContextPlugin::create( const QString& key )
+
+ Creates and returns a QInputContext object for the input context
+ key \a key. The input context key is usually the class name of
+ the required input method.
+
+ \sa keys()
+*/
+
+/*!
+ \fn QStringList QInputContextPlugin::languages(const QString &key)
+
+ Returns the languages supported by the QInputContext object
+ specified by \a key.
+
+ The languages are expressed as language code (e.g. "zh_CN",
+ "zh_TW", "zh_HK", "ja", "ko", ...). An input context that supports
+ multiple languages can return all supported languages as
+ QStringList. The name has to be consistent with
+ QInputContext::language().
+
+ This information may be used to optimize user interface.
+
+ \sa keys(), QInputContext::language(), QLocale
+*/
+
+/*!
+ \fn QString QInputContextPlugin::displayName(const QString &key)
+
+ Returns a user friendly internationalized name of the
+ QInputContext object specified by \a key. You can, for example,
+ use this name in a menu.
+
+ \sa keys(), QInputContext::identifierName()
+*/
+
+/*!
+ \fn QString QInputContextPlugin::description(const QString &key)
+
+ Returns an internationalized brief description of the QInputContext
+ object specified by \a key. You can, for example, use this
+ description in a user interface.
+
+ \sa keys(), displayName()
+*/
+
+
+/*!
+ Constructs a input context plugin with the given \a parent. This
+ is invoked automatically by the Q_EXPORT_PLUGIN2() macro.
+*/
+QInputContextPlugin::QInputContextPlugin(QObject *parent)
+ :QObject(parent)
+{
+}
+
+/*!
+ Destroys the input context plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it's no longer used.
+*/
+QInputContextPlugin::~QInputContextPlugin()
+{
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_LIBRARY
+
+#endif // QT_NO_IM
diff --git a/src/gui/inputmethod/qinputcontextplugin.h b/src/gui/inputmethod/qinputcontextplugin.h
new file mode 100644
index 0000000000..3038298792
--- /dev/null
+++ b/src/gui/inputmethod/qinputcontextplugin.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Definition of QInputContextPlugin class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#ifndef QINPUTCONTEXTPLUGIN_H
+#define QINPUTCONTEXTPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+#include <QtCore/qstringlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+#if !defined(QT_NO_IM)
+
+class QInputContext;
+class QInputContextPluginPrivate;
+
+struct Q_GUI_EXPORT QInputContextFactoryInterface : public QFactoryInterface
+{
+ virtual QInputContext *create( const QString &key ) = 0;
+ virtual QStringList languages( const QString &key ) = 0;
+ virtual QString displayName( const QString &key ) = 0;
+ virtual QString description( const QString &key ) = 0;
+};
+
+#define QInputContextFactoryInterface_iid "com.trolltech.Qt.QInputContextFactoryInterface"
+Q_DECLARE_INTERFACE(QInputContextFactoryInterface, QInputContextFactoryInterface_iid)
+
+class Q_GUI_EXPORT QInputContextPlugin : public QObject, public QInputContextFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QInputContextFactoryInterface:QFactoryInterface)
+public:
+ explicit QInputContextPlugin(QObject *parent = 0);
+ ~QInputContextPlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QInputContext *create( const QString &key ) = 0;
+ virtual QStringList languages( const QString &key ) = 0;
+ virtual QString displayName( const QString &key ) = 0;
+ virtual QString description( const QString &key ) = 0;
+};
+
+#endif // QT_NO_IM
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QINPUTCONTEXTPLUGIN_H
diff --git a/src/gui/inputmethod/qmacinputcontext_mac.cpp b/src/gui/inputmethod/qmacinputcontext_mac.cpp
new file mode 100644
index 0000000000..a1ba39c1d6
--- /dev/null
+++ b/src/gui/inputmethod/qmacinputcontext_mac.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qvarlengtharray.h>
+#include <qwidget.h>
+#include <private/qmacinputcontext_p.h>
+#include "qtextformat.h"
+#include <qdebug.h>
+#include <private/qapplication_p.h>
+#include <private/qkeymapper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+extern bool qt_sendSpontaneousEvent(QObject*, QEvent*);
+
+#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
+# define typeRefCon typeSInt32
+# define typeByteCount typeSInt32
+#endif
+
+QMacInputContext::QMacInputContext(QObject *parent)
+ : QInputContext(parent), composing(false), recursionGuard(false), textDocument(0),
+ keydownEvent(0)
+{
+// createTextDocument();
+}
+
+QMacInputContext::~QMacInputContext()
+{
+#ifndef QT_MAC_USE_COCOA
+ if(textDocument)
+ DeleteTSMDocument(textDocument);
+#endif
+}
+
+void
+QMacInputContext::createTextDocument()
+{
+#ifndef QT_MAC_USE_COCOA
+ if(!textDocument) {
+ InterfaceTypeList itl = { kUnicodeDocument };
+ NewTSMDocument(1, itl, &textDocument, SRefCon(this));
+ }
+#endif
+}
+
+
+QString QMacInputContext::language()
+{
+ return QString();
+}
+
+
+void QMacInputContext::mouseHandler(int pos, QMouseEvent *e)
+{
+#ifndef QT_MAC_USE_COCOA
+ if(e->type() != QEvent::MouseButtonPress)
+ return;
+
+ if (!composing)
+ return;
+ if (pos < 0 || pos > currentText.length())
+ reset();
+ // ##### handle mouse position
+#else
+ Q_UNUSED(pos);
+ Q_UNUSED(e);
+#endif
+}
+
+#if !defined QT_MAC_USE_COCOA
+
+static QTextFormat qt_mac_compose_format()
+{
+ QTextCharFormat ret;
+ ret.setFontUnderline(true);
+ return ret;
+}
+
+void QMacInputContext::reset()
+{
+ if (recursionGuard)
+ return;
+ if (!currentText.isEmpty()){
+ QInputMethodEvent e;
+ e.setCommitString(currentText);
+ qt_sendSpontaneousEvent(focusWidget(), &e);
+ currentText = QString();
+ }
+ recursionGuard = true;
+ createTextDocument();
+ composing = false;
+ ActivateTSMDocument(textDocument);
+ FixTSMDocument(textDocument);
+ recursionGuard = false;
+}
+
+bool QMacInputContext::isComposing() const
+{
+ return composing;
+}
+#endif
+
+void QMacInputContext::setFocusWidget(QWidget *w)
+{
+ createTextDocument();
+#ifndef QT_MAC_USE_COCOA
+ if(w)
+ ActivateTSMDocument(textDocument);
+ else
+ DeactivateTSMDocument(textDocument);
+#endif
+ QInputContext::setFocusWidget(w);
+}
+
+
+#ifndef QT_MAC_USE_COCOA
+static EventTypeSpec input_events[] = {
+ { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent },
+ { kEventClassTextInput, kEventTextInputOffsetToPos },
+ { kEventClassTextInput, kEventTextInputUpdateActiveInputArea }
+};
+static EventHandlerUPP input_proc_handlerUPP = 0;
+static EventHandlerRef input_proc_handler = 0;
+#endif
+
+void
+QMacInputContext::initialize()
+{
+#ifndef QT_MAC_USE_COCOA
+ if(!input_proc_handler) {
+ input_proc_handlerUPP = NewEventHandlerUPP(QMacInputContext::globalEventProcessor);
+ InstallEventHandler(GetApplicationEventTarget(), input_proc_handlerUPP,
+ GetEventTypeCount(input_events), input_events,
+ 0, &input_proc_handler);
+ }
+#endif
+}
+
+void
+QMacInputContext::cleanup()
+{
+#ifndef QT_MAC_USE_COCOA
+ if(input_proc_handler) {
+ RemoveEventHandler(input_proc_handler);
+ input_proc_handler = 0;
+ }
+ if(input_proc_handlerUPP) {
+ DisposeEventHandlerUPP(input_proc_handlerUPP);
+ input_proc_handlerUPP = 0;
+ }
+#endif
+}
+
+void QMacInputContext::setLastKeydownEvent(EventRef event)
+{
+ EventRef tmpEvent = keydownEvent;
+ keydownEvent = event;
+ if (keydownEvent)
+ RetainEvent(keydownEvent);
+ if (tmpEvent)
+ ReleaseEvent(tmpEvent);
+}
+
+OSStatus
+QMacInputContext::globalEventProcessor(EventHandlerCallRef, EventRef event, void *)
+{
+#ifndef QT_MAC_USE_COCOA
+ QScopedLoopLevelCounter loopLevelCounter(QApplicationPrivate::instance()->threadData);
+
+ SRefCon refcon = 0;
+ GetEventParameter(event, kEventParamTextInputSendRefCon, typeRefCon, 0,
+ sizeof(refcon), 0, &refcon);
+ QMacInputContext *context = reinterpret_cast<QMacInputContext*>(refcon);
+
+ bool handled_event=true;
+ UInt32 ekind = GetEventKind(event), eclass = GetEventClass(event);
+ switch(eclass) {
+ case kEventClassTextInput: {
+ handled_event = false;
+ QWidget *widget = QApplicationPrivate::focus_widget;
+ bool canCompose = widget && (!context || widget->inputContext() == context)
+ && !(widget->inputMethodHints() & Qt::ImhDigitsOnly
+ || widget->inputMethodHints() & Qt::ImhFormattedNumbersOnly
+ || widget->inputMethodHints() & Qt::ImhHiddenText);
+ if(!canCompose) {
+ handled_event = false;
+ } else if(ekind == kEventTextInputOffsetToPos) {
+ if(!widget->testAttribute(Qt::WA_InputMethodEnabled)) {
+ handled_event = false;
+ break;
+ }
+
+ QRect mr(widget->inputMethodQuery(Qt::ImMicroFocus).toRect());
+ QPoint mp(widget->mapToGlobal(QPoint(mr.topLeft())));
+ Point pt;
+ pt.h = mp.x();
+ pt.v = mp.y() + mr.height();
+ SetEventParameter(event, kEventParamTextInputReplyPoint, typeQDPoint,
+ sizeof(pt), &pt);
+ handled_event = true;
+ } else if(ekind == kEventTextInputUpdateActiveInputArea) {
+ if(!widget->testAttribute(Qt::WA_InputMethodEnabled)) {
+ handled_event = false;
+ break;
+ }
+
+ if (context->recursionGuard)
+ break;
+
+ ByteCount unilen = 0;
+ GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText,
+ 0, 0, &unilen, 0);
+ UniChar *unicode = (UniChar*)NewPtr(unilen);
+ GetEventParameter(event, kEventParamTextInputSendText, typeUnicodeText,
+ 0, unilen, 0, unicode);
+ QString text((QChar*)unicode, unilen / sizeof(UniChar));
+ DisposePtr((char*)unicode);
+
+ ByteCount fixed_length = 0;
+ GetEventParameter(event, kEventParamTextInputSendFixLen, typeByteCount, 0,
+ sizeof(fixed_length), 0, &fixed_length);
+ if(fixed_length == ULONG_MAX || fixed_length == unilen) {
+ QInputMethodEvent e;
+ e.setCommitString(text);
+ context->currentText = QString();
+ qt_sendSpontaneousEvent(context->focusWidget(), &e);
+ handled_event = true;
+ context->reset();
+ } else {
+ ByteCount rngSize = 0;
+ OSStatus err = GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray, 0,
+ 0, &rngSize, 0);
+ QVarLengthArray<TextRangeArray> highlight(rngSize);
+ if (noErr == err) {
+ err = GetEventParameter(event, kEventParamTextInputSendHiliteRng, typeTextRangeArray, 0,
+ rngSize, &rngSize, highlight.data());
+ }
+ context->composing = true;
+ if(fixed_length > 0) {
+ const int qFixedLength = fixed_length / sizeof(UniChar);
+ QList<QInputMethodEvent::Attribute> attrs;
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ qFixedLength, text.length()-qFixedLength,
+ qt_mac_compose_format());
+ QInputMethodEvent e(text, attrs);
+ context->currentText = text;
+ e.setCommitString(text.left(qFixedLength), 0, qFixedLength);
+ qt_sendSpontaneousEvent(widget, &e);
+ handled_event = true;
+ } else {
+ /* Apple's enums that they have removed from Tiger :(
+ enum {
+ kCaretPosition = 1,
+ kRawText = 2,
+ kSelectedRawText = 3,
+ kConvertedText = 4,
+ kSelectedConvertedText = 5,
+ kBlockFillText = 6,
+ kOutlineText = 7,
+ kSelectedText = 8
+ };
+ */
+#ifndef kConvertedText
+#define kConvertedText 4
+#endif
+#ifndef kCaretPosition
+#define kCaretPosition 1
+#endif
+ QList<QInputMethodEvent::Attribute> attrs;
+ if (!highlight.isEmpty()) {
+ TextRangeArray *data = highlight.data();
+ for (int i = 0; i < data->fNumOfRanges; ++i) {
+ int start = data->fRange[i].fStart / sizeof(UniChar);
+ int len = (data->fRange[i].fEnd - data->fRange[i].fStart) / sizeof(UniChar);
+ if (data->fRange[i].fHiliteStyle == kCaretPosition) {
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, start, 0, QVariant());
+ continue;
+ }
+ QTextCharFormat format;
+ format.setFontUnderline(true);
+ if (data->fRange[i].fHiliteStyle == kConvertedText)
+ format.setUnderlineColor(Qt::gray);
+ else
+ format.setUnderlineColor(Qt::black);
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, len, format);
+ }
+ } else {
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ 0, text.length(), qt_mac_compose_format());
+ }
+ context->currentText = text;
+ QInputMethodEvent e(text, attrs);
+ qt_sendSpontaneousEvent(widget, &e);
+ handled_event = true;
+ }
+ }
+#if 0
+ if(!context->composing)
+ handled_event = false;
+#endif
+
+ extern bool qt_mac_eat_unicode_key; //qapplication_mac.cpp
+ qt_mac_eat_unicode_key = handled_event;
+ } else if(ekind == kEventTextInputUnicodeForKeyEvent) {
+ EventRef key_ev = 0;
+ GetEventParameter(event, kEventParamTextInputSendKeyboardEvent, typeEventRef, 0,
+ sizeof(key_ev), 0, &key_ev);
+ QString text;
+ ByteCount unilen = 0;
+ if(GetEventParameter(key_ev, kEventParamKeyUnicodes, typeUnicodeText, 0, 0, &unilen, 0) == noErr) {
+ UniChar *unicode = (UniChar*)NewPtr(unilen);
+ GetEventParameter(key_ev, kEventParamKeyUnicodes, typeUnicodeText, 0, unilen, 0, unicode);
+ text = QString((QChar*)unicode, unilen / sizeof(UniChar));
+ DisposePtr((char*)unicode);
+ }
+ unsigned char chr = 0;
+ GetEventParameter(key_ev, kEventParamKeyMacCharCodes, typeChar, 0, sizeof(chr), 0, &chr);
+ if(!chr || chr >= 128 || (text.length() > 0 && (text.length() > 1 || text.at(0) != QLatin1Char(chr))))
+ handled_event = !widget->testAttribute(Qt::WA_InputMethodEnabled);
+ QMacInputContext *context = qobject_cast<QMacInputContext*>(qApp->inputContext());
+ if (context && context->lastKeydownEvent()) {
+ qt_keymapper_private()->translateKeyEvent(widget, 0, context->lastKeydownEvent(),
+ 0, false);
+ context->setLastKeydownEvent(0);
+ }
+ }
+ break; }
+ default:
+ break;
+ }
+ if(!handled_event) //let the event go through
+ return eventNotHandledErr;
+#else
+ Q_UNUSED(event);
+#endif
+ return noErr; //we eat the event
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/inputmethod/qmacinputcontext_p.h b/src/gui/inputmethod/qmacinputcontext_p.h
new file mode 100644
index 0000000000..c4575a3c60
--- /dev/null
+++ b/src/gui/inputmethod/qmacinputcontext_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMACINPUTCONTEXT_P_H
+#define QMACINPUTCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtGui/qinputcontext.h"
+#include "private/qt_mac_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_GUI_EXPORT QMacInputContext : public QInputContext
+{
+ Q_OBJECT
+ //Q_DECLARE_PRIVATE(QMacInputContext)
+ void createTextDocument();
+public:
+ explicit QMacInputContext(QObject* parent = 0);
+ virtual ~QMacInputContext();
+
+ virtual void setFocusWidget(QWidget *w);
+ virtual QString identifierName() { return QLatin1String("mac"); }
+ virtual QString language();
+
+ virtual void reset();
+
+ virtual bool isComposing() const;
+
+ static OSStatus globalEventProcessor(EventHandlerCallRef, EventRef, void *);
+ static void initialize();
+ static void cleanup();
+
+ EventRef lastKeydownEvent() { return keydownEvent; }
+ void setLastKeydownEvent(EventRef);
+
+protected:
+ void mouseHandler(int pos, QMouseEvent *);
+private:
+ bool composing;
+ bool recursionGuard;
+ TSMDocumentID textDocument;
+ QString currentText;
+ EventRef keydownEvent;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMACINPUTCONTEXT_P_H
diff --git a/src/gui/inputmethod/qwininputcontext_p.h b/src/gui/inputmethod/qwininputcontext_p.h
new file mode 100644
index 0000000000..dc87000b6c
--- /dev/null
+++ b/src/gui/inputmethod/qwininputcontext_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWININPUTCONTEXT_P_H
+#define QWININPUTCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qinputcontext.cpp. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtGui/qinputcontext.h"
+#include "QtCore/qt_windows.h"
+
+#if !defined(IMR_RECONVERTSTRING)
+typedef struct tagRECONVERTSTRING {
+ DWORD dwSize;
+ DWORD dwVersion;
+ DWORD dwStrLen;
+ DWORD dwStrOffset;
+ DWORD dwCompStrLen;
+ DWORD dwCompStrOffset;
+ DWORD dwTargetStrLen;
+ DWORD dwTargetStrOffset;
+} RECONVERTSTRING, *PRECONVERTSTRING;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QWinInputContext : public QInputContext
+{
+ Q_OBJECT
+public:
+ explicit QWinInputContext(QObject* parent = 0);
+ virtual ~QWinInputContext();
+
+ virtual QString identifierName() { return QLatin1String("win"); }
+ virtual QString language();
+
+ virtual void reset();
+ virtual void update();
+
+ virtual void mouseHandler(int x, QMouseEvent *event);
+ virtual bool isComposing() const;
+
+ virtual void setFocusWidget(QWidget *w);
+
+ bool startComposition();
+ bool endComposition();
+ bool composition(LPARAM lparam);
+ int reconvertString(RECONVERTSTRING *reconv);
+
+ static void TranslateMessage(const MSG *msg);
+ static LRESULT DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+ static void updateImeStatus(QWidget *w, bool hasFocus);
+ static void enablePopupChild(QWidget *w, bool e);
+ static void enable(QWidget *w, bool e);
+
+private:
+ void init();
+ bool recursionGuard;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWININPUTCONTEXT_P_H
diff --git a/src/gui/inputmethod/qwininputcontext_win.cpp b/src/gui/inputmethod/qwininputcontext_win.cpp
new file mode 100644
index 0000000000..4289cf4191
--- /dev/null
+++ b/src/gui/inputmethod/qwininputcontext_win.cpp
@@ -0,0 +1,847 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwininputcontext_p.h"
+#include "qinputcontext_p.h"
+
+#include "qfont.h"
+#include "qwidget.h"
+#include "qapplication.h"
+#include "qevent.h"
+#include "qtextformat.h"
+#include "qtextboundaryfinder.h"
+
+//#define Q_IME_DEBUG
+
+#ifdef Q_IME_DEBUG
+#include "qdebug.h"
+#endif
+
+#if defined(Q_WS_WINCE)
+extern void qt_wince_show_SIP(bool show); // defined in qguifunctions_wince.cpp
+#endif
+
+QT_BEGIN_NAMESPACE
+
+extern bool qt_sendSpontaneousEvent(QObject*, QEvent*);
+
+
+DEFINE_GUID(IID_IActiveIMMApp,
+0x08c0e040, 0x62d1, 0x11d1, 0x93, 0x26, 0x0, 0x60, 0xb0, 0x67, 0xb8, 0x6e);
+
+
+
+DEFINE_GUID(CLSID_CActiveIMM,
+0x4955DD33, 0xB159, 0x11d0, 0x8F, 0xCF, 0x0, 0xAA, 0x00, 0x6B, 0xCC, 0x59);
+
+
+
+DEFINE_GUID(IID_IActiveIMMMessagePumpOwner,
+0xb5cf2cfa, 0x8aeb, 0x11d1, 0x93, 0x64, 0x0, 0x60, 0xb0, 0x67, 0xb8, 0x6e);
+
+
+
+interface IEnumRegisterWordW;
+interface IEnumInputContext;
+
+
+bool qt_sendSpontaneousEvent(QObject*, QEvent*);
+
+
+#define IFMETHOD HRESULT STDMETHODCALLTYPE
+
+interface IActiveIMMApp : public IUnknown
+{
+public:
+ virtual IFMETHOD AssociateContext(HWND hWnd, HIMC hIME, HIMC __RPC_FAR *phPrev) = 0;
+ virtual IFMETHOD dummy_ConfigureIMEA() = 0;
+ virtual IFMETHOD ConfigureIMEW(HKL hKL, HWND hWnd, DWORD dwMode, REGISTERWORDW __RPC_FAR *pData) = 0;
+ virtual IFMETHOD CreateContext(HIMC __RPC_FAR *phIMC) = 0;
+ virtual IFMETHOD DestroyContext(HIMC hIME) = 0;
+ virtual IFMETHOD dummy_EnumRegisterWordA() = 0;
+ virtual IFMETHOD EnumRegisterWordW(HKL hKL, LPWSTR szReading, DWORD dwStyle, LPWSTR szRegister, LPVOID pData,
+ IEnumRegisterWordW __RPC_FAR *__RPC_FAR *pEnum) = 0;
+ virtual IFMETHOD dummy_EscapeA() = 0;
+ virtual IFMETHOD EscapeW(HKL hKL, HIMC hIMC, UINT uEscape, LPVOID pData, LRESULT __RPC_FAR *plResult) = 0;
+ virtual IFMETHOD dummy_GetCandidateListA() = 0;
+ virtual IFMETHOD GetCandidateListW(HIMC hIMC, DWORD dwIndex, UINT uBufLen, CANDIDATELIST __RPC_FAR *pCandList,
+ UINT __RPC_FAR *puCopied) = 0;
+ virtual IFMETHOD dummy_GetCandidateListCountA() = 0;
+ virtual IFMETHOD GetCandidateListCountW(HIMC hIMC, DWORD __RPC_FAR *pdwListSize, DWORD __RPC_FAR *pdwBufLen) = 0;
+ virtual IFMETHOD GetCandidateWindow(HIMC hIMC, DWORD dwIndex, CANDIDATEFORM __RPC_FAR *pCandidate) = 0;
+ virtual IFMETHOD dummy_GetCompositionFontA() = 0;
+ virtual IFMETHOD GetCompositionFontW(HIMC hIMC, LOGFONTW __RPC_FAR *plf) = 0;
+ virtual IFMETHOD dummy_GetCompositionStringA() = 0;
+ virtual IFMETHOD GetCompositionStringW(HIMC hIMC, DWORD dwIndex, DWORD dwBufLen, LONG __RPC_FAR *plCopied, LPVOID pBuf) = 0;
+ virtual IFMETHOD GetCompositionWindow(HIMC hIMC, COMPOSITIONFORM __RPC_FAR *pCompForm) = 0;
+ virtual IFMETHOD GetContext(HWND hWnd, HIMC __RPC_FAR *phIMC) = 0;
+ virtual IFMETHOD dummy_GetConversionListA() = 0;
+ virtual IFMETHOD GetConversionListW(HKL hKL, HIMC hIMC, LPWSTR pSrc, UINT uBufLen, UINT uFlag,
+ CANDIDATELIST __RPC_FAR *pDst, UINT __RPC_FAR *puCopied) = 0;
+ virtual IFMETHOD GetConversionStatus(HIMC hIMC, DWORD __RPC_FAR *pfdwConversion, DWORD __RPC_FAR *pfdwSentence) = 0;
+ virtual IFMETHOD GetDefaultIMEWnd(HWND hWnd, HWND __RPC_FAR *phDefWnd) = 0;
+ virtual IFMETHOD dummy_GetDescriptionA() = 0;
+ virtual IFMETHOD GetDescriptionW(HKL hKL, UINT uBufLen, LPWSTR szDescription, UINT __RPC_FAR *puCopied) = 0;
+ virtual IFMETHOD dummy_GetGuideLineA() = 0;
+ virtual IFMETHOD GetGuideLineW(HIMC hIMC, DWORD dwIndex, DWORD dwBufLen, LPWSTR pBuf, DWORD __RPC_FAR *pdwResult) = 0;
+ virtual IFMETHOD dummy_GetIMEFileNameA() = 0;
+ virtual IFMETHOD GetIMEFileNameW(HKL hKL, UINT uBufLen, LPWSTR szFileName, UINT __RPC_FAR *puCopied) = 0;
+ virtual IFMETHOD GetOpenStatus(HIMC hIMC) = 0;
+ virtual IFMETHOD GetProperty(HKL hKL, DWORD fdwIndex, DWORD __RPC_FAR *pdwProperty) = 0;
+ virtual IFMETHOD dummy_GetRegisterWordStyleA() = 0;
+ virtual IFMETHOD GetRegisterWordStyleW(HKL hKL, UINT nItem, STYLEBUFW __RPC_FAR *pStyleBuf, UINT __RPC_FAR *puCopied) = 0;
+ virtual IFMETHOD GetStatusWindowPos(HIMC hIMC, POINT __RPC_FAR *pptPos) = 0;
+ virtual IFMETHOD GetVirtualKey(HWND hWnd, UINT __RPC_FAR *puVirtualKey) = 0;
+ virtual IFMETHOD dummy_InstallIMEA() = 0;
+ virtual IFMETHOD InstallIMEW(LPWSTR szIMEFileName, LPWSTR szLayoutText, HKL __RPC_FAR *phKL) = 0;
+ virtual IFMETHOD IsIME(HKL hKL) = 0;
+ virtual IFMETHOD dummy_IsUIMessageA() = 0;
+ virtual IFMETHOD IsUIMessageW(HWND hWndIME, UINT msg, WPARAM wParam, LPARAM lParam) = 0;
+ virtual IFMETHOD NotifyIME(HIMC hIMC, DWORD dwAction, DWORD dwIndex, DWORD dwValue) = 0;
+ virtual IFMETHOD dummy_RegisterWordA() = 0;
+ virtual IFMETHOD RegisterWordW(HKL hKL, LPWSTR szReading, DWORD dwStyle, LPWSTR szRegister) = 0;
+ virtual IFMETHOD ReleaseContext(HWND hWnd, HIMC hIMC) = 0;
+ virtual IFMETHOD SetCandidateWindow(HIMC hIMC, CANDIDATEFORM __RPC_FAR *pCandidate) = 0;
+ virtual IFMETHOD SetCompositionFontA(HIMC hIMC, LOGFONTA __RPC_FAR *plf) = 0;
+ virtual IFMETHOD SetCompositionFontW(HIMC hIMC, LOGFONTW __RPC_FAR *plf) = 0;
+ virtual IFMETHOD dummy_SetCompositionStringA() = 0;
+ virtual IFMETHOD SetCompositionStringW(HIMC hIMC, DWORD dwIndex, LPVOID pComp, DWORD dwCompLen,
+ LPVOID pRead, DWORD dwReadLen) = 0;
+ virtual IFMETHOD SetCompositionWindow(HIMC hIMC, COMPOSITIONFORM __RPC_FAR *pCompForm) = 0;
+ virtual IFMETHOD SetConversionStatus(HIMC hIMC, DWORD fdwConversion, DWORD fdwSentence) = 0;
+ virtual IFMETHOD SetOpenStatus(HIMC hIMC, BOOL fOpen) = 0;
+ virtual IFMETHOD SetStatusWindowPos(HIMC hIMC, POINT __RPC_FAR *pptPos) = 0;
+ virtual IFMETHOD SimulateHotKey(HWND hWnd, DWORD dwHotKeyID) = 0;
+ virtual IFMETHOD dummy_UnregisterWordA() = 0;
+ virtual IFMETHOD UnregisterWordW(HKL hKL, LPWSTR szReading, DWORD dwStyle, LPWSTR szUnregister) = 0;
+ virtual IFMETHOD Activate(BOOL fRestoreLayout) = 0;
+ virtual IFMETHOD Deactivate(void) = 0;
+ virtual IFMETHOD OnDefWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, LRESULT __RPC_FAR *plResult) = 0;
+ virtual IFMETHOD FilterClientWindows(ATOM __RPC_FAR *aaClassList, UINT uSize) = 0;
+ virtual IFMETHOD dummy_GetCodePageA() = 0;
+ virtual IFMETHOD GetLangId(HKL hKL, LANGID __RPC_FAR *plid) = 0;
+ virtual IFMETHOD AssociateContextEx(HWND hWnd, HIMC hIMC, DWORD dwFlags) = 0;
+ virtual IFMETHOD DisableIME(DWORD idThread) = 0;
+ virtual IFMETHOD dummy_GetImeMenuItemsA() = 0;
+ virtual IFMETHOD GetImeMenuItemsW(HIMC hIMC, DWORD dwFlags, DWORD dwType, /*IMEMENUITEMINFOW*/ void __RPC_FAR *pImeParentMenu,
+ /*IMEMENUITEMINFOW*/ void __RPC_FAR *pImeMenu, DWORD dwSize, DWORD __RPC_FAR *pdwResult) = 0;
+ virtual IFMETHOD EnumInputContext(DWORD idThread, IEnumInputContext __RPC_FAR *__RPC_FAR *ppEnum) = 0;
+};
+
+interface IActiveIMMMessagePumpOwner : public IUnknown
+{
+public:
+ virtual IFMETHOD Start(void) = 0;
+ virtual IFMETHOD End(void) = 0;
+ virtual IFMETHOD OnTranslateMessage(const MSG __RPC_FAR *pMsg) = 0;
+ virtual IFMETHOD Pause(DWORD __RPC_FAR *pdwCookie) = 0;
+ virtual IFMETHOD Resume(DWORD dwCookie) = 0;
+};
+
+
+static IActiveIMMApp *aimm = 0;
+static IActiveIMMMessagePumpOwner *aimmpump = 0;
+static QString *imeComposition = 0;
+static int imePosition = -1;
+bool qt_use_rtl_extensions = false;
+static bool haveCaret = false;
+
+#ifndef LGRPID_INSTALLED
+#define LGRPID_INSTALLED 0x00000001 // installed language group ids
+#define LGRPID_SUPPORTED 0x00000002 // supported language group ids
+#endif
+
+#ifndef LGRPID_ARABIC
+#define LGRPID_WESTERN_EUROPE 0x0001 // Western Europe & U.S.
+#define LGRPID_CENTRAL_EUROPE 0x0002 // Central Europe
+#define LGRPID_BALTIC 0x0003 // Baltic
+#define LGRPID_GREEK 0x0004 // Greek
+#define LGRPID_CYRILLIC 0x0005 // Cyrillic
+#define LGRPID_TURKISH 0x0006 // Turkish
+#define LGRPID_JAPANESE 0x0007 // Japanese
+#define LGRPID_KOREAN 0x0008 // Korean
+#define LGRPID_TRADITIONAL_CHINESE 0x0009 // Traditional Chinese
+#define LGRPID_SIMPLIFIED_CHINESE 0x000a // Simplified Chinese
+#define LGRPID_THAI 0x000b // Thai
+#define LGRPID_HEBREW 0x000c // Hebrew
+#define LGRPID_ARABIC 0x000d // Arabic
+#define LGRPID_VIETNAMESE 0x000e // Vietnamese
+#define LGRPID_INDIC 0x000f // Indic
+#define LGRPID_GEORGIAN 0x0010 // Georgian
+#define LGRPID_ARMENIAN 0x0011 // Armenian
+#endif
+
+static DWORD WM_MSIME_MOUSE = 0;
+
+QWinInputContext::QWinInputContext(QObject *parent)
+ : QInputContext(parent), recursionGuard(false)
+{
+#ifndef Q_WS_WINCE
+ QSysInfo::WinVersion ver = QSysInfo::windowsVersion();
+ if (ver & QSysInfo::WV_NT_based && ver >= QSysInfo::WV_VISTA) {
+ // Since the IsValidLanguageGroup/IsValidLocale functions always return true on
+ // Vista, check the Keyboard Layouts for enabling RTL.
+ UINT nLayouts = GetKeyboardLayoutList(0, 0);
+ if (nLayouts) {
+ HKL *lpList = new HKL[nLayouts];
+ GetKeyboardLayoutList(nLayouts, lpList);
+ for (int i = 0; i<(int)nLayouts; i++) {
+ WORD plangid = PRIMARYLANGID((quintptr)lpList[i]);
+ if (plangid == LANG_ARABIC
+ || plangid == LANG_HEBREW
+ || plangid == LANG_FARSI
+#ifdef LANG_SYRIAC
+ || plangid == LANG_SYRIAC
+#endif
+ ) {
+ qt_use_rtl_extensions = true;
+ break;
+ }
+ }
+ delete []lpList;
+ }
+ } else {
+ // figure out whether a RTL language is installed
+ qt_use_rtl_extensions = IsValidLanguageGroup(LGRPID_ARABIC, LGRPID_INSTALLED)
+ || IsValidLanguageGroup(LGRPID_HEBREW, LGRPID_INSTALLED)
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_ARABIC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_HEBREW, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
+#ifdef LANG_SYRIAC
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_SYRIAC, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED)
+#endif
+ || IsValidLocale(MAKELCID(MAKELANGID(LANG_FARSI, SUBLANG_DEFAULT), SORT_DEFAULT), LCID_INSTALLED);
+ }
+#else
+ qt_use_rtl_extensions = false;
+#endif
+
+ WM_MSIME_MOUSE = RegisterWindowMessage(L"MSIMEMouseOperation");
+}
+
+QWinInputContext::~QWinInputContext()
+{
+ // release active input method if we have one
+ if (aimm) {
+ aimmpump->End();
+ aimmpump->Release();
+ aimm->Deactivate();
+ aimm->Release();
+ aimm = 0;
+ aimmpump = 0;
+ }
+ delete imeComposition;
+ imeComposition = 0;
+}
+
+static HWND getDefaultIMEWnd(HWND wnd)
+{
+ HWND ime_wnd;
+ if(aimm)
+ aimm->GetDefaultIMEWnd(wnd, &ime_wnd);
+ else
+ ime_wnd = ImmGetDefaultIMEWnd(wnd);
+ return ime_wnd;
+}
+
+static HIMC getContext(HWND wnd)
+{
+ HIMC imc;
+ if (aimm)
+ aimm->GetContext(wnd, &imc);
+ else
+ imc = ImmGetContext(wnd);
+
+ return imc;
+}
+
+static void releaseContext(HWND wnd, HIMC imc)
+{
+ if (aimm)
+ aimm->ReleaseContext(wnd, imc);
+ else
+ ImmReleaseContext(wnd, imc);
+}
+
+static void notifyIME(HIMC imc, DWORD dwAction, DWORD dwIndex, DWORD dwValue)
+{
+ if (!imc)
+ return;
+ if (aimm)
+ aimm->NotifyIME(imc, dwAction, dwIndex, dwValue);
+ else
+ ImmNotifyIME(imc, dwAction, dwIndex, dwValue);
+}
+
+static LONG getCompositionString(HIMC himc, DWORD dwIndex, LPVOID lpbuf, DWORD dBufLen)
+{
+ LONG len = 0;
+ if (aimm)
+ aimm->GetCompositionStringW(himc, dwIndex, dBufLen, &len, lpbuf);
+ else
+ len = ImmGetCompositionString(himc, dwIndex, lpbuf, dBufLen);
+ return len;
+}
+
+static int getCursorPosition(HIMC himc)
+{
+ return getCompositionString(himc, GCS_CURSORPOS, 0, 0);
+}
+
+static QString getString(HIMC himc, DWORD dwindex, int *selStart = 0, int *selLength = 0)
+{
+ const int bufferSize = 256;
+ wchar_t buffer[bufferSize];
+ int len = getCompositionString(himc, dwindex, buffer, bufferSize * sizeof(wchar_t));
+
+ if (selStart) {
+ char attrbuffer[bufferSize];
+ int attrlen = getCompositionString(himc, GCS_COMPATTR, attrbuffer, bufferSize);
+ *selStart = attrlen+1;
+ *selLength = -1;
+ for (int i = 0; i < attrlen; i++) {
+ if (attrbuffer[i] & ATTR_TARGET_CONVERTED) {
+ *selStart = qMin(*selStart, i);
+ *selLength = qMax(*selLength, i);
+ }
+ }
+ *selLength = qMax(0, *selLength - *selStart + 1);
+ }
+
+ if (len <= 0)
+ return QString();
+
+ return QString((QChar*)buffer, len / sizeof(QChar));
+}
+
+void QWinInputContext::TranslateMessage(const MSG *msg)
+{
+ if (!aimmpump || aimmpump->OnTranslateMessage(msg) != S_OK)
+ ::TranslateMessage(msg);
+}
+
+LRESULT QWinInputContext::DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT retval;
+ if (!aimm || aimm->OnDefWindowProc(hwnd, msg, wParam, lParam, &retval) != S_OK)
+ {
+ retval = ::DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return retval;
+}
+
+
+void QWinInputContext::update()
+{
+ QWidget *w = focusWidget();
+ if(!w)
+ return;
+
+ Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
+ HIMC imc = getContext(w->effectiveWinId());
+
+ if (!imc)
+ return;
+
+ QFont f = qvariant_cast<QFont>(w->inputMethodQuery(Qt::ImFont));
+ HFONT hf;
+ hf = f.handle();
+
+ LOGFONT lf;
+ if (GetObject(hf, sizeof(lf), &lf)) {
+ if (aimm)
+ aimm->SetCompositionFontW(imc, &lf);
+ else
+ ImmSetCompositionFont(imc, &lf);
+ }
+
+ QRect r = w->inputMethodQuery(Qt::ImMicroFocus).toRect();
+
+ // The ime window positions are based on the WinId with active focus.
+ QWidget *imeWnd = QWidget::find(::GetFocus());
+ if (imeWnd && !aimm) {
+ QPoint pt (r.topLeft());
+ pt = w->mapToGlobal(pt);
+ pt = imeWnd->mapFromGlobal(pt);
+ r.moveTo(pt);
+ }
+
+ COMPOSITIONFORM cf;
+ // ### need X-like inputStyle config settings
+ cf.dwStyle = CFS_FORCE_POSITION;
+ cf.ptCurrentPos.x = r.x();
+ cf.ptCurrentPos.y = r.y();
+
+ CANDIDATEFORM candf;
+ candf.dwIndex = 0;
+ candf.dwStyle = CFS_EXCLUDE;
+ candf.ptCurrentPos.x = r.x();
+ candf.ptCurrentPos.y = r.y() + r.height();
+ candf.rcArea.left = r.x();
+ candf.rcArea.top = r.y();
+ candf.rcArea.right = r.x() + r.width();
+ candf.rcArea.bottom = r.y() + r.height();
+
+ if(haveCaret)
+ SetCaretPos(r.x(), r.y());
+
+ if (aimm) {
+ aimm->SetCompositionWindow(imc, &cf);
+ aimm->SetCandidateWindow(imc, &candf);
+ } else {
+ ImmSetCompositionWindow(imc, &cf);
+ ImmSetCandidateWindow(imc, &candf);
+ }
+
+ releaseContext(w->effectiveWinId(), imc);
+}
+
+
+bool QWinInputContext::endComposition()
+{
+ QWidget *fw = focusWidget();
+#ifdef Q_IME_DEBUG
+ qDebug("endComposition! fw = %s", fw ? fw->className() : "(null)");
+#endif
+ bool result = true;
+ if(imePosition == -1 || recursionGuard)
+ return result;
+
+ // Googles Pinyin Input Method likes to call endComposition again
+ // when we call notifyIME with CPS_CANCEL, so protect ourselves
+ // against that.
+ recursionGuard = true;
+
+ if (fw) {
+ Q_ASSERT(fw->testAttribute(Qt::WA_WState_Created));
+ HIMC imc = getContext(fw->effectiveWinId());
+ notifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
+ releaseContext(fw->effectiveWinId(), imc);
+ if(haveCaret) {
+ DestroyCaret();
+ haveCaret = false;
+ }
+ }
+
+ if (!fw)
+ fw = QApplication::focusWidget();
+
+ if (fw) {
+ QInputMethodEvent e;
+ result = qt_sendSpontaneousEvent(fw, &e);
+ }
+
+ if (imeComposition)
+ imeComposition->clear();
+ imePosition = -1;
+
+ recursionGuard = false;
+
+ return result;
+}
+
+void QWinInputContext::reset()
+{
+ QWidget *fw = focusWidget();
+
+#ifdef Q_IME_DEBUG
+ qDebug("sending accept to focus widget %s", fw ? fw->className() : "(null)");
+#endif
+
+ if (fw && imePosition != -1) {
+ QInputMethodEvent e;
+ if (imeComposition)
+ e.setCommitString(*imeComposition);
+ imePosition = -1;
+ qt_sendSpontaneousEvent(fw, &e);
+ }
+
+ if (imeComposition)
+ imeComposition->clear();
+ imePosition = -1;
+
+ if (fw) {
+ Q_ASSERT(fw->testAttribute(Qt::WA_WState_Created));
+ HIMC imc = getContext(fw->effectiveWinId());
+ notifyIME(imc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
+ releaseContext(fw->effectiveWinId(), imc);
+ }
+
+}
+
+
+bool QWinInputContext::startComposition()
+{
+#ifdef Q_IME_DEBUG
+ qDebug("startComposition");
+#endif
+
+ if (!imeComposition)
+ imeComposition = new QString();
+
+ QWidget *fw = focusWidget();
+ if (fw) {
+ Q_ASSERT(fw->testAttribute(Qt::WA_WState_Created));
+ imePosition = 0;
+ haveCaret = CreateCaret(fw->effectiveWinId(), 0, 1, 1);
+ HideCaret(fw->effectiveWinId());
+ update();
+ }
+ return fw != 0;
+}
+
+enum StandardFormat {
+ PreeditFormat,
+ SelectionFormat
+};
+
+bool QWinInputContext::composition(LPARAM lParam)
+{
+#ifdef Q_IME_DEBUG
+ QString str;
+ if (lParam & GCS_RESULTSTR)
+ str += "RESULTSTR ";
+ if (lParam & GCS_COMPSTR)
+ str += "COMPSTR ";
+ if (lParam & GCS_COMPATTR)
+ str += "COMPATTR ";
+ if (lParam & GCS_CURSORPOS)
+ str += "CURSORPOS ";
+ if (lParam & GCS_COMPCLAUSE)
+ str += "COMPCLAUSE ";
+ if (lParam & CS_INSERTCHAR)
+ str += "INSERTCHAR ";
+ if (lParam & CS_NOMOVECARET)
+ str += "NOMOVECARET ";
+ qDebug("composition, lParam=(%x) %s imePosition=%d", lParam, str.latin1(), imePosition);
+#endif
+
+ bool result = true;
+
+ if(!lParam)
+ // bogus event
+ return true;
+
+ QWidget *fw = QApplication::focusWidget();
+ if (fw) {
+ Q_ASSERT(fw->testAttribute(Qt::WA_WState_Created));
+ HIMC imc = getContext(fw->effectiveWinId());
+ QInputMethodEvent e;
+ if (lParam & (GCS_COMPSTR | GCS_COMPATTR | GCS_CURSORPOS)) {
+ if (imePosition == -1)
+ // need to send a start event
+ startComposition();
+
+ // some intermediate composition result
+ int selStart, selLength;
+ *imeComposition = getString(imc, GCS_COMPSTR, &selStart, &selLength);
+ imePosition = getCursorPosition(imc);
+ if (lParam & CS_INSERTCHAR && lParam & CS_NOMOVECARET) {
+ // make korean work correctly. Hope this is correct for all IMEs
+ selStart = 0;
+ selLength = imeComposition->length();
+ }
+ if(selLength == 0)
+ selStart = 0;
+
+ QList<QInputMethodEvent::Attribute> attrs;
+ if (selStart > 0)
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, selStart,
+ standardFormat(PreeditFormat));
+ if (selLength)
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selStart, selLength,
+ standardFormat(SelectionFormat));
+ if (selStart + selLength < imeComposition->length())
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selStart + selLength,
+ imeComposition->length() - selStart - selLength,
+ standardFormat(PreeditFormat));
+ if(imePosition >= 0)
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, imePosition, selLength ? 0 : 1, QVariant());
+
+ e = QInputMethodEvent(*imeComposition, attrs);
+ }
+ if (lParam & GCS_RESULTSTR) {
+ if(imePosition == -1)
+ startComposition();
+ // a fixed result, return the converted string
+ *imeComposition = getString(imc, GCS_RESULTSTR);
+ imePosition = -1;
+ e.setCommitString(*imeComposition);
+ imeComposition->clear();
+ }
+ result = qt_sendSpontaneousEvent(fw, &e);
+ update();
+ releaseContext(fw->effectiveWinId(), imc);
+ }
+#ifdef Q_IME_DEBUG
+ qDebug("imecomposition: cursor pos at %d, str=%x", imePosition, str[0].unicode());
+#endif
+ return result;
+}
+
+static HIMC defaultContext = 0;
+
+// checks whether widget is a popup
+inline bool isPopup(QWidget *w)
+{
+ if (w && (w->windowFlags() & Qt::Popup) == Qt::Popup)
+ return true;
+ else
+ return false;
+}
+// checks whether widget is in a popup
+inline bool isInPopup(QWidget *w)
+{
+ if (w && (isPopup(w) || isPopup(w->window())))
+ return true;
+ else
+ return false;
+}
+
+// find the parent widget, which is a non popup toplevel
+// this is valid only if the widget is/in a popup
+inline QWidget *findParentforPopup(QWidget *w)
+{
+ QWidget *e = QWidget::find(w->effectiveWinId());
+ // check if this or its parent is a popup
+ while (isInPopup(e)) {
+ e = e->window()->parentWidget();
+ if (!e)
+ break;
+ e = QWidget::find(e->effectiveWinId());
+ }
+ if (e)
+ return e->window();
+ else
+ return 0;
+}
+
+// enables or disables the ime
+inline void enableIme(QWidget *w, bool value)
+{
+ if (value) {
+ // enable ime
+ if (defaultContext)
+ ImmAssociateContext(w->effectiveWinId(), defaultContext);
+#ifdef Q_WS_WINCE
+ if (qApp->autoSipEnabled())
+ qt_wince_show_SIP(true);
+#endif
+ } else {
+ // disable ime
+ HIMC oldimc = ImmAssociateContext(w->effectiveWinId(), 0);
+ if (!defaultContext)
+ defaultContext = oldimc;
+#ifdef Q_WS_WINCE
+ if (qApp->autoSipEnabled())
+ qt_wince_show_SIP(false);
+#endif
+ }
+}
+
+
+void QWinInputContext::updateImeStatus(QWidget *w, bool hasFocus)
+{
+ if (!w)
+ return;
+ // It's always the proxy that carries the hints.
+ QWidget *focusProxyWidget = w->focusProxy();
+ if (!focusProxyWidget)
+ focusProxyWidget = w;
+ bool e = w->testAttribute(Qt::WA_InputMethodEnabled) && w->isEnabled()
+ && !(focusProxyWidget->inputMethodHints() & (Qt::ImhExclusiveInputMask | Qt::ImhHiddenText));
+ bool hasIme = e && hasFocus;
+#ifdef Q_IME_DEBUG
+ qDebug("%s HasFocus = %d hasIme = %d e = %d ", w->className(), hasFocus, hasIme, e);
+#endif
+ if (hasFocus || e) {
+ if (isInPopup(w))
+ QWinInputContext::enablePopupChild(w, hasIme);
+ else
+ QWinInputContext::enable(w, hasIme);
+ }
+}
+
+void QWinInputContext::enablePopupChild(QWidget *w, bool e)
+{
+ if (aimm) {
+ enable(w, e);
+ return;
+ }
+
+ if (!w || !isInPopup(w))
+ return;
+#ifdef Q_IME_DEBUG
+ qDebug("enablePopupChild: w=%s, enable = %s", w ? w->className() : "(null)" , e ? "true" : "false");
+#endif
+ QWidget *parent = findParentforPopup(w);
+ if (parent) {
+ // update ime status of the normal toplevel parent of the popup
+ enableIme(parent, e);
+ }
+ QWidget *toplevel = w->window();
+ if (toplevel) {
+ // update ime status of the toplevel popup
+ enableIme(toplevel, e);
+ }
+}
+
+void QWinInputContext::enable(QWidget *w, bool e)
+{
+ if(w) {
+#ifdef Q_IME_DEBUG
+ qDebug("enable: w=%s, enable = %s", w ? w->className() : "(null)" , e ? "true" : "false");
+#endif
+ if (!w->testAttribute(Qt::WA_WState_Created))
+ return;
+ if(aimm) {
+ HIMC oldimc;
+ if (!e) {
+ aimm->AssociateContext(w->effectiveWinId(), 0, &oldimc);
+ if (!defaultContext)
+ defaultContext = oldimc;
+ } else if (defaultContext) {
+ aimm->AssociateContext(w->effectiveWinId(), defaultContext, &oldimc);
+ }
+ } else {
+ // update ime status on the widget
+ QWidget *p = QWidget::find(w->effectiveWinId());
+ if (p)
+ enableIme(p, e);
+ }
+ }
+}
+
+void QWinInputContext::setFocusWidget(QWidget *w)
+{
+ QWidget *oldFocus = focusWidget();
+ if (oldFocus == w)
+ return;
+ if (w) {
+ QWinInputContext::updateImeStatus(w, true);
+ } else {
+ if (oldFocus)
+ QWinInputContext::updateImeStatus(oldFocus , false);
+ }
+ QInputContext::setFocusWidget(w);
+ update();
+}
+
+bool QWinInputContext::isComposing() const
+{
+ return imeComposition && !imeComposition->isEmpty();
+}
+
+void QWinInputContext::mouseHandler(int pos, QMouseEvent *e)
+{
+ if(e->type() != QEvent::MouseButtonPress)
+ return;
+
+ if (pos < 0 || pos > imeComposition->length())
+ reset();
+
+ // Probably should pass the correct button, but it seems to work fine like this.
+ DWORD button = MK_LBUTTON;
+
+ QWidget *fw = focusWidget();
+ if (fw) {
+ Q_ASSERT(fw->testAttribute(Qt::WA_WState_Created));
+ HIMC himc = getContext(fw->effectiveWinId());
+ HWND ime_wnd = getDefaultIMEWnd(fw->effectiveWinId());
+ SendMessage(ime_wnd, WM_MSIME_MOUSE, MAKELONG(MAKEWORD(button, pos == 0 ? 2 : 1), pos), (LPARAM)himc);
+ releaseContext(fw->effectiveWinId(), himc);
+ }
+ //qDebug("mouseHandler: got value %d pos=%d", ret,pos);
+}
+
+QString QWinInputContext::language()
+{
+ return QString();
+}
+
+int QWinInputContext::reconvertString(RECONVERTSTRING *reconv)
+{
+ QWidget *w = focusWidget();
+ if(!w)
+ return -1;
+
+ Q_ASSERT(w->testAttribute(Qt::WA_WState_Created));
+ QString surroundingText = qvariant_cast<QString>(w->inputMethodQuery(Qt::ImSurroundingText));
+ int memSize = sizeof(RECONVERTSTRING)+(surroundingText.length()+1)*sizeof(ushort);
+ // If memory is not allocated, return the required size.
+ if (!reconv) {
+ if (surroundingText.isEmpty())
+ return -1;
+ else
+ return memSize;
+ }
+ int pos = qvariant_cast<int>(w->inputMethodQuery(Qt::ImCursorPosition));
+ // find the word in the surrounding text.
+ QTextBoundaryFinder bounds(QTextBoundaryFinder::Word, surroundingText);
+ bounds.setPosition(pos);
+ if (bounds.isAtBoundary()) {
+ if (QTextBoundaryFinder::EndWord == bounds.boundaryReasons())
+ bounds.toPreviousBoundary();
+ } else {
+ bounds.toPreviousBoundary();
+ }
+ int startPos = bounds.position();
+ bounds.toNextBoundary();
+ int endPos = bounds.position();
+ // select the text, this will be overwritten by following ime events.
+ QList<QInputMethodEvent::Attribute> attrs;
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, startPos, endPos-startPos, QVariant());
+ QInputMethodEvent e(QString(), attrs);
+ qt_sendSpontaneousEvent(w, &e);
+
+ reconv->dwSize = memSize;
+ reconv->dwVersion = 0;
+
+ reconv->dwStrLen = surroundingText.length();
+ reconv->dwStrOffset = sizeof(RECONVERTSTRING);
+ reconv->dwCompStrLen = endPos-startPos;
+ reconv->dwCompStrOffset = startPos*sizeof(ushort);
+ reconv->dwTargetStrLen = reconv->dwCompStrLen;
+ reconv->dwTargetStrOffset = reconv->dwCompStrOffset;
+ memcpy((char*)(reconv+1), surroundingText.utf16(), surroundingText.length()*sizeof(ushort));
+ return memSize;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/inputmethod/qwsinputcontext_p.h b/src/gui/inputmethod/qwsinputcontext_p.h
new file mode 100644
index 0000000000..72b06a0b8f
--- /dev/null
+++ b/src/gui/inputmethod/qwsinputcontext_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWSINPUTCONTEXT_P_H
+#define QWSINPUTCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtGui/qinputcontext.h"
+
+#ifndef QT_NO_QWS_INPUTMETHODS
+
+QT_BEGIN_NAMESPACE
+
+class QWSIMEvent;
+class QWSIMQueryEvent;
+class QWSIMInitEvent;
+
+class QWSInputContext : public QInputContext
+{
+ Q_OBJECT
+public:
+ explicit QWSInputContext(QObject* parent = 0);
+ ~QWSInputContext() {}
+
+
+ QString identifierName() { return QString(); }
+ QString language() { return QString(); }
+
+ void reset();
+ void update();
+ void mouseHandler( int x, QMouseEvent *event);
+
+ void setFocusWidget( QWidget *w );
+ void widgetDestroyed(QWidget *w);
+
+ bool isComposing() const;
+
+ static QWidget *activeWidget();
+ static bool translateIMEvent(QWidget *w, const QWSIMEvent *e);
+ static bool translateIMQueryEvent(QWidget *w, const QWSIMQueryEvent *e);
+ static bool translateIMInitEvent(const QWSIMInitEvent *e);
+ static void updateImeStatus(QWidget *w, bool hasFocus);
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_INPUTMETHODS
+
+#endif // QWSINPUTCONTEXT_P_H
diff --git a/src/gui/inputmethod/qwsinputcontext_qws.cpp b/src/gui/inputmethod/qwsinputcontext_qws.cpp
new file mode 100644
index 0000000000..d8d64f28d4
--- /dev/null
+++ b/src/gui/inputmethod/qwsinputcontext_qws.cpp
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwsinputcontext_p.h"
+#include "qinputcontext_p.h"
+#include "qwsdisplay_qws.h"
+#include "qwsevent_qws.h"
+#include "private/qwscommand_qws_p.h"
+#include "qwindowsystem_qws.h"
+#include "qevent.h"
+#include "qtextformat.h"
+
+#include <qbuffer.h>
+
+#include <qdebug.h>
+
+#ifndef QT_NO_QWS_INPUTMETHODS
+
+QT_BEGIN_NAMESPACE
+
+static QWidget* activeWidget = 0;
+
+//#define EXTRA_DEBUG
+
+QWSInputContext::QWSInputContext(QObject *parent)
+ :QInputContext(parent)
+{
+}
+
+void QWSInputContext::reset()
+{
+ QPaintDevice::qwsDisplay()->resetIM();
+}
+
+
+void QWSInputContext::setFocusWidget( QWidget *w )
+{
+ QWidget *oldFocus = focusWidget();
+ if (oldFocus == w)
+ return;
+
+ if (w) {
+ QWSInputContext::updateImeStatus(w, true);
+ } else {
+ if (oldFocus)
+ QWSInputContext::updateImeStatus(oldFocus, false);
+ }
+
+ if (oldFocus) {
+ QWidget *tlw = oldFocus->window();
+ int winid = tlw->internalWinId();
+
+ int widgetid = oldFocus->internalWinId();
+ QPaintDevice::qwsDisplay()->sendIMUpdate(QWSInputMethod::FocusOut, winid, widgetid);
+ }
+
+ QInputContext::setFocusWidget(w);
+
+ if (!w)
+ return;
+
+ QWidget *tlw = w->window();
+ int winid = tlw->winId();
+
+ int widgetid = w->winId();
+ QPaintDevice::qwsDisplay()->sendIMUpdate(QWSInputMethod::FocusIn, winid, widgetid);
+
+ //setfocus ???
+
+ update();
+}
+
+
+void QWSInputContext::widgetDestroyed(QWidget *w)
+{
+ if (w == QT_PREPEND_NAMESPACE(activeWidget))
+ QT_PREPEND_NAMESPACE(activeWidget) = 0;
+ QInputContext::widgetDestroyed(w);
+}
+
+void QWSInputContext::update()
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ QWidget *tlw = w->window();
+ int winid = tlw->winId();
+
+ int widgetid = w->winId();
+ QPaintDevice::qwsDisplay()->sendIMUpdate(QWSInputMethod::Update, winid, widgetid);
+
+}
+
+void QWSInputContext::mouseHandler( int x, QMouseEvent *event)
+{
+ if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)
+ QPaintDevice::qwsDisplay()->sendIMMouseEvent( x, event->type() == QEvent::MouseButtonPress );
+}
+
+QWidget *QWSInputContext::activeWidget()
+{
+ return QT_PREPEND_NAMESPACE(activeWidget);
+}
+
+
+bool QWSInputContext::isComposing() const
+{
+ return QT_PREPEND_NAMESPACE(activeWidget) != 0;
+}
+
+bool QWSInputContext::translateIMQueryEvent(QWidget *w, const QWSIMQueryEvent *e)
+{
+ Qt::InputMethodQuery type = static_cast<Qt::InputMethodQuery>(e->simpleData.property);
+ QVariant result = w->inputMethodQuery(type);
+ QWidget *tlw = w->window();
+ int winId = tlw->winId();
+
+ if ( type == Qt::ImMicroFocus ) {
+ // translate to relative to tlw
+ QRect mf = result.toRect();
+ mf.moveTopLeft(w->mapTo(tlw,mf.topLeft()));
+ result = mf;
+ }
+
+ QPaintDevice::qwsDisplay()->sendIMResponse(winId, e->simpleData.property, result);
+
+ return false;
+}
+
+bool QWSInputContext::translateIMInitEvent(const QWSIMInitEvent *e)
+{
+ Q_UNUSED(e);
+ qDebug("### QWSInputContext::translateIMInitEvent not implemented ###");
+ return false;
+}
+
+bool QWSInputContext::translateIMEvent(QWidget *w, const QWSIMEvent *e)
+{
+ QDataStream stream(e->streamingData);
+ QString preedit;
+ QString commit;
+
+ stream >> preedit;
+ stream >> commit;
+
+ if (preedit.isEmpty() && QT_PREPEND_NAMESPACE(activeWidget))
+ w = QT_PREPEND_NAMESPACE(activeWidget);
+
+ QInputContext *qic = w->inputContext();
+ if (!qic)
+ return false;
+
+ QList<QInputMethodEvent::Attribute> attrs;
+
+
+ while (!stream.atEnd()) {
+ int type = -1;
+ int start = -1;
+ int length = -1;
+ QVariant data;
+ stream >> type >> start >> length >> data;
+ if (stream.status() != QDataStream::Ok) {
+ qWarning("corrupted QWSIMEvent");
+ //qic->reset(); //???
+ return false;
+ }
+ if (type == QInputMethodEvent::TextFormat)
+ data = qic->standardFormat(static_cast<QInputContext::StandardFormat>(data.toInt()));
+ attrs << QInputMethodEvent::Attribute(static_cast<QInputMethodEvent::AttributeType>(type), start, length, data);
+ }
+#ifdef EXTRA_DEBUG
+ qDebug() << "preedit" << preedit << "len" << preedit.length() <<"commit" << commit << "len" << commit.length()
+ << "n attr" << attrs.count();
+#endif
+
+ if (preedit.isEmpty())
+ QT_PREPEND_NAMESPACE(activeWidget) = 0;
+ else
+ QT_PREPEND_NAMESPACE(activeWidget) = w;
+
+
+ QInputMethodEvent ime(preedit, attrs);
+ if (!commit.isEmpty() || e->simpleData.replaceLength > 0)
+ ime.setCommitString(commit, e->simpleData.replaceFrom, e->simpleData.replaceLength);
+
+
+ extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_qws.cpp
+ qt_sendSpontaneousEvent(w, &ime);
+
+ return true;
+}
+
+Q_GUI_EXPORT void (*qt_qws_inputMethodStatusChanged)(QWidget*) = 0;
+
+void QWSInputContext::updateImeStatus(QWidget *w, bool hasFocus)
+{
+ Q_UNUSED(hasFocus);
+
+ if (!w || !qt_qws_inputMethodStatusChanged)
+ return;
+ qt_qws_inputMethodStatusChanged(w);
+}
+
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_QWS_INPUTMETHODS
diff --git a/src/gui/inputmethod/qximinputcontext_p.h b/src/gui/inputmethod/qximinputcontext_p.h
new file mode 100644
index 0000000000..13c389cce6
--- /dev/null
+++ b/src/gui/inputmethod/qximinputcontext_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Definition of QXIMInputContext class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#ifndef QXIMINPUTCONTEXT_P_H
+#define QXIMINPUTCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#if !defined(Q_NO_IM)
+
+#include "QtCore/qglobal.h"
+#include "QtGui/qinputcontext.h"
+#include "QtGui/qfont.h"
+#include "QtCore/qhash.h"
+#ifdef Q_WS_X11
+#include "QtCore/qlist.h"
+#include "QtCore/qbitarray.h"
+#include "QtGui/qwindowdefs.h"
+#include "private/qt_x11_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QKeyEvent;
+class QWidget;
+class QFont;
+class QString;
+
+class QXIMInputContext : public QInputContext
+{
+ Q_OBJECT
+public:
+ struct ICData {
+ XIC ic;
+ XFontSet fontset;
+ QWidget *widget;
+ QString text;
+ QBitArray selectedChars;
+ bool composing;
+ bool preeditEmpty;
+ void clear();
+ };
+
+ QXIMInputContext();
+ ~QXIMInputContext();
+
+ QString identifierName();
+ QString language();
+
+ void reset();
+
+ void mouseHandler( int x, QMouseEvent *event);
+ bool isComposing() const;
+
+ void setFocusWidget( QWidget *w );
+ void widgetDestroyed(QWidget *w);
+
+ void create_xim();
+ void close_xim();
+
+ void update();
+
+ ICData *icData() const;
+protected:
+ bool x11FilterEvent( QWidget *keywidget, XEvent *event );
+
+private:
+ static XIMStyle xim_style;
+
+ QString _language;
+ XIM xim;
+ QHash<WId, ICData *> ximData;
+
+ ICData *createICData(QWidget *w);
+};
+
+QT_END_NAMESPACE
+
+#endif // Q_NO_IM
+
+#endif // QXIMINPUTCONTEXT_P_H
diff --git a/src/gui/inputmethod/qximinputcontext_x11.cpp b/src/gui/inputmethod/qximinputcontext_x11.cpp
new file mode 100644
index 0000000000..155796828e
--- /dev/null
+++ b/src/gui/inputmethod/qximinputcontext_x11.cpp
@@ -0,0 +1,885 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Implementation of QXIMInputContext class
+**
+** Copyright (C) 2003-2004 immodule for Qt Project. All rights reserved.
+**
+** This file is written to contribute to Nokia Corporation and/or its subsidiary(-ies) under their own
+** license. You may use this file under your Qt license. Following
+** description is copied from their original file headers. Contact
+** immodule-qt@freedesktop.org if any conditions of this licensing are
+** not clear to you.
+**
+****************************************************************************/
+
+#include "qplatformdefs.h"
+#include "qdebug.h"
+#include "qximinputcontext_p.h"
+
+#if !defined(QT_NO_IM)
+
+QT_BEGIN_NAMESPACE
+
+#if !defined(QT_NO_XIM)
+
+QT_BEGIN_INCLUDE_NAMESPACE
+#include "qplatformdefs.h"
+
+#include "qapplication.h"
+#include "qwidget.h"
+#include "qstring.h"
+#include "qlist.h"
+#include "qtextcodec.h"
+#include "qevent.h"
+#include "qtextformat.h"
+
+#include "qx11info_x11.h"
+
+#include <stdlib.h>
+#include <limits.h>
+QT_END_INCLUDE_NAMESPACE
+
+// #define QT_XIM_DEBUG
+#ifdef QT_XIM_DEBUG
+#define XIM_DEBUG qDebug
+#else
+#define XIM_DEBUG if (0) qDebug
+#endif
+
+// from qapplication_x11.cpp
+// #### move to X11 struct
+extern XIMStyle qt_xim_preferred_style;
+extern char *qt_ximServer;
+extern int qt_ximComposingKeycode;
+extern QTextCodec * qt_input_mapper;
+
+XIMStyle QXIMInputContext::xim_style = 0;
+// moved from qapplication_x11.cpp
+static const XIMStyle xim_default_style = XIMPreeditCallbacks | XIMStatusNothing;
+
+
+extern "C" {
+#ifdef USE_X11R6_XIM
+ static void xim_create_callback(XIM /*im*/,
+ XPointer client_data,
+ XPointer /*call_data*/)
+ {
+ QXIMInputContext *qic = reinterpret_cast<QXIMInputContext *>(client_data);
+ // qDebug("xim_create_callback");
+ qic->create_xim();
+ }
+
+ static void xim_destroy_callback(XIM /*im*/,
+ XPointer client_data,
+ XPointer /*call_data*/)
+ {
+ QXIMInputContext *qic = reinterpret_cast<QXIMInputContext *>(client_data);
+ // qDebug("xim_destroy_callback");
+ qic->close_xim();
+ XRegisterIMInstantiateCallback(X11->display, 0, 0, 0,
+ (XIMProc) xim_create_callback, reinterpret_cast<char *>(qic));
+ }
+#endif // USE_X11R6_XIM
+
+ static int xic_start_callback(XIC, XPointer client_data, XPointer) {
+ QXIMInputContext *qic = (QXIMInputContext *) client_data;
+ if (!qic) {
+ XIM_DEBUG("xic_start_callback: no qic");
+ return 0;
+ }
+ QXIMInputContext::ICData *data = qic->icData();
+ if (!data) {
+ XIM_DEBUG("xic_start_callback: no ic data");
+ return 0;
+ }
+ XIM_DEBUG("xic_start_callback");
+
+ data->clear();
+ data->composing = true;
+
+ return 0;
+ }
+
+ static int xic_draw_callback(XIC, XPointer client_data, XPointer call_data) {
+ QXIMInputContext *qic = (QXIMInputContext *) client_data;
+ if (!qic) {
+ XIM_DEBUG("xic_draw_callback: no qic");
+ return 0;
+ }
+ QXIMInputContext::ICData *data = qic->icData();
+ if (!data) {
+ XIM_DEBUG("xic_draw_callback: no ic data");
+ return 0;
+ }
+ XIM_DEBUG("xic_draw_callback");
+
+
+ if(!data->composing) {
+ data->clear();
+ data->composing = true;
+ }
+
+ XIMPreeditDrawCallbackStruct *drawstruct = (XIMPreeditDrawCallbackStruct *) call_data;
+ XIMText *text = (XIMText *) drawstruct->text;
+ int cursor = drawstruct->caret, sellen = 0, selstart = 0;
+
+ if (!drawstruct->caret && !drawstruct->chg_first && !drawstruct->chg_length && !text) {
+ if(data->text.isEmpty()) {
+ XIM_DEBUG("compose emptied");
+ // if the composition string has been emptied, we need
+ // to send an InputMethodEnd event
+ QInputMethodEvent e;
+ qic->sendEvent(e);
+ data->clear();
+
+ // if the commit string has coming after here, InputMethodStart
+ // will be sent dynamically
+ }
+ return 0;
+ }
+
+ if (text) {
+ char *str = 0;
+ if (text->encoding_is_wchar) {
+ int l = wcstombs(NULL, text->string.wide_char, text->length);
+ if (l != -1) {
+ str = new char[l + 1];
+ wcstombs(str, text->string.wide_char, l);
+ str[l] = 0;
+ }
+ } else
+ str = text->string.multi_byte;
+
+ if (!str)
+ return 0;
+
+ QString s = QString::fromLocal8Bit(str);
+
+ if (text->encoding_is_wchar)
+ delete [] str;
+
+ if (drawstruct->chg_length < 0)
+ data->text.replace(drawstruct->chg_first, INT_MAX, s);
+ else
+ data->text.replace(drawstruct->chg_first, drawstruct->chg_length, s);
+
+ if (data->selectedChars.size() < data->text.length()) {
+ // expand the selectedChars array if the compose string is longer
+ int from = data->selectedChars.size();
+ data->selectedChars.resize(data->text.length());
+ for (int x = from; x < data->selectedChars.size(); ++x)
+ data->selectedChars.clearBit(x);
+ }
+
+ // determine if the changed chars are selected based on text->feedback
+ for (int x = 0; x < text->length; ++x)
+ data->selectedChars.setBit(x + drawstruct->chg_first,
+ (text->feedback ? (text->feedback[x] & XIMReverse) : 0));
+
+ // figure out where the selection starts, and how long it is
+ bool started = false;
+ for (int x = 0; x < qMin(data->selectedChars.size(), data->text.length()); ++x) {
+ if (started) {
+ if (data->selectedChars.testBit(x)) ++sellen;
+ else break;
+ } else {
+ if (data->selectedChars.testBit(x)) {
+ selstart = x;
+ started = true;
+ sellen = 1;
+ }
+ }
+ }
+ } else {
+ if (drawstruct->chg_length == 0)
+ drawstruct->chg_length = -1;
+
+ data->text.remove(drawstruct->chg_first, drawstruct->chg_length);
+ bool qt_compose_emptied = data->text.isEmpty();
+ if (qt_compose_emptied) {
+ XIM_DEBUG("compose emptied 2 text=%s", data->text.toUtf8().constData());
+ // if the composition string has been emptied, we need
+ // to send an InputMethodEnd event
+ QInputMethodEvent e;
+ qic->sendEvent(e);
+ data->clear();
+ // if the commit string has coming after here, InputMethodStart
+ // will be sent dynamically
+ return 0;
+ }
+ }
+
+ XIM_DEBUG("sending compose: '%s', cursor=%d, sellen=%d",
+ data->text.toUtf8().constData(), cursor, sellen);
+ QList<QInputMethodEvent::Attribute> attrs;
+ if (selstart > 0)
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, selstart,
+ qic->standardFormat(QInputContext::PreeditFormat));
+ if (sellen)
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selstart, sellen,
+ qic->standardFormat(QInputContext::SelectionFormat));
+ if (selstart + sellen < data->text.length())
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
+ selstart + sellen, data->text.length() - selstart - sellen,
+ qic->standardFormat(QInputContext::PreeditFormat));
+ attrs << QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursor, sellen ? 0 : 1, QVariant());
+ QInputMethodEvent e(data->text, attrs);
+ data->preeditEmpty = data->text.isEmpty();
+ qic->sendEvent(e);
+
+ return 0;
+ }
+
+ static int xic_done_callback(XIC, XPointer client_data, XPointer) {
+ QXIMInputContext *qic = (QXIMInputContext *) client_data;
+ if (!qic)
+ return 0;
+
+ XIM_DEBUG("xic_done_callback");
+ // Don't send InputMethodEnd here. QXIMInputContext::x11FilterEvent()
+ // handles InputMethodEnd with commit string.
+ return 0;
+ }
+}
+
+void QXIMInputContext::ICData::clear()
+{
+ text = QString();
+ selectedChars.clear();
+ composing = false;
+ preeditEmpty = true;
+}
+
+QXIMInputContext::ICData *QXIMInputContext::icData() const
+{
+ if (QWidget *w = focusWidget())
+ return ximData.value(w->effectiveWinId());
+ return 0;
+}
+/* The cache here is needed, as X11 leaks a few kb for every
+ XFreeFontSet call, so we avoid creating and deletion of fontsets as
+ much as possible
+*/
+static XFontSet fontsetCache[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+static int fontsetRefCount = 0;
+
+static const char * const fontsetnames[] = {
+ "-*-fixed-medium-r-*-*-16-*,-*-*-medium-r-*-*-16-*",
+ "-*-fixed-medium-i-*-*-16-*,-*-*-medium-i-*-*-16-*",
+ "-*-fixed-bold-r-*-*-16-*,-*-*-bold-r-*-*-16-*",
+ "-*-fixed-bold-i-*-*-16-*,-*-*-bold-i-*-*-16-*",
+ "-*-fixed-medium-r-*-*-24-*,-*-*-medium-r-*-*-24-*",
+ "-*-fixed-medium-i-*-*-24-*,-*-*-medium-i-*-*-24-*",
+ "-*-fixed-bold-r-*-*-24-*,-*-*-bold-r-*-*-24-*",
+ "-*-fixed-bold-i-*-*-24-*,-*-*-bold-i-*-*-24-*"
+};
+
+static XFontSet getFontSet(const QFont &f)
+{
+ int i = 0;
+ if (f.italic())
+ i |= 1;
+ if (f.bold())
+ i |= 2;
+
+ if (f.pointSize() > 20)
+ i += 4;
+
+ if (!fontsetCache[i]) {
+ Display* dpy = X11->display;
+ int missCount;
+ char** missList;
+ fontsetCache[i] = XCreateFontSet(dpy, fontsetnames[i], &missList, &missCount, 0);
+ if(missCount > 0)
+ XFreeStringList(missList);
+ if (!fontsetCache[i]) {
+ fontsetCache[i] = XCreateFontSet(dpy, "-*-fixed-*-*-*-*-16-*", &missList, &missCount, 0);
+ if(missCount > 0)
+ XFreeStringList(missList);
+ if (!fontsetCache[i])
+ fontsetCache[i] = (XFontSet)-1;
+ }
+ }
+ return (fontsetCache[i] == (XFontSet)-1) ? 0 : fontsetCache[i];
+}
+
+extern bool qt_use_rtl_extensions; // from qapplication_x11.cpp
+#ifndef QT_NO_XKB
+extern QLocale q_getKeyboardLocale(const QByteArray &layoutName, const QByteArray &variantName);
+#endif
+
+QXIMInputContext::QXIMInputContext()
+{
+ if (!qt_xim_preferred_style) // no configured input style, use the default
+ qt_xim_preferred_style = xim_default_style;
+
+ xim = 0;
+ QByteArray ximServerName(qt_ximServer);
+ if (qt_ximServer)
+ ximServerName.prepend("@im=");
+ else
+ ximServerName = "";
+
+ if (!XSupportsLocale())
+#ifndef QT_NO_DEBUG
+ qWarning("Qt: Locale not supported on X server")
+#endif
+ ;
+#ifdef USE_X11R6_XIM
+ else if (XSetLocaleModifiers (ximServerName.constData()) == 0)
+ qWarning("Qt: Cannot set locale modifiers: %s", ximServerName.constData());
+ else
+ XRegisterIMInstantiateCallback(X11->display, 0, 0, 0,
+ (XIMProc) xim_create_callback, reinterpret_cast<char *>(this));
+#else // !USE_X11R6_XIM
+ else if (XSetLocaleModifiers ("") == 0)
+ qWarning("Qt: Cannot set locale modifiers");
+ else
+ QXIMInputContext::create_xim();
+#endif // USE_X11R6_XIM
+
+#ifndef QT_NO_XKB
+ if (X11->use_xkb) {
+ QByteArray layoutName;
+ QByteArray variantName;
+
+ Atom type = XNone;
+ int format = 0;
+ ulong nitems = 0;
+ ulong bytesAfter = 0;
+ uchar *data = 0;
+ if (XGetWindowProperty(X11->display, RootWindow(X11->display, 0), ATOM(_XKB_RULES_NAMES), 0, 1024,
+ false, XA_STRING, &type, &format, &nitems, &bytesAfter, &data) == Success
+ && type == XA_STRING && format == 8 && nitems > 2) {
+
+ char *names[5] = { 0, 0, 0, 0, 0 };
+ char *p = reinterpret_cast<char *>(data), *end = p + nitems;
+ int i = 0;
+ do {
+ names[i++] = p;
+ p += qstrlen(p) + 1;
+ } while (p < end);
+
+ QList<QByteArray> layoutNames = QByteArray::fromRawData(names[2], qstrlen(names[2])).split(',');
+ QList<QByteArray> variantNames = QByteArray::fromRawData(names[3], qstrlen(names[3])).split(',');
+ for (int i = 0; i < qMin(layoutNames.count(), variantNames.count()); ++i ) {
+ QByteArray variantName = variantNames.at(i);
+ const int dashPos = variantName.indexOf("-");
+ if (dashPos >= 0)
+ variantName.truncate(dashPos);
+ QLocale keyboardInputLocale = q_getKeyboardLocale(layoutNames.at(i), variantName);
+ if (keyboardInputLocale.textDirection() == Qt::RightToLeft)
+ qt_use_rtl_extensions = true;
+ }
+ }
+
+ if (data)
+ XFree(data);
+ }
+#endif // QT_NO_XKB
+
+}
+
+
+/*!\internal
+ Creates the application input method.
+*/
+void QXIMInputContext::create_xim()
+{
+ ++fontsetRefCount;
+#ifndef QT_NO_XIM
+ xim = XOpenIM(X11->display, 0, 0, 0);
+ if (xim) {
+
+#ifdef USE_X11R6_XIM
+ XIMCallback destroy;
+ destroy.callback = (XIMProc) xim_destroy_callback;
+ destroy.client_data = XPointer(this);
+ if (XSetIMValues(xim, XNDestroyCallback, &destroy, (char *) 0) != 0)
+ qWarning("Xlib doesn't support destroy callback");
+#endif // USE_X11R6_XIM
+
+ XIMStyles *styles = 0;
+ XGetIMValues(xim, XNQueryInputStyle, &styles, (char *) 0, (char *) 0);
+ if (styles) {
+ int i;
+ for (i = 0; !xim_style && i < styles->count_styles; i++) {
+ if (styles->supported_styles[i] == qt_xim_preferred_style) {
+ xim_style = qt_xim_preferred_style;
+ break;
+ }
+ }
+ // if the preferred input style couldn't be found, look for
+ // Nothing
+ for (i = 0; !xim_style && i < styles->count_styles; i++) {
+ if (styles->supported_styles[i] == (XIMPreeditNothing | XIMStatusNothing)) {
+ xim_style = XIMPreeditNothing | XIMStatusNothing;
+ break;
+ }
+ }
+ // ... and failing that, None.
+ for (i = 0; !xim_style && i < styles->count_styles; i++) {
+ if (styles->supported_styles[i] == (XIMPreeditNone |
+ XIMStatusNone)) {
+ xim_style = XIMPreeditNone | XIMStatusNone;
+ break;
+ }
+ }
+
+ // qDebug("QApplication: using im style %lx", xim_style);
+ XFree((char *)styles);
+ }
+
+ if (xim_style) {
+
+#ifdef USE_X11R6_XIM
+ XUnregisterIMInstantiateCallback(X11->display, 0, 0, 0,
+ (XIMProc) xim_create_callback, reinterpret_cast<char *>(this));
+#endif // USE_X11R6_XIM
+
+ if (QWidget *focusWidget = QApplication::focusWidget()) {
+ // reinitialize input context after the input method
+ // server (like SCIM) has been launched without
+ // requiring the user to manually switch focus.
+ if (focusWidget->testAttribute(Qt::WA_InputMethodEnabled)
+ && focusWidget->testAttribute(Qt::WA_WState_Created)
+ && focusWidget->isEnabled())
+ setFocusWidget(focusWidget);
+ }
+ // following code fragment is not required for immodule
+ // version of XIM
+#if 0
+ QWidgetList list = qApp->topLevelWidgets();
+ for (int i = 0; i < list.size(); ++i) {
+ QWidget *w = list.at(i);
+ w->d->createTLSysExtra();
+ }
+#endif
+ } else {
+ // Give up
+ qWarning("No supported input style found."
+ " See InputMethod documentation.");
+ close_xim();
+ }
+ }
+#endif // QT_NO_XIM
+}
+
+/*!\internal
+ Closes the application input method.
+*/
+void QXIMInputContext::close_xim()
+{
+ for(QHash<WId, ICData *>::const_iterator i = ximData.constBegin(),
+ e = ximData.constEnd(); i != e; ++i) {
+ ICData *data = i.value();
+ if (data->ic)
+ XDestroyIC(data->ic);
+ delete data;
+ }
+ ximData.clear();
+
+ if ( --fontsetRefCount == 0 ) {
+ Display *dpy = X11->display;
+ for ( int i = 0; i < 8; i++ ) {
+ if ( fontsetCache[i] && fontsetCache[i] != (XFontSet)-1 ) {
+ XFreeFontSet(dpy, fontsetCache[i]);
+ fontsetCache[i] = 0;
+ }
+ }
+ }
+
+ setFocusWidget(0);
+ xim = 0;
+}
+
+
+
+QXIMInputContext::~QXIMInputContext()
+{
+ XIM old_xim = xim; // close_xim clears xim pointer.
+ close_xim();
+ if (old_xim)
+ XCloseIM(old_xim);
+}
+
+
+QString QXIMInputContext::identifierName()
+{
+ // the name should be "xim" rather than "XIM" to be consistent
+ // with corresponding immodule of GTK+
+ return QLatin1String("xim");
+}
+
+
+QString QXIMInputContext::language()
+{
+ QString language;
+ if (xim) {
+ QByteArray locale(XLocaleOfIM(xim));
+
+ if (locale.startsWith("zh")) {
+ // Chinese language should be formed as "zh_CN", "zh_TW", "zh_HK"
+ language = QLatin1String(locale.left(5));
+ } else {
+ // other languages should be two-letter ISO 639 language code
+ language = QLatin1String(locale.left(2));
+ }
+ }
+ return language;
+}
+
+void QXIMInputContext::reset()
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ ICData *data = ximData.value(w->effectiveWinId());
+ if (!data)
+ return;
+
+ if (data->ic) {
+ char *mb = XmbResetIC(data->ic);
+ QInputMethodEvent e;
+ if (mb) {
+ e.setCommitString(QString::fromLocal8Bit(mb));
+ XFree(mb);
+ data->preeditEmpty = false; // force sending an event
+ }
+ if (!data->preeditEmpty) {
+ sendEvent(e);
+ update();
+ }
+ }
+ data->clear();
+}
+
+void QXIMInputContext::widgetDestroyed(QWidget *w)
+{
+ QInputContext::widgetDestroyed(w);
+ ICData *data = ximData.take(w->effectiveWinId());
+ if (!data)
+ return;
+
+ data->clear();
+ if (data->ic)
+ XDestroyIC(data->ic);
+ delete data;
+}
+
+void QXIMInputContext::mouseHandler(int pos, QMouseEvent *e)
+{
+ if(e->type() != QEvent::MouseButtonPress)
+ return;
+
+ XIM_DEBUG("QXIMInputContext::mouseHandler pos=%d", pos);
+ if (QWidget *w = focusWidget()) {
+ ICData *data = ximData.value(w->effectiveWinId());
+ if (!data)
+ return;
+ if (pos < 0 || pos > data->text.length())
+ reset();
+ // ##### handle mouse position
+ }
+}
+
+bool QXIMInputContext::isComposing() const
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return false;
+
+ ICData *data = ximData.value(w->effectiveWinId());
+ if (!data)
+ return false;
+ return data->composing;
+}
+
+void QXIMInputContext::setFocusWidget(QWidget *w)
+{
+ if (!xim)
+ return;
+ QWidget *oldFocus = focusWidget();
+ if (oldFocus == w)
+ return;
+
+ if (language() != QLatin1String("ja"))
+ reset();
+
+ if (oldFocus) {
+ ICData *data = ximData.value(oldFocus->effectiveWinId());
+ if (data && data->ic)
+ XUnsetICFocus(data->ic);
+ }
+
+ QInputContext::setFocusWidget(w);
+
+ if (!w || w->inputMethodHints() & (Qt::ImhExclusiveInputMask | Qt::ImhHiddenText))
+ return;
+
+ ICData *data = ximData.value(w->effectiveWinId());
+ if (!data)
+ data = createICData(w);
+
+ if (data->ic)
+ XSetICFocus(data->ic);
+
+ update();
+}
+
+
+bool QXIMInputContext::x11FilterEvent(QWidget *keywidget, XEvent *event)
+{
+ int xkey_keycode = event->xkey.keycode;
+ if (!keywidget->testAttribute(Qt::WA_WState_Created))
+ return false;
+ if (XFilterEvent(event, keywidget->effectiveWinId())) {
+ qt_ximComposingKeycode = xkey_keycode; // ### not documented in xlib
+
+ update();
+
+ return true;
+ }
+ if (event->type != XKeyPress || event->xkey.keycode != 0)
+ return false;
+
+ QWidget *w = focusWidget();
+ if (keywidget != w)
+ return false;
+ ICData *data = ximData.value(w->effectiveWinId());
+ if (!data)
+ return false;
+
+ // input method has sent us a commit string
+ QByteArray string;
+ string.resize(513);
+ KeySym key; // unused
+ Status status; // unused
+ QString text;
+ int count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(),
+ &key, &status);
+
+ if (status == XBufferOverflow) {
+ string.resize(count + 1);
+ count = XmbLookupString(data->ic, &event->xkey, string.data(), string.size(),
+ &key, &status);
+ }
+ if (count > 0) {
+ // XmbLookupString() gave us some text, convert it to unicode
+ text = qt_input_mapper->toUnicode(string.constData() , count);
+ if (text.isEmpty()) {
+ // codec couldn't convert to unicode? this can happen when running in the
+ // C locale (or with no LANG set). try converting from latin-1
+ text = QString::fromLatin1(string.constData(), count);
+ }
+ }
+
+#if 0
+ if (!(xim_style & XIMPreeditCallbacks) || !isComposing()) {
+ // ############### send a regular key event here!
+ ;
+ }
+#endif
+
+ QInputMethodEvent e;
+ e.setCommitString(text);
+ sendEvent(e);
+ data->clear();
+
+ update();
+
+ return true;
+}
+
+
+QXIMInputContext::ICData *QXIMInputContext::createICData(QWidget *w)
+{
+ ICData *data = new ICData;
+ data->widget = w;
+ data->preeditEmpty = true;
+
+ XVaNestedList preedit_attr = 0;
+ XIMCallback startcallback, drawcallback, donecallback;
+
+ QFont font = w->font();
+ data->fontset = getFontSet(font);
+
+ if (xim_style & XIMPreeditArea) {
+ XRectangle rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = w->width();
+ rect.height = w->height();
+
+ preedit_attr = XVaCreateNestedList(0,
+ XNArea, &rect,
+ XNFontSet, data->fontset,
+ (char *) 0);
+ } else if (xim_style & XIMPreeditPosition) {
+ XPoint spot;
+ spot.x = 1;
+ spot.y = 1;
+
+ preedit_attr = XVaCreateNestedList(0,
+ XNSpotLocation, &spot,
+ XNFontSet, data->fontset,
+ (char *) 0);
+ } else if (xim_style & XIMPreeditCallbacks) {
+ startcallback.client_data = (XPointer) this;
+ startcallback.callback = (XIMProc) xic_start_callback;
+ drawcallback.client_data = (XPointer) this;
+ drawcallback.callback = (XIMProc)xic_draw_callback;
+ donecallback.client_data = (XPointer) this;
+ donecallback.callback = (XIMProc) xic_done_callback;
+
+ preedit_attr = XVaCreateNestedList(0,
+ XNPreeditStartCallback, &startcallback,
+ XNPreeditDrawCallback, &drawcallback,
+ XNPreeditDoneCallback, &donecallback,
+ (char *) 0);
+ }
+
+ if (preedit_attr) {
+ data->ic = XCreateIC(xim,
+ XNInputStyle, xim_style,
+ XNClientWindow, w->effectiveWinId(),
+ XNPreeditAttributes, preedit_attr,
+ (char *) 0);
+ XFree(preedit_attr);
+ } else {
+ data->ic = XCreateIC(xim,
+ XNInputStyle, xim_style,
+ XNClientWindow, w->effectiveWinId(),
+ (char *) 0);
+ }
+
+ if (data->ic) {
+ // when resetting the input context, preserve the input state
+ (void) XSetICValues(data->ic, XNResetState, XIMPreserveState, (char *) 0);
+ } else {
+ qWarning("Failed to create XIC");
+ }
+
+ ximData[w->effectiveWinId()] = data;
+ return data;
+}
+
+void QXIMInputContext::update()
+{
+ QWidget *w = focusWidget();
+ if (!w)
+ return;
+
+ ICData *data = ximData.value(w->effectiveWinId());
+ if (!data || !data->ic)
+ return;
+
+ QRect r = w->inputMethodQuery(Qt::ImMicroFocus).toRect();
+ QPoint p;
+ if (w->nativeParentWidget())
+ p = w->mapTo(w->nativeParentWidget(), QPoint((r.left() + r.right() + 1)/2, r.bottom()));
+ else
+ p = QPoint((r.left() + r.right() + 1)/2, r.bottom());
+ XPoint spot;
+ spot.x = p.x();
+ spot.y = p.y();
+
+ r = w->rect();
+ XRectangle area;
+ area.x = r.x();
+ area.y = r.y();
+ area.width = r.width();
+ area.height = r.height();
+
+ XFontSet fontset = getFontSet(qvariant_cast<QFont>(w->inputMethodQuery(Qt::ImFont)));
+ if (data->fontset == fontset)
+ fontset = 0;
+ else
+ data->fontset = fontset;
+
+ XVaNestedList preedit_attr;
+ if (fontset)
+ preedit_attr = XVaCreateNestedList(0,
+ XNSpotLocation, &spot,
+ XNArea, &area,
+ XNFontSet, fontset,
+ (char *) 0);
+ else
+ preedit_attr = XVaCreateNestedList(0,
+ XNSpotLocation, &spot,
+ XNArea, &area,
+ (char *) 0);
+
+ XSetICValues(data->ic, XNPreeditAttributes, preedit_attr, (char *) 0);
+ XFree(preedit_attr);
+}
+
+
+#else
+/*
+ When QT_NO_XIM is defined, we provide a dummy implementation for
+ this class. The reason for this is that the header file is moc'ed
+ regardless of QT_NO_XIM. The best would be to remove the file
+ completely from the pri file is QT_NO_XIM was defined, or for moc
+ to understand this preprocessor directive. Since the header does
+ not declare this class when QT_NO_XIM is defined, this is dead
+ code.
+*/
+bool QXIMInputContext::isComposing() const { return false; }
+QString QXIMInputContext::identifierName() { return QString(); }
+void QXIMInputContext::mouseHandler(int, QMouseEvent *) {}
+void QXIMInputContext::setFocusWidget(QWidget *) {}
+void QXIMInputContext::reset() {}
+void QXIMInputContext::update() {}
+QXIMInputContext::~QXIMInputContext() {}
+void QXIMInputContext::widgetDestroyed(QWidget *) {}
+QString QXIMInputContext::language() { return QString(); }
+bool QXIMInputContext::x11FilterEvent(QWidget *, XEvent *) { return true; }
+
+#endif //QT_NO_XIM
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_IM