前言:基于android webview 上定制自己使用的可移植浏览器apk,遇到好多按键处理的问题。所以索性研究了一下keyevent 事件的传递流程。
frameworks 层
keyevent 事件开始是从/frameworks/base/core/java/android/webkit
目录下WebViewClassic.java 中onKeyDown() 函数开始的
// Bubble up the key event if // 1. it is a system key; or // 2. the host application wants to handle it; if ((event.isSystem() || mCallbackProxy.uiOverrideKeyEvent(event))
这个的作用是判断event是不是系统按键,或者调用webview应用处理event。
系统按键直接返回,如果webview应用处理了也直接返回。
其它key事件调用 sendKeyEvent(event),在sendKeyEvent() 函数中又调用
sendBatchableInputMessage()函数在这个函数中的又调用
mWebViewCore.sendMessage(message)
将event封装成Message传递给WebViewCore.java中的EventHub 类
在sendMessage()函数又通过它发送到Handler在transferMessages()
中handleMessage()处理keydown事件
case KEY_DOWN:
key((KeyEvent) msg.obj, msg.arg1, true);
break;
webkit层
key中调用nativeKey() 将事件传入webkit中Source/WebKit/android/jni
WebViewCore.cpp中的
{ "nativeKey", "(IIIIZZZZ)Z", (void*) Key },
WebViewCore::key(const PlatformKeyboardEvent& event)
eventHandler->keyEvent(event);
此时调用进入Source/WebCore/page
EventHandler.cpp
会区分为keyup keydown keypress 事件发送到Node中处理
bool Node::dispatchEvent(PassRefPtr<Event> event) {
return EventDispatcher::dispatchEvent(this, EventDispatchMediator(event));
}
通过中转最终调用到EventDispatcher.cpp中
bool EventDispatcher::dispatchEvent(PassRefPtr<Event> event)
m_node->handleLocalEvents(event.get());
在Node.cpp 中调用
fireEventListeners(event);
class Node : public EventTarget Node继承了EventTarget
EventTarget.cpp中实现注册监听
bool EventTarget::fireEventListeners(Event* event)
registeredListener.listener->handleEvent(scriptExecutionContext(), event);
发送到注册监听的javascript中。
如果在js中注册了一个keypress事件处理而我们要兼容支持它我们可以只动WebViewClassic.java或者在app层代码实现转换并传入js中即可。
在WebViewClassic.java中实现了passVirtualKeyEvent(int KeyCode)。