testing/marionette/marionette-sendkeys.js

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

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

mercurial