20 ** |
20 ** |
21 ** If you have questions regarding the use of this file, please contact |
21 ** If you have questions regarding the use of this file, please contact |
22 ** Nokia at developer.feedback@nokia.com. |
22 ** Nokia at developer.feedback@nokia.com. |
23 ** |
23 ** |
24 ****************************************************************************/ |
24 ****************************************************************************/ |
|
25 #include "hbinputmethod.h" |
|
26 #include "hbinputmethod_p.h" |
|
27 |
25 #include <QInputMethodEvent> |
28 #include <QInputMethodEvent> |
26 #include <QGraphicsView> |
29 #include <QGraphicsView> |
27 #include <QGraphicsProxyWidget> |
30 #include <QGraphicsProxyWidget> |
28 #include <QLocale> |
31 #include <QLocale> |
29 |
32 |
30 #include "hbinputmethod.h" |
|
31 #include "hbinputmethod_p.h" |
|
32 #include "hbinputmodecache_p.h" |
33 #include "hbinputmodecache_p.h" |
33 #include "hbinputsettingproxy.h" |
34 #include "hbinputsettingproxy.h" |
34 #include "hbinputcontextproxy_p.h" |
35 #include "hbinputcontextproxy_p.h" |
35 #include "hbinputfilter.h" |
36 #include "hbinputfilter.h" |
36 #include "hbinputmethodnull_p.h" |
37 #include "hbinputmethodnull_p.h" |
37 #include "hbinputpredictionfactory.h" |
38 #include "hbinputpredictionfactory.h" |
38 #include "hbinputextradictionaryfactory.h" |
39 #include "hbinputextradictionaryfactory.h" |
39 #include "hbinputstandardfilters.h" |
40 #include "hbinputstandardfilters.h" |
40 #include "hbinpututils.h" |
41 #include "hbinpututils.h" |
41 #include "hbinputvkbhost.h" |
42 #include "hbinputvkbhost.h" |
|
43 #include "hbinputvkbhostbridge.h" |
42 |
44 |
43 /*! |
45 /*! |
44 @alpha |
46 @alpha |
45 @hbcore |
47 @hbcore |
46 \class HbInputMethod |
48 \class HbInputMethod |
60 |
62 |
61 Custom input methods are a special class of input methods. Once a custom input method is |
63 Custom input methods are a special class of input methods. Once a custom input method is |
62 activated from UI, input mode cache stops resolving input methods upon focus operations |
64 activated from UI, input mode cache stops resolving input methods upon focus operations |
63 and the custom input is active in all editors until it is deactivated. |
65 and the custom input is active in all editors until it is deactivated. |
64 |
66 |
65 Following is the basic input framework program flow: |
67 \bold The input framework program flow |
66 |
68 |
67 1. An editor gains input focus. |
69 1. An editor gains input focus.<BR> |
68 2 Input mode cache resolves correct mode handler and activates it. |
70 2. Editor sets requestSoftwareInputPanel event to active input context.<BR> |
69 3. A virtual function HbInputMethod::focusReceived is called. At this point the input method |
71 3. The input framework creates input state based on editor attributes and the input mode cache <BR> |
70 initializes whatever it needs to initialize in order to start the input operation (for example, |
72 resolves correct mode handler and activates it.<BR> |
71 opens the virtual keyboard by using HbVkbHost API) and waits for user actions. |
73 4. A virtual function HbInputMethod::focusReceived is called. At this point the input method<BR> |
72 4. Text is written. The input method delivers results to the editor buffer by using HbInputFocusObject API. |
74 initializes whatever it needs to initialize in order to start the input operation (for example,<BR> |
73 It can access editor attributes via HbEditorInterface API. |
75 opens the virtual keyboard by using HbVkbHost API) and waits for user actions.<BR> |
74 5. The active editor loses focus. At this point the input method receives a call to virtual function |
76 5. Text is written. The input method delivers results to the editor buffer by using HbInputFocusObject API.<BR> |
75 HbInputMethod::focusLost and is expected to conclude any ongoing input operations and shut down active |
77 It can access editor attributes via HbEditorInterface API.<BR> |
76 UI elements (such as the virtual keyboard). |
78 6. The active editor loses focus. At this point the input method receives a call to virtual function<BR> |
77 6. The input method waits for next focusReceived() call. |
79 HbInputMethod::focusLost and is expected to conclude any ongoing input operations and shut down active<BR> |
|
80 UI elements (such as the virtual keyboard).<BR> |
|
81 7. The input method waits for next focusReceived() call. <BR> |
|
82 |
|
83 \bold Input method resolving |
|
84 |
|
85 The input framework resolves correct input state handler based on three attributes: input mode, |
|
86 keyboard type and input language. |
|
87 |
|
88 The framework recognizes three different input modes: default, numeric and custom. |
|
89 Default and numeric input modes are something that the framework resolves for active |
|
90 input language and keyboard type. Custom input mode is something that the framework never |
|
91 activates automatically, but it is activated from UI or directly from application |
|
92 (or input method) code. |
|
93 |
|
94 Numeric input mode is something that can handle those editors that are configured to only accept |
|
95 numeric data (for example those that have Qt::ImhDigitsOnly hints on). |
|
96 |
|
97 Language attribute is matched either as a direct match or as a language range. Language range |
|
98 means the input method is capable of handling all the languages that |
|
99 HbKeymapFactory::availableLanguages() returns. Direct match always wins so it is possible |
|
100 to override language range for specific languages. |
|
101 |
|
102 The keyboard attribute is always matched directly. Note that event though the constant |
|
103 has term "keyboard" in it, it covers all input devices such as hand writing recognition widgets |
|
104 that don't utilize traditional keys. it is up the the input method what that constant |
|
105 really means. |
|
106 |
|
107 The input method resolving parameters are part of input plugin meta data and they are returned |
|
108 by QInputContextPlugin::languages() method. A single entry in the returned string list |
|
109 is formed by packing resolving parameters into HbInputModeProperties structure and calling |
|
110 HbInputModeProperties::asString() method. |
|
111 |
|
112 Following code snippet shows how the input context plugin returns resolving parameters |
|
113 |
|
114 \snippet{unittest_hbinputmethod/unittest_hbinputmethod.cpp,1} |
|
115 |
|
116 \bold Input method resolving example |
|
117 |
|
118 Say that we have implemented touch input methods for 12 key portrait mode and qwerty landscape mode. |
|
119 Then we have Chinese touch input method for both portrait and landscape orientations and also |
|
120 Chinese handwriting recognition input mode for portrait mode. |
|
121 |
|
122 Touch input methods resolve to language range, which means that they will handle all |
|
123 the other languages, except Chinese, which has its own designated input method. |
|
124 |
|
125 Touch input methods also implement support for numeric mode. Because Chinese language uses |
|
126 same numeric system as "latin" based languages, we only want to implement numeric mode |
|
127 handling in one input method and arrange resolving parameters so that the numeric mode |
|
128 is handled by default touch input method even when the global input language is Chinese. |
|
129 |
|
130 Chinese handwriting input method is something that is a custom mode, and will be activated |
|
131 from UI. |
|
132 |
|
133 Following example shows how the resolving attributes are set up to achieve above configuration. |
|
134 |
|
135 Portait touch input method returns following attributes |
|
136 |
|
137 \snippet{unittest_hbinputmethod/unittest_hbinputmethod.cpp,2} |
|
138 |
|
139 Landscape touch input method returns following attributes |
|
140 |
|
141 \snippet{unittest_hbinputmethod/unittest_hbinputmethod.cpp,3} |
|
142 |
|
143 Chinese portrait input method returns following attributes |
|
144 |
|
145 \snippet{unittest_hbinputmethod/unittest_hbinputmethod.cpp,4} |
|
146 |
|
147 Chinese landscape input method returns following attributes |
|
148 |
|
149 \snippet{unittest_hbinputmethod/unittest_hbinputmethod.cpp,5} |
|
150 |
|
151 Chinese handwriting recognition input method returns following attributes |
|
152 (note use of HbInputModeCustom, in this example HWR is something that we |
|
153 want to active from UI separately). |
|
154 |
|
155 \snippet{unittest_hbinputmethod/unittest_hbinputmethod.cpp,6} |
78 |
156 |
79 \sa QInputContext |
157 \sa QInputContext |
80 \sa HbInputFocusObject |
158 \sa HbInputFocusObject |
81 \sa HbEditorInterface |
159 \sa HbEditorInterface |
82 \sa HbVkbHost |
160 \sa HbVkbHost |
118 } |
196 } |
119 |
197 |
120 master->d_ptr->mIsActive = true; |
198 master->d_ptr->mIsActive = true; |
121 |
199 |
122 // Finally set application input context. |
200 // Finally set application input context. |
123 QInputContext* proxy = master->d_ptr->newProxy(); |
201 QInputContext *proxy = master->d_ptr->proxy(); |
124 app.setInputContext(proxy); |
202 // A check required so that Qt does not delete inputcontext |
|
203 // which we are passing. |
|
204 if (proxy != app.inputContext()) { |
|
205 app.setInputContext(proxy); |
|
206 } |
125 |
207 |
126 return true; |
208 return true; |
127 } |
209 } |
128 |
210 |
129 /*! |
211 /*! |
130 Returns the active instance of HbInputMethod. There is always active HbInputMethod instance after |
212 Returns the active instance of HbInputMethod. There is always active HbInputMethod instance after |
131 InitializeFramework method has been called, even when there is no focused editor (in some cases it may |
213 InitializeFramework method has been called, even when there is no focused editor (in some cases it may |
132 be so called null input method). |
214 be so called null input method). |
133 */ |
215 */ |
134 HbInputMethod* HbInputMethod::activeInputMethod() |
216 HbInputMethod *HbInputMethod::activeInputMethod() |
135 { |
217 { |
136 // First try, try app input context directly. It is possible that it is an instance |
218 // First try, try app input context directly. It is possible that it is an instance |
137 // of HbInputMethod that is installed directly there without framework knowing about it |
219 // of HbInputMethod that is installed directly there without framework knowing about it |
138 // (that shouldn't be done, but it is possible). That's why we rely on app input context as |
220 // (that shouldn't be done, but it is possible). That's why we rely on app input context as |
139 // a primary source instead of mode cache. |
221 // a primary source instead of mode cache. |
140 QInputContext* context = qApp->inputContext(); |
222 QInputContext *context = qApp->inputContext(); |
141 if (context && context->inherits("HbInputMethod")) { |
223 if (context && context->inherits("HbInputMethod")) { |
142 HbInputMethod* active = static_cast<HbInputMethod*>(context); |
224 HbInputMethod *active = static_cast<HbInputMethod *>(context); |
143 return active; |
225 return active; |
144 } |
226 } |
145 |
227 |
146 // Then check if the 'null' is active. |
228 // Then check if the 'null' is active. |
147 HbInputMethod* nullInstance = HbInputMethodNull::Instance(); |
229 HbInputMethod *nullInstance = HbInputMethodNull::Instance(); |
148 if (nullInstance && nullInstance->isActiveMethod()) { |
230 if (nullInstance && nullInstance->isActiveMethod()) { |
149 return nullInstance; |
231 return nullInstance; |
150 } |
232 } |
151 |
233 |
152 // No it wasn't, then go through the methods in the cache and see which one is |
234 // No it wasn't, then go through the methods in the cache and see which one is |
153 // active. |
235 // active. |
154 return HbInputModeCache::instance()->activeMethod(); |
236 return HbInputModeCache::instance()->activeMethod(); |
155 } |
237 } |
156 |
238 |
157 /*! |
239 /*! |
158 Lists custom input methods. |
240 Lists all custom input methods. |
159 */ |
241 */ |
160 QList<HbInputMethodDescriptor> HbInputMethod::listCustomInputMethods() |
242 QList<HbInputMethodDescriptor> HbInputMethod::listCustomInputMethods() |
161 { |
243 { |
162 return HbInputModeCache::instance()->listCustomInputMethods(); |
244 return HbInputModeCache::instance()->listCustomInputMethods(); |
163 } |
245 } |
164 |
246 |
165 /*! |
247 /*! |
166 Activates given input method. Input context is |
248 Lists custom input methods for given parameters. |
167 switched to custom method. Returns false if input method was not found |
249 */ |
|
250 QList<HbInputMethodDescriptor> HbInputMethod::listCustomInputMethods(Qt::Orientation orientation, const HbInputLanguage &language) |
|
251 { |
|
252 return HbInputModeCache::instance()->listCustomInputMethods(orientation, language); |
|
253 } |
|
254 |
|
255 /*! |
|
256 Returns default input method for given orientation. |
|
257 */ |
|
258 HbInputMethodDescriptor HbInputMethod::defaultInputMethod(Qt::Orientation orientation) |
|
259 { |
|
260 return HbInputModeCache::instance()->defaultInputMethod(orientation); |
|
261 } |
|
262 |
|
263 /*! |
|
264 Activates given input method. Returns false if input method was not found |
168 or the framework was not able to activate it. |
265 or the framework was not able to activate it. |
169 */ |
266 */ |
170 bool HbInputMethod::activateInputMethod(const HbInputMethodDescriptor &inputMethod) |
267 bool HbInputMethod::activateInputMethod(const HbInputMethodDescriptor &inputMethod) |
171 { |
268 { |
172 Q_D(HbInputMethod); |
269 Q_D(HbInputMethod); |
173 |
270 |
174 if (!inputMethod.isEmpty()) { |
271 if (!inputMethod.isEmpty()) { |
175 HbInputSettingProxy::instance()->setActiveCustomInputMethod(inputMethod); |
|
176 |
|
177 if (inputMethod.isDefault()) { |
272 if (inputMethod.isDefault()) { |
178 d->setFocusCommon(); |
273 d->setFocusCommon(); |
179 return true; |
274 return true; |
180 } else { |
275 } else { |
181 HbInputMethod *customMethod = HbInputModeCache::instance()->loadInputMethod(inputMethod); |
276 HbInputMethod *customMethod = HbInputModeCache::instance()->loadInputMethod(inputMethod); |
182 if (customMethod) { |
277 if (customMethod && HbInputModeCache::instance()->acceptsState(customMethod, d->mInputState)) { |
183 d->contextSwitch(customMethod); |
278 d->contextSwitch(customMethod); |
184 return true; |
279 return true; |
185 } |
280 } |
186 } |
281 } |
187 } |
282 } |
188 |
283 |
189 return false; |
284 return false; |
190 } |
285 } |
294 default focus handling mechanism for QInputContext system. Input method |
391 default focus handling mechanism for QInputContext system. Input method |
295 implementation should never override this method unless it knows what it is doing. |
392 implementation should never override this method unless it knows what it is doing. |
296 |
393 |
297 \sa setFocusObject |
394 \sa setFocusObject |
298 */ |
395 */ |
299 void HbInputMethod::setFocusWidget(QWidget* widget) |
396 void HbInputMethod::setFocusWidget(QWidget *widget) |
300 { |
397 { |
301 Q_D(HbInputMethod); |
398 Q_D(HbInputMethod); |
302 |
399 |
303 if (d->mFocusLocked) { |
400 if (d->mFocusLocked) { |
304 return; |
401 return; |
305 } |
402 } |
306 |
403 |
307 QInputContext::setFocusWidget(widget); |
|
308 |
|
309 if (!widget) { |
404 if (!widget) { |
|
405 bool unfocus = true; |
|
406 |
|
407 if (d->mFocusObject) { |
|
408 // If the input focus is inside HbGraphicsScene then do not unfocus automatically. |
|
409 if (d->ignoreFrameworkFocusRelease(d->mFocusObject->object())) { |
|
410 unfocus = false; |
|
411 } |
|
412 } |
|
413 |
310 // Losing focus. |
414 // Losing focus. |
311 if (d->mFocusObject) { |
415 if (d->mFocusObject && unfocus) { |
312 focusLost(false); |
416 focusLost(false); |
|
417 d->hideMainWindow(); |
313 delete d->mFocusObject; |
418 delete d->mFocusObject; |
314 d->mFocusObject = 0; |
419 d->mFocusObject = 0; |
315 } |
420 } |
|
421 |
316 return; |
422 return; |
317 } |
423 } |
318 |
424 |
319 QGraphicsView* gView = qobject_cast<QGraphicsView*>(widget); |
425 // attach focuswidget to prxoy inputcontext as proxy is |
|
426 // the only inputcotext known to qt framework. |
|
427 d->proxy()->QInputContext::setFocusWidget(widget); |
|
428 |
|
429 QGraphicsView *gView = qobject_cast<QGraphicsView *>(widget); |
320 if (gView) { |
430 if (gView) { |
321 // We don't want to focus to graphics view but the items inside the scene, so just return |
431 // We don't want to focus to graphics view but the items inside the scene, so just return |
322 return; |
432 return; |
323 } |
433 } |
324 |
434 |
399 requestSoftwareInputPanel event. |
514 requestSoftwareInputPanel event. |
400 |
515 |
401 \sa setFocusWidget |
516 \sa setFocusWidget |
402 \sa HbInputFocusObject |
517 \sa HbInputFocusObject |
403 */ |
518 */ |
404 void HbInputMethod::setFocusObject(HbInputFocusObject* focusObject) |
519 void HbInputMethod::setFocusObject(HbInputFocusObject *focusObject) |
405 { |
520 { |
406 Q_D(HbInputMethod); |
521 Q_D(HbInputMethod); |
407 |
522 |
408 if (d->mFocusLocked) { |
523 if (d->mFocusLocked) { |
409 return; |
524 return; |
410 } |
525 } |
411 |
526 |
412 if (focusObject == 0) { |
527 if (focusObject == 0) { |
413 // Losing focus. |
528 // Losing focus. |
414 if (d->mFocusObject != 0) { |
529 if (d->mFocusObject != 0) { |
|
530 disconnect(d->mFocusObject->object(), SIGNAL(destroyed(QObject *)), this, SLOT(editorDeleted(QObject *))); |
415 focusLost(false); |
531 focusLost(false); |
|
532 d->hideMainWindow(); |
416 delete d->mFocusObject; |
533 delete d->mFocusObject; |
417 d->mFocusObject = 0; |
534 d->mFocusObject = 0; |
418 } |
535 } |
419 return; |
536 return; |
420 } |
537 } |
421 |
538 |
422 if(d->compareWithCurrentFocusObject( focusObject )) { |
539 if (d->compareWithCurrentFocusObject(focusObject)) { |
423 // The incoming focus object is either same or points to same |
540 // The incoming focus object is either same or points to same |
424 // widget that the framework is already focused to and nothing needs to be done here. |
541 // widget that the framework is already focused to and nothing needs to be done here. |
425 // But because the ownership of the focus object is transferred to the |
|
426 // the framework, we need to delete the the incoming focus object in case it is |
|
427 // dirrefent than current one. |
|
428 if (d->mFocusObject != focusObject) { |
|
429 delete focusObject; |
|
430 } |
|
431 return; |
542 return; |
432 } |
543 } |
433 |
544 |
434 bool refreshHost = false; |
545 bool refreshHost = false; |
435 |
546 |
436 // Delete previous focus object. |
547 // Delete previous focus object. |
437 if (d->mFocusObject) { |
548 if (d->mFocusObject) { |
438 refreshHost = true; |
549 refreshHost = true; |
439 focusLost(true); |
550 focusLost(true); |
440 disconnect(d->mFocusObject->object(), SIGNAL(destroyed(QObject*)), this, SLOT(editorDeleted(QObject*))); |
551 disconnect(d->mFocusObject->object(), SIGNAL(destroyed(QObject *)), this, SLOT(editorDeleted(QObject *))); |
441 delete d->mFocusObject; |
552 delete d->mFocusObject; |
442 d->mFocusObject = 0; |
553 d->mFocusObject = 0; |
443 } |
554 } |
444 QInputContext::setFocusWidget(0); |
|
445 |
555 |
446 // Attach focus. |
556 // Attach focus. |
447 d->mFocusObject = focusObject; |
557 d->mFocusObject = focusObject; |
448 connect(d->mFocusObject->object(), SIGNAL(destroyed(QObject*)), this, SLOT(editorDeleted(QObject*))); |
558 connect(d->mFocusObject->object(), SIGNAL(destroyed(QObject *)), this, SLOT(editorDeleted(QObject *))); |
449 |
|
450 // If this is embedded QWidget, then set base class focus too. |
|
451 QWidget *widget = qobject_cast<QWidget*>(focusObject->object()); |
|
452 if (widget) { |
|
453 QInputContext::setFocusWidget(widget); |
|
454 } |
|
455 |
559 |
456 d->setFocusCommon(); |
560 d->setFocusCommon(); |
457 |
561 |
458 // The focus jumped from one editor to another. Make sure that vkb host |
562 // The focus jumped from one editor to another. Make sure that vkb host |
459 // updates the situation correctly. |
563 // updates the situation correctly. |
639 Receives the screen orientation signal. Will determine correct input state for new |
743 Receives the screen orientation signal. Will determine correct input state for new |
640 orientation and find state handler for it. |
744 orientation and find state handler for it. |
641 */ |
745 */ |
642 void HbInputMethod::orientationChanged(Qt::Orientation orientation) |
746 void HbInputMethod::orientationChanged(Qt::Orientation orientation) |
643 { |
747 { |
|
748 Q_D(HbInputMethod); |
644 Q_UNUSED(orientation); |
749 Q_UNUSED(orientation); |
645 |
750 |
646 if (isActiveMethod()) { |
751 if (d->mOldFocusObject) { |
647 // Make sure that if there was an editor focus before the orientation change, |
752 setFocusObject(d->mOldFocusObject); |
648 // it will re-focus. |
753 d->mOldFocusObject = 0; |
649 QInputContext *ic = qApp->inputContext(); |
754 } |
650 if (ic) { |
755 |
651 QEvent *event = new QEvent(QEvent::RequestSoftwareInputPanel); |
|
652 ic->filterEvent(event); |
|
653 delete event; |
|
654 } |
|
655 } |
|
656 } |
756 } |
657 |
757 |
658 /*! |
758 /*! |
659 This slot is connected to setting proxy's orientation change warning signal. The default |
759 This slot is connected to setting proxy's orientation change warning signal. The default |
660 base class implementation is empty. |
760 base class implementation is empty. |
661 |
761 |
662 \sa HbInputSettingProxy |
762 \sa HbInputSettingProxy |
663 */ |
763 */ |
664 void HbInputMethod::orientationAboutToChange() |
764 void HbInputMethod::orientationAboutToChange() |
665 { |
765 { |
|
766 Q_D(HbInputMethod); |
|
767 if(isActiveMethod()) { |
|
768 reset(); |
|
769 } |
|
770 d->inputStateToEditor(d->mInputState); |
|
771 if (d->mFocusObject) { |
|
772 d->mOldFocusObject = d->mFocusObject; |
|
773 d->mFocusObject = 0; |
|
774 } |
|
775 HbVkbHostBridge::instance()->closeKeypad(true); |
666 } |
776 } |
667 |
777 |
668 /*! |
778 /*! |
669 Returns active input language. Unlike setting proxy's global input language, |
779 Returns active input language. Unlike setting proxy's global input language, |
670 this method takes into account input state language and possible editor local language, |
780 this method takes into account input state language and possible editor local language, |
710 /*! |
820 /*! |
711 Removes input method focus and asks active input plugin to close its active UI-components |
821 Removes input method focus and asks active input plugin to close its active UI-components |
712 (such as touch keypads). This may be needed in some special cases where the underlying |
822 (such as touch keypads). This may be needed in some special cases where the underlying |
713 application wants to make sure that there are no input related elements on the screen. |
823 application wants to make sure that there are no input related elements on the screen. |
714 |
824 |
715 This is a if-all-else fails backup method. Same can be done (more efficiently) by doing |
825 This is a if-all-else fails backup method. Same can be done by doing |
716 following. |
826 following. |
717 |
827 |
718 \code |
828 \code |
719 QInputContext* inputContext = qApp->inputContext(); |
829 QInputContext* ic = qApp->inputContext(); |
720 if (inputContext) { |
830 if (ic) { |
721 inputContext->setFocusWidget(0); |
831 QEvent *closeEvent = new QEvent(QEvent::CloseSoftwareInputPanel); |
|
832 ic->filterEvent(closeEvent); |
|
833 delete closeEvent; |
722 } |
834 } |
723 \endcode |
835 \endcode |
724 */ |
836 */ |
725 void HbInputMethod::forceUnfocus() |
837 void HbInputMethod::forceUnfocus() |
726 { |
838 { |
727 HbInputMethod* active = activeInputMethod(); |
839 HbInputMethod *active = activeInputMethod(); |
728 |
840 |
729 if (active) { |
841 if (active) { |
730 active->focusLost(false); |
842 active->focusLost(false); |
731 delete active->d_ptr->mFocusObject; |
843 delete active->d_ptr->mFocusObject; |
732 active->d_ptr->mFocusObject = 0; |
844 active->d_ptr->mFocusObject = 0; |
733 } |
845 } |
734 } |
846 } |
735 |
847 |