您尚未登录。

楼主 # 昨天 11:14:20

memory
会员
注册时间: 2021-08-11
已发帖子: 700
积分: 675

Linux 使用 poll 检测所有 event设备的输入的 demo

detect2.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <linux/input.h>
#include <linux/input-event-codes.h>

#define MAX_DEVICES 64
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x)  ((x)%BITS_PER_LONG)
#define BIT(x)  (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)

static inline int test_bit(int bit, const unsigned long *array) {
    return (array[LONG(bit)] >> OFF(bit)) & 1;
}

const char* get_device_type(int fd) {
    unsigned long evbit[NBITS(EV_MAX)] = {0};
    unsigned long keybit[NBITS(KEY_MAX)] = {0};
    unsigned long absbit[NBITS(ABS_MAX)] = {0};
    unsigned long propbit[NBITS(INPUT_PROP_MAX)] = {0};

    if (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0)
        return "unknown";

    // 先获取所有需要的位图
    if (test_bit(EV_KEY, evbit))
        ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit);
    if (test_bit(EV_ABS, evbit))
        ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit);

    // 获取设备属性(用于区分 touchscreen vs touchpad)
    int has_direct = 0, has_pointer = 0;
    if (ioctl(fd, EVIOCGPROP(sizeof(propbit)), propbit) >= 0) {
        has_direct  = test_bit(INPUT_PROP_DIRECT, propbit);
        has_pointer = test_bit(INPUT_PROP_POINTER, propbit);
    }

    // ✅ 优先判断:多点触摸 + DIRECT → touchscreen
    if (test_bit(EV_ABS, evbit) &&
        test_bit(ABS_MT_POSITION_X, absbit) &&
        test_bit(ABS_MT_POSITION_Y, absbit)) {
        if (has_direct) {
            return "touchscreen";  // 明确是触摸屏
        } else {
            return "multitouch-device"; // 保守判断
        }
    }

    // 单点绝对坐标 + BTN_TOUCH
    if (test_bit(EV_ABS, evbit) &&
        test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
        test_bit(BTN_TOUCH, keybit)) {
        if (has_direct) {
            return "touchscreen";
        } else if (has_pointer) {
            return "touchpad";
        } else {
            // 启发式:分辨率高可能是屏,低可能是板(简化处理)
            return "touch-input";
        }
    }

    // 鼠标:相对移动 + 按键
    if (test_bit(EV_REL, evbit)) {
        unsigned long relbit[NBITS(REL_MAX)] = {0};
        ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit);
        if (test_bit(REL_X, relbit) && test_bit(REL_Y, relbit) &&
            test_bit(BTN_MOUSE, keybit)) {
            return "mouse";
        }
    }

    // 键盘:包含基本字符或控制键
    if (test_bit(EV_KEY, evbit)) {
        // 常见键盘按键
        if (test_bit(KEY_A, keybit) || test_bit(KEY_Z, keybit) ||
            test_bit(KEY_1, keybit) || test_bit(KEY_SPACE, keybit) ||
            test_bit(KEY_ESC, keybit) || test_bit(KEY_ENTER, keybit)) {
            return "keyboard";
        }
        // 如果只有特殊功能键(如你的 gt911 的 KEY_SWITCHVIDEOMODE),不视为键盘
    }

    // 游戏手柄/摇杆
    if (test_bit(EV_ABS, evbit) &&
        (test_bit(ABS_RX, absbit) || test_bit(ABS_X, absbit)) &&
        (test_bit(BTN_A, keybit) || test_bit(BTN_TRIGGER, keybit))) {
        return "joystick/gamepad";
    }

    // 如果有 BTN_TOUCH 但没 ABS_X/Y,可能是虚拟按键?归为 button
    if (test_bit(BTN_TOUCH, keybit)) {
        return "touch-button"; // 如屏幕上的虚拟键
    }

    // 仅有一些特殊 KEY_*
    if (test_bit(EV_KEY, evbit)) {
        return "special-keys"; // 如电源、音量、多媒体键
    }

    return "unknown";
}

