First off I want to say that I do not have the option to modify or even view the c source code so anything that involves modifying the c file will not be helpful.
In VP.h:
typedef enum VPEvent {
...
EVENT_OBJECT_CLICK,
...
}
...
typedef void *VPInstance;
typedef void(*VPEventHandler)(VPInstance);
...
VPSDK_API VPInstance vp_create(void);
...
VPSDK_API int vp_event_set(VPInstance instance, VPEvent eventname, VPEventHandler event);
...
In VP.pyx:
cdef extern from "VP.h":
...
cdef enum VPEvent:
...
VP_EVENT_OBJECT_CLICK,
...
...
ctypedef void *VPInstance
ctypedef void(*VPEventHandler)(VPInstance)
...
VPInstance vp_create()
...
int vp_event_set(VPInstance instance, VPEvent eventname, VPEventHandler event)
...
...
EVENT_OBJECT_CLICK = VP_EVENT_OBJECT_CLICK
...
cdef class create:
cdef VPInstance instance
def __init__(self):
self.instance = vp_create()
...
def event_set(self, eventname, event):
return vp_event_set(self.instance, eventname, event)
What I want to have In Python:
import VP
...
def click(bot):
bot.say("Someone clicked something!")
...
bot = VP.create()
bot.event_set(VP.EVENT_OBJECT_CLICK, click)
This is how you would do it in c:
#include <VP.h>
void click(VPInstance instance) {
vp_say(instance, "Someone clicked something!");
}
int main(int argc, char ** argv) {
...
VPInstance instance;
instance = vp_create();
...
vp_event_set(instance, VP_EVENT_OBJECT_CLICK, click)
}
However the problem is that when compiling VP.pyx I get
Cannot convert Python object to 'VPEventHandler'
As well, by default the callback is given a VPInstance pointer but I want to abstract this value into a class.
As you probably figured out, the problem in the call
bot.event_set(VP.EVENT_OBJECT_CLICK, click)
Indeed, the third argument click
is a Python function object which you are passing in event_set
to vp_event_set
. Alas vp_event_set
is expecting a VPEventHandler
that is a C function pointer of type void(*VPEventHandler)(VPInstance);
I think I would build a dictionary associating to a VPInstance
(void *
pointer casted as integer) an instance of some PyEvent
class which should contains itself the function click. Using that you can ensure that you need on one C function as callback.
In foo.pxd
:
cdef class PyEvent(object):
cdef VPInstance instance
cdef object py_callback
In foo.pyx
:
events = dict()
cdef void EventCallBack(VPInstance instance):
PyEvent ev = <PyEvent> dict[events[<size_t> self.instance]
ev.py_callback(ev)
cdef class PyEvent(object):
def __init__(self, click):
self.instance = vp_create()
self.py_callback = click
def event_set(self, eventname):
global events
events[<size_t> self.instance] = self
return vp_event_set(self.instance, eventname, EventCallBack)
I don't have a chance to test this, so I hope it more or less works. Also I would recommend asking on cython-users@googlegroups.com as they are usually really helpful and more expert than me.