src/gui/inputmethod/qcoefepinputcontext_s60.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
child 7 f7bc934e204c
child 18 2f34d5167611
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
     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
    45 #include <qapplication.h>
    45 #include <qapplication.h>
    46 #include <qtextformat.h>
    46 #include <qtextformat.h>
    47 #include <private/qcore_symbian_p.h>
    47 #include <private/qcore_symbian_p.h>
    48 
    48 
    49 #include <fepitfr.h>
    49 #include <fepitfr.h>
       
    50 #include <hal.h>
    50 
    51 
    51 #include <limits.h>
    52 #include <limits.h>
    52 // You only find these enumerations on SDK 5 onwards, so we need to provide our own
    53 // You only find these enumerations on SDK 5 onwards, so we need to provide our own
    53 // to remain compatible with older releases. They won't be called by pre-5.0 SDKs.
    54 // to remain compatible with older releases. They won't be called by pre-5.0 SDKs.
    54 
    55 
    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 {
   136 void QCoeFepInputContext::widgetDestroyed(QWidget *w)
   138 void QCoeFepInputContext::widgetDestroyed(QWidget *w)
   137 {
   139 {
   138     // Make sure that the input capabilities of whatever new widget got focused are queried.
   140     // Make sure that the input capabilities of whatever new widget got focused are queried.
   139     CCoeControl *ctrl = w->effectiveWinId();
   141     CCoeControl *ctrl = w->effectiveWinId();
   140     if (ctrl->IsFocused()) {
   142     if (ctrl->IsFocused()) {
   141         ctrl->SetFocus(false);
   143         queueInputCapabilitiesChanged();
   142         ctrl->SetFocus(true);
       
   143     }
   144     }
   144 }
   145 }
   145 
   146 
   146 QString QCoeFepInputContext::language()
   147 QString QCoeFepInputContext::language()
   147 {
   148 {
   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);
   208     return false;
   254     return false;
   209 }
   255 }
   210 
   256 
   211 void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event)
   257 void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event)
   212 {
   258 {
   213     Q_ASSERT(m_isEditing);
       
   214     Q_ASSERT(focusWidget());
   259     Q_ASSERT(focusWidget());
   215 
   260 
   216     if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) {
   261     if (event->type() == QEvent::MouseButtonPress && event->button() == Qt::LeftButton) {
   217         commitCurrentString(false);
   262         commitCurrentString(false);
   218         int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
   263         int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
   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);
   443 {
   500 {
   444     QWidget *w = focusWidget();
   501     QWidget *w = focusWidget();
   445     if (!w)
   502     if (!w)
   446         return;
   503         return;
   447 
   504 
   448     m_isEditing = true;
   505     m_cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt();
   449 
   506     
   450     QList<QInputMethodEvent::Attribute> attributes;
   507     QList<QInputMethodEvent::Attribute> attributes;
   451 
   508 
   452     m_cursorVisibility = aCursorVisibility ? 1 : 0;
   509     m_cursorVisibility = aCursorVisibility ? 1 : 0;
   453     m_inlinePosition = aPositionOfInsertionPointInInlineText;
   510     m_inlinePosition = aPositionOfInsertionPointInInlineText;
   454     m_preeditString = qt_TDesC2QString(aInitialInlineText);
   511     m_preeditString = qt_TDesC2QString(aInitialInlineText);
   508     QList<QInputMethodEvent::Attribute> attributes;
   565     QList<QInputMethodEvent::Attribute> attributes;
   509     QInputMethodEvent event(QLatin1String(""), attributes);
   566     QInputMethodEvent event(QLatin1String(""), attributes);
   510     event.setCommitString(QLatin1String(""), 0, 0);
   567     event.setCommitString(QLatin1String(""), 0, 0);
   511     m_preeditString.clear();
   568     m_preeditString.clear();
   512     sendEvent(event);
   569     sendEvent(event);
   513 
       
   514     m_isEditing = false;
       
   515 }
   570 }
   516 
   571 
   517 TInt QCoeFepInputContext::DocumentLengthForFep() const
   572 TInt QCoeFepInputContext::DocumentLengthForFep() const
   518 {
   573 {
   519     QWidget *w = focusWidget();
   574     QWidget *w = focusWidget();
   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();
   678 TTypeUid::Ptr QCoeFepInputContext::MopSupplyObject(TTypeUid /*id*/)
   759 TTypeUid::Ptr QCoeFepInputContext::MopSupplyObject(TTypeUid /*id*/)
   679 {
   760 {
   680     return TTypeUid::Null();
   761     return TTypeUid::Null();
   681 }
   762 }
   682 
   763 
       
   764 MObjectProvider *QCoeFepInputContext::MopNext()
       
   765 {
       
   766     QWidget *w = focusWidget();
       
   767     if (w)
       
   768         return w->effectiveWinId();
       
   769     return 0;
       
   770 }
       
   771 
   683 QT_END_NAMESPACE
   772 QT_END_NAMESPACE
   684 
   773 
   685 #endif // QT_NO_IM
   774 #endif // QT_NO_IM