Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: chrome/browser/resources/keyboard/common.js

Issue 10399046: Remove virtual keyboard support. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: final rebase Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 /**
6 * @fileoverview A simple virtual keyboard implementation.
7 */
8
9 var KEY_MODE = 'key';
10 var SHIFT_MODE = 'shift';
11 var NUMBER_MODE = 'number';
12 var SYMBOL_MODE = 'symbol';
13 var MODES = [ KEY_MODE, SHIFT_MODE, NUMBER_MODE, SYMBOL_MODE ];
14 var currentMode = SHIFT_MODE;
15 var enterShiftModeOnSpace = false;
16 var MODE_TRANSITIONS = {};
17
18 MODE_TRANSITIONS[KEY_MODE + SHIFT_MODE] = SHIFT_MODE;
19 MODE_TRANSITIONS[KEY_MODE + NUMBER_MODE] = NUMBER_MODE;
20 MODE_TRANSITIONS[SHIFT_MODE + SHIFT_MODE] = KEY_MODE;
21 MODE_TRANSITIONS[SHIFT_MODE + NUMBER_MODE] = NUMBER_MODE;
22 MODE_TRANSITIONS[NUMBER_MODE + SHIFT_MODE] = SYMBOL_MODE;
23 MODE_TRANSITIONS[NUMBER_MODE + NUMBER_MODE] = KEY_MODE;
24 MODE_TRANSITIONS[SYMBOL_MODE + SHIFT_MODE] = NUMBER_MODE;
25 MODE_TRANSITIONS[SYMBOL_MODE + NUMBER_MODE] = KEY_MODE;
26
27 var KEYBOARDS = {};
28
29 /**
30 * The long-press delay in milliseconds before long-press handler is invoked.
31 * @type {number}
32 */
33 var LONGPRESS_DELAY_MSEC = 500;
34
35 /**
36 * The repeat delay in milliseconds before a key starts repeating. Use the same
37 * rate as Chromebook. (See chrome/browser/chromeos/language_preferences.cc)
38 * @type {number}
39 */
40 var REPEAT_DELAY_MSEC = 500;
41
42 /**
43 * The repeat interval or number of milliseconds between subsequent keypresses.
44 * Use the same rate as Chromebook.
45 * @type {number}
46 */
47 var REPEAT_INTERVAL_MSEC = 50;
48
49 /**
50 * The keyboard layout name currently in use.
51 * @type {string}
52 */
53 var currentKeyboardLayout = 'us';
54
55 /**
56 * The popup keyboard layout name currently in use.
57 * @type {string}
58 */
59 var currentPopupName = '';
60
61 /**
62 * A structure to track the currently repeating key on the keyboard.
63 */
64 var repeatKey = {
65 /**
66 * The timer for the delay before repeating behaviour begins.
67 * @type {number|undefined}
68 */
69 timer: undefined,
70
71 /**
72 * The interval timer for issuing keypresses of a repeating key.
73 * @type {number|undefined}
74 */
75 interval: undefined,
76
77 /**
78 * The key which is currently repeating.
79 * @type {BaseKey|undefined}
80 */
81 key: undefined,
82
83 /**
84 * Cancel the repeat timers of the currently active key.
85 */
86 cancel: function() {
87 clearTimeout(this.timer);
88 clearInterval(this.interval);
89 this.timer = undefined;
90 this.interval = undefined;
91 this.key = undefined;
92 }
93 };
94
95 /**
96 * An array to track the currently touched keys on the popup keyboard.
97 */
98 var touchedKeys = [];
99
100 /**
101 * Set the keyboard mode.
102 * @param {string} mode The new mode.
103 * @return {void}
104 */
105 function setMode(mode) {
106 currentMode = mode;
107
108 var rows = KEYBOARDS[currentKeyboardLayout]['rows'];
109 for (var i = 0; i < rows.length; ++i) {
110 rows[i].showMode(currentMode);
111 }
112
113 if (!currentPopupName) {
114 return;
115 }
116 var popupRows = KEYBOARDS[currentPopupName]['rows'];
117 for (var i = 0; i < popupRows.length; ++i) {
118 popupRows[i].showMode(currentMode);
119 }
120 }
121
122 /**
123 * Transition the mode according to the given transition.
124 * @param {string} transition The transition to take.
125 * @return {void}
126 */
127 function transitionMode(transition) {
128 setMode(MODE_TRANSITIONS[currentMode + transition]);
129 }
130
131 /**
132 * Send the given key to chrome, via the experimental extension API.
133 * @param {string} key The key to send.
134 * @return {void}
135 */
136 function sendKey(key) {
137 var keyEvent = {'keyIdentifier': key};
138 // A keypress event is automatically generated for printable characters
139 // immediately following the keydown event.
140 if (chrome.experimental) {
141 keyEvent.type = 'keydown';
142 chrome.experimental.input.virtualKeyboard.sendKeyboardEvent(keyEvent);
143 keyEvent.type = 'keyup';
144 chrome.experimental.input.virtualKeyboard.sendKeyboardEvent(keyEvent);
145 }
146 // Exit shift mode after pressing any key but space.
147 if (currentMode == SHIFT_MODE && key != 'Spacebar') {
148 transitionMode(SHIFT_MODE);
149 }
150 // Enter shift mode after typing a closing punctuation and then a space for a
151 // new sentence.
152 if (enterShiftModeOnSpace) {
153 enterShiftModeOnSpace = false;
154 if (currentMode != SHIFT_MODE && key == 'Spacebar') {
155 setMode(SHIFT_MODE);
156 }
157 }
158 if (currentMode != SHIFT_MODE && (key == '.' || key == '?' || key == '!')) {
159 enterShiftModeOnSpace = true;
160 }
161 }
162
163 /**
164 * Add a child div element that represents the content of the given element.
165 * A child div element that represents a text content is added if
166 * opt_textContent is given. Otherwise a child element that represents an image
167 * content is added. If the given element already has a child, the child element
168 * is modified.
169 * @param {Element} element The DOM Element to which the content is added.
170 * @param {string} opt_textContent The text to be inserted.
171 * @return {void}
172 */
173 function addContent(element, opt_textContent) {
174 if (element.childNodes.length > 0) {
175 var content = element.childNodes[0];
176 if (opt_textContent) {
177 content.textContent = opt_textContent;
178 }
179 return;
180 }
181
182 var content = document.createElement('div');
183 if (opt_textContent) {
184 content.textContent = opt_textContent;
185 content.className = 'text-key';
186 } else {
187 content.className = 'image-key';
188 }
189 element.appendChild(content);
190 }
191
192 /**
193 * Set up the event handlers necessary to respond to mouse and touch events on
194 * the virtual keyboard.
195 * @param {BaseKey} key The BaseKey object corresponding to this key.
196 * @param {Element} element The top-level DOM Element to set event handlers on.
197 * @param {Object.<string, function()>} handlers The object that contains key
198 * event handlers in the following form.
199 *
200 * { 'up': keyUpHandler,
201 * 'down': keyDownHandler,
202 * 'long': keyLongHandler }
203 *
204 * keyUpHandler: Called when the key is pressed. This will be called
205 * repeatedly when holding a repeating key.
206 * keyDownHandler: Called when the keyis released. This is only called
207 * once per actual key press.
208 * keyLongHandler: Called when the key is long-pressed for
209 * |LONGPRESS_DELAY_MSEC| milliseconds.
210 *
211 * The object does not necessarily contain all the handlers above, but
212 * needs to contain at least one of them.
213 */
214 function setupKeyEventHandlers(key, element, handlers) {
215 var keyDownHandler = handlers['down'];
216 var keyUpHandler = handlers['up'];
217 var keyLongHandler = handlers['long'];
218 if (!(keyDownHandler || keyUpHandler || keyLongPressHandler)) {
219 throw new Error('Invalid handlers passed to setupKeyEventHandlers');
220 }
221
222 /**
223 * Handle a key down event on the virtual key.
224 * @param {UIEvent} evt The UI event which triggered the key down.
225 */
226 var downHandler = function(evt) {
227 // Prevent any of the system gestures from happening.
228 evt.preventDefault();
229
230 // Don't process a key down if the key is already down.
231 if (key.pressed) {
232 return;
233 }
234 key.pressed = true;
235 if (keyDownHandler) {
236 keyDownHandler();
237 }
238 repeatKey.cancel();
239
240 // Start a repeating timer if there is a repeat interval and a function to
241 // process key down events.
242 if (key.repeat && keyDownHandler) {
243 repeatKey.key = key;
244 // The timeout for the repeating timer occurs at
245 // REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC so that the interval
246 // function can handle all repeat keypresses and will get the first one
247 // at the correct time.
248 repeatKey.timer = setTimeout(function() {
249 repeatKey.timer = undefined;
250 repeatKey.interval = setInterval(function() {
251 keyDownHandler();
252 }, REPEAT_INTERVAL_MSEC);
253 }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC));
254 }
255
256 if (keyLongHandler) {
257 // Copy the currentTarget of event, which is neccessary in
258 // showPopupKeyboard, because |evt| can be modified before
259 // |keyLongHandler| is called.
260 var evtCopy = {};
261 evtCopy.currentTarget = evt.currentTarget;
262 key.longPressTimer = setTimeout(function() {
263 keyLongHandler(evtCopy),
264 clearTimeout(key.longPressTimer);
265 delete key.longPressTimer;
266 key.pressed = false;
267 }, LONGPRESS_DELAY_MSEC);
268 }
269 };
270
271 /**
272 * Handle a key up event on the virtual key.
273 * @param {UIEvent} evt The UI event which triggered the key up.
274 */
275 var upHandler = function(evt) {
276 // Prevent any of the system gestures from happening.
277 evt.preventDefault();
278
279 // Reset long-press timer.
280 if (key.longPressTimer) {
281 clearTimeout(key.longPressTimer);
282 delete key.longPressTimer
283 }
284
285 // If they key was not actually pressed do not send a key up event.
286 if (!key.pressed) {
287 return;
288 }
289 key.pressed = false;
290
291 // Cancel running repeat timer for the released key only.
292 if (repeatKey.key == key) {
293 repeatKey.cancel();
294 }
295
296 if (keyUpHandler) {
297 keyUpHandler();
298 }
299 };
300
301 var outHandler = function(evt) {
302 // Key element contains a div that holds text like this.
303 //
304 // <div class="key r1">
305 // <div class="text-key">a</div>
306 // </div>
307 //
308 // We are interested in mouseout event sent when mouse cursor moves out of
309 // the external div, but mouseout event is sent when mouse cursor moves out
310 // of the internal div or moves into the internal div, too.
311 // Filter out the last two cases here.
312 if (evt.target != evt.currentTarget ||
313 evt.toElement.parentNode == evt.fromElement) {
314 return;
315 }
316 // Reset key press state if the point goes out of the element.
317 key.pressed = false;
318 // Reset long-press timer.
319 if (key.longPressTimer) {
320 clearTimeout(key.longPressTimer);
321 delete key.longPressTimer
322 }
323 }
324
325 // Setup mouse event handlers.
326 element.addEventListener('mousedown', downHandler);
327 element.addEventListener('mouseup', upHandler);
328 element.addEventListener('mouseout', outHandler);
329
330 // Setup touch handlers.
331 element.addEventListener('touchstart', downHandler);
332 element.addEventListener('touchend', upHandler);
333 // TODO(mazda): Add a handler for touchleave once Webkit supports it.
334 // element.addEventListener('touchleave', outHandler);
335 }
336
337 /**
338 * Create closure for the sendKey function.
339 * @param {string} key The key paramater to sendKey.
340 * @return {function()} A function which calls sendKey(key).
341 */
342 function sendKeyFunction(key) {
343 return function() {
344 sendKey(key);
345 };
346 }
347
348 /**
349 * Dispatch custom events to the elements at the touch points.
350 * touchmove_popup events are dispatched responding to a touchmove and
351 * touchend_popup events responding to a touchend event respectively.
352 * @param {UIEvent} evt The touch event that contains touch points information.
353 * @return {void}
354 */
355 function dispatchCustomPopupEvents(evt) {
356 var type = null;
357 var touches = null;
358 if (evt.type == 'touchmove') {
359 type = 'touchmove_popup';
360 touches = evt.touches;
361 } else if (evt.type == 'touchend') {
362 type = 'touchend_popup';
363 touches = evt.changedTouches;
364 } else {
365 return;
366 }
367
368 for (var i = 0; i < touches.length; ++i) {
369 var dispatchedEvent = document.createEvent('Event');
370 dispatchedEvent.initEvent(type, true, false);
371 var touch = touches[i];
372 var key = document.elementFromPoint(touch.screenX, touch.screenY);
373 if (key) {
374 key.dispatchEvent(dispatchedEvent);
375 }
376 }
377 }
378
379 /**
380 * Handle a touch move event on the key to make changes to the popup keyboard.
381 * @param {UIEvent} evt The UI event which triggered the touch move.
382 * @return {void}
383 */
384 function trackTouchMoveForPopup(evt) {
385 var previous = touchedKeys;
386 touchedKeys = [];
387 dispatchCustomPopupEvents(evt);
388 for (var i = 0; i < previous.length; ++i) {
389 if (touchedKeys.indexOf(previous[i]) == -1) {
390 previous[i].classList.remove('highlighted');
391 }
392 }
393 for (var i = 0; i < touchedKeys.length; ++i) {
394 touchedKeys[i].classList.add('highlighted');
395 }
396 }
397
398 /**
399 * Handle a touch end event on the key to make changes to the popup keyboard.
400 * @param {UIEvent} evt The UI event which triggered the touch end.
401 * @return {void}
402 */
403 function trackTouchEndForPopup(evt) {
404 for (var i = 0; i < touchedKeys.length; ++i) {
405 touchedKeys[i].classList.remove('highlighted');
406 }
407 dispatchCustomPopupEvents(evt);
408 hidePopupKeyboard();
409
410 touchedKeys = [];
411 evt.target.removeEventListener('touchmove', trackTouchMoveForPopup);
412 evt.target.removeEventListener('touchend', trackTouchEndForPopup);
413 }
414
415 /**
416 * Show the popup keyboard.
417 * @param {string} name The name of the popup keyboard.
418 * @param {UIEvent} evt The UI event which triggered the touch start.
419 * @return {void}
420 */
421 function showPopupKeyboard(name, evt) {
422 var popupDiv = document.getElementById('popup');
423 if (popupDiv.style.visibility == 'visible') {
424 return;
425 }
426
427 // Iitialize the rows of the popup keyboard
428 initRows(name, popupDiv, true);
429 currentPopupName = name;
430
431 // Set the mode of the popup keyboard
432 var popupRows = KEYBOARDS[name]['rows'];
433 for (var i = 0; i < popupRows.length; ++i) {
434 popupRows[i].showMode(currentMode);
435 }
436
437 // Calculate the size of popup keyboard based on the size of the key.
438 var keyElement = evt.currentTarget;
439 var keyboard = KEYBOARDS[name];
440 var rows = keyboard['definition'];
441 var height = keyElement.offsetHeight * rows.length;
442 var aspect = keyboard['aspect'];
443 var width = aspect * height;
444 popupDiv.style.width = width + 'px';
445 popupDiv.style.height = height + 'px';
446
447 // Place the popup keyboard above the key
448 var rect = keyElement.getBoundingClientRect();
449 var left = (rect.left + rect.right) / 2 - width / 2;
450 left = Math.min(Math.max(left, 0), window.innerWidth - width);
451 var top = rect.top - height;
452 top = Math.min(Math.max(top, 0), window.innerHeight - height);
453 popupDiv.style.left = left + 'px';
454 popupDiv.style.top = top + 'px';
455 popupDiv.style.visibility = 'visible';
456
457 keyElement.addEventListener('touchmove', trackTouchMoveForPopup);
458 keyElement.addEventListener('touchend', trackTouchEndForPopup);
459 }
460
461 /**
462 * Create closure for the showPopupKeyboard function.
463 * @param {string} name The name paramater to showPopupKeyboard.
464 * @return {function()} A function which calls showPopupKeyboard(name, evt).
465 */
466 function showPopupKeyboardFunction(name) {
467 return function (evt) {
468 showPopupKeyboard(name, evt);
469 };
470 }
471
472 /**
473 * Hide the popup keyboard.
474 * @return {void}
475 */
476 function hidePopupKeyboard() {
477 // Clean up the popup keyboard
478 var popupDiv = document.getElementById('popup');
479 popupDiv.style.visibility = 'hidden';
480 while (popupDiv.firstChild) {
481 popupDiv.removeChild(popupDiv.firstChild);
482 }
483 if (currentPopupName in KEYBOARDS) {
484 delete KEYBOARDS[currentPopupName].rows;
485 }
486 currentPopupName = '';
487 }
488
489 /**
490 * Plain-old-data class to represent a character.
491 * @param {string} display The HTML to be displayed.
492 * @param {string} id The key identifier for this Character.
493 * @constructor
494 */
495 function Character(display, id) {
496 this.display = display;
497 this.keyIdentifier = id;
498 }
499
500 /**
501 * Convenience function to make the keyboard data more readable.
502 * @param {string} display The display for the created Character.
503 * @param {string} opt_id The id for the created Character.
504 * @return {Character} A character that contains display and opt_id. If
505 * opt_id is omitted, display is used as the id.
506 */
507 function C(display, opt_id) {
508 var id = opt_id || display;
509 return new Character(display, id);
510 }
511
512 /**
513 * Convenience function to make the keyboard data more readable.
514 * @param {string} display The display for the created Character.
515 * @param {string} opt_id The id for the created Character.
516 * @param {string} opt_popupName The popup keyboard name for this character.
517 * @return {Object} An object that contains a Character and the popup keyboard
518 * name.
519 */
520 function CP(display, opt_id, opt_popupName) {
521 var result = { character: C(display, opt_id) };
522 if (opt_popupName) {
523 result['popupName'] = opt_popupName;
524 }
525 return result;
526 }
527
528 /**
529 * An abstract base-class for all keys on the keyboard.
530 * @constructor
531 */
532 function BaseKey() {}
533
534 BaseKey.prototype = {
535 /**
536 * The cell type of this key. Determines the background colour.
537 * @type {string}
538 */
539 cellType_: '',
540
541 /**
542 * If true, holding this key will issue repeat keypresses.
543 * @type {boolean}
544 */
545 repeat_: false,
546
547 /**
548 * Track the pressed state of the key. This is true if currently pressed.
549 * @type {boolean}
550 */
551 pressed_: false,
552
553 /**
554 * Get the repeat behaviour of the key.
555 * @return {boolean} True if the key will repeat.
556 */
557 get repeat() {
558 return this.repeat_;
559 },
560
561 /**
562 * Set the repeat behaviour of the key
563 * @param {boolean} repeat True if the key should repeat.
564 */
565 set repeat(repeat) {
566 this.repeat_ = repeat;
567 },
568
569 /**
570 * Get the pressed state of the key.
571 * @return {boolean} True if the key is currently pressed.
572 */
573 get pressed() {
574 return this.pressed_;
575 },
576
577 /**
578 * Set the pressed state of the key.
579 * @param {boolean} pressed True if the key is currently pressed.
580 */
581 set pressed(pressed) {
582 this.pressed_ = pressed;
583 },
584
585 /**
586 * Create the DOM elements for the given keyboard mode. Must be overridden.
587 * @param {string} mode The keyboard mode to create elements for.
588 * @return {Element} The top-level DOM Element for the key.
589 */
590 makeDOM: function(mode) {
591 throw new Error('makeDOM not implemented in BaseKey');
592 },
593 };
594
595 /**
596 * A simple key which displays Characters.
597 * @param {Object} key The Character and the popup name for KEY_MODE.
598 * @param {Object} shift The Character and the popup name for SHIFT_MODE.
599 * @param {Object} num The Character and the popup name for NUMBER_MODE.
600 * @param {Object} symbol The Character and the popup name for SYMBOL_MODE.
601 * @constructor
602 * @extends {BaseKey}
603 */
604 function Key(key, shift, num, symbol) {
605 this.modeElements_ = {};
606 this.cellType_ = '';
607
608 this.modes_ = {};
609 this.modes_[KEY_MODE] = key ? key.character : null;
610 this.modes_[SHIFT_MODE] = shift ? shift.character : null;
611 this.modes_[NUMBER_MODE] = num ? num.character : null;
612 this.modes_[SYMBOL_MODE] = symbol ? symbol.character : null;
613
614 this.popupNames_ = {};
615 this.popupNames_[KEY_MODE] = key ? key.popupName : null;
616 this.popupNames_[SHIFT_MODE] = shift ? shift.popupName : null;
617 this.popupNames_[NUMBER_MODE] = num ? num.popupName : null;
618 this.popupNames_[SYMBOL_MODE] = symbol ? symbol.popupName : null;
619 }
620
621 Key.prototype = {
622 __proto__: BaseKey.prototype,
623
624 /** @inheritDoc */
625 makeDOM: function(mode) {
626 if (!this.modes_[mode]) {
627 return null;
628 }
629
630 this.modeElements_[mode] = document.createElement('div');
631 var element = this.modeElements_[mode];
632 element.className = 'key';
633
634 addContent(element, this.modes_[mode].display);
635
636 var longHandler = this.popupNames_[mode] ?
637 showPopupKeyboardFunction(this.popupNames_[mode]) : null;
638 setupKeyEventHandlers(this, element,
639 { 'up': sendKeyFunction(this.modes_[mode].keyIdentifier),
640 'long': longHandler });
641 return element;
642 }
643 };
644
645 /**
646 * A simple key which displays Characters on the popup keyboard.
647 * @param {Character} key The Character for KEY_MODE.
648 * @param {Character} shift The Character for SHIFT_MODE.
649 * @param {Character} num The Character for NUMBER_MODE.
650 * @param {Character} symbol The Character for SYMBOL_MODE.
651 * @constructor
652 * @extends {BaseKey}
653 */
654 function PopupKey(key, shift, num, symbol) {
655 this.modeElements_ = {};
656 this.cellType_ = '';
657
658 this.modes_ = {};
659 this.modes_[KEY_MODE] = key;
660 this.modes_[SHIFT_MODE] = shift;
661 this.modes_[NUMBER_MODE] = num;
662 this.modes_[SYMBOL_MODE] = symbol;
663 }
664
665 PopupKey.prototype = {
666 __proto__: BaseKey.prototype,
667
668 /** @inheritDoc */
669 makeDOM: function(mode) {
670 if (!this.modes_[mode]) {
671 return null;
672 }
673
674 this.modeElements_[mode] = document.createElement('div');
675 var element = this.modeElements_[mode];
676 element.className = 'key popupkey';
677
678 addContent(element, this.modes_[mode].display);
679
680 var upHandler = sendKeyFunction(this.modes_[mode].keyIdentifier);
681 element.addEventListener('touchmove_popup', function(evt) {
682 touchedKeys.push(element);
683 });
684 element.addEventListener('touchend_popup', upHandler);
685 element.addEventListener('mouseup', upHandler);
686 element.addEventListener('mouseover', function(evt) {
687 element.classList.add('highlighted');
688 });
689 element.addEventListener('mouseout', function(evt) {
690 element.classList.remove('highlighted');
691 });
692 return element;
693 }
694 };
695
696 /**
697 * A key which displays an SVG image.
698 * @param {string} className The class that provides the image.
699 * @param {string} keyId The key identifier for the key.
700 * @param {boolean} opt_repeat True if the key should repeat.
701 * @constructor
702 * @extends {BaseKey}
703 */
704 function SvgKey(className, keyId, opt_repeat) {
705 this.modeElements_ = {};
706 this.cellType_ = 'nc';
707 this.className_ = className;
708 this.keyId_ = keyId;
709 this.repeat_ = opt_repeat || false;
710 }
711
712 SvgKey.prototype = {
713 __proto__: BaseKey.prototype,
714
715 /** @inheritDoc */
716 makeDOM: function(mode) {
717 this.modeElements_[mode] = document.createElement('div');
718 this.modeElements_[mode].className = 'key';
719 this.modeElements_[mode].classList.add(this.className_);
720 addContent(this.modeElements_[mode]);
721
722 // send the key event on key down if key repeat is enabled
723 var handler = this.repeat_ ? { 'down' : sendKeyFunction(this.keyId_) } :
724 { 'up' : sendKeyFunction(this.keyId_) };
725 setupKeyEventHandlers(this, this.modeElements_[mode], handler);
726
727 return this.modeElements_[mode];
728 }
729 };
730
731 /**
732 * A Key that remains the same through all modes.
733 * @param {string} content The display text for the key.
734 * @param {string} keyId The key identifier for the key.
735 * @constructor
736 * @extends {BaseKey}
737 */
738 function SpecialKey(className, content, keyId) {
739 this.modeElements_ = {};
740 this.cellType_ = 'nc';
741 this.content_ = content;
742 this.keyId_ = keyId;
743 this.className_ = className;
744 }
745
746 SpecialKey.prototype = {
747 __proto__: BaseKey.prototype,
748
749 /** @inheritDoc */
750 makeDOM: function(mode) {
751 this.modeElements_[mode] = document.createElement('div');
752 this.modeElements_[mode].className = 'key';
753 this.modeElements_[mode].classList.add(this.className_);
754 addContent(this.modeElements_[mode], this.content_);
755
756 setupKeyEventHandlers(this, this.modeElements_[mode],
757 { 'up': sendKeyFunction(this.keyId_) });
758
759 return this.modeElements_[mode];
760 }
761 };
762
763 /**
764 * A shift key.
765 * @constructor
766 * @extends {BaseKey}
767 */
768 function ShiftKey(className) {
769 this.modeElements_ = {};
770 this.cellType_ = 'nc';
771 this.className_ = className;
772 }
773
774 ShiftKey.prototype = {
775 __proto__: BaseKey.prototype,
776
777 /** @inheritDoc */
778 makeDOM: function(mode) {
779 this.modeElements_[mode] = document.createElement('div');
780 this.modeElements_[mode].className = 'key shift';
781 this.modeElements_[mode].classList.add(this.className_);
782
783 if (mode == KEY_MODE || mode == SHIFT_MODE) {
784 addContent(this.modeElements_[mode]);
785 } else if (mode == NUMBER_MODE) {
786 addContent(this.modeElements_[mode], 'more');
787 } else if (mode == SYMBOL_MODE) {
788 addContent(this.modeElements_[mode], '#123');
789 }
790
791 if (mode == SHIFT_MODE || mode == SYMBOL_MODE) {
792 this.modeElements_[mode].classList.add('moddown');
793 } else {
794 this.modeElements_[mode].classList.remove('moddown');
795 }
796
797 setupKeyEventHandlers(this, this.modeElements_[mode],
798 { 'down': function() {
799 transitionMode(SHIFT_MODE);
800 }});
801
802 return this.modeElements_[mode];
803 },
804 };
805
806 /**
807 * The symbol key: switches the keyboard into symbol mode.
808 * @constructor
809 * @extends {BaseKey}
810 */
811 function SymbolKey() {
812 this.modeElements_ = {}
813 this.cellType_ = 'nc';
814 }
815
816 SymbolKey.prototype = {
817 __proto__: BaseKey.prototype,
818
819 /** @inheritDoc */
820 makeDOM: function(mode, height) {
821 this.modeElements_[mode] = document.createElement('div');
822 this.modeElements_[mode].className = 'key symbol';
823
824 if (mode == KEY_MODE || mode == SHIFT_MODE) {
825 addContent(this.modeElements_[mode], '#123');
826 } else if (mode == NUMBER_MODE || mode == SYMBOL_MODE) {
827 addContent(this.modeElements_[mode], 'abc');
828 }
829
830 if (mode == NUMBER_MODE || mode == SYMBOL_MODE) {
831 this.modeElements_[mode].classList.add('moddown');
832 } else {
833 this.modeElements_[mode].classList.remove('moddown');
834 }
835
836 setupKeyEventHandlers(this, this.modeElements_[mode],
837 { 'down': function() {
838 transitionMode(NUMBER_MODE);
839 }});
840
841 return this.modeElements_[mode];
842 }
843 };
844
845 /**
846 * The ".com" key.
847 * @constructor
848 * @extends {BaseKey}
849 */
850 function DotComKey() {
851 this.modeElements_ = {}
852 this.cellType_ = 'nc';
853 }
854
855 DotComKey.prototype = {
856 __proto__: BaseKey.prototype,
857
858 /** @inheritDoc */
859 makeDOM: function(mode) {
860 this.modeElements_[mode] = document.createElement('div');
861 this.modeElements_[mode].className = 'key com';
862 addContent(this.modeElements_[mode], '.com');
863
864 setupKeyEventHandlers(this, this.modeElements_[mode],
865 { 'up': function() {
866 sendKey('.');
867 sendKey('c');
868 sendKey('o');
869 sendKey('m');
870 }});
871
872 return this.modeElements_[mode];
873 }
874 };
875
876 /**
877 * The key that hides the keyboard.
878 * @constructor
879 * @extends {BaseKey}
880 */
881 function HideKeyboardKey() {
882 this.modeElements_ = {}
883 this.cellType_ = 'nc';
884 }
885
886 HideKeyboardKey.prototype = {
887 __proto__: BaseKey.prototype,
888
889 /** @inheritDoc */
890 makeDOM: function(mode) {
891 this.modeElements_[mode] = document.createElement('div');
892 this.modeElements_[mode].className = 'key hide';
893 addContent(this.modeElements_[mode]);
894
895 setupKeyEventHandlers(this, this.modeElements_[mode],
896 { 'down': function() {
897 if (chrome.experimental) {
898 chrome.experimental.input.virtualKeyboard.hideKeyboard();
899 }
900 }});
901
902 return this.modeElements_[mode];
903 }
904 };
905
906 /**
907 * A container for keys.
908 * @param {number} position The position of the row (0-3).
909 * @param {Array.<BaseKey>} keys The keys in the row.
910 * @constructor
911 */
912 function Row(position, keys) {
913 this.position_ = position;
914 this.keys_ = keys;
915 this.element_ = null;
916 this.modeElements_ = {};
917 }
918
919 Row.prototype = {
920 /**
921 * Create the DOM elements for the row.
922 * @return {Element} The top-level DOM Element for the row.
923 */
924 makeDOM: function() {
925 this.element_ = document.createElement('div');
926 this.element_.className = 'row';
927 for (var i = 0; i < MODES.length; ++i) {
928 var mode = MODES[i];
929 this.modeElements_[mode] = document.createElement('div');
930 this.modeElements_[mode].style.display = 'none';
931 this.element_.appendChild(this.modeElements_[mode]);
932 }
933
934 for (var j = 0; j < this.keys_.length; ++j) {
935 var key = this.keys_[j];
936 for (var i = 0; i < MODES.length; ++i) {
937 var keyDom = key.makeDOM(MODES[i]);
938 if (keyDom) {
939 this.modeElements_[MODES[i]].appendChild(keyDom);
940 }
941 }
942 }
943
944 for (var i = 0; i < MODES.length; ++i) {
945 var clearingDiv = document.createElement('div');
946 clearingDiv.style.clear = 'both';
947 this.modeElements_[MODES[i]].appendChild(clearingDiv);
948 }
949
950 return this.element_;
951 },
952
953 /**
954 * Shows the given mode.
955 * @param {string} mode The mode to show.
956 * @return {void}
957 */
958 showMode: function(mode) {
959 for (var i = 0; i < MODES.length; ++i) {
960 this.modeElements_[MODES[i]].style.display = 'none';
961 }
962 this.modeElements_[mode].style.display = '-webkit-box';
963 },
964
965 /**
966 * Returns the size of keys this row contains.
967 * @return {number} The size of keys.
968 */
969 get length() {
970 return this.keys_.length;
971 }
972 };
OLDNEW
« no previous file with comments | « chrome/browser/resources/keyboard/chevron.svg ('k') | chrome/browser/resources/keyboard/del.svg » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698