Qt 4.8
qbbinputcontext_imf.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 - 2012 Research In Motion <blackberry-qt@qnx.com>
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 /* TODO
42  * Support inputMethodHints to restrict input (needs additional features in IMF).
43 */
44 
45 // #define QBBINPUTCONTEXT_DEBUG
46 // #define QBBINPUTCONTEXT_IMF_EVENT_DEBUG
47 
48 #define STRX(x) #x
49 #define STR(x) STRX(x)
50 #define TAG __FILE__ "(" STR(__LINE__) ")" << __func__ << ":"
51 
52 #include <qbbeventthread.h>
53 #include <qbbinputcontext.h>
55 
56 #include <QAction>
57 #include <QCoreApplication>
58 #include <QDebug>
59 #include <QInputMethodEvent>
60 #include <QMutex>
61 #include <QTextCharFormat>
62 #include <QVariant>
63 #include <QVariantHash>
64 #include <QWaitCondition>
65 
66 #include <dlfcn.h>
67 #include "imf/imf_client.h"
68 #include "imf/input_control.h"
69 #include <process.h>
70 #include <sys/keycodes.h>
71 
72 // Someone tell me why input_control methods are in this namespace, but the rest is not.
73 using namespace InputMethodSystem;
74 
75 #define qs(x) QString::fromLatin1(x)
76 #define iarg(name) event->mArgs[qs(#name)] = QVariant::fromValue(name)
77 #define parg(name) event->mArgs[qs(#name)] = QVariant::fromValue((void*)name)
78 namespace
79 {
80 
81 spannable_string_t* toSpannableString(QString const& text);
82 static const input_session_t *sInputSession = 0;
83 bool isSessionOkay(input_session_t *ic)
84 {
85  return ic !=0 && sInputSession != 0 && ic->component_id == sInputSession->component_id;
86 }
87 
89 {
90  ImfBeginBatchEdit,
91  ImfClearMetaKeyStates,
92  ImfCommitText,
93  ImfDeleteSurroundingText,
94  ImfEndBatchEdit,
95  ImfFinishComposingText,
96  ImfGetCursorCapsMode,
97  ImfGetCursorPosition,
98  ImfGetExtractedText,
99  ImfGetSelectedText,
100  ImfGetTextAfterCursor,
101  ImfGetTextBeforeCursor,
102  ImfPerformEditorAction,
103  ImfReportFullscreenMode,
104  ImfSendEvent,
105  ImfSendAsyncEvent,
106  ImfSetComposingRegion,
107  ImfSetComposingText,
108  ImfSetSelection
109 };
110 
111 // We use this class as a round about way to support a posting synchronous event into
112 // Qt's main thread from the IMF thread.
113 class ImfEventResult
114 {
115 public:
116  ImfEventResult()
117  {
118  mMutex.lock();
119  }
120 
121  ~ImfEventResult()
122  {
123  mMutex.unlock();
124  }
125 
126  void wait()
127  {
128  mWait.wait(&mMutex);
129  }
130 
131  void signal()
132  {
133  mWait.wakeAll();
134  }
135 
136  void setResult(QVariant const& result)
137  {
138  mMutex.lock();
139  mRetVal = result;
140  signal();
141  mMutex.unlock();
142  }
143 
144  QVariant& getResult()
145  {
146  return mRetVal;
147  }
148 
149 private:
150  QVariant mRetVal;
151  QMutex mMutex;
152  QWaitCondition mWait;
153 };
154 
155 class ImfEvent : public QEvent
156 {
157  public:
158  ImfEvent(input_session_t* session, ImfEventType type, ImfEventResult* result) :
159  QEvent((QEvent::Type)sUserEventType),
160  mSession(session),
161  mImfType(type),
162  mResult(result)
163  {
164  }
165  ~ImfEvent() { }
166 
167  input_session_t* mSession;
168  ImfEventType mImfType;
169  QVariantHash mArgs;
170  ImfEventResult *mResult;
171 
172  static int sUserEventType;
173 };
174 int ImfEvent::sUserEventType = QEvent::registerEventType();
175 
176 static int32_t imfBeginBatchEdit(input_session_t* ic)
177 {
178 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
179  qDebug() << TAG;
180 #endif
181 
182  if (!isSessionOkay(ic))
183  return 0;
184 
185  ImfEventResult result;
186  ImfEvent* event = new ImfEvent(ic, ImfBeginBatchEdit, &result);
188 
189  result.wait();
190  int32_t ret = result.getResult().toInt();
191 
192  return ret;
193 }
194 
195 static int32_t imfClearMetaKeyStates(input_session_t* ic, int32_t states)
196 {
197 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
198  qDebug() << TAG;
199 #endif
200 
201  if (!isSessionOkay(ic))
202  return 0;
203 
204  ImfEventResult result;
205  ImfEvent* event = new ImfEvent(ic, ImfClearMetaKeyStates, &result);
206  iarg(states);
207 
209 
210  result.wait();
211  int32_t ret = result.getResult().toInt();
212 
213  return ret;
214 }
215 
216 static int32_t imfCommitText(input_session_t* ic, spannable_string_t* text, int32_t new_cursor_position)
217 {
218 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
219  qDebug() << TAG;
220 #endif
221 
222  if (!isSessionOkay(ic))
223  return 0;
224 
225  ImfEventResult result;
226  ImfEvent* event = new ImfEvent(ic, ImfCommitText, &result);
227  parg(text);
228  iarg(new_cursor_position);
229 
231 
232  result.wait();
233  int32_t ret = result.getResult().toInt();
234 
235  return ret;
236 }
237 
238 static int32_t imfDeleteSurroundingText(input_session_t* ic, int32_t left_length, int32_t right_length)
239 {
240 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
241  qDebug() << TAG;
242 #endif
243 
244  if (!isSessionOkay(ic))
245  return 0;
246 
247  ImfEventResult result;
248  ImfEvent* event = new ImfEvent(ic, ImfDeleteSurroundingText, &result);
249  iarg(left_length);
250  iarg(right_length);
251 
253 
254  result.wait();
255  int32_t ret = result.getResult().toInt();
256 
257  return ret;
258 }
259 
260 static int32_t imfEndBatchEdit(input_session_t* ic)
261 {
262 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
263  qDebug() << TAG;
264 #endif
265 
266  if (!isSessionOkay(ic))
267  return 0;
268 
269  ImfEventResult result;
270  ImfEvent* event = new ImfEvent(ic, ImfEndBatchEdit, &result);
271 
273 
274  result.wait();
275  int32_t ret = result.getResult().toInt();
276 
277  return ret;
278 }
279 
280 static int32_t imfFinishComposingText(input_session_t* ic)
281 {
282 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
283  qDebug() << TAG;
284 #endif
285 
286  if (!isSessionOkay(ic))
287  return 0;
288 
289  ImfEventResult result;
290  ImfEvent* event = new ImfEvent(ic, ImfFinishComposingText, &result);
291 
293 
294  result.wait();
295  int32_t ret = result.getResult().toInt();
296 
297  return ret;
298 }
299 
300 static int32_t imfGetCursorCapsMode(input_session_t* ic, int32_t req_modes)
301 {
302 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
303  qDebug() << TAG;
304 #endif
305 
306  if (!isSessionOkay(ic))
307  return 0;
308 
309  ImfEventResult result;
310  ImfEvent* event = new ImfEvent(ic, ImfGetCursorCapsMode, &result);
311  iarg(req_modes);
312 
314 
315  int32_t ret = result.getResult().value<int>();
316  return ret;
317 }
318 
319 static int32_t imfGetCursorPosition(input_session_t* ic)
320 {
321 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
322  qDebug() << TAG;
323 #endif
324 
325  if (!isSessionOkay(ic))
326  return 0;
327 
328  ImfEventResult result;
329  ImfEvent* event = new ImfEvent(ic, ImfGetCursorPosition, &result);
330 
332 
333  result.wait();
334  int32_t ret = result.getResult().toInt();
335 
336  return ret;
337 }
338 
339 static extracted_text_t* imfGetExtractedText(input_session_t* ic, extracted_text_request_t* request, int32_t flags)
340 {
341 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
342  qDebug() << TAG;
343 #endif
344 
345  if (!isSessionOkay(ic)) {
346  extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1);
347  et->text = (spannable_string_t *)calloc(sizeof(spannable_string_t),1);
348  return et;
349  }
350 
351  ImfEventResult result;
352  ImfEvent* event = new ImfEvent(ic, ImfGetExtractedText, &result);
353  parg(request);
354  iarg(flags);
355 
357 
358  result.wait();
359  void* ret = result.getResult().value<void*>();
360  return (extracted_text_t*)ret;
361 }
362 
363 static spannable_string_t* imfGetSelectedText(input_session_t* ic, int32_t flags)
364 {
365 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
366  qDebug() << TAG;
367 #endif
368 
369  if (!isSessionOkay(ic))
370  return toSpannableString("");
371 
372  ImfEventResult result;
373  ImfEvent* event = new ImfEvent(ic, ImfGetSelectedText, &result);
374  iarg(flags);
375 
377 
378  result.wait();
379  void* ret = result.getResult().value<void*>();
380  return (spannable_string_t*)ret;
381 }
382 
383 static spannable_string_t* imfGetTextAfterCursor(input_session_t* ic, int32_t n, int32_t flags)
384 {
385 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
386  qDebug() << TAG;
387 #endif
388 
389  if (!isSessionOkay(ic))
390  return toSpannableString("");
391 
392  ImfEventResult result;
393  ImfEvent* event = new ImfEvent(ic, ImfGetTextAfterCursor, &result);
394  iarg(n);
395  iarg(flags);
396 
398 
399  result.wait();
400  void* ret = result.getResult().value<void*>();
401  return (spannable_string_t*)ret;
402 }
403 
404 static spannable_string_t* imfGetTextBeforeCursor(input_session_t* ic, int32_t n, int32_t flags)
405 {
406 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
407  qDebug() << TAG;
408 #endif
409 
410  if (!isSessionOkay(ic))
411  return toSpannableString("");
412 
413  ImfEventResult result;
414  ImfEvent* event = new ImfEvent(ic, ImfGetTextBeforeCursor, &result);
415  iarg(n);
416  iarg(flags);
417 
419 
420  result.wait();
421  void* ret = result.getResult().value<void*>();
422  return (spannable_string_t*)ret;
423 }
424 
425 static int32_t imfPerformEditorAction(input_session_t* ic, int32_t editor_action)
426 {
427 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
428  qDebug() << TAG;
429 #endif
430 
431  if (!isSessionOkay(ic))
432  return 0;
433 
434  ImfEventResult result;
435  ImfEvent* event = new ImfEvent(ic, ImfPerformEditorAction, &result);
436  iarg(editor_action);
437 
439 
440  result.wait();
441  int32_t ret = result.getResult().value<int>();
442  return ret;
443 }
444 
445 static int32_t imfReportFullscreenMode(input_session_t* ic, int32_t enabled)
446 {
447 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
448  qDebug() << TAG;
449 #endif
450 
451  if (!isSessionOkay(ic))
452  return 0;
453 
454  ImfEventResult result;
455  ImfEvent* event = new ImfEvent(ic, ImfReportFullscreenMode, &result);
456  iarg(enabled);
457 
459 
460  result.wait();
461  int32_t ret = result.getResult().value<int>();
462  return ret;
463 }
464 
465 static int32_t imfSendEvent(input_session_t* ic, event_t * event)
466 {
467 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
468  qDebug() << TAG;
469 #endif
470 
471  if (!isSessionOkay(ic))
472  return 0;
473 
474  ImfEvent* imfEvent = new ImfEvent(ic, ImfSendEvent, 0);
475  imfEvent->mArgs[qs("event")] = QVariant::fromValue((void*)event);
476 
478 
479  return 0;
480 }
481 
482 static int32_t imfSendAsyncEvent(input_session_t* ic, event_t * event)
483 {
484 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
485  qDebug() << TAG;
486 #endif
487 
488  if (!isSessionOkay(ic))
489  return 0;
490 
491  ImfEvent* imfEvent = new ImfEvent(ic, ImfSendAsyncEvent, 0);
492  imfEvent->mArgs[qs("event")] = QVariant::fromValue((void*)event);
493 
495 
496  return 0;
497 }
498 
499 static int32_t imfSetComposingRegion(input_session_t* ic, int32_t start, int32_t end)
500 {
501 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
502  qDebug() << TAG;
503 #endif
504 
505  if (!isSessionOkay(ic))
506  return 0;
507 
508  ImfEventResult result;
509  ImfEvent* event = new ImfEvent(ic, ImfSetComposingRegion, &result);
510  iarg(start);
511  iarg(end);
512 
514 
515  result.wait();
516  int32_t ret = result.getResult().value<int>();
517  return ret;
518 }
519 
520 static int32_t imfSetComposingText(input_session_t* ic, spannable_string_t* text, int32_t new_cursor_position)
521 {
522 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
523  qDebug() << TAG;
524 #endif
525 
526  if (!isSessionOkay(ic))
527  return 0;
528 
529  ImfEventResult result;
530  ImfEvent* event = new ImfEvent(ic, ImfSetComposingText, &result);
531  parg(text);
532  iarg(new_cursor_position);
533 
535 
536  result.wait();
537  int32_t ret = result.getResult().value<int>();
538  return ret;
539 }
540 
541 static int32_t imfSetSelection(input_session_t* ic, int32_t start, int32_t end)
542 {
543 #if defined(QBBINPUTCONTEXT_IMF_EVENT_DEBUG)
544  qDebug() << TAG;
545 #endif
546 
547  if (!isSessionOkay(ic))
548  return 0;
549 
550  ImfEventResult result;
551  ImfEvent* event = new ImfEvent(ic, ImfSetSelection, &result);
552  iarg(start);
553  iarg(end);
554 
556 
557  result.wait();
558  int32_t ret = result.getResult().value<int>();
559  return ret;
560 }
561 
562 static connection_interface_t ic_funcs = {
563  imfBeginBatchEdit,
564  imfClearMetaKeyStates,
565  imfCommitText,
566  imfDeleteSurroundingText,
567  imfEndBatchEdit,
568  imfFinishComposingText,
569  imfGetCursorCapsMode,
570  imfGetCursorPosition,
571  imfGetExtractedText,
572  imfGetSelectedText,
573  imfGetTextAfterCursor,
574  imfGetTextBeforeCursor,
575  imfPerformEditorAction,
576  imfReportFullscreenMode,
577  NULL, //ic_send_key_event
578  imfSendEvent,
579  imfSendAsyncEvent,
580  imfSetComposingRegion,
581  imfSetComposingText,
582  imfSetSelection,
583  NULL, //ic_set_candidates,
584 };
585 
586 static void
587 initEvent(event_t *pEvent, const input_session_t *pSession, EventType eventType, int eventId)
588 {
589  static int s_transactionId;
590 
591  // Make sure structure is squeaky clean since it's not clear just what is significant.
592  memset(pEvent, 0, sizeof(event_t));
593  pEvent->event_type = eventType;
594  pEvent->event_id = eventId;
595  pEvent->pid = getpid();
596  pEvent->component_id = pSession->component_id;
597  pEvent->transaction_id = ++s_transactionId;
598 }
599 
600 spannable_string_t* toSpannableString(QString const& text)
601 {
602 #if defined(QBBINPUTCONTEXT_DEBUG)
603  qDebug() << TAG << text;
604 #endif
605 
606  spannable_string_t *pString = (spannable_string_t *)malloc(sizeof(spannable_string_t));
607  pString->str = (wchar_t *)malloc(sizeof(wchar_t) * text.length()+1);
608  pString->length = text.length();
609  pString->spans = NULL;
610  pString->spans_count = 0;
611 
612  QChar const* pData = text.constData();
613  wchar_t* pDst = pString->str;
614 
615  while (!pData->isNull())
616  {
617  *pDst = pData->unicode();
618  pDst++;
619  pData++;
620  }
621  *pDst = 0;
622 
623  return pString;
624 }
625 
626 } // namespace
627 
628 static const input_session_t *(*p_ictrl_open_session)(connection_interface_t *) = 0;
629 static void (*p_ictrl_close_session)(input_session_t *) = 0;
630 static int32_t (*p_ictrl_dispatch_event)(event_t*) = 0;
631 static int32_t (*p_imf_client_init)() = 0;
632 static void (*p_imf_client_disconnect)() = 0;
633 static int32_t (*p_vkb_init_selection_service)() = 0;
634 static int32_t (*p_ictrl_get_num_active_sessions)() = 0;
635 static bool s_imfInitFailed = false;
636 
637 static bool imfAvailable()
638 {
639  static bool s_imfDisabled = getenv("DISABLE_IMF") != NULL;
640  static bool s_imfReady = false;
641 
642  if ( s_imfInitFailed || s_imfDisabled) {
643  return false;
644  }
645  else if ( s_imfReady ) {
646  return true;
647  }
648 
649  if ( p_imf_client_init == NULL ) {
650  void *handle = dlopen("libinput_client.so.1", 0);
651  if ( handle ) {
652  p_imf_client_init = (int32_t (*)()) dlsym(handle, "imf_client_init");
653  p_imf_client_disconnect = (void (*)()) dlsym(handle, "imf_client_disconnect");
654  p_ictrl_open_session = (const input_session_t* (*)(connection_interface_t*))dlsym(handle, "ictrl_open_session");
655  p_ictrl_close_session = (void (*)(input_session_t*))dlsym(handle, "ictrl_close_session");
656  p_ictrl_dispatch_event = (int32_t (*)(event_t*))dlsym(handle, "ictrl_dispatch_event");
657  p_vkb_init_selection_service = (int32_t (*)())dlsym(handle, "vkb_init_selection_service");
658  p_ictrl_get_num_active_sessions = (int32_t (*)())dlsym(handle, "ictrl_get_num_active_sessions");
659  }
660  else
661  {
662  qCritical() << TAG << "libinput_client.so.1 is not present - IMF services are disabled.";
663  s_imfDisabled = true;
664  return false;
665  }
667  s_imfReady = true;
668  }
669  else {
670  p_ictrl_open_session = NULL;
671  p_ictrl_dispatch_event = NULL;
672  s_imfDisabled = true;
673  qCritical() << TAG << "libinput_client.so.1 did not contain the correct symbols, library mismatch? IMF services are disabled.";
674  return false;
675  }
676  }
677 
678  return s_imfReady;
679 }
680 
682 
684  QInputContext(parent),
685  mLastCaretPos(0),
686  mIsComposing(false),
687  mVirtualKeyboard(keyboard)
688 {
689 #if defined(QBBINPUTCONTEXT_DEBUG)
690  qDebug() << TAG;
691 #endif
692 
693  if (!imfAvailable())
694  return;
695 
696  if ( p_imf_client_init() != 0 ) {
697  s_imfInitFailed = true;
698  qCritical("imf_client_init failed - IMF services will be unavailable");
699  }
700 
702 
703  // p_vkb_init_selection_service();
704 }
705 
707 {
708 #if defined(QBBINPUTCONTEXT_DEBUG)
709  qDebug() << TAG;
710 #endif
711 
712  if (!imfAvailable())
713  return;
714 
717 }
718 
719 #define getarg(type, name) type name = imfEvent->mArgs[qs(#name)].value<type>()
720 #define getparg(type, name) type name = (type)(imfEvent->mArgs[qs(#name)].value<void*>())
721 
723 {
724 
725  if (event->type() == ImfEvent::sUserEventType) {
726  // Forward the event to our real handler.
727  ImfEvent* imfEvent = static_cast<ImfEvent*>(event);
728  switch (imfEvent->mImfType) {
729  case ImfBeginBatchEdit:
730  {
731  int32_t ret = onBeginBatchEdit(imfEvent->mSession);
732  imfEvent->mResult->setResult(QVariant::fromValue(ret));
733  break;
734  }
735 
736  case ImfClearMetaKeyStates:
737  {
738  getarg(int32_t, states);
739  int32_t ret = onClearMetaKeyStates(imfEvent->mSession, states);
740  imfEvent->mResult->setResult(QVariant::fromValue(ret));
741  break;
742  }
743 
744  case ImfCommitText:
745  {
746  getparg(spannable_string_t*, text);
747  getarg(int32_t, new_cursor_position);
748  int32_t ret = onCommitText(imfEvent->mSession, text, new_cursor_position);
749  imfEvent->mResult->setResult(QVariant::fromValue(ret));
750  break;
751  }
752 
753  case ImfDeleteSurroundingText:
754  {
755  getarg(int32_t, left_length);
756  getarg(int32_t, right_length);
757  int32_t ret = onDeleteSurroundingText(imfEvent->mSession, left_length, right_length);
758  imfEvent->mResult->setResult(QVariant::fromValue(ret));
759  break;
760  }
761 
762  case ImfEndBatchEdit:
763  {
764  int32_t ret = onEndBatchEdit(imfEvent->mSession);
765  imfEvent->mResult->setResult(QVariant::fromValue(ret));
766  break;
767  }
768 
769  case ImfFinishComposingText:
770  {
771  int32_t ret = onFinishComposingText(imfEvent->mSession);
772  imfEvent->mResult->setResult(QVariant::fromValue(ret));
773  break;
774  }
775 
776  case ImfGetCursorCapsMode:
777  {
778  getarg(int32_t, req_modes);
779  int32_t ret = onGetCursorCapsMode(imfEvent->mSession, req_modes);
780  imfEvent->mResult->setResult(QVariant::fromValue(ret));
781  break;
782  }
783 
784  case ImfGetCursorPosition:
785  {
786  int32_t ret = onGetCursorPosition(imfEvent->mSession);
787  imfEvent->mResult->setResult(QVariant::fromValue(ret));
788  break;
789  }
790 
791  case ImfGetExtractedText:
792  {
793  getparg(extracted_text_request_t*, request);
794  getarg(int32_t, flags);
795  extracted_text_t* ret = onGetExtractedText(imfEvent->mSession, request, flags);
796  imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
797  break;
798  }
799 
800  case ImfGetSelectedText:
801  {
802  getarg(int32_t, flags);
803  spannable_string_t* ret = onGetSelectedText(imfEvent->mSession, flags);
804  imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
805  break;
806  }
807 
808  case ImfGetTextAfterCursor:
809  {
810  getarg(int32_t, n);
811  getarg(int32_t, flags);
812  spannable_string_t* ret = onGetTextAfterCursor(imfEvent->mSession, n, flags);
813  imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
814  break;
815  }
816 
817  case ImfGetTextBeforeCursor:
818  {
819  getarg(int32_t, n);
820  getarg(int32_t, flags);
821  spannable_string_t* ret = onGetTextBeforeCursor(imfEvent->mSession, n, flags);
822  imfEvent->mResult->setResult(QVariant::fromValue((void*)ret));
823  break;
824  }
825 
826  case ImfPerformEditorAction:
827  {
828  getarg(int32_t, editor_action);
829  int32_t ret = onPerformEditorAction(imfEvent->mSession, editor_action);
830  imfEvent->mResult->setResult(QVariant::fromValue(ret));
831  break;
832  }
833 
834  case ImfReportFullscreenMode:
835  {
836  getarg(int32_t, enabled);
837  int32_t ret = onReportFullscreenMode(imfEvent->mSession, enabled);
838  imfEvent->mResult->setResult(QVariant::fromValue(ret));
839  break;
840  }
841 
842  case ImfSendEvent:
843  {
844  getparg(event_t*, event);
845  onSendEvent(imfEvent->mSession, event);
846  break;
847  }
848 
849  case ImfSendAsyncEvent:
850  {
851  getparg(event_t*, event);
852  onSendAsyncEvent(imfEvent->mSession, event);
853  break;
854  }
855 
856  case ImfSetComposingRegion:
857  {
858  getarg(int32_t, start);
859  getarg(int32_t, end);
860  int32_t ret = onSetComposingRegion(imfEvent->mSession, start, end);
861  imfEvent->mResult->setResult(QVariant::fromValue(ret));
862  break;
863  }
864 
865  case ImfSetComposingText:
866  {
867  getparg(spannable_string_t*, text);
868  getarg(int32_t, new_cursor_position);
869  int32_t ret = onSetComposingText(imfEvent->mSession, text, new_cursor_position);
870  imfEvent->mResult->setResult(QVariant::fromValue(ret));
871  break;
872  }
873 
874  case ImfSetSelection:
875  {
876  getarg(int32_t, start);
877  getarg(int32_t, end);
878  int32_t ret = onSetSelection(imfEvent->mSession, start, end);
879  imfEvent->mResult->setResult(QVariant::fromValue(ret));
880  break;
881  }
882  }; //switch
883 
884  return true;
885  } else {
886  // standard event processing
887  return QObject::eventFilter(obj, event);
888  }
889 }
890 
892 {
893  return tr("PlayBook IMF");
894 }
895 
897 {
898  return mVirtualKeyboard.languageId();
899 }
900 
902 {
903 #if defined(QBBINPUTCONTEXT_DEBUG)
904  qDebug() << TAG << event;
905 #endif
906 
907  switch (event->type()) {
910  }
913  }
914  default:
915  return false;
916  }
917 }
918 
920 {
921 #if defined(QBBINPUTCONTEXT_DEBUG)
922  qDebug() << TAG;
923 #endif
924  return QInputContext::actions();
925 }
926 
928 {
929 #if defined(QBBINPUTCONTEXT_DEBUG)
930  qDebug() << TAG;
931 #endif
932  return QInputContext::font();
933 }
934 
936 {
937 #if defined(QBBINPUTCONTEXT_DEBUG)
938  qDebug() << TAG;
939 #endif
940  return mIsComposing;
941 }
942 
944 {
945 #if defined(QBBINPUTCONTEXT_DEBUG)
946  qDebug() << TAG;
947 #endif
948  return QInputContext::mouseHandler(x, event);
949 }
950 
952 {
953 #if defined(QBBINPUTCONTEXT_DEBUG)
954  qDebug() << TAG;
955 #endif
956 
957  endComposition();
958 }
959 
961 {
962 #if defined(QBBINPUTCONTEXT_DEBUG)
963  qDebug() << TAG;
964 #endif
965 
966  if (hasSession()) {
967  endComposition();
968  dispatchFocusEvent(FOCUS_LOST);
969  closeSession();
970  }
971 
972  // Update the widget before moving on.
974 
975  // If we have hidden text, or any flags that restrict input (exclusive flags), then we just disable
976  // imf for this field.
977  if (widget != 0 && !(widget->inputMethodHints() & Qt::ImhHiddenText) && !(widget->inputMethodHints() >= Qt::ImhDigitsOnly && widget->inputMethodHints() <= Qt::ImhUrlCharactersOnly))
978  {
979 #if defined(QBBINPUTCONTEXT_DEBUG)
980  qDebug() << TAG << "Starting input session for " << widget;
981 #endif
982  openSession();
983  dispatchFocusEvent(FOCUS_GAINED, widget->inputMethodHints());
984  }
985 }
986 
988 {
989 #if defined(QBBINPUTCONTEXT_DEBUG)
990  qDebug() << TAG;
991 #endif
992 
993  reset();
994 
996 }
997 
999 {
1000 #if defined(QBBINPUTCONTEXT_DEBUG)
1001  qDebug() << TAG;
1002 #endif
1004 }
1005 
1007 {
1008 #if defined(QBBINPUTCONTEXT_DEBUG)
1009  qDebug() << TAG;;
1010 #endif
1011 
1012  if (!imfAvailable())
1013  return;
1014 
1015  if (sInputSession) {
1016  p_ictrl_close_session((input_session_t *)sInputSession);
1017  sInputSession = 0;
1018  }
1019 }
1020 
1022 {
1023 #if defined(QBBINPUTCONTEXT_DEBUG)
1024  qDebug() << TAG;;
1025 #endif
1026 
1027  if (!imfAvailable())
1028  return;
1029 
1030  closeSession();
1031  sInputSession = p_ictrl_open_session(&ic_funcs);
1032 }
1033 
1035 {
1036  return sInputSession != 0;
1037 }
1038 
1040 {
1041  if (focusWidget()) {
1043  }
1044  else
1045  {
1046  return false;
1047  }
1048 }
1049 
1051 {
1053 #if defined(QBBINPUTCONTEXT_DEBUG)
1054  qDebug() << "QBB: requesting virtual keyboard";
1055 #endif
1056 
1057  if (!imfAvailable() || !focusWidget())
1058  return true;
1059 
1060  // This also means that the caret position has moved
1062  caret_event_t caretEvent;
1063  memset(&caretEvent, 0, sizeof(caret_event_t));
1064  initEvent(&caretEvent.event, sInputSession, EVENT_CARET, CARET_POS_CHANGED);
1065  caretEvent.old_pos = mLastCaretPos;
1066  mLastCaretPos = caretEvent.new_pos = caretPos;
1067  p_ictrl_dispatch_event((event_t *)&caretEvent);
1068  return true;
1069 }
1070 
1072 {
1074 #if defined(QBBINPUTCONTEXT_DEBUG)
1075  qDebug() << "QBB: hiding virtual keyboard";
1076 #endif
1077 
1078  // This also means we are stopping composition, but we should already have done that.
1079  return true;
1080 }
1081 
1082 /*
1083  * IMF Event Dispatchers.
1084  */
1085 bool QBBInputContext::dispatchFocusEvent(FocusEventId id, int hints)
1086 {
1087 #if defined(QBBINPUTCONTEXT_DEBUG)
1088  qDebug() << TAG;
1089 #endif
1090 
1091  if (!sInputSession) {
1092  qWarning() << TAG << "Attempt to dispatch a focus event with no input session.";
1093  return false;
1094  }
1095 
1096  if (!imfAvailable())
1097  return false;
1098 
1099  // Set the last caret position to 0 since we don't really have one and we don't
1100  // want to have the old one.
1101  mLastCaretPos = 0;
1102 
1103  focus_event_t focusEvent;
1104  memset(&focusEvent, 0, sizeof(focusEvent));
1105  initEvent(&focusEvent.event, sInputSession, EVENT_FOCUS, id);
1106  focusEvent.style = DEFAULT_STYLE;
1107 
1108  if (hints && Qt::ImhNoPredictiveText)
1109  focusEvent.style |= NO_PREDICTION | NO_AUTO_CORRECTION;
1110  if (hints && Qt::ImhNoAutoUppercase)
1111  focusEvent.style |= NO_AUTO_TEXT;
1112 
1113  p_ictrl_dispatch_event((event_t *)&focusEvent);
1114 
1115  return true;
1116 }
1117 
1118 bool QBBInputContext::handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
1119 {
1120  if (!imfAvailable())
1121  return false;
1122 
1123  int key = (flags & KEY_SYM_VALID) ? sym : cap;
1124  bool navKey = false;
1125  switch ( key ) {
1126  case KEYCODE_RETURN:
1127  /* In a single line edit we should end composition because enter might be used by something.
1128  endComposition();
1129  return false;*/
1130  break;
1131 
1132  case KEYCODE_BACKSPACE:
1133  case KEYCODE_DELETE:
1134  // If there is a selection range, then we want a delete key to operate on that (by
1135  // deleting the contents of the select range) rather than operating on the composition
1136  // range.
1137  if (hasSelectedText())
1138  return false;
1139  break;
1140  case KEYCODE_LEFT:
1141  key = NAVIGATE_LEFT;
1142  navKey = true;
1143  break;
1144  case KEYCODE_RIGHT:
1145  key = NAVIGATE_RIGHT;
1146  navKey = true;
1147  break;
1148  case KEYCODE_UP:
1149  key = NAVIGATE_UP;
1150  navKey = true;
1151  break;
1152  case KEYCODE_DOWN:
1153  key = NAVIGATE_DOWN;
1154  navKey = true;
1155  break;
1156  case KEYCODE_CAPS_LOCK:
1157  case KEYCODE_LEFT_SHIFT:
1158  case KEYCODE_RIGHT_SHIFT:
1159  case KEYCODE_LEFT_CTRL:
1160  case KEYCODE_RIGHT_CTRL:
1161  case KEYCODE_LEFT_ALT:
1162  case KEYCODE_RIGHT_ALT:
1163  case KEYCODE_MENU:
1164  case KEYCODE_LEFT_HYPER:
1165  case KEYCODE_RIGHT_HYPER:
1166  case KEYCODE_INSERT:
1167  case KEYCODE_HOME:
1168  case KEYCODE_PG_UP:
1169  case KEYCODE_END:
1170  case KEYCODE_PG_DOWN:
1171  // Don't send these
1172  key = 0;
1173  break;
1174  }
1175 
1176  if ( mod & KEYMOD_CTRL ) {
1177  // If CTRL is pressed, just let AIR handle it. But terminate any composition first
1178  //endComposition();
1179  return false;
1180  }
1181 
1182  // Pass the keys we don't know about on through
1183  if ( key == 0 )
1184  return false;
1185 
1186  // IMF doesn't need key releases so just swallow them.
1187  if (!(flags & KEY_DOWN))
1188  return true;
1189 
1190  if ( navKey ) {
1191  // Even if we're forwarding up events, we can't do this for
1192  // navigation keys.
1193  if ( flags & KEY_DOWN ) {
1194  navigation_event_t navEvent;
1195  initEvent(&navEvent.event, sInputSession, EVENT_NAVIGATION, key);
1196  navEvent.magnitude = 1;
1197 #if defined(QBBINPUTCONTEXT_DEBUG)
1198  qDebug() << TAG << "dispatch navigation event " << key;
1199 #endif
1200  p_ictrl_dispatch_event(&navEvent.event);
1201  }
1202  }
1203  else {
1204  key_event_t keyEvent;
1205  initEvent(&keyEvent.event, sInputSession, EVENT_KEY, flags & KEY_DOWN ? IMF_KEY_DOWN : IMF_KEY_UP);
1206  keyEvent.key_code = key;
1207  keyEvent.character = 0;
1208  keyEvent.meta_key_state = 0;
1209 
1210  p_ictrl_dispatch_event(&keyEvent.event);
1211 #if defined(QBBINPUTCONTEXT_DEBUG)
1212  qDebug() << TAG << "dispatch key event " << key;
1213 #endif
1214  }
1215 
1216  scan = 0;
1217  return true;
1218 }
1219 
1221 {
1222  if (!imfAvailable())
1223  return;
1224 
1225  if (!isComposing())
1226  return;
1227 
1229  QInputMethodEvent event(QLatin1String(""), attributes);
1230  event.setCommitString(mComposingText);
1231  mComposingText = QString();
1232  mIsComposing = false;
1233  sendEvent(event);
1234 
1235  action_event_t actionEvent;
1236  memset(&actionEvent, 0, sizeof(actionEvent));
1237  initEvent(&actionEvent.event, sInputSession, EVENT_ACTION, ACTION_END_COMPOSITION);
1238  p_ictrl_dispatch_event(&actionEvent.event);
1239 }
1240 
1241 void QBBInputContext::setComposingText(QString const& composingText)
1242 {
1243  mComposingText = composingText;
1244  mIsComposing = true;
1245 
1248  format.setFontUnderline(true);
1250 
1251  QInputMethodEvent event(composingText, attributes);
1252 
1253  sendEvent(event);
1254 }
1255 
1257 {
1258  int32_t result = -1;
1259  switch (event->event_type) {
1260  case EVENT_SPELL_CHECK: {
1261  #if defined(QBBINPUTCONTEXT_DEBUG)
1262  qDebug() << TAG << "EVENT_SPELL_CHECK";
1263  #endif
1264  result = 0;
1265  break;
1266  }
1267 
1268  case EVENT_NAVIGATION: {
1269  #if defined(QBBINPUTCONTEXT_DEBUG)
1270  qDebug() << TAG << "EVENT_NAVIGATION";
1271  #endif
1272 
1273  int key = event->event_id == NAVIGATE_UP ? KEYCODE_UP :
1274  event->event_id == NAVIGATE_DOWN ? KEYCODE_DOWN :
1275  event->event_id == NAVIGATE_LEFT ? KEYCODE_LEFT :
1276  event->event_id == NAVIGATE_RIGHT ? KEYCODE_RIGHT : 0;
1277 
1278  QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, key, 0, 0, 0);
1279  QBBEventThread::injectKeyboardEvent(KEY_CAP_VALID, key, 0, 0, 0);
1280  result = 0;
1281  break;
1282  }
1283 
1284  case EVENT_KEY: {
1285  #if defined(QBBINPUTCONTEXT_DEBUG)
1286  qDebug() << TAG << "EVENT_KEY";
1287  #endif
1288  key_event_t* kevent = (key_event_t*) event;
1289 
1290  QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code);
1291  QBBEventThread::injectKeyboardEvent(KEY_SYM_VALID | KEY_CAP_VALID, kevent->key_code, 0, 0, kevent->key_code);
1292 
1293  result = 0;
1294  break;
1295  }
1296 
1297  case EVENT_ACTION:
1298  // Don't care, indicates that IMF is done.
1299  break;
1300 
1301  case EVENT_CARET:
1302  case EVENT_NOTHING:
1303  case EVENT_FOCUS:
1304  case EVENT_USER_ACTION:
1305  case EVENT_STROKE:
1306  case EVENT_INVOKE_LATER:
1307  qCritical() << TAG << "Unsupported event type: " << event->event_type;
1308  break;
1309  default:
1310  qCritical() << TAG << "Unknown event type: " << event->event_type;
1311  }
1312  return result;
1313 }
1314 
1315 /*
1316  * IMF Event Handlers
1317  */
1318 
1319 int32_t QBBInputContext::onBeginBatchEdit(input_session_t* ic)
1320 {
1321 #if defined(QBBINPUTCONTEXT_DEBUG)
1322  qDebug() << TAG;
1323 #endif
1324 
1325  if (!isSessionOkay(ic))
1326  return 0;
1327 
1328  // We don't care.
1329  return 0;
1330 }
1331 
1332 int32_t QBBInputContext::onClearMetaKeyStates(input_session_t* ic, int32_t states)
1333 {
1334  Q_UNUSED(states);
1335 #if defined(QBBINPUTCONTEXT_DEBUG)
1336  qDebug() << TAG;
1337 #endif
1338 
1339  if (!isSessionOkay(ic))
1340  return 0;
1341 
1342  // Should never get called.
1343  qCritical() << TAG << "onClearMetaKeyStates is unsupported.";
1344  return 0;
1345 }
1346 
1347 int32_t QBBInputContext::onCommitText(input_session_t* ic, spannable_string_t* text, int32_t new_cursor_position)
1348 {
1349  Q_UNUSED(new_cursor_position); // TODO: How can we set the cursor position it's not part of the API.
1350  if (!isSessionOkay(ic))
1351  return 0;
1352 
1353  QString commitString = QString::fromWCharArray(text->str, text->length);
1354 
1355 #if defined(QBBINPUTCONTEXT_DEBUG)
1356  qDebug() << TAG << "Committing [" << commitString << "]";
1357 #endif
1358 
1360  QInputMethodEvent event(QLatin1String(""), attributes);
1361  event.setCommitString(commitString, 0, 0);
1362 
1363  sendEvent(event);
1364  mComposingText = QString();
1365 
1366  return 0;
1367 }
1368 
1369 int32_t QBBInputContext::onDeleteSurroundingText(input_session_t* ic, int32_t left_length, int32_t right_length)
1370 {
1371 #if defined(QBBINPUTCONTEXT_DEBUG)
1372  qDebug() << TAG << "L:" << left_length << " R:" << right_length;
1373 #endif
1374 
1375  if (!isSessionOkay(ic))
1376  return 0;
1377 
1378  if (hasSelectedText()) {
1379  QBBEventThread::injectKeyboardEvent(KEY_DOWN | KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0);
1380  QBBEventThread::injectKeyboardEvent(KEY_CAP_VALID, KEYCODE_DELETE, 0, 0, 0);
1381  reset();
1382  return 0;
1383  }
1384 
1385  int replacementLength = left_length + right_length;
1386  int replacementStart = -left_length;
1387 
1389  QInputMethodEvent event(QLatin1String(""), attributes);
1390  event.setCommitString(QLatin1String(""), replacementStart, replacementLength);
1391  sendEvent(event);
1392 
1393  return 0;
1394 }
1395 
1396 int32_t QBBInputContext::onEndBatchEdit(input_session_t* ic)
1397 {
1398 #if defined(QBBINPUTCONTEXT_DEBUG)
1399  qDebug() << TAG;
1400 #endif
1401 
1402  if (!isSessionOkay(ic))
1403  return 0;
1404 
1405  return 0;
1406 }
1407 
1408 int32_t QBBInputContext::onFinishComposingText(input_session_t* ic)
1409 {
1410 #if defined(QBBINPUTCONTEXT_DEBUG)
1411  qDebug() << TAG;
1412 #endif
1413 
1414  if (!isSessionOkay(ic))
1415  return 0;
1416 
1417  // Only update the control, no need to send a message back to imf (don't call
1418  // end composition)
1420  QInputMethodEvent event(QLatin1String(""), attributes);
1421  event.setCommitString(mComposingText);
1422  mComposingText = QString();
1423  mIsComposing = false;
1424  sendEvent(event);
1425 
1426  return 0;
1427 }
1428 
1429 int32_t QBBInputContext::onGetCursorCapsMode(input_session_t* ic, int32_t req_modes)
1430 {
1431  Q_UNUSED(req_modes);
1432 #if defined(QBBINPUTCONTEXT_DEBUG)
1433  qDebug() << TAG;
1434 #endif
1435 
1436  if (!isSessionOkay(ic))
1437  return 0;
1438 
1439  // Should never get called.
1440  qCritical() << TAG << "onGetCursorCapsMode is unsupported.";
1441 
1442  return 0;
1443 }
1444 
1445 int32_t QBBInputContext::onGetCursorPosition(input_session_t* ic)
1446 {
1447 #if defined(QBBINPUTCONTEXT_DEBUG)
1448  qDebug() << TAG;
1449 #endif
1450 
1451  if (!isSessionOkay(ic))
1452  return 0;
1453 
1455  return mLastCaretPos;
1456 }
1457 
1458 extracted_text_t* QBBInputContext::onGetExtractedText(input_session_t* ic, extracted_text_request_t* request, int32_t flags)
1459 {
1460  Q_UNUSED(flags);
1461  Q_UNUSED(request);
1462 #if defined(QBBINPUTCONTEXT_DEBUG)
1463  qDebug() << TAG;
1464 #endif
1465 
1466  if (!isSessionOkay(ic)) {
1467  extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1);
1468  et->text = (spannable_string_t *)calloc(sizeof(spannable_string_t),1);
1469  return 0;
1470  }
1471 
1472  // Used to update dictionaries, but not supported right now.
1473  extracted_text_t *et = (extracted_text_t *)calloc(sizeof(extracted_text_t),1);
1474  et->text = (spannable_string_t *)calloc(sizeof(spannable_string_t),1);
1475 
1476  return et;
1477 }
1478 
1479 spannable_string_t* QBBInputContext::onGetSelectedText(input_session_t* ic, int32_t flags)
1480 {
1481  Q_UNUSED(flags);
1482 #if defined(QBBINPUTCONTEXT_DEBUG)
1483  qDebug() << TAG;
1484 #endif
1485 
1486  if (!isSessionOkay(ic))
1487  return toSpannableString("");
1488 
1490  return toSpannableString(text);
1491 }
1492 
1493 spannable_string_t* QBBInputContext::onGetTextAfterCursor(input_session_t* ic, int32_t n, int32_t flags)
1494 {
1495  Q_UNUSED(flags);
1496 #if defined(QBBINPUTCONTEXT_DEBUG)
1497  qDebug() << TAG;
1498 #endif
1499 
1500  if (!isSessionOkay(ic))
1501  return toSpannableString("");
1502 
1505 
1506  return toSpannableString(text.mid(mLastCaretPos+1, n));
1507 }
1508 
1509 spannable_string_t* QBBInputContext::onGetTextBeforeCursor(input_session_t* ic, int32_t n, int32_t flags)
1510 {
1511  Q_UNUSED(flags);
1512 #if defined(QBBINPUTCONTEXT_DEBUG)
1513  qDebug() << TAG;
1514 #endif
1515 
1516  if (!isSessionOkay(ic))
1517  return toSpannableString("");
1518 
1521 
1522  if (n < mLastCaretPos)
1523  {
1524  return toSpannableString(text.mid(mLastCaretPos - n, n));
1525  }
1526  else
1527  return toSpannableString(text.mid(0, mLastCaretPos));
1528 }
1529 
1530 int32_t QBBInputContext::onPerformEditorAction(input_session_t* ic, int32_t editor_action)
1531 {
1532  Q_UNUSED(editor_action);
1533 #if defined(QBBINPUTCONTEXT_DEBUG)
1534  qDebug() << TAG;
1535 #endif
1536 
1537  if (!isSessionOkay(ic))
1538  return 0;
1539 
1540  // Should never get called.
1541  qCritical() << TAG << "onPerformEditorAction is unsupported.";
1542 
1543  return 0;
1544 }
1545 
1546 int32_t QBBInputContext::onReportFullscreenMode(input_session_t* ic, int32_t enabled)
1547 {
1548  Q_UNUSED(enabled);
1549 #if defined(QBBINPUTCONTEXT_DEBUG)
1550  qDebug() << TAG;
1551 #endif
1552 
1553  if (!isSessionOkay(ic))
1554  return 0;
1555 
1556  // Should never get called.
1557  qCritical() << TAG << "onReportFullscreenMode is unsupported.";
1558 
1559  return 0;
1560 }
1561 
1562 int32_t QBBInputContext::onSendEvent(input_session_t* ic, event_t * event)
1563 {
1564 #if defined(QBBINPUTCONTEXT_DEBUG)
1565  qDebug() << TAG;
1566 #endif
1567 
1568  if (!isSessionOkay(ic))
1569  return 0;
1570 
1571  return processEvent(event);
1572 }
1573 
1574 int32_t QBBInputContext::onSendAsyncEvent(input_session_t* ic, event_t * event)
1575 {
1576 #if defined(QBBINPUTCONTEXT_DEBUG)
1577  qDebug() << TAG;
1578 #endif
1579 
1580  if (!isSessionOkay(ic))
1581  return 0;
1582 
1583  return processEvent(event);
1584 }
1585 
1586 int32_t QBBInputContext::onSetComposingRegion(input_session_t* ic, int32_t start, int32_t end)
1587 {
1588 #if defined(QBBINPUTCONTEXT_DEBUG)
1589  qDebug() << TAG;
1590 #endif
1591 
1592  if (!isSessionOkay(ic))
1593  return 0;
1594 
1595  if (!focusWidget())
1596  {
1597  qCritical() << "No focus widget!";
1598  return 0;
1599  }
1600 
1602 
1605  QString empty = QString::fromLatin1("");
1606  text = text.mid(start, end - start);
1607 
1608  // Delete the current text.
1609  {
1610  QInputMethodEvent event(empty, attributes);
1611  event.setCommitString(empty, start - mLastCaretPos, end - start);
1612  sendEvent(event);
1613  }
1614 
1615  // Move the specified text into a preedit string.
1616  {
1617  setComposingText(text);
1618  }
1619 
1620  return 0;
1621 }
1622 
1623 int32_t QBBInputContext::onSetComposingText(input_session_t* ic, spannable_string_t* text, int32_t new_cursor_position)
1624 {
1625  Q_UNUSED(new_cursor_position);
1626 #if defined(QBBINPUTCONTEXT_DEBUG)
1627  qDebug() << TAG;
1628 #endif
1629 
1630  if (!isSessionOkay(ic))
1631  return 0;
1632 
1633  if (!focusWidget())
1634  {
1635  qCritical() << "No focus widget!";
1636  return 0;
1637  }
1638 
1639  mIsComposing = true;
1640 
1641  QString preeditString = QString::fromWCharArray(text->str, text->length);
1642  setComposingText(preeditString);
1643 
1644  return 0;
1645 }
1646 
1647 int32_t QBBInputContext::onSetSelection(input_session_t* ic, int32_t start, int32_t end)
1648 {
1649  Q_UNUSED(start);
1650  Q_UNUSED(end);
1651 #if defined(QBBINPUTCONTEXT_DEBUG)
1652  qDebug() << TAG;
1653 #endif
1654 
1655  if (!isSessionOkay(ic))
1656  return 0;
1657 
1658  // Should never get called.
1659  qCritical() << TAG << "onSetSelection is unsupported.";
1660 
1661  return 0;
1662 }
1663 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
extracted_text_t * onGetExtractedText(input_session_t *ic, extracted_text_request_t *request, int32_t flags)
static QString fromWCharArray(const wchar_t *, int size=-1)
Returns a copy of the string, where the encoding of string depends on the size of wchar...
Definition: qstring.cpp:1019
virtual void widgetDestroyed(QWidget *widget)
This virtual function is called when the specified widget is destroyed.
#define getparg(type, name)
static const input_session_t *(* p_ictrl_open_session)(connection_interface_t *)=0
virtual void update()
This virtual function is called when a state in the focus widget has changed.
virtual bool hideKeyboard()=0
void push_back(const T &t)
This function is provided for STL compatibility.
Definition: qlist.h:296
int type
Definition: qmetatype.cpp:239
The QTextCharFormat class provides formatting information for characters in a QTextDocument.
Definition: qtextformat.h:372
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
The QMutex class provides access serialization between threads.
Definition: qmutex.h:60
EventRef event
QPointer< QWidget > widget
The QInputMethodEvent::Attribute class stores an input method attribute.
Definition: qevent.h:441
virtual void mouseHandler(int x, QMouseEvent *event)
This function can be reimplemented in a subclass to handle mouse press, release, double-click, and move events within the preedit text.
int32_t onFinishComposingText(input_session_t *ic)
static void keyEvent(KeyAction action, QWidget *widget, char ascii, Qt::KeyboardModifiers modifier=Qt::NoModifier, int delay=-1)
ushort unicode() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qchar.h:251
int32_t onSetSelection(input_session_t *ic, int32_t start, int32_t end)
bool isNull() const
Returns true if the character is the Unicode character 0x0000 (&#39;\0&#39;); otherwise returns false...
Definition: qchar.h:262
static void(* p_imf_client_disconnect)()=0
static void postEvent(QObject *receiver, QEvent *event)
Adds the event event, with the object receiver as the receiver of the event, to an event queue and re...
int32_t onSendAsyncEvent(input_session_t *ic, event_t *event)
int32_t onPerformEditorAction(input_session_t *ic, int32_t editor_action)
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
void removeEventFilter(QObject *)
Removes an event filter object obj from this object.
Definition: qobject.cpp:2099
The QWidget class is the base class of all user interface objects.
Definition: qwidget.h:150
QString toString() const
Returns the variant as a QString if the variant has type() String , Bool , ByteArray ...
Definition: qvariant.cpp:2270
int32_t onSetComposingText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
int32_t onGetCursorCapsMode(input_session_t *ic, int32_t req_modes)
static QString tr(const char *sourceText, const char *comment=0, int n=-1)
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool dispatchFocusEvent(FocusEventId id, int hints=Qt::ImhNone)
virtual void reset()
This function can be reimplemented in a subclass to reset the state of the input method.
spannable_string_t * onGetTextBeforeCursor(input_session_t *ic, int32_t n, int32_t flags)
virtual QVariant inputMethodQuery(Qt::InputMethodQuery) const
This method is only relevant for input widgets.
Definition: qwidget.cpp:9683
#define TAG
QWidget * focusWidget() const
Returns the widget that has an input focus for this input context.
The QString class provides a Unicode character string.
Definition: qstring.h:83
virtual QString identifierName()
This function must be implemented in any subclasses to return the identifier name of the input method...
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
QBBAbstractVirtualKeyboard & mVirtualKeyboard
virtual bool event(QEvent *)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition: qobject.cpp:1200
int32_t onGetCursorPosition(input_session_t *ic)
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
virtual QList< QAction * > actions()
This is a preliminary interface for Qt 4.
bool eventFilter(QObject *obj, QEvent *event)
Filters events if this object has been installed as an event filter for the watched object...
bool handleKeyboardEvent(int flags, int sym, int mod, int scan, int cap)
int toInt(bool *ok=0) const
Returns the variant as an int if the variant has type() Int , Bool , ByteArray , Char ...
Definition: qvariant.cpp:2625
static bool imfAvailable()
Q_CORE_EXPORT void qDebug(const char *,...)
int32_t processEvent(event_t *event)
QBBInputContext(QBBAbstractVirtualKeyboard &keyboard, QObject *parent=0)
int32_t onBeginBatchEdit(input_session_t *ic)
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
static int32_t(* p_ictrl_get_num_active_sessions)()=0
virtual void widgetDestroyed(QWidget *w)
This virtual function is called when the specified widget is destroyed.
static bool s_imfInitFailed
virtual void update()
This virtual function is called when a state in the focus widget has changed.
#define calloc(a, b)
int32_t onEndBatchEdit(input_session_t *ic)
Q_CORE_EXPORT void qWarning(const char *,...)
virtual QFont font() const
Returns the font of the current input widget.
int32_t onReportFullscreenMode(input_session_t *ic, int32_t enabled)
virtual void mouseHandler(int x, QMouseEvent *event)
This function can be reimplemented in a subclass to handle mouse press, release, double-click, and move events within the preedit text.
static QVariant fromValue(const T &value)
Returns a QVariant containing a copy of value.
Definition: qvariant.h:336
int32_t onSendEvent(input_session_t *ic, event_t *event)
virtual QFont font() const
Returns the font of the current input widget.
virtual bool eventFilter(QObject *, QEvent *)
Filters events if this object has been installed as an event filter for the watched object...
Definition: qobject.cpp:1375
The QMouseEvent class contains parameters that describe a mouse event.
Definition: qevent.h:85
virtual bool filterEvent(const QEvent *event)
This function can be reimplemented in a subclass to filter input events.
static int32_t(* p_vkb_init_selection_service)()=0
virtual QString language()
This function must be implemented in any subclasses to return a language code (e. ...
The QInputMethodEvent class provides parameters for input method events.
Definition: qevent.h:431
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
int32_t onDeleteSurroundingText(input_session_t *ic, int32_t left_length, int32_t right_length)
void setComposingText(QString const &composingText)
virtual void setFocusWidget(QWidget *widget)
Sets the widget that has an input focus for this input context.
Type
This enum type defines the valid event types in Qt.
Definition: qcoreevent.h:62
int32_t onClearMetaKeyStates(input_session_t *ic, int32_t states)
The QFont class specifies a font used for drawing text.
Definition: qfont.h:64
static QCoreApplication * instance()
Returns a pointer to the application&#39;s QCoreApplication (or QApplication) instance.
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
virtual QList< QAction * > actions()
This is a preliminary interface for Qt 4.
void sendEvent(const QInputMethodEvent &event)
Sends an input method event specified by event to the current focus widget.
void setFontUnderline(bool underline)
If underline is true, sets the text format&#39;s font to be underlined; otherwise it is displayed non-und...
Definition: qtextformat.h:432
virtual bool isComposing() const
This function indicates whether InputMethodStart event had been sent to the current focus widget...
#define getarg(type, name)
int key
void installEventFilter(QObject *)
Installs an event filter filterObj on this object.
Definition: qobject.cpp:2070
static int32_t(* p_ictrl_dispatch_event)(event_t *)=0
int32_t onCommitText(input_session_t *ic, spannable_string_t *text, int32_t new_cursor_position)
virtual bool showKeyboard()=0
static int registerEventType(int hint=-1)
Registers and returns a custom event type.
Definition: qcoreevent.cpp:398
int32_t onSetComposingRegion(input_session_t *ic, int32_t start, int32_t end)
spannable_string_t * onGetTextAfterCursor(input_session_t *ic, int32_t n, int32_t flags)
static void(* p_ictrl_close_session)(input_session_t *)=0
The QInputContext class abstracts the input method dependent data and composing state.
Definition: qinputcontext.h:83
Qt::InputMethodHints inputMethodHints
What input method specific hints the widget has.
Definition: qwidget.h:224
#define parg(name)
static const KeyPair *const end
static int32_t(* p_imf_client_init)()=0
virtual void setFocusWidget(QWidget *w)
Sets the widget that has an input focus for this input context.
#define iarg(name)
The QEvent class is the base class of all event classes.
Definition: qcoreevent.h:56
Type type() const
Returns the event type.
Definition: qcoreevent.h:303
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
#define enabled
spannable_string_t * onGetSelectedText(input_session_t *ic, int32_t flags)
bool dispatchRequestSoftwareInputPanel()
Q_CORE_EXPORT void qCritical(const char *,...)
#define text
Definition: qobjectdefs.h:80
#define qs(x)
The QList class is a template class that provides lists.
Definition: qdatastream.h:62