如何利用Linux获取触摸屏原始数据坐标

wmtdaxz3  于 2023-02-21  发布在  Linux
关注(0)|答案(2)|浏览(313)

我们有一个3 m的微触摸显示器。它通过USB连接到我的Debian系统,并被识别为人机接口(hid)。我正在尝试访问和推送实时信息...如果它被触摸,我想知道在哪里(x,y),并通过netcat将其传输到另一个主机。
遗憾的是,我只能使用以下方法获得原始数据:

cat /dev/input/event2 | hexdump

evtest

你得到的十六进制码似乎没有记录...
有人知道如何得到这些信息吗?一定有办法从十六进制代码中提取出来。不幸的是,我不知道如何解释十六进制代码。我找不到任何记录它的来源...
内核有办法实时提供我想要的信息吗?
作为一个解决方案,也许有一个解决方案,X-服务器可以告诉我?触摸屏的行为就像一个鼠标在X。我实际上已经尝试过通过xlib获得鼠标的x,y位置。但它太慢,不会告诉我,如果有人正在触摸或没有...
evtest样本输出:

Event: time 1425319271.595631, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 51
Event: time 1425319271.595631, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 10304
Event: time 1425319271.595631, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 30629
Event: time 1425319271.595631, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 893
Event: time 1425319271.595631, type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 414
Event: time 1425319271.595631, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1425319271.595631, type 3 (EV_ABS), code 0 (ABS_X), value 10304
Event: time 1425319271.595631, type 3 (EV_ABS), code 1 (ABS_Y), value 30629
Event: time 1425319271.595631, -------------- SYN_REPORT ------------
Event: time 1425319271.601632, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 10306
Event: time 1425319271.601632, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 30625
Event: time 1425319271.601632, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 962
Event: time 1425319271.601632, type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 421
Event: time 1425319271.601632, type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 1
Event: time 1425319271.601632, type 3 (EV_ABS), code 57 (ABS_MT_TRACKING_ID), value 52
Event: time 1425319271.601632, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 15416
Event: time 1425319271.601632, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 24159
Event: time 1425319271.601632, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 649
Event: time 1425319271.601632, type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 354
Event: time 1425319271.601632, type 3 (EV_ABS), code 0 (ABS_X), value 10306
Event: time 1425319271.601632, type 3 (EV_ABS), code 1 (ABS_Y), value 30625
Event: time 1425319271.601632, -------------- SYN_REPORT ------------
Event: time 1425319271.606626, type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 0
Event: time 1425319271.606626, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 10318
Event: time 1425319271.606626, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 30609
Event: time 1425319271.606626, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 1014
Event: time 1425319271.606626, type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 426
Event: time 1425319271.606626, type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 1
Event: time 1425319271.606626, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 24161
Event: time 1425319271.606626, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 681
Event: time 1425319271.606626, type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 376
Event: time 1425319271.606626, type 3 (EV_ABS), code 0 (ABS_X), value 10318
Event: time 1425319271.606626, type 3 (EV_ABS), code 1 (ABS_Y), value 30609
Event: time 1425319271.606626, -------------- SYN_REPORT ------------
Event: time 1425319271.611629, type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 0
Event: time 1425319271.611629, type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 10320
Event: time 1425319271.611629, type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 30605
Event: time 1425319271.611629, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 1053
Event: time 1425319271.611629, type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 430
Event: time 1425319271.611629, type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 1
Event: time 1425319271.611629, type 3 (EV_ABS), code 48 (ABS_MT_TOUCH_MAJOR), value 705
Event: time 1425319271.611629, type 3 (EV_ABS), code 49 (ABS_MT_TOUCH_MINOR), value 392
Event: time 1425319271.611629, type 3 (EV_ABS), code 0 (ABS_X), value 10320
Event: time 1425319271.611629, type 3 (EV_ABS), code 1 (ABS_Y), value 30605
n9vozmp4

n9vozmp41#

基于控制台的解决方案

可以使用evtest工具获取解析坐标。
1.如果您只需要单点触控坐标:查找ABS_XABS_Y字段:

type 3 (EV_ABS), code 0 (ABS_X), value 10306
 type 3 (EV_ABS), code 1 (ABS_Y), value 30625
  • 如果您需要多点触控坐标:
  • ABS_MT_SLOT表示指状物的数量
  • ABS_MT_POSITION_XABS_MT_POSITION_Y--坐标

手指编号0:

type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 0
 type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 10318
 type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 30609

手指#1:

type 3 (EV_ABS), code 47 (ABS_MT_SLOT), value 1
 type 3 (EV_ABS), code 53 (ABS_MT_POSITION_X), value 20301
 type 3 (EV_ABS), code 54 (ABS_MT_POSITION_Y), value 24161

例如,如果您需要通过网络发送单点触控坐标,则可以使用如下脚本:

#!/bin/sh

# ---- Global variables ----

input=/dev/input/event0
code_prefix="ABS"
code="${code_prefix}_[XY]"
val_regex=".*(${code_prefix}_\(.\)), value \([-]\?[0-9]\+\)"
val_subst="\1=\2"

# ---- Functions ----

send_axis() {
    # 1. Convert axis value ($1) from device specific units
    # 2. Send this axis value via UDP packet
    echo $1
}

process_line() {  
    while read line; do
        axis=$(echo $line | grep "^Event:" | grep $code | \
               sed "s/$val_regex/$val_subst/")

        if [ -n "$axis" ]; then
            send_axis $axis
        fi
    done
}

# ---- Entry point ----

if [ $(id -u) -ne 0 ]; then
    echo "This script must be run from root" >&2
    exit 1
fi

evtest $input | process_line

基于程序的解决方案

您可以编写C应用程序来读取您的事件文件。获取的二进制数据可以很容易地解释,请参阅kernel documentation中的第5节。您可以使用select()系统调用等待下一个数据部分。

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

/* Change it to your dev file for the touch screen */
#define EVENT_DEVICE    "/dev/input/event2"
#define EVENT_TYPE      EV_ABS
#define EVENT_CODE_X    ABS_X
#define EVENT_CODE_Y    ABS_Y

/* TODO: Close fd on SIGINT (Ctrl-C), if it's open */
static int fd = -1;

int main(int argc, char *argv[])
{
    struct input_event ev;
    char name[256] = "Unknown";
    fd_set readfds;

    /* /dev/input/event* files are only readable by root:input */
    if ((getuid()) != 0) {
        fprintf(stderr, "You are not root! This may not work...\n");
        return EXIT_SUCCESS;
    }

    /* Open device for non-blocking read */
    fd = open(EVENT_DEVICE, O_RDONLY | O_NONBLOCK);
    if (fd == -1) {
        fprintf(stderr, "%s is not a vaild device\n", EVENT_DEVICE);
        return EXIT_FAILURE;
    }

    /* Print device name */
    ioctl(fd, EVIOCGNAME(sizeof(name)), name);
    printf("Reading from:\n");
    printf("  - device file: %s\n", EVENT_DEVICE);
    printf("  - device name: %s\n", name);

    /* Prepare for select(): zero and set the fd into fd_set */
    FD_ZERO(&readfds);
    FD_SET(fd, &readfds);

    /* Press Ctrl-C to stop the program */
    for (;;) {
        const size_t ev_size = sizeof(struct input_event);
        ssize_t size;
        int ret;
        /* struct timeval timeout = { 30, 0 }; */

        /*
         * select(): no-timeout version, just stop on errors or
         * interrupts.
         */
        ret = select(fd + 1, &readfds, NULL, NULL, NULL);
        /*
         * select(): timeout-enabled version, stop if no event has
         * occurred until timeout; might be useful e.g. for background
         * tasks.
         */
        /* ret = select(fd + 1, &readfds, NULL, NULL, &timeout); */
        if (ret == -1) {
            perror("Error: select() failed");
            goto err;
        } else if (ret == 0) {
            fprintf(stderr, "Error: select() timeout\n");
            continue;
        }

        size = read(fd, &ev, ev_size);
        if (size < ev_size) {
            fprintf(stderr, "Error: Wrong size when reading\n");
            goto err;
        }

        if (ev.type == EVENT_TYPE && (ev.code == EVENT_CODE_X
                                      || ev.code == EVENT_CODE_Y)) {
            /* TODO: convert value to pixels */
            printf("%s = %d\n", ev.code == EVENT_CODE_X ? "X" : "Y",
                   ev.value);
        }
    }

    return EXIT_SUCCESS;

err:
    close(fd);
    return EXIT_FAILURE;
}

坐标单位

首先,你需要知道接下来的事情:

  • 其中是坐标原点(即[x=0;y=0]
  • 您的设备用于表示坐标的单位

此信息通常可以在设备的驱动程序代码中找到。
这是您设备的驱动程序。
因此,您需要将evtest中的轴值除以65535,然后乘以设备的宽度或高度(以像素为单位)。例如,如果您得到X=30000,LCD面板的宽度为1080像素,您需要执行以下操作:

X = round((30000 / 65535) * 1080) = 494 pixels
hfwmuf9z

hfwmuf9z2#

你得到的十六进制码似乎没有记录...
这是由设备本身 * 记录 * 的,这是hid-multitouch驱动程序解释它接收到的USB数据的方式。
您可以使用以下命令查找信息:

$ lsusb              # determine the bus & device numbers
...
Bus 001 Device 067: ID 1aad:000f KeeTouch
...

$ sudo usbhid-dump -a 1:67 -e d
001:067:002:DESCRIPTOR         1615651625.434241
 05 0D 09 04 A1 01 85 03 09 22 09 00 15 00 26 FF
 00 75 08 95 09 81 02 A1 00 05 0D 09 51 15 00 26
 FF 00 75 08 95 01 81 02 05 0D 09 42 15 00 25 01
 75 01 95 01 81 02 09 32 81 02 09 47 81 02 95 05
 81 03 05 01 09 30 26 FF 7F 55 00 65 00 35 00 46
 00 00 75 10 95 01 81 02 09 31 35 00 46 00 00 81
 02 05 0D 09 48 15 00 26 FF 7F 75 10 95 01 81 02
 09 49 15 00 26 FF 7F 75 10 95 01 81 02 C0 A1 00
 05 0D 09 51 15 00 26 FF 00 75 08 95 01 81 02 05
 0D 09 42 15 00 25 01 75 01 95 01 81 02 09 32 81
 02 09 47 81 02 95 05 81 03 05 01 09 30 26 FF 7F
 55 00 65 00 35 00 46 00 00 75 10 95 01 81 02 09
 31 35 00 46 00 00 81 02 05 0D 09 48 15 00 26 FF
 7F 75 10 95 01 81 02 09 49 15 00 26 FF 7F 75 10
 95 01 81 02 C0 A1 00 05 0D 09 51 15 00 26 FF 00
 75 08 95 01 81 02 05 0D 09 42 15 00 25 01 75 01
 95 01 81 02 09 32 81 02 09 47 81 02 95 05 81 03
 05 01 09 30 26 FF 7F 55 00 65 00 35 00 46 00 00
 75 10 95 01 81 02 09 31 35 00 46 00 00 81 02 05
 0D 09 48 15 00 26 FF 7F 75 10 95 01 81 02 09 49
 15 00 26 FF 7F 75 10 95 01 81 02 C0 A1 00 05 0D
 09 51 15 00 26 FF 00 75 08 95 01 81 02 05 0D 09
 42 15 00 25 01 75 01 95 01 81 02 09 32 81 02 09
 47 81 02 95 05 81 03 05 01 09 30 26 FF 7F 55 00
 65 00 35 00 46 00 00 75 10 95 01 81 02 09 31 35
 00 46 00 00 81 02 05 0D 09 48 15 00 26 FF 7F 75
 10 95 01 81 02 09 49 15 00 26 FF 7F 75 10 95 01
 81 02 C0 A1 00 05 0D 09 51 15 00 26 FF 00 75 08
 95 01 81 02 05 0D 09 42 15 00 25 01 75 01 95 01
 81 02 09 32 81 02 09 47 81 02 95 05 81 03 05 01
 09 30 26 FF 7F 55 00 65 00 35 00 46 00 00 75 10
 95 01 81 02 09 31 35 00 46 00 00 81 02 05 0D 09
 48 15 00 26 FF 7F 75 10 95 01 81 02 09 49 15 00
 26 FF 7F 75 10 95 01 81 02 C0 A1 00 05 0D 09 54
 15 00 25 1F 75 08 95 01 81 02 C0 09 55 85 FD 15
 00 26 FF 00 75 08 95 01 B1 02 C0 05 0D 09 0E A1
 01 85 FC 09 52 09 53 15 00 26 FF 00 75 08 95 02
 B1 02 C0

001:067:001:DESCRIPTOR         1615651625.436655
 05 01 09 02 A1 01 85 02 09 01 A1 00 06 00 FF 09
 00 15 00 26 FF 00 75 08 95 09 81 02 05 01 09 30
 09 31 15 00 26 FF 7F 75 10 95 02 81 02 05 09 19
 01 29 08 15 00 25 01 95 08 75 01 81 02 C0 C0

001:067:000:DESCRIPTOR         1615651625.437001
 06 00 FF 09 00 A1 01 09 00 85 01 A1 00 09 00 15
 00 26 FF 00 35 00 46 FF 00 75 08 95 3F 81 02 C0
 09 02 85 FE A1 00 09 06 15 00 26 FF 00 35 00 46
 FF 00 75 08 95 3F B1 02 C0 C0

我使用lsusb命令来确定总线和设备号,并将其传递给usbhid-dump命令。您可以使用dump命令而不使用这些编号,但这样您会得到所有设备的列表。在大多数情况下,这可能不是您想要的。
这里的代码是由内核中的hid_parser()命令解释的。只有一些设备可能无法正确识别,这就是你需要这些信息的时候。
如何解释该数据由USB协会定义。目前,它是版本1.11,可以找到on this page用于HID类型的设备。
这主要包括键盘、鼠标、触摸屏、触摸板、操纵杆,尽管一些其他类型的设备也支持此功能(电源按钮、显示器上的各种按钮等)。

相关问题