Lomiri
PhysicalKeysMapper.qml
1 /*
2  * Copyright (C) 2014-2015 Canonical Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.12
18 import Powerd 0.1
19 import Utils 0.1
20 
21 /*!
22  \brief A mapper for the physical keys on the device
23 
24  A mapper to handle events triggered by pressing physical keys on a device.
25  Keys included are
26  * Volume Decrease
27  * Volume Increase
28  * Power
29 
30  This allows for handling the following events
31  * Power dialog
32  * Volume Decreases/Increases
33  * Screenshots
34 */
35 
36 Item {
37  id: root
38 
39  signal powerKeyLongPressed;
40  signal volumeDownTriggered;
41  signal volumeUpTriggered;
42  signal screenshotTriggered;
43 
44  readonly property bool altTabPressed: d.altTabPressed
45  readonly property bool superPressed: d.superPressed
46  readonly property bool superTabPressed: d.superTabPressed
47 
48  property int powerKeyLongPressTime: 2000
49 
50  // For testing. If running windowed (e.g. tryShell), Alt+Tab is taken by the
51  // running desktop, set this to true to use Ctrl+Tab instead.
52  property bool controlInsteadOfAlt: false
53  property bool controlInsteadOfSuper: false
54 
55  QtObject {
56  id: d
57 
58  property bool volumeDownKeyPressed: false
59  property bool volumeUpKeyPressed: false
60  property bool ignoreVolumeEvents: false
61 
62  property bool altPressed: false
63  property bool altTabPressed: false
64 
65  property bool superPressed: false
66  property bool superTabPressed: false
67 
68  property var powerButtonPressStart: -1
69  }
70 
71  InputEventGenerator {
72  id: inputEventGenerator
73  }
74 
75  function onKeyPressed(event, currentEventTimestamp) {
76  if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
77  if (event.isAutoRepeat) {
78  if (d.powerButtonPressStart != -1
79  && currentEventTimestamp - d.powerButtonPressStart >= powerKeyLongPressTime) {
80  d.powerButtonPressStart = -1;
81  root.powerKeyLongPressed();
82  }
83  } else {
84  d.powerButtonPressStart = currentEventTimestamp;
85  }
86  } else if ((event.key == Qt.Key_MediaTogglePlayPause || event.key == Qt.Key_MediaPlay) && !event.isAutoRepeat) {
87  event.accepted = callManager.handleMediaKey(false);
88  } else if (event.key == Qt.Key_VolumeDown) {
89  if (event.isAutoRepeat && !d.ignoreVolumeEvents) root.volumeDownTriggered();
90  else if (!event.isAutoRepeat) {
91  if (d.volumeUpKeyPressed) {
92  if (Powerd.status === Powerd.On) {
93  root.screenshotTriggered();
94  }
95  d.ignoreVolumeEvents = true;
96  }
97  d.volumeDownKeyPressed = true;
98  }
99  } else if (event.key == Qt.Key_VolumeUp) {
100  if (event.isAutoRepeat && !d.ignoreVolumeEvents) root.volumeUpTriggered();
101  else if (!event.isAutoRepeat) {
102  if (d.volumeDownKeyPressed) {
103  if (Powerd.status === Powerd.On) {
104  root.screenshotTriggered();
105  }
106  d.ignoreVolumeEvents = true;
107  }
108  d.volumeUpKeyPressed = true;
109  }
110  } else if (event.key == Qt.Key_Alt || (root.controlInsteadOfAlt && event.key == Qt.Key_Control)) {
111  d.altPressed = true;
112 
113  // Adding MetaModifier here because that's what keyboards do. Pressing Super_L actually gives
114  // Super_L + MetaModifier. This helps to make sure we only invoke superPressed if no other
115  // Modifier is pressed too.
116  } else if (((event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R) && event.modifiers === Qt.MetaModifier)
117  || (root.controlInsteadOfSuper && event.key == Qt.Key_Control)
118  ) {
119  d.superPressed = true;
120  } else if (event.key == Qt.Key_Tab) {
121  if (d.altPressed && !d.altTabPressed) {
122  inputEventGenerator.generateKeyEvent(Qt.Key_Alt, false, Qt.NoModifier, currentEventTimestamp, 56);
123  d.altTabPressed = true;
124  event.accepted = true;
125  }
126  if (d.superPressed && !d.superTabPressed) {
127  d.superTabPressed = true;
128  event.accepted = true;
129  }
130  }
131  }
132 
133  function onKeyReleased(event, currentEventTimestamp) {
134  if (event.key == Qt.Key_PowerDown || event.key == Qt.Key_PowerOff) {
135  d.powerButtonPressStart = -1;
136  event.accepted = true;
137  } else if (event.key == Qt.Key_VolumeDown) {
138  if (!d.ignoreVolumeEvents) root.volumeDownTriggered();
139  d.volumeDownKeyPressed = false;
140  if (!d.volumeUpKeyPressed) d.ignoreVolumeEvents = false;
141  } else if (event.key == Qt.Key_VolumeUp) {
142  if (!d.ignoreVolumeEvents) root.volumeUpTriggered();
143  d.volumeUpKeyPressed = false;
144  if (!d.volumeDownKeyPressed) d.ignoreVolumeEvents = false;
145  } else if (event.key == Qt.Key_Alt || (root.controlInsteadOfAlt && event.key == Qt.Key_Control)) {
146  if (d.altTabPressed) {
147  d.altTabPressed = false;
148  event.accepted = true;
149  }
150  d.altPressed = false;
151  } else if (event.key == Qt.Key_Tab) {
152  if (d.altTabPressed) {
153  event.accepted = true;
154  }
155  } else if (event.key == Qt.Key_Super_L || event.key == Qt.Key_Super_R || (root.controlInsteadOfSuper && event.key == Qt.Key_Control)) {
156  d.superPressed = false;
157  if (d.superTabPressed) {
158  d.superTabPressed = false;
159  event.accepted = true;
160  }
161  }
162  }
163 }