ARTICLE DETAIL

资讯详情

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

6、单点触摸Mapper:SingleTouchMapper的process()函数,坐标转换与事件封装

6、单点触摸Mapper:SingleTouchMapper的process()函数,坐标转换与事件封装 6.1 process()函数入口与流程每个Mapper的灵魂都在process()函数里。SingleTouchMapper也不例外。当InputReader从设备节点读到原始数据后就会调用这个函数。void SingleTouchMapper::process(const RawEvent* rawEvent) { // 1. 更新原始数据 updateTouchState(rawEvent); // 2. 检查是否有有效触摸 if (!mCurrentTouch.present) { return; } // 3. 坐标转换 int32_t x mCurrentTouch.x; int32_t y mCurrentTouch.y; transformTouch(x, y); // 4. 封装事件并上报 dispatchTouch(x, y, mCurrentTouch.pressure); }嗯这里要注意代码是我简化过的但核心逻辑就这四步。我在项目中遇到过一些奇怪的触摸问题最后发现都是因为第二步的检查没做好——明明手指已经离开了但驱动还在上报无效数据。6.2 坐标转换从硬件到屏幕的魔法坐标转换这块是很多初学者容易懵的地方。你想想触摸屏的物理坐标和屏幕的显示坐标它们之间可不是简单的1:1关系。举个例子我手头有一块800x480的屏幕但触摸屏的物理分辨率可能是1024x600。这时候就需要做映射。SingleTouchMapper里是怎么做的呢void SingleTouchMapper::transformTouch(int32_t* x, int32_t* y) { // 获取屏幕尺寸 int32_t screenWidth mViewport.width; int32_t screenHeight mViewport.height; // 获取触摸屏物理尺寸 int32_t touchWidth mTouchDevice-getTouchWidth(); int32_t touchHeight mTouchDevice-getTouchHeight(); // 线性映射 *x (*x) * screenWidth / touchWidth; *y (*y) * screenHeight / touchHeight; }说白了这就是一个简单的比例缩放。但实际项目中事情往往没那么简单。我曾经踩过的坑有一次某款设备的触摸屏和屏幕的宽高比不一致。直接做线性映射结果触摸点总是偏移。后来我查了驱动文档才发现需要做裁剪处理——先按比例缩放然后取交集区域。这个坑让我折腾了两天。6.3 事件封装从RawEvent到MotionEvent坐标转换完成后下一步就是封装事件。SingleTouchMapper需要把原始数据包装成MotionEvent这样才能被上层使用。这里有个关键点事件类型。单点触摸的事件类型主要有三种事件类型触发条件说明ACTION_DOWN手指按下触摸开始只有一个触点ACTION_MOVE手指滑动触点位置发生变化ACTION_UP手指抬起触摸结束封装的过程其实就是把这些信息填到MotionEvent的结构体里。我习惯用下面这个伪代码来理解void SingleTouchMapper::dispatchTouch(int32_t x, int32_t y, float pressure) { // 创建MotionEvent对象 MotionEvent* event new MotionEvent(); // 设置事件属性 event-setAction(getActionType()); // DOWN/MOVE/UP event-setPointerCount(1); // 单点触摸 event-setPointerId(0, 0); // 指针ID为0 event-setCoords(0, x, y); // 转换后的坐标 event-setPressure(0, pressure); // 压力值 // 上报给InputReader mListener-notifyMotion(event); }核心要点SingleTouchMapper的process()函数本质上就是一个“翻译官”。它把驱动层的原始语言RawEvent翻译成应用层能理解的语言MotionEvent。坐标转换是翻译过程中的关键步骤而事件封装则是最终的输出格式。6.4 避坑指南我踩过的那些雷做Android系统这么多年SingleTouchMapper这块我遇到过不少问题。挑几个典型的说说坐标翻转问题有些设备的触摸屏是倒着装上去的。这时候x和y轴需要做翻转。我曾经遇到过一款平板触摸屏的x轴和屏幕的x轴方向相反结果触摸点总是镜像的。解决方案是在transformTouch()里加一个方向判断。压力值异常有些低端触摸屏压力值永远返回0。这时候如果上层代码依赖压力值做判断就会出问题。我的建议是在Mapper层做一次过滤如果压力值一直为0就强制设为1.0。多点误触虽然叫SingleTouchMapper但有些设备在物理上支持多点只是驱动层把它模拟成了单点。这时候如果用户同时触摸两个点驱动可能会上报混乱的数据。嗯这种情况我一般建议升级到MultiTouchMapper。个人经验调试触摸问题时我建议先在process()函数里加日志打印出原始坐标和转换后的坐标。这样能快速定位是驱动问题还是Mapper问题。我曾经靠这个办法半小时就找到了一个困扰团队三天的bug。6.5 小结SingleTouchMapper的process()函数说白了就是三步走更新状态、转换坐标、封装事件。虽然现在多点触摸已经普及了但理解单点触摸的处理逻辑能帮你更好地理解整个Input系统的工作机制。
返回列表