Skip to content

Commit

Permalink
Initial implementation of isKey
Browse files Browse the repository at this point in the history
  • Loading branch information
lukemelia committed May 24, 2020
1 parent d2edf02 commit d50035c
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 0 deletions.
26 changes: 26 additions & 0 deletions addon/utils/is-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { KeyCombo } from "./key-combo";

export default function isKey(keyComboOrKeyComboString, keyboardEvent) {
let keyCombo;
if (keyComboOrKeyComboString instanceof KeyCombo) {
keyCombo = keyComboOrKeyComboString;
} else if (typeof keyComboOrKeyComboString === 'string') {
keyCombo = KeyCombo.parse(keyComboOrKeyComboString);
} else {
throw new Error('Expected a `string` or `KeyCombo` as `keyComboOrKeyComboString` argument to `isKey`');
}

return modifiersMatch(keyCombo, keyboardEvent)
&& keyOrCodeMatches(keyCombo, keyboardEvent);
}

function modifiersMatch(keyCombo, keyboardEvent) {
return keyCombo.altKey === keyboardEvent.altKey
&& keyCombo.ctrlKey === keyboardEvent.ctrlKey
&& keyCombo.metaKey === keyboardEvent.metaKey
&& keyCombo.shiftKey === keyboardEvent.shiftKey;
}

function keyOrCodeMatches(keyCombo, keyboardEvent) {
return keyCombo.keyOrCode === keyboardEvent.code || keyCombo.keyOrCode === keyboardEvent.key;
}
29 changes: 29 additions & 0 deletions addon/utils/key-combo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export class KeyCombo {
altKey = false;
ctrlKey = false;
shiftKey = false;
metaKey = false;
keyOrCode;
static parse(s) {
let keyCombo = new KeyCombo();
s.split('+').forEach((part) => {
switch (part) {
case 'alt':
keyCombo.altKey = true;
break;
case 'ctrl':
keyCombo.ctrlKey = true;
break;
case 'meta':
keyCombo.metaKey = true;
break;
case 'shift':
keyCombo.shiftKey = true;
break;
default:
keyCombo.keyOrCode = part;
}
});
return keyCombo;
}
}
84 changes: 84 additions & 0 deletions tests/unit/utils/is-key-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { module, skip, test } from 'qunit';
import isKey from 'ember-keyboard/utils/is-key';

module('Unit | Utility | isKey', function() {
let table = `
keyCombo alt ctrl meta shift key code expected pending note
alt+c T F F F c KeyC T F
alt+c T F F F j KeyC F F simulates dvorak j
alt+c T F F F c KeyI T F simulates dvorak c
alt+c T F F F ç KeyC T T simulates Mac alt+c
alt+KeyC T F F F c KeyC T F
alt+c F F F F c KeyC F F alt not pressed
alt+c T F F T c KeyC F F alt+shift pressed
alt+KeyC F F F F c KeyC F F alt not pressed
alt+KeyC T F F T c KeyC F F alt+shift pressed
shift+c F F F T c KeyC T F
shift+KeyC F F F T c KeyC T F
ctrl+shift+t F T F T t KeyT T F
ctrl+shift+KeyT F T F T t KeyT T F
alt+Digit2 T F F F 2 Digit2 T F
shift+Digit2 F F F T @ Digit2 T F
shift+2 F F F T @ Digit2 T T
@ F F F F @ Digit2 T F
? F F F T ? Slash T T
ctrl+? F T F T ? Slash T T
ctrl+Slash F T F F / Slash T F
ctrl+Slash F T F T ? Slash F F
/ F F F F / Slash T F slash key with us language
/ F F F F - Slash F F same key with german language
/ F F F F / Digit7 T F slash key on german keyboard
`;
for (let line of table.split("\n").map(line => line.trim())) {
if (line === '' || line.match(/^keyCombo/)) { continue; } // blank or header row
buildTestFromLine(line);
}
});

function stringToBoolean(s) {
if (s === 'T') return true;
if (s === 'F') return false;
throw new Error(`Invalid boolean string value: ${s}. Must be 'T' or 'F'`);
}

function buildTestFromLine(line) {
let [keyCombo,alt,ctrl,meta,shift,key,code,expected,pending,...note] = line.split(/\s+/);
let altKey = stringToBoolean(alt);
let ctrlKey = stringToBoolean(ctrl);
let metaKey = stringToBoolean(meta);
let shiftKey = stringToBoolean(shift);
let expectedResult = stringToBoolean(expected);
let isPending = stringToBoolean(pending);
let testDescription = `with "${keyCombo}", `;
note = note ? note.join(' ') : null;
testDescription += expectedResult ? 'should ' : 'should not ';
testDescription += `match keydown event with `;
testDescription += `key: ${key}, `;
testDescription += `code: ${code}, `;
testDescription += `with modifiers `;
let modifiers = [];
if (altKey) {
modifiers.push('alt');
}
if (ctrlKey) {
modifiers.push('ctrl');
}
if (metaKey) {
modifiers.push('meta');
}
if (shiftKey) {
modifiers.push('shift');
}
testDescription += modifiers.join('+');
let testFunc = isPending ? skip : test;
testFunc(testDescription, async function(assert) {
let fakeEvent = new KeyboardEvent('keydown', { key, code, altKey, ctrlKey, metaKey, shiftKey });
if (expectedResult) {
let expectedTriggerMessage = `should match${note ? ', ' + note : ''}`;
assert.ok(isKey(keyCombo, fakeEvent), expectedTriggerMessage);
} else {
let expectedNoTriggerMessage = `should not match${note ? ', ' + note : ''}`;
assert.ok(!isKey(keyCombo, fakeEvent), expectedNoTriggerMessage);
}
});
}

0 comments on commit d50035c

Please sign in to comment.