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