// 获取设备名称
void get_device_name(int fd, char *name, size_t size) {
    if (ioctl(fd, EVIOCGNAME(size), name) < 0) {
        snprintf(name, size, "unknown");
    }
}

int main(void) {
    struct pollfd fds[MAX_DEVICES];
    char names[MAX_DEVICES][256];
    const char* types[MAX_DEVICES];
    int fd_count = 0;
    char path[256];
    DIR *dir;
    struct dirent *entry;

    dir = opendir("/dev/input");
    if (!dir) {
        perror("opendir /dev/input");
        return EXIT_FAILURE;
    }

    while ((entry = readdir(dir)) != NULL) {
        if (strncmp(entry->d_name, "event", 5) == 0) {
            snprintf(path, sizeof(path), "/dev/input/%s", entry->d_name);
            int fd = open(path, O_RDONLY | O_NONBLOCK);
            if (fd < 0) {
                fprintf(stderr, "无法打开 %s: %s\n", path, strerror(errno));
                continue;
            }

            char name[256];
            get_device_name(fd, name, sizeof(name));
            const char* type = get_device_type(fd);

            printf("监听 [%s] (%s) -> 类型: %s\n", path, name, type);

            fds[fd_count].fd = fd;
            fds[fd_count].events = POLLIN;
            strncpy(names[fd_count], name, sizeof(names[fd_count]) - 1);
            types[fd_count] = type;
            fd_count++;
            if (fd_count >= MAX_DEVICES) break;
        }
    }
    closedir(dir);

    if (fd_count == 0) {
        fprintf(stderr, "未找到任何 event 设备。\n");
        return EXIT_FAILURE;
    }

    printf("\n开始监听输入事件...(按 Ctrl+C 退出)\n");

    struct input_event ev;
    while (1) {
        int ret = poll(fds, fd_count, -1);
        if (ret < 0) {
            perror("poll");
            break;
        }

        for (int i = 0; i < fd_count; i++) {
            if (fds[i].revents & POLLIN) {
                ssize_t bytes;
                while ((bytes = read(fds[i].fd, &ev, sizeof(ev))) == sizeof(ev)) {
                    printf("[%s] (%s): time=%ld.%06ld, type=%d, code=%d, value=%d\n",
                           names[i], types[i],
                           ev.time.tv_sec, ev.time.tv_usec,
                           ev.type, ev.code, ev.value);
                }
            }
        }
    }

    for (int i = 0; i < fd_count; i++) {
        close(fds[i].fd);
    }

    return EXIT_SUCCESS;
}

测试:

root@TinaLinux:/# chmod +x /tmp/detect2 && /tmp/detect2
监听 [/dev/input/event0] (sunxi_ir_recv) -> 类型: special-keys
监听 [/dev/input/event1] (sunxi-gpadc0/channel0/input0) -> 类型: special-keys
监听 [/dev/input/event2] (audiocodec Headphones) -> 类型: unknown
监听 [/dev/input/event3] (A4Tech USB Keyboard) -> 类型: keyboard
监听 [/dev/input/event4] (A4Tech USB Keyboard) -> 类型: special-keys
监听 [/dev/input/event5] (gt9xxnew_ts) -> 类型: touchscreen

开始监听输入事件...(按 Ctrl+C 退出)
[gt9xxnew_ts] (touchscreen): time=84163.016200, type=1, code=330, value=1
[gt9xxnew_ts] (touchscreen): time=84163.016200, type=3, code=53, value=680
[gt9xxnew_ts] (touchscreen): time=84163.016200, type=3, code=54, value=399
[gt9xxnew_ts] (touchscreen): time=84163.016200, type=3, code=48, value=9
...
[gt9xxnew_ts] (touchscreen): time=84163.036021, type=0, code=0, value=0
[A4Tech USB Keyboard] (keyboard): time=84167.859830, type=4, code=4, value=458756
[A4Tech USB Keyboard] (keyboard): time=84167.859830, type=1, code=30, value=1
[A4Tech USB Keyboard] (keyboard): time=84167.859830, type=0, code=0, value=0
[A4Tech USB Keyboard] (keyboard): time=84167.931824, type=4, code=4, value=458756
[A4Tech USB Keyboard] (keyboard): time=84167.931824, type=1, code=30, value=0
[A4Tech USB Keyboard] (keyboard): time=84167.931824, type=0, code=0, value=0
[A4Tech USB Keyboard] (keyboard): time=84176.259844, type=4, code=4, value=458979
[A4Tech USB Keyboard] (keyboard): time=84176.259844, type=1, code=125, value=1
[A4Tech USB Keyboard] (keyboard): time=84176.259844, type=0, code=0, value=0
[A4Tech USB Keyboard] (keyboard): time=84176.451820, type=4, code=4, value=458811
[A4Tech USB Keyboard] (keyboard): time=84176.451820, type=1, code=60, value=1
[A4Tech USB Keyboard] (keyboard): time=84176.451820, type=0, code=0, value=0
[A4Tech USB Keyboard] (keyboard): time=84176.547841, type=4, code=4, value=458811
[A4Tech USB Keyboard] (keyboard): time=84176.547841, type=1, code=60, value=0
[A4Tech USB Keyboard] (keyboard): time=84176.547841, type=0, code=0, value=0
[A4Tech USB Keyboard] (keyboard): time=84176.627824, type=4, code=4, value=458979
[A4Tech USB Keyboard] (keyboard): time=84176.627824, type=1, code=125, value=0
[A4Tech USB Keyboard] (keyboard): time=84176.627824, type=0, code=0, value=0
[sunxi-gpadc0/channel0/input0] (special-keys): time=84180.164279, type=1, code=103, value=1
[sunxi-gpadc0/channel0/input0] (special-keys): time=84180.164279, type=0, code=0, value=0
[sunxi-gpadc0/channel0/input0] (special-keys): time=84180.301283, type=1, code=103, value=0
[sunxi-gpadc0/channel0/input0] (special-keys): time=84180.301283, type=0, code=0, value=0

离线

楼主 #1 昨天 11:45:16

memory
会员
注册时间: 2021-08-11
已发帖子: 700
积分: 675

Re: Linux 使用 poll 检测所有 event设备的输入的 demo

支持USB鼠标键盘拔插:hotplug.c

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <poll.h>
#include <errno.h>
#include <sys/inotify.h>
#include <linux/input.h>
#include <linux/input-event-codes.h>

#define MAX_DEVICES 64
#define EVENT_NAME_PREFIX "event"
#define INPUT_DIR "/dev/input"

// --- 工具宏 ---
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x)  ((x)%BITS_PER_LONG)
#define BIT(x)  (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)

static inline int test_bit(int bit, const unsigned long *array) {
    return (array[LONG(bit)] >> OFF(bit)) & 1;
}

// --- 设备类型判断(改进版)---
const char* get_device_type(int fd) {
    unsigned long evbit[NBITS(EV_MAX)] = {0};
    unsigned long keybit[NBITS(KEY_MAX)] = {0};
    unsigned long absbit[NBITS(ABS_MAX)] = {0};
    unsigned long propbit[NBITS(INPUT_PROP_MAX)] = {0};

    if (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0)
        return "unknown";

    if (test_bit(EV_KEY, evbit))
        ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit);
    if (test_bit(EV_ABS, evbit))
        ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit);
    ioctl(fd, EVIOCGPROP(sizeof(propbit)), propbit); // 可能失败,但没关系

    int has_direct = test_bit(INPUT_PROP_DIRECT, propbit);

    // ✅ 优先:多点触摸 + DIRECT → touchscreen
    if (test_bit(EV_ABS, evbit) &&
        test_bit(ABS_MT_POSITION_X, absbit) &&
        test_bit(ABS_MT_POSITION_Y, absbit)) {
        return has_direct ? "touchscreen" : "multitouch";
    }

    if (test_bit(EV_ABS, evbit) &&
        test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
        test_bit(BTN_TOUCH, keybit)) {
        return has_direct ? "touchscreen" : "touchpad";
    }

    if (test_bit(EV_REL, evbit)) {
        unsigned long relbit[NBITS(REL_MAX)] = {0};
        ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit);
        if (test_bit(REL_X, relbit) && test_bit(REL_Y, relbit) &&
            test_bit(BTN_MOUSE, keybit))
            return "mouse";
    }

    if (test_bit(EV_KEY, evbit)) {
        if (test_bit(KEY_A, keybit) || test_bit(KEY_SPACE, keybit) ||
            test_bit(KEY_ENTER, keybit) || test_bit(KEY_ESC, keybit))
            return "keyboard";
        if (test_bit(BTN_TOUCH, keybit))
            return "touch-button";
        return "special-keys";
    }

    return "unknown";
}

