on xenial help sign in
Enable the PIN lockscreen to be used with a HW keyboard Fixes: #1550359
8391b0aLukáš Tinkl
qml/Components/Lockscreen.qml+80−94
@@ -121,108 +121,94 @@ Showable {
121 opacity: root.darkenBackground
121 opacity: root.darkenBackground
122 }
122 }
123
123
124− MouseArea {
124+ Loader {
125− anchors.fill: root
125+ id: pinPadLoader
126− onClicked: {
126+ objectName: "pinPadLoader"
127− if (pinPadLoader.item)
128− pinPadLoader.item.forceActiveFocus()
129− }
130− }
131−
132− FocusScope {
133− id: loaderScope
134 anchors.fill: parent
127 anchors.fill: parent
135−
136− Loader {
137− id: pinPadLoader
138− objectName: "pinPadLoader"
139− anchors.fill: parent
140− property bool resetting: false
128+ property bool resetting: false
141− property bool waiting: false
129+ property bool waiting: false
142− property bool showWrongText: false
130+ property bool showWrongText: false
143−
131+ focus: true
132+
144− source: {
133+ source: {
145− if (resetting || !root.required) {
134+ if (resetting || !root.required) {
146− return ""
135+ return ""
147− } else if (root.delayMinutes > 0) {
136+ } else if (root.delayMinutes > 0) {
148− return "DelayedLockscreen.qml"
137+ return "DelayedLockscreen.qml"
149− } else if (root.alphaNumeric) {
138+ } else if (root.alphaNumeric) {
150− return "PassphraseLockscreen.qml"
139+ return "PassphraseLockscreen.qml"
151− } else {
140+ } else {
152− return "PinLockscreen.qml"
141+ return "PinLockscreen.qml"
153− }
154− }
155− onSourceChanged: {
156− waiting = false
157− showWrongText = false
158− if (loaderScope.activeFocus && pinPadLoader.item)
159− pinPadLoader.item.forceActiveFocus()
160 }
142 }
143+ }
144+ onSourceChanged: {
145+ waiting = false
146+ showWrongText = false
147+ }
161
148
162− Connections {
149+ Connections {
163− target: pinPadLoader.item
150+ target: pinPadLoader.item
164−
165− onEntered: {
166− pinPadLoader.waiting = true
167− root.entered(passphrase);
168− }
169
151
170− onCancel: {
152+ onEntered: {
171− root.cancel()
153+ pinPadLoader.waiting = true
172− }
154+ root.entered(passphrase);
173 }
155 }
174
156
175− Binding {
157+ onCancel: {
176− target: pinPadLoader.item
158+ root.cancel()
177− property: "minPinLength"
178− value: root.minPinLength
179− }
180− Binding {
181− target: pinPadLoader.item
182− property: "maxPinLength"
183− value: root.maxPinLength
184− }
185− Binding {
186− target: pinPadLoader.item
187− property: "infoText"
188− value: root.infoText
189− }
190− Binding {
191− target: pinPadLoader.item
192− property: "retryText"
193− value: root.retryText
194− }
195− Binding {
196− target: pinPadLoader.item
197− property: "errorText"
198− value: pinPadLoader.showWrongText ? root.errorText : ""
199− }
200− Binding {
201− target: pinPadLoader.item
202− property: "entryEnabled"
203− value: !pinPadLoader.waiting
204− }
205− Binding {
206− target: pinPadLoader.item
207− property: "alphaNumeric"
208− value: root.alphaNumeric
209− }
210− Binding {
211− target: pinPadLoader.item
212− property: "delayMinutes"
213− value: root.delayMinutes
214− }
215− Binding {
216− target: pinPadLoader.item
217− property: "showCancelButton"
218− value: root.showCancelButton
219− }
220− Binding {
221− target: pinPadLoader.item
222− property: "foregroundColor"
223− value: root.foregroundColor
224 }
159 }
225 }
160 }
161+
162+ Binding {
163+ target: pinPadLoader.item
164+ property: "minPinLength"
165+ value: root.minPinLength
166+ }
167+ Binding {
168+ target: pinPadLoader.item
169+ property: "maxPinLength"
170+ value: root.maxPinLength
171+ }
172+ Binding {
173+ target: pinPadLoader.item
174+ property: "infoText"
175+ value: root.infoText
176+ }
177+ Binding {
178+ target: pinPadLoader.item
179+ property: "retryText"
180+ value: root.retryText
181+ }
182+ Binding {
183+ target: pinPadLoader.item
184+ property: "errorText"
185+ value: pinPadLoader.showWrongText ? root.errorText : ""
186+ }
187+ Binding {
188+ target: pinPadLoader.item
189+ property: "entryEnabled"
190+ value: !pinPadLoader.waiting
191+ }
192+ Binding {
193+ target: pinPadLoader.item
194+ property: "alphaNumeric"
195+ value: root.alphaNumeric
196+ }
197+ Binding {
198+ target: pinPadLoader.item
199+ property: "delayMinutes"
200+ value: root.delayMinutes
201+ }
202+ Binding {
203+ target: pinPadLoader.item
204+ property: "showCancelButton"
205+ value: root.showCancelButton
206+ }
207+ Binding {
208+ target: pinPadLoader.item
209+ property: "foregroundColor"
210+ value: root.foregroundColor
211+ }
226 }
212 }
227
213
228 Item {
214 Item {
qml/Components/PassphraseLockscreen.qml+5−4
@@ -18,10 +18,11 @@ import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import "../Components"
19import "../Components"
20
20
21−Item {
21+FocusScope {
22 id: root
22 id: root
23 y: units.gu(4)
23 y: units.gu(4)
24 height: shakeContainer.height
24 height: shakeContainer.height
25+ focus: true
25
26
26 property string infoText
27 property string infoText
27 property string errorText
28 property string errorText
@@ -42,8 +43,6 @@ Item {
42 }
43 }
43 }
44 }
44
45
45− onActiveFocusChanged: if (activeFocus) pinentryField.forceActiveFocus()
46−
47 Column {
46 Column {
48 id: shakeContainer
47 id: shakeContainer
49 anchors.horizontalCenter: parent.horizontalCenter
48 anchors.horizontalCenter: parent.horizontalCenter
@@ -59,14 +58,16 @@ Item {
59 text: root.infoText
58 text: root.infoText
60 }
59 }
61
60
62− Item {
61+ FocusScope {
63 id: entryContainer
62 id: entryContainer
64 anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
63 anchors { left: parent.left; right: parent.right; margins: units.gu(2) }
65 height: units.gu(4)
64 height: units.gu(4)
65+ focus: true
66
66
67 TextInput {
67 TextInput {
68 id: pinentryField
68 id: pinentryField
69 objectName: "pinentryField"
69 objectName: "pinentryField"
70+ focus: true
70
71
71 property bool incorrectOverride: false
72 property bool incorrectOverride: false
72
73
qml/Components/PinLockscreen.qml+22−1
@@ -19,8 +19,9 @@ import Ubuntu.Components 1.3
19import Ubuntu.Components.ListItems 1.3
19import Ubuntu.Components.ListItems 1.3
20import "../Components"
20import "../Components"
21
21
22−Item {
22+FocusScope {
23 id: root
23 id: root
24+ focus: true
24
25
25 property string infoText
26 property string infoText
26 property string retryText
27 property string retryText
@@ -45,6 +46,24 @@ Item {
45 }
46 }
46 }
47 }
47
48
49+ Keys.onPressed: {
50+ if (pinentryField.text.length == root.maxPinLength)
51+ return;
52+
53+ if (event.key === Qt.Key_Backspace) {
54+ pinentryField.backspace();
55+ } else if (event.key === Qt.Key_Delete || event.key === Qt.Key_Escape) {
56+ closeButton.clicked()
57+ } else if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
58+ confirmButton.clicked()
59+ } else {
60+ var digit = parseInt(event.text);
61+ if (!isNaN(digit) && typeof digit == "number") {
62+ pinentryField.appendNumber(digit);
63+ }
64+ }
65+ }
66+
48 Column {
67 Column {
49 anchors {
68 anchors {
50 left: parent.left;
69 left: parent.left;
@@ -204,6 +223,7 @@ Item {
204 width: numbersGrid.buttonWidth
223 width: numbersGrid.buttonWidth
205 }
224 }
206 PinPadButton {
225 PinPadButton {
226+ id: closeButton
207 iconName: "close"
227 iconName: "close"
208 height: units.gu(5) // visual spec has this row a little closer in
228 height: units.gu(5) // visual spec has this row a little closer in
209 width: numbersGrid.buttonWidth
229 width: numbersGrid.buttonWidth
@@ -216,6 +236,7 @@ Item {
216 width: numbersGrid.buttonWidth
236 width: numbersGrid.buttonWidth
217 }
237 }
218 PinPadButton {
238 PinPadButton {
239+ id: confirmButton
219 iconName: "tick"
240 iconName: "tick"
220 objectName: "confirmButton"
241 objectName: "confirmButton"
221 height: units.gu(5)
242 height: units.gu(5)
qml/Greeter/NarrowView.qml+12
@@ -125,6 +125,18 @@ FocusScope {
125 onCancel: coverPage.show()
125 onCancel: coverPage.show()
126 onEmergencyCall: root.emergencyCall()
126 onEmergencyCall: root.emergencyCall()
127
127
128+ onEnabledChanged: {
129+ if (enabled) {
130+ lockscreen.forceActiveFocus();
131+ }
132+ }
133+
134+ onVisibleChanged: {
135+ if (visible) {
136+ lockscreen.forceActiveFocus();
137+ }
138+ }
139+
128 function maybeShow() {
140 function maybeShow() {
129 if (root.locked && !shown) {
141 if (root.locked && !shown) {
130 showNow();
142 showNow();
tests/qmltests/Components/tst_Lockscreen.qml+14−7
@@ -235,11 +235,14 @@ Rectangle {
235
235
236 function test_unlock_data() {
236 function test_unlock_data() {
237 return [
237 return [
238− {tag: "numeric", alphanumeric: false, password: "1234", minPinLength: 4, maxPinLength: 4},
238+ {tag: "numeric", alphanumeric: false, password: "1234", minPinLength: 4, maxPinLength: 4, keyboard: false},
239− {tag: "alphanumeric", alphanumeric: true, password: "password", minPinLength: -1, maxPinLength: -1},
239+ {tag: "alphanumeric", alphanumeric: true, password: "password", minPinLength: -1, maxPinLength: -1, keyboard: false},
240− {tag: "numeric (wrong)", alphanumeric: false, password: "4321", minPinLength: 4, maxPinLength: 4},
240+ {tag: "numeric (wrong)", alphanumeric: false, password: "4321", minPinLength: 4, maxPinLength: 4, keyboard: false},
241− {tag: "alphanumeric (wrong)", alphanumeric: true, password: "drowssap", minPinLength: -1, maxPinLength: -1},
241+ {tag: "alphanumeric (wrong)", alphanumeric: true, password: "drowssap", minPinLength: -1, maxPinLength: -1, keyboard: false},
242− {tag: "flexible length", alphanumeric: false, password: "1234", minPinLength: -1, maxPinLength: -1},
242+ {tag: "flexible length", alphanumeric: false, password: "1234", minPinLength: -1, maxPinLength: -1, keyboard: false},
243+ {tag: "numeric", alphanumeric: false, password: "1234", minPinLength: 4, maxPinLength: 4, keyboard: true},
244+ {tag: "numeric (wrong)", alphanumeric: false, password: "4321", minPinLength: 4, maxPinLength: 4, keyboard: true},
245+ {tag: "flexible length", alphanumeric: false, password: "1234", minPinLength: -1, maxPinLength: -1, keyboard: true}
243 ]
246 ]
244 }
247 }
245
248
@@ -259,8 +262,12 @@ Rectangle {
259 } else {
262 } else {
260 for (var i = 0; i < data.password.length; ++i) {
263 for (var i = 0; i < data.password.length; ++i) {
261 var character = data.password.charAt(i)
264 var character = data.password.charAt(i)
265+ if (data.keyboard) {
266+ typeString(character)
267+ } else {
262− var button = findChild(lockscreen, "pinPadButton" + character)
268+ var button = findChild(lockscreen, "pinPadButton" + character)
263− mouseClick(button, units.gu(1), units.gu(1))
269+ mouseClick(button, units.gu(1), units.gu(1))
270+ }
264 }
271 }
265 var confirmButton = findChild(lockscreen, "confirmButton");
272 var confirmButton = findChild(lockscreen, "confirmButton");
266 mouseClick(confirmButton, units.gu(1), units.gu(1));
273 mouseClick(confirmButton, units.gu(1), units.gu(1));