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久久久精品国产一区二区 | 亚洲电影在线观看 | 91精品一区二区三区久久久久久 | 国产精品免费观看 | 久久机热综合久久国产 | 国产高清一区二区 | 成人免费一区二区三区视频网站 | 亚洲 中文 欧美 日韩 在线观看 | 九九综合视频 | 特黄视频| 91久久极品| 久久色播| 首页亚洲国产丝袜长腿综合 | 精品久久久一二三区 | 亚洲视频 欧美视频 | 国产AV亚洲精品久久久久 | 成人a视频片在线观看免费 中文字幕三区 | 日韩欧美专区 | 欧美第一色 | 99精品一区二区免费视频 | 亚洲天堂日本 | 一级毛片网 | 91九色视频在线播放 | 无遮挡羞羞视频 | 97日日摸天天碰免费视频 | 久草免费新视频 | 九九九九九热 | 国产成人综合久久 | 欧美一区二区三区免费观看视频 | 国产精品久久久久久久午夜 | 男人添女人下面免费网站 | 亚洲好视频 | 欧美日韩精品一区二区在线播放 | 91视频这里只有精品 | 一级毛片一级毛片一级毛片一级毛片 | 爱人同志国语免费观看全集 | 午夜网页 | 欧美精品免费在线 | www.com黄| 午夜影院在线观看版 |