Android系统--输入系统(十)Reader线程_核心类及配置文件深入分析

0. 前言

个人认为该知识点阅读Android源代码会不仅容易走进死胡同,并且效果并不好,前脚看完后脚忘记,故进行总结,希望可以更好帮助大家了解,了解之后在进行阅读源代码会有事半功倍的效果。

1. 引入

由输入系统(九)实验得出
  • keylayout文件:只是用来表示驱动上报的scancode对应哪一个android按键(AKEYCODE_x)只是表示按键被按下。
  • kcm文件: 用来表示android按键(AKEYCODE_x)对应哪一个字符。也表示同时按下其他按键后,对应哪个字符。
但是要想深入理解其中的读取转化过程,需要仔细分析源代码,了解其中涉及的类和结构体,本次博文就是针对其进行解析。

2. 函数具体实现

Event_Hub.cpp
  • open--打开设备节点
  • ioctl得到设备信息
  • 创建device对象
  • 加载IDC配置文件
  • 加载.kl,kcm文件
status_t EventHub::openDeviceLocked(const char *devicePath) {
char buffer[80]; ALOGV("Opening device: %s", devicePath); int fd = open(devicePath, O_RDWR | O_CLOEXEC);
if(fd < 0) {
ALOGE("could not open %s, %s\n", devicePath, strerror(errno));
return -1;
} InputDeviceIdentifier identifier; // Get device name.
if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.name.setTo(buffer);
} // Get device driver version.
int driverVersion;
if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {
ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
} // Get device identifier.
struct input_id inputId;
if(ioctl(fd, EVIOCGID, &inputId)) {
ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
close(fd);
return -1;
}
identifier.bus = inputId.bustype;
identifier.product = inputId.product;
identifier.vendor = inputId.vendor;
identifier.version = inputId.version; // Get device physical location.
if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.location.setTo(buffer);
} // Get device unique id.
if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
//fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
} else {
buffer[sizeof(buffer) - 1] = '\0';
identifier.uniqueId.setTo(buffer);
} // Allocate device. (The device object takes ownership of the fd at this point.)
int32_t deviceId = mNextDeviceId++;
Device* device = new Device(fd, deviceId, String8(devicePath), identifier); // Load the configuration file for the device.
loadConfigurationLocked(device); ...... addDeviceLocked(device);
return 0;
}

3. 类调用过程

4. EventHub类

在Reader线程中,采用EventHub类记录多个输入设备
- mNextDeviceId   : int32_t
- mDevices : KeyedVector<int32_t, Device*> //表示设备,记录设备编号和设备
- mOpeningDevices : Device *
- mClosingDevices : Device *

5. Device类

描述输入设备
- fd                    : int //设备节点所打开的文件句柄
- identifier : const InputDeviceIdentifier //记录厂商信息,存储了设备的供应商、型号等信息
- keyBitmask[] : uint8_t
- configurationFile : String8 //IDC文件名
- configuration : PropertyMap* //IDC属性:(内嵌OR外接)设备
- keyMap : KeyMap //保存配置文件(kl,kcm)
IDC文件调用顺序说明
Input device configuration files are located by USB vendor, product (and optionally version) id or by input device name.

The following paths are consulted in order.

/system/usr/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
/system/usr/idc/Vendor_XXXX_Product_XXXX.idc
/system/usr/idc/DEVICE_NAME.idc
/data/system/devices/idc/Vendor_XXXX_Product_XXXX_Version_XXXX.idc
/data/system/devices/idc/Vendor_XXXX_Product_XXXX.idc
/data/system/devices/idc/DEVICE_NAME.idc

6. Keymap对象详解

6.1 Keymap类
- keyLayoutFile        : String8
- keyLayoutMap : sp<KeyLayoutMap>
- keyCharacterMapFile : String8
- keyCharacterMap : sp<KeyCharacterMap>
6.2 KeyLayoutMap类
- mKeysByScanCode     : KeyedVector<int32_t, Key> //内核上报的扫描码,返回key结构体
- mKeysByUsageCode : KeyedVector<int32_t, Key> //使用usrage码上报,少用(USB键盘等)
  • key结构体
