Ubuntu下的一次捕捉键盘输入的实验

linux 专栏收录该内容
3 篇文章 0 订阅

之前一直奇怪应用程序是如何得到键盘输入的,首先这肯定与键盘的驱动程序有关,但驱动程序是如何把键盘输入传递给用户进程的?这个问题在用了windows下一个按键精灵后达到了顶峰,该案件精灵使用一个脚本表达模拟发送的键盘按键和鼠标移动,之后可以自动进行操作,这说明上层应用有操作鼠标键盘的能力.查找资料后,发现原来对于linux,鼠标和键盘驱动是这样写的:
鼠标\键盘的输入会转为/dev/input下的io事件event*,设备对应的event号可通过cat /proc/bus/input/devices查看.比如我查看该文件的内容:

I: Bus=0019 Vendor=0000 Product=0003 Version=0000
N: Name="Sleep Button"
P: Phys=PNP0C0E/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0E:00/input/input0
U: Uniq=
H: Handlers=kbd event0 
B: PROP=0
B: EV=3
B: KEY=4000 0 0

I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=PNP0C0C/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0C0C:00/input/input1
U: Uniq=
H: Handlers=kbd event1 
B: PROP=0
B: EV=3
B: KEY=10000000000000 0

I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button"
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXPWRBN:00/input/input2
U: Uniq=
H: Handlers=kbd event2 
B: PROP=0
B: EV=3
B: KEY=10000000000000 0

I: Bus=0019 Vendor=0000 Product=0006 Version=0000
N: Name="Video Bus"
P: Phys=LNXVIDEO/video/input0
S: Sysfs=/devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/LNXVIDEO:00/input/input3
U: Uniq=
H: Handlers=kbd event3 
B: PROP=0
B: EV=3
B: KEY=3e000b00000000 0 0 0

I: Bus=0003 Vendor=413c Product=2113 Version=0111
N: Name="Dell KB216 Wired Keyboard"
P: Phys=usb-0000:00:14.0-1/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.0/0003:413C:2113.0001/input/input4
U: Uniq=
H: Handlers=sysrq kbd event4 leds 
B: PROP=0
B: EV=120013
B: KEY=1000000000007 ff9f207ac14057ff febeffdfffefffff fffffffffffffffe
B: MSC=10
B: LED=1f

I: Bus=0003 Vendor=413c Product=2113 Version=0111
N: Name="Dell KB216 Wired Keyboard"
P: Phys=usb-0000:00:14.0-1/input1
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-1/1-1:1.1/0003:413C:2113.0002/input/input5
U: Uniq=
H: Handlers=kbd event5 
B: PROP=0
B: EV=1f
B: KEY=300ff 0 0 483ffff17aff32d bf54444600000000 1 130c730b17c000 267bfad941dfed 9e168000004400 10000002
B: REL=40
B: ABS=100000000
B: MSC=10

I: Bus=0003 Vendor=03f0 Product=134a Version=0111
N: Name="PixArt HP USB Optical Mouse"
P: Phys=usb-0000:00:14.0-2/input0
S: Sysfs=/devices/pci0000:00/0000:00:14.0/usb1/1-2/1-2:1.0/0003:03F0:134A.0003/input/input6
U: Uniq=
H: Handlers=mouse0 event6 
B: PROP=0
B: EV=17
B: KEY=ff0000 0 0 0 0
B: REL=103
B: MSC=10

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH Front Mic"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input7
U: Uniq=
H: Handlers=event7 
B: PROP=0
B: EV=21
B: SW=10

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH Rear Mic"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input8
U: Uniq=
H: Handlers=event8 
B: PROP=0
B: EV=21
B: SW=10

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH Line"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input9
U: Uniq=
H: Handlers=event9 
B: PROP=0
B: EV=21
B: SW=2000

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH Line Out Front"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input10
U: Uniq=
H: Handlers=event10 
B: PROP=0
B: EV=21
B: SW=40

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH Line Out Surround"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input11
U: Uniq=
H: Handlers=event11 
B: PROP=0
B: EV=21
B: SW=40

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH Line Out CLFE"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input12
U: Uniq=
H: Handlers=event12 
B: PROP=0
B: EV=21
B: SW=40

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH Front Headphone"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input13
U: Uniq=
H: Handlers=event13 
B: PROP=0
B: EV=21
B: SW=4

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH HDMI/DP,pcm=3"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input14
U: Uniq=
H: Handlers=event14 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH HDMI/DP,pcm=7"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input15
U: Uniq=
H: Handlers=event15 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH HDMI/DP,pcm=8"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input16
U: Uniq=
H: Handlers=event16 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH HDMI/DP,pcm=9"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input17
U: Uniq=
H: Handlers=event17 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA Intel PCH HDMI/DP,pcm=10"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:1f.3/sound/card0/input18
U: Uniq=
H: Handlers=event18 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0019 Vendor=0000 Product=0000 Version=0000
N: Name="Eee PC WMI hotkeys"
P: Phys=eeepc-wmi/input0
S: Sysfs=/devices/platform/eeepc-wmi/input/input19
U: Uniq=
H: Handlers=rfkill kbd event19 
B: PROP=0
B: EV=100013
B: KEY=7e40000 0 800000000000 0 0 1400b00100000 300180001100800 e000000000000 2
B: MSC=10

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA NVidia HDMI/DP,pcm=3"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:01.0/0000:01:00.1/sound/card1/input20
U: Uniq=
H: Handlers=event20 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA NVidia HDMI/DP,pcm=7"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:01.0/0000:01:00.1/sound/card1/input21
U: Uniq=
H: Handlers=event21 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA NVidia HDMI/DP,pcm=8"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:01.0/0000:01:00.1/sound/card1/input22
U: Uniq=
H: Handlers=event22 
B: PROP=0
B: EV=21
B: SW=140

