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