- keyCode : int32_t //对应Android系统返回的AKEYCODE码
- flags : uint32_t
/*flags参数说明*/
/*The following policy flags are recognized:
*FUNCTION:The key should be interpreted as if the FUNCTION key were also pressed.
*GESTURE: The key generated by a user gesture, such as palming the touchscreen.
*VIRTUAL: The key is a virtual soft key (capacitive button) adjacent to the main touch screen. This causes special debouncing logic to be enabled (see below).
*/
总结:通过内核上报的扫描码,查找并取出对应Android系统中的AKEYCODE_XXX码。
6.3 KeyCharacterMap类
- mKeys : KeyedVector<int32_t, Key*>

//在kcm文件中也可以进行按键的映射,原理跟kl文件一样
//但在虚拟按键中处理效果差,故一般通过kl文件进行映射
- mKeysByScanCode : KeyedVector<int32_t, int32_t>
- mKeysByUsageCode : KeyedVector<int32_t, int32_t>
  • key结构体
- label  : char16_t
- number : char16_t //在安卓系统中,操作只能输入数字框,按下按键则输出该参数
- firstBehavior : Behavior*
  • Behavior结构体
- metaState : int32_t
- character : char16_t
- fallbackKeyCode : int32_t
参数具体说明:用kcm文件中B字符举例,下面根据Android中的AKEYCODE_B(例1),得出对应的key结构体,结构体包括label、number、firstBehavior三个参数,label参数:对应例1中的label;number参数:在安卓系统中,操作只能输入数字框,按下按键则输出该参数;对于例1中base会生成一个behavior结构体描述,即behavior结构体中的metaState参数为0,character为‘b’,同样shift,也会构建一个behavior结构体,此时mstaState为shift,character为'A',capslock与shift同理。
例1:KCM文件(AKEYCODE_B)
key B {
label: 'B' # 印在按键上的文字
base: 'b' # 如果没有其他按键(shift, ctrl等)同时按下,此按键对应的字符是'b'
shift, capslock: 'B' # 当按下shift/capslock,输出为'B'
}
对于fallbackKeyCode 参数说明:同理AKETOCDE_SPACE(例2),前面对应关系就不赘述,从例2中的base开始分析,对于base会生成一个behavior结构体描述,即behavior结构体中的metaState参数为0,character为‘ ’,alt,也会构建一个behavior结构体,此时mstaState为shift,character无,fallbackKeyCode为AKEYCODE_SEARCH,meta与alt与同理。crtl也会构建一个behavior结构体,此时mstaState为crtl,character无,fallbackKeyCode为AKEYCODE_LANGUAGE_SWITCH。
对应的behavior结构体构建为一条链表,firstBehavio即指向该链表。
fallbackKeyCode作用:底层的Linux驱动检测有输入事件产生,上报一个Android:keycode,应用程序收到后进行处理,如果可以处理,处理之后会回复一个处理成功的信号,如果不可以处理,输入系统会再次上报一个值,即为fallbackKeyCode。
例2:KCM文件(AKEYCODE_SAPCE)
key SPACE {
label: ' '
base: ' '
alt,meta: 'fallback SEARCH'
ctrl: 'fallback LANGUAGE_SWITCH'
}
7. 类的调用过程概述
  • Reader线程使用EventHub类记录多个输入设备
  • 从EventHub类中通过Device类,根据设备编号查找并打开对应输入设备
  • 打开设备,并通过ioctl获取该设备信息
  • 根据设备信息读取IDC文件,加载keylayout、KCM配置文件(保存在KeyMap类中)
  • keylayout负责将Linux内核上报的扫码转化为Android中的AKEYCODE_XXX
    • 读取一个kl文件
    • 扫描码转为keycode码
    • 将信息存在KeyedVector当中key结构中
  • KCM文件负责将keycode码转化为输出字符
    • 根据keycode在KeyedVector扫描出对应的key结构体
    • key结构体中的firstBehavior结构体指针指向一系列的behavior结构体
    • 根据mateState找出对应的behavior结构体,返回对应的character
    • 如果无法处理,则输入系统将再次上报一个值,即为fallbackKeyCode

