欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

linux input子系统学习笔记

程序员文章站 2024-02-23 22:30:40
...

1.什么是子系统?

内核是操作系统的核心。linux内核把不同功能分成不同的子系统。如进程管理、内存管理、文件系统、网络等等。

2.input子系统原理

硬件驱动层:
其中硬件驱动层负责操作具体的硬件设备,这层的代码是针对具体的驱动程序的,需要驱动程序的作者来编写。
子系统核心层:
子系统核心层是链接其他两个层之间的纽带与桥梁,向下提供驱动层的接口,向上提供事件处理层的接口。
事件处理层:
事件处理层负责与用户程序打交道,将硬件驱动层传来的事件报告给用户程序。

linux input子系统学习笔记
linux input子系统学习笔记

3.input 子系统有如下优点 :

(1) 统一了各种各样的输入设备的处理方法.
(2) 提供了用于分布给用户使用的简单接口
(3) 提炼了输入驱动程序的通用部分 , 简化了驱动程序的开发和移植工作.

4.open、read、write这些系统调用是如何和设备驱动程序关联起来的?

ile_operation就是把系统调用和驱动程序关联起来的关键数据结构,以鼠标设备文件为例,我们对设备文件调用open系统调用,实际上内部的调用是mousedev_open.

static const struct file_operations mousedev_fops = {
    .owner      = THIS_MODULE,
    .read       = mousedev_read,
    .write      = mousedev_write,
    .poll       = mousedev_poll,
    .open       = mousedev_open,
    .release    = mousedev_release,
    .fasync     = mousedev_fasync,
    .llseek     = noop_llseek,
};

顺便说下fs.h中的两个文件相关的数据结构:
struct inode结构是用来在内核表示文件的.同一个文件可以被打开好多次,所以可以对应很多struct file,但是只对应一个struct inode.

5.对鼠标设备文件调用open系统调用的流程

open系统调用 (以鼠标为例)
   --> mousedev_open()
      --> mousedev::open_device()  
   		 --> mousedev_open_device()
             --> input_open_device()
  				--> input_dev::open()

6.鼠标事件上报流程

mousedev_init 内核加载的时候会调用该函数,主要做两个事情:
(1)mousedev_create()创建一个mousedev结构体对象
(2)input_register_handler()将设备对应的input_handler对象注册到输入子系统(dev与handler建立绑定关系)

static struct input_handler mousedev_handler = {
    .event      = mousedev_event,
    .connect    = mousedev_connect,
    .disconnect = mousedev_disconnect,
    .legacy_minors  = true,
    .minor      = MOUSEDEV_MINOR_BASE,
    .name       = "mousedev",
    .id_table   = mousedev_ids,
};

input_event是核心层input.c提供给设备驱动层上报设备数据的接口

input_event()
   --> input_handle_event()
      --> input_pass_values()
         --> input_to_handler()
            --> handler->event()
               --> mousedev_event()    //最终调用到mousedev_handler中的mousedev_event

7.两个例子

/* 读取键盘设备文件 */
#include <stdio.h>
#include <linux/input.h>
#include <fcntl.h>
#include <unistd.h>

#define DEV_PATH "/dev/input/event4"   //键盘对应的设备文件(后面数字可能不同)

int main(int argc, char* argv[])
{
    int keys_fd;
    char ret[2];
    struct input_event t;  //读取到的input设备数据是一个结构体
    
    keys_fd = open(DEV_PATH, O_RDONLY);
    if (keys_fd <= 0) {
        printf("open device error!\n");
        return -1;
    }
    while (1) {
        if (read(keys_fd, &t, sizeof(t)) == sizeof(t)) {
            if (t.type == EV_KEY) {
                if (t.value == 0 || t.value == 1) {
                    //t.code值所对应的按键在/usr/include/linux/input-event-codes.h可以查到  
                    printf("key %d %s\n", t.code, (t.value) ? "Pressed" : "Released");  
                }
            }
        }
    }
    close(keys_fd);
    return 0;
}
/* 
* 模拟鼠标按键和键盘按键事件 
* https://www.cnblogs.com/zhoug2020/p/6404767.html
*/

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

//按键模拟,按键包含按下和松开两个环节
void simulate_key(int fd, int kval)
{
    struct input_event event;
    gettimeofday(&event.time, 0);

    //按下kval键
    event.type = EV_KEY;
    event.value = 1;
    event.code = kval;
    write(fd, &event, sizeof(event));

    //同步,也就是把它报告给系统
    event.type = EV_SYN;
    event.value = 0;
    event.code = SYN_REPORT;
    write(fd, &event, sizeof(event));

    memset(&event, 0, sizeof(event));
    gettimeofday(&event.time, 0);

    //松开kval键
    event.type = EV_KEY;
    event.value = 0;
    event.code = kval;
    write(fd, &event, sizeof(event));

    //同步,也就是把它报告给系统
    event.type = EV_SYN;
    event.value = 0;
    event.code = SYN_REPORT;
    write(fd, &event, sizeof(event));
}

//鼠标移动模拟
void simulate_mouse(int fd, int rel_x, int rel_y)
{
    struct input_event event;
    gettimeofday(&event.time, 0);

    //x轴坐标的相对位移
    event.type = EV_REL;
    event.value = rel_x;
    event.code = REL_X;
    write(fd, &event, sizeof(event));

    //y轴坐标的相对位移
    event.type = EV_REL;
    event.value = rel_y;
    event.code = REL_Y;
    write(fd, &event, sizeof(event));

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

 

int main(int argc, char *argv[])
{
    int fd_mouse = -1;
    int fd_kbd = -1;
    int i = 0;

    fd_kbd = open("/dev/input/event4", O_RDWR);

    if(fd_kbd <= 0)
    {
        printf("Can not open keyboard input file\n");
        return -1;
    }

    fd_mouse = open("/dev/input/event3", O_RDWR);
    if(fd_mouse <= 0)
    {
        printf("Can not open mouse input file\n");
        return -1;
    }


	//simulate_key(fd_mouse, BTN_RIGHT);  //模拟按下鼠标左键
	simulate_key(fd_kbd, KEY_A);  //模拟按下键盘A键
	//模拟鼠标相对上次x和y轴相应移动10个像素
	//simulate_mouse(fd_mouse, 10, 10);                 
    close(fd_kbd);
    close(fd_mouse);
}