T-vK / ESP32-BLE-Mouse

Bluetooth LE Mouse library for the ESP32 (Arduino IDE compatible)
733 stars 142 forks source link

Is it possible to use the lib as ble Touchscreen, to send absolute coordinates to a device? #5

Open jrsmile opened 4 years ago

jrsmile commented 4 years ago

Hi, is it possible to use the lib as ble Touchscreen, to send absolute coordinates to a device? if so how would i do this?

regards, J

T-vK commented 4 years ago

Interesting idea. However, that's not possible with this library. But it would be great to see someone fork this repo and create ESP32-BLE-Touchscreen or something like that. It's probably not even that difficult. Change the hid descriptor and adjust the methods and you should be good to go. But I think the input device of touch screens probably don't actually know what resolution the output device is running at. So they probably use percentages rather than pixel units.

Cubyte commented 4 years ago

Is it possible to have zoom in and zoom out?

T-vK commented 4 years ago

You can only do mouse movement, clicks and scrolling. If your target applications allows zooming by scrolling then it would work, otherwise no.

xcarcelle commented 4 years ago

Very interesting idea, currently looking at adding absolute coordinates to ESP32-BLE to behave like a touch-screen. Looking at other absolute coordinates HID Mouse implementation :

T-vK commented 4 years ago

I think even with resetPosition, you'd still have to know the screen resolution. If it was possible then I'd expect there to already be an implementation for the USB Mouse library.

xcarcelle commented 4 years ago

Yes totally one needs to know the screen resolution to adjust the moveTo formula. It seems that several Arduino absolute Mouse library exist based on specific HID_REPORT_DESCRIPTOR ? @jrsmile : did you implement something to get an absolute moveTo function ?

xcarcelle commented 4 years ago

@T-vK : playing with the move(x, y) function of BleMouse class, I observed that sometimes I have some glitches. If move(0, 127), where 127 is the max for the x or y values, the mouse jumps from 127px but sometimes only 84px. I am wondering how I could debug this glitch in the actual pixel jump ?

T-vK commented 4 years ago

I guess you could add some Serial.prints to the underlying ble functions if you really want to go through the hassle. But first you should try this against different devices/operating systems and also play around with OS level mouse settings, especially acceleration to pin the problem down.

jrsmile commented 4 years ago

have a look here, this helped me a lot: https://www.codeproject.com/Articles/1001891/A-USB-HID-Keyboard-Mouse-Touchscreen-emulator-with

igrek-xavier commented 4 years ago

Thanks for this great project and your replies. @jrsmile : thanks for the hints link, very complete and mature. I played with it using a teensy3.2 and the moveTo function is working properly as a touchscreen emulator for absolute moves. Did you port this work on the esp32 board ? @T-vK : when using blemouse.move function I observed that I need to place a delay(50) between the moves other the moves got disturbed (the move does not reach the target coordinates). Do you have an idea for that ? Regards.

jrsmile commented 4 years ago

@igrek-xavier : unfortunately Not i use it myself on a teensy But my knowledge of the esp32 is to limited to Port it.

not-tor-app-ci commented 4 years ago

Would anyone be willing to get started on this in another repo?

xcarcelle commented 4 years ago

