@aptre/v86 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/LICENSE +22 -0
  2. package/LICENSE.MIT +22 -0
  3. package/Readme.md +237 -0
  4. package/dist/v86.browser.js +26666 -0
  5. package/dist/v86.browser.js.map +7 -0
  6. package/dist/v86.js +26632 -0
  7. package/dist/v86.js.map +7 -0
  8. package/gen/generate_analyzer.ts +512 -0
  9. package/gen/generate_interpreter.ts +522 -0
  10. package/gen/generate_jit.ts +624 -0
  11. package/gen/rust_ast.ts +107 -0
  12. package/gen/util.ts +35 -0
  13. package/gen/x86_table.ts +1836 -0
  14. package/lib/9p.ts +1547 -0
  15. package/lib/filesystem.ts +1879 -0
  16. package/lib/marshall.ts +168 -0
  17. package/lib/softfloat/softfloat.c +32501 -0
  18. package/lib/zstd/zstddeclib.c +13520 -0
  19. package/package.json +75 -0
  20. package/src/acpi.ts +267 -0
  21. package/src/browser/dummy_screen.ts +106 -0
  22. package/src/browser/fake_network.ts +1771 -0
  23. package/src/browser/fetch_network.ts +361 -0
  24. package/src/browser/filestorage.ts +124 -0
  25. package/src/browser/inbrowser_network.ts +57 -0
  26. package/src/browser/keyboard.ts +564 -0
  27. package/src/browser/main.ts +3415 -0
  28. package/src/browser/mouse.ts +255 -0
  29. package/src/browser/network.ts +142 -0
  30. package/src/browser/print_stats.ts +336 -0
  31. package/src/browser/screen.ts +978 -0
  32. package/src/browser/serial.ts +316 -0
  33. package/src/browser/speaker.ts +1223 -0
  34. package/src/browser/starter.ts +1688 -0
  35. package/src/browser/wisp_network.ts +332 -0
  36. package/src/browser/worker_bus.ts +64 -0
  37. package/src/buffer.ts +652 -0
  38. package/src/bus.ts +78 -0
  39. package/src/const.ts +128 -0
  40. package/src/cpu.ts +2891 -0
  41. package/src/dma.ts +474 -0
  42. package/src/elf.ts +251 -0
  43. package/src/floppy.ts +1778 -0
  44. package/src/ide.ts +3455 -0
  45. package/src/io.ts +504 -0
  46. package/src/iso9660.ts +317 -0
  47. package/src/kernel.ts +250 -0
  48. package/src/lib.ts +645 -0
  49. package/src/log.ts +149 -0
  50. package/src/main.ts +199 -0
  51. package/src/ne2k.ts +1589 -0
  52. package/src/pci.ts +815 -0
  53. package/src/pit.ts +406 -0
  54. package/src/ps2.ts +820 -0
  55. package/src/rtc.ts +537 -0
  56. package/src/rust/analysis.rs +101 -0
  57. package/src/rust/codegen.rs +2660 -0
  58. package/src/rust/config.rs +3 -0
  59. package/src/rust/control_flow.rs +425 -0
  60. package/src/rust/cpu/apic.rs +658 -0
  61. package/src/rust/cpu/arith.rs +1207 -0
  62. package/src/rust/cpu/call_indirect.rs +2 -0
  63. package/src/rust/cpu/cpu.rs +4501 -0
  64. package/src/rust/cpu/fpu.rs +923 -0
  65. package/src/rust/cpu/global_pointers.rs +112 -0
  66. package/src/rust/cpu/instructions.rs +2486 -0
  67. package/src/rust/cpu/instructions_0f.rs +5261 -0
  68. package/src/rust/cpu/ioapic.rs +316 -0
  69. package/src/rust/cpu/memory.rs +351 -0
  70. package/src/rust/cpu/misc_instr.rs +613 -0
  71. package/src/rust/cpu/mod.rs +16 -0
  72. package/src/rust/cpu/modrm.rs +133 -0
  73. package/src/rust/cpu/pic.rs +402 -0
  74. package/src/rust/cpu/sse_instr.rs +361 -0
  75. package/src/rust/cpu/string.rs +701 -0
  76. package/src/rust/cpu/vga.rs +175 -0
  77. package/src/rust/cpu_context.rs +69 -0
  78. package/src/rust/dbg.rs +98 -0
  79. package/src/rust/gen/analyzer.rs +3807 -0
  80. package/src/rust/gen/analyzer0f.rs +3992 -0
  81. package/src/rust/gen/interpreter.rs +4447 -0
  82. package/src/rust/gen/interpreter0f.rs +5404 -0
  83. package/src/rust/gen/jit.rs +5080 -0
  84. package/src/rust/gen/jit0f.rs +5547 -0
  85. package/src/rust/gen/mod.rs +14 -0
  86. package/src/rust/jit.rs +2443 -0
  87. package/src/rust/jit_instructions.rs +7881 -0
  88. package/src/rust/js_api.rs +6 -0
  89. package/src/rust/leb.rs +46 -0
  90. package/src/rust/lib.rs +29 -0
  91. package/src/rust/modrm.rs +330 -0
  92. package/src/rust/opstats.rs +249 -0
  93. package/src/rust/page.rs +15 -0
  94. package/src/rust/paging.rs +25 -0
  95. package/src/rust/prefix.rs +15 -0
  96. package/src/rust/profiler.rs +155 -0
  97. package/src/rust/regs.rs +38 -0
  98. package/src/rust/softfloat.rs +286 -0
  99. package/src/rust/state_flags.rs +27 -0
  100. package/src/rust/wasmgen/mod.rs +2 -0
  101. package/src/rust/wasmgen/wasm_builder.rs +1047 -0
  102. package/src/rust/wasmgen/wasm_opcodes.rs +221 -0
  103. package/src/rust/zstd.rs +105 -0
  104. package/src/sb16.ts +1928 -0
  105. package/src/state.ts +359 -0
  106. package/src/uart.ts +472 -0
  107. package/src/vga.ts +2791 -0
  108. package/src/virtio.ts +1756 -0
  109. package/src/virtio_balloon.ts +273 -0
  110. package/src/virtio_console.ts +372 -0
  111. package/src/virtio_net.ts +326 -0
