on xenial help sign in
Pay attention to input event timestamps
commitc61e6039817494f3750102cf35d859cf9e37f1df authorMichael Terry <michael.terry@canonical.com> dateThu 22 Oct 2015, 13:37 (11 years ago) parentcde772b
5 files changed+41−27
plugins/Utils/windowkeysfilter.cpp+15−1 plugins/Utils/windowkeysfilter.h+7 qml/Components/PhysicalKeysMapper.qml+10−14 qml/Shell.qml+2−2 tests/qmltests/Components/tst_PhysicalKeysMapper.qml+7−10
plugins/Utils/windowkeysfilter.cpp+15−1
@@ -21,7 +21,8 @@
2121#include <QQuickWindow>
2222
2323WindowKeysFilter::WindowKeysFilter(QQuickItem *parent)
24− : QQuickItem(parent)
24+ : QQuickItem(parent),
25+ m_currentEventTimestamp(0)
2526{
2627 connect(this, &QQuickItem::windowChanged,
2728 this, &WindowKeysFilter::setupFilterOnWindow);
@@ -36,7 +37,15 @@ bool WindowKeysFilter::eventFilter(QObject *watched, QEvent *event)
3637 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
3738 // Let QML see this event and decide if it does not want it
3839 event->accept();
40+
41+ m_currentEventTimestamp = static_cast<QInputEvent*>(event)->timestamp();
42+ Q_EMIT currentEventTimestampChanged();
43+
3944 QCoreApplication::sendEvent(this, event);
45+
46+ m_currentEventTimestamp = 0;
47+ Q_EMIT currentEventTimestampChanged();
48+
4049 return event->isAccepted();
4150 } else {
4251 // Not interested
@@ -56,3 +65,8 @@ void WindowKeysFilter::setupFilterOnWindow(QQuickWindow *window)
5665 m_filteredWindow = window;
5766 }
5867}
68+
69+ulong WindowKeysFilter::currentEventTimestamp() const
70+{
71+ return m_currentEventTimestamp;
72+}
plugins/Utils/windowkeysfilter.h+7
@@ -36,16 +36,23 @@
3636class WindowKeysFilter : public QQuickItem
3737{
3838 Q_OBJECT
39+ Q_PROPERTY(ulong currentEventTimestamp READ currentEventTimestamp NOTIFY currentEventTimestampChanged)
3940public:
4041 WindowKeysFilter(QQuickItem *parent = 0);
4142
4243 bool eventFilter(QObject *watched, QEvent *event) override;
4344
45+ ulong currentEventTimestamp() const;
46+
47+Q_SIGNALS:
48+ void currentEventTimestampChanged();
49+
4450private Q_SLOTS:
4551 void setupFilterOnWindow(QQuickWindow *window);
4652
4753private:
4854 QPointer<QQuickWindow> m_filteredWindow;
55+ ulong m_currentEventTimestamp;
4956};
5057
5158#endif // UNITY_WINDOWKEYSFILTER_H
qml/Components/PhysicalKeysMapper.qml+10−14
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.0
1818import Powerd 0.1
19+import Utils 0.1 as Utils
1920
2021/*!
2122 \brief A mapper for the physical keys on the device
@@ -42,7 +43,7 @@ Item {
4243
4344 readonly property bool altTabPressed: d.altTabPressed
4445
45− property int powerKeyLongPressCount: 31 // about 2s
46+ property int powerKeyLongPressTime: 2000
4647
4748 // For testing. If running windowed (e.g. tryShell), Alt+Tab is taken by the
4849 // running desktop, set this to true to use Ctrl+Tab instead.
@@ -58,25 +59,19 @@ Item {
5859 property bool altPressed: false
5960 property bool altTabPressed: false
6061
61− property int powerButtonCount
62+ property var powerButtonPressStart: 0
6263 }
6364
64− function onKeyPressed(event) {
65+ function onKeyPressed(event, currentEventTimestamp) {
6566 if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
6667 if (event.isAutoRepeat) {
67− d.powerButtonCount++;
68−
69− // We count repeats rather than watch the time because if the
70− // system is loaded, we may misinterpret a long wall-clock
71− // delay as a long press, when in fact we just didn't get
72− // around to noticing the key-release event in time. But if we
73− // count events instead, we will be in sync with the event
74− // queue.
75− if (d.powerButtonCount === powerKeyLongPressCount) {
68+ if (d.powerButtonPressStart > 0
69+ && currentEventTimestamp - d.powerButtonPressStart >= powerKeyLongPressTime) {
70+ d.powerButtonPressStart = 0;
7671 root.powerKeyLongPressed();
7772 }
7873 } else {
79− d.powerButtonCount = 0;
74+ d.powerButtonPressStart = currentEventTimestamp;
8075 }
8176 } else if ((event.key == Qt.Key_MediaTogglePlayPause || event.key == Qt.Key_MediaPlay) && !event.isAutoRepeat) {
8277 event.accepted = callManager.handleMediaKey(false);
@@ -112,8 +107,9 @@ Item {
112107 }
113108 }
114109
115− function onKeyReleased(event) {
110+ function onKeyReleased(event, currentEventTimestamp) {
116111 if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
112+ d.powerButtonPressStart = 0;
117113 event.accepted = true;
118114 } else if (event.key == Qt.Key_VolumeDown) {
119115 if (!d.ignoreVolumeEvents) root.volumeDownTriggered();
qml/Shell.qml+2−2
@@ -200,8 +200,8 @@ Item {
200200 }
201201
202202 WindowKeysFilter {
203− Keys.onPressed: physicalKeysMapper.onKeyPressed(event);
204− Keys.onReleased: physicalKeysMapper.onKeyReleased(event);
203+ Keys.onPressed: physicalKeysMapper.onKeyPressed(event, currentEventTimestamp);
204+ Keys.onReleased: physicalKeysMapper.onKeyReleased(event, currentEventTimestamp);
205205 }
206206
207207 HomeKeyWatcher {
tests/qmltests/Components/tst_PhysicalKeysMapper.qml+7−10
@@ -65,27 +65,24 @@ TestCase {
6565
6666 function test_powerKeyLongPressed(data) {
6767 Powerd.setStatus(data.status, Powerd.Unknown);
68− physicalKeysMapper.powerKeyLongPressCount = 5;
68+ physicalKeysMapper.powerKeyLongPressTime = 500;
6969
70− physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: false });
70+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: false }, 100);
7171
7272 // After the first key press the screen is always on
7373 // and the rest of keypresses are auto repeat
7474 Powerd.setStatus(Powerd.On, Powerd.Unknown);
7575
76− for (var i = 0; i < 4; ++i) {
77− physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true});
78− }
76+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 300);
77+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 400);
78+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 500);
79+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 599);
7980
8081 // powerKeyLongPressed should not have been emitted yet.
8182 compare(powerSpy.count, 0);
8283
83− // Fifth repeat event will trigger emission
84− physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true});
85− compare(powerSpy.count, 1);
84+ physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true}, 600);
8685
87− // Make sure we don't double-emit
88− physicalKeysMapper.onKeyPressed({ key: Qt.Key_PowerDown, isAutoRepeat: true});
8986 compare(powerSpy.count, 1);
9087 }
9188