2017-12-10 20:40:37 +00:00
|
|
|
#include "api.h"
|
2016-11-19 09:28:01 +00:00
|
|
|
#include "event/event.h"
|
2019-06-21 05:21:31 +00:00
|
|
|
#include "thread/thread.h"
|
2019-12-14 03:36:46 +00:00
|
|
|
#include "core/os.h"
|
2019-06-02 07:20:10 +00:00
|
|
|
#include "core/ref.h"
|
2019-12-10 21:01:28 +00:00
|
|
|
#include "core/util.h"
|
2019-05-14 11:37:56 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2016-11-29 06:59:27 +00:00
|
|
|
|
2020-09-28 00:13:00 +00:00
|
|
|
StringEntry lovrEventType[] = {
|
2020-02-17 02:31:02 +00:00
|
|
|
[EVENT_QUIT] = ENTRY("quit"),
|
2020-04-16 03:59:39 +00:00
|
|
|
[EVENT_RESTART] = ENTRY("restart"),
|
2020-02-17 02:31:02 +00:00
|
|
|
[EVENT_FOCUS] = ENTRY("focus"),
|
2020-05-02 19:05:21 +00:00
|
|
|
[EVENT_RESIZE] = ENTRY("resize"),
|
2020-08-03 08:00:47 +00:00
|
|
|
[EVENT_KEYPRESSED] = ENTRY("keypressed"),
|
|
|
|
[EVENT_KEYRELEASED] = ENTRY("keyreleased"),
|
2020-08-07 21:17:19 +00:00
|
|
|
[EVENT_TEXTINPUT] = ENTRY("textinput"),
|
2021-02-07 23:45:03 +00:00
|
|
|
#ifndef LOVR_DISABLE_THREAD
|
2020-02-17 02:31:02 +00:00
|
|
|
[EVENT_THREAD_ERROR] = ENTRY("threaderror"),
|
2019-07-10 23:20:43 +00:00
|
|
|
#endif
|
2020-02-17 02:31:02 +00:00
|
|
|
{ 0 }
|
2018-07-05 03:11:52 +00:00
|
|
|
};
|
2017-03-11 11:08:07 +00:00
|
|
|
|
2020-10-25 19:11:46 +00:00
|
|
|
StringEntry lovrKeyboardKey[] = {
|
2020-08-03 08:00:47 +00:00
|
|
|
[KEY_A] = ENTRY("a"),
|
2020-08-08 22:04:20 +00:00
|
|
|
[KEY_B] = ENTRY("b"),
|
|
|
|
[KEY_C] = ENTRY("c"),
|
2020-08-03 08:00:47 +00:00
|
|
|
[KEY_D] = ENTRY("d"),
|
|
|
|
[KEY_E] = ENTRY("e"),
|
2020-08-08 22:04:20 +00:00
|
|
|
[KEY_F] = ENTRY("f"),
|
|
|
|
[KEY_G] = ENTRY("g"),
|
|
|
|
[KEY_H] = ENTRY("h"),
|
|
|
|
[KEY_I] = ENTRY("i"),
|
|
|
|
[KEY_J] = ENTRY("j"),
|
|
|
|
[KEY_K] = ENTRY("k"),
|
|
|
|
[KEY_L] = ENTRY("l"),
|
|
|
|
[KEY_M] = ENTRY("m"),
|
|
|
|
[KEY_N] = ENTRY("n"),
|
|
|
|
[KEY_O] = ENTRY("o"),
|
|
|
|
[KEY_P] = ENTRY("p"),
|
|
|
|
[KEY_Q] = ENTRY("q"),
|
|
|
|
[KEY_R] = ENTRY("r"),
|
|
|
|
[KEY_S] = ENTRY("s"),
|
|
|
|
[KEY_T] = ENTRY("t"),
|
|
|
|
[KEY_U] = ENTRY("u"),
|
|
|
|
[KEY_V] = ENTRY("v"),
|
|
|
|
[KEY_W] = ENTRY("w"),
|
|
|
|
[KEY_X] = ENTRY("x"),
|
|
|
|
[KEY_Y] = ENTRY("y"),
|
|
|
|
[KEY_Z] = ENTRY("z"),
|
|
|
|
[KEY_0] = ENTRY("0"),
|
|
|
|
[KEY_1] = ENTRY("1"),
|
|
|
|
[KEY_2] = ENTRY("2"),
|
|
|
|
[KEY_3] = ENTRY("3"),
|
|
|
|
[KEY_4] = ENTRY("4"),
|
|
|
|
[KEY_5] = ENTRY("5"),
|
|
|
|
[KEY_6] = ENTRY("6"),
|
|
|
|
[KEY_7] = ENTRY("7"),
|
|
|
|
[KEY_8] = ENTRY("8"),
|
|
|
|
[KEY_9] = ENTRY("9"),
|
|
|
|
[KEY_SPACE] = ENTRY("space"),
|
|
|
|
[KEY_ENTER] = ENTRY("return"),
|
|
|
|
[KEY_TAB] = ENTRY("tab"),
|
|
|
|
[KEY_ESCAPE] = ENTRY("escape"),
|
|
|
|
[KEY_BACKSPACE] = ENTRY("backspace"),
|
2020-08-03 08:00:47 +00:00
|
|
|
[KEY_UP] = ENTRY("up"),
|
|
|
|
[KEY_DOWN] = ENTRY("down"),
|
|
|
|
[KEY_LEFT] = ENTRY("left"),
|
|
|
|
[KEY_RIGHT] = ENTRY("right"),
|
2020-08-08 22:04:20 +00:00
|
|
|
[KEY_HOME] = ENTRY("home"),
|
|
|
|
[KEY_END] = ENTRY("end"),
|
|
|
|
[KEY_PAGE_UP] = ENTRY("pageup"),
|
|
|
|
[KEY_PAGE_DOWN] = ENTRY("pagedown"),
|
|
|
|
[KEY_INSERT] = ENTRY("insert"),
|
|
|
|
[KEY_DELETE] = ENTRY("delete"),
|
|
|
|
[KEY_F1] = ENTRY("f1"),
|
|
|
|
[KEY_F2] = ENTRY("f2"),
|
|
|
|
[KEY_F3] = ENTRY("f3"),
|
|
|
|
[KEY_F4] = ENTRY("f4"),
|
|
|
|
[KEY_F5] = ENTRY("f5"),
|
|
|
|
[KEY_F6] = ENTRY("f6"),
|
|
|
|
[KEY_F7] = ENTRY("f7"),
|
|
|
|
[KEY_F8] = ENTRY("f8"),
|
|
|
|
[KEY_F9] = ENTRY("f9"),
|
|
|
|
[KEY_F10] = ENTRY("f10"),
|
|
|
|
[KEY_F11] = ENTRY("f11"),
|
|
|
|
[KEY_F12] = ENTRY("f12"),
|
|
|
|
[KEY_BACKTICK] = ENTRY("`"),
|
|
|
|
[KEY_MINUS] = ENTRY("-"),
|
|
|
|
[KEY_EQUALS] = ENTRY("="),
|
|
|
|
[KEY_LEFT_BRACKET] = ENTRY("["),
|
|
|
|
[KEY_RIGHT_BRACKET] = ENTRY("]"),
|
|
|
|
[KEY_BACKSLASH] = ENTRY("\\"),
|
|
|
|
[KEY_SEMICOLON] = ENTRY(";"),
|
|
|
|
[KEY_APOSTROPHE] = ENTRY("'"),
|
|
|
|
[KEY_COMMA] = ENTRY(","),
|
|
|
|
[KEY_PERIOD] = ENTRY("."),
|
|
|
|
[KEY_SLASH] = ENTRY("/"),
|
|
|
|
[KEY_LEFT_CONTROL] = ENTRY("lctrl"),
|
2020-08-29 21:27:00 +00:00
|
|
|
[KEY_LEFT_SHIFT] = ENTRY("lshift"),
|
2020-08-08 22:04:20 +00:00
|
|
|
[KEY_LEFT_ALT] = ENTRY("lalt"),
|
2020-08-19 20:03:06 +00:00
|
|
|
[KEY_LEFT_OS] = ENTRY("lgui"),
|
2020-08-29 21:27:00 +00:00
|
|
|
[KEY_RIGHT_CONTROL] = ENTRY("rctrl"),
|
|
|
|
[KEY_RIGHT_SHIFT] = ENTRY("rshift"),
|
|
|
|
[KEY_RIGHT_ALT] = ENTRY("ralt"),
|
2020-08-19 20:03:06 +00:00
|
|
|
[KEY_RIGHT_OS] = ENTRY("rgui"),
|
2020-08-08 22:04:20 +00:00
|
|
|
[KEY_CAPS_LOCK] = ENTRY("capslock"),
|
|
|
|
[KEY_SCROLL_LOCK] = ENTRY("scrolllock"),
|
|
|
|
[KEY_NUM_LOCK] = ENTRY("numlock"),
|
|
|
|
{ 0 }
|
2020-08-03 08:00:47 +00:00
|
|
|
};
|
|
|
|
|
2019-05-20 11:05:39 +00:00
|
|
|
static LOVR_THREAD_LOCAL int pollRef;
|
2017-01-18 06:11:17 +00:00
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
void luax_checkvariant(lua_State* L, int index, Variant* variant) {
|
|
|
|
int type = lua_type(L, index);
|
|
|
|
switch (type) {
|
|
|
|
case LUA_TNIL:
|
2020-02-26 22:40:40 +00:00
|
|
|
case LUA_TNONE:
|
2018-07-26 21:02:54 +00:00
|
|
|
variant->type = TYPE_NIL;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TBOOLEAN:
|
|
|
|
variant->type = TYPE_BOOLEAN;
|
|
|
|
variant->value.boolean = lua_toboolean(L, index);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TNUMBER:
|
|
|
|
variant->type = TYPE_NUMBER;
|
|
|
|
variant->value.number = lua_tonumber(L, index);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TSTRING:
|
|
|
|
variant->type = TYPE_STRING;
|
|
|
|
size_t length;
|
|
|
|
const char* string = lua_tolstring(L, index, &length);
|
2019-01-29 10:49:09 +00:00
|
|
|
variant->value.string = malloc(length + 1);
|
|
|
|
lovrAssert(variant->value.string, "Out of memory");
|
2018-10-23 18:11:47 +00:00
|
|
|
memcpy(variant->value.string, string, length);
|
2019-01-29 10:49:09 +00:00
|
|
|
variant->value.string[length] = '\0';
|
2018-07-26 21:02:54 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case LUA_TUSERDATA:
|
|
|
|
variant->type = TYPE_OBJECT;
|
2019-06-02 07:20:10 +00:00
|
|
|
Proxy* proxy = lua_touserdata(L, index);
|
|
|
|
lua_getmetatable(L, index);
|
|
|
|
|
|
|
|
lua_pushliteral(L, "__name");
|
|
|
|
lua_rawget(L, -2);
|
|
|
|
variant->value.object.type = (const char*) lua_touserdata(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
lua_pushliteral(L, "__destructor");
|
|
|
|
lua_rawget(L, -2);
|
2019-08-21 21:37:22 +00:00
|
|
|
variant->value.object.destructor = (void (*)(void*)) lua_tocfunction(L, -1);
|
2019-06-02 07:20:10 +00:00
|
|
|
lua_pop(L, 1);
|
|
|
|
|
|
|
|
variant->value.object.pointer = proxy->object;
|
|
|
|
lovrRetain(proxy->object);
|
2019-10-22 23:42:10 +00:00
|
|
|
lua_pop(L, 1);
|
2018-07-26 21:02:54 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2019-12-13 23:50:10 +00:00
|
|
|
lovrThrow("Bad variant type for argument %d: %s", index, lua_typename(L, type));
|
2018-07-26 21:02:54 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int luax_pushvariant(lua_State* L, Variant* variant) {
|
|
|
|
switch (variant->type) {
|
|
|
|
case TYPE_NIL: lua_pushnil(L); return 1;
|
|
|
|
case TYPE_BOOLEAN: lua_pushboolean(L, variant->value.boolean); return 1;
|
|
|
|
case TYPE_NUMBER: lua_pushnumber(L, variant->value.number); return 1;
|
2019-01-13 04:50:43 +00:00
|
|
|
case TYPE_STRING: lua_pushstring(L, variant->value.string); return 1;
|
2019-09-07 22:07:07 +00:00
|
|
|
case TYPE_OBJECT: _luax_pushtype(L, variant->value.object.type, hash64(variant->value.object.type, strlen(variant->value.object.type)), variant->value.object.pointer); return 1;
|
2019-02-17 07:43:20 +00:00
|
|
|
default: return 0;
|
2018-07-26 21:02:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-29 06:59:27 +00:00
|
|
|
static int nextEvent(lua_State* L) {
|
2017-05-17 06:03:42 +00:00
|
|
|
Event event;
|
2016-11-29 06:59:27 +00:00
|
|
|
|
2017-05-17 06:03:42 +00:00
|
|
|
if (!lovrEventPoll(&event)) {
|
2016-11-29 06:59:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
if (event.type == EVENT_CUSTOM) {
|
|
|
|
lua_pushstring(L, event.data.custom.name);
|
|
|
|
} else {
|
2020-09-28 00:13:00 +00:00
|
|
|
luax_pushenum(L, EventType, event.type);
|
2018-07-26 21:02:54 +00:00
|
|
|
}
|
2018-02-26 00:40:48 +00:00
|
|
|
|
2017-05-17 06:03:42 +00:00
|
|
|
switch (event.type) {
|
2018-02-26 00:40:48 +00:00
|
|
|
case EVENT_QUIT:
|
2020-04-16 03:59:39 +00:00
|
|
|
lua_pushnumber(L, event.data.quit.exitCode);
|
|
|
|
return 2;
|
2016-11-29 06:59:27 +00:00
|
|
|
|
2018-02-26 00:40:48 +00:00
|
|
|
case EVENT_FOCUS:
|
2018-07-26 20:40:15 +00:00
|
|
|
lua_pushboolean(L, event.data.boolean.value);
|
2018-02-26 00:40:48 +00:00
|
|
|
return 2;
|
|
|
|
|
2020-05-02 19:05:21 +00:00
|
|
|
case EVENT_RESIZE:
|
|
|
|
lua_pushinteger(L, event.data.resize.width);
|
|
|
|
lua_pushinteger(L, event.data.resize.height);
|
|
|
|
return 3;
|
|
|
|
|
2020-08-03 08:00:47 +00:00
|
|
|
case EVENT_KEYPRESSED:
|
2020-10-25 19:11:46 +00:00
|
|
|
luax_pushenum(L, KeyboardKey, event.data.key.code);
|
2020-08-07 20:15:45 +00:00
|
|
|
lua_pushinteger(L, event.data.key.scancode);
|
|
|
|
lua_pushboolean(L, event.data.key.repeat);
|
|
|
|
return 4;
|
|
|
|
|
2020-08-03 08:00:47 +00:00
|
|
|
case EVENT_KEYRELEASED:
|
2020-10-25 19:11:46 +00:00
|
|
|
luax_pushenum(L, KeyboardKey, event.data.key.code);
|
2020-08-07 20:15:45 +00:00
|
|
|
lua_pushinteger(L, event.data.key.scancode);
|
|
|
|
return 3;
|
2020-08-03 08:00:47 +00:00
|
|
|
|
2020-08-07 21:17:19 +00:00
|
|
|
case EVENT_TEXTINPUT:
|
2020-08-07 22:25:56 +00:00
|
|
|
lua_pushlstring(L, event.data.text.utf8, strnlen(event.data.text.utf8, 4));
|
2020-08-07 21:17:19 +00:00
|
|
|
lua_pushinteger(L, event.data.text.codepoint);
|
2020-08-07 22:25:56 +00:00
|
|
|
return 3;
|
2020-08-07 21:17:19 +00:00
|
|
|
|
2021-02-07 23:45:03 +00:00
|
|
|
#ifndef LOVR_DISABLE_THREAD
|
2018-02-26 00:40:48 +00:00
|
|
|
case EVENT_THREAD_ERROR:
|
2019-06-02 07:20:10 +00:00
|
|
|
luax_pushtype(L, Thread, event.data.thread.thread);
|
2018-07-26 20:40:15 +00:00
|
|
|
lua_pushstring(L, event.data.thread.error);
|
2019-06-21 05:21:31 +00:00
|
|
|
lovrRelease(Thread, event.data.thread.thread);
|
2018-02-17 17:49:24 +00:00
|
|
|
return 3;
|
2019-07-10 23:20:43 +00:00
|
|
|
#endif
|
2018-02-17 17:49:24 +00:00
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
case EVENT_CUSTOM:
|
2019-05-14 11:37:56 +00:00
|
|
|
for (uint32_t i = 0; i < event.data.custom.count; i++) {
|
2019-01-13 04:50:43 +00:00
|
|
|
Variant* variant = &event.data.custom.data[i];
|
|
|
|
luax_pushvariant(L, variant);
|
|
|
|
lovrVariantDestroy(variant);
|
2018-07-26 21:02:54 +00:00
|
|
|
}
|
|
|
|
return event.data.custom.count + 1;
|
|
|
|
|
2016-11-29 06:59:27 +00:00
|
|
|
default:
|
2018-02-26 00:40:48 +00:00
|
|
|
return 1;
|
2016-11-29 06:59:27 +00:00
|
|
|
}
|
|
|
|
}
|
2016-08-10 06:28:17 +00:00
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventClear(lua_State* L) {
|
2016-11-29 06:59:27 +00:00
|
|
|
lovrEventClear();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventPoll(lua_State* L) {
|
2017-01-18 06:11:17 +00:00
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, pollRef);
|
2016-11-29 06:59:27 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventPump(lua_State* L) {
|
2016-11-29 06:59:27 +00:00
|
|
|
lovrEventPump();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventPush(lua_State* L) {
|
2018-07-26 21:02:54 +00:00
|
|
|
CustomEvent eventData;
|
|
|
|
const char* name = luaL_checkstring(L, 1);
|
|
|
|
strncpy(eventData.name, name, MAX_EVENT_NAME_LENGTH - 1);
|
|
|
|
eventData.count = MIN(lua_gettop(L) - 1, 4);
|
2019-05-14 11:37:56 +00:00
|
|
|
for (uint32_t i = 0; i < eventData.count; i++) {
|
2018-07-26 21:02:54 +00:00
|
|
|
luax_checkvariant(L, 2 + i, &eventData.data[i]);
|
2016-11-29 06:59:27 +00:00
|
|
|
}
|
|
|
|
|
2018-07-26 21:02:54 +00:00
|
|
|
lovrEventPush((Event) { .type = EVENT_CUSTOM, .data.custom = eventData });
|
2016-08-10 06:28:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static int l_lovrEventQuit(lua_State* L) {
|
2020-10-26 08:30:56 +00:00
|
|
|
int exitCode = luaL_optinteger(L, 1, 0);
|
2020-10-27 07:40:08 +00:00
|
|
|
Event event = { .type = EVENT_QUIT, .data.quit.exitCode = exitCode };
|
2018-01-26 02:32:16 +00:00
|
|
|
lovrEventPush(event);
|
2018-01-27 03:01:20 +00:00
|
|
|
return 0;
|
2016-08-10 06:28:17 +00:00
|
|
|
}
|
2017-03-11 11:08:07 +00:00
|
|
|
|
2020-02-26 22:40:40 +00:00
|
|
|
static int l_lovrEventRestart(lua_State* L) {
|
2020-10-26 08:30:56 +00:00
|
|
|
Event event = { .type = EVENT_RESTART };
|
2020-02-26 22:40:40 +00:00
|
|
|
lovrEventPush(event);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
static const luaL_Reg lovrEvent[] = {
|
2017-03-11 11:08:07 +00:00
|
|
|
{ "clear", l_lovrEventClear },
|
|
|
|
{ "poll", l_lovrEventPoll },
|
|
|
|
{ "pump", l_lovrEventPump },
|
|
|
|
{ "push", l_lovrEventPush },
|
|
|
|
{ "quit", l_lovrEventQuit },
|
2020-02-26 22:40:40 +00:00
|
|
|
{ "restart", l_lovrEventRestart },
|
2017-03-11 11:08:07 +00:00
|
|
|
{ NULL, NULL }
|
|
|
|
};
|
2018-09-27 01:27:38 +00:00
|
|
|
|
2019-08-26 22:53:10 +00:00
|
|
|
int luaopen_lovr_event(lua_State* L) {
|
2018-09-27 01:27:38 +00:00
|
|
|
lua_newtable(L);
|
2020-08-19 19:12:06 +00:00
|
|
|
luax_register(L, lovrEvent);
|
2018-09-27 01:27:38 +00:00
|
|
|
|
|
|
|
// Store nextEvent in the registry to avoid creating a closure every time we poll for events.
|
|
|
|
lua_pushcfunction(L, nextEvent);
|
|
|
|
pollRef = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
|
2018-11-19 16:08:56 +00:00
|
|
|
if (lovrEventInit()) {
|
|
|
|
luax_atexit(L, lovrEventDestroy);
|
|
|
|
}
|
|
|
|
|
2018-09-27 01:27:38 +00:00
|
|
|
return 1;
|
|
|
|
}
|