Is there a good way to expose sf::Event to Lua with Luabridge?
Asked Answered
A

3

12

According to the LuaBridge readme, LuaBridge does not support "Enumerated constants", which I assume is just enums. Since sf::Event is almost entirely enums, is there any way I can expose the class? Currently the only other solution I can come up with is detect key presses in C++, then send a string to Lua, that describes the event. Obviously, there are around 100+ keys on a modern keyboard, which would cause a massive, ugly segment of just if statements.

For those who haven't used SFML: Link to sf::Event class source code


UPDATE:

After attempting to create the function outlined in my question, I discovered that it don't work anyway, because you can't return more than one string in C++, so most events are ignored.

Example Source (doesn't work):

std::string getEvent()
{
    sf::Event event;
    while (window.pollEvent(event))
    {
        if (event.type == sf::Event::Closed) {window.close(); return "";}
        else if (event.type == sf::Event::GainedFocus) {return "GainedFocus";}
        else if (event.type == sf::Event::LostFocus) {return "LostFocus";}
        else if (event.type == sf::Event::Resized) {return "Resized";}
        else if (event.type == sf::Event::TextEntered)
        {
            if ((event.text.unicode < 128) && (event.text.unicode > 0)) {return "" + static_cast<char>(event.text.unicode);}
        }
        else if (event.type == sf::Event::KeyPressed)
        {
            //If else for all keys on keyboard
        }
        else if (event.type == sf::Event::KeyReleased)
        {
            //If else for all keys on keyboard
        }
        else {return "";}
    }
    return "";
}

UPDATE UPDATE:

Since this question has received zero comments or answers, I've decided not to rule out other libraries. So, if there is a C++ library that supports enums, I will accept it

Admix answered 19/7, 2015 at 18:1 Comment(11)
An enum is just named constants, which you can export as a Lua table. No if statements required. I don't know LuaBridge, but scanning their docs it looks like you could expose EventType via a member proxy, then just return a LuaTable that you've initialized with the enumeration key/values. You can create a macro using the stringizing operator to do most of the typing for you.Sidonia
The enum is not the difficult problem here. I think that handling the union and the composite member variables correctly is much more complicated. I'd be very impressed if there is a binding generator out there that can do it (or even one of those) ...Amarillo
@Amarillo The memory layout of the C++ object has no effect on the complexity of the binding. The object is just a pointer, to both the C++ code and the Lua code, and the offset math for member access is a detail handled by the C++ compiler.Sidonia
@Mud: The lifetime of the member-userdata depends on the lifetime of the main-userdata. The member-userdata doesn't free its memory, because it is owned by someone else (the main-userdata), and if the main-userdata is collected before the member-userdata, you will get a dangling pointer in the member-userdata.Amarillo
@Amarillo o.O That has nothing to do with your previous comment, or anything I've said in this thread. When you export a pointer to Lua via userdata, you create a __gc metamethod so you can free the C++ memory when the Lua userdata is garbage collected. That has absolutely nothing to do with whether or not that C++ object is a union. The fact the the object may contain unions or bitfields or packing/alignment pragmas has no bearing whatsoever on this discussion in any way.Sidonia
@Mud: ??? sf:Event contains a union of structs (by value). LuaBridge can't handle either correctly for the reasons I gave in my comment. I don't think there is a binding generator that can, but as I said I'd be happy to be wrong on this one. Why is this not relevant?Amarillo
@Amarillo You've yet to give a reason why a binding generator can't (in fact there are several binding generators that do), but you did go off on a bizarre, irrelevant tangent about "lifetime of member-userdata".Sidonia
@Mud: Great! Would you mind giving an example, so I can see for myself? Preferably one which also handles enums, so that the OP is happy as well. And I never said can't, I just said that those I know don't, and that I'd be genuinely impressed if there are any that do! My guess is that most don't because it's a rare use case, yet it complicates the userdata handling of all classes/structs. Btw., by "member-userdata" I meant a userdata representing a member variable of struct/class/union type that's embedded by value in another object (represented by "main-userdata").Amarillo
If the question is less about sf::Event, and more about objects with Unions and Enums in general, should I edit the question to remove all references to SFML? (that's if the reason the question got no answers was because the SFML tag scared people off)Admix
And I'm also considering removing LuaBridge and making it about how to do it with the normal Lua C API or any other binding generator, since I can't find anything about C++ Unions with Lua (Google only showed SO questions because there is a hot network question about the soviet union!)Admix
I decided to create a new question, which I will use to answer this question, if the other question gets an answer.Admix
B
2

Since this question has received zero comments or answers, I've decided not to rule out other libraries. So, if there is a C++ library that supports enums, I will accept it

The Thor library, an SFML extension, supports conversions between SFML key types and strings. This would help you serialize enumerators and pass them as strings to Lua -- and back if you need.

Beriosova answered 11/10, 2015 at 15:23 Comment(0)
W
1

if you only want enum to number, consider this. <luabridge/detail/Vector.h> methods.

#include <LuaBridge/detail/Stack.h>
enum class LogLevels { LOG_1, LOG_2 }  

namespace luabridge
{
    template <>
    struct Stack<LogLevels>
    {
        static void push(lua_State* L, LogLevels const& v) { lua_pushnumber( L, static_cast<int>(v) ); }
        static LogLevels get(lua_State* L, int index) { return LuaRef::fromStack(L, index); }
    };
}
Wilkison answered 11/11, 2020 at 14:16 Comment(0)
G
0

Add this into Namespace class:

template<class T>
Namespace& addConstant(char const* name, T value)
{
    if (m_stackSize == 1)
    {
        throw std::logic_error("addConstant () called on global namespace");
    }

    assert(lua_istable(L, -1)); // Stack: namespace table (ns)

    Stack<T>::push(L,value); // Stack: ns, value
    rawsetfield(L, -2, name); // Stack: ns

    return *this;
}

Then use:

getGlobalNamespace(L)
    .addNamespace("sf")
        .addNamespace("Event")
            .addConstant("KeyPressed",sf::Event::KeyPressed)
            //....
        .endNamespace()
    .endNamespace();
Gatling answered 6/7, 2021 at 7:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.