繁体   English   中英

D到C函数中的类方法回调

[英]Class method callbacks in D to C functions

我在D中编写了一个简单,轻量级的引擎。对于输入调用,我使用GLFW3。 有问题的库使用回调将输入事件发送到程序。

我想要的是使用类中的方法作为回调函数,而不是函数。 事实证明这很困难(就像C ++中一样)。 我相信有一种优雅的方法可以做到这一点,但这就是我现在的方法。

public void initialise(string logPath) {
    [...]
    m_Window = new RenderWindow();
    m_Window.create();

    // Lets set up the input loop.
    GLFWkeyfun keyCB = function(GLFWwindow* win, int key, int scancode, int action, int mods) {
        printf("Got key event: %d:%d:%d:%d\n");
        RenderWindow rw = Root().getRenderWindow();

        switch (key) {
            case KeyboardKeyID.Q:
                glfwSetWindowShouldClose(win, true);
                break;

            case KeyboardKeyID.H:
                if (rw.hidden) {
                    rw.show();
                } else {
                    rw.hide();
                }
                break;

            default:
                break;
        }
    };
    glfwSetKeyCallback(m_Window.window, keyCB);
}

这是回调设置函数和类型的定义:

extern (C) {
    alias              GLFWkeyfun = void function(GLFWwindow*, int, int, int, int);
    GLFWkeyfun         glfwSetKeyCallback(GLFWwindow*, GLFWkeyfun);
}

我想做的是创建一个属于类的方法。 有什么办法吗?

我尝试过的一个解决方案是在extern (C)包裹一个static方法,该方法可以调用它,但是后来我(显然)无法访问this方法或任何其他方法,这不符合本练习的要点。

提前致谢。

我这样做的方法是拥有指向该类的指针的静态映射,如下所示:

static YourWindowClass[GLFWwindow*] mappings;

然后,在构造函数中,一旦获得GLFWwindow指针,请在以下位置添加它:

mappings[m_Window.window] = this;

现在,使静态extern(C)函数用作回调。 当它从C获取指针时,请在该映射数组中查找类引用,然后继续通过它调用成员函数,并转发参数。

因此,这是一个额外的步骤,但是由于它看起来不像回调使您可以将用户定义的数据传递给它(顺便说一句,请注意所有lib编写器:用户定义的void *对回调非常有用,您应该这样做只要有可能就可以!),但由于这样做不行,所以关联数组是下一个最好的选择。

好吧,我自己解决了。 我使用的解决方案是Singleton类InputManager RenderWindow实例通过以下函数将其自身附加到它。 然后, InputManager为接收事件的RenderWindow创建一个匿名function() ,然后该匿名function()调用一个处理实际事件的函数。

然后的想法是,侦听器将自己附加到InputManager并接收他们请求的RenderWindow键盘事件。

class InputManager {
    private static InputManager m_Instance;
    private RenderWindow[] m_Watched;
    private KeyboardListener[][RenderWindow] m_KeyListeners;

    public void recvKeyEvent(GLFWwindow* w, int k, int c, int a, int m) {
        writeln("Received key: ", k);
    }

    public void watch(RenderWindow win) {
        if (!isWatched(win)) {
            // Relay the key callbacks onto the InputManager.
            GLFWkeyfun keyCB = function(GLFWwindow* w, int k, int c, int a, int m) {
                InputManager().recvKeyEvent(w, k, c, a, m);
            };
            glfwSetKeyCallback(win.window, keyCB);
        }
    }

    private bool isWatched(RenderWindow win) {
        foreach(RenderWindow w; m_Watched) {
            if (win == w) {
                return true;
            }
        }

        return false;
    }

    public static InputManager opCall() {
        if (m_Instance is null) {
            m_Instance = new InputManager();
        }

        return m_Instance;
    }

    private this() {
        // nothing
    }
}

现在就像魅力一样工作,以弄清楚如何正确地优雅地吸引听众。

对于那些好奇的人,可以在https://github.com/Adel92/Mage2D中找到有关如何设置的完整源代码。 我希望它可以帮助其他处于类似位置的人使用回调。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM