当前位置: 首页 > news >正文

android 输入系统

一、输入系统的核心角色与分层架构

Android 输入系统的本质是桥梁:一端连接硬件驱动产生的原始事件,另一端将事件精准派发给应用窗口。整个过程涉及三层架构和多个关键组件,可类比为 “快递分拣系统”:

1. 硬件与内核层(源头)

  • 角色:当用户触摸屏幕或按下按键时,硬件驱动将事件写入设备节点(如/dev/input),生成原始的内核事件(类似 “快递包裹的原始数据”)。
  • 技术实现:通过EventHub(事件枢纽)监听设备路径,使用epoll和inotify机制高效检测事件变化和设备插拔。

驱动上报

struct RawEvent{

nsecs_t when;

nsecs_t readtime;

int32_t deviceId; 输入设备唯一标识符

int32_t type; 事件类型 如EV_KEY, EV_ABS

int32_t code; 事件码

int32_t value; 事件值

}

RawEvent的定义位于 frameworks/native/services/inputflinger/reader/include/EventHub.h

2. Native 层(事件处理与分发)

InputReader(事件快递员)

    • 从EventHub读取原始事件(如触摸坐标、按键码),按规则封装为标准事件(如MotionEvent、KeyEvent)。
    • 类比:将 “原始包裹数据” 解析为 “标准化快递单”。

InputDispatcher(事件分拣员)

    • 接收InputReader处理后的事件,结合窗口信息(如焦点窗口),将事件派发给对应的应用窗口。
    • 类比:根据 “快递单地址” 将包裹分拣到正确的配送路线。

InputManager(调度中心)

    • 管理InputReader和InputDispatcher,创建并启动它们的工作线程。
2.1 按键事件类型

RawEvent的 type == EV_KEY:

rawEvent 的code 对应android的scanCode,

scanCode 通过 Generic.kl 映射到android 的keycode。

通常使用 frameworks/base/data/keyboards/Generic.kl 建立linux到android的按键映射关系。

2.2 触摸事件类型

RawEvent的type ==EV_ABS (绝对坐标事件)

在 Linux 输入子系统(Input Subsystem)中,多点触控(Multi-Touch)事件通过一系列以 ABS_MT_ 开头的绝对坐标类事件代码(ABS 代表 Absolute Position)来描述每个触摸点(Slot)的属性。以下是你列出的各个 ABS_MT_ 事件的详细说明:

1. ABS_MT_SLOT
  • 作用:标识当前操作的触摸点槽位(Slot)。
    多点触控设备通过 “槽位” 机制管理多个触摸点(类似数组索引),每个槽位对应一个独立的触摸点。当设备报告某个触摸点的属性时,需先通过 ABS_MT_SLOT 指明操作的是哪个槽位。
  • 值范围:通常从 0 开始递增(如 0、1、2...),具体取决于设备支持的最大触摸点数(如 5 点触控则槽位为 0~4)。
2. ABS_MT_TRACKING_ID
  • 作用:为每个触摸点分配唯一的追踪 ID,用于在触摸点生命周期内(按下、移动、抬起)标识其身份。
    • 当触摸点按下时,系统分配一个非负整数 ID(如 1、2...);
    • 当触摸点抬起时,ID 会被重置为 -1(表示该槽位不再被占用)。
  • 值范围:
    • 有效触摸点:>= 0(如 1, 2);
    • 无效 / 释放的槽位:-1。
  • 用途:区分不同触摸点(即使槽位重用),例如:
    • 槽位 0 先用于触摸点 A(ID=1),抬起后 ID 重置为 -1;
    • 新触摸点 B 按下时,可能再次使用槽位 0,但分配新 ID=2。
      通过 ID 可确保触摸点的移动轨迹不会因槽位重用而混淆。
3. ABS_MT_TOUCH_MAJOR
  • 作用:表示触摸点接触面积的主轴长度(椭圆的长轴,单位为像素或设备特定单位)。
    可粗略理解为触摸点的 “宽度” 或 “接触区域大小”,例如手指按下时的接触面积。
  • 值范围:通常为正整数,值越大表示接触面积越大。
  • 示例:手指轻轻触摸时值为 20,用力按下时值为 30
4. ABS_MT_WIDTH_MAJOR
  • 作用:表示触摸点接触面积的次轴长度(椭圆的长轴,单位与 ABS_MT_TOUCH_MAJOR 一致)。
    在某些设备中,TOUCH_MAJOR 和 WIDTH_MAJOR 可能分别对应椭圆的长轴和短轴,用于描述触摸点的形状。
  • 值范围:正整数,通常与 ABS_MT_TOUCH_MAJOR 成比例。
5. ABS_MT_POSITION_X 和 ABS_MT_POSITION_Y
  • 作用:
    • ABS_MT_POSITION_X:触摸点在屏幕坐标系中的 X 轴坐标(水平位置)。
    • ABS_MT_POSITION_Y:触摸点在屏幕坐标系中的 Y 轴坐标(垂直位置)。
  • 坐标原点:通常为屏幕左上角(X=0, Y=0),向右 / 向下递增。
  • 单位:设备特定的逻辑单位(如像素、毫米等),需通过输入子系统校准后映射到屏幕像素。
