关闭

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

1310人阅读 评论(0) 收藏 举报
分类:

//这个是矩阵键盘映射表,使用内核定义的宏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句,使用行列组织在一起的codekeycodes[]数组中提出映射键码,这是怎么做到的呢?


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上报事件:

1code= MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);

2input_event(input_dev,EV_MSC, MSC_SCAN, code);

3input_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来实现操作了。




0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    最新评论