加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • 实现原理
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

Linux input子系统(二)uinput 原理和用途

05/11 11:27
4773
阅读需 8 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

哈喽,大家好,我是程序员秘书LittleG。

前言

uinputUserspace Input,uinput 的实现是基于 Linux input子系统(Input Subsystem),允许用户空间程序创建虚拟的输入设备并向内核发送输入事件,比如键盘敲击、鼠标移动等,就像这些事件来自真实的物理设备一样。对于开发自定义输入设备驱动、自动化测试、游戏控制模拟以及各种人机交互实验等场景非常有用。

可能的使用场景有:

自动化测试:模拟用户操作,如点击、滑动等,进行UI自动化测试。在自动化测试过程中,可以模拟用户的输入操作来测试软件的功能。

自定义输入设备:为没有驱动支持的新奇设备创建虚拟驱动。

游戏控制模拟:模拟游戏手柄或其他特殊控制器。一些游戏玩家可能会使用脚本来自动执行一些复杂的操作。

辅助工具开发:如屏幕键盘、宏命令工具等。实现一些辅助工具(如屏幕阅读器、残疾人辅助工具等)可能需要模拟输入设备来与操作系统或其他应用程序进行交互。

uinput的使用场景非常广泛,包括但不限于以上场景。下面就学习看下原理和如何使用。

实现原理

uinput 通过在内核和用户空间之间创建一个特殊的设备文件(通常是 /dev/uinput)来工作。用户空间程序可以打开这个文件,并向其中写入数据来模拟输入事件。这些数据会被内核的输入子系统接收,并像真实的输入设备产生的事件一样进行处理。

具体来说,uinput 的实现包括以下几个步骤:

创建 uinput 设备:用户空间程序通过 ioctl 调用 UINPUT_CREATE_DEVICE 请求来创建一个 uinput 设备。这个请求需要指定模拟的输入设备的类型和属性。

设置输入事件:用户空间程序通过写入 /dev/uinput 设备文件来设置要模拟的输入事件。这些事件可以是键盘按键、鼠标移动、触摸屏触摸等。

启用 uinput 设备:在设置完所有需要的输入事件后,用户空间程序通过 ioctl 调用 UINPUT_START_DEVICE 请求来启用 uinput 设备。此时,内核的输入子系统会开始处理这些模拟的输入事件。

发送输入事件:一旦 uinput 设备被启用,用户空间程序就可以通过写入 /dev/uinput 设备文件来发送输入事件了。这些事件会被内核的输入子系统接收,并像真实的输入设备产生的事件一样进行处理。

销毁 uinput 设备:当用户空间程序不再需要模拟输入设备时,它可以通过 ioctl 调用 UINPUT_DESTROY_DEVICE 请求来销毁 uinput 设备。

补充说明

关于配置设备属性
在创建虚拟设备之前,需要通过ioctl调用配置设备的各种属性,比如设备名称、ID(厂商ID、产品ID、版本等)、支持的事件类型(EV_KEY、EV_REL、EV_ABS等)和具体的事件代码(如BTN_LEFT、KEY_A、REL_X等)。

关于发送事件
一旦设备被创建,就可以通过写入input_event结构体到文件描述符来模拟输入事件。每个事件包括类型(EV_KEY、EV_REL等)、代码(按键、轴等)、值(按键状态、移动距离等)以及一个同步事件(EV_SYN)来标记事件包的结束。

使用举例

下面是一个简单的使用例子,通过uinput创建虚拟键盘并发送一次键击事件:

#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <stdio.h>
#include <unistd.h>

int main() {
    int fd;
    struct uinput_user_dev uidev;
    struct input_event ev;

    /* 打开uinput设备 */
    fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    if (fd < 0) {
        perror("Error opening /dev/uinput");
        return 1;
    }

    /* 配置虚拟设备 */
    memset(&uidev, 0, sizeof(uidev));
    strncpy(uidev.name, "Virtual Keyboard", UINPUT_MAX_NAME_SIZE);
    uidev.id.bustype = BUS_USB;
    uidev.id.vendor = 0x1234;
    uidev.id.product = 0x5678;
    uidev.id.version = 1;

    /* 设置支持的事件类型 */
    ioctl(fd, UI_SET_EVBIT, EV_KEY);
    ioctl(fd, UI_SET_KEYBIT, KEY_A);

    /* 创建虚拟设备 */
    write(fd, &uidev, sizeof(uidev));
    ioctl(fd, UI_DEV_CREATE);

    /* 发送按键事件 */
    memset(&ev, 0, sizeof(ev));
    ev.type = EV_KEY;
    ev.code = KEY_A;
    ev.value = 1; // 按下
    write(fd, &ev, sizeof(ev));

    ev.value = 0; // 抬起
    write(fd, &ev, sizeof(ev));

    /* 发送同步事件 */
    memset(&ev, 0, sizeof(ev));
    ev.type = EV_SYN;
    ev.code = SYN_REPORT;
    ev.value = 0;
    write(fd, &ev, sizeof(ev));

    /* 销毁设备 */
    ioctl(fd, UI_DEV_DESTROY);
    close(fd);

    return 0;
}

说明:以上代码中,创建了一个名为"Virtual Keyboard"的虚拟键盘设备,发送了一个"A"键的按下与释放事件,并在最后销毁了虚拟设备。

注意,调试运行时,可能会存在相应的权限问题,可以使用root登录运行或chmod修改/dev/uinput权限。

下期见~

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
530BC50M0000DG 1 Silicon Laboratories Inc LVDS Output Clock Oscillator, 10MHz Min, 945MHz Max, 50MHz Nom, ROHS COMPLIANT, SMD, 6 PIN
$125.26 查看
ASVMX-25.000MHZ-5ABB 1 Abracon Corporation XTAL OSC XO 25.0000MHZ LVDS SMD
$6.67 查看
CSTCE16M0V13C99-R0 1 Murata Manufacturing Co Ltd Ceramic Resonator, 16MHz Nom, SMD, 3 PIN

ECAD模型

下载ECAD模型
$1.6 查看

相关推荐

电子产业图谱

记录和分享C/C++、Linux、ARM、Android、IoT相关知识。技术相伴于生活和成长,愿你我永为少年,心中有火,眼中有光,始保热情。