mirror of
https://github.com/kasmtech/KasmVNC.git
synced 2024-12-03 13:33:45 +01:00
796de9653f
There is no obvious choice what works best here, but this is what TigerVNC has been doing for years without complaints. Let's follow them until we get reports that this doesn't work well.
209 lines
6.7 KiB
JavaScript
209 lines
6.7 KiB
JavaScript
import KeyTable from "./keysym.js";
|
|
import keysyms from "./keysymdef.js";
|
|
import vkeys from "./vkeys.js";
|
|
import fixedkeys from "./fixedkeys.js";
|
|
import DOMKeyTable from "./domkeytable.js";
|
|
import * as browser from "../util/browser.js";
|
|
|
|
// Get 'KeyboardEvent.code', handling legacy browsers
|
|
export function getKeycode(evt) {
|
|
// Are we getting proper key identifiers?
|
|
// (unfortunately Firefox and Chrome are crappy here and gives
|
|
// us an empty string on some platforms, rather than leaving it
|
|
// undefined)
|
|
if (evt.code) {
|
|
// Mozilla isn't fully in sync with the spec yet
|
|
switch (evt.code) {
|
|
case 'OSLeft': return 'MetaLeft';
|
|
case 'OSRight': return 'MetaRight';
|
|
}
|
|
|
|
return evt.code;
|
|
}
|
|
|
|
// The de-facto standard is to use Windows Virtual-Key codes
|
|
// in the 'keyCode' field for non-printable characters. However
|
|
// Webkit sets it to the same as charCode in 'keypress' events.
|
|
if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) {
|
|
let code = vkeys[evt.keyCode];
|
|
|
|
// macOS has messed up this code for some reason
|
|
if (browser.isMac() && (code === 'ContextMenu')) {
|
|
code = 'MetaRight';
|
|
}
|
|
|
|
// The keyCode doesn't distinguish between left and right
|
|
// for the standard modifiers
|
|
if (evt.location === 2) {
|
|
switch (code) {
|
|
case 'ShiftLeft': return 'ShiftRight';
|
|
case 'ControlLeft': return 'ControlRight';
|
|
case 'AltLeft': return 'AltRight';
|
|
}
|
|
}
|
|
|
|
// Nor a bunch of the numpad keys
|
|
if (evt.location === 3) {
|
|
switch (code) {
|
|
case 'Delete': return 'NumpadDecimal';
|
|
case 'Insert': return 'Numpad0';
|
|
case 'End': return 'Numpad1';
|
|
case 'ArrowDown': return 'Numpad2';
|
|
case 'PageDown': return 'Numpad3';
|
|
case 'ArrowLeft': return 'Numpad4';
|
|
case 'ArrowRight': return 'Numpad6';
|
|
case 'Home': return 'Numpad7';
|
|
case 'ArrowUp': return 'Numpad8';
|
|
case 'PageUp': return 'Numpad9';
|
|
case 'Enter': return 'NumpadEnter';
|
|
}
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
return 'Unidentified';
|
|
}
|
|
|
|
// Get 'KeyboardEvent.key', handling legacy browsers
|
|
export function getKey(evt) {
|
|
// Are we getting a proper key value?
|
|
if (evt.key !== undefined) {
|
|
// IE and Edge use some ancient version of the spec
|
|
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/
|
|
switch (evt.key) {
|
|
case 'Spacebar': return ' ';
|
|
case 'Esc': return 'Escape';
|
|
case 'Scroll': return 'ScrollLock';
|
|
case 'Win': return 'Meta';
|
|
case 'Apps': return 'ContextMenu';
|
|
case 'Up': return 'ArrowUp';
|
|
case 'Left': return 'ArrowLeft';
|
|
case 'Right': return 'ArrowRight';
|
|
case 'Down': return 'ArrowDown';
|
|
case 'Del': return 'Delete';
|
|
case 'Divide': return '/';
|
|
case 'Multiply': return '*';
|
|
case 'Subtract': return '-';
|
|
case 'Add': return '+';
|
|
case 'Decimal': return evt.char;
|
|
}
|
|
|
|
// Mozilla isn't fully in sync with the spec yet
|
|
switch (evt.key) {
|
|
case 'OS': return 'Meta';
|
|
case 'LaunchMyComputer': return 'LaunchApplication1';
|
|
case 'LaunchCalculator': return 'LaunchApplication2';
|
|
}
|
|
|
|
// iOS leaks some OS names
|
|
switch (evt.key) {
|
|
case 'UIKeyInputUpArrow': return 'ArrowUp';
|
|
case 'UIKeyInputDownArrow': return 'ArrowDown';
|
|
case 'UIKeyInputLeftArrow': return 'ArrowLeft';
|
|
case 'UIKeyInputRightArrow': return 'ArrowRight';
|
|
case 'UIKeyInputEscape': return 'Escape';
|
|
}
|
|
|
|
// Broken behaviour in Chrome
|
|
if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) {
|
|
return 'Delete';
|
|
}
|
|
|
|
// IE and Edge need special handling, but for everyone else we
|
|
// can trust the value provided
|
|
if (!browser.isIE() && !browser.isEdge()) {
|
|
return evt.key;
|
|
}
|
|
|
|
// IE and Edge have broken handling of AltGraph so we can only
|
|
// trust them for non-printable characters (and unfortunately
|
|
// they also specify 'Unidentified' for some problem keys)
|
|
if ((evt.key.length !== 1) && (evt.key !== 'Unidentified')) {
|
|
return evt.key;
|
|
}
|
|
}
|
|
|
|
// Try to deduce it based on the physical key
|
|
const code = getKeycode(evt);
|
|
if (code in fixedkeys) {
|
|
return fixedkeys[code];
|
|
}
|
|
|
|
// If that failed, then see if we have a printable character
|
|
if (evt.charCode) {
|
|
return String.fromCharCode(evt.charCode);
|
|
}
|
|
|
|
// At this point we have nothing left to go on
|
|
return 'Unidentified';
|
|
}
|
|
|
|
// Get the most reliable keysym value we can get from a key event
|
|
export function getKeysym(evt) {
|
|
const key = getKey(evt);
|
|
|
|
if (key === 'Unidentified') {
|
|
return null;
|
|
}
|
|
|
|
// First look up special keys
|
|
if (key in DOMKeyTable) {
|
|
let location = evt.location;
|
|
|
|
// Safari screws up location for the right cmd key
|
|
if ((key === 'Meta') && (location === 0)) {
|
|
location = 2;
|
|
}
|
|
|
|
// And for Clear
|
|
if ((key === 'Clear') && (location === 3)) {
|
|
let code = getKeycode(evt);
|
|
if (code === 'NumLock') {
|
|
location = 0;
|
|
}
|
|
}
|
|
|
|
if ((location === undefined) || (location > 3)) {
|
|
location = 0;
|
|
}
|
|
|
|
// The original Meta key now gets confused with the Windows key
|
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=1020141
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1232918
|
|
if (key === 'Meta') {
|
|
let code = getKeycode(evt);
|
|
if (code === 'AltLeft') {
|
|
return KeyTable.XK_Meta_L;
|
|
} else if (code === 'AltRight') {
|
|
return KeyTable.XK_Meta_R;
|
|
}
|
|
}
|
|
|
|
// macOS has Clear instead of NumLock, but the remote system is
|
|
// probably not macOS, so lying here is probably best...
|
|
if (key === 'Clear') {
|
|
let code = getKeycode(evt);
|
|
if (code === 'NumLock') {
|
|
return KeyTable.XK_Num_Lock;
|
|
}
|
|
}
|
|
|
|
return DOMKeyTable[key][location];
|
|
}
|
|
|
|
// Now we need to look at the Unicode symbol instead
|
|
|
|
// Special key? (FIXME: Should have been caught earlier)
|
|
if (key.length !== 1) {
|
|
return null;
|
|
}
|
|
|
|
const codepoint = key.charCodeAt();
|
|
if (codepoint) {
|
|
return keysyms.lookup(codepoint);
|
|
}
|
|
|
|
return null;
|
|
}
|