Initial commit
This commit is contained in:
@@ -0,0 +1,338 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <ctype.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include "api.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#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 <windows.h>
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user