Android Input系统(1) Input事件的产生与传递

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Android Input系统(1) Input事件的产生与传递

这篇博客介绍了Android系统中的Input系统,它是负责处理用户输入操作的核心组件。该系统从各种输入设备获取原始输入事件,并将其转换为Android应用可以理解和消费的KeyEvent或MotionEvent对象。博客详细解释了Input系统的角色和重要性,以及它的主要组成部分,包括InputReader、InputDispatcher等。同时,还介绍了输入事件的来源,包括硬件设备和软件模拟,以及不同类型的输入事件,如按键事件和触摸事件。

Android Input系统简介

  • Input系统的角色和重要性
  • Input系统是Android系统中负责处理用户输入操作的核心组件,它负责从各种输入设备(如屏幕、键盘、鼠标等)获取原始的输入事件(如按键、触摸、滑动等),并将其转换为Android应用可以理解和消费的KeyEvent或MotionEvent对象。
  • Input系统对于提供流畅、灵敏和一致的用户交互体验至关重要,它需要在不同的设备、场景和应用中保证输入事件的正确性、及时性和安全性。
  • Input系统的主要组成部分
  • Input系统由以下几个主要部分组成:
组件 功能 位置
./native/services/inputflinger/reader/EventHub.cpp 监听/dev/input目录下的输入设备节点,获取内核事件 Native层
./native/services/inputflinger/reader/InputReader.cpp 从EventHub读取内核事件,进行预处理和分类,生成InputEvent对象 Native层
./native/services/inputflinger/dispatcher/InputDispatcher.cpp 从InputReader接收InputEvent对象,进行策略判断和分发,将事件发送给目标窗口或应用 Native层
./base/services/core/java/com/android/server/input/InputManagerService.java 提供Binder服务接口,管理InputReader和InputDispatcher,处理来自应用层或策略层的请求或回调 Java层
./base/core/java/android/hardware/input/InputManager.java 提供Java API接口,供应用层或策略层调用InputManagerService Java层

Input事件的来源

硬件设备

  • 硬件设备是最常见的输入事件来源,例如触摸屏、物理键盘、鼠标、游戏手柄等。这些设备通过驱动程序将用户操作转换为内核事件,并写入到/dev/input目录下对应的设备节点中。
  • EventHub会监听这些设备节点,并通过getevent工具读取内核事件。内核事件包含了事件类型(如EV_KEY, EV_ABS等)、事件代码(如KEY_A, ABS_X等)和事件值(如0, 1等)。
软件模拟
  • 软件模拟是另一种输入事件来源,例如虚拟键盘、语音输入、手势识别等。这些软件通过sendevent工具或InputManagerService的injectInputEvent方法向/dev/input目录下的设备节点写入内核事件。
  • EventHub也会监听这些设备节点,并通过getevent工具读取内核事件。内核事件的格式和硬件设备产生的一样,只是事件源(source)不同。

截图中的2个 第一部分是由adb 发送了input keyevent 224 , 第二部分是由鼠标点击了左键1次。

Event Type deviceId source action keyCode scanCode buttonState xCursorPosition yCursorPosition policyFlags age
KeyEvent -1 0x00000000 DOWN 224 0 - - - 0x2b000000 5205ms
KeyEvent -1 0x00000000 UP 224 0 - - - 0x2b000000 5205ms
MotionEvent 4 0x00002002 DOWN - - 0x00000001 708.6 586.5 0x62000001 1118ms
MotionEvent 4 0x00002002 UNKNOWN - - 0x00000001 708.6 586.5 0x62000001 1118ms
MotionEvent 4 0x00002002 UNKNOWN - - 0x00000000 708.6 586.5 0x62000000 974ms
MotionEvent 4 0x00002002 UP - - 0x00000000 708.6 586.5 0x62000000 974ms

