ac6502 1.0.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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +261 -0
  3. package/dist/components/CPU.js +1170 -0
  4. package/dist/components/CPU.js.map +1 -0
  5. package/dist/components/Cart.js +23 -0
  6. package/dist/components/Cart.js.map +1 -0
  7. package/dist/components/IO/Empty.js +19 -0
  8. package/dist/components/IO/Empty.js.map +1 -0
  9. package/dist/components/IO/GPIOAttachments/GPIOAttachment.js +71 -0
  10. package/dist/components/IO/GPIOAttachments/GPIOAttachment.js.map +1 -0
  11. package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js +90 -0
  12. package/dist/components/IO/GPIOAttachments/GPIOJoystickAttachment.js.map +1 -0
  13. package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js +489 -0
  14. package/dist/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.js.map +1 -0
  15. package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js +274 -0
  16. package/dist/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.js.map +1 -0
  17. package/dist/components/IO/GPIOCard.js +597 -0
  18. package/dist/components/IO/GPIOCard.js.map +1 -0
  19. package/dist/components/IO/InputBoard.js +19 -0
  20. package/dist/components/IO/InputBoard.js.map +1 -0
  21. package/dist/components/IO/LCDCard.js +19 -0
  22. package/dist/components/IO/LCDCard.js.map +1 -0
  23. package/dist/components/IO/RAMCard.js +63 -0
  24. package/dist/components/IO/RAMCard.js.map +1 -0
  25. package/dist/components/IO/RTCCard.js +483 -0
  26. package/dist/components/IO/RTCCard.js.map +1 -0
  27. package/dist/components/IO/SerialCard.js +282 -0
  28. package/dist/components/IO/SerialCard.js.map +1 -0
  29. package/dist/components/IO/SoundCard.js +620 -0
  30. package/dist/components/IO/SoundCard.js.map +1 -0
  31. package/dist/components/IO/StorageCard.js +428 -0
  32. package/dist/components/IO/StorageCard.js.map +1 -0
  33. package/dist/components/IO/VGACard.js +9 -0
  34. package/dist/components/IO/VGACard.js.map +1 -0
  35. package/dist/components/IO/VideoCard.js +623 -0
  36. package/dist/components/IO/VideoCard.js.map +1 -0
  37. package/dist/components/IO.js +3 -0
  38. package/dist/components/IO.js.map +1 -0
  39. package/dist/components/Machine.js +310 -0
  40. package/dist/components/Machine.js.map +1 -0
  41. package/dist/components/RAM.js +24 -0
  42. package/dist/components/RAM.js.map +1 -0
  43. package/dist/components/ROM.js +23 -0
  44. package/dist/components/ROM.js.map +1 -0
  45. package/dist/index.js +441 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/tests/CPU.test.js +1626 -0
  48. package/dist/tests/CPU.test.js.map +1 -0
  49. package/dist/tests/Cart.test.js +119 -0
  50. package/dist/tests/Cart.test.js.map +1 -0
  51. package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js +339 -0
  52. package/dist/tests/IO/GPIOAttachments/GPIOAttachment.test.js.map +1 -0
  53. package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js +126 -0
  54. package/dist/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.js.map +1 -0
  55. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js +779 -0
  56. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.js.map +1 -0
  57. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js +355 -0
  58. package/dist/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.js.map +1 -0
  59. package/dist/tests/IO/GPIOCard.test.js +503 -0
  60. package/dist/tests/IO/GPIOCard.test.js.map +1 -0
  61. package/dist/tests/IO/RAMCard.test.js +229 -0
  62. package/dist/tests/IO/RAMCard.test.js.map +1 -0
  63. package/dist/tests/IO/RTCCard.test.js +177 -0
  64. package/dist/tests/IO/RTCCard.test.js.map +1 -0
  65. package/dist/tests/IO/SerialCard.test.js +423 -0
  66. package/dist/tests/IO/SerialCard.test.js.map +1 -0
  67. package/dist/tests/IO/SoundCard.test.js +528 -0
  68. package/dist/tests/IO/SoundCard.test.js.map +1 -0
  69. package/dist/tests/IO/StorageCard.test.js +647 -0
  70. package/dist/tests/IO/StorageCard.test.js.map +1 -0
  71. package/dist/tests/IO/VideoCard.test.js +549 -0
  72. package/dist/tests/IO/VideoCard.test.js.map +1 -0
  73. package/dist/tests/Machine.test.js +383 -0
  74. package/dist/tests/Machine.test.js.map +1 -0
  75. package/dist/tests/RAM.test.js +160 -0
  76. package/dist/tests/RAM.test.js.map +1 -0
  77. package/dist/tests/ROM.test.js +123 -0
  78. package/dist/tests/ROM.test.js.map +1 -0
  79. package/jest.config.cjs +9 -0
  80. package/package.json +43 -0
  81. package/src/components/CPU.ts +1371 -0
  82. package/src/components/Cart.ts +20 -0
  83. package/src/components/IO/GPIOAttachments/GPIOAttachment.ts +189 -0
  84. package/src/components/IO/GPIOAttachments/GPIOJoystickAttachment.ts +99 -0
  85. package/src/components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.ts +465 -0
  86. package/src/components/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.ts +287 -0
  87. package/src/components/IO/GPIOCard.ts +677 -0
  88. package/src/components/IO/RAMCard.ts +68 -0
  89. package/src/components/IO/RTCCard.ts +518 -0
  90. package/src/components/IO/SerialCard.ts +335 -0
  91. package/src/components/IO/SoundCard.ts +711 -0
  92. package/src/components/IO/StorageCard.ts +473 -0
  93. package/src/components/IO/VideoCard.ts +730 -0
  94. package/src/components/IO.ts +11 -0
  95. package/src/components/Machine.ts +364 -0
  96. package/src/components/RAM.ts +23 -0
  97. package/src/components/ROM.ts +19 -0
  98. package/src/index.ts +474 -0
  99. package/src/tests/CPU.test.ts +2045 -0
  100. package/src/tests/Cart.test.ts +149 -0
  101. package/src/tests/IO/GPIOAttachments/GPIOAttachment.test.ts +413 -0
  102. package/src/tests/IO/GPIOAttachments/GPIOJoystickAttachment.test.ts +147 -0
  103. package/src/tests/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment.test.ts +961 -0
  104. package/src/tests/IO/GPIOAttachments/GPIOKeyboardMatrixAttachment.test.ts +449 -0
  105. package/src/tests/IO/GPIOCard.test.ts +644 -0
  106. package/src/tests/IO/RAMCard.test.ts +284 -0
  107. package/src/tests/IO/RTCCard.test.ts +222 -0
  108. package/src/tests/IO/SerialCard.test.ts +530 -0
  109. package/src/tests/IO/SoundCard.test.ts +659 -0
  110. package/src/tests/IO/StorageCard.test.ts +787 -0
  111. package/src/tests/IO/VideoCard.test.ts +668 -0
  112. package/src/tests/Machine.test.ts +437 -0
  113. package/src/tests/RAM.test.ts +196 -0
  114. package/src/tests/ROM.test.ts +154 -0
  115. package/tsconfig.json +12 -0
