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 {
|
typedef struct {
|
||||||
KEY key;
|
KEY key;
|
||||||
EVENT_ACTION action;
|
EVENT_ACTION action;
|
||||||
|
uword mod;
|
||||||
} INPUTEVENT_KEYBOARD;
|
} INPUTEVENT_KEYBOARD;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
177
DGLKBRD.C
177
DGLKBRD.C
|
@ -1,4 +1,5 @@
|
||||||
#include "dglkbrd.h"
|
#include "dglkbrd.h"
|
||||||
|
#include "dglcmn.h"
|
||||||
#include "dglevent.h"
|
#include "dglevent.h"
|
||||||
#include "dglutil.h"
|
#include "dglutil.h"
|
||||||
#include "dglerror.h"
|
#include "dglerror.h"
|
||||||
|
@ -22,6 +23,13 @@
|
||||||
#define KEYBRD_LED_NUMLOCK 0x2
|
#define KEYBRD_LED_NUMLOCK 0x2
|
||||||
#define KEYBRD_LED_CAPSLOCK 0x4
|
#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 boolean _installed = FALSE;
|
||||||
static INPUTEVENT *keyboard_event;
|
static INPUTEVENT *keyboard_event;
|
||||||
|
|
||||||
|
@ -29,12 +37,18 @@ volatile ubyte keys[128];
|
||||||
|
|
||||||
volatile KEY _key_last_scan;
|
volatile KEY _key_last_scan;
|
||||||
volatile KEY _key_scan;
|
volatile KEY _key_scan;
|
||||||
|
volatile uword _key_flags;
|
||||||
|
volatile uword _key_mod;
|
||||||
|
|
||||||
uword _old_flags;
|
uword _old_flags;
|
||||||
|
|
||||||
void (interrupt far *_old_handler)();
|
void (interrupt far *_old_handler)();
|
||||||
|
|
||||||
static void reset_key_states() {
|
static void reset_key_states() {
|
||||||
|
_key_last_scan = 0;
|
||||||
|
_key_scan = 0;
|
||||||
|
_key_flags = 0;
|
||||||
|
_key_mod = 0;
|
||||||
memset((void*)keys, 0, 128);
|
memset((void*)keys, 0, 128);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,48 +79,6 @@ static boolean send_kb_data(ubyte data) {
|
||||||
return (result == 0xFA);
|
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) {
|
static uword get_kb_flags(void) {
|
||||||
return *((uword*)KEYBRD_FLAGS_ADDR);
|
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
|
// set in the passed keyboard flags. returns FALSE if the LEDs could not
|
||||||
// be updated (if keyboard data write did not succeed)
|
// be updated (if keyboard data write did not succeed)
|
||||||
static boolean update_kb_led(byte flags) {
|
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)) {
|
if (!send_kb_data(KEYBRD_CMD_SET_LED)) {
|
||||||
dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE);
|
dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!send_kb_data(led)) {
|
if (!send_kb_data((flags >> 4) & 3)) {
|
||||||
dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE);
|
dgl_set_error(DGL_KEYBOARD_UPDATE_LED_FAILURE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -140,23 +103,126 @@ static boolean update_kb_led(byte flags) {
|
||||||
return TRUE;
|
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) {
|
boolean keyboard_init(void) {
|
||||||
if (_installed) {
|
if (_installed) {
|
||||||
dgl_set_error(DGL_KEYBOARD_ALREADY_INITIALIZED);
|
dgl_set_error(DGL_KEYBOARD_ALREADY_INITIALIZED);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset_key_states();
|
||||||
|
|
||||||
// preserve old flags
|
// preserve old flags
|
||||||
_old_flags = get_kb_flags();
|
_old_flags = get_kb_flags();
|
||||||
|
_key_flags = _old_flags;
|
||||||
|
|
||||||
|
handler_update_modifiers();
|
||||||
|
|
||||||
reset_key_states();
|
|
||||||
_old_handler = _dos_getvect(9);
|
_old_handler = _dos_getvect(9);
|
||||||
_dos_setvect(9, kb_int_handler);
|
_dos_setvect(9, kb_int_handler);
|
||||||
|
|
||||||
// turn off keyboard LEDs since our interrupt handler does not currently
|
// turn off keyboard LEDs since our interrupt handler does not currently
|
||||||
// respect the num/caps/scroll lock statuses
|
// respect the num/caps/scroll lock statuses
|
||||||
int_disable();
|
int_disable();
|
||||||
update_kb_led(0);
|
update_kb_led(_key_flags);
|
||||||
int_enable();
|
int_enable();
|
||||||
|
|
||||||
_installed = TRUE;
|
_installed = TRUE;
|
||||||
|
@ -173,11 +239,12 @@ boolean keyboard_shutdown(void) {
|
||||||
int_enable();
|
int_enable();
|
||||||
|
|
||||||
_dos_setvect(9, _old_handler);
|
_dos_setvect(9, _old_handler);
|
||||||
reset_key_states();
|
|
||||||
|
|
||||||
// restore keyboard flags to previous state
|
// restore keyboard flags to previous state
|
||||||
set_kb_flags(_old_flags);
|
set_kb_flags(_old_flags);
|
||||||
|
|
||||||
|
reset_key_states();
|
||||||
|
|
||||||
_installed = FALSE;
|
_installed = FALSE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,10 @@ void test_events(void) {
|
||||||
|
|
||||||
switch (event->type) {
|
switch (event->type) {
|
||||||
case EVENT_TYPE_KEYBOARD:
|
case EVENT_TYPE_KEYBOARD:
|
||||||
printf("KEYBOARD: %2d - %d\n",
|
printf("KEYBOARD: %2d - %d (%d)\n",
|
||||||
event->keyboard.key,
|
event->keyboard.key,
|
||||||
event->keyboard.action);
|
event->keyboard.action,
|
||||||
|
event->keyboard.mod);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EVENT_TYPE_MOUSE_MOTION:
|
case EVENT_TYPE_MOUSE_MOTION:
|
||||||
|
|
Loading…
Reference in a new issue