diff options
Diffstat (limited to 'chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js')
-rw-r--r-- | chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js | 633 |
1 files changed, 0 insertions, 633 deletions
diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js b/chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js deleted file mode 100644 index 0a6f3d51c01..00000000000 --- a/chromium/chrome/browser/resources/chromeos/chromevox/common/key_sequence.js +++ /dev/null @@ -1,633 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview A JavaScript class that represents a sequence of keys entered - * by the user. - */ - - -goog.provide('cvox.KeySequence'); - -goog.require('cvox.ChromeVox'); -goog.require('cvox.PlatformFilter'); - - -/** - * A class to represent a sequence of keys entered by a user or affiliated with - * a ChromeVox command. - * This class can represent the data from both types of key sequences: - * - * COMMAND KEYS SPECIFIED IN A KEYMAP: - * - Two discrete keys (at most): [Down arrow], [A, A] or [O, W] etc. Can - * specify one or both. - * - Modifiers (like ctrl, alt, meta, etc) - * - Whether or not the ChromeVox modifier key is required with the command. - * - * USER INPUT: - * - Two discrete keys (at most): [Down arrow], [A, A] or [O, W] etc. - * - Modifiers (like ctlr, alt, meta, etc) - * - Whether or not the ChromeVox modifier key was active when the keys were - * entered. - * - Whether or not a prefix key was entered before the discrete keys. - * - Whether sticky mode was active. - * @param {Event|Object} originalEvent The original key event entered by a user. - * The originalEvent may or may not have parameters stickyMode and keyPrefix - * specified. We will also accept an event-shaped object. - * @param {boolean=} opt_cvoxModifier Whether or not the ChromeVox modifier key - * is active. If not specified, we will try to determine whether the modifier - * was active by looking at the originalEvent. - * @param {boolean=} opt_skipStripping Skips stripping of ChromeVox modifiers - * from key events when the cvox modifiers are set. Defaults to false. - * @param {boolean=} opt_doubleTap Whether this is triggered via double tap. - * @constructor - */ -cvox.KeySequence = function( - originalEvent, opt_cvoxModifier, opt_skipStripping, opt_doubleTap) { - /** @type {boolean} */ - this.doubleTap = !!opt_doubleTap; - - /** @type {cvox.PlatformFilter} */ - this.platformFilter; - - if (opt_cvoxModifier == undefined) { - this.cvoxModifier = this.isCVoxModifierActive(originalEvent); - } else { - this.cvoxModifier = opt_cvoxModifier; - } - this.stickyMode = !!originalEvent['stickyMode']; - this.prefixKey = !!originalEvent['keyPrefix']; - this.skipStripping = !!opt_skipStripping; - - if (this.stickyMode && this.prefixKey) { - throw 'Prefix key and sticky mode cannot both be enabled: ' + originalEvent; - } - - var event = this.resolveChromeOSSpecialKeys_(originalEvent); - - // TODO (rshearer): We should take the user out of sticky mode if they - // try to use the CVox modifier or prefix key. - - /** - * Stores the key codes and modifiers for the keys in the key sequence. - * TODO(rshearer): Consider making this structure an array of minimal - * keyEvent-like objects instead so we don't have to worry about what happens - * when ctrlKey.length is different from altKey.length. - * - * NOTE: If a modifier key is pressed by itself, we will store the keyCode - * *and* set the appropriate modKey to be true. This mirrors the way key - * events are created on Mac and Windows. For example, if the Meta key was - * pressed by itself, the keys object will have: - * {metaKey: [true], keyCode:[91]} - * - * @type {Object} - */ - this.keys = { - ctrlKey: [], - searchKeyHeld: [], - altKey: [], - altGraphKey: [], - shiftKey: [], - metaKey: [], - keyCode: [] - }; - - this.extractKey_(event); -}; - - -// TODO(dtseng): This is incomplete; pull once we have appropriate libs. -/** - * Maps a keypress keycode to a keydown or keyup keycode. - * @type {Object<number, number>} - */ -cvox.KeySequence.KEY_PRESS_CODE = { - 39: 222, - 44: 188, - 45: 189, - 46: 190, - 47: 191, - 59: 186, - 91: 219, - 92: 220, - 93: 221 -}; - -/** - * A cache of all key sequences that have been set as double-tappable. We need - * this cache because repeated key down computations causes ChromeVox to become - * less responsive. This list is small so we currently use an array. - * @type {!Array<cvox.KeySequence>} - */ -cvox.KeySequence.doubleTapCache = []; - - -/** - * Adds an additional key onto the original sequence, for use when the user - * is entering two shortcut keys. This happens when the user presses a key, - * releases it, and then presses a second key. Those two keys together are - * considered part of the sequence. - * @param {Event|Object} additionalKeyEvent The additional key to be added to - * the original event. Should be an event or an event-shaped object. - * @return {boolean} Whether or not we were able to add a key. Returns false - * if there are already two keys attached to this event. - */ -cvox.KeySequence.prototype.addKeyEvent = function(additionalKeyEvent) { - if (this.keys.keyCode.length > 1) { - return false; - } - this.extractKey_(additionalKeyEvent); - return true; -}; - - -/** - * Check for equality. Commands are matched based on the actual key codes - * involved and on whether or not they both require a ChromeVox modifier key. - * - * If sticky mode or a prefix is active on one of the commands but not on - * the other, then we try and match based on key code first. - * - If both commands have the same key code and neither of them have the - * ChromeVox modifier active then we have a match. - * - Next we try and match with the ChromeVox modifier. If both commands have - * the same key code, and one of them has the ChromeVox modifier and the other - * has sticky mode or an active prefix, then we also have a match. - * @param {!cvox.KeySequence} rhs The key sequence to compare against. - * @return {boolean} True if equal. - */ -cvox.KeySequence.prototype.equals = function(rhs) { - // Check to make sure the same keys with the same modifiers were pressed. - if (!this.checkKeyEquality_(rhs)) { - return false; - } - - if (this.doubleTap != rhs.doubleTap) { - return false; - } - - // So now we know the actual keys are the same. - // If they both have the ChromeVox modifier, or they both don't have the - // ChromeVox modifier, then they are considered equal. - if (this.cvoxModifier === rhs.cvoxModifier) { - return true; - } - - // So only one of them has the ChromeVox modifier. If the one that doesn't - // have the ChromeVox modifier has sticky mode or the prefix key then the - // keys are still considered equal. - var unmodified = this.cvoxModifier ? rhs : this; - return unmodified.stickyMode || unmodified.prefixKey; -}; - - -/** - * Utility method that extracts the key code and any modifiers from a given - * event and adds them to the object map. - * @param {Event|Object} keyEvent The keyEvent or event-shaped object to extract - * from. - * @private - */ -cvox.KeySequence.prototype.extractKey_ = function(keyEvent) { - for (var prop in this.keys) { - if (prop == 'keyCode') { - var keyCode; - // TODO (rshearer): This is temporary until we find a library that can - // convert between ASCII charcodes and keycodes. - if (keyEvent.type == 'keypress' && keyEvent[prop] >= 97 && - keyEvent[prop] <= 122) { - // Alphabetic keypress. Convert to the upper case ASCII code. - keyCode = keyEvent[prop] - 32; - } else if (keyEvent.type == 'keypress') { - keyCode = cvox.KeySequence.KEY_PRESS_CODE[keyEvent[prop]]; - } - this.keys[prop].push(keyCode || keyEvent[prop]); - } else { - if (this.isKeyModifierActive(keyEvent, prop)) { - this.keys[prop].push(true); - } else { - this.keys[prop].push(false); - } - } - } - if (this.cvoxModifier) { - this.rationalizeKeys_(); - } -}; - - -/** - * Rationalizes the key codes and the ChromeVox modifier for this keySequence. - * This means we strip out the key codes and key modifiers stored for this - * KeySequence that are also present in the ChromeVox modifier. For example, if - * the ChromeVox modifier keys are Ctrl+Alt, and we've determined that the - * ChromeVox modifier is active (meaning the user has pressed Ctrl+Alt), we - * don't want this.keys.ctrlKey = true also because that implies that this - * KeySequence involves the ChromeVox modifier and the ctrl key being held down - * together, which doesn't make any sense. - * @private - */ -cvox.KeySequence.prototype.rationalizeKeys_ = function() { - if (this.skipStripping) { - return; - } - - // TODO (rshearer): This is a hack. When the modifier key becomes customizable - // then we will not have to deal with strings here. - var modifierKeyCombo = cvox.ChromeVox.modKeyStr.split(/\+/g); - - var index = this.keys.keyCode.length - 1; - // For each modifier that is part of the CVox modifier, remove it from keys. - if (modifierKeyCombo.indexOf('Ctrl') != -1) { - this.keys.ctrlKey[index] = false; - } - if (modifierKeyCombo.indexOf('Alt') != -1) { - this.keys.altKey[index] = false; - } - if (modifierKeyCombo.indexOf('Shift') != -1) { - this.keys.shiftKey[index] = false; - } - var metaKeyName = this.getMetaKeyName_(); - if (modifierKeyCombo.indexOf(metaKeyName) != -1) { - if (metaKeyName == 'Search') { - this.keys.searchKeyHeld[index] = false; - // TODO(dmazzoni): http://crbug.com/404763 Get rid of the code that - // tracks the search key and just use meta everywhere. - this.keys.metaKey[index] = false; - } else if (metaKeyName == 'Cmd' || metaKeyName == 'Win') { - this.keys.metaKey[index] = false; - } - } -}; - - -/** - * Get the user-facing name for the meta key (keyCode = 91), which varies - * depending on the platform. - * @return {string} The user-facing string name for the meta key. - * @private - */ -cvox.KeySequence.prototype.getMetaKeyName_ = function() { - if (cvox.ChromeVox.isChromeOS) { - return 'Search'; - } else if (cvox.ChromeVox.isMac) { - return 'Cmd'; - } else { - return 'Win'; - } -}; - - -/** - * Utility method that checks for equality of the modifiers (like shift and alt) - * and the equality of key codes. - * @param {!cvox.KeySequence} rhs The key sequence to compare against. - * @return {boolean} True if the modifiers and key codes in the key sequence are - * the same. - * @private - */ -cvox.KeySequence.prototype.checkKeyEquality_ = function(rhs) { - for (var i in this.keys) { - for (var j = this.keys[i].length; j--;) { - if (this.keys[i][j] !== rhs.keys[i][j]) - return false; - } - } - return true; -}; - - -/** - * Gets first key code - * @return {number} The first key code. - */ -cvox.KeySequence.prototype.getFirstKeyCode = function() { - return this.keys.keyCode[0]; -}; - - -/** - * Gets the number of keys in the sequence. Should be 1 or 2. - * @return {number} The number of keys in the sequence. - */ -cvox.KeySequence.prototype.length = function() { - return this.keys.keyCode.length; -}; - - - -/** - * Checks if the specified key code represents a modifier key, i.e. Ctrl, Alt, - * Shift, Search (on ChromeOS) or Meta. - * - * @param {number} keyCode key code. - * @return {boolean} true if it is a modifier keycode, false otherwise. - */ -cvox.KeySequence.prototype.isModifierKey = function(keyCode) { - // Shift, Ctrl, Alt, Search/LWin - return keyCode == 16 || keyCode == 17 || keyCode == 18 || keyCode == 91 || - keyCode == 93; -}; - - -/** - * Determines whether the Cvox modifier key is active during the keyEvent. - * @param {Event|Object} keyEvent The keyEvent or event-shaped object to check. - * @return {boolean} Whether or not the modifier key was active during the - * keyEvent. - */ -cvox.KeySequence.prototype.isCVoxModifierActive = function(keyEvent) { - // TODO (rshearer): Update this when the modifier key becomes customizable - var modifierKeyCombo = cvox.ChromeVox.modKeyStr.split(/\+/g); - - // For each modifier that is held down, remove it from the combo. - // If the combo string becomes empty, then the user has activated the combo. - if (this.isKeyModifierActive(keyEvent, 'ctrlKey')) { - modifierKeyCombo = modifierKeyCombo.filter(function(modifier) { - return modifier != 'Ctrl'; - }); - } - if (this.isKeyModifierActive(keyEvent, 'altKey')) { - modifierKeyCombo = modifierKeyCombo.filter(function(modifier) { - return modifier != 'Alt'; - }); - } - if (this.isKeyModifierActive(keyEvent, 'shiftKey')) { - modifierKeyCombo = modifierKeyCombo.filter(function(modifier) { - return modifier != 'Shift'; - }); - } - if (this.isKeyModifierActive(keyEvent, 'metaKey') || - this.isKeyModifierActive(keyEvent, 'searchKeyHeld')) { - var metaKeyName = this.getMetaKeyName_(); - modifierKeyCombo = modifierKeyCombo.filter(function(modifier) { - return modifier != metaKeyName; - }); - } - return (modifierKeyCombo.length == 0); -}; - - -/** - * Determines whether a particular key modifier (for example, ctrl or alt) is - * active during the keyEvent. - * @param {Event|Object} keyEvent The keyEvent or Event-shaped object to check. - * @param {string} modifier The modifier to check. - * @return {boolean} Whether or not the modifier key was active during the - * keyEvent. - */ -cvox.KeySequence.prototype.isKeyModifierActive = function(keyEvent, modifier) { - // We need to check the key event modifier and the keyCode because Linux will - // not set the keyEvent.modKey property if it is the modKey by itself. - // This bug filed as crbug.com/74044 - switch (modifier) { - case 'ctrlKey': - return (keyEvent.ctrlKey || keyEvent.keyCode == 17); - break; - case 'altKey': - return (keyEvent.altKey || (keyEvent.keyCode == 18)); - break; - case 'shiftKey': - return (keyEvent.shiftKey || (keyEvent.keyCode == 16)); - break; - case 'metaKey': - return (keyEvent.metaKey || (keyEvent.keyCode == 91)); - break; - case 'searchKeyHeld': - return ((cvox.ChromeVox.isChromeOS && keyEvent.keyCode == 91) || - keyEvent['searchKeyHeld']); - break; - } - return false; -}; - -/** - * Returns if any modifier is active in this sequence. - * @return {boolean} The result. - */ -cvox.KeySequence.prototype.isAnyModifierActive = function() { - for (var modifierType in this.keys) { - for (var i = 0; i < this.length(); i++) { - if (this.keys[modifierType][i] && modifierType != 'keyCode') { - return true; - } - } - } - return false; -}; - - -/** - * Creates a KeySequence event from a generic object. - * @param {Object} sequenceObject The object. - * @return {cvox.KeySequence} The created KeySequence object. - */ -cvox.KeySequence.deserialize = function(sequenceObject) { - var firstSequenceEvent = {}; - - firstSequenceEvent['stickyMode'] = (sequenceObject.stickyMode == undefined) ? - false : sequenceObject.stickyMode; - firstSequenceEvent['prefixKey'] = (sequenceObject.prefixKey == undefined) ? - false : sequenceObject.prefixKey; - - - var secondKeyPressed = sequenceObject.keys.keyCode.length > 1; - var secondSequenceEvent = {}; - - for (var keyPressed in sequenceObject.keys) { - firstSequenceEvent[keyPressed] = sequenceObject.keys[keyPressed][0]; - if (secondKeyPressed) { - secondSequenceEvent[keyPressed] = sequenceObject.keys[keyPressed][1]; - } - } - - var keySeq = new cvox.KeySequence(firstSequenceEvent, - sequenceObject.cvoxModifier, true, sequenceObject.doubleTap); - if (secondKeyPressed) { - cvox.ChromeVox.sequenceSwitchKeyCodes.push( - new cvox.KeySequence(firstSequenceEvent, sequenceObject.cvoxModifier)); - keySeq.addKeyEvent(secondSequenceEvent); - } - - if (sequenceObject.doubleTap) { - cvox.KeySequence.doubleTapCache.push(keySeq); - } - - return keySeq; -}; - - -/** - * Creates a KeySequence event from a given string. The string should be in the - * standard key sequence format described in keyUtil.keySequenceToString and - * used in the key map JSON files. - * @param {string} keyStr The string representation of a key sequence. - * @return {!cvox.KeySequence} The created KeySequence object. - */ -cvox.KeySequence.fromStr = function(keyStr) { - var sequenceEvent = {}; - var secondSequenceEvent = {}; - - var secondKeyPressed; - if (keyStr.indexOf('>') == -1) { - secondKeyPressed = false; - } else { - secondKeyPressed = true; - } - - var cvoxPressed = false; - sequenceEvent['stickyMode'] = false; - sequenceEvent['prefixKey'] = false; - - var tokens = keyStr.split('+'); - for (var i = 0; i < tokens.length; i++) { - var seqs = tokens[i].split('>'); - for (var j = 0; j < seqs.length; j++) { - if (seqs[j].charAt(0) == '#') { - var keyCode = parseInt(seqs[j].substr(1), 10); - if (j > 0) { - secondSequenceEvent['keyCode'] = keyCode; - } else { - sequenceEvent['keyCode'] = keyCode; - } - } - var keyName = seqs[j]; - if (seqs[j].length == 1) { - // Key is A/B/C...1/2/3 and we don't need to worry about setting - // modifiers. - if (j > 0) { - secondSequenceEvent['keyCode'] = seqs[j].charCodeAt(0); - } else { - sequenceEvent['keyCode'] = seqs[j].charCodeAt(0); - } - } else { - // Key is a modifier key - if (j > 0) { - cvox.KeySequence.setModifiersOnEvent_(keyName, secondSequenceEvent); - if (keyName == 'Cvox') { - cvoxPressed = true; - } - } else { - cvox.KeySequence.setModifiersOnEvent_(keyName, sequenceEvent); - if (keyName == 'Cvox') { - cvoxPressed = true; - } - } - } - } - } - var keySeq = new cvox.KeySequence(sequenceEvent, cvoxPressed); - if (secondKeyPressed) { - keySeq.addKeyEvent(secondSequenceEvent); - } - return keySeq; -}; - - -/** - * Utility method for populating the modifiers on an event object that will be - * used to create a KeySequence. - * @param {string} keyName A particular modifier key name (such as 'Ctrl'). - * @param {Object} seqEvent The event to populate. - * @private - */ -cvox.KeySequence.setModifiersOnEvent_ = function(keyName, seqEvent) { - if (keyName == 'Ctrl') { - seqEvent['ctrlKey'] = true; - seqEvent['keyCode'] = 17; - } else if (keyName == 'Alt') { - seqEvent['altKey'] = true; - seqEvent['keyCode'] = 18; - } else if (keyName == 'Shift') { - seqEvent['shiftKey'] = true; - seqEvent['keyCode'] = 16; - } else if (keyName == 'Search') { - seqEvent['searchKeyHeld'] = true; - seqEvent['keyCode'] = 91; - } else if (keyName == 'Cmd') { - seqEvent['metaKey'] = true; - seqEvent['keyCode'] = 91; - } else if (keyName == 'Win') { - seqEvent['metaKey'] = true; - seqEvent['keyCode'] = 91; - } else if (keyName == 'Insert') { - seqEvent['keyCode'] = 45; - } -}; - - -/** - * Used to resolve special ChromeOS keys (see link for more detail). - * http://crbug.com/162268 - * @param {Object} originalEvent The event. - * @return {Object} The resolved event. - * @private - */ -cvox.KeySequence.prototype.resolveChromeOSSpecialKeys_ = - function(originalEvent) { - if (!this.cvoxModifier || this.stickyMode || this.prefixKey || - !cvox.ChromeVox.isChromeOS) { - return originalEvent; - } - var evt = {}; - for (var key in originalEvent) { - evt[key] = originalEvent[key]; - } - switch (evt['keyCode']) { - case 33: // Page up. - evt['keyCode'] = 38; // Up arrow. - break; - case 34: // Page down. - evt['keyCode'] = 40; // Down arrow. - break; - case 35: // End. - evt['keyCode'] = 39; // Right arrow. - break; - case 36: // Home. - evt['keyCode'] = 37; // Left arrow. - break; - case 45: // Insert. - evt['keyCode'] = 190; // Period. - break; - case 46: // Delete. - evt['keyCode'] = 8; // Backspace. - break; - case 112: // F1. - evt['keyCode'] = 49; // 1. - break; - case 113: // F2. - evt['keyCode'] = 50; // 2. - break; - case 114: // F3. - evt['keyCode'] = 51; // 3. - break; - case 115: // F4. - evt['keyCode'] = 52; // 4. - break; - case 116: // F5. - evt['keyCode'] = 53; // 5. - break; - case 117: // F6. - evt['keyCode'] = 54; // 6. - break; - case 118: // F7. - evt['keyCode'] = 55; // 7. - break; - case 119: // F8. - evt['keyCode'] = 56; // 8. - break; - case 120: // F9. - evt['keyCode'] = 57; // 9. - break; - case 121: // F10. - evt['keyCode'] = 48; // 0. - break; - case 122: // F11 - evt['keyCode'] = 189; // Hyphen. - break; - case 123: // F12 - evt['keyCode'] = 187; // Equals. - break; - } - return evt; -}; |