详细解释下:

  1. Event Type: 表示事件的类型,可以是按键事件(KeyEvent)或触摸事件(MotionEvent)。在提供的日志中,既包含了按键事件又包含了触摸事件。
  2. deviceId: 表示输入设备的ID,每个输入设备都有一个唯一的ID。在日志中,deviceId为-1表示未指定或不适用。
  3. source: 表示事件的来源或输入设备类型。它是一个位掩码,指示事件来自哪种类型的输入设备。在提供的日志中,source的值采用16进制表示,例如0x00000000和0x00002002。
  4. action: 表示事件的动作,即事件的状态或操作类型。对于按键事件,动作可以是DOWN(按下)或UP(释放)。对于触摸事件,动作可以是DOWN(按下)、UP(释放)或其他(如UNKNOWN)。
  5. keyCode: 表示按键事件中按下或释放的按键的唯一标识符。它与具体硬件设备无关,是Android系统定义的一套统一的按键编码。
  6. scanCode: 表示内核事件中用来表示按键的唯一标识符,它与硬件设备相关,不同的设备可能有不同的scanCode。
  7. buttonState: 表示触摸事件中的鼠标按钮状态。在提供的日志中,buttonState为0x00000000表示没有按下鼠标按钮,为0x00000001表示按下了鼠标左键。
  8. xCursorPosition: 表示触摸事件或鼠标事件发生时的X轴坐标位置。
  9. yCursorPosition: 表示触摸事件或鼠标事件发生时的Y轴坐标位置。
  10. policyFlags: 表示事件的策略标志或属性,它是一个位掩码,表示事件相关的特征或行为。
  11. age: 表示事件生成的时间或年龄,单位为毫秒。它表示事件生成时间与当前时间的间隔。

Input事件的类型

  • 按键事件(KeyEvent)
  • 按键事件是指用户按下或松开一个按键时产生的事件,例如物理键盘上的字母键、数字键、功能键等,或者虚拟键盘上的返回键、菜单键、音量键等。
  • 按键事件由KeyEvent类表示,它包含了按键的状态(如ACTION_DOWN, ACTION_UP等)、代码(如KEYCODE_A, KEYCODE_BACK等)、标志(如FLAG_CANCELED, FLAG_LONG_PRESS等)、源(如SOURCE_KEYBOARD, SOURCE_GAMEPAD等)、设备(如Keyboard, Mouse等)等属性。
  • 触摸事件(MotionEvent)
  • 触摸事件是指用户在触摸屏上进行触摸、滑动、缩放等操作时产生的事件,例如单点触摸、多点触摸、手势识别等。
  • 触摸事件由MotionEvent类表示,它包含了触摸的状态(如ACTION_DOWN, ACTION_MOVE等)、位置(如X, Y坐标)、压力(如pressure, size等)、速度(如xVelocity, yVelocity等)、源(如SOURCE_TOUCHSCREEN, SOURCE_STYLUS等)、设备(如Touchscreen, Stylus等)等属性。
  • 其他事件(GenericMotionEvent)

  • 其他事件是指用户使用非触摸屏的输入设备进行移动或旋转操作时产生的事件,例如鼠标移动、滚轮滚动、操纵杆移动、陀螺仪旋转等。
  • 其他事件也由MotionEvent类表示,但是它们的状态是ACTION_GENERIC_MOTION,而且它们的属性可能和触摸事件不同,例如轴值(如AXIS_X, AXIS_Y等)、旋转角度(如AXIS_ORIENTATION, AXIS_TILT等)、源(如SOURCE_MOUSE, SOURCE_JOYSTICK等)、设备(如Mouse, Joystick等)等。

Input事件的属性

  • 事件代码(scanCode和keyCode)
  • scanCode是内核事件中用来表示按键的唯一标识符,它与硬件设备相关,不同的设备可能有不同的scanCode。
  • keyCode是KeyEvent中用来表示按键的唯一标识符,它与硬件设备无关,是Android系统定义的一套统一的按键编码。
  • scanCode和keyCode之间有一个映射关系,由KeyLayout文件定义。KeyLayout文件是一种文本文件,用来描述输入设备的按键布局和功能。Android系统会根据输入设备的名称或ID加载对应的KeyLayout文件,并根据文件中的映射规则将scanCode转换为keyCode。
  • 事件标志(flags)
  • flags是KeyEvent或MotionEvent中用来表示事件特征或行为的位掩码,它可以有多个值同时存在,例如FLAG_CANCELED表示事件被取消,FLAG_LONG_PRESS表示长按事件,FLAG_FROM_SYSTEM表示系统产生的事件等 。
  • flags可以影响事件的分发和处理过程,例如FLAG_CANCELED会导致后续的ACTION_UP或ACTION_MOVE被忽略,FLAG_FROM_SYSTEM会导致某些策略层拦截或修改事件等。
  • 事件源(source)
  • source是KeyEvent或MotionEvent中用来表示输入设备类型或类别的位掩码,它可以有多个值同时存在,例如SOURCE_KEYBOARD表示来自物理键盘的事件,SOURCE_TOUCHSCREEN表示来自触摸屏。

