src/hbplugins/inputmethods/touchinput/hbinputbasic12keyhandler.cpp
changeset 0 16d8024aca5e
child 1 f7ac710697a9
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hbplugins/inputmethods/touchinput/hbinputbasic12keyhandler.cpp	Mon Apr 19 14:02:13 2010 +0300
@@ -0,0 +1,462 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (developer.feedback@nokia.com)
+**
+** This file is part of the HbPlugins module of the UI Extensions for Mobile.
+**
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this file.
+** Please review the following information to ensure the GNU Lesser General
+** Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at developer.feedback@nokia.com.
+**
+****************************************************************************/
+
+#include "virtual12key.h"
+#include <QTimer>
+#include <hbinputmethod.h>
+#include <hbinputkeymapfactory.h>
+#include <hbinputpredictionengine.h>
+#include <hbinputsettingproxy.h>
+#include <hbinputpredictionfactory.h>
+#include "hbinputabstractbase.h"
+#include "hbinputbasic12keyhandler.h"
+#include "hbinputbasichandler_p.h"
+
+class HbInputBasic12KeyHandlerPrivate: public HbInputBasicHandlerPrivate
+{
+    Q_DECLARE_PUBLIC(HbInputBasic12KeyHandler)
+
+public:
+    HbInputBasic12KeyHandlerPrivate();
+    ~HbInputBasic12KeyHandlerPrivate();
+
+    void handleAlphaEvent(int buttonId);
+    bool buttonPressed(const QKeyEvent *keyEvent);
+    bool buttonReleased(const QKeyEvent *keyEvent);
+    bool actionHandler(HbInputModeHandler::HbInputModeAction action);
+
+    void _q_timeout();
+
+public:
+    int mLastKey;
+    QChar mCurrentChar;
+    int mNumChr;
+    int mDownKey;
+    HbInputFocusObject *mCurrentlyFocused;
+    bool mLongPressHappened;
+	bool mShiftKeyDoubleTapped;
+};
+
+HbInputBasic12KeyHandlerPrivate::HbInputBasic12KeyHandlerPrivate()
+:    mLastKey(0),
+    mCurrentChar(0),
+    mNumChr(0),
+    mDownKey(0),
+    mCurrentlyFocused(0),
+	mLongPressHappened(false),
+	mShiftKeyDoubleTapped(false)
+{
+}
+
+HbInputBasic12KeyHandlerPrivate::~HbInputBasic12KeyHandlerPrivate()
+{
+}
+
+// handles the key press events.
+void HbInputBasic12KeyHandlerPrivate::handleAlphaEvent(int buttonId)
+{
+    Q_Q(HbInputBasic12KeyHandler);
+    HbInputFocusObject *focusObject = 0;
+    focusObject = mInputMethod->focusObject();
+    if (!focusObject) {
+        return;
+    }
+
+    mCurrentChar = q->getNthCharacterInKey(mNumChr, buttonId);
+
+
+    if (mCurrentChar != 0) {
+        QString str;
+        str += mCurrentChar;
+
+        QList<QInputMethodEvent::Attribute> list;
+        QInputMethodEvent event(str, list);
+        focusObject->sendEvent(event);
+    }
+}
+
+bool HbInputBasic12KeyHandlerPrivate::buttonPressed(const QKeyEvent *keyEvent)
+{
+    Q_UNUSED(keyEvent);
+    mLongPressHappened = false;
+    HbInputFocusObject *focusObject = 0;
+    focusObject = mInputMethod->focusObject();
+    if (!focusObject) {
+        return false;
+    }
+	int buttonId = keyEvent->key();
+	// mark a shift key double tap. This would be handled when the release event is received.
+	if ( (buttonId == Qt::Key_Shift) && (mLastKey == buttonId) && mTimer->isActive() ) {
+		mShiftKeyDoubleTapped = true;		
+	}
+    if (mInputMethod) {
+        if (mLastKey != buttonId)
+        {
+            if(mCurrentChar != 0) {
+                if (!focusObject->characterAllowedInEditor(mCurrentChar)) {
+					focusObject->sendCommitString(QString());			
+                } else {
+                    if (isEnterCharacter(mCurrentChar)) {
+                        focusObject->sendPreEditString(QString("")); // Make sure the enter character is cleared.
+                        mCurrentChar = QChar('\n');                  // Convert enter character to line feed.
+                    }
+                    QChar commitChar(mCurrentChar);
+                    mCurrentChar = 0;
+                    focusObject->filterAndCommitCharacter(commitChar);
+                }			
+            }			
+        }
+
+		mDownKey = buttonId;
+        mTimer->stop();
+		mTimer->start(HbMultiTapTimerTimeout);
+	}
+    return false;
+}
+
+/*!
+Handles the key release events from the VKB. Launches the SCT with key release event of
+asterisk.
+*/
+bool HbInputBasic12KeyHandlerPrivate::buttonReleased(const QKeyEvent *keyEvent)
+{
+    HbInputVkbWidget::HbFlickDirection flickDir = static_cast<HbVirtual12Key*>(mInputMethod)->flickDirection();
+	if (mInputMethod && flickDir!=HbInputVkbWidget::HbFlickDirectionDown) {
+		Q_Q(HbInputBasic12KeyHandler);
+		int buttonId = keyEvent->key();
+		HbInputFocusObject *focusObject = 0;
+		focusObject = mInputMethod->focusObject();
+		if (!focusObject || !mDownKey) {
+			return false;
+		}
+		mDownKey = 0;
+		if ( mLongPressHappened ){
+			return false;
+		}
+		if(mTimer->isActive() && mLastKey != buttonId) {
+			mNumChr = 0;
+
+
+			// For QLineEdit it works fine. For HbLineEdit, need to set the state 
+			// to lower by calling activateState().
+			// This is needed for the scenario - When automatic text case is true
+			// click a button and before the multitap timer expires click on
+			// another button.
+			// Need to check for shift key : In empty editor, click on editor
+			// press shift, multitap on a button. The char is entered in upper case.
+			// It should be entered in lower case.
+            if (Qt::Key_Shift != mLastKey) {
+			    mInputMethod->updateState();
+            }
+			refreshAutoCompleter();
+		}
+
+		if (buttonId == Qt::Key_Return) {
+			mInputMethod->closeKeypad();
+			mLastKey = buttonId;
+			return true;
+		} else if (buttonId == Qt::Key_Shift) {
+            // single tap of shift key toggles prediction status in case insensitive languages
+            if (!HbInputSettingProxy::instance()->globalInputLanguage().isCaseSensitiveLanguage() && 
+                // when the language does not support prediction in that case we should not update the state and prediction
+                HbPredictionFactory::instance()->predictionEngineForLanguage(mInputMethod->inputState().language())) {
+                HbInputSettingProxy::instance()->togglePrediction();
+            } else {
+                // For single key press, change the text input case. If the second shift key press is 
+				// received within long key press time out interval, then activate the next state
+                if (mShiftKeyDoubleTapped){
+                    mShiftKeyDoubleTapped = false;
+                    mTimer->stop();
+                    if( HbInputSettingProxy::instance()->globalInputLanguage() == mInputMethod->inputState().language() ||
+                        HbInputSettingProxy::instance()->globalSecondaryInputLanguage() == mInputMethod->inputState().language() ){
+                        // in latin variants , double tap of shift key toggles the prediction status	
+                        // revert back to the old case as this is a double tap 
+                        // (the case was changed on the single tap)
+                        updateTextCase();
+                        // when the language does not support prediction in that case we should not update the state and prediction
+                        if(HbPredictionFactory::instance()->predictionEngineForLanguage(mInputMethod->inputState().language())) {
+                            HbInputSettingProxy::instance()->togglePrediction();
+                        }
+                    } else {
+					    // if the global language is different from the input mode language, we should 
+                        // go back to the root state
+                        // e.g. double tap of hash/shift key is used to change 
+                        // to chinese input mode from latin input mode
+                        HbInputState rootState;
+                        mInputMethod->editorRootState(rootState);
+                        mInputMethod->activateState(rootState); 		
+                    }
+                } else {
+                    updateTextCase();
+                    mTimer->start(HbLongPressTimerTimeout);
+                }
+            }	
+			mLastKey = buttonId;
+			mCurrentChar = 0;
+            return true;
+		}
+
+		// Let's see if we can get the handler for this button in the base class.
+		if (q->HbInputBasicHandler::filterEvent(keyEvent)) {
+			mCurrentChar = 0;
+			return true;
+		}
+		mLastKey = buttonId;
+		handleAlphaEvent(buttonId);
+
+		// it was a long press on sct swith button. so just return form here.
+		if (!mTimer->isActive() && buttonId == Qt::Key_Control) {
+			return true;
+		}
+		if (buttonId == Qt::Key_Asterisk || buttonId == Qt::Key_Control) {
+			//Same asterisk key is used for launching candidate list (long key press)
+			//and also for SCT. So, do not launch SCT if candidate list is already launched.            
+			mInputMethod->switchMode(buttonId);
+			return true;
+		}
+	}
+	return false;
+}
+
+void HbInputBasic12KeyHandlerPrivate::_q_timeout()
+{
+    Q_Q(HbInputBasic12KeyHandler);
+    mTimer->stop();
+    mNumChr = 0;
+
+    HbInputFocusObject *focusedObject = 0;
+    focusedObject = mInputMethod->focusObject();
+    if (!focusedObject) {
+        qDebug("HbInputBasic12KeyHandler::timeout focusObject == 0");
+        return;
+    }
+
+    if (isEnterCharacter(mCurrentChar)) {
+        focusedObject->sendPreEditString(QString("")); // Make sure the enter character is cleared.
+        mCurrentChar = QChar('\n');                    // Convert enter character to line feed.
+    }
+
+    //Long key press number key is applicable to all keys
+    if (mDownKey ) {       
+        //switch to numeric mode for long key press of Hash key	
+        if (mDownKey == Qt::Key_Shift) {
+            mInputMethod->switchMode(Qt::Key_Shift);				
+        } else if (mDownKey == Qt::Key_Control ) {
+            mInputMethod->selectSpecialCharacterTableMode();
+            mLongPressHappened = true;
+        } else if (mDownKey == Qt::Key_Asterisk) {
+				//switch to sct mode for long tap of * key
+				mInputMethod->switchMode(mDownKey);
+		} else if (mDownKey != Qt::Key_Delete) {
+            q->commitFirstMappedNumber(mDownKey);
+            mLongPressHappened = true;
+        }
+ 	mDownKey = 0;        
+    } else if(mLastKey != Qt::Key_Shift){
+        if (!focusedObject->characterAllowedInEditor(mCurrentChar)) {
+            focusedObject->sendCommitString(QString());
+        } else {
+            if ( mCurrentChar != 0){
+                focusedObject->filterAndCommitCharacter(mCurrentChar);
+            }
+            mInputMethod->updateState();
+            // pass this character to autocompleter.
+            refreshAutoCompleter();
+        }
+    }
+
+    mCurrentChar = 0;
+    return;	
+}
+
+bool HbInputBasic12KeyHandlerPrivate::actionHandler(HbInputModeHandler::HbInputModeAction action)
+{
+    HbInputFocusObject *focusObject = 0;
+    focusObject = mInputMethod->focusObject();
+    if (!focusObject) {
+        return false;
+    }
+
+    bool ret = true;
+    switch (action) {
+    case HbInputModeHandler::HbInputModeActionReset:
+        mTimer->stop();
+        if (mCurrentChar != 0) {
+            focusObject->filterAndCommitCharacter(mCurrentChar);
+            mCurrentChar = 0;
+        }
+        mLastKey = 0;
+        mNumChr = 0;
+        mDownKey = 0;
+        mShiftKeyDoubleTapped = false;
+    break;        
+	case HbInputModeHandler::HbInputModeActionCancelButtonPress:
+        mLastKey = 0;
+        mNumChr = 0;
+        mDownKey = 0;
+        mShiftKeyDoubleTapped = false;
+        if (mTimer->isActive()) {
+            mTimer->stop();
+        }
+    break;
+    case HbInputModeHandler::HbInputModeActionDeleteAndCommit:{
+        mTimer->stop();
+        mNumChr = 0;
+        QString empty;
+        if(mInputMethod) {
+            if (mCurrentChar != 0) {
+                mCurrentChar = 0;
+            } else if (focusObject->editorCursorPosition()){
+                QList<QInputMethodEvent::Attribute> list;
+                QInputMethodEvent event(QString(), list);
+                event.setCommitString(empty, -1, 1);
+                focusObject->sendEvent(event);
+				mInputMethod->updateState();            
+			}
+        } else {
+            // Close event was originated from a button press, remove the uncommitted character.
+            focusObject->sendCommitString(empty);
+        }
+    }
+    break;
+    case HbInputModeHandler::HbInputModeActionFocusRecieved:
+        mTimer->stop();
+        mNumChr = 0;        
+        // set up auto completer
+        setUpAutoCompleter();
+    break;
+    case HbInputModeHandler::HbInputModeActionCommit:
+    case HbInputModeHandler::HbInputModeActionFocusLost:
+        if (mTimer->isActive()) {
+            mTimer->stop();
+            if (mCurrentChar != 0) {
+                if (isEnterCharacter(mCurrentChar)) {
+                    focusObject->sendPreEditString(QString("")); // Make sure the enter character is cleared.
+                    mCurrentChar = QChar('\n');                    // Convert enter character to line feed.
+                }
+                focusObject->filterAndCommitCharacter(mCurrentChar);
+                mCurrentChar = 0;
+            }
+            mLastKey = 0;
+            mNumChr = 0;
+            mInputMethod->updateState();
+        }
+		// We should add the commit autocompleting text when focus lost happens
+		if(HbInputModeHandler::HbInputModeActionFocusLost == action){
+			if (mCurrentlyFocused != focusObject) {
+				mCurrentlyFocused = focusObject;
+				if (mAutoCompleter) {
+					mAutoCompleter->commit();
+				}
+			}
+		}
+        break;
+    default: {
+        ret = false;
+    }
+    break;
+    };
+
+    return ret;
+}
+
+
+HbInputBasic12KeyHandler::HbInputBasic12KeyHandler(HbInputAbstractMethod* inputMethod)
+:HbInputBasicHandler( *new HbInputBasic12KeyHandlerPrivate, inputMethod)
+{
+    Q_D(HbInputBasic12KeyHandler);
+    d->q_ptr = this;
+}
+
+HbInputBasic12KeyHandler::~HbInputBasic12KeyHandler()
+{
+}
+
+/*!
+ filterEvent function for handling different keyevents.
+*/
+bool HbInputBasic12KeyHandler::filterEvent(const QKeyEvent * event)
+{
+    Q_D(HbInputBasic12KeyHandler);
+
+    if (event->type() == QEvent::KeyRelease) {
+        return d->buttonReleased(event);
+    } else {
+        return d->buttonPressed(event);
+    }
+}
+
+/*!
+ returns true if in inline edit.
+*/
+bool HbInputBasic12KeyHandler::isComposing() const
+{
+    Q_D(const HbInputBasic12KeyHandler);
+    return d->mTimer->isActive();
+}
+
+/*!
+ list different input modes.
+*/
+void HbInputBasic12KeyHandler::listInputModes(QVector<HbInputModeProperties>& modes) const
+{
+    HbInputModeProperties binding;
+    binding.iMode = HbInputModeDefault;
+    binding.iKeyboard = HbKeyboardVirtual12Key;
+
+    QList<HbInputLanguage> languages = HbKeymapFactory::availableLanguages();
+    foreach (HbInputLanguage language, languages) {
+        binding.iLanguage = language;
+        modes.push_back(binding);
+    }
+}
+
+/*!
+Action Handler
+*/
+bool HbInputBasic12KeyHandler::actionHandler(HbInputModeAction action)
+{
+    Q_D(HbInputBasic12KeyHandler);
+    if (!d->actionHandler(action)) {
+        // no action taken so let's pass it to the base class.
+        return HbInputBasicHandler::actionHandler(action);
+    }
+    return false;
+}
+
+void HbInputBasic12KeyHandler::cursorPositionChanged(int oldPos, int newPos)
+{
+    Q_D(HbInputBasic12KeyHandler);
+
+    if (d->mTimer->isActive() && d->mCurrentChar != 0) {
+        QString commitString(d->mCurrentChar);
+        d->mCurrentChar = 0;
+        commitAndUpdate(commitString, oldPos - newPos, 0);
+        d->actionHandler(HbInputModeActionReset);
+    }
+    HbInputModeHandler::cursorPositionChanged(oldPos,newPos);
+}
+
+// EOF