@@ -0,0 +1,779 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const GPIOKeyboardEncoderAttachment_1 = require("../../../components/IO/GPIOAttachments/GPIOKeyboardEncoderAttachment");
4
+ describe('GPIOKeyboardEncoderAttachment', () => {
5
+ let encoder;
6
+ beforeEach(() => {
7
+ encoder = new GPIOKeyboardEncoderAttachment_1.GPIOKeyboardEncoderAttachment(5);
8
+ });
9
+ describe('Initialization', () => {
10
+ it('should initialize with no data ready', () => {
11
+ expect(encoder.hasDataReadyA()).toBe(false);
12
+ expect(encoder.hasDataReadyB()).toBe(false);
13
+ });
14
+ it('should initialize with no interrupts pending', () => {
15
+ expect(encoder.hasCA1Interrupt()).toBe(false);
16
+ expect(encoder.hasCB1Interrupt()).toBe(false);
17
+ });
18
+ it('should be disabled by default (CA2/CB2 high)', () => {
19
+ encoder.updateControlLines(false, true, false, true);
20
+ encoder.updateKey(0x04, true); // 'a'
21
+ expect(encoder.hasCA1Interrupt()).toBe(false);
22
+ expect(encoder.hasCB1Interrupt()).toBe(false);
23
+ });
24
+ it('should have correct priority', () => {
25
+ expect(encoder.getPriority()).toBe(5);
26
+ });
27
+ });
28
+ describe('Reset', () => {
29
+ it('should clear all data and states', () => {
30
+ // Enable and generate some data
31
+ encoder.updateControlLines(false, false, false, false);
32
+ encoder.updateKey(0x04, true); // 'a'
33
+ expect(encoder.hasDataReadyA()).toBe(true);
34
+ // Reset
35
+ encoder.reset();
36
+ expect(encoder.hasDataReadyA()).toBe(false);
37
+ expect(encoder.hasDataReadyB()).toBe(false);
38
+ expect(encoder.hasCA1Interrupt()).toBe(false);
39
+ expect(encoder.hasCB1Interrupt()).toBe(false);
40
+ });
41
+ });
42
+ describe('Enable/Disable Control', () => {
43
+ it('should enable Port A when CA2 is LOW', () => {
44
+ encoder.updateControlLines(false, false, false, true);
45
+ encoder.updateKey(0x04, true); // 'a'
46
+ expect(encoder.hasCA1Interrupt()).toBe(true);
47
+ expect(encoder.hasCB1Interrupt()).toBe(false);
48
+ });
49
+ it('should enable Port B when CB2 is LOW', () => {
50
+ encoder.updateControlLines(false, true, false, false);
51
+ encoder.updateKey(0x04, true); // 'a'
52
+ expect(encoder.hasCA1Interrupt()).toBe(false);
53
+ expect(encoder.hasCB1Interrupt()).toBe(true);
54
+ });
55
+ it('should enable both ports when both CA2 and CB2 are LOW', () => {
56
+ encoder.updateControlLines(false, false, false, false);
57
+ encoder.updateKey(0x04, true); // 'a'
58
+ expect(encoder.hasCA1Interrupt()).toBe(true);
59
+ expect(encoder.hasCB1Interrupt()).toBe(true);
60
+ });
61
+ it('should disable Port A when CA2 is HIGH', () => {
62
+ encoder.updateControlLines(false, true, false, false);
63
+ encoder.updateKey(0x04, true); // 'a'
64
+ expect(encoder.hasCA1Interrupt()).toBe(false);
65
+ });
66
+ it('should disable Port B when CB2 is HIGH', () => {
67
+ encoder.updateControlLines(false, false, false, true);
68
+ encoder.updateKey(0x04, true); // 'a'
69
+ expect(encoder.hasCB1Interrupt()).toBe(false);
70
+ });
71
+ });
72
+ describe('Port Reading', () => {
73
+ it('should return 0xFF when no data ready on Port A', () => {
74
+ const value = encoder.readPortA(0xFF, 0x00);
75
+ expect(value).toBe(0xFF);
76
+ });
77
+ it('should return 0xFF when no data ready on Port B', () => {
78
+ const value = encoder.readPortB(0xFF, 0x00);
79
+ expect(value).toBe(0xFF);
80
+ });
81
+ it('should return ASCII data when data ready on Port A', () => {
82
+ encoder.updateControlLines(false, false, false, false);
83
+ encoder.updateKey(0x04, true); // 'a' = 0x61
84
+ const value = encoder.readPortA(0xFF, 0x00);
85
+ expect(value).toBe(0x61);
86
+ });
87
+ it('should return ASCII data when data ready on Port B', () => {
88
+ encoder.updateControlLines(false, false, false, false);
89
+ encoder.updateKey(0x04, true); // 'a' = 0x61
90
+ const value = encoder.readPortB(0xFF, 0x00);
91
+ expect(value).toBe(0x61);
92
+ });
93
+ it('should return 0xFF on disabled port even with data ready', () => {
94
+ encoder.updateControlLines(false, true, false, true); // Both disabled
95
+ encoder.updateKey(0x04, true); // 'a'
96
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFF);
97
+ expect(encoder.readPortB(0xFF, 0x00)).toBe(0xFF);
98
+ });
99
+ it('should provide same data on both ports', () => {
100
+ encoder.updateControlLines(false, false, false, false);
101
+ encoder.updateKey(0x04, true); // 'a'
102
+ const valueA = encoder.readPortA(0xFF, 0x00);
103
+ const valueB = encoder.readPortB(0xFF, 0x00);
104
+ expect(valueA).toBe(valueB);
105
+ expect(valueA).toBe(0x61);
106
+ });
107
+ });
108
+ describe('Interrupt Handling', () => {
109
+ it('should trigger CA1 interrupt when Port A enabled and key pressed', () => {
110
+ encoder.updateControlLines(false, false, false, true);
111
+ expect(encoder.hasCA1Interrupt()).toBe(false);
112
+ encoder.updateKey(0x04, true); // 'a'
113
+ expect(encoder.hasCA1Interrupt()).toBe(true);
114
+ });
115
+ it('should trigger CB1 interrupt when Port B enabled and key pressed', () => {
116
+ encoder.updateControlLines(false, true, false, false);
117
+ expect(encoder.hasCB1Interrupt()).toBe(false);
118
+ encoder.updateKey(0x04, true); // 'a'
119
+ expect(encoder.hasCB1Interrupt()).toBe(true);
120
+ });
121
+ it('should clear CA1 interrupt and data ready when cleared', () => {
122
+ encoder.updateControlLines(false, false, false, false);
123
+ encoder.updateKey(0x04, true); // 'a'
124
+ expect(encoder.hasCA1Interrupt()).toBe(true);
125
+ expect(encoder.hasDataReadyA()).toBe(true);
126
+ encoder.clearInterrupts(true, false, false, false);
127
+ expect(encoder.hasCA1Interrupt()).toBe(false);
128
+ expect(encoder.hasDataReadyA()).toBe(false);
129
+ });
130
+ it('should clear CB1 interrupt and data ready when cleared', () => {
131
+ encoder.updateControlLines(false, false, false, false);
132
+ encoder.updateKey(0x04, true); // 'a'
133
+ expect(encoder.hasCB1Interrupt()).toBe(true);
134
+ expect(encoder.hasDataReadyB()).toBe(true);
135
+ encoder.clearInterrupts(false, false, true, false);
136
+ expect(encoder.hasCB1Interrupt()).toBe(false);
137
+ expect(encoder.hasDataReadyB()).toBe(false);
138
+ });
139
+ it('should not trigger interrupt when port is disabled', () => {
140
+ encoder.updateControlLines(false, true, false, true); // Both disabled
141
+ encoder.updateKey(0x04, true); // 'a'
142
+ expect(encoder.hasCA1Interrupt()).toBe(false);
143
+ expect(encoder.hasCB1Interrupt()).toBe(false);
144
+ });
145
+ });
146
+ describe('Basic Key Mapping', () => {
147
+ beforeEach(() => {
148
+ encoder.updateControlLines(false, false, false, false);
149
+ });
150
+ it('should map lowercase letters correctly', () => {
151
+ encoder.updateKey(0x04, true); // 'a'
152
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x61);
153
+ encoder.clearInterrupts(true, false, true, false);
154
+ encoder.updateKey(0x1D, true); // 'z'
155
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x7A);
156
+ });
157
+ it('should map numbers correctly', () => {
158
+ encoder.updateKey(0x1E, true); // '1'
159
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x31);
160
+ encoder.clearInterrupts(true, false, true, false);
161
+ encoder.updateKey(0x27, true); // '0'
162
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x30);
163
+ });
164
+ it('should map special keys correctly', () => {
165
+ encoder.updateKey(0x28, true); // Enter
166
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x0D);
167
+ encoder.clearInterrupts(true, false, true, false);
168
+ encoder.updateKey(0x29, true); // Escape
169
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x1B);
170
+ encoder.clearInterrupts(true, false, true, false);
171
+ encoder.updateKey(0x2C, true); // Space
172
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x20);
173
+ });
174
+ it('should ignore key releases', () => {
175
+ encoder.updateKey(0x04, true); // Press 'a'
176
+ expect(encoder.hasDataReadyA()).toBe(true);
177
+ encoder.clearInterrupts(true, false, true, false);
178
+ encoder.updateKey(0x04, false); // Release 'a'
179
+ expect(encoder.hasDataReadyA()).toBe(false); // No new data
180
+ });
181
+ it('should ignore unknown keycodes', () => {
182
+ encoder.updateKey(0xFF, true); // Invalid keycode
183
+ expect(encoder.hasDataReadyA()).toBe(false);
184
+ });
185
+ });
186
+ describe('Modifier Keys', () => {
187
+ beforeEach(() => {
188
+ encoder.updateControlLines(false, false, false, false);
189
+ });
190
+ it('should not generate output for modifier keys alone', () => {
191
+ encoder.updateKey(0xE0, true); // Left Ctrl
192
+ expect(encoder.hasDataReadyA()).toBe(false);
193
+ encoder.updateKey(0xE1, true); // Left Shift
194
+ expect(encoder.hasDataReadyA()).toBe(false);
195
+ encoder.updateKey(0xE2, true); // Left Alt
196
+ expect(encoder.hasDataReadyA()).toBe(false);
197
+ });
198
+ it('should track modifier key state across presses', () => {
199
+ // Press Shift
200
+ encoder.updateKey(0xE1, true);
201
+ encoder.updateKey(0x04, true); // 'a' -> 'A'
202
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x41);
203
+ // Release Shift
204
+ encoder.clearInterrupts(true, false, true, false);
205
+ encoder.updateKey(0xE1, false);
206
+ encoder.updateKey(0x04, true); // 'a'
207
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x61);
208
+ });
209
+ it('should handle both left and right modifiers', () => {
210
+ // Left Ctrl
211
+ encoder.updateKey(0xE0, true);
212
+ encoder.updateKey(0x04, true); // Ctrl+a
213
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x01);
214
+ encoder.clearInterrupts(true, false, true, false);
215
+ encoder.updateKey(0xE0, false);
216
+ // Right Ctrl
217
+ encoder.updateKey(0xE4, true);
218
+ encoder.updateKey(0x04, true); // Ctrl+a
219
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x01);
220
+ });
221
+ });
222
+ describe('Shift Key Mapping', () => {
223
+ beforeEach(() => {
224
+ encoder.updateControlLines(false, false, false, false);
225
+ });
226
+ it('should map Shift+letter to uppercase', () => {
227
+ encoder.updateKey(0xE1, true); // Press Shift
228
+ encoder.updateKey(0x04, true); // 'a' -> 'A'
229
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x41);
230
+ });
231
+ it('should map Shift+number to symbols', () => {
232
+ encoder.updateKey(0xE1, true); // Press Shift
233
+ encoder.updateKey(0x1E, true); // '1' -> '!'
234
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x21);
235
+ encoder.clearInterrupts(true, false, true, false);
236
+ encoder.updateKey(0x25, true); // '8' -> '*'
237
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x2A);
238
+ });
239
+ it('should map Shift+special keys to shifted symbols', () => {
240
+ encoder.updateKey(0xE1, true); // Press Shift
241
+ encoder.updateKey(0x2D, true); // '-' -> '_'
242
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x5F);
243
+ encoder.clearInterrupts(true, false, true, false);
244
+ encoder.updateKey(0x2E, true); // '=' -> '+'
245
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x2B);
246
+ encoder.clearInterrupts(true, false, true, false);
247
+ encoder.updateKey(0x2F, true); // '[' -> '{'
248
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x7B);
249
+ });
250
+ });
251
+ describe('Ctrl Key Mapping', () => {
252
+ beforeEach(() => {
253
+ encoder.updateControlLines(false, false, false, false);
254
+ });
255
+ it('should map Ctrl+letter to control codes', () => {
256
+ encoder.updateKey(0xE0, true); // Press Ctrl
257
+ encoder.updateKey(0x04, true); // Ctrl+a -> 0x01
258
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x01);
259
+ encoder.clearInterrupts(true, false, true, false);
260
+ encoder.updateKey(0x1D, true); // Ctrl+z -> 0x1A
261
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x1A);
262
+ });
263
+ it('should map Ctrl+special keys to control codes', () => {
264
+ encoder.updateKey(0xE0, true); // Press Ctrl
265
+ encoder.updateKey(0x2F, true); // Ctrl+[ -> ESC (0x1B)
266
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x1B);
267
+ encoder.clearInterrupts(true, false, true, false);
268
+ encoder.updateKey(0x31, true); // Ctrl+\ -> FS (0x1C)
269
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x1C);
270
+ encoder.clearInterrupts(true, false, true, false);
271
+ encoder.updateKey(0x30, true); // Ctrl+] -> GS (0x1D)
272
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x1D);
273
+ });
274
+ it('should map Ctrl+2 to NUL', () => {
275
+ encoder.updateKey(0xE0, true); // Press Ctrl
276
+ encoder.updateKey(0x1F, true); // Ctrl+2 -> 0x00
277
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x00);
278
+ });
279
+ it('should map Ctrl+6 to RS (UP arrow)', () => {
280
+ encoder.updateKey(0xE0, true); // Press Ctrl
281
+ encoder.updateKey(0x23, true); // Ctrl+6 -> 0x1E
282
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x1E);
283
+ });
284
+ it('should map Ctrl+- to US (DOWN arrow)', () => {
285
+ encoder.updateKey(0xE0, true); // Press Ctrl
286
+ encoder.updateKey(0x2D, true); // Ctrl+- -> 0x1F
287
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x1F);
288
+ });
289
+ });
290
+ describe('MENU Key Mapping', () => {
291
+ beforeEach(() => {
292
+ encoder.updateControlLines(false, false, false, false);
293
+ });
294
+ it('should map MENU key to 0x80', () => {
295
+ encoder.updateKey(0xE3, true); // Left GUI (MENU)
296
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x80);
297
+ });
298
+ it('should map Alt+MENU to 0x90', () => {
299
+ encoder.updateKey(0xE2, true); // Press Alt
300
+ encoder.updateKey(0xE3, true); // MENU
301
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x90);
302
+ });
303
+ it('should handle Right GUI as MENU', () => {
304
+ encoder.updateKey(0xE7, true); // Right GUI (MENU)
305
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x80);
306
+ });
307
+ });
308
+ describe('Function Key Mapping', () => {
309
+ beforeEach(() => {
310
+ encoder.updateControlLines(false, false, false, false);
311
+ });
312
+ it('should map F1-F12 to 0x81-0x8C', () => {
313
+ encoder.updateKey(0x3A, true); // F1
314
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x81);
315
+ encoder.clearInterrupts(true, false, true, false);
316
+ encoder.updateKey(0x3B, true); // F2
317
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x82);
318
+ encoder.clearInterrupts(true, false, true, false);
319
+ encoder.updateKey(0x45, true); // F12
320
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x8C);
321
+ });
322
+ it('should map F13-F15 to 0x8D-0x8F', () => {
323
+ encoder.updateKey(0x68, true); // F13
324
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x8D);
325
+ encoder.clearInterrupts(true, false, true, false);
326
+ encoder.updateKey(0x6A, true); // F15
327
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x8F);
328
+ });
329
+ it('should map Alt+F1-F12 to 0x91-0x9C', () => {
330
+ encoder.updateKey(0xE2, true); // Press Alt
331
+ encoder.updateKey(0x3A, true); // Alt+F1
332
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x91);
333
+ encoder.clearInterrupts(true, false, true, false);
334
+ encoder.updateKey(0x45, true); // Alt+F12
335
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x9C);
336
+ });
337
+ it('should map Alt+F13-F15 to 0x9D-0x9F', () => {
338
+ encoder.updateKey(0xE2, true); // Press Alt
339
+ encoder.updateKey(0x68, true); // Alt+F13
340
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x9D);
341
+ encoder.clearInterrupts(true, false, true, false);
342
+ encoder.updateKey(0x6A, true); // Alt+F15
343
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x9F);
344
+ });
345
+ });
346
+ describe('Alt Key Mapping', () => {
347
+ beforeEach(() => {
348
+ encoder.updateControlLines(false, false, false, false);
349
+ });
350
+ it('should map Alt+letter to extended character set', () => {
351
+ encoder.updateKey(0xE2, true); // Press Alt
352
+ encoder.updateKey(0x04, true); // Alt+a -> 0xE1
353
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xE1);
354
+ encoder.clearInterrupts(true, false, true, false);
355
+ encoder.updateKey(0x1D, true); // Alt+z -> 0xFA
356
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFA);
357
+ });
358
+ it('should map Alt+number to extended character set', () => {
359
+ encoder.updateKey(0xE2, true); // Press Alt
360
+ encoder.updateKey(0x1E, true); // Alt+1 -> 0xB1
361
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xB1);
362
+ encoder.clearInterrupts(true, false, true, false);
363
+ encoder.updateKey(0x27, true); // Alt+0 -> 0xB0
364
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xB0);
365
+ });
366
+ it('should map Alt+Space to 0xA0', () => {
367
+ encoder.updateKey(0xE2, true); // Press Alt
368
+ encoder.updateKey(0x2C, true); // Alt+Space -> 0xA0
369
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA0);
370
+ });
371
+ it('should map Alt+DEL to 0xFF', () => {
372
+ encoder.updateKey(0xE2, true); // Press Alt
373
+ encoder.updateKey(0x4C, true); // Alt+DEL -> 0xFF
374
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFF);
375
+ });
376
+ });
377
+ describe('Alt+Shift Key Mapping', () => {
378
+ beforeEach(() => {
379
+ encoder.updateControlLines(false, false, false, false);
380
+ });
381
+ it('should map Alt+Shift+letter to extended character set', () => {
382
+ encoder.updateKey(0xE2, true); // Press Alt
383
+ encoder.updateKey(0xE1, true); // Press Shift
384
+ encoder.updateKey(0x04, true); // Alt+Shift+a -> 0xC1
385
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC1);
386
+ encoder.clearInterrupts(true, false, true, false);
387
+ encoder.updateKey(0x1D, true); // Alt+Shift+z -> 0xDA
388
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xDA);
389
+ });
390
+ it('should map Alt+Shift+number to extended character set', () => {
391
+ encoder.updateKey(0xE2, true); // Press Alt
392
+ encoder.updateKey(0xE1, true); // Press Shift
393
+ encoder.updateKey(0x1E, true); // Alt+Shift+1 -> 0xA1
394
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA1);
395
+ encoder.clearInterrupts(true, false, true, false);
396
+ encoder.updateKey(0x1F, true); // Alt+Shift+2 -> 0xC0
397
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC0);
398
+ });
399
+ it('should map Alt+Shift+symbols to extended character set', () => {
400
+ encoder.updateKey(0xE2, true); // Press Alt
401
+ encoder.updateKey(0xE1, true); // Press Shift
402
+ encoder.updateKey(0x2D, true); // Alt+Shift+- -> 0xDF
403
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xDF);
404
+ encoder.clearInterrupts(true, false, true, false);
405
+ encoder.updateKey(0x2F, true); // Alt+Shift+[ -> 0xFB
406
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFB);
407
+ });
408
+ });
409
+ describe('Complex Key Combinations', () => {
410
+ beforeEach(() => {
411
+ encoder.updateControlLines(false, false, false, false);
412
+ });
413
+ it('should handle Ctrl+C combination', () => {
414
+ encoder.updateKey(0xE0, true); // Press Ctrl
415
+ encoder.updateKey(0x06, true); // c
416
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x03); // ETX
417
+ });
418
+ it('should prioritize Ctrl over Shift', () => {
419
+ encoder.updateKey(0xE0, true); // Press Ctrl
420
+ encoder.updateKey(0xE1, true); // Press Shift
421
+ encoder.updateKey(0x04, true); // a
422
+ // When both Ctrl and Shift are pressed, shift is ignored for Ctrl combinations
423
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x01); // Ctrl+a
424
+ });
425
+ it('should prioritize Alt+Shift over Alt alone', () => {
426
+ encoder.updateKey(0xE2, true); // Press Alt
427
+ encoder.updateKey(0xE1, true); // Press Shift
428
+ encoder.updateKey(0x04, true); // a
429
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC1); // Alt+Shift+a, not Alt+a (0xE1)
430
+ });
431
+ it('should apply Alt when both Ctrl and Alt are active', () => {
432
+ encoder.updateKey(0xE0, true); // Press Ctrl
433
+ encoder.updateKey(0xE2, true); // Press Alt
434
+ encoder.updateKey(0x04, true); // a
435
+ // Alt takes effect when both Ctrl and Alt are pressed (per C++ implementation)
436
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xE1); // Alt+a
437
+ });
438
+ });
439
+ describe('Sequential Key Presses', () => {
440
+ beforeEach(() => {
441
+ encoder.updateControlLines(false, false, false, false);
442
+ });
443
+ it('should handle multiple sequential key presses', () => {
444
+ encoder.updateKey(0x04, true); // 'a'
445
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x61);
446
+ encoder.clearInterrupts(true, false, true, false);
447
+ encoder.updateKey(0x05, true); // 'b'
448
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x62);
449
+ encoder.clearInterrupts(true, false, true, false);
450
+ encoder.updateKey(0x06, true); // 'c'
451
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x63);
452
+ });
453
+ it('should overwrite previous data with new key press', () => {
454
+ encoder.updateKey(0x04, true); // 'a'
455
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x61);
456
+ // New key press without clearing interrupts
457
+ encoder.updateKey(0x05, true); // 'b'
458
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x62); // Overwritten
459
+ });
460
+ });
461
+ describe('Edge Cases', () => {
462
+ beforeEach(() => {
463
+ encoder.updateControlLines(false, false, false, false);
464
+ });
465
+ it('should handle rapid modifier changes', () => {
466
+ encoder.updateKey(0xE1, true); // Press Shift
467
+ encoder.updateKey(0xE1, false); // Release Shift
468
+ encoder.updateKey(0xE1, true); // Press Shift again
469
+ encoder.updateKey(0x04, true); // 'a' -> 'A'
470
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x41);
471
+ });
472
+ it('should handle all modifiers released', () => {
473
+ encoder.updateKey(0xE0, true); // Press Ctrl
474
+ encoder.updateKey(0xE1, true); // Press Shift
475
+ encoder.updateKey(0xE2, true); // Press Alt
476
+ encoder.updateKey(0xE0, false); // Release Ctrl
477
+ encoder.updateKey(0xE1, false); // Release Shift
478
+ encoder.updateKey(0xE2, false); // Release Alt
479
+ encoder.updateKey(0x04, true); // 'a'
480
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x61); // Plain 'a'
481
+ });
482
+ it('should handle port disabled mid-operation', () => {
483
+ encoder.updateKey(0x04, true); // 'a'
484
+ expect(encoder.hasCA1Interrupt()).toBe(true);
485
+ // Disable port
486
+ encoder.updateControlLines(false, true, false, true);
487
+ expect(encoder.hasCA1Interrupt()).toBe(false); // Interrupt not visible when disabled
488
+ });
489
+ it('should handle re-enabling port with data still present', () => {
490
+ encoder.updateKey(0x04, true); // 'a'
491
+ encoder.updateControlLines(false, true, false, true); // Disable
492
+ // Re-enable
493
+ encoder.updateControlLines(false, false, false, false);
494
+ // Data should still be there
495
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x61);
496
+ });
497
+ });
498
+ describe('Alt+Shift Symbol Mapping (Extended Character Set)', () => {
499
+ beforeEach(() => {
500
+ encoder.updateControlLines(false, false, false, false);
501
+ encoder.updateKey(0xE2, true); // Press Alt
502
+ encoder.updateKey(0xE1, true); // Press Shift
503
+ });
504
+ afterEach(() => {
505
+ encoder.clearInterrupts(true, false, true, false);
506
+ encoder.updateKey(0xE2, false); // Release Alt
507
+ encoder.updateKey(0xE1, false); // Release Shift
508
+ });
509
+ it('should map Alt+Shift+1 to ¡ (0xA1)', () => {
510
+ encoder.updateKey(0x1E, true); // '1'
511
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA1);
512
+ });
513
+ it('should map Alt+Shift+\' to ¢ (0xA2)', () => {
514
+ encoder.updateKey(0x34, true); // '\'' (apostrophe, USB HID 0x34)
515
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA2);
516
+ });
517
+ it('should map Alt+Shift+3 to £ (0xA3)', () => {
518
+ encoder.updateKey(0x20, true); // '3'
519
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA3);
520
+ });
521
+ it('should map Alt+Shift+4 to ¤ (0xA4)', () => {
522
+ encoder.updateKey(0x21, true); // '4'
523
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA4);
524
+ });
525
+ it('should map Alt+Shift+5 to ¥ (0xA5)', () => {
526
+ encoder.updateKey(0x22, true); // '5'
527
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA5);
528
+ });
529
+ it('should map Alt+Shift+7 to ¦ (0xA6)', () => {
530
+ encoder.updateKey(0x24, true); // '7'
531
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA6);
532
+ });
533
+ it('should map Alt+Shift+9 to ¨ (0xA8)', () => {
534
+ encoder.updateKey(0x26, true); // '9'
535
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA8);
536
+ });
537
+ it('should map Alt+Shift+0 to © (0xA9)', () => {
538
+ encoder.updateKey(0x27, true); // '0'
539
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA9);
540
+ });
541
+ it('should map Alt+Shift+8 to ª (0xAA)', () => {
542
+ encoder.updateKey(0x25, true); // '8'
543
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xAA);
544
+ });
545
+ it('should map Alt+Shift+= to « (0xAB)', () => {
546
+ encoder.updateKey(0x2E, true); // '='
547
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xAB);
548
+ });
549
+ it('should map Alt+Shift+; to º (0xBA)', () => {
550
+ encoder.updateKey(0x33, true); // ';'
551
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xBA);
552
+ });
553
+ it('should map Alt+Shift+, to ¼ (0xBC)', () => {
554
+ encoder.updateKey(0x36, true); // ','
555
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xBC);
556
+ });
557
+ it('should map Alt+Shift+. to ¾ (0xBE)', () => {
558
+ encoder.updateKey(0x37, true); // '.'
559
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xBE);
560
+ });
561
+ it('should map Alt+Shift+/ to ¿ (0xBF)', () => {
562
+ encoder.updateKey(0x38, true); // '/'
563
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xBF);
564
+ });
565
+ it('should map Alt+Shift+2 to À (0xC0)', () => {
566
+ encoder.updateKey(0x1F, true); // '2'
567
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC0);
568
+ });
569
+ it('should map Alt+Shift+b to  (0xC2)', () => {
570
+ encoder.updateKey(0x05, true); // 'b'
571
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC2);
572
+ });
573
+ it('should map Alt+Shift+c to à (0xC3)', () => {
574
+ encoder.updateKey(0x06, true); // 'c'
575
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC3);
576
+ });
577
+ it('should map Alt+Shift+d to Ä (0xC4)', () => {
578
+ encoder.updateKey(0x07, true); // 'd'
579
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC4);
580
+ });
581
+ it('should map Alt+Shift+e to Å (0xC5)', () => {
582
+ encoder.updateKey(0x08, true); // 'e'
583
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC5);
584
+ });
585
+ it('should map Alt+Shift+f to Æ (0xC6)', () => {
586
+ encoder.updateKey(0x09, true); // 'f'
587
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC6);
588
+ });
589
+ it('should map Alt+Shift+g to Ç (0xC7)', () => {
590
+ encoder.updateKey(0x0A, true); // 'g'
591
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC7);
592
+ });
593
+ it('should map Alt+Shift+h to È (0xC8)', () => {
594
+ encoder.updateKey(0x0B, true); // 'h'
595
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xC8);
596
+ });
597
+ it('should map Alt+Shift+6 to Þ (0xDE)', () => {
598
+ encoder.updateKey(0x23, true); // '6'
599
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xDE);
600
+ });
601
+ it('should map Alt+Shift+- to ß (0xDF)', () => {
602
+ encoder.updateKey(0x2D, true); // '-'
603
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xDF);
604
+ });
605
+ it('should map Alt+Shift+[ to û (0xFB)', () => {
606
+ encoder.updateKey(0x2F, true); // '['
607
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFB);
608
+ });
609
+ it('should map Alt+Shift+\\ to ü (0xFC)', () => {
610
+ encoder.updateKey(0x31, true); // '\\'
611
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFC);
612
+ });
613
+ it('should map Alt+Shift+] to ý (0xFD)', () => {
614
+ encoder.updateKey(0x30, true); // ']'
615
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFD);
616
+ });
617
+ it('should map Alt+Shift+` to þ (0xFE)', () => {
618
+ encoder.updateKey(0x35, true); // '`'
619
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xFE);
620
+ });
621
+ });
622
+ describe('Alt Symbol Mapping (Without Shift)', () => {
623
+ beforeEach(() => {
624
+ encoder.updateControlLines(false, false, false, false);
625
+ encoder.updateKey(0xE2, true); // Press Alt
626
+ });
627
+ afterEach(() => {
628
+ encoder.clearInterrupts(true, false, true, false);
629
+ encoder.updateKey(0xE2, false); // Release Alt
630
+ });
631
+ it('should map Alt+\' to § (0xA7)', () => {
632
+ encoder.updateKey(0x34, true); // '\''
633
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xA7);
634
+ });
635
+ it('should map Alt+, to ¬ (0xAC)', () => {
636
+ encoder.updateKey(0x36, true); // ','
637
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xAC);
638
+ });
639
+ it('should map Alt+- to soft hyphen (0xAD)', () => {
640
+ encoder.updateKey(0x2D, true); // '-'
641
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xAD);
642
+ });
643
+ it('should map Alt+. to ® (0xAE)', () => {
644
+ encoder.updateKey(0x37, true); // '.'
645
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xAE);
646
+ });
647
+ it('should map Alt+/ to ¯ (0xAF)', () => {
648
+ encoder.updateKey(0x38, true); // '/'
649
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xAF);
650
+ });
651
+ it('should map Alt+; to » (0xBB)', () => {
652
+ encoder.updateKey(0x33, true); // ';'
653
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xBB);
654
+ });
655
+ it('should map Alt+= to ½ (0xBD)', () => {
656
+ encoder.updateKey(0x2E, true); // '='
657
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xBD);
658
+ });
659
+ it('should map Alt+[ to Û (0xDB)', () => {
660
+ encoder.updateKey(0x2F, true); // '['
661
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xDB);
662
+ });
663
+ it('should map Alt+\\ to Ü (0xDC)', () => {
664
+ encoder.updateKey(0x31, true); // '\\'
665
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xDC);
666
+ });
667
+ it('should map Alt+] to Ý (0xDD)', () => {
668
+ encoder.updateKey(0x30, true); // ']'
669
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xDD);
670
+ });
671
+ it('should map Alt+` to à (0xE0)', () => {
672
+ encoder.updateKey(0x35, true); // '`'
673
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0xE0);
674
+ });
675
+ });
676
+ describe('Ctrl Combinations Coverage', () => {
677
+ beforeEach(() => {
678
+ encoder.updateControlLines(false, false, false, false);
679
+ encoder.updateKey(0xE0, true); // Press Ctrl
680
+ });
681
+ afterEach(() => {
682
+ encoder.clearInterrupts(true, false, true, false);
683
+ encoder.updateKey(0xE0, false); // Release Ctrl
684
+ });
685
+ it('should map Ctrl+b to 0x02', () => {
686
+ encoder.updateKey(0x05, true); // 'b'
687
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x02);
688
+ });
689
+ it('should map Ctrl+d to 0x04', () => {
690
+ encoder.updateKey(0x07, true); // 'd'
691
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x04);
692
+ });
693
+ it('should map Ctrl+e to 0x05', () => {
694
+ encoder.updateKey(0x08, true); // 'e'
695
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x05);
696
+ });
697
+ it('should map Ctrl+f to 0x06', () => {
698
+ encoder.updateKey(0x09, true); // 'f'
699
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x06);
700
+ });
701
+ it('should map Ctrl+g to 0x07', () => {
702
+ encoder.updateKey(0x0A, true); // 'g'
703
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x07);
704
+ });
705
+ it('should map Ctrl+h to 0x08', () => {
706
+ encoder.updateKey(0x0B, true); // 'h'
707
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x08);
708
+ });
709
+ it('should map Ctrl+i to 0x09', () => {
710
+ encoder.updateKey(0x0C, true); // 'i'
711
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x09);
712
+ });
713
+ it('should map Ctrl+j to 0x0A', () => {
714
+ encoder.updateKey(0x0D, true); // 'j'
715
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x0A);
716
+ });
717
+ it('should map Ctrl+k to 0x0B', () => {
718
+ encoder.updateKey(0x0E, true); // 'k'
719
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x0B);
720
+ });
721
+ it('should map Ctrl+l to 0x0C', () => {
722
+ encoder.updateKey(0x0F, true); // 'l'
723
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x0C);
724
+ });
725
+ it('should map Ctrl+m to 0x0D', () => {
726
+ encoder.updateKey(0x10, true); // 'm'
727
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x0D);
728
+ });
729
+ it('should map Ctrl+n to 0x0E', () => {
730
+ encoder.updateKey(0x11, true); // 'n'
731
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x0E);
732
+ });
733
+ it('should map Ctrl+o to 0x0F', () => {
734
+ encoder.updateKey(0x12, true); // 'o'
735
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x0F);
736
+ });
737
+ it('should map Ctrl+p to 0x10', () => {
738
+ encoder.updateKey(0x13, true); // 'p'
739
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x10);
740
+ });
741
+ it('should map Ctrl+q to 0x11', () => {
742
+ encoder.updateKey(0x14, true); // 'q'
743
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x11);
744
+ });
745
+ it('should map Ctrl+r to 0x12', () => {
746
+ encoder.updateKey(0x15, true); // 'r'
747
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x12);
748
+ });
749
+ it('should map Ctrl+s to 0x13', () => {
750
+ encoder.updateKey(0x16, true); // 's'
751
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x13);
752
+ });
753
+ it('should map Ctrl+t to 0x14', () => {
754
+ encoder.updateKey(0x17, true); // 't'
755
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x14);
756
+ });
757
+ it('should map Ctrl+u to 0x15', () => {
758
+ encoder.updateKey(0x18, true); // 'u'
759
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x15);
760
+ });
761
+ it('should map Ctrl+v to 0x16', () => {
762
+ encoder.updateKey(0x19, true); // 'v'
763
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x16);
764
+ });
765
+ it('should map Ctrl+w to 0x17', () => {
766
+ encoder.updateKey(0x1A, true); // 'w'
767
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x17);
768
+ });
769
+ it('should map Ctrl+x to 0x18', () => {
770
+ encoder.updateKey(0x1B, true); // 'x'
771
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x18);
772
+ });
773
+ it('should map Ctrl+y to 0x19', () => {
774
+ encoder.updateKey(0x1C, true); // 'y'
775
+ expect(encoder.readPortA(0xFF, 0x00)).toBe(0x19);
776
+ });
777
+ });
778
+ });
779
+ //# sourceMappingURL=GPIOKeyboardEncoderAttachment.test.js.map