您的位置:首页 > 移动开发 > Android开发

StevGuo系列文章翻译之Android中的输入事件如何分发

2010-12-17 20:16 691 查看
了解老码农个人隐私,请看这里:http://www.koulianbing.com/?page_id=12

输入事件分发的源头在WindowManagerService.java中,它创建了一个线程从KeyInputQueue.java中读取输入事件并通过Binder分发给当前聚焦的Window:

// Retrieve next event, waiting only
as long as the next repeat timeout. If the configuration has changed, then don't wait at all -- we'll report the change as soon as we have processed all events.

QueuedEvent ev = mQueue.getEvent(

(int)((!configChanged && curTime < nextKeyTime)

? (nextKeyTime-curTime) : 0));

读取到一个输入事件后,它会判断事件的类型,并根据类型调用相应的分发方法分发到Window。现在只支持三种类型:按键、轨迹球和触摸。例如,对于按键事件来说,它调用以下代码:

focus.mClient.dispatchKey(event);

在最底层,Android从Linux输入设备中读取真正的事件,相应的代码在EventHub.cpp中。对按键事件来说,Android通过一个按键键盘布局映射表文件把scan
code转换成key code。OEM需要根据自己的设备更改这个键盘布局映射表文件。OEM使用下面的方法找到键盘布局映射表文件:

// a more descriptive name

ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);

devname[sizeof(devname)-1] = 0;

device->name = devname;



// replace all the spaces with underscores

strcpy(tmpfn, devname);

for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))

*p = '_';



// find the .kl file we need for this device

const char* root = getenv("ANDROID_ROOT");

snprintf(keylayoutFilename, sizeof(keylayoutFilename),

"%s/usr/keylayout/%s.kl", root, tmpfn);

bool defaultKeymap = false;

if (access(keylayoutFilename, R_OK)) {

snprintf(keylayoutFilename, sizeof(keylayoutFilename),

"%s/usr/keylayout/%s", root, "qwerty.kl");

defaultKeymap = true;

}

device->layoutMap->load(keylayoutFilename);

OEM可以在Android启动时得到键盘布局映射表文件,因为Android会在启动时打印它的名字。Java层对它的包装是KeyInputQueue.java,而KeyInputQueue.java是供WindowManagerService.java使用的。KeyInputQueue.java通过JNI调用EventHub.cpp。而com_android_server_KeyInputQueue.cpp是JNI实现。



当一个Activity启动时,ActivityManagerService.java调用ActivityThread.java创建activity:

activity.attach(appContext, this, getInstrumentation(), r.token, app,

r.intent, r.activityInfo, title, r.parent, r.embeddedID,

r.lastNonConfigurationInstance, config);

接下来,Activity.java创建一个代表这个activity的PhoneWindow.java实例。Activity中每一个PhoneWindow.java包含一个DecorView.java实例作为View树的根:

mWindow = PolicyManager.makeNewWindow(this);

mWindow.setCallback(this);

当activity被创建后,ActivityManagerService.java调用ActivityThread.java来resume这个activity。这时,ActivityThread.java调用WindowManagerImpl.java添加DecorView.java:

r.window = r.activity.getWindow();

View decor = r.window.getDecorView();

decor.setVisibility(View.INVISIBLE);

ViewManager wm = a.getWindowManager();

WindowManager.LayoutParams l = r.window.getAttributes();

a.mDecor = decor;

l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;

wm.addView(decor, l);

WindowManagerImpl.java创建了一个ViewRoot.java实例。ViewRoot有一个对每个进程初始化一次的静态成员。通过它,WindowManagerService.java可以知道,现在有一个进程被连接了:

if (!mInitialized) {

try {

sWindowSession = IWindowManager.Stub.asInterface(

ServiceManager.getService("window"))

.openSession(new Binder());

mInitialized = true;

} catch (RemoteException e) {

}

}

ViewRoot.java实例被创建后,WindowManagerImpl.java会调用它的setView为DecorView.java绑定ViewRoot.java:

// do this last because it fires off messages to start doing things

root.setView(view, wparams, panelParentView);

在setView中,ViewRoot.java最后会渲染DecorView.java,然后注册一个IWindow实例到WindowManagerService.java中:

res = sWindowSession.add(mWindow, attrs,

getHostVisibility(), mCoveredInsets);

接下来,WindowManagerService.java直接与ViewRoot.java中的IWindow实例通信。然后,ViewRoot.java调用View.java处理输入事件。例如,对按键事件来说,View中的dispatchKeyEvent会被调用:

public boolean dispatchKeyEvent(KeyEvent event) {

// If any attached key listener a first crack at the event.

//noinspection SimplifiableIfStatement

if (mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED

&& mOnKeyListener.onKey(this, event.getKeyCode(), event)) {

return true;

}



return event.dispatch(this);

}

View.java检查是否有按键监听器注册到了这个view。如果有的话,按键事件会被监听器处理。否则,就调用onKeyDown/onKeyUp。



所有的按键监听器的实现都在/frameworks/base/core/java/android/text/method文件夹中:

MultiTapKeyListener.java:如果键盘是数字键盘的话,这个监听器可以把数字输入转化成字符。
QwertyKeyListener.java:如果键盘是QWERTY键盘的话,会使用这个监听器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: