10#include <QtGui/QGuiApplication>
11#include <QtGui/QInputMethodEvent>
12#include <QtGui/QTextCharFormat>
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>
23#include "imf/imf_client.h"
24#include "imf/input_control.h"
26#include <sys/keycodes.h>
68 : session(_session),
type(_type)
95 spannable_string_t*
text;
96 int32_t new_cursor_position;
142static int32_t ic_begin_batch_edit(input_session_t *ic)
152static int32_t ic_commit_text(input_session_t *ic, spannable_string_t *
text, int32_t new_cursor_position)
157 event.ct.text =
text;
158 event.ct.new_cursor_position = new_cursor_position;
159 event.ct.result = -1;
162 return event.ct.result;
167static int32_t ic_delete_surrounding_text(input_session_t *ic, int32_t left_length, int32_t right_length)
172 event.dst.left_length = left_length;
173 event.dst.right_length = right_length;
174 event.dst.result = -1;
177 return event.dst.result;
181static int32_t ic_end_batch_edit(input_session_t *ic)
191static int32_t ic_finish_composing_text(input_session_t *ic)
196 event.fct.result = -1;
199 return event.fct.result;
204static int32_t ic_get_cursor_position(input_session_t *ic)
209 event.gcp.result = -1;
212 return event.gcp.result;
217static spannable_string_t *ic_get_text_after_cursor(input_session_t *ic, int32_t
n, int32_t
flags)
223 event.gtac.flags =
flags;
224 event.gtac.result = 0;
227 return event.gtac.result;
232static spannable_string_t *ic_get_text_before_cursor(input_session_t *ic, int32_t
n, int32_t
flags)
238 event.gtac.flags =
flags;
239 event.gtac.result = 0;
242 return event.gtac.result;
247static int32_t ic_send_event(input_session_t *ic, event_t *
event)
252 imfEvent.sae.event =
event;
253 imfEvent.sae.result = -1;
256 return imfEvent.sae.result;
261static int32_t ic_send_async_event(input_session_t *ic, event_t *
event)
267 imfEvent.sae.event =
event;
268 imfEvent.sae.result = -1;
271 return imfEvent.sae.result;
276static int32_t ic_set_composing_region(input_session_t *ic, int32_t
start, int32_t
end)
281 event.scr.start =
start;
283 event.scr.result = -1;
286 return event.scr.result;
292static int32_t ic_set_composing_text(input_session_t *ic, spannable_string_t *
text, int32_t new_cursor_position)
297 event.sct.text =
text;
298 event.sct.new_cursor_position = new_cursor_position;
299 event.sct.result = -1;
302 return event.sct.result;
307static int32_t ic_is_text_selected(input_session_t* ic, int32_t* pIsSelected)
312 event.its.pIsSelected = pIsSelected;
313 event.its.result = -1;
316 return event.its.result;
321static int32_t ic_is_all_text_selected(input_session_t* ic, int32_t* pIsSelected)
326 event.its.pIsSelected = pIsSelected;
327 event.its.result = -1;
330 return event.its.result;
337static int32_t ic_perform_editor_action(input_session_t *ic, int32_t editor_action)
342 qCritical(
"ic_perform_editor_action not implemented");
347static int32_t ic_report_fullscreen_mode(input_session_t *ic, int32_t
enabled)
352 qCritical(
"ic_report_fullscreen_mode not implemented");
357static extracted_text_t *ic_get_extracted_text(input_session_t *ic, extracted_text_request_t *
request, int32_t
flags)
363 qCritical(
"ic_get_extracted_text not implemented");
368static spannable_string_t *ic_get_selected_text(input_session_t *ic, int32_t
flags)
373 qCritical(
"ic_get_selected_text not implemented");
378static int32_t ic_get_cursor_caps_mode(input_session_t *ic, int32_t req_modes)
383 qCritical(
"ic_get_cursor_caps_mode not implemented");
388static int32_t ic_clear_meta_key_states(input_session_t *ic, int32_t
states)
393 qCritical(
"ic_clear_meta_key_states not implemented");
398static int32_t ic_set_selection(input_session_t *ic, int32_t
start, int32_t
end)
404 qCritical(
"ic_set_selection not implemented");
412static connection_interface_t ic_funcs = {
414 ic_clear_meta_key_states,
416 ic_delete_surrounding_text,
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,
430 ic_set_composing_region,
431 ic_set_composing_text,
437 ic_is_all_text_selected,
444initEvent(event_t *pEvent,
const input_session_t *pSession,
EventType eventType,
int eventId,
int eventSize)
446 static int s_transactionId;
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;
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));
465 pString->spans_count = 0;
466 pString->str[pString->length] = 0;
472static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) =
nullptr;
483 static bool s_imfDisabled = getenv(
"DISABLE_IMF") != 0;
484 static bool s_imfReady =
false;
488 else if ( s_imfReady )
492 void *
handle = dlopen(
"libinput_client.so.1", 0);
494 qCritical(
"libinput_client.so.1 is not present - IMF services are disabled.");
495 s_imfDisabled =
true;
509 s_imfDisabled =
true;
510 qCritical(
"libinput_client.so.1 did not contain the correct symbols, library mismatch? IMF services are disabled.");
525 m_isComposing(
false),
526 m_isUpdatingText(
false),
527 m_inputPanelVisible(
false),
530 m_integration(integration),
531 m_virtualKeyboard(keyboard)
545 qCritical(
"imf_client_init failed - IMF services will be unavailable");
548 connect(&keyboard,
SIGNAL(visibilityChanged(
bool)),
this,
SLOT(keyboardVisibilityChanged(
bool)));
550 keyboardVisibilityChanged(keyboard.
isVisible());
551 keyboardLocaleChanged(keyboard.
locale());
577 if (imfEvent->type !=
ImfSendEvent || imfEvent->sae.event->event_type != EVENT_SPELL_CHECK) {
582 switch (imfEvent->type) {
584 imfEvent->ct.result = onCommitText(imfEvent->ct.text, imfEvent->ct.new_cursor_position);
588 imfEvent->dst.result = onDeleteSurroundingText(imfEvent->dst.left_length, imfEvent->dst.right_length);
592 imfEvent->fct.result = onFinishComposingText();
596 imfEvent->gcp.result = onGetCursorPosition();
600 imfEvent->gtac.result = onGetTextAfterCursor(imfEvent->gtac.n, imfEvent->gtac.flags);
604 imfEvent->gtac.result = onGetTextBeforeCursor(imfEvent->gtac.n, imfEvent->gtac.flags);
608 imfEvent->sae.result = onSendEvent(imfEvent->sae.event);
612 imfEvent->scr.result = onSetComposingRegion(imfEvent->scr.start, imfEvent->scr.end);
616 imfEvent->sct.result = onSetComposingText(imfEvent->sct.text, imfEvent->sct.new_cursor_position);
620 imfEvent->its.result = onIsTextSelected(imfEvent->its.pIsSelected);
624 imfEvent->its.result = onIsAllTextSelected(imfEvent->its.pIsSelected);
633 switch (
event->type()) {
635 return dispatchCloseSoftwareInputPanel();
638 return dispatchRequestSoftwareInputPanel();
649 screenGeometry.
width(), m_virtualKeyboard.
height());
669 int lastCaret = m_caretPosition;
670 updateCursorPosition();
673 if (hasSession() && !m_isUpdatingText && lastCaret != m_caretPosition) {
674 caret_event_t 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);
685void QQnxInputContext::closeSession()
697 m_isComposing =
false;
698 m_composingText.
clear();
701bool QQnxInputContext::openSession()
714bool QQnxInputContext::hasSession()
719bool QQnxInputContext::hasSelectedText()
731bool QQnxInputContext::dispatchRequestSoftwareInputPanel()
733 qCDebug(lcQpaInputMethods) <<
"Requesting keyboard" << m_inputPanelVisible;
739bool QQnxInputContext::dispatchCloseSoftwareInputPanel()
741 qCDebug(lcQpaInputMethods) <<
"Hiding keyboard" << m_inputPanelVisible;
750bool QQnxInputContext::dispatchFocusGainEvent(
int inputHints)
753 dispatchFocusLossEvent();
757 if (!
input || !openSession())
767 focus_event_t focusEvent;
769 focusEvent.style = DEFAULT_STYLE;
772 focusEvent.style |= NO_PREDICTION | NO_AUTO_CORRECTION;
774 focusEvent.style |= NO_AUTO_TEXT;
778 focusEvent.style |= IMF_PASSWORD_TYPE;
780 focusEvent.style |= IMF_PHONE_TYPE;
782 focusEvent.style |= IMF_URL_TYPE;
784 focusEvent.style |= IMF_EMAIL_TYPE;
787 qCDebug(lcQpaInputMethods) <<
"ictrl_dispatch_event focus gain style:" << focusEvent.style;
794void QQnxInputContext::dispatchFocusLossEvent()
797 qCDebug(lcQpaInputMethods) <<
"ictrl_dispatch_event focus lost";
799 focus_event_t focusEvent;
814 bool navigationKey =
false;
822 case KEYCODE_BACKSPACE:
827 if (hasSelectedText())
832 navigationKey =
true;
835 key = NAVIGATE_RIGHT;
836 navigationKey =
true;
840 navigationKey =
true;
844 navigationKey =
true;
846 case KEYCODE_LEFT_CTRL:
847 case KEYCODE_RIGHT_CTRL:
849 case KEYCODE_LEFT_HYPER:
850 case KEYCODE_RIGHT_HYPER:
855 case KEYCODE_PG_DOWN:
868 if (
flags & KEY_DOWN ) {
869 navigation_event_t navEvent;
871 navEvent.magnitude = 1;
872 qCDebug(lcQpaInputMethods,
"ictrl_dispatch_even navigation %d",
key);
876 key_event_t keyEvent;
879 keyEvent.key_code =
cap;
880 keyEvent.character = sym;
881 keyEvent.meta_key_state = mod;
882 keyEvent.sequence_id = sequenceId;
885 qCDebug(lcQpaInputMethods,
"ictrl_dispatch_even key %d",
key);
892void QQnxInputContext::updateCursorPosition()
902 qCDebug(lcQpaInputMethods,
"ictrl_dispatch_even key %d",
key);
905void QQnxInputContext::endComposition()
910 finishComposingText();
913 action_event_t actionEvent;
915 qCDebug(lcQpaInputMethods,
"ictrl_dispatch_even end composition");
920void QQnxInputContext::updateComposition(spannable_string_t *
text, int32_t new_cursor_position)
926 if (new_cursor_position > 0)
930 m_isComposing =
true;
932 qCDebug(lcQpaInputMethods) <<
"Text =" << m_composingText <<
"Cursor position =" << new_cursor_position;
934 QList<QInputMethodEvent::Attribute> attributes;
940 for (
unsigned int i = 0;
i <
text->spans_count; ++
i) {
942 bool underline =
false;
944 if ((
text->spans[
i].attributes_mask & COMPOSED_TEXT_ATTRIB) != 0)
947 if ((
text->spans[
i].attributes_mask & ACTIVE_REGION_ATTRIB) != 0) {
950 }
else if ((
text->spans[
i].attributes_mask & AUTO_CORRECTION_ATTRIB) != 0) {
952 }
else if ((
text->spans[
i].attributes_mask & REVERT_CORRECTION_ATTRIB) != 0) {
953 highlightColor = m_highlightColor[
Reverted];
956 if (underline || highlightColor.isValid()) {
960 if (highlightColor.isValid())
962 qCDebug(lcQpaInputMethods) <<
"attrib: " << underline << highlightColor <<
text->spans[
i].start <<
text->spans[
i].
end;
969 m_isUpdatingText =
true;
971 m_isUpdatingText =
false;
973 updateCursorPosition();
976void QQnxInputContext::finishComposingText()
984 event.setCommitString(m_composingText);
985 m_isUpdatingText =
true;
987 m_isUpdatingText =
false;
990 m_isComposing =
false;
992 updateCursorPosition();
1001 int utf16Index = utf32Index + *highSurrogateCount;
1002 while (utf16StartIndex < utf16Index) {
1003 if (
text[utf16StartIndex].isHighSurrogate()) {
1005 ++*highSurrogateCount;
1009 return utf16StartIndex;
1012int QQnxInputContext::handleSpellCheck(spell_check_event_t *
event)
1015 if (sSpellCheckQueue->isEmpty() ||
event->event.event_id != NOTIFY_SP_CHECK_MISSPELLINGS)
1019 spannable_string_t* spellCheckData = *
event->data;
1028 for (
unsigned int i = 0;
i < spellCheckData->spans_count; ++
i) {
1029 if (spellCheckData->spans[
i].attributes_mask & MISSPELLED_WORD_ATTRIB) {
1036 callerInfo.spellCheckDone(callerInfo.context,
text,
indices);
1041int32_t QQnxInputContext::processEvent(event_t *
event)
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));
1051 case EVENT_NAVIGATION: {
1052 qCDebug(lcQpaInputMethods) <<
"EVENT_NAVIGATION";
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;
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;
1070 if (kevent->meta_key_state & META_SHIFT_ON)
1072 int flags = KEY_SYM_VALID | KEY_CAP_VALID;
1073 if (
event->event_id == IMF_KEY_DOWN)
1075 qCDebug(lcQpaInputMethods,
"EVENT_KEY %d %d",
flags, keySym);
1088 case EVENT_USER_ACTION:
1090 case EVENT_INVOKE_LATER:
1091 qCritical() <<
"Unsupported event type: " <<
event->event_type;
1094 qCritical() <<
"Unknown event type: " <<
event->event_type;
1103int32_t QQnxInputContext::onCommitText(spannable_string_t *
text, int32_t new_cursor_position)
1107 updateComposition(
text, new_cursor_position);
1108 finishComposingText();
1113int32_t QQnxInputContext::onDeleteSurroundingText(int32_t left_length, int32_t right_length)
1115 qCDebug(lcQpaInputMethods,
"L: %d R: %d",
int(left_length),
int(right_length));
1121 int replacementLength = left_length + right_length;
1122 int replacementStart = -left_length;
1124 finishComposingText();
1127 event.setCommitString(
QString(), replacementStart, replacementLength);
1128 m_isUpdatingText =
true;
1130 m_isUpdatingText =
false;
1132 updateCursorPosition();
1137int32_t QQnxInputContext::onFinishComposingText()
1139 finishComposingText();
1144int32_t QQnxInputContext::onGetCursorPosition()
1152 updateCursorPosition();
1154 return m_caretPosition;
1157spannable_string_t *QQnxInputContext::onGetTextAfterCursor(int32_t
n, int32_t
flags)
1174spannable_string_t *QQnxInputContext::onGetTextBeforeCursor(int32_t
n, int32_t
flags)
1188 if (
n < m_caretPosition)
1194int32_t QQnxInputContext::onSendEvent(event_t *
event)
1198 return processEvent(
event);
1201int32_t QQnxInputContext::onSetComposingRegion(int32_t
start, int32_t
end)
1214 m_isUpdatingText =
true;
1222 m_isComposing =
true;
1224 QList<QInputMethodEvent::Attribute> attributes;
1232 m_isUpdatingText =
false;
1237int32_t QQnxInputContext::onSetComposingText(spannable_string_t *
text, int32_t new_cursor_position)
1240 updateComposition(
text, new_cursor_position);
1245 m_composingText.
clear();
1246 finishComposingText();
1251int32_t QQnxInputContext::onIsTextSelected(int32_t* pIsSelected)
1253 *pIsSelected = hasSelectedText();
1260int32_t QQnxInputContext::onIsAllTextSelected(int32_t* pIsSelected)
1279 dispatchRequestSoftwareInputPanel();
1285 dispatchCloseSoftwareInputPanel();
1290 return m_inputPanelVisible;
1295 return m_inputPanelLocale;
1298void QQnxInputContext::keyboardVisibilityChanged(
bool visible)
1301 if (m_inputPanelVisible != visible) {
1302 m_inputPanelVisible = visible;
1307void QQnxInputContext::keyboardLocaleChanged(
const QLocale &locale)
1310 if (m_inputPanelLocale !=
locale) {
1311 m_inputPanelLocale =
locale;
1343 if (m_inputPanelVisible)
1346 dispatchFocusLossEvent();
1353 dispatchFocusGainEvent(inputHints);
1360 if (!m_inputPanelVisible)
1375 action_event_t spellEvent;
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);
The QColor class provides colors based on RGB, HSV or CMYK values.
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
@ CloseSoftwareInputPanel
@ RequestSoftwareInputPanel
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
The QPlatformInputContext class abstracts the input method dependent data and composing state.
bool inputMethodAccepted() const
Returns true if current focus object supports input method events.
void emitInputPanelVisibleChanged()
Active QPlatformInputContext is responsible for providing visible property to QInputMethod.
void setEnterKeyType(EnterKeyType type)
virtual bool showKeyboard()=0
void setInputHints(int inputHints)
static EnterKeyType qtEnterKeyTypeToQnx(Qt::EnterKeyType type)
virtual bool hideKeyboard()=0
input_session_t * session
spannable_string_t * text
int32_t new_cursor_position
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.
QQnxInputContext(QQnxIntegration *integration, QQnxAbstractVirtualKeyboard &keyboard)
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.
static bool checkSpelling(const QString &text, void *context, void(*spellCheckDone)(void *context, const QString &text, const QList< int > &indices))
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 setHighlightColor(int index, const QColor &color)
QQnxScreen * primaryDisplay() const
static void injectKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
QRect geometry() const override
Reimplement in subclass to return the pixel geometry of the screen.
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height of the rectangle.
constexpr int x() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr int width() const noexcept
Returns the width of the rectangle.
\macro QT_RESTRICTED_CAST_FROM_ASCII
qsizetype toWCharArray(wchar_t *array) const
QString mid(qsizetype position, qsizetype n=-1) const &
void clear()
Clears the contents of the string and makes it null.
iterator end()
Returns an \l{STL-style iterators}{STL-style iterator} pointing just after the last character in the ...
QChar * data()
Returns a pointer to the data stored in the QString.
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
qsizetype length() const noexcept
Returns the number of characters in this string.
void setFontUnderline(bool underline)
If underline is true, sets the text format's font to be underlined; otherwise it is displayed non-und...
EGLImageKHR int int EGLuint64KHR * modifiers
Combined button and popup list for selecting options.
@ ImhDialableCharactersOnly
@ BlockingQueuedConnection
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define Q_ARG(Type, data)
GLuint64 GLenum void * handle
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLint GLsizei GLsizei GLenum format
GLsizei GLenum const void * indices
GLenum GLenum GLenum input
static QColor sSelectedColor(0, 0xb8, 0, 85)
static const input_session_t * sInputSession
static const input_session_t *(* p_ictrl_open_session)(connection_interface_t *)
static void(* p_imf_client_disconnect)()
static bool imfAvailable()
static const input_session_t * sSpellCheckSession
static bool s_imfInitFailed
static bool isSessionOkay(input_session_t *ic)
static QQnxInputContext * sInputContextInstance
static spannable_string_t * toSpannableString(const QString &text)
static int32_t(* p_ictrl_get_num_active_sessions)()
static int adjustIndex(const QChar *text, int utf32Index, int utf16StartIndex, int *highSurrogateCount)
static int32_t(* p_imf_client_init)()
static void(* p_ictrl_close_session)(input_session_t *)
static void initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId, int eventSize)
static int32_t(* p_ictrl_dispatch_event)(event_t *)
static void executeIMFRequest(QQnxImfRequest *event)
@ ImfDeleteSurroundingText
static int32_t(* p_vkb_init_selection_service)()
QNetworkRequest request(url)
void(* spellCheckDone)(void *, const QString &, const QList< int > &)
SpellCheckInfo(void *_context, void(*_spellCheckDone)(void *, const QString &, const QList< int > &))