版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、Android多点触摸的实现1.6patch(一)第一章摘要在Linux内核支持的基础上,Android在其2.0源码中加入多点触摸功能。由此触摸屏在Android的frameworks被完全分为2种实现途径:单点触摸屏的单点方式,多点触摸屏的单点和多点方式。第二章软件位在Linux的input.h中,多点触摸功能依赖于以下几个主要的软件位:.#define SYN_REPORT 0#define SYN_CONFIG 1#define SYN_MT_REPORT 2.#define ABS_MT_TOUCH_MAJOR0x30/* Major axis of touching ellipse
2、 */#define ABS_MT_TOUCH_MINOR0x31/* Minor axis (omit if circular) */#define ABS_MT_WIDTH_MAJOR0x32/* Major axis of approaching ellipse */#define ABS_MT_WIDTH_MINOR0x33/* Minor axis (omit if circular) */#define ABS_MT_ORIENTATION0x34/* Ellipse orientation */#define ABS_MT_POSITION_X0x35/* Center X el
3、lipse position */#define ABS_MT_POSITION_Y0x36/* Center Y ellipse position */#define ABS_MT_TOOL_TYPE0x37/* Type of touching device */#define ABS_MT_BLOB_ID 0x38/* Group a set of packets as a blob */在Android中对应的软件位定义在RawInputEvent.java中:.public class RawInputEvent . public static final int CLASS_TOU
4、CHSCREEN_MT = 0x00000010;. public static final int ABS_MT_TOUCH_MAJOR = 0x30; public static final int ABS_MT_TOUCH_MINOR = 0x31; public static final int ABS_MT_WIDTH_MAJOR = 0x32; public static final int ABS_MT_WIDTH_MINOR = 0x33; public static final int ABS_MT_ORIENTATION = 0x34; public static fina
5、l int ABS_MT_POSITION_X = 0x35; public static final int ABS_MT_POSITION_Y = 0x36; public static final int ABS_MT_TOOL_TYPE = 0x37; public static final int ABS_MT_BLOB_ID = 0x38;.public static final int SYN_REPORT = 0; public static final int SYN_CONFIG = 1;public static final int SYN_MT_REPORT = 2;.
6、在Android中,多点触摸的实现方法在具体的代码实现中和单点是完全区分开的。在Android代码的EventHub.cpp中,单点屏和多点屏由如下代码段来判定:int EventHub:open_device(const char *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 |= C
7、LASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;/ LOGI("It is a multi-touch screen!"); /single-touch?else if (test_bit(BTN_TOUCH, key_bitmask)&& test_bit(ABS_X, abs_bitmask) && test_bit(ABS_Y, abs_bitmask) device->classes |= CLASS_TOUCHSCREEN;/ LOGI("It is a single-touch sc
8、reen!");.我们知道,在触摸屏驱动中,通常在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
9、(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_PRESSUREinput_set_abs_params(mcs_data.input, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0); /相当于单点屏的ABS_TOOL_WIDTH注:为了让我们的驱动代码支持所有的Android版本,无论是多点
10、屏还是单点屏,一般都会保留单点屏的事件,如ABS_TOUCH, ABS_PRESSURE, ABS_X, ABS_Y等。另外,由于在Android2.0前支持多点的frameworks大多是用HAT0X,HAT0Y来实现的,所以一般也会上报这2个事件。第三章同步方式由于多点触摸技术需要采集到多个点,然后再一起处理这些点,所以在软件实现中需要保证每一波点的准确性和完整性。因此,Linux内核提供了input_mt_sync(struct input_dev * input)函数。在每波的每个点上报后需要紧跟一句input_mt_sync(), 当这波所有点上报后再使用input_sync()进行
11、同步。例如一波要上报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事件放入一个队列:public abstract class KeyInputQueue Thread mThread = new Thread("InputDevic
12、eReader") 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);if (ev.type = RawInputEvent.EV_DEVICE_ADDED) sync
13、hronized (mFirst) di = newInputDevice(ev.deviceId); mDevices.put(ev.deviceId, di); configChanged = true; else if (ev.type = RawInputEvent.EV_DEVICE_REMOVED) synchronized (mFirst) Log.i(TAG, "Device removed: id=0x" + Integer.toHexString(ev.deviceId); di = mDevices.get(ev.deviceId); if (di !
14、= null) mDevices.delete(ev.deviceId); configChanged = true; else Log.w(TAG, "Bad device id: " + ev.deviceId); else di = getInputDevice(ev.deviceId); / first crack at it send = preprocessEvent(di, ev); if (ev.type = RawInputEvent.EV_KEY) di.mMetaKeysState = makeMetaState(ev.keycode, ev.valu
15、e != 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 &
16、;& (classes&RawInputEvent.CLASS_KEYBOARD) != 0 && (scancode < RawInputEvent.BTN_FIRST | scancode > RawInputEvent.BTN_LAST) /* 键盘按键事件 */ . else if (ev.type = RawInputEvent.EV_KEY) /* 下面是EV_KEY事件分支,只支持单点的触摸屏有按键事件, * 而支持多点的触摸屏没有按键事件,只有绝对坐标事件*/ if (ev.scancode = RawInputEvent.BTN_T
17、OUCH && (classes&(RawInputEvent.CLASS_TOUCHSCREEN |RawInputEvent.CLASS_TOUCHSCREEN_MT) = RawInputEvent.CLASS_TOUCHSCREEN) /* 只支持单点的触摸屏的按键事件 */ else if (ev.scancode = RawInputEvent.BTN_MOUSE && (classes&RawInputEvent.CLASS_TRACKBALL) != 0) /* 鼠标和轨迹球 */ . else if (ev.type = Raw
18、InputEvent.EV_ABS && (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) /* 下面才是多点触摸屏上报的事件 */ if (ev.scancode = RawInputEvent.ABS_MT_TOUCH_MAJOR) di.mAbs.changed = true; di.mAbs.mNextDatadi.mAbs.mAddingPointerOffset + MotionEvent.SAMPLE_PRESSURE = ev.value; else if (ev.scancode = RawInput
19、Event.ABS_MT_POSITION_X) di.mAbs.changed = true; di.mAbs.mNextDatadi.mAbs.mAddingPointerOffset + MotionEvent.SAMPLE_X = ev.value; else if (ev.scancode = RawInputEvent.ABS_MT_POSITION_Y) di.mAbs.changed = true; di.mAbs.mNextDatadi.mAbs.mAddingPointerOffset + MotionEvent.SAMPLE_Y = ev.value; else if (
20、ev.scancode = RawInputEvent.ABS_MT_WIDTH_MAJOR) di.mAbs.changed = true; di.mAbs.mNextDatadi.mAbs.mAddingPointerOffset + MotionEvent.SAMPLE_SIZE = ev.value; /* 上面这段就是多点触摸屏要用到的事件上报部分; * 使用一个数组mNextData来保存,其中di.mAbs.mAddingPointerOffset * 是当前点的偏移量,在每个点中还在MotionEvent中定义了X,Y,PRESSURE * SIZE等偏移量,多点触摸屏的压力值
21、由绝对坐标事件ABS_MT_TOUCH_MAJOR确定。 */ else if (ev.type = RawInputEvent.EV_ABS && (classes&RawInputEvent.CLASS_TOUCHSCREEN) != 0) /* 这里是对单点触摸屏上报坐标事件的新的处理方法,同样使用了数组来保存 */ if (ev.scancode = RawInputEvent.ABS_X) di.mAbs.changed = true; di.curTouchValsMotionEvent.SAMPLE_X = ev.value; else if (ev.sc
22、ancode = RawInputEvent.ABS_Y) di.mAbs.changed = true; di.curTouchValsMotionEvent.SAMPLE_Y = ev.value; else if (ev.scancode = RawInputEvent.ABS_PRESSURE) di.mAbs.changed = true; di.curTouchValsMotionEvent.SAMPLE_PRESSURE = ev.value; di.curTouchValsMotionEvent.NUM_SAMPLE_DATA + MotionEvent.SAMPLE_PRES
23、SURE = ev.value; else if (ev.scancode = RawInputEvent.ABS_TOOL_WIDTH) di.mAbs.changed = true; di.curTouchValsMotionEvent.SAMPLE_SIZE = ev.value; di.curTouchValsMotionEvent.NUM_SAMPLE_DATA + MotionEvent.SAMPLE_SIZE = ev.value; . /* 下面是关键的同步处理方法 */ if (ev.type = RawInputEvent.EV_SYN && ev.scan
24、code = RawInputEvent.SYN_MT_REPORT && di.mAbs != null) /* 在这里实现了对SYN_MT_REPORT事件的处理, * 改变了di.mAbs.mAddingPointerOffset的值,从而将 * 新增的点的参数保存到下一组偏移量的位置。 */ . final int newOffset = (num <= InputDevice.MAX_POINTERS) ? (num * MotionEvent.NUM_SAMPLE_DATA) : (InputDevice.MAX_POINTERS * MotionEvent.
25、NUM_SAMPLE_DATA); di.mAbs.mAddingPointerOffset = newOffset; di.mAbs.mNextDatanewOffset + MotionEvent.SAMPLE_PRESSURE = 0; . else if (send | (ev.type = RawInputEvent.EV_SYN && ev.scancode = RawInputEvent.SYN_REPORT) /* 这里实现了对SYN_REPORT事件的处理 * 如果是单点触摸屏,即使用di.curTouchVals数组保存的点 * 转化为多点触摸屏的mNext
26、Data数组保存 * 最后是调用InputDevice中的generateAbsMotion处理这个数组。这个函数 * 的具体实现方法将在后面补充 */ . ms.finish(); /重置所有点和偏移量 .由于上层的代码仍然使用ABS_X, ABS_Y这些事件,为了使多点触摸屏代码有良好的兼容性,在KeyInputQueue.java的最后,我们将多点事件类型转化为单点事件类型,返回一个新的InputDevice:private InputDevice newInputDevice(int deviceId) int classes = getDeviceClasses(deviceId);
27、String name = getDeviceName(deviceId);InputDevice.AbsoluteInfo absX; InputDevice.AbsoluteInfo absY; InputDevice.AbsoluteInfo absPressure; InputDevice.AbsoluteInfo absSize; if (classes&RawInputEvent.CLASS_TOUCHSCREEN_MT) != 0) absX = loadAbsoluteInfo(deviceId, RawInputEvent.ABS_MT_POSITION_X, &qu
28、ot;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"); else if (classes
29、&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 = loadAbsolute
30、Info(deviceId, RawInputEvent.ABS_TOOL_WIDTH, "Size"); else absX = null; absY = null; absPressure = null; absSize = null; return new InputDevice(deviceId, classes, name, absX, absY, absPressure, absSize); 第四章触摸事件数组的处理上面我们曾说到generateAbsMotion这个方法,它们在InputDevice类的内部类MotionState中实现,该类被定义为Input
31、Device类的静态成员类(static class),调用它们可以直接使用:InputDeviceClass.MotionStateClass.generateAbsMotion()。public class InputDevice static class MotionState /下面是这个内部类的几个函数 ./* mLastNumPointers 为上一个动作在触屏上按键的个数 */int mLastNumPointers = 0;final int mLastData = new intMotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS;/* mNe
32、xtNumPointers 为下一个动作在触屏上按键的个数 */* 通过对这2个值大小的判断,可以确认新的动作方式 */int mNextNumPointers = 0;final int mNextData = new int(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS) + MotionEvent.NUM_SAMPLE_DATA;. int generateAveragedData(int upOrDownPointer, int lastNumPointers, int nextNumPointers) /平滑处理 . private boole
33、an assignPointer(int nextIndex, boolean allowOverlap) /指派按键 private int updatePointerIdentifiers() /更新按键ID . void removeOldPointer(int index) MotionEvent generateAbsMotion(InputDevice device, long curTime, long curTimeNano, Display display, int orientation, int metaState) int upOrDownPointer = updat
34、ePointerIdentifiers(); final int numPointers = mLastNumPointers; /* 对行为的判断 */ if (nextNumPointers != lastNumPointers) /前后在触屏上点个数不同,说明有手指up或down if (nextNumPointers > lastNumPointers) if (lastNumPointers = 0) /上次触屏上没有按键,新值又大,说明有按键按下 action = MotionEvent.ACTION_DOWN; mDownTime = curTime; else /有新点按下,分配给新点ID号 action = MotionEvent.ACTION_POINTER_DOWN | (upOrDownPointer <&
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 塑料制品的高温和低温性能分析考核试卷
- 建筑安全施工工程费用管理考核试卷
- 遗传学血友病讲解
- 无人机在交通管制中的路况监测应用考核试卷
- 《司法制度的比较》课件
- 《激光倍频技术》课件
- 凝集反应(免疫学检验课件)
- 建筑拆除现场的施工质量监测与评估考核试卷
- 医药制造业的品牌管理与推广考核试卷
- 复杂铁合金冶炼技术考核试卷
- 2024-2025学年浙教版八年级上册科学期中模拟卷
- (正式版)HGT 6313-2024 化工园区智慧化评价导则
- 常用焊条合格证
- 站场明敷接地扁钢安装技术要求
- 《个人防护用品PPE》ppt课件
- 国际贸易SimTrade外贸实习报告
- 导师带徒实施办法6、30
- 《Fishing with Grandpa》RAZ分级阅读绘本pdf资源
- 水稳施工方案(完整版)
- 跨海大桥施工方案
- MATLAB语言课程论文 基于MATLAB的电磁场数值图像分析
评论
0/150
提交评论