6. ABS_MT_PRESSURE
  • 作用:表示触摸点的压力值,用于检测触摸力度(如手指按下的轻重)。
    • 值为 0 时表示无压力(触摸点抬起);
    • 值越大表示压力越大。
  • 值范围:通常为 0 到设备支持的最大值(如 255、1024 等)。
  • 用途:实现压感功能,例如绘图应用中根据压力调整笔触粗细。
2.3.EV_SYN(同步事件)​​
  • ​​核心作用​​:标记事件数据包的边界,确保用户空间程序能完整处理一组事件

· ​​子类型​​:

  • ​​SYN_REPORT​​:表示当前数据包结束,触发用户空间处理累积事件(如鼠标移动后必须发送该事件完成坐标更新)

· ​​SYN_DROPPED​​:内核缓冲区溢出时通知用户丢弃数据包并重新查询设备状态

· ​​SYN_MT_REPORT​​:多点触控协议中分隔不同触点的数据包(Type A协议使用)

· ​​底层依赖​​:驱动必须正确发送该事件,否则用户空间无法识别事件边界

2.4.EV_REL(相对坐标事件)​​
  • ​​功能​​:报告相对位移变化,适用于鼠标等设备
2.5.EV_SW(开关事件)​​
  • ​​功能​​:报告二进制状态切换,如设备休眠/唤醒、盖子开合等
2.6.EV_MSC(杂项事件)​​
  • ​​功能​​:处理无法归类到其他类型的事件,如硬件特定状态或补充信息

3. Java 层(系统服务与交互)

InputManagerService(IMS,总控中心)

    • 作为 Android 系统服务(运行于system_server进程),通过 JNI 与 Native 层交互。
    • 与窗口管理服务(WMS)同步窗口信息,为InputDispatcher提供派发依据(如哪个窗口当前可见)。
    • 类比:“快递总控中心”,协调底层分拣与上层应用的对接。

二、启动流程详解:从 IMS 初始化到线程启动

IMS 的启动伴随system_server进程启动,整个过程可分为对象创建线程启动两个阶段,涉及 Java 层、JNI 层和 Native 层的跨层调用。

1. 初始化阶段:搭建组件链路

/ /Java层:IMS初始化(InputManagerService.java)inputManager = new InputManagerService(context);

步骤 1:创建 Java 层 IMS 对象

初始化mHandler,运行在 “android.display” 线程(负责处理 Java 层消息)。

通过nativeInit调用 JNI,进入 Native 层初始化。

// JNI层:nativeInit(com_android_server_input_InputManagerService.cpp)NativeInputManager* im = new NativeInputManager(...);

步骤 2:创建 NativeInputManager(JNI 桥梁)

持有 Java 层 IMS 对象的引用(mServiceObj),作为 Native 层与 Java 层交互的桥梁。

创建EventHub(监听设备事件)和InputManager(管理读写线程)。

// Native层:InputManager构造(InputManager.cpp)

mDispatcher = new InputDispatcher(...); // 分拣员

mReader = new InputReader(...); // 快递员

步骤 3:创建 InputDispatcher 和 InputReader

  • InputDispatcher关联NativeInputManager(获取派发策略,如超时参数)。
  • InputReader通过QueuedInputListener与InputDispatcher建立连接(事件传递的枢纽)。

2. 启动阶段:激活工作线程

inputManager.start(); // 调用nativeStart

·启动 Native 层线程
通过InputManager.start()启动两个核心线程:

  • InputReaderThread:循环调用EventHub.getEvents()读取事件,交由InputReader处理。
  • InputDispatcherThread:循环处理事件队列,将事件派发给目标窗口。

·关键线程分工

  • android.display 线程(Java 层):处理 IMS 的消息(如配置变更、ANR 通知)。
  • InputReaderThread(Native 层):专注读取硬件事件,不阻塞其他操作。
  • InputDispatcherThread(Native 层):专注事件派发,确保实时性。

三、事件如何从硬件传到应用?

事件分发链:InputReader → InputDispatcher → 应用窗口
  1. InputReader → InputDispatcher
  2. 通过QueuedInputListener将封装好的事件传递给InputDispatcher,存入mInboundQueue队列。

InputDispatcher 派发事件

  1. 从 WMS 获取焦点窗口信息(通过 IMS 同步),确定事件目标窗口。
  2. 通过InputChannel(跨进程通信通道)将事件发送给应用的InputConsumer,最终由ViewRootImpl处理并传递给界面组件(如按钮、文本框)。

四. 应用层的事件传递

ViewRootImpl ->DecorView 的dispatchTouchEvent

Android 系统ViewGroup的dispatchTouchEvent 是触摸事件分发核心方法,整个 Android 触摸分发、拦截、子 View 投递、滑动冲突全部由这段逻辑驱动。全程分为以下步骤:

