Android Input Event Dispatching
2011-03-26 15:37
316 查看
The input event dispatch engine is in WindowManagerService.java. WindowManagerService.java creates a thread to read input event from KeyInputQueue.java and dispatches the event to the window which has current focus through binder.
// 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));
If an input event is read, it judges the input event type. Currently support three input event types: key, trackball and pointer. Then according to event type call corresponding dispatch function to the window which has current focus through binder. For example, for key event, it calls the following code.
focus.mClient.dispatchKey(event);
At the lowest level, Android reads the real input event (keyboard, mouse or touch) from Linux input device. The corresponding source code is EventHub.cpp. For key input event, Android maps scan code to key code according to a key layout map file. OEM needs customize the key layout map file to match the needs of his own device. It uses the following method to find out the key layout map file.
// 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 can get the key layout map file name during Android booting, because Android will log the name. The J***A layer wrapper is KeyInputQueue.java which is used by WindowManagerService.java. It calls EventHub.cpp through JNI. com_android_server_KeyInputQueue.cpp is the JNI implementation.
[b]Input Event Processing[/b]
When an activity is to be launched, ActivityManagerService.java calls ActivityThread.java for creating the activity.
activity.attach(appContext, this, getInstrumentation(), r.token, app,
r.intent, r.activityInfo, title, r.parent, r.embeddedID,
r.lastNonConfigurationInstance, config);
Then Activity.java creates a PhoneWindow.java instance to represent the activity. Each PhoneWindow.java contains a DecorView.java instance as the root of any views in the activity.
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
After an activity is created, ActivityManagerService.java calls ActivityThread.java for resume the activity. At this time, ActivityThread.java calls WindowManagerImpl.java to add the DecorView.java instance.
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 news a ViewRoot.java instance. ViewRoot.java has a static member which will be only initialized once for each process. It’s used to let WindowManagerService.java know that there is a process linked now.
if (!mInitialized) {
try {
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(new Binder());
mInitialized = true;
} catch (RemoteException e) {
}
}
After ViewRoot.java instance is created, WindowManagerImpl.java calls its setView API to bind the ViewRoot.java for the DecorView.java.
// do this last because it fires off messages to start doing things
root.setView(view, wparams, panelParentView);
In setView API, ViewRoot.java finally draws the DecorView.java and registers an IWindow instance to WindowManagerService.java.
res = sWindowSession.add(mWindow, attrs,
getHostVisibility(), mCoveredInsets);
After that WindowManagerService.java directly communicates (including dispatching input event) with this IWindow instance in ViewRoot.java. Then ViewRoot.java calls View.java to process input event. For example, for key event, dispatchKeyEvent API in View.java will be called.
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 detects if any key listener is registered for this view. If so, the key event will be handled by the key listener. Otherwise, it calls OnKeyDown/OnKeyUp as usual.
All the key listener implementations are under frameworks/base/core/java/android/text/method folder.
MultiTapKeyListener.java - if the keypad is NUMERIC keypad, this listener is used to transform digit inputs to characters.
QwertyKeyListener.java – if the keypad is QWERTY keypad, this listener is used.
// 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));
If an input event is read, it judges the input event type. Currently support three input event types: key, trackball and pointer. Then according to event type call corresponding dispatch function to the window which has current focus through binder. For example, for key event, it calls the following code.
focus.mClient.dispatchKey(event);
At the lowest level, Android reads the real input event (keyboard, mouse or touch) from Linux input device. The corresponding source code is EventHub.cpp. For key input event, Android maps scan code to key code according to a key layout map file. OEM needs customize the key layout map file to match the needs of his own device. It uses the following method to find out the key layout map file.
// 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 can get the key layout map file name during Android booting, because Android will log the name. The J***A layer wrapper is KeyInputQueue.java which is used by WindowManagerService.java. It calls EventHub.cpp through JNI. com_android_server_KeyInputQueue.cpp is the JNI implementation.
[b]Input Event Processing[/b]
When an activity is to be launched, ActivityManagerService.java calls ActivityThread.java for creating the activity.
activity.attach(appContext, this, getInstrumentation(), r.token, app,
r.intent, r.activityInfo, title, r.parent, r.embeddedID,
r.lastNonConfigurationInstance, config);
Then Activity.java creates a PhoneWindow.java instance to represent the activity. Each PhoneWindow.java contains a DecorView.java instance as the root of any views in the activity.
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
After an activity is created, ActivityManagerService.java calls ActivityThread.java for resume the activity. At this time, ActivityThread.java calls WindowManagerImpl.java to add the DecorView.java instance.
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 news a ViewRoot.java instance. ViewRoot.java has a static member which will be only initialized once for each process. It’s used to let WindowManagerService.java know that there is a process linked now.
if (!mInitialized) {
try {
sWindowSession = IWindowManager.Stub.asInterface(
ServiceManager.getService("window"))
.openSession(new Binder());
mInitialized = true;
} catch (RemoteException e) {
}
}
After ViewRoot.java instance is created, WindowManagerImpl.java calls its setView API to bind the ViewRoot.java for the DecorView.java.
// do this last because it fires off messages to start doing things
root.setView(view, wparams, panelParentView);
In setView API, ViewRoot.java finally draws the DecorView.java and registers an IWindow instance to WindowManagerService.java.
res = sWindowSession.add(mWindow, attrs,
getHostVisibility(), mCoveredInsets);
After that WindowManagerService.java directly communicates (including dispatching input event) with this IWindow instance in ViewRoot.java. Then ViewRoot.java calls View.java to process input event. For example, for key event, dispatchKeyEvent API in View.java will be called.
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 detects if any key listener is registered for this view. If so, the key event will be handled by the key listener. Otherwise, it calls OnKeyDown/OnKeyUp as usual.
All the key listener implementations are under frameworks/base/core/java/android/text/method folder.
MultiTapKeyListener.java - if the keypad is NUMERIC keypad, this listener is used to transform digit inputs to characters.
QwertyKeyListener.java – if the keypad is QWERTY keypad, this listener is used.
相关文章推荐
- Android Input Event Dispatching
- Android Input Event Dispatching
- Android App层通过JNI从驱动获取Input Event
- android getevent、sendevent、input keyevent 使用说明
- android input设备event处理以及hotplug检测
- 在 Android 通过 get_event 获得 input 设备 上报event
- Android 4.0 事件输入(Event Input)系统
- Android 4.0 事件输入(Event Input)系统
- Android 4.0 事件输入(Event Input)系统
- Android 4.0 事件输入(Event Input)系统
- Android 4.0 事件输入(Event Input)系统
- Android 4.0 事件输入(Event Input)系统
- Linux/Android——输入子系统input_event传递 (二)
- android input设备event处理以及hotplug检测
- Android 的Input Event 子系统的来龙去脉
- [android] 调试linux input子系统驱动的用户空间命令 getevent/sendevent
- Android 4.0 事件输入(Event Input)系统
- Android 4.0 事件输入(Event Input)系统
- Linux/Android——输入子系统input_event传递 (二)
- Android 下收发input事件的工具 getevent 和 sendevent