2 * SAM Coupé 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 "sam_keyboard.h"
32 //#define DEBUG_SAM_KEYBOARD
34 #ifdef DEBUG_SAM_KEYBOARD
35 #define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
37 #define DPRINTF(fmt, ...)
40 static int keystate
[9];
42 uint32_t sam_keyboard_read(void *opaque
, uint32_t addr
)
45 uint8_t colbits
= 0xff;
46 uint32_t rowbits
= ((addr
>> 8) & 0xff);
48 if (rowbits
== 0xff) {
49 colbits
&= keystate
[8];
51 for (r
= 0; r
< 8; r
++) {
52 if (!(rowbits
& (1 << r
))) {
53 colbits
&= keystate
[r
];
65 #define DEF_SAM_KEY(name, row, column) SAM_KEY_ ## name,
67 #include "sam_key_template.h"
71 #define DEF_SAM_KEY(name, row, column) [SAM_KEY_ ## name] = {row, column},
72 static const SAMKeypos keypos
[SAM_MAX_KEYS
] = {
73 #include "sam_key_template.h"
76 static int sam_keypressed
[SAM_MAX_KEYS
];
77 static int qemu_keypressed
[0x100];
79 static const int map
[0x100][2] = {
80 [0 ... 0xff] = {-1, -1}, /* Unmapped by default */
82 [0x01] = {SAM_KEY_ESCAPE
, -1},
84 [0x02] = {SAM_KEY_1
, -1},
85 [0x03] = {SAM_KEY_2
, -1},
86 [0x04] = {SAM_KEY_3
, -1},
87 [0x05] = {SAM_KEY_4
, -1},
88 [0x06] = {SAM_KEY_5
, -1},
89 [0x07] = {SAM_KEY_6
, -1},
90 [0x08] = {SAM_KEY_7
, -1},
91 [0x09] = {SAM_KEY_8
, -1},
92 [0x0a] = {SAM_KEY_9
, -1},
93 [0x0b] = {SAM_KEY_0
, -1},
95 [0x0c] = {SAM_KEY_MINUS
, -1},
97 [0x0e] = {SAM_KEY_DELETE
, -1}, /* Backspace */
99 [0x10] = {SAM_KEY_Q
, -1},
100 [0x11] = {SAM_KEY_W
, -1},
101 [0x12] = {SAM_KEY_E
, -1},
102 [0x13] = {SAM_KEY_R
, -1},
103 [0x14] = {SAM_KEY_T
, -1},
104 [0x15] = {SAM_KEY_Y
, -1},
105 [0x16] = {SAM_KEY_U
, -1},
106 [0x17] = {SAM_KEY_I
, -1},
107 [0x18] = {SAM_KEY_O
, -1},
108 [0x19] = {SAM_KEY_P
, -1},
110 [0x0d] = {SAM_KEY_PLUS
, -1},
111 [0x0f] = {SAM_KEY_TAB
, -1},
113 [0x1a] = {SAM_KEY_EQUALS
, -1},
114 [0x1b] = {SAM_KEY_DQUOTE
, -1},
116 [0x1c] = {SAM_KEY_ENTER
, -1},
118 [0x1d] = {SAM_KEY_CONTROL
, -1}, /* Left Control */
120 [0x1e] = {SAM_KEY_A
, -1},
121 [0x1f] = {SAM_KEY_S
, -1},
122 [0x20] = {SAM_KEY_D
, -1},
123 [0x21] = {SAM_KEY_F
, -1},
124 [0x22] = {SAM_KEY_G
, -1},
125 [0x23] = {SAM_KEY_H
, -1},
126 [0x24] = {SAM_KEY_J
, -1},
127 [0x25] = {SAM_KEY_K
, -1},
128 [0x26] = {SAM_KEY_L
, -1},
130 [0x27] = {SAM_KEY_SEMICOLON
, -1}, /* Semicolon */
131 [0x28] = {SAM_KEY_SYMBSHIFT
, SAM_KEY_7
}, /* Apostrophe */
133 [0x2a] = {SAM_KEY_CAPSSHIFT
, -1}, /* Left Shift */
135 [0x2b] = {SAM_KEY_SYMBSHIFT
, SAM_KEY_3
}, /* Hash */
137 [0x2c] = {SAM_KEY_Z
, -1},
138 [0x2d] = {SAM_KEY_X
, -1},
139 [0x2e] = {SAM_KEY_C
, -1},
140 [0x2f] = {SAM_KEY_V
, -1},
141 [0x30] = {SAM_KEY_B
, -1},
142 [0x31] = {SAM_KEY_N
, -1},
143 [0x32] = {SAM_KEY_M
, -1},
145 [0x33] = {SAM_KEY_COMMA
, -1},
146 [0x34] = {SAM_KEY_PERIOD
, -1},
147 [0x35] = {SAM_KEY_SYMBSHIFT
, -1}, /* Slash */
149 [0x36] = {SAM_KEY_CAPSSHIFT
, -1}, /* Right Shift */
150 [0x37] = {SAM_KEY_SYMBSHIFT
, SAM_KEY_B
}, /* * (Numpad) */
151 [0x38] = {SAM_KEY_SYMBSHIFT
, -1}, /* Left Alt */
152 [0x39] = {SAM_KEY_SPACE
, -1}, /* Space Bar */
154 [0x47] = {SAM_KEY_F7
, -1}, /* 7 (Numpad) */
155 [0x48] = {SAM_KEY_F8
, -1}, /* 8 (Numpad) */
156 [0x49] = {SAM_KEY_F9
, -1}, /* 9 (Numpad) */
157 [0x4a] = {SAM_KEY_MINUS
, -1}, /* Minus (Numpad) */
158 [0x4b] = {SAM_KEY_F4
, -1}, /* 4 (Numpad) */
159 [0x4c] = {SAM_KEY_F5
, -1}, /* 5 (Numpad) */
160 [0x4d] = {SAM_KEY_F6
, -1}, /* 6 (Numpad) */
161 [0x4e] = {SAM_KEY_PLUS
, -1}, /* Plus (Numpad) */
162 [0x4f] = {SAM_KEY_F1
, -1}, /* 1 (Numpad) */
163 [0x50] = {SAM_KEY_F2
, -1}, /* 2 (Numpad) */
164 [0x51] = {SAM_KEY_F3
, -1}, /* 3 (Numpad) */
165 [0x52] = {SAM_KEY_F0
, -1}, /* 0 (Numpad) */
166 [0x53] = {SAM_KEY_PERIOD
, -1}, /* Period (Numpad) */
168 [0x9c] = {SAM_KEY_ENTER
, -1}, /* Enter (Numpad) */
169 [0x9d] = {SAM_KEY_CONTROL
, -1}, /* Right Control */
170 [0xb5] = {SAM_KEY_SYMBSHIFT
, SAM_KEY_V
}, /* Slash (Numpad) */
171 [0xb8] = {SAM_KEY_EDIT
, -1}, /* Right Alt */
173 [0xc8] = {SAM_KEY_UP
, SAM_KEY_7
}, /* Up Arrow */
174 [0xcb] = {SAM_KEY_LEFT
, SAM_KEY_5
}, /* Left Arrow */
175 [0xcd] = {SAM_KEY_RIGHT
, SAM_KEY_8
}, /* Right Arrow */
176 [0xd0] = {SAM_KEY_DOWN
, SAM_KEY_6
}, /* Down Arrow */
178 [0xdb] = {SAM_KEY_CONTROL
, SAM_KEY_SYMBSHIFT
}, /* Left Meta */
179 [0xdc] = {SAM_KEY_EDIT
, SAM_KEY_SYMBSHIFT
}, /* Menu */
180 [0xdd] = {SAM_KEY_CONTROL
, SAM_KEY_SYMBSHIFT
}, /* Right Meta */
184 * Need to mappings from stepping on each other...
185 * or at least make them step on one another in a consistent manner?
186 * Could use separate state arrays for surpressing/adding keys
187 * and allow only one change to the modifier keys at a time...
189 * Also need to implement shifted mappings.
192 static void sam_put_keycode(void *opaque
, int keycode
)
194 int release
= keycode
& 0x80;
196 static int ext_keycode
= 0;
200 if (keycode
== 0xe0) {
210 DPRINTF("Keycode 0x%02x (%s)\n", keycode
,
211 release
? "release" : "press");
213 if (release
&& qemu_keypressed
[keycode
]) {
215 qemu_keypressed
[keycode
] = 0;
216 } else if (!release
&& !qemu_keypressed
[keycode
]) {
218 qemu_keypressed
[keycode
] = 1;
224 for (i
= 0; i
< 2; i
++) {
225 key
= map
[keycode
][i
];
227 row
= keypos
[key
].row
;
228 col
= keypos
[key
].column
;
230 if (--sam_keypressed
[key
] <= 0) {
231 DPRINTF("Releasing 0x%02x\n", key
);
232 sam_keypressed
[key
] = 0;
233 keystate
[row
] |= 1 << col
;
236 DPRINTF("Pressing 0x%02x\n", key
);
237 sam_keypressed
[key
]++;
238 keystate
[row
] &= ~(1 << col
);
246 void sam_keyboard_init(void)
249 for (i
=0; i
<9; i
++) {
252 memset(sam_keypressed
, 0, sizeof(sam_keypressed
));
253 memset(qemu_keypressed
, 0, sizeof(qemu_keypressed
));
254 qemu_add_kbd_event_handler(sam_put_keycode
, NULL
);