#include #include #include #include #include "api.h" #ifdef _WIN32 #include #endif extern SDL_Window *window; static const char* button_name(int button) { switch (button) { case 1 : return "left"; case 2 : return "middle"; case 3 : return "right"; default : return "?"; } } static char* key_name(char *dst, int sym) { strcpy(dst, SDL_GetKeyName(sym)); char *p = dst; while (*p) { *p = tolower(*p); p++; } return dst; } static int f_poll_event(lua_State *L) { char buf[16]; SDL_Event e; top: if ( !SDL_PollEvent(&e) ) { return 0; } switch (e.type) { case SDL_QUIT: lua_pushstring(L, "quit"); return 1; case SDL_WINDOWEVENT: if (e.window.event == SDL_WINDOWEVENT_RESIZED) { lua_pushstring(L, "resized"); lua_pushnumber(L, e.window.data1); lua_pushnumber(L, e.window.data2); return 3; } else if (e.window.event == SDL_WINDOWEVENT_EXPOSED) { SDL_UpdateWindowSurface(window); } /* on some systems, when alt-tabbing to the window SDL will queue up ** several KEYDOWN events for the `tab` key; we flush all keydown ** events on focus so these are discarded */ if (e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) { SDL_FlushEvent(SDL_KEYDOWN); } goto top; case SDL_DROPFILE: lua_pushstring(L, "filedropped"); lua_pushstring(L, e.drop.file); SDL_free(e.drop.file); return 2; case SDL_KEYDOWN: lua_pushstring(L, "keypressed"); lua_pushstring(L, key_name(buf, e.key.keysym.sym)); return 2; case SDL_KEYUP: lua_pushstring(L, "keyreleased"); lua_pushstring(L, key_name(buf, e.key.keysym.sym)); return 2; case SDL_TEXTINPUT: lua_pushstring(L, "textinput"); lua_pushstring(L, e.text.text); return 2; case SDL_MOUSEBUTTONDOWN: if (e.button.button == 1) { SDL_CaptureMouse(1); } lua_pushstring(L, "mousepressed"); lua_pushstring(L, button_name(e.button.button)); lua_pushnumber(L, e.button.x); lua_pushnumber(L, e.button.y); lua_pushnumber(L, e.button.clicks); return 5; case SDL_MOUSEBUTTONUP: if (e.button.button == 1) { SDL_CaptureMouse(0); } lua_pushstring(L, "mousereleased"); lua_pushstring(L, button_name(e.button.button)); lua_pushnumber(L, e.button.x); lua_pushnumber(L, e.button.y); return 4; case SDL_MOUSEMOTION: lua_pushstring(L, "mousemoved"); lua_pushnumber(L, e.motion.x); lua_pushnumber(L, e.motion.y); lua_pushnumber(L, e.motion.xrel); lua_pushnumber(L, e.motion.yrel); return 5; case SDL_MOUSEWHEEL: lua_pushstring(L, "mousewheel"); lua_pushnumber(L, e.wheel.y); return 2; default: goto top; } return 0; } static SDL_Cursor* cursor_cache[SDL_SYSTEM_CURSOR_HAND + 1]; static const char *cursor_opts[] = { "arrow", "ibeam", "sizeh", "sizev", "hand", NULL }; static const int cursor_enums[] = { SDL_SYSTEM_CURSOR_ARROW, SDL_SYSTEM_CURSOR_IBEAM, SDL_SYSTEM_CURSOR_SIZEWE, SDL_SYSTEM_CURSOR_SIZENS, SDL_SYSTEM_CURSOR_HAND }; static int f_set_cursor(lua_State *L) { int opt = luaL_checkoption(L, 1, "arrow", cursor_opts); int n = cursor_enums[opt]; SDL_Cursor *cursor = cursor_cache[n]; if (!cursor) { cursor = SDL_CreateSystemCursor(n); cursor_cache[n] = cursor; } SDL_SetCursor(cursor); return 0; } static int f_set_window_title(lua_State *L) { const char *title = luaL_checkstring(L, 1); SDL_SetWindowTitle(window, title); return 0; } static int f_window_has_focus(lua_State *L) { unsigned flags = SDL_GetWindowFlags(window); lua_pushboolean(L, flags & SDL_WINDOW_INPUT_FOCUS); return 1; } static int f_show_confirm_dialog(lua_State *L) { const char *title = luaL_checkstring(L, 1); const char *msg = luaL_checkstring(L, 2); #if _WIN32 int id = MessageBox(0, msg, title, MB_YESNO | MB_ICONWARNING); lua_pushboolean(L, id == IDYES); #else SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Yes" }, { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 0, "No" }, }; SDL_MessageBoxData data = { .title = title, .message = msg, .numbuttons = 2, .buttons = buttons, }; int buttonid; SDL_ShowMessageBox(&data, &buttonid); lua_pushboolean(L, buttonid == 1); #endif return 1; } static int f_list_dir(lua_State *L) { const char *path = luaL_checkstring(L, 1); DIR *dir = opendir(path); if (!dir) { luaL_error(L, "could not open directory: %s", path); } lua_newtable(L); int i = 1; struct dirent *entry; while ( (entry = readdir(dir)) ) { if (strcmp(entry->d_name, "." ) == 0) { continue; } if (strcmp(entry->d_name, "..") == 0) { continue; } lua_pushstring(L, entry->d_name); lua_rawseti(L, -2, i); i++; } closedir(dir); return 1; } #ifdef _WIN32 #include #define realpath(x, y) _fullpath(y, x, MAX_PATH) #endif static int f_absolute_path(lua_State *L) { const char *path = luaL_checkstring(L, 1); char *res = realpath(path, NULL); if (!res) { return 0; } lua_pushstring(L, res); free(res); return 1; } static int f_get_file_info(lua_State *L) { const char *path = luaL_checkstring(L, 1); struct stat s; int err = stat(path, &s); if (err < 0) { return 0; } lua_newtable(L); lua_pushnumber(L, s.st_mtime); lua_setfield(L, -2, "modified"); lua_pushnumber(L, s.st_size); lua_setfield(L, -2, "size"); if (S_ISREG(s.st_mode)) { lua_pushstring(L, "file"); } else if (S_ISDIR(s.st_mode)) { lua_pushstring(L, "dir"); } else { lua_pushnil(L); } lua_setfield(L, -2, "type"); return 1; } static int f_get_clipboard(lua_State *L) { char *text = SDL_GetClipboardText(); if (!text) { return 0; } lua_pushstring(L, text); SDL_free(text); return 1; } static int f_set_clipboard(lua_State *L) { const char *text = luaL_checkstring(L, 1); SDL_SetClipboardText(text); return 0; } static int f_get_time(lua_State *L) { double n = SDL_GetPerformanceCounter() / (double) SDL_GetPerformanceFrequency(); lua_pushnumber(L, n); return 1; } static int f_sleep(lua_State *L) { double n = luaL_checknumber(L, 1); SDL_Delay(n * 1000); return 0; } static int f_fuzzy_match(lua_State *L) { const char *str = luaL_checkstring(L, 1); const char *ptn = luaL_checkstring(L, 2); int score = 0; int run = 0; while (*str && *ptn) { while (*str == ' ') { str++; } while (*ptn == ' ') { ptn++; } if (tolower(*str) == tolower(*ptn)) { score += run; run++; ptn++; } else { score--; run = 0; } str++; } if (*ptn) { return 0; } lua_pushnumber(L, score - (int) strlen(str)); return 1; } static const luaL_Reg lib[] = { { "poll_event", f_poll_event }, { "set_cursor", f_set_cursor }, { "set_window_title", f_set_window_title }, { "window_has_focus", f_window_has_focus }, { "show_confirm_dialog", f_show_confirm_dialog }, { "list_dir", f_list_dir }, { "absolute_path", f_absolute_path }, { "get_file_info", f_get_file_info }, { "get_clipboard", f_get_clipboard }, { "set_clipboard", f_set_clipboard }, { "get_time", f_get_time }, { "sleep", f_sleep }, { "fuzzy_match", f_fuzzy_match }, { NULL, NULL } }; int luaopen_system(lua_State *L) { luaL_newlib(L, lib); return 1; }