1. 程式人生 > >Android按鍵訊息處理

Android按鍵訊息處理

Android按鍵訊息處理

    在android系統中,鍵盤按鍵事件是由SystemServer服務來管理的;然後在以訊息的形式分發給應用程式處理。產生鍵盤按鍵事件則是有Linux kernel的相關驅動來實現。

     鍵盤訊息有別於其他型別的訊息;需要從Linux kernel drivers產生由上層app來處理。同時按鍵有著不同的對映值,因此從模組獨立性角度各個獨立的模組應該擁有不同的鍵盤對映。這樣以來,kernel產生的按鍵事件必然回經過不同的對映才到app

1kernel中同按鍵相關程式碼

    Android 使用標準的linux 

輸入事件裝置(/dev/input/)和驅動按鍵定義在linux 核心include/linux/input.h ,按鍵的定義形式如下(僅以BACK HOME MENU為例):


    有了按鍵的定義,就需要產生相應的按鍵事件了。在kernel/arch/arm/mach-msm/xxx/xxx/xxx.c會對BACK HOMEMENU進行註冊。這裡使用在螢幕上的座標來對按鍵進行區分。這部分程式碼會在系統啟動的時候,將相應的資料儲存,以供framework查詢。

(這裡以xxx代替,是因為針對不同的硬體,需要的Linux kernel不同)


當然從核心板原理圖到

kernel是屬於驅動範疇,不討論。

2framework針對鍵盤事件的處理

    上層對輸入事件的偵聽和分發是在InputManagerService 中實現

    首先來看看InputManagerService的建立,

Step 1

SystemServer.java

點選(此處)摺疊或開啟

  1. class ServerThread extends Thread {
  2.     //省略。。
  3.     public void run() {
  4.         // Create a handler thread just for the window manager to enjoy.

  5.         HandlerThread wmHandlerThread = new HandlerThread("WindowManager");
  6.         wmHandlerThread.start();
  7.         Handler wmHandler = new Handler(wmHandlerThread.getLooper());
  8.         //此處省略5k字。。
  9.         Slog.i(TAG, "Input Manager");
  10.         inputManager = new InputManagerService(context, wmHandler);
  11.     }
  12. }

可以看到,在系統啟動的時候,會首先建立一個系統級別的Handler執行緒wmHandlerThread用於處理鍵盤訊息(僅說明鍵盤訊息)。然後在建立輸入管理服務inputManagerInputManagerService 的第二個引數就是用於處理按鍵訊息的Handler

Step 2

在往下走到InputManagerService.java的建構函式。

點選(此處)摺疊或開啟

  1. public InputManagerService(Context context, Handler handler) {
  2.     this.mContext = context;
  3.     this.mHandler = new InputManagerHandler(handler.getLooper());
  4.     mUseDevInputEventForAudioJack =
  5.                 context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
  6.     Slog.i(TAG, "Initializing input manager, mUseDevInputEventForAudioJack="
  7.                     + mUseDevInputEventForAudioJack);
  8.     mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
  9. }

這裡做了重要的兩件事情,第一:將SystemServer級別的Handler賦值給InputManagerService自己的訊息處理Handler;第二:呼叫nativeInit繼續進行初始化。

Step 3

com_android_server_ InputManagerService.cpp

點選(此處)摺疊或開啟

  1. static jint nativeInit(JNIEnv* env, jclass clazz,
  2.     jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
  3.     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
  4.     NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
  5.     messageQueue->getLooper());
  6.     im->incStrong(serviceObj);
  7.     return reinterpret_cast<jint>(im);
  8. }

這裡nativeInit直接呼叫了NativeInputManager的建構函式

Step 4

點選(此處)摺疊或開啟

  1. NativeInputManager::NativeInputManager(jobject contextObj,
  2.     jobject serviceObj, const sp<Looper>& looper) :
  3.     mLooper(looper) {
  4.     JNIEnv* env = jniEnv();
  5.     mContextObj = env->NewGlobalRef(contextObj);
  6.     mServiceObj = env->NewGlobalRef(serviceObj);
  7.     {
  8.         AutoMutex _l(mLock);
  9.         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
  10.         mLocked.pointerSpeed = 0;
  11.         mLocked.pointerGesturesEnabled = true;
  12.         mLocked.showTouches = false;
  13.     }
  14.     sp<EventHub> eventHub = new EventHub();
  15.     mInputManager = new InputManager(eventHub, this, this);
  16. }

這裡需要特別注意最後兩行程式碼。第一:建立了EventHub;第二:建立InputManager並將EventHub作為引數傳入InputManager

Step 5

接下來繼續看看InputManager的建構函式。

點選(此處)摺疊或開啟

  1. InputManager::InputManager(
  2.     const sp<EventHubInterface>& eventHub,
  3.     const sp<InputReaderPolicyInterface>& readerPolicy,
  4.     const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
  5.         mDispatcher = new InputDispatcher(dispatcherPolicy);
  6.         mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
  7.         initialize();
  8. }
  9. void InputManager::initialize() {
  10.     mReaderThread = new InputReaderThread(mReader)