手把手教你写Linux设备驱动---input子系统(一)--input事件应用程序的读写实现(基于友善之臂4412开发板)

     这节,我们来说下input子系统,什么是input子系统?

input子系统就是输入子系统。

     输入子系统是 Linux内核用于管理各种输入设备 (键盘,鼠标,遥控杆,书写板等等 )的部分,用户通过输入子系统进行内核,命令行,图形接口之间的交换。输入子系统在内核里实现,因为设备经常要通过特定的硬件接口被访问 (例如串口, ps/2, usb等等 ),这些硬件接口由内核保护和管理。内核给用户导出一套固定的硬件无关的 input API,供用户空间程序使用。

输入子系统分为三块: input core, drivers和 event handlers。正常的路径是从底层硬件到驱动,从驱动到 input core,

从 input core到 event handler,从 event handler到 user space。在应用程序的角度,我们只要关心user space就行了

其余的部分我们不用关心。

我们先从应用程序的角度来认识下input子系统,我们可以从这个文件可以看到对应的设备
/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

在Linux系统下cat //proc/bus/input/devices即可看到以上相关的信息,这些devices主要是用来描述注册在input子系统的一些

设备文件,可能有鼠标,键盘,触摸屏,重力传感器,温度传感器等等的设备。

那我们如何来描述这样的一个设备呢?Linux系统为我们提供了以下这个头文件:

#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. */
};

其中,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     //绝对事件
#define EV_MSC			0x04
#define EV_SW			0x05
#define EV_LED			0x11
#define EV_SND			0x12
#define EV_REP			0x14
#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
#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:%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 ;
}
编译完后,执行,当移动鼠标的时候我们就可以看到以下信息:

说明,此时已经读到鼠标事件所反应出来的值了。

那么,既然可以做读的操作,那肯定也就可以写了,可不可以写一个程序,让鼠标画个正方形,或者让它自动按着自己

的路径去移动?答案是肯定可以的,要不然游戏外挂都是怎么做出来的?大家说是吧,下面我们就让鼠标来自己画一个

正方形,上代码:

#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 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_X ;
		   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);
		}
		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);
		}
		for(i = 0 ; i > -20 ; i--){
		   event_mouse.type = EV_REL ; 
		   event_mouse.code = REL_X ;
		   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);
		}
		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 ;
}
执行结果:

此时鼠标是在移动的,由于以下的图片是禁止的,效果留给大家自己去尝试。


下节,我们将来实现一下input驱动。







  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Engineer-Bruce_Yang

谢谢您

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值