2 * Copyright (c) 2014 The xterm.js authors. All rights reserved.
3 * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
7 import { IKeyboardEvent, IKeyboardResult, KeyboardResultType } from 'common/Types';
8 import { C0 } from 'common/data/EscapeSequences';
10 // reg + shift key mappings for digits and special chars
11 const KEYCODE_KEY_MAPPINGS: { [key: number]: [string, string]} = {
38 export function evaluateKeyboardEvent(
40 applicationCursorMode: boolean,
42 macOptionIsMeta: boolean
44 const result: IKeyboardResult = {
45 type: KeyboardResultType.SEND_KEY,
46 // Whether to cancel event propagation (NOTE: this may not be needed since the event is
47 // canceled at the end of keyDown
49 // The new key even to emit
52 const modifiers = (ev.shiftKey ? 1 : 0) | (ev.altKey ? 2 : 0) | (ev.ctrlKey ? 4 : 0) | (ev.metaKey ? 8 : 0);
55 if (ev.key === 'UIKeyInputUpArrow') {
56 if (applicationCursorMode) {
57 result.key = C0.ESC + 'OA';
59 result.key = C0.ESC + '[A';
62 else if (ev.key === 'UIKeyInputLeftArrow') {
63 if (applicationCursorMode) {
64 result.key = C0.ESC + 'OD';
66 result.key = C0.ESC + '[D';
69 else if (ev.key === 'UIKeyInputRightArrow') {
70 if (applicationCursorMode) {
71 result.key = C0.ESC + 'OC';
73 result.key = C0.ESC + '[C';
76 else if (ev.key === 'UIKeyInputDownArrow') {
77 if (applicationCursorMode) {
78 result.key = C0.ESC + 'OB';
80 result.key = C0.ESC + '[B';
87 result.key = C0.BS; // ^H
89 } else if (ev.altKey) {
90 result.key = C0.ESC + C0.DEL; // \e ^?
93 result.key = C0.DEL; // ^?
98 result.key = C0.ESC + '[Z';
102 result.cancel = true;
107 result.cancel = true;
112 result.cancel = true;
120 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'D';
121 // HACK: Make Alt + left-arrow behave like Ctrl + left-arrow: move one word backwards
122 // http://unix.stackexchange.com/a/108106
123 // macOS uses different escape sequences than linux
124 if (result.key === C0.ESC + '[1;3D') {
125 result.key = C0.ESC + (isMac ? 'b' : '[1;5D');
127 } else if (applicationCursorMode) {
128 result.key = C0.ESC + 'OD';
130 result.key = C0.ESC + '[D';
139 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'C';
140 // HACK: Make Alt + right-arrow behave like Ctrl + right-arrow: move one word forward
141 // http://unix.stackexchange.com/a/108106
142 // macOS uses different escape sequences than linux
143 if (result.key === C0.ESC + '[1;3C') {
144 result.key = C0.ESC + (isMac ? 'f' : '[1;5C');
146 } else if (applicationCursorMode) {
147 result.key = C0.ESC + 'OC';
149 result.key = C0.ESC + '[C';
158 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'A';
159 // HACK: Make Alt + up-arrow behave like Ctrl + up-arrow
160 // http://unix.stackexchange.com/a/108106
161 // macOS uses different escape sequences than linux
162 if (!isMac && result.key === C0.ESC + '[1;3A') {
163 result.key = C0.ESC + '[1;5A';
165 } else if (applicationCursorMode) {
166 result.key = C0.ESC + 'OA';
168 result.key = C0.ESC + '[A';
177 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'B';
178 // HACK: Make Alt + down-arrow behave like Ctrl + down-arrow
179 // http://unix.stackexchange.com/a/108106
180 // macOS uses different escape sequences than linux
181 if (!isMac && result.key === C0.ESC + '[1;3B') {
182 result.key = C0.ESC + '[1;5B';
184 } else if (applicationCursorMode) {
185 result.key = C0.ESC + 'OB';
187 result.key = C0.ESC + '[B';
192 if (!ev.shiftKey && !ev.ctrlKey) {
193 // <Ctrl> or <Shift> + <Insert> are used to
194 // copy-paste on some systems.
195 result.key = C0.ESC + '[2~';
201 result.key = C0.ESC + '[3;' + (modifiers + 1) + '~';
203 result.key = C0.ESC + '[3~';
209 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'H';
210 } else if (applicationCursorMode) {
211 result.key = C0.ESC + 'OH';
213 result.key = C0.ESC + '[H';
219 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'F';
220 } else if (applicationCursorMode) {
221 result.key = C0.ESC + 'OF';
223 result.key = C0.ESC + '[F';
229 result.type = KeyboardResultType.PAGE_UP;
231 result.key = C0.ESC + '[5~';
237 result.type = KeyboardResultType.PAGE_DOWN;
239 result.key = C0.ESC + '[6~';
245 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'P';
247 result.key = C0.ESC + 'OP';
252 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'Q';
254 result.key = C0.ESC + 'OQ';
259 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'R';
261 result.key = C0.ESC + 'OR';
266 result.key = C0.ESC + '[1;' + (modifiers + 1) + 'S';
268 result.key = C0.ESC + 'OS';
273 result.key = C0.ESC + '[15;' + (modifiers + 1) + '~';
275 result.key = C0.ESC + '[15~';
280 result.key = C0.ESC + '[17;' + (modifiers + 1) + '~';
282 result.key = C0.ESC + '[17~';
287 result.key = C0.ESC + '[18;' + (modifiers + 1) + '~';
289 result.key = C0.ESC + '[18~';
294 result.key = C0.ESC + '[19;' + (modifiers + 1) + '~';
296 result.key = C0.ESC + '[19~';
301 result.key = C0.ESC + '[20;' + (modifiers + 1) + '~';
303 result.key = C0.ESC + '[20~';
308 result.key = C0.ESC + '[21;' + (modifiers + 1) + '~';
310 result.key = C0.ESC + '[21~';
315 result.key = C0.ESC + '[23;' + (modifiers + 1) + '~';
317 result.key = C0.ESC + '[23~';
322 result.key = C0.ESC + '[24;' + (modifiers + 1) + '~';
324 result.key = C0.ESC + '[24~';
329 if (ev.ctrlKey && !ev.shiftKey && !ev.altKey && !ev.metaKey) {
330 if (ev.keyCode >= 65 && ev.keyCode <= 90) {
331 result.key = String.fromCharCode(ev.keyCode - 64);
332 } else if (ev.keyCode === 32) {
334 } else if (ev.keyCode >= 51 && ev.keyCode <= 55) {
335 // escape, file sep, group sep, record sep, unit sep
336 result.key = String.fromCharCode(ev.keyCode - 51 + 27);
337 } else if (ev.keyCode === 56) {
339 } else if (ev.keyCode === 219) {
341 } else if (ev.keyCode === 220) {
343 } else if (ev.keyCode === 221) {
346 } else if ((!isMac || macOptionIsMeta) && ev.altKey && !ev.metaKey) {
347 // On macOS this is a third level shift when !macOptionIsMeta. Use <Esc> instead.
348 const keyMapping = KEYCODE_KEY_MAPPINGS[ev.keyCode];
349 const key = keyMapping && keyMapping[!ev.shiftKey ? 0 : 1];
351 result.key = C0.ESC + key;
352 } else if (ev.keyCode >= 65 && ev.keyCode <= 90) {
353 const keyCode = ev.ctrlKey ? ev.keyCode - 64 : ev.keyCode + 32;
354 result.key = C0.ESC + String.fromCharCode(keyCode);
356 } else if (isMac && !ev.altKey && !ev.ctrlKey && ev.metaKey) {
357 if (ev.keyCode === 65) { // cmd + a
358 result.type = KeyboardResultType.SELECT_ALL;
360 } else if (ev.key && !ev.ctrlKey && !ev.altKey && !ev.metaKey && ev.keyCode >= 48 && ev.key.length === 1) {
361 // Include only keys that that result in a _single_ character; don't include num lock, volume up, etc.
363 } else if (ev.key && ev.ctrlKey) {
364 if (ev.key === '_') { // ^_