I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="HDA NVidia HDMI/DP,pcm=9"
P: Phys=ALSA
S: Sysfs=/devices/pci0000:00/0000:00:01.0/0000:01:00.1/sound/card1/input23
U: Uniq=
H: Handlers=event23 
B: PROP=0
B: EV=21
B: SW=140

鼠标对应event6比较明显,键盘可能是event4或event5,应用程序试了两次发现event5无效,event4有效,至于为什么有2个event对应键盘就不知道了.
应用程序如下:

//读取键盘输入
#include <stdio.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    int fd_kb;

    struct input_event event_kb;

    fd_kb = open("/dev/input/event4", O_RDONLY); //键盘输入
    if (fd_kb <= 0)
    {
        printf("open device error\n");
        return 0;
    }

    while (1)
    {
        if (read(fd_kb, &event_kb, sizeof(event_kb)) == sizeof(event_kb))
        {
            if (event_kb.type == EV_KEY)
            {
                //if (event_kb.value == 0 || event_kb.value == 1)//1表示按下,0表示释放,会检测到两次
                if (event_kb.value == 1) //键按下
                {
                    //printf("key %d %s\n", event_kb.code, (event_kb.value) ? "Pressed" : "Released");
                    if (event_kb.code == KEY_ESC)
                        break;
                    if (event_kb.code == KEY_Q)
                        printf("q\n");
                    if (event_kb.code == KEY_W)
                        printf("w\n");
                    if (event_kb.code == KEY_E)
                        printf("e\n");
                    if (event_kb.code == KEY_R)
                        printf("r\n");
                }
            }
        }
    }
    close(fd_kb);
    return 0;
}

以上程序不管是不是在前台输入,程序都能捕捉到Q\W\E\R按键,并且多个进程居然可以同时捕捉到事件;推测只让前台进程获取到事件是内核的职责,前台进程是与终端绑定的概念,内核的终端调度程序(不是调度器!)负责把信号传给前台进程,并清掉信号,这就和我们平时看到的现象一致了.按键精灵是通过模拟键盘\鼠标事件实现的,demo程序如下:

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

void simulate_key(int fd, int kval)
{
    struct input_event event;
    event.type = EV_KEY;
    event.value = 1;
    event.code = kval;

    gettimeofday(&event.time, 0);
    write(fd, &event, sizeof(event));

    event.type = EV_SYN;
    event.code = SYN_REPORT;
    event.value = 0;
    write(fd, &event, sizeof(event));

    memset(&event, 0, sizeof(event));
    gettimeofday(&event.time, NULL);
    event.type = EV_KEY;
    event.code = kval;
    event.value = 0;
    write(fd, &event, sizeof(event));
    event.type = EV_SYN;
    event.code = SYN_REPORT;
    event.value = 0;
    write(fd, &event, sizeof(event));
}
void simulate_mouse(int fd)
{
    struct input_event event;
    memset(&event, 0, sizeof(event));
    gettimeofday(&event.time, NULL);
    event.type = EV_REL;
    event.code = REL_X;
    event.value = 10;
    write(fd, &event, sizeof(event));

    event.type = EV_REL;
    event.code = REL_Y;
    event.value = 10;
    write(fd, &event, sizeof(event));

    event.type = EV_SYN;
    event.code = SYN_REPORT;
    event.value = 0;
    write(fd, &event, sizeof(event));
}
int main()
{
    int fd_kbd;
    int fd_mouse;
    fd_kbd = open("/dev/input/event4", O_RDWR);
    if (fd_kbd <= 0)
    {
        printf("error open keyboard:\n");
        return -1;
    }
    fd_mouse = open("/dev/input/event6", O_RDWR);
    if (fd_mouse <= 0)
    {
        printf("error open mouse\n");
        return -2;
    }
    int i = 0;
    for (i = 0; i < 10; i++)
    {
        simulate_key(fd_kbd, KEY_A + i);
        simulate_mouse(fd_mouse);
        sleep(1);
    }
    close(fd_kbd);
}

以上程序居然可以让键盘\鼠标自己输出,自己移动,可以明显看到现象!

参考了:

linux 处理键盘 鼠标事件
Linux如何查看与/dev/input目录下的event对应的设备
linux c语言 模拟键盘输入

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 1024 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值