1.安全校验与初始化:无障碍焦点、调试日志、安全过滤;
2.DOWN 事件重置状态:每次新手势按下清空上一轮触摸缓存;
3.判断是否拦截事件intercepted = onInterceptTouchEvent(ev):核心滑动判定入口(RecyclerView 左右 / 上下滑动判断就在这里);
4.未拦截时:遍历子 View,寻找能接收触摸的子 View,建立TouchTarget链表
5.向所有有效子 TouchTarget 分发事件dispatchTransformedTouchEvent,拦截时给子 View 发送 CANCEL;
6.UP/CANCEL 手势结束,清空触摸状态
7.返回handled标记当前 ViewGroup 是否消费本次触摸。

其中 dispatchTransformedTouchEvent 是ViewGroup 的私有方法。负责将触摸事件分发给子view。

三段触摸源码完整调用链路串联:

ViewGroup.dispatchTouchEvent(总调度:拦截判断、构建TouchTarget链表) ↓

dispatchTransformedTouchEvent(坐标转换、多指裁剪、下发CANCEL工具方法) ↓

View.dispatchTouchEvent(普通控件处理触摸:OnTouchListener > onTouchEvent)

手指按下 ACTION_DOWN


Activity.dispatchTouchEvent()


DecorView.dispatchTouchEvent()


LinearLayout.dispatchTouchEvent()

├── LinearLayout.onInterceptTouchEvent()
│ │
│ ├── true → LinearLayout.onTouchEvent()
│ │
│ └── false → 继续向子 View 分发

RecyclerView.dispatchTouchEvent()

├── RecyclerView.onInterceptTouchEvent()
│ │
│ ├── true → RecyclerView.onTouchEvent()
│ │
│ └── false → 继续分发给 ItemView

ItemView.dispatchTouchEvent()


Button.dispatchTouchEvent()

├── OnTouchListener.onTouch()
│ ├── true → 事件到此结束
│ └── false → 继续


Button.onTouchEvent()

├── true → Button 消费事件
└── false → 事件逐层回传给父容器处理

http://www.jsqmd.com/news/1201992/

相关文章:

  • 新手电子鼓选购指南!4大核心部件+4款长效机型推荐
  • 网络攻击工具深度解析:Zarp框架架构与实战应用指南
  • 食品包装线实战:C#上位机+国产PLC落地自动化,这份避坑指南请收好
  • Howl编辑器多语言支持:50+编程语言语法高亮与自动补全
  • 西安劳力士回收价格查询和靠谱平台实测排行(2026年7月最新) - 天价名表回收平台
  • JupyterLab变量监控插件:数据科学家的终极调试神器
  • 从单体到分布式:Apache Kyuubi的多租户架构转型与数据服务价值实现
  • 国内 GEO 赛道天花板!人数最多、权威性拉满的汇搜社全域搜索优化社群完整解析 - 速递信息
  • 鸣潮游戏自动化工具ok-ww:解放双手的智能辅助解决方案
  • 三步解锁123云盘VIP特权:终极免费解决方案,快速享受会员下载
  • 江西南昌美术培训专业的机构是哪 - GrowUME
  • 如何高效解锁B站缓存视频:m4s-converter完全解析与实战指南
  • datascience数据聚合分析:分组统计与汇总的实用教程 [特殊字符]
  • 免费API资源宝库:730+接口助你快速构建应用
  • 5步掌握:如何快速搭建云安全实战环境,提升攻防能力
  • 上海百达翡丽回收价格查询和各大回收平台实测排行(2026年7月最新) - 嘉价奢侈品回收平台
  • 跨界融合:用Rust的静态优雅重构Lua的动态灵魂
  • 100个练习掌握Rust编程:从零到精通的完整学习指南
  • GTA IV FusionFix终极指南:一站式解决完整版技术难题与性能优化
  • 2026瑞安黄金回收避坑实录:塘下、安阳、莘塍、仙降、阁巷正规回收渠道整理 - 不晚生活号
  • Agent 的上下文继承:子 Agent 如何获取和传递父 Agent 的中间推理结果
  • mlx-community/Qwopus3.6-35B-A3B-Coder-4bit高级技巧:调整温度参数与最大 tokens 提升模型性能
  • CANNAscendC数据类型转换API
  • 亿级流量系统的灰度发布:从金丝雀到蓝绿再到全量放量的工程框架
  • 互动叙事创作终极指南:如何用Twine打造你的第一个非线性故事
  • GPT-5.6 团队协作应用教程:会议纪要、需求拆解、代码说明和资料整理实践
  • 重庆劳力士回收价格查询及各大回收平台实测排行(2026年7月最新数据) - 收的高名表回收平台
  • jpa-spec vs 传统JPQL:为什么说动态查询框架能提升开发效率300%?
  • 如何在Windows环境构建macOS开发环境:OSX-Hyper-V实战解决方案
  • Gemma-4-e4b-it-mxfp8未来展望:多模态AI的发展趋势与路线图