热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

LinuxInput子系统EventInterface详解一得到InputDevice信息

在之前的工作中,常遇到对Input子系统中EventDevice操作和设置的需求。但一直没有总结过。这次借机总结一下。LinuxInput子系统中,每个
在之前的工作中,常遇到对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);
结果通常为&#xff1a;
Phys location is&#xff1a; usb-hiusb-ehci-2.1/input1
Phys location is&#xff1a; usb-hiusb-ehci-2.1/input2
涵义&#xff1a; Usb部分意味着这使用 usb系统的一个物理拓扑。 2.1表示了从 root hub device的路径&#xff0c;这里表示上行 hub接在 root hub的第 2个端口上&#xff0c;设备接在上行 hub的第 1个端口上。 Input0表示这是设备的第 1event device 节点。


1.7: 得到唯一的ID&#xff1a;
#define EVIOCGUNIQ(len) _IOC(_IOC_READ, &#39;E&#39;, 0x08, len) //get unique identifier 
此处暗示ioctl()参数二&#xff1a;EVIOCGUNIQ(len)

char uniq[256]&#61; "Unknown";
if(ioctl(fd, EVIOCGUNIQ(sizeof(uniq)), uniq) <0) 
{
perror("EVIOCGUNIQ ioctl");
}
else
printf("UID is %s\n", uniq);
绝大多数设备没有这样的唯一号&#xff0c;所以你使用该 ioctl将返回一个空字符串


1.8&#xff1a;得到全局key/button状态&#xff0c;看其是否被按下或释放&#xff1a;
#define EVIOCGKEY(len) _IOC(_IOC_READ, &#39;E&#39;, 0x18, len)
此处暗示 ioctl()参数二是&#xff1a;EVIOCGKEY(len)
通过这个ioctl, 参数三中得到信息。它在 bit array里设置了每个 key/button是否被释放。


1.9: 得到LED状态&#xff1a;
#define EVIOCGLED(len) _IOC(_IOC_READ, &#39;E&#39;, 0x19, len)

LED排列如下&#xff1a;
#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&#43;1)



1.10&#xff1a;得到Device能力集&#xff1a;

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

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


//找到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 &#61; 0; 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);

}

}

}

 



通过这个办法&#xff0c;就可以的到能力集。例如&#xff1a;
Event type 0x00  (Synch Events)
 Event type 0x01  (Keys or Buttons)
 Event type 0x02  (Relative Axes)



推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • IB 物理真题解析:比潜热、理想气体的应用
    本文是对2017年IB物理试卷paper 2中一道涉及比潜热、理想气体和功率的大题进行解析。题目涉及液氧蒸发成氧气的过程,讲解了液氧和氧气分子的结构以及蒸发后分子之间的作用力变化。同时,文章也给出了解题技巧,建议根据得分点的数量来合理分配答题时间。最后,文章提供了答案解析,标注了每个得分点的位置。 ... [详细]
  • 本文介绍了游标的使用方法,并以一个水果供应商数据库为例进行了说明。首先创建了一个名为fruits的表,包含了水果的id、供应商id、名称和价格等字段。然后使用游标查询了水果的名称和价格,并将结果输出。最后对游标进行了关闭操作。通过本文可以了解到游标在数据库操作中的应用。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
author-avatar
coco2冰冰
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有