Android多点触摸.docx
- 文档编号:5949325
- 上传时间:2023-01-02
- 格式:DOCX
- 页数:13
- 大小:20.10KB
Android多点触摸.docx
《Android多点触摸.docx》由会员分享,可在线阅读,更多相关《Android多点触摸.docx(13页珍藏版)》请在冰豆网上搜索。
Android多点触摸
第一章摘要在Linux内核支持的基础上,Android在其2.0源码中加入多点触摸功能。
由此触摸屏在Android的frameworks被完全分为2种实现途径:
单点触摸屏的单点方式,多点触摸屏的单点和多点方式。
第二章软件位在Linux的input.h中,多点触摸功能依赖于以下几个主要的软件位:
………………………..
#defineSYN_REPORT0
#defineSYN_CONFIG1
#defineSYN_MT_REPORT2
………………………...
#defineABS_MT_TOUCH_MAJOR0x30/*Majoraxisoftouchingellipse*/
#defineABS_MT_TOUCH_MINOR0x31/*Minoraxis(omitifcircular)*/
#defineABS_MT_WIDTH_MAJOR0x32/*Majoraxisofapproachingellipse*/
#defineABS_MT_WIDTH_MINOR0x33/*Minoraxis(omitifcircular)*/
#defineABS_MT_ORIENTATION0x34/*Ellipseorientation*/
#defineABS_MT_POSITION_X0x35/*CenterXellipseposition*/
#defineABS_MT_POSITION_Y0x36/*CenterYellipseposition*/
#defineABS_MT_TOOL_TYPE0x37/*Typeoftouchingdevice*/
#defineABS_MT_BLOB_ID0x38/*Groupasetofpacketsasablob*/
…………………………
在Android中对应的软件位定义在RawInputEvent.java中:
…………………..
publicclassRawInputEvent{
……………….
publicstaticfinalintCLASS_TOUCHSCREEN_MT=0x00000010;
………………..
publicstaticfinalintABS_MT_TOUCH_MAJOR=0x30;
publicstaticfinalintABS_MT_TOUCH_MINOR=0x31;
publicstaticfinalintABS_MT_WIDTH_MAJOR=0x32;
publicstaticfinalintABS_MT_WIDTH_MINOR=0x33;
publicstaticfinalintABS_MT_ORIENTATION=0x34;
publicstaticfinalintABS_MT_POSITION_X=0x35;
publicstaticfinalintABS_MT_POSITION_Y=0x36;
publicstaticfinalintABS_MT_TOOL_TYPE=0x37;
publicstaticfinalintABS_MT_BLOB_ID=0x38;
………………….
publicstaticfinalintSYN_REPORT=0;
publicstaticfinalintSYN_CONFIG=1;
publicstaticfinalintSYN_MT_REPORT=2;
………………..
在Android中,多点触摸的实现方法在具体的代码实现中和单点是完全区分开的。
在Android代码的EventHub.cpp中,单点屏和多点屏由如下代码段来判定:
intEventHub:
:
open_device(constchar*deviceName)
{
………………………
if(test_bit(ABS_MT_TOUCH_MAJOR,abs_bitmask)
&&test_bit(ABS_MT_POSITION_X,abs_bitmask)
&&test_bit(ABS_MT_POSITION_Y,abs_bitmask)){
device->classes|=CLASS_TOUCHSCREEN|CLASS_TOUCHSCREEN_MT;
//LOGI("Itisamulti-touchscreen!
");
}
//single-touch?
elseif(test_bit(BTN_TOUCH,key_bitmask)
&&test_bit(ABS_X,abs_bitmask)
&&test_bit(ABS_Y,abs_bitmask)){
device->classes|=CLASS_TOUCHSCREEN;
//LOGI("Itisasingle-touchscreen!
");
}
………………..
}
我们知道,在触摸屏驱动中,通常在probe函数中会调用input_set_abs_params给设备的input_dev结构体初始化,这些input_dev的参数会在Android的EventHub.cpp中被读取。
如上可知,如果我们的触摸屏想被当成多点屏被处理,只需要在驱动中给input_dev额外增加以下几个参数即可:
input_set_abs_params(mcs_data.input,ABS_MT_POSITION_X,pdata->abs_x_min,pdata->abs_x_max,0,0);
input_set_abs_params(mcs_data.input,ABS_MT_POSITION_Y,pdata->abs_y_min,pdata->abs_y_max,0,0);
input_set_abs_params(mcs_data.input,ABS_MT_TOUCH_MAJOR,0,15,0,0);
//相当于单点屏的ABX_PRESSURE
input_set_abs_params(mcs_data.input,ABS_MT_WIDTH_MAJOR,0,15,0,0);
//相当于单点屏的ABS_TOOL_WIDTH
注:
为了让我们的驱动代码支持所有的Android版本,无论是多点屏还是单点屏,一般都会保留单点屏的事件,如ABS_TOUCH,ABS_PRESSURE,ABS_X,ABS_Y等。
另外,由于在Android2.0前支持多点的frameworks大多是用HAT0X,HAT0Y来实现的,所以一般也会上报这2个事件。
第三章同步方式由于多点触摸技术需要采集到多个点,然后再一起处理这些点,所以在软件实现中需要保证每一波点的准确性和完整性。
因此,Linux内核提供了input_mt_sync(structinput_dev*input)函数。
在每波的每个点上报后需要紧跟一句input_mt_sync(),当这波所有点上报后再使用input_sync()进行同步。
例如一波要上报3个点:
/*上报点1*/
……………..
input_mt_sync(input);
/*上报点2*/
……………..
input_mt_sync(input);
/*上报点3*/
……………..
input_mt_sync(input);
input_sync(input);
注:
即使是仅上报一个点的单点事件,也需要一次input_my_sync。
文章出处:
飞诺网():
在Android的KeyInputQueue.java中,系统创建了一个线程,然后把所有的Input事件放入一个队列:
publicabstractclassKeyInputQueue{
……………………
ThreadmThread=newThread("InputDeviceReader"){
publicvoidrun(){
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);
try{
RawInputEventev=newRawInputEvent();
while(true){
InputDevicedi;
//block,doesn'treleasethemonitor
readEvent(ev);
if(ev.type==RawInputEvent.EV_DEVICE_ADDED){
synchronized(mFirst){
di=newInputDevice(ev.deviceId);
mDevices.put(ev.deviceId,di);
configChanged=true;
}
}elseif(ev.type==RawInputEvent.EV_DEVICE_REMOVED){
synchronized(mFirst){
Log.i(TAG,"Deviceremoved:
id=0x"
+Integer.toHexString(ev.deviceId));
di=mDevices.get(ev.deviceId);
if(di!
=null){
mDevices.delete(ev.deviceId);
configChanged=true;
}else{
Log.w(TAG,"Baddeviceid:
"+ev.deviceId);
}
}
}else{
di=getInputDevice(ev.deviceId);
//firstcrackatit
send=preprocessEvent(di,ev);
if(ev.type==RawInputEvent.EV_KEY){
di.mMetaKeysState=makeMetaState(ev.keycode,
ev.value!
=0,di.mMetaKeysState);
mHaveGlobalMetaState=false;
}
}
if(di==null){
continue;
}
if(configChanged){
synchronized(mFirst){
addLocked(di,SystemClock.uptimeMillis(),0,
RawInputEvent.CLASS_CONFIGURATION_CHANGED,
null);
}
}
if(!
send){
continue;
}
synchronized(mFirst){
……………………….
if(type==RawInputEvent.EV_KEY&&
(classes&RawInputEvent.CLASS_KEYBOARD)!
=0&&
(scancode scancode>RawInputEvent.BTN_LAST)){ /*键盘按键事件*/ ……………………. }elseif(ev.type==RawInputEvent.EV_KEY){ /*下面是EV_KEY事件分支,只支持单点的触摸屏有按键事件, *而支持多点的触摸屏没有按键事件,只有绝对坐标事件 */ if(ev.scancode==RawInputEvent.BTN_TOUCH&& (classes&(RawInputEvent.CLASS_TOUCHSCREEN |RawInputEvent.CLASS_TOUCHSCREEN_MT)) ==RawInputEvent.CLASS_TOUCHSCREEN){ /*只支持单点的触摸屏的按键事件*/ ………………………………… }elseif(ev.scancode==RawInputEvent.BTN_MOUSE&& (classes&RawInputEvent.CLASS_TRACKBALL)! =0){ /*鼠标和轨迹球*/ ………………………. }elseif(ev.type==RawInputEvent.EV_ABS&& (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT)! =0){ /*下面才是多点触摸屏上报的事件*/ if(ev.scancode==RawInputEvent.ABS_MT_TOUCH_MAJOR){ di.mAbs.changed=true; di.mAbs.mNextData[di.mAbs.mAddingPointerOffset +MotionEvent.SAMPLE_PRESSURE]=ev.value; }elseif(ev.scancode==RawInputEvent.ABS_MT_POSITION_X){ di.mAbs.changed=true; di.mAbs.mNextData[di.mAbs.mAddingPointerOffset +MotionEvent.SAMPLE_X]=ev.value; }elseif(ev.scancode==RawInputEvent.ABS_MT_POSITION_Y){ di.mAbs.changed=true; di.mAbs.mNextData[di.mAbs.mAddingPointerOffset +MotionEvent.SAMPLE_Y]=ev.value; }elseif(ev.scancode==RawInputEvent.ABS_MT_WIDTH_MAJOR){ di.mAbs.changed=true; di.mAbs.mNextData[di.mAbs.mAddingPointerOffset +MotionEvent.SAMPLE_SIZE]=ev.value; } /*上面这段就是多点触摸屏要用到的事件上报部分; *使用一个数组mNextData来保存,其中di.mAbs.mAddingPointerOffset *是当前点的偏移量,在每个点中还在MotionEvent中定义了X,Y,PRESSURE *SIZE等偏移量,多点触摸屏的压力值由绝对坐标事件ABS_MT_TOUCH_MAJOR确定。 */ }elseif(ev.type==RawInputEvent.EV_ABS&& (classes&RawInputEvent.CLASS_TOUCHSCREEN)! =0){ /*这里是对单点触摸屏上报坐标事件的新的处理方法,同样使用了数组来保存*/ if(ev.scancode==RawInputEvent.ABS_X){ di.mAbs.changed=true; di.curTouchVals[MotionEvent.SAMPLE_X]=ev.value; }elseif(ev.scancode==RawInputEvent.ABS_Y){ di.mAbs.changed=true; di.curTouchVals[MotionEvent.SAMPLE_Y]=ev.value; }elseif(ev.scancode==RawInputEvent.ABS_PRESSURE){ di.mAbs.changed=true; di.curTouchVals[MotionEvent.SAMPLE_PRESSURE]=ev.value; di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA +MotionEvent.SAMPLE_PRESSURE]=ev.value; }elseif(ev.scancode==RawInputEvent.ABS_TOOL_WIDTH){ di.mAbs.changed=true; di.curTouchVals[MotionEvent.SAMPLE_SIZE]=ev.value; di.curTouchVals[MotionEvent.NUM_SAMPLE_DATA +MotionEvent.SAMPLE_SIZE]=ev.value; } …………………………………………….} /*下面是关键的同步处理方法*/ if(ev.type==RawInputEvent.EV_SYN &&ev.scancode==RawInputEvent.SYN_MT_REPORT &&di.mAbs! =null){ /*在这里实现了对SYN_MT_REPORT事件的处理, *改变了di.mAbs.mAddingPointerOffset的值,从而将 *新增的点的参数保存到下一组偏移量的位置。 */ ……………………. finalintnewOffset=(num<=InputDevice.MAX_POINTERS) ? (num*MotionEvent.NUM_SAMPLE_DATA) : (InputDevice.MAX_POINTERS* MotionEvent.NUM_SAMPLE_DATA); di.mAbs.mAddingPointerOffset=newOffset; di.mAbs.mNextData[newOffset +MotionEvent.SAMPLE_PRESSURE]=0; } ………………. }elseif(send||(ev.type==RawInputEvent.EV_SYN &&ev.scancode==RawInputEvent.SYN_REPORT)){ /*这里实现了对SYN_REPORT事件的处理 *如果是单点触摸屏,即使用di.curTouchVals数组保存的点 *转化为多点触摸屏的mNextData数组保存 *最后是调用InputDevice中的generateAbsMotion处理这个数组。 这个函数 *的具体实现方法将在后面补充 */ ………………………….. ms.finish();//重置所有点和偏移量 …………………….. } 由于上层的代码仍然使用ABS_X,ABS_Y这些事件,为了使多点触摸屏代码有良好的兼容性,在KeyInputQueue.java的最后,我们将多点事件类型转化为单点事件类型,返回一个新的InputDevice: privateInputDevicenewInputDevice(intdeviceId){ intclasses=getDeviceClasses(deviceId); Stringname=getDeviceName(deviceId); InputDevice.AbsoluteInfoabsX; InputDevice.AbsoluteInfoabsY; InputDevice.AbsoluteInfoabsPressure; InputDevice.AbsoluteInfoabsSize; if((classes&RawInputEvent.CLASS_TOUCHSCREEN_MT)! =0){ absX=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X,"X"); absY=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_Y,"Y"); absPressure=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_TOUCH_MAJOR,"Pressure"); absSize=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_WIDTH_MAJOR,"Size"); }elseif((classes&RawInputEvent.CLASS_TOUCHSCREEN)! =0){ absX=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_X,"X"); absY=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_Y,"Y"); absPressure=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_PRESSURE,"Pressure"); absSize=loadAbsoluteInfo(deviceId, RawInputEvent.ABS_TOOL_WIDTH,"Size"); }else{ absX=null; absY=null; absPressure=null; absSize=null; } returnnewInputDevice(deviceId,classes,name,absX,absY,absPressure,absSize); } 文章出处: 飞诺网(): 第四章触摸事件数组的处理上面我们曾说到generateAbsMotion这个方法,它们在InputDevice类的内部类MotionState中实现,该类被定义为InputDevice类的静态成员类(staticclass),调用它们可以直接使用: InputDeviceClass.MotionStateClass.generateAbsMotion()。 publicclassIn
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 多点 触摸