Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqnxinputcontext_imf.cpp
Go to the documentation of this file.
1// Copyright (C) 2013 BlackBerry Limited. All rights reserved.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
8#include "qqnxscreen.h"
10
11#include <QtGui/QGuiApplication>
12#include <QtGui/QInputMethodEvent>
13#include <QtGui/QTextCharFormat>
14
15#include <QtCore/QDebug>
16#include <QtCore/QMutex>
17#include <QtCore/QVariant>
18#include <QtCore/QVariantHash>
19#include <QtCore/QWaitCondition>
20#include <QtCore/QQueue>
21#include <QtCore/QGlobalStatic>
22
23#include <dlfcn.h>
24#include "imf/imf_client.h"
25#include "imf/input_control.h"
26#include <process.h>
27#include <sys/keycodes.h>
28
29Q_LOGGING_CATEGORY(lcQpaInputMethods, "qt.qpa.input.methods");
30
32static QColor sSelectedColor(0,0xb8,0,85);
33
34static const input_session_t *sSpellCheckSession = nullptr;
35static const input_session_t *sInputSession = nullptr;
36static bool isSessionOkay(input_session_t *ic)
37{
38 return ic !=0 && sInputSession != 0 && ic->component_id == sInputSession->component_id;
39}
40
55
57 SpellCheckInfo(void *_context, void (*_spellCheckDone)(void *, const QString &, const QList<int> &))
58 : context(_context), spellCheckDone(_spellCheckDone) {}
59 void *context;
60 void (*spellCheckDone)(void *, const QString &, const QList<int> &);
61};
63
64// IMF requests all arrive on IMF's own thread and have to be posted to the main thread to be processed.
66{
67public:
68 QQnxImfRequest(input_session_t *_session, ImfEventType _type)
69 : session(_session), type(_type)
70 { }
72
75 union {
76 struct {
77 int32_t n;
78 int32_t flags;
79 bool before;
81 } gtac; // ic_get_text_before_cursor/ic_get_text_after_cursor
82 struct {
83 int32_t result;
84 } gcp; // ic_get_cursor_position
85 struct {
86 int32_t start;
87 int32_t end;
88 int32_t result;
89 } scr; // ic_set_composing_region
90 struct {
93 int32_t result;
94 } sct; // ic_set_composing_text
95 struct {
96 spannable_string_t* text;
97 int32_t new_cursor_position;
98 int32_t result;
99 } ct; // ic_commit_text
100 struct {
101 int32_t result;
102 } fct; // ic_finish_composing_text
103 struct {
104 int32_t left_length;
106 int32_t result;
107 } dst; // ic_delete_surrounding_text
108 struct {
110 int32_t result;
111 } sae; // ic_send_async_event/ic_send_event
112 struct {
113 int32_t *pIsSelected;
114 int32_t result;
115 } its; // ic_is_text_selected/ic_is_all_text_selected
116 };
117};
118
119// Invoke an IMF initiated request synchronously on Qt's main thread. As describe below all
120// IMF requests are made from another thread but need to be executed on the main thread.
122{
123 QMetaObject::invokeMethod(sInputContextInstance,
124 "processImfEvent",
125 Qt::BlockingQueuedConnection,
126 Q_ARG(QQnxImfRequest*, event));
127}
128
129// The following functions (ic_*) are callback functions called by the input system to query information
130// about the text object that currently has focus or to make changes to it. All calls are made from the
131// input system's own thread. The pattern for each callback function is to copy its parameters into
132// a QQnxImfRequest structure and call executeIMFRequest to have it passed synchronously to Qt's main thread.
133// Any return values should be pre-initialised with suitable default values as in some cases
134// (e.g. a stale session) the call will return without having executed any request specific code.
135//
136// To make the correspondence more obvious, the names of these functions match those defined in the headers.
137// They're in an anonymous namespace to avoid compiler conflicts with external functions defined with the
138// same names.
139namespace
140{
141
142// See comment at beginning of namespace declaration for general information
143static int32_t ic_begin_batch_edit(input_session_t *ic)
144{
145 Q_UNUSED(ic);
146
147 // Ignore silently.
148 return 0;
149}
150
151// End composition, committing the supplied text.
152// See comment at beginning of namespace declaration for general information
153static int32_t ic_commit_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
154{
155 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
156
157 QQnxImfRequest event(ic, ImfCommitText);
158 event.ct.text = text;
159 event.ct.new_cursor_position = new_cursor_position;
160 event.ct.result = -1;
162
163 return event.ct.result;
164}
165
166// Delete left_length characters before and right_length characters after the cursor.
167// See comment at beginning of namespace declaration for general information
168static int32_t ic_delete_surrounding_text(input_session_t *ic, int32_t left_length, int32_t right_length)
169{
170 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
171
173 event.dst.left_length = left_length;
174 event.dst.right_length = right_length;
175 event.dst.result = -1;
177
178 return event.dst.result;
179}
180
181// See comment at beginning of namespace declaration for general information
182static int32_t ic_end_batch_edit(input_session_t *ic)
183{
184 Q_UNUSED(ic);
185
186 // Ignore silently.
187 return 0;
188}
189
190// End composition, committing what's there.
191// See comment at beginning of namespace declaration for general information
192static int32_t ic_finish_composing_text(input_session_t *ic)
193{
194 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
195
197 event.fct.result = -1;
199
200 return event.fct.result;
201}
202
203// Return the position of the cursor.
204// See comment at beginning of namespace declaration for general information
205static int32_t ic_get_cursor_position(input_session_t *ic)
206{
207 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
208
210 event.gcp.result = -1;
212
213 return event.gcp.result;
214}
215
216// Return the n characters after the cursor.
217// See comment at beginning of namespace declaration for general information
218static spannable_string_t *ic_get_text_after_cursor(input_session_t *ic, int32_t n, int32_t flags)
219{
220 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
221
223 event.gtac.n = n;
224 event.gtac.flags = flags;
225 event.gtac.result = 0;
227
228 return event.gtac.result;
229}
230
231// Return the n characters before the cursor.
232// See comment at beginning of namespace declaration for general information
233static spannable_string_t *ic_get_text_before_cursor(input_session_t *ic, int32_t n, int32_t flags)
234{
235 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
236
238 event.gtac.n = n;
239 event.gtac.flags = flags;
240 event.gtac.result = 0;
242
243 return event.gtac.result;
244}
245
246// Process an event from IMF. Primarily used for reflecting back keyboard events.
247// See comment at beginning of namespace declaration for general information
248static int32_t ic_send_event(input_session_t *ic, event_t *event)
249{
250 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
251
252 QQnxImfRequest imfEvent(ic, ImfSendEvent);
253 imfEvent.sae.event = event;
254 imfEvent.sae.result = -1;
255 executeIMFRequest(&imfEvent);
256
257 return imfEvent.sae.result;
258}
259
260// Same as ic_send_event.
261// See comment at beginning of namespace declaration for general information
262static int32_t ic_send_async_event(input_session_t *ic, event_t *event)
263{
264 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
265
266 // There's no difference from our point of view between ic_send_event & ic_send_async_event
267 QQnxImfRequest imfEvent(ic, ImfSendEvent);
268 imfEvent.sae.event = event;
269 imfEvent.sae.result = -1;
270 executeIMFRequest(&imfEvent);
271
272 return imfEvent.sae.result;
273}
274
275// Set the range of text between start and end as the composition range.
276// See comment at beginning of namespace declaration for general information
277static int32_t ic_set_composing_region(input_session_t *ic, int32_t start, int32_t end)
278{
279 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
280
282 event.scr.start = start;
283 event.scr.end = end;
284 event.scr.result = -1;
286
287 return event.scr.result;
288}
289
290// Update the composition range with the supplied text. This can be called when no composition
291// range is in effect in which case one is started at the current cursor position.
292// See comment at beginning of namespace declaration for general information
293static int32_t ic_set_composing_text(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
294{
295 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
296
298 event.sct.text = text;
299 event.sct.new_cursor_position = new_cursor_position;
300 event.sct.result = -1;
302
303 return event.sct.result;
304}
305
306// Indicate if any text is selected
307// See comment at beginning of namespace declaration for general information
308static int32_t ic_is_text_selected(input_session_t* ic, int32_t* pIsSelected)
309{
310 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
311
313 event.its.pIsSelected = pIsSelected;
314 event.its.result = -1;
316
317 return event.its.result;
318}
319
320// Indicate if all text is selected
321// See comment at beginning of namespace declaration for general information
322static int32_t ic_is_all_text_selected(input_session_t* ic, int32_t* pIsSelected)
323{
324 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
325
327 event.its.pIsSelected = pIsSelected;
328 event.its.result = -1;
330
331 return event.its.result;
332}
333
334// LCOV_EXCL_START - exclude from code coverage analysis
335// The following functions are defined in the IMF headers but are not currently called.
336
337// Not currently used
338static int32_t ic_perform_editor_action(input_session_t *ic, int32_t editor_action)
339{
340 Q_UNUSED(ic);
341 Q_UNUSED(editor_action);
342
343 qCritical("ic_perform_editor_action not implemented");
344 return 0;
345}
346
347// Not currently used
348static int32_t ic_report_fullscreen_mode(input_session_t *ic, int32_t enabled)
349{
350 Q_UNUSED(ic);
351 Q_UNUSED(enabled);
352
353 qCritical("ic_report_fullscreen_mode not implemented");
354 return 0;
355}
356
357// Not currently used
358static extracted_text_t *ic_get_extracted_text(input_session_t *ic, extracted_text_request_t *request, int32_t flags)
359{
360 Q_UNUSED(ic);
361 Q_UNUSED(request);
362 Q_UNUSED(flags);
363
364 qCritical("ic_get_extracted_text not implemented");
365 return 0;
366}
367
368// Not currently used
369static spannable_string_t *ic_get_selected_text(input_session_t *ic, int32_t flags)
370{
371 Q_UNUSED(ic);
372 Q_UNUSED(flags);
373
374 qCritical("ic_get_selected_text not implemented");
375 return 0;
376}
377
378// Not currently used
379static int32_t ic_get_cursor_caps_mode(input_session_t *ic, int32_t req_modes)
380{
381 Q_UNUSED(ic);
382 Q_UNUSED(req_modes);
383
384 qCritical("ic_get_cursor_caps_mode not implemented");
385 return 0;
386}
387
388// Not currently used
389static int32_t ic_clear_meta_key_states(input_session_t *ic, int32_t states)
390{
391 Q_UNUSED(ic);
392 Q_UNUSED(states);
393
394 qCritical("ic_clear_meta_key_states not implemented");
395 return 0;
396}
397
398// Not currently used
399static int32_t ic_set_selection(input_session_t *ic, int32_t start, int32_t end)
400{
401 Q_UNUSED(ic);
402 Q_UNUSED(start);
403 Q_UNUSED(end);
404
405 qCritical("ic_set_selection not implemented");
406 return 0;
407}
408
409// End of un-hittable code
410// LCOV_EXCL_STOP
411
412
413static connection_interface_t ic_funcs = {
414 ic_begin_batch_edit,
415 ic_clear_meta_key_states,
416 ic_commit_text,
417 ic_delete_surrounding_text,
418 ic_end_batch_edit,
419 ic_finish_composing_text,
420 ic_get_cursor_caps_mode,
421 ic_get_cursor_position,
422 ic_get_extracted_text,
423 ic_get_selected_text,
424 ic_get_text_after_cursor,
425 ic_get_text_before_cursor,
426 ic_perform_editor_action,
427 ic_report_fullscreen_mode,
428 0, //ic_send_key_event
429 ic_send_event,
430 ic_send_async_event,
431 ic_set_composing_region,
432 ic_set_composing_text,
433 ic_set_selection,
434 0, //ic_set_candidates,
435 0, //ic_get_cursor_offset,
436 0, //ic_get_selection,
437 ic_is_text_selected,
438 ic_is_all_text_selected,
439 0, //ic_get_max_cursor_offset_t
440};
441
442} // namespace
443
444static void
445initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId, int eventSize)
446{
447 static int s_transactionId;
448
449 // Make sure structure is squeaky clean since it's not clear just what is significant.
450 memset(pEvent, 0, eventSize);
451 pEvent->event_type = eventType;
452 pEvent->event_id = eventId;
453 pEvent->pid = getpid();
454 pEvent->component_id = pSession->component_id;
455 pEvent->transaction_id = ++s_transactionId;
456}
457
458static spannable_string_t *toSpannableString(const QString &text)
459{
460 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text:" << text;
461
462 spannable_string_t *pString = static_cast<spannable_string_t *>(malloc(sizeof(spannable_string_t)));
463 pString->str = static_cast<wchar_t *>(malloc(sizeof(wchar_t) * text.length() + 1));
464 pString->length = text.toWCharArray(pString->str);
465 pString->spans = 0;
466 pString->spans_count = 0;
467 pString->str[pString->length] = 0;
468
469 return pString;
470}
471
472
473static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = nullptr;
474static void (*p_ictrl_close_session)(input_session_t *) = nullptr;
475static int32_t (*p_ictrl_dispatch_event)(event_t*) = nullptr;
476static int32_t (*p_imf_client_init)() = nullptr;
477static void (*p_imf_client_disconnect)() = nullptr;
478static int32_t (*p_vkb_init_selection_service)() = nullptr;
479static int32_t (*p_ictrl_get_num_active_sessions)() = nullptr;
480static bool s_imfInitFailed = false;
481
482static bool imfAvailable()
483{
484 static bool s_imfDisabled = getenv("DISABLE_IMF") != 0;
485 static bool s_imfReady = false;
486
487 if ( s_imfInitFailed || s_imfDisabled)
488 return false;
489 else if ( s_imfReady )
490 return true;
491
492 if ( p_imf_client_init == 0 ) {
493 void *handle = dlopen("libinput_client.so.1", 0);
494 if (Q_UNLIKELY(!handle)) {
495 qCritical("libinput_client.so.1 is not present - IMF services are disabled.");
496 s_imfDisabled = true;
497 return false;
498 }
499 p_imf_client_init = (int32_t (*)()) dlsym(handle, "imf_client_init");
500 p_imf_client_disconnect = (void (*)()) dlsym(handle, "imf_client_disconnect");
501 p_ictrl_open_session = (const input_session_t *(*)(connection_interface_t *))dlsym(handle, "ictrl_open_session");
502 p_ictrl_close_session = (void (*)(input_session_t *))dlsym(handle, "ictrl_close_session");
503 p_ictrl_dispatch_event = (int32_t (*)(event_t *))dlsym(handle, "ictrl_dispatch_event");
504 p_vkb_init_selection_service = (int32_t (*)())dlsym(handle, "vkb_init_selection_service");
505 p_ictrl_get_num_active_sessions = (int32_t (*)())dlsym(handle, "ictrl_get_num_active_sessions");
506
507 if (Q_UNLIKELY(!p_imf_client_init || !p_ictrl_open_session || !p_ictrl_dispatch_event)) {
509 p_ictrl_dispatch_event = 0;
510 s_imfDisabled = true;
511 qCritical("libinput_client.so.1 did not contain the correct symbols, library mismatch? IMF services are disabled.");
512 return false;
513 }
514
515 s_imfReady = true;
516 }
517
518 return s_imfReady;
519}
520
521QT_BEGIN_NAMESPACE
522
523QQnxInputContext::QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVirtualKeyboard &keyboard) :
524 QPlatformInputContext(),
525 m_caretPosition(0),
526 m_isComposing(false),
527 m_isUpdatingText(false),
528 m_inputPanelVisible(false),
529 m_inputPanelLocale(QLocale::c()),
530 m_focusObject(0),
531 m_integration(integration),
532 m_virtualKeyboard(keyboard)
533{
534 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
535
536 if (!imfAvailable())
537 return;
538
539 // Save a pointer to ourselves so we can execute calls from IMF through executeIMFRequest
540 // In practice there will only ever be a single instance.
541 Q_ASSERT(sInputContextInstance == 0);
542 sInputContextInstance = this;
543
544 if (Q_UNLIKELY(p_imf_client_init() != 0)) {
545 s_imfInitFailed = true;
546 qCritical("imf_client_init failed - IMF services will be unavailable");
547 }
548
549 connect(&keyboard, SIGNAL(visibilityChanged(bool)), this, SLOT(keyboardVisibilityChanged(bool)));
550 connect(&keyboard, SIGNAL(localeChanged(QLocale)), this, SLOT(keyboardLocaleChanged(QLocale)));
551 keyboardVisibilityChanged(keyboard.isVisible());
552 keyboardLocaleChanged(keyboard.locale());
553}
554
556{
557 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
558
559 Q_ASSERT(sInputContextInstance == this);
560 sInputContextInstance = nullptr;
561
562 if (!imfAvailable())
563 return;
564
566}
567
569{
570 return imfAvailable();
571}
572
573void QQnxInputContext::processImfEvent(QQnxImfRequest *imfEvent)
574{
575 // If input session is no longer current, just bail, imfEvent should already be set with the appropriate
576 // return value. The only exception is spell check events since they're not associated with the
577 // object with focus.
578 if (imfEvent->type != ImfSendEvent || imfEvent->sae.event->event_type != EVENT_SPELL_CHECK) {
579 if (!isSessionOkay(imfEvent->session))
580 return;
581 }
582
583 switch (imfEvent->type) {
584 case ImfCommitText:
585 imfEvent->ct.result = onCommitText(imfEvent->ct.text, imfEvent->ct.new_cursor_position);
586 break;
587
588 case ImfDeleteSurroundingText:
589 imfEvent->dst.result = onDeleteSurroundingText(imfEvent->dst.left_length, imfEvent->dst.right_length);
590 break;
591
592 case ImfFinishComposingText:
593 imfEvent->fct.result = onFinishComposingText();
594 break;
595
596 case ImfGetCursorPosition:
597 imfEvent->gcp.result = onGetCursorPosition();
598 break;
599
600 case ImfGetTextAfterCursor:
601 imfEvent->gtac.result = onGetTextAfterCursor(imfEvent->gtac.n, imfEvent->gtac.flags);
602 break;
603
604 case ImfGetTextBeforeCursor:
605 imfEvent->gtac.result = onGetTextBeforeCursor(imfEvent->gtac.n, imfEvent->gtac.flags);
606 break;
607
608 case ImfSendEvent:
609 imfEvent->sae.result = onSendEvent(imfEvent->sae.event);
610 break;
611
612 case ImfSetComposingRegion:
613 imfEvent->scr.result = onSetComposingRegion(imfEvent->scr.start, imfEvent->scr.end);
614 break;
615
616 case ImfSetComposingText:
617 imfEvent->sct.result = onSetComposingText(imfEvent->sct.text, imfEvent->sct.new_cursor_position);
618 break;
619
620 case ImfIsTextSelected:
621 imfEvent->its.result = onIsTextSelected(imfEvent->its.pIsSelected);
622 break;
623
624 case ImfIsAllTextSelected:
625 imfEvent->its.result = onIsAllTextSelected(imfEvent->its.pIsSelected);
626 break;
627 }; //switch
628}
629
630bool QQnxInputContext::filterEvent( const QEvent *event )
631{
632 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << event;
633
634 switch (event->type()) {
635 case QEvent::CloseSoftwareInputPanel:
636 return dispatchCloseSoftwareInputPanel();
637
638 case QEvent::RequestSoftwareInputPanel:
639 return dispatchRequestSoftwareInputPanel();
640
641 default:
642 return false;
643 }
644}
645
647{
648 QRect screenGeometry = m_integration->primaryDisplay()->geometry();
649 return QRectF(screenGeometry.x(), screenGeometry.height() - m_virtualKeyboard.height(),
650 screenGeometry.width(), m_virtualKeyboard.height());
651}
652
654{
655 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
656 endComposition();
657}
658
660{
661 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
662 endComposition();
663}
664
665void QQnxInputContext::update(Qt::InputMethodQueries queries)
666{
667 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Queries:" << queries;
668
669 if (queries & Qt::ImCursorPosition) {
670 int lastCaret = m_caretPosition;
671 updateCursorPosition();
672 // If caret position has changed we need to inform IMF unless this is just due to our own action
673 // such as committing text.
674 if (hasSession() && !m_isUpdatingText && lastCaret != m_caretPosition) {
675 caret_event_t caretEvent;
676 initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED, sizeof(caretEvent));
677 caretEvent.old_pos = lastCaret;
678 caretEvent.new_pos = m_caretPosition;
679 qCDebug(lcQpaInputMethods, "ictrl_dispatch_event caret changed %d %d", lastCaret, m_caretPosition);
680
681 p_ictrl_dispatch_event(&caretEvent.event);
682 }
683 }
684}
685
686void QQnxInputContext::closeSession()
687{
688 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
689 if (!imfAvailable())
690 return;
691
692 if (sInputSession) {
693 p_ictrl_close_session((input_session_t *)sInputSession);
694 sInputSession = nullptr;
695 }
696 // These are likely already in the right state but this depends on the text control
697 // having called reset or commit. So, just in case, set them to proper values.
698 m_isComposing = false;
699 m_composingText.clear();
700}
701
702bool QQnxInputContext::openSession()
703{
704 if (!imfAvailable())
705 return false;
706
707 closeSession();
708 sInputSession = p_ictrl_open_session(&ic_funcs);
709
710 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
711
712 return sInputSession != 0;
713}
714
715bool QQnxInputContext::hasSession()
716{
717 return sInputSession != 0;
718}
719
720bool QQnxInputContext::hasSelectedText()
721{
722 QObject *input = qGuiApp->focusObject();
723 if (!input)
724 return false;
725
726 QInputMethodQueryEvent query(Qt::ImCurrentSelection);
727 QCoreApplication::sendEvent(input, &query);
728
729 return !query.value(Qt::ImCurrentSelection).toString().isEmpty();
730}
731
732bool QQnxInputContext::dispatchRequestSoftwareInputPanel()
733{
734 qCDebug(lcQpaInputMethods) << "Requesting keyboard" << m_inputPanelVisible;
735 m_virtualKeyboard.showKeyboard();
736
737 return true;
738}
739
740bool QQnxInputContext::dispatchCloseSoftwareInputPanel()
741{
742 qCDebug(lcQpaInputMethods) << "Hiding keyboard" << m_inputPanelVisible;
743 m_virtualKeyboard.hideKeyboard();
744
745 return true;
746}
747
748/**
749 * IMF Event Dispatchers.
750 */
751bool QQnxInputContext::dispatchFocusGainEvent(int inputHints)
752{
753 if (hasSession())
754 dispatchFocusLossEvent();
755
756 QObject *input = qGuiApp->focusObject();
757
758 if (!input || !openSession())
759 return false;
760
761 // Set the last caret position to 0 since we don't really have one and we don't
762 // want to have the old one.
763 m_caretPosition = 0;
764
765 QInputMethodQueryEvent query(Qt::ImHints);
766 QCoreApplication::sendEvent(input, &query);
767
768 focus_event_t focusEvent;
769 initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, FOCUS_GAINED, sizeof(focusEvent));
770 focusEvent.style = DEFAULT_STYLE;
771
772 if (inputHints & Qt::ImhNoPredictiveText)
773 focusEvent.style |= NO_PREDICTION | NO_AUTO_CORRECTION;
774 if (inputHints & Qt::ImhNoAutoUppercase)
775 focusEvent.style |= NO_AUTO_TEXT;
776
777 // Following styles are mutually exclusive
778 if (inputHints & Qt::ImhHiddenText) {
779 focusEvent.style |= IMF_PASSWORD_TYPE;
780 } else if (inputHints & Qt::ImhDialableCharactersOnly) {
781 focusEvent.style |= IMF_PHONE_TYPE;
782 } else if (inputHints & Qt::ImhUrlCharactersOnly) {
783 focusEvent.style |= IMF_URL_TYPE;
784 } else if (inputHints & Qt::ImhEmailCharactersOnly) {
785 focusEvent.style |= IMF_EMAIL_TYPE;
786 }
787
788 qCDebug(lcQpaInputMethods) << "ictrl_dispatch_event focus gain style:" << focusEvent.style;
789
790 p_ictrl_dispatch_event((event_t *)&focusEvent);
791
792 return true;
793}
794
795void QQnxInputContext::dispatchFocusLossEvent()
796{
797 if (hasSession()) {
798 qCDebug(lcQpaInputMethods) << "ictrl_dispatch_event focus lost";
799
800 focus_event_t focusEvent;
801 initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, FOCUS_LOST, sizeof(focusEvent));
802 p_ictrl_dispatch_event((event_t *)&focusEvent);
803 closeSession();
804 }
805}
806
807bool QQnxInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap, int sequenceId)
808{
809 Q_UNUSED(scan);
810
811 if (!hasSession())
812 return false;
813
814 int key = (flags & KEY_SYM_VALID) ? sym : cap;
815 bool navigationKey = false;
816 switch (key) {
817 case KEYCODE_RETURN:
818 /* In a single line edit we should end composition because enter might be used by something.
819 endComposition();
820 return false;*/
821 break;
822
823 case KEYCODE_BACKSPACE:
824 case KEYCODE_DELETE:
825 // If there is a selection range, then we want a delete key to operate on that (by
826 // deleting the contents of the select range) rather than operating on the composition
827 // range.
828 if (hasSelectedText())
829 return false;
830 break;
831 case KEYCODE_LEFT:
832 key = NAVIGATE_LEFT;
833 navigationKey = true;
834 break;
835 case KEYCODE_RIGHT:
836 key = NAVIGATE_RIGHT;
837 navigationKey = true;
838 break;
839 case KEYCODE_UP:
840 key = NAVIGATE_UP;
841 navigationKey = true;
842 break;
843 case KEYCODE_DOWN:
844 key = NAVIGATE_DOWN;
845 navigationKey = true;
846 break;
847 case KEYCODE_LEFT_CTRL:
848 case KEYCODE_RIGHT_CTRL:
849 case KEYCODE_MENU:
850 case KEYCODE_LEFT_HYPER:
851 case KEYCODE_RIGHT_HYPER:
852 case KEYCODE_INSERT:
853 case KEYCODE_HOME:
854 case KEYCODE_PG_UP:
855 case KEYCODE_END:
856 case KEYCODE_PG_DOWN:
857 // Don't send these
858 key = 0;
859 break;
860 }
861
862 // Pass the keys we don't know about on through
863 if ( key == 0 )
864 return false;
865
866 if (navigationKey) {
867 // Even if we're forwarding up events, we can't do this for
868 // navigation keys.
869 if ( flags & KEY_DOWN ) {
870 navigation_event_t navEvent;
871 initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key, sizeof(navEvent));
872 navEvent.magnitude = 1;
873 qCDebug(lcQpaInputMethods, "ictrl_dispatch_even navigation %d", key);
874 p_ictrl_dispatch_event(&navEvent.event);
875 }
876 } else {
877 key_event_t keyEvent;
878 initEvent(&keyEvent.event, sInputSession, EVENT_KEY, flags & KEY_DOWN ? IMF_KEY_DOWN : IMF_KEY_UP,
879 sizeof(keyEvent));
880 keyEvent.key_code = cap;
881 keyEvent.character = sym;
882 keyEvent.meta_key_state = mod;
883 keyEvent.sequence_id = sequenceId;
884
885 p_ictrl_dispatch_event(&keyEvent.event);
886 qCDebug(lcQpaInputMethods, "ictrl_dispatch_even key %d", key);
887
888 }
889
890 return true;
891}
892
893void QQnxInputContext::updateCursorPosition()
894{
895 QObject *input = qGuiApp->focusObject();
896 if (!input)
897 return;
898
899 QInputMethodQueryEvent query(Qt::ImCursorPosition);
900 QCoreApplication::sendEvent(input, &query);
901 m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
902
903 qCDebug(lcQpaInputMethods, "ictrl_dispatch_even key %d", key);
904}
905
906void QQnxInputContext::endComposition()
907{
908 if (!m_isComposing)
909 return;
910
911 finishComposingText();
912
913 if (hasSession()) {
914 action_event_t actionEvent;
915 initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION, sizeof(actionEvent));
916 qCDebug(lcQpaInputMethods, "ictrl_dispatch_even end composition");
917 p_ictrl_dispatch_event(&actionEvent.event);
918 }
919}
920
921void QQnxInputContext::updateComposition(spannable_string_t *text, int32_t new_cursor_position)
922{
923 QObject *input = qGuiApp->focusObject();
924 if (!input)
925 return;
926
927 if (new_cursor_position > 0)
928 new_cursor_position += text->length - 1;
929
930 m_composingText = QString::fromWCharArray(text->str, text->length);
931 m_isComposing = true;
932
933 qCDebug(lcQpaInputMethods) << "Text =" << m_composingText << "Cursor position =" << new_cursor_position;
934
935 QList<QInputMethodEvent::Attribute> attributes;
936 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
937 new_cursor_position,
938 1,
939 QVariant()));
940
941 for (unsigned int i = 0; i < text->spans_count; ++i) {
942 QColor highlightColor;
943 bool underline = false;
944
945 if ((text->spans[i].attributes_mask & COMPOSED_TEXT_ATTRIB) != 0)
946 underline = true;
947
948 if ((text->spans[i].attributes_mask & ACTIVE_REGION_ATTRIB) != 0) {
949 underline = true;
950 highlightColor = m_highlightColor[ActiveRegion];
951 } else if ((text->spans[i].attributes_mask & AUTO_CORRECTION_ATTRIB) != 0) {
952 highlightColor = m_highlightColor[AutoCorrected];
953 } else if ((text->spans[i].attributes_mask & REVERT_CORRECTION_ATTRIB) != 0) {
954 highlightColor = m_highlightColor[Reverted];
955 }
956
957 if (underline || highlightColor.isValid()) {
958 QTextCharFormat format;
959 if (underline)
960 format.setFontUnderline(true);
961 if (highlightColor.isValid())
962 format.setBackground(QBrush(highlightColor));
963 qCDebug(lcQpaInputMethods) << "attrib: " << underline << highlightColor << text->spans[i].start << text->spans[i].end;
964 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, text->spans[i].start,
965 text->spans[i].end - text->spans[i].start + 1, QVariant(format)));
966
967 }
968 }
969 QInputMethodEvent event(m_composingText, attributes);
970 m_isUpdatingText = true;
971 QCoreApplication::sendEvent(input, &event);
972 m_isUpdatingText = false;
973
974 updateCursorPosition();
975}
976
977void QQnxInputContext::finishComposingText()
978{
979 QObject *input = qGuiApp->focusObject();
980
981 if (input) {
982 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << m_composingText;
983
984 QInputMethodEvent event;
985 event.setCommitString(m_composingText);
986 m_isUpdatingText = true;
987 QCoreApplication::sendEvent(input, &event);
988 m_isUpdatingText = false;
989 }
990 m_composingText = QString();
991 m_isComposing = false;
992
993 updateCursorPosition();
994}
995
996// Return the index relative to a UTF-16 sequence of characters for a index that is relative to the
997// corresponding UTF-32 character string given a starting index in the UTF-16 string and a count
998// of the number of lead surrogates prior to that index. Updates the highSurrogateCount to reflect the
999// new surrogate characters encountered.
1000static int adjustIndex(const QChar *text, int utf32Index, int utf16StartIndex, int *highSurrogateCount)
1001{
1002 int utf16Index = utf32Index + *highSurrogateCount;
1003 while (utf16StartIndex < utf16Index) {
1004 if (text[utf16StartIndex].isHighSurrogate()) {
1005 ++utf16Index;
1006 ++*highSurrogateCount;
1007 }
1008 ++utf16StartIndex;
1009 }
1010 return utf16StartIndex;
1011}
1012
1013int QQnxInputContext::handleSpellCheck(spell_check_event_t *event)
1014{
1015 // These should never happen.
1016 if (sSpellCheckQueue->isEmpty() || event->event.event_id != NOTIFY_SP_CHECK_MISSPELLINGS)
1017 return -1;
1018
1019 SpellCheckInfo callerInfo = sSpellCheckQueue->dequeue();
1020 spannable_string_t* spellCheckData = *event->data;
1021 QString text = QString::fromWCharArray(spellCheckData->str, spellCheckData->length);
1022 // Generate the list of indices indicating misspelled words in the text. We use end + 1
1023 // since it's more conventional to have the end index point just past the string. We also
1024 // can't use the indices directly since they are relative to UTF-32 encoded data and the
1025 // conversion to Qt's UTF-16 internal format might cause lengthening.
1026 QList<int> indices;
1027 int adjustment = 0;
1028 int index = 0;
1029 for (unsigned int i = 0; i < spellCheckData->spans_count; ++i) {
1030 if (spellCheckData->spans[i].attributes_mask & MISSPELLED_WORD_ATTRIB) {
1031 index = adjustIndex(text.data(), spellCheckData->spans[i].start, index, &adjustment);
1032 indices.push_back(index);
1033 index = adjustIndex(text.data(), spellCheckData->spans[i].end + 1, index, &adjustment);
1034 indices.push_back(index);
1035 }
1036 }
1037 callerInfo.spellCheckDone(callerInfo.context, text, indices);
1038
1039 return 0;
1040}
1041
1042int32_t QQnxInputContext::processEvent(event_t *event)
1043{
1044 int32_t result = -1;
1045 switch (event->event_type) {
1046 case EVENT_SPELL_CHECK: {
1047 qCDebug(lcQpaInputMethods) << "EVENT_SPELL_CHECK";
1048 result = handleSpellCheck(reinterpret_cast<spell_check_event_t *>(event));
1049 break;
1050 }
1051
1052 case EVENT_NAVIGATION: {
1053 qCDebug(lcQpaInputMethods) << "EVENT_NAVIGATION";
1054
1055 int key = event->event_id == NAVIGATE_UP ? KEYCODE_UP :
1056 event->event_id == NAVIGATE_DOWN ? KEYCODE_DOWN :
1057 event->event_id == NAVIGATE_LEFT ? KEYCODE_LEFT :
1058 event->event_id == NAVIGATE_RIGHT ? KEYCODE_RIGHT : 0;
1059
1060 QQnxScreenEventHandler::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, key, 0, 0, 0);
1061 QQnxScreenEventHandler::injectKeyboardEvent(KEY_CAP_VALID, key, 0, 0, 0);
1062 result = 0;
1063 break;
1064 }
1065
1066 case EVENT_KEY: {
1067 key_event_t *kevent = reinterpret_cast<key_event_t *>(event);
1068 int keySym = kevent->character != 0 ? kevent->character : kevent->key_code;
1069 int keyCap = kevent->key_code;
1070 int modifiers = 0;
1071 if (kevent->meta_key_state & META_SHIFT_ON)
1072 modifiers |= KEYMOD_SHIFT;
1073 int flags = KEY_SYM_VALID | KEY_CAP_VALID;
1074 if (event->event_id == IMF_KEY_DOWN)
1075 flags |= KEY_DOWN;
1076 qCDebug(lcQpaInputMethods, "EVENT_KEY %d %d", flags, keySym);
1077 QQnxScreenEventHandler::injectKeyboardEvent(flags, keySym, modifiers, 0, keyCap);
1078 result = 0;
1079 break;
1080 }
1081
1082 case EVENT_ACTION:
1083 // Don't care, indicates that IMF is done.
1084 break;
1085
1086 case EVENT_CARET:
1087 case EVENT_NOTHING:
1088 case EVENT_FOCUS:
1089 case EVENT_USER_ACTION:
1090 case EVENT_STROKE:
1091 case EVENT_INVOKE_LATER:
1092 qCritical() << "Unsupported event type: " << event->event_type;
1093 break;
1094 default:
1095 qCritical() << "Unknown event type: " << event->event_type;
1096 }
1097 return result;
1098}
1099
1100/**
1101 * IMF Event Handlers
1102 */
1103
1104int32_t QQnxInputContext::onCommitText(spannable_string_t *text, int32_t new_cursor_position)
1105{
1106 Q_UNUSED(new_cursor_position);
1107
1108 updateComposition(text, new_cursor_position);
1109 finishComposingText();
1110
1111 return 0;
1112}
1113
1114int32_t QQnxInputContext::onDeleteSurroundingText(int32_t left_length, int32_t right_length)
1115{
1116 qCDebug(lcQpaInputMethods, "L: %d R: %d", int(left_length), int(right_length));
1117
1118 QObject *input = qGuiApp->focusObject();
1119 if (!input)
1120 return 0;
1121
1122 int replacementLength = left_length + right_length;
1123 int replacementStart = -left_length;
1124
1125 finishComposingText();
1126
1127 QInputMethodEvent event;
1128 event.setCommitString(QString(), replacementStart, replacementLength);
1129 m_isUpdatingText = true;
1130 QCoreApplication::sendEvent(input, &event);
1131 m_isUpdatingText = false;
1132
1133 updateCursorPosition();
1134
1135 return 0;
1136}
1137
1138int32_t QQnxInputContext::onFinishComposingText()
1139{
1140 finishComposingText();
1141
1142 return 0;
1143}
1144
1145int32_t QQnxInputContext::onGetCursorPosition()
1146{
1147 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
1148
1149 QObject *input = qGuiApp->focusObject();
1150 if (!input)
1151 return 0;
1152
1153 updateCursorPosition();
1154
1155 return m_caretPosition;
1156}
1157
1158spannable_string_t *QQnxInputContext::onGetTextAfterCursor(int32_t n, int32_t flags)
1159{
1160 Q_UNUSED(flags);
1161 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
1162
1163 QObject *input = qGuiApp->focusObject();
1164 if (!input)
1165 return toSpannableString("");
1166
1167 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText);
1168 QCoreApplication::sendEvent(input, &query);
1169 QString text = query.value(Qt::ImSurroundingText).toString();
1170 m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
1171
1172 return toSpannableString(text.mid(m_caretPosition, n));
1173}
1174
1175spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(int32_t n, int32_t flags)
1176{
1177 Q_UNUSED(flags);
1178 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
1179
1180 QObject *input = qGuiApp->focusObject();
1181 if (!input)
1182 return toSpannableString("");
1183
1184 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText);
1185 QCoreApplication::sendEvent(input, &query);
1186 QString text = query.value(Qt::ImSurroundingText).toString();
1187 m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
1188
1189 if (n < m_caretPosition)
1190 return toSpannableString(text.mid(m_caretPosition - n, n));
1191 else
1192 return toSpannableString(text.mid(0, m_caretPosition));
1193}
1194
1195int32_t QQnxInputContext::onSendEvent(event_t *event)
1196{
1197 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
1198
1199 return processEvent(event);
1200}
1201
1202int32_t QQnxInputContext::onSetComposingRegion(int32_t start, int32_t end)
1203{
1204 QObject *input = qGuiApp->focusObject();
1205 if (!input)
1206 return 0;
1207
1208 QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImSurroundingText);
1209 QCoreApplication::sendEvent(input, &query);
1210 QString text = query.value(Qt::ImSurroundingText).toString();
1211 m_caretPosition = query.value(Qt::ImCursorPosition).toInt();
1212
1213 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << text;
1214
1215 m_isUpdatingText = true;
1216
1217 // Delete the current text.
1218 QInputMethodEvent deleteEvent;
1219 deleteEvent.setCommitString(QString(), start - m_caretPosition, end - start);
1220 QCoreApplication::sendEvent(input, &deleteEvent);
1221
1222 m_composingText = text.mid(start, end - start);
1223 m_isComposing = true;
1224
1225 QList<QInputMethodEvent::Attribute> attributes;
1226 QTextCharFormat format;
1227 format.setFontUnderline(true);
1228 attributes.push_back(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, m_composingText.length(), format));
1229
1230 QInputMethodEvent setTextEvent(m_composingText, attributes);
1231 QCoreApplication::sendEvent(input, &setTextEvent);
1232
1233 m_isUpdatingText = false;
1234
1235 return 0;
1236}
1237
1238int32_t QQnxInputContext::onSetComposingText(spannable_string_t *text, int32_t new_cursor_position)
1239{
1240 if (text->length > 0) {
1241 updateComposition(text, new_cursor_position);
1242 } else {
1243 // If the composing text is empty we can simply end composition, the visual effect is the same.
1244 // However, sometimes one wants to display hint text in an empty text field and for this to work
1245 // QQuickTextEdit.inputMethodComposing has to be false if the composition string is empty.
1246 m_composingText.clear();
1247 finishComposingText();
1248 }
1249 return 0;
1250}
1251
1252int32_t QQnxInputContext::onIsTextSelected(int32_t* pIsSelected)
1253{
1254 *pIsSelected = hasSelectedText();
1255
1256 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << *pIsSelected;
1257
1258 return 0;
1259}
1260
1261int32_t QQnxInputContext::onIsAllTextSelected(int32_t* pIsSelected)
1262{
1263 QObject *input = qGuiApp->focusObject();
1264 if (!input)
1265 return -1;
1266
1267 QInputMethodQueryEvent query(Qt::ImCurrentSelection | Qt::ImSurroundingText);
1268 QCoreApplication::sendEvent(input, &query);
1269
1270 *pIsSelected = query.value(Qt::ImSurroundingText).toString().length() == query.value(Qt::ImCurrentSelection).toString().length();
1271
1272 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << *pIsSelected;
1273
1274 return 0;
1275}
1276
1278{
1279 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
1280 dispatchRequestSoftwareInputPanel();
1281}
1282
1284{
1285 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO;
1286 dispatchCloseSoftwareInputPanel();
1287}
1288
1290{
1291 return m_inputPanelVisible;
1292}
1293
1295{
1296 return m_inputPanelLocale;
1297}
1298
1299void QQnxInputContext::keyboardVisibilityChanged(bool visible)
1300{
1301 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "visible=" << visible;
1302 if (m_inputPanelVisible != visible) {
1303 m_inputPanelVisible = visible;
1304 emitInputPanelVisibleChanged();
1305 }
1306}
1307
1308void QQnxInputContext::keyboardLocaleChanged(const QLocale &locale)
1309{
1310 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "locale=" << locale;
1311 if (m_inputPanelLocale != locale) {
1312 m_inputPanelLocale = locale;
1313 emitLocaleChanged();
1314 }
1315}
1316
1317void QQnxInputContext::setHighlightColor(int index, const QColor &color)
1318{
1319 qCDebug(lcQpaInputMethods) << "setHighlightColor" << index << color << qGuiApp->focusObject();
1320
1322 return;
1323
1324 // If the focus has changed, revert all colors to the default.
1325 if (sInputContextInstance->m_focusObject != qGuiApp->focusObject()) {
1326 QColor invalidColor;
1327 sInputContextInstance->m_highlightColor[ActiveRegion] = sSelectedColor;
1328 sInputContextInstance->m_highlightColor[AutoCorrected] = invalidColor;
1329 sInputContextInstance->m_highlightColor[Reverted] = invalidColor;
1330 sInputContextInstance->m_focusObject = qGuiApp->focusObject();
1331 }
1332 if (index >= 0 && index <= Reverted)
1333 sInputContextInstance->m_highlightColor[index] = color;
1334}
1335
1336void QQnxInputContext::setFocusObject(QObject *object)
1337{
1338 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "input item=" << object;
1339
1340 // Ensure the colors are reset if we've a change in focus object
1341 setHighlightColor(-1, QColor());
1342
1343 if (!inputMethodAccepted()) {
1344 if (m_inputPanelVisible)
1346 if (hasSession())
1347 dispatchFocusLossEvent();
1348 } else {
1349 QInputMethodQueryEvent query(Qt::ImHints | Qt::ImEnterKeyType);
1350 QCoreApplication::sendEvent(object, &query);
1351 int inputHints = query.value(Qt::ImHints).toInt();
1352 Qt::EnterKeyType qtEnterKeyType = Qt::EnterKeyType(query.value(Qt::ImEnterKeyType).toInt());
1353
1354 dispatchFocusGainEvent(inputHints);
1355
1356 m_virtualKeyboard.setInputHints(inputHints);
1357 m_virtualKeyboard.setEnterKeyType(
1358 QQnxAbstractVirtualKeyboard::qtEnterKeyTypeToQnx(qtEnterKeyType)
1359 );
1360
1361 if (!m_inputPanelVisible)
1363 }
1364}
1365
1366bool QQnxInputContext::checkSpelling(const QString &text, void *context, void (*spellCheckDone)(void *context, const QString &text, const QList<int> &indices))
1367{
1368 qCDebug(lcQpaInputMethods) << Q_FUNC_INFO << "Text =" << text;
1369
1370 if (!imfAvailable())
1371 return false;
1372
1373 if (!sSpellCheckSession)
1374 sSpellCheckSession = p_ictrl_open_session(&ic_funcs);
1375
1376 action_event_t spellEvent;
1377 initEvent(&spellEvent.event, sSpellCheckSession, EVENT_ACTION, ACTION_CHECK_MISSPELLINGS, sizeof(spellEvent));
1378 int len = text.length();
1379 spellEvent.event_data = alloca(sizeof(wchar_t) * (len + 1));
1380 spellEvent.length_data = text.toWCharArray(static_cast<wchar_t*>(spellEvent.event_data)) * sizeof(wchar_t);
1381
1382 int rc = p_ictrl_dispatch_event(reinterpret_cast<event_t*>(&spellEvent));
1383
1384 if (rc == 0) {
1385 sSpellCheckQueue->enqueue(SpellCheckInfo(context, spellCheckDone));
1386 return true;
1387 }
1388 return false;
1389}
1390
1391QT_END_NAMESPACE
spannable_string_t * text
input_session_t * session
spannable_string_t * result
QQnxImfRequest(input_session_t *_session, ImfEventType _type)
bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap, int sequenceId) override
void update(Qt::InputMethodQueries) override
Notification on editor updates.
bool isInputPanelVisible() const override
Returns input panel visibility status.
void reset() override
Method to be called when input method needs to be reset.
void hideInputPanel() override
Request to hide input panel.
void setFocusObject(QObject *object) override
This virtual method gets called to notify updated focus to object.
QLocale locale() const override
bool isValid() const override
Returns input context validity.
bool filterEvent(const QEvent *event) override
This function can be reimplemented to filter input events.
QRectF keyboardRect() const override
This function can be reimplemented to return virtual keyboard rectangle in currently active window co...
void showInputPanel() override
Request to show input panel.
QQnxScreen * primaryDisplay() const
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
Q_LOGGING_CATEGORY(lcEventDispatcher, "qt.eventdispatcher")
Q_GLOBAL_STATIC(QReadWriteLock, g_updateMutex)
static void(* p_imf_client_disconnect)()
static const input_session_t * sInputSession
static QQnxInputContext * sInputContextInstance
static bool imfAvailable()
static bool isSessionOkay(input_session_t *ic)
static spannable_string_t * toSpannableString(const QString &text)
static int adjustIndex(const QChar *text, int utf32Index, int utf16StartIndex, int *highSurrogateCount)
static bool s_imfInitFailed
static void initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId, int eventSize)
static const input_session_t * sSpellCheckSession
static const input_session_t *(* p_ictrl_open_session)(connection_interface_t *)
static QColor sSelectedColor(0, 0xb8, 0, 85)
static void executeIMFRequest(QQnxImfRequest *event)
@ ImfSetComposingRegion
@ ImfFinishComposingText
@ ImfIsTextSelected
@ ImfGetTextAfterCursor
@ ImfGetTextBeforeCursor
@ ImfIsAllTextSelected
@ ImfSetComposingText
@ ImfGetCursorPosition
@ ImfDeleteSurroundingText
static void(* p_ictrl_close_session)(input_session_t *)
void(* spellCheckDone)(void *, const QString &, const QList< int > &)
SpellCheckInfo(void *_context, void(*_spellCheckDone)(void *, const QString &, const QList< int > &))