diff -r 56cd8111b7f7 -r 41300fa6a67c src/gui/inputmethod/qcoefepinputcontext_s60.cpp --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp Tue Jan 26 12:42:25 2010 +0200 +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp Tue Feb 02 00:43:10 2010 +0200 @@ -4,7 +4,7 @@ ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** -** This file is part of the QtGui of the Qt Toolkit. +** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage @@ -47,6 +47,7 @@ #include #include +#include #include // You only find these enumerations on SDK 5 onwards, so we need to provide our own @@ -64,13 +65,14 @@ m_fepState(q_check_ptr(new CAknEdwinState)), // CBase derived object needs check on new m_lastImHints(Qt::ImhNone), m_textCapabilities(TCoeInputCapabilities::EAllText), - m_isEditing(false), m_inDestruction(false), m_pendingInputCapabilitiesChanged(false), m_cursorVisibility(1), m_inlinePosition(0), m_formatRetriever(0), - m_pointerHandler(0) + m_pointerHandler(0), + m_longPress(0), + m_cursorPos(0) { m_fepState->SetObjectProvider(this); m_fepState->SetFlags(EAknEditorFlagDefault); @@ -78,7 +80,7 @@ m_fepState->SetPermittedInputModes( EAknEditorAllInputModes ); m_fepState->SetDefaultCase( EAknEditorLowerCase ); m_fepState->SetPermittedCases( EAknEditorLowerCase|EAknEditorUpperCase ); - m_fepState->SetSpecialCharacterTableResourceId( 0 ); + m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); } @@ -138,8 +140,7 @@ // Make sure that the input capabilities of whatever new widget got focused are queried. CCoeControl *ctrl = w->effectiveWinId(); if (ctrl->IsFocused()) { - ctrl->SetFocus(false); - ctrl->SetFocus(true); + queueInputCapabilitiesChanged(); } } @@ -154,6 +155,44 @@ } } +bool QCoeFepInputContext::needsInputPanel() +{ + switch (QSysInfo::s60Version()) { + case QSysInfo::SV_S60_3_1: + case QSysInfo::SV_S60_3_2: + // There are no touch phones for pre-5.0 SDKs. + return false; +#ifdef Q_CC_NOKIAX86 + default: + // For emulator we assume that we need an input panel, since we can't + // separate between phone types. + return true; +#else + case QSysInfo::SV_S60_5_0: { + // For SDK == 5.0, we need phone specific detection, since the HAL API + // is no good on most phones. However, all phones at the time of writing use the + // input panel, except N97 in landscape mode, but in this mode it refuses to bring + // up the panel anyway, so we don't have to care. + return true; + } + default: + // For unknown/newer types, we try to use the HAL API. + int keyboardEnabled; + int keyboardType; + int err[2]; + err[0] = HAL::Get(HAL::EKeyboard, keyboardType); + err[1] = HAL::Get(HAL::EKeyboardState, keyboardEnabled); + if (err[0] == KErrNone && err[1] == KErrNone + && keyboardType != 0 && keyboardEnabled) + // Means that we have some sort of keyboard. + return false; + + // Fall back to using the input panel. + return true; +#endif // !Q_CC_NOKIAX86 + } +} + bool QCoeFepInputContext::filterEvent(const QEvent *event) { // The CloseSoftwareInputPanel event is not handled here, because the VK will automatically @@ -164,24 +203,31 @@ if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { const QKeyEvent *keyEvent = static_cast(event); - Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); - if (keyEvent->key() == Qt::Key_F20 && m_lastImHints & Qt::ImhHiddenText) { - // Special case in Symbian. On editors with secret text, F20 is for some reason - // considered to be a backspace. - QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(), - keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count()); - QApplication::sendEvent(focusWidget(), &modifiedEvent); - return true; + switch (keyEvent->key()) { + case Qt::Key_F20: + Q_ASSERT(m_lastImHints == focusWidget()->inputMethodHints()); + if (m_lastImHints & Qt::ImhHiddenText) { + // Special case in Symbian. On editors with secret text, F20 is for some reason + // considered to be a backspace. + QKeyEvent modifiedEvent(keyEvent->type(), Qt::Key_Backspace, keyEvent->modifiers(), + keyEvent->text(), keyEvent->isAutoRepeat(), keyEvent->count()); + QApplication::sendEvent(focusWidget(), &modifiedEvent); + return true; + } + break; + case Qt::Key_Select: + if (!m_preeditString.isEmpty()) { + commitCurrentString(false); + return true; + } + break; + default: + break; } } - // :QTP: Always show virtual keyboard - fix needed to use feature manager - // For pre-5.0 SDKs, we don't launch the keyboard. - /* - if (QSysInfo::s60Version() != QSysInfo::SV_S60_5_0) { + if (!needsInputPanel()) return false; - } - */ if (event->type() == QEvent::RequestSoftwareInputPanel) { // Notify S60 that we want the virtual keyboard to show up. @@ -210,7 +256,6 @@ void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event) { - Q_ASSERT(m_isEditing); Q_ASSERT(focusWidget()); if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) { @@ -374,6 +419,14 @@ } m_fepState->SetNumericKeymap(static_cast(flags)); + if (hints & ImhEmailCharactersOnly) { + m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_EMAIL_ADDR_SPECIAL_CHARACTER_TABLE_DIALOG); + } else if (hints & ImhUrlCharactersOnly) { + m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_URL_SPECIAL_CHARACTER_TABLE_DIALOG); + } else { + m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); + } + if (hints & ImhHiddenText) { m_textCapabilities = TCoeInputCapabilities::EAllText | TCoeInputCapabilities::ESecretText; } else { @@ -384,6 +437,10 @@ void QCoeFepInputContext::applyFormat(QList *attributes) { TCharFormat cFormat; + QColor styleTextColor = QApplication::palette("QLineEdit").text().color(); + TLogicalRgb tontColor(TRgb(styleTextColor.red(), styleTextColor.green(), styleTextColor.blue(), styleTextColor.alpha())); + cFormat.iFontPresentation.iTextColor = tontColor; + TInt numChars = 0; TInt charPos = 0; int oldSize = attributes->size(); @@ -445,8 +502,8 @@ if (!w) return; - m_isEditing = true; - + m_cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt(); + QList attributes; m_cursorVisibility = aCursorVisibility ? 1 : 0; @@ -510,8 +567,6 @@ event.setCommitString(QLatin1String(""), 0, 0); m_preeditString.clear(); sendEvent(event); - - m_isEditing = false; } TInt QCoeFepInputContext::DocumentLengthForFep() const @@ -565,8 +620,28 @@ int cursor = w->inputMethodQuery(Qt::ImCursorPosition).toInt() + m_preeditString.size(); int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt() + m_preeditString.size(); - aCursorSelection.iAnchorPos = anchor; - aCursorSelection.iCursorPos = cursor; + QString text = w->inputMethodQuery(Qt::ImSurroundingText).value(); + int combinedSize = text.size() + m_preeditString.size(); + if (combinedSize < anchor || combinedSize < cursor) { + // ### TODO! FIXME! QTBUG-5050 + // This is a hack to prevent crashing in 4.6 with QLineEdits that use input masks. + // The root problem is that cursor position is relative to displayed text instead of the + // actual text we get. + // + // To properly fix this we would need to know the displayText of QLineEdits instead + // of just the text, which on itself should be a trivial change. The difficulties start + // when we need to commit the changes back to the QLineEdit, which would have to be somehow + // able to handle displayText, too. + // + // Until properly fixed, the cursor and anchor positions will not reflect correct positions + // for masked QLineEdits, unless all the masked positions are filled in order so that + // cursor position relative to the displayed text matches position relative to actual text. + aCursorSelection.iAnchorPos = combinedSize; + aCursorSelection.iCursorPos = combinedSize; + } else { + aCursorSelection.iAnchorPos = anchor; + aCursorSelection.iCursorPos = cursor; + } } void QCoeFepInputContext::GetEditorContentForFep(TDes& aEditorContent, TInt aDocumentPosition, @@ -630,16 +705,22 @@ void QCoeFepInputContext::commitCurrentString(bool triggeredBySymbian) { if (m_preeditString.size() == 0) { + QWidget *w = focusWidget(); + if (triggeredBySymbian && w) { + // We must replace the last character only if the input box has already accepted one + if (w->inputMethodQuery(Qt::ImCursorPosition).toInt() != m_cursorPos) + m_longPress = 1; + } return; } QList attributes; QInputMethodEvent event(QLatin1String(""), attributes); - event.setCommitString(m_preeditString, 0, 0);//m_preeditString.size()); + event.setCommitString(m_preeditString, 0-m_longPress, m_longPress); m_preeditString.clear(); sendEvent(event); - m_isEditing = false; + m_longPress = 0; if (!triggeredBySymbian) { CCoeFep* fep = CCoeEnv::Static()->Fep(); @@ -680,6 +761,14 @@ return TTypeUid::Null(); } +MObjectProvider *QCoeFepInputContext::MopNext() +{ + QWidget *w = focusWidget(); + if (w) + return w->effectiveWinId(); + return 0; +} + QT_END_NAMESPACE #endif // QT_NO_IM