2 * ZX Spectrum Keyboard Emulation
4 * Copyright (c) 2007-2009 Stuart Brady <stuart.brady@gmail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 #include "qemu-timer.h"
29 #include "zx_keyboard.h"
32 //#define DEBUG_ZX_KEYBOARD
34 #ifdef DEBUG_ZX_KEYBOARD
35 #define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
37 #define DPRINTF(fmt, ...)
40 static int keystate
[8];
42 uint32_t zx_keyboard_read(void *opaque
, uint32_t addr
)
45 uint8_t colbits
= 0xff;
47 uint32_t rowbits
= ((addr
>> 8) & 0xff);
49 for (r
= 0; r
< 8; r
++) {
50 if (!(rowbits
& (1 << r
))) {
51 colbits
&= keystate
[r
];
62 #define DEF_ZX_KEY(name, row, column) ZX_KEY_ ## name,
64 #include "zx_key_template.h"
68 #define DEF_ZX_KEY(name, row, column) [ZX_KEY_ ## name] = {row, column},
69 static const ZXKeypos keypos
[ZX_MAX_KEYS
] = {
70 #include "zx_key_template.h"
73 static int zx_keypressed
[ZX_MAX_KEYS
];
74 static int qemu_keypressed
[0x100];
76 static const int map
[0x100][2] = {
77 [0 ... 0xff] = {-1, -1}, /* Unmapped by default */
79 [0x01] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_SPACE
}, /* Escape */
81 [0x02] = {ZX_KEY_1
, -1},
82 [0x03] = {ZX_KEY_2
, -1},
83 [0x04] = {ZX_KEY_3
, -1},
84 [0x05] = {ZX_KEY_4
, -1},
85 [0x06] = {ZX_KEY_5
, -1},
86 [0x07] = {ZX_KEY_6
, -1},
87 [0x08] = {ZX_KEY_7
, -1},
88 [0x09] = {ZX_KEY_8
, -1},
89 [0x0a] = {ZX_KEY_9
, -1},
90 [0x0b] = {ZX_KEY_0
, -1},
92 [0x0c] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_J
}, /* Minus */
94 [0x0e] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_0
}, /* Backspace */
96 [0x10] = {ZX_KEY_Q
, -1},
97 [0x11] = {ZX_KEY_W
, -1},
98 [0x12] = {ZX_KEY_E
, -1},
99 [0x13] = {ZX_KEY_R
, -1},
100 [0x14] = {ZX_KEY_T
, -1},
101 [0x15] = {ZX_KEY_Y
, -1},
102 [0x16] = {ZX_KEY_U
, -1},
103 [0x17] = {ZX_KEY_I
, -1},
104 [0x18] = {ZX_KEY_O
, -1},
105 [0x19] = {ZX_KEY_P
, -1},
107 [0x0d] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_L
}, /* Equals */
108 [0x0f] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_1
}, /* Tab */
110 [0x1c] = {ZX_KEY_ENTER
, -1},
112 [0x1d] = {ZX_KEY_SYMBSHIFT
, -1}, /* Left Control */
114 [0x1e] = {ZX_KEY_A
, -1},
115 [0x1f] = {ZX_KEY_S
, -1},
116 [0x20] = {ZX_KEY_D
, -1},
117 [0x21] = {ZX_KEY_F
, -1},
118 [0x22] = {ZX_KEY_G
, -1},
119 [0x23] = {ZX_KEY_H
, -1},
120 [0x24] = {ZX_KEY_J
, -1},
121 [0x25] = {ZX_KEY_K
, -1},
122 [0x26] = {ZX_KEY_L
, -1},
124 [0x27] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_O
}, /* Semicolon */
125 [0x28] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_7
}, /* Apostrophe */
127 [0x2a] = {ZX_KEY_CAPSSHIFT
, -1}, /* Left Shift */
129 [0x2b] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_3
}, /* Hash */
131 [0x2c] = {ZX_KEY_Z
, -1},
132 [0x2d] = {ZX_KEY_X
, -1},
133 [0x2e] = {ZX_KEY_C
, -1},
134 [0x2f] = {ZX_KEY_V
, -1},
135 [0x30] = {ZX_KEY_B
, -1},
136 [0x31] = {ZX_KEY_N
, -1},
137 [0x32] = {ZX_KEY_M
, -1},
139 [0x33] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_N
}, /* Comma */
140 [0x34] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_M
}, /* Period */
141 [0x35] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_V
}, /* Slash */
143 [0x36] = {ZX_KEY_CAPSSHIFT
, -1}, /* Right Shift */
144 [0x37] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_B
}, /* * (Numpad) */
145 [0x38] = {ZX_KEY_SYMBSHIFT
, -1}, /* Left Alt */
146 [0x39] = {ZX_KEY_SPACE
, -1}, /* Space Bar */
148 [0x47] = {ZX_KEY_7
, -1}, /* 7 (Numpad) */
149 [0x48] = {ZX_KEY_8
, -1}, /* 8 (Numpad) */
150 [0x49] = {ZX_KEY_9
, -1}, /* 9 (Numpad) */
151 [0x4a] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_J
}, /* Minus (Numpad) */
152 [0x4b] = {ZX_KEY_4
, -1}, /* 4 (Numpad) */
153 [0x4c] = {ZX_KEY_5
, -1}, /* 5 (Numpad) */
154 [0x4d] = {ZX_KEY_6
, -1}, /* 6 (Numpad) */
155 [0x4e] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_K
}, /* Plus (Numpad) */
156 [0x4f] = {ZX_KEY_1
, -1}, /* 1 (Numpad) */
157 [0x50] = {ZX_KEY_2
, -1}, /* 2 (Numpad) */
158 [0x51] = {ZX_KEY_3
, -1}, /* 3 (Numpad) */
159 [0x52] = {ZX_KEY_0
, -1}, /* 0 (Numpad) */
160 [0x53] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_M
}, /* Period (Numpad) */
162 [0x9c] = {ZX_KEY_SYMBSHIFT
, -1}, /* Enter (Numpad) */
163 [0x9d] = {ZX_KEY_SYMBSHIFT
, -1}, /* Right Control */
164 [0xb5] = {ZX_KEY_SYMBSHIFT
, ZX_KEY_V
}, /* Slash (Numpad) */
165 [0xb8] = {ZX_KEY_SYMBSHIFT
, -1}, /* Right Alt */
167 [0xc8] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_7
}, /* Up Arrow */
168 [0xcb] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_5
}, /* Left Arrow */
169 [0xcd] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_8
}, /* Right Arrow */
170 [0xd0] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_6
}, /* Down Arrow */
172 [0xdb] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_SYMBSHIFT
}, /* Left Meta */
173 [0xdc] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_SYMBSHIFT
}, /* Menu */
174 [0xdd] = {ZX_KEY_CAPSSHIFT
, ZX_KEY_SYMBSHIFT
}, /* Right Meta */
178 * Need to mappings from stepping on each other...
179 * or at least make them step on one another in a consistent manner?
180 * Could use separate state arrays for surpressing/adding keys
181 * and allow only one change to the modifier keys at a time...
183 * Also need to implement shifted mappings.
186 static void zx_put_keycode(void *opaque
, int keycode
)
188 int release
= keycode
& 0x80;
190 static int ext_keycode
= 0;
194 if (keycode
== 0xe0) {
204 DPRINTF("Keycode 0x%02x (%s)\n", keycode
, release
? "release" : "press");
206 if (release
&& qemu_keypressed
[keycode
]) {
208 qemu_keypressed
[keycode
] = 0;
209 } else if (!release
&& !qemu_keypressed
[keycode
]) {
211 qemu_keypressed
[keycode
] = 1;
217 for (i
= 0; i
< 2; i
++) {
218 key
= map
[keycode
][i
];
220 row
= keypos
[key
].row
;
221 col
= keypos
[key
].column
;
223 if (--zx_keypressed
[key
] <= 0) {
224 DPRINTF("Releasing 0x%02x\n", key
);
225 zx_keypressed
[key
] = 0;
226 keystate
[row
] |= 1 << col
;
229 DPRINTF("Pressing 0x%02x\n", key
);
230 zx_keypressed
[key
]++;
231 keystate
[row
] &= ~(1 << col
);
239 void zx_keyboard_init(void)
242 for (i
=0; i
<8; i
++) {
245 memset(zx_keypressed
, 0, sizeof(zx_keypressed
));
246 memset(qemu_keypressed
, 0, sizeof(qemu_keypressed
));
247 qemu_add_kbd_event_handler(zx_put_keycode
, NULL
);