OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview A simple virtual keyboard implementation. | 6 * @fileoverview A simple virtual keyboard implementation. |
7 */ | 7 */ |
8 | 8 |
9 var KEY_MODE = 'key'; | 9 var KEY_MODE = 'key'; |
10 var SHIFT_MODE = 'shift'; | 10 var SHIFT_MODE = 'shift'; |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 * @return {void} | 79 * @return {void} |
80 */ | 80 */ |
81 function transitionMode(transition) { | 81 function transitionMode(transition) { |
82 currentMode = MODE_TRANSITIONS[currentMode + transition]; | 82 currentMode = MODE_TRANSITIONS[currentMode + transition]; |
83 setMode(currentMode); | 83 setMode(currentMode); |
84 } | 84 } |
85 | 85 |
86 /** | 86 /** |
87 * Send the given key to chrome, via the experimental extension API. | 87 * Send the given key to chrome, via the experimental extension API. |
88 * @param {string} key The key to send. | 88 * @param {string} key The key to send. |
89 * @param {string=} opt_type The type of event to send (keydown or keyup). If | |
90 * omitted send both keydown and keyup events. | |
91 * @return {void} | 89 * @return {void} |
92 */ | 90 */ |
93 function sendKey(key, type) { | 91 function sendKey(key) { |
94 var keyEvent = {'keyIdentifier': key}; | 92 var keyEvent = {'keyIdentifier': key}; |
95 if (!type || type == 'keydown') { | 93 // A keypress event is automatically generated for printable characters |
96 // A keypress event is automatically generated for printable characters | 94 // immediately following the keydown event. |
97 // immediately following the keydown event. | 95 if (chrome.experimental) { |
98 keyEvent.type = 'keydown'; | 96 keyEvent.type = 'keydown'; |
99 if (chrome.experimental) { | 97 chrome.experimental.input.sendKeyboardEvent(keyEvent); |
100 chrome.experimental.input.sendKeyboardEvent(keyEvent); | 98 keyEvent.type = 'keyup'; |
101 } | 99 chrome.experimental.input.sendKeyboardEvent(keyEvent); |
102 // Exit shift mode after pressing any key but space. | |
103 if (currentMode == SHIFT_MODE && key != 'Spacebar') { | |
104 transitionMode(SHIFT_MODE); | |
105 } | |
106 // Enter shift mode after typing a period for a new sentence. | |
107 if (currentMode != SHIFT_MODE && key == '.') { | |
108 transitionMode(SHIFT_MODE); | |
109 } | |
110 } | 100 } |
111 if (!type || type == 'keyup') { | 101 // Exit shift mode after pressing any key but space. |
112 keyEvent.type = 'keyup'; | 102 if (currentMode == SHIFT_MODE && key != 'Spacebar') { |
113 if (chrome.experimental) { | 103 transitionMode(SHIFT_MODE); |
114 chrome.experimental.input.sendKeyboardEvent(keyEvent); | 104 } |
115 } | 105 // Enter shift mode after typing a period for a new sentence. |
| 106 if (currentMode != SHIFT_MODE && key == '.') { |
| 107 transitionMode(SHIFT_MODE); |
116 } | 108 } |
117 } | 109 } |
118 | 110 |
119 /** | 111 /** |
120 * Add a child div element that represents the content of the given element. | 112 * Add a child div element that represents the content of the given element. |
121 * A child div element that represents a text content is added if | 113 * A child div element that represents a text content is added if |
122 * opt_textContent is given. Otherwise a child element that represents an image | 114 * opt_textContent is given. Otherwise a child element that represents an image |
123 * content is added. If the given element already has a child, the child element | 115 * content is added. If the given element already has a child, the child element |
124 * is modified. | 116 * is modified. |
125 * @param {Element} element The DOM Element to which the content is added. | 117 * @param {Element} element The DOM Element to which the content is added. |
(...skipping 19 matching lines...) Expand all Loading... |
145 element.appendChild(content); | 137 element.appendChild(content); |
146 } | 138 } |
147 | 139 |
148 /** | 140 /** |
149 * Set up the event handlers necessary to respond to mouse and touch events on | 141 * Set up the event handlers necessary to respond to mouse and touch events on |
150 * the virtual keyboard. | 142 * the virtual keyboard. |
151 * @param {BaseKey} key The BaseKey object corresponding to this key. | 143 * @param {BaseKey} key The BaseKey object corresponding to this key. |
152 * @param {Element} element The top-level DOM Element to set event handlers on. | 144 * @param {Element} element The top-level DOM Element to set event handlers on. |
153 * @param {function()} keyDownHandler The event handler called when the key is | 145 * @param {function()} keyDownHandler The event handler called when the key is |
154 * pressed. This will be called repeatedly when holding a repeating key. | 146 * pressed. This will be called repeatedly when holding a repeating key. |
155 * @param {function()=} opt_keyUpHandler The event handler called when the key | 147 * @param {function()=} keyUpHandler The event handler called when the key |
156 * is released. This is only called once per actual key press. | 148 * is released. This is only called once per actual key press. |
157 */ | 149 */ |
158 function setupKeyEventHandlers(key, element, keyDownHandler, opt_keyUpHandler) { | 150 function setupKeyEventHandlersHelper(key, element, keyDownHandler, |
| 151 keyUpHandler) { |
159 /** | 152 /** |
160 * Handle a key down event on the virtual key. | 153 * Handle a key down event on the virtual key. |
161 * @param {UIEvent} evt The UI event which triggered the key down. | 154 * @param {UIEvent} evt The UI event which triggered the key down. |
162 */ | 155 */ |
163 var downHandler = function(evt) { | 156 var downHandler = function(evt) { |
164 // Don't process a key down if the key is already down. | 157 // Don't process a key down if the key is already down. |
165 if (key.pressed) { | 158 if (key.pressed) { |
166 return; | 159 return; |
167 } | 160 } |
168 key.pressed = true; | 161 key.pressed = true; |
(...skipping 29 matching lines...) Expand all Loading... |
198 if (!key.pressed) { | 191 if (!key.pressed) { |
199 return; | 192 return; |
200 } | 193 } |
201 key.pressed = false; | 194 key.pressed = false; |
202 | 195 |
203 // Cancel running repeat timer for the released key only. | 196 // Cancel running repeat timer for the released key only. |
204 if (repeatKey.key == key) { | 197 if (repeatKey.key == key) { |
205 repeatKey.cancel(); | 198 repeatKey.cancel(); |
206 } | 199 } |
207 | 200 |
208 if (opt_keyUpHandler) { | 201 if (keyUpHandler) { |
209 opt_keyUpHandler(); | 202 keyUpHandler(); |
210 } | 203 } |
211 evt.preventDefault(); | 204 evt.preventDefault(); |
212 }; | 205 }; |
213 | 206 |
| 207 var outHandler = function(evt) { |
| 208 // Reset key press state if the point goes out of the element. |
| 209 key.pressed = false; |
| 210 } |
| 211 |
214 // Setup mouse event handlers. | 212 // Setup mouse event handlers. |
215 element.addEventListener('mousedown', downHandler); | 213 element.addEventListener('mousedown', downHandler); |
216 element.addEventListener('mouseup', upHandler); | 214 element.addEventListener('mouseup', upHandler); |
217 element.addEventListener('mouseout', upHandler); | 215 element.addEventListener('mouseout', outHandler); |
218 | 216 |
219 // Setup touch handlers. | 217 // Setup touch handlers. |
220 element.addEventListener('touchstart', downHandler); | 218 element.addEventListener('touchstart', downHandler); |
221 element.addEventListener('touchend', upHandler); | 219 element.addEventListener('touchend', upHandler); |
| 220 // TODO(mazda): Add a handler for touchleave once Webkit supports it. |
| 221 // element.addEventListener('touchleave', outHandler); |
222 } | 222 } |
223 | 223 |
224 /** | 224 /** |
| 225 * Set up the event handlers necessary to respond to the key down event on the |
| 226 * virtual keyboard. |
| 227 * @param {BaseKey} key The BaseKey object corresponding to this key. |
| 228 * @param {Element} element The top-level DOM Element to set event handlers on. |
| 229 * @param {function()} keyDownHandler The event handler called when the key is |
| 230 * pressed. This will be called repeatedly when holding a repeating key. |
| 231 */ |
| 232 function setupKeyDownEventHandler(key, element, keyDownHandler) { |
| 233 setupKeyEventHandlersHelper(key, element, keyDownHandler, null); |
| 234 } |
| 235 |
| 236 /** |
| 237 * Set up the event handlers necessary to respond to the key up event on the |
| 238 * virtual keyboard. |
| 239 * @param {BaseKey} key The BaseKey object corresponding to this key. |
| 240 * @param {Element} element The top-level DOM Element to set event handlers on. |
| 241 * @param {function()=} keyUpHandler The event handler called when the key |
| 242 * is released. This is only called once per actual key press. |
| 243 */ |
| 244 function setupKeyUpEventHandler(key, element, keyUpHandler) { |
| 245 setupKeyEventHandlersHelper(key, element, null, keyUpHandler); |
| 246 } |
| 247 |
| 248 /** |
225 * Create closure for the sendKey function. | 249 * Create closure for the sendKey function. |
226 * @param {string} key The key paramater to sendKey. | 250 * @param {string} key The key paramater to sendKey. |
227 * @param {string=} type The type parameter to sendKey. | 251 * @param {string=} type The type parameter to sendKey. |
228 * @return {function()} A function which calls sendKey(key, type). | 252 * @return {function()} A function which calls sendKey(key, type). |
229 */ | 253 */ |
230 function sendKeyFunction(key, type) { | 254 function sendKeyFunction(key, type) { |
231 return function() { | 255 return function() { |
232 sendKey(key, type); | 256 sendKey(key, type); |
233 }; | 257 }; |
234 } | 258 } |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 /** @inheritDoc */ | 379 /** @inheritDoc */ |
356 makeDOM: function(mode) { | 380 makeDOM: function(mode) { |
357 if (!this.modes_[mode]) { | 381 if (!this.modes_[mode]) { |
358 return null; | 382 return null; |
359 } | 383 } |
360 | 384 |
361 this.modeElements_[mode] = document.createElement('div'); | 385 this.modeElements_[mode] = document.createElement('div'); |
362 this.modeElements_[mode].className = 'key'; | 386 this.modeElements_[mode].className = 'key'; |
363 addContent(this.modeElements_[mode], this.modes_[mode].display); | 387 addContent(this.modeElements_[mode], this.modes_[mode].display); |
364 | 388 |
365 setupKeyEventHandlers(this, this.modeElements_[mode], | 389 setupKeyUpEventHandler(this, this.modeElements_[mode], |
366 sendKeyFunction(this.modes_[mode].keyIdentifier, 'keydown'), | 390 sendKeyFunction(this.modes_[mode].keyIdentifier)); |
367 sendKeyFunction(this.modes_[mode].keyIdentifier, 'keyup')); | |
368 | 391 |
369 return this.modeElements_[mode]; | 392 return this.modeElements_[mode]; |
370 } | 393 } |
371 }; | 394 }; |
372 | 395 |
373 /** | 396 /** |
374 * A key which displays an SVG image. | 397 * A key which displays an SVG image. |
375 * @param {string} className The class that provides the image. | 398 * @param {string} className The class that provides the image. |
376 * @param {string} keyId The key identifier for the key. | 399 * @param {string} keyId The key identifier for the key. |
377 * @param {boolean} opt_repeat True if the key should repeat. | 400 * @param {boolean} opt_repeat True if the key should repeat. |
(...skipping 11 matching lines...) Expand all Loading... |
389 SvgKey.prototype = { | 412 SvgKey.prototype = { |
390 __proto__: BaseKey.prototype, | 413 __proto__: BaseKey.prototype, |
391 | 414 |
392 /** @inheritDoc */ | 415 /** @inheritDoc */ |
393 makeDOM: function(mode) { | 416 makeDOM: function(mode) { |
394 this.modeElements_[mode] = document.createElement('div'); | 417 this.modeElements_[mode] = document.createElement('div'); |
395 this.modeElements_[mode].className = 'key'; | 418 this.modeElements_[mode].className = 'key'; |
396 this.modeElements_[mode].classList.add(this.className_); | 419 this.modeElements_[mode].classList.add(this.className_); |
397 addContent(this.modeElements_[mode]); | 420 addContent(this.modeElements_[mode]); |
398 | 421 |
399 setupKeyEventHandlers(this, this.modeElements_[mode], | 422 if (this.repeat_) { |
400 sendKeyFunction(this.keyId_, 'keydown'), | 423 // send the key event on key down if key repeat is enabled |
401 sendKeyFunction(this.keyId_, 'keyup')); | 424 setupKeyDownEventHandler(this, this.modeElements_[mode], |
| 425 sendKeyFunction(this.keyId_)); |
| 426 } else { |
| 427 setupKeyUpEventHandler(this, this.modeElements_[mode], |
| 428 sendKeyFunction(this.keyId_)); |
| 429 } |
402 | 430 |
403 return this.modeElements_[mode]; | 431 return this.modeElements_[mode]; |
404 } | 432 } |
405 }; | 433 }; |
406 | 434 |
407 /** | 435 /** |
408 * A Key that remains the same through all modes. | 436 * A Key that remains the same through all modes. |
409 * @param {string} content The display text for the key. | 437 * @param {string} content The display text for the key. |
410 * @param {string} keyId The key identifier for the key. | 438 * @param {string} keyId The key identifier for the key. |
411 * @constructor | 439 * @constructor |
(...skipping 10 matching lines...) Expand all Loading... |
422 SpecialKey.prototype = { | 450 SpecialKey.prototype = { |
423 __proto__: BaseKey.prototype, | 451 __proto__: BaseKey.prototype, |
424 | 452 |
425 /** @inheritDoc */ | 453 /** @inheritDoc */ |
426 makeDOM: function(mode) { | 454 makeDOM: function(mode) { |
427 this.modeElements_[mode] = document.createElement('div'); | 455 this.modeElements_[mode] = document.createElement('div'); |
428 this.modeElements_[mode].className = 'key'; | 456 this.modeElements_[mode].className = 'key'; |
429 this.modeElements_[mode].classList.add(this.className_); | 457 this.modeElements_[mode].classList.add(this.className_); |
430 addContent(this.modeElements_[mode], this.content_); | 458 addContent(this.modeElements_[mode], this.content_); |
431 | 459 |
432 setupKeyEventHandlers(this, this.modeElements_[mode], | 460 setupKeyUpEventHandler(this, this.modeElements_[mode], |
433 sendKeyFunction(this.keyId_, 'keydown'), | 461 sendKeyFunction(this.keyId_)); |
434 sendKeyFunction(this.keyId_, 'keyup')); | |
435 | 462 |
436 return this.modeElements_[mode]; | 463 return this.modeElements_[mode]; |
437 } | 464 } |
438 }; | 465 }; |
439 | 466 |
440 /** | 467 /** |
441 * A shift key. | 468 * A shift key. |
442 * @constructor | 469 * @constructor |
443 * @extends {BaseKey} | 470 * @extends {BaseKey} |
444 */ | 471 */ |
(...skipping 19 matching lines...) Expand all Loading... |
464 } else if (mode == SYMBOL_MODE) { | 491 } else if (mode == SYMBOL_MODE) { |
465 addContent(this.modeElements_[mode], '#123'); | 492 addContent(this.modeElements_[mode], '#123'); |
466 } | 493 } |
467 | 494 |
468 if (mode == SHIFT_MODE || mode == SYMBOL_MODE) { | 495 if (mode == SHIFT_MODE || mode == SYMBOL_MODE) { |
469 this.modeElements_[mode].classList.add('moddown'); | 496 this.modeElements_[mode].classList.add('moddown'); |
470 } else { | 497 } else { |
471 this.modeElements_[mode].classList.remove('moddown'); | 498 this.modeElements_[mode].classList.remove('moddown'); |
472 } | 499 } |
473 | 500 |
474 setupKeyEventHandlers(this, this.modeElements_[mode], | 501 setupKeyDownEventHandler(this, this.modeElements_[mode], |
475 function() { | 502 function() { |
476 transitionMode(SHIFT_MODE); | 503 transitionMode(SHIFT_MODE); |
477 }); | 504 }); |
478 | 505 |
479 return this.modeElements_[mode]; | 506 return this.modeElements_[mode]; |
480 }, | 507 }, |
481 }; | 508 }; |
482 | 509 |
483 /** | 510 /** |
484 * The symbol key: switches the keyboard into symbol mode. | 511 * The symbol key: switches the keyboard into symbol mode. |
(...skipping 18 matching lines...) Expand all Loading... |
503 } else if (mode == NUMBER_MODE || mode == SYMBOL_MODE) { | 530 } else if (mode == NUMBER_MODE || mode == SYMBOL_MODE) { |
504 addContent(this.modeElements_[mode], 'abc'); | 531 addContent(this.modeElements_[mode], 'abc'); |
505 } | 532 } |
506 | 533 |
507 if (mode == NUMBER_MODE || mode == SYMBOL_MODE) { | 534 if (mode == NUMBER_MODE || mode == SYMBOL_MODE) { |
508 this.modeElements_[mode].classList.add('moddown'); | 535 this.modeElements_[mode].classList.add('moddown'); |
509 } else { | 536 } else { |
510 this.modeElements_[mode].classList.remove('moddown'); | 537 this.modeElements_[mode].classList.remove('moddown'); |
511 } | 538 } |
512 | 539 |
513 setupKeyEventHandlers(this, this.modeElements_[mode], | 540 setupKeyDownEventHandler(this, this.modeElements_[mode], |
514 function() { | 541 function() { |
515 transitionMode(NUMBER_MODE); | 542 transitionMode(NUMBER_MODE); |
516 }); | 543 }); |
517 | 544 |
518 return this.modeElements_[mode]; | 545 return this.modeElements_[mode]; |
519 } | 546 } |
520 }; | 547 }; |
521 | 548 |
522 /** | 549 /** |
523 * The ".com" key. | 550 * The ".com" key. |
524 * @constructor | 551 * @constructor |
525 * @extends {BaseKey} | 552 * @extends {BaseKey} |
526 */ | 553 */ |
527 function DotComKey() { | 554 function DotComKey() { |
528 this.modeElements_ = {} | 555 this.modeElements_ = {} |
529 this.cellType_ = 'nc'; | 556 this.cellType_ = 'nc'; |
530 } | 557 } |
531 | 558 |
532 DotComKey.prototype = { | 559 DotComKey.prototype = { |
533 __proto__: BaseKey.prototype, | 560 __proto__: BaseKey.prototype, |
534 | 561 |
535 /** @inheritDoc */ | 562 /** @inheritDoc */ |
536 makeDOM: function(mode) { | 563 makeDOM: function(mode) { |
537 this.modeElements_[mode] = document.createElement('div'); | 564 this.modeElements_[mode] = document.createElement('div'); |
538 this.modeElements_[mode].className = 'key com'; | 565 this.modeElements_[mode].className = 'key com'; |
539 addContent(this.modeElements_[mode], '.com'); | 566 addContent(this.modeElements_[mode], '.com'); |
540 | 567 |
541 setupKeyEventHandlers(this, this.modeElements_[mode], | 568 setupKeyUpEventHandler(this, this.modeElements_[mode], |
542 function() { | 569 function() { |
543 sendKey('.'); | 570 sendKey('.'); |
544 sendKey('c'); | 571 sendKey('c'); |
545 sendKey('o'); | 572 sendKey('o'); |
546 sendKey('m'); | 573 sendKey('m'); |
547 }); | 574 }); |
548 | 575 |
549 return this.modeElements_[mode]; | 576 return this.modeElements_[mode]; |
550 } | 577 } |
551 }; | 578 }; |
(...skipping 10 matching lines...) Expand all Loading... |
562 | 589 |
563 HideKeyboardKey.prototype = { | 590 HideKeyboardKey.prototype = { |
564 __proto__: BaseKey.prototype, | 591 __proto__: BaseKey.prototype, |
565 | 592 |
566 /** @inheritDoc */ | 593 /** @inheritDoc */ |
567 makeDOM: function(mode) { | 594 makeDOM: function(mode) { |
568 this.modeElements_[mode] = document.createElement('div'); | 595 this.modeElements_[mode] = document.createElement('div'); |
569 this.modeElements_[mode].className = 'key hide'; | 596 this.modeElements_[mode].className = 'key hide'; |
570 addContent(this.modeElements_[mode]); | 597 addContent(this.modeElements_[mode]); |
571 | 598 |
572 setupKeyEventHandlers(this, this.modeElements_[mode], | 599 setupKeyDownEventHandler(this, this.modeElements_[mode], |
573 function() { | 600 function() { |
574 if (chrome.experimental) { | 601 if (chrome.experimental) { |
575 chrome.experimental.input.hideKeyboard(); | 602 chrome.experimental.input.hideKeyboard(); |
576 } | 603 } |
577 }); | 604 }); |
578 | 605 |
579 return this.modeElements_[mode]; | 606 return this.modeElements_[mode]; |
580 } | 607 } |
581 }; | 608 }; |
582 | 609 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 * @param {string} mode The mode to show. | 663 * @param {string} mode The mode to show. |
637 * @return {void} | 664 * @return {void} |
638 */ | 665 */ |
639 showMode: function(mode) { | 666 showMode: function(mode) { |
640 for (var i = 0; i < MODES.length; ++i) { | 667 for (var i = 0; i < MODES.length; ++i) { |
641 this.modeElements_[MODES[i]].style.display = 'none'; | 668 this.modeElements_[MODES[i]].style.display = 'none'; |
642 } | 669 } |
643 this.modeElements_[mode].style.display = '-webkit-box'; | 670 this.modeElements_[mode].style.display = '-webkit-box'; |
644 }, | 671 }, |
645 }; | 672 }; |
OLD | NEW |