void get_device_name(int fd, char *name, size_t size) {
    if (ioctl(fd, EVIOCGNAME(size), name) < 0)
        snprintf(name, size, "unknown");
}

// --- 动态管理设备 ---
struct device {
    int fd;
    char path[64];
    char name[256];
    const char* type;
};

static struct device devices[MAX_DEVICES];
static int dev_count = 0;

int add_device(const char *basename) {
    if (dev_count >= MAX_DEVICES) return -1;
    char path[256];
    snprintf(path, sizeof(path), "%s/%s", INPUT_DIR, basename);
    int fd = open(path, O_RDONLY | O_NONBLOCK);
    if (fd < 0) return -1;

    char name[256];
    get_device_name(fd, name, sizeof(name));
    const char* type = get_device_type(fd);

    printf("🔌 添加设备: %s (%s) -> %s\n", path, name, type);

    struct device *dev = &devices[dev_count];
    dev->fd = fd;
    strncpy(dev->path, path, sizeof(dev->path)-1);
    strncpy(dev->name, name, sizeof(dev->name)-1);
    dev->type = type;
    dev_count++;
    return 0;
}

void remove_device_by_fd(int fd) {
    for (int i = 0; i < dev_count; i++) {
        if (devices[i].fd == fd) {
            printf("⏏️  移除设备: %s (%s)\n", devices[i].path, devices[i].name);
            close(fd);
            // 移动最后一个覆盖
            if (i != dev_count - 1) {
                devices[i] = devices[dev_count - 1];
            }
            dev_count--;
            return;
        }
    }
}

void scan_initial_devices() {
    DIR *dir = opendir(INPUT_DIR);
    if (!dir) return;
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (strncmp(entry->d_name, EVENT_NAME_PREFIX, strlen(EVENT_NAME_PREFIX)) == 0) {
            add_device(entry->d_name);
        }
    }
    closedir(dir);
}

