1 /**************************************************************************** |
1 /**************************************************************************** |
2 ** |
2 ** |
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
4 ** All rights reserved. |
4 ** All rights reserved. |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
6 ** |
6 ** |
7 ** This file is part of the QtGui module of the Qt Toolkit. |
7 ** This file is part of the QtGui module of the Qt Toolkit. |
8 ** |
8 ** |
69 m_pendingInputCapabilitiesChanged(false), |
69 m_pendingInputCapabilitiesChanged(false), |
70 m_cursorVisibility(1), |
70 m_cursorVisibility(1), |
71 m_inlinePosition(0), |
71 m_inlinePosition(0), |
72 m_formatRetriever(0), |
72 m_formatRetriever(0), |
73 m_pointerHandler(0), |
73 m_pointerHandler(0), |
74 m_longPress(0), |
74 m_cursorPos(0), |
75 m_cursorPos(0) |
75 m_hasTempPreeditString(false) |
76 { |
76 { |
77 m_fepState->SetObjectProvider(this); |
77 m_fepState->SetObjectProvider(this); |
78 m_fepState->SetFlags(EAknEditorFlagDefault); |
78 m_fepState->SetFlags(EAknEditorFlagDefault); |
79 m_fepState->SetDefaultInputMode( EAknEditorTextInputMode ); |
79 m_fepState->SetDefaultInputMode( EAknEditorTextInputMode ); |
80 m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); |
80 m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); |
98 delete m_fepState; |
98 delete m_fepState; |
99 } |
99 } |
100 |
100 |
101 void QCoeFepInputContext::reset() |
101 void QCoeFepInputContext::reset() |
102 { |
102 { |
103 CCoeFep* fep = CCoeEnv::Static()->Fep(); |
103 commitCurrentString(true); |
104 if (fep) |
|
105 fep->CancelTransaction(); |
|
106 } |
104 } |
107 |
105 |
108 void QCoeFepInputContext::ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateEvent aEventType) |
106 void QCoeFepInputContext::ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateEvent aEventType) |
109 { |
107 { |
110 QT_TRAP_THROWING(m_fepState->ReportAknEdStateEventL(aEventType)); |
108 QT_TRAP_THROWING(m_fepState->ReportAknEdStateEventL(aEventType)); |
112 |
110 |
113 void QCoeFepInputContext::update() |
111 void QCoeFepInputContext::update() |
114 { |
112 { |
115 updateHints(false); |
113 updateHints(false); |
116 |
114 |
117 // :QTP: Always show virtual keyboard - fix needed to use feature manager |
|
118 // For pre-5.0 SDKs, we don't do text updates on S60 side. |
115 // For pre-5.0 SDKs, we don't do text updates on S60 side. |
119 //if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { |
116 if (QSysInfo::s60Version() < QSysInfo::SV_S60_5_0) { |
120 // return; |
117 return; |
121 //} |
118 } |
122 |
119 |
123 // Don't be fooled (as I was) by the name of this enumeration. |
120 // Don't be fooled (as I was) by the name of this enumeration. |
124 // What it really does is tell the virtual keyboard UI that the text has been |
121 // What it really does is tell the virtual keyboard UI that the text has been |
125 // updated and it should be reflected in the internal display of the VK. |
122 // updated and it should be reflected in the internal display of the VK. |
126 ReportAknEdStateEvent(QT_EAknCursorPositionChanged); |
123 ReportAknEdStateEvent(QT_EAknCursorPositionChanged); |
127 } |
124 } |
128 |
125 |
129 void QCoeFepInputContext::setFocusWidget(QWidget *w) |
126 void QCoeFepInputContext::setFocusWidget(QWidget *w) |
130 { |
127 { |
131 commitCurrentString(false); |
128 commitCurrentString(true); |
132 |
129 |
133 QInputContext::setFocusWidget(w); |
130 QInputContext::setFocusWidget(w); |
134 |
131 |
135 updateHints(true); |
132 updateHints(true); |
136 } |
133 } |
199 // close when it discovers that the underlying widget does not have input capabilities. |
196 // close when it discovers that the underlying widget does not have input capabilities. |
200 |
197 |
201 if (!focusWidget()) |
198 if (!focusWidget()) |
202 return false; |
199 return false; |
203 |
200 |
204 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { |
201 switch (event->type()) { |
|
202 case QEvent::KeyPress: |
|
203 commitTemporaryPreeditString(); |
|
204 // fall through intended |
|
205 case QEvent::KeyRelease: |
205 const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event); |
206 const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event); |
206 switch (keyEvent->key()) { |
207 switch (keyEvent->key()) { |
207 case Qt::Key_F20: |
208 case Qt::Key_F20: |
208 Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); |
209 Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); |
209 if (m_lastImHints & Qt::ImhHiddenText) { |
210 if (m_lastImHints & Qt::ImhHiddenText) { |
215 return true; |
216 return true; |
216 } |
217 } |
217 break; |
218 break; |
218 case Qt::Key_Select: |
219 case Qt::Key_Select: |
219 if (!m_preeditString.isEmpty()) { |
220 if (!m_preeditString.isEmpty()) { |
220 commitCurrentString(false); |
221 commitCurrentString(true); |
221 return true; |
222 return true; |
222 } |
223 } |
223 break; |
224 break; |
224 default: |
225 default: |
225 break; |
226 break; |
226 } |
227 } |
|
228 |
|
229 if (keyEvent->type() == QEvent::KeyPress |
|
230 && focusWidget()->inputMethodHints() & Qt::ImhHiddenText |
|
231 && !keyEvent->text().isEmpty()) { |
|
232 // Send some temporary preedit text in order to make text visible for a moment. |
|
233 m_cursorPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); |
|
234 m_preeditString = keyEvent->text(); |
|
235 QList<QInputMethodEvent::Attribute> attributes; |
|
236 QInputMethodEvent imEvent(m_preeditString, attributes); |
|
237 sendEvent(imEvent); |
|
238 m_tempPreeditStringTimeout.start(1000, this); |
|
239 m_hasTempPreeditString = true; |
|
240 update(); |
|
241 return true; |
|
242 } |
|
243 break; |
227 } |
244 } |
228 |
245 |
229 if (!needsInputPanel()) |
246 if (!needsInputPanel()) |
230 return false; |
247 return false; |
231 |
248 |
252 } |
269 } |
253 |
270 |
254 return false; |
271 return false; |
255 } |
272 } |
256 |
273 |
|
274 void QCoeFepInputContext::timerEvent(QTimerEvent *timerEvent) |
|
275 { |
|
276 if (timerEvent->timerId() == m_tempPreeditStringTimeout.timerId()) |
|
277 commitTemporaryPreeditString(); |
|
278 } |
|
279 |
|
280 void QCoeFepInputContext::commitTemporaryPreeditString() |
|
281 { |
|
282 if (m_tempPreeditStringTimeout.isActive()) |
|
283 m_tempPreeditStringTimeout.stop(); |
|
284 |
|
285 if (!m_hasTempPreeditString) |
|
286 return; |
|
287 |
|
288 commitCurrentString(false); |
|
289 } |
|
290 |
257 void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event) |
291 void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event) |
258 { |
292 { |
259 Q_ASSERT(focusWidget()); |
293 Q_ASSERT(focusWidget()); |
260 |
294 |
261 if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) { |
295 if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) { |
262 commitCurrentString(false); |
296 commitCurrentString(true); |
263 int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); |
297 int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); |
264 |
298 |
265 QList<QInputMethodEvent::Attribute> attributes; |
299 QList<QInputMethodEvent::Attribute> attributes; |
266 attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos + x, 0, QVariant()); |
300 attributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, pos + x, 0, QVariant()); |
267 QInputMethodEvent event(QLatin1String(""), attributes); |
301 QInputMethodEvent event(QLatin1String(""), attributes); |
308 } |
342 } |
309 |
343 |
310 void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints) |
344 void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints) |
311 { |
345 { |
312 using namespace Qt; |
346 using namespace Qt; |
|
347 |
|
348 commitTemporaryPreeditString(); |
313 |
349 |
314 bool numbersOnly = hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly |
350 bool numbersOnly = hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly |
315 || hints & ImhDialableCharactersOnly; |
351 || hints & ImhDialableCharactersOnly; |
316 bool noOnlys = !(numbersOnly || hints & ImhUppercaseOnly |
352 bool noOnlys = !(numbersOnly || hints & ImhUppercaseOnly |
317 || hints & ImhLowercaseOnly); |
353 || hints & ImhLowercaseOnly); |
500 { |
536 { |
501 QWidget *w = focusWidget(); |
537 QWidget *w = focusWidget(); |
502 if (!w) |
538 if (!w) |
503 return; |
539 return; |
504 |
540 |
|
541 commitTemporaryPreeditString(); |
|
542 |
505 m_cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); |
543 m_cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); |
506 |
544 |
507 QList<QInputMethodEvent::Attribute> attributes; |
545 QList<QInputMethodEvent::Attribute> attributes; |
508 |
546 |
509 m_cursorVisibility = aCursorVisibility ? 1 : 0; |
547 m_cursorVisibility = aCursorVisibility ? 1 : 0; |
510 m_inlinePosition = aPositionOfInsertionPointInInlineText; |
548 m_inlinePosition = aPositionOfInsertionPointInInlineText; |
511 m_preeditString = qt_TDesC2QString(aInitialInlineText); |
549 m_preeditString = qt_TDesC2QString(aInitialInlineText); |
512 |
550 |
513 m_formatRetriever = &aInlineTextFormatRetriever; |
551 m_formatRetriever = &aInlineTextFormatRetriever; |
514 m_pointerHandler = &aPointerEventHandlerDuringInlineEdit; |
552 m_pointerHandler = &aPointerEventHandlerDuringInlineEdit; |
|
553 |
|
554 // With T9 aInitialInlineText is typically empty when StartFepInlineEditL is called, |
|
555 // but FEP requires that selected text is always removed at StartFepInlineEditL. |
|
556 // Let's remove the selected text if aInitialInlineText is empty and there is selected text |
|
557 if (m_preeditString.isEmpty()) { |
|
558 int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt(); |
|
559 int replacementLength = qAbs(m_cursorPos-anchor); |
|
560 if (replacementLength > 0) { |
|
561 int replacementStart = m_cursorPos < anchor ? 0 : -replacementLength; |
|
562 QList<QInputMethodEvent::Attribute> clearSelectionAttributes; |
|
563 QInputMethodEvent clearSelectionEvent(QLatin1String(""), clearSelectionAttributes); |
|
564 clearSelectionEvent.setCommitString(QLatin1String(""), replacementStart, replacementLength); |
|
565 sendEvent(clearSelectionEvent); |
|
566 } |
|
567 } |
515 |
568 |
516 applyFormat(&attributes); |
569 applyFormat(&attributes); |
517 |
570 |
518 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, |
571 attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, |
519 m_inlinePosition, |
572 m_inlinePosition, |
598 void QCoeFepInputContext::SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection) |
651 void QCoeFepInputContext::SetCursorSelectionForFepL(const TCursorSelection& aCursorSelection) |
599 { |
652 { |
600 QWidget *w = focusWidget(); |
653 QWidget *w = focusWidget(); |
601 if (!w) |
654 if (!w) |
602 return; |
655 return; |
|
656 |
|
657 commitTemporaryPreeditString(); |
603 |
658 |
604 int pos = aCursorSelection.iAnchorPos; |
659 int pos = aCursorSelection.iAnchorPos; |
605 int length = aCursorSelection.iCursorPos - pos; |
660 int length = aCursorSelection.iCursorPos - pos; |
606 |
661 |
607 QList<QInputMethodEvent::Attribute> attributes; |
662 QList<QInputMethodEvent::Attribute> attributes; |
697 aAscent = metrics.ascent(); |
752 aAscent = metrics.ascent(); |
698 } |
753 } |
699 |
754 |
700 void QCoeFepInputContext::DoCommitFepInlineEditL() |
755 void QCoeFepInputContext::DoCommitFepInlineEditL() |
701 { |
756 { |
702 commitCurrentString(true); |
757 commitCurrentString(false); |
703 } |
758 if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) |
704 |
759 ReportAknEdStateEvent(QT_EAknCursorPositionChanged); |
705 void QCoeFepInputContext::commitCurrentString(bool triggeredBySymbian) |
760 |
706 { |
761 } |
|
762 |
|
763 void QCoeFepInputContext::commitCurrentString(bool cancelFepTransaction) |
|
764 { |
|
765 int longPress = 0; |
|
766 |
707 if (m_preeditString.size() == 0) { |
767 if (m_preeditString.size() == 0) { |
708 QWidget *w = focusWidget(); |
768 QWidget *w = focusWidget(); |
709 if (triggeredBySymbian && w) { |
769 if (!cancelFepTransaction && w) { |
710 // We must replace the last character only if the input box has already accepted one |
770 // We must replace the last character only if the input box has already accepted one |
711 if (w->inputMethodQuery(Qt::ImCursorPosition).toInt() != m_cursorPos) |
771 if (w->inputMethodQuery(Qt::ImCursorPosition).toInt() != m_cursorPos) |
712 m_longPress = 1; |
772 longPress = 1; |
713 } |
773 } |
714 return; |
774 return; |
715 } |
775 } |
716 |
776 |
717 QList<QInputMethodEvent::Attribute> attributes; |
777 QList<QInputMethodEvent::Attribute> attributes; |
718 QInputMethodEvent event(QLatin1String(""), attributes); |
778 QInputMethodEvent event(QLatin1String(""), attributes); |
719 event.setCommitString(m_preeditString, 0-m_longPress, m_longPress); |
779 event.setCommitString(m_preeditString, 0-longPress, longPress); |
720 m_preeditString.clear(); |
780 m_preeditString.clear(); |
721 sendEvent(event); |
781 sendEvent(event); |
722 |
782 |
723 m_longPress = 0; |
783 m_hasTempPreeditString = false; |
724 |
784 longPress = 0; |
725 if (!triggeredBySymbian) { |
785 |
|
786 if (cancelFepTransaction) { |
726 CCoeFep* fep = CCoeEnv::Static()->Fep(); |
787 CCoeFep* fep = CCoeEnv::Static()->Fep(); |
727 if (fep) |
788 if (fep) |
728 fep->CancelTransaction(); |
789 fep->CancelTransaction(); |
729 } |
790 } |
730 } |
791 } |