flush.cpp

  name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-5572165936844014&dt=1194442938015&lmt=1194190197&format=336x280_as&output=html&correlator=1194442937843&url=file%3A%2F%2F%2FC%3A%2FDocuments%2520and%2520Settings%2Flhh1%2F%E6%A1%8C%E9%9D%A2%2FCLanguage.htm&color_bg=FFFFFF&color_text=000000&color_link=000000&color_url=FFFFFF&color_border=FFFFFF&ad_type=text&ga_vid=583001034.1194442938&ga_sid=1194442938&ga_hid=1942779085&flash=9&u_h=768&u_w=1024&u_ah=740&u_aw=1024&u_cd=32&u_tz=480&u_java=true" frameborder="0" width="336" scrolling="no" height="280" allowtransparency="allowtransparency"> #include <iostream.h>

void main(void)
 {
   cout << "This immediately appears" << flush;
   clog << "/nSo does this..." << flush;
 }

 

`InputReader.cpp` 是 Android 输入子系统中的**核心本地代码文件**,位于 Android 开源项目(AOSP)中,负责从内核驱动读取原始输入事件,并将其解析为高层次的 `input_event` 流,最终封装成 `MotionEvent` 或其他输入事件供上层使用。 --- ## 📚 文件位置 ```bash /system/core/inputreader/InputReader.cpp ``` > 在较老版本 AOSP 中路径可能是: > > - `frameworks/native/services/inputflinger/InputReader.cpp` 它是 **InputFlinger 服务** 的一部分,运行在 `android.hardware.input@1.0-service` 进程中,具有高权限和实时性要求。 --- ## 🔧 主要职责 `InputReader.cpp` 的主要任务是: 1. **监听 `/dev/input/eventX` 设备节点** 2. **读取来自内核的 `struct input_event`** 3. **识别设备类型(键盘、鼠标、触摸屏等)** 4. **将原始事件分类并打包成 `RawEvent`** 5. **通过策略和映射转换为 `QueuedEvent`** 6. **传递给 `InputDispatcher` 分发到应用** --- ## 🏗️ 架构概览(Android 11+) ```text [硬件] ↓ (evdev) /dev/input/event0~N ↓ InputReader.loopOnce() → poll(获取新事件) ↓ InputReader.readEvents() → 从设备读取一批 struct input_event ↓ EventHub 提供跨平台抽象(屏蔽 Linux evdev 差异) ↓ InputReader.processEventsLocked() 处理每个事件 ↓ → 根据设备配置选择合适的 InputMapper(如 TouchInputMapper, KeyboardInputMapper) ↓ Mapper 解析事件 → 生成中间表示(如 MoveGesture, KeyDown) ↓ 封装为 NotifyMotionArgs / NotifyKeyArgs ↓ enqueueNotifyRequest() → 加入队列 ↓ 唤醒 InputDispatcher 处理事件 ``` --- ## 📌 核心类结构(摘自 InputReader.cpp 及相关头文件) | 类 | 作用 | |----|------| | `InputReader` | 主循环类,协调多个输入设备 | | `InputDevice` | 表示一个物理/逻辑输入设备 | | `InputMapper` | 抽象基类,用于将原始事件映射为高级语义 | | `TouchInputMapper` | 处理多点触控事件 | | `KeyboardInputMapper` | 处理按键事件 | | `CursorInputMapper` | 处理鼠标、轨迹球等指针设备 | | `SensorInputMapper` | 处理传感器类输入(如陀螺仪) | --- ## 🔍 关键函数详解(基于 AOSP 源码) ### 1. `void InputReader::loopOnce()` 这是主循环函数,每几毫秒执行一次。 ```cpp void InputReader::loopOnce() { int32_t timeoutMillis; // 步骤1:读取事件 size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); { // 锁定 if (count) { // 步骤2:处理所有读取到的事件 processEventsLocked(mEventBuffer, count); } // 步骤3:更新设备状态(热插拔检测) updateReopenDevicesIfNeededLocked(); } // 解锁 // 步骤4:通知分发器处理新的输入事件 mQueuedListener->flush(); } ``` --- ### 2. `void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count)` 逐个处理从 EventHub 读出的原始事件。 ```cpp void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { for (const RawEvent* event = rawEvents; event != rawEvents + count;) { if (event->type == EV_DEVICE_REMOVED) { // 设备移除 handleDeviceRemovedLocked(event->deviceId, event->when); event++; } else { // 获取设备对象 InputDevice* device = mDevices.valueAt(deviceIndex); // 将事件交给设备处理 device->process(rawEvents, &rawEvents); } } } ``` --- ### 3. `void InputDevice::process(const RawEvent* rawEvents, size_t count)` 将事件分发给注册的 Mapper。 ```cpp void InputDevice::process(const RawEvent* rawEvents, size_t count) { size_t i = 0; while (i < count) { const RawEvent& evt = rawEvents[i]; bool handled = false; // 遍历所有 Mapper(例如 TouchInputMapper) for (auto& mapper : mMappers) { if (mapper->resolveDeviceClasses(&evt)) { mapper->process(&evt); // 处理事件 handled = true; break; } } if (!handled) { mErrorMessages << "Could not resolve event device class.\n"; } i++; } } ``` --- ## 💡 示例:鼠标滚轮如何变成 `ACTION_SCROLL` 我们以 **鼠标滚轮滚动** 为例,说明它如何被 `InputReader.cpp` 处理并最终成为 `ACTION_SCROLL` 事件。 ### 场景:用户向前滚动鼠标滚轮 #### 1. 内核上报事件 ```c struct input_event { .type = EV_REL, .code = REL_WHEEL, .value = 1 // 向前滚动一格 }; ``` #### 2. `EventHub` 捕获并传给 `InputReader` ```cpp // InputReader.cpp if (event.type == EV_REL) { switch (event.code) { case REL_WHEEL: // 被 CursorInputMapper 捕获 mRelWheel = accumulate(mRelWheel, event.value); break; } } ``` #### 3. `CursorInputMapper` 收集相对运动数据 ```cpp void CursorInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { case EV_REL: switch (rawEvent->code) { case REL_WHEEL: mPendingRelativeVScroll += rawEvent->value; break; case REL_HWHEEL: mPendingRelativeHScroll += rawEvent->value; break; } break; } } ``` #### 4. 提交为 `NotifyMotionArgs` ```cpp NotifyMotionArgs args( rawEvent.when, rawEvent.readTime, DEVICE_ID_DEFAULT, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_ACTION_SCROLL, flags, 0, // metaState 0, 0, // x/y 当前指针位置 mOrientationComponents, precisionX, precisionY, xCursorPosition, yCursorPosition, mAxeValueHelper.getAxisBits() ); args.caxisValues.append(AMOTION_EVENT_AXIS_VSCROLL, mPendingRelativeVScroll); args.caxisValues.append(AMOTION_EVENT_AXIS_HSCROLL, mPendingRelativeHScroll); notifyMotion(&args); // 发送给 dispatcher ``` #### 5. 上层收到 `ACTION_SCROLL` Java 层通过 JNI 接收,最终调用: ```java View.onGenericMotionEvent(MotionEvent { action: ACTION_SCROLL, axis: AXIS_VSCROLL = 1.0f }) ``` --- ## 🛠 调试技巧(适用于 ROM 开发者) ### 查看当前输入设备列表 ```bash adb shell getevent -ilp ``` 输出示例: ``` add device 6: /dev/input/event4 name: "Logitech USB Optical Mouse" events: KEY (0001): BTN_LEFT, BTN_RIGHT, BTN_MIDDLE REL (0002): REL_X, REL_Y, REL_WHEEL, REL_HWHEEL input props: INPUT_PROP_POINTER ``` ### 使用 ADB 模拟滚动 ```bash # 垂直滚动(+1 表示向上) adb shell input mouse scroll --vertical 1 # 水平滚动 adb shell input mouse scroll --horizontal 1 ``` --- ## 📈 与 Java 层的关系图 ```text Kernel (evdev) ↓ EventHub (C++) ↓ InputReader.cpp → 解析原始事件 ↓ InputDispatcher.cpp → 分发事件 ↓ JNI (com_android_server_input_InputManagerService.cpp) ↓ Java: InputManagerService → ViewRootImpl ↓ View.onGenericMotionEvent(event) ↓ 开发者处理 ACTION_SCROLL ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值