Wed, 16 Apr 2014 02:07:24 -0600
added keyboard mappings for ENTER, CANCL, and EXIT
1 #include <stdbool.h>
2 #include "SDL.h"
3 #include "utils.h"
4 #include "keyboard.h"
6 // Enable/disable KBC debugging
7 #define kbc_debug false
9 /**
10 * Key map -- a mapping from SDLK_xxx constants to scancodes and vice versa.
11 */
12 struct {
13 SDLKey key; ///< SDLK_xxx key code constant
14 int extended; ///< 1 if this is an extended keycode
15 unsigned char scancode; ///< Keyboard scan code
16 } keymap[] = {
17 { SDLK_UP, 0, 0x01 }, // ROLL/Up [UpArrow]
18 { SDLK_KP2, 0, 0x01 }, // ROLL/Up [Keypad 2]
19 // { SDLK_, 1, 0x02 }, // Clear Line
20 // { SDLK_, 1, 0x03 }, // Rstrt / Ref
21 { SDLK_ESCAPE, 1, 0x04 }, // Exit
22 { SDLK_KP1, 0, 0x05 }, // PREV [Keypad 1]
23 // { SDLK_, 1, 0x06 }, // Msg
24 { SDLK_BACKSPACE, 1, 0x07 }, // Cancl
25 { SDLK_BACKSPACE, 0, 0x08 }, // Backspace
26 { SDLK_TAB, 0, 0x09 }, // Tab
27 { SDLK_RETURN, 1, 0x0a }, // ENTER
28 { SDLK_DOWN, 0, 0x0b }, // ROLL/Down [DownArrow]
29 { SDLK_KP0, 0, 0x0b }, // ROLL/Down [Keypad 0]
30 { SDLK_KP3, 0, 0x0c }, // NEXT [Keypad 3]
31 { SDLK_RETURN, 0, 0x0d }, // RETURN [Return]
32 { SDLK_LEFT, 0, 0x0e }, // <-- [LeftArrow]
33 { SDLK_KP_MINUS, 0, 0x0e }, // <-- [Keypad -]
34 { SDLK_RIGHT, 0, 0x0f }, // --> [RightArrow]
35 { SDLK_KP_PERIOD, 0, 0x0f }, // --> [Keypad .]
36 // { SDLK_, 1, 0x10 }, // Creat
37 // { SDLK_, 1, 0x11 }, // Save
38 // { SDLK_, 1, 0x12 }, // Move
39 // { SDLK_, 1, 0x13 }, // Ops
40 // { SDLK_, 1, 0x14 }, // Copy
41 { SDLK_F1, 0, 0x15 }, // F1
42 { SDLK_F2, 0, 0x16 }, // F2
43 { SDLK_F3, 0, 0x17 }, // F3
44 { SDLK_F4, 0, 0x18 }, // F4
45 { SDLK_F5, 0, 0x19 }, // F5
46 { SDLK_F6, 0, 0x1a }, // F6
47 { SDLK_ESCAPE, 0, 0x1b }, // ESC/DEL [Escape]
48 { SDLK_F7, 0, 0x1c }, // F7
49 { SDLK_F8, 0, 0x1d }, // F8
50 // { SDLK_, 1, 0x1e }, // Suspd
51 // { SDLK_, 1, 0x1f }, // Rsume
52 { SDLK_SPACE, 0, 0x20 }, // SPACE [Spacebar]
53 // { SDLK_, 1, 0x21 }, // Undo
54 // { SDLK_, 1, 0x22 }, // Redo
55 // { SDLK_, 1, 0x23 }, // FIND
56 // { SDLK_, 1, 0x24 }, // RPLAC
57 { SDLK_BREAK, 0, 0x25 }, // RESET/BREAK [Pause/Break]
58 // { SDLK_, 1, 0x26 }, // DleteChar
59 { SDLK_QUOTE, 0, 0x27 }, // ' (single-quote)
60 // { SDLK_, 1, 0x28 }, // SLCT/MARK
61 // { SDLK_, 1, 0x29 }, // INPUT/MODE
62 // { SDLK_, 1, 0x2a }, // HELP
63 // Keycode 2B not used
64 { SDLK_COMMA, 0, 0x2c }, // , [Comma]
65 { SDLK_MINUS, 0, 0x2d }, // - [Dash]
66 { SDLK_PERIOD, 0, 0x2e }, // . [Period]
67 { SDLK_SLASH, 0, 0x2f }, // / [Forward-slash]
68 { SDLK_0, 0, 0x30 }, // 0
69 { SDLK_1, 0, 0x31 }, // 1
70 { SDLK_2, 0, 0x32 }, // 2
71 { SDLK_3, 0, 0x33 }, // 3
72 { SDLK_4, 0, 0x34 }, // 4
73 { SDLK_5, 0, 0x35 }, // 5
74 { SDLK_6, 0, 0x36 }, // 6
75 { SDLK_7, 0, 0x37 }, // 7
76 { SDLK_8, 0, 0x38 }, // 8
77 { SDLK_9, 0, 0x39 }, // 9
78 // Keycode 3A not used
79 { SDLK_SEMICOLON, 0, 0x3b }, // ; [Semicolon]
80 // Keycode 3C not used
81 { SDLK_EQUALS, 0, 0x3d }, // = [Equals]
82 // Keycodes 3E, 3F, 40 not used
83 // { SDLK_, 1, 0x41 }, // CMD
84 // { SDLK_, 1, 0x42 }, // CLOSE/OPEN
85 { SDLK_KP7, 0, 0x43 }, // PRINT
86 { SDLK_KP8, 0, 0x44 }, // CLEAR/RFRSH
87 { SDLK_CAPSLOCK, 0, 0x45 }, // Caps Lock
88 { SDLK_KP9, 0, 0x46 }, // PAGE
89 { SDLK_KP4, 0, 0x47 }, // BEG
90 { SDLK_LSHIFT, 0, 0x48 }, // Left Shift
91 { SDLK_RSHIFT, 0, 0x49 }, // Right Shift
92 { SDLK_HOME, 0, 0x4a }, // Home
93 { SDLK_KP5, 0, 0x4a }, // Home [Keypad 5]
94 { SDLK_END, 0, 0x4b }, // End
95 { SDLK_KP6, 0, 0x4b }, // End [Keypad 6]
96 { SDLK_LCTRL, 0, 0x4c }, // Left Ctrl? \___ not sure which is left and which is right...
97 { SDLK_RCTRL, 0, 0x4d }, // Right Ctrl? /
98 // Keycodes 4E thru 5A not used
99 { SDLK_LEFTBRACKET, 0, 0x5b }, // [
100 { SDLK_BACKSLASH, 0, 0x5c }, // \ (backslash)
101 { SDLK_RIGHTBRACKET, 0, 0x5d }, // ]
102 // Keycodes 5E, 5F not used
103 { SDLK_BACKQUOTE, 0, 0x60 }, // `
104 { SDLK_a, 0, 0x61 }, // A
105 { SDLK_b, 0, 0x62 }, // B
106 { SDLK_c, 0, 0x63 }, // C
107 { SDLK_d, 0, 0x64 }, // D
108 { SDLK_e, 0, 0x65 }, // E
109 { SDLK_f, 0, 0x66 }, // F
110 { SDLK_g, 0, 0x67 }, // G
111 { SDLK_h, 0, 0x68 }, // H
112 { SDLK_i, 0, 0x69 }, // I
113 { SDLK_j, 0, 0x6a }, // J
114 { SDLK_k, 0, 0x6b }, // K
115 { SDLK_l, 0, 0x6c }, // L
116 { SDLK_m, 0, 0x6d }, // M
117 { SDLK_n, 0, 0x6e }, // N
118 { SDLK_o, 0, 0x6f }, // O
119 { SDLK_p, 0, 0x70 }, // P
120 { SDLK_q, 0, 0x71 }, // Q
121 { SDLK_r, 0, 0x72 }, // R
122 { SDLK_s, 0, 0x73 }, // S
123 { SDLK_t, 0, 0x74 }, // T
124 { SDLK_u, 0, 0x75 }, // U
125 { SDLK_v, 0, 0x76 }, // V
126 { SDLK_w, 0, 0x77 }, // W
127 { SDLK_x, 0, 0x78 }, // X
128 { SDLK_y, 0, 0x79 }, // Y
129 { SDLK_z, 0, 0x7a }, // Z
130 // Keycodes 7B, 7C, 7D not used
131 { SDLK_NUMLOCK, 0, 0x7e }, // Numlock
132 { SDLK_DELETE, 0, 0x7f } // Dlete
133 };
135 /**
136 * List of special key codes
137 */
138 enum {
139 KEY_ALL_UP = 0x40, ///< All keys up
140 KEY_LIST_END = 0x80, ///< End of key code list
141 KEY_BEGIN_MOUSE = 0xCF, ///< Mouse data follows
142 KEY_BEGIN_KEYBOARD = 0xDF, ///< Keyboard data follows
143 };
145 /**
146 * List of keyboard commands
147 */
148 enum {
149 KEY_CMD_RESET = 0x92, ///< Reset keyboard
150 KEY_CMD_CAPSLED_OFF = 0xB1, ///< Caps Lock LED off--CHECK!
151 KEY_CMD_CAPSLED_ON = 0xB0, ///< Caps Lock LED on --CHECK!
152 KEY_CMD_NUMLED_OFF = 0xA1, ///< Num Lock LED off --CHECK!
153 KEY_CMD_NUMLED_ON = 0xA0, ///< Num Lock LED on --CHECK!
154 KEY_CMD_MOUSE_ENABLE = 0xD0, ///< Enable mouse
155 KEY_CMD_MOUSE_DISABLE = 0xD1 ///< Disable mouse
156 };
158 void keyboard_init(KEYBOARD_STATE *ks)
159 {
160 // Set all key states to "not pressed"
161 for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
162 ks->keystate[i] = 0;
163 }
165 // Reset the R/W pointers and length
166 ks->readp = ks->writep = ks->buflen = 0;
168 // Clear the update flag
169 ks->update_flag = false;
170 }
172 void keyboard_event(KEYBOARD_STATE *ks, SDL_Event *ev)
173 {
174 int v = 0;
175 switch (ev->type) {
176 case SDL_KEYDOWN:
177 // Key down (pressed)
178 v = 1;
179 break;
180 case SDL_KEYUP:
181 // Key up (released)
182 v = 0;
183 break;
184 default:
185 // Not a keyboard event
186 return;
187 }
189 // scan the keymap
190 for (int i=0; i < sizeof(keymap)/sizeof(keymap[0]); i++) {
191 if (keymap[i].key == ev->key.keysym.sym) {
192 // Keycode match. Is this an Extended Map key?
193 if (keymap[i].extended) {
194 // Yes -- need ALT set when pressing the key for this to be a match
195 if (ev->key.keysym.mod & KMOD_ALT) {
196 ks->keystate[keymap[i].scancode] = v;
197 ks->update_flag = true;
198 break;
199 }
200 } else {
201 // Standard Map key. ALT must NOT be pressed for this to be a match
202 if (!(ev->key.keysym.mod & KMOD_ALT)) {
203 ks->keystate[keymap[i].scancode] = v;
204 ks->update_flag = true;
205 break;
206 }
207 }
208 }
209 }
210 }
211 void keyboard_scan(KEYBOARD_STATE *ks)
212 {
213 int nkeys = 0;
215 // Skip doing the scan if the keyboard hasn't changed state
216 if (!ks->update_flag) return;
219 // if buffer empty, do a keyboard scan
220 if (ks->buflen == 0) {
221 // Keyboard Data Begins Here (BEGKBD)
222 //ks->buffer[ks->writep] = KEY_BEGIN_KEYBOARD;
223 //ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
224 //if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
226 for (int i=0; i<(sizeof(ks->keystate)/sizeof(ks->keystate[0])); i++) {
227 if (ks->keystate[i]) {
228 LOG_IF(kbc_debug, "KBC KEY DOWN: %d\n", i);
229 ks->buffer[ks->writep] = i;
230 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
231 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
232 nkeys++;
233 }
234 }
235 if (nkeys) {
236 ks->buffer[ks->writep - 1] |= 0x80;
237 }else{
238 // If no keys down, then send All Keys Up byte
239 LOG_IFS(kbc_debug, "KBC ALL KEYS UP\n");
240 ks->buffer[ks->writep] = KEY_ALL_UP;
241 ks->writep = (ks->writep + 1) % KEYBOARD_BUFFER_SIZE;
242 if (ks->buflen < KEYBOARD_BUFFER_SIZE) ks->buflen++;
243 }
245 // TODO: inject "mouse data follows" chunk header and mouse movement info
247 }
249 // Clear the update flag
250 ks->update_flag = false;
251 }
253 bool keyboard_get_irq(KEYBOARD_STATE *ks)
254 {
255 bool irq_status = false;
257 // Conditions which may cause an IRQ :-
258 // Read Data Reg has data and RxIRQ enabled
259 if (ks->rxie)
260 if (ks->buflen > 0) irq_status = true;
262 // Transmit Data Reg empty and TxIRQ enabled
263 // if (ks->txie)
265 // DCD set and RxIRQ enabled
266 //
268 // returns interrupt status -- i.e. is there data in the buffer?
269 return irq_status;
270 }
272 uint8_t keyboard_read(KEYBOARD_STATE *ks, uint8_t addr)
273 {
274 if ((addr & 1) == 0) {
275 // Status register -- RS=0, read
276 uint8_t sr = 0;
277 if (ks->buflen > 0) sr |= 1; // SR0: a new character has been received
278 sr |= 2; // SR1: Transmitter Data Register Empty
279 // 0 + // SR2: Data Carrier Detect
280 // 0 + // SR3: Clear To Send
281 // 0 + // SR4: Framing Error
282 // 0 + // SR5: Receiver Overrun
283 // 0 + // SR6: Parity Error
284 if (keyboard_get_irq(ks)) sr |= 0x80; // SR7: IRQ status
285 //LOG_IF(kbc_debug, "KBC DBG: sr=%02X\n", sr);
286 return sr;
287 } else {
288 // return data, pop off the fifo
289 uint8_t x = ks->buffer[ks->readp];
290 ks->readp = (ks->readp + 1) % KEYBOARD_BUFFER_SIZE;
291 if (ks->buflen > 0) ks->buflen--;
292 //LOG_IF(kbc_debug, "\tKBC DBG: rxd=%02X\n", x);
293 return x;
294 }
295 }
297 void keyboard_write(KEYBOARD_STATE *ks, uint8_t addr, uint8_t val)
298 {
299 if ((addr & 1) == 0) {
300 // write to control register
301 // transmit intr enabled when CR6,5 = 01
302 // receive intr enabled when CR7 = 1
304 // CR0,1 = divider registers. When =11, do a software reset
305 if ((val & 3) == 3) {
306 ks->readp = ks->writep = ks->buflen = 0;
307 }
309 // Ignore CR2,3,4 (word length)...
311 // CR5,6 = Transmit Mode
312 ks->txie = (val & 0x60)==0x20;
314 // CR7 = Receive Interrupt Enable
315 ks->rxie = (val & 0x80)==0x80;
316 } else {
317 // Write command to KBC -- TODO!
318 if (val == KEY_CMD_RESET) {
319 LOG_IFS(kbc_debug, "KBC: KEYBOARD RESET!\n");
320 ks->readp = ks->writep = ks->buflen = 0;
321 } else {
322 LOG("KBC TODO: write keyboard data 0x%02X\n", val);
323 }
324 }
325 }