// --- 主函数 ---
int main(void) {
    int inotify_fd = inotify_init1(IN_NONBLOCK);
    if (inotify_fd < 0) {
        perror("inotify_init1");
        return EXIT_FAILURE;
    }

    int watch_desc = inotify_add_watch(inotify_fd, INPUT_DIR, IN_CREATE | IN_DELETE);
    if (watch_desc < 0) {
        perror("inotify_add_watch /dev/input");
        close(inotify_fd);
        return EXIT_FAILURE;
    }

    // 初始扫描
    scan_initial_devices();

    printf("✅ 正在监听输入事件和热插拔...(Ctrl+C 退出)\n");

    struct input_event ev;
    char inotify_buf[4096];

    while (1) {
        // 构建 pollfd 数组:所有设备 + inotify_fd
        struct pollfd *pfds = malloc((dev_count + 1) * sizeof(struct pollfd));
        for (int i = 0; i < dev_count; i++) {
            pfds[i].fd = devices[i].fd;
            pfds[i].events = POLLIN;
        }
        pfds[dev_count].fd = inotify_fd;
        pfds[dev_count].events = POLLIN;

        int ret = poll(pfds, dev_count + 1, -1);
        if (ret < 0) {
            perror("poll");
            free(pfds);
            break;
        }

        // 检查 inotify 事件(热插拔)
        if (pfds[dev_count].revents & POLLIN) {
            ssize_t len = read(inotify_fd, inotify_buf, sizeof(inotify_buf));
            if (len > 0) {
                char *ptr = inotify_buf;
                while (ptr < inotify_buf + len) {
                    struct inotify_event *event = (struct inotify_event *)ptr;
                    if (event->len > 0 && strncmp(event->name, EVENT_NAME_PREFIX, strlen(EVENT_NAME_PREFIX)) == 0) {
                        if (event->mask & IN_CREATE) {
                            add_device(event->name);
                        } else if (event->mask & IN_DELETE) {
                            // 需要找到对应 fd(通过路径匹配)
                            char path[256];
                            snprintf(path, sizeof(path), "%s/%s", INPUT_DIR, event->name);
                            for (int i = 0; i < dev_count; i++) {
                                if (strcmp(devices[i].path, path) == 0) {
                                    remove_device_by_fd(devices[i].fd);
                                    break;
                                }
                            }
                        }
                    }
                    ptr += sizeof(struct inotify_event) + event->len;
                }
            }
        }

        // 检查输入事件
        for (int i = 0; i < dev_count; i++) {
            if (pfds[i].revents & POLLIN) {
                ssize_t bytes;
                while ((bytes = read(pfds[i].fd, &ev, sizeof(ev))) == sizeof(ev)) {
                    printf("[%s] (%s): t=%ld.%06ld, type=%d, code=%d, val=%d\n",
                           devices[i].name, devices[i].type,
                           ev.time.tv_sec, ev.time.tv_usec,
                           ev.type, ev.code, ev.value);
                }
            }
        }

        free(pfds);
    }

    // 清理
    for (int i = 0; i < dev_count; i++) {
        close(devices[i].fd);
    }
    inotify_rm_watch(inotify_fd, watch_desc);
    close(inotify_fd);
    return EXIT_SUCCESS;
}

拔插USB鼠标键盘和游戏手柄 测试:

root@TinaLinux:/#
root@TinaLinux:/# chmod +x /tmp/detect2 && /tmp/detect2
🔌 添加设备: /dev/input/event0 (sunxi_ir_recv) -> special-keys
🔌 添加设备: /dev/input/event1 (sunxi-gpadc0/channel0/input0) -> special-keys
🔌 添加设备: /dev/input/event2 (audiocodec Headphones) -> unknown
🔌 添加设备: /dev/input/event3 (A4Tech USB Keyboard) -> keyboard
🔌 添加设备: /dev/input/event4 (A4Tech USB Keyboard) -> special-keys
🔌 添加设备: /dev/input/event5 (gt9xxnew_ts) -> touchscreen
✅ 正在监听输入事件和热插拔...(Ctrl+C 退出)
⏏️  移除设备: /dev/input/event3 (A4Tech USB Keyboard)
⏏️  移除设备: /dev/input/event4 (A4Tech USB Keyboard)
🔌 添加设备: /dev/input/event3 ( USB OPTICAL MOUSE) -> mouse
[ USB OPTICAL MOUSE] (mouse): t=86070.380692, type=2, code=0, val=-5
[ USB OPTICAL MOUSE] (mouse): t=86070.380692, type=2, code=1, val=-2
[ USB OPTICAL MOUSE] (mouse): t=86070.380692, type=0, code=0, val=0
[ USB OPTICAL MOUSE] (mouse): t=86070.388716, type=2, code=0, val=-4
[ USB OPTICAL MOUSE] (mouse): t=86070.716714, type=2, code=0, val=1
[ USB OPTICAL MOUSE] (mouse): t=86070.716714, type=2, code=1, val=-2
[ USB OPTICAL MOUSE] (mouse): t=86070.716714, type=0, code=0, val=0
[ USB OPTICAL MOUSE] (mouse): t=86070.724699, type=2, code=0, val=1
[ USB OPTICAL MOUSE] (mouse): t=86070.724699, type=2, code=1, val=-2
[ USB OPTICAL MOUSE] (mouse): t=86070.724699, type=0, code=0, val=0
[ USB OPTICAL MOUSE] (mouse): t=86070.748693, type=2, code=1, val=-2
[ USB OPTICAL MOUSE] (mouse): t=86070.748693, type=0, code=0, val=0
[ USB OPTICAL MOUSE] (mouse): t=86070.772708, type=2, code=0, val=-2
[ USB OPTICAL MOUSE] (mouse): t=86070.772708, type=2, code=1, val=-3
[ USB OPTICAL MOUSE] (mouse): t=86070.772708, type=0, code=0, val=0
⏏️  移除设备: /dev/input/event3 ( USB OPTICAL MOUSE)
🔌 添加设备: /dev/input/event3 (USB gamepad           ) -> special-keys
[USB gamepad           ] (special-keys): t=86191.685715, type=3, code=0, val=127
[USB gamepad           ] (special-keys): t=86191.685715, type=3, code=1, val=127
[USB gamepad           ] (special-keys): t=86191.685715, type=0, code=0, val=0
[USB gamepad           ] (special-keys): t=86243.085705, type=3, code=1, val=0
[USB gamepad           ] (special-keys): t=86243.085705, type=0, code=0, val=0
[USB gamepad           ] (special-keys): t=86243.253702, type=3, code=1, val=127
[USB gamepad           ] (special-keys): t=86243.253702, type=0, code=0, val=0
[USB gamepad           ] (special-keys): t=86244.533720, type=4, code=4, val=589826
[USB gamepad           ] (special-keys): t=86244.533720, type=1, code=289, val=1
[USB gamepad           ] (special-keys): t=86244.533720, type=0, code=0, val=0

离线

楼主 #2 昨天 11:59:43

memory
会员
注册时间: 2021-08-11
已发帖子: 700
积分: 675

Re: Linux 使用 poll 检测所有 event设备的输入的 demo

接上HUB,鼠标键盘手柄一起测试:

root@TinaLinux:/# chmod +x /tmp/detect2 && /tmp/detect2
🔌 添加设备: /dev/input/event0 (sunxi_ir_recv) -> special-keys
🔌 添加设备: /dev/input/event1 (sunxi-gpadc0/channel0/input0) -> special-keys
🔌 添加设备: /dev/input/event2 (audiocodec Headphones) -> unknown
🔌 添加设备: /dev/input/event5 (gt9xxnew_ts) -> touchscreen
🔌 添加设备: /dev/input/event6 (A4Tech USB Keyboard) -> keyboard
🔌 添加设备: /dev/input/event7 (A4Tech USB Keyboard) -> special-keys
🔌 添加设备: /dev/input/event4 (USB gamepad           ) -> special-keys
🔌 添加设备: /dev/input/event3 ( USB OPTICAL MOUSE) -> mouse
✅ 正在监听输入事件和热插拔...(Ctrl+C 退出)
[USB gamepad           ] (special-keys): t=86981.448700, type=4, code=4, val=589827
[USB gamepad           ] (special-keys): t=86981.448700, type=1, code=290, val=1
[USB gamepad           ] (special-keys): t=86981.448700, type=0, code=0, val=0
[USB gamepad           ] (special-keys): t=86981.648719, type=4, code=4, val=589827
[USB gamepad           ] (special-keys): t=86981.648719, type=1, code=290, val=0
[USB gamepad           ] (special-keys): t=86981.648719, type=0, code=0, val=0
[ USB OPTICAL MOUSE] (mouse): t=86983.889697, type=2, code=0, val=-2
[ USB OPTICAL MOUSE] (mouse): t=86983.889697, type=2, code=1, val=-3
[ USB OPTICAL MOUSE] (mouse): t=86984.145699, type=0, code=0, val=0
[A4Tech USB Keyboard] (keyboard): t=86985.946704, type=4, code=4, val=458831
[A4Tech USB Keyboard] (keyboard): t=86985.946704, type=1, code=106, val=1
[A4Tech USB Keyboard] (keyboard): t=86985.946704, type=0, code=0, val=0
[A4Tech USB Keyboard] (keyboard): t=86986.050719, type=4, code=4, val=458831
[A4Tech USB Keyboard] (keyboard): t=86986.050719, type=1, code=106, val=0
[A4Tech USB Keyboard] (keyboard): t=86986.050719, type=0, code=0, val=0

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn


太原小智科技有限责任公司 - 东莞哇酷科技有限公司联合开发