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.
8 * The possible states of the shift key.
9 * Unlocked is the default state. Locked for capslocked, pressed is a
10 * key-down and tapped for a key-down followed by an immediate key-up.
15 PRESSED
: "pressed", // Key-down on shift key.
16 LOCKED
: "locked", // Key is capslocked.
17 UNLOCKED
: "unlocked", // Default state.
18 TAPPED
: "tapped", // Key-down followed by key-up.
19 CHORDING
: "chording" // Key-down followed by other keys.
23 * The pointerdown event on shiftkey that may eventually trigger chording
24 * state. pointerId and eventTarget are the two fields that is used now.
25 * @type {PointerEvent}
27 var enterChordingEvent
= undefined;
30 * Uses a closure to define one long press timer among all shift keys
31 * regardless of the layout they are in.
34 var shiftLongPressTimer
= undefined;
37 * The current state of the shift key.
40 var state
= KEY_STATES
.UNLOCKED
;
42 Polymer('kb-shift-key', {
44 * Defines how capslock effects keyset transition. We always transition
45 * from the lowerCaseKeysetId to the upperCaseKeysetId if capslock is
49 lowerCaseKeysetId
: 'lower',
50 upperCaseKeysetId
: 'upper',
53 if (state
== KEY_STATES
.CHORDING
&&
54 event
.pointerId
!= enterChordingEvent
.pointerId
) {
55 // Disables all other pointer events on shift keys when chording.
59 case KEY_STATES
.PRESSED
:
60 state
= KEY_STATES
.TAPPED
;
62 case KEY_STATES
.CHORDING
:
63 // Leaves chording only if the pointer that triggered it is
65 state
= KEY_STATES
.UNLOCKED
;
70 // When releasing the shift key, it is not the same shift key that was
71 // pressed. Updates the pointerId of the releasing shift key to make
72 // sure key-up event fires correctly in kb-key-base.
73 this.pointerId
= enterChordingEvent
.pointerId
;
77 out: function(event
) {
78 // Sliding off the shift key while chording is treated as a key-up.
79 // Note that we switch to a new keyset on shift keydown, and a finger
80 // movement on the new shift key will trigger this function being
81 // called on the old shift key. We should not end chording in that
83 if (state
== KEY_STATES
.CHORDING
&&
84 event
.pointerId
== enterChordingEvent
.pointerId
&&
85 event
.target
!= enterChordingEvent
.target
) {
86 state
= KEY_STATES
.UNLOCKED
;
87 var detail
= this.populateDetails('out');
88 this.fire("key-out", detail
);
92 down: function(event
) {
93 // First transition state so that populateDetails generates
96 case KEY_STATES
.UNLOCKED
:
97 state
= KEY_STATES
.PRESSED
;
99 case KEY_STATES
.TAPPED
:
100 case KEY_STATES
.LOCKED
:
101 state
= KEY_STATES
.UNLOCKED
;
103 case KEY_STATES
.PRESSED
:
104 case KEY_STATES
.CHORDING
:
105 // We pressed another shift key at the same time,
106 // so ignore second press.
109 console
.error("Undefined shift key state: " + state
);
112 enterChordingEvent
= event
;
113 // Trigger parent behaviour.
115 this.fire('enable-sel');
116 // Populate double click transition details.
118 detail
.char = this.char || this.textContent
;
119 detail
.toKeyset
= this.upperCaseKeysetId
;
120 detail
.nextKeyset
= undefined;
121 detail
.callback
= this.onDoubleClick
;
122 this.fire('enable-dbl', detail
);
125 generateLongPressTimer: function() {
126 return this.async(function() {
127 var detail
= this.populateDetails();
128 if (state
== KEY_STATES
.LOCKED
) {
129 // We don't care about the longpress if we are already
133 state
= KEY_STATES
.LOCKED
;
134 detail
.toKeyset
= this.upperCaseKeysetId
;
135 detail
.nextKeyset
= undefined;
137 this.fire('key-longpress', detail
);
138 }, null, LONGPRESS_DELAY_MSEC
);
141 // @return Whether the shift modifier is currently active.
142 isActive: function() {
143 return state
!= KEY_STATES
.UNLOCKED
;
147 * Callback function for when a double click is triggered.
149 onDoubleClick: function() {
150 state
= KEY_STATES
.LOCKED
;
154 * Notifies shift key that a non-control key was pressed down.
155 * A control key is defined as one of shift, control or alt.
157 onNonControlKeyDown: function() {
159 case (KEY_STATES
.PRESSED
):
160 state
= KEY_STATES
.CHORDING
;
161 // Disable longpress timer.
162 clearTimeout(shiftLongPressTimer
);
170 * Notifies key that a non-control keyed was typed.
171 * A control key is defined as one of shift, control or alt.
173 onNonControlKeyTyped: function() {
174 if (state
== KEY_STATES
.TAPPED
)
175 state
= KEY_STATES
.UNLOCKED
;
179 * Callback function for when a space is pressed after punctuation.
180 * @return {Object} The keyset transitions the keyboard should make.
182 onSpaceAfterPunctuation: function() {
184 detail
.toKeyset
= this.upperCaseKeysetId
;
185 detail
.nextKeyset
= this.lowerCaseKeysetId
;
186 state
= KEY_STATES
.TAPPED
;
190 populateDetails: function(caller
) {
191 var detail
= this.super([caller
]);
193 case(KEY_STATES
.LOCKED
):
194 detail
.toKeyset
= this.upperCaseKeysetId
;
196 case(KEY_STATES
.UNLOCKED
):
197 detail
.toKeyset
= this.lowerCaseKeysetId
;
199 case(KEY_STATES
.PRESSED
):
200 detail
.toKeyset
= this.upperCaseKeysetId
;
202 case(KEY_STATES
.TAPPED
):
203 detail
.toKeyset
= this.upperCaseKeysetId
;
204 detail
.nextKeyset
= this.lowerCaseKeysetId
;
206 case(KEY_STATES
.CHORDING
):
207 detail
.toKeyset
= this.lowerCaseKeysetId
;
216 * Resets the shift key state.
219 state
= KEY_STATES
.UNLOCKED
;
223 * Overrides longPressTimer for the shift key.
225 get longPressTimer() {
226 return shiftLongPressTimer
;
229 set longPressTimer(timer
) {
230 shiftLongPressTimer
= timer
;
239 case KEY_STATES
.UNLOCKED
:
240 return this.lowerCaseKeysetId
;
242 return this.upperCaseKeysetId
;