目录
一、简介
Linux系统是通过输入子系统
来管理输入设备(如鼠标、键盘、触摸屏、游戏摇杆)的。配置了内核支持且安装对应驱动后,当系统接入输入设备,会在/dev/input
下生成对应设备文件,下图是鼠标、键盘在不同情况下/dev/input
的设备文件。
当输入设备有事件产生时,内核就会将事件上报到设备文件,事件的数据以struct input_event
为单位存入设备文件,所以读取事件数据时使用struct input_event
结构体,这个结构体定义在/usr/include/linux/input.h
中。
struct input_event {
struct timeval time;
__u16 type;
__u16 code;
__s32 value;
};
1.1 type
:事件类型
type:事件类型,常见的有:EV_KEY(键盘)、EV_REL(相对坐标)、EV_ABS(绝对坐标)、,定义在[input-event-codes.h] (https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h#LC35) 或 input.h 中。
EV_REL 按键事件:(鼠标,键盘等)
EV_REL 相对坐标(如:鼠标移动,报告相对最后一次位置的偏移)
EV_ABS 绝对坐标(如:触摸屏或操作杆,报告绝对的坐标位置)
/*
* Event types
*/
#define EV_SYN 0x00
#define EV_KEY 0x01 //按键
#define EV_REL 0x02 //相对坐标(轨迹球)
#define EV_ABS 0x03 //绝对坐标
#define EV_MSC 0x04 //其他、杂项
#define EV_SW 0x05 //软件
#define EV_LED 0x11 //LED
#define EV_SND 0x12 //声音
#define EV_REP 0x14 //repeat、会自动发出重复按键
#define EV_FF 0x15
#define EV_PWR 0x16 //电源开关、按键
#define EV_FF_STATUS 0x17
#define EV_MAX 0x1f
#define EV_CNT (EV_MAX+1)
1.2 code
code
:事件的代码,对事件进一步的描述
盘事件的键值(KEY_NUMLOCK、KEY_ESC、KEY_1、KEY_A),定义在[input-event-codes.h]
鼠标事件的位置信息(REL_X、REL_Y),滚轮信息(REL_WHEEL),定义在[input-event-codes.h]
触摸屏事的地位置信息(ABS_MT_POSITION_X),slot信息(ABS_MT_SLOT)定义在[input-event-codes.h]
1.3 value
value:
事件的值,对事件更具体地描述,如:
按键的按下/抬起
鼠标位置信息的具体 x值、y值
触摸屏事件slot信息表示第几个的值、ABS_MT_TRACKING_ID
的值
二 linux应用系统编程
2.1 驱动对象的确定
通常情况下,开发板的出厂系统,已经帮我们配置好了底层的驱动。我们只需要确定驱动的位置和名称,使用open,read,write,close等函数对驱动进行操作即可。
一般鼠标、键盘、触摸屏等输入设备的驱动都放在 /dev/input 这个文件夹下。
查看对应的硬件。注意,测试时需要将鼠标插上,有些开发板的驱动在外设插入的时候才启动
但是还是有点模糊,比如出现好几个Mouse,到底是哪个? 通过一下命令来测试:
hexdump /dev/input/event2 //event3、event4
来测试一下,我使用的开发板,当测试event2时,发现鼠标移动就不断输出数据,说明正是event2。
2.2 鼠标事件的介绍
鼠标的事件一般有 EV_REL(相对坐标)、EV_KEY(按键)
两种类型,EV_REL
用来表示鼠标在屏幕的位置(相对位置),EV_KEY
用来表示鼠标的按钮。
EV_REL类型(相对坐标)
如果事件是相对坐标时,读取到的struct input_event的type字段的值为 2 ,
code字段的取值可能是REL_X(相对坐标X值)、REL_X(相对坐标Y值)、REL_WHEEL(滚轮),
value字段根据code的取值不同而不同,可以表示坐标(X值、Y值),滚轮上滑(-1)、下滑(1)
下图是相对坐标时,code的定义的值。
#define REL_X 0x00
#define REL_Y 0x01
#define REL_Z 0x02
#define REL_RX 0x03
#define REL RY 0x04
#define REL_RZ 0x05
#define REL_HWHEEL 0x06
#define REL_DIAL 0x07
#define REL_WHEEL 0x08
#define REL_MISC 0x09
EV_KEY类型(按键:左键、右键、滚轮键)
上文说过,鼠标事件也有按键类型,表示左键、右键、滚轮键按下/抬起,读取到的struct input_event的type字段的值为 1 ,
code字段取值可能是BTN_LEFT(左键)、BTN_RIGHT(右键)、BTN_MIDDLE(滚轮键),
value字段一般是 1 表示按下,0 表示抬起,
下图是鼠标按键,code的定义的值:
#define BTN_MOUSE 0x110
#define BTN_LEFT 0x110
#define BTN_RIGHT 0x111
#define BTN_MIDDLE 0x112
#define BTN_SIDE 0x113
#define BTN_EXTRA 0x114
#define BTN_FORWARD 0x115
#define BTN_BACK 0x116
#define BTN_TASK 0x117
2.3 编写代码步骤
第一步:定义一个事件的结构体变量,我们要用到事件,需要得到事件,在程序中肯定需要一个变量来描述这个事件。
第二步:打开设备节点,Linux中一切皆文件,所以用open函数,打开输入设备节点
第三步:读取事件,读取打开的输入设备节点中的数据,到我们第一步的定义的事件变量中
第四步:利用获取的事件信息来完成我们自己编写的处理逻辑,这里就简单输出一下鼠标位置。
2.4 完整代码
代码实现的功能:
1、 读取鼠标的相对位移x,y,以及中间滑轮上下的数值(上滑动为1,下滑动为0);
2、读取鼠标左键,右键和中间滑轮点击情况,点击(按下)为1,松开为0 。
具体代码如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
//1、定义一个结构体变量用来描述input事件
struct input_event event_mouse ;
//2、打开input设备的事件节点 我的通用USB鼠标事件的节点是event2
int fd = -1 ;
if(2!= argc){
fprintf(stderr,"usage: %s <input-dev>\n", argv[0]);
exit(-1);
}
fd = open(argv[1], O_RDONLY);
if(-1 == fd)
{
printf("open mouse event fair!\n");
return -1 ;
}
while(1)
{
//3、读事件
read(fd, &event_mouse, sizeof(event_mouse));
if(EV_REL == event_mouse.type)
{
//code表示位移X或者Y,当判断是X时,打印X的位移value
//当判断是Y时,打印Y的位移value
if(event_mouse.code == REL_X)
{
printf("event_mouse.code_X:%d\n", event_mouse.code);
printf("event_mouse.value_X:%d\n", event_mouse.value);
}
else if(event_mouse.code == REL_Y)
{
printf("event_mouse.code_Y:%d\n", event_mouse.code);
printf("event_mouse.value_Y:%d\n", event_mouse.value);
}
else if(event_mouse.code == REL_WHEEL)
{
printf("event_mouse.code_WHEEL:%d\n", event_mouse.code);
printf("event_mouse.value_WHEEL:%d\n", event_mouse.value);
}
}
else if(EV_KEY == event_mouse.type)
{
if(event_mouse.code == BTN_LEFT)
{
printf("event_mouse.code_left:%d\n", event_mouse.code);
printf("event_mouse.value_left:%d\n", event_mouse.value);
}
else if(event_mouse.code == BTN_RIGHT)
{
printf("event_mouse.code_right:%d\n", event_mouse.code);
printf("event_mouse.value_right:%d\n", event_mouse.value);
}
else if(event_mouse.code == BTN_MIDDLE)
{
printf("event_mouse.code_middle:%d\n", event_mouse.code);
printf("event_mouse.value_middle:%d\n", event_mouse.value);
}
}
}
close(fd);
return 0 ;
}
2.5 代码编译和测试
使用交叉编译器编译好之后,通过nfs或其他方法挂载(或拷贝)到开发板上,在USB口插入鼠标。
运行如下代码(代码名字和路径根据实际开发板情况修改)
./read_mouse /dev/input/event2
运行效果: