maintain keyboard flags/led states in interrupt handler
report additional "modifier state" in keyboard events. can be used to help translate key events to string/characters for text input
This commit is contained in:
parent
c907d7b144
commit
dcb8f3edaf
|
@ -20,6 +20,7 @@ typedef byte EVENT_ACTION;
|
|||
typedef struct {
|
||||
KEY key;
|
||||
EVENT_ACTION action;
|
||||
uword mod;
|
||||
} INPUTEVENT_KEYBOARD;
|
||||
|
||||
typedef struct {
|
||||
|
|
177
DGLKBRD.C
177
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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue