2 ** |
2 ** |
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
3 ** Copyright (C) 2009 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 of the Qt Toolkit. |
7 ** This file is part of the QtGui module of the Qt Toolkit. |
8 ** |
8 ** |
9 ** $QT_BEGIN_LICENSE:LGPL$ |
9 ** $QT_BEGIN_LICENSE:LGPL$ |
10 ** No Commercial Usage |
10 ** No Commercial Usage |
11 ** This file contains pre-release code and may not be distributed. |
11 ** This file contains pre-release code and may not be distributed. |
12 ** You may use this file in accordance with the terms and conditions |
12 ** You may use this file in accordance with the terms and conditions |
62 QCoeFepInputContext::QCoeFepInputContext(QObject *parent) |
63 QCoeFepInputContext::QCoeFepInputContext(QObject *parent) |
63 : QInputContext(parent), |
64 : QInputContext(parent), |
64 m_fepState(q_check_ptr(new CAknEdwinState)), // CBase derived object needs check on new |
65 m_fepState(q_check_ptr(new CAknEdwinState)), // CBase derived object needs check on new |
65 m_lastImHints(Qt::ImhNone), |
66 m_lastImHints(Qt::ImhNone), |
66 m_textCapabilities(TCoeInputCapabilities::EAllText), |
67 m_textCapabilities(TCoeInputCapabilities::EAllText), |
67 m_isEditing(false), |
|
68 m_inDestruction(false), |
68 m_inDestruction(false), |
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), |
|
75 m_cursorPos(0) |
74 { |
76 { |
75 m_fepState->SetObjectProvider(this); |
77 m_fepState->SetObjectProvider(this); |
76 m_fepState->SetFlags(EAknEditorFlagDefault); |
78 m_fepState->SetFlags(EAknEditorFlagDefault); |
77 m_fepState->SetDefaultInputMode( EAknEditorTextInputMode ); |
79 m_fepState->SetDefaultInputMode( EAknEditorTextInputMode ); |
78 m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); |
80 m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); |
79 m_fepState->SetDefaultCase( EAknEditorLowerCase ); |
81 m_fepState->SetDefaultCase( EAknEditorLowerCase ); |
80 m_fepState->SetPermittedCases( EAknEditorLowerCase|EAknEditorUpperCase ); |
82 m_fepState->SetPermittedCases( EAknEditorLowerCase|EAknEditorUpperCase ); |
81 m_fepState->SetSpecialCharacterTableResourceId( 0 ); |
83 m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); |
82 m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); |
84 m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); |
83 } |
85 } |
84 |
86 |
85 QCoeFepInputContext::~QCoeFepInputContext() |
87 QCoeFepInputContext::~QCoeFepInputContext() |
86 { |
88 { |
152 } else { |
153 } else { |
153 return QString::fromLatin1("C"); |
154 return QString::fromLatin1("C"); |
154 } |
155 } |
155 } |
156 } |
156 |
157 |
|
158 bool QCoeFepInputContext::needsInputPanel() |
|
159 { |
|
160 switch (QSysInfo::s60Version()) { |
|
161 case QSysInfo::SV_S60_3_1: |
|
162 case QSysInfo::SV_S60_3_2: |
|
163 // There are no touch phones for pre-5.0 SDKs. |
|
164 return false; |
|
165 #ifdef Q_CC_NOKIAX86 |
|
166 default: |
|
167 // For emulator we assume that we need an input panel, since we can't |
|
168 // separate between phone types. |
|
169 return true; |
|
170 #else |
|
171 case QSysInfo::SV_S60_5_0: { |
|
172 // For SDK == 5.0, we need phone specific detection, since the HAL API |
|
173 // is no good on most phones. However, all phones at the time of writing use the |
|
174 // input panel, except N97 in landscape mode, but in this mode it refuses to bring |
|
175 // up the panel anyway, so we don't have to care. |
|
176 return true; |
|
177 } |
|
178 default: |
|
179 // For unknown/newer types, we try to use the HAL API. |
|
180 int keyboardEnabled; |
|
181 int keyboardType; |
|
182 int err[2]; |
|
183 err[0] = HAL::Get(HAL::EKeyboard, keyboardType); |
|
184 err[1] = HAL::Get(HAL::EKeyboardState, keyboardEnabled); |
|
185 if (err[0] == KErrNone && err[1] == KErrNone |
|
186 && keyboardType != 0 && keyboardEnabled) |
|
187 // Means that we have some sort of keyboard. |
|
188 return false; |
|
189 |
|
190 // Fall back to using the input panel. |
|
191 return true; |
|
192 #endif // !Q_CC_NOKIAX86 |
|
193 } |
|
194 } |
|
195 |
157 bool QCoeFepInputContext::filterEvent(const QEvent *event) |
196 bool QCoeFepInputContext::filterEvent(const QEvent *event) |
158 { |
197 { |
159 // The CloseSoftwareInputPanel event is not handled here, because the VK will automatically |
198 // The CloseSoftwareInputPanel event is not handled here, because the VK will automatically |
160 // close when it discovers that the underlying widget does not have input capabilities. |
199 // close when it discovers that the underlying widget does not have input capabilities. |
161 |
200 |
162 if (!focusWidget()) |
201 if (!focusWidget()) |
163 return false; |
202 return false; |
164 |
203 |
165 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { |
204 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { |
166 const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event); |
205 const QKeyEvent *keyEvent = static_cast<const QKeyEvent *>(event); |
167 Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); |
206 switch (keyEvent->key()) { |
168 if (keyEvent->key() == Qt::Key_F20 && m_lastImHints & Qt::ImhHiddenText) { |
207 case Qt::Key_F20: |
169 // Special case in Symbian. On editors with secret text, F20 is for some reason |
208 Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); |
170 // considered to be a backspace. |
209 if (m_lastImHints & Qt::ImhHiddenText) { |
171 QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(), |
210 // Special case in Symbian. On editors with secret text, F20 is for some reason |
172 keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count()); |
211 // considered to be a backspace. |
173 QApplication::sendEvent(focusWidget(), &modifiedEvent); |
212 QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(), |
174 return true; |
213 keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count()); |
175 } |
214 QApplication::sendEvent(focusWidget(), &modifiedEvent); |
176 } |
215 return true; |
177 |
216 } |
178 // :QTP: Always show virtual keyboard - fix needed to use feature manager |
217 break; |
179 // For pre-5.0 SDKs, we don't launch the keyboard. |
218 case Qt::Key_Select: |
180 /* |
219 if (!m_preeditString.isEmpty()) { |
181 if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { |
220 commitCurrentString(false); |
|
221 return true; |
|
222 } |
|
223 break; |
|
224 default: |
|
225 break; |
|
226 } |
|
227 } |
|
228 |
|
229 if (!needsInputPanel()) |
182 return false; |
230 return false; |
183 } |
|
184 */ |
|
185 |
231 |
186 if (event->type() == QEvent::RequestSoftwareInputPanel) { |
232 if (event->type() == QEvent::RequestSoftwareInputPanel) { |
187 // Notify S60 that we want the virtual keyboard to show up. |
233 // Notify S60 that we want the virtual keyboard to show up. |
188 QSymbianControl *sControl; |
234 QSymbianControl *sControl; |
189 sControl = focusWidget()->effectiveWinId()->MopGetObject(sControl); |
235 sControl = focusWidget()->effectiveWinId()->MopGetObject(sControl); |
372 // that flag. |
417 // that flag. |
373 flags = EAknEditorStandardNumberModeKeymap; |
418 flags = EAknEditorStandardNumberModeKeymap; |
374 } |
419 } |
375 m_fepState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(flags)); |
420 m_fepState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(flags)); |
376 |
421 |
|
422 if (hints & ImhEmailCharactersOnly) { |
|
423 m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_EMAIL_ADDR_SPECIAL_CHARACTER_TABLE_DIALOG); |
|
424 } else if (hints & ImhUrlCharactersOnly) { |
|
425 m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_URL_SPECIAL_CHARACTER_TABLE_DIALOG); |
|
426 } else { |
|
427 m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); |
|
428 } |
|
429 |
377 if (hints & ImhHiddenText) { |
430 if (hints & ImhHiddenText) { |
378 m_textCapabilities = TCoeInputCapabilities::EAllText | TCoeInputCapabilities::ESecretText; |
431 m_textCapabilities = TCoeInputCapabilities::EAllText | TCoeInputCapabilities::ESecretText; |
379 } else { |
432 } else { |
380 m_textCapabilities = TCoeInputCapabilities::EAllText; |
433 m_textCapabilities = TCoeInputCapabilities::EAllText; |
381 } |
434 } |
382 } |
435 } |
383 |
436 |
384 void QCoeFepInputContext::applyFormat(QList<QInputMethodEvent::Attribute> *attributes) |
437 void QCoeFepInputContext::applyFormat(QList<QInputMethodEvent::Attribute> *attributes) |
385 { |
438 { |
386 TCharFormat cFormat; |
439 TCharFormat cFormat; |
|
440 QColor styleTextColor = QApplication::palette("QLineEdit").text().color(); |
|
441 TLogicalRgb tontColor(TRgb(styleTextColor.red(), styleTextColor.green(), styleTextColor.blue(), styleTextColor.alpha())); |
|
442 cFormat.iFontPresentation.iTextColor = tontColor; |
|
443 |
387 TInt numChars = 0; |
444 TInt numChars = 0; |
388 TInt charPos = 0; |
445 TInt charPos = 0; |
389 int oldSize = attributes->size(); |
446 int oldSize = attributes->size(); |
390 while (m_formatRetriever) { |
447 while (m_formatRetriever) { |
391 m_formatRetriever->GetFormatOfFepInlineText(cFormat, numChars, charPos); |
448 m_formatRetriever->GetFormatOfFepInlineText(cFormat, numChars, charPos); |
563 return; |
618 return; |
564 } |
619 } |
565 |
620 |
566 int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + m_preeditString.size(); |
621 int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + m_preeditString.size(); |
567 int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt() + m_preeditString.size(); |
622 int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt() + m_preeditString.size(); |
568 aCursorSelection.iAnchorPos = anchor; |
623 QString text = w->inputMethodQuery(Qt::ImSurroundingText).value<QString>(); |
569 aCursorSelection.iCursorPos = cursor; |
624 int combinedSize = text.size() + m_preeditString.size(); |
|
625 if (combinedSize < anchor || combinedSize < cursor) { |
|
626 // ### TODO! FIXME! QTBUG-5050 |
|
627 // This is a hack to prevent crashing in 4.6 with QLineEdits that use input masks. |
|
628 // The root problem is that cursor position is relative to displayed text instead of the |
|
629 // actual text we get. |
|
630 // |
|
631 // To properly fix this we would need to know the displayText of QLineEdits instead |
|
632 // of just the text, which on itself should be a trivial change. The difficulties start |
|
633 // when we need to commit the changes back to the QLineEdit, which would have to be somehow |
|
634 // able to handle displayText, too. |
|
635 // |
|
636 // Until properly fixed, the cursor and anchor positions will not reflect correct positions |
|
637 // for masked QLineEdits, unless all the masked positions are filled in order so that |
|
638 // cursor position relative to the displayed text matches position relative to actual text. |
|
639 aCursorSelection.iAnchorPos = combinedSize; |
|
640 aCursorSelection.iCursorPos = combinedSize; |
|
641 } else { |
|
642 aCursorSelection.iAnchorPos = anchor; |
|
643 aCursorSelection.iCursorPos = cursor; |
|
644 } |
570 } |
645 } |
571 |
646 |
572 void QCoeFepInputContext::GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, |
647 void QCoeFepInputContext::GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, |
573 TInt aLengthToRetrieve) const |
648 TInt aLengthToRetrieve) const |
574 { |
649 { |
628 } |
703 } |
629 |
704 |
630 void QCoeFepInputContext::commitCurrentString(bool triggeredBySymbian) |
705 void QCoeFepInputContext::commitCurrentString(bool triggeredBySymbian) |
631 { |
706 { |
632 if (m_preeditString.size() == 0) { |
707 if (m_preeditString.size() == 0) { |
|
708 QWidget *w = focusWidget(); |
|
709 if (triggeredBySymbian && w) { |
|
710 // We must replace the last character only if the input box has already accepted one |
|
711 if (w->inputMethodQuery(Qt::ImCursorPosition).toInt() != m_cursorPos) |
|
712 m_longPress = 1; |
|
713 } |
633 return; |
714 return; |
634 } |
715 } |
635 |
716 |
636 QList<QInputMethodEvent::Attribute> attributes; |
717 QList<QInputMethodEvent::Attribute> attributes; |
637 QInputMethodEvent event(QLatin1String(""), attributes); |
718 QInputMethodEvent event(QLatin1String(""), attributes); |
638 event.setCommitString(m_preeditString, 0, 0);//m_preeditString.size()); |
719 event.setCommitString(m_preeditString, 0-m_longPress, m_longPress); |
639 m_preeditString.clear(); |
720 m_preeditString.clear(); |
640 sendEvent(event); |
721 sendEvent(event); |
641 |
722 |
642 m_isEditing = false; |
723 m_longPress = 0; |
643 |
724 |
644 if (!triggeredBySymbian) { |
725 if (!triggeredBySymbian) { |
645 CCoeFep* fep = CCoeEnv::Static()->Fep(); |
726 CCoeFep* fep = CCoeEnv::Static()->Fep(); |
646 if (fep) |
727 if (fep) |
647 fep->CancelTransaction(); |
728 fep->CancelTransaction(); |