Touchscreen on Linux with Mouse.moveTo()

Status
Not open for further replies.

Elmue

Well-known member
Hello

Teensy 3.1 is really great.
I have been searching a long time for a HID touch screen simulator.
The new command moveTo() works perfectly.

______________________________________________________________________________________

Just a hint for a better marketing:

The description on the page
https://www.pjrc.com/teensy/td_mouse.html
does not explain explicitly that the Mouse.moveTo() command sends absolute positions.
This is a great feature that you should mention because it is missing in products of competing vendors.
Practically it is a touch screen device.
Selling the Teensy as mouse device you are selling it at less than fair value.


You also do not explain on this page that coordinates passed to the Mouse.move() command are not pixel values.
It depends on the operating system's configuration how they are interpreted.
If you set the mouse speed high in Control Panel the mouse moves more for the same Teensy command than when you set mouse speed low in Control Panel.
And if you enable "Mouse Enhancement" in Control Panel it becomes even worse.
If you try to position the mouse exactly with Mouse.move(), well then you are welcome in a nightmare.

______________________________________________________________________________________

But now my questions:
You already know that moveTo() does not work on Linux.
https://forum.pjrc.com/threads/27330-Mouse-moveTo-not-working-in-linux


Sadly I need it to work just on Linux.
Yes, I know that the Teensy is not the culprit.
It is the ugly humpy design of the X11 which is full of bugs.

But what is the solution for me?

I'm not an expert in USB HID descriptor tables.
And I do not have the time to study huge documents from USB.org

Question 1)
Do you have plans to make a new version that also works on Linux in the future?
I think that this would be far more useful than a flight simulator.

Question 2)
Is there anyone who already did that work successfully and uploaded a working code of modified usb_desc.c that I can compile ?
 
Last edited:
Question 1)
Do you have plans to make a new version that also works on Linux in the future?

No, not really. As far as I'm concerned, it's a bug or limitation of X11.

Question 2)
Is there anyone who already did that work successfully and uploaded a working code of modified usb_desc.c that I can compile ?

Maybe try something like this? Please let everyone know if it works, or if you find anything else that allows moveTo() to work with Linux?

Code:
#ifdef MOUSE_INTERFACE
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension
static uint8_t mouse_report_desc[] = {
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x02,                     // Usage (Mouse)
        0xA1, 0x01,                     // Collection (Application)
        0x85, 0x01,                     //   REPORT_ID (1)
        0x05, 0x09,                     //   Usage Page (Button)
        0x19, 0x01,                     //   Usage Minimum (Button #1)
        0x29, 0x08,                     //   Usage Maximum (Button #8)
        0x15, 0x00,                     //   Logical Minimum (0)
        0x25, 0x01,                     //   Logical Maximum (1)
        0x95, 0x08,                     //   Report Count (8)
        0x75, 0x01,                     //   Report Size (1)
        0x81, 0x02,                     //   Input (Data, Variable, Absolute)
        0x75, 0x08,                     //   Report Size (8)
        0x95, 0x02,                     //   Report Count (2)
        0x81, 0x03,                     //   Input (Constant)   <---- ignore the X & Y relative, for Linux X11 limitation
        0x05, 0x01,                     //   Usage Page (Generic Desktop)
        0x09, 0x38,                     //   Usage (Wheel)
        0x15, 0x81,                     //   Logical Minimum (-127)
        0x25, 0x7F,                     //   Logical Maximum (127)
        0x75, 0x08,                     //   Report Size (8),
        0x95, 0x01,                     //   Report Count (1),
        0x81, 0x06,                     //   Input (Data, Variable, Relative)
        0xC0,                           // End Collection
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x02,                     // Usage (Mouse)
        0xA1, 0x01,                     // Collection (Application)
        0x85, 0x02,                     //   REPORT_ID (2)
        0x05, 0x01,                     //   Usage Page (Generic Desktop)
        0x09, 0x30,                     //   Usage (X)
        0x09, 0x31,                     //   Usage (Y)
        0x15, 0x00,                     //   Logical Minimum (0)
        0x26, 0xFF, 0x7F,               //   Logical Maximum (32767)
        0x75, 0x10,                     //   Report Size (16),
        0x95, 0x02,                     //   Report Count (2),
        0x81, 0x02,                     //   Input (Data, Variable, Absolute)
        0xC0                            // End Collection
};
#endif
 
Hello All

Paul:
Thanks for your reply. I already noted that you are the guru here.
You are GREAT !!
It works.
With your change now Mouse.moveTo() works perfectly even on buggy Linux.
But Mouse.move() does not work anymore.
But this does not matter because move() can fully be replaced with moveTo().

THANKS A LOT !
Where do you find such a great support (over night) nowadays as on PJRC ?

linuxgeek:
I know xdotool. But I cannot use it because I have to control a Linux computer where I have no permission to access the operating system. For that reason I have to use the Teensy.

defragster:
Your question has nothing to do. Apart from that I posted an answer in that thread.
 
Last edited:
Just a question:

With the changes I made recently I noticed that on Windows now I see a yellow exclamation mark beside one of the mouse devices in Control Panel.

Question 1:
Why are there two mouse devices appearing in Control Panel ? (There were already two before these changes)

Question 2:
Why does Windows now tell me that one of the mice cannot start.

The device
HID\VID_16C0&PID_0482&MI_01&COL02\7&D4CF14F&0&0001
is showing normally.

But the device
HID\VID_16C0&PID_0482&MI_01&COL01\7&D4CF14F&0&0000
cannot start.


This does not matter, because it works.
I just want to know.
 
Glad that lets Mouse.moveTo() work on Linux. Of course it breaks Mouse.move(), since the 2 relative position report fields are changed to constant.

I've added a link on the mouse page. Hopefully anyone else needing Mouse.moveTo() on Linux will at least be able to apply this hack to get it working.

Obviously Windows doesn't like something about the report descriptor. I don't know the inner details of Windows well enough to say how to get more info about why, if that's even possible. On Linux, usually the kernel prints terse messages into /var/log/syslog when things aren't as it expected. Maybe Windows gives similar info somewhere? I really do not know?

As a blind guess, maybe Windows is still parsing on the button usage page, and maybe it doesn't like 8 bit fields? You could try changing the 3 new lines to this:

Code:
        0x75, 0x01,                     //   Report Size (1)
        0x95, 0x10,                     //   Report Count (16)
        0x81, 0x03,                     //   Input (Constant)   <---- ignore the X & Y relative, for Linux X11 limitation

Also, you should be careful to never send Mouse.move() to Windows. It will put non-zero numbers into those 2 fields. Windows will expect them to be zero (or not to change), since the report descriptor says they're constant. Maybe that's what's causing Windows to print the yellow exclamation mark? It's a shame Windows doesn't easily show real info about *why* it prints that exclamation mark.

It's also possible Windows simply can't accept a mouse report that lacks X & Y usage fields.
 
Last edited:
Hello Paul

No. There is no log file in Windows.
I suppose that the Microsoft programmers have their own logging system in the Debug version of Windows.
But in the Release version this is all turned off.
I do the same in my software because logging makes it all run more slowly.
To write to a logfile you must use a lock to make the logging code thread safe and this makes it slower.
Apart from that I suppose that Microsoft does not want to show Windows internals.

But you are right: The error messages like "The device could not start" are really a shame.
There should be the reason what is wrong with the device.

After changing the two lines that you have posted above nothing has changed.

But there is still one question unanswered:
Why do there appear 2 mouse devices in control panel ?
One cannot start but the other one is working.
So what is the one, that cannot start, good for ?
______________________________________

> I've added a link on the mouse page

I cannot find the link on the mouse page
https://www.pjrc.com/teensy/td_mouse.html


Elmü
 
Last edited:
Ohhh Shit.

After testing all on Linux, where it works fine now, I went back to test on Windows.
And with your changes now on Windows the wheel and the clicks do not work anymore.
The mouse moves, but nothing more functions.

It seems that one mouse in control panel is only for movement and the other for wheel and clicks.

Do you think that there is a way to modifiy the USB descriptor in a way that it works on both: Windows and Linux ?
 
Last edited:
But there is still one question unanswered:
Why do there appear 2 mouse devices in control panel ?

If you read the report descriptor, you'll see it's 2 different reports, each with their own ID.

Looks like Microsoft sometimes shows that as 2 different devices?


So what is the one, that cannot start, good for ?

Originally Teensyduino's USB mouse code only had the regular relative move usage fields, which are controlled by Mouse.move().

But since Teensy can't see your screen to know where the pointer is located, Mouse.move() is only useful in some limited situations. I had thought nobody ever used it, but that turned out to be a wrong assumption. Some people do indeed use Mouse.move() in real projects, especially to make custom controllers with certain games.

In an attempt to make something more useful, in Teensyduino 1.17 I redesigned the USB mouse code to use absolute positioning. Mouse.moveTo() and Mouse.screenSize() were added. Mouse.move() was designed to send changes in absolute position.

It turned out games and some software was incompatible with absolute positioning. So in Teensyduino 1.19, I changed the Mouse design to use 2 reports. One has all the traditional mouse stuff, and the other has absolute positioning. It works great on Windows and Mac, and on Linux everything works except moveTo(). The Linux problem is a limitation in X11 that appears to be impossible to work around.

The hack I posted in #2 simply removes the X and Y from the traditional report ID. I guessed that would make X11 happen on Linux, based on those log messages (if anyone from Microsoft ever reads this message.... why can't you guys give useful logging?)

But Windows doesn't seem to like the hack. Even though it's HID compliant to seen pretty much any combination of HID usage fields, my guess is Microsoft's driver simply gives up if the X and Y fields aren't present. That's actually not such an unreasonable thing to do.

You could try rearranging the report descriptor AND the mouse code to send the wheel and buttons in the other report ID.

Or you could look at the code that was in Teensyduino 1.17 & 1.18. It has only a single report, without any relative movement (which turned out to be incompatible with games and some Windows software). The old versions still on the server, just without links to the files. Simply right click on the download link, copy the URL to your clipboard, and then paste it into the address bar of your browser. Edit the 3 digit version number before you press Enter to download the file.

It seems there's no combination that allows perfect compatibility with everything. :( I believe the Mouse support we have now in 1.19 to 1.23 is probably the best trade-off, where everything works except Mouse.moveTo() on X11. Even though I personally use Linux, it is the smallest user base. It's also the one system most likely to actually improve, and it's the one system that's rejecting what seems like the best way to do this. The descriptors we're using are, as I understand, fully HID compliant.... so maybe there's hope to someday convince the X11 devs to fix their software?
 
Last edited:
Thanks for your large answer.

Sadly I'm not an expert of USB internals and your code doesn't say me anything.
I copied your snippet, but I don't understand these cryptic numbers.
And I don't have the time to become an USB expert now.
I have to finish this project, then other work is waiting on my stack.

Just a question:
Wouldn't it be the perfect solution to replace the 2 mouse reports with
1.) one real HID mouse report that implements only move()
2.) one real HID touch screen report that implements only moveTo(), and which would appear in Control Panel as an additional touch screen device rather than a mouse?

In my humble opinion that would work on ALL operating systems, or not ?

What happens if you connect a REAL touchscreen (for example of a tablet) to Windows, Linux, Mac ?
I suppose that it works everywhere with the correct driver.

Or does X11 also have problems with touch screens ?

Elmü
 
Last edited:
What happens if you connect a REAL touchscreen (for example of a tablet) to Windows, Linux, Mac ?
I suppose that it works everywhere with the correct driver.

Or does X11 also have problems with touch screens ?

Good question. Maybe you could try testing with these real devices and report your results?

If you do find combinations of absolute and relative position devices that work, please capture as much info as possible. Run "lsusb -v" as root. Use the special "unbind" step described here, so you can capture the hid report descriptors.
 
I cannot help with a Linux with real touch screen.

But I actually have seen Linux working with touch screen.

