Lua: Allow creation of commands

This commit is contained in:
Ilari Liusvaara 2013-05-04 18:26:18 +03:00
parent 089602bd77
commit 3f493d24d1
3 changed files with 112 additions and 2 deletions

View file

@ -1155,6 +1155,31 @@ To create press/release commands, use aliases +foo and -foo .
Keep the returned object around.
\end_layout
\begin_layout Subsubsection
create_command(string name, function a[, function b])
\end_layout
\begin_layout Standard
Return object representing a command (pair).
\end_layout
\begin_layout Itemize
If b is NIL, the command is level-sensitive, a is callback.
\end_layout
\begin_layout Itemize
If b is function, the function is edge-sensitive, a is positive edge callback
and b is negative edge callback.
\end_layout
\begin_layout Itemize
All callbacks get single argument: The parameters passed.
\end_layout
\begin_layout Itemize
Keep the returned object around.
\end_layout
\begin_layout Subsection
Table bit:
\end_layout

View file

@ -555,6 +555,19 @@ and specified command.
• Keep the returned object around.
7.1.13 create_command(string name, function a[, function b])
Return object representing a command (pair).
• If b is NIL, the command is level-sensitive, a is callback.
• If b is function, the function is edge-sensitive, a is positive
edge callback and b is negative edge callback.
• All callbacks get single argument: The parameters passed.
• Keep the returned object around.
7.2 Table bit:
Bitwise logical functions and related.

View file

@ -6,16 +6,76 @@
class lua_inverse_bind
{
public:
lua_inverse_bind(const std::string name, const std::string cmd);
lua_inverse_bind(const std::string& name, const std::string& cmd);
private:
inverse_bind ikey;
};
lua_inverse_bind::lua_inverse_bind(const std::string name, const std::string cmd)
class lua_command_binding : public command
{
public:
lua_command_binding(lua_state& _L, const std::string& cmd, int idx)
: command(lsnes_cmd, cmd), L(_L)
{
L.pushlightuserdata(this);
L.pushvalue(idx);
L.rawset(LUA_REGISTRYINDEX);
}
void invoke(const std::string& arguments) throw(std::bad_alloc, std::runtime_error)
{
L.pushlightuserdata(this);
L.rawget(LUA_REGISTRYINDEX);
L.pushstring(arguments.c_str());
int r = L.pcall(1, 0, 0);
std::string err;
if(r == LUA_ERRRUN)
err = L.get_string(-1, "Lua command callback");
else if(r == LUA_ERRMEM)
err = "Out of memory";
else if(r == LUA_ERRERR)
err = "Double fault";
else
err = "Unknown error";
if(r) {
messages << "Error running lua command hook: " << err << std::endl;
}
}
private:
lua_state& L;
};
class lua_command_bind
{
public:
lua_command_bind(lua_state* L, const std::string& cmd, int idx1, int idx2);
~lua_command_bind();
private:
lua_command_binding* a;
lua_command_binding* b;
};
lua_inverse_bind::lua_inverse_bind(const std::string& name, const std::string& cmd)
: ikey(lsnes_mapper, cmd, "Lua‣" + name)
{
}
lua_command_bind::lua_command_bind(lua_state* L, const std::string& cmd, int idx1, int idx2)
{
if(L->type(idx2) == LUA_TFUNCTION) {
a = new lua_command_binding(*L, "+" + cmd, idx1);
b = new lua_command_binding(*L, "-" + cmd, idx2);
} else {
a = new lua_command_binding(*L, cmd, idx1);
b = NULL;
}
}
lua_command_bind::~lua_command_bind()
{
delete a;
delete b;
}
namespace
{
function_ptr_luafun input_bindings(LS, "list_bindings", [](lua_state& L, const std::string& fname) -> int {
@ -73,6 +133,18 @@ namespace
lua_inverse_bind* b = lua_class<lua_inverse_bind>::create(L, name, command);
return 1;
});
function_ptr_luafun create_cmd(LS, "create_command", [](lua_state& L, const std::string& fname) -> int {
if(L.type(2) != LUA_TFUNCTION)
throw std::runtime_error("Argument 2 of create_command must be function");
if(L.type(3) != LUA_TFUNCTION && L.type(3) != LUA_TNIL && L.type(3) != LUA_TNONE)
throw std::runtime_error("Argument 2 of create_command must be function or nil");
std::string name = L.get_string(1, fname.c_str());
lua_command_bind* b = lua_class<lua_command_bind>::create(L, &L, name, 2, 3);
return 1;
});
}
DECLARE_LUACLASS(lua_inverse_bind, "INVERSEBIND");
DECLARE_LUACLASS(lua_command_bind, "COMMANDBIND");