Implement focus change for Windows Input context.
Keep track of the focus object in the input context ensuring that events on canceling are sent to the right object. Task-number: QTBUG-40402 Change-Id: I79820db94d97e21b47abc8fe2bae6fa012d31236 Reviewed-by: Liang Qi <liang.qi@digia.com> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
parent
219c2eb4e2
commit
501fe9f939
@ -83,6 +83,10 @@ static inline QByteArray debugComposition(int lParam)
|
|||||||
// Cancel current IME composition.
|
// Cancel current IME composition.
|
||||||
static inline void imeNotifyCancelComposition(HWND hwnd)
|
static inline void imeNotifyCancelComposition(HWND hwnd)
|
||||||
{
|
{
|
||||||
|
if (!hwnd) {
|
||||||
|
qWarning() << __FUNCTION__ << "called with" << hwnd;
|
||||||
|
return;
|
||||||
|
}
|
||||||
const HIMC himc = ImmGetContext(hwnd);
|
const HIMC himc = ImmGetContext(hwnd);
|
||||||
ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
ImmNotifyIME(himc, NI_COMPOSITIONSTR, CPS_CANCEL, 0);
|
||||||
ImmReleaseContext(hwnd, himc);
|
ImmReleaseContext(hwnd, himc);
|
||||||
@ -175,21 +179,27 @@ void QWindowsInputContext::reset()
|
|||||||
QPlatformInputContext::reset();
|
QPlatformInputContext::reset();
|
||||||
if (!m_compositionContext.hwnd)
|
if (!m_compositionContext.hwnd)
|
||||||
return;
|
return;
|
||||||
QObject *fo = qApp->focusObject();
|
qCDebug(lcQpaInputMethods) << __FUNCTION__;
|
||||||
qCDebug(lcQpaInputMethods) << __FUNCTION__<< fo;
|
if (m_compositionContext.isComposing && m_compositionContext.focusObject.isNull()) {
|
||||||
if (!fo)
|
|
||||||
return;
|
|
||||||
if (m_compositionContext.isComposing) {
|
|
||||||
QInputMethodEvent event;
|
QInputMethodEvent event;
|
||||||
if (!m_compositionContext.composition.isEmpty())
|
if (!m_compositionContext.composition.isEmpty())
|
||||||
event.setCommitString(m_compositionContext.composition);
|
event.setCommitString(m_compositionContext.composition);
|
||||||
QCoreApplication::sendEvent(fo, &event);
|
QCoreApplication::sendEvent(m_compositionContext.focusObject, &event);
|
||||||
endContextComposition();
|
endContextComposition();
|
||||||
}
|
}
|
||||||
imeNotifyCancelComposition(m_compositionContext.hwnd);
|
imeNotifyCancelComposition(m_compositionContext.hwnd);
|
||||||
doneContext();
|
doneContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QWindowsInputContext::setFocusObject(QObject *)
|
||||||
|
{
|
||||||
|
// ### fixme: On Windows 8.1, it has been observed that the Input context
|
||||||
|
// remains active when this happens resulting in a lock-up. Consecutive
|
||||||
|
// key events still have VK_PROCESSKEY set and are thus ignored.
|
||||||
|
if (m_compositionContext.isComposing)
|
||||||
|
imeNotifyCancelComposition(m_compositionContext.hwnd);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Moves the candidate window along with microfocus of the focus object.
|
\brief Moves the candidate window along with microfocus of the focus object.
|
||||||
*/
|
*/
|
||||||
@ -317,7 +327,7 @@ static inline QTextFormat standardFormat(StandardFormat format)
|
|||||||
|
|
||||||
bool QWindowsInputContext::startComposition(HWND hwnd)
|
bool QWindowsInputContext::startComposition(HWND hwnd)
|
||||||
{
|
{
|
||||||
const QObject *fo = qApp->focusObject();
|
QObject *fo = QGuiApplication::focusObject();
|
||||||
if (!fo)
|
if (!fo)
|
||||||
return false;
|
return false;
|
||||||
// This should always match the object.
|
// This should always match the object.
|
||||||
@ -327,7 +337,7 @@ bool QWindowsInputContext::startComposition(HWND hwnd)
|
|||||||
qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window;
|
qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window;
|
||||||
if (!fo || QWindowsWindow::handleOf(window) != hwnd)
|
if (!fo || QWindowsWindow::handleOf(window) != hwnd)
|
||||||
return false;
|
return false;
|
||||||
initContext(hwnd);
|
initContext(hwnd, fo);
|
||||||
startContextComposition();
|
startContextComposition();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -341,6 +351,7 @@ void QWindowsInputContext::startContextComposition()
|
|||||||
m_compositionContext.isComposing = true;
|
m_compositionContext.isComposing = true;
|
||||||
m_compositionContext.composition.clear();
|
m_compositionContext.composition.clear();
|
||||||
m_compositionContext.position = 0;
|
m_compositionContext.position = 0;
|
||||||
|
cursorRectChanged(); // position cursor initially.
|
||||||
update(Qt::ImQueryAll);
|
update(Qt::ImQueryAll);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,11 +395,10 @@ static inline QList<QInputMethodEvent::Attribute>
|
|||||||
|
|
||||||
bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn)
|
bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn)
|
||||||
{
|
{
|
||||||
QObject *fo = qApp->focusObject();
|
|
||||||
const int lParam = int(lParamIn);
|
const int lParam = int(lParamIn);
|
||||||
qCDebug(lcQpaInputMethods) << '>' << __FUNCTION__ << fo << debugComposition(lParam)
|
qCDebug(lcQpaInputMethods) << '>' << __FUNCTION__ << m_compositionContext.focusObject
|
||||||
<< " composing=" << m_compositionContext.isComposing;
|
<< debugComposition(lParam) << " composing=" << m_compositionContext.isComposing;
|
||||||
if (!fo || m_compositionContext.hwnd != hwnd || !lParam)
|
if (m_compositionContext.focusObject.isNull() || m_compositionContext.hwnd != hwnd || !lParam)
|
||||||
return false;
|
return false;
|
||||||
const HIMC himc = ImmGetContext(m_compositionContext.hwnd);
|
const HIMC himc = ImmGetContext(m_compositionContext.hwnd);
|
||||||
if (!himc)
|
if (!himc)
|
||||||
@ -425,10 +435,10 @@ bool QWindowsInputContext::composition(HWND hwnd, LPARAM lParamIn)
|
|||||||
event->setCommitString(getCompositionString(himc, GCS_RESULTSTR));
|
event->setCommitString(getCompositionString(himc, GCS_RESULTSTR));
|
||||||
endContextComposition();
|
endContextComposition();
|
||||||
}
|
}
|
||||||
const bool result = QCoreApplication::sendEvent(fo, event.data());
|
const bool result = QCoreApplication::sendEvent(m_compositionContext.focusObject, event.data());
|
||||||
qCDebug(lcQpaInputMethods) << '<' << __FUNCTION__ << "sending markup="
|
qCDebug(lcQpaInputMethods) << '<' << __FUNCTION__ << "sending markup="
|
||||||
<< event->attributes().size() << " commit=" << event->commitString()
|
<< event->attributes().size() << " commit=" << event->commitString()
|
||||||
<< " to " << fo << " returns " << result;
|
<< " to " << m_compositionContext.focusObject << " returns " << result;
|
||||||
update(Qt::ImQueryAll);
|
update(Qt::ImQueryAll);
|
||||||
ImmReleaseContext(m_compositionContext.hwnd, himc);
|
ImmReleaseContext(m_compositionContext.hwnd, himc);
|
||||||
return result;
|
return result;
|
||||||
@ -442,8 +452,7 @@ bool QWindowsInputContext::endComposition(HWND hwnd)
|
|||||||
// against that.
|
// against that.
|
||||||
if (m_endCompositionRecursionGuard || m_compositionContext.hwnd != hwnd)
|
if (m_endCompositionRecursionGuard || m_compositionContext.hwnd != hwnd)
|
||||||
return false;
|
return false;
|
||||||
QObject *fo = qApp->focusObject();
|
if (m_compositionContext.focusObject.isNull())
|
||||||
if (!fo)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_endCompositionRecursionGuard = true;
|
m_endCompositionRecursionGuard = true;
|
||||||
@ -451,7 +460,7 @@ bool QWindowsInputContext::endComposition(HWND hwnd)
|
|||||||
imeNotifyCancelComposition(m_compositionContext.hwnd);
|
imeNotifyCancelComposition(m_compositionContext.hwnd);
|
||||||
if (m_compositionContext.isComposing) {
|
if (m_compositionContext.isComposing) {
|
||||||
QInputMethodEvent event;
|
QInputMethodEvent event;
|
||||||
QCoreApplication::sendEvent(fo, &event);
|
QCoreApplication::sendEvent(m_compositionContext.focusObject, &event);
|
||||||
}
|
}
|
||||||
doneContext();
|
doneContext();
|
||||||
|
|
||||||
@ -459,11 +468,12 @@ bool QWindowsInputContext::endComposition(HWND hwnd)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWindowsInputContext::initContext(HWND hwnd)
|
void QWindowsInputContext::initContext(HWND hwnd, QObject *focusObject)
|
||||||
{
|
{
|
||||||
if (m_compositionContext.hwnd)
|
if (m_compositionContext.hwnd)
|
||||||
doneContext();
|
doneContext();
|
||||||
m_compositionContext.hwnd = hwnd;
|
m_compositionContext.hwnd = hwnd;
|
||||||
|
m_compositionContext.focusObject = focusObject;
|
||||||
// Create a hidden caret which is kept at the microfocus
|
// Create a hidden caret which is kept at the microfocus
|
||||||
// position in update(). This is important for some
|
// position in update(). This is important for some
|
||||||
// Chinese input methods.
|
// Chinese input methods.
|
||||||
@ -484,6 +494,7 @@ void QWindowsInputContext::doneContext()
|
|||||||
m_compositionContext.composition.clear();
|
m_compositionContext.composition.clear();
|
||||||
m_compositionContext.position = 0;
|
m_compositionContext.position = 0;
|
||||||
m_compositionContext.isComposing = m_compositionContext.haveCaret = false;
|
m_compositionContext.isComposing = m_compositionContext.haveCaret = false;
|
||||||
|
m_compositionContext.focusObject = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QWindowsInputContext::handleIME_Request(WPARAM wParam,
|
bool QWindowsInputContext::handleIME_Request(WPARAM wParam,
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
#include "qtwindows_additional.h"
|
#include "qtwindows_additional.h"
|
||||||
|
|
||||||
|
#include <QtCore/QPointer>
|
||||||
#include <qpa/qplatforminputcontext.h>
|
#include <qpa/qplatforminputcontext.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@ -63,6 +64,7 @@ class QWindowsInputContext : public QPlatformInputContext
|
|||||||
QString composition;
|
QString composition;
|
||||||
int position;
|
int position;
|
||||||
bool isComposing;
|
bool isComposing;
|
||||||
|
QPointer<QObject> focusObject;
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
explicit QWindowsInputContext();
|
explicit QWindowsInputContext();
|
||||||
@ -71,6 +73,7 @@ public:
|
|||||||
void reset() Q_DECL_OVERRIDE;
|
void reset() Q_DECL_OVERRIDE;
|
||||||
void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE;
|
void update(Qt::InputMethodQueries) Q_DECL_OVERRIDE;
|
||||||
void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE;
|
void invokeAction(QInputMethod::Action, int cursorPosition) Q_DECL_OVERRIDE;
|
||||||
|
void setFocusObject(QObject *object) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
static QWindowsInputContext *instance();
|
static QWindowsInputContext *instance();
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ private slots:
|
|||||||
void cursorRectChanged();
|
void cursorRectChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void initContext(HWND hwnd);
|
void initContext(HWND hwnd, QObject *focusObject);
|
||||||
void doneContext();
|
void doneContext();
|
||||||
void startContextComposition();
|
void startContextComposition();
|
||||||
void endContextComposition();
|
void endContextComposition();
|
||||||
|
Loading…
Reference in New Issue
Block a user