summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms
diff options
context:
space:
mode:
authorAndre de la Rocha <andre.rocha@qt.io>2018-06-20 18:50:07 +0200
committerAndre de la Rocha <andre.rocha@qt.io>2018-06-28 09:28:57 +0000
commit3d867b84a3ac4c2b32b7d476eaeadc2c7fae277b (patch)
tree4fe08abf12d5308c9435031c21e2baa7fcf4a712 /src/plugins/platforms
parent023a818738d64da01ebecc5d4a26356055ba0021 (diff)
Fix automatic showing/hiding of the Windows 10 on-screen keyboard
The automatic showing/hiding of the built-in on-screen keyboard in touchscreen-based Windows computers, like the Microsoft Surface line, has stopped working after recent Windows updates. The OSK no longer seems to rely on UI Automation properties to detect text widgets. However, it can be triggered by showing an invisible caret. Task-number: QTBUG-68808 Change-Id: Ia604d21e314965dcdc61f1ced050cc3ed771f567 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.cpp92
-rw-r--r--src/plugins/platforms/windows/qwindowsinputcontext.h9
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h11
3 files changed, 74 insertions, 38 deletions
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
index 2dbca6047c..261c931f2b 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp
@@ -164,19 +164,22 @@ Q_CORE_EXPORT QLocale qt_localeFromLCID(LCID id); // from qlocale_win.cpp
*/
-HIMC QWindowsInputContext::m_defaultContext = 0;
-
QWindowsInputContext::QWindowsInputContext() :
m_WM_MSIME_MOUSE(RegisterWindowMessage(L"MSIMEMouseOperation")),
m_languageId(currentInputLanguageId()),
m_locale(qt_localeFromLCID(m_languageId))
{
+ const quint32 bmpData = 0;
+ m_transparentBitmap = CreateBitmap(2, 2, 1, 1, &bmpData);
+
connect(QGuiApplication::inputMethod(), &QInputMethod::cursorRectangleChanged,
this, &QWindowsInputContext::cursorRectChanged);
}
QWindowsInputContext::~QWindowsInputContext()
{
+ if (m_transparentBitmap)
+ DeleteObject(m_transparentBitmap);
}
bool QWindowsInputContext::hasCapability(Capability capability) const
@@ -243,6 +246,43 @@ bool QWindowsInputContext::isInputPanelVisible() const
return hwnd && ::IsWindowEnabled(hwnd) && ::IsWindowVisible(hwnd);
}
+void QWindowsInputContext::showInputPanel()
+{
+ if (!inputMethodAccepted())
+ return;
+
+ QWindow *window = QGuiApplication::focusWindow();
+ if (!window)
+ return;
+
+ QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(window);
+ if (!platformWindow)
+ return;
+
+ // Create an invisible 2x2 caret, which will be kept at the microfocus position.
+ // It is important for triggering the on-screen keyboard in touch-screen devices,
+ // for some Chinese input methods, and for Magnifier's "follow keyboard" feature.
+ if (!m_caretCreated && m_transparentBitmap)
+ m_caretCreated = CreateCaret(platformWindow->handle(), m_transparentBitmap, 0, 0);
+
+ // For some reason, the on-screen keyboard is only triggered on the Surface
+ // with Windows 10 if the Windows IME is (re)enabled _after_ the caret is shown.
+ if (m_caretCreated) {
+ cursorRectChanged();
+ ShowCaret(platformWindow->handle());
+ setWindowsImeEnabled(platformWindow, false);
+ setWindowsImeEnabled(platformWindow, true);
+ }
+}
+
+void QWindowsInputContext::hideInputPanel()
+{
+ if (m_caretCreated) {
+ DestroyCaret();
+ m_caretCreated = false;
+ }
+}
+
void QWindowsInputContext::updateEnabled()
{
if (!QGuiApplication::focusObject())
@@ -257,18 +297,14 @@ void QWindowsInputContext::updateEnabled()
void QWindowsInputContext::setWindowsImeEnabled(QWindowsWindow *platformWindow, bool enabled)
{
- if (!platformWindow || platformWindow->testFlag(QWindowsWindow::InputMethodDisabled) == !enabled)
+ if (!platformWindow)
return;
if (enabled) {
- // Re-enable Windows IME by associating default context saved on first disabling.
- ImmAssociateContext(platformWindow->handle(), QWindowsInputContext::m_defaultContext);
- platformWindow->clearFlag(QWindowsWindow::InputMethodDisabled);
+ // Re-enable Windows IME by associating default context.
+ ImmAssociateContextEx(platformWindow->handle(), 0, IACE_DEFAULT);
} else {
- // Disable Windows IME by associating 0 context. Store context first time.
- const HIMC oldImC = ImmAssociateContext(platformWindow->handle(), 0);
- platformWindow->setFlag(QWindowsWindow::InputMethodDisabled);
- if (!QWindowsInputContext::m_defaultContext && oldImC)
- QWindowsInputContext::m_defaultContext = oldImC;
+ // Disable Windows IME by associating 0 context.
+ ImmAssociateContext(platformWindow->handle(), 0);
}
}
@@ -285,15 +321,25 @@ void QWindowsInputContext::update(Qt::InputMethodQueries queries)
void QWindowsInputContext::cursorRectChanged()
{
- if (!m_compositionContext.hwnd)
+ QWindow *window = QGuiApplication::focusWindow();
+ if (!window)
return;
+
+ qreal factor = QHighDpiScaling::factor(window);
+
const QInputMethod *inputMethod = QGuiApplication::inputMethod();
const QRectF cursorRectangleF = inputMethod->cursorRectangle();
if (!cursorRectangleF.isValid())
return;
+
const QRect cursorRectangle =
- QRectF(cursorRectangleF.topLeft() * m_compositionContext.factor,
- cursorRectangleF.size() * m_compositionContext.factor).toRect();
+ QRectF(cursorRectangleF.topLeft() * factor, cursorRectangleF.size() * factor).toRect();
+
+ if (m_caretCreated)
+ SetCaretPos(cursorRectangle.x(), cursorRectangle.y());
+
+ if (!m_compositionContext.hwnd)
+ return;
qCDebug(lcQpaInputMethods) << __FUNCTION__<< cursorRectangle;
@@ -317,9 +363,6 @@ void QWindowsInputContext::cursorRectChanged()
candf.rcArea.right = cursorRectangle.x() + cursorRectangle.width();
candf.rcArea.bottom = cursorRectangle.y() + cursorRectangle.height();
- if (m_compositionContext.haveCaret)
- SetCaretPos(cursorRectangle.x(), cursorRectangle.y());
-
ImmSetCompositionWindow(himc, &cf);
ImmSetCandidateWindow(himc, &candf);
ImmReleaseContext(m_compositionContext.hwnd, himc);
@@ -411,7 +454,7 @@ bool QWindowsInputContext::startComposition(HWND hwnd)
qCDebug(lcQpaInputMethods) << __FUNCTION__ << fo << window << "language=" << m_languageId;
if (!fo || QWindowsWindow::handleOf(window) != hwnd)
return false;
- initContext(hwnd, QHighDpiScaling::factor(window), fo);
+ initContext(hwnd, fo);
startContextComposition();
return true;
}
@@ -551,18 +594,13 @@ bool QWindowsInputContext::endComposition(HWND hwnd)
return true;
}
-void QWindowsInputContext::initContext(HWND hwnd, qreal factor, QObject *focusObject)
+void QWindowsInputContext::initContext(HWND hwnd, QObject *focusObject)
{
if (m_compositionContext.hwnd)
doneContext();
m_compositionContext.hwnd = hwnd;
m_compositionContext.focusObject = focusObject;
- m_compositionContext.factor = factor;
- // Create a hidden caret which is kept at the microfocus
- // position in update(). This is important for some
- // Chinese input methods.
- m_compositionContext.haveCaret = CreateCaret(hwnd, 0, 1, 1);
- HideCaret(hwnd);
+
update(Qt::ImQueryAll);
m_compositionContext.isComposing = false;
m_compositionContext.position = 0;
@@ -572,12 +610,10 @@ void QWindowsInputContext::doneContext()
{
if (!m_compositionContext.hwnd)
return;
- if (m_compositionContext.haveCaret)
- DestroyCaret();
m_compositionContext.hwnd = 0;
m_compositionContext.composition.clear();
m_compositionContext.position = 0;
- m_compositionContext.isComposing = m_compositionContext.haveCaret = false;
+ m_compositionContext.isComposing = false;
m_compositionContext.focusObject = 0;
}
diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.h b/src/plugins/platforms/windows/qwindowsinputcontext.h
index ada1fc0d29..d647628ff1 100644
--- a/src/plugins/platforms/windows/qwindowsinputcontext.h
+++ b/src/plugins/platforms/windows/qwindowsinputcontext.h
@@ -58,12 +58,10 @@ class QWindowsInputContext : public QPlatformInputContext
struct CompositionContext
{
HWND hwnd = 0;
- bool haveCaret = false;
QString composition;
int position = 0;
bool isComposing = false;
QPointer<QObject> focusObject;
- qreal factor = 1;
};
public:
explicit QWindowsInputContext();
@@ -81,6 +79,8 @@ public:
QRectF keyboardRect() const override;
bool isInputPanelVisible() const override;
+ void showInputPanel() override;
+ void hideInputPanel() override;
bool startComposition(HWND hwnd);
bool composition(HWND hwnd, LPARAM lParam);
@@ -96,7 +96,7 @@ private slots:
void cursorRectChanged();
private:
- void initContext(HWND hwnd, qreal factor, QObject *focusObject);
+ void initContext(HWND hwnd, QObject *focusObject);
void doneContext();
void startContextComposition();
void endContextComposition();
@@ -104,7 +104,8 @@ private:
HWND getVirtualKeyboardWindowHandle() const;
const DWORD m_WM_MSIME_MOUSE;
- static HIMC m_defaultContext;
+ bool m_caretCreated = false;
+ HBITMAP m_transparentBitmap;
CompositionContext m_compositionContext;
bool m_endCompositionRecursionGuard = false;
LCID m_languageId;
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index fe2518e329..6d439bce1a 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -214,12 +214,11 @@ public:
WithinCreate = 0x20000,
WithinMaximize = 0x40000,
MaximizeToFullScreen = 0x80000,
- InputMethodDisabled = 0x100000,
- Compositing = 0x200000,
- HasBorderInFullScreen = 0x400000,
- WithinDpiChanged = 0x800000,
- VulkanSurface = 0x1000000,
- ResizeMoveActive = 0x2000000
+ Compositing = 0x100000,
+ HasBorderInFullScreen = 0x200000,
+ WithinDpiChanged = 0x400000,
+ VulkanSurface = 0x800000,
+ ResizeMoveActive = 0x1000000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);