@T-vK : I have a question related to the void BleMouse::buttons(uint8_t b) function You need to call the BleMouse::move function (https://github.com/T-vK/ESP32-BLE-Mouse/blob/master/BleMouse.cpp#L111) which can induces on some OS (iOS for instance) to have the page (for instance HTML full-screen browser) to move with the "press". Is there a way to call directly the notification of a MOUSE_LEFT press/release ? Much regards, Xavier.

consciouspnm commented 4 years ago

@xcarcelle Did you get anywhere with absolute coordinates?

xcarcelle commented 4 years ago

@consciouspnm @not-tor-app-ci : I have not reached a real absolute coordinates move function. At this point I am wondering if we can use a touchscreen HID Descriptor over BLE/GATT with this library and have the behaviour we observed with USB HID. Do you know if the OS is able to send back information from the screen position over BLE/GATT HID to implement the touch HID Descriptor ? @not-tor-app-ci : maybe you are right we could start another repo on this specific topic. Regards.

xcarcelle commented 4 years ago

@xcarcelle Did you get anywhere with absolute coordinates?

@consciouspnm @T-vK : for absolute mouse move I wonder if we have to modifiy the m[5] array (https://github.com/T-vK/ESP32-BLE-Mouse/blob/138f67a54fe532338cc21aaf2007d379f1088223/BleMouse.cpp#L95) notified over ble to have uint16_t for (x, y) in place of wheel and hWheel ? As we want to have the logical minimum/maximum on 2bytes in the HID Descriptor for (x, y), we should adapt the size of (x, y) reported in the data packet sent to the BLE host ? What do you think ?

consciouspnm commented 4 years ago

I noticed that on IOS, with the current code, if you start at a consistent place, like the top left corner, a move will always end up at the same place so a move(50,50,0,0) goes to the same spot and a move(127,127,0,0) goes further. If the limit was increased to two bytes you should be able to get to the bottom corner. It won't be generic and will need calibrating per device but it's nearly absolute movement.

xcarcelle commented 4 years ago

@consciouspnm : thanks for your update. I have done some tests using this HID Report :

    USAGE_PAGE(1),      0x01,         // Generic Desktop
    USAGE(1),           0x02,         // Mouse
    COLLECTION(1),      0x01,         // Application
    USAGE(1),           0x01,         //  Pointer
    COLLECTION(1),      0x00,         //  Physical
    USAGE_PAGE(1),      0x09,         //   Buttons
    USAGE_MINIMUM(1),   0x01,
    USAGE_MAXIMUM(1),   0x03,
    LOGICAL_MINIMUM(1), 0x00,
    LOGICAL_MAXIMUM(1), 0x01,
    REPORT_COUNT(1),    0x03,         //   3 bits (Buttons)
    REPORT_SIZE(1),     0x01,
    INPUT(1),           0x02,         //   Data, Variable, Absolute
    REPORT_COUNT(1),    0x01,         //   5 bits (Padding)
    REPORT_SIZE(1),     0x05,
    INPUT(1),           0x01,         //   Constant
    USAGE_PAGE(1),      0x01,         //   Generic Desktop
    USAGE(1),           0x30,         //   X
    USAGE(1),           0x31,         //   Y
    // USAGE(1),           0x38,         //   Wheel
    PHYSICAL_MINIMUM(2), 0x00, 0x00,         //  0 
    PHYSICAL_MAXIMUM(2), 0x10, 0x27,         //  10000 
    LOGICAL_MINIMUM(2), 0x00, 0x00,         //   0
    LOGICAL_MAXIMUM(2), 0x10, 0x27,         //   10000
    UNIT(2), 0x00, 0x00,         //  No unit 
    REPORT_SIZE(1),     0x10,         //   Three bytes
    REPORT_COUNT(1),    0x02,
    INPUT(1),           0x06,         //   Data, Variable, Relative
    END_COLLECTION(0),
    END_COLLECTION(0),`

and extending the move function to have uint16_t for (x, y) passed in the report. This allowed relative larger movement on the screen (for instance move(5000, 0) will move to half of the screen). Android ok but ios14 not detecting the HID Report. Also this is still a relative movement and when enabling absolute (INPUT = 0x2) it is neither detected by Android nor by iOS. If someone have an idea what could be the issue with enabling absolute in the HID Report as the large movement issue seems feasible with this HID Report. Thanks.

Nesh108 commented 4 years ago

In a similar position, I tried using many different HDI descriptors but couldn't get it to work. Not even with Android.

Any thoughts @T-vK ?

T-vK commented 4 years ago

Why not stick to the standard descriptor and call move multiple times to get the pointer to the desired position?

Nesh108 commented 4 years ago

That's the worst case scenario (at least for me), if you move the pointer X times to get to the desired position, you will see it blinking on the screen while it moves. Also, that means having to keep track of the last position of the cursor each time, instead of just telling the cursor to go to <X,Y>.

Less than ideal and makes things really complicated :(

I wonder why the descriptor for absolute positioning is so much more complex.

T-vK commented 4 years ago

Well mice usually move pixel by pixel so it just doesn't matter if you can only move 127 units at a time and is thus probably not tested by OS developers. Hacking the mouse descriptor seems like the wrong approach to begin with. I'd try to start with a touch screen descriptor.

Nesh108 commented 4 years ago

I tried with a digitizer and a touch screen descriptor but couldn't get that to work either. I assumed that the main differences are the Descriptor and what you send in the message, right?

Btw, I totally agree that mice don't normally use absolute coordinates but, out there, the "absmouse" repository for USB HID is available and (at least myself) people might be looking for something similar but for ESP32-BLE.

T-vK commented 4 years ago

Fpor most use cases I would expect that people don't mind if move was called multiple times. I doubt the "blinking" would be very noticable if at all. And keeping track of the position is not necessary if you go to 0,0 before every move.

Sure I guess the main differences are the descriptor and the messages. I haven't really looked into it though.

Nesh108 commented 4 years ago

Well, depends for the use though. An absolute "mouse" would definitely be helpful in a lot of cases, definitely decreasing headaches.

Anyway, now I'm trying to find the perfect Descriptor and message for mobile devices. No luck for now.

T-vK commented 4 years ago

I have an external USB touchscreen that works fine on Linux, Windows, Mac OS and Android. (Never tried it on iOS though.) I could try to extract the descriptor when I find some time. Compatibility-wise I'd imagine you'd be much better off with that over some homebrew mouse descriptor.

xcarcelle commented 4 years ago

@T-vK : cool can you tell us the model of the usb touchscreen ? do you have the lsusb verbose output ? I believe the descriptor is quite long.

Nesh108 commented 4 years ago

@T-vK that would be extremely useful! Keep me updated :)

T-vK commented 4 years ago

It's a Wimaxit M1560CTV2. I don't have the lsusb verbose output right now. I'll see if I can find some time this week to dump the descriptor and lsusb and share it.

xcarcelle commented 4 years ago

Thanks ! will check if any comments on ios support or HID already dumped

T-vK commented 4 years ago

I think officially they say it doesn't support Mac OS and iOS. But I've seen it work on a macbook, so that definitely works. iOS would be difficult to even test because there is no USB port on iPhones/iPads... It might work with an adapter though, but I have no idea and don't own any Apple devices.

consciouspnm commented 4 years ago

Apple sell this: https://www.apple.com/uk/shop/product/MD821ZM/A/lightning-to-usb-camera-adapter which various articles say you can use with a USB mouse.

consciouspnm commented 4 years ago

This video has it working over Bluetooth on IOS13, so it must now be supported: https://www.youtube.com/watch?v=CGYNBJojfTM

And as far as I can tell, their device is just an interface to the touchscreen, (though if it's usb, it should be able to be plugged in directly) so the Bluetooth bit must be standard if we can get the right descriptor.

xcarcelle commented 4 years ago

But in this video there is a BLE dongle from a company specialized in usb-to-ble interface which tricks the direct connexion. We are looking for a direct BLE between the esp32 stack and the central BLE device. However if someone if someone has tested this solution with ios it could be interesting to have some feedbacks or some BLE HID packets from the handshake.

consciouspnm commented 4 years ago

If you watch the video, previous versions of their device only worked with a jailbroken phone as they had to install drivers, IOS13 and above seems to have direct support for the touchscreen via Bluetooth. They have plugged a standard Bluetooth dongle into their device and it works, which implies the esp32 can emulate it. Their device is taking touchscreen signals via USB and sending them out via Bluetooth, so with the correct descriptor, we should be able to do the same.

T-vK commented 4 years ago

The touchscreen show up as 3 different devices in lsusb:

Bus 003 Device 011: ID 1d5c:7102 Fresco Logic 
Bus 003 Device 010: ID 222a:0001
Bus 003 Device 009: ID 1a40:0101 Terminus Technology Inc. Hub

Here is the verbose lsusb for those devices: lsusb-1d5c_7102.txt lsusb-222a_0001.txt lsusb-1a40_0101.txt

I haven't been able to get usbhid-dump running on my system. So I can't provide the report descriptor(s) yet.

T-vK commented 4 years ago

Finally managed to build usbhid-dump and hidrd-convert.

For Bus 003 Device 011: ID 1d5c:7102 Fresco Logic and Bus 003 Device 009: ID 1a40:0101 Terminus Technology Inc. Hub I get No matching HID interfaces.

For Bus 003 Device 010: ID 222a:0001 IO get the following: (The first one is in hex format the second one is converted to spec format and the third one is converted to code format.)

sudo usbhid-dump --model=222a:0001:

003:010:000:DESCRIPTOR         1602504483.137758
 05 0D 09 04 A1 01 85 04 09 22 A1 02 05 0D 95 01
 75 06 09 51 15 00 25 3F 81 02 09 42 25 01 75 01
 95 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0E
 65 11 09 30 26 00 40 35 00 46 15 0C 81 42 09 31
 26 00 40 46 CB 06 81 42 C0 05 0D 09 22 A1 02 05
 0D 95 01 75 06 09 51 15 00 25 3F 81 02 09 42 25
 01 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75
 10 55 0E 65 11 09 30 26 00 40 35 00 46 15 0C 81
 42 09 31 26 00 40 46 CB 06 81 42 C0 05 0D 09 22
 A1 02 05 0D 95 01 75 06 09 51 15 00 25 3F 81 02
 09 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03
 05 01 75 10 55 0E 65 11 09 30 26 00 40 35 00 46
 15 0C 81 42 09 31 26 00 40 46 CB 06 81 42 C0 05
 0D 09 22 A1 02 05 0D 95 01 75 06 09 51 15 00 25
 3F 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95
 01 81 03 05 01 75 10 55 0E 65 11 09 30 26 00 40
 35 00 46 15 0C 81 42 09 31 26 00 40 46 CB 06 81
 42 C0 05 0D 09 22 A1 02 05 0D 95 01 75 06 09 51
 15 00 25 3F 81 02 09 42 25 01 75 01 95 01 81 02
 75 01 95 01 81 03 05 01 75 10 55 0E 65 11 09 30
 26 00 40 35 00 46 15 0C 81 42 09 31 26 00 40 46
 CB 06 81 42 C0 05 0D 09 22 A1 02 05 0D 95 01 75
 06 09 51 15 00 25 3F 81 02 09 42 25 01 75 01 95
 01 81 02 75 01 95 01 81 03 05 01 75 10 55 0E 65
 11 09 30 26 00 40 35 00 46 15 0C 81 42 09 31 26
 00 40 46 CB 06 81 42 C0 05 0D 09 22 A1 02 05 0D
 95 01 75 06 09 51 15 00 25 3F 81 02 09 42 25 01
 75 01 95 01 81 02 75 01 95 01 81 03 05 01 75 10
 55 0E 65 11 09 30 26 00 40 35 00 46 15 0C 81 42
 09 31 26 00 40 46 CB 06 81 42 C0 05 0D 09 22 A1
 02 05 0D 95 01 75 06 09 51 15 00 25 3F 81 02 09
 42 25 01 75 01 95 01 81 02 75 01 95 01 81 03 05
 01 75 10 55 0E 65 11 09 30 26 00 40 35 00 46 15
 0C 81 42 09 31 26 00 40 46 CB 06 81 42 C0 05 0D
 09 22 A1 02 05 0D 95 01 75 06 09 51 15 00 25 3F
 81 02 09 42 25 01 75 01 95 01 81 02 75 01 95 01
 81 03 05 01 75 10 55 0E 65 11 09 30 26 00 40 35
 00 46 15 0C 81 42 09 31 26 00 40 46 CB 06 81 42
 C0 05 0D 09 22 A1 02 05 0D 95 01 75 06 09 51 15
 00 25 3F 81 02 09 42 25 01 75 01 95 01 81 02 75
 01 95 01 81 03 05 01 75 10 55 0E 65 11 09 30 26
 00 40 35 00 46 15 0C 81 42 09 31 26 00 40 46 CB
 06 81 42 C0 05 0D 09 56 55 00 65 00 27 FF FF FF
 7F 95 01 75 20 81 02 09 54 25 7F 95 01 75 08 81
 02 75 08 95 08 81 03 85 02 09 55 25 0A 75 08 95
 01 B1 02 06 00 FF 09 C5 85 06 15 00 26 FF 00 75
 08 96 00 01 B1 02 C0 06 00 FF 09 01 A1 01 09 01
 85 03 15 00 26 FF 00 75 08 95 3F 81 02 06 00 FF
 09 01 15 00 26 FF 00 75 08 95 3F 91 02 C0

sudo usbhid-dump --model=222a:0001 | grep -v : | xxd -r -p | hidrd-convert -o spec:

Usage Page (Digitizer),                 ; Digitizer (0Dh)
Usage (Touchscreen),                    ; Touch screen (04h, application collection)
Collection (Application),
    Report ID (4),
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (Finger),                     ; Finger (22h, logical collection)
    Collection (Logical),
        Usage Page (Digitizer),         ; Digitizer (0Dh)
        Report Count (1),
        Report Size (6),
        Usage (51h),
        Logical Minimum (0),
        Logical Maximum (63),
        Input (Variable),
        Usage (Tip Switch),             ; Tip switch (42h, momentary control)
        Logical Maximum (1),
        Report Size (1),
        Report Count (1),
        Input (Variable),
        Report Size (1),
        Report Count (1),
        Input (Constant, Variable),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Report Size (16),
        Unit Exponent (14),
        Unit (Centimeter),
        Usage (X),                      ; X (30h, dynamic value)
        Logical Maximum (16384),
        Physical Minimum (0),
        Physical Maximum (3093),
        Input (Variable, Null State),
        Usage (Y),                      ; Y (31h, dynamic value)
        Logical Maximum (16384),
        Physical Maximum (1739),
        Input (Variable, Null State),
    End Collection,
    Usage Page (Digitizer),             ; Digitizer (0Dh)
    Usage (56h),
    Unit Exponent (0),
    Unit,
    Logical Maximum (2147483647),
    Report Count (1),
    Report Size (32),
    Input (Variable),
    Usage (54h),
    Logical Maximum (127),
    Report Count (1),
    Report Size (8),
    Input (Variable),
    Report Size (8),
    Report Count (8),
    Input (Constant, Variable),
    Report ID (2),
    Usage (55h),
    Logical Maximum (10),
    Report Size (8),
    Report Count (1),
    Feature (Variable),
    Usage Page (FF00h),                 ; FF00h, vendor-defined
    Usage (C5h),
    Report ID (6),
    Logical Minimum (0),
    Logical Maximum (255),
    Report Size (8),
    Report Count (256),
    Feature (Variable),
End Collection,
Usage Page (FF00h),                     ; FF00h, vendor-defined
Usage (01h),
Collection (Application),
    Usage (01h),
    Report ID (3),
    Logical Minimum (0),
    Logical Maximum (255),
    Report Size (8),
    Report Count (63),
    Input (Variable),
    Usage Page (FF00h),                 ; FF00h, vendor-defined
    Usage (01h),
    Logical Minimum (0),
    Logical Maximum (255),
    Report Size (8),
    Report Count (63),
    Output (Variable),
End Collection

sudo usbhid-dump --model=222a:0001 | grep -v : | xxd -r -p | hidrd-convert -o code:

0x05, 0x0D,                     /*  Usage Page (Digitizer),                 */
0x09, 0x04,                     /*  Usage (Touchscreen),                    */
0xA1, 0x01,                     /*  Collection (Application),               */
0x85, 0x04,                     /*      Report ID (4),                      */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x22,                     /*      Usage (Finger),                     */
0xA1, 0x02,                     /*      Collection (Logical),               */
0x05, 0x0D,                     /*          Usage Page (Digitizer),         */
0x95, 0x01,                     /*          Report Count (1),               */
0x75, 0x06,                     /*          Report Size (6),                */
0x09, 0x51,                     /*          Usage (51h),                    */
0x15, 0x00,                     /*          Logical Minimum (0),            */
0x25, 0x3F,                     /*          Logical Maximum (63),           */
0x81, 0x02,                     /*          Input (Variable),               */
0x09, 0x42,                     /*          Usage (Tip Switch),             */
0x25, 0x01,                     /*          Logical Maximum (1),            */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x02,                     /*          Input (Variable),               */
0x75, 0x01,                     /*          Report Size (1),                */
0x95, 0x01,                     /*          Report Count (1),               */
0x81, 0x03,                     /*          Input (Constant, Variable),     */
0x05, 0x01,                     /*          Usage Page (Desktop),           */
0x75, 0x10,                     /*          Report Size (16),               */
0x55, 0x0E,                     /*          Unit Exponent (14),             */
0x65, 0x11,                     /*          Unit (Centimeter),              */
0x09, 0x30,                     /*          Usage (X),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x35, 0x00,                     /*          Physical Minimum (0),           */
0x46, 0x15, 0x0C,               /*          Physical Maximum (3093),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0x09, 0x31,                     /*          Usage (Y),                      */
0x26, 0x00, 0x40,               /*          Logical Maximum (16384),        */
0x46, 0xCB, 0x06,               /*          Physical Maximum (1739),        */
0x81, 0x42,                     /*          Input (Variable, Null State),   */
0xC0,                           /*      End Collection,                     */
0x05, 0x0D,                     /*      Usage Page (Digitizer),             */
0x09, 0x56,                     /*      Usage (56h),                        */
0x55, 0x00,                     /*      Unit Exponent (0),                  */
0x65, 0x00,                     /*      Unit,                               */
0x27, 0xFF, 0xFF, 0xFF, 0x7F,   /*      Logical Maximum (2147483647),       */
0x95, 0x01,                     /*      Report Count (1),                   */
0x75, 0x20,                     /*      Report Size (32),                   */
0x81, 0x02,                     /*      Input (Variable),                   */
0x09, 0x54,                     /*      Usage (54h),                        */
0x25, 0x7F,                     /*      Logical Maximum (127),              */
0x95, 0x01,                     /*      Report Count (1),                   */
0x75, 0x08,                     /*      Report Size (8),                    */
0x81, 0x02,                     /*      Input (Variable),                   */
0x75, 0x08,                     /*      Report Size (8),                    */
0x95, 0x08,                     /*      Report Count (8),                   */
0x81, 0x03,                     /*      Input (Constant, Variable),         */
0x85, 0x02,                     /*      Report ID (2),                      */
0x09, 0x55,                     /*      Usage (55h),                        */
0x25, 0x0A,                     /*      Logical Maximum (10),               */
0x75, 0x08,                     /*      Report Size (8),                    */
0x95, 0x01,                     /*      Report Count (1),                   */
0xB1, 0x02,                     /*      Feature (Variable),                 */
0x06, 0x00, 0xFF,               /*      Usage Page (FF00h),                 */
0x09, 0xC5,                     /*      Usage (C5h),                        */
0x85, 0x06,                     /*      Report ID (6),                      */
0x15, 0x00,                     /*      Logical Minimum (0),                */
0x26, 0xFF, 0x00,               /*      Logical Maximum (255),              */
0x75, 0x08,                     /*      Report Size (8),                    */
0x96, 0x00, 0x01,               /*      Report Count (256),                 */
0xB1, 0x02,                     /*      Feature (Variable),                 */
0xC0,                           /*  End Collection,                         */
0x06, 0x00, 0xFF,               /*  Usage Page (FF00h),                     */
0x09, 0x01,                     /*  Usage (01h),                            */
0xA1, 0x01,                     /*  Collection (Application),               */
0x09, 0x01,                     /*      Usage (01h),                        */
0x85, 0x03,                     /*      Report ID (3),                      */
0x15, 0x00,                     /*      Logical Minimum (0),                */
0x26, 0xFF, 0x00,               /*      Logical Maximum (255),              */
0x75, 0x08,                     /*      Report Size (8),                    */
0x95, 0x3F,                     /*      Report Count (63),                  */
0x81, 0x02,                     /*      Input (Variable),                   */
0x06, 0x00, 0xFF,               /*      Usage Page (FF00h),                 */
0x09, 0x01,                     /*      Usage (01h),                        */
0x15, 0x00,                     /*      Logical Minimum (0),                */
0x26, 0xFF, 0x00,               /*      Logical Maximum (255),              */
0x75, 0x08,                     /*      Report Size (8),                    */
0x95, 0x3F,                     /*      Report Count (63),                  */
0x91, 0x02,                     /*      Output (Variable),                  */
0xC0                            /*  End Collection                          */
Nesh108 commented 4 years ago

@T-vK: that's great! (And really huge 😛 ) Next is to figure out what is important for us and how to use it.

I am currently doing some tests on iOS. I managed to get absolute coordinates working on Android, although I haven't nailed how to send coordinates that make sense (sending 0,0 doesn't seem to be going at the origin but somewhere else)

T-vK commented 4 years ago

Well a huge part of the descriptor is the 10 digitizer collections (probably to get 10 point touch). But it's just a 1:1 copy 10 times inserted in a row.

Nesh108 commented 4 years ago

Did some tests but I didn't manage to achieve anything, so I share what I have so far:

REPORT MAP (taken from @T-vK 's dump):

const uint8_t reportMapMouse[] = {
0x05, 0x0D,        // Usage Page (Digitizer)
0x09, 0x04,        // Usage (Touch Screen)
0xA1, 0x01,        // Collection (Application)
0x85, 0x04,        //   Report ID (4)
0x09, 0x22,        //   Usage (Finger)
0xA1, 0x02,        //   Collection (Logical)
0x05, 0x0D,        //     Usage Page (Digitizer)
0x95, 0x01,        //     Report Count (1)
0x75, 0x06,        //     Report Size (6)
0x09, 0x51,        //     Usage (0x51)
0x15, 0x00,        //     Logical Minimum (0)
0x25, 0x3F,        //     Logical Maximum (63)
0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x42,        //     Usage (Tip Switch)
0x25, 0x01,        //     Logical Maximum (1)
0x75, 0x01,        //     Report Size (1)
0x95, 0x01,        //     Report Count (1)
0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01,        //     Report Size (1)
0x95, 0x01,        //     Report Count (1)
0x81, 0x03,        //     Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
0x75, 0x10,        //     Report Size (16)
0x55, 0x0E,        //     Unit Exponent (-2)
0x65, 0x11,        //     Unit (System: SI Linear, Length: Centimeter)
0x09, 0x30,        //     Usage (X)
0x26, 0x00, 0x40,  //     Logical Maximum (16384)
0x35, 0x00,        //     Physical Minimum (0)
0x46, 0x15, 0x0C,  //     Physical Maximum (3093)
0x81, 0x42,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0x09, 0x31,        //     Usage (Y)
0x26, 0x00, 0x40,  //     Logical Maximum (16384)
0x46, 0xCB, 0x06,  //     Physical Maximum (1739)
0x81, 0x42,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,Null State)
0xC0,              //   End Collection
0xC0,              // End Collection

// 73 bytes
};

CODE

void moveTo(uint16_t x, uint16_t y) {
  unsigned char buffer[] = {0x04, (uint8_t) 0x00, x & 0xFF, (x & 0xFF) >> 8, y & 0xFF, (y & 0xFF) >> 8};

  inputMouse->setValue(buffer,sizeof(buffer));
  inputMouse->notify();
}

uint16_t x = 0;
uint16_t y = 0;
void loop() {
  if(connected){
        x = 0;
        y = 0;
        moveTo(x, y);
        delay(1000);

        x = 100;
        y = 250;
        moveTo(x, y);
        delay(1000);

        x = 0;
        y = 0;
        moveTo(x, y);
        delay(1000);

        x = 1000;
        y = 0;
        moveTo(x, y);
        delay(1000);

    }
  delay(50);
}
T-vK commented 4 years ago

Have you adjusted BleMouse::taskServer? There's probably some things like the the inputReport, hidInfo and setAppearance calls that would have to be changed...

Nesh108 commented 4 years ago

For that I'm using:

 BLEDevice::init("Nesh-O-Matic");
    BLEServer *pServer = BLEDevice::createServer();
    pServer->setCallbacks(new MyCallbacks());

    hid = new BLEHIDDevice(pServer);
    inputMouse = hid->inputReport(4); // <-- input REPORTID from report map

    std::string name = "Neshius Industries Corp.";
    hid->manufacturer()->setValue(name);

    hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
    hid->hidInfo(0x00,0x02);

  BLESecurity *pSecurity = new BLESecurity();

  pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND);

I never really touched those as I wasn't aware they mattered too much 🤔

T-vK commented 4 years ago

I haven't looked into it, it may or may not matter. I'd have to look at the source code of all the hid methods to know what they are responsible for. But it could also be that your report descriptor is not correct or something. You should try to get some debug information from your OS. Maybe from dmesg is you're on Linux.

And of course there is also the question what the two non hid devices are that my touchscreen is exposing and if they are important.

Nesh108 commented 4 years ago

I gave a try setting the inputReport, hidInfo, and setAppareance to pen digitizer but nothing seemed to change. 🤔

pattontim commented 4 years ago

@xcarcelle

I noticed in your repository that you have a https://github.com/xcarcelle/ESP32-BLE-Mouse/tree/master/examples/Android_AbsoluteMouse example. I was able to run it on my Android 9. Is this absolute functional and do you just use your own app to print the pointer location to confirm? Mainly I'm looking to get absolute mouse movement on Windows. I may have read the thread so far wrong but we're still waiting for something that isn't relative and works on all systems?

xcarcelle commented 4 years ago

@pattontim : this code enables correctly the mouse (and the mouse pointer is visible) in absolute mode for Android 8.x/9.x devices. However there is an issue in landscape mode as it seems that the moving zone is limited to a virtual portrait zone (in width namely). I have created an issue dedicated to this matter https://github.com/T-vK/ESP32-BLE-Mouse/issues/18 If we solve this issue then there is great solution for android abs mouse using ESP32-BLE-Mouse library. Do you guys observed this issue with Android using abs mode mouse ?

pattontim commented 4 years ago

Using the Android absolute mouse code on a windows system I get weird scaling of mouse coordinates. I can get accuracy to within 2 or so pixels by applying a formula to the coordinates sent to the moveTo method. I assume that pens work by accepting a percentage value which scales up to around 1000 but it didn't quite make it to the edge of the screen. Some weird behaviour is that when issuing a right click using my trackpad the mouse temporarily jumps back to a previous position of the mouse. I want to see what happens when I issue a pen click on Windows.

Here's the formula I used (if anyone is anxious to use the pen on windows, it works if you apply this formula). I had SCREEN_WIDTH=1920 and SCREEN_HEIGHT=1080

(X/SCREEN_WIDTH)1079 (Y/SCREEN_HEIGHT)1079

I don't really understand why 1079 does it.

Edit:

void moveTo(uint16_t x, uint16_t y) {
  unsigned char buffer[] = {4, x & 0x00FF, (x & 0xFF00) >> 8, y & 0x00FF, (y & 0xFF00) >> 8};

  inputMouse->setValue(buffer,sizeof(buffer));
  inputMouse->notify();
}

Also if I could get some help understanding what's going on here, I would appreciate it. I thought that this is an input report and the first argument tells what input action to do (move mouse), but I don't think that's it. I'm trying to send a click event, thank you.

T-vK commented 4 years ago

I don't know if this is of interest for any of you, but I wrote a simple absolute mouse example for the standard mouse descriptor: https://github.com/T-vK/ESP32-BLE-Mouse/issues/19#issuecomment-713838753

xcarcelle commented 4 years ago

Dear @pattontim : regarding this line of code

unsigned char buffer[] = {4, x & 0x00FF, (x & 0xFF00) >> 8, y & 0x00FF, (y & 0xFF00) >> 8};
Abdurashid200112 commented 1 year ago

hi the program is great but what should i do to make the screen down with 1mm resolution