]>
Commit | Line | Data |
---|---|---|
75839905 | 1 | import KeyTable from "./keysym.js"; |
3ae0bb09 | 2 | import keysyms from "./keysymdef.js"; |
80cb8ffd | 3 | import vkeys from "./vkeys.js"; |
f714f7de | 4 | import fixedkeys from "./fixedkeys.js"; |
9782d4a3 | 5 | import DOMKeyTable from "./domkeytable.js"; |
59ef2916 | 6 | import * as browser from "../util/browser.js"; |
4ef7566b | 7 | |
80cb8ffd | 8 | // Get 'KeyboardEvent.code', handling legacy browsers |
3f1cda2e | 9 | export function getKeycode(evt) { |
80cb8ffd PO |
10 | // Are we getting proper key identifiers? |
11 | // (unfortunately Firefox and Chrome are crappy here and gives | |
12 | // us an empty string on some platforms, rather than leaving it | |
13 | // undefined) | |
14 | if (evt.code) { | |
15 | // Mozilla isn't fully in sync with the spec yet | |
16 | switch (evt.code) { | |
17 | case 'OSLeft': return 'MetaLeft'; | |
18 | case 'OSRight': return 'MetaRight'; | |
19 | } | |
20 | ||
21 | return evt.code; | |
6d6f0db0 | 22 | } |
80cb8ffd PO |
23 | |
24 | // The de-facto standard is to use Windows Virtual-Key codes | |
25 | // in the 'keyCode' field for non-printable characters. However | |
26 | // Webkit sets it to the same as charCode in 'keypress' events. | |
27 | if ((evt.type !== 'keypress') && (evt.keyCode in vkeys)) { | |
2b5f94fa | 28 | let code = vkeys[evt.keyCode]; |
80cb8ffd PO |
29 | |
30 | // macOS has messed up this code for some reason | |
59ef2916 | 31 | if (browser.isMac() && (code === 'ContextMenu')) { |
80cb8ffd PO |
32 | code = 'MetaRight'; |
33 | } | |
34 | ||
35 | // The keyCode doesn't distinguish between left and right | |
36 | // for the standard modifiers | |
37 | if (evt.location === 2) { | |
38 | switch (code) { | |
39 | case 'ShiftLeft': return 'ShiftRight'; | |
40 | case 'ControlLeft': return 'ControlRight'; | |
41 | case 'AltLeft': return 'AltRight'; | |
42 | } | |
43 | } | |
44 | ||
45 | // Nor a bunch of the numpad keys | |
46 | if (evt.location === 3) { | |
47 | switch (code) { | |
48 | case 'Delete': return 'NumpadDecimal'; | |
49 | case 'Insert': return 'Numpad0'; | |
50 | case 'End': return 'Numpad1'; | |
51 | case 'ArrowDown': return 'Numpad2'; | |
52 | case 'PageDown': return 'Numpad3'; | |
53 | case 'ArrowLeft': return 'Numpad4'; | |
54 | case 'ArrowRight': return 'Numpad6'; | |
55 | case 'Home': return 'Numpad7'; | |
56 | case 'ArrowUp': return 'Numpad8'; | |
57 | case 'PageUp': return 'Numpad9'; | |
58 | case 'Enter': return 'NumpadEnter'; | |
59 | } | |
60 | } | |
61 | ||
62 | return code; | |
6d6f0db0 | 63 | } |
80cb8ffd PO |
64 | |
65 | return 'Unidentified'; | |
6d6f0db0 SR |
66 | } |
67 | ||
9782d4a3 PO |
68 | // Get 'KeyboardEvent.key', handling legacy browsers |
69 | export function getKey(evt) { | |
70 | // Are we getting a proper key value? | |
71 | if (evt.key !== undefined) { | |
72 | // IE and Edge use some ancient version of the spec | |
73 | // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8860571/ | |
74 | switch (evt.key) { | |
75 | case 'Spacebar': return ' '; | |
76 | case 'Esc': return 'Escape'; | |
77 | case 'Scroll': return 'ScrollLock'; | |
78 | case 'Win': return 'Meta'; | |
79 | case 'Apps': return 'ContextMenu'; | |
80 | case 'Up': return 'ArrowUp'; | |
81 | case 'Left': return 'ArrowLeft'; | |
82 | case 'Right': return 'ArrowRight'; | |
83 | case 'Down': return 'ArrowDown'; | |
84 | case 'Del': return 'Delete'; | |
85 | case 'Divide': return '/'; | |
86 | case 'Multiply': return '*'; | |
87 | case 'Subtract': return '-'; | |
88 | case 'Add': return '+'; | |
89 | case 'Decimal': return evt.char; | |
90 | } | |
91 | ||
92 | // Mozilla isn't fully in sync with the spec yet | |
93 | switch (evt.key) { | |
94 | case 'OS': return 'Meta'; | |
ebee9cdd PO |
95 | case 'LaunchMyComputer': return 'LaunchApplication1'; |
96 | case 'LaunchCalculator': return 'LaunchApplication2'; | |
9782d4a3 PO |
97 | } |
98 | ||
e7c4d669 PO |
99 | // iOS leaks some OS names |
100 | switch (evt.key) { | |
101 | case 'UIKeyInputUpArrow': return 'ArrowUp'; | |
102 | case 'UIKeyInputDownArrow': return 'ArrowDown'; | |
103 | case 'UIKeyInputLeftArrow': return 'ArrowLeft'; | |
104 | case 'UIKeyInputRightArrow': return 'ArrowRight'; | |
105 | case 'UIKeyInputEscape': return 'Escape'; | |
106 | } | |
107 | ||
9d956e91 PO |
108 | // Broken behaviour in Chrome |
109 | if ((evt.key === '\x00') && (evt.code === 'NumpadDecimal')) { | |
110 | return 'Delete'; | |
111 | } | |
112 | ||
dccf6fac | 113 | return evt.key; |
9782d4a3 | 114 | } |
bfa1b237 | 115 | |
9782d4a3 | 116 | // Try to deduce it based on the physical key |
2b5f94fa | 117 | const code = getKeycode(evt); |
f714f7de PO |
118 | if (code in fixedkeys) { |
119 | return fixedkeys[code]; | |
6d6f0db0 | 120 | } |
bfa1b237 | 121 | |
9782d4a3 PO |
122 | // If that failed, then see if we have a printable character |
123 | if (evt.charCode) { | |
124 | return String.fromCharCode(evt.charCode); | |
125 | } | |
4ef7566b | 126 | |
9782d4a3 PO |
127 | // At this point we have nothing left to go on |
128 | return 'Unidentified'; | |
129 | } | |
130 | ||
131 | // Get the most reliable keysym value we can get from a key event | |
3f1cda2e | 132 | export function getKeysym(evt) { |
2b5f94fa | 133 | const key = getKey(evt); |
9782d4a3 PO |
134 | |
135 | if (key === 'Unidentified') { | |
136 | return null; | |
4ef7566b | 137 | } |
138 | ||
9782d4a3 PO |
139 | // First look up special keys |
140 | if (key in DOMKeyTable) { | |
2b5f94fa | 141 | let location = evt.location; |
f714f7de | 142 | |
9782d4a3 PO |
143 | // Safari screws up location for the right cmd key |
144 | if ((key === 'Meta') && (location === 0)) { | |
145 | location = 2; | |
f714f7de | 146 | } |
4ef7566b | 147 | |
3388c92c PO |
148 | // And for Clear |
149 | if ((key === 'Clear') && (location === 3)) { | |
150 | let code = getKeycode(evt); | |
151 | if (code === 'NumLock') { | |
152 | location = 0; | |
153 | } | |
154 | } | |
155 | ||
9782d4a3 PO |
156 | if ((location === undefined) || (location > 3)) { |
157 | location = 0; | |
f714f7de | 158 | } |
4ef7566b | 159 | |
75839905 PO |
160 | // The original Meta key now gets confused with the Windows key |
161 | // https://bugs.chromium.org/p/chromium/issues/detail?id=1020141 | |
162 | // https://bugzilla.mozilla.org/show_bug.cgi?id=1232918 | |
163 | if (key === 'Meta') { | |
164 | let code = getKeycode(evt); | |
165 | if (code === 'AltLeft') { | |
166 | return KeyTable.XK_Meta_L; | |
167 | } else if (code === 'AltRight') { | |
168 | return KeyTable.XK_Meta_R; | |
169 | } | |
170 | } | |
171 | ||
3388c92c PO |
172 | // macOS has Clear instead of NumLock, but the remote system is |
173 | // probably not macOS, so lying here is probably best... | |
174 | if (key === 'Clear') { | |
175 | let code = getKeycode(evt); | |
176 | if (code === 'NumLock') { | |
177 | return KeyTable.XK_Num_Lock; | |
178 | } | |
179 | } | |
180 | ||
9782d4a3 | 181 | return DOMKeyTable[key][location]; |
6d6f0db0 | 182 | } |
282834ca | 183 | |
f714f7de | 184 | // Now we need to look at the Unicode symbol instead |
4ef7566b | 185 | |
9782d4a3 PO |
186 | // Special key? (FIXME: Should have been caught earlier) |
187 | if (key.length !== 1) { | |
188 | return null; | |
f714f7de | 189 | } |
6d6f0db0 | 190 | |
2b5f94fa | 191 | const codepoint = key.charCodeAt(); |
f714f7de PO |
192 | if (codepoint) { |
193 | return keysyms.lookup(codepoint); | |
4ef7566b | 194 | } |
f714f7de PO |
195 | |
196 | return null; | |
6d6f0db0 | 197 | } |