mirror of
https://github.com/whscullin/apple2js.git
synced 2024-01-12 14:14:38 +00:00
1e79d9d59d
* Enabled prettier * Update lint, fix issues * Restore some array formatting
576 lines
18 KiB
TypeScript
576 lines
18 KiB
TypeScript
import { byte, DeepMemberOf, KnownKeys } from '../types';
|
|
import Apple2IO from '../apple2io';
|
|
import { CPU6502 } from '@whscullin/cpu6502';
|
|
import { debug, toHex } from '../util';
|
|
|
|
// keycode: [plain, cntl, shift]
|
|
const keymap = {
|
|
// Most of these won't happen
|
|
0x00: [0x00, 0x00, 0x00], //
|
|
0x01: [0x01, 0x01, 0x01], //
|
|
0x02: [0x02, 0x02, 0x02], //
|
|
0x03: [0x03, 0x03, 0x03], //
|
|
0x04: [0x04, 0x04, 0x04], //
|
|
0x05: [0x05, 0x05, 0x05], //
|
|
0x06: [0x06, 0x06, 0x06], //
|
|
0x07: [0x07, 0x07, 0x07], //
|
|
0x08: [0x7f, 0x7f, 0x7f], // BS/DELETE
|
|
0x09: [0x09, 0x09, 0x09], // TAB
|
|
0x0a: [0x0a, 0x0a, 0x0a], //
|
|
0x0b: [0x0b, 0x0b, 0x0b], //
|
|
0x0c: [0x0c, 0x0c, 0x0c], //
|
|
0x0d: [0x0d, 0x0d, 0x0d], // CR
|
|
0x0e: [0x0e, 0x0e, 0x0e], //
|
|
0x0f: [0x0f, 0x0f, 0x0f], //
|
|
|
|
0x10: [0xff, 0xff, 0xff], // SHIFT
|
|
0x11: [0xff, 0xff, 0xff], // CTRL
|
|
0x12: [0xff, 0xff, 0xff], // ALT/OPTION
|
|
0x13: [0x13, 0x13, 0x13], //
|
|
0x14: [0x14, 0x14, 0x14], //
|
|
0x15: [0x15, 0x15, 0x15], //
|
|
0x16: [0x16, 0x16, 0x16], //
|
|
0x17: [0x17, 0x17, 0x18], //
|
|
0x18: [0x18, 0x18, 0x18], //
|
|
0x19: [0x19, 0x19, 0x19], //
|
|
0x1a: [0x1a, 0x1a, 0x1a], //
|
|
0x1b: [0x1b, 0x1b, 0x1b], // ESC
|
|
0x1c: [0x1c, 0x1c, 0x1c], //
|
|
0x1d: [0x1d, 0x1d, 0x1d], //
|
|
0x1e: [0x1e, 0x1e, 0x1e], //
|
|
0x1f: [0x1f, 0x1f, 0x1f], //
|
|
|
|
// Most of these besides space won't happen
|
|
0x20: [0x20, 0x20, 0x20], //
|
|
0x21: [0x21, 0x21, 0x21], //
|
|
0x22: [0x22, 0x22, 0x22], //
|
|
0x23: [0x23, 0x23, 0x23], //
|
|
0x24: [0x24, 0x24, 0x24], //
|
|
0x25: [0x08, 0x08, 0x08], // <- left
|
|
0x26: [0x0b, 0x0b, 0x0b], // ^ up
|
|
0x27: [0x15, 0x15, 0x15], // -> right
|
|
0x28: [0x0a, 0x0a, 0x0a], // v down
|
|
0x29: [0x29, 0x29, 0x29], // )
|
|
0x2a: [0x2a, 0x2a, 0x2a], // *
|
|
0x2b: [0x2b, 0x2b, 0x2b], // +
|
|
0x2c: [0x2c, 0x2c, 0x3c], // , - <
|
|
0x2d: [0x2d, 0x2d, 0x5f], // - - _
|
|
0x2e: [0x2e, 0x2e, 0x3e], // . - >
|
|
0x2f: [0x2f, 0x2f, 0x3f], // / - ?
|
|
|
|
0x30: [0x30, 0x30, 0x29], // 0 - )
|
|
0x31: [0x31, 0x31, 0x21], // 1 - !
|
|
0x32: [0x32, 0x00, 0x40], // 2 - @
|
|
0x33: [0x33, 0x33, 0x23], // 3 - #
|
|
0x34: [0x34, 0x34, 0x24], // 4 - $
|
|
0x35: [0x35, 0x35, 0x25], // 5 - %
|
|
0x36: [0x36, 0x36, 0x5e], // 6 - ^
|
|
0x37: [0x37, 0x37, 0x26], // 7 - &
|
|
0x38: [0x38, 0x38, 0x2a], // 8 - *
|
|
0x39: [0x39, 0x39, 0x28], // 9 - (
|
|
0x3a: [0x3a, 0x3a, 0x3a], // :
|
|
0x3b: [0x3b, 0x3b, 0x3a], // ; - :
|
|
0x3c: [0x3c, 0x3c, 0x3c], // <
|
|
0x3d: [0x3d, 0x3d, 0x2b], // = - +
|
|
0x3e: [0x3e, 0x3e, 0x3e], // >
|
|
0x3f: [0x3f, 0x3f, 0x3f], // ?
|
|
|
|
// Alpha and control
|
|
0x40: [0x40, 0x00, 0x40], // @
|
|
0x41: [0x61, 0x01, 0x41], // A
|
|
0x42: [0x62, 0x02, 0x42], // B
|
|
0x43: [0x63, 0x03, 0x43], // C - BRK
|
|
0x44: [0x64, 0x04, 0x44], // D
|
|
0x45: [0x65, 0x05, 0x45], // E
|
|
0x46: [0x66, 0x06, 0x46], // F
|
|
0x47: [0x67, 0x07, 0x47], // G - BELL
|
|
0x48: [0x68, 0x08, 0x48], // H
|
|
0x49: [0x69, 0x09, 0x49], // I - TAB
|
|
0x4a: [0x6a, 0x0a, 0x4a], // J - NL
|
|
0x4b: [0x6b, 0x0b, 0x4b], // K - VT
|
|
0x4c: [0x6c, 0x0c, 0x4c], // L
|
|
0x4d: [0x6d, 0x0d, 0x4d], // M - CR
|
|
0x4e: [0x6e, 0x0e, 0x4e], // N
|
|
0x4f: [0x6f, 0x0f, 0x4f], // O
|
|
|
|
0x50: [0x70, 0x10, 0x50], // P
|
|
0x51: [0x71, 0x11, 0x51], // Q
|
|
0x52: [0x72, 0x12, 0x52], // R
|
|
0x53: [0x73, 0x13, 0x53], // S
|
|
0x54: [0x74, 0x14, 0x54], // T
|
|
0x55: [0x75, 0x15, 0x55], // U
|
|
0x56: [0x76, 0x16, 0x56], // V
|
|
0x57: [0x77, 0x17, 0x57], // W
|
|
0x58: [0x78, 0x18, 0x58], // X
|
|
0x59: [0x79, 0x19, 0x59], // Y
|
|
0x5a: [0x7a, 0x1a, 0x5a], // Z
|
|
0x5b: [0xff, 0xff, 0xff], // Left window
|
|
0x5c: [0xff, 0xff, 0xff], // Right window
|
|
0x5d: [0xff, 0xff, 0xff], // Select
|
|
0x5e: [0x5e, 0x1e, 0x5e], //
|
|
0x5f: [0x5f, 0x1f, 0x5f], // _
|
|
|
|
// Numeric pad
|
|
0x60: [0x30, 0x30, 0x30], // 0
|
|
0x61: [0x31, 0x31, 0x31], // 1
|
|
0x62: [0x32, 0x32, 0x32], // 2
|
|
0x63: [0x33, 0x33, 0x33], // 3
|
|
0x64: [0x34, 0x34, 0x34], // 4
|
|
0x65: [0x35, 0x35, 0x35], // 5
|
|
0x66: [0x36, 0x36, 0x36], // 6
|
|
0x67: [0x37, 0x37, 0x37], // 7
|
|
0x68: [0x38, 0x38, 0x38], // 8
|
|
0x69: [0x39, 0x39, 0x39], // 9
|
|
|
|
0x6a: [0x2a, 0x2a, 0x2a], // *
|
|
0x6b: [0x2b, 0x2b, 0x2b], // +
|
|
0x6d: [0x2d, 0x2d, 0x2d], // -
|
|
0x6e: [0x2e, 0x2e, 0x2e], // .
|
|
0x6f: [0x2f, 0x2f, 0x39], // /
|
|
|
|
// Stray keys
|
|
0xad: [0x2d, 0x2d, 0x5f], // - - _
|
|
0xba: [0x3b, 0x3b, 0x3a], // ; - :
|
|
0xbb: [0x3d, 0x3d, 0x2b], // = - +
|
|
0xbc: [0x2c, 0x2c, 0x3c], // , - <
|
|
0xbd: [0x2d, 0x2d, 0x5f], // - - _
|
|
0xbe: [0x2e, 0x2e, 0x3e], // . - >
|
|
0xbf: [0x2f, 0x2f, 0x3f], // / - ?
|
|
0xc0: [0x60, 0x60, 0x7e], // ` - ~
|
|
0xdb: [0x5b, 0x1b, 0x7b], // [ - {
|
|
0xdc: [0x5c, 0x1c, 0x7c], // \ - |
|
|
0xdd: [0x5d, 0x1d, 0x7d], // ] - }
|
|
0xde: [0x27, 0x22, 0x22], // ' - '
|
|
|
|
0xff: [0xff, 0xff, 0xff], // No comma line
|
|
} as const;
|
|
|
|
function isKeyboardCode(code: number): code is KnownKeys<typeof keymap> {
|
|
return code in keymap;
|
|
}
|
|
|
|
const uiKitMap = {
|
|
Dead: 0xff,
|
|
UIKeyInputLeftArrow: 0x08,
|
|
UIKeyInputRightArrow: 0x15,
|
|
UIKeyInputUpArrow: 0x0b,
|
|
UIKeyInputDownArrow: 0x0a,
|
|
UIKeyInputEscape: 0x1b,
|
|
} as const;
|
|
|
|
function isUiKitKey(k: string): k is KnownKeys<typeof uiKitMap> {
|
|
return k in uiKitMap;
|
|
}
|
|
|
|
// prettier-ignore
|
|
export const keys2 = [
|
|
[
|
|
['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', ':', '-', 'RESET'],
|
|
['ESC', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 'REPT', 'RETURN'],
|
|
['CTRL', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '←', '→'],
|
|
['SHIFT', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'SHIFT'],
|
|
['POWER', ' ']
|
|
], [
|
|
['!', '"', '#', '$', '%', '&', '\'', '(', ')', '0', '*', '=', 'RESET'],
|
|
['ESC', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', '@', 'REPT', 'RETURN'],
|
|
['CTRL', 'A', 'S', 'D', 'F', 'BELL', 'H', 'J', 'K', 'L', '+', '←', '→'],
|
|
['SHIFT', 'Z', 'X', 'C', 'V', 'B', '^', ']', '<', '>', '?', 'SHIFT'],
|
|
['POWER', ' ']
|
|
]
|
|
] as const;
|
|
|
|
type Key2 = DeepMemberOf<typeof keys2>;
|
|
|
|
// prettier-ignore
|
|
export const keys2e = [
|
|
[
|
|
['ESC', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'DELETE'],
|
|
['TAB', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '[', ']', '\\'],
|
|
['CTRL', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', '"', 'RETURN'],
|
|
['SHIFT', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', ',', '.', '/', 'SHIFT'],
|
|
['LOCK', '`', 'POW', 'OPEN_APPLE', ' ', 'CLOSED_APPLE', '←', '→', '↓', '↑']
|
|
], [
|
|
['ESC', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', 'DELETE'],
|
|
['TAB', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '|'],
|
|
['CTRL', 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\'', 'RETURN'],
|
|
['SHIFT', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 'SHIFT'],
|
|
['CAPS', '~', 'POW', 'OPEN_APPLE', ' ', 'CLOSED_APPLE', '←', '→', '↓', '↑']
|
|
]
|
|
] as const;
|
|
|
|
type Key2e = DeepMemberOf<typeof keys2e>;
|
|
|
|
type Key = Key2 | Key2e;
|
|
|
|
type KeyFunction = (key: KeyboardEvent) => void;
|
|
|
|
export default class KeyBoard {
|
|
private kb: HTMLElement;
|
|
private keys;
|
|
|
|
private shifted = false;
|
|
private controlled = false;
|
|
private capslocked = true;
|
|
|
|
// Initially caps lock on physical keyboard is assumed to be off,
|
|
// but on emulated keyboard it is on.
|
|
private capslockKeyUsed = false;
|
|
private optioned = false;
|
|
private commanded = false;
|
|
|
|
private functions: Record<string, KeyFunction> = {};
|
|
|
|
constructor(
|
|
private cpu: CPU6502,
|
|
private io: Apple2IO,
|
|
private e: boolean
|
|
) {
|
|
this.keys = e ? keys2e : keys2;
|
|
|
|
window.addEventListener('keydown', this.keydown);
|
|
window.addEventListener('keyup', this.keyup);
|
|
}
|
|
|
|
setFunction(key: string, fn: KeyFunction) {
|
|
this.functions[key] = fn;
|
|
}
|
|
|
|
mapKeyEvent(evt: KeyboardEvent) {
|
|
const code = evt.keyCode;
|
|
let key: byte = 0xff;
|
|
|
|
if (isUiKitKey(evt.key)) {
|
|
key = uiKitMap[evt.key];
|
|
} else if (isKeyboardCode(code)) {
|
|
key = keymap[code][evt.shiftKey ? 2 : evt.ctrlKey ? 1 : 0];
|
|
|
|
if (code !== 20 && this.capslockKeyUsed) {
|
|
this.capslockKey(evt.getModifierState('CapsLock'));
|
|
}
|
|
|
|
if (this.capslocked && key >= 0x61 && key <= 0x7a) {
|
|
key -= 0x20;
|
|
}
|
|
} else {
|
|
debug('Unhandled key = ' + toHex(code));
|
|
}
|
|
|
|
if (key === 0x7f && evt.shiftKey && evt.ctrlKey) {
|
|
this.cpu.reset();
|
|
key = 0xff;
|
|
}
|
|
|
|
return key;
|
|
}
|
|
|
|
shiftKey(down: boolean) {
|
|
const shiftKeys = this.kb.querySelectorAll('.key-SHIFT');
|
|
this.shifted = down;
|
|
if (down) {
|
|
this.io.buttonUp(2);
|
|
shiftKeys.forEach((key) => {
|
|
key.classList.add('active');
|
|
});
|
|
} else {
|
|
this.io.buttonDown(2);
|
|
shiftKeys.forEach((key) => {
|
|
key.classList.remove('active');
|
|
});
|
|
}
|
|
}
|
|
|
|
controlKey(down: boolean) {
|
|
const ctrlKey = this.kb.querySelector('.key-CTRL');
|
|
this.controlled = down;
|
|
if (down) {
|
|
ctrlKey!.classList.add('active');
|
|
} else {
|
|
ctrlKey!.classList.remove('active');
|
|
}
|
|
}
|
|
|
|
commandKey(down: boolean) {
|
|
const commandKey = this.kb.querySelector('.key-OPEN_APPLE');
|
|
if (!commandKey) {
|
|
return;
|
|
}
|
|
this.commanded = down;
|
|
if (down) {
|
|
this.io.buttonDown(0);
|
|
commandKey.classList.add('active');
|
|
} else {
|
|
this.io.buttonUp(0);
|
|
commandKey.classList.remove('active');
|
|
}
|
|
}
|
|
|
|
optionKey(down: boolean) {
|
|
const optionKey = this.kb.querySelector('.key-CLOSED_APPLE');
|
|
if (!optionKey) {
|
|
return;
|
|
}
|
|
this.optioned = down;
|
|
if (down) {
|
|
this.io.buttonDown(1);
|
|
optionKey.classList.add('active');
|
|
} else {
|
|
this.io.buttonUp(1);
|
|
optionKey.classList.remove('active');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the state of the Caps Lock key. It is very complicated.
|
|
* @param down if `true`, Caps Lock is pressed; if `false` Caps Lock is not pressed;
|
|
* if `undefined`, Caps Lock is toggled and its "used" state is set to false;
|
|
* if called with no arguments, the state is toggled _if_ it has been used before,
|
|
* otherwise the used state is set to true.
|
|
*/
|
|
capslockKey(down?: boolean | undefined) {
|
|
const capsLock = this.kb.querySelector('.key-LOCK');
|
|
|
|
if (arguments.length === 0) {
|
|
if (this.capslockKeyUsed) {
|
|
this.capslocked = !this.capslocked;
|
|
} else {
|
|
this.capslockKeyUsed = true;
|
|
}
|
|
} else if (down === undefined) {
|
|
this.capslocked = !this.capslocked;
|
|
this.capslockKeyUsed = false;
|
|
} else {
|
|
this.capslocked = down;
|
|
}
|
|
|
|
if (this.capslocked) {
|
|
capsLock!.classList.add('active');
|
|
} else {
|
|
capsLock!.classList.remove('active');
|
|
}
|
|
}
|
|
|
|
reset(event: Event) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
this.cpu.reset();
|
|
}
|
|
|
|
create(el: string) {
|
|
this.kb = document.querySelector(el)!;
|
|
let x, y, row, key, label, label1, label2;
|
|
|
|
const buildLabel = (k: string) => {
|
|
const span = document.createElement('span');
|
|
span.innerHTML = k;
|
|
if (k.length > 1 && k.slice(0, 1) !== '&')
|
|
span.classList.add('small');
|
|
return span;
|
|
};
|
|
|
|
for (y = 0; y < 5; y++) {
|
|
row = document.createElement('div');
|
|
row.classList.add('row');
|
|
row.classList.add(`row${y}`);
|
|
this.kb.append(row);
|
|
for (x = 0; x < this.keys[0][y].length; x++) {
|
|
const key1 = this.keys[0][y][x];
|
|
const key2 = this.keys[1][y][x];
|
|
|
|
label = document.createElement('div');
|
|
label1 = buildLabel(key1);
|
|
label2 = buildLabel(key2);
|
|
|
|
key = document.createElement('div');
|
|
key.classList.add('key');
|
|
key.classList.add('key-' + key1.replace(/[&#;]/g, ''));
|
|
|
|
if (key1.length > 1) {
|
|
if (key1 === 'LOCK') key.classList.add('v-center2');
|
|
else key.classList.add('v-center');
|
|
}
|
|
if (key1 !== key2) {
|
|
key.classList.add('key-' + key2.replace(/[&;]/g, ''));
|
|
label.append(label2);
|
|
label.append(document.createElement('br'));
|
|
}
|
|
if (key1 === 'LOCK') {
|
|
key.classList.add('active');
|
|
}
|
|
|
|
label.append(label1);
|
|
key.append(label);
|
|
key.dataset.key1 = key1;
|
|
key.dataset.key2 = key2;
|
|
|
|
const mouseDown = this.genMouseDown(key, key1, key2);
|
|
const mouseUp = this.genMouseUp(key);
|
|
if (window.ontouchstart === undefined) {
|
|
key.addEventListener('mousedown', mouseDown);
|
|
key.addEventListener('mouseup', mouseUp);
|
|
key.addEventListener('mouseleave', mouseUp);
|
|
} else {
|
|
key.addEventListener('touchstart', mouseDown);
|
|
key.addEventListener('touchend', mouseUp);
|
|
key.addEventListener('touchleave', mouseUp);
|
|
}
|
|
|
|
row.append(key);
|
|
}
|
|
}
|
|
}
|
|
|
|
private genMouseDown(target: HTMLElement, key1: Key, key2: Key) {
|
|
return (ev: MouseEvent) => {
|
|
ev.preventDefault();
|
|
target.classList.add('pressed');
|
|
|
|
let key: string = this.shifted ? key2 : key1;
|
|
switch (key) {
|
|
case 'BELL':
|
|
key = 'G';
|
|
break;
|
|
case 'RETURN':
|
|
key = '\r';
|
|
break;
|
|
case 'TAB':
|
|
key = '\t';
|
|
break;
|
|
case 'DELETE':
|
|
key = '\x7F';
|
|
break;
|
|
case '←':
|
|
key = '\x08';
|
|
break;
|
|
case '→':
|
|
key = '\x15';
|
|
break;
|
|
case '↓':
|
|
key = '\x0A';
|
|
break;
|
|
case '↑':
|
|
key = '\x0B';
|
|
break;
|
|
case ' ':
|
|
key = ' ';
|
|
break;
|
|
case 'ESC':
|
|
key = '\x1B';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (key.length > 1) {
|
|
switch (key) {
|
|
case 'SHIFT':
|
|
this.shiftKey(!this.shifted);
|
|
break;
|
|
case 'CTRL':
|
|
this.controlKey(!this.controlled);
|
|
break;
|
|
case 'CAPS':
|
|
case 'LOCK':
|
|
this.capslockKey(undefined);
|
|
break;
|
|
case 'POW':
|
|
case 'POWER':
|
|
if (window.confirm('Power Cycle?'))
|
|
window.location.reload();
|
|
break;
|
|
case 'RESET':
|
|
this.cpu.reset();
|
|
break;
|
|
case 'OPEN_APPLE':
|
|
this.commandKey(!this.commanded);
|
|
break;
|
|
case 'CLOSED_APPLE':
|
|
this.optionKey(!this.optioned);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else {
|
|
if (this.controlled && key >= '@' && key <= '_') {
|
|
this.io.keyDown(key.charCodeAt(0) - 0x40);
|
|
} else if (
|
|
this.e &&
|
|
!this.shifted &&
|
|
!this.capslocked &&
|
|
key >= 'A' &&
|
|
key <= 'Z'
|
|
) {
|
|
this.io.keyDown(key.charCodeAt(0) + 0x20);
|
|
} else {
|
|
this.io.keyDown(key.charCodeAt(0));
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
private dialogOpen() {
|
|
return !!document.querySelector('.modal.is-open');
|
|
}
|
|
|
|
private genMouseUp(target: HTMLElement) {
|
|
return () => target.classList.remove('pressed');
|
|
}
|
|
|
|
private keydown = (evt: KeyboardEvent) => {
|
|
if (!this.dialogOpen() && (!evt.metaKey || evt.ctrlKey || this.e)) {
|
|
evt.preventDefault();
|
|
|
|
const key = this.mapKeyEvent(evt);
|
|
if (key !== 0xff) {
|
|
this.io.keyDown(key);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (evt.key === 'Shift') {
|
|
this.shiftKey(true);
|
|
} else if (evt.key === 'CapsLock') {
|
|
this.capslockKey();
|
|
} else if (evt.key === 'Control') {
|
|
this.controlKey(true);
|
|
} else if (evt.key === 'Meta') {
|
|
// AKA Command
|
|
this.commandKey(true);
|
|
} else if (evt.key === 'Alt') {
|
|
if (evt.location === 1) {
|
|
this.commandKey(true);
|
|
} else {
|
|
this.optionKey(true);
|
|
}
|
|
} else {
|
|
if (evt.key in this.functions) {
|
|
this.functions[evt.key](evt);
|
|
evt.preventDefault();
|
|
}
|
|
}
|
|
};
|
|
|
|
private keyup = (evt: KeyboardEvent) => {
|
|
if (!this.dialogOpen()) {
|
|
this.io.keyUp();
|
|
}
|
|
|
|
if (evt.key === 'Shift') {
|
|
// Shift
|
|
this.shiftKey(false);
|
|
} else if (evt.key === 'Control') {
|
|
// Control
|
|
this.controlKey(false);
|
|
} else if (evt.key === 'Meta') {
|
|
// AKA Command
|
|
this.commandKey(false);
|
|
} else if (evt.key === 'Alt') {
|
|
// Alt
|
|
if (evt.location === 1) {
|
|
this.commandKey(false);
|
|
} else {
|
|
this.optionKey(false);
|
|
}
|
|
}
|
|
};
|
|
}
|