I think the touch screen HID interface will be the solution.

Currently we have:
1.) A mouse record that works only on Linux,
2.) Another mouse record that works only on Windows
3.) A workaround for MAC (passing true to Mouse.screenSize())

I think that this situation is not desirable.
When I go to the computer shop and buy a mouse it works everywhere: On Linux, Windows, MAC.
I don't have to configure my mouse to work on Linux or on Windows.
So should the Teensy do also.
HID is a standardized protocol.
It should work everywhere without workarounds.

I think the touch screen will be the correct decision to go and remove all the current problems.
 
Last edited:
that unbind method didn't work for me. I can see the file, but I can't write to it.

I can tell that it is using "usb-multitouch" driver.
 
Ok, I'm guessing I read it wrong.

Here's the text output. Hopefully it's useful.

Code:
Bus 001 Device 003: ID 04f3:0191 Elan Microelectronics Corp. 
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x04f3 Elan Microelectronics Corp.
  idProduct          0x0191 
  bcdDevice           10.11
  iManufacturer           4 ELAN
  iProduct               14 Touchscreen
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           41
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xe0
      Self Powered
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength     925
          Report Descriptor: (length is 925)
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x04 ] 4
                            Touch Screen
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Global): Report ID, data= [ 0x01 ] 1
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x22 ] 34
                            Finger
            Item(Main  ): Collection, data= [ 0x02 ] 2
                            Logical
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x42 ] 66
                            Tip Switch
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x01 ] 1
            Item(Main  ): Input, data= [ 0x03 ] 3
                            Constant Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Size, data= [ 0x06 ] 6
            Item(Local ): Usage, data= [ 0x51 ] 81
                            Contact ID
            Item(Global): Logical Maximum, data= [ 0x3f ] 63
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Local ): Usage, data= [ 0x48 ] 72
                            Width
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x49 ] 73
                            Height
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Usage Page, data= [ 0x01 ] 1
                            Generic Desktop Controls
            Item(Global): Logical Maximum, data= [ 0xc0 0x0c ] 3264
            Item(Global): Report Size, data= [ 0x10 ] 16
            Item(Global): Unit Exponent, data= [ 0x0f ] 15
                            Unit Exponent: 15
            Item(Global): Unit, data= [ 0x11 ] 17
                            System: SI Linear, Unit: Centimeter
            Item(Local ): Usage, data= [ 0x30 ] 48
                            Direction-X
            Item(Global): Physical Minimum, data= [ 0x00 ] 0
            Item(Global): Physical Maximum, data= [ 0x00 0x01 ] 256
            Item(Global): Report Count, data= [ 0x02 ] 2
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Logical Maximum, data= [ 0x40 0x07 ] 1856
            Item(Global): Physical Maximum, data= [ 0x90 0x00 ] 144
            Item(Local ): Usage, data= [ 0x31 ] 49
                            Direction-Y
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x0d ] 13
                            Digitizer
            Item(Local ): Usage, data= [ 0x56 ] 86
                            (null)
            Item(Global): Unit Exponent, data= [ 0x00 ] 0
                            Unit Exponent: 0
            Item(Global): Unit, data= [ 0x00 ] 0
                            System: None, Unit: (None)
            Item(Global): Logical Maximum, data= [ 0xff 0xff 0xff 0x7f ] 2147483647
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x20 ] 32
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Local ): Usage, data= [ 0x54 ] 84
                            Contact Count
            Item(Global): Logical Maximum, data= [ 0x7f ] 127
            Item(Global): Report Count, data= [ 0x01 ] 1
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x0a ] 10
            Item(Local ): Usage, data= [ 0x55 ] 85
                            Maximum Contact Number
            Item(Global): Logical Maximum, data= [ 0x0a ] 10
            Item(Main  ): Feature, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Global): Report ID, data= [ 0x44 ] 68
            Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
                            (null)
            Item(Local ): Usage, data= [ 0xc5 ] 197
                            (null)
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x00 0x01 ] 256
            Item(Main  ): Feature, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0xff 0x01 ] 511
                            (null)
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Global): Report ID, data= [ 0x02 ] 2
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x40 ] 64
            Item(Local ): Usage, data= [ 0x00 ] 0
                            (null)
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x00 0xff ] 65280
                            (null)
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Global): Report ID, data= [ 0x03 ] 3
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x1f ] 31
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Output, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
            Item(Global): Usage Page, data= [ 0x01 0xff ] 65281
                            (null)
            Item(Local ): Usage, data= [ 0x01 ] 1
                            (null)
            Item(Main  ): Collection, data= [ 0x01 ] 1
                            Application
            Item(Global): Report ID, data= [ 0x04 ] 4
            Item(Global): Logical Minimum, data= [ 0x00 ] 0
            Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
            Item(Global): Report Size, data= [ 0x08 ] 8
            Item(Global): Report Count, data= [ 0x13 ] 19
            Item(Local ): Usage, data= [ 0x00 ] 0
                            (null)
            Item(Main  ): Input, data= [ 0x02 ] 2
                            Data Variable Absolute No_Wrap Linear
                            Preferred_State No_Null_Position Non_Volatile Bitfield
            Item(Main  ): End Collection, data=none
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               1
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0020  1x 32 bytes
        bInterval              10
