layoutMap->map進行映射。映射實際是由KeyLayoutMap::map完成的,KeyLayoutMap類里讀取配置文件qwerty.kl,由配置文件qwerty.kl決定鍵值的映射關(guān)系。你可以通過修改./development/emulator/keymaps/qwerty.kl來改變鍵值的映射關(guān)系。JNI函數(shù)在frameworks/base/services/jni/com_android_se" />

欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

Android事件處理分析

系統(tǒng) 1991 0

按鍵事件

對于按鍵事件,調(diào)用mDevices->layoutMap->map進行映射。映射實際是由 KeyLayoutMap::map完成的,KeyLayoutMap類里讀取配置文件qwerty.kl,由配置 文件 qwerty.kl 決定鍵值的映射關(guān)系。你可以通過修 改./development/emulator/keymaps/qwerty.kl來改變鍵值的映射關(guān)系。

JNI 函數(shù)
在 frameworks/base/services/jni/com_android_server_KeyInputQueue.cpp文 件中,向 JAVA提供了函數(shù)android_server_KeyInputQueue_readEvent,用于讀 取輸入設(shè)備事件。
C代碼:

<!-- <br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> static jbooleanandroid_server_KeyInputQueue_readEvent(JNIEnv * env,jobjectclazz,
jobject
event )
{
gLock.
lock ();
sphub
= gHub;
if (hub == NULL){
hub
= new EventHub;
gHub
= hub;
}
gLock.unlock();
int32_tdeviceId;
int32_ttype;
int32_tscancode,keycode;
uint32_tflags;
int32_tvalue;
nsecs_twhen;
bool res = hub -> getEvent( & deviceId, & type, & scancode, & keycode,
& flags, & value, & when);
env
-> SetIntField( event ,gInputOffsets.mDeviceId,(jint)deviceId);
env
-> SetIntField( event ,gInputOffsets.mType,(jint)type);
env
-> SetIntField( event ,gInputOffsets.mScancode,(jint)scancode);
env
-> SetIntField( event ,gInputOffsets.mKeycode,(jint)keycode);
env
-> SetIntField( event ,gInputOffsets.mFlags,(jint)flags);
env
-> SetIntField( event ,gInputOffsets.mValue,value);
env
-> SetLongField( event ,gInputOffsets.mWhen,
(jlong)(nanoseconds_to_milliseconds(when)));
return res;
}

readEvent調(diào)用hub->getEvent讀了取事件,然后轉(zhuǎn)換成JAVA的結(jié)構(gòu)。

事件中轉(zhuǎn)線程
在frameworks/base/services/java/com/android/server/KeyInputQueue.java 里創(chuàng)建了一個線程,它循環(huán)的讀取事件,然后把事件放入事件隊列里。
Java代碼:

<!-- <br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />-->

Thread mThread = new Thread("InputDeviceReader") {
public void run() {
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

try {
RawInputEvent ev = new RawInputEvent();
while (true) {
InputDevice di;

// block, doesn't release the monitor
readEvent(ev);

boolean send = false;
boolean configChanged = false;

if (false) {
Log.i(TAG, "Input event: dev=0x"
+ Integer.toHexString(ev.deviceId)
+ " type=0x" + Integer.toHexString(ev.type)
+ " scancode=" + ev.scancode
+ " keycode=" + ev.keycode
+ " value=" + ev.value);
}

if (ev.type == RawInputEvent.EV_DEVICE_ADDED) {
synchronized (mFirst) {
di = newInputDevice(ev.deviceId);
mDevices.put(ev.deviceId, di);
configChanged = true;
}
}

            ......
          }
        }
      }
};

按鍵、觸摸屏流、軌跡球程分析

輸入事件分發(fā)線程
在frameworks/base/services/java/com/android/server/WindowManagerService.java里創(chuàng)建了一個輸入事件分發(fā)線程,它負(fù)責(zé)把事件分發(fā)到相應(yīng)的窗口上去。


按鍵觸摸屏流程分析:

WindowManagerService類的構(gòu)造函數(shù)

WindowManagerService()

mQueue = new KeyQ();

因為 WindowManagerService.java (frameworks/base/services/java/com/android/server)中有:

private class KeyQ extends KeyInputQueue implements KeyInputQueue.FilterCallback

KeyQ 是抽象類 KeyInputQueue 的實現(xiàn),所以 new KeyQ類的時候?qū)嶋H上在 KeyInputQueue 類中創(chuàng)建了一個線程 InputDeviceReader 專門用來從設(shè)備讀取按鍵事件,

代碼:

