Backout 2ea2669b53c3, Bug 917642 - [Helix] Please update the helix blobs
[gecko.git] / testing / marionette / marionette-sendkeys.js
blobb3f57659ea12251e73e4bc8ae2eb21ab1709f955
1 /*
2  *  Copyright 2007-2009 WebDriver committers
3  *  Copyright 2007-2009 Google Inc.
4  *  Portions copyright 2012 Software Freedom Conservancy
5  *
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *  http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  */
20 var type = function(doc, element, text, releaseModifiers,
21     opt_keysState) {
23   var currentTextLength = element.value ? element.value.length : 0;
24   element.selectionStart = currentTextLength;
25   element.selectionEnd = currentTextLength;
27   // For consistency between native and synthesized events, convert common
28   // escape sequences to their Key enum aliases.
29   text = text.replace(new RegExp('\b', 'g'), '\uE003').   // DOM_VK_BACK_SPACE
30       replace(/\t/g, '\uE004').                           // DOM_VK_TAB
31       replace(/(\r\n|\n|\r)/g, '\uE006');                 // DOM_VK_RETURN
33   var controlKey = false;
34   var shiftKey = false;
35   var altKey = false;
36   var metaKey = false;
37   if (opt_keysState) {
38     controlKey = opt_keysState.control;
39     shiftKey = opt_keysState.shiftKey;
40     altKey = opt_keysState.alt;
41     metaKey = opt_keysState.meta;
42   }
44   shiftCount = 0;
46   var upper = text.toUpperCase();
48   for (var i = 0; i < text.length; i++) {
49     var c = text.charAt(i);
51     // NULL key: reset modifier key states, and continue
53     if (c == '\uE000') {
54       if (controlKey) {
55         var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
56         keyEvent(doc, element, "keyup", kCode, 0,
57             controlKey = false, shiftKey, altKey, metaKey, false);
58       }
60       if (shiftKey) {
61         var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
62         keyEvent(doc, element, "keyup", kCode, 0,
63             controlKey, shiftKey = false, altKey, metaKey, false);
64       }
66       if (altKey) {
67         var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
68         keyEvent(doc, element, "keyup", kCode, 0,
69             controlKey, shiftKey, altKey = false, metaKey, false);
70       }
72       if (metaKey) {
73         var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
74         keyEvent(doc, element, "keyup", kCode, 0,
75             controlKey, shiftKey, altKey, metaKey = false, false);
76       }
78       continue;
79     }
81     // otherwise decode keyCode, charCode, modifiers ...
83     var modifierEvent = "";
84     var charCode = 0;
85     var keyCode = 0;
87     if (c == '\uE001') {
88       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CANCEL;
89     } else if (c == '\uE002') {
90       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_HELP;
91     } else if (c == '\uE003') {
92       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_BACK_SPACE;
93     } else if (c == '\uE004') {
94       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_TAB;
95     } else if (c == '\uE005') {
96       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CLEAR;
97     } else if (c == '\uE006') {
98       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_RETURN;
99     } else if (c == '\uE007') {
100       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ENTER;
101     } else if (c == '\uE008') {
102       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
103       shiftKey = !shiftKey;
104       modifierEvent = shiftKey ? "keydown" : "keyup";
105     } else if (c == '\uE009') {
106       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
107       controlKey = !controlKey;
108       modifierEvent = controlKey ? "keydown" : "keyup";
109     } else if (c == '\uE00A') {
110       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
111       altKey = !altKey;
112       modifierEvent = altKey ? "keydown" : "keyup";
113     } else if (c == '\uE03D') {
114       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
115       metaKey = !metaKey;
116       modifierEvent = metaKey ? "keydown" : "keyup";
117     } else if (c == '\uE00B') {
118       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PAUSE;
119     } else if (c == '\uE00C') {
120       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ESCAPE;
121     } else if (c == '\uE00D') {
122       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SPACE;
123       keyCode = charCode = ' '.charCodeAt(0);  // printable
124     } else if (c == '\uE00E') {
125       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PAGE_UP;
126     } else if (c == '\uE00F') {
127       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN;
128     } else if (c == '\uE010') {
129       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_END;
130     } else if (c == '\uE011') {
131       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_HOME;
132     } else if (c == '\uE012') {
133       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_LEFT;
134     } else if (c == '\uE013') {
135       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_UP;
136     } else if (c == '\uE014') {
137       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_RIGHT;
138     } else if (c == '\uE015') {
139       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DOWN;
140     } else if (c == '\uE016') {
141       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_INSERT;
142     } else if (c == '\uE017') {
143       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DELETE;
144     } else if (c == '\uE018') {
145       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SEMICOLON;
146       charCode = ';'.charCodeAt(0);
147     } else if (c == '\uE019') {
148       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_EQUALS;
149       charCode = '='.charCodeAt(0);
150     } else if (c == '\uE01A') {
151       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD0;
152       charCode = '0'.charCodeAt(0);
153     } else if (c == '\uE01B') {
154       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD1;
155       charCode = '1'.charCodeAt(0);
156     } else if (c == '\uE01C') {
157       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD2;
158       charCode = '2'.charCodeAt(0);
159     } else if (c == '\uE01D') {
160       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD3;
161       charCode = '3'.charCodeAt(0);
162     } else if (c == '\uE01E') {
163       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD4;
164       charCode = '4'.charCodeAt(0);
165     } else if (c == '\uE01F') {
166       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD5;
167       charCode = '5'.charCodeAt(0);
168     } else if (c == '\uE020') {
169       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD6;
170       charCode = '6'.charCodeAt(0);
171     } else if (c == '\uE021') {
172       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD7;
173       charCode = '7'.charCodeAt(0);
174     } else if (c == '\uE022') {
175       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD8;
176       charCode = '8'.charCodeAt(0);
177     } else if (c == '\uE023') {
178       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_NUMPAD9;
179       charCode = '9'.charCodeAt(0);
180     } else if (c == '\uE024') {
181       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_MULTIPLY;
182       charCode = '*'.charCodeAt(0);
183     } else if (c == '\uE025') {
184       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ADD;
185       charCode = '+'.charCodeAt(0);
186     } else if (c == '\uE026') {
187       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SEPARATOR;
188       charCode = ','.charCodeAt(0);
189     } else if (c == '\uE027') {
190       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SUBTRACT;
191       charCode = '-'.charCodeAt(0);
192     } else if (c == '\uE028') {
193       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DECIMAL;
194       charCode = '.'.charCodeAt(0);
195     } else if (c == '\uE029') {
196       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_DIVIDE;
197       charCode = '/'.charCodeAt(0);
198     } else if (c == '\uE031') {
199       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F1;
200     } else if (c == '\uE032') {
201       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F2;
202     } else if (c == '\uE033') {
203       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F3;
204     } else if (c == '\uE034') {
205       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F4;
206     } else if (c == '\uE035') {
207       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F5;
208     } else if (c == '\uE036') {
209       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F6;
210     } else if (c == '\uE037') {
211       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F7;
212     } else if (c == '\uE038') {
213       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F8;
214     } else if (c == '\uE039') {
215       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F9;
216     } else if (c == '\uE03A') {
217       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F10;
218     } else if (c == '\uE03B') {
219       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F11;
220     } else if (c == '\uE03C') {
221       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_F12;
222     } else if (c == ',' || c == '<') {
223       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_COMMA;
224       charCode = c.charCodeAt(0);
225     } else if (c == '.' || c == '>') {
226       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_PERIOD;
227       charCode = c.charCodeAt(0);
228     } else if (c == '/' || c == '?') {
229       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SLASH;
230       charCode = text.charCodeAt(i);
231     } else if (c == '`' || c == '~') {
232       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_BACK_QUOTE;
233       charCode = c.charCodeAt(0);
234     } else if (c == '{' || c == '[') {
235       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET;
236       charCode = c.charCodeAt(0);
237     } else if (c == '\\' || c == '|') {
238       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_BACK_SLASH;
239       charCode = c.charCodeAt(0);
240     } else if (c == '}' || c == ']') {
241       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET;
242       charCode = c.charCodeAt(0);
243     } else if (c == '\'' || c == '"') {
244       keyCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_QUOTE;
245       charCode = c.charCodeAt(0);
246     } else {
247       keyCode = upper.charCodeAt(i);
248       charCode = text.charCodeAt(i);
249     }
251     // generate modifier key event if needed, and continue
253     if (modifierEvent) {
254       keyEvent(doc, element, modifierEvent, keyCode, 0,
255           controlKey, shiftKey, altKey, metaKey, false);
256       continue;
257     }
259     // otherwise, shift down if needed
261     var needsShift = false;
262     if (charCode) {
263       needsShift = /[A-Z\!\$\^\*\(\)\+\{\}\:\?\|~@#%&_"<>]/.test(c);
264     }
266     if (needsShift && !shiftKey) {
267       var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
268       keyEvent(doc, element, "keydown", kCode, 0,
269           controlKey, true, altKey, metaKey, false);
270       shiftCount += 1;
271     }
273     // generate key[down/press/up] for key
275     var pressCode = keyCode;
276     if (charCode >= 32 && charCode < 127) {
277       pressCode = 0;
278       if (!needsShift && shiftKey && charCode > 32) {
279         // If typing a lowercase character key and the shiftKey is down, the
280         // charCode should be mapped to the shifted key value. This assumes
281         // a default 104 international keyboard layout.
282         if (charCode >= 97 && charCode <= 122) {
283           charCode = charCode + 65 - 97;  // [a-z] -> [A-Z]
284         } else {
285           var mapFrom = '`1234567890-=[]\\;\',./';
286           var mapTo = '~!@#$%^&*()_+{}|:"<>?';
288           var value = String.fromCharCode(charCode).
289               replace(/([\[\\\.])/g, '\\$1');
290           var index = mapFrom.search(value);
291           if (index >= 0) {
292             charCode = mapTo.charCodeAt(index);
293           }
294         }
295       }
296     }
298     var accepted =
299         keyEvent(doc, element, "keydown", keyCode, 0,
300             controlKey, needsShift || shiftKey, altKey, metaKey, false);
302     keyEvent(doc, element, "keypress", pressCode, charCode,
303         controlKey, needsShift || shiftKey, altKey, metaKey, !accepted);
305     keyEvent(doc, element, "keyup", keyCode, 0,
306         controlKey, needsShift || shiftKey, altKey, metaKey, false);
308     // shift up if needed
310     if (needsShift && !shiftKey) {
311       var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
312       keyEvent(doc, element, "keyup", kCode, 0,
313           controlKey, false, altKey, metaKey, false);
314     }
315   }
317   // exit cleanup: keyup active modifier keys
319   if (controlKey && releaseModifiers) {
320     var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL;
321     keyEvent(doc, element, "keyup", kCode, 0,
322         controlKey = false, shiftKey, altKey, metaKey, false);
323   }
325   if (shiftKey && releaseModifiers) {
326     var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_SHIFT;
327     keyEvent(doc, element, "keyup", kCode, 0,
328         controlKey, shiftKey = false, altKey, metaKey, false);
329   }
331   if (altKey && releaseModifiers) {
332     var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_ALT;
333     keyEvent(doc, element, "keyup", kCode, 0,
334         controlKey, shiftKey, altKey = false, metaKey, false);
335   }
337   if (metaKey && releaseModifiers) {
338     var kCode = Components.interfaces.nsIDOMKeyEvent.DOM_VK_META;
339     keyEvent(doc, element, "keyup", kCode, 0,
340         controlKey, shiftKey, altKey, metaKey = false, false);
341   }
343   return {
344     shiftKey: shiftKey,
345     alt: altKey,
346     meta: metaKey,
347     control: controlKey
348   };
352 var keyEvent = function(doc, element, type, keyCode, charCode,
353                           controlState, shiftState, altState, metaState,
354                           shouldPreventDefault) {
355   var preventDefault = shouldPreventDefault == undefined ? false
356       : shouldPreventDefault;
358   var keyboardEvent = doc.createEvent("KeyEvents");
359   var currentView = doc.defaultView;
361   keyboardEvent.initKeyEvent(
362       type, //  in DOMString typeArg,
363       true, //  in boolean canBubbleArg
364       true, //  in boolean cancelableArg
365       currentView, //  in nsIDOMAbstractView viewArg
366       controlState, //  in boolean ctrlKeyArg
367       altState, //  in boolean altKeyArg
368       shiftState, //  in boolean shiftKeyArg
369       metaState, //  in boolean metaKeyArg
370       keyCode, //  in unsigned long keyCodeArg
371       charCode);    //  in unsigned long charCodeArg
373   if (preventDefault) {
374     keyboardEvent.preventDefault();
375   }
377   var win = doc.defaultView;
378   var domUtil = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
379                 .getInterface(Components.interfaces.nsIDOMWindowUtils);
380   return domUtil.dispatchDOMEventViaPresShell(element, keyboardEvent, true);