Input事件的流程

  • InputReader
  • InputReader是Input系统中负责从EventHub读取内核事件,并将其转换为InputEvent对象的组件。它运行在一个单独的线程(InputReaderThread)中,不断地调用EventHub的getEvents方法获取内核事件。
  • InputReader会根据内核事件的类型(EV_KEY, EV_ABS等)和设备节点(event0, event1等)进行分类和预处理,例如根据KeyLayout文件将scanCode转换为keyCode,根据TouchScreenCalibration文件将触摸坐标进行校准,根据InputDeviceConfiguration文件将设备信息进行解析等。
  • InputReader还会根据内核事件的属性(source, device等)和策略层(InputReaderPolicy)的建议,将内核事件转换为KeyEvent或MotionEvent对象,并赋予相应的状态(action, flags等)和时间戳(eventTime, downTime等)。
  • InputReader最后会将生成的InputEvent对象发送给InputClassifier,进行进一步的处理。
  • InputDispatcher
  • InputDispatcher是Input系统中负责从InputClassifier接收InputEvent对象,并将其分发给目标窗口或应用的组件。它运行在另一个单独的线程(InputDispatcherThread)中,不断地调用InputClassifier的process方法获取InputEvent对象。
  • InputDispatcher会根据InputEvent对象的类型(KeyEvent或MotionEvent)、属性(flags, source等)和策略层(InputDispatcherPolicy)的建议,进行策略判断和分发,例如判断是否需要拦截或修改事件,判断是否需要唤醒设备或关闭屏幕,判断是否需要显示或隐藏输入法等。
  • InputDispatcher还会根据窗口管理层(WindowManagerService)提供的窗口信息(WindowState, LayoutParams等),找到合适的目标窗口或应用,并通过InputChannel与之通信,将事件发送给目标窗口或应用。
  • InputDispatcher最后会等待目标窗口或应用对事件的消费结果(如Consumed, Injected等),并根据结果进行相应的处理,例如回调策略层或窗口管理层,更新事件状态或队列等。
  • InputChannel
  • InputChannel是一种用于在进程间传递InputEvent对象的通信机制,它是基于Binder机制实现的。每个InputChannel都包含一对文件描述符(fd),分别用于读取和写入InputEvent对象。
  • InputChannel可以在不同的进程间传递,例如InputDispatcher可以将一个InputChannel传递给目标窗口或应用所在的进程,然后通过这个InputChannel向目标窗口或应用发送InputEvent对象。
  • InputChannel还可以在同一个进程内传递,例如目标窗口或应用可以将一个InputChannel传递给它自己的子线程或子组件,然后通过这个InputChannel向子线程或子组件发送InputEvent对象。

参考:

创建输入法 | Android 开发者 | Android Developers

Android 设备输入事件(input)派发原理总结 - 掘金

Android Input架构 - 简书

还没写完 , 有空继续…

有什么问题 欢迎留言~

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
10月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
5月前
|
安全 搜索推荐 Android开发
Android系统SELinux安全机制详解
如此看来,SELinux对于大家来说,就像那位不眠不休,严阵以待的港口管理员,守护我们安卓系统的平安,维护这片海港的和谐生态。SELinux就这样,默默无闻,却卫士如山,给予Android系统一份厚重的安全保障。
203 18
|
10月前
|
算法 JavaScript Android开发
|
10月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
10月前
|
监控 Java Android开发
深入探讨Android系统的内存管理机制
本文将深入分析Android系统的内存管理机制,包括其内存分配、回收策略以及常见的内存泄漏问题。通过对这些方面的详细讨论,读者可以更好地理解Android系统如何高效地管理内存资源,从而提高应用程序的性能和稳定性。
379 16
|
9月前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
9月前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
10月前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
10月前
|
安全 搜索推荐 程序员
深入探索Android系统的碎片化问题及其解决方案
在移动操作系统的世界中,Android以其开放性和灵活性赢得了广泛的市场份额。然而,这种开放性也带来了一个众所周知的问题——系统碎片化。本文旨在探讨Android系统碎片化的现状、成因以及可能的解决方案,为开发者和用户提供一种全新的视角来理解这一现象。通过分析不同版本的Android系统分布、硬件多样性以及更新机制的影响,我们提出了一系列针对性的策略,旨在减少碎片化带来的影响,提升用户体验。
|
10月前
|
安全 Android开发 iOS开发
深入探索iOS与Android系统的差异性及优化策略
在当今数字化时代,移动操作系统的竞争尤为激烈,其中iOS和Android作为市场上的两大巨头,各自拥有庞大的用户基础和独特的技术特点。本文旨在通过对比分析iOS与Android的核心差异,探讨各自的优势与局限,并提出针对性的优化策略,以期为用户提供更优质的使用体验和为开发者提供有价值的参考。

热门文章

最新文章