diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:18:55 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:18:55 (GMT) |
commit | e5fcad302d86d316390c6b0f62759a067313e8a9 (patch) | |
tree | c2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/gui/inputmethod | |
download | Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.zip Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.gz Qt-e5fcad302d86d316390c6b0f62759a067313e8a9.tar.bz2 |
Long live Qt 4.5!
Diffstat (limited to 'src/gui/inputmethod')
-rw-r--r-- | src/gui/inputmethod/inputmethod.pri | 26 | ||||
-rw-r--r-- | src/gui/inputmethod/qinputcontext.cpp | 464 | ||||
-rw-r--r-- | src/gui/inputmethod/qinputcontext.h | 134 | ||||
-rw-r--r-- | src/gui/inputmethod/qinputcontext_p.h | 98 | ||||
-rw-r--r-- | src/gui/inputmethod/qinputcontextfactory.cpp | 287 | ||||
-rw-r--r-- | src/gui/inputmethod/qinputcontextfactory.h | 88 | ||||
-rw-r--r-- | src/gui/inputmethod/qinputcontextplugin.cpp | 178 | ||||
-rw-r--r-- | src/gui/inputmethod/qinputcontextplugin.h | 106 | ||||
-rw-r--r-- | src/gui/inputmethod/qmacinputcontext_mac.cpp | 349 | ||||
-rw-r--r-- | src/gui/inputmethod/qmacinputcontext_p.h | 92 | ||||
-rw-r--r-- | src/gui/inputmethod/qwininputcontext_p.h | 96 | ||||
-rw-r--r-- | src/gui/inputmethod/qwininputcontext_win.cpp | 861 | ||||
-rw-r--r-- | src/gui/inputmethod/qwsinputcontext_p.h | 96 | ||||
-rw-r--r-- | src/gui/inputmethod/qwsinputcontext_qws.cpp | 239 | ||||
-rw-r--r-- | src/gui/inputmethod/qximinputcontext_p.h | 141 | ||||
-rw-r--r-- | src/gui/inputmethod/qximinputcontext_x11.cpp | 832 |
16 files changed, 4087 insertions, 0 deletions
diff --git a/src/gui/inputmethod/inputmethod.pri b/src/gui/inputmethod/inputmethod.pri new file mode 100644 index 0000000..d321cd4 --- /dev/null +++ b/src/gui/inputmethod/inputmethod.pri @@ -0,0 +1,26 @@ +# 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 { + HEADERS += inputmethod/qmacinputcontext_p.h + SOURCES += inputmethod/qmacinputcontext_mac.cpp +} + diff --git a/src/gui/inputmethod/qinputcontext.cpp b/src/gui/inputmethod/qinputcontext.cpp new file mode 100644 index 0000000..f78b86a --- /dev/null +++ b/src/gui/inputmethod/qinputcontext.cpp @@ -0,0 +1,464 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 to input 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 is belonging 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 + + \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() +{ +} + +/*! + \internal + Returns the widget that has an input focus for this input + context. Ordinary input methods should not call this function + directly to keep platform independence and flexible configuration + possibility. + + The return value may differ from holderWidget() if the input + context is shared between several text widgets. + + \sa setFocusWidget(), holderWidget() +*/ +QWidget *QInputContext::focusWidget() const +{ + Q_D(const QInputContext); + return d->focusWidget; +} + + +/*! + \internal + Sets the widget that has an input focus for this input + context. 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 QKeyEvent. 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); + qApp->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::MouseButtonMove. 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. + + You must not send any QInputMethodEvent except empty InputMethodEnd event using + QInputContext::reset() at reimplemented reset(). It will break + 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() : qApp->palette(); + + QTextCharFormat fmt; + QColor bg; + switch (s) { + case QInputContext::PreeditFormat: { + fmt.setUnderlineStyle(QTextCharFormat::DashUnderline); +#ifndef Q_WS_WIN + int h1, s1, v1, h2, s2, v2; + pal.color(QPalette::Base).getHsv(&h1, &s1, &v1); + pal.color(QPalette::Background).getHsv(&h2, &s2, &v2); + bg.setHsv(h1, s1, (v1 + v2) / 2); + fmt.setBackground(QBrush(bg)); +#endif + 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 + +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 0000000..bcaa7fe --- /dev/null +++ b/src/gui/inputmethod/qinputcontext.h @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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; + + +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 + 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 0000000..8c1b8de --- /dev/null +++ b/src/gui/inputmethod/qinputcontext_p.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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; + +#if defined(Q_WS_WIN) || defined(Q_WS_QWS) + static void updateImeStatus(QWidget *w, bool hasFocus); +#endif +}; + +QT_END_NAMESPACE + +#endif + +#endif + diff --git a/src/gui/inputmethod/qinputcontextfactory.cpp b/src/gui/inputmethod/qinputcontextfactory.cpp new file mode 100644 index 0000000..06625f9 --- /dev/null +++ b/src/gui/inputmethod/qinputcontextfactory.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 + +#include "private/qfactoryloader_p.h" +#include "qmutex.h" + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) +Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, + (QInputContextFactoryInterface_iid, QLatin1String("/inputmethods"))) +#endif + +/*! + \class QInputContextFactory + \brief The QInputContextFactory class creates QInputContext objects. + + \ingroup appearance + + 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(QT_NO_LIBRARY) || defined(QT_NO_SETTINGS) + 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(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS) + result += loader()->keys(); +#endif // QT_NO_LIBRARY + return result; +} + +/*! + 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(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 +#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(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 0000000..bc17fd3 --- /dev/null +++ b/src/gui/inputmethod/qinputcontextfactory.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 0000000..69b4800 --- /dev/null +++ b/src/gui/inputmethod/qinputcontextplugin.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 0000000..6c57284 --- /dev/null +++ b/src/gui/inputmethod/qinputcontextplugin.h @@ -0,0 +1,106 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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) && !defined(QT_NO_LIBRARY) + +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 0000000..f0e7ea9 --- /dev/null +++ b/src/gui/inputmethod/qmacinputcontext_mac.cpp @@ -0,0 +1,349 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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> + +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 + +static QTextFormat qt_mac_compose_format() +{ + QTextCharFormat ret; + ret.setFontUnderline(true); + return ret; +} + +QMacInputContext::QMacInputContext(QObject *parent) + : QInputContext(parent), composing(false), recursionGuard(false), textDocument(0) +{ +// createTextDocument(); +} + +QMacInputContext::~QMacInputContext() +{ +#ifdef Q_WS_MAC32 + if(textDocument) + DeleteTSMDocument(textDocument); +#endif +} + +void +QMacInputContext::createTextDocument() +{ +#ifdef Q_WS_MAC32 + if(!textDocument) { + InterfaceTypeList itl = { kUnicodeDocument }; + NewTSMDocument(1, itl, &textDocument, SRefCon(this)); + } +#endif +} + + +QString QMacInputContext::language() +{ + return QString(); +} + + +void QMacInputContext::mouseHandler(int pos, QMouseEvent *e) +{ +#ifdef Q_WS_MAC32 + if(e->type() != QEvent::MouseButtonPress) + return; + + if (!composing) + return; + if (pos < 0 || pos > currentText.length()) + reset(); + // ##### handle mouse position +#endif +} + +#if !defined QT_MAC_USE_COCOA + +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(); +#ifdef Q_WS_MAC32 + if(w) + ActivateTSMDocument(textDocument); + else + DeactivateTSMDocument(textDocument); +#endif + QInputContext::setFocusWidget(w); +} + + +static EventTypeSpec input_events[] = { + { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, + { kEventClassTextInput, kEventTextInputOffsetToPos }, + { kEventClassTextInput, kEventTextInputUpdateActiveInputArea } +}; +static EventHandlerUPP input_proc_handlerUPP = 0; +static EventHandlerRef input_proc_handler = 0; + +void +QMacInputContext::initialize() +{ +#ifdef Q_WS_MAC32 + 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() +{ +#ifdef Q_WS_MAC32 + 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 +} + +OSStatus +QMacInputContext::globalEventProcessor(EventHandlerCallRef, EventRef event, void *) +{ +#ifdef Q_WS_MAC32 + 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; + if(!widget || (context && widget->inputContext() != context)) { + 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); + } + break; } + default: + break; + } + if(!handled_event) //let the event go through + return eventNotHandledErr; +#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 0000000..f708040 --- /dev/null +++ b/src/gui/inputmethod/qmacinputcontext_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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(); +protected: + void mouseHandler(int pos, QMouseEvent *); +private: + bool composing; + bool recursionGuard; + TSMDocumentID textDocument; + QString currentText; +}; + +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 0000000..38d7e32 --- /dev/null +++ b/src/gui/inputmethod/qwininputcontext_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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" + +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); + + static void TranslateMessage(const MSG *msg); + static LRESULT DefWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + + 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 0000000..720f0b8 --- /dev/null +++ b/src/gui/inputmethod/qwininputcontext_win.cpp @@ -0,0 +1,861 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwininputcontext_p.h" +#include "qinputcontext_p.h" + +#include "qfont.h" +#include "qwidget.h" +#include "qapplication.h" +#include "qlibrary.h" +#include "qevent.h" +#include "qtextformat.h" + +//#define Q_IME_DEBUG + +/* Active Input method support on Win95/98/NT */ +#include <objbase.h> +#include <initguid.h> + +#ifdef Q_IME_DEBUG +#include "qdebug.h" +#endif + +QT_BEGIN_NAMESPACE + +extern bool qt_sendSpontaneousEvent(QObject*, QEvent*); +#if defined(Q_OS_WINCE) +extern void qt_wince_show_SIP(bool show); // defined in qguifunctions_wince.cpp +#endif + +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) +{ + if (QSysInfo::WindowsVersion < QSysInfo::WV_2000) { + // try to get the Active IMM COM object on Win95/98/NT, where english versions don't + // support the regular Windows input methods. + if (CoCreateInstance(CLSID_CActiveIMM, NULL, CLSCTX_INPROC_SERVER, + IID_IActiveIMMApp, (LPVOID *)&aimm) != S_OK) { + aimm = 0; + } + if (aimm && (aimm->QueryInterface(IID_IActiveIMMMessagePumpOwner, (LPVOID *)&aimmpump) != S_OK || + aimm->Activate(true) != S_OK)) { + aimm->Release(); + aimm = 0; + if (aimmpump) + aimmpump->Release(); + aimmpump = 0; + } + if (aimmpump) + aimmpump->Start(); + } + +#ifndef Q_OS_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 + typedef BOOL(WINAPI *PtrIsValidLanguageGroup)(DWORD,DWORD); + PtrIsValidLanguageGroup isValidLanguageGroup = (PtrIsValidLanguageGroup)QLibrary::resolve(QLatin1String("kernel32"), "IsValidLanguageGroup"); + if (isValidLanguageGroup) { + qt_use_rtl_extensions = isValidLanguageGroup(LGRPID_ARABIC, LGRPID_INSTALLED) + || isValidLanguageGroup(LGRPID_HEBREW, LGRPID_INSTALLED); + } + qt_use_rtl_extensions |= 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 = QT_WA_INLINE(RegisterWindowMessage(L"MSIMEMouseOperation"), RegisterWindowMessageA("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, bool *unicode = 0) +{ + LONG len = 0; + if (unicode) + *unicode = true; + if (aimm) + aimm->GetCompositionStringW(himc, dwIndex, dBufLen, &len, lpbuf); + else + { + if(QSysInfo::WindowsVersion != QSysInfo::WV_95) { + len = ImmGetCompositionStringW(himc, dwIndex, lpbuf, dBufLen); + } +#if !defined(Q_OS_WINCE) + else { + len = ImmGetCompositionStringA(himc, dwIndex, lpbuf, dBufLen); + if (unicode) + *unicode = false; + } +#endif + } + 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) +{ + static char *buffer = 0; + static int buflen = 0; + + int len = getCompositionString(himc, dwindex, 0, 0) + 1; + if (!buffer || len > buflen) { + delete [] buffer; + buflen = qMin(len, 256); + buffer = new char[buflen]; + } + + bool unicode = true; + len = getCompositionString(himc, dwindex, buffer, buflen, &unicode); + + if (selStart) { + static char *attrbuffer = 0; + static int attrbuflen = 0; + int attrlen = getCompositionString(himc, dwindex, 0, 0) + 1; + if (!attrbuffer || attrlen> attrbuflen) { + delete [] attrbuffer; + attrbuflen = qMin(attrlen, 256); + attrbuffer = new char[attrbuflen]; + } + attrlen = getCompositionString(himc, GCS_COMPATTR, attrbuffer, attrbuflen); + *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(); + if (unicode) { + return QString((QChar *)buffer, len/sizeof(QChar)); + } + else { + buffer[len] = 0; + WCHAR *wc = new WCHAR[len+1]; + int l = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, + buffer, len, wc, len+1); + QString res = QString((QChar *)wc, l); + delete [] wc; + return res; + } +} + +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) + { + QT_WA({ + retval = ::DefWindowProc(hwnd, msg, wParam, lParam); + } , { + retval = ::DefWindowProcA(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(); + + QT_WA({ + LOGFONT lf; + if (GetObject(hf, sizeof(lf), &lf)) + if (aimm) + aimm->SetCompositionFontW(imc, &lf); + else + ImmSetCompositionFont(imc, &lf); + } , { + LOGFONTA lf; + if (GetObjectA(hf, sizeof(lf), &lf)) + if (aimm) + aimm->SetCompositionFontA(imc, &lf); + else + ImmSetCompositionFontA(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 = qApp->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 = qApp->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_OS_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_OS_WINCE + if (qApp->autoSipEnabled()) + qt_wince_show_SIP(false); +#endif + } +} + + +void QInputContextPrivate::updateImeStatus(QWidget *w, bool hasFocus) +{ + if (!w) + return; + bool e = w->testAttribute(Qt::WA_InputMethodEnabled) && w->isEnabled(); + 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) +{ + 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(); +} + +QT_END_NAMESPACE diff --git a/src/gui/inputmethod/qwsinputcontext_p.h b/src/gui/inputmethod/qwsinputcontext_p.h new file mode 100644 index 0000000..20811da --- /dev/null +++ b/src/gui/inputmethod/qwsinputcontext_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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); +}; + +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 0000000..46ac13d --- /dev/null +++ b/src/gui/inputmethod/qwsinputcontext_qws.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 (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 == ::activeWidget) + ::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 ::activeWidget; +} + + +bool QWSInputContext::isComposing() const +{ + return ::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() && ::activeWidget) + w = ::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()) + ::activeWidget = 0; + else + ::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 QInputContextPrivate::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 0000000..ca2103b --- /dev/null +++ b/src/gui/inputmethod/qximinputcontext_p.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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; + 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 0000000..48a96b1 --- /dev/null +++ b/src/gui/inputmethod/qximinputcontext_x11.cpp @@ -0,0 +1,832 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@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 "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); + 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; +} + +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]; +} + + + +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 +} + + +/*!\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)) + 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); + } + 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) + 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; + + 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 |