How to get Coordinates of Touchscreen Rawdata using Linux
Asked Answered
T

2

15

We have a 3m microtouch display. It's connected to my Debian system via USB and recognized as human interface (hid). I am trying to access and push realtime information... if its getting touched I want to know where (x,y) and pipe it through netcat to another host.

Unfortunately I am only able to get raw data using:

cat /dev/input/event2 | hexdump

or

evtest

You get hexcode that seem nowhere documented...

Does anybody have a clue how to get that information? There must be a way to extract it from the hexcode. Unfortunately I have no idea how to interpret the hexcode. I couldn't find any source where its documented...

Is there a way the Kernel could provide me those desired information in realtime?

As a workaround, is there, maybe, a solution where the X-Server could tell me? The touchscreen behaves like a mouse in X. I actually already tried to get x,y-position of the mouse via xlib. But it was too slow and wouldn't tell me if somebody is touching or not...

evtest sample output:

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
Toile answered 3/3, 2015 at 20:16 Comment(19)
You want to do this from terminal or from code?Hexose
Also, do you know exact model of your touchscreen? At least we need to know, is it multi-touch or single-touch. If evtest couldn't decode those hex codes, we should look for a driver code for this touchscreen, it should give some clue on those numbers.Hexose
evtest can decode somehow but I am not getting it at all. Device is multitouch, but if it would work like singletouch it will be appropriate for the situation. Code or terminal doesnt matter.Toile
We need to know model of your touchscreen (even better if you can tell us model of touchscreen controller). Also it's unclear if you managed to get it to work in Linux (so your cursor is moving when you are touching this touchscreen). I'd say it's first thing you need to do -- find and install the proper driver for this touchscreen and get it to work at all.Hexose
Kernel drivers are working fine in X out of the box. I dont have it accesible right now. I will provide you the model tomorow.Toile
I found some evtest output in from an old sshsession in my terminallog. If I press touchscreen lets say form half second I get dozens of these lines. X and Y values are there with large integers, I dont know how to interpret.Toile
Obviously you only need ABS_X and ABS_Y lines. Those are your x and y coordinates, respectively.Hexose
ABS_X and ABS_Y values are device specific. From this guide: coordinates origin are in the upper left corner of the sensor. The controller outputs 0 to 16K on both axes independent of display screen resolution.. So you need to divide each your coordinate value from evtest output by 16000 and then multiply result by width or height of device, respectively. If you multiply by width/heigh in pixels - you will have your coordinates in pixles. If by millimeters - will have it in millimeters.Hexose
Thanks for your help, I'll give this a try tomorow. So basically for pushing this information via udp I could write a bash-script taking output from evtest?Toile
Yes, if performance of this way is good enough for you. If no, you can write C application to read raw data from /dev/input/event2, parsing it effectively (reading only coordinates) and then sending them via UDP packet.Hexose
This would be nice, but the data from /dev/input/event2 is not understandable by me. Its just undocumented hexcode...Toile
Actually it's well documented in Linux kernel documentation :) See also this answer on SO for more compact version.Hexose
whats the easiest way to parse out those 2 values? Bashscript sed magic?Toile
Ok, I'm gonna post all this stuff as an actual answer, because it's obviously too much information in comments, may be not convenient to read for someone with problem similar to yours.Hexose
Thanks dude, you are real good soul :)Toile
Meanwhile I digged a bit in some c code where one guys does something similar with keyboard. I really hope I can figure out this tomorow. Cheers!Toile
Just checked the formula you posted. Seems not to fit in my case I have y-Values like 30000. If I divide by 16000 the results are still bigger than 1. Which means if I multiply by 1080p I am getting values higher than the screen hast pixels :(Toile
Seems like this is correct manual for you. It says that controller gives you values from 0 to 64000 for each axis.Hexose
Or no... I just realized that it must be kernel driver who changed this value to 65535 (and also inverted Y axis, so 0 is top). You should check it on device: which corner gives you [0;0] coordinates; and what are maximum values for X and Y coordinates?Hexose
H
42

Console-based solution

You can obtain parsed coordinates using evtest tool.

  1. If you only need single-touch coordinates: look for ABS_X and ABS_Y fields:

     type 3 (EV_ABS), code 0 (ABS_X), value 10306
     type 3 (EV_ABS), code 1 (ABS_Y), value 30625
    
  2. If you need multi-touch coordinates:

    • ABS_MT_SLOT represents number of finger
    • ABS_MT_POSITION_X and ABS_MT_POSITION_Y -- coordinates

    Finger #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
    

    Finger #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
    

For example, if you need to send single-touch coordinates via network, you can use script like this:

#!/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

Program-based solution

You can write C application that will read your event file. Obtained binary data can be easily interpreted, see section 5 in kernel documentation. You can wait for next data portion using select() syscall.

#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;
}

Coordinates units

First of all you need to know next things:

  • where is coordinates origin point (i.e. [x=0;y=0])
  • which units your device is using for representing coordinates

This information usually can be found in driver code for your device.

This is the driver for your device.

So it seems like you need to divide your axis value from evtest by 65535 and multiply it by width or height of device (in pixels). For example, if you get X=30000, and width of your LCD panel is 1080 pixels, you need to do:

X = round((30000 / 65535) * 1080) = 494 pixels
Hexose answered 4/3, 2015 at 1:49 Comment(7)
Hi, can I use your c code to inject touch events in Android app? Also, is it possible to use the getruntime.exe ("some linux command to inject event") in android?Sc
@Sc My code is suitable for reading events exclusively. If you need to perform touch event, please see this, this and this.Hexose
Thanks a lot for your response, but I need something in linux commands, because my app needs to inject events throughout the entire system, I checked the links, they make touches only within the context of an app. I think I can do that by injecting an event in /dev/input/eventX, I found this link regarding this yhcting.wordpress.com/2010/11/29/…, but I'm not sure about the syntax, is it /dev/input/eventX ABS_X value and /dev/input/eventX ABS_Y value? Thanks.Sc
@Sc If you need Linux command to simulate input event, check out xdotool. Or you can try uinput driver, but I doubt that there is a command-line tool for that.Hexose
@SamProtsenko I was facing a similar issue. And I can get the absolute coordinates using xinput test <id> but am unable to figure out out to transform them to relative ones with respect to my screen. My device works fine on windows, is there someone I can figure it out. More details: unix.stackexchange.com/questions/281164/…Semicolon
@AbhishekBhatia What x/y coordinates you see for top-left corner and for bottom-right corner? What is your screen resolution?Hexose
@SamProtsenko I have a 800x480 touchscreen and the x/y values are 0->4096. I Now i want to know, which value is my "65535"? Where can i get the "units your device is using for representing coordinates" - information from?Corsair
C
1

You get hexcode that seem nowhere documented...

This is documented by the device itself, which is how the hid-multitouch driver can interpret the USB data it receives.

You can find the information using the following commands:

$ 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

I use the lsusb command to determine the bus and device numbers and pass that to the usbhid-dump command. You can use the dump command without those numbers, but then you get a list of all your devices. Probably not what you want in most cases.

The codes in there are interpreted by the hid_parser() command in the kernel. Only some devices may not be properly recognized and that's when you need this information.

How to interpret that data is defined by the USB consortium. At this time, it is version 1.11 and it can be found on this page for the hid type of devices.

This mainly includes Keyboards, Mice, Touchscreens, Touchpads, Joysticks, although some other types of devices support this too (your Power button, various buttons on your monitor, etc.)

Carrera answered 13/3, 2021 at 17:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.