您当前的位置: 首页 >  linux

韦东山

暂无认证

  • 0浏览

    0关注

    506博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Linux 下Input系统应用编程实战

韦东山 发布时间:2019-05-28 16:43:21 ,浏览量:0

作者:杨源鑫(也是我们的校园代理)

经授权转载于公众号嵌入式开发圈,有些许修改。

什么是input子系统?不管是什么操作系统,都有一个程序用于管理各种输入设备,哪些是输入设备?比如,电脑键盘、鼠标,智能手机上的触摸屏,按键。都是输入设备。那么操作系统怎么管理这些输入设备?这里以最常用的Linux操作系统进行讲解。

在Linux内核中,有非常多用于管理诸多设备的子系统,比如显示系统,输入子系统,音频子系统,电源管理子系统,时钟管理子系统等等,本节我们重点关注输入子系统。

输入子系统是在内核里实现,因为设备经常要通过特定的硬件接口被访问 (例如串口, ps/2, usb等等 ),这些硬件接口由内核保护和管理。内核给用户导出一套固定的与硬件无关的 input API,供用户空间程序使用。

在Linux input子系统中,分三块进行管理,分别是: input core(输入系统核心层), drivers(输入系统驱动层)和 event handlers(输入系统事件层),可能你感觉太抽象,看下图4-5-9就清楚了。

在这里插入图片描述

先从应用程序角度认识input子系统,我们可以从以下这个文件看到对应的设备。

打开Linux终端,输入命令cat /proc/bus/input/devices可以看到类似下面的内容。

I: Bus=0003 Vendor=046d Product=c018 Version=0111
N: Name=" USB Optical Mouse"
P: Phys=usb-0000:00:1d.1-2/input0
S: Sysfs=/class/input/input24
U: Uniq=
H: Handlers=mouse1 event2
B: EV=7
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=103

这些devices主要是用来描述注册在input子系统的设备文件,可能有鼠标,键盘,触摸屏,重力传感器,温度传感器等等,写驱动的时候,通过内核提供的input设备注册设备相关的接口后,这些信息都会保存到对应的文件里。

那么,input子系统如何描述输入设备呢?

Linux系统为我们提供了这个输入系统操作相关的头文件:

#include

在这个文件中,可以找到这个结构体:

//用于描述一个输入事件
struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

在这里我们看到input_event结构体中还嵌套了另一个结构体struct timeval time;

先解读struct timeval time,它在time.h中定义如下

struct timeval
{
__time_t tv_sec;        /* Seconds. */
__suseconds_t tv_usec;    /*Microseconds. */
};

其中,tv_sec为Epoch到创建struct timeval时的秒数,tv_usec为微秒数,即秒后面的零头。

type域是被报告事件的类型,例如,一个 key press或者 button press, relative motion(比如移动鼠标 )或者 absolute motion(比如移动游戏杆 );

code域告诉你是哪一个key或者坐标轴在被操作;

value域告诉你设备现在的状态或者运动情况是什么。

最主要的事件有以下三种: 相对事件(例如鼠标),绝对事件(例如触摸屏),键盘事件。

例如鼠标,我们在移动鼠标的时候鼠标就是一个相对事件,所以type的类型也就是底层上报给用户的事件为相对事件类型,code表示的就是相对于鼠标当前的位置的X或者Y的坐标,value也就是相对于当前的位置偏移了多少。

事件类型(type)在input.h分类如下:

 /*
  * Event types
  */
 #define EV_SYN            0x00     //同步事件,就是将结果上报给系统的过程
 #define EV_KEY            0x01     //按键事件
 #define EV_REL            0x02     //相对事件
 #define EV_ABS            0x03     //绝对事件
 本节,我们来实现一个input控制鼠标的应用程序。所以还会用到以下事件:
 /*
 * Relative axes
 */
//在这里,我们暂时只会用REL_X和REL_Y这两个参数
#define REL_X            0x00    //相对X坐标
#define REL_Y            0x01    //相对Y坐标

我们可以使用cat命令来测试当前的鼠标事件到底属于哪一个事件节点,如图4-5-10所示: 在这里插入图片描述

只需切换到/dev/input,找到对应的事件节点,再使用cat eventx(事件节点),然后移动鼠标就可以看到数据打印啦,但是这些数据我们显然是看不懂的,不过可以使用测试程序将鼠标的值读出来。

接下来,我们写个程序mouse.c来看看如何读取鼠标事件,

 #include 
 #include 
 #include 
 #include 
 #include 
 /*
 struct input_event {
         struct timeval time;
         __u16 type;
        __u16 code;
        __s32 value;
};
*/
/*
Event types
#define EV_SYN                  0x00
#define EV_KEY                  0x01
#define EV_REL                  0x02
#define EV_ABS                  0x03
*/
/*
 Relative axes
#define REL_X                   0x00
#define REL_Y                   0x01
#define REL_Z                   0x02
#define REL_MAX                 0x0f
#define REL_CNT                 (REL_MAX+1)
*/
//event8  mouse
//event9  keyboard
int main(void)
{
    //1、定义一个结构体变量用来描述input事件
    struct input_event event_mouse ;
    //2、打开input设备的事件节点我的电脑对应的鼠标事件的节点是event3
//读者的电脑的设备节点可能和我的不一样,可以使用cat命令去获取,然后
//不断尝试
    int fd = open("/dev/input/event4",O_RDWR);
    int value ;
    int type ;
    int buffer[10]={0};
    if(-1 == fd){
        printf("open mouse event fair!\n");
        return -1 ;
    }   
    while(1){
        //3、读事件
       read(fd ,&event_mouse ,sizeof(event_mouse));
        //4、判断事件类型,并打印键码
        switch(event_mouse.type){
            //同步事件
            case EV_SYN:
                printf("sync!\n");
                 break ;
            case EV_REL:
            //鼠标事件,XY相对位移
            //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);  
            }
            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);  
           }
            defalut:
           break ;
       }
    }   
    return 0 ;
}

运行结果,如图4-5-11所示。 在这里插入图片描述 当我们不断移动鼠标的时候,这些值将会被打印出来。

请思考一个问题,既然我们移动鼠标能够打印数值,那能不能够写一个程序控制鼠标自动移动呢?肯定可以,下面我们写个程序让鼠标自己画一个正方形,上代码:

 #include 
 #include 
 #include 
 #include 
 #include 
 
 //event8  mouse
 //event9  keyboard
 int main(void)
{
    //1、定义一个结构体变量用来描述input事件
    struct input_event event_mouse ;
   //2、打开input设备的事件节点  我的电脑鼠标事件的节点是event3
    int fd = open("/dev/input/event3",O_RDWR);
    int value ;
    int type ;
    int i ;
    int buffer[10]={0};
    if(-1 == fd){
        printf("open mouse event fair!\n");
        return -1 ;
    }   
    while(1){
        //3、写事件
        for(i = 0 ; i  -20 ; i--){
           event_mouse.type = EV_REL ; 
           event_mouse.code = REL_Y ;
           event_mouse.value = i ;  
           write(fd,&event_mouse,sizeof(event_mouse));         
           event_mouse.code = 0 ; 
           event_mouse.value = 0 ;
           event_mouse.type = EV_SYN ;
           write(fd,&event_mouse,sizeof(event_mouse));         
           usleep(50000);
        }

    }   
    return 0 ;
}

执行效果请读者自行验证。

接下来我们再写一个案例:在Tiny4412平台上获取电容屏的坐标值。

触摸屏上报坐标值的事件属于绝对事件,也就是,触摸的坐标点X和Y会在屏幕的分辨率范围内上报一个绝对的坐标(X,Y)。

那么上报对于的类型(type)如下:EV_ABS

对于的code如下:

绝对于X:

ABS_MT_POSITION_X

绝对于Y:

ABS_MT_POSITION_Y

我用了一个程序获取了屏幕的分辨率,得知分辨率宽为480,高为800。

首先,写这个程序时,我通过adb进到Android根目录,然后用getevent -p查到触摸屏的事件节点为event0, 同时也知道触摸屏是一个绝对事件,如下: 在这里插入图片描述

接下来,我在Android5.0的源代码external目录下创建了如下目录:Getft5x0x_Test

该目录下有如下两个文件文件:

Android.mk和Get_ft5x0x_tp.c

(1) 先看Android.mk

 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 LOCAL_MODULE_TAGS := eng
 LOCAL_SHARED_LIBRARIES += libcutils libutils
 #LOCAL_STATIC_LIBRARIES += libz libstdc++ libpng libvtpng
 LOCAL_STATIC_LIBRARIES += libz libstdc++ libpng
 
 LOCAL_SRC_FILES := Get_ft5x0x_tp.c
 LOCAL_MODULE := ft5x0x_tp
 include $(BUILD_EXECUTABLE)

(2)Get_ft5x0x_tp.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//ft5x0x_ts触摸屏事件初始化
18int touch_fd = -1 ;
19int ft5x0x_ts__init(void)
{
    touch_fd = open("/dev/input/event0", O_RDONLY);
    if (touch_fd             
关注
打赏
1658827356
查看更多评论
0.0807s