/* ============================================================ */ /* File: KEYBOARD.C */ /* */ /* Copyright (C) 2001, Daniel W. Lewis and Prentice-Hall */ /* */ /* Purpose: Library routines for access to the keyboard. */ /* See file LIBEPC.H for function descriptions. */ /* */ /* Designed for use with the DJGPP port of the GNU C/C++ */ /* protected mode 386 compiler. */ /* */ /* Modification History: */ /* */ /* ============================================================ */ #include "libepc.h" typedef struct STATE { BOOL ins ; BOOL rshift ; BOOL lshift ; BOOL alt ; BOOL ctrl ; BOOL caps ; BOOL scrl ; BOOL num ; } __attribute__((packed)) STATE ; #define KYBD_STS_PORT 0x64 #define KYBD_DAT_PORT 0x60 #define KYBD_DAT_RDY 0x01 #define BREAK_CODE 0x80 PRIVATE void Install_ISR(void) ; PRIVATE BOOL Dequeue(BYTE8 *ch) ; #define SIZE 20 extern void KeyboardISR(void) __asm__("KeyboardISR") ; extern ISR old_kybd_isr __asm__("old_kybd_isr") ; PRIVATE STATE state ; /* Initialized to all FALSE by loader */ PRIVATE BYTE8 scan_codes[SIZE] ; PRIVATE unsigned int nq = 0 ; PRIVATE unsigned int dq = 0 ; PRIVATE unsigned int count = 0 ; /* -------------------------------------------------------------------- */ /* Scan code translation table. */ /* The incoming scan code from the keyboard selects a row. */ /* The modifier status selects the column. */ /* The word at the intersection of the two is the scan/ASCII code to */ /* put into the PC's type ahead buffer. */ /* If the value fetched from the table is zero, then we do not put the */ /* character into the type ahead buffer. */ /* -------------------------------------------------------------------- */ PRIVATE WORD16 scan_ascii[][8] = { /* norm, shft, ctrl, alt, num, caps, shcap, shnum */ /*--*/ {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /*ESC*/ {0x011B, 0x011B, 0x011B, 0x011B, 0x011B, 0x011B, 0x011B, 0x011B}, /*1 !*/ {0x0231, 0x0221, 0x0000, 0x7800, 0x0231, 0x0231, 0x0231, 0x0321}, /*2 @*/ {0x0332, 0x0340, 0x0300, 0x7900, 0x0332, 0x0332, 0x0332, 0x0332}, /*3 #*/ {0x0433, 0x0423, 0x0000, 0x7A00, 0x0433, 0x0433, 0x0423, 0x0423}, /*4 $*/ {0x0534, 0x0524, 0x0000, 0x7B00, 0x0534, 0x0534, 0x0524, 0x0524}, /*5 %*/ {0x0635, 0x0625, 0x0000, 0x7C00, 0x0635, 0x0635, 0x0625, 0x0625}, /*6 ^*/ {0x0736, 0x075E, 0x071E, 0x7D00, 0x0736, 0x0736, 0x075E, 0x075E}, /*7 &*/ {0x0837, 0x0826, 0x0000, 0x7E00, 0x0837, 0x0837, 0x0826, 0x0826}, /*8 **/ {0x0938, 0x092A, 0x0000, 0x7F00, 0x0938, 0x0938, 0x092A, 0x092A}, /*9 (*/ {0x0A39, 0x0A28, 0x0000, 0x8000, 0x0A39, 0x0A39, 0x0A28, 0x0A28}, /*0 )*/ {0x0B30, 0x0B29, 0x0000, 0x8100, 0x0B30, 0x0B30, 0x0B29, 0x0B29}, /*- _*/ {0x0C2D, 0x0C5F, 0x0000, 0x8200, 0x0C2D, 0x0C2D, 0x0C5F, 0x0C5F}, /*= +*/ {0x0D3D, 0x0D2B, 0x0000, 0x8300, 0x0D3D, 0x0D3D, 0x0D2B, 0x0D2B}, /*bksp*/{0x0E08, 0x0E08, 0x0E7F, 0x0000, 0x0E08, 0x0E08, 0x0E08, 0x0E08}, /*Tab*/ {0x0F09, 0x0F00, 0x0000, 0x0000, 0x0F09, 0x0F09, 0x0F00, 0x0F00}, /*Q*/ {0x1071, 0x1051, 0x1011, 0x1000, 0x1071, 0x1051, 0x1051, 0x1071}, /*W*/ {0x1177, 0x1057, 0x1017, 0x1100, 0x1077, 0x1057, 0x1057, 0x1077}, /*E*/ {0x1265, 0x1245, 0x1205, 0x1200, 0x1265, 0x1245, 0x1245, 0x1265}, /*R*/ {0x1372, 0x1352, 0x1312, 0x1300, 0x1272, 0x1252, 0x1252, 0x1272}, /*T*/ {0x1474, 0x1454, 0x1414, 0x1400, 0x1474, 0x1454, 0x1454, 0x1474}, /*Y*/ {0x1579, 0x1559, 0x1519, 0x1500, 0x1579, 0x1559, 0x1579, 0x1559}, /*U*/ {0x1675, 0x1655, 0x1615, 0x1600, 0x1675, 0x1655, 0x1675, 0x1655}, /*I*/ {0x1769, 0x1749, 0x1709, 0x1700, 0x1769, 0x1749, 0x1769, 0x1749}, /*O*/ {0x186F, 0x184F, 0x180F, 0x1800, 0x186F, 0x184F, 0x186F, 0x184F}, /*P*/ {0x1970, 0x1950, 0x1910, 0x1900, 0x1970, 0x1950, 0x1970, 0x1950}, /*[ {*/ {0x1A5B, 0x1A7B, 0x1A1B, 0x0000, 0x1A5B, 0x1A5B, 0x1A7B, 0x1A7B}, /*] }*/ {0x1B5D, 0x1B7D, 0x1B1D, 0x0000, 0x1B5D, 0x1B5D, 0x1B7D, 0x1B7D}, /*entr*/{0x1C0D, 0x1C0D, 0x1C0A, 0x0000, 0x1C0D, 0x1C0D, 0x1C0A, 0x1C0A}, /*ctrl*/{0x1D00, 0x1D00, 0x1D00, 0x1D00, 0x1D00, 0x1D00, 0x1D00, 0x1D00}, /*A*/ {0x1E61, 0x1E41, 0x1E01, 0x1E00, 0x1E61, 0x1E41, 0x1E61, 0x1E41}, /*S*/ {0x1F73, 0x1F53, 0x1F13, 0x1F00, 0x1F73, 0x1F53, 0x1F73, 0x1F53}, /*D*/ {0x2064, 0x2044, 0x2004, 0x2000, 0x2064, 0x2044, 0x2064, 0x2044}, /*F*/ {0x2166, 0x2146, 0x2106, 0x2100, 0x2166, 0x2146, 0x2166, 0x2146}, /*G*/ {0x2267, 0x2247, 0x2207, 0x2200, 0x2267, 0x2247, 0x2267, 0x2247}, /*H*/ {0x2368, 0x2348, 0x2308, 0x2300, 0x2368, 0x2348, 0x2368, 0x2348}, /*J*/ {0x246A, 0x244A, 0x240A, 0x2400, 0x246A, 0x244A, 0x246A, 0x244A}, /*K*/ {0x256B, 0x254B, 0x250B, 0x2500, 0x256B, 0x254B, 0x256B, 0x254B}, /*L*/ {0x266C, 0x264C, 0x260C, 0x2600, 0x266C, 0x264C, 0x266C, 0x264C}, /*; :*/ {0x273B, 0x273A, 0x0000, 0x0000, 0x273B, 0x273B, 0x273A, 0x273A}, /*' "*/ {0x2827, 0x2822, 0x0000, 0x0000, 0x2827, 0x2827, 0x2822, 0x2822}, /*` ~*/ {0x2960, 0x297E, 0x0000, 0x0000, 0x2960, 0x2960, 0x297E, 0x297E}, /*LShf*/{0x2A00, 0x2A00, 0x2A00, 0x2A00, 0x2A00, 0x2A00, 0x2A00, 0x2A00}, /*\ |*/ {0x2B5C, 0x2B7C, 0x2B1C, 0x0000, 0x2B5C, 0x2B5C, 0x2B7C, 0x2B7C}, /*Z*/ {0x2C7A, 0x2C5A, 0x2C1A, 0x2C00, 0x2C7A, 0x2C5A, 0x2C7A, 0x2C5A}, /*X*/ {0x2D78, 0x2D58, 0x2D18, 0x2D00, 0x2D78, 0x2D58, 0x2D78, 0x2D58}, /*C*/ {0x2E63, 0x2E43, 0x2E03, 0x2E00, 0x2E63, 0x2E43, 0x2E63, 0x2E43}, /*V*/ {0x2F76, 0x2F56, 0x2F16, 0x2F00, 0x2F76, 0x2F56, 0x2F76, 0x2F56}, /*B*/ {0x3062, 0x3042, 0x3002, 0x3000, 0x3062, 0x3042, 0x3062, 0x3042}, /*N*/ {0x316E, 0x314E, 0x310E, 0x3100, 0x316E, 0x314E, 0x316E, 0x314E}, /*M*/ {0x326D, 0x324D, 0x320D, 0x3200, 0x326D, 0x324D, 0x326D, 0x324D}, /*, <*/ {0x332C, 0x333C, 0x0000, 0x0000, 0x332C, 0x332C, 0x333C, 0x333C}, /*. >*/ {0x342E, 0x343E, 0x0000, 0x0000, 0x342E, 0x342E, 0x343E, 0x343E}, /*/ ?*/ {0x352F, 0x353F, 0x0000, 0x0000, 0x352F, 0x352F, 0x353F, 0x353F}, /*rshf*/{0x3600, 0x3600, 0x3600, 0x3600, 0x3600, 0x3600, 0x3600, 0x3600}, /** PS*/{0x372A, 0x0000, 0x3710, 0x0000, 0x372A, 0x372A, 0x0000, 0x0000}, /*alt*/ {0x3800, 0x3800, 0x3800, 0x3800, 0x3800, 0x3800, 0x3800, 0x3800}, /*spc*/ {0x3920, 0x3920, 0x3920, 0x0000, 0x3920, 0x3920, 0x3920, 0x3920}, /*caps*/{0x3A00, 0x3A00, 0x3A00, 0x3A00, 0x3A00, 0x3A00, 0x3A00, 0x3A00}, /*F1*/ {0x3B00, 0x5400, 0x5E00, 0x6800, 0x3B00, 0x3B00, 0x5400, 0x5400}, /*F2*/ {0x3C00, 0x5500, 0x5F00, 0x6900, 0x3C00, 0x3C00, 0x5500, 0x5500}, /*F3*/ {0x3D00, 0x5600, 0x6000, 0x6A00, 0x3D00, 0x3D00, 0x5600, 0x5600}, /*F4*/ {0x3E00, 0x5700, 0x6100, 0x6B00, 0x3E00, 0x3E00, 0x5700, 0x5700}, /*F5*/ {0x3F00, 0x5800, 0x6200, 0x6C00, 0x3F00, 0x3F00, 0x5800, 0x5800}, /*F6*/ {0x4000, 0x5900, 0x6300, 0x6D00, 0x4000, 0x4000, 0x5900, 0x5900}, /*F7*/ {0x4100, 0x5A00, 0x6400, 0x6E00, 0x4100, 0x4100, 0x5A00, 0x5A00}, /*F8*/ {0x4200, 0x5B00, 0x6500, 0x6F00, 0x4200, 0x4200, 0x5B00, 0x5B00}, /*F9*/ {0x4300, 0x5C00, 0x6600, 0x7000, 0x4300, 0x4300, 0x5C00, 0x5C00}, /*F10*/ {0x4400, 0x5D00, 0x6700, 0x7100, 0x4400, 0x4400, 0x5D00, 0x5D00}, /*num*/ {0x4500, 0x4500, 0x4500, 0x4500, 0x4500, 0x4500, 0x4500, 0x4500}, /*scrl*/{0x4600, 0x4600, 0x4600, 0x4600, 0x4600, 0x4600, 0x4600, 0x4600}, /*home*/{0x4700, 0x4737, 0x7700, 0x0000, 0x4737, 0x4700, 0x4737, 0x4700}, /*up*/ {0x4800, 0x4838, 0x0000, 0x0000, 0x4838, 0x4800, 0x4838, 0x4800}, /*pgup*/{0x4900, 0x4939, 0x8400, 0x0000, 0x4939, 0x4900, 0x4939, 0x4900}, /*-*/ {0x4A2D, 0x4A2D, 0x0000, 0x0000, 0x4A2D, 0x4A2D, 0x4A2D, 0x4A2D}, /*left*/{0x4B00, 0x4B34, 0x7300, 0x0000, 0x4B34, 0x4B00, 0x4B34, 0x4B00}, /*Cntr*/{0x4C00, 0x4C35, 0x0000, 0x0000, 0x4C35, 0x4C00, 0x4C35, 0x4C00}, /*rght*/{0x4D00, 0x4D36, 0x7400, 0x0000, 0x4D36, 0x4D00, 0x4D36, 0x4D00}, /*+*/ {0x4E2B, 0x4E2B, 0x0000, 0x0000, 0x4E2B, 0x4E2B, 0x4E2B, 0x4E2B}, /*end*/ {0x4F00, 0x4F31, 0x7500, 0x0000, 0x4F31, 0x4F00, 0x4F31, 0x4F00}, /*down*/{0x5000, 0x5032, 0x0000, 0x0000, 0x5032, 0x5000, 0x5032, 0x5000}, /*pgdn*/{0x5100, 0x5133, 0x7600, 0x0000, 0x5133, 0x5100, 0x5133, 0x5100}, /*ins*/ {0x5200, 0x5230, 0x0000, 0x0000, 0x5230, 0x5200, 0x5230, 0x5200}, /*del*/ {0x5300, 0x532E, 0x0000, 0x0000, 0x532E, 0x5300, 0x532E, 0x5300}, /*--*/ {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /*--*/ {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /*--*/ {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}, /*F11*/ {0x5700, 0x0000, 0x0000, 0x0000, 0x5700, 0x5700, 0x0000, 0x0000}, /*F12*/ {0x5800, 0x0000, 0x0000, 0x0000, 0x5800, 0x5800, 0x0000, 0x0000} } ; /* ------------------------------------------------------------ */ /* Public functions ... */ /* ------------------------------------------------------------ */ BOOL ScanCodeRdy(void) { Install_ISR() ; return (count > 0) ; } BYTE8 GetScanCode(void) { BYTE8 scan_code ; return Dequeue(&scan_code) ? scan_code : 0x00 ; } WORD16 ScanCode2Ascii(BYTE8 code) { if (code == 0xE0 || code == 0xE1) return 0x0000 ; /* ignore */ if (code & 0x80) return code << 8 ; /* KeyUp */ if (code >= ENTRIES(scan_ascii)) return 0x0000 ; /* ignore */ if (state.alt) return scan_ascii[code][3] ; if (state.ctrl) return scan_ascii[code][2] ; if (code >= 0x47) { if (state.num) { if (state.lshift || state.rshift) { return scan_ascii[code][7] ; } return scan_ascii[code][4] ; } } else if (state.caps) { if (state.lshift || state.rshift) { return scan_ascii[code][6] ; } return scan_ascii[code][5] ; } if (state.lshift || state.rshift) { return scan_ascii[code][1] ; } return scan_ascii[code][0] ; } BOOL SetsKybdState(BYTE8 code) { switch (code) { case 0x36: state.rshift = TRUE ; break ; case 0xB6: state.rshift = FALSE ; break ; case 0x2A: state.lshift = TRUE ; break ; case 0xAA: state.lshift = FALSE ; break ; case 0x38: state.alt = TRUE ; break ; case 0xB8: state.alt = FALSE ; break ; case 0x1D: state.ctrl = TRUE ; break ; case 0x9D: state.ctrl = FALSE ; break ; case 0x3A: state.caps = !state.caps ; case 0xBA: break ; case 0x46: state.scrl = !state.scrl ; case 0xC6: break ; case 0x45: state.num = !state.num ; case 0xC5: break ; case 0x52: state.ins = !state.ins ; case 0xD2: break ; default: return FALSE ; } return TRUE ; } /* ------------------------------------------------------------ */ /* Private functions ... */ /* ------------------------------------------------------------ */ BOOL Enqueue(BYTE8 scan_code) __asm("Enqueue") ; BOOL Enqueue(BYTE8 scan_code) { BOOL full ; PUSHF ; CLI ; full = count >= SIZE ; if (!full) { scan_codes[nq] = scan_code ; if (++nq == SIZE) nq = 0 ; count++ ; } POPF ; return !full ; } PRIVATE BOOL Dequeue(BYTE8 *scan_code) { BOOL empty ; PUSHF ; CLI ; empty = count <= 0 ; if (!empty) { *scan_code = scan_codes[dq] ; if (++dq == SIZE) dq = 0 ; count-- ; } POPF ; return !empty ; } PRIVATE void Install_ISR(void) { static BOOL installed = FALSE ; if (installed) return ; old_kybd_isr = GetISR(IRQ2INT(IRQ_KYBD)) ; SetISR(IRQ2INT(IRQ_KYBD), KeyboardISR) ; outportb(0x21, inportb(0x21) & ~0x02) ; /* Unmask IRQ1 (Keyboard) */ installed = TRUE ; }