ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

5、InputMapper体系:各类Mapper的注册与选择

5、InputMapper体系:各类Mapper的注册与选择 5.1 Mapper的注册机制Mapper不是凭空冒出来的。系统得知道你这个设备该用哪个Mapper。这个注册过程发生在InputReader初始化的时候。我们来看关键代码。在InputReader.cpp里有个方法叫createDeviceLocked它会根据设备的配置信息决定挂载哪些Mapper。// 简化自 InputReader.cpp InputDevice* InputReader::createDeviceLocked(int32_t deviceId, const String8 identifier, const PropertyMap configuration) { InputDevice* device new InputDevice(mContext, deviceId, generator, identifier); // 根据设备类型创建对应的Mapper if (configuration.getInt(touch.deviceType, 0) 1) { // 多点触摸设备 device-addMapper(new MultiTouchInputMapper(*device)); } else if (configuration.getInt(touch.deviceType, 0) 0) { // 单点触摸设备 device-addMapper(new SingleTouchInputMapper(*device)); } // 还有按键、轨迹球等Mapper... return device; }嗯这里要注意。注册的决策依据主要来自两个地方内核上报的设备信息比如通过ioctl查询到的设备能力idc配置文件也就是.idc文件厂商可以在这里覆盖默认行为我曾经遇到过一个坑某款触摸屏在idc里把touch.deviceType写成了2结果系统不认识这个值直接用了默认的SingleTouchMapper。多点手势全部失效。排查了半天才发现是配置文件写错了。5.2 SingleTouchMapper老派但可靠SingleTouchMapper顾名思义处理单点触摸。它对应的硬件就是那些老式的电阻屏或者只支持单点触控的电容屏。它的工作流程其实很简单从原始数据中提取X、Y坐标判断触摸状态按下、移动、抬起封装成MotionEvent设置ACTION_DOWN、ACTION_MOVE、ACTION_UP你想想看单点触摸没有复杂的多点手势所以它的逻辑非常直白。核心代码大概长这样// 简化自 SingleTouchInputMapper.cpp void SingleTouchInputMapper::process(const RawEvent* rawEvent) { // 读取原始坐标 int32_t x rawEvent-getValue(ABS_X); int32_t y rawEvent-getValue(ABS_Y); // 判断触摸状态 if (rawEvent-getValue(ABS_PRESSURE) 0) { // 有压力认为是按下或移动 if (!mIsDown) { // 之前没按下现在是按下事件 dispatchDown(x, y); mIsDown true; } else { // 已经按下了是移动事件 dispatchMove(x, y); } } else { // 无压力抬起 if (mIsDown) { dispatchUp(x, y); mIsDown false; } } }小提示SingleTouchMapper虽然简单但在一些低端设备上仍然在用。我建议你在做兼容性测试时别忽略这类设备。有些用户还在用老式手机他们的触摸体验同样重要。5.3 MultiTouchMapper现代触摸的核心现在的手机哪个不是多点触控MultiTouchMapper才是主角。它要处理的事情复杂得多跟踪多个手指的ID处理手指的按下、移动、抬起处理手势识别缩放、旋转等处理协议差异Type A vs Type B这里有个关键点协议差异。Linux内核支持两种多点触摸协议协议类型特点常见场景Type A每次上报所有手指的完整数据老式多点触摸屏Type B只上报变化的手指数据带Slot概念现代触摸屏主流MultiTouchMapper会根据内核上报的MT_PROTOCOL类型自动选择解析方式。我个人习惯在调试时先看/proc/bus/input/devices里的协议类型心里就有底了。它的核心处理逻辑我简化一下// 简化自 MultiTouchInputMapper.cpp void MultiTouchInputMapper::process(const RawEvent* rawEvent) { // 根据协议类型分流 if (usingTypeBProtocol()) { processTypeB(rawEvent); } else { processTypeA(rawEvent); } } void MultiTouchInputMapper::processTypeB(const RawEvent* rawEvent) { // Type B协议每个手指有独立的Slot int32_t slot rawEvent-getValue(MT_SLOT); int32_t x rawEvent-getValue(MT_POSITION_X); int32_t y rawEvent-getValue(MT_POSITION_Y); // 更新对应Slot的手指状态 mSlots[slot].x x; mSlots[slot].y y; mSlots[slot].updated true; // 当收到SYN_REPORT时统一处理所有更新 if (rawEvent-type EV_SYN rawEvent-code SYN_REPORT) { syncSlots(); } }重点MultiTouchMapper最核心的设计就是「延迟处理」。它不会每收到一个原始事件就立刻上报而是等SYN_REPORT信号来了才把所有变化打包成一个MotionEvent。这样做的好处是能保证一次触摸事件的所有数据是完整的、一致的。5.4 Mapper的选择策略系统怎么决定用哪个Mapper说白了就是一套优先级判断idc配置文件最优先如果idc里明确指定了touch.deviceType那就听它的内核能力查询如果没有idc就通过ioctl查询设备支持的事件类型默认兜底如果以上都没有就用SingleTouchMapper我记得有一次客户反馈他们的设备触摸不灵敏。我查了半天发现是idc文件里写错了协议类型。把touch.deviceType 1写成了touch.deviceType 0导致多点触摸屏被当成了单点屏处理。嗯这种低级错误排查起来最费时间。避坑指南我曾经遇到过一款奇葩设备它同时上报了单点和多点的事件。结果系统同时注册了SingleTouchMapper和MultiTouchMapper导致一个触摸操作产生了两个MotionEvent。解决方案是在idc里明确禁用其中一个。所以如果你遇到触摸事件重复先检查Mapper的注册情况。5.5 小结Mapper体系说白了就是「看菜下饭」。系统根据硬件的能力选择合适的翻译官。SingleTouchMapper简单直接适合老设备MultiTouchMapper复杂强大是现代触摸的核心。
返回列表