1 | // Copyright (C) 2016 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qplatforminputcontext.h" |
5 | #include <qguiapplication.h> |
6 | #include <QRect> |
7 | #include "private/qkeymapper_p.h" |
8 | #include "private/qhighdpiscaling_p.h" |
9 | #include <qpa/qplatforminputcontext_p.h> |
10 | |
11 | #include <QtGui/qtransform.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | /*! |
16 | \class QPlatformInputContext |
17 | \since 5.0 |
18 | \internal |
19 | \preliminary |
20 | \ingroup qpa |
21 | \brief The QPlatformInputContext class abstracts the input method dependent data and composing state. |
22 | |
23 | An input method is responsible for inputting complex text that cannot |
24 | be inputted via simple keymap. It converts a sequence of input |
25 | events (typically key events) into a text string through the input |
26 | method specific converting process. The class of the processes are |
27 | widely ranging from simple finite state machine to complex text |
28 | translator that pools a whole paragraph of a text with text |
29 | editing capability to perform grammar and semantic analysis. |
30 | |
31 | To abstract such different input method specific intermediate |
32 | information, Qt offers the QPlatformInputContext as base class. The |
33 | concept is well known as 'input context' in the input method |
34 | domain. An input context is created for a text widget in response |
35 | to a demand. It is ensured that an input context is prepared for |
36 | an input method before input to a text widget. |
37 | |
38 | QPlatformInputContext provides an interface the actual input methods |
39 | can derive from by reimplementing methods. |
40 | |
41 | \sa QInputMethod |
42 | */ |
43 | |
44 | /*! |
45 | \internal |
46 | */ |
47 | QPlatformInputContext::QPlatformInputContext() |
48 | : QObject(*(new QPlatformInputContextPrivate)) |
49 | { |
50 | // Delay initialization of cached input direction |
51 | // until super class has finished constructing. |
52 | QMetaObject::invokeMethod(object: this, function: [this]{ |
53 | m_inputDirection = inputDirection(); |
54 | }, type: Qt::QueuedConnection); |
55 | } |
56 | |
57 | /*! |
58 | \internal |
59 | */ |
60 | QPlatformInputContext::~QPlatformInputContext() |
61 | { |
62 | } |
63 | |
64 | /*! |
65 | Returns input context validity. Deriving implementations should return true. |
66 | */ |
67 | bool QPlatformInputContext::isValid() const |
68 | { |
69 | return false; |
70 | } |
71 | |
72 | /*! |
73 | Returns whether the implementation supports \a capability. |
74 | \internal |
75 | \since 5.4 |
76 | */ |
77 | bool QPlatformInputContext::hasCapability(Capability capability) const |
78 | { |
79 | Q_UNUSED(capability); |
80 | return true; |
81 | } |
82 | |
83 | /*! |
84 | Method to be called when input method needs to be reset. Called by QInputMethod::reset(). |
85 | No further QInputMethodEvents should be sent as response. |
86 | */ |
87 | void QPlatformInputContext::reset() |
88 | { |
89 | } |
90 | |
91 | void QPlatformInputContext::commit() |
92 | { |
93 | } |
94 | |
95 | /*! |
96 | Notification on editor updates. Called by QInputMethod::update(). |
97 | */ |
98 | void QPlatformInputContext::update(Qt::InputMethodQueries) |
99 | { |
100 | } |
101 | |
102 | /*! |
103 | Called when the word currently being composed in the input item is tapped by |
104 | the user. Input methods often use this information to offer more word |
105 | suggestions to the user. |
106 | */ |
107 | void QPlatformInputContext::invokeAction(QInputMethod::Action action, int cursorPosition) |
108 | { |
109 | Q_UNUSED(cursorPosition); |
110 | // Default behavior for simple ephemeral input contexts. Some |
111 | // complex input contexts should not be reset here. |
112 | if (action == QInputMethod::Click) |
113 | reset(); |
114 | } |
115 | |
116 | /*! |
117 | This function can be reimplemented to filter input events. |
118 | Return true if the event has been consumed. Otherwise, the unfiltered event will |
119 | be forwarded to widgets as ordinary way. Although the input events have accept() |
120 | and ignore() methods, leave it untouched. |
121 | */ |
122 | bool QPlatformInputContext::filterEvent(const QEvent *event) |
123 | { |
124 | Q_UNUSED(event); |
125 | return false; |
126 | } |
127 | |
128 | /*! |
129 | This function can be reimplemented to return virtual keyboard rectangle in currently active |
130 | window coordinates. Default implementation returns invalid rectangle. |
131 | */ |
132 | QRectF QPlatformInputContext::keyboardRect() const |
133 | { |
134 | return QRectF(); |
135 | } |
136 | |
137 | /*! |
138 | Active QPlatformInputContext is responsible for providing keyboardRectangle property to QInputMethod. |
139 | In addition of providing the value in keyboardRect function, it also needs to call this emit |
140 | function whenever the property changes. |
141 | */ |
142 | void QPlatformInputContext::emitKeyboardRectChanged() |
143 | { |
144 | emit QGuiApplication::inputMethod()->keyboardRectangleChanged(); |
145 | } |
146 | |
147 | /*! |
148 | This function can be reimplemented to return true whenever input method is animating |
149 | shown or hidden. Default implementation returns \c false. |
150 | */ |
151 | bool QPlatformInputContext::isAnimating() const |
152 | { |
153 | return false; |
154 | } |
155 | |
156 | /*! |
157 | Active QPlatformInputContext is responsible for providing animating property to QInputMethod. |
158 | In addition of providing the value in isAnimation function, it also needs to call this emit |
159 | function whenever the property changes. |
160 | */ |
161 | void QPlatformInputContext::emitAnimatingChanged() |
162 | { |
163 | emit QGuiApplication::inputMethod()->animatingChanged(); |
164 | } |
165 | |
166 | /*! |
167 | Request to show input panel. |
168 | */ |
169 | void QPlatformInputContext::showInputPanel() |
170 | { |
171 | } |
172 | |
173 | /*! |
174 | Request to hide input panel. |
175 | */ |
176 | void QPlatformInputContext::hideInputPanel() |
177 | { |
178 | } |
179 | |
180 | /*! |
181 | Returns input panel visibility status. Default implementation returns \c false. |
182 | */ |
183 | bool QPlatformInputContext::isInputPanelVisible() const |
184 | { |
185 | return false; |
186 | } |
187 | |
188 | /*! |
189 | Active QPlatformInputContext is responsible for providing visible property to QInputMethod. |
190 | In addition of providing the value in isInputPanelVisible function, it also needs to call this emit |
191 | function whenever the property changes. |
192 | */ |
193 | void QPlatformInputContext::emitInputPanelVisibleChanged() |
194 | { |
195 | emit QGuiApplication::inputMethod()->visibleChanged(); |
196 | } |
197 | |
198 | QLocale QPlatformInputContext::locale() const |
199 | { |
200 | return QLocale::system(); |
201 | } |
202 | |
203 | void QPlatformInputContext::emitLocaleChanged() |
204 | { |
205 | emit QGuiApplication::inputMethod()->localeChanged(); |
206 | |
207 | // Changing the locale might have updated the input direction |
208 | emitInputDirectionChanged(newDirection: inputDirection()); |
209 | } |
210 | |
211 | Qt::LayoutDirection QPlatformInputContext::inputDirection() const |
212 | { |
213 | return locale().textDirection(); |
214 | } |
215 | |
216 | void QPlatformInputContext::emitInputDirectionChanged(Qt::LayoutDirection newDirection) |
217 | { |
218 | if (newDirection == m_inputDirection) |
219 | return; |
220 | |
221 | emit QGuiApplication::inputMethod()->inputDirectionChanged(newDirection); |
222 | m_inputDirection = newDirection; |
223 | } |
224 | |
225 | /*! |
226 | This virtual method gets called to notify updated focus to \a object. |
227 | \warning Input methods must not call this function directly. |
228 | */ |
229 | void QPlatformInputContext::setFocusObject(QObject *object) |
230 | { |
231 | Q_UNUSED(object); |
232 | } |
233 | |
234 | /*! |
235 | Returns \c true if current focus object supports input method events. |
236 | */ |
237 | bool QPlatformInputContext::inputMethodAccepted() const |
238 | { |
239 | return QPlatformInputContextPrivate::s_inputMethodAccepted; |
240 | } |
241 | |
242 | bool QPlatformInputContextPrivate::s_inputMethodAccepted = false; |
243 | |
244 | void QPlatformInputContextPrivate::setInputMethodAccepted(bool accepted) |
245 | { |
246 | QPlatformInputContextPrivate::s_inputMethodAccepted = accepted; |
247 | } |
248 | |
249 | /*! |
250 | \brief QPlatformInputContext::setSelectionOnFocusObject |
251 | \param anchorPos Beginning of selection in currently active window native coordinates |
252 | \param cursorPos End of selection in currently active window native coordinates |
253 | */ |
254 | void QPlatformInputContext::setSelectionOnFocusObject(const QPointF &nativeAnchorPos, const QPointF &nativeCursorPos) |
255 | { |
256 | QObject *focus = qApp->focusObject(); |
257 | if (!focus) |
258 | return; |
259 | |
260 | QWindow *window = qApp->focusWindow(); |
261 | const QPointF &anchorPos = QHighDpi::fromNativePixels(value: nativeAnchorPos, context: window); |
262 | const QPointF &cursorPos = QHighDpi::fromNativePixels(value: nativeCursorPos, context: window); |
263 | |
264 | QInputMethod *im = QGuiApplication::inputMethod(); |
265 | const QTransform mapToLocal = im->inputItemTransform().inverted(); |
266 | bool success; |
267 | int anchor = QInputMethod::queryFocusObject(query: Qt::ImCursorPosition, argument: anchorPos * mapToLocal).toInt(ok: &success); |
268 | if (success) { |
269 | int cursor = QInputMethod::queryFocusObject(query: Qt::ImCursorPosition, argument: cursorPos * mapToLocal).toInt(ok: &success); |
270 | if (success) { |
271 | if (anchor == cursor && anchorPos != cursorPos) |
272 | return; |
273 | QList<QInputMethodEvent::Attribute> imAttributes; |
274 | imAttributes.append(t: QInputMethodEvent::Attribute(QInputMethodEvent::Selection, anchor, cursor - anchor, QVariant())); |
275 | QInputMethodEvent event(QString(), imAttributes); |
276 | QGuiApplication::sendEvent(receiver: focus, event: &event); |
277 | } |
278 | } |
279 | } |
280 | |
281 | /*! |
282 | \brief QPlatformInputContext::queryFocusObject |
283 | |
284 | Queries the current foucus object with a window position in native pixels. |
285 | */ |
286 | QVariant QPlatformInputContext::queryFocusObject(Qt::InputMethodQuery query, QPointF nativePosition) |
287 | { |
288 | const QPointF position = QHighDpi::fromNativePixels(value: nativePosition, context: QGuiApplication::focusWindow()); |
289 | const QInputMethod *im = QGuiApplication::inputMethod(); |
290 | const QTransform mapToLocal = im->inputItemTransform().inverted(); |
291 | return im->queryFocusObject(query, argument: mapToLocal.map(p: position)); |
292 | } |
293 | |
294 | /*! |
295 | \brief QPlatformInputContext::inputItemRectangle |
296 | |
297 | Returns the input item rectangle for the currently active window |
298 | and input methiod in native window coordinates. |
299 | */ |
300 | QRectF QPlatformInputContext::inputItemRectangle() |
301 | { |
302 | QInputMethod *im = QGuiApplication::inputMethod(); |
303 | const QRectF deviceIndependentRectangle = im->inputItemTransform().mapRect(im->inputItemRectangle()); |
304 | return QHighDpi::toNativePixels(value: deviceIndependentRectangle, context: QGuiApplication::focusWindow()); |
305 | } |
306 | |
307 | /*! |
308 | \brief QPlatformInputContext::inputItemClipRectangle |
309 | |
310 | Returns the input item clip rectangle for the currently active window |
311 | and input methiod in native window coordinates. |
312 | */ |
313 | QRectF QPlatformInputContext::inputItemClipRectangle() |
314 | { |
315 | return QHighDpi::toNativePixels( |
316 | value: QGuiApplication::inputMethod()->inputItemClipRectangle(), context: QGuiApplication::focusWindow()); |
317 | } |
318 | |
319 | /*! |
320 | \brief QPlatformInputContext::cursorRectangle |
321 | |
322 | Returns the cursor rectangle for the currently active window |
323 | and input methiod in native window coordinates. |
324 | */ |
325 | QRectF QPlatformInputContext::cursorRectangle() |
326 | { |
327 | return QHighDpi::toNativePixels( |
328 | value: QGuiApplication::inputMethod()->cursorRectangle(), context: QGuiApplication::focusWindow()); |
329 | } |
330 | |
331 | /*! |
332 | \brief QPlatformInputContext::anchorRectangle |
333 | |
334 | Returns the anchor rectangle for the currently active window |
335 | and input methiod in native window coordinates. |
336 | */ |
337 | QRectF QPlatformInputContext::anchorRectangle() |
338 | { |
339 | return QHighDpi::toNativePixels( |
340 | value: QGuiApplication::inputMethod()->anchorRectangle(), context: QGuiApplication::focusWindow()); |
341 | } |
342 | |
343 | /*! |
344 | \brief QPlatformInputContext::keyboardRectangle |
345 | |
346 | Returns the keyboard rectangle for the currently active window |
347 | and input methiod in native window coordinates. |
348 | */ |
349 | QRectF QPlatformInputContext::keyboardRectangle() |
350 | { |
351 | return QHighDpi::toNativePixels( |
352 | value: QGuiApplication::inputMethod()->keyboardRectangle(), context: QGuiApplication::focusWindow()); |
353 | } |
354 | |
355 | QT_END_NAMESPACE |
356 | |
357 | #include "moc_qplatforminputcontext.cpp" |
358 |
Definitions
- QPlatformInputContext
- ~QPlatformInputContext
- isValid
- hasCapability
- reset
- commit
- update
- invokeAction
- filterEvent
- keyboardRect
- emitKeyboardRectChanged
- isAnimating
- emitAnimatingChanged
- showInputPanel
- hideInputPanel
- isInputPanelVisible
- emitInputPanelVisibleChanged
- locale
- emitLocaleChanged
- inputDirection
- emitInputDirectionChanged
- setFocusObject
- inputMethodAccepted
- s_inputMethodAccepted
- setInputMethodAccepted
- setSelectionOnFocusObject
- queryFocusObject
- inputItemRectangle
- inputItemClipRectangle
- cursorRectangle
- anchorRectangle
Learn Advanced QML with KDAB
Find out more