您的位置:首页 > 其它

input core输入事件 矩阵键盘 映射 原理分析

2015-07-08 11:20 381 查看
//这个是矩阵键盘映射表,使用内核定义的宏KEY()来建立
//#defineKEY(row,
col,val)
((((row)& (MATRIX_MAX_ROWS - 1)) << 24) |\
//(((col)&
(MATRIX_MAX_COLS - 1)) << 16) |\
//((val)&
0xffff))
//从上面的定义来看KEY用于唯一确认一个值,用于将(row,col,val)转换为一个单一个32位的值。
//这样存储起来,比较节省空间。高高字节用于存储行号,高低字节用于存储列号,低高和低低字节用于保存值。
//如此一来,将二维坐标(x,y)及值val转换为一个单一的32int数据。
//但是取出来的时候还得使用特殊的宏来操作。
//将扫描码映射为内核定义的标准键值,以方便上层应用程序使用。
staticintmx6sl_evk_keymap[]
= {
KEY(0,0, KEY_SELECT),
//映射矩阵(0,0)处按键为内核标准的KEY_SELECT键码。
KEY(0,1, KEY_BACK),
KEY(0,2, KEY_F1),
//映射矩阵(0,2)处按键为内核标准的KEY_F1键码。
KEY(0,3, KEY_F2),
//映射矩阵(0,3)处按键为内核标准的KEY_F2键码。
//内核自己定义的键码在linux/input.h中定义。
KEY(1,0, KEY_F3),
KEY(1,1, KEY_F4),
KEY(1,2, KEY_F5),
KEY(1,3, KEY_MENU),

KEY(2,0, KEY_PREVIOUS),
KEY(2,1, KEY_NEXT),
KEY(2,2, KEY_HOME),
KEY(2,3, KEY_NEXT),

KEY(3,0, KEY_UP),
KEY(3,1, KEY_LEFT),
KEY(3,2, KEY_RIGHT),
KEY(3,3, KEY_DOWN),
};
//这个结构体也是内核抽象出来的,定义在linux/input/matrix_keypad.h中。
//structmatrix_keymap_data
{
//
constuint32_t *keymap;
// unsignedint
keymap_size;
//};
staticconststructmatrix_keymap_data
mx6sl_evk_map_data__initconst = {
.keymap
=mx6sl_evk_keymap,
.keymap_size
=ARRAY_SIZE(mx6sl_evk_keymap),
};
//#defineARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
//这里的ARRAY_SIZE宏用于确认数组大小(数组有多少元素)。
//从实现来看就是使用sizeof求出整个数组占用内存大小,然后用sizeof(第一个元素)占用内存大小
//这2个数一除就能得到整个数组中元素的个数。
#defineMATRIX_MAX_ROWS
32
#defineMATRIX_MAX_COLS
32

//内核使用一个32位的数据来保存3种信息:行号,列号,键码。
//最高8位<31:24>用于保存行号。
//低高8位<23:16>用于保存列号。
//低16位<15:0>用于保存内核定义的键码。
#defineKEY_ROW(k)
(((k) >> 24) & 0xff) //从32位数据中提取最高8位的行号
#defineKEY_COL(k)
(((k) >> 16) & 0xff) //从32位数据中提取次高8位的列号
#defineKEY_VAL(k)
((k) & 0xffff) //从32位数据中提取低16位的映射的内核定义的键码!

//这个应该用于行列的索引值,可以在映射数组中根据行,列获取下标。
//其中对于row_shift的定义为:
*@row_shift: number of bits to shift row value by to advance to thenext line
in the keymap
//大体的意思就是:在keymap中用于移至下一行的值的位数。
//在内核中找到了imx6kpp的驱动,他的定义如下,结合起来,更好理解。
//#defineMAX_MATRIX_KEY_ROWS 8
//#defineMAX_MATRIX_KEY_COLS 8
//#defineMATRIX_ROW_SHIFT 3 //这里就是row_shift了,这里行大小为8,移至下行需要移到8个,所以2^3=8,所以这里
//row_shift就为8了。
#defineMATRIX_SCAN_CODE(row,
col, row_shift) (((row) << (row_shift)) +(col))
//从上面的定义来看使用<<左移,所以2<<3=8.感觉这个函数只是将行号和列号组织在了一起而已。

//一般的驱动会有以下的代码,用于向inputcore提供事件。
//这里比较关键的是第3句,使用行列组织在一起的code从keycodes[]数组中提出映射键码,这是怎么做到的呢?

code=
MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
input_event(input_dev,EV_MSC,
MSC_SCAN, code);
input_report_key(input_dev,keypad->keycodes[code],matrix_volatile_state[col]&
(1 << row));

//来看一下,下面这些代码,分析一下,找出为什么?
input_dev->keycode= keypad->keycodes;

input_dev->keycodesize=
sizeof(keypad->keycodes[0]);
input_dev->keycodemax= ARRAY_SIZE(keypad->keycodes);

//其实这里比较关键的,建立了映射关系!
conststructmatrix_keymap_data
*keymap_data =pdev->dev.platform_data;//从平台设备中拿到映射表。

matrix_keypad_build_keymap(keymap_data,MATRIX_ROW_SHIFT,
keypad->keycodes,input_dev->keybit);
//再来看看这个映射函数的实现过程吧。
//内核中注释的意思将keymap_data转换到keymap中存储,并使用行+列来索引。
staticinlinevoid
matrix_keypad_build_keymap(conststructmatrix_keymap_data
*keymap_data,
unsignedintrow_shift,
unsignedshort*keymap,
unsignedlong*keybit)
{
inti;

for(i
= 0; i < keymap_data->keymap_size;i++) { //循环处理每一个元素。
unsignedintkey
= keymap_data->keymap[i];//存储的32位值。
unsignedintrow
= KEY_ROW(key); //从32位值中拿到行号。
unsignedintcol
= KEY_COL(key); //从32位值中拿到列号。
unsignedshortcode
= KEY_VAL(key); //从32位值中拿到键码。

keymap[MATRIX_SCAN_CODE(row,col, row_shift)] = code; //最最关键的这句话!!在keymap中指定位置(行号+列号)存储键码!
//这里就是
行号<<8+列号 形成一个16位的数据,这样就可以唯一的标识一个数组的下标索引,将相关的键码保存在此单元中。
__set_bit(code,keybit);
}
__clear_bit(KEY_RESERVED,keybit); //这句真不知道什么意思?
//从structinput_dev结构体中找到的定义如下:
*@evbit:bitmap
of types of events supported by the device (EV_KEY,
* EV_REL,etc.)
按位操作,表示这个设备支持的事件。
*@keybit:bitmap
of keys/buttons this device has :按位操作,表示这个设备支持的按键。
}

好,我们再来看看上面那3句代码,用于向inputcore上报事件:
1、code=
MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
2、input_event(input_dev,EV_MSC,
MSC_SCAN, code);
3、input_report_key(input_dev,keypad->keycodes[code],matrix_volatile_state[col]&
(1 << row));
第1句知道了吧,根据上面的分析就是将行号<<8+列号,组合起来,构成一个16位的数据。
第2句这应该是上报类似于键盘扩展码之类的,这个暂时用不到。不过在内核中很多代码都加了这句。
第3句比较关键,关键是要正确上报映射的键码。由于之前使用matrix_keypad_build_keymap函数将键码存储到数组指定的位置,
那么下面可以轻松的使用行号<<8+列号来取到键码了。
1表示按下,0表示松开。现在来分析一下,还是比较简单的。
之前看到imx6中的kpp的驱动代码,结合数据手册,感觉imx6的这个kpp简单很鸡肋,没有什么功能。
是提供了I/O的开漏输出和图腾柱输出模式,具体的扫描、消抖还得在代码中手工完成。
因为最近有个项目需要用于自定义的矩阵键盘,同时上层使用Qt来实现,看了下现在最新的qt5支持evdev,可直接从/dev/input/eventx
中读取输入事件,所以只要驱动使用input子系统上报输入事件,那么qt就肯定能收到。
由于是嵌入式设备,界面上就不能使用鼠标进行操作了,就必须使用keyPressEvent/keyReleaseEvent来实现操作了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: