2 * The 15-410 reference kernel keyboard handling code.
4 * @author Steve Muckle <smuckle@andrew.cmu.edu>
6 * @author Edited by zra for the 2003-2004 season.
8 * @author Edited by mpa for spring 2004
10 * @author Rewritten by nwf for spring 2007.
12 * Functions for turning keyboard scancodes
15 * Notice that we use Scancode Set 1
22 * This is returned as the upper bits of the result of
23 * process_scancode and may be interrogated more readily by
24 * the KH_ macros in keyhelp.h
27 * The bottom bits overlap with the KH_RESULT_ codes in the
30 static short key_state = 0;
32 /** Currently processing a PRINT SCREEN BREAK sequence */
33 #define KH_PRSCR_UP_SCAN 0x0008
34 /** Currently processing a PRINT SCREEN MAKE sequence */
35 #define KH_PRSCR_DOWN_SCAN 0x0004
36 /** Currently processing a PAUSE/BREAK (MAKE) sequence */
37 #define KH_PAUSE_SCAN 0x0002
38 /** Currently processing an extended sequence (E0 prefix) */
39 #define KH_EXTENDED_SCAN 0x0001
40 static short key_internal_state = 0;
42 static int key_sequence = 0;
44 #define KHS_SHIFT_CORE (key_state & (KH_LSHIFT_KEY | KH_RSHIFT_KEY))
45 #define KHS_CTL_CORE (key_state & (KH_LCONTROL_KEY | KH_RCONTROL_KEY))
47 #define KHS_SHIFT(c,r,s,u) \
48 { c = KHS_SHIFT_CORE ? s : u; r = u; }
49 #define KHS_SHIFTCTL(c,r,cc,s,u) \
50 { c = KHS_CTL_CORE ? cc : (KHS_SHIFT_CORE ? s : u); r = u; }
51 #define KHS_SHIFTCAPSCTL(c,r,cc,s,u) \
52 { c = KHS_CTL_CORE ? cc : (((KHS_SHIFT_CORE || (key_state & KH_CAPS_LOCK)) && \
53 !(KHS_SHIFT_CORE && (key_state & KH_CAPS_LOCK))) ? s : u) ; r = u; }
56 * This function performs the mapping
57 * from simple scancodes to chars.
59 * @param scancode a simple scancode.
60 * @param pressed 0 if released, nonzero if pressed.
62 * @return A partially constructed kh_type.
65 process_simple_scan(int scancode, int pressed)
67 unsigned char code = 0x80;
68 unsigned char rcode = 0x80;
71 switch(scancode & 0x7F)
79 KHS_SHIFT(code, rcode, '!', '1');
83 KHS_SHIFTCTL(code, rcode, 0x00, '@', '2');
87 KHS_SHIFT(code, rcode, '#', '3');
91 KHS_SHIFT(code, rcode, '$', '4');
95 KHS_SHIFT(code, rcode, '%', '5');
99 KHS_SHIFTCTL(code, rcode, 0x1E, '^', '6');
103 KHS_SHIFT(code, rcode, '&', '7');
107 KHS_SHIFT(code, rcode, '*', '8');
111 KHS_SHIFT(code, rcode, '(', '9');
115 KHS_SHIFT(code, rcode, ')', '0');
119 KHS_SHIFTCTL(code, rcode, 0x1F, '_', '-');
123 KHS_SHIFT(code, rcode, '+', '=');
135 KHS_SHIFTCAPSCTL(code, rcode, 0x11, 'Q', 'q');
139 KHS_SHIFTCAPSCTL(code, rcode, 0x17, 'W', 'w');
143 KHS_SHIFTCAPSCTL(code, rcode, 0x05, 'E', 'e');
147 KHS_SHIFTCAPSCTL(code, rcode, 0x12, 'R', 'r');
151 KHS_SHIFTCAPSCTL(code, rcode, 0x14, 'T', 't');
155 KHS_SHIFTCAPSCTL(code, rcode, 0x19, 'Y', 'y');
159 KHS_SHIFTCAPSCTL(code, rcode, 0x15, 'U', 'u');
163 KHS_SHIFTCAPSCTL(code, rcode, 0x09, 'I', 'i');
167 KHS_SHIFTCAPSCTL(code, rcode, 0x0F, 'O', 'o');
171 KHS_SHIFTCAPSCTL(code, rcode, 0x10, 'P', 'p');
175 KHS_SHIFTCAPSCTL(code, rcode, 0x1B, '{', '[');
179 KHS_SHIFTCAPSCTL(code, rcode, 0x1D, '}', ']');
186 if((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 0))
188 /* Stage 1 of a pause sequence */
192 key_internal_state &= ~KH_PAUSE_SCAN;
197 key_state |= KH_LCONTROL_KEY;
199 key_state &= ~KH_LCONTROL_KEY;
203 KHS_SHIFTCAPSCTL(code, rcode, 0x01, 'A', 'a');
207 KHS_SHIFTCAPSCTL(code, rcode, 0x13, 'S', 's');
211 KHS_SHIFTCAPSCTL(code, rcode, 0x04, 'D', 'd');
215 KHS_SHIFTCAPSCTL(code, rcode, 0x06, 'F', 'f');
219 KHS_SHIFTCAPSCTL(code, rcode, 0x07, 'G', 'g');
223 KHS_SHIFTCAPSCTL(code, rcode, 0x08, 'H', 'h');
227 KHS_SHIFTCAPSCTL(code, rcode, 0x0A, 'J', 'j');
231 KHS_SHIFTCAPSCTL(code, rcode, 0x0B, 'K', 'k');
235 KHS_SHIFTCAPSCTL(code, rcode, 0x0C, 'L', 'l');
239 KHS_SHIFT(code, rcode, ':', ';');
243 KHS_SHIFT(code, rcode, '\"', '\'');
246 KHS_SHIFT(code, rcode, '~', '`');
251 key_state |= KH_LSHIFT_KEY;
253 key_state &= ~KH_LSHIFT_KEY;
257 KHS_SHIFTCTL(code, rcode, 0x1C, '|', '\\');
261 KHS_SHIFTCAPSCTL(code, rcode, 0x1A, 'Z', 'z');
265 KHS_SHIFTCAPSCTL(code, rcode, 0x18, 'X', 'x');
269 KHS_SHIFTCAPSCTL(code, rcode, 0x03, 'C', 'c');
273 KHS_SHIFTCAPSCTL(code, rcode, 0x16, 'V', 'v');
277 KHS_SHIFTCAPSCTL(code, rcode, 0x02, 'B', 'b');
281 KHS_SHIFTCAPSCTL(code, rcode, 0x0E, 'N', 'n');
285 KHS_SHIFTCAPSCTL(code, rcode, 0x0D, 'M', 'm');
289 KHS_SHIFT(code, rcode, '<', ',');
293 KHS_SHIFT(code, rcode, '>', '.');
297 KHS_SHIFT(code, rcode, '?', '/');
302 key_state |= KH_RSHIFT_KEY;
304 key_state &= ~KH_RSHIFT_KEY;
309 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
314 key_state |= KH_LALT_KEY;
316 key_state &= ~KH_LALT_KEY;
323 rcode = KHE_CAPSLOCK;
326 if(key_state & KH_CAPS_LOCK)
327 key_state &= ~KH_CAPS_LOCK;
329 key_state |= KH_CAPS_LOCK;
334 rcode = code = KHE_F1;
338 rcode = code = KHE_F2;
342 rcode = code = KHE_F3;
346 rcode = code = KHE_F4;
350 rcode = code = KHE_F5;
354 rcode = code = KHE_F6;
358 rcode = code = KHE_F7;
362 rcode = code = KHE_F8;
366 rcode = code = KHE_F9;
370 rcode = code = KHE_F10;
373 if((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 1))
375 /* Stage 2 of a pause sequence */
379 key_internal_state &= ~KH_PAUSE_SCAN;
385 if(key_state & KH_NUM_LOCK)
386 key_state &= ~KH_NUM_LOCK;
388 key_state |= KH_NUM_LOCK;
393 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
397 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
401 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
405 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
409 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
413 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
417 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
421 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
425 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
429 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
433 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
437 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
441 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
445 rcode = code = KHE_F11;
449 rcode = code = KHE_F12;
452 if(!(key_internal_state & KH_PAUSE_SCAN))
454 /* Stage 0 of a pause sequence */
455 key_internal_state |= KH_PAUSE_SCAN;
458 } else if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 2)) {
462 key_internal_state &= ~KH_PAUSE_SCAN;
467 rcode = code = KHE_UNDEFINED;
471 if ( rcode != KHE_UNDEFINED && code != KHE_UNDEFINED )
472 res |= (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
476 return res | (code << KH_CHAR_SHIFT)
477 | (rcode << KH_RAWCHAR_SHIFT)
478 | (KH_RESULT_HASRAW << KH_RMODS_SHIFT);
482 * Processes extended scan codes. Notably, this includes
483 * the arrow keys as well as some of the more unusual keys
486 * @param keypress the extended scancode.
487 * @param 0 if released. non-zero if pressed.
489 * @return A partially constructed kh_type.
492 process_extended_scan(int keypress, int pressed)
494 unsigned char code = 0x80;
495 unsigned char rcode = 0x80;
498 /* Intermediate states in multiple byte scancodes should return
499 * zero from this function, rather than returning a RESULT code.
502 switch(keypress & 0x7F)
507 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
510 /* Right control key */
513 key_state |= KH_RCONTROL_KEY;
515 key_state &= ~KH_RCONTROL_KEY;
518 /* Stage 0 of PRINT SCREEN MAKE and Stage 1 of PRINT SCREEN BREAK */
519 if(key_internal_state & KH_PRSCR_UP_SCAN)
521 rcode = code = KHE_PRINT_SCREEN;
522 key_internal_state &= ~KH_PRSCR_UP_SCAN;
523 } else if (!(key_internal_state & KH_PRSCR_UP_SCAN)) {
524 key_internal_state |= KH_PRSCR_DOWN_SCAN;
525 key_internal_state &= ~KH_EXTENDED_SCAN;
528 rcode = code = KHE_UNDEFINED;
534 res |= KH_RESULT_NUMPAD << KH_RMODS_SHIFT;
537 /* Stage 1 of PRINT SCREEN MAKE and Stage 0 of PRINT SCREEN BREAK */
538 if(key_internal_state & KH_PRSCR_DOWN_SCAN)
540 rcode = code = KHE_PRINT_SCREEN;
541 key_internal_state &= ~KH_PRSCR_DOWN_SCAN;
542 } else if (!(key_internal_state & KH_PRSCR_DOWN_SCAN)) {
543 key_internal_state |= KH_PRSCR_UP_SCAN;
544 key_internal_state &= ~KH_EXTENDED_SCAN;
547 rcode = code = KHE_UNDEFINED;
554 key_state |= KH_RALT_KEY;
556 key_state &= ~KH_RALT_KEY;
560 rcode = code=KHE_ARROW_UP;
564 rcode = code=KHE_ARROW_LEFT;
568 rcode = code=KHE_ARROW_RIGHT;
572 rcode = code = KHE_ARROW_DOWN;
579 rcode = code = KHE_UNDEFINED;
583 key_internal_state &= ~KH_EXTENDED_SCAN;
585 if ( rcode != KHE_UNDEFINED && code != KHE_UNDEFINED )
586 res |= (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
590 return res | (code << KH_CHAR_SHIFT)
591 | (rcode << KH_RAWCHAR_SHIFT)
592 | (KH_RESULT_HASRAW << KH_RMODS_SHIFT);
595 /** The entrypoint to the keyboard processing library.
597 * @param keypress A raw scancode as returned by the keyboard hardware.
598 * @return A kh_type indicating the keyboard modifier key states, result
599 * modifier bits, and potentially ASCII/410 Upper Code Plane
602 kh_type process_scancode(int keypress) {
604 int pressed = !(keypress & 0x80);
605 int keycode = keypress & 0x7F;
607 if (key_internal_state & KH_EXTENDED_SCAN)
608 res = process_extended_scan(keycode, pressed);
611 switch(keypress & 0xFF)
614 if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 3))
619 key_internal_state &= ~KH_PAUSE_SCAN;
624 if ((key_internal_state & KH_PAUSE_SCAN) && (key_sequence == 4))
626 key_internal_state &= ~KH_PAUSE_SCAN;
627 /* Pause sequence completed */
628 res = (KHE_PAUSE << KH_CHAR_SHIFT)
629 | (KHE_PAUSE << KH_RAWCHAR_SHIFT)
630 | (KH_RESULT_HASDATA << KH_RMODS_SHIFT);
633 key_internal_state &= ~KH_PAUSE_SCAN;
637 key_internal_state |= KH_EXTENDED_SCAN;
638 /* Return no result for this intermediate state */
639 return key_state << KH_STATE_SHIFT;
642 key_internal_state &= ~(KH_PRSCR_UP_SCAN | KH_PRSCR_DOWN_SCAN);
643 res = process_simple_scan(keycode, pressed);
648 res |= KH_RESULT_MAKE << KH_RMODS_SHIFT;
650 res |= (key_state & KH_STATE_SMASK) << KH_STATE_SHIFT;