From a5c66d61549ad8d1544ac1447ab0c62723a5733c Mon Sep 17 00:00:00 2001 From: rxi Date: Sat, 15 Oct 2016 17:40:23 +0100 Subject: [PATCH] Added event.c/h and lua binding * Changed mouse.c to mimic keyboard.c * Changed boot.lua to use event.poll() instead of mouse/keyboard.poll() * Removed love.keyboard.poll() --- src/embed/boot.lua | 41 +++++++------- src/event.c | 76 ++++++++++++++++++++++++++ src/event.h | 44 +++++++++++++++ src/modules/l_event.c | 56 +++++++++++++++++++ src/modules/l_keyboard.c | 36 ------------- src/modules/l_love.c | 2 + src/modules/l_mouse.c | 58 ++------------------ src/mouse.c | 113 +++++++++++++++++++++++++++------------ src/mouse.h | 25 +++++---- 9 files changed, 302 insertions(+), 149 deletions(-) create mode 100644 src/event.c create mode 100644 src/event.h create mode 100644 src/modules/l_event.c diff --git a/src/embed/boot.lua b/src/embed/boot.lua index 1899e21..969a5d8 100644 --- a/src/embed/boot.lua +++ b/src/embed/boot.lua @@ -13,6 +13,23 @@ function love.boot() end end) + -- Init event handlers table + local t = { + "mousepressed", + "mousereleased", + "mousemoved", + "keypressed", + "keyreleased", + "textinput", + } + love.handlers = {} + for i, name in ipairs(t) do + love.handlers[name] = function(...) + local fn = love[name] + if fn then fn(...) end + end + end + -- Try to mount .exe file, then the first argument for i, v in ipairs { love.argv[1], love.argv[2] } do local mounted = love.filesystem.mount(v) @@ -48,25 +65,13 @@ function love.run() love.timer.step() while true do - -- Handle mouse events - for _, e in ipairs(love.mouse.poll()) do - if e.type == "motion" then - if love.mousemoved then love.mousemoved(e.x, e.y, e.dx, e.dy) end - elseif e.type == "pressed" then - if love.mousepressed then love.mousepressed(e.x, e.y, e.button) end - elseif e.type == "released" then - if love.mousereleased then love.mousereleased(e.x, e.y, e.button) end - end - end - -- Handle keyboard events - for _, e in ipairs(love.keyboard.poll()) do - if e.type == "down" then - if love.keypressed then love.keypressed(e.key, e.code, e.isrepeat) end - elseif e.type == "up" then - if love.keyreleased then love.keyreleased(e.key, e.code) end - elseif e.type == "text" then - if love.textinput then love.textinput(e.text) end + -- Handle events + while 1 do + local name, a,b,c,d = love.event.poll() + if not name then + break end + love.handlers[name](a, b, c, d) end -- Update love.timer.step() diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..0d2b2bb --- /dev/null +++ b/src/event.c @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2016 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "keyboard.h" +#include "mouse.h" +#include "event.h" + + +const char* event_typestr(int type) { + switch (type) { + case EVENT_KEYBOARD_PRESSED : return "keypressed"; + case EVENT_KEYBOARD_RELEASED : return "keyreleased"; + case EVENT_KEYBOARD_TEXTINPUT : return "textinput"; + case EVENT_MOUSE_MOVED : return "mousemoved"; + case EVENT_MOUSE_PRESSED : return "mousepressed"; + case EVENT_MOUSE_RELEASED : return "mousereleased"; + } + return "?"; +} + + +int event_poll(event_t *e) { + + /* Poll keyboard */ + keyboard_Event ke; + if (keyboard_poll(&ke)) { + if (ke.type == KEYBOARD_PRESSED || ke.type == KEYBOARD_RELEASED) { + if (ke.type == KEYBOARD_PRESSED) { + e->type = EVENT_KEYBOARD_PRESSED; + } else { + e->type = EVENT_KEYBOARD_RELEASED; + } + e->keyboard.key = ke.key; + e->keyboard.isrepeat = ke.isrepeat; + + } else if (ke.type == KEYBOARD_TEXTINPUT) { + e->type = EVENT_KEYBOARD_TEXTINPUT; + strcpy(e->keyboard.text, ke.text); + } + + return 1; + } + + /* Poll mouse */ + mouse_Event me; + if (mouse_poll(&me)) { + if (me.type == MOUSE_PRESSED || me.type == MOUSE_RELEASED) { + if (me.type == MOUSE_PRESSED) { + e->type = EVENT_MOUSE_PRESSED; + } else { + e->type = EVENT_MOUSE_RELEASED; + } + e->mouse.button = me.button; + e->mouse.x = me.x; + e->mouse.y = me.y; + e->mouse.dx = me.dx; + e->mouse.dy = me.dy; + + } else if (me.type == MOUSE_MOVED) { + e->type = EVENT_MOUSE_MOVED; + e->mouse.x = me.x; + e->mouse.y = me.y; + } + + return 1; + } + + /* No events */ + return 0; +} diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..a50ba6f --- /dev/null +++ b/src/event.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2016 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef EVENT_H +#define EVENT_H + +enum { + EVENT_NULL, + EVENT_KEYBOARD_PRESSED, + EVENT_KEYBOARD_RELEASED, + EVENT_KEYBOARD_TEXTINPUT, + EVENT_MOUSE_MOVED, + EVENT_MOUSE_PRESSED, + EVENT_MOUSE_RELEASED +}; + +typedef union { + int type; + + struct { + int type; + int x, y; + int dx, dy; + int button; + } mouse; + + struct { + int type; + const char *key; + char text[64]; + int isrepeat; + } keyboard; + +} event_t; + + +const char* event_typestr(int type); +int event_poll(event_t *e); + +#endif diff --git a/src/modules/l_event.c b/src/modules/l_event.c new file mode 100644 index 0000000..7f4c11a --- /dev/null +++ b/src/modules/l_event.c @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2016 rxi + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include "luaobj.h" +#include "event.h" + + +int l_event_poll(lua_State *L) { + event_t e; + if (event_poll(&e)) { + lua_pushstring(L, event_typestr(e.type)); + + switch(e.type) { + case EVENT_KEYBOARD_PRESSED: + case EVENT_KEYBOARD_RELEASED: + lua_pushstring(L, e.keyboard.key); + lua_pushstring(L, e.keyboard.key); + lua_pushboolean(L, e.keyboard.isrepeat); + return 4; + + case EVENT_KEYBOARD_TEXTINPUT: + lua_pushstring(L, e.keyboard.text); + return 2; + + case EVENT_MOUSE_MOVED: + lua_pushnumber(L, e.mouse.x); + lua_pushnumber(L, e.mouse.y); + lua_pushnumber(L, e.mouse.dx); + lua_pushnumber(L, e.mouse.dy); + return 5; + + case EVENT_MOUSE_PRESSED: + case EVENT_MOUSE_RELEASED: + lua_pushnumber(L, e.mouse.x); + lua_pushnumber(L, e.mouse.y); + lua_pushnumber(L, e.mouse.button); + return 4; + } + } + + return 0; +} + + +int luaopen_event(lua_State *L) { + luaL_Reg reg[] = { + { "poll", l_event_poll }, + { 0, 0 }, + }; + luaL_newlib(L, reg); + return 1; +} diff --git a/src/modules/l_keyboard.c b/src/modules/l_keyboard.c index ab512c0..dbf7ad6 100644 --- a/src/modules/l_keyboard.c +++ b/src/modules/l_keyboard.c @@ -29,44 +29,8 @@ int l_keyboard_isDown(lua_State *L) { } -int l_keyboard_poll(lua_State *L) { - lua_newtable(L); - keyboard_Event e; - int idx = 1; - - while (keyboard_poll(&e)) { - - if (e.type == KEYBOARD_PRESSED || e.type == KEYBOARD_RELEASED) { - lua_newtable(L); - lua_pushstring(L, e.type == KEYBOARD_PRESSED ? "down" : "up"); - lua_setfield(L, -2, "type"); - lua_pushnumber(L, e.code); - lua_setfield(L, -2, "code"); - lua_pushstring(L, e.key); - lua_setfield(L, -2, "key"); - if (e.type == KEYBOARD_PRESSED) { - lua_pushboolean(L, e.isrepeat); - lua_setfield(L, -2, "isrepeat"); - } - lua_rawseti(L, -2, idx++); - - } else if (e.type == KEYBOARD_TEXTINPUT) { - lua_newtable(L); - lua_pushstring(L, "text"); - lua_setfield(L, -2, "type"); - lua_pushstring(L, e.text); - lua_setfield(L, -2, "text"); - lua_rawseti(L, -2, idx++); - } - } - - return 1; -} - - int luaopen_keyboard(lua_State *L) { luaL_Reg reg[] = { - { "poll", l_keyboard_poll }, { "setKeyRepeat", l_keyboard_setKeyRepeat }, { "isDown", l_keyboard_isDown }, { 0, 0 }, diff --git a/src/modules/l_love.c b/src/modules/l_love.c index af31aa0..0d96bed 100644 --- a/src/modules/l_love.c +++ b/src/modules/l_love.c @@ -20,6 +20,7 @@ int luaopen_image(lua_State *L); int luaopen_quad(lua_State *L); int luaopen_font(lua_State *L); int luaopen_system(lua_State *L); +int luaopen_event(lua_State *L); int luaopen_filesystem(lua_State *L); int luaopen_graphics(lua_State *L); int luaopen_timer(lua_State *L); @@ -52,6 +53,7 @@ int luaopen_love(lua_State *L) { /* Init submodules */ struct { char *name; int (*fn)(lua_State *L); } mods[] = { { "system", luaopen_system }, + { "event", luaopen_event }, { "filesystem", luaopen_filesystem }, { "graphics", luaopen_graphics }, { "timer", luaopen_timer }, diff --git a/src/modules/l_mouse.c b/src/modules/l_mouse.c index b858417..32d411c 100644 --- a/src/modules/l_mouse.c +++ b/src/modules/l_mouse.c @@ -10,23 +10,20 @@ int l_mouse_getPosition(lua_State *L) { - mouse_State *state = mouse_getState(); - lua_pushinteger(L, state->x); - lua_pushinteger(L, state->y); + lua_pushinteger(L, mouse_getX()); + lua_pushinteger(L, mouse_getY()); return 2; } int l_mouse_getX(lua_State *L) { - mouse_State *state = mouse_getState(); - lua_pushinteger(L, state->x); + lua_pushinteger(L, mouse_getX()); return 1; } int l_mouse_getY(lua_State *L) { - mouse_State *state = mouse_getState(); - lua_pushinteger(L, state->y); + lua_pushinteger(L, mouse_getY()); return 1; } @@ -35,11 +32,10 @@ int l_mouse_isDown(lua_State *L) { int n = lua_gettop(L); int res = 0; int i; - mouse_State *state = mouse_getState(); for (i = 1; i <= n; i++) { int idx = luaL_checknumber(L, i) - 1; if (idx >= 0 && idx < MOUSE_BUTTON_MAX) { - res |= state->buttonsDown[idx]; + res |= mouse_isDown(idx); } } lua_pushboolean(L, res); @@ -47,53 +43,9 @@ int l_mouse_isDown(lua_State *L) { } -int l_mouse_poll(lua_State *L) { - mouse_update(); - mouse_State *state = mouse_getState(); - - int i; - int n = 1; - lua_newtable(L); - - /* Add motion event if mouse moved */ - if ( state->x != state->lastX || state->y != state->lastY ) { - lua_newtable(L); - lua_pushstring(L, "motion"); - lua_setfield(L, -2, "type"); - lua_pushinteger(L, state->x); - lua_setfield(L, -2, "x"); - lua_pushinteger(L, state->y); - lua_setfield(L, -2, "y"); - lua_pushinteger(L, state->x - state->lastX); - lua_setfield(L, -2, "dx"); - lua_pushinteger(L, state->y - state->lastY); - lua_setfield(L, -2, "dy"); - lua_rawseti(L, -2, n++); - } - - /* Add `pressed` and `released` events */ - for (i = 0; i < MOUSE_BUTTON_MAX; i++) { - if ( state->buttonsPressed[i] || state->buttonsReleased[i] ) { - lua_newtable(L); - lua_pushstring(L, state->buttonsPressed[i] ? "pressed" : "released"); - lua_setfield(L, -2, "type"); - lua_pushinteger(L, i + 1); - lua_setfield(L, -2, "button"); - lua_pushinteger(L, state->x); - lua_setfield(L, -2, "x"); - lua_pushinteger(L, state->y); - lua_setfield(L, -2, "y"); - lua_rawseti(L, -2, n++); - } - } - - return 1; -} - int luaopen_mouse(lua_State *L) { luaL_Reg reg[] = { - { "poll", l_mouse_poll }, { "getPosition", l_mouse_getPosition }, { "getX", l_mouse_getX }, { "getY", l_mouse_getY }, diff --git a/src/mouse.c b/src/mouse.c index 018b1c0..c317e62 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -11,60 +11,107 @@ #include "luaobj.h" #include "mouse.h" -mouse_State mouse_state; +#define BUFFER_SIZE 32 +#define BUFFER_MASK (BUFFER_SIZE - 1) + +int mouse_inited; +int mouse_x, mouse_y; +int mouse_lastX, mouse_lastY; +int mouse_buttonStates[MOUSE_BUTTON_MAX]; + +struct { + mouse_Event data[BUFFER_SIZE]; + int writei, readi; +} mouse_events; void mouse_init(void) { union REGS regs = {}; int86(0x33, ®s, ®s); - mouse_state.inited = regs.x.ax ? 1 : 0; + mouse_inited = regs.x.ax ? 1 : 0; } void mouse_update(void) { - if (!mouse_state.inited) { + if (!mouse_inited) { return; } - /* Update last mouse position */ - mouse_state.lastX = mouse_state.x; - mouse_state.lastY = mouse_state.y; - /* Update mouse position */ union REGS regs = {}; regs.x.ax = 3; int86(0x33, ®s, ®s); - mouse_state.x = regs.x.cx >> 1; - mouse_state.y = regs.x.dx; + mouse_x = regs.x.cx >> 1; + mouse_y = regs.x.dx; - /* Update button states */ - int i; + /* Do moved event if mouse moved */ + if (mouse_x != mouse_lastX || mouse_y != mouse_lastY) { + mouse_Event e; + e.type = MOUSE_MOVED; + e.x = mouse_x; + e.y = mouse_y; + e.dx = mouse_x - mouse_lastX; + e.dy = mouse_y - mouse_lastY; + mouse_events.data[mouse_events.writei++ & BUFFER_MASK] = e; + } + + /* Update last position */ + mouse_lastX = mouse_x; + mouse_lastY = mouse_y; + + /* Update button states and push pressed/released events */ + int i, t; for (i = 0; i < MOUSE_BUTTON_MAX; i++) { - /* Reset pressed/released */ - mouse_state.buttonsPressed[i] = 0; - mouse_state.buttonsReleased[i] = 0; - /* Handle mouse pressed */ - memset(®s, 0, sizeof(regs)); - regs.x.ax = 5; - regs.x.bx = i; - int86(0x33, ®s, ®s); - if (regs.x.bx) { - mouse_state.buttonsPressed[i] = 1; - mouse_state.buttonsDown[i] = 1; - } - /* Handle mouse released */ - memset(®s, 0, sizeof(regs)); - regs.x.ax = 6; - regs.x.bx = i; - int86(0x33, ®s, ®s); - if (regs.x.bx) { - mouse_state.buttonsReleased[i] = 1; - mouse_state.buttonsDown[i] = 0; + for (t = 0; t < 2; t++) { + memset(®s, 0, sizeof(regs)); + regs.x.ax = 5 + t; + regs.x.bx = i; + int86(0x33, ®s, ®s); + if (regs.x.bx) { + /* Push event */ + mouse_Event e; + e.type = t == 0 ? MOUSE_PRESSED : MOUSE_RELEASED; + e.button = i; + e.x = mouse_x; + e.y = mouse_y; + mouse_events.data[mouse_events.writei++ & BUFFER_MASK] = e; + /* Set state */ + mouse_buttonStates[i] = t == 0 ? 1 : 0; + } } } } -mouse_State* mouse_getState(void) { - return &mouse_state; +int mouse_poll(mouse_Event *e) { +retry: + /* Event in event buffer? Store and return */ + if (mouse_events.readi != mouse_events.writei) { + *e = mouse_events.data[mouse_events.readi++ & BUFFER_MASK]; + return 1; + } + + /* No events in buffer -- update; return `0` if no new events were pushed by + * the update */ + mouse_update(); + if (mouse_events.readi != mouse_events.writei) { + goto retry; + } + + return 0; +} + + +int mouse_isDown(int button) { + return mouse_buttonStates[button]; +} + + +int mouse_getX(void) { + return mouse_x; +} + + +int mouse_getY(void) { + return mouse_y; } diff --git a/src/mouse.h b/src/mouse.h index 4958065..6d8e9f9 100644 --- a/src/mouse.h +++ b/src/mouse.h @@ -5,20 +5,27 @@ enum { MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE, - MOUSE_BUTTON_MAX, + MOUSE_BUTTON_MAX +}; + +enum { + MOUSE_PRESSED, + MOUSE_RELEASED, + MOUSE_MOVED }; typedef struct { - int inited; + int type; int x, y; - int lastX, lastY; - int buttonsPressed[MOUSE_BUTTON_MAX]; - int buttonsReleased[MOUSE_BUTTON_MAX]; - int buttonsDown[MOUSE_BUTTON_MAX]; -} mouse_State; + int dx, dy; + int button; +} mouse_Event; + void mouse_init(void); -void mouse_update(void); -mouse_State* mouse_getState(void); +int mouse_poll(mouse_Event *e); +int mouse_isDown(int button); +int mouse_getX(void); +int mouse_getY(void); #endif