diff --git a/DGLEVENT.H b/DGLEVENT.H index 4b6a19c..4769666 100644 --- a/DGLEVENT.H +++ b/DGLEVENT.H @@ -20,6 +20,7 @@ typedef byte EVENT_ACTION; typedef struct { KEY key; EVENT_ACTION action; + uword mod; } INPUTEVENT_KEYBOARD; typedef struct { diff --git a/DGLKBRD.C b/DGLKBRD.C index e327078..7e57e6c 100644 --- a/DGLKBRD.C +++ b/DGLKBRD.C @@ -1,4 +1,5 @@ #include "dglkbrd.h" +#include "dglcmn.h" #include "dglevent.h" #include "dglutil.h" #include "dglerror.h" @@ -22,6 +23,13 @@ #define KEYBRD_LED_NUMLOCK 0x2 #define KEYBRD_LED_CAPSLOCK 0x4 +#define KEYBRD_MOD_EXTENDED 0x1 +#define KEYBRD_MOD_SHIFT 0x2 +#define KEYBRD_MOD_NUMLOCK 0x4 +#define KEYBRD_MOD_CAPSLOCK 0x8 + +#define KEY_EXTENDED ((KEY)0xe0) + static boolean _installed = FALSE; static INPUTEVENT *keyboard_event; @@ -29,12 +37,18 @@ volatile ubyte keys[128]; volatile KEY _key_last_scan; volatile KEY _key_scan; +volatile uword _key_flags; +volatile uword _key_mod; uword _old_flags; void (interrupt far *_old_handler)(); static void reset_key_states() { + _key_last_scan = 0; + _key_scan = 0; + _key_flags = 0; + _key_mod = 0; memset((void*)keys, 0, 128); } @@ -65,48 +79,6 @@ static boolean send_kb_data(ubyte data) { return (result == 0xFA); } -static void push_keyboard_event(KEY key, EVENT_ACTION action) { - if (_events_enabled) { - // HACK: skipping extended (?) key extra keyscan code. - // we only actually care about the subsequent key code... - // (this is a terrible way to do this, doesn't handle all cases) - if (key != 0x60) { - _events_push(&keyboard_event); - keyboard_event->type = EVENT_TYPE_KEYBOARD; - keyboard_event->keyboard.key = key; - keyboard_event->keyboard.action = action; - } - } -} - -// keyboard interrupt handler -void interrupt far kb_int_handler(void) { - // read scan code of key that was just pressed - _key_scan = inp(KEYBRD_DATA_PORT); - if (_key_scan & 0x80) { - // high bit set indicates key was released, clear high bit to get - // the actual key scan code - _key_scan &= 0x7f; - keys[(int)_key_scan] = 0; - push_keyboard_event(_key_scan, EVENT_ACTION_RELEASED); - } else { - if (keys[(int)_key_scan]) - push_keyboard_event(_key_scan, EVENT_ACTION_HELD); - else { - keys[(int)_key_scan] = 1; - push_keyboard_event(_key_scan, EVENT_ACTION_PRESSED); - } - } - - _key_last_scan = _key_scan; - - // indicate key event was processed to keyboard controller - _key_scan = inp(KEYBRD_CTRL_PORT) | 0x82; - outp(KEYBRD_CTRL_PORT, _key_scan); - outp(KEYBRD_CTRL_PORT, _key_scan & 0x7f); - outp(PIC_CTRL_PORT, 0x20); -} - static uword get_kb_flags(void) { return *((uword*)KEYBRD_FLAGS_ADDR); } @@ -119,20 +91,11 @@ static void set_kb_flags(uword flags) { // set in the passed keyboard flags. returns FALSE if the LEDs could not // be updated (if keyboard data write did not succeed) static boolean update_kb_led(byte flags) { - ubyte led = 0; - - if (flags & KEYBRD_FLAGS_SCROLLOCK) - led |= KEYBRD_LED_SCROLLOCK; - if (flags & KEYBRD_FLAGS_NUMLOCK) - led |= KEYBRD_LED_NUMLOCK; - if (flags & KEYBRD_FLAGS_CAPSLOCK) - led |= KEYBRD_LED_CAPSLOCK; - if (!send_kb_data(KEYBRD_CMD_SET_LED)) { dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE); return FALSE; } - if (!send_kb_data(led)) { + if (!send_kb_data((flags >> 4) & 3)) { dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE); return FALSE; } @@ -140,23 +103,126 @@ static boolean update_kb_led(byte flags) { return TRUE; } +static void push_keyboard_event(KEY key, EVENT_ACTION action) { + if (_events_enabled) { + _events_push(&keyboard_event); + keyboard_event->type = EVENT_TYPE_KEYBOARD; + keyboard_event->keyboard.key = key; + keyboard_event->keyboard.action = action; + keyboard_event->keyboard.mod = _key_mod; + } +} + +static boolean handler_filter_keys(void) { + if (BIT_ISSET(KEYBRD_MOD_EXTENDED, _key_mod)) { + // extended key + leftshift comes with cursor key presses when + // numlock is enabled + if ((_key_scan & 0x7f) == (KEY)KEY_LEFTSHIFT) + return TRUE; + } + return FALSE; +} + +static void handler_update_flags_and_leds(void) { + switch (_key_scan) { + case (KEY)KEY_CAPSLOCK: + BIT_TOGGLE(KEYBRD_FLAGS_CAPSLOCK, _key_flags); + update_kb_led(_key_flags); + set_kb_flags(_key_flags); + break; + case (KEY)KEY_NUMLOCK: + BIT_TOGGLE(KEYBRD_FLAGS_NUMLOCK, _key_flags); + update_kb_led(_key_flags); + set_kb_flags(_key_flags); + break; + case (KEY)KEY_SCROLLLOCK: + BIT_TOGGLE(KEYBRD_FLAGS_SCROLLOCK, _key_flags); + update_kb_led(_key_flags); + set_kb_flags(_key_flags); + break; + default: + break; + } +} + +static void handler_update_modifiers(void) { + if (BIT_ISSET(KEYBRD_FLAGS_NUMLOCK, _key_flags)) + BIT_SET(KEYBRD_MOD_NUMLOCK, _key_mod); + else + BIT_CLEAR(KEYBRD_MOD_NUMLOCK, _key_mod); + + if (BIT_ISSET(KEYBRD_FLAGS_CAPSLOCK, _key_flags)) + BIT_SET(KEYBRD_MOD_CAPSLOCK, _key_mod); + else + BIT_CLEAR(KEYBRD_MOD_CAPSLOCK, _key_mod); + + if (keys[KEY_LEFTSHIFT] || keys[KEY_RIGHTSHIFT]) + BIT_SET(KEYBRD_MOD_SHIFT, _key_mod); + else + BIT_CLEAR(KEYBRD_MOD_SHIFT, _key_mod); +} + +// keyboard interrupt handler +void interrupt far kb_int_handler(void) { + // read scan code of key that was just pressed + _key_scan = inp(KEYBRD_DATA_PORT); + if (_key_scan == KEY_EXTENDED) { + // extended key scan + BIT_SET(KEYBRD_MOD_EXTENDED, _key_mod); + + } else { + if (!handler_filter_keys()) { + if (_key_scan & 0x80) { + // high bit set indicates key was released, clear high bit + // to get the actual key scan code + _key_scan &= 0x7f; + keys[(int)_key_scan] = 0; + handler_update_modifiers(); + push_keyboard_event(_key_scan, EVENT_ACTION_RELEASED); + } else { + if (keys[(int)_key_scan]) + push_keyboard_event(_key_scan, EVENT_ACTION_HELD); + else { + keys[(int)_key_scan] = 1; + handler_update_flags_and_leds(); + handler_update_modifiers(); + push_keyboard_event(_key_scan, EVENT_ACTION_PRESSED); + } + } + _key_last_scan = _key_scan; + } + + BIT_CLEAR(KEYBRD_MOD_EXTENDED, _key_mod); + } + + // indicate key event was processed to keyboard controller + _key_scan = inp(KEYBRD_CTRL_PORT) | 0x82; + outp(KEYBRD_CTRL_PORT, _key_scan); + outp(KEYBRD_CTRL_PORT, _key_scan & 0x7f); + outp(PIC_CTRL_PORT, 0x20); +} + boolean keyboard_init(void) { if (_installed) { dgl_set_error(DGL_KEYBOARD_ALREADY_INITIALIZED); return FALSE; } + reset_key_states(); + // preserve old flags _old_flags = get_kb_flags(); + _key_flags = _old_flags; + + handler_update_modifiers(); - reset_key_states(); _old_handler = _dos_getvect(9); _dos_setvect(9, kb_int_handler); // turn off keyboard LEDs since our interrupt handler does not currently // respect the num/caps/scroll lock statuses int_disable(); - update_kb_led(0); + update_kb_led(_key_flags); int_enable(); _installed = TRUE; @@ -173,11 +239,12 @@ boolean keyboard_shutdown(void) { int_enable(); _dos_setvect(9, _old_handler); - reset_key_states(); // restore keyboard flags to previous state set_kb_flags(_old_flags); + reset_key_states(); + _installed = FALSE; return TRUE; } diff --git a/TEST/EVENTS.C b/TEST/EVENTS.C index f59a8ef..86fa0db 100644 --- a/TEST/EVENTS.C +++ b/TEST/EVENTS.C @@ -29,9 +29,10 @@ void test_events(void) { switch (event->type) { case EVENT_TYPE_KEYBOARD: - printf("KEYBOARD: %2d - %d\n", + printf("KEYBOARD: %2d - %d (%d)\n", event->keyboard.key, - event->keyboard.action); + event->keyboard.action, + event->keyboard.mod); break; case EVENT_TYPE_MOUSE_MOTION: