src/gui/inputmethod/qcoefepinputcontext_s60.cpp
changeset 37 758a864f9613
parent 33 3e2da88830cd
--- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp	Fri Sep 17 08:34:18 2010 +0300
+++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp	Mon Oct 04 01:19:32 2010 +0300
@@ -47,6 +47,7 @@
 #include <qgraphicsview.h>
 #include <qgraphicsscene.h>
 #include <qgraphicswidget.h>
+#include <qsymbianevent.h>
 #include <private/qcore_symbian_p.h>
 
 #include <fepitfr.h>
@@ -79,7 +80,6 @@
       m_inlinePosition(0),
       m_formatRetriever(0),
       m_pointerHandler(0),
-      m_cursorPos(0),
       m_hasTempPreeditString(false)
 {
     m_fepState->SetObjectProvider(this);
@@ -237,11 +237,17 @@
             break;
         }
 
+        QString widgetText = focusWidget()->inputMethodQuery(Qt::ImSurroundingText).toString();
+        int maxLength = focusWidget()->inputMethodQuery(Qt::ImMaximumTextLength).toInt();
+        if (!keyEvent->text().isEmpty() && widgetText.size() + m_preeditString.size() >= maxLength) {
+            // Don't send key events with string content if the widget is "full".
+            return true;
+        }
+
         if (keyEvent->type() == QEvent::KeyPress
             && focusWidget()->inputMethodHints() & Qt::ImhHiddenText
             && !keyEvent->text().isEmpty()) {
             // Send some temporary preedit text in order to make text visible for a moment.
-            m_cursorPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
             m_preeditString = keyEvent->text();
             QList<QInputMethodEvent::Attribute> attributes;
             QInputMethodEvent imEvent(m_preeditString, attributes);
@@ -282,6 +288,18 @@
     return false;
 }
 
+bool QCoeFepInputContext::symbianFilterEvent(QWidget *keyWidget, const QSymbianEvent *event)
+{
+    Q_UNUSED(keyWidget);
+    if (event->type() == QSymbianEvent::CommandEvent)
+        // A command basically means the same as a button being pushed. With Qt buttons
+        // that would normally result in a reset of the input method due to the focus change.
+        // This should also happen for commands.
+        reset();
+
+    return false;
+}
+
 void QCoeFepInputContext::timerEvent(QTimerEvent *timerEvent)
 {
     if (timerEvent->timerId() == m_tempPreeditStringTimeout.timerId())
@@ -297,10 +315,6 @@
         return;
 
     commitCurrentString(false);
-
-    //update cursor position, now this pre-edit text has been committed.
-    //this prevents next keypress overwriting it (QTBUG-11673)
-    m_cursorPos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt();
 }
 
 void QCoeFepInputContext::mouseHandler( int x, QMouseEvent *event)
@@ -364,10 +378,10 @@
 
     commitTemporaryPreeditString();
 
-    bool numbersOnly = hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly
-            || hints & ImhDialableCharactersOnly;
-    bool noOnlys = !(numbersOnly || hints & ImhUppercaseOnly
-            || hints & ImhLowercaseOnly);
+    const bool anynumbermodes = hints & (ImhDigitsOnly | ImhFormattedNumbersOnly | ImhDialableCharactersOnly);
+    const bool anytextmodes = hints & (ImhUppercaseOnly | ImhLowercaseOnly | ImhEmailCharactersOnly | ImhUrlCharactersOnly);
+    const bool numbersOnly = anynumbermodes && !anytextmodes;
+    const bool noOnlys = !(hints & ImhExclusiveInputMask);
     TInt flags;
     Qt::InputMethodHints oldHints = hints;
 
@@ -379,8 +393,7 @@
     }
     if (!noOnlys) {
         // Make sure that the preference is within the permitted set.
-        if (hints & ImhPreferNumbers && !(hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly
-                || hints & ImhDialableCharactersOnly)) {
+        if (hints & ImhPreferNumbers && !anynumbermodes) {
             hints &= ~ImhPreferNumbers;
         } else if (hints & ImhPreferUppercase && !(hints & ImhUppercaseOnly)) {
             hints &= ~ImhPreferUppercase;
@@ -393,8 +406,7 @@
                 hints |= ImhPreferLowercase;
             } else if (hints & ImhUppercaseOnly) {
                 hints |= ImhPreferUppercase;
-            } else if (hints & ImhDigitsOnly || hints & ImhFormattedNumbersOnly
-                    || hints & ImhDialableCharactersOnly) {
+            } else if (numbersOnly) {
                 hints |= ImhPreferNumbers;
             }
         }
@@ -408,13 +420,21 @@
         m_fepState->SetCurrentInputMode(EAknEditorTextInputMode);
     }
     flags = 0;
-    if (numbersOnly) {
+    if (noOnlys || (anynumbermodes && anytextmodes)) {
+        flags = EAknEditorAllInputModes;
+    }
+    else if (anynumbermodes) {
         flags |= EAknEditorNumericInputMode;
+        if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0
+            && ((hints & ImhFormattedNumbersOnly) || (hints & ImhDialableCharactersOnly))) {
+            //workaround - the * key does not launch the symbols menu, making it impossible to use these modes unless text mode is enabled.
+            flags |= EAknEditorTextInputMode;
+        }
     }
