diff --git a/DGL.C b/DGL.C index 7c38fea..16b5318 100644 --- a/DGL.C +++ b/DGL.C @@ -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(); diff --git a/DGL.H b/DGL.H index 262d82c..3a1bfc1 100644 --- a/DGL.H +++ b/DGL.H @@ -18,6 +18,7 @@ #include "dglmtx33.h" #include "dglutil.h" #include "dglpcx.h" +#include "dglevent.h" void dgl_init(void); diff --git a/DGLERROR.H b/DGLERROR.H index c6bd353..01545ba 100644 --- a/DGLERROR.H +++ b/DGLERROR.H @@ -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; diff --git a/DGLEVENT.C b/DGLEVENT.C new file mode 100644 index 0000000..d23f9ea --- /dev/null +++ b/DGLEVENT.C @@ -0,0 +1,69 @@ +#include "dglevent.h" +#include "dglerror.h" +#include "dglutil.h" +#include + +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(); +} + diff --git a/DGLEVENT.H b/DGLEVENT.H new file mode 100644 index 0000000..4b6a19c --- /dev/null +++ b/DGLEVENT.H @@ -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 + diff --git a/DGLKBRD.C b/DGLKBRD.C index 82db172..e327078 100644 --- a/DGLKBRD.C +++ b/DGLKBRD.C @@ -1,4 +1,5 @@ #include "dglkbrd.h" +#include "dglevent.h" #include "dglutil.h" #include "dglerror.h" #include @@ -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 { - keys[(int)_key_scan] = 1; + 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; diff --git a/DGLMOUSE.C b/DGLMOUSE.C index a5f34b9..4ca5ce6 100644 --- a/DGLMOUSE.C +++ b/DGLMOUSE.C @@ -1,4 +1,5 @@ #include "dglmouse.h" +#include "dglevent.h" #include "dglerror.h" #include #include @@ -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, ®s, ®s); 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) diff --git a/DGLMOUSE.H b/DGLMOUSE.H index bcc7399..a5cc1c8 100644 --- a/DGLMOUSE.H +++ b/DGLMOUSE.H @@ -3,6 +3,8 @@ #include "dglcmn.h" +typedef byte MOUSE_BUTTON; + #define MOUSE_LEFTBUTTON 0x01 #define MOUSE_RIGHTBUTTON 0x02 #define MOUSE_CENTERBUTTON 0x04 diff --git a/MAKEFILE b/MAKEFILE index edb3f2e..0a0d4cd 100644 --- a/MAKEFILE +++ b/MAKEFILE @@ -9,6 +9,7 @@ object_files = & dgl.obj & dgldraw.obj & dgldrawa.obj & + dglevent.obj & dglgfx.obj & dglpal.obj & dglkbrd.obj & diff --git a/TEST/EVENTS.C b/TEST/EVENTS.C new file mode 100644 index 0000000..f59a8ef --- /dev/null +++ b/TEST/EVENTS.C @@ -0,0 +1,73 @@ +#include "events.h" +#include "dgl.h" +#include +#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(); +} + diff --git a/TEST/EVENTS.H b/TEST/EVENTS.H new file mode 100644 index 0000000..66046bd --- /dev/null +++ b/TEST/EVENTS.H @@ -0,0 +1,5 @@ +#ifndef DGL_TEST_EVENTS_H_INCLUDED +#define DGL_TEST_EVENTS_H_INCLUDED + +#endif + diff --git a/TEST/MAKEFILE b/TEST/MAKEFILE index 4862194..d972697 100644 --- a/TEST/MAKEFILE +++ b/TEST/MAKEFILE @@ -3,6 +3,7 @@ target_config = debug target_name = test object_files = blit.obj & + events.obj & fixed.obj & helpers.obj & kbrd.obj & diff --git a/TEST/TEST.C b/TEST/TEST.C index e46cd04..7bed11a 100644 --- a/TEST/TEST.C +++ b/TEST/TEST.C @@ -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();