From a1bfa3965102972323a1f6407036df3f65dcce2c Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Wed, 1 Jul 2015 14:24:43 +0900 Subject: Use ibus ProcessKeyEvent asynchronously. ibus-hangul sends "CommitText" dbus asynchronous API during "ProcessKeyEvent" dbus API is called. If "ProcessKeyEvent" is synchronous, "ProcessKeyEvent" finishes before "CommitText" finishes and the order of Hangul characters and space is not correct. Task-number: QTBUG-40541 Change-Id: Ia526bc11833853082205ef1c3d64cf7943e2274f Reviewed-by: Lars Knoll --- .../ibus/qibusplatforminputcontext.cpp | 106 +++++++++++++++++++-- 1 file changed, 98 insertions(+), 8 deletions(-) (limited to 'src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp') diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp index 0b5775bc15..4a276dc834 100644 --- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp +++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp @@ -39,6 +39,10 @@ #include #include +#include +#include +#include + #include "qibusproxy.h" #include "qibusinputcontextproxy.h" #include "qibustypes.h" @@ -48,8 +52,14 @@ #include +#ifndef IBUS_RELEASE_MASK +#define IBUS_RELEASE_MASK (1 << 30) +#endif + QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(qtQpaInputMethods, "qt.qpa.input.methods") + enum { debug = 0 }; class QIBusPlatformInputContextPrivate @@ -86,6 +96,13 @@ QIBusPlatformInputContext::QIBusPlatformInputContext () } QInputMethod *p = qApp->inputMethod(); connect(p, SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged())); + m_eventFilterUseSynchronousMode = false; + if (qEnvironmentVariableIsSet("IBUS_ENABLE_SYNC_MODE")) { + bool ok; + int enableSync = qgetenv("IBUS_ENABLE_SYNC_MODE").toInt(&ok); + if (ok && enableSync == 1) + m_eventFilterUseSynchronousMode = true; + } } QIBusPlatformInputContext::~QIBusPlatformInputContext (void) @@ -272,8 +289,7 @@ void QIBusPlatformInputContext::deleteSurroundingText(int offset, uint n_chars) QCoreApplication::sendEvent(input, &event); } -bool -QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, bool press) +bool QIBusPlatformInputContext::filterEvent(const QEvent *event) { if (!d->valid) return false; @@ -281,15 +297,89 @@ QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, if (!inputMethodAccepted()) return false; - if (!press) - return false; + const QKeyEvent *keyEvent = static_cast(event); + quint32 sym = keyEvent->nativeVirtualKey(); + quint32 code = keyEvent->nativeScanCode(); + quint32 state = keyEvent->nativeModifiers(); + + if (keyEvent->type() != QEvent::KeyPress) + state |= IBUS_RELEASE_MASK; + + code -= 8; // ### + QDBusPendingReply reply = d->context->ProcessKeyEvent(sym, code, state); + + if (m_eventFilterUseSynchronousMode || reply.isFinished()) { + bool retval = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEvent return" << code << sym << state << retval; + return retval; + } + + Qt::KeyboardModifiers modifiers = keyEvent->modifiers(); + + QVariantList args; + args << QVariant::fromValue(keyEvent->timestamp()); + args << QVariant::fromValue(static_cast(keyEvent->type())); + args << QVariant::fromValue(keyEvent->key()); + args << QVariant::fromValue(code) << QVariant::fromValue(sym) << QVariant::fromValue(state); + args << QVariant::fromValue(keyEvent->text()); + args << QVariant::fromValue(keyEvent->isAutoRepeat()); + args << QVariant::fromValue(keyEvent->count()); + + QIBusFilterEventWatcher *watcher = new QIBusFilterEventWatcher(reply, this, qApp->focusObject(), modifiers, args); + QObject::connect(watcher, &QDBusPendingCallWatcher::finished, this, &QIBusPlatformInputContext::filterEventFinished); - keycode -= 8; // ### - QDBusReply reply = d->context->ProcessKeyEvent(keyval, keycode, state); + return true; +} + +void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *call) +{ + QIBusFilterEventWatcher *watcher = (QIBusFilterEventWatcher *) call; + QDBusPendingReply reply = *call; + + if (reply.isError()) { + call->deleteLater(); + return; + } -// qDebug() << "x11FilterEvent return" << reply.value(); + // Use watcher's window instead of the current focused window + // since there is a time lag until filterEventFinished() returns. + QObject *input = watcher->input(); - return reply.value(); + if (!input) { + call->deleteLater(); + return; + } + + Qt::KeyboardModifiers modifiers = watcher->modifiers(); + QVariantList args = watcher->arguments(); + const ulong time = static_cast(args.at(0).toUInt()); + const QEvent::Type type = static_cast(args.at(1).toUInt()); + const int qtcode = args.at(2).toInt(); + const quint32 code = args.at(3).toUInt(); + const quint32 sym = args.at(4).toUInt(); + const quint32 state = args.at(5).toUInt(); + const QString string = args.at(6).toString(); + const bool isAutoRepeat = args.at(7).toBool(); + const int count = args.at(8).toInt(); + + // copied from QXcbKeyboard::handleKeyEvent() + bool retval = reply.value(); + qCDebug(qtQpaInputMethods) << "filterEventFinished return" << code << sym << state << retval; + if (!retval) { + QWindow *window = dynamic_cast(input); + if (type == QEvent::KeyPress && qtcode == Qt::Key_Menu + && window != NULL) { + const QPoint globalPos = window->screen()->handle()->cursor()->pos(); + const QPoint pos = window->mapFromGlobal(globalPos); + QWindowSystemInterface::handleContextMenuEvent(window, false, pos, + globalPos, modifiers); + } + QKeyEvent event(type, qtcode, modifiers, code, sym, + state, string, isAutoRepeat, count); + event.setTimestamp(time); + QCoreApplication::sendEvent(input, &event); + } + call->deleteLater(); } QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate() -- cgit v1.2.3