123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- /**
- * This extension allows you to record a sequence using Mousetrap.
- *
- * @author Dan Tao <daniel.tao@gmail.com>
- */
- (function(Mousetrap) {
- /**
- * the sequence currently being recorded
- *
- * @type {Array}
- */
- var _recordedSequence = [],
- /**
- * a callback to invoke after recording a sequence
- *
- * @type {Function|null}
- */
- _recordedSequenceCallback = null,
- /**
- * a list of all of the keys currently held down
- *
- * @type {Array}
- */
- _currentRecordedKeys = [],
- /**
- * temporary state where we remember if we've already captured a
- * character key in the current combo
- *
- * @type {boolean}
- */
- _recordedCharacterKey = false,
- /**
- * a handle for the timer of the current recording
- *
- * @type {null|number}
- */
- _recordTimer = null,
- /**
- * the original handleKey method to override when Mousetrap.record() is
- * called
- *
- * @type {Function}
- */
- _origHandleKey = Mousetrap.handleKey;
- /**
- * handles a character key event
- *
- * @param {string} character
- * @param {Array} modifiers
- * @param {Event} e
- * @returns void
- */
- function _handleKey(character, modifiers, e) {
- // remember this character if we're currently recording a sequence
- if (e.type == 'keydown') {
- if (character.length === 1 && _recordedCharacterKey) {
- _recordCurrentCombo();
- }
- for (i = 0; i < modifiers.length; ++i) {
- _recordKey(modifiers[i]);
- }
- _recordKey(character);
- // once a key is released, all keys that were held down at the time
- // count as a keypress
- } else if (e.type == 'keyup' && _currentRecordedKeys.length > 0) {
- _recordCurrentCombo();
- }
- }
- /**
- * marks a character key as held down while recording a sequence
- *
- * @param {string} key
- * @returns void
- */
- function _recordKey(key) {
- var i;
- // one-off implementation of Array.indexOf, since IE6-9 don't support it
- for (i = 0; i < _currentRecordedKeys.length; ++i) {
- if (_currentRecordedKeys[i] === key) {
- return;
- }
- }
- _currentRecordedKeys.push(key);
- if (key.length === 1) {
- _recordedCharacterKey = true;
- }
- }
- /**
- * marks whatever key combination that's been recorded so far as finished
- * and gets ready for the next combo
- *
- * @returns void
- */
- function _recordCurrentCombo() {
- _recordedSequence.push(_currentRecordedKeys);
- _currentRecordedKeys = [];
- _recordedCharacterKey = false;
- _restartRecordTimer();
- }
- /**
- * ensures each combo in a sequence is in a predictable order and formats
- * key combos to be '+'-delimited
- *
- * modifies the sequence in-place
- *
- * @param {Array} sequence
- * @returns void
- */
- function _normalizeSequence(sequence) {
- var i;
- for (i = 0; i < sequence.length; ++i) {
- sequence[i].sort(function(x, y) {
- // modifier keys always come first, in alphabetical order
- if (x.length > 1 && y.length === 1) {
- return -1;
- } else if (x.length === 1 && y.length > 1) {
- return 1;
- }
- // character keys come next (list should contain no duplicates,
- // so no need for equality check)
- return x > y ? 1 : -1;
- });
- sequence[i] = sequence[i].join('+');
- }
- }
- /**
- * finishes the current recording, passes the recorded sequence to the stored
- * callback, and sets Mousetrap.handleKey back to its original function
- *
- * @returns void
- */
- function _finishRecording() {
- if (_recordedSequenceCallback) {
- _normalizeSequence(_recordedSequence);
- _recordedSequenceCallback(_recordedSequence);
- }
- // reset all recorded state
- _recordedSequence = [];
- _recordedSequenceCallback = null;
- _currentRecordedKeys = [];
- Mousetrap.handleKey = _origHandleKey;
- }
- /**
- * called to set a 1 second timeout on the current recording
- *
- * this is so after each key press in the sequence the recording will wait for
- * 1 more second before executing the callback
- *
- * @returns void
- */
- function _restartRecordTimer() {
- clearTimeout(_recordTimer);
- _recordTimer = setTimeout(_finishRecording, 1000);
- }
- /**
- * records the next sequence and passes it to a callback once it's
- * completed
- *
- * @param {Function} callback
- * @returns void
- */
- Mousetrap.record = function(callback) {
- Mousetrap.handleKey = _handleKey;
- _recordedSequenceCallback = callback;
- };
- })(Mousetrap);
|