Device Status:     0x0001
  Self Powered
 

Attachments

  • usbhid.txt
    43.5 KB · Views: 288
HID is a standardized protocol.
It should work everywhere without workarounds.

Tell that to Apple, who arbitrarily decide to ignore a margin and use only the center of the HID coordinates.

And tell that to the X11 devs for Linux, who have a known limitation where they don't accept both relative and absolute coordinates, despite Teensy properly following the HID protocol.
 
I believe this X11 limitation is about to disappear. The X.org input stack is transitioning to libinput (initially developed for Wayland), and Fedora should be using libinput in Fedora 22.

I just tested the sample code from the other topic after enabling libinput myself, and indeed, both absolute and relative moves worked. To be sure I also tested it with the current X.org evdev driver, and absolute moves do not work there.

If you want to read more about this:
- https://fedoraproject.org/wiki/Changes/LibinputForXorg
- http://who-t.blogspot.fr/2015/01/xf86-input-libinput-compatibility-with.html
 
Tell that to Apple, who arbitrarily decide to ignore a margin and use only the center of the HID coordinates.

And tell that to the X11 devs for Linux, who have a known limitation where they don't accept both relative and absolute coordinates, despite Teensy properly following the HID protocol.

The point is that nobody sends absolute coordinates with a mouse.
Mice send relative coordinates.
Neither Apple nor X11 folks have ever tested that.
For that reason it is not working.

On the other hand a touchscreen is designed for absolute coordinates.
 
Hello Paul

You did not respond anymore.

I tell you that today I tested the Teensy with the modified mouse report for Linux on another computer and it behaves completely different.

Here on my SUSE Linux all works fine after changing the mouse report that you have posted above.
But on the other computer the mouse is about 10 centimeters beside the correct position.
Additionally the mouse position depends on the movement speed.
Sometimes it even jumps out of the screen.

I have no idea what is different on that computer.
The strange thing is that it is also a SUSE Linux !
But I already noted in another programming project that Linux behaves different on each computer.

Summary:
You will never have any success with absolute coordinates sent via a mouse descriptor.
Now we have one workaround for MAC and another workaround for Linux and it is still not working.

So my question is again:
Do you have any plans to implement a fully functional moveTo() command ?
The only possible way to get this working on all operating systems is with a HID touch screen device.
It will never work with another modification of the mouse report.

Please answer me soon, because for my company this is very urgent.
We need this working.
When you say you will not do that we have to search for an alternative to Teensy.
 
Last edited:
Hello Paul

You did not respond anymore.

I was not aware of anything else needing more response from me.

So my question is again:
Do you have any plans to implement a fully functional moveTo() command ?

My position is Teensy is implementing HID protocol properly and the problems on Linux are due to a known limitation in X11.

The only possible way to get this working on all operating systems is with a HID touch screen device.
It will never work with another modification of the mouse report.

