3
\$\begingroup\$

I'm working on my first big project and I've decided to integrate Lua with my C++ framework. Everything's worked out so far, but the only way I've managed to pass the SDL_GetKeyboardState(NULL) array to Lua is by building a Lua table manually.

void passKeyboard(const Uint8* keyboard){
    std::map<std::string,std::string> kmap;
    kmap.clear();
    kmap["UP"]=toString(keyboard[SDL_GetScancodeFromKey(SDLK_UP)]);
    kmap["DOWN"]=toString(keyboard[SDL_GetScancodeFromKey(SDLK_DOWN)]);
    kmap["LEFT"]=toString(keyboard[SDL_GetScancodeFromKey(SDLK_LEFT)]);
    kmap["RIGHT"]=toString(keyboard[SDL_GetScancodeFromKey(SDLK_RIGHT)]);
    ...
    vbind_SetTable("keyboard",kmap);
}

Now, the code works and is reasonably fast for my purposes, but it's undeniably ugly. I even feel dirty looking at it. Is there any way I could to this more elegantly?

For reference, vbind.h:

void vbind_SetTable(const std::string &name,std::map<std::string,std::string> &t){
    lua_newtable(L);
    for(std::map<std::string,std::string>::iterator it=t.begin();it!=t.end();it++){
        lua_pushstring(L,it->first.c_str());
        std::string value=it->second;
        const char* p=value.c_str();
        char* end;
        long t=strtol(value.c_str(),&end,10);
        if(p!=end&&errno!=ERANGE){
            lua_pushnumber(L,t);
        }
        else{
            lua_pushstring(L,value.c_str());
        }
        lua_settable(L,-3);
    }
    lua_setglobal(L,name.c_str());
}
\$\endgroup\$
1
\$\begingroup\$

First - have you considered Sol2 for lua binding (https://github.com/ThePhD/sol2)? It's very easy to use, I love it.

With it, you could register a function to lua which takes a string and returns bool if the key is pressed:

// something like this
bool KeyPressed(const std::string &key_name)
{
    auto key = SDL_GetKeyFromName(key_name.c_str());
    if (key == SDLK_UNKNOWN)
        return false;

    auto state = SDL_GetKeyboardState(NULL);
    return state[SDL_GetScancodeFromKey(key)];
}

With Sol2, it is super each to register a function to lua (and you can easily integrate it with plain lua API stuff):

// sol2
sol::state lua;
// Or use sol::state_view(lua_State *L) with
// an existing lua_State
// i.e. 
//    sol::state_view lua(L);
lua.set_function("keypressed", KeyPressed);

Then in your lua code, you can use the KeyPressed function as you would expect:

if keypressed("Left") then
    -- do stuff
end
\$\endgroup\$
0
\$\begingroup\$

This is a bit hard on the eyes. And... you are doing a LOT of work just to get a keyboard state. Take a look at the LuaSDL implementation.

https://github.com/Tangent128/luasdl2/blob/master/src/keyboard.c#L128

Follow it to KeysIndex at Line 29. You will probably notice that he used the original function, as well as a checkinteger() function from the Lua library, and compares the data to registered Enums. A pretty simple solution from this code.

SDL_GetKeyboardState(int *numkeys)
{
    SDL_Keyboard *keyboard = &SDL_keyboard;

    if (numkeys != (int *) 0) {
        *numkeys = SDL_NUM_SCANCODES;
    }
    return keyboard->keystate;
}

So instead of using a map, you can actually just write to a pre-existing table.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.