blob: 3f2318411872e638748ca49fc2fd3b9bdb1b5ff8 [file] [log] [blame]
// Copyright (c) 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
/**
* A mapping from hterm.Keyboard.KeyPattern to an action.
*
* TODO(rginda): For now this bindings code is only used for user overrides.
* hterm.Keyboard.KeyMap still handles all of the built-in key mappings.
* It'd be nice if we migrated that over to be hterm.Keyboard.Bindings based.
*/
hterm.Keyboard.Bindings = function() {
this.bindings_ = {};
};
/**
* Remove all bindings.
*/
hterm.Keyboard.Bindings.prototype.clear = function () {
this.bindings_ = {};
};
/**
* Add a new binding.
*
* Internal API that assumes parsed objects as inputs.
* See the public addBinding for more details.
*
* @param {hterm.Keyboard.KeyPattern} keyPattern
* @param {string|function|hterm.Keyboard.KeyAction} action
*/
hterm.Keyboard.Bindings.prototype.addBinding_ = function(keyPattern, action) {
var binding = null;
var list = this.bindings_[keyPattern.keyCode];
if (list) {
for (var i = 0; i < list.length; i++) {
if (list[i].keyPattern.matchKeyPattern(keyPattern)) {
binding = list[i];
break;
}
}
}
if (binding) {
binding.action = action;
} else {
binding = {keyPattern: keyPattern, action: action};
if (!list) {
this.bindings_[keyPattern.keyCode] = [binding];
} else {
this.bindings_[keyPattern.keyCode].push(binding);
list.sort(function(a, b) {
return hterm.Keyboard.KeyPattern.sortCompare(
a.keyPattern, b.keyPattern);
});
}
}
};
/**
* Add a new binding.
*
* If a binding for the keyPattern already exists it will be overridden.
*
* More specific keyPatterns take precedence over those with wildcards. Given
* bindings for "Ctrl-A" and "Ctrl-*-A", and a "Ctrl-A" keydown, the "Ctrl-A"
* binding will match even if "Ctrl-*-A" was created last.
*
* If action is a string, it will be passed through hterm.Parser.parseKeyAction.
*
* For example:
* // Will replace Ctrl-P keystrokes with the string "hiya!".
* addBinding('Ctrl-P', "'hiya!'");
* // Will cancel the keystroke entirely (make it do nothing).
* addBinding('Alt-D', hterm.Keyboard.KeyActions.CANCEL);
* // Will execute the code and return the action.
* addBinding('Ctrl-T', function() {
* console.log('Got a T!');
* return hterm.Keyboard.KeyActions.PASS;
* });
*
* @param {string|hterm.Keyboard.KeyPattern} keyPattern
* @param {string|function|hterm.Keyboard.KeyAction} action
*/
hterm.Keyboard.Bindings.prototype.addBinding = function(key, action) {
// If we're given a hterm.Keyboard.KeyPattern object, pass it down.
if (typeof key != 'string') {
this.addBinding_(key, action);
return;
}
// Here we treat key as a string.
var p = new hterm.Parser();
p.reset(key);
var sequence;
try {
sequence = p.parseKeySequence();
} catch (ex) {
console.error(ex);
return;
}
if (!p.isComplete()) {
console.error(p.error('Expected end of sequence: ' + sequence));
return;
}
// If action is a string, parse it. Otherwise assume it's callable.
if (typeof action == 'string') {
p.reset(action);
try {
action = p.parseKeyAction();
} catch (ex) {
console.error(ex);
return;
}
}
if (!p.isComplete()) {
console.error(p.error('Expected end of sequence: ' + sequence));
return;
}
this.addBinding_(new hterm.Keyboard.KeyPattern(sequence), action);
};
/**
* Add multiple bindings at a time using a map of {string: string, ...}
*
* This uses hterm.Parser to parse the maps key into KeyPatterns, and the
* map values into {string|function|KeyAction}.
*
* For example:
* {
* // Will replace Ctrl-P keystrokes with the string "hiya!".
* 'Ctrl-P': "'hiya!'",
* // Will cancel the keystroke entirely (make it do nothing).
* 'Alt-D': hterm.Keyboard.KeyActions.CANCEL,
* }
*
* @param {Object} map
*/
hterm.Keyboard.Bindings.prototype.addBindings = function(map) {
for (var key in map) {
this.addBinding(key, map[key]);
}
};
/**
* Return the binding that is the best match for the given keyDown record,
* or null if there is no match.
*
* @param {Object} keyDown An object with a keyCode property and zero or
* more boolean properties representing key modifiers. These property names
* must match those defined in hterm.Keyboard.KeyPattern.modifiers.
*/
hterm.Keyboard.Bindings.prototype.getBinding = function(keyDown) {
var list = this.bindings_[keyDown.keyCode];
if (!list)
return null;
for (var i = 0; i < list.length; i++) {
var binding = list[i];
if (binding.keyPattern.matchKeyDown(keyDown))
return binding;
}
return null;
};