Android 键盘驱动移植呆板手册(从kernel到Java应用层简单描述)

发布时间:2016-12-8 13:55:52 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Android 键盘驱动移植呆板手册(从kernel到Java应用层简单描述)",主要涉及到Android 键盘驱动移植呆板手册(从kernel到Java应用层简单描述)方面的内容,对于Android 键盘驱动移植呆板手册(从kernel到Java应用层简单描述)感兴趣的同学可以参考一下。

Android 键盘驱动移植呆板手册 --write by fpga_dsp (以前一直没有写博客习惯,近来发现博客不仅能够和别人分享知识,同时也是自己的笔记,所以计划将多年来的一些技术经验,拿出来和大家分享一下。 今天开始第一步,来个简单的内容:android键盘驱动,期望大家看到不妥的地方提出来,只有这样大家才会共同进步。 本人不反对转载之类的,但是期望你能够把其中发现的错误改过来 发表之前先说csdn两句,这个内容编辑框做的有点差劲,贴进来格式全变了)   1          Android系统键盘结构 1.1         Anroid linux输入设备系统架构 1.2         android键盘设备代码层次结构 2          键盘驱动详细分析 2.1         Kernel驱动(这里不介绍怎么扫描按键,因为不同的产品可能采用不同的方式,如矩阵,AD,单GPIO等) 2.1.1    重要的数据结构介绍 1)、struct input_dev:该数据结构是所有linux事件输入设备中都要涉及的结构。这里介绍几个键盘驱动相关重要成员 l name 键盘驱动名称,在android驱动,按键配置文件名称需要与其一致,这样系统才能找到你的配置文件。否则可能出现的情况就是,上传按键,其结果是应用层总是得到按键码为0的按键,其原因系统默认的按键转换表中没有你上报的按键 l unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];:按键mask位,键盘驱动中,用keybit标示是否是合法的按键,所以在驱动初始化的时候,一定要调用set_bit函数将keybit对应按键值的位置1,这样按键上报的时候才会被系统接受,否则会被忽略,应用用搜不到按键值 l int (*open)(struct input_dev *dev);键盘打开函数指针,系统准备ok之后会调用该接口打开键盘,然后开始监听键盘事件 l void (*close)(struct input_dev *dev);键盘关闭函数指针 2.1.2    初始化并注册键盘驱动 (注:由于这里主要针对键盘驱动,所以驱动模块注册部分省略直接默认进入键盘初始化模块),键盘初始化的基本步骤(假设定义的input_dev指针为*pkey_dev): l  pkey_dev = input_allocate_device();//申请键盘设备,必不可少 l  补充键盘驱动信息,主要是驱动名,设备节点设置   pkey_dev->name = INPUT_DEV_NAME;  //键盘驱动名称,android系统中键盘配置文件需要和气保持一致       pkey_dev->phys = "xxx/input0"; // 设备节点,应用层需要打开该设备节点进行监听,如果省略该步骤,采用标准节点/dev/input/       pkey_dev->id.bustype= BUS_HOST;  //基本是固定值          pkey_dev->id.vendor = 0x0001;       pkey_dev->id.product= 0x0001;       pkey->id.version= 0x0100; l  设置键盘触发类型 pkey_dev->evbit[0] = BIT_MASK(EV_KEY);//表示输入设备为KEY l  标示有效按键,假设keycodes为用户自己定义的无符号整形码表(数组) for (i =0; i < KEY_MAX_CNT; i++)                set_bit(keycodes[i],pkey_dev ->keybit);//标示设备有效的按键,如果不做该处理,按键将被内核输入设备管理层过滤 l  初始化键盘硬件,比如GPIO设置,矩阵键盘设置,AD键盘寄存器设置等等 l  初始化键盘打开关闭接口(非必须,可以在初始化(调用probe)之后键盘即进入工作状态,但是个人建议按标准来做会比较好) pkey_dev->open = 键盘打开函数名,记住类型不要定义错误,否则编译的时候没有问题,但是运行会有问题。Open主要处理的内容:比如打开键盘中断,启动定时器;       pkey_dev->close = 键盘关闭函数名,关闭中断,定时器; l  注册键盘设备,至此最基本按键设备初始化完成 input_register_device(pkey_dev);   2.1.3    按键扫描上报处理 (这里省略如何获得按键值的步骤,) l  当驱动检测到按键按下时:一般采用以下方式汇报按键值: input_report_key(pkey_dev,keycodes[检测到按下的按键], 1);//汇报按键按下事件        input_sync(pkey_dev);   //事件同步,执行该函数之后事件才能传到应用层 l  当驱动检测到按键释放时:一般采用以下方式汇报按键值: input_report_key(pkey_dev, keycodes[检测到按下的按键],0);//汇报按键释放事件  input_sync(pkey_dev);   //事件同步,执行该函数之后事件才能传到应用层 2.1.4    按键休眠支持(针对较新内核) 1、  完成structdev_pm_ops数据结构,如下所示 //add by fpga_dsp staticconst struct dev_pm_ops keypad_pm_ops = {        .suspend  =keypad_suspend,//休眠挂起处理函数        .resume            =keypad_resume,//唤醒处理函数 }; 2、  完成structplatform_driver结构 staticstruct platform_driver keypad_driver = {        .probe                =keypad_probe,//驱动初始化接口        .remove            =__devexit_p(keypad_remove),//驱动退出接口        .driver                ={                 .name       = "keypad",//驱动名                 .owner     = THIS_MODULE, #ifdef CONFIG_PM//add by fpga_dsp        .pm  =&keypad_pm_ops,//电源管理接口,即休眠唤醒等处理接口 #endif        }, }; 2.2         键盘配置文件 2.2.1    .idc文件 Idc配置文件,这个必须和键盘驱动的pkey_dev->name一致,   keyboard.layout= xxx//指明键盘布局文件,对键盘驱动来说,即键值转换表. xxx.kl keyboard.characterMap= xxxxx //按键字符表xxxxx.kcm   2.2.2    .kl文件 按键映射表,可以在frameworks\base\include\ui\KeycodeLabels.h文件中查到   第二列,kernel驱动上报的按键值,第三列,转换后的android键值转义字符串,android系统中有些按键按下是不唤醒系统的,可以加上第4列WAKE使能唤醒功能,也可以用WAKE_DROPPED将一些按键唤醒功能屏蔽掉 key 399  GRAVE key2     1 key3     2 key4     3 key5     4 key6     5   key230  SOFT_RIGHT        WAKE key 139  MENU                  WAKE_DROPPED //add byfpga_dsp 2.2.3    .kcm文件 该文件主要处理多功能键,组合键等功能,下面举个例子说明一下 #jin wang add key A {     label:                              'A'     number:                             '2'     base:                               'a'     shift, capslock:                    'A'     alt:                                '#'     shift+alt, capslock+alt:            none } //add by fpga_dsp 以上标示针对按键A(android层定义的按键)的定义: Label:标示按键标签 Number:带键盘的手机都这个功能就是数字1,连续按下之后可以切换结果,这里表示连续按A键之后,可以得到字符‘2’ Base:key A原始字符,就是单独按下A键的结果,这里表示得到小写的字母‘a’ shift, capslock:标示按下shift键或者capslock之后再按A键的结果,‘A’表示得到大写的字母A alt:表示按alt键在按A键得到#号 shift+alt,capslock+alt: 表示按shift+alt,或者capslock+alt,再按A键的结果,none表示忽略 (注:不同android版本文件格式可能不一致) 2.3         C++应用层 2.3.1    重要的数据结构 2.3.1.1   struct KeycodeLabel {    const char *literal;    int value; }; 2.3.2    代码简介 一般情况如果没有特殊按键(自定义的特殊按键),android C++部分是不用修改的,这里只作简单介绍: l  frameworks\base\services\input\目录是输入设备处理代码,其中EventHub.cpp主要用来读取设备文件中的RawEvent,而InputReader.cpp和InputDispatcher.cpp算是它们之间的对接层。InputReader从设备文件中读取的是RawEvent,在交给InputDispatcher进行分发之前,它需要先把RawEvent进行转化分类,拆分成KeyEvent、MotionEvent、TrackEvent各种类型等,InputDispatcher同时也能够过滤一些输入事件,功能类似linux内核中的iptables。 l  frameworks/base/libs/ui/KeyLayoutMap.cpp (处理linux按键码和android按键码转换文件*.kl) l  frameworks/base/libs/ui/KeyCharacterMap.cpp  (处理键盘字符关系表*./Kcm) l  经过一系列处理之后,需要通过一个接口将这些事件传送到android 应用层,这个文件便是 frameworks/base/services/jni/com_android_server_InputManager.cpp(EventHub和KeyInputQueue的JNI接口),java通过JNI可以直接调用C++模块函数   2.4         Java代码 2.4.1  Android服务层 framework/base/services/java/com/android/server/InputMethodManagerService.java:主要向Android窗口系统提供服务,把KeyEvent分发给最上层的窗口,WindowManagerService通过InputManager提供的native接口开启了两个线程驱动做KeyEvent读取和分发给WindowManagerService管理的客户端。 2.4.2  com/android/server/wm/InputManager.java jnijava接口 2.5         Java键盘应用程序 2.5.1    创建类继承Activity public class EventTest01 extends Activity {…} 2.5.2    重写onKeyDown方法 举例:public booleanonKeyDown(int keyCode, KeyEvent event)      {          switch(keyCode)          {          case KeyEvent.KEYCODE_DPAD_CENTER:              …添加自己的代码;break;          case KeyEvent.KEYCODE_DPAD_UP:              …添加自己的代码;break;  //add by fpga_dsp         }          return super.onKeyDown(keyCode,event);      } 2.5.3    重写onKeyUp方法 举例: public booleanonKeyUp(int keyCode, KeyEvent event)      {          switch(keyCode)          {          case KeyEvent.KEYCODE_DPAD_CENTER:              …添加自己的代码;              break;          case KeyEvent.KEYCODE_DPAD_DOWN:              …添加自己的代码;              break;          }          return super.onKeyUp(keyCode, event);      } 3          Android键盘调试常见的问题 3.1         如何添加一个新的按键(非标准) 3.1.1    在内核中input.h自定义一个按键。 不要和其他按键值冲突,不要超过KEY_MAX。例如#define KEY_MYTEST 0x21b 3.1.2    在键盘驱动中添加新按键上报处理 3.1.3    修改.kl文件 添加key 539  MYTEST,539要和自定义按键值对应,记住MYTEST字符串待会用到 3.1.4    修改按键转义字符文件 Frameworks/base/include/ui/KeycodeLabels.h,在static constKeycodeLabel KEYCODES[] = 数组最后添加{ " MYTEST ", 211 },记得literal变量值”MYTEST”要和.k文件定义的一致,而且不要与其他按键冲突,value值也一样 3.1.5    修改frameworks/base/native/include/android/keycodes.h添加枚举变量,这里主要是为了方便按键值记忆: /*  * Key codes.  */ enum { … AKEYCODE_MYTEST     = 211,//这个值要和KeycodeLabels.h中value值一样 3.1.6    修改frameworks/base/core/java/android/view/KeyEvent.java文件 l  添加public static final int KEYCODE_MYTEST      = 211; l  修改privatestatic final int LAST_KEYCODE           =KEYCODE_MYTEST; //如果这里不修改,按键会被android系统认为是非法的按键 l  修改privatestatic void populateKeycodeSymbolicNames()在末尾添加 names.append(KEYCODE_MYTEST, " KEYCODE_MYTEST "); //记得名称别搞错了 l  修改 isSystem(),追踪jni需要修改 frameworks/base/lib/androidrw/input.cpp KeyEvent::isSystemKey boolKeyEvent::isSystemKey(int32_t keyCode) {     switch (keyCode) {                case AKEYCODE_MYTEST: //add by fpga_dsp             return true;     } 3.1.7    修改external/webkit/Source/WebKit/android/plugins/ ANPKeyCodes.h enumANPKeyCodes {      … kMyTest_ANPKeyCode=211,//add byfpga_dsp … };   3.1.8    最后修改UI  frameworks/base/core/res/res/values/attr.xml <attrname="keycode">         <enum name="KEYCODE_UNKNOWN"value="0" />           …. <enumname=" KEYCODE_MYTEST " value="211"/>(新加代码) //记住这里要和3.1.6节中定义的一致 3.2         内核上报按键了,但是android应用没有反应 3.2.1    情况一:按键在内核中被屏蔽了,注意检查set_bit(keycodes[i], pkey_dev ->keybit);是否正常执行 3.2.2    情况二:android会过滤特殊按键,比如POWER键,当然如果是自定义按键就需要检查3.1节提到每一个步骤了 3.3         应用层得到按键值总是0 检查按键布局文件.kl,一般都是由于.kl文件中没有处理内核上报的按键值导致的

上一篇:toj3073 Country road prim算法 典型题
下一篇:MySQL数据库MyISAM和InnoDB存储引擎的比较

相关文章

相关评论