JavaScript 65.5%
Python 17.8%
CSS 13%
HTML 3.7%
1import KeyTable from "./keysym.js";2import keysyms from "./keysymdef.js";3import vkeys from "./vkeys.js";4import fixedkeys from "./fixedkeys.js";5import DOMKeyTable from "./domkeytable.js";6import * as browser from "../util/browser.js";78// Get 'KeyboardEvent.code', handling legacy browsers9export function getKeycode(evt) {10 // Are we getting proper key identifiers?11 // (unfortunately Firefox and Chrome are crappy here and gives12 // us an empty string on some platforms, rather than leaving it13 // undefined)14 if (evt.code) {15 // Mozilla isn't fully in sync with the spec yet16 switch (evt.code) {17 case 'OSLeft': return 'MetaLeft';18 case 'OSRight': return 'MetaRight';19 }2021 return evt.code;22 }2324 // The de-facto standard is to use Windows Virtual-Key codes25 // in the 'keyCode' field for non-printable characters26 if (evt.keyCode in vkeys) {27 let code = vkeys[evt.keyCode];2829 // macOS has messed up this code for some reason30 if (browser.isMac() && (code === 'ContextMenu')) {31 code = 'MetaRight';32 }3334 // The keyCode doesn't distinguish between left and right35 // for the standard modifiers36 if (evt.location === 2) {37 switch (code) {38 case 'ShiftLeft': return 'ShiftRight';39 case 'ControlLeft': return 'ControlRight';40 case 'AltLeft': return 'AltRight';41 }42 }4344 // Nor a bunch of the numpad keys45 if (evt.location === 3) {46 switch (code) {47 case 'Delete': return 'NumpadDecimal';48 case 'Insert': return 'Numpad0';49 case 'End': return 'Numpad1';50 case 'ArrowDown': return 'Numpad2';51 case 'PageDown': return 'Numpad3';52 case 'ArrowLeft': return 'Numpad4';53 case 'ArrowRight': return 'Numpad6';54 case 'Home': return 'Numpad7';55 case 'ArrowUp': return 'Numpad8';56 case 'PageUp': return 'Numpad9';57 case 'Enter': return 'NumpadEnter';58 }59 }6061 return code;62 }6364 return 'Unidentified';65}6667// Get 'KeyboardEvent.key', handling legacy browsers68export function getKey(evt) {69 // Are we getting a proper key value?70 if ((evt.key !== undefined) && (evt.key !== 'Unidentified')) {71 // Mozilla isn't fully in sync with the spec yet72 switch (evt.key) {73 case 'OS': return 'Meta';74 case 'LaunchMyComputer': return 'LaunchApplication1';75 case 'LaunchCalculator': return 'LaunchApplication2';76 }7778 // iOS leaks some OS names79 switch (evt.key) {80 case 'UIKeyInputUpArrow': return 'ArrowUp';81 case 'UIKeyInputDownArrow': return 'ArrowDown';82 case 'UIKeyInputLeftArrow': return 'ArrowLeft';83 case 'UIKeyInputRightArrow': return 'ArrowRight';84 case 'UIKeyInputEscape': return 'Escape';85 }8687 // Broken behaviour in Chrome88 if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) {89 return 'Delete';90 }9192 return evt.key;93 }9495 // Try to deduce it based on the physical key96 const code = getKeycode(evt);97 if (code in fixedkeys) {98 return fixedkeys[code];99 }100101 // If that failed, then see if we have a printable character102 if (evt.charCode) {103 return String.fromCharCode(evt.charCode);104 }105106 // At this point we have nothing left to go on107 return 'Unidentified';108}109110// Get the most reliable keysym value we can get from a key event111export function getKeysym(evt) {112 const key = getKey(evt);113114 if (key === 'Unidentified') {115 return null;116 }117118 // First look up special keys119 if (key in DOMKeyTable) {120 let location = evt.location;121122 // Safari screws up location for the right cmd key123 if ((key === 'Meta') && (location === 0)) {124 location = 2;125 }126127 // And for Clear128 if ((key === 'Clear') && (location === 3)) {129 let code = getKeycode(evt);130 if (code === 'NumLock') {131 location = 0;132 }133 }134135 if ((location === undefined) || (location > 3)) {136 location = 0;137 }138139 // The original Meta key now gets confused with the Windows key140 // https://bugs.chromium.org/p/chromium/issues/detail?id=1020141141 // https://bugzilla.mozilla.org/show_bug.cgi?id=1232918142 if (key === 'Meta') {143 let code = getKeycode(evt);144 if (code === 'AltLeft') {145 return KeyTable.XK_Meta_L;146 } else if (code === 'AltRight') {147 return KeyTable.XK_Meta_R;148 }149 }150151 // macOS has Clear instead of NumLock, but the remote system is152 // probably not macOS, so lying here is probably best...153 if (key === 'Clear') {154 let code = getKeycode(evt);155 if (code === 'NumLock') {156 return KeyTable.XK_Num_Lock;157 }158 }159160 // Windows sends alternating symbols for some keys when using a161 // Japanese layout. We have no way of synchronising with the IM162 // running on the remote system, so we send some combined keysym163 // instead and hope for the best.164 if (browser.isWindows()) {165 switch (key) {166 case 'Zenkaku':167 case 'Hankaku':168 return KeyTable.XK_Zenkaku_Hankaku;169 case 'Romaji':170 case 'KanaMode':171 return KeyTable.XK_Romaji;172 }173 }174175 return DOMKeyTable[key][location];176 }177178 // Now we need to look at the Unicode symbol instead179180 // Special key? (FIXME: Should have been caught earlier)181 if (key.length !== 1) {182 return null;183 }184185 const codepoint = key.charCodeAt();186 if (codepoint) {187 return keysyms.lookup(codepoint);188 }189190 return null;191}192