0

我正在将 WebKitGTK+ 项目从 C++ 转换为 Python(使用 PyGI)。我需要检测<input>页面上的元素获得或失去焦点的任何时间。在 C++ 项目中,我使用此代码(基于此示例):

WebKitDOMDocument* document = webkit_web_view_get_dom_document(view);
WebKitDOMNodeList* nodes = webkit_dom_document_get_elements_by_tag_name(document, "*");
int len = webkit_dom_node_list_get_length(nodes);
for(int i = 0; i < len; i++) {
    WebKitDOMNode* node = webkit_dom_node_list_item(nodes, i);
    if(WEBKIT_DOM_IS_HTML_INPUT_ELEMENT(node)) {
        webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(node), "focus", G_CALLBACK(inputFocus), false);
        webkit_dom_event_target_add_event_listener(WEBKIT_DOM_EVENT_TARGET(node), "blur", G_CALLBACK(inputBlur), false);
    }
}

我尝试在 Python 中做同样的事情并想出了:

document = view.get_dom_document()
nodes = document.get_elements_by_tag_name('*')
for i in range(nodes.get_length()):
    node = nodes.item(i)
    if isinstance(node, WebKit.DOMHTMLInputElement):
        node.add_event_listener('focus', inputFocus, False)

问题是,DOMHTMLInputElement没有add_event_listener方法。基于 C 绑定,它应该是DOMEventTarget(which DOMHTMLInputElementextends) 的一部分,但它与 一起丢失remove_event_listener,尽管dispatch_event以某种方式进入。这可能是由于这个 WebKit 错误;我不确定

有没有办法在 Python 中做到这一点?它不必使用我在 C++ 中使用的相同方案,我只需要一些方法来注册一个回调,该回调在每次焦点更改页面上的某些元素时调用

4

2 回答 2

0

我最终通过作弊解决了这个问题,并使用 C 添加了一个回调 Python 的事件侦听器。我编写了这个简短的 C 文件并将其编译为共享对象:

typedef void (*callback)(WebKitDOMNode* node);

static bool handler(WebKitDOMNode* node, WebKitDOMEvent* event, callback cb) {
    cb(node);
    return true;
}

void add_event_listener(WebKitDOMEventTarget* target, callback focused, callback blurred) {
    webkit_dom_event_target_add_event_listener(target, "focus", G_CALLBACK(handler), false, (void*)focused);
    webkit_dom_event_target_add_event_listener(target, "blur", G_CALLBACK(handler), false, (void*)blurred);
}

我从这个答案中窃取了一些代码来在 Python 对象和 C 指针之间进行转换,并对其进行了一些调整:

class _PyGObject_Functions(ctypes.Structure):
    _fields_ = [
        ('register_class', ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p, ctypes.c_int, ctypes.py_object, ctypes.py_object)),
        ('register_wrapper', ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.py_object)),
        ('lookup_class', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)),
        ('newgobj', ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
    ]

class PyGObjectCPAI(object):
    def __init__(self):
        PyCObject_AsVoidPtr = ctypes.pythonapi.PyCObject_AsVoidPtr
        PyCObject_AsVoidPtr.restype = ctypes.c_void_p
        PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
        addr = PyCObject_AsVoidPtr(ctypes.py_object(gi._gobject._PyGObject_API))
        self._api = _PyGObject_Functions.from_address(addr)

    def pygobject_new(self, addr):
        return self._api.newgobj(addr)

def cToPython(ptr, capi = PyGObjectCPAI()):
    return capi.pygobject_new(ptr)

def pythonToC(obj):
    return hash(obj)

我写了一个python事件监听器:

def focusChanged(node, focused):
    ....

制作了 C 可调用函数(它们需要是全局的,因此它们不会被垃圾收集):

native = ctypes.cdll.LoadLibrary('native.so')
native.add_event_listener.argtypes = [ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]

def focused(nodeAddr): focusChanged(cToPython(nodeAddr), True)
def blurred(nodeAddr): focusChanged(cToPython(nodeAddr), False)

CALLBACK = ctypes.CFUNCTYPE(None, ctypes.c_void_p)
focused = CALLBACK(focused)
blurred = CALLBACK(blurred)

并将事件监听器添加到每个节点:

document = view.get_dom_document()
nodes = document.get_elements_by_tag_name('*')
for i in range(nodes.get_length()):
    node = nodes.item(i)
    if isinstance(node, WebKit.DOMHTMLInputElement) or isinstance(node, WebKit.DOMHTMLTextAreaElement):
        native.add_event_listener(pythonToC(node), focused, blurred)
于 2013-07-08T19:12:05.520 回答
0

我的理解是这些函数没有公开用于自省,因此在 python 中不可用。我也遇到了同样的问题,并找到了一种解决问题的方法。它确实对我有用。

  1. 使用 javascript 来监听你感兴趣的事件。在 javascript 事件处理函数中调用警报函数,例如

    alert("FOCUS:"+ node.getId()); //Or name or whatever that can help python side to identify

  2. 在 python 端使用警报处理程序获取消息并解析消息以确定哪个节点

如果您无法通过名称/id 或 xpath 识别唯一节点,这将不起作用,但如果您正在控制 html,则可以轻松处理此问题。

我的示例代码可以在https://github.com/nhrdl/notesMD/blob/master/notesmd.py找到。看一下文件中的警报功能。HTML 文件只调用警报,python 端解析消息并对其进行操作。

于 2013-06-26T18:15:03.297 回答