@@ -0,0 +1,564 @@
1
+ import { BusConnector } from '../bus.js'
2
+
3
+ const SHIFT_SCAN_CODE = 0x2a
4
+ const SCAN_CODE_RELEASE = 0x80
5
+
6
+ const PLATFORM_WINDOWS =
7
+ typeof window !== 'undefined' &&
8
+ window.navigator.platform.toString().toLowerCase().search('win') >= 0
9
+
10
+ export class KeyboardAdapter {
11
+ emu_enabled = true
12
+ bus: BusConnector
13
+
14
+ private keys_pressed: Record<number, boolean> = {}
15
+ private deferred_event: KeyboardEvent | null = null
16
+ private deferred_keydown = false
17
+ private deferred_timeout_id: ReturnType<typeof setTimeout> | 0 = 0
18
+
19
+ // Format:
20
+ // Javascript event.keyCode -> make code
21
+ private charmap = new Uint16Array([
22
+ 0, 0, 0, 0, 0, 0, 0, 0,
23
+ // 0x08: backspace, tab, enter
24
+ 0x0e, 0x0f, 0, 0, 0, 0x1c, 0, 0,
25
+
26
+ // 0x10: shift, ctrl, alt, pause, caps lock
27
+ 0x2a, 0x1d, 0x38, 0, 0x3a, 0, 0, 0,
28
+
29
+ // 0x18: escape
30
+ 0, 0, 0, 0x01, 0, 0, 0, 0,
31
+
32
+ // 0x20: spacebar, page down/up, end, home, arrow keys, ins, del
33
+ 0x39, 0xe049, 0xe051, 0xe04f, 0xe047, 0xe04b, 0xe048, 0xe04d, 0x50, 0,
34
+ 0, 0, 0, 0x52, 0x53, 0,
35
+
36
+ // 0x30: numbers
37
+ 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
38
+
39
+ // 0x3B: ;= (firefox only)
40
+ 0, 0x27, 0, 0x0d, 0, 0,
41
+
42
+ // 0x40
43
+ 0,
44
+
45
+ // 0x41: letters
46
+ 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
47
+ 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d,
48
+ 0x15, 0x2c,
49
+
50
+ // 0x5B: Left Win, Right Win, Menu
51
+ 0xe05b, 0xe05c, 0xe05d, 0, 0,
52
+
53
+ // 0x60: keypad
54
+ 0x52, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, 0x48, 0x49, 0, 0, 0, 0,
55
+ 0, 0,
56
+
57
+ // 0x70: F1 to F12
58
+ 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x57, 0x58,
59
+
60
+ 0, 0, 0, 0,
61
+
62
+ // 0x80
63
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
64
+
65
+ // 0x90: Numlock
66
+ 0x45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
67
+
68
+ // 0xA0: - (firefox only)
69
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0c, 0, 0,
70
+
71
+ // 0xB0
72
+ // ,
73
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x27, 0x0d, 0x33, 0x0c, 0x34, 0x35,
74
+
75
+ // 0xC0
76
+ // `
77
+ 0x29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78
+
79
+ // 0xD0
80
+ // [']\
81
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1a, 0x2b, 0x1b, 0x28, 0,
82
+
83
+ // 0xE0
84
+ // Apple key on Gecko, Right alt
85
+ 0xe05b, 0xe038, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86
+ ])
87
+
88
+ // ascii -> javascript event code (US layout)
89
+ private asciimap: Record<number, number> = {
90
+ 8: 8,
91
+ 10: 13,
92
+ 32: 32,
93
+ 39: 222,
94
+ 44: 188,
95
+ 45: 189,
96
+ 46: 190,
97
+ 47: 191,
98
+ 48: 48,
99
+ 49: 49,
100
+ 50: 50,
101
+ 51: 51,
102
+ 52: 52,
103
+ 53: 53,
104
+ 54: 54,
105
+ 55: 55,
106
+ 56: 56,
107
+ 57: 57,
108
+ 59: 186,
109
+ 61: 187,
110
+ 91: 219,
111
+ 92: 220,
112
+ 93: 221,
113
+ 96: 192,
114
+ 97: 65,
115
+ 98: 66,
116
+ 99: 67,
117
+ 100: 68,
118
+ 101: 69,
119
+ 102: 70,
120
+ 103: 71,
121
+ 104: 72,
122
+ 105: 73,
123
+ 106: 74,
124
+ 107: 75,
125
+ 108: 76,
126
+ 109: 77,
127
+ 110: 78,
128
+ 111: 79,
129
+ 112: 80,
130
+ 113: 81,
131
+ 114: 82,
132
+ 115: 83,
133
+ 116: 84,
134
+ 117: 85,
135
+ 118: 86,
136
+ 119: 87,
137
+ 120: 88,
138
+ 121: 89,
139
+ 122: 90,
140
+ }
141
+ private asciimap_shift: Record<number, number> = {
142
+ 33: 49,
143
+ 34: 222,
144
+ 35: 51,
145
+ 36: 52,
146
+ 37: 53,
147
+ 38: 55,
148
+ 40: 57,
149
+ 41: 48,
150
+ 42: 56,
151
+ 43: 187,
152
+ 58: 186,
153
+ 60: 188,
154
+ 62: 190,
155
+ 63: 191,
156
+ 64: 50,
157
+ 65: 65,
158
+ 66: 66,
159
+ 67: 67,
160
+ 68: 68,
161
+ 69: 69,
162
+ 70: 70,
163
+ 71: 71,
164
+ 72: 72,
165
+ 73: 73,
166
+ 74: 74,
167
+ 75: 75,
168
+ 76: 76,
169
+ 77: 77,
170
+ 78: 78,
171
+ 79: 79,
172
+ 80: 80,
173
+ 81: 81,
174
+ 82: 82,
175
+ 83: 83,
176
+ 84: 84,
177
+ 85: 85,
178
+ 86: 86,
179
+ 87: 87,
180
+ 88: 88,
181
+ 89: 89,
182
+ 90: 90,
183
+ 94: 54,
184
+ 95: 189,
185
+ 123: 219,
186
+ 124: 220,
187
+ 125: 221,
188
+ 126: 192,
189
+ }
190
+
191
+ // Mapping from event.code to scancode
192
+ private codemap: Record<string, number> = {
193
+ Escape: 0x0001,
194
+ Digit1: 0x0002,
195
+ Digit2: 0x0003,
196
+ Digit3: 0x0004,
197
+ Digit4: 0x0005,
198
+ Digit5: 0x0006,
199
+ Digit6: 0x0007,
200
+ Digit7: 0x0008,
201
+ Digit8: 0x0009,
202
+ Digit9: 0x000a,
203
+ Digit0: 0x000b,
204
+ Minus: 0x000c,
205
+ Equal: 0x000d,
206
+ Backspace: 0x000e,
207
+ Tab: 0x000f,
208
+ KeyQ: 0x0010,
209
+ KeyW: 0x0011,
210
+ KeyE: 0x0012,
211
+ KeyR: 0x0013,
212
+ KeyT: 0x0014,
213
+ KeyY: 0x0015,
214
+ KeyU: 0x0016,
215
+ KeyI: 0x0017,
216
+ KeyO: 0x0018,
217
+ KeyP: 0x0019,
218
+ BracketLeft: 0x001a,
219
+ BracketRight: 0x001b,
220
+ Enter: 0x001c,
221
+ ControlLeft: 0x001d,
222
+ KeyA: 0x001e,
223
+ KeyS: 0x001f,
224
+ KeyD: 0x0020,
225
+ KeyF: 0x0021,
226
+ KeyG: 0x0022,
227
+ KeyH: 0x0023,
228
+ KeyJ: 0x0024,
229
+ KeyK: 0x0025,
230
+ KeyL: 0x0026,
231
+ Semicolon: 0x0027,
232
+ Quote: 0x0028,
233
+ Backquote: 0x0029,
234
+ ShiftLeft: 0x002a,
235
+ Backslash: 0x002b,
236
+ KeyZ: 0x002c,
237
+ KeyX: 0x002d,
238
+ KeyC: 0x002e,
239
+ KeyV: 0x002f,
240
+ KeyB: 0x0030,
241
+ KeyN: 0x0031,
242
+ KeyM: 0x0032,
243
+ Comma: 0x0033,
244
+ Period: 0x0034,
245
+ Slash: 0x0035,
246
+ IntlRo: 0x0035,
247
+ ShiftRight: 0x0036,
248
+ NumpadMultiply: 0x0037,
249
+ AltLeft: 0x0038,
250
+ Space: 0x0039,
251
+ CapsLock: 0x003a,
252
+ F1: 0x003b,
253
+ F2: 0x003c,
254
+ F3: 0x003d,
255
+ F4: 0x003e,
256
+ F5: 0x003f,
257
+ F6: 0x0040,
258
+ F7: 0x0041,
259
+ F8: 0x0042,
260
+ F9: 0x0043,
261
+ F10: 0x0044,
262
+ NumLock: 0x0045,
263
+ ScrollLock: 0x0046,
264
+ Numpad7: 0x0047,
265
+ Numpad8: 0x0048,
266
+ Numpad9: 0x0049,
267
+ NumpadSubtract: 0x004a,
268
+ Numpad4: 0x004b,
269
+ Numpad5: 0x004c,
270
+ Numpad6: 0x004d,
271
+ NumpadAdd: 0x004e,
272
+ Numpad1: 0x004f,
273
+ Numpad2: 0x0050,
274
+ Numpad3: 0x0051,
275
+ Numpad0: 0x0052,
276
+ NumpadDecimal: 0x0053,
277
+ IntlBackslash: 0x0056,
278
+ F11: 0x0057,
279
+ F12: 0x0058,
280
+
281
+ NumpadEnter: 0xe01c,
282
+ ControlRight: 0xe01d,
283
+ NumpadDivide: 0xe035,
284
+ AltRight: 0xe038,
285
+ Home: 0xe047,
286
+ ArrowUp: 0xe048,
287
+ PageUp: 0xe049,
288
+ ArrowLeft: 0xe04b,
289
+ ArrowRight: 0xe04d,
290
+ End: 0xe04f,
291
+ ArrowDown: 0xe050,
292
+ PageDown: 0xe051,
293
+ Insert: 0xe052,
294
+ Delete: 0xe053,
295
+
296
+ MetaLeft: 0xe05b,
297
+ OSLeft: 0xe05b,
298
+ MetaRight: 0xe05c,
299
+ OSRight: 0xe05c,
300
+ ContextMenu: 0xe05d,
301
+ }
302
+
303
+ private keyup_handler: (e: KeyboardEvent) => void
304
+ private keydown_handler: (e: KeyboardEvent) => void
305
+ private blur_handler: (e: FocusEvent) => void
306
+ private input_handler: (e: InputEvent) => void
307
+
308
+ constructor(bus: BusConnector) {
309
+ this.bus = bus
310
+
311
+ this.keyup_handler = (e: KeyboardEvent) => {
312
+ if (!e.altKey && this.keys_pressed[0x38]) {
313
+ this.handle_code(0x38, false)
314
+ }
315
+ return this.handler(e, false)
316
+ }
317
+
318
+ this.keydown_handler = (e: KeyboardEvent) => {
319
+ if (!e.altKey && this.keys_pressed[0x38]) {
320
+ this.handle_code(0x38, false)
321
+ }
322
+ return this.handler(e, true)
323
+ }
324
+
325
+ this.blur_handler = (_e: FocusEvent) => {
326
+ const keys = Object.keys(this.keys_pressed)
327
+
328
+ for (let i = 0; i < keys.length; i++) {
329
+ const key = +keys[i]
330
+
331
+ if (this.keys_pressed[key]) {
332
+ this.handle_code(key, false)
333
+ }
334
+ }
335
+
336
+ this.keys_pressed = {}
337
+ }
338
+
339
+ this.input_handler = (e: InputEvent) => {
340
+ if (!this.bus) {
341
+ return
342
+ }
343
+
344
+ if (!this.may_handle(e)) {
345
+ return
346
+ }
347
+
348
+ switch (e.inputType) {
349
+ case 'insertText':
350
+ if (e.data) {
351
+ for (let i = 0; i < e.data.length; i++) {
352
+ this.simulate_char(e.data[i])
353
+ }
354
+ }
355
+ break
356
+
357
+ case 'insertLineBreak':
358
+ this.simulate_press(13) // enter
359
+ break
360
+
361
+ case 'deleteContentBackward':
362
+ this.simulate_press(8) // backspace
363
+ break
364
+ }
365
+ }
366
+
367
+ this.init()
368
+ }
369
+
370
+ destroy(): void {
371
+ if (typeof window !== 'undefined') {
372
+ window.removeEventListener('keyup', this.keyup_handler, false)
373
+ window.removeEventListener('keydown', this.keydown_handler, false)
374
+ window.removeEventListener('blur', this.blur_handler, false)
375
+
376
+ window.removeEventListener(
377
+ 'input',
378
+ this.input_handler as any,
379
+ false,
380
+ )
381
+ }
382
+ }
383
+
384
+ init(): void {
385
+ if (typeof window === 'undefined') {
386
+ return
387
+ }
388
+ this.destroy()
389
+
390
+ window.addEventListener('keyup', this.keyup_handler, false)
391
+ window.addEventListener('keydown', this.keydown_handler, false)
392
+ window.addEventListener('blur', this.blur_handler, false)
393
+
394
+ window.addEventListener('input', this.input_handler as any, false)
395
+ }
396
+
397
+ simulate_press(code: number): void {
398
+ const ev = { keyCode: code } as KeyboardEvent
399
+ this.handler(ev, true)
400
+ this.handler(ev, false)
401
+ }
402
+
403
+ simulate_char(chr: string): void {
404
+ const code = chr.charCodeAt(0)
405
+
406
+ if (code in this.asciimap) {
407
+ this.simulate_press(this.asciimap[code])
408
+ } else if (code in this.asciimap_shift) {
409
+ this.send_to_controller(SHIFT_SCAN_CODE)
410
+ this.simulate_press(this.asciimap_shift[code])
411
+ this.send_to_controller(SHIFT_SCAN_CODE | SCAN_CODE_RELEASE)
412
+ } else {
413
+ console.log('ascii -> keyCode not found: ', code, chr)
414
+ }
415
+ }
416
+
417
+ private may_handle(e: Event): boolean {
418
+ const ke = e as KeyboardEvent
419
+ if (
420
+ ke.shiftKey &&
421
+ ke.ctrlKey &&
422
+ (ke.keyCode === 73 || ke.keyCode === 74 || ke.keyCode === 75)
423
+ ) {
424
+ return false
425
+ }
426
+
427
+ if (!this.emu_enabled) {
428
+ return false
429
+ }
430
+
431
+ if (e.target) {
432
+ const target = e.target as HTMLElement
433
+ return (
434
+ target.classList.contains('phone_keyboard') ||
435
+ (target.nodeName !== 'INPUT' && target.nodeName !== 'TEXTAREA')
436
+ )
437
+ }
438
+
439
+ return true
440
+ }
441
+
442
+ private translate(e: KeyboardEvent): number {
443
+ if (e.code !== undefined) {
444
+ const code = this.codemap[e.code]
445
+
446
+ if (code !== undefined) {
447
+ return code
448
+ }
449
+ }
450
+
451
+ return this.charmap[e.keyCode]
452
+ }
453
+
454
+ private handler(e: KeyboardEvent, keydown: boolean): false | undefined {
455
+ if (!this.bus) {
456
+ return
457
+ }
458
+
459
+ if (!this.may_handle(e)) {
460
+ return
461
+ }
462
+
463
+ if (
464
+ e.code === '' ||
465
+ e.key === 'Process' ||
466
+ e.key === 'Unidentified' ||
467
+ e.keyCode === 229
468
+ ) {
469
+ return
470
+ }
471
+
472
+ if (e.preventDefault) {
473
+ e.preventDefault()
474
+ }
475
+
476
+ if (PLATFORM_WINDOWS) {
477
+ if (this.deferred_event) {
478
+ clearTimeout(this.deferred_timeout_id)
479
+ if (
480
+ !(
481
+ e.getModifierState &&
482
+ e.getModifierState('AltGraph') &&
483
+ this.deferred_keydown === keydown &&
484
+ this.deferred_event.code === 'ControlLeft' &&
485
+ e.code === 'AltRight'
486
+ )
487
+ ) {
488
+ this.handle_event(
489
+ this.deferred_event,
490
+ this.deferred_keydown,
491
+ )
492
+ }
493
+ this.deferred_event = null
494
+ }
495
+
496
+ if (e.code === 'ControlLeft') {
497
+ this.deferred_event = e
498
+ this.deferred_keydown = keydown
499
+ this.deferred_timeout_id = setTimeout(() => {
500
+ if (this.deferred_event) {
501
+ this.handle_event(
502
+ this.deferred_event,
503
+ this.deferred_keydown,
504
+ )
505
+ this.deferred_event = null
506
+ }
507
+ }, 10)
508
+ return false
509
+ }
510
+ }
511
+
512
+ this.handle_event(e, keydown)
513
+ return false
514
+ }
515
+
516
+ private handle_event(e: KeyboardEvent, keydown: boolean): void {
517
+ const code = this.translate(e)
518
+
519
+ if (!code) {
520
+ console.log(
521
+ 'Missing char in map: keyCode=' +
522
+ (e.keyCode || -1).toString(16) +
523
+ ' code=' +
524
+ e.code,
525
+ )
526
+ return
527
+ }
528
+
529
+ this.handle_code(code, keydown, e.repeat)
530
+ }
531
+
532
+ private handle_code(
533
+ code: number,
534
+ keydown: boolean,
535
+ is_repeat?: boolean,
536
+ ): void {
537
+ if (keydown) {
538
+ if (this.keys_pressed[code] && !is_repeat) {
539
+ this.handle_code(code, false)
540
+ }
541
+ } else {
542
+ if (!this.keys_pressed[code]) {
543
+ return
544
+ }
545
+ }
546
+
547
+ this.keys_pressed[code] = keydown
548
+
549
+ if (!keydown) {
550
+ code |= 0x80
551
+ }
552
+
553
+ if (code > 0xff) {
554
+ this.send_to_controller(code >> 8)
555
+ this.send_to_controller(code & 0xff)
556
+ } else {
557
+ this.send_to_controller(code)
558
+ }
559
+ }
560
+
561
+ private send_to_controller(code: number): void {
562
+ this.bus.send('keyboard-code', code)
563
+ }
564
+ }