blob: 327f8c9c084ab89bd587cdde9e640519d066a6cc [file] [log] [blame]
// 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.
goog.provide('ChromeVoxKbHandler');
goog.require('ChromeVox');
goog.require('KeyMap');
goog.require('KeySequence');
goog.require('KeyUtil');
goog.require('ChromeVoxState');
/**
* @fileoverview Handles user keyboard input events.
*
*/
ChromeVoxKbHandler = {};
/**
* The key map
*
* @type {!KeyMap}
*/
ChromeVoxKbHandler.handlerKeyMap = KeyMap.get();
/**
* Handler for ChromeVox commands. Returns undefined if the command does not
* exist. Otherwise, returns the result of executing the command.
* @type {function(string): (boolean|undefined)}
*/
ChromeVoxKbHandler.commandHandler;
/**
* Converts the key bindings table into an array that is sorted by the lengths
* of the key bindings. After the sort, the key bindings that describe single
* keys will come before the key bindings that describe multiple keys.
* @param {Object<string>} keyToFunctionsTable Contains each key binding and its
* associated function name.
* @return {Array<Array<string>>} The sorted key bindings table in
* array form. Each entry in the array is itself an array containing the
* key binding and its associated function name.
* @private
*/
ChromeVoxKbHandler.sortKeyToFunctionsTable_ = function(keyToFunctionsTable) {
const sortingArray = [];
for (const keySeqStr in keyToFunctionsTable) {
sortingArray.push([keySeqStr, keyToFunctionsTable[keySeqStr]]);
}
function compareKeyStr(a, b) {
// Compare the lengths of the key bindings.
if (a[0].length < b[0].length) {
return -1;
} else if (b[0].length < a[0].length) {
return 1;
} else {
// The keys are the same length. Sort lexicographically.
return a[0].localeCompare(b[0]);
}
}
sortingArray.sort(compareKeyStr);
return sortingArray;
};
/**
* Handles key down events.
*
* @param {Event} evt The key down event to process.
* @return {boolean} True if the default action should be performed.
*/
ChromeVoxKbHandler.basicKeyDownActionsListener = function(evt) {
const keySequence = KeyUtil.keyEventToKeySequence(evt);
const chromeVoxState = ChromeVoxState.instance;
const monitor = chromeVoxState ? chromeVoxState.getUserActionMonitor() : null;
if (monitor && !monitor.onKeySequence(keySequence)) {
// UserActionMonitor returns true if this key sequence should propagate.
// Prevent the default action if it returns false.
return false;
}
let functionName;
if (ChromeVoxKbHandler.handlerKeyMap !== undefined) {
functionName = ChromeVoxKbHandler.handlerKeyMap.commandForKey(keySequence);
} else {
functionName = null;
}
// TODO (clchen): Disambiguate why functions are null. If the user pressed
// something that is not a valid combination, make an error noise so there
// is some feedback.
if (!functionName) {
return !KeyUtil.sequencing;
}
// This is the key event handler return value - true if the event should
// propagate and the default action should be performed, false if we eat
// the key.
let returnValue = true;
const commandResult = ChromeVoxKbHandler.commandHandler(functionName);
if (commandResult !== undefined) {
returnValue = commandResult;
} else if (keySequence.cvoxModifier) {
// Modifier/prefix is active -- prevent default action
returnValue = false;
}
// If the whole document is hidden from screen readers, let the app
// catch keys as well.
if (ChromeVox.entireDocumentIsHidden) {
returnValue = true;
}
return returnValue;
};