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 <lars.knoll@theqtcompany.com>
This commit is contained in:
parent
424e6386c6
commit
a1bfa39651
@ -39,6 +39,10 @@
|
|||||||
#include <qwindow.h>
|
#include <qwindow.h>
|
||||||
#include <qevent.h>
|
#include <qevent.h>
|
||||||
|
|
||||||
|
#include <qpa/qplatformcursor.h>
|
||||||
|
#include <qpa/qplatformscreen.h>
|
||||||
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
|
|
||||||
#include "qibusproxy.h"
|
#include "qibusproxy.h"
|
||||||
#include "qibusinputcontextproxy.h"
|
#include "qibusinputcontextproxy.h"
|
||||||
#include "qibustypes.h"
|
#include "qibustypes.h"
|
||||||
@ -48,8 +52,14 @@
|
|||||||
|
|
||||||
#include <QtDBus>
|
#include <QtDBus>
|
||||||
|
|
||||||
|
#ifndef IBUS_RELEASE_MASK
|
||||||
|
#define IBUS_RELEASE_MASK (1 << 30)
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_LOGGING_CATEGORY(qtQpaInputMethods, "qt.qpa.input.methods")
|
||||||
|
|
||||||
enum { debug = 0 };
|
enum { debug = 0 };
|
||||||
|
|
||||||
class QIBusPlatformInputContextPrivate
|
class QIBusPlatformInputContextPrivate
|
||||||
@ -86,6 +96,13 @@ QIBusPlatformInputContext::QIBusPlatformInputContext ()
|
|||||||
}
|
}
|
||||||
QInputMethod *p = qApp->inputMethod();
|
QInputMethod *p = qApp->inputMethod();
|
||||||
connect(p, SIGNAL(cursorRectangleChanged()), this, SLOT(cursorRectChanged()));
|
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)
|
QIBusPlatformInputContext::~QIBusPlatformInputContext (void)
|
||||||
@ -272,8 +289,7 @@ void QIBusPlatformInputContext::deleteSurroundingText(int offset, uint n_chars)
|
|||||||
QCoreApplication::sendEvent(input, &event);
|
QCoreApplication::sendEvent(input, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool QIBusPlatformInputContext::filterEvent(const QEvent *event)
|
||||||
QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, bool press)
|
|
||||||
{
|
{
|
||||||
if (!d->valid)
|
if (!d->valid)
|
||||||
return false;
|
return false;
|
||||||
@ -281,15 +297,89 @@ QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state,
|
|||||||
if (!inputMethodAccepted())
|
if (!inputMethodAccepted())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!press)
|
const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event);
|
||||||
return false;
|
quint32 sym = keyEvent->nativeVirtualKey();
|
||||||
|
quint32 code = keyEvent->nativeScanCode();
|
||||||
|
quint32 state = keyEvent->nativeModifiers();
|
||||||
|
|
||||||
keycode -= 8; // ###
|
if (keyEvent->type() != QEvent::KeyPress)
|
||||||
QDBusReply<bool> reply = d->context->ProcessKeyEvent(keyval, keycode, state);
|
state |= IBUS_RELEASE_MASK;
|
||||||
|
|
||||||
// qDebug() << "x11FilterEvent return" << reply.value();
|
code -= 8; // ###
|
||||||
|
QDBusPendingReply<bool> reply = d->context->ProcessKeyEvent(sym, code, state);
|
||||||
|
|
||||||
return reply.value();
|
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<uint>(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);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QIBusPlatformInputContext::filterEventFinished(QDBusPendingCallWatcher *call)
|
||||||
|
{
|
||||||
|
QIBusFilterEventWatcher *watcher = (QIBusFilterEventWatcher *) call;
|
||||||
|
QDBusPendingReply<bool> reply = *call;
|
||||||
|
|
||||||
|
if (reply.isError()) {
|
||||||
|
call->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use watcher's window instead of the current focused window
|
||||||
|
// since there is a time lag until filterEventFinished() returns.
|
||||||
|
QObject *input = watcher->input();
|
||||||
|
|
||||||
|
if (!input) {
|
||||||
|
call->deleteLater();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::KeyboardModifiers modifiers = watcher->modifiers();
|
||||||
|
QVariantList args = watcher->arguments();
|
||||||
|
const ulong time = static_cast<const ulong>(args.at(0).toUInt());
|
||||||
|
const QEvent::Type type = static_cast<const QEvent::Type>(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<QWindow *>(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()
|
QIBusPlatformInputContextPrivate::QIBusPlatformInputContextPrivate()
|
||||||
|
@ -35,11 +35,43 @@
|
|||||||
|
|
||||||
#include <qpa/qplatforminputcontext.h>
|
#include <qpa/qplatforminputcontext.h>
|
||||||
|
|
||||||
|
#include <QtCore/qpointer.h>
|
||||||
|
#include <QtDBus/qdbuspendingreply.h>
|
||||||
|
#include <QLoggingCategory>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_DECLARE_LOGGING_CATEGORY(qtQpaInputMethods)
|
||||||
|
|
||||||
class QIBusPlatformInputContextPrivate;
|
class QIBusPlatformInputContextPrivate;
|
||||||
class QDBusVariant;
|
class QDBusVariant;
|
||||||
|
|
||||||
|
class QIBusFilterEventWatcher: public QDBusPendingCallWatcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QIBusFilterEventWatcher(const QDBusPendingCall &call,
|
||||||
|
QObject *parent = 0,
|
||||||
|
QObject *input = 0,
|
||||||
|
const Qt::KeyboardModifiers modifiers = 0,
|
||||||
|
const QVariantList arguments = QVariantList())
|
||||||
|
: QDBusPendingCallWatcher(call, parent)
|
||||||
|
, m_input(input)
|
||||||
|
, m_modifiers(modifiers)
|
||||||
|
, m_arguments(arguments)
|
||||||
|
{}
|
||||||
|
~QIBusFilterEventWatcher()
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline QObject *input() const { return m_input; }
|
||||||
|
inline const Qt::KeyboardModifiers modifiers() const { return m_modifiers; }
|
||||||
|
inline const QVariantList arguments() const { return m_arguments; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
QPointer<QObject> m_input;
|
||||||
|
const Qt::KeyboardModifiers m_modifiers;
|
||||||
|
const QVariantList m_arguments;
|
||||||
|
};
|
||||||
|
|
||||||
class QIBusPlatformInputContext : public QPlatformInputContext
|
class QIBusPlatformInputContext : public QPlatformInputContext
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -54,8 +86,7 @@ public:
|
|||||||
void reset() Q_DECL_OVERRIDE;
|
void reset() Q_DECL_OVERRIDE;
|
||||||
void commit() Q_DECL_OVERRIDE;
|
void commit() Q_DECL_OVERRIDE;
|
||||||
void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE;
|
void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE;
|
||||||
|
bool filterEvent(const QEvent *event) Q_DECL_OVERRIDE;
|
||||||
Q_INVOKABLE bool x11FilterEvent(uint keyval, uint keycode, uint state, bool press);
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void commitText(const QDBusVariant &text);
|
void commitText(const QDBusVariant &text);
|
||||||
@ -63,9 +94,11 @@ public Q_SLOTS:
|
|||||||
void cursorRectChanged();
|
void cursorRectChanged();
|
||||||
void deleteSurroundingText(int offset, uint n_chars);
|
void deleteSurroundingText(int offset, uint n_chars);
|
||||||
void surroundingTextRequired();
|
void surroundingTextRequired();
|
||||||
|
void filterEventFinished(QDBusPendingCallWatcher *call);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QIBusPlatformInputContextPrivate *d;
|
QIBusPlatformInputContextPrivate *d;
|
||||||
|
bool m_eventFilterUseSynchronousMode;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user