Did you try using the code from Teensyduino 1.17 or 1.18, as I suggested in reply #11.

That should make Teensy appear as a touch screen only, without traditional relative-coordinate mouse descriptors. It seems to be exactly what you're asking.

EDIT: but do be aware, the HID descriptors from 1.17 or 1.18 are known to be incompatible with certain programs on Windows, especially games, which can't work with touch screens or other absolute coordinate input devices. That's the reason Teensyduino was changed to the relative+absolute approach (which works with everything except X11, and even on X11, everything but moveTo works).

Please answer me soon, because for my company this is very urgent.
We need this working.
When you say you will not do that we have to search an alternative to Teensy.

Again, the Linux problem is a known issue with X11. I am confident you will never find ANY device with both absolute and relative position HID reports that works with X11.

But if you wish to abandon using Teensy because I can not offer a comprehensive solution that is perfect on all 3 platforms, even after I've tried to help you, can you at least post a followup here when/if you find something else that meets all these requirements? I would very much like to hear if any product manages to do this!
 
Last edited:
I was not aware of anything else needing more response from me.

Mmmmh!
Now you are really surprising me.
If I remember well you asked for some data from a real touch screen.
And linuxgeek has sent you some data.
Wouldn't it be interesting to let us know if this data was useful for you ?
I suppose that you asked for this data because you intended to do something with it ?
Or am I misinterpreting something ?


My position is Teensy is implementing HID protocol properly and the problems on Linux are due to a known limitation in X11.

I'am completely on your side.
But we both know this since the first day of this thread.
Linux does not only have this bug. There are much more bugs in Linux.
And Apple has another bug.


But if we wait until X11 changes there may pass 10 years into the land, or more.
But I need a solution now.
I would change the code in Teensy on my own if I knew more about the HID protocol.
I saw the code that writes the coordinates into an USB packet in usb_mouse_position().
It's a little weird but not really complicated.
I suppose that changing this code so that it writes the same data into a touch screen HID packet instead of a mouse HID packet must be quite easy for someone who is expert in this USB stuff.



I am confident you will never find ANY device with both absolute and relative position HID reports that works with X11.

No.
And I do not want that, neither.
Not in the same mouse device.
But why not in a mouse device separated from another real touch screen device ?


Teensy currently appears a SIX HID devices in my control panel.
Two of them are mouse devices.

1.) One mouse device for click, wheel and move() relative
2.) Another mouse device for moveTo() absolute

My idea is to replace mouse device 2.) with a HID touch screen device that for sure will work on X11 because I have seen a touch screen working on Linux and linuxgeek also has seen Linux work with a real touch screen.


By the way:
The Linux computer that is causing my headaches works with a real touch screen correctly!
It has only problems with Teensy's coordinates.



I would very much like to hear if any product manages to do this!

Of course!
There are millions of real HID touch screens out there that work seamlessly.
And they work not only on Windows.

You search in Google and you find a lot.
Have a look at this one:
http://shop-on-line.tvielectronics.com/product_info.php?products_id=209
This chip fully implements a USB HID touch screen.
It comes with a calibration guide for Windows and Ubuntu. (See tab "Documents")
So why can Teensy not do the same ?


And when Teensy already can implement

1.) a flight simulator
2.) a joystick
3.) a serial device
4.) a raw device
5.) a keyboard device
6.) a relative mouse device
7.) an absolute mouse device

why should Teensy not also be able to implement additionally a touch screen device ??
Teensy could even implement a video camera or a storage device !


OK.
If you say that you are not interested in that solution, you will only lose some potential clients like for example my company.
If you don't care, this is your decision.

But I like Teensy and would like to use it.
The HID keyboards works great.

It is only a little modification of software.
For a HID freak not such a big thing.
 
Last edited:
There are millions of real HID touch screens out there that work seamlessly.
And they work not only on Windows.

Yes, but they do not have relative movement like Mouse.move(), which is needed for some Windows software, especially games.

Again, did you try the absolute-only code in the old versions?
 
Status
Not open for further replies.
Back
Top