add input device events

as a new subsystem that must be explicitly enabled/disabled
This commit is contained in:
Gered 2018-05-21 14:48:22 -04:00
parent 9f568987d0
commit ab9fe0cb9a
13 changed files with 341 additions and 1 deletions

3
DGL.C
View file

@ -45,6 +45,8 @@ const char* dgl_last_error_message(void) {
return "Failed to set mouse interrupt handler callback.";
case DGL_MOUSE_INT_CALLBACK_RESTORE_FAILURE:
return "Failed to restore original mouse interrupt handler callback.";
case DGL_EVENTS_ALREADY_INITIALIZED:
return "Input device events subsystem is already initialized.";
case DGL_IO_ERROR:
return "File IO error.";
case DGL_PCX_BAD_FORMAT:
@ -59,6 +61,7 @@ void dgl_set_error(DGL_ERROR error) {
}
void _dgl_atexit(void) {
events_shutdown();
mouse_shutdown();
keyboard_shutdown();
video_shutdown();

1
DGL.H
View file

@ -18,6 +18,7 @@
#include "dglmtx33.h"
#include "dglutil.h"
#include "dglpcx.h"
#include "dglevent.h"
void dgl_init(void);

View file

@ -19,6 +19,7 @@ typedef enum {
DGL_MOUSE_FREE_CALLBACK_FAILURE,
DGL_MOUSE_INT_CALLBACK_SET_FAILURE,
DGL_MOUSE_INT_CALLBACK_RESTORE_FAILURE,
DGL_EVENTS_ALREADY_INITIALIZED,
DGL_IO_ERROR,
DGL_PCX_BAD_FORMAT
} DGL_ERROR;

69
DGLEVENT.C Normal file
View file

@ -0,0 +1,69 @@
#include "dglevent.h"
#include "dglerror.h"
#include "dglutil.h"
#include <string.h>
volatile boolean _events_enabled;
volatile INPUTEVENT _events_buffer[EVENTS_BUFFER_SIZE];
volatile int _events_buffer_start = 0;
volatile int _events_buffer_end = 0;
boolean events_init(void) {
if (_events_enabled) {
dgl_set_error(DGL_EVENTS_ALREADY_INITIALIZED);
return FALSE;
}
events_clear();
_events_enabled = TRUE;
return TRUE;
}
boolean events_shutdown(void) {
if (!_events_enabled)
return TRUE; // don't care
_events_enabled = FALSE;
events_clear();
return TRUE;
}
boolean events_poll(INPUTEVENT **event) {
if (events_is_empty())
return FALSE;
int_disable();
*event = &_events_buffer[_events_buffer_start];
++_events_buffer_start;
if (_events_buffer_start >= EVENTS_BUFFER_SIZE)
_events_buffer_start = 0;
int_enable();
return TRUE;
}
boolean events_peek(INPUTEVENT **event) {
if (events_is_empty())
return FALSE;
*event = &_events_buffer[_events_buffer_start];
return TRUE;
}
void events_clear(void) {
int_disable();
memset(_events_buffer, 0, sizeof(_events_buffer));
_events_buffer_start = 0;
_events_buffer_end = 0;
int_enable();
}

102
DGLEVENT.H Normal file
View file

@ -0,0 +1,102 @@
#ifndef DGL_DGLEVENT_H_INCLUDED
#define DGL_DGLEVENT_H_INCLUDED
#include "dglcmn.h"
#include "dglkbrd.h"
#include "dglmouse.h"
typedef byte EVENT_TYPE;
#define EVENT_TYPE_KEYBOARD 1
#define EVENT_TYPE_MOUSE_MOTION 2
#define EVENT_TYPE_MOUSE_BUTTON 3
typedef byte EVENT_ACTION;
#define EVENT_ACTION_PRESSED 1
#define EVENT_ACTION_RELEASED 2
#define EVENT_ACTION_HELD 3
typedef struct {
KEY key;
EVENT_ACTION action;
} INPUTEVENT_KEYBOARD;
typedef struct {
int x;
int y;
int x_delta;
int y_delta;
MOUSE_BUTTON buttons;
} INPUTEVENT_MOUSE_MOTION;
typedef struct {
int x;
int y;
MOUSE_BUTTON button;
EVENT_ACTION action;
} INPUTEVENT_MOUSE_BUTTON;
typedef struct {
EVENT_TYPE type;
union {
INPUTEVENT_KEYBOARD keyboard;
INPUTEVENT_MOUSE_MOTION mouse_motion;
INPUTEVENT_MOUSE_BUTTON mouse_button;
};
} INPUTEVENT;
extern volatile boolean _events_enabled;
#define EVENTS_BUFFER_SIZE 32
extern volatile INPUTEVENT _events_buffer[EVENTS_BUFFER_SIZE];
extern volatile int _events_buffer_start;
extern volatile int _events_buffer_end;
boolean events_init(void);
boolean events_shutdown(void);
static boolean events_is_initialized(void);
static boolean events_is_empty(void);
boolean events_poll(INPUTEVENT **event);
boolean events_peek(INPUTEVENT **event);
void events_clear(void);
static void _events_push(INPUTEVENT **out_event);
// ---------------------------------------------------------------------------
static boolean events_is_initialized(void) {
return _events_enabled;
}
static boolean events_is_empty(void) {
return (_events_buffer_start == _events_buffer_end);
}
// only intended to be called from input device interrupt handler (the
// usage is a little weird as a result)
static void _events_push(INPUTEVENT **out_event) {
*out_event = &_events_buffer[_events_buffer_end];
++_events_buffer_end;
// wrap around
if (_events_buffer_end >= EVENTS_BUFFER_SIZE)
_events_buffer_end = 0;
// is the events buffer full? (if the end meets up to the start, yes)
if (_events_buffer_end == _events_buffer_start) {
// move the start up. this ensures start always points to the oldest
// event in the buffer
++_events_buffer_start;
if (_events_buffer_start >= EVENTS_BUFFER_SIZE)
_events_buffer_start = 0;
}
}
#endif

View file

@ -1,4 +1,5 @@
#include "dglkbrd.h"
#include "dglevent.h"
#include "dglutil.h"
#include "dglerror.h"
#include <string.h>
@ -22,6 +23,7 @@
#define KEYBRD_LED_CAPSLOCK 0x4
static boolean _installed = FALSE;
static INPUTEVENT *keyboard_event;
volatile ubyte keys[128];
@ -63,6 +65,20 @@ 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
@ -72,8 +88,14 @@ void interrupt far kb_int_handler(void) {
// 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;

View file

@ -1,4 +1,5 @@
#include "dglmouse.h"
#include "dglevent.h"
#include "dglerror.h"
#include <string.h>
#include <dos.h>
@ -6,11 +7,14 @@
static boolean _installed = FALSE;
static boolean _has_mouse = FALSE;
static INPUTEVENT *mouse_event;
volatile int mouse_x;
volatile int mouse_y;
volatile int mouse_buttons;
volatile int mouse_delta_x;
volatile int mouse_delta_y;
volatile int mouse_prev_buttons;
static void reset_mouse_state(void) {
mouse_x = 0;
@ -18,6 +22,7 @@ static void reset_mouse_state(void) {
mouse_buttons = 0;
mouse_delta_x = 0;
mouse_delta_y = 0;
mouse_prev_buttons = 0;
}
static boolean init_mouse_driver(void) {
@ -38,11 +43,31 @@ static void update_mouse_state(void) {
int386(0x33, &regs, &regs);
mouse_x = (regs.w.cx / 2);
mouse_y = regs.w.dx;
mouse_prev_buttons = mouse_buttons;
mouse_buttons = regs.w.bx;
mouse_delta_x = 0;
mouse_delta_y = 0;
}
static void push_motion_event(void) {
_events_push(&mouse_event);
mouse_event->type = EVENT_TYPE_MOUSE_MOTION;
mouse_event->mouse_motion.x = mouse_x;
mouse_event->mouse_motion.y = mouse_y;
mouse_event->mouse_motion.x_delta = mouse_delta_x;
mouse_event->mouse_motion.y_delta = mouse_delta_y;
mouse_event->mouse_motion.buttons = mouse_buttons;
}
static void push_button_event(EVENT_ACTION action, MOUSE_BUTTON button) {
_events_push(&mouse_event);
mouse_event->type = EVENT_TYPE_MOUSE_BUTTON;
mouse_event->mouse_button.x = mouse_x;
mouse_event->mouse_button.y = mouse_y;
mouse_event->mouse_button.action = action;
mouse_event->mouse_button.button = button;
}
#pragma off (check_stack)
void __loadds far mouse_int_handler(int eax, int ebx, int ecx, int edx) {
#pragma aux mouse_int_handler parm [eax] [ebx] [ecx] [edx]
@ -50,7 +75,40 @@ void __loadds far mouse_int_handler(int eax, int ebx, int ecx, int edx) {
mouse_delta_y = edx - mouse_y;
mouse_x = (ecx / 2);
mouse_y = edx;
mouse_prev_buttons = mouse_buttons;
mouse_buttons = ebx;
if (_events_enabled) {
if (mouse_delta_x || mouse_delta_y) {
push_motion_event();
}
if (mouse_buttons != mouse_prev_buttons) {
if ((mouse_buttons & MOUSE_LEFTBUTTON) !=
(mouse_prev_buttons & MOUSE_LEFTBUTTON)) {
if (mouse_buttons & MOUSE_LEFTBUTTON)
push_button_event(EVENT_ACTION_PRESSED, MOUSE_LEFTBUTTON);
else
push_button_event(EVENT_ACTION_RELEASED, MOUSE_LEFTBUTTON);
}
if ((mouse_buttons & MOUSE_RIGHTBUTTON) !=
(mouse_prev_buttons & MOUSE_RIGHTBUTTON)) {
if (mouse_buttons & MOUSE_RIGHTBUTTON)
push_button_event(EVENT_ACTION_PRESSED, MOUSE_RIGHTBUTTON);
else
push_button_event(EVENT_ACTION_RELEASED, MOUSE_RIGHTBUTTON);
}
if ((mouse_buttons & MOUSE_CENTERBUTTON) !=
(mouse_prev_buttons & MOUSE_CENTERBUTTON)) {
if (mouse_buttons & MOUSE_CENTERBUTTON)
push_button_event(EVENT_ACTION_PRESSED, MOUSE_CENTERBUTTON);
else
push_button_event(EVENT_ACTION_RELEASED, MOUSE_CENTERBUTTON);
}
}
}
}
#pragma on (check_stack)

View file

@ -3,6 +3,8 @@
#include "dglcmn.h"
typedef byte MOUSE_BUTTON;
#define MOUSE_LEFTBUTTON 0x01
#define MOUSE_RIGHTBUTTON 0x02
#define MOUSE_CENTERBUTTON 0x04

View file

@ -9,6 +9,7 @@ object_files = &
dgl.obj &
dgldraw.obj &
dgldrawa.obj &
dglevent.obj &
dglgfx.obj &
dglpal.obj &
dglkbrd.obj &

73
TEST/EVENTS.C Normal file
View file

@ -0,0 +1,73 @@
#include "events.h"
#include "dgl.h"
#include <stdio.h>
#include "helpers.h"
void test_events(void) {
boolean result;
INPUTEVENT *event;
clrscr(0);
delay(500);
result = keyboard_init();
ASSERT(result == TRUE);
result = mouse_init();
ASSERT(result == TRUE);
ASSERT(events_is_initialized() == FALSE);
result = events_init();
ASSERT(result == TRUE);
ASSERT(events_is_initialized() == TRUE);
printf("Displaying events:\n\n");
while (!keys[1]) {
if (!events_poll(&event))
continue;
switch (event->type) {
case EVENT_TYPE_KEYBOARD:
printf("KEYBOARD: %2d - %d\n",
event->keyboard.key,
event->keyboard.action);
break;
case EVENT_TYPE_MOUSE_MOTION:
printf("MOUSE MOTION: %3d, %3d (%3d, %3d), %d\n",
event->mouse_motion.x,
event->mouse_motion.y,
event->mouse_motion.x_delta,
event->mouse_motion.y_delta,
event->mouse_motion.buttons);
break;
case EVENT_TYPE_MOUSE_BUTTON:
printf("MOUSE BUTTON: %3d, %3d, %d - %d\n",
event->mouse_button.x,
event->mouse_button.y,
event->mouse_button.button,
event->mouse_button.action);
break;
default:
printf("** UNKNOWN: %d **\n", event->type);
break;
}
}
result = events_shutdown();
ASSERT(result == TRUE);
ASSERT(events_is_initialized() == FALSE);
result = mouse_shutdown();
ASSERT(result == TRUE);
result = keyboard_shutdown();
ASSERT(result == TRUE);
printf("\nPress a key to continue...\n");
getch();
}

5
TEST/EVENTS.H Normal file
View file

@ -0,0 +1,5 @@
#ifndef DGL_TEST_EVENTS_H_INCLUDED
#define DGL_TEST_EVENTS_H_INCLUDED
#endif

View file

@ -3,6 +3,7 @@ target_config = debug
target_name = test
object_files = blit.obj &
events.obj &
fixed.obj &
helpers.obj &
kbrd.obj &

View file

@ -4,6 +4,7 @@
#include "helpers.h"
#include "blit.h"
#include "events.h"
#include "fixed.h"
#include "kbrd.h"
#include "line.h"
@ -43,6 +44,7 @@ int main(void) {
test_keyboard();
test_mouse();
test_events();
test_fixed();
test_vector2i();
test_vector2f();