-    if (hints & ImhUppercaseOnly || hints & ImhLowercaseOnly) {
+    else if (anytextmodes) {
         flags |= EAknEditorTextInputMode;
     }
-    if (flags == 0) {
+    else {
         flags = EAknEditorAllInputModes;
     }
     m_fepState->SetPermittedInputModes(flags);
@@ -461,24 +481,33 @@
     if (hints & ImhNoPredictiveText || hints & ImhHiddenText) {
         flags |= EAknEditorFlagNoT9;
     }
+    // if alphanumeric input, or if multiple incompatible number modes are selected;
+    // then make all symbols available in numeric mode too.
+    if (!numbersOnly || ((hints & ImhFormattedNumbersOnly) && (hints & ImhDialableCharactersOnly)))
+        flags |= EAknEditorFlagUseSCTNumericCharmap;
     m_fepState->SetFlags(flags);
     ReportAknEdStateEvent(MAknEdStateObserver::EAknEdwinStateFlagsUpdate);
 
-    if (hints & ImhFormattedNumbersOnly) {
+    if (hints & ImhDialableCharactersOnly) {
+        // This is first, because if (ImhDialableCharactersOnly | ImhFormattedNumbersOnly)
+        // is specified, this one is more natural (# key enters a #)
+        flags = EAknEditorStandardNumberModeKeymap;
+    } else if (hints & ImhFormattedNumbersOnly) {
+        // # key enters decimal point
         flags = EAknEditorCalculatorNumberModeKeymap;
     } else if (hints & ImhDigitsOnly) {
+        // This is last, because it is most restrictive (# key is inactive)
         flags = EAknEditorPlainNumberModeKeymap;
     } else {
-        // ImhDialableCharactersOnly is the fallback as well, so we don't need to check for
-        // that flag.
         flags = EAknEditorStandardNumberModeKeymap;
     }
     m_fepState->SetNumericKeymap(static_cast<TAknEditorNumericKeymap>(flags));
 
-    if (hints & ImhEmailCharactersOnly) {
+    if (hints & ImhUrlCharactersOnly) {
+        // URL characters is everything except space, so a superset of the other restrictions
+        m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_URL_SPECIAL_CHARACTER_TABLE_DIALOG);
+    } else 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);
     }
@@ -581,8 +610,6 @@
 
     commitTemporaryPreeditString();
 
-    m_cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt();
-    
     QList<QInputMethodEvent::Attribute> attributes;
 
     m_cursorVisibility = aCursorVisibility ? 1 : 0;
@@ -597,9 +624,10 @@
     // Let's remove the selected text if aInitialInlineText is empty and there is selected text
     if (m_preeditString.isEmpty()) {
         int anchor = w->inputMethodQuery(Qt::ImAnchorPosition).toInt();
-        int replacementLength = qAbs(m_cursorPos-anchor);
+        int cursorPos = w->inputMethodQuery(Qt::ImCursorPosition).toInt();
+        int replacementLength = qAbs(cursorPos-anchor);
         if (replacementLength > 0) {
-            int replacementStart = m_cursorPos < anchor ? 0 : -replacementLength;
+            int replacementStart = cursorPos < anchor ? 0 : -replacementLength;
             QList<QInputMethodEvent::Attribute> clearSelectionAttributes;
             QInputMethodEvent clearSelectionEvent(QLatin1String(""), clearSelectionAttributes);
             clearSelectionEvent.setCommitString(QLatin1String(""), replacementStart, replacementLength);
@@ -632,8 +660,13 @@
                                                    m_inlinePosition,
                                                    m_cursorVisibility,
                                                    QVariant()));
-    m_preeditString = qt_TDesC2QString(aNewInlineText);
-    QInputMethodEvent event(m_preeditString, attributes);
+    QString newPreeditString = qt_TDesC2QString(aNewInlineText);
+    QInputMethodEvent event(newPreeditString, attributes);
+    if (newPreeditString.isEmpty() && m_preeditString.isEmpty()) {
+        // In Symbian world this means "erase last character".
+        event.setCommitString(QLatin1String(""), -1, 1);
+    }
+    m_preeditString = newPreeditString;
     sendEvent(event);
 }
 
@@ -803,25 +836,13 @@
 
 void QCoeFepInputContext::commitCurrentString(bool cancelFepTransaction)
 {
-    int longPress = 0;
-
-    if (m_preeditString.size() == 0) {
-        QWidget *w = focusWidget();
-        if (!cancelFepTransaction && w) {
-            // We must replace the last character only if the input box has already accepted one 
-            if (w->inputMethodQuery(Qt::ImCursorPosition).toInt() != m_cursorPos)
-                longPress = 1;
-        }
-    }
-
     QList<QInputMethodEvent::Attribute> attributes;
     QInputMethodEvent event(QLatin1String(""), attributes);
-    event.setCommitString(m_preeditString, 0-longPress, longPress);
+    event.setCommitString(m_preeditString, 0, 0);
     m_preeditString.clear();
     sendEvent(event);
 
     m_hasTempPreeditString = false;
-    longPress = 0;
 
     if (cancelFepTransaction) {
         CCoeFep* fep = CCoeEnv::Static()->Fep();