layoutMap->map進(jìn)行映射。映射實(shí)際是由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" />

亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

Android事件處理分析

系統(tǒng) 2118 0

按鍵事件

對于按鍵事件,調(diào)用mDevices->layoutMap->map進(jìn)行映射。映射實(shí)際是由 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)建了一個(gè)線程,它循環(huán)的讀取事件,然后把事件放入事件隊(duì)列里。
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)建了一個(gè)輸入事件分發(fā)線程,它負(fù)責(zé)把事件分發(fā)到相應(yīng)的窗口上去。


按鍵觸摸屏流程分析:

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

WindowManagerService()

mQueue = new KeyQ();

因?yàn)?WindowManagerService.java (frameworks/base/services/java/com/android/server)中有:

private class KeyQ extends KeyInputQueue implements KeyInputQueue.FilterCallback

KeyQ 是抽象類 KeyInputQueue 的實(shí)現(xiàn),所以 new KeyQ類的時(shí)候?qū)嶋H上在 KeyInputQueue 類中創(chuàng)建了一個(gè)線程 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);
//實(shí)際調(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() 實(shí)際上調(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();

來啟動一個(gè)線程 InputDispatcherThread

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

因?yàn)閃indowManagerService類中: final KeyQ mQueue;

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

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;

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

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

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

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

處理之前進(jìn)行處理。

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

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

這部分代碼最好添加在

@Override
boolean preprocessEvent(InputDevice device, RawInputEvent event)

方法中,這個(gè)方法是KeyInputQueue中的一個(gè)虛函數(shù),在處理按鍵事件之前的一個(gè)“預(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è)備的時(shí)候,如果 device->classes&CLASS_KEYBOARD 不等于 0 表明是鍵盤。

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

enum {
CLASS_KEYBOARD = 0x00000001, //鍵盤

CLASS_ALPHAKEY = 0x00000002, //

CLASS_TOUCHSCREEN = 0x00000004, //觸摸屏

CLASS_TRACKBALL = 0x00000008 //軌跡球
};

打開鍵盤設(shè)備的時(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元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 久久国产免费 | 成年人性生活免费视频 | 国产色a在线观看 | 伊人色综合一区二区三区 | 色偷偷777 | 日韩亚洲欧洲在线rrrr片 | 国产成人综合亚洲亚洲欧美 | 色青青草原桃花久久综合 | 美女被爆羞羞视频网站视频 | 日本激情视频一区二区三区 | 亚洲第一se情网站 | 亚洲视频在线网 | 日韩欧美视频一区 | 欧美色欧美亚洲高清在线观看 | 99久久免费费视频在线观看 | 色综合欧美色综合七久久 | 亚洲一区二区三区在线 | 亚洲和欧美毛片久久久久 | 欧美另类videos粗暴黑人 | 天天插天天操天天干 | 国产成人经典三级在线观看 | 国产在线乱子伦一区二区 | 欧美白人猛性xxxxx交69 | 福利免费在线 | 久久久久久噜噜噜久久久精品 | 老妇激情毛片免费中国 | 毛片免费毛片一级jjj毛片 | 香蕉成人啪国产精品视频综合网 | h片网站在线观看 | 国产成人久久综合热 | 九九热国产 | 国产一级久久久久久毛片 | 香蕉国产人午夜视频在线观看 | 美女被羞羞产奶视频网站 | 特级中国aaa毛片 | 久久久久免费精品国产小说 | 免费久 | 久久久亚洲欧洲日产国码二区 | 国产精品视频福利视频网 | 黑人特级粗α级毛片 | 四虎影视国产精品婷婷 |