Android按鍵訊息處理
Android按鍵訊息處理
在android系統中,鍵盤按鍵事件是由SystemServer服務來管理的;然後在以訊息的形式分發給應用程式處理。產生鍵盤按鍵事件則是有Linux kernel的相關驅動來實現。
鍵盤訊息有別於其他型別的訊息;需要從Linux kernel drivers產生由上層app來處理。同時按鍵有著不同的對映值,因此從模組獨立性角度各個獨立的模組應該擁有不同的鍵盤對映。這樣以來,kernel產生的按鍵事件必然回經過不同的對映才到app。
1、kernel中同按鍵相關程式碼
Android 使用標準的linux
有了按鍵的定義,就需要產生相應的按鍵事件了。在kernel/arch/arm/mach-msm/xxx/xxx/xxx.c會對BACK HOME和MENU進行註冊。這裡使用在螢幕上的座標來對按鍵進行區分。這部分程式碼會在系統啟動的時候,將相應的資料儲存,以供framework查詢。
(這裡以xxx代替,是因為針對不同的硬體,需要的Linux kernel不同)
當然從核心板原理圖到
2、framework針對鍵盤事件的處理
上層對輸入事件的偵聽和分發是在InputManagerService 中實現
首先來看看InputManagerService的建立,
Step 1
在SystemServer.java
點選(此處)摺疊或開啟
- class ServerThread extends Thread {
- //省略。。
- public void run() {
- // Create a handler thread just for the window manager to enjoy.
- HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
- wmHandlerThread.start();
- Handler wmHandler = new Handler(wmHandlerThread.getLooper());
- //此處省略5k字。。
- Slog.i(TAG, "Input
Manager");
- inputManager = new InputManagerService(context, wmHandler);
- }
- }
可以看到,在系統啟動的時候,會首先建立一個系統級別的Handler執行緒wmHandlerThread用於處理鍵盤訊息(僅說明鍵盤訊息)。然後在建立輸入管理服務inputManager,InputManagerService 的第二個引數就是用於處理按鍵訊息的Handler。
Step 2
在往下走到InputManagerService.java的建構函式。
點選(此處)摺疊或開啟
- public InputManagerService(Context context, Handler handler) {
- this.mContext = context;
- this.mHandler = new InputManagerHandler(handler.getLooper());
- mUseDevInputEventForAudioJack =
- context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
- Slog.i(TAG, "Initializing
input manager, mUseDevInputEventForAudioJack="
- + mUseDevInputEventForAudioJack);
- mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
- }
這裡做了重要的兩件事情,第一:將SystemServer級別的Handler賦值給InputManagerService自己的訊息處理Handler;第二:呼叫nativeInit繼續進行初始化。
Step 3
com_android_server_ InputManagerService.cpp
點選(此處)摺疊或開啟
- static jint nativeInit(JNIEnv* env, jclass
clazz,
- jobject serviceObj, jobject
contextObj, jobject messageQueueObj) {
- sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
- NativeInputManager* im = new
NativeInputManager(contextObj, serviceObj,
- messageQueue->getLooper());
- im->incStrong(serviceObj);
- return reinterpret_cast<jint>(im);
- }
這裡nativeInit直接呼叫了NativeInputManager的建構函式
Step 4
點選(此處)摺疊或開啟
- NativeInputManager::NativeInputManager(jobject
contextObj,
- jobject serviceObj, const sp<Looper>& looper) :
- mLooper(looper) {
- JNIEnv* env = jniEnv();
- mContextObj = env->NewGlobalRef(contextObj);
- mServiceObj = env->NewGlobalRef(serviceObj);
- {
- AutoMutex _l(mLock);
- mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
- mLocked.pointerSpeed = 0;
- mLocked.pointerGesturesEnabled = true;
- mLocked.showTouches = false;
- }
- sp<EventHub> eventHub = new
EventHub();
- mInputManager = new
InputManager(eventHub, this, this);
- }
這裡需要特別注意最後兩行程式碼。第一:建立了EventHub;第二:建立InputManager並將EventHub作為引數傳入InputManager。
Step 5
接下來繼續看看InputManager的建構函式。
點選(此處)摺疊或開啟
- InputManager::InputManager(
- const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& readerPolicy,
- const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
- mDispatcher = new InputDispatcher(dispatcherPolicy);
- mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
- initialize();
- }
- void InputManager::initialize() {
- mReaderThread = new InputReaderThread(mReader)