add new events api, replaces legacy event functions

event.register(event.mousedown, function(...) print(...) end)
event.unregister(event.mousedown, somefunc)

mouseclick event split into mousedown, mouseup, mousemove, mousewheel
keypress event split into keypress, keyrelease, textinput. key* events only contain keycode and scancode, don't attempt to represent a letter (was very broken at this before). Also have helpful shift/ctrl/alt flags passed in. textinput just represents inserted text, can probably even handle foreign characters.
register_step replaced with event.tick event

All legacy register_* and unregister_ functions are removed. There is a compatibility lua script, might embed it later. tpt.set_shortcuts / tpt.test also removed. event.getmodifiers added, just a misc function to get the currently held modifiers

Lots of code duplication to handle each event is removed, it's not handled in a more generic way. Although the Event class / child classes could use some work.
This commit is contained in:
jacob1 2018-11-16 00:07:26 -05:00
parent fa0809d146
commit a8489ba6f5
13 changed files with 494 additions and 556 deletions

View File

@ -37,6 +37,7 @@
#else
#include "lua/TPTScriptInterface.h"
#endif
#include "lua/LuaEvents.h"
using namespace std;
@ -157,11 +158,6 @@ GameController::GameController():
commandInterface = new TPTScriptInterface(this, gameModel);
#endif
ActiveToolChanged(0, gameModel->GetActiveTool(0));
ActiveToolChanged(1, gameModel->GetActiveTool(1));
ActiveToolChanged(2, gameModel->GetActiveTool(2));
ActiveToolChanged(3, gameModel->GetActiveTool(3));
Client::Ref().AddListener(this);
debugInfo.push_back(new DebugParts(0x1, gameModel->GetSimulation()));
@ -626,12 +622,12 @@ void GameController::CutRegion(ui::Point point1, ui::Point point2, bool includeP
bool GameController::MouseMove(int x, int y, int dx, int dy)
{
return commandInterface->OnMouseMove(x, y, dx, dy);
return commandInterface->HandleEvent(EventTypes::mousemove, new MouseMoveEvent(x, y, dx, dy));
}
bool GameController::MouseDown(int x, int y, unsigned button)
{
bool ret = commandInterface->OnMouseDown(x, y, button);
bool ret = commandInterface->HandleEvent(EventTypes::mousedown, new MouseDownEvent(x, y, button));
if (ret && y<YRES && x<XRES && !gameView->GetPlacingSave() && !gameView->GetPlacingZoom())
{
ui::Point point = gameModel->AdjustZoomCoords(ui::Point(x, y));
@ -653,7 +649,7 @@ bool GameController::MouseDown(int x, int y, unsigned button)
bool GameController::MouseUp(int x, int y, unsigned button, char type)
{
bool ret = commandInterface->OnMouseUp(x, y, button, type);
bool ret = commandInterface->HandleEvent(EventTypes::mouseup, new MouseUpEvent(x, y, button, type));
if (type)
return ret;
if (ret && foundSignID != -1 && y<YRES && x<XRES && !gameView->GetPlacingSave())
@ -711,12 +707,17 @@ bool GameController::MouseUp(int x, int y, unsigned button, char type)
bool GameController::MouseWheel(int x, int y, int d)
{
return commandInterface->OnMouseWheel(x, y, d);
return commandInterface->HandleEvent(EventTypes::mousewheel, new MouseWheelEvent(x, y, d));
}
bool GameController::TextInput(String text)
{
return commandInterface->HandleEvent(EventTypes::textinput, new TextInputEvent(text));
}
bool GameController::KeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
{
bool ret = commandInterface->OnKeyPress(key, scan, repeat, shift, ctrl, alt);
bool ret = commandInterface->HandleEvent(EventTypes::keypress, new KeyEvent(key, scan, repeat, shift, ctrl, alt));
if (repeat)
return ret;
if (ret)
@ -795,7 +796,7 @@ bool GameController::KeyPress(int key, int scan, bool repeat, bool shift, bool c
bool GameController::KeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
{
bool ret = commandInterface->OnKeyRelease(key, scan, repeat, shift, ctrl, alt);
bool ret = commandInterface->HandleEvent(EventTypes::keyrelease, new KeyEvent(key, scan, repeat, shift, ctrl, alt));
if (repeat)
return ret;
if (ret)
@ -832,11 +833,6 @@ bool GameController::KeyRelease(int key, int scan, bool repeat, bool shift, bool
return ret;
}
bool GameController::MouseTick()
{
return commandInterface->OnMouseTick();
}
void GameController::Tick()
{
if(firstTick)
@ -1150,11 +1146,6 @@ void GameController::RebuildFavoritesMenu()
gameModel->BuildFavoritesMenu();
}
void GameController::ActiveToolChanged(int toolSelection, Tool *tool)
{
commandInterface->OnActiveToolChanged(toolSelection, tool);
}
Tool * GameController::GetActiveTool(int selection)
{
return gameModel->GetActiveTool(selection);

View File

@ -64,9 +64,9 @@ public:
bool MouseDown(int x, int y, unsigned button);
bool MouseUp(int x, int y, unsigned button, char type);
bool MouseWheel(int x, int y, int d);
bool TextInput(String text);
bool KeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
bool KeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
bool MouseTick();
void Tick();
void Exit();
@ -113,7 +113,6 @@ public:
void SetLastTool(Tool * tool);
int GetReplaceModeFlags();
void SetReplaceModeFlags(int flags);
void ActiveToolChanged(int toolSelection, Tool *tool);
void SetActiveColourPreset(int preset);
void SetColour(ui::Colour colour);
void SetToolStrength(float value);

View File

@ -709,8 +709,7 @@ void GameView::NotifyActiveToolsChanged(GameModel * sender)
toolButtons[i]->SetSelectionState(-1);
}
}
//need to do this for all tools every time just in case it wasn't caught if you weren't in the menu a tool was changed to
c->ActiveToolChanged(0, sender->GetActiveTool(0));
if (sender->GetRenderer()->findingElement)
{
Tool *active = sender->GetActiveTool(0);
@ -719,9 +718,6 @@ void GameView::NotifyActiveToolsChanged(GameModel * sender)
else
ren->findingElement = sender->GetActiveTool(0)->GetToolID()%256;
}
c->ActiveToolChanged(1, sender->GetActiveTool(1));
c->ActiveToolChanged(2, sender->GetActiveTool(2));
c->ActiveToolChanged(3, sender->GetActiveTool(3));
}
void GameView::NotifyLastToolChanged(GameModel * sender)
@ -1841,6 +1837,12 @@ void GameView::DoMouseWheel(int x, int y, int d)
Window::DoMouseWheel(x, y, d);
}
void GameView::DoTextInput(String text)
{
if (c->TextInput(text))
Window::DoTextInput(text);
}
void GameView::DoKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
{
if (c->KeyPress(key, scan, repeat, shift, ctrl, alt))
@ -1853,18 +1855,6 @@ void GameView::DoKeyRelease(int key, int scan, bool repeat, bool shift, bool ctr
Window::DoKeyRelease(key, scan, repeat, shift, ctrl, alt);
}
void GameView::DoTick(float dt)
{
//mouse events trigger every frame when mouse is held down, needs to happen here (before things are drawn) so it can clear the point queue if false is returned from a lua mouse event
if (!c->MouseTick())
{
isMouseDown = false;
selectMode = SelectNone;
drawMode = DrawPoints;
}
Window::DoTick(dt);
}
void GameView::DoDraw()
{
Window::DoDraw();

View File

@ -198,12 +198,12 @@ public:
virtual void OnBlur();
//Top-level handlers, for Lua interface
virtual void DoTick(float dt);
virtual void DoDraw();
virtual void DoMouseMove(int x, int y, int dx, int dy);
virtual void DoMouseDown(int x, int y, unsigned button);
virtual void DoMouseUp(int x, int y, unsigned button);
virtual void DoMouseWheel(int x, int y, int d);
virtual void DoTextInput(String text);
virtual void DoKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
virtual void DoKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);

View File

@ -2,13 +2,16 @@
#define COMMANDINTERFACE_H_
#include "common/String.h"
#include "lua/LuaEvents.h"
#include "gui/interface/Engine.h"
//#include "game/GameModel.h"
class Event;
class GameModel;
class GameController;
class Tool;
class CommandInterface {
class CommandInterface
{
protected:
String lastError;
GameModel * m;
@ -20,15 +23,11 @@ public:
int GetPropertyOffset(ByteString key, FormatType & format);
void Log(LogType type, String message);
//void AttachGameModel(GameModel * m);
virtual bool OnActiveToolChanged(int toolSelection, Tool * tool) {return true;}
virtual bool OnMouseMove(int x, int y, int dx, int dy) {return true;}
virtual bool OnMouseDown(int x, int y, unsigned button) {return true;}
virtual bool OnMouseUp(int x, int y, unsigned button, char type) {return true;}
virtual bool OnMouseWheel(int x, int y, int d) {return true;}
virtual bool OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) {return true;}
virtual bool OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) {return true;}
virtual bool OnMouseTick() { return true; }
virtual void OnTick() { }
virtual bool HandleEvent(EventTypes eventType, Event * event) { return true; }
virtual int Command(String command);
virtual String FormatCommand(String command);
String GetLastError();

View File

@ -243,164 +243,6 @@ int luacon_elementwrite(lua_State* l)
return 0;
}
bool shortcuts = true;
int luacon_keyevent(int key, int scan, int modifier, int event)
{
ui::Engine::Ref().LastTick(Platform::GetTime());
int kycontinue = 1;
lua_State* l=luacon_ci->l;
lua_pushstring(l, "keyfunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if(!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "keyfunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int len = lua_objlen(l, -1);
for (int i = 1; i <= len && kycontinue; i++)
{
lua_rawgeti(l, -1, i);
if ((modifier & KMOD_CTRL) && (scan < ' ' || scan > '~') && key < 256)
lua_pushlstring(l, (const char*)&key, 1);
else
lua_pushlstring(l, (const char*)&scan, 1);
lua_pushinteger(l, key);
lua_pushinteger(l, modifier);
lua_pushinteger(l, event);
int callret = lua_pcall(l, 4, 1, 0);
if (callret)
{
if (luacon_geterror() == "Error: Script not responding")
{
ui::Engine::Ref().LastTick(Platform::GetTime());
for (int j = i; j <= len-1; j++)
{
lua_rawgeti(l, -2, j+1);
lua_rawseti(l, -3, j);
}
lua_pushnil(l);
lua_rawseti(l, -3, len);
i--;
}
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
lua_pop(l, 1);
}
else
{
if(!lua_isnoneornil(l, -1))
kycontinue = lua_toboolean(l, -1);
lua_pop(l, 1);
}
len = lua_objlen(l, -1);
}
lua_pop(l, 1);
return kycontinue && shortcuts;
}
int luacon_mouseevent(int mx, int my, int mb, int event, int mouse_wheel)
{
ui::Engine::Ref().LastTick(Platform::GetTime());
int mpcontinue = 1;
lua_State* l=luacon_ci->l;
lua_pushstring(l, "mousefunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if(!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "mousefunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int len = lua_objlen(l, -1);
for (int i = 1; i <= len && mpcontinue; i++)
{
lua_rawgeti(l, -1, i);
lua_pushinteger(l, mx);
lua_pushinteger(l, my);
lua_pushinteger(l, mb);
lua_pushinteger(l, event);
lua_pushinteger(l, mouse_wheel);
int callret = lua_pcall(l, 5, 1, 0);
if (callret)
{
if (luacon_geterror() == "Error: Script not responding")
{
ui::Engine::Ref().LastTick(Platform::GetTime());
for (int j = i; j <= len-1; j++)
{
lua_rawgeti(l, -2, j+1);
lua_rawseti(l, -3, j);
}
lua_pushnil(l);
lua_rawseti(l, -3, len);
i--;
}
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
lua_pop(l, 1);
}
else
{
if(!lua_isnoneornil(l, -1))
mpcontinue = lua_toboolean(l, -1);
lua_pop(l, 1);
}
len = lua_objlen(l, -1);
}
lua_pop(l, 1);
return mpcontinue;
}
int luacon_step(int mx, int my)
{
ui::Engine::Ref().LastTick(Platform::GetTime());
lua_State* l = luacon_ci->l;
lua_pushinteger(l, my);
lua_pushinteger(l, mx);
lua_setfield(l, tptProperties, "mousex");
lua_setfield(l, tptProperties, "mousey");
lua_pushstring(l, "stepfunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "stepfunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int len = lua_objlen(l, -1);
for (int i = 1; i <= len; i++)
{
lua_rawgeti(l, -1, i);
int callret = lua_pcall(l, 0, 0, 0);
if (callret)
{
if (luacon_geterror() == "Error: Script not responding")
{
ui::Engine::Ref().LastTick(Platform::GetTime());
for (int j = i; j <= len-1; j++)
{
lua_rawgeti(l, -2, j+1);
lua_rawseti(l, -3, j);
}
lua_pushnil(l);
lua_rawseti(l, -3, len);
i--;
}
luacon_ci->Log(CommandInterface::LogError, luacon_geterror());
lua_pop(l, 1);
}
len = lua_objlen(l, -1);
}
lua_pop(l, 1);
return 0;
}
int luacon_eval(const char *command)
{
ui::Engine::Ref().LastTick(Platform::GetTime());
@ -417,30 +259,6 @@ void luacon_hook(lua_State * l, lua_Debug * ar)
}
}
int luaL_tostring (lua_State *L, int n)
{
luaL_checkany(L, n);
switch (lua_type(L, n))
{
case LUA_TNUMBER:
lua_pushstring(L, lua_tostring(L, n));
break;
case LUA_TSTRING:
lua_pushvalue(L, n);
break;
case LUA_TBOOLEAN:
lua_pushstring(L, (lua_toboolean(L, n) ? "true" : "false"));
break;
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
default:
lua_pushfstring(L, "%s: %p", luaL_typename(L, n), lua_topointer(L, n));
break;
}
return 1;
}
String luacon_geterror()
{
luaL_tostring(luacon_ci->l, -1);
@ -449,15 +267,7 @@ String luacon_geterror()
return err;
}
//TPT Interface methods
int luatpt_test(lua_State* l)
{
int testint = 0;
testint = luaL_optint(l, 1, 0);
printf("Test successful, got %d\n", testint);
return 0;
}
//tpt. api methods
int luatpt_getelement(lua_State *l)
{
int t;
@ -1272,19 +1082,6 @@ int luatpt_get_name(lua_State* l)
return 1;
}
int luatpt_set_shortcuts(lua_State* l)
{
int acount = lua_gettop(l);
if (acount == 0)
{
lua_pushnumber(l, shortcuts);
return 1;
}
int shortcut = luaL_checkinteger(l, 1);
shortcuts = shortcut?true:false;
return 0;
}
int luatpt_delete(lua_State* l)
{
int arg1, arg2;
@ -1304,171 +1101,6 @@ int luatpt_delete(lua_State* l)
return luaL_error(l,"Invalid coordinates or particle ID");
}
int luatpt_register_step(lua_State* l)
{
if (lua_isfunction(l, 1))
{
lua_pushstring(l, "stepfunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "stepfunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int c = lua_objlen(l, -1);
lua_pushvalue(l, 1);
lua_rawseti(l, -2, c+1);
}
return 0;
}
int luatpt_unregister_step(lua_State* l)
{
if (lua_isfunction(l, 1))
{
lua_pushstring(l, "stepfunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, -1);
lua_newtable(l);
lua_pushstring(l, "stepfunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int len = lua_objlen(l, -1);
int adjust = 0;
for (int i = 1; i <= len; i++)
{
lua_rawgeti(l, -1, i+adjust);
//unregister the function
if (lua_equal(l, 1, -1))
{
lua_pop(l, 1);
adjust++;
i--;
}
//else, move everything down if we removed something earlier
else
{
lua_rawseti(l, -2, i);
}
}
}
return 0;
}
int luatpt_register_keypress(lua_State* l)
{
if (lua_isfunction(l, 1))
{
lua_pushstring(l, "keyfunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "keyfunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int c = lua_objlen(l, -1);
lua_pushvalue(l, 1);
lua_rawseti(l, -2, c+1);
}
return 0;
}
int luatpt_unregister_keypress(lua_State* l)
{
if (lua_isfunction(l, 1))
{
lua_pushstring(l, "keyfunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "keyfunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int c = lua_objlen(l, -1);
int d = 0;
int i = 0;
for (i=1;i<=c;i++)
{
lua_rawgeti(l, -1, i+d);
if (lua_equal(l, 1, -1))
{
lua_pop(l, 1);
d++;
i--;
}
else
lua_rawseti(l, -2, i);
}
}
return 0;
}
int luatpt_register_mouseclick(lua_State* l)
{
if (lua_isfunction(l, 1))
{
lua_pushstring(l, "mousefunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "mousefunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int c = lua_objlen(l, -1);
lua_pushvalue(l, 1);
lua_rawseti(l, -2, c+1);
}
return 0;
}
int luatpt_unregister_mouseclick(lua_State* l)
{
if (lua_isfunction(l, 1))
{
lua_pushstring(l, "mousefunctions");
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, "mousefunctions");
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int c = lua_objlen(l, -1);
int d = 0;
int i = 0;
for (i=1;i<=c;i++)
{
lua_rawgeti(l, -1, i+d);
if (lua_equal(l, 1, -1))
{
lua_pop(l, 1);
d++;
i--;
}
else
lua_rawseti(l, -2, i);
}
}
return 0;
}
int luatpt_input(lua_State* l)
{
String prompt, title, result, shadow, text;

View File

@ -17,3 +17,28 @@ void lua_pushglobaltable(lua_State *L)
}
#endif
// Useful helper function, mainly used for logging
int luaL_tostring(lua_State *L, int n)
{
luaL_checkany(L, n);
switch (lua_type(L, n))
{
case LUA_TNUMBER:
lua_pushstring(L, lua_tostring(L, n));
break;
case LUA_TSTRING:
lua_pushvalue(L, n);
break;
case LUA_TBOOLEAN:
lua_pushstring(L, (lua_toboolean(L, n) ? "true" : "false"));
break;
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
default:
lua_pushfstring(L, "%s: %p", luaL_typename(L, n), lua_topointer(L, n));
break;
}
return 1;
}

View File

@ -29,6 +29,7 @@ LUALIB_API int (luaL_typerror) (lua_State *L, int narg, const char *tname);
#else
LUALIB_API void (lua_pushglobaltable) (lua_State *L);
#endif
int luaL_tostring(lua_State *L, int n);
#ifdef __cplusplus
}

244
src/lua/LuaEvents.cpp Normal file
View File

@ -0,0 +1,244 @@
#include "LuaEvents.h"
#ifdef LUACONSOLE
#include "LuaCompat.h"
#include "LuaScriptInterface.h"
#include "Platform.h"
#include "gui/interface/Engine.h"
#endif
void Event::PushInteger(lua_State * l, int num)
{
#ifdef LUACONSOLE
lua_pushinteger(l, num);
#endif
}
void Event::PushBoolean(lua_State * l, bool flag)
{
#ifdef LUACONSOLE
lua_pushboolean(l, flag);
#endif
}
void Event::PushString(lua_State * l, ByteString str)
{
#ifdef LUACONSOLE
lua_pushstring(l, str.c_str());
#endif
}
TextInputEvent::TextInputEvent(String text):
text(text)
{}
int TextInputEvent::PushToStack(lua_State * l)
{
PushString(l, text.ToUtf8());
return 1;
}
KeyEvent::KeyEvent(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt):
key(key),
scan(scan),
repeat(repeat),
shift(shift),
ctrl(ctrl),
alt(alt)
{}
int KeyEvent::PushToStack(lua_State * l)
{
PushInteger(l, key);
PushInteger(l, scan);
PushBoolean(l, repeat);
PushBoolean(l, shift);
PushBoolean(l, ctrl);
PushBoolean(l, alt);
return 6;
}
MouseDownEvent::MouseDownEvent(int x, int y, int button):
x(x),
y(y),
button(button)
{}
int MouseDownEvent::PushToStack(lua_State * l)
{
PushInteger(l, x);
PushInteger(l, y);
PushInteger(l, button);
return 3;
}
MouseUpEvent::MouseUpEvent(int x, int y, int button, int reason):
x(x),
y(y),
button(button),
reason(reason)
{}
int MouseUpEvent::PushToStack(lua_State * l)
{
PushInteger(l, x);
PushInteger(l, y);
PushInteger(l, button);
PushInteger(l, reason);
return 4;
}
MouseMoveEvent::MouseMoveEvent(int x, int y, int dx, int dy):
x(x),
y(y),
dx(dx),
dy(dy)
{}
int MouseMoveEvent::PushToStack(lua_State * l)
{
PushInteger(l, x);
PushInteger(l, y);
PushInteger(l, dx);
PushInteger(l, dy);
return 4;
}
MouseWheelEvent::MouseWheelEvent(int x, int y, int d):
x(x),
y(y),
d(d)
{}
int MouseWheelEvent::PushToStack(lua_State * l)
{
PushInteger(l, x);
PushInteger(l, y);
PushInteger(l, d);
return 3;
}
#ifdef LUACONSOLE
int LuaEvents::RegisterEventHook(lua_State *l, ByteString eventName)
{
if (lua_isfunction(l, 2))
{
lua_pushstring(l, eventName.c_str());
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, eventName.c_str());
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int c = lua_objlen(l, -1);
lua_pushvalue(l, 2);
lua_rawseti(l, -2, c + 1);
}
lua_pushvalue(l, 2);
return 1;
}
#include <iostream>
int LuaEvents::UnregisterEventHook(lua_State *l, ByteString eventName)
{
if (lua_isfunction(l, 2))
{
lua_pushstring(l, eventName.c_str());
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, -1);
lua_newtable(l);
lua_pushstring(l, eventName.c_str());
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int len = lua_objlen(l, -1);
int adjust = 0;
for (int i = 1; i <= len; i++)
{
lua_rawgeti(l, -1, i + adjust);
// unregister the function
if (lua_equal(l, 2, -1))
{
lua_pop(l, 1);
adjust++;
i--;
}
// Update the function index in the table if we've removed a previous function
else if (adjust)
lua_rawseti(l, -2, i);
else
lua_pop(l, 1);
}
}
return 0;
}
bool LuaEvents::HandleEvent(LuaScriptInterface *luacon_ci, Event *event, ByteString eventName)
{
ui::Engine::Ref().LastTick(Platform::GetTime());
bool cont = true;
lua_State* l = luacon_ci->l;
lua_pushstring(l, eventName.c_str());
lua_rawget(l, LUA_REGISTRYINDEX);
if (!lua_istable(l, -1))
{
lua_pop(l, 1);
lua_newtable(l);
lua_pushstring(l, eventName.c_str());
lua_pushvalue(l, -2);
lua_rawset(l, LUA_REGISTRYINDEX);
}
int len = lua_objlen(l, -1);
for (int i = 1; i <= len && cont; i++)
{
lua_rawgeti(l, -1, i);
int numArgs = event->PushToStack(l);
int callret = lua_pcall(l, numArgs, 1, 0);
if (callret)
{
if (luacon_geterror(luacon_ci) == "Error: Script not responding")
{
ui::Engine::Ref().LastTick(Platform::GetTime());
for (int j = i; j <= len - 1; j++)
{
lua_rawgeti(l, -2, j + 1);
lua_rawseti(l, -3, j);
}
lua_pushnil(l);
lua_rawseti(l, -3, len);
i--;
}
luacon_ci->Log(CommandInterface::LogError, luacon_geterror(luacon_ci));
lua_pop(l, 1);
}
else
{
if (!lua_isnoneornil(l, -1))
cont = lua_toboolean(l, -1);
lua_pop(l, 1);
}
len = lua_objlen(l, -1);
}
lua_pop(l, 1);
return cont;
}
String LuaEvents::luacon_geterror(LuaScriptInterface * luacon_ci)
{
luaL_tostring(luacon_ci->l, -1);
String err = ByteString(luaL_optstring(luacon_ci->l, -1, "failed to execute")).FromUtf8();
lua_pop(luacon_ci->l, 1);
return err;
}
#endif

122
src/lua/LuaEvents.h Normal file
View File

@ -0,0 +1,122 @@
#ifndef LUAEVENTS_H
#define LUAEVENTS_H
#include "common/String.h"
class lua_State;
class LuaScriptInterface;
class Event
{
protected:
void PushInteger(lua_State * l, int num);
void PushBoolean(lua_State * l, bool flag);
void PushString(lua_State * l, ByteString str);
public:
virtual int PushToStack(lua_State * l) = 0;
};
class TextInputEvent : public Event
{
String text;
public:
TextInputEvent(String text);
int PushToStack(lua_State * l) override;
};
class KeyEvent : public Event
{
int key;
int scan;
bool repeat;
bool shift;
bool ctrl;
bool alt;
public:
KeyEvent(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
int PushToStack(lua_State * l) override;
};
class MouseDownEvent : public Event
{
int x;
int y;
int button;
public:
MouseDownEvent(int x, int y, int button);
int PushToStack(lua_State * l) override;
};
class MouseUpEvent : public Event
{
int x;
int y;
int button;
int reason;
public:
MouseUpEvent(int x, int y, int button, int reason);
int PushToStack(lua_State * l) override;
};
class MouseMoveEvent : public Event
{
int x;
int y;
int dx;
int dy;
public:
MouseMoveEvent(int x, int y, int dx, int dy);
int PushToStack(lua_State * l) override;
};
class MouseWheelEvent : public Event
{
int x;
int y;
int d;
public:
MouseWheelEvent(int x, int y, int d);
int PushToStack(lua_State * l) override;
};
class TickEvent: public Event
{
public:
int PushToStack(lua_State *l) override { return 0; }
};
enum EventTypes {
keypress,
keyrelease,
textinput,
mousedown,
mouseup,
mousemove,
mousewheel,
tick
};
class LuaEvents
{
public:
static int RegisterEventHook(lua_State* l, ByteString eventName);
static int UnregisterEventHook(lua_State* l, ByteString eventName);
static bool HandleEvent(LuaScriptInterface * luacon_ci, Event * event, ByteString eventName);
static String luacon_geterror(LuaScriptInterface *luacon_ci);
};
#endif // LUAEVENTS_H

View File

@ -9,7 +9,6 @@ extern Graphics * luacon_g;
extern Renderer * luacon_ren;
extern bool *luacon_currentCommand;
extern int luaL_tostring(lua_State* l, int n);
extern String *luacon_lastError;
extern int *lua_el_func, *lua_el_mode, *lua_gr_func;
@ -21,9 +20,6 @@ extern int tptElements; //Table for TPT element names
extern int tptParts, tptPartsMeta, tptElementTransitions, tptPartsCData, tptPartMeta, tptPart, cIndex;
void luacon_hook(lua_State *L, lua_Debug *ar);
int luacon_step(int mx, int my);
int luacon_mouseevent(int mx, int my, int mb, int event, int mouse_wheel);
int luacon_keyevent(int key, int scan, int modifier, int event);
int luacon_eval(const char *command);
String luacon_geterror();
void luacon_close();
@ -38,8 +34,7 @@ int luacon_transitionread(lua_State* l);
int luacon_transitionwrite(lua_State* l);
//int process_command_lua(pixel *vid_buf, char *console, char *console_error);
//Interface
int luatpt_test(lua_State* l);
//tpt. api
int luatpt_getelement(lua_State *l);
int luacon_graphicsReplacement(GRAPHICS_FUNC_ARGS, int i);
@ -94,15 +89,7 @@ int luatpt_drawline(lua_State* l);
int luatpt_textwidth(lua_State* l);
int luatpt_get_name(lua_State* l);
int luatpt_set_shortcuts(lua_State* l);
int luatpt_delete(lua_State* l);
int luatpt_register_step(lua_State* l);
int luatpt_unregister_step(lua_State* l);
int luatpt_register_keypress(lua_State* l);
int luatpt_unregister_keypress(lua_State* l);
int luatpt_register_mouseclick(lua_State* l);
int luatpt_unregister_mouseclick(lua_State* l);
int luatpt_input(lua_State* l);
int luatpt_message_box(lua_State* l);
int luatpt_confirm(lua_State* l);

View File

@ -28,14 +28,14 @@
#include "PowderToy.h"
#include "LuaBit.h"
#include "LuaWindow.h"
#include "LuaButton.h"
#include "LuaLabel.h"
#include "LuaTextbox.h"
#include "LuaCheckbox.h"
#include "LuaSlider.h"
#include "LuaEvents.h"
#include "LuaLabel.h"
#include "LuaProgressBar.h"
#include "LuaSlider.h"
#include "LuaTextbox.h"
#include "LuaWindow.h"
#ifndef WIN
#include <unistd.h>
@ -136,11 +136,11 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
initGraphicsAPI();
initFileSystemAPI();
initPlatformAPI();
initEventAPI();
//Old TPT API
int currentElementMeta, currentElement;
const static struct luaL_Reg tptluaapi [] = {
{"test", &luatpt_test},
{"drawtext", &luatpt_drawtext},
{"create", &luatpt_create},
{"set_pause", &luatpt_setpause},
@ -164,18 +164,7 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
{"drawline", &luatpt_drawline},
{"textwidth", &luatpt_textwidth},
{"get_name", &luatpt_get_name},
{"set_shortcuts", &luatpt_set_shortcuts},
{"delete", &luatpt_delete},
{"register_step", &luatpt_register_step},
{"unregister_step", &luatpt_unregister_step},
{"register_mouseclick", &luatpt_register_mouseclick},
{"unregister_mouseclick", &luatpt_unregister_mouseclick},
{"register_keypress", &luatpt_register_keypress},
{"unregister_keypress", &luatpt_unregister_keypress},
{"register_mouseevent", &luatpt_register_mouseclick},
{"unregister_mouseevent", &luatpt_unregister_mouseclick},
{"register_keyevent", &luatpt_register_keypress},
{"unregister_keyevent", &luatpt_unregister_keypress},
{"input", &luatpt_input},
{"message_box", &luatpt_message_box},
{"confirm", &luatpt_confirm},
@ -226,11 +215,6 @@ LuaScriptInterface::LuaScriptInterface(GameController * c, GameModel * m):
tptProperties = lua_gettop(l);
lua_pushinteger(l, 0);
lua_setfield(l, tptProperties, "mousex");
lua_pushinteger(l, 0);
lua_setfield(l, tptProperties, "mousey");
lua_newtable(l);
tptPropertiesVersion = lua_gettop(l);
lua_pushinteger(l, SAVE_VERSION);
@ -373,19 +357,23 @@ void LuaScriptInterface::SetWindow(ui::Window * window)
int LuaScriptInterface::tpt_index(lua_State *l)
{
ByteString key = luaL_checkstring(l, 2);
if (!key.compare("selectedl"))
return lua_pushstring(l, luacon_selectedl.c_str()), 1;
if (!key.compare("selectedr"))
return lua_pushstring(l, luacon_selectedr.c_str()), 1;
if (!key.compare("selecteda"))
return lua_pushstring(l, luacon_selectedalt.c_str()), 1;
if (!key.compare("selectedreplace"))
return lua_pushstring(l, luacon_selectedreplace.c_str()), 1;
if (!key.compare("brushx"))
if (!key.compare("mousex"))
return lua_pushnumber(l, c->GetView()->GetMousePosition().X), 1;
else if (!key.compare("mousey"))
return lua_pushnumber(l, c->GetView()->GetMousePosition().Y), 1;
else if (!key.compare("selectedl"))
return lua_pushstring(l, m->GetActiveTool(0)->GetIdentifier().c_str()), 1;
else if (!key.compare("selectedr"))
return lua_pushstring(l, m->GetActiveTool(1)->GetIdentifier().c_str()), 1;
else if (!key.compare("selecteda"))
return lua_pushstring(l, m->GetActiveTool(2)->GetIdentifier().c_str()), 1;
else if (!key.compare("selectedreplace"))
return lua_pushstring(l, m->GetActiveTool(3)->GetIdentifier().c_str()), 1;
else if (!key.compare("brushx"))
return lua_pushnumber(l, m->GetBrush()->GetRadius().X), 1;
if (!key.compare("brushy"))
else if (!key.compare("brushy"))
return lua_pushnumber(l, m->GetBrush()->GetRadius().Y), 1;
if (!key.compare("brushID"))
else if (!key.compare("brushID"))
return lua_pushnumber(l, m->GetBrushID()), 1;
//if not a special key, return the value in the table
@ -3299,99 +3287,57 @@ int LuaScriptInterface::platform_clipboardPaste(lua_State * l)
return 0;
}
bool LuaScriptInterface::OnActiveToolChanged(int toolSelection, Tool * tool)
//// Begin Event API
void LuaScriptInterface::initEventAPI()
{
ByteString identifier;
if (tool)
identifier = tool->GetIdentifier();
else
identifier = "";
if (toolSelection == 0)
luacon_selectedl = identifier;
else if (toolSelection == 1)
luacon_selectedr = identifier;
else if (toolSelection == 2)
luacon_selectedalt = identifier;
else if (toolSelection == 3)
luacon_selectedreplace = identifier;
return true;
struct luaL_Reg eventAPIMethods [] = {
{"register", event_register},
{"unregister", event_unregister},
{"getmodifiers", event_getmodifiers},
{NULL, NULL}
};
luaL_register(l, "event", eventAPIMethods);
lua_getglobal(l, "event");
lua_setglobal(l, "evt");
lua_pushinteger(l, EventTypes::keypress); lua_setfield(l, -2, "keypress");
lua_pushinteger(l, EventTypes::keyrelease); lua_setfield(l, -2, "keyrelease");
lua_pushinteger(l, EventTypes::textinput); lua_setfield(l, -2, "textinput");
lua_pushinteger(l, EventTypes::mousedown); lua_setfield(l, -2, "mousedown");
lua_pushinteger(l, EventTypes::mouseup); lua_setfield(l, -2, "mouseup");
lua_pushinteger(l, EventTypes::mousemove); lua_setfield(l, -2, "mousemove");
lua_pushinteger(l, EventTypes::mousewheel); lua_setfield(l, -2, "mousewheel");
lua_pushinteger(l, EventTypes::tick); lua_setfield(l, -2, "tick");
}
bool LuaScriptInterface::OnMouseMove(int x, int y, int dx, int dy)
int LuaScriptInterface::event_register(lua_State * l)
{
luacon_mousex = x;
luacon_mousey = y;
return true;
//ByteString eventname = luaL_checkstring(l, 1);
int eventName = luaL_checkinteger(l, 1);
luaL_checktype(l, 2, LUA_TFUNCTION);
return LuaEvents::RegisterEventHook(l, ByteString::Build("tptevents-", eventName));
}
bool LuaScriptInterface::OnMouseDown(int x, int y, unsigned button)
int LuaScriptInterface::event_unregister(lua_State * l)
{
if (button == 3)
button = 4;
luacon_mousedown = true;
luacon_mousebutton = button;
luacon_mousex = x;
luacon_mousey = y;
return luacon_mouseevent(x, y, button, LUACON_MDOWN, 0);
//ByteString eventname = luaL_checkstring(l, 1);
int eventName = luaL_checkinteger(l, 1);
luaL_checktype(l, 2, LUA_TFUNCTION);
return LuaEvents::UnregisterEventHook(l, ByteString::Build("tptevents-", eventName));
}
bool LuaScriptInterface::OnMouseUp(int x, int y, unsigned button, char type)
int LuaScriptInterface::event_getmodifiers(lua_State * l)
{
luacon_mousebutton = 0;
if (type != 1)
{
luacon_mousex = x;
luacon_mousey = y;
}
if (button == 3)
button = 4;
// mouse was never down, probably due to fake mouse event
if (!luacon_mousedown)
{
return true;
}
// fake mouseup event, triggered when mouse drawing is canceled due to moving in / out of the zoom window
if (type == 2)
return luacon_mouseevent(x, y, button, LUACON_MUPZOOM, 0);
luacon_mousedown = false;
// fake mouseup event, triggered when user enters another interface while the mouse is down
if (type == 1)
return luacon_mouseevent(x, y, button, LUACON_MUPALT, 0);
else
return luacon_mouseevent(x, y, button, LUACON_MUP, 0);
lua_pushnumber(l, GetModifiers());
return 1;
}
bool LuaScriptInterface::OnMouseWheel(int x, int y, int d)
bool LuaScriptInterface::HandleEvent(EventTypes eventType, Event * event)
{
return luacon_mouseevent(x, y, luacon_mousedown?luacon_mousebutton:0, 0, d);
}
bool LuaScriptInterface::OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
{
return luacon_keyevent(key, scan, GetModifiers(), LUACON_KDOWN);
}
bool LuaScriptInterface::OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt)
{
int modifiers = 0;
if(shift)
modifiers |= 0x001;
if(ctrl)
modifiers |= 0x040;
if(alt)
modifiers |= 0x100;
return luacon_keyevent(key, key < 256 ? key : 0, modifiers, LUACON_KUP);
}
bool LuaScriptInterface::OnMouseTick()
{
if (luacon_mousedown)
return luacon_mouseevent(luacon_mousex, luacon_mousey, luacon_mousebutton, LUACON_MPRESS, 0);
return true;
return LuaEvents::HandleEvent(this, event, ByteString::Build("tptevents-", eventType));
}
void LuaScriptInterface::OnTick()
@ -3403,7 +3349,7 @@ void LuaScriptInterface::OnTick()
lua_setfield(l, -2, "NUM_PARTS");
}
lua_pop(l, 1);
luacon_step(luacon_mousex, luacon_mousey);
HandleEvent(EventTypes::tick, new TickEvent());
}
int LuaScriptInterface::Command(String command)

View File

@ -4,6 +4,7 @@
#include "LuaCompat.h"
#include "CommandInterface.h"
#include "lua/LuaEvents.h"
#include "simulation/Simulation.h"
namespace ui
@ -34,6 +35,7 @@ class Tool;
lua_setfield(L, -2, #NAME)
class TPTScriptInterface;
class LuaScriptInterface: public CommandInterface
{
int luacon_mousex, luacon_mousey, luacon_mousebutton;
@ -167,6 +169,11 @@ class LuaScriptInterface: public CommandInterface
static int platform_clipboardCopy(lua_State * l);
static int platform_clipboardPaste(lua_State * l);
void initEventAPI();
static int event_register(lua_State * l);
static int event_unregister(lua_State * l);
static int event_getmodifiers(lua_State * l);
public:
int tpt_index(lua_State *l);
int tpt_newIndex(lua_State *l);
@ -177,15 +184,10 @@ public:
ui::Window * Window;
lua_State *l;
LuaScriptInterface(GameController * c, GameModel * m);
virtual bool OnActiveToolChanged(int toolSelection, Tool * tool);
virtual bool OnMouseMove(int x, int y, int dx, int dy);
virtual bool OnMouseDown(int x, int y, unsigned button);
virtual bool OnMouseUp(int x, int y, unsigned button, char type);
virtual bool OnMouseWheel(int x, int y, int d);
virtual bool OnKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
virtual bool OnKeyRelease(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt);
virtual bool OnMouseTick();
virtual void OnTick();
virtual bool HandleEvent(EventTypes eventType, Event * event);
virtual void Init();
virtual void SetWindow(ui::Window * window);
virtual int Command(String command);