2013-06-26 76 views
0

我將一個WebKitGTK +項目從C++轉換爲Python(使用PyGI)。我需要檢測頁面上的某個<input>元素是否獲得或失去焦點。在C++項目,我做到了使用此代碼(基於this example):在Python中找不到DOMEventTarget.add_event_listener

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(其中DOMHTMLInputElement擴展)的一部分,但它與remove_event_listener一起丟失,儘管dispatch_event以某種方式使其進入。可能是由於this WebKit bug;我不確定

有什麼辦法可以在Python中做到這一點?它不必使用我在C++中使用的相同方案,我只需要一些方法來註冊一個回調,每次調用頁面上某些元素的焦點更改

回答

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); 
} 

我偷了一些代碼this answer到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) 
0

我的理解是那些函數不公開內省,因此在python中不可用。我也遇到了同樣的問題,並找到了解決問題的方法。它爲我工作。

  1. 使用JavaScript來聽你感興趣的事件。在JavaScript事件處理函數調用alert函數中,例如

    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文件只是調用alert和python端解析消息並對其執行操作。