Linux Input 子系统Event Interface详解---得到Input Device信息

在之前的工作中,常遇到对Input 子系统中Event Device操作和设置的需求。但一直没有总结过。这次借机总结一下。







Linux Input子系统中,每个输入设备可以建立一个Device。例如:当插入USB Mouse,USB Keyboard,或者采用UInput建立Input Device时。在系统/dev/input/ 目录下就会生成对应的Device。 如:/dev/input/event0, /dev/input/mouse0, /dev/input/misc等。







可以通过读取这些Device获取输入设备输入的信息。同时,也可以通过一系列ioctl()得到和设置(主要是得到)这些Device 的信息。 这里,我们主要分析此Event Interface 的ioctl().







0. 基础信息:

0.1:关键结构体input_event信息:


struct input_event {

struct timeval time;

__u16 type;

__u16 code;

__s32 value;

};




type: 设备类型。可以设置为:



#define EV_SYN          0x00    表示设备支持所有的事件

#define EV_KEY          0x01    键盘或者按键,表示一个键码  

#define EV_REL          0x02    鼠标设备,表示一个相对的光标位置结果

#define EV_ABS          0x03    手写板产生的值,其是一个绝对整数值 

#define EV_MSC          0x04    其他类型 

#define EV_LED          0x11    LED灯设备

#define EV_SND          0x12    蜂鸣器,输入声音 

#define EV_REP          0x14    允许重复按键类型 

#define EV_PWR          0x16    电源管理事件 

#define EV_FF_STATUS 0x17

#define EV_MAX 0x1f

#define EV_CNT (EV_MAX+1)




code: 根据Type的不同而含义不同。

例如:

Type为EV_KEY时,code表示键盘code或者鼠标Button值。

取值范围:

#define EV_SYN 0x00

到:


#define KEY_MIN_INTERESTING KEY_MUTE

#define KEY_MAX 0x2ff

#define KEY_CNT (KEY_MAX+1)







Type为EV_REL时,code表示操作的是哪个坐标轴,如:REL_X,REL_Y。(因为鼠标有x,y两个轴向,所以一次鼠标移动,会产生两个input_event)

取值范围:

#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)

Type为EV_ABS时,code表示绝对坐标轴向。







value:根据Type的不同而含义不同。

例如:


Type为EV_KEY时,value: 0表示按键抬起。1表示按键按下。(4表示持续按下等?)。

Type为EV_REL时,value: 表明移动的值和方向(正负值)。

Type为EV_ABS时,code表示绝对位置。







0.2: Device ID 结构体信息:


struct input_id {

__u16 bustype;

__u16 vendor;

__u16 product;

__u16 version;

};




bustype: 一些枚举类型。如 USB, PCI等。

 取值范围:


#define BUS_PCI 0x01

#define BUS_ISAPNP 0x02

#define BUS_USB 0x03

#define BUS_HIL 0x04

#define BUS_BLUETOOTH 0x05

#define BUS_VIRTUAL 0x06




#define BUS_ISA 0x10

#define BUS_I8042 0x11

#define BUS_XTKBD 0x12

#define BUS_RS232 0x13

#define BUS_GAMEPORT 0x14

#define BUS_PARPORT 0x15

#define BUS_AMIGA 0x16

#define BUS_ADB 0x17

#define BUS_I2C 0x18

#define BUS_HOST 0x19

#define BUS_GSC 0x1A

#define BUS_ATARI 0x1B

#define BUS_SPI 0x1C




vendor,product,version: 厂商号,产品号,版本号。










1. 各类ioctl:

1.1:得到Driver Version:

#define EVIOCGVERSION _IOR('E', 0x01, int)

int 暗示了ioctl()参数三能够得到int值。




例:


vesion = 0;

ioctl(fd, EVIOCGVERSION, &vesion);

printf("\nDriver Version:[0x%x]\n", vesion);







1.2:得到Device ID:

#define EVIOCGID _IOR('E', 0x02, struct input_id)

从struct input_id暗示,ioctl参数三可以得到此结构体内容。


// 2. Device ID.

memset(&Device_ID, 0, sizeof(struct input_id));

ioctl(fd, EVIOCGID, &Device_ID);

printf("\nbustype:[%d]. vendor:[%d]. product:[%d]. version:[%d]\n", Device_ID.bustype, Device_ID.vendor, Device_ID.product, Device_ID.version);







1.3: 得到和设置Repeat速度:


#define EVIOCGREP _IOR('E', 0x03, unsigned int[2])

#define EVIOCSREP _IOW('E', 0x03, unsigned int[2])

从unsigned int[2] 暗示,ioctl的第三个参数是个数组。





int rep[2];

ioctl(fd, EVIOCGREP, rep);

printf("[0]= %d, [1] = %d\n", rep[0], rep[1]);




注意,其中一些Device不支持Get Set Repeat。此时,Ioctl会报错。

另:参数说明: rep[0]表示在按键重复出现之前 delay的时间; rep[1]表示按键重复出现的时间间隔。







