summaryrefslogtreecommitdiffstats
path: root/src/gui/s60framework
diff options
context:
space:
mode:
authorHonglei Zhang <honglei.zhang@nokia.com>2011-07-03 17:22:41 (GMT)
committerHonglei Zhang <honglei.zhang@nokia.com>2011-07-03 17:22:41 (GMT)
commit3b6a61953bcd319a6df55d66116ce92f7525ec00 (patch)
tree4642541a9ab510546b1bc77bd4c0790a8eaedfec /src/gui/s60framework
parent2d930fdabccad6bfbbd0075610a302027c8d499b (diff)
downloadQt-3b6a61953bcd319a6df55d66116ce92f7525ec00.zip
Qt-3b6a61953bcd319a6df55d66116ce92f7525ec00.tar.gz
Qt-3b6a61953bcd319a6df55d66116ce92f7525ec00.tar.bz2
Enable key capture and RemCon interfaces for Qt apps on Symbian
The volume and other multimedia keys in Symbian are not delivered through the normal key events, but through a seperate API called CRemConCoreApiTarget. The commit implements the feature that multimedia key events are delivered via normal key events to Qt Application, if the Qt::AA_CaptureMultimediaKeys is defined. Task-number: QTBUG-4415 Reviewed-by: Sami Merila Reviewed-by: Miikka Heikkinen
Diffstat (limited to 'src/gui/s60framework')
-rw-r--r--src/gui/s60framework/qs60keycapture.cpp308
-rw-r--r--src/gui/s60framework/qs60keycapture_p.h116
-rw-r--r--src/gui/s60framework/qs60mainappui.cpp17
-rw-r--r--src/gui/s60framework/s60framework.pri21
4 files changed, 453 insertions, 9 deletions
diff --git a/src/gui/s60framework/qs60keycapture.cpp b/src/gui/s60framework/qs60keycapture.cpp
new file mode 100644
index 0000000..db4cc0e
--- /dev/null
+++ b/src/gui/s60framework/qs60keycapture.cpp
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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 qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <remconinterfaceselector.h>
+#include <remconcoreapitarget.h>
+#include <coemain.h>
+#include "qkeymapper_p.h"
+#include "qs60keycapture_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * Helper class for sending key handling responses to RemCon.
+*/
+class CResponseHandler : public CActive
+{
+public:
+ static CResponseHandler *NewL(CRemConCoreApiTarget &remConCoreApiTarget);
+ virtual ~CResponseHandler();
+ void CompleteAnyKey(TRemConCoreApiOperationId operationId);
+
+private:
+ CResponseHandler(CRemConCoreApiTarget &remConCoreApiTarget);
+
+ void RunL();
+ void DoCancel();
+
+private:
+ RArray<TRemConCoreApiOperationId> iResponseArray;
+ CRemConCoreApiTarget &iRemConCoreApiTarget;
+};
+
+CResponseHandler::CResponseHandler(CRemConCoreApiTarget &remConCoreApiTarget)
+ : CActive(CActive::EPriorityStandard),
+ iRemConCoreApiTarget(remConCoreApiTarget)
+{
+ CActiveScheduler::Add(this);
+}
+
+CResponseHandler *CResponseHandler::NewL(CRemConCoreApiTarget &remConCoreApiTarget)
+{
+ CResponseHandler *self =
+ new (ELeave) CResponseHandler(remConCoreApiTarget);
+ return self;
+}
+
+CResponseHandler::~CResponseHandler()
+{
+ Cancel();
+ iResponseArray.Close();
+}
+
+void CResponseHandler::CompleteAnyKey(TRemConCoreApiOperationId operationId)
+{
+ if (!IsActive()) {
+ TInt error = KErrNone;
+ iRemConCoreApiTarget.SendResponse(iStatus, operationId, error);
+ SetActive();
+ } else {
+ // already active. Append to array and complete later.
+ iResponseArray.Append(operationId);
+ }
+}
+
+void CResponseHandler::DoCancel()
+{
+ iRemConCoreApiTarget.Cancel();
+}
+
+void CResponseHandler::RunL()
+{
+ // if any existing -> Send response
+ if (iResponseArray.Count()) {
+ CompleteAnyKey(iResponseArray[0]);
+ // Remove already completed key
+ iResponseArray.Remove(0);
+ iResponseArray.Compress();
+ }
+}
+
+
+/*
+ * QS60KeyCapture provides media key handling using services from RemCon.
+ */
+QS60KeyCapture::QS60KeyCapture(CCoeEnv *env, QObject *parent):
+ QObject(parent), coeEnv(env), selector(0), target(0), handler(0)
+{
+ initRemCon();
+
+ TTimeIntervalMicroSeconds32 initialTime;
+ TTimeIntervalMicroSeconds32 time;
+ coeEnv->WsSession().GetKeyboardRepeatRate(initialTime, time);
+ initialRepeatTime = (initialTime.Int() / 1000); // msecs
+ repeatTime = (time.Int() / 1000); // msecs
+
+ int clickTimeout = initialRepeatTime + repeatTime;
+
+ volumeUpClickTimer.setSingleShot(true);
+ volumeDownClickTimer.setSingleShot(true);
+ repeatTimer.setSingleShot(true);
+
+ volumeUpClickTimer.setInterval(clickTimeout);
+ volumeDownClickTimer.setInterval(clickTimeout);
+ repeatTimer.setInterval(initialRepeatTime);
+
+ connect(&volumeUpClickTimer, SIGNAL(timeout()), this, SLOT(volumeUpClickTimerExpired()));
+ connect(&volumeDownClickTimer, SIGNAL(timeout()), this, SLOT(volumeDownClickTimerExpired()));
+ connect(&repeatTimer, SIGNAL(timeout()), this, SLOT(repeatTimerExpired()));
+}
+
+/*
+ * Initializes RemCon connection for receiving key events
+ */
+void QS60KeyCapture::initRemCon()
+{
+ try {
+ QT_TRAP_THROWING(
+ selector = CRemConInterfaceSelector::NewL();
+ target = CRemConCoreApiTarget::NewL(*selector, *this);
+ handler = CResponseHandler::NewL(*target);
+ selector->OpenTargetL());
+ } catch (const std::exception &e) {
+ delete handler;
+ delete selector;
+ selector = 0;
+ target = 0;
+ handler = 0;
+ }
+}
+
+QS60KeyCapture::~QS60KeyCapture()
+{
+ delete handler;
+ delete selector;
+}
+
+void QS60KeyCapture::MrccatoCommand(TRemConCoreApiOperationId operationId,
+ TRemConCoreApiButtonAction buttonAction)
+{
+ if (!target)
+ return;
+
+ switch (operationId) {
+ // Volume up/down keys auto repeat if user hold the key long enough
+ case ERemConCoreApiVolumeUp:
+ case ERemConCoreApiVolumeDown:
+ {
+ // Side key events are sent using following scheme:
+ // - ButtonClick is sent first
+ // - if nothing happens before repeat timer expires, no further events are generated
+ // - if user holds the button longer, ButtonPress is sent and
+ // when button is finally released ButtonRelease is sent.
+
+ QTimer &timer = (operationId == ERemConCoreApiVolumeUp) ? volumeUpClickTimer : volumeDownClickTimer;
+
+ switch (buttonAction) {
+ case ERemConCoreApiButtonPress:
+ if (timer.isActive()) {
+ timer.stop();
+ // force repeat event
+ repeatKeyEvent = mapToKeyEvent(operationId);
+ repeatTimerExpired();
+ } else {
+ sendKey(operationId, QEvent::KeyPress);
+ repeatTimer.start(initialRepeatTime);
+ }
+ break;
+ case ERemConCoreApiButtonRelease:
+ timer.stop();
+ sendKey(operationId, QEvent::KeyRelease);
+ repeatTimer.stop();
+ break;
+ case ERemConCoreApiButtonClick:
+ if (timer.isActive()) {
+ timer.stop();
+ sendKey(operationId, QEvent::KeyRelease);
+ }
+ sendKey(operationId, QEvent::KeyPress);
+ timer.start();
+ repeatTimer.stop();
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ switch (buttonAction) {
+ case ERemConCoreApiButtonPress:
+ sendKey(operationId, QEvent::KeyPress);
+ repeatTimer.start(initialRepeatTime);
+ break;
+ case ERemConCoreApiButtonRelease:
+ sendKey(operationId, QEvent::KeyRelease);
+ repeatTimer.stop();
+ break;
+ case ERemConCoreApiButtonClick:
+ sendKey(operationId, QEvent::KeyPress);
+ sendKey(operationId, QEvent::KeyRelease);
+ repeatTimer.stop();
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (handler)
+ handler->CompleteAnyKey(operationId);
+}
+
+/*
+ * Sends volume up KeyRelease event
+ */
+void QS60KeyCapture::volumeUpClickTimerExpired()
+{
+ sendKey(ERemConCoreApiVolumeUp, QEvent::KeyRelease);
+}
+
+/*
+ * Sends volume down KeyRelease event
+ */
+void QS60KeyCapture::volumeDownClickTimerExpired()
+{
+ sendKey(ERemConCoreApiVolumeDown, QEvent::KeyRelease);
+}
+
+/*
+ * Repeats last key event
+ */
+void QS60KeyCapture::repeatTimerExpired()
+{
+ // set auto repeat flag on
+ repeatKeyEvent.iRepeats = 1;
+ coeEnv->SimulateKeyEventL(repeatKeyEvent, EEventKey);
+ repeatTimer.start(repeatTime);
+}
+
+/*
+ * Maps RemCon operation id to key event (includes key code and scan codes)
+ */
+TKeyEvent QS60KeyCapture::mapToKeyEvent(TRemConCoreApiOperationId operationId)
+{
+ TKeyEvent keyEvent;
+ keyEvent.iModifiers = 0;
+ keyEvent.iRepeats = 0;
+ keyEvent.iCode = qt_keymapper_private()->mapS60RemConIdToS60Key(operationId);
+ keyEvent.iScanCode = qt_keymapper_private()->mapS60RemConIdToS60ScanCodes(operationId);
+ return keyEvent;
+}
+
+/*
+ * Delivers key events to the application.
+ * RemCon operations are converted to simulated key events
+ */
+void QS60KeyCapture::sendKey(TRemConCoreApiOperationId operationId, QEvent::Type type)
+{
+ TKeyEvent keyEvent = mapToKeyEvent(operationId);
+
+ if (type == QEvent::KeyPress) {
+ coeEnv->SimulateKeyEventL(keyEvent, EEventKeyDown);
+ coeEnv->SimulateKeyEventL(keyEvent, EEventKey);
+ // save the key press event for repeats
+ repeatKeyEvent = keyEvent;
+ } else {
+ coeEnv->SimulateKeyEventL(keyEvent, EEventKeyUp);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/s60framework/qs60keycapture_p.h b/src/gui/s60framework/qs60keycapture_p.h
new file mode 100644
index 0000000..41cb765
--- /dev/null
+++ b/src/gui/s60framework/qs60keycapture_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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 qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QS60KEYCAPTURE_P_H
+#define QS60KEYCAPTURE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qglobal.h>
+
+#ifdef Q_OS_SYMBIAN
+
+#include <QObject>
+#include <QEvent>
+#include <QTimer>
+#include <remconcoreapitargetobserver.h>
+#include <w32std.h>
+
+class CRemConInterfaceSelector;
+class CRemConCoreApiTarget;
+class CResponseHandler;
+class CCoeEnv;
+
+QT_BEGIN_NAMESPACE
+
+class QS60KeyCapture: public QObject,
+ public MRemConCoreApiTargetObserver
+{
+ Q_OBJECT
+public:
+ QS60KeyCapture(CCoeEnv *env, QObject *parent = 0);
+ ~QS60KeyCapture();
+
+ void MrccatoCommand(TRemConCoreApiOperationId operationId,
+ TRemConCoreApiButtonAction buttonAct);
+
+private slots:
+ void volumeUpClickTimerExpired();
+ void volumeDownClickTimerExpired();
+ void repeatTimerExpired();
+
+private:
+ void sendKey(TRemConCoreApiOperationId operationId, QEvent::Type type);
+ TKeyEvent mapToKeyEvent(TRemConCoreApiOperationId operationId);
+ void initRemCon();
+
+private:
+ QS60KeyCapture();
+ Q_DISABLE_COPY(QS60KeyCapture)
+
+ CCoeEnv *coeEnv;
+
+ CRemConInterfaceSelector *selector;
+ CRemConCoreApiTarget *target;
+ CResponseHandler *handler;
+
+ QTimer volumeUpClickTimer;
+ QTimer volumeDownClickTimer;
+
+ TKeyEvent repeatKeyEvent;
+ int initialRepeatTime; // time before first repeat key event
+ int repeatTime; // time between subsequent repeat key events
+ QTimer repeatTimer;
+};
+
+QT_END_NAMESPACE
+
+#endif // Q_OS_SYMBIAN
+#endif // QS60KEYCAPTURE_P_H
diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp
index bfd1825..f120287 100644
--- a/src/gui/s60framework/qs60mainappui.cpp
+++ b/src/gui/s60framework/qs60mainappui.cpp
@@ -59,6 +59,7 @@
#include <private/qmenu_p.h>
#include <private/qt_s60_p.h>
#include <qdebug.h>
+#include "qs60keycapture_p.h"
//Animated wallpapers in Qt applications are not supported.
const TInt KAknDisableAnimationBackground = 0x02000000;
@@ -66,6 +67,20 @@ const TInt KAknSingleClickCompatible = 0x01000000;
QT_BEGIN_NAMESPACE
+static QS60KeyCapture *qt_S60KeyCapture = 0;
+
+static void installS60KeyCapture(CCoeEnv *env)
+{
+ if (QApplication::testAttribute(Qt::AA_CaptureMultimediaKeys))
+ qt_S60KeyCapture = new QS60KeyCapture(env);
+}
+
+static void removeS60KeyCapture()
+{
+ delete qt_S60KeyCapture;
+ qt_S60KeyCapture = 0;
+}
+
/*!
\class QS60MainAppUi
\since 4.6
@@ -127,6 +142,7 @@ void QS60MainAppUi::ConstructL()
}
#endif
BaseConstructL(flags);
+ installS60KeyCapture(iCoeEnv);
}
/*!
@@ -142,6 +158,7 @@ QS60MainAppUi::QS60MainAppUi()
*/
QS60MainAppUi::~QS60MainAppUi()
{
+ removeS60KeyCapture();
}
/*!
diff --git a/src/gui/s60framework/s60framework.pri b/src/gui/s60framework/s60framework.pri
index 19525b7..e30d2c0 100644
--- a/src/gui/s60framework/s60framework.pri
+++ b/src/gui/s60framework/s60framework.pri
@@ -1,10 +1,13 @@
SOURCES += s60framework/qs60mainapplication.cpp \
- s60framework/qs60mainappui.cpp \
- s60framework/qs60maindocument.cpp
-
-HEADERS += s60framework/qs60mainapplication_p.h \
- s60framework/qs60mainapplication.h \
- s60framework/qs60mainappui.h \
- s60framework/qs60maindocument.h
-
-!isEmpty(QT_LIBINFIX): DEFINES += QT_LIBINFIX_UNQUOTED=$$QT_LIBINFIX \ No newline at end of file
+ s60framework/qs60mainappui.cpp \
+ s60framework/qs60maindocument.cpp \
+ s60framework/qs60keycapture.cpp
+HEADERS += qs60keycapture_p.h \
+ s60framework/qs60mainapplication_p.h \
+ s60framework/qs60mainapplication.h \
+ s60framework/qs60mainappui.h \
+ s60framework/qs60maindocument.h \
+ s60framework/qs60keycapture_p.h
+LIBS += -lremconcoreapi \
+ -lremconinterfacebase
+!isEmpty(QT_LIBINFIX):DEFINES += QT_LIBINFIX_UNQUOTED=$$QT_LIBINFIX