18.linux输入设备应用

        输入设备包括:键盘、鼠标、按键、触摸屏等。

        在linux系统中为了处理输入设备上报的信息,统一管理这些设备,实现了一套可以兼容各种设备的驱动框架就是INPUT子系统。

        通过INPUT子系统管理的设备,通常都会在/dev/input目录下创建对应的设备节点,以供上层应用进行读取。

一、读取的数据类型

        对于INPUT子系统管理的设备,每次读取的数据都是一个struct input_event 结构体类型数据,其定义在<linux/input.h>头文件中:

struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

time:内核记录的上报该数据的时间
type:用于描述发生的是哪一种事件类型(比如按键事件)
code:描述的是该类事件中的一个具体事件(比如按键事件中按的是KEY_0按键)
value: 内核每次上报事件都会向应用层发送一个数据 value, 对 value 值的解释随着 code 的变化而
变化。

具体的关于INPUT子系统数据的定义可以在头文件input-event-codes.h中进行查找。

二、通过代码读取struct input_event 数据

       读取按键上报的数据

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

int main(int argc, char *argv[]) 
{
    struct input_event event;

    int fd;

    if(argc != 2) { //命令行输入参数个数不等于2,返回错误
        fprintf(stderr, "usage: %s <input-errpr>\n", argv[0]);
        exit(-1);
    }

    fd = open(argv[1], O_RDONLY);
    if(fd < 0) {
        perror("open failed \n");
        exit(-1);
    }
    for ( ; ; ) {
    /* 循环读取数据 */
    if (sizeof(struct input_event) !=
        read(fd, &event, sizeof(struct input_event))) {
        perror("read error");
        exit(-1);
        }
    printf("type:%d code:%d value:%d\n",
    event.type, event.code, event.value);
    }

    exit(0);
}

        程序流程很简单,循环读取按键对应的设备节点上传的数据信息,并进行打印,测试效果如下:

  第一行中 type 等于 1,表示上报的是按键事件 EV_KEY, code=114, 打开 input-event-codes.h 头文件进行查找,可以发现 cpde=114 对应的是键盘上的 KEY_VOLUMEDOWN 按键,而 value=1 表示按键按下
    第二行, 表示上报了 EV_SYN 同步类事件(type=0)中的 SYN_REPORT 事件(code=0), 表示本轮数据已经完整、报告同步。
    第三行, type 等于 1,表示按键类事件, code 等于 114、value 等于 0,所以表示按键 KEY_VOLUMEDOWN被松开。
    第四行,又上报了同步事件

        读取触摸屏上报的数据 

     第一行中type = 3表示是绝对位移事件EV_ABS,code = 57表示是一个ABS_MT_TRACKING_ID,value = 51表示这是第51个创建的点

    第二行中type = 3表示是绝对位移事件EV_ABS,code = 53 表示ABS_MT_POSITION_X,value = 309表示是x的坐标。

          同理第三行是y的坐标。

         第四行type = 1表示EV_KEY按键类事件,code = 330表示是一个BIN_TOUCH触摸事件,value = 1表示按下。 

        第五行和第六行分别上报了绝对位移事件 EV_ABS(type=3)中的 ABS_X(code=0)和 ABS_Y(code=1),其 value 分别对应的是触摸点的 X 坐标和 Y 坐标。 多点触摸设备也会通过 ABS_X、 ABS_Y 事件上报触摸点的 X、 Y 坐标。

        最后一行上报了同步类事件 EV_SYN(type=0)中的 SYN_REPORT(code=0)事件,表示此次触摸点的信息全部上报完毕。

 三、触摸屏单点触摸程序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>

struct key_struct {
    int touch_x;    //保存触摸点x
    int touch_y;    //保存触摸点y
    int down;   //触摸状态 1:按下 0:松开 -1:移动
    int valid;  //判断数据是否有效 1:有效 0:无效
};

int main(int argc, char *argv[])
{
    struct input_event event;
    struct key_struct touch;
    int fd;
    

    /*检验命令行参数是否正确*/
    if(argc != 2) {
        fprintf(stderr, "error used!\n");
        exit(-1);
    }

    /*打开文件*/
    fd = open(argv[1], O_RDONLY);
    if(fd < 0) {
        perror("open failed!\n");
        exit(-1);
    }

    /*初始化触摸状态*/
    touch.touch_x = 0;
    touch.touch_y = 0;  
    touch.down = -1;
    touch.valid = 0;

    while(1) {
        /*循环读取数据*/
        if (read(fd, &event, sizeof(struct input_event)) !=
            sizeof(struct input_event)) {
            perror("read error");
            exit(EXIT_FAILURE);
            }
        
        switch(event.type) {
            case EV_KEY :   //按键事件
                if(event.code = BTN_TOUCH) {
                    touch.down = event.value;   //保存按键事件的数值
                    touch.valid = 1;
                }
                break;

            case EV_ABS : //绝对位移事件
                switch(event.code) {
                    case ABS_X : //绝对位移X坐标
                        touch.touch_x = event.value;    //保存X坐标
                        touch.valid = 1;
                        break;
                    case ABS_Y : //绝对位移Y坐标
                        touch.touch_y = event.value;    //保存Y坐标
                        touch.valid = 1;
                        break;
                }
                break;
            
            case EV_SYN : //同步事件
                if(event.value == SYN_REPORT) {
                    if(touch.valid) {   //判断按键是否有效
                        switch(touch.down) {
                            case 1 : //按下按键
                                printf("按下%d, %d\n",touch.touch_x,touch.touch_y);
                                break;
                            case 0: 
                                printf("松开触摸\n");
                                break;
                            case -1: 
                                printf("移动%d, %d\n",touch.touch_x,touch.touch_y);
                                break;
                        }
                        touch.valid = 0;
                        touch.down = -1;
                    }
                }
                break;
        }
    }
    exit(0);
}

        代码流程:

① 创建一个结构体其中touch_x表示x点的坐标,touch_y表示y点的坐标,down表示按键的状态,valid表示本次按键是否是有效的。

②变量 down 表示手指状态时候按下、松开还是滑动, down=1 表示手指按下、 down=0 表示手指松开、down=-1 表示手指滑动;

③变量 valid 表示数据是否有效, valid=1 表示有效、 valid=0 表示无效;有效指的是我们检测的信息发生了更改,譬如程序中只检测了手指的按下、松开动作以及坐标值的变化。

④调用open函数打开触摸屏对线的设备节点,并在死循环中反复读取input子系统上报的数据。

测试效果如下:

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值