给webkit增加一个系统事件

在开发一个项目的时候,有个需求,需要让JS能够接收C的事件。如何实现呢!?其实DOM中已经有一个类似的实现,就是document.keypress。页面通过注册keypress事件的回调获取按键信息,而按键信息就是由底层送上来的。
依葫芦画瓢,再添加多一个document.onsystemevent到webkit中。
首先需要在document对象的C++实现中增加onsystemevent成员,如下:
在Source/WebCore/dom/Document.cpp中加入:
/*
add by junhai.xiao 20140115
为document 增加两个成员onsystemnotify onsystemevent
以下是这两个成员对应的C函数,
其实调用了onsystemnotify来注册listener
*/
EventListener* Document::onsystemevent()
{
return getAttributeEventListener(eventNames().systemnotifyEvent);
}

void Document::setOnsystemevent(PassRefPtr listener)
{
setAttributeEventListener(eventNames().systemnotifyEvent, listener);
}
/*add end*/
相应的头文件也加入声明。
注意在Document.idl中加入对onsystemnotify属性的声明。
/*add by junhai.xiao 20140115
为document 增加两个成员onsystemnotify onsystemevent
两个成员其实是一样的,onsystemevent最终调用onsystemnotify
*/
attribute [NotEnumerable] EventListener onsystemnotify;
attribute [NotEnumerable] EventListener onsystemevent; //onsystemevent 和onsystemnotify一样
/*add end*/

到此为止,已经为document添加了onsystemevent属性。
下一步需要在event对象中加入新的事件类型:SYSTEMNOTIFY,以及系统事件需要存储的事件变量:, m_systemnotify_value,m_modifiers
在Event.h中的EventType枚举中加入:
SYSTEMNOTIFY= 65536,/*add by junhai.xiao 增加一个系统信息类型*
在方法声明中加入:

/*add by junhai.xiao 增加以便上层获知是否有JS处理该事件*/
unsigned int modifiers() const { return m_modifiers; }/*在js中可以调用*/
void set_modifiers(unsigned int modifiers){ m_modifiers =modifiers; }
void set_systemnotify_value(unsigned int systemnotify_val){ m_systemnotify_value = https://www.it610.com/article/systemnotify_val; }
const unsigned int get_systemnotify_value() const { return m_systemnotify_value; }
/*add end*/
event对应的idl中加入相应的信息。

现在event对象中也有我们需要的自定义属性了。
下一步是需要实现C++产生新的事件的代码了。
在PlatformKeyboardEventGtk.cpp加入:
bool PlatformKeyboardEvent::isGdkSystemEvent() const
{
//if(m_gdkEventKey->type == GDK_CLIENT_EVENT)
{
if(m_gdkEventKey->keyval == 0xfefeffff)
{
return true;
}
}

return false;
}

int PlatformKeyboardEvent::getGdkEventState () const
{
return (int)m_gdkEventKey->state;
}

在EventHandler.cpp中加入:
bool EventHandler::systemNotifyEvent(int type, int value, int modify)
{
if (!(m_frame->document()))
return false;

RefPtr node = eventTargetNodeForDocument(m_frame->document());
if (!node)
return false;

ExceptionCode ec;
const String keyIdentifier(" ");

RefPtr systemevent = \
KeyboardEvent::create(eventNames().systemnotifyEvent, true, false, \
m_frame->document()->defaultView(),\
keyIdentifier, 0, false, false, false,
false, false);

systemevent->set_modifiers(modify);
systemevent->set_systemnotify_value(value); /*相当于设置keycode*/
systemevent->setTarget(m_frame->document());

m_frame->document()->dispatchEvent(systemevent, ec);

return true;
}
keyEvent方法加入:
/*由于外部不能直接调用systemNotifyEvent,固由keyevent传递systemevent*/
if(initialKeyEvent.isGdkSystemEvent())
{
printf("[WEBKIT]System Event Get!\n");
bool ret;
WEBCORE_SYSTEM_EVENT_S *systemevent = (WEBCORE_SYSTEM_EVENT_S *)initialKeyEvent.getGdkEventState();

ret = systemNotifyEvent(systemevent->type,systemevent->value,systemevent->modify);
free(systemevent);

return ret;
}
到此webkit中的实现就完成了。
因为这个事GTK+WEBKIT的实现,当需要发生系统事件给js时,可以通过调用GTK的按键发送接口,配置按键类型为SYSTEMNOTIFY,利用state作为私有数据。
例如:
GdkEvent gdkevent;

memset(&gdkevent, 0, sizeof(GdkEvent));

WEBCORE_SYSTEM_EVENT_S *systemevent = (WEBCORE_SYSTEM_EVENT_S*)malloc(sizeof(WEBCORE_SYSTEM_EVENT_S));
memset(systemevent, 0x00, sizeof(WEBCORE_SYSTEM_EVENT_S));
systemevent->type = type;
systemevent->value = https://www.it610.com/article/value;
systemevent->modify = modify;

gdkevent.key.type = GDK_KEY_PRESS;
gdkevent.key.keyval = WEBKIT_SYSTEMEVENT;
gdkevent.key.hardware_keycode = 4;
gdkevent.key.string = "";
gdkevent.key.length = 0;
gdkevent.key.state = systemevent;
gdkevent.key.window = gtk_widget_get_window(GTK_WIDGET(browser_window[0].web_view));

gdk_event_put(&gdkevent);
gtk_widget_queue_draw(browser_window[0].window);
如此,webkit收到gtk的按键,在eventhandle的keyevent方法中判断是systemevent就将这个event交给systemNotifyEvent方法 通过document的dispatchEvent方法送给js处理。




【给webkit增加一个系统事件】write by tsunami!

    推荐阅读