1.4:得到ScanKey和KeyMap。

这个功能Sam没有测试过。所以不具体讨论。


#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2])

#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2])







1.5:得到DeviceName:

#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len)

此处暗示ioctl参数二:EVIOCGNAME(len)




char name[256]= "Unknown";


ioctl(fd, EVIOCGNAME(sizeof(name)), name);

printf("\nDevice Name:[%s]. \n", name);







1.6:得到设备物理位置:

#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) //get physical location

此处暗示参数二为:EVIOCGPHYS(len)

尽管设备身份信息和名字信息通常很有用,但是它也许并没有提供足够的信息告诉你当前在使用哪个设备。例如,你当前有两个完全相同的遥控杆,你需要确定每个使用哪个端口。这通常属于拓扑信息( topology information),可以使用 EVIOCGPHYS ioctl获取:




char physic[256]= "Unknown";


if(ioctl(fd, EVIOCGPHYS(sizeof(physic)), physic) < 0) 

{

perror("EVIOCGPHYS ioctl");

}

else

printf("Phys location is %s\n", physic);

结果通常为:

Phys location is: usb-hiusb-ehci-2.1/input1

Phys location is: usb-hiusb-ehci-2.1/input2

涵义: Usb部分意味着这使用 usb系统的一个物理拓扑。 2.1表示了从 root hub到 device的路径,这里表示上行 hub接在 root hub的第 2个端口上,设备接在上行 hub的第 1个端口上。 Input0表示这是设备的第 1个event device 节点。







1.7: 得到唯一的ID:

#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) //get unique identifier 

此处暗示ioctl()参数二:EVIOCGUNIQ(len)




char uniq[256]= "Unknown";


if(ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq) < 0) 

{

perror("EVIOCGUNIQ ioctl");

}

else

printf("UID is %s\n", uniq);

绝大多数设备没有这样的唯一号,所以你使用该 ioctl将返回一个空字符串







1.8:得到全局key/button状态,看其是否被按下或释放:

#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len)

此处暗示 ioctl()参数二是:EVIOCGKEY(len)

通过这个ioctl, 参数三中得到信息。它在 bit array里设置了每个 key/button是否被释放。







1.9: 得到LED状态:

#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) 




LED排列如下:

#define LED_NUML 0x00

#define LED_CAPSL 0x01

#define LED_SCROLLL 0x02

#define LED_COMPOSE 0x03

#define LED_KANA 0x04

#define LED_SLEEP 0x05

#define LED_SUSPEND 0x06

#define LED_MUTE 0x07

#define LED_MISC 0x08

#define LED_MAIL 0x09

#define LED_CHARGING 0x0a

#define LED_MAX 0x0f

#define LED_CNT (LED_MAX+1)










1.10:得到Device能力集:


使用 EVIOCGBIT ioctl可以获取设备的能力和特性。它告知你设备是否有 key或者 button。

EVIOCGBIT ioctl处理 4个参数 ( ioctl(fd, EVIOCGBIT(ev_type, max_bytes), bitfield))。 ev_type是返回的 type feature( 0是个特殊 case,表示返回设备支持的所有的type features)。 max_bytes表示返回的最大字节数。 bitfield域是指向保存结果的内存指针。 return value表示保存结果的实际字节数,如果调用失败,则返回负值。




//找到addr中的对应bit.看其是否为1。

 

static int test_bit(int nr, const volatile unsigned long *addr)

{

return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));

}







 

memset(pEvtype, 0, sizeof(pEvtype));

if (ioctl(fd, EVIOCGBIT(0, EV_MAX), pEvtype) < 0) 

{

//printf();

}

for (yalv = 0; yalv < EV_MAX; yalv++) 

{

if (test_bit(yalv, pEvtype)) 

{

 

printf(" Event type 0xx ", yalv);

switch ( yalv)

{

case EV_SYN :

printf(" (Synch Events)\n");

break;

case EV_KEY :

printf(" (Keys or Buttons)\n");

break;

case EV_REL :

printf(" (Relative Axes)\n");

break;

case EV_ABS :

printf(" (Absolute Axes)\n");

break;

case EV_MSC :

printf(" (Miscellaneous)\n");

break;

case EV_LED :

printf(" (LEDs)\n");

break;

case EV_SND :

printf(" (Sounds)\n");

break;

case EV_REP :

printf(" (Repeat)\n");

break;

case EV_FF :

case EV_FF_STATUS:

printf(" (Force Feedback)\n");

break;

case EV_PWR:

printf(" (Power Management)\n");

break;

default:

printf(" (Unknown: 0xhx)\n",yalv);

}

}

}

 







通过这个办法,就可以的到能力集。例如:


Event type 0x00  (Synch Events)

 Event type 0x01  (Keys or Buttons)

 Event type 0x02  (Relative Axes)

 

转载于:https://www.cnblogs.com/MMLoveMeMM/articles/3796868.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值