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

Side by Side Diff: ui/keyboard/resources/elements/kb-keyboard.js

Issue 730573002: Remove dead code for system VK. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 1 month 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
OLDNEW
(Empty)
1 // Copyright 2014 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 * The repeat delay in milliseconds before a key starts repeating. Use the
7 * same rate as Chromebook.
8 * (See chrome/browser/chromeos/language_preferences.cc)
9 * @const
10 * @type {number}
11 */
12 var REPEAT_DELAY_MSEC = 500;
13
14 /**
15 * The repeat interval or number of milliseconds between subsequent
16 * keypresses. Use the same rate as Chromebook.
17 * @const
18 * @type {number}
19 */
20 var REPEAT_INTERVAL_MSEC = 50;
21
22 /**
23 * The double click/tap interval.
24 * @const
25 * @type {number}
26 */
27 var DBL_INTERVAL_MSEC = 300;
28
29 /**
30 * The index of the name of the keyset when searching for all keysets.
31 * @const
32 * @type {number}
33 */
34 var REGEX_KEYSET_INDEX = 1;
35
36 /**
37 * The integer number of matches when searching for keysets.
38 * @const
39 * @type {number}
40 */
41 var REGEX_MATCH_COUNT = 2;
42
43 /**
44 * The boolean to decide if keyboard should transit to upper case keyset
45 * when spacebar is pressed. If a closing punctuation is followed by a
46 * spacebar, keyboard should automatically transit to upper case.
47 * @type {boolean}
48 */
49 var enterUpperOnSpace = false;
50
51 /**
52 * A structure to track the currently repeating key on the keyboard.
53 */
54 var repeatKey = {
55
56 /**
57 * The timer for the delay before repeating behaviour begins.
58 * @type {number|undefined}
59 */
60 timer: undefined,
61
62 /**
63 * The interval timer for issuing keypresses of a repeating key.
64 * @type {number|undefined}
65 */
66 interval: undefined,
67
68 /**
69 * The key which is currently repeating.
70 * @type {BaseKey|undefined}
71 */
72 key: undefined,
73
74 /**
75 * Cancel the repeat timers of the currently active key.
76 */
77 cancel: function() {
78 clearTimeout(this.timer);
79 clearInterval(this.interval);
80 this.timer = undefined;
81 this.interval = undefined;
82 this.key = undefined;
83 }
84 };
85
86 /**
87 * The minimum movement interval needed to trigger cursor move on
88 * horizontal and vertical way.
89 * @const
90 * @type {number}
91 */
92 var MIN_SWIPE_DIST_X = 50;
93 var MIN_SWIPE_DIST_Y = 20;
94
95 /**
96 * The maximum swipe distance that will trigger hintText of a key
97 * to be typed.
98 * @const
99 * @type {number}
100 */
101 var MAX_SWIPE_FLICK_DIST = 60;
102
103 /**
104 * The boolean to decide if it is swipe in process or finished.
105 * @type {boolean}
106 */
107 var swipeInProgress = false;
108
109 // Flag values for ctrl, alt and shift as defined by EventFlags
110 // in "event_constants.h".
111 // @enum {number}
112 var Modifier = {
113 NONE: 0,
114 ALT: 8,
115 CONTROL: 4,
116 SHIFT: 2
117 };
118
119 /**
120 * A structure to track the current swipe status.
121 */
122 var swipeTracker = {
123 /**
124 * The latest PointerMove event in the swipe.
125 * @type {Object}
126 */
127 currentEvent: undefined,
128
129 /**
130 * Whether or not a swipe changes direction.
131 * @type {false}
132 */
133 isComplex: false,
134
135 /**
136 * The count of horizontal and vertical movement.
137 * @type {number}
138 */
139 offset_x : 0,
140 offset_y : 0,
141
142 /**
143 * Last touch coordinate.
144 * @type {number}
145 */
146 pre_x : 0,
147 pre_y : 0,
148
149 /**
150 * The PointerMove event which triggered the swipe.
151 * @type {Object}
152 */
153 startEvent: undefined,
154
155 /**
156 * The flag of current modifier key.
157 * @type {number}
158 */
159 swipeFlags : 0,
160
161 /**
162 * Current swipe direction.
163 * @type {number}
164 */
165 swipeDirection : 0,
166
167 /**
168 * The number of times we've swiped within a single swipe.
169 * @type {number}
170 */
171 swipeIndex: 0,
172
173 /**
174 * Returns the combined direction of the x and y offsets.
175 * @return {number} The latest direction.
176 */
177 getOffsetDirection: function() {
178 // TODO (rsadam): Use angles to figure out the direction.
179 var direction = 0;
180 // Checks for horizontal swipe.
181 if (Math.abs(this.offset_x) > MIN_SWIPE_DIST_X) {
182 if (this.offset_x > 0) {
183 direction |= SwipeDirection.RIGHT;
184 } else {
185 direction |= SwipeDirection.LEFT;
186 }
187 }
188 // Checks for vertical swipe.
189 if (Math.abs(this.offset_y) > MIN_SWIPE_DIST_Y) {
190 if (this.offset_y < 0) {
191 direction |= SwipeDirection.UP;
192 } else {
193 direction |= SwipeDirection.DOWN;
194 }
195 }
196 return direction;
197 },
198
199 /**
200 * Populates the swipe update details.
201 * @param {boolean} endSwipe Whether this is the final event for this
202 * swipe.
203 * @return {Object} The current state of the swipeTracker.
204 */
205 populateDetails: function(endSwipe) {
206 var detail = {};
207 detail.direction = this.swipeDirection;
208 detail.index = this.swipeIndex;
209 detail.status = this.swipeStatus;
210 detail.endSwipe = endSwipe;
211 detail.startEvent = this.startEvent;
212 detail.currentEvent = this.currentEvent;
213 detail.isComplex = this.isComplex;
214 return detail;
215 },
216
217 /**
218 * Reset all the values when swipe finished.
219 */
220 resetAll: function() {
221 this.offset_x = 0;
222 this.offset_y = 0;
223 this.pre_x = 0;
224 this.pre_y = 0;
225 this.swipeFlags = 0;
226 this.swipeDirection = 0;
227 this.swipeIndex = 0;
228 this.startEvent = undefined;
229 this.currentEvent = undefined;
230 this.isComplex = false;
231 },
232
233 /**
234 * Updates the swipe path with the current event.
235 * @param {Object} event The PointerEvent that triggered this update.
236 * @return {boolean} Whether or not to notify swipe observers.
237 */
238 update: function(event) {
239 if(!event.isPrimary)
240 return false;
241 // Update priors.
242 this.offset_x += event.screenX - this.pre_x;
243 this.offset_y += event.screenY - this.pre_y;
244 this.pre_x = event.screenX;
245 this.pre_y = event.screenY;
246
247 // Check if movement crosses minimum thresholds in each direction.
248 var direction = this.getOffsetDirection();
249 if (direction == 0)
250 return false;
251 // If swipeIndex is zero the current event is triggering the swipe.
252 if (this.swipeIndex == 0) {
253 this.startEvent = event;
254 } else if (direction != this.swipeDirection) {
255 // Toggle the isComplex flag.
256 this.isComplex = true;
257 }
258 // Update the swipe tracker.
259 this.swipeDirection = direction;
260 this.offset_x = 0;
261 this.offset_y = 0;
262 this.currentEvent = event;
263 this.swipeIndex++;
264 return true;
265 },
266
267 };
268
269 Polymer('kb-keyboard', {
270 alt: null,
271 config: null,
272 control: null,
273 dblDetail_: null,
274 dblTimer_: null,
275 inputType: null,
276 lastPressedKey: null,
277 shift: null,
278 sounds: {},
279 stale: true,
280 swipeHandler: null,
281 voiceInput_: null,
282 //TODO(rsadam@): Add a control to let users change this.
283 volume: DEFAULT_VOLUME,
284
285 /**
286 * The default input type to keyboard layout map. The key must be one of
287 * the input box type values.
288 * @type {object}
289 */
290 inputTypeToLayoutMap: {
291 number: "numeric",
292 text: "qwerty",
293 password: "qwerty"
294 },
295
296 /**
297 * Caches the specified sound on the keyboard.
298 * @param {string} soundId The name of the .wav file in the "sounds"
299 directory.
300 */
301 addSound: function(soundId) {
302 // Check if already loaded.
303 if (soundId == Sound.NONE || this.sounds[soundId])
304 return;
305 var pool = [];
306 for (var i = 0; i < SOUND_POOL_SIZE; i++) {
307 var audio = document.createElement('audio');
308 audio.preload = "auto";
309 audio.id = soundId;
310 audio.src = "../sounds/" + soundId + ".wav";
311 audio.volume = this.volume;
312 pool.push(audio);
313 }
314 this.sounds[soundId] = pool;
315 },
316
317 /**
318 * Changes the current keyset.
319 * @param {Object} detail The detail of the event that called this
320 * function.
321 */
322 changeKeyset: function(detail) {
323 if (detail.relegateToShift && this.shift) {
324 this.keyset = this.shift.textKeyset;
325 this.activeKeyset.nextKeyset = undefined;
326 return true;
327 }
328 var toKeyset = detail.toKeyset;
329 if (toKeyset) {
330 this.keyset = toKeyset;
331 this.activeKeyset.nextKeyset = detail.nextKeyset;
332 return true;
333 }
334 return false;
335 },
336
337 keysetChanged: function() {
338 var keyset = this.activeKeyset;
339 // Show the keyset if it has been initialized.
340 if (keyset)
341 keyset.show();
342 },
343
344 configChanged: function() {
345 this.layout = this.config.layout;
346 },
347
348 ready: function() {
349 this.voiceInput_ = new VoiceInput(this);
350 this.swipeHandler = this.move.bind(this);
351 var self = this;
352 getKeyboardConfig(function(config) {
353 self.config = config;
354 });
355 },
356
357 /**
358 * Registers a callback for state change events.
359 * @param{!Function} callback Callback function to register.
360 */
361 addKeysetChangedObserver: function(callback) {
362 this.addEventListener('stateChange', callback);
363 },
364
365 /**
366 * Called when the type of focused input box changes. If a keyboard layout
367 * is defined for the current input type, that layout will be loaded.
368 * Otherwise, the keyboard layout for 'text' type will be loaded.
369 */
370 inputTypeChanged: function() {
371 // Disable layout switching at accessibility mode.
372 if (this.config && this.config.a11ymode)
373 return;
374
375 // TODO(bshe): Toggle visibility of some keys in a keyboard layout
376 // according to the input type.
377 var layout = this.inputTypeToLayoutMap[this.inputType];
378 if (!layout)
379 layout = this.inputTypeToLayoutMap.text;
380 this.layout = layout;
381 },
382
383 /**
384 * When double click/tap event is enabled, the second key-down and key-up
385 * events on the same key should be skipped. Return true when the event
386 * with |detail| should be skipped.
387 * @param {Object} detail The detail of key-up or key-down event.
388 */
389 skipEvent: function(detail) {
390 if (this.dblDetail_) {
391 if (this.dblDetail_.char != detail.char) {
392 // The second key down is not on the same key. Double click/tap
393 // should be ignored.
394 this.dblDetail_ = null;
395 clearTimeout(this.dblTimer_);
396 } else if (this.dblDetail_.clickCount == 1) {
397 return true;
398 }
399 }
400 return false;
401 },
402
403 /**
404 * Handles a swipe update.
405 * param {Object} detail The swipe update details.
406 */
407 onSwipeUpdate: function(detail) {
408 var direction = detail.direction;
409 if (!direction)
410 console.error("Swipe direction cannot be: " + direction);
411 // Triggers swipe editting if it's a purely horizontal swipe.
412 if (!(direction & (SwipeDirection.UP | SwipeDirection.DOWN))) {
413 // Nothing to do if the swipe has ended.
414 if (detail.endSwipe)
415 return;
416 var modifiers = 0;
417 // TODO (rsadam): This doesn't take into account index shifts caused
418 // by vertical swipes.
419 if (detail.index % 2 != 0) {
420 modifiers |= Modifier.SHIFT;
421 modifiers |= Modifier.CONTROL;
422 }
423 MoveCursor(direction, modifiers);
424 return;
425 }
426 // Triggers swipe hintText if it's a purely vertical swipe.
427 if (this.activeKeyset.flick &&
428 !(direction & (SwipeDirection.LEFT | SwipeDirection.RIGHT))) {
429 // Check if event is relevant to us.
430 if ((!detail.endSwipe) || (detail.isComplex))
431 return;
432 // Too long a swipe.
433 var distance = Math.abs(detail.startEvent.screenY -
434 detail.currentEvent.screenY);
435 if (distance > MAX_SWIPE_FLICK_DIST)
436 return;
437 var triggerKey = detail.startEvent.target;
438 if (triggerKey && triggerKey.onFlick)
439 triggerKey.onFlick(detail);
440 }
441 },
442
443 /**
444 * This function is bound to swipeHandler. Updates the current swipe
445 * status so that PointerEvents can be converted to Swipe events.
446 * @param {PointerEvent} event.
447 */
448 move: function(event) {
449 if (!swipeTracker.update(event))
450 return;
451 // Conversion was successful, swipe is now in progress.
452 swipeInProgress = true;
453 if (this.lastPressedKey) {
454 this.lastPressedKey.classList.remove('active');
455 this.lastPressedKey = null;
456 }
457 this.onSwipeUpdate(swipeTracker.populateDetails(false));
458 },
459
460 /**
461 * Handles key-down event that is sent by kb-key-base.
462 * @param {CustomEvent} event The key-down event dispatched by
463 * kb-key-base.
464 * @param {Object} detail The detail of pressed kb-key.
465 */
466 keyDown: function(event, detail) {
467 if (this.skipEvent(detail))
468 return;
469
470 if (this.lastPressedKey) {
471 this.lastPressedKey.classList.remove('active');
472 this.lastPressedKey.autoRelease();
473 }
474 this.lastPressedKey = event.target;
475 this.lastPressedKey.classList.add('active');
476 repeatKey.cancel();
477 this.playSound(detail.sound);
478
479 var char = detail.char;
480 switch(char) {
481 case 'Shift':
482 this.classList.remove('caps-locked');
483 break;
484 case 'Alt':
485 case 'Ctrl':
486 var modifier = char.toLowerCase() + "-active";
487 // Removes modifier if already active.
488 if (this.classList.contains(modifier))
489 this.classList.remove(modifier);
490 break;
491 case 'Invalid':
492 // Not all Invalid keys are transition keys. Reset control keys if
493 // we pressed a transition key.
494 if (event.target.toKeyset || detail.relegateToShift)
495 this.onNonControlKeyTyped();
496 break;
497 default:
498 // Notify shift key.
499 if (this.shift)
500 this.shift.onNonControlKeyDown();
501 if (this.ctrl)
502 this.ctrl.onNonControlKeyDown();
503 if (this.alt)
504 this.alt.onNonControlKeyDown();
505 break;
506 }
507 if(this.changeKeyset(detail))
508 return;
509 if (detail.repeat) {
510 this.keyTyped(detail);
511 this.onNonControlKeyTyped();
512 repeatKey.key = this.lastPressedKey;
513 var self = this;
514 repeatKey.timer = setTimeout(function() {
515 repeatKey.timer = undefined;
516 repeatKey.interval = setInterval(function() {
517 self.playSound(detail.sound);
518 self.keyTyped(detail);
519 }, REPEAT_INTERVAL_MSEC);
520 }, Math.max(0, REPEAT_DELAY_MSEC - REPEAT_INTERVAL_MSEC));
521 }
522 },
523
524 /**
525 * Handles key-out event that is sent by kb-shift-key.
526 * @param {CustomEvent} event The key-out event dispatched by
527 * kb-shift-key.
528 * @param {Object} detail The detail of pressed kb-shift-key.
529 */
530 keyOut: function(event, detail) {
531 this.changeKeyset(detail);
532 },
533
534 /**
535 * Enable/start double click/tap event recognition.
536 * @param {CustomEvent} event The enable-dbl event dispatched by
537 * kb-shift-key.
538 * @param {Object} detail The detail of pressed kb-shift-key.
539 */
540 enableDbl: function(event, detail) {
541 if (!this.dblDetail_) {
542 this.dblDetail_ = detail;
543 this.dblDetail_.clickCount = 0;
544 var self = this;
545 this.dblTimer_ = setTimeout(function() {
546 self.dblDetail_.callback = null;
547 self.dblDetail_ = null;
548 }, DBL_INTERVAL_MSEC);
549 }
550 },
551
552 /**
553 * Enable the selection while swipe.
554 * @param {CustomEvent} event The enable-dbl event dispatched by
555 * kb-shift-key.
556 */
557 enableSel: function(event) {
558 // TODO(rsadam): Disabled for now. May come back if we revert swipe
559 // selection to not do word selection.
560 },
561
562 /**
563 * Handles pointerdown event. This is used for swipe selection process.
564 * to get the start pre_x and pre_y. And also add a pointermove handler
565 * to start handling the swipe selection event.
566 * @param {PointerEvent} event The pointerup event that received by
567 * kb-keyboard.
568 */
569 down: function(event) {
570 var layout = getKeysetLayout(this.activeKeysetId);
571 var key = layout.findClosestKey(event.clientX, event.clientY);
572 if (key)
573 key.down(event);
574 if (event.isPrimary) {
575 swipeTracker.pre_x = event.screenX;
576 swipeTracker.pre_y = event.screenY;
577 this.addEventListener("pointermove", this.swipeHandler, false);
578 }
579 },
580
581 /**
582 * Handles pointerup event. This is used for double tap/click events.
583 * @param {PointerEvent} event The pointerup event that bubbled to
584 * kb-keyboard.
585 */
586 up: function(event) {
587 var layout = getKeysetLayout(this.activeKeysetId);
588 var key = layout.findClosestKey(event.clientX, event.clientY);
589 if (key)
590 key.up(event);
591 // When touch typing, it is very possible that finger moves slightly out
592 // of the key area before releases. The key should not be dropped in
593 // this case.
594 // TODO(rsadam@) Change behaviour such that the key drops and the second
595 // key gets pressed.
596 if (this.lastPressedKey &&
597 this.lastPressedKey.pointerId == event.pointerId) {
598 this.lastPressedKey.autoRelease();
599 }
600
601 if (this.dblDetail_) {
602 this.dblDetail_.clickCount++;
603 if (this.dblDetail_.clickCount == 2) {
604 this.dblDetail_.callback();
605 this.changeKeyset(this.dblDetail_);
606 clearTimeout(this.dblTimer_);
607
608 this.classList.add('caps-locked');
609
610 this.dblDetail_ = null;
611 }
612 }
613
614 // TODO(zyaozhujun): There are some edge cases to deal with later.
615 // (for instance, what if a second finger trigger a down and up
616 // event sequence while swiping).
617 // When pointer up from the screen, a swipe selection session finished,
618 // all the data should be reset to prepare for the next session.
619 if (event.isPrimary && swipeInProgress) {
620 swipeInProgress = false;
621 this.onSwipeUpdate(swipeTracker.populateDetails(true))
622 swipeTracker.resetAll();
623 }
624 this.removeEventListener('pointermove', this.swipeHandler, false);
625 },
626
627 /**
628 * Handles PointerOut event. This is used for when a swipe gesture goes
629 * outside of the keyboard window.
630 * @param {Object} event The pointerout event that bubbled to the
631 * kb-keyboard.
632 */
633 out: function(event) {
634 repeatKey.cancel();
635 // Ignore if triggered from one of the keys.
636 if (this.compareDocumentPosition(event.relatedTarget) &
637 Node.DOCUMENT_POSITION_CONTAINED_BY)
638 return;
639 if (swipeInProgress)
640 this.onSwipeUpdate(swipeTracker.populateDetails(true))
641 // Touched outside of the keyboard area, so disables swipe.
642 swipeInProgress = false;
643 swipeTracker.resetAll();
644 this.removeEventListener('pointermove', this.swipeHandler, false);
645 },
646
647 /**
648 * Handles a TypeKey event. This is used for when we programmatically
649 * want to type a specific key.
650 * @param {CustomEvent} event The TypeKey event that bubbled to the
651 * kb-keyboard.
652 */
653 type: function(event) {
654 this.keyTyped(event.detail);
655 },
656
657 /**
658 * Handles key-up event that is sent by kb-key-base.
659 * @param {CustomEvent} event The key-up event dispatched by kb-key-base.
660 * @param {Object} detail The detail of pressed kb-key.
661 */
662 keyUp: function(event, detail) {
663 if (this.skipEvent(detail))
664 return;
665 if (swipeInProgress)
666 return;
667 if (detail.activeModifier) {
668 var modifier = detail.activeModifier.toLowerCase() + "-active";
669 this.classList.add(modifier);
670 }
671 // Adds the current keyboard modifiers to the detail.
672 if (this.ctrl)
673 detail.controlModifier = this.ctrl.isActive();
674 if (this.alt)
675 detail.altModifier = this.alt.isActive();
676 if (this.lastPressedKey)
677 this.lastPressedKey.classList.remove('active');
678 // Keyset transition key. This is needed to transition from upper
679 // to lower case when we are not in caps mode, as well as when
680 // we're ending chording.
681 this.changeKeyset(detail);
682
683 if (this.lastPressedKey &&
684 this.lastPressedKey.charValue != event.target.charValue) {
685 return;
686 }
687 if (repeatKey.key == event.target) {
688 repeatKey.cancel();
689 this.lastPressedKey = null;
690 return;
691 }
692 var toLayoutId = detail.toLayout;
693 // Layout transition key.
694 if (toLayoutId)
695 this.layout = toLayoutId;
696 var char = detail.char;
697 this.lastPressedKey = null;
698 // Characters that should not be typed.
699 switch(char) {
700 case 'Invalid':
701 case 'Shift':
702 case 'Ctrl':
703 case 'Alt':
704 enterUpperOnSpace = false;
705 swipeTracker.swipeFlags = 0;
706 return;
707 case 'Microphone':
708 this.voiceInput_.onDown();
709 return;
710 default:
711 break;
712 }
713 // Tries to type the character. Resorts to insertText if that fails.
714 if(!this.keyTyped(detail))
715 insertText(char);
716 // Post-typing logic.
717 switch(char) {
718 case '\n':
719 case ' ':
720 if(enterUpperOnSpace) {
721 enterUpperOnSpace = false;
722 if (this.shift) {
723 var shiftDetail = this.shift.onSpaceAfterPunctuation();
724 // Check if transition defined.
725 this.changeKeyset(shiftDetail);
726 } else {
727 console.error('Capitalization on space after punctuation \
728 enabled, but cannot find target keyset.');
729 }
730 // Immediately return to maintain shift-state. Space is a
731 // non-control key and would otherwise trigger a reset of the
732 // shift key, causing a transition to lower case.
733 return;
734 }
735 break;
736 case '.':
737 case '?':
738 case '!':
739 enterUpperOnSpace = this.shouldUpperOnSpace();
740 break;
741 default:
742 enterUpperOnSpace = false;
743 break;
744 }
745 // Reset control keys.
746 this.onNonControlKeyTyped();
747 },
748
749 /**
750 * Handles key-longpress event that is sent by kb-key-base.
751 * @param {CustomEvent} event The key-longpress event dispatched by
752 * kb-key-base.
753 * @param {Object} detail The detail of pressed key.
754 */
755 keyLongpress: function(event, detail) {
756 // If the gesture is long press, remove the pointermove listener.
757 this.removeEventListener('pointermove', this.swipeHandler, false);
758 // Keyset transtion key.
759 if (this.changeKeyset(detail)) {
760 // Locks the keyset before removing active to prevent flicker.
761 this.classList.add('caps-locked');
762 // Makes last pressed key inactive if transit to a new keyset on long
763 // press.
764 if (this.lastPressedKey)
765 this.lastPressedKey.classList.remove('active');
766 }
767 },
768
769 /**
770 * Plays the specified sound.
771 * @param {Sound} sound The id of the audio tag.
772 */
773 playSound: function(sound) {
774 if (!SOUND_ENABLED || !sound || sound == Sound.NONE)
775 return;
776 var pool = this.sounds[sound];
777 if (!pool) {
778 console.error("Cannot find audio tag: " + sound);
779 return;
780 }
781 // Search the sound pool for a free resource.
782 for (var i = 0; i < pool.length; i++) {
783 if (pool[i].paused) {
784 pool[i].play();
785 return;
786 }
787 }
788 },
789
790 /**
791 * Whether we should transit to upper case when seeing a space after
792 * punctuation.
793 * @return {boolean}
794 */
795 shouldUpperOnSpace: function() {
796 // TODO(rsadam): Add other input types in which we should not
797 // transition to upper after a space.
798 return this.inputTypeValue != 'password';
799 },
800
801 /**
802 * Handler for the 'set-layout' event.
803 * @param {!Event} event The triggering event.
804 * @param {{layout: string}} details Details of the event, which contains
805 * the name of the layout to activate.
806 */
807 setLayout: function(event, details) {
808 this.layout = details.layout;
809 },
810
811 /**
812 * Handles a change in the keyboard layout. Auto-selects the default
813 * keyset for the new layout.
814 */
815 layoutChanged: function() {
816 this.stale = true;
817 if (!this.selectDefaultKeyset()) {
818 console.error('No default keyset found for layout: ' + this.layout);
819 return;
820 }
821 this.activeKeyset.show();
822 },
823
824 /**
825 * Notifies the modifier keys that a non-control key was typed. This
826 * lets them reset sticky behaviour. A non-control key is defined as
827 * any key that is not Control, Alt, or Shift.
828 */
829 onNonControlKeyTyped: function() {
830 if (this.shift)
831 this.shift.onNonControlKeyTyped();
832 if (this.ctrl)
833 this.ctrl.onNonControlKeyTyped();
834 if (this.alt)
835 this.alt.onNonControlKeyTyped();
836 this.classList.remove('ctrl-active');
837 this.classList.remove('alt-active');
838 },
839
840 /**
841 * Callback function for when volume is changed.
842 */
843 volumeChanged: function() {
844 var toChange = Object.keys(this.sounds);
845 for (var i = 0; i < toChange.length; i++) {
846 var pool = this.sounds[toChange[i]];
847 for (var j = 0; j < pool.length; j++) {
848 pool[j].volume = this.volume;
849 }
850 }
851 },
852
853 /**
854 * Id for the active keyset.
855 * @type {string}
856 */
857 get activeKeysetId() {
858 return this.layout + '-' + this.keyset;
859 },
860
861 /**
862 * The active keyset DOM object.
863 * @type {kb-keyset}
864 */
865 get activeKeyset() {
866 return this.querySelector('#' + this.activeKeysetId);
867 },
868
869 /**
870 * The current input type.
871 * @type {string}
872 */
873 get inputTypeValue() {
874 return this.inputType;
875 },
876
877 /**
878 * Changes the input type if it's different from the current
879 * type, else resets the keyset to the default keyset.
880 * @type {string}
881 */
882 set inputTypeValue(value) {
883 if (value == this.inputType)
884 this.selectDefaultKeyset();
885 else
886 this.inputType = value;
887 },
888
889 /**
890 * The keyboard is ready for input once the target keyset appears
891 * in the distributed nodes for the keyboard.
892 * @return {boolean} Indicates if the keyboard is ready for input.
893 */
894 isReady: function() {
895 var keyset = this.activeKeyset;
896 if (!keyset)
897 return false;
898 var nodes = this.$.content.getDistributedNodes();
899 for (var i = 0; i < nodes.length; i++) {
900 if (nodes[i].id && nodes[i].id == keyset.id)
901 return true;
902 }
903 return false;
904 },
905
906 /**
907 * Generates fabricated key events to simulate typing on a
908 * physical keyboard.
909 * @param {Object} detail Attributes of the key being typed.
910 * @return {boolean} Whether the key type succeeded.
911 */
912 keyTyped: function(detail) {
913 var builder = this.$.keyCodeMetadata;
914 if (this.ctrl)
915 detail.controlModifier = this.ctrl.isActive();
916 if (this.alt)
917 detail.altModifier = this.alt.isActive();
918 var downEvent = builder.createVirtualKeyEvent(detail, "keydown");
919 if (downEvent) {
920 sendKeyEvent(downEvent);
921 sendKeyEvent(builder.createVirtualKeyEvent(detail, "keyup"));
922 return true;
923 }
924 return false;
925 },
926
927 /**
928 * Selects the default keyset for a layout.
929 * @return {boolean} True if successful. This method can fail if the
930 * keysets corresponding to the layout have not been injected.
931 */
932 selectDefaultKeyset: function() {
933 var keysets = this.querySelectorAll('kb-keyset');
934 // Full name of the keyset is of the form 'layout-keyset'.
935 var regex = new RegExp('^' + this.layout + '-(.+)');
936 var keysetsLoaded = false;
937 for (var i = 0; i < keysets.length; i++) {
938 var matches = keysets[i].id.match(regex);
939 if (matches && matches.length == REGEX_MATCH_COUNT) {
940 keysetsLoaded = true;
941 // Without both tests for a default keyset, it is possible to get
942 // into a state where multiple layouts are displayed. A
943 // reproducable test case is do the following set of keyset
944 // transitions: qwerty -> system -> dvorak -> qwerty.
945 // TODO(kevers): Investigate why this is the case.
946 if (keysets[i].isDefault ||
947 keysets[i].getAttribute('isDefault') == 'true') {
948 this.keyset = matches[REGEX_KEYSET_INDEX];
949 this.classList.remove('caps-locked');
950 this.classList.remove('alt-active');
951 this.classList.remove('ctrl-active');
952 // Caches shift key.
953 this.shift = this.querySelector('kb-shift-key');
954 if (this.shift)
955 this.shift.reset();
956 // Caches control key.
957 this.ctrl = this.querySelector('kb-modifier-key[char=Ctrl]');
958 if (this.ctrl)
959 this.ctrl.reset();
960 // Caches alt key.
961 this.alt = this.querySelector('kb-modifier-key[char=Alt]');
962 if (this.alt)
963 this.alt.reset();
964 this.fire('stateChange', {
965 state: 'keysetLoaded',
966 value: this.keyset,
967 });
968 keyboardLoaded();
969 return true;
970 }
971 }
972 }
973 if (keysetsLoaded)
974 console.error('No default keyset found for ' + this.layout);
975 return false;
976 }
977 });
OLDNEW
« no previous file with comments | « ui/keyboard/resources/elements/kb-keyboard.html ('k') | ui/keyboard/resources/elements/kb-keyset.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698