Merge lp:~bfiller/ubuntu-keyboard/back-to-rev-44 into lp:ubuntu-keyboard
- back-to-rev-44
- Merge into trunk
Proposed by
Bill Filler
Status: | Merged |
---|---|
Approved by: | Bill Filler |
Approved revision: | 49 |
Merged at revision: | 47 |
Proposed branch: | lp:~bfiller/ubuntu-keyboard/back-to-rev-44 |
Merge into: | lp:ubuntu-keyboard |
Diff against target: |
947 lines (+449/-238) 10 files modified
data/data.pro (+4/-1) data/schemas/com.canonical.keyboard.maliit.gschema.xml (+30/-0) debian/changelog (+8/-4) debian/ubuntu-keyboard-data.install (+1/-0) qml/KeyboardContainer.qml (+2/-0) tests/autopilot/ubuntu_keyboard/emulators/__init__.py (+6/-0) tests/autopilot/ubuntu_keyboard/emulators/key.py (+33/-0) tests/autopilot/ubuntu_keyboard/emulators/keyboard.py (+164/-211) tests/autopilot/ubuntu_keyboard/emulators/keypad.py (+174/-0) tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py (+27/-22) |
To merge this branch: | bzr merge lp:~bfiller/ubuntu-keyboard/back-to-rev-44 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bill Filler (community) | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email:
|
Commit message
revert back to rev 44
Description of the change
revert back to rev 44
To post a comment you must log in.
- 48. By Bill Filler
-
fix changelog
- 49. By Bill Filler
-
fix changelog
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'data/data.pro' | |||
2 | --- data/data.pro 2013-09-26 10:08:30 +0000 | |||
3 | +++ data/data.pro 2013-09-26 16:09:59 +0000 | |||
4 | @@ -8,10 +8,13 @@ | |||
5 | 8 | # make it available for testing, not intended for proper release though: | 8 | # make it available for testing, not intended for proper release though: |
6 | 9 | languages.files += languages/debug/showcase.xml | 9 | languages.files += languages/debug/showcase.xml |
7 | 10 | 10 | ||
8 | 11 | schemas.path = $${PREFIX}/share/glib-2.0/schemas | ||
9 | 12 | schemas.files = schemas/*.gschema.xml | ||
10 | 13 | |||
11 | 11 | styles.path = $${UBUNTU_KEYBOARD_DATA_DIR} | 14 | styles.path = $${UBUNTU_KEYBOARD_DATA_DIR} |
12 | 12 | styles.files = styles | 15 | styles.files = styles |
13 | 13 | 16 | ||
15 | 14 | INSTALLS += languages styles | 17 | INSTALLS += languages schemas styles |
16 | 15 | 18 | ||
17 | 16 | QMAKE_EXTRA_TARGETS += check | 19 | QMAKE_EXTRA_TARGETS += check |
18 | 17 | check.target = check | 20 | check.target = check |
19 | 18 | 21 | ||
20 | === added directory 'data/schemas' | |||
21 | === added file 'data/schemas/com.canonical.keyboard.maliit.gschema.xml' | |||
22 | --- data/schemas/com.canonical.keyboard.maliit.gschema.xml 1970-01-01 00:00:00 +0000 | |||
23 | +++ data/schemas/com.canonical.keyboard.maliit.gschema.xml 2013-09-26 16:09:59 +0000 | |||
24 | @@ -0,0 +1,30 @@ | |||
25 | 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
26 | 2 | <schemalist> | ||
27 | 3 | <schema id="com.canonical.keyboard.maliit" path="/com/canonical/keyboard/maliit/"> | ||
28 | 4 | <key name="enabled-languages" type="as"> | ||
29 | 5 | <summary>Enabled languages</summary> | ||
30 | 6 | <description>User-defined list of activatable languages.</description> | ||
31 | 7 | <default>[]</default> | ||
32 | 8 | </key> | ||
33 | 9 | <key name="auto-capitalization" type="b"> | ||
34 | 10 | <summary>Auto-capitalization</summary> | ||
35 | 11 | <description>Capitalize the first letter of each sentence.</description> | ||
36 | 12 | <default>true</default> | ||
37 | 13 | </key> | ||
38 | 14 | <key name="auto-completion" type="b"> | ||
39 | 15 | <summary>Auto-completion</summary> | ||
40 | 16 | <description>Complete current word with first suggestion when hitting space.</description> | ||
41 | 17 | <default>true</default> | ||
42 | 18 | </key> | ||
43 | 19 | <key name="predictive-text" type="b"> | ||
44 | 20 | <summary>Predictive text</summary> | ||
45 | 21 | <description>Suggest potential words in word ribbon.</description> | ||
46 | 22 | <default>true</default> | ||
47 | 23 | </key> | ||
48 | 24 | <key name="key-press-feedback" type="b"> | ||
49 | 25 | <summary>Key press feedback</summary> | ||
50 | 26 | <description>Vibrate or emit sound on key press.</description> | ||
51 | 27 | <default>true</default> | ||
52 | 28 | </key> | ||
53 | 29 | </schema> | ||
54 | 30 | </schemalist> | ||
55 | 0 | 31 | ||
56 | === modified file 'debian/changelog' | |||
57 | --- debian/changelog 2013-09-26 10:37:17 +0000 | |||
58 | +++ debian/changelog 2013-09-26 16:09:59 +0000 | |||
59 | @@ -1,7 +1,11 @@ | |||
60 | 1 | ubuntu-keyboard (0.99.trunk.phablet2+13.10.20130926-0ubuntu1) saucy; urgency=low | 1 | ubuntu-keyboard (0.99.trunk.phablet2+13.10.20130926-0ubuntu1) saucy; urgency=low |
62 | 2 | 2 | ||
63 | 3 | [ Ubuntu daily release ] | 3 | [ Ubuntu daily release ] |
65 | 4 | * New rebuild forced | 4 | * New rebuild forced from rev 45 |
66 | 5 | |||
67 | 6 | -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 26 Sep 2013 10:37:17 +0000 | ||
68 | 7 | |||
69 | 8 | ubuntu-keyboard (0.99.trunk.phablet2+13.10.20130925-0ubuntu1) saucy; urgency=low | ||
70 | 5 | 9 | ||
71 | 6 | [ William Hua ] | 10 | [ William Hua ] |
72 | 7 | * Add GSettings schema file. | 11 | * Add GSettings schema file. |
73 | @@ -11,9 +15,9 @@ | |||
74 | 11 | (moving more UI code to QML). | 15 | (moving more UI code to QML). |
75 | 12 | 16 | ||
76 | 13 | [ Ubuntu daily release ] | 17 | [ Ubuntu daily release ] |
78 | 14 | * Automatic snapshot from revision 45 | 18 | * Automatic snapshot from revision 43 |
79 | 15 | 19 | ||
81 | 16 | -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Thu, 26 Sep 2013 10:37:17 +0000 | 20 | -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 25 Sep 2013 11:05:45 +0000 |
82 | 17 | 21 | ||
83 | 18 | ubuntu-keyboard (0.99.trunk.phablet2+13.10.20130920-0ubuntu1) saucy; urgency=low | 22 | ubuntu-keyboard (0.99.trunk.phablet2+13.10.20130920-0ubuntu1) saucy; urgency=low |
84 | 19 | 23 | ||
85 | 20 | 24 | ||
86 | === modified file 'debian/ubuntu-keyboard-data.install' | |||
87 | --- debian/ubuntu-keyboard-data.install 2013-09-26 10:08:30 +0000 | |||
88 | +++ debian/ubuntu-keyboard-data.install 2013-09-26 16:09:59 +0000 | |||
89 | @@ -1,1 +1,2 @@ | |||
90 | 1 | usr/share/glib-2.0/schemas/ | ||
91 | 1 | usr/share/maliit/plugins/com/ubuntu/ | 2 | usr/share/maliit/plugins/com/ubuntu/ |
92 | 2 | 3 | ||
93 | === modified file 'qml/KeyboardContainer.qml' | |||
94 | --- qml/KeyboardContainer.qml 2013-09-26 10:08:30 +0000 | |||
95 | +++ qml/KeyboardContainer.qml 2013-09-26 16:09:59 +0000 | |||
96 | @@ -47,6 +47,7 @@ | |||
97 | 47 | 47 | ||
98 | 48 | Loader { | 48 | Loader { |
99 | 49 | id: characterKeypadLoader | 49 | id: characterKeypadLoader |
100 | 50 | objectName: "characterKeyPadLoader" | ||
101 | 50 | anchors.fill: parent | 51 | anchors.fill: parent |
102 | 51 | asynchronous: true | 52 | asynchronous: true |
103 | 52 | source: "languages/Keyboard_en_us.qml" | 53 | source: "languages/Keyboard_en_us.qml" |
104 | @@ -59,6 +60,7 @@ | |||
105 | 59 | 60 | ||
106 | 60 | Loader { | 61 | Loader { |
107 | 61 | id: symbolKeypadLoader | 62 | id: symbolKeypadLoader |
108 | 63 | objectName: "symbolKeyPadLoader" | ||
109 | 62 | anchors.fill: parent | 64 | anchors.fill: parent |
110 | 63 | asynchronous: true | 65 | asynchronous: true |
111 | 64 | } | 66 | } |
112 | 65 | 67 | ||
113 | === modified file 'tests/autopilot/ubuntu_keyboard/emulators/__init__.py' | |||
114 | --- tests/autopilot/ubuntu_keyboard/emulators/__init__.py 2013-09-26 10:08:30 +0000 | |||
115 | +++ tests/autopilot/ubuntu_keyboard/emulators/__init__.py 2013-09-26 16:09:59 +0000 | |||
116 | @@ -16,3 +16,9 @@ | |||
117 | 16 | # You should have received a copy of the GNU General Public License | 16 | # You should have received a copy of the GNU General Public License |
118 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
119 | 18 | # | 18 | # |
120 | 19 | |||
121 | 20 | from autopilot.introspection import CustomEmulatorBase | ||
122 | 21 | |||
123 | 22 | |||
124 | 23 | class UbuntuKeyboardEmulatorBase(CustomEmulatorBase): | ||
125 | 24 | """A base class for all Ubuntu Keyboard emulators.""" | ||
126 | 19 | 25 | ||
127 | === added file 'tests/autopilot/ubuntu_keyboard/emulators/key.py' | |||
128 | --- tests/autopilot/ubuntu_keyboard/emulators/key.py 1970-01-01 00:00:00 +0000 | |||
129 | +++ tests/autopilot/ubuntu_keyboard/emulators/key.py 2013-09-26 16:09:59 +0000 | |||
130 | @@ -0,0 +1,33 @@ | |||
131 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
132 | 2 | # | ||
133 | 3 | # Ubuntu Keyboard Test Suite | ||
134 | 4 | # Copyright (C) 2013 Canonical | ||
135 | 5 | # | ||
136 | 6 | # This program is free software: you can redistribute it and/or modify | ||
137 | 7 | # it under the terms of the GNU General Public License as published by | ||
138 | 8 | # the Free Software Foundation, either version 3 of the License, or | ||
139 | 9 | # (at your option) any later version. | ||
140 | 10 | # | ||
141 | 11 | # This program is distributed in the hope that it will be useful, | ||
142 | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
143 | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
144 | 14 | # GNU General Public License for more details. | ||
145 | 15 | # | ||
146 | 16 | # You should have received a copy of the GNU General Public License | ||
147 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
148 | 18 | # | ||
149 | 19 | |||
150 | 20 | from ubuntu_keyboard.emulators import UbuntuKeyboardEmulatorBase | ||
151 | 21 | |||
152 | 22 | from collections import namedtuple | ||
153 | 23 | import logging | ||
154 | 24 | |||
155 | 25 | logger = logging.getLogger(__name__) | ||
156 | 26 | |||
157 | 27 | |||
158 | 28 | class Key(UbuntuKeyboardEmulatorBase): | ||
159 | 29 | """An emulator that encapsulates details of a keyboard key (i.e. extended | ||
160 | 30 | characters). | ||
161 | 31 | |||
162 | 32 | """ | ||
163 | 33 | Pos = namedtuple("KeyPosition", ['x', 'y', 'w', 'h']) | ||
164 | 0 | 34 | ||
165 | === modified file 'tests/autopilot/ubuntu_keyboard/emulators/keyboard.py' | |||
166 | --- tests/autopilot/ubuntu_keyboard/emulators/keyboard.py 2013-09-26 10:08:30 +0000 | |||
167 | +++ tests/autopilot/ubuntu_keyboard/emulators/keyboard.py 2013-09-26 16:09:59 +0000 | |||
168 | @@ -17,7 +17,9 @@ | |||
169 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
170 | 18 | # | 18 | # |
171 | 19 | 19 | ||
173 | 20 | from collections import defaultdict, namedtuple | 20 | from ubuntu_keyboard.emulators import UbuntuKeyboardEmulatorBase |
174 | 21 | from ubuntu_keyboard.emulators.keypad import KeyPad | ||
175 | 22 | |||
176 | 21 | from time import sleep | 23 | from time import sleep |
177 | 22 | import logging | 24 | import logging |
178 | 23 | 25 | ||
179 | @@ -31,70 +33,69 @@ | |||
180 | 31 | logger = logging.getLogger(__name__) | 33 | logger = logging.getLogger(__name__) |
181 | 32 | 34 | ||
182 | 33 | 35 | ||
202 | 34 | # Definitions of enums used within the cpp source code. | 36 | class KeyPadNotLoaded(Exception): |
203 | 35 | class KeyboardState: | 37 | pass |
204 | 36 | DEFAULT = 0 | 38 | |
205 | 37 | SHIFTED = 1 | 39 | |
206 | 38 | SYMBOL_1 = 2 | 40 | class QQuickLoader(UbuntuKeyboardEmulatorBase): |
207 | 39 | SYMBOL_2 = 3 | 41 | # This is a work around so that when we select_single a KeyPad we don't get |
208 | 40 | 42 | # back a generic version. | |
190 | 41 | |||
191 | 42 | class KeyAction: | ||
192 | 43 | INSERT = 0 | ||
193 | 44 | SHIFT = 1 | ||
194 | 45 | BACKSPACE = 2 | ||
195 | 46 | SPACE = 3 | ||
196 | 47 | SYM = 6 | ||
197 | 48 | RETURN = 7 | ||
198 | 49 | SWITCH = 11 | ||
199 | 50 | |||
200 | 51 | |||
201 | 52 | class UnsupportedKey(RuntimeError): | ||
209 | 53 | pass | 43 | pass |
210 | 54 | 44 | ||
211 | 55 | 45 | ||
212 | 56 | class Keyboard(object): | 46 | class Keyboard(object): |
213 | 57 | 47 | ||
231 | 58 | KeyPos = namedtuple("KeyPos", ['x', 'y', 'h', 'w']) | 48 | _action_to_label = { |
232 | 59 | 49 | 'SHIFT': 'shift', | |
233 | 60 | # Note (veebers 19-aug-13): this hardcoded right now, but will be reading | 50 | '\b': 'backspace', |
234 | 61 | # data from the keyboard itself in the very near future. Moved '/' to | 51 | 'ABC': 'symbols', |
235 | 62 | # primary symbol, default layout can have a .com instead. | 52 | '?123': 'symbols', |
236 | 63 | default_keys = "qwertyuiopasdfghjklzxcvbnm." | 53 | ' ': 'space', |
237 | 64 | shifted_keys = "QWERTYUIOPASDFGHJKLZXCVBNM." | 54 | '\n': 'return', |
221 | 65 | primary_symbol = "1234567890*#+-=()!?@~/\\';:,." | ||
222 | 66 | secondary_symbol = u"$%<>[]`^|_{}\"&,.\u20ac\xa3\xa5\u20b9\xa7\xa1\xbf" \ | ||
223 | 67 | u"\xab\xbb\u201c\u201d\u201e" | ||
224 | 68 | |||
225 | 69 | # The ability to name the non-text keys. | ||
226 | 70 | _action_id_to_text = { | ||
227 | 71 | KeyAction.SHIFT: 'SHIFT', | ||
228 | 72 | KeyAction.BACKSPACE: '\b', | ||
229 | 73 | KeyAction.SPACE: ' ', | ||
230 | 74 | KeyAction.RETURN: '\n' | ||
238 | 75 | } | 55 | } |
239 | 76 | 56 | ||
240 | 57 | # mallit is a class attribute because get_proxy_object_for_existing_process | ||
241 | 58 | # clears backends for proxy objects, this means that with: | ||
242 | 59 | # kb = Keyboard() | ||
243 | 60 | # kb2 = Keyboard() | ||
244 | 61 | # The proxy objects in kb have had their _Backends cleared which means we | ||
245 | 62 | # can no longer query them. | ||
246 | 63 | try: | ||
247 | 64 | maliit = get_proxy_object_for_existing_process( | ||
248 | 65 | connection_name='org.maliit.server', | ||
249 | 66 | emulator_base=UbuntuKeyboardEmulatorBase | ||
250 | 67 | ) | ||
251 | 68 | except ProcessSearchError as e: | ||
252 | 69 | e.args += ( | ||
253 | 70 | "Unable to find maliit-server dbus object. Has it been " | ||
254 | 71 | "started with introspection enabled?", | ||
255 | 72 | ) | ||
256 | 73 | raise | ||
257 | 74 | |||
258 | 77 | def __init__(self, pointer=None): | 75 | def __init__(self, pointer=None): |
259 | 78 | try: | 76 | try: |
262 | 79 | maliit = get_proxy_object_for_existing_process( | 77 | self.orientation = Keyboard.maliit.select_single( |
263 | 80 | connection_name='org.maliit.server' | 78 | "OrientationHelper" |
264 | 81 | ) | 79 | ) |
266 | 82 | except ProcessSearchError as e: | 80 | if self.orientation is None: |
267 | 81 | raise RuntimeError( | ||
268 | 82 | "Unable to find the Orientation Helper, aborting." | ||
269 | 83 | ) | ||
270 | 84 | except ValueError as e: | ||
271 | 83 | e.args += ( | 85 | e.args += ( |
274 | 84 | "Unable to find maliit-server dbus object. Has it been " | 86 | "More than one OrientationHelper object was found, aborting." |
273 | 85 | "started with introspection enabled?", | ||
275 | 86 | ) | 87 | ) |
276 | 87 | raise | 88 | raise |
277 | 88 | 89 | ||
278 | 89 | try: | 90 | try: |
281 | 90 | self.keyboard = maliit.select_single( | 91 | self.keyboard = Keyboard.maliit.select_single( |
282 | 91 | "Keyboard", | 92 | "QQuickItem", |
283 | 92 | objectName="ubuntuKeyboard" | 93 | objectName="ubuntuKeyboard" |
284 | 93 | ) | 94 | ) |
285 | 94 | if self.keyboard is None: | 95 | if self.keyboard is None: |
286 | 95 | raise RuntimeError( | 96 | raise RuntimeError( |
287 | 96 | "Unable to find the Ubuntu Keyboard object within the " | 97 | "Unable to find the Ubuntu Keyboard object within the " |
289 | 97 | "maliit server" | 98 | "maliit server." |
290 | 98 | ) | 99 | ) |
291 | 99 | except ValueError as e: | 100 | except ValueError as e: |
292 | 100 | e.args += ( | 101 | e.args += ( |
293 | @@ -102,35 +103,54 @@ | |||
294 | 102 | ) | 103 | ) |
295 | 103 | raise | 104 | raise |
296 | 104 | 105 | ||
320 | 105 | try: | 106 | self._character_keypad = None |
321 | 106 | self.keypad = self.keyboard.select_single( | 107 | self._symbol_keypad = None |
322 | 107 | "QQuickItem", | 108 | |
323 | 108 | objectName="keyboardKeypad" | 109 | self._store_current_orientation() |
324 | 109 | ) | 110 | self._store_current_language_id() |
302 | 110 | |||
303 | 111 | if self.keypad is None: | ||
304 | 112 | raise RuntimeError( | ||
305 | 113 | "Unable to find the keypad object within the " | ||
306 | 114 | "maliit server" | ||
307 | 115 | ) | ||
308 | 116 | except ValueError as e: | ||
309 | 117 | e.args += ( | ||
310 | 118 | "There was more than one keyboard keypad object found, " | ||
311 | 119 | "aborting.", | ||
312 | 120 | ) | ||
313 | 121 | raise | ||
314 | 122 | |||
315 | 123 | # Contains instructions on how to move the keyboard into a specific | ||
316 | 124 | # state/layout so that we can successfully press the required key. | ||
317 | 125 | self._state_lookup_table = self._generate_state_lookup_table() | ||
318 | 126 | # Cache the position of the keys | ||
319 | 127 | self._key_pos_table = defaultdict(dict) | ||
325 | 128 | 111 | ||
326 | 129 | if pointer is None: | 112 | if pointer is None: |
327 | 130 | self.pointer = Pointer(Touch.create()) | 113 | self.pointer = Pointer(Touch.create()) |
328 | 131 | else: | 114 | else: |
329 | 132 | self.pointer = pointer | 115 | self.pointer = pointer |
330 | 133 | 116 | ||
331 | 117 | def _keyboard_details_changed(self): | ||
332 | 118 | return self._language_changed() or self._orientation_changed() | ||
333 | 119 | |||
334 | 120 | @property | ||
335 | 121 | def character_keypad(self): | ||
336 | 122 | if self._character_keypad is None or self._keyboard_details_changed(): | ||
337 | 123 | self._character_keypad = self._get_keypad("character") | ||
338 | 124 | return self._character_keypad | ||
339 | 125 | |||
340 | 126 | @property | ||
341 | 127 | def symbol_keypad(self): | ||
342 | 128 | if (self._symbol_keypad is None | ||
343 | 129 | or (self._language_changed() or self._orientation_changed())): | ||
344 | 130 | self._symbol_keypad = self._get_keypad("symbol") | ||
345 | 131 | |||
346 | 132 | return self._symbol_keypad | ||
347 | 133 | |||
348 | 134 | def _get_keypad(self, name): | ||
349 | 135 | """Attempt to retrieve KeyPad object of either 'character' or 'symbol' | ||
350 | 136 | |||
351 | 137 | *name* must be either 'character' or 'symbol'. | ||
352 | 138 | |||
353 | 139 | Raises KeyPadNotLoaded exception if none or more than one keypad is | ||
354 | 140 | found. | ||
355 | 141 | |||
356 | 142 | """ | ||
357 | 143 | objectName = "{name}KeyPadLoader".format(name=name) | ||
358 | 144 | loader = Keyboard.maliit.select_single( | ||
359 | 145 | QQuickLoader, | ||
360 | 146 | objectName=objectName | ||
361 | 147 | ) | ||
362 | 148 | keypad = loader.select_single(KeyPad) | ||
363 | 149 | if keypad is None: | ||
364 | 150 | raise KeyPadNotLoaded("{name} keypad is not currently loaded.") | ||
365 | 151 | |||
366 | 152 | return keypad | ||
367 | 153 | |||
368 | 134 | def dismiss(self): | 154 | def dismiss(self): |
369 | 135 | """Swipe the keyboard down to hide it. | 155 | """Swipe the keyboard down to hide it. |
370 | 136 | 156 | ||
371 | @@ -150,14 +170,20 @@ | |||
372 | 150 | 170 | ||
373 | 151 | def is_available(self): | 171 | def is_available(self): |
374 | 152 | """Returns true if the keyboard is shown and ready to use.""" | 172 | """Returns true if the keyboard is shown and ready to use.""" |
379 | 153 | return ( | 173 | return (self.keyboard.state == "SHOWN") |
376 | 154 | self.keyboard.state == "SHOWN" | ||
377 | 155 | and not self.keyboard.hideAnimationFinished | ||
378 | 156 | ) | ||
380 | 157 | 174 | ||
381 | 158 | @property | 175 | @property |
382 | 159 | def current_state(self): | 176 | def current_state(self): |
384 | 160 | return self.keyboard.layoutState | 177 | return self.keyboard.state |
385 | 178 | |||
386 | 179 | @property | ||
387 | 180 | def active_keypad(self): | ||
388 | 181 | if self.character_keypad.enabled: | ||
389 | 182 | return self.character_keypad | ||
390 | 183 | elif self.symbol_keypad.enabled: | ||
391 | 184 | return self.symbol_keypad | ||
392 | 185 | else: | ||
393 | 186 | raise RuntimeError("There are no currently active KeyPads.") | ||
394 | 161 | 187 | ||
395 | 162 | # Much like is_available, but attempts to wait for the keyboard to be | 188 | # Much like is_available, but attempts to wait for the keyboard to be |
396 | 163 | # ready. | 189 | # ready. |
397 | @@ -177,31 +203,6 @@ | |||
398 | 177 | except RuntimeError: | 203 | except RuntimeError: |
399 | 178 | return False | 204 | return False |
400 | 179 | 205 | ||
401 | 180 | def get_key_position(self, key): | ||
402 | 181 | """Returns the global rect of the given key. | ||
403 | 182 | |||
404 | 183 | It may need to do a lookup to update the table of positions. | ||
405 | 184 | |||
406 | 185 | """ | ||
407 | 186 | current_state = self.keyboard.layoutState | ||
408 | 187 | if self._key_pos_table.get(current_state) is None: | ||
409 | 188 | self._update_pos_table_for_current_state() | ||
410 | 189 | |||
411 | 190 | return self._key_pos_table[current_state][key] | ||
412 | 191 | |||
413 | 192 | def _update_pos_table_for_current_state(self): | ||
414 | 193 | all_keys = self.keypad.select_many('QQuickText') | ||
415 | 194 | current_state = self.keyboard.layoutState | ||
416 | 195 | labeled_keys = (KeyAction.INSERT, KeyAction.SWITCH, KeyAction.SYM) | ||
417 | 196 | for key in all_keys: | ||
418 | 197 | with key.no_automatic_refreshing(): | ||
419 | 198 | key_pos = Keyboard.KeyPos(*key.globalRect) | ||
420 | 199 | if key.action_type in labeled_keys: | ||
421 | 200 | self._key_pos_table[current_state][key.text] = key_pos | ||
422 | 201 | else: | ||
423 | 202 | key_text = Keyboard._action_id_to_text[key.action_type] | ||
424 | 203 | self._key_pos_table[current_state][key_text] = key_pos | ||
425 | 204 | |||
426 | 205 | def press_key(self, key): | 206 | def press_key(self, key): |
427 | 206 | """Tap on the key with the internal pointer | 207 | """Tap on the key with the internal pointer |
428 | 207 | 208 | ||
429 | @@ -209,18 +210,31 @@ | |||
430 | 209 | 210 | ||
431 | 210 | :raises: *RuntimeError* if the keyboard is not available and thus not | 211 | :raises: *RuntimeError* if the keyboard is not available and thus not |
432 | 211 | ready to be used. | 212 | ready to be used. |
434 | 212 | :raises: *UnsupportedKey* if the supplied key cannot be found on any of | 213 | :raises: *ValueError* if the supplied key cannot be found on any of |
435 | 213 | the the current keyboards layouts. | 214 | the the current keyboards layouts. |
436 | 214 | """ | 215 | """ |
437 | 215 | if not self.is_available(): | 216 | if not self.is_available(): |
438 | 216 | raise RuntimeError("Keyboard is not on screen") | 217 | raise RuntimeError("Keyboard is not on screen") |
439 | 217 | 218 | ||
446 | 218 | if not self._is_special_key(key): | 219 | key = self._translate_key(key) |
447 | 219 | required_state_for_key = self._get_keys_required_state(key) | 220 | active_keypad = None |
448 | 220 | self._switch_keyboard_to_state(required_state_for_key) | 221 | |
449 | 221 | 222 | try: | |
450 | 222 | key_rect = self.get_key_position(key) | 223 | if self.character_keypad.contains_key(key): |
451 | 223 | self.pointer.click_object(key_rect) | 224 | self._show_character_keypad() |
452 | 225 | active_keypad = self.character_keypad | ||
453 | 226 | elif self.symbol_keypad.contains_key(key): | ||
454 | 227 | self._show_symbol_keypad() | ||
455 | 228 | active_keypad = self.symbol_keypad | ||
456 | 229 | except KeyPadNotLoaded: | ||
457 | 230 | pass | ||
458 | 231 | |||
459 | 232 | if active_keypad is None: | ||
460 | 233 | raise ValueError( | ||
461 | 234 | "Key '%s' was not found on the keyboard." % key | ||
462 | 235 | ) | ||
463 | 236 | |||
464 | 237 | active_keypad.press_key(key) | ||
465 | 224 | 238 | ||
466 | 225 | def type(self, string, delay=0.1): | 239 | def type(self, string, delay=0.1): |
467 | 226 | """Type the string *string* with a delay of *delay* between each key | 240 | """Type the string *string* with a delay of *delay* between each key |
468 | @@ -231,7 +245,7 @@ | |||
469 | 231 | 245 | ||
470 | 232 | Only 'normal' or single characters can be typed this way. | 246 | Only 'normal' or single characters can be typed this way. |
471 | 233 | 247 | ||
473 | 234 | :raises: *UnsupportedKey* if one of the the supplied keys cannot be | 248 | :raises: *ValueError* if one of the the supplied keys cannot be |
474 | 235 | found on any of the the current keyboards layouts. | 249 | found on any of the the current keyboards layouts. |
475 | 236 | 250 | ||
476 | 237 | """ | 251 | """ |
477 | @@ -239,108 +253,47 @@ | |||
478 | 239 | self.press_key(char) | 253 | self.press_key(char) |
479 | 240 | sleep(delay) | 254 | sleep(delay) |
480 | 241 | 255 | ||
586 | 242 | def _get_keys_required_state(self, char): | 256 | def _orientation_changed(self): |
587 | 243 | """Given a character determine which state the keyboard needs to be in | 257 | if self._stored_orientation != self.orientation.orientationAngle: |
588 | 244 | so that it is visible and can be clicked. | 258 | self._store_current_orientation() |
589 | 245 | 259 | return True | |
590 | 246 | """ | 260 | else: |
591 | 247 | 261 | return False | |
592 | 248 | if char in Keyboard.default_keys: | 262 | |
593 | 249 | return KeyboardState.DEFAULT | 263 | def _language_changed(self): |
594 | 250 | elif char in Keyboard.shifted_keys: | 264 | if self._stored_language_id != self.keyboard.layoutId: |
595 | 251 | return KeyboardState.SHIFTED | 265 | self._store_current_language_id() |
596 | 252 | elif char in Keyboard.primary_symbol: | 266 | return True |
597 | 253 | return KeyboardState.SYMBOL_1 | 267 | else: |
598 | 254 | elif char in Keyboard.secondary_symbol: | 268 | return False |
599 | 255 | return KeyboardState.SYMBOL_2 | 269 | |
600 | 256 | else: | 270 | def _store_current_orientation(self): |
601 | 257 | raise UnsupportedKey( | 271 | self._stored_orientation = self.orientation.orientationAngle |
602 | 258 | "Don't know which state key '%s' requires" % char | 272 | |
603 | 259 | ) | 273 | def _store_current_language_id(self): |
604 | 260 | 274 | self._stored_language_id = self.keyboard.layoutId | |
605 | 261 | def _switch_keyboard_to_state(self, target_state): | 275 | |
606 | 262 | """Given a target_state, presses the required keys to bring the | 276 | def _show_character_keypad(self): |
607 | 263 | keyboard into the correct state. | 277 | """Brings the characters KeyPad to the forefront.""" |
608 | 264 | 278 | if not self.character_keypad.enabled: | |
609 | 265 | :raises: *RuntimeError* if unable to change the keyboard into the | 279 | # If the character keypad isn't enabled than the symbol keypad must |
610 | 266 | expected state. | 280 | # be active |
611 | 267 | 281 | self.symbol_keypad.press_key("symbols") | |
612 | 268 | """ | 282 | self.character_keypad.enabled.wait_for(True) |
613 | 269 | current_state = self.keyboard.layoutState | 283 | self.character_keypad.opacity.wait_for(1.0) |
614 | 270 | 284 | ||
615 | 271 | if target_state == current_state: | 285 | def _show_symbol_keypad(self): |
616 | 272 | return | 286 | """Brings the symbol KeyPad to the forefront.""" |
617 | 273 | 287 | if not self.symbol_keypad.enabled: | |
618 | 274 | instructions = self._state_lookup_table[target_state].get( | 288 | # If the symbol keypad isn't enabled than the character keypad must |
619 | 275 | current_state, | 289 | # be active |
620 | 276 | None | 290 | self.character_keypad.press_key("symbols") |
621 | 277 | ) | 291 | self.symbol_keypad.enabled.wait_for(True) |
622 | 278 | if instructions is None: | 292 | self.symbol_keypad.opacity.wait_for(1.0) |
623 | 279 | raise RuntimeError( | 293 | |
624 | 280 | "Don't know how to get to state %d from current state (%d)" | 294 | def _translate_key(self, label): |
625 | 281 | % (target_state, current_state) | 295 | """Get the label for a 'special key' (i.e. space) so that it can be |
626 | 282 | ) | 296 | addressed and clicked. |
627 | 283 | 297 | ||
628 | 284 | for step in instructions: | 298 | """ |
629 | 285 | key, expected_state = step | 299 | return Keyboard._action_to_label.get(label, label) |
525 | 286 | self.press_key(key) | ||
526 | 287 | self.keyboard.layoutState.wait_for(expected_state) | ||
527 | 288 | |||
528 | 289 | def _is_special_key(self, key): | ||
529 | 290 | return key in ["\n", "\b", " ", "SHIFT", "?123", "ABC", "1/2", "2/2"] | ||
530 | 291 | |||
531 | 292 | # Give the state that you want and the current state, get instructions on | ||
532 | 293 | # how to move to that state. | ||
533 | 294 | # lookup_table[REQUESTED_STATE][CURRENT_STATE] -> Instructions(Key to | ||
534 | 295 | # press, Expected state after key press.) | ||
535 | 296 | def _generate_state_lookup_table(self): | ||
536 | 297 | return { | ||
537 | 298 | KeyboardState.DEFAULT: { | ||
538 | 299 | KeyboardState.SHIFTED: [ | ||
539 | 300 | ("SHIFT", KeyboardState.DEFAULT) | ||
540 | 301 | ], | ||
541 | 302 | KeyboardState.SYMBOL_1: [ | ||
542 | 303 | ("ABC", KeyboardState.DEFAULT) | ||
543 | 304 | ], | ||
544 | 305 | KeyboardState.SYMBOL_2: [ | ||
545 | 306 | ("ABC", KeyboardState.DEFAULT) | ||
546 | 307 | ], | ||
547 | 308 | }, | ||
548 | 309 | KeyboardState.SHIFTED: { | ||
549 | 310 | KeyboardState.DEFAULT: [ | ||
550 | 311 | ("SHIFT", KeyboardState.SHIFTED) | ||
551 | 312 | ], | ||
552 | 313 | KeyboardState.SYMBOL_1: [ | ||
553 | 314 | ("ABC", KeyboardState.DEFAULT), | ||
554 | 315 | ("SHIFT", KeyboardState.SHIFTED) | ||
555 | 316 | ], | ||
556 | 317 | KeyboardState.SYMBOL_2: [ | ||
557 | 318 | ("ABC", KeyboardState.DEFAULT), | ||
558 | 319 | ("SHIFT", KeyboardState.SHIFTED) | ||
559 | 320 | ], | ||
560 | 321 | }, | ||
561 | 322 | KeyboardState.SYMBOL_1: { | ||
562 | 323 | KeyboardState.DEFAULT: [ | ||
563 | 324 | ("?123", KeyboardState.SYMBOL_1) | ||
564 | 325 | ], | ||
565 | 326 | KeyboardState.SHIFTED: [ | ||
566 | 327 | ("?123", KeyboardState.SYMBOL_1) | ||
567 | 328 | ], | ||
568 | 329 | KeyboardState.SYMBOL_2: [ | ||
569 | 330 | ("2/2", KeyboardState.SYMBOL_1) | ||
570 | 331 | ], | ||
571 | 332 | }, | ||
572 | 333 | KeyboardState.SYMBOL_2: { | ||
573 | 334 | KeyboardState.DEFAULT: [ | ||
574 | 335 | ("?123", KeyboardState.SYMBOL_1), | ||
575 | 336 | ("1/2", KeyboardState.SYMBOL_2) | ||
576 | 337 | ], | ||
577 | 338 | KeyboardState.SHIFTED: [ | ||
578 | 339 | ("?123", KeyboardState.SYMBOL_1), | ||
579 | 340 | ("1/2", KeyboardState.SYMBOL_2) | ||
580 | 341 | ], | ||
581 | 342 | KeyboardState.SYMBOL_1: [ | ||
582 | 343 | ("1/2", KeyboardState.SYMBOL_2) | ||
583 | 344 | ], | ||
584 | 345 | }, | ||
585 | 346 | } | ||
630 | 347 | 300 | ||
631 | === added file 'tests/autopilot/ubuntu_keyboard/emulators/keypad.py' | |||
632 | --- tests/autopilot/ubuntu_keyboard/emulators/keypad.py 1970-01-01 00:00:00 +0000 | |||
633 | +++ tests/autopilot/ubuntu_keyboard/emulators/keypad.py 2013-09-26 16:09:59 +0000 | |||
634 | @@ -0,0 +1,174 @@ | |||
635 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
636 | 2 | # | ||
637 | 3 | # Ubuntu Keyboard Test Suite | ||
638 | 4 | # Copyright (C) 2013 Canonical | ||
639 | 5 | # | ||
640 | 6 | # This program is free software: you can redistribute it and/or modify | ||
641 | 7 | # it under the terms of the GNU General Public License as published by | ||
642 | 8 | # the Free Software Foundation, either version 3 of the License, or | ||
643 | 9 | # (at your option) any later version. | ||
644 | 10 | # | ||
645 | 11 | # This program is distributed in the hope that it will be useful, | ||
646 | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
647 | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
648 | 14 | # GNU General Public License for more details. | ||
649 | 15 | # | ||
650 | 16 | # You should have received a copy of the GNU General Public License | ||
651 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
652 | 18 | # | ||
653 | 19 | |||
654 | 20 | from ubuntu_keyboard.emulators import UbuntuKeyboardEmulatorBase | ||
655 | 21 | from ubuntu_keyboard.emulators.key import Key | ||
656 | 22 | |||
657 | 23 | import logging | ||
658 | 24 | |||
659 | 25 | from autopilot.input import Pointer, Touch | ||
660 | 26 | from time import sleep | ||
661 | 27 | |||
662 | 28 | logger = logging.getLogger(__name__) | ||
663 | 29 | |||
664 | 30 | |||
665 | 31 | class CharKey(UbuntuKeyboardEmulatorBase): | ||
666 | 32 | pass | ||
667 | 33 | |||
668 | 34 | |||
669 | 35 | class ActionKey(UbuntuKeyboardEmulatorBase): | ||
670 | 36 | pass | ||
671 | 37 | |||
672 | 38 | |||
673 | 39 | class KeyPad(UbuntuKeyboardEmulatorBase): | ||
674 | 40 | """An emulator that understands the KeyPad and its internals and how to | ||
675 | 41 | interact with it. | ||
676 | 42 | |||
677 | 43 | - Which keys are displayed within it | ||
678 | 44 | - The positions of these keys | ||
679 | 45 | - The state (NORMAL/SHIFTED) the KeyPad is in | ||
680 | 46 | |||
681 | 47 | """ | ||
682 | 48 | |||
683 | 49 | class State: | ||
684 | 50 | NORMAL = "NORMAL" | ||
685 | 51 | SHIFTED = "SHIFTED" | ||
686 | 52 | CAPSLOCK = "CAPSLOCK" | ||
687 | 53 | |||
688 | 54 | def __init__(self, *args): | ||
689 | 55 | super(KeyPad, self).__init__(*args) | ||
690 | 56 | self._key_pos = dict() | ||
691 | 57 | self._contained_keys = [] | ||
692 | 58 | self._contained_shifted_keys = [] | ||
693 | 59 | |||
694 | 60 | self.update_key_details() | ||
695 | 61 | |||
696 | 62 | def contains_key(self, label): | ||
697 | 63 | """Returns true if a key with the label *label* is contained within | ||
698 | 64 | this KeyPad. | ||
699 | 65 | |||
700 | 66 | """ | ||
701 | 67 | return (label in self._contained_keys | ||
702 | 68 | or label in self._contained_shifted_keys) | ||
703 | 69 | |||
704 | 70 | def update_key_details(self): | ||
705 | 71 | def _iter_keys(key_type, label_fn): | ||
706 | 72 | for key in self.select_many(key_type): | ||
707 | 73 | with key.no_automatic_refreshing(): | ||
708 | 74 | key_pos = Key.Pos(*key.globalRect) | ||
709 | 75 | label = label_fn(key) | ||
710 | 76 | if label != '': | ||
711 | 77 | self._contained_keys.append(label) | ||
712 | 78 | self._key_pos[label] = key_pos | ||
713 | 79 | if key.shifted != '': | ||
714 | 80 | self._contained_shifted_keys.append(key.shifted) | ||
715 | 81 | self._key_pos[key.shifted] = key_pos | ||
716 | 82 | |||
717 | 83 | _iter_keys(CharKey, lambda x: x.label) | ||
718 | 84 | _iter_keys(ActionKey, lambda x: x.action) | ||
719 | 85 | |||
720 | 86 | def press_key(self, key, pointer=None): | ||
721 | 87 | """Taps key *key* with *pointer* | ||
722 | 88 | |||
723 | 89 | If no pointer is passed in one is created for this purpose | ||
724 | 90 | |||
725 | 91 | raises *ValueError* if *key* is not contained within this KeyPad. | ||
726 | 92 | raises *RuntimeError* if this KeyPad is not visible. | ||
727 | 93 | |||
728 | 94 | """ | ||
729 | 95 | if not self.contains_key(key): | ||
730 | 96 | raise ValueError( | ||
731 | 97 | "Key '%s' is not contained by this KeyPad (%s)," | ||
732 | 98 | " cannot press it." % (key, self.objectName) | ||
733 | 99 | ) | ||
734 | 100 | |||
735 | 101 | if not self.visible: | ||
736 | 102 | raise RuntimeError( | ||
737 | 103 | "This Keypad (%s) is not visible" % self.objectName | ||
738 | 104 | ) | ||
739 | 105 | |||
740 | 106 | required_state = self._get_keys_required_keypad_state(key) | ||
741 | 107 | |||
742 | 108 | self._switch_to_state(required_state, pointer) | ||
743 | 109 | |||
744 | 110 | key_rect = self.get_key_position(key) | ||
745 | 111 | self._tap_key(key_rect, pointer) | ||
746 | 112 | |||
747 | 113 | def get_key_position(self, key): | ||
748 | 114 | """Returns Key.Pos for the key with *key*. | ||
749 | 115 | |||
750 | 116 | raises *ValueError* if unable to find the stored position for *key* | ||
751 | 117 | (i.e. not contained within this KeyPad.) | ||
752 | 118 | |||
753 | 119 | """ | ||
754 | 120 | key_rect = self._key_pos.get(key) | ||
755 | 121 | |||
756 | 122 | if key_rect is None: | ||
757 | 123 | raise ValueError("Unknown position for key '%s'" % key) | ||
758 | 124 | |||
759 | 125 | return key_rect | ||
760 | 126 | |||
761 | 127 | def _get_keys_required_keypad_state(self, key): | ||
762 | 128 | if key in ('shift', 'backspace', 'symbols', 'space', 'return'): | ||
763 | 129 | return self.state | ||
764 | 130 | elif key in self._contained_keys: | ||
765 | 131 | return KeyPad.State.NORMAL | ||
766 | 132 | elif key in self._contained_shifted_keys: | ||
767 | 133 | return KeyPad.State.SHIFTED | ||
768 | 134 | else: | ||
769 | 135 | raise ValueError( | ||
770 | 136 | "Don't know which state key '%s' requires." % key | ||
771 | 137 | ) | ||
772 | 138 | |||
773 | 139 | def _switch_to_state(self, state, pointer): | ||
774 | 140 | """Move from one state to the other. | ||
775 | 141 | |||
776 | 142 | i.e. move from NORMAL to SHIFTED | ||
777 | 143 | |||
778 | 144 | """ | ||
779 | 145 | if state == self.state: | ||
780 | 146 | return | ||
781 | 147 | |||
782 | 148 | # If shifted is needed and we're in CAPSLOCK that's fine. | ||
783 | 149 | if (state == KeyPad.State.SHIFTED | ||
784 | 150 | and self.state == KeyPad.State.CAPSLOCK): | ||
785 | 151 | logger.debug( | ||
786 | 152 | "Ignoring request to switch to SHIFTED, already in CAPSLOCK." | ||
787 | 153 | ) | ||
788 | 154 | return | ||
789 | 155 | |||
790 | 156 | logger.debug("Switching from %s to %s" % (self.state, state)) | ||
791 | 157 | |||
792 | 158 | if self.state == KeyPad.State.NORMAL: | ||
793 | 159 | expected_state = KeyPad.State.SHIFTED | ||
794 | 160 | else: | ||
795 | 161 | expected_state = KeyPad.State.NORMAL | ||
796 | 162 | |||
797 | 163 | key_rect = self.get_key_position("shift") | ||
798 | 164 | |||
799 | 165 | # Hack as we cannot tell when the shift key is ready to be pressed | ||
800 | 166 | # bug lp:1229003 and lp:1229001 | ||
801 | 167 | sleep(.2) | ||
802 | 168 | self._tap_key(key_rect, pointer) | ||
803 | 169 | self.state.wait_for(expected_state) | ||
804 | 170 | |||
805 | 171 | def _tap_key(self, key_rect, pointer): | ||
806 | 172 | if pointer is None: | ||
807 | 173 | pointer = Pointer(Touch.create()) | ||
808 | 174 | pointer.click_object(key_rect) | ||
809 | 0 | 175 | ||
810 | === modified file 'tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py' | |||
811 | --- tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py 2013-09-26 10:08:30 +0000 | |||
812 | +++ tests/autopilot/ubuntu_keyboard/tests/test_keyboard.py 2013-09-26 16:09:59 +0000 | |||
813 | @@ -22,12 +22,14 @@ | |||
814 | 22 | from testtools.matchers import Equals | 22 | from testtools.matchers import Equals |
815 | 23 | from tempfile import mktemp | 23 | from tempfile import mktemp |
816 | 24 | from textwrap import dedent | 24 | from textwrap import dedent |
817 | 25 | from time import sleep | ||
818 | 25 | 26 | ||
819 | 26 | from autopilot.testcase import AutopilotTestCase | 27 | from autopilot.testcase import AutopilotTestCase |
820 | 27 | from autopilot.input import Pointer, Touch | 28 | from autopilot.input import Pointer, Touch |
821 | 28 | from autopilot.matchers import Eventually | 29 | from autopilot.matchers import Eventually |
822 | 29 | 30 | ||
824 | 30 | from ubuntu_keyboard.emulators.keyboard import Keyboard, KeyboardState | 31 | from ubuntu_keyboard.emulators.keyboard import Keyboard |
825 | 32 | from ubuntu_keyboard.emulators.keypad import KeyPad | ||
826 | 31 | 33 | ||
827 | 32 | 34 | ||
828 | 33 | class UbuntuKeyboardTests(AutopilotTestCase): | 35 | class UbuntuKeyboardTests(AutopilotTestCase): |
829 | @@ -141,10 +143,12 @@ | |||
830 | 141 | ) | 143 | ) |
831 | 142 | ), | 144 | ), |
832 | 143 | ( | 145 | ( |
833 | 146 | # Currently the en_us layout doesn't have ", but has \u201c and | ||
834 | 147 | # \u201d | ||
835 | 144 | 'punctuation', | 148 | 'punctuation', |
836 | 145 | dict( | 149 | dict( |
837 | 146 | label="Puncuation", | 150 | label="Puncuation", |
839 | 147 | input='`~!@#$%^&*()_-+={}[]|\\:;"\'<>,.?/' | 151 | input=u'`~!@#$%^&*()_-+={}[]|\\:;\'<>,.?/\u201c' |
840 | 148 | ) | 152 | ) |
841 | 149 | ) | 153 | ) |
842 | 150 | ] | 154 | ] |
843 | @@ -169,14 +173,18 @@ | |||
844 | 169 | shifted/capitalised. | 173 | shifted/capitalised. |
845 | 170 | 174 | ||
846 | 171 | """ | 175 | """ |
847 | 176 | self.skip( | ||
848 | 177 | "Skipping as feature hasn't landed yet, refer to bug lp:1214695" | ||
849 | 178 | ) | ||
850 | 179 | |||
851 | 172 | text_area = self.launch_test_input_area() | 180 | text_area = self.launch_test_input_area() |
852 | 173 | self.ensure_focus_on_input(text_area) | 181 | self.ensure_focus_on_input(text_area) |
853 | 174 | keyboard = Keyboard() | 182 | keyboard = Keyboard() |
854 | 175 | self.addCleanup(keyboard.dismiss) | 183 | self.addCleanup(keyboard.dismiss) |
855 | 176 | 184 | ||
856 | 177 | self.assertThat( | 185 | self.assertThat( |
859 | 178 | keyboard.keyboard.layoutState, | 186 | keyboard.active_keypad.state, |
860 | 179 | Eventually(Equals(KeyboardState.SHIFTED)) | 187 | Eventually(Equals(KeyPad.State.SHIFTED)) |
861 | 180 | ) | 188 | ) |
862 | 181 | 189 | ||
863 | 182 | def test_shift_latch(self): | 190 | def test_shift_latch(self): |
864 | @@ -194,13 +202,15 @@ | |||
865 | 194 | self.addCleanup(keyboard.dismiss) | 202 | self.addCleanup(keyboard.dismiss) |
866 | 195 | 203 | ||
867 | 196 | keyboard.type('abc') | 204 | keyboard.type('abc') |
870 | 197 | keyboard.press_key('SHIFT') | 205 | # Bug lp:1229003 and lp:1229001 |
871 | 198 | keyboard.press_key('SHIFT') | 206 | sleep(.2) |
872 | 207 | keyboard.press_key('shift') | ||
873 | 208 | keyboard.press_key('shift') | ||
874 | 199 | keyboard.type('S') | 209 | keyboard.type('S') |
875 | 200 | 210 | ||
876 | 201 | self.assertThat( | 211 | self.assertThat( |
879 | 202 | keyboard.keyboard.layoutState, | 212 | keyboard.active_keypad.state, |
880 | 203 | Eventually(Equals(KeyboardState.SHIFTED)) | 213 | Eventually(Equals(KeyPad.State.CAPSLOCK)) |
881 | 204 | ) | 214 | ) |
882 | 205 | self.assertThat(text_area.text, Eventually(Equals('abcS'))) | 215 | self.assertThat(text_area.text, Eventually(Equals('abcS'))) |
883 | 206 | 216 | ||
884 | @@ -224,8 +234,8 @@ | |||
885 | 224 | # Once the capital letter has been typed, we must be able to access the | 234 | # Once the capital letter has been typed, we must be able to access the |
886 | 225 | # lowercase letters, otherwise it's not in the correct state. | 235 | # lowercase letters, otherwise it's not in the correct state. |
887 | 226 | self.assertThat( | 236 | self.assertThat( |
890 | 227 | keyboard.keyboard.layoutState, | 237 | keyboard.active_keypad.state, |
891 | 228 | Eventually(Equals(KeyboardState.DEFAULT)) | 238 | Eventually(Equals(KeyPad.State.NORMAL)) |
892 | 229 | ) | 239 | ) |
893 | 230 | 240 | ||
894 | 231 | self.assertThat(text_area.text, Eventually(Equals('abcA'))) | 241 | self.assertThat(text_area.text, Eventually(Equals('abcA'))) |
895 | @@ -237,6 +247,9 @@ | |||
896 | 237 | enter the shifted state. | 247 | enter the shifted state. |
897 | 238 | 248 | ||
898 | 239 | """ | 249 | """ |
899 | 250 | self.skip( | ||
900 | 251 | "Skipping as feature hasn't landed yet, refer to bug lp:1214695" | ||
901 | 252 | ) | ||
902 | 240 | text_area = self.launch_test_input_area() | 253 | text_area = self.launch_test_input_area() |
903 | 241 | self.ensure_focus_on_input(text_area) | 254 | self.ensure_focus_on_input(text_area) |
904 | 242 | keyboard = Keyboard() | 255 | keyboard = Keyboard() |
905 | @@ -250,8 +263,8 @@ | |||
906 | 250 | ) | 263 | ) |
907 | 251 | 264 | ||
908 | 252 | self.assertThat( | 265 | self.assertThat( |
911 | 253 | keyboard.keyboard.layoutState, | 266 | keyboard.active_keypad.state, |
912 | 254 | Eventually(Equals(KeyboardState.SHIFTED)) | 267 | Eventually(Equals(KeyPad.State.SHIFTED)) |
913 | 255 | ) | 268 | ) |
914 | 256 | 269 | ||
915 | 257 | def test_switching_between_states(self): | 270 | def test_switching_between_states(self): |
916 | @@ -292,14 +305,6 @@ | |||
917 | 292 | ) | 305 | ) |
918 | 293 | ), | 306 | ), |
919 | 294 | ( | 307 | ( |
920 | 295 | "Password", | ||
921 | 296 | dict( | ||
922 | 297 | label="Password", | ||
923 | 298 | hints=['Qt.ImhHiddenText', 'Qt.ImhSensitiveData'], | ||
924 | 299 | expected_activeview="password" | ||
925 | 300 | ) | ||
926 | 301 | ), | ||
927 | 302 | ( | ||
928 | 303 | "Email", | 308 | "Email", |
929 | 304 | dict( | 309 | dict( |
930 | 305 | label="Email", | 310 | label="Email", |
931 | @@ -320,7 +325,7 @@ | |||
932 | 320 | dict( | 325 | dict( |
933 | 321 | label="Telephone", | 326 | label="Telephone", |
934 | 322 | hints=['Qt.ImhDigitsOnly'], | 327 | hints=['Qt.ImhDigitsOnly'], |
936 | 323 | expected_activeview="phonenumber" | 328 | expected_activeview="number" |
937 | 324 | ) | 329 | ) |
938 | 325 | ), | 330 | ), |
939 | 326 | ] | 331 | ] |
940 | @@ -337,6 +342,6 @@ | |||
941 | 337 | self.addCleanup(keyboard.dismiss) | 342 | self.addCleanup(keyboard.dismiss) |
942 | 338 | 343 | ||
943 | 339 | self.assertThat( | 344 | self.assertThat( |
945 | 340 | keyboard.keyboard.activeView, | 345 | keyboard.keyboard.layoutId, |
946 | 341 | Eventually(Equals(self.expected_activeview)) | 346 | Eventually(Equals(self.expected_activeview)) |
947 | 342 | ) | 347 | ) |
PASSED: Continuous integration, rev:49 jenkins. qa.ubuntu. com/job/ ubuntu- keyboard- ci/102/ jenkins. qa.ubuntu. com/job/ ubuntu- keyboard- saucy-amd64- ci/103 jenkins. qa.ubuntu. com/job/ ubuntu- keyboard- saucy-armhf- ci/102 jenkins. qa.ubuntu. com/job/ ubuntu- keyboard- saucy-armhf- ci/102/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ ubuntu- keyboard- saucy-i386- ci/102
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ ubuntu- keyboard- ci/102/ rebuild
http://