Android系统--输入系统(十)Reader线程_核心类及配置文件深入分析的更多相关文章

  1. Android系统--输入系统(九)Reader线程_核心类及配置文件

    Android系统--输入系统(九)Reader线程_核心类及配置文件 1. Reader线程核心类--EventHub 1.1 Reader线程核心结构体 实例化对象:mEventHub--表示多个 ...

  2. Android系统--输入系统(八)Reader线程_使用EventHub读取事件

    Android系统--输入系统(八)Reader线程_使用EventHub读取事件 1. Reader线程工作流程 获得事件 size_t count = mEventHub->getEvent ...

  3. Android系统--输入系统(十一)Reader线程_简单处理

    Android系统--输入系统(十一)Reader线程_简单处理 1. 引入 Reader线程主要负责三件事情 获得输入事件 简单处理 上传给Dispatch线程 InputReader.cpp vo ...

  4. 10.5 android输入系统_Reader线程_使用EventHub读取事件和核心类及配置文件_实验_分析

    4. Reader线程_使用EventHub读取事件 使用inotify监测/dev/input下文件的创建和删除 使用epoll监测有无数据上报 细节: a.fd1 = inotify_init(& ...

  5. Android系统--输入系统(十二)Dispatch线程_总体框架

    Android系统--输入系统(十二)Dispatch线程_总体框架 1. Dispatch线程框架 我们知道Dispatch线程是分发之意,那么便可以引入两个问题:1. 发什么;2. 发给谁.这两个 ...

  6. Android系统--输入系统(十四)Dispatcher线程情景分析_dispatch前处理

    Android系统--输入系统(十四)Dispatcher线程情景分析_dispatch前处理 1. 回顾 我们知道Android输入系统是Reader线程通过驱动程序得到上报的输入事件,还要经过处理 ...

  7. Android系统--输入系统(十五)实战_使用GlobalKey一键启动程序

    Android系统--输入系统(十五)实战_使用GlobalKey一键启动程序 1. 一键启动的过程 1.1 对于global key, 系统会根据global_keys.xml发送消息给某个组件 & ...

  8. Android系统--输入系统(十七)Dispatcher线程_分发dispatch

    Android系统--输入系统(十七)Dispatcher线程_分发dispatch 1. 回顾 InputRead线程从输入设备当中得到输入事件 对于读到输入事件稍作处理,比如紧急事件,来电时候按下 ...

  9. Android系统--输入系统(七)Reader_Dispatcher线程启动分析

    Android系统--输入系统(七)Reader_Dispatcher线程启动分析 1. Reader/Dispatcher的引入 对于输入系统来说,将会创建两个线程: Reader线程(读取事件) ...

随机推荐

  1. Android:NavigationView 导航抽屉

    NavigationView是一种标准的应用导航菜单,菜单栏的内容可以来自菜单栏资源文件. NavigationView最典型的应用场景是放到DrawerLayout里使用. API:https:// ...

  2. 使用JSON.parse(),JSON.stringify()实现对对象的深拷贝

    根据不包含引用对象的普通数组深拷贝得到启发,不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系. 测试例子: var test={ a:"ss", ...

  3. 用python抓取求职网站信息

    本次抓取的是智联招聘网站搜索“数据分析师”之后的信息. python版本: python3.5. 我用的主要package是 Beautifulsoup + Requests+csv 另外,我将招聘内 ...

  4. 优雅的使用sublime写lua~ sublime lua相关必装插件推荐~~

    缘起 lua脚本语言虽好,代码写得飞快,可是写错了调试起来却很困难,lua使用者经常容易犯得一个错误是--写错变量名了,if end 嵌套太多没匹配~,多打了一个逗号, 假设定义了一个变量 local ...

  5. Unity 3D Framework Designing(2)——使用中介者模式解耦ViewModel之间通信

    当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件).越是复杂的页面,被切割出来的子模块就越多,子模块 ...

  6. x战警 天启高清完整版下载

    天启出生于埃及第一王朝,是地球上最古老.最强大的变种人沙巴泊,曾拥有无数信众,但后来遭人背叛,被人活埋.几千年后,强大无匹而且永生不朽的天启从数千年的深埋中获释,愤怒的他发现同类不再被视为神祇,他对人 ...

  7. web works importScripts

    html: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <tit ...

  8. 判断是否支持WebP

    PC端,触屏版: 前端JS方案——利用img标签加载一张base64的WebP图片,在img标签的onload事件中判断该图片是否具有宽高的属性,若有表示支持webP,若没有表示不支持webP.后台判 ...

  9. JavaScript贪食蛇游戏制作详解

    之前闲时开发过一个简单的网页版贪食蛇游戏程序,现在把程序的实现思路写下来,供有兴趣同学参考阅读. 代码的实现比较简单,整个程序由三个类,一组常量和一些游戏逻辑以外的初始化和控制代码组成,总共400多行 ...

  10. Android之仿京东淘宝的自动无限轮播控件

    在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的思路和过程. 一.自定义控件属性 新建自定义控件SliderLayout继承于Re ...