<!-- <br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> ThreadmThread = new Thread( " InputDeviceReader " ){

public void run(){

// 在循環(huán)中調(diào)用:
     readEvent(ev);
...
send
= preprocessEvent(di,ev);
//實際調(diào)用的是KeyQ類的preprocessEvent函數(shù)
...
int keycode = rotateKeyCodeLocked(ev.keycode);
int []map = mKeyRotationMap;

for ( int i = 0 ;i < N;i += 2 ){

if (map == keyCode)

return map[i + 1 ];

}
//

addLocked(di,curTime,ev.flags,RawInputEvent.CLASS_KEYBOARD,
newKeyEvent(di,di.mDownTime,curTime,down,keycode,
0 ,scancode,...));

QueuedEventev
= obtainLocked(device,when,flags,classType,event);
}
};

readEvent() 實際上調(diào)用的是 com_android_server_KeyInputQueue.cpp (frameworks/base/services/jni)中的

static jboolean android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,jobject event) 來讀取事件,

bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,&flags, &value, &when)調(diào)用的是EventHub.cpp (frameworks/base/libs/ui)中的:

bool EventHub::getEvent (int32_t* outDeviceId, int32_t* outType,

int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,

int32_t* outValue, nsecs_t* outWhen)

在函數(shù)中調(diào)用了讀設(shè)備操作:res = read(mFDs.fd, &iev, sizeof(iev));

在構(gòu)造函數(shù) WindowManagerService()調(diào)用 new KeyQ() 以后接著調(diào)用了:

mInputThread = new InputDispatcherThread();
...

mInputThread.start();

來啟動一個線程 InputDispatcherThread

run()
process();
QueuedEvent ev = mQueue.getEvent(...)

因為WindowManagerService類中: final KeyQ mQueue;

所以實際上 InputDispatcherThread 線程實際上從 KeyQ 的事件隊列中讀取按鍵事件,在process() 方法中進行處理事件。

switch (ev.classType)
case RawInputEvent.CLASS_KEYBOARD:
...
dispatchKey((KeyEvent)ev.event, 0, 0);
mQueue.recycleEvent(ev);
break;
case RawInputEvent.CLASS_TOUCHSCREEN:
//Log.i(TAG, "Read next event " + ev);
dispatchPointer(ev, (MotionEvent)ev.event, 0, 0);
break;

 case RawInputEvent.CLASS_TRACKBALL:
dispatchTrackball(ev, (MotionEvent)ev.event, 0, 0);
break;

===============================================================

補充一些內(nèi)容:

在寫程序時,需要捕獲KEYCODE_HOME、KEYCODE_ENDCALL、KEYCODE_POWER這幾個按鍵,但是這幾個按鍵系統(tǒng)做了特殊處理,

在進行dispatch之前做了一些操作,HOME除了Keygaurd之外,不分發(fā)給任何其他APP,ENDCALL和POWER也類似,所以需要我們系統(tǒng)

處理之前進行處理。

我的做法是自己定義一個FLAG,在自己的程序中添加此FLAG,然后在WindowManagerServices.java中獲取當(dāng)前窗口的FLAG屬性,如果是我

們自己設(shè)置的那個FLAG,則不進行特殊處理,直接分發(fā)按鍵消息到我們的APP當(dāng)中,由APP自己處理。

這部分代碼最好添加在

@Override
boolean preprocessEvent(InputDevice device, RawInputEvent event)

方法中,這個方法是KeyInputQueue中的一個虛函數(shù),在處理按鍵事件之前的一個“預(yù)處理”。

PS:對HOME鍵的處理好像必需要修改PhoneWindowManager.java中的interceptKeyTi方法,具體可以參考對KeyGuard程序的處理。

===============================================================

系統(tǒng)底層事件處理過程


在系統(tǒng)啟動后,android 會通過

static const char *device_path = "/dev/input";

bool EventHub::penPlatformInput(void)

res = scan_dir(device_path);

通過下面的函數(shù)打開設(shè)備。

<!-- <br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> int EventHub::pen_device( const char * deviceName)
{
...
fd
= open(deviceName,O_RDWR);
...
mFDs[mFDCount].fd
= fd;
mFDs[mFDCount].events
= POLLIN;
...
ioctl(mFDs[mFDCount].fd,EVIOCGNAME(
sizeof (devname) - 1 ),devname);
...
const char * root = getenv( " ANDROID_ROOT " );
snprintf(keylayoutFilename,
sizeof (keylayoutFilename),
" %s/usr/keylayout/%s.kl " ,root,tmpfn);
...
device
-> layoutMap -> load(keylayoutFilename);
...
}

打開設(shè)備的時候,如果 device->classes&CLASS_KEYBOARD 不等于 0 表明是鍵盤。

常用輸入設(shè)備的定義有:

enum {
CLASS_KEYBOARD = 0x00000001, //鍵盤

CLASS_ALPHAKEY = 0x00000002, //

CLASS_TOUCHSCREEN = 0x00000004, //觸摸屏

CLASS_TRACKBALL = 0x00000008 //軌跡球
};

打開鍵盤設(shè)備的時候通過上面的 ioctl 獲得設(shè)備名稱,命令字 EVIOCGNAME 的定義在文件:

kernel/include/linux/input.h 中。

#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */

在內(nèi)核鍵盤驅(qū)動文件 drivers/input/keyboard/pxa27x_keypad.c 中定義了設(shè)備名稱:pxa27x-keypad

static struct platform_driver pxa27x_keypad_driver = {

.probe = pxa27x_keypad_probe,

.remove = __devexit_p(pxa27x_keypad_remove),

.suspend = pxa27x_keypad_suspend,

.resume = pxa27x_keypad_resume,

.driver = {

.name = "pxa27x-keypad",

.owner = THIS_MODULE,

},

};

ANDROID_ROOT 為環(huán)境變量,在android的命令模式下通過 printenv 可以知道它為: system

所以 keylayoutFilename 為:/system/usr/keylayout/pxa27x-keypad.kl

pxa27x-keypad.kl 定義了按鍵映射,具體內(nèi)容如下:

<!-- <br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> #NUMERICKEYS3x4
key
2 1
key
3 2
key
4 3
key
5 4
key
6 5
key
7 6
key
8 7
key
9 8
key
10 9
key
11 0
key
83 POUND
key
55 STAR

#FUNCTIONALKEYS
key
231 MENUWAKE_DROPPED
key
192 BACKWAKE_DROPPED
key
193 HOMEWAKE
key
107 DELWAKE
key
102 CALLWAKE_DROPPED
key
158 ENDCALLWAKE_DROPPED
key
28 DPAD_CENTERWAKE
key
115 VOLUME_UP
key
114 VOLUME_DOWN

如果沒有定義鍵盤映射文件,那么默認(rèn)使用系統(tǒng)的 /system/usr/keylayout/qwerty.kl 可以修改 /system/usr/keylayout/qwerty.kl 文件改變Android公司的按鍵映射。

device->layoutMap->load(keylayoutFilename) 調(diào)用的是文件 KeyLayoutMap.cpp (frameworks/base/libs/ui)中的函數(shù):

status_t KeyLayoutMap::load(const char* filename)通過解析 pxa27x-keypad.kl
把按鍵的映射關(guān)系保存在 :KeyedVector<int32_t,Key> m_keys; 中。

當(dāng)獲得按鍵事件以后調(diào)用:
status_t KeyLayoutMap::map(int32_t scancode, int32_t *keycode, uint32_t *flags)

由映射關(guān)系 KeyedVector<int32_t,Key> m_keys 把掃描碼轉(zhuǎn)換成andorid上層可以識別的按鍵。

Android事件處理分析


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美精品99久久久久久人 | 久久精品伊人 | 精品久久久中文字幕一区 | 亚洲一级视频在线观看 | 日本美女一区二区 | 4hc44四虎www在线影院男同 | 色中色资源| 久久夜视频 | 波多野结衣xxxx性精品 | 欧美区一区二区三 | 久久影城| 国产在线观看av | 草草国产成人免费视频 | 污视频免费看网站 | 久热香蕉精品视频在线播放 | 91免费官网| 尤物网站永久在线观看 | 日本视频在线播放 | 狠狠五月 | 欧美一级欧美三级 | 亚洲国产一区二区三区四区五区 | 日本AAA片爽快视频 波多在线 | 蜜桃精品噜噜噜成人av | 99精品视频在线观看免费专区 | 蜜桃av一区二区三区 | 国产午夜精品久久久 | 欧美精品九九99久久在观看 | 比比资源先锋影音网 | 性香港xxxxx免费视频播放 | 精品亚洲欧美高清不卡高清 | 狠狠影院 | 精品国产乱码久久久久久1区2区 | 午夜精品久久久久久久久久久久久 | 欧美日韩中文 | www国产成人免费观看视频,深夜成人网 | jizzyouxxxx| 国产成人综合在线观看 | 四虎4hu | 视频二区 | 精品极品三级久久久久 | 亚洲综合五月天激动情网 |