加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

Linux input子系统(一)初识

05/03 08:50
4049
阅读需 14 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

哈喽,大家好,我是LittleG。

如果将 Linux 比作一个人,那么Linux input子系统就好比我们的眼睛,手,脚,以及到大脑的神经网络,可以通过它们获取和传递信息,感知外围世界。回到 Linux/Android 世界,像手机设备中,按键、触摸屏、各种sensor,数据流一般也是走的input子系统上报给上层的,所以学习和理解input子系统很重要。

正文

#include <linux/input.h>

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

描述一个输入事件
/*
 * The event structure itself
 */
struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

先来解读下这个结构体的含义:

struct timeval结构体在time.h中的定义为:

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

【time】域的 tv_sec 为Epoch到创建struct timeval时的秒数,tv_usec为微秒数,即秒后面的零头。

【type】域显示了被报告事件的类型,例如,一个 key press或者 button press, relative motion(比如移动鼠标 ) 或者 absolute motion(比如移动游戏杆 ); 常用的事件类型 type有 EV_KEY , EV_REL , EV_ABS , EV_SYN ;分别对应keyboard事件,相对事件,绝对事件,同步事件;EV_SYN 则表示一组完整事件已经完成,需要处理;

【code】域根据type的不同而含义不同,上报是哪一个key或者哪一个坐标轴在被操作; 例如,type为 EV_KEY 时,code表示键盘code或者鼠标Button值;type为 EV_REL 时,code表示操作的是哪个坐标轴,如:REL_X,REL_Y (因为鼠标有x,y两个轴向,所以一次鼠标移动,会产生两个input_event);type为 EV_ABS 时,code表示绝对坐标轴向。

【value】域也是根据type的不同而含义不同,上报现在的状态或者运动情况是什么。例如:type为EV_KEY时,value:0表示按键抬起,1表示按键按下;(4表示持续按下等?)type为EV_REL时,value: 表明移动的值和方向(正负值);type为EV_ABS时,value: 表示绝对位置;

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

例如:

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

事件类型(type)在 input.h 主要有以下:

/*
 * Event types
 */
 
#define EV_SYN          0x00     //同步事件,就是将结果上报给系统的过程
#define EV_KEY          0x01     //按键事件,如 KEY_VOLUMEDOWN 事件
#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)

以鼠标为例,涉及鼠标的事件读取/控制相关的code有:

/*
 * Relative axes
 */
//在这里,我们暂时只会用来REL_X和REL_Y这两个参数
#define REL_X           0x00    //相对X坐标
#define REL_Y           0x01    //相对Y坐标
#define REL_Z           0x02    //相对Z坐标
#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
#define REL_MAX         0x0f
#define REL_CNT         (REL_MAX+1)

最后value,就是选择具体的type、具体的code以后所反应出来的值,鼠标就是相对于当前X或者相对于当前Y的值。

接下来,我们来看一下如何来读取鼠标事件,写一段代码测试一下:

#include <stdio.h>
#include <linux/input.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
/*
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_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
#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
    int fd = open("/dev/input/event3",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:%dn",event_mouse.code);    
                 printf("event_mouse.value_X:%dn",event_mouse.value);  
            }
            if(event_mouse.code == REL_Y){
                 printf("event_mouse.code_Y:%dn",event_mouse.code);    
                 printf("event_mouse.value_Y:%dn",event_mouse.value);  
            }
            defalut:
            break ;
        }
    }   
    return 0 ;
}

附:在Linux系统下通过如下命令可以看到所有的input设备

cat /proc/bus/input/devices

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="qpnp_pon"
P: Phys=qpnp_pon/input0
S: Sysfs=/devices/platform/soc/c440000.qcom,spmi/spmi-0/spmi0-00/c440000.qcom,spmi:qcom,pm8150@0:qcom,power-on@800/input/input0
U: Uniq=
H: Handlers=event0 cpufreq
B: PROP=0
B: EV=3

B: KEY=600000000000000 0 14000000000000 0

............

I: Bus=0018 Vendor=0000 Product=0000 Version=0000
N: Name="light"
P: Phys=
S: Sysfs=/devices/virtual/input/input3
U: Uniq=
H: Handlers=event3
B: PROP=0
B: EV=5

B: REL=3

......

I: Bus=0019 Vendor=0001 Product=0001 Version=0100
N: Name="gpio-keys"
P: Phys=gpio-keys/input0
S: Sysfs=/devices/platform/soc/soc:gpio_keys/input/input6
U: Uniq=
H: Handlers=event6 cpufreq
B: PROP=0
B: EV=3
B: KEY=8000000000000 0

下期见~

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
NC7SZ04P5X 1 Rochester Electronics LLC LVC/LCX/Z SERIES, 1-INPUT INVERT GATE, PDSO5, 1.25 MM, EIAJ, SC-88A, SC-70, 5 PIN
$0.32 查看
9DBV0441AKLFT 1 Integrated Device Technology Inc VFQFPN-32, Reel

ECAD模型

下载ECAD模型
$4.96 查看
FOD4208SD 1 Fairchild Semiconductor Corporation Triac Output Optocoupler, 1-Element, 5000V Isolation, LEAD FREE, SURFACE MOUNT PACKAGE-6
$4.14 查看

相关推荐

电子产业图谱

记录和分享C/C++、Linux、ARM、Android、IoT相关知识。技术相伴于生活和成长,愿你我永为少年,心中有火,眼中有光,始保热情。