From abadb2bde9405a97f16e4cf7875eee7b2025c61e Mon Sep 17 00:00:00 2001 From: Fang Lu Date: Sat, 19 Jun 2021 19:22:18 -0700 Subject: [PATCH 1/7] Initial touchscreen implementation --- src/HID-APIs/MultiTouchAPI.h | 118 +++++++++++++++ src/HID-APIs/MultiTouchAPI.hpp | 105 ++++++++++++++ src/HID-Project.h | 1 + src/SingleReport/MultiTouch.cpp | 246 ++++++++++++++++++++++++++++++++ src/SingleReport/MultiTouch.h | 62 ++++++++ 5 files changed, 532 insertions(+) create mode 100644 src/HID-APIs/MultiTouchAPI.h create mode 100644 src/HID-APIs/MultiTouchAPI.hpp create mode 100644 src/SingleReport/MultiTouch.cpp create mode 100644 src/SingleReport/MultiTouch.h diff --git a/src/HID-APIs/MultiTouchAPI.h b/src/HID-APIs/MultiTouchAPI.h new file mode 100644 index 00000000..09564011 --- /dev/null +++ b/src/HID-APIs/MultiTouchAPI.h @@ -0,0 +1,118 @@ +/* +Copyright (c) 2021 ilufang +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Include guard +#pragma once + +/// Maximum amount of fingers supported +#define HID_MULTITOUCH_MAXFINGERS 10 +/// Number of fingers in a single report +#define HID_MULTITOUCH_REPORTFINGERS 2 + +// A report will always be the same size, even if you report fewer fingers than +// REPORTFINGERS. The unused finger entries will simply be zero. If more fingers +// are present than REPORTFINGERS, multiple reports will be sent to report all +// fingers. This is know as "Hybrid Mode" on MSDN. The number of supported +// fingers identified by Windows will still be MAXFINGERS. More than MAXFINGERS +// contacts may be ignored by Windows even with hybrid mode. + +#define _MT_STATE_INACTIVE 0 +#define _MT_STATE_CONTACT 1 +#define _MT_STATE_RELEASED 2 + +typedef struct ATTRIBUTE_PACKED { + uint8_t reportID; + uint8_t count; + struct ATTRIBUTE_PACKED { + uint8_t identifier; + uint8_t touch; + uint8_t pressure; + uint8_t x1, x0; + uint8_t y1, y0; + } contacts[HID_MULTITOUCH_REPORTFINGERS]; +} HID_MultiTouchReport_Data_t; + +typedef struct { + uint8_t status; + int8_t pressure; + int16_t x, y; +} _finger_t; + +class MultiTouchAPI +{ +public: + MultiTouchAPI() { + _fingers_count = 0; + for (int i = 0; i < HID_MULTITOUCH_MAXFINGERS; i++) { + _fingers[i].status = _MT_STATE_INACTIVE; + } + } + + inline void begin(); + + /** + * Set contact status for a finger in the internal data structure. You must + * call send manually after setting all fingers to flush them through USB. + * + * @param id Finger id. Must be in the range of 0-MAXFINGERS. Same finger + * must have same id throughout contact. Allocations does not need + * to be continuous. + * @param x, y Coordinates. Range 0-10000. (0,0) is top-left on Windows. + * @param pressure Contact pressure. Range 0-127. When set to 0, the touch + * is reported as hovering (in-range) + * @return 1 if success. 0 if id is out-of-bounds + */ + inline int setFinger(uint8_t id, int16_t x, int16_t y, int8_t pressure=100); + + /** + * Release finger in the internal data structure. You must call send + * manually after setting all fingers to flush them through USB. + * + * @param id Finger id. Must be in the range of 0-MAXFINGERS. Same finger + * must have same id throughout contact. Allocations does not need + * to be continuous. + * @return 1 if success. 0 if id is out-of-bounds + */ + inline int releaseFinger(uint8_t id); + + /** + * Generates an HID report reflecting the currently recorded touch status + * and send through USB. + */ + inline int send(); + +protected: + /// Send the generated report. Needs to be implemented in a lower level + virtual int _sendReport() = 0; + + /// Internal records of the current touch status + _finger_t _fingers[HID_MULTITOUCH_MAXFINGERS]; + /// Number of active contacts, including just release contacts + uint8_t _fingers_count; + + /// HID report to send. Not + HID_MultiTouchReport_Data_t _report; +}; + +// Implementation is inline +#include "MultiTouchAPI.hpp" diff --git a/src/HID-APIs/MultiTouchAPI.hpp b/src/HID-APIs/MultiTouchAPI.hpp new file mode 100644 index 00000000..cf00d7da --- /dev/null +++ b/src/HID-APIs/MultiTouchAPI.hpp @@ -0,0 +1,105 @@ +/* +Copyright (c) 2021 ilufang +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Include guard +#pragma once + +#define _LSB(v) ((v >> 8) & 0xff) +#define _MSB(v) (v & 0xff) + +void MultiTouchAPI::begin() { + send(); +} + +int MultiTouchAPI::setFinger(uint8_t id, int16_t x, int16_t y, int8_t pressure) { + if (id >= HID_MULTITOUCH_MAXFINGERS) { + return 0; + } + if (_fingers[id].status == _MT_STATE_INACTIVE) { + _fingers_count++; + } + _fingers[id].status = _MT_STATE_CONTACT; + _fingers[id].pressure = pressure; + _fingers[id].x = x; + _fingers[id].y = y; + return 1; +} + +int MultiTouchAPI::releaseFinger(uint8_t id) { + if (id >= HID_MULTITOUCH_MAXFINGERS) { + return 0; + } + _fingers[id].status = _MT_STATE_RELEASED; + return 1; +} + +int MultiTouchAPI::send() { + int ret = 0; + + // Craft report(s) + _report.count = _fingers_count; + + int rptentry=0; + for (int i = 0; i < HID_MULTITOUCH_MAXFINGERS; i++) { + if (_fingers[i].status == _MT_STATE_INACTIVE) + continue; + + _report.contacts[rptentry].identifier = i; // valid for first report only + + if (_fingers[i].status == _MT_STATE_RELEASED) { + // Released contacts need to be reported once with TipSW=0 + _report.contacts[rptentry].touch = {}; + _fingers_count--; + _fingers[i].status = _MT_STATE_INACTIVE; + } else { + // Active contacts must be reported even when not moved + _report.contacts[rptentry].touch = _fingers[i].pressure > 0 ? 3 : 1; + _report.contacts[rptentry].x1 = _MSB(_fingers[i].x); + _report.contacts[rptentry].x0 = _LSB(_fingers[i].x); + _report.contacts[rptentry].y1 = _MSB(_fingers[i].y); + _report.contacts[rptentry].y0 = _LSB(_fingers[i].y); + _report.contacts[rptentry].pressure = _fingers[i].pressure; + } + + rptentry++; + if (rptentry == HID_MULTITOUCH_REPORTFINGERS) { + // Report full. Send now. + // If there are more contacts, they will be sent in subsequent + // reports with contact count set to 0 + // See "Hybrid Mode" on MSDN docs + ret += _sendReport(); + rptentry = 0; + _report.count = 0; + } + } + + if (rptentry != 0) { + // Send remaining touches + for (; rptentry != HID_MULTITOUCH_REPORTFINGERS; rptentry++) { + _report.contacts[rptentry] = {}; + } + ret += _sendReport(); + } + + return ret; +} diff --git a/src/HID-Project.h b/src/HID-Project.h index 0e9d05a4..0ce8e7bf 100644 --- a/src/HID-Project.h +++ b/src/HID-Project.h @@ -52,5 +52,6 @@ THE SOFTWARE. #include "SingleReport/SingleNKROKeyboard.h" #include "MultiReport/NKROKeyboard.h" #include "MultiReport/SurfaceDial.h" +#include "SingleReport/MultiTouch.h" // Include Teensy HID afterwards to overwrite key definitions if used diff --git a/src/SingleReport/MultiTouch.cpp b/src/SingleReport/MultiTouch.cpp new file mode 100644 index 00000000..e9c901be --- /dev/null +++ b/src/SingleReport/MultiTouch.cpp @@ -0,0 +1,246 @@ +/* +Copyright (c) 2021 ilufang +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "MultiTouch.h" + +// HID Report identifiers +#define _HID_REPORTID_TOUCH 0x01 +#define _HID_REPORTID_FEATURE 0x05 + +// First part of the descriptor. It appears only once +static const uint8_t _hidReportDescriptorTouchscreen_1[] PROGMEM = { + 0x05, 0x0D, // USAGE_PAGE(Digitizers) + 0x09, 0x04, // USAGE (Touch Screen) + 0xA1, 0x01, // COLLECTION(Application) + + // define the actual amount of fingers that are concurrently touching the screen + 0x85, _HID_REPORTID_TOUCH, // REPORT_ID (Touch) + 0x09, 0x54, // USAGE (Contact count) + 0x25, 0x7f, // LOGICAL_MAXIMUM (128) + 0x95, 0x01, // REPORT_COUNT(1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x02 // INPUT (Data,Var,Abs) +}; + +// Finger definition part of the descriptor. It will repeat REPORTFINGERS times, once for each finger. +// If more actual fingers are present than descriptor fingers, multiple reports will be sent sequentially under "Hybrid Mode" rule (See MSDN) +static const uint8_t _hidReportDescriptorTouchscreen_2[] PROGMEM = { + // declare a finger collection + 0x05, 0x0D, // USAGE_PAGE(Digitizers) + 0x09, 0x22, // USAGE (Finger) + 0xA1, 0x02, // COLLECTION (Logical) + + // declare an identifier for the finger + 0x09, 0x51, // USAGE (Contact Identifier) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + // declare Tip Switch & In range + 0x09, 0x42, // USAGE (Tip Switch) + 0x09, 0x32, // USAGE (In Range) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x02, // REPORT_COUNT(2) + 0x81, 0x02, // INPUT (Data,Var,Abs) + // declare the 6 padding bits as constant so the driver will ignore them + 0x95, 0x06, // REPORT_COUNT (6) + 0x81, 0x03, // INPUT (Cnst,Ary,Abs) + + // declare pressure + 0x09, 0x30, // USAGE (Pressure) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + + // define absolute X and Y coordinates of 16 bit each (percent values multiplied with 100) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x16, 0x00, 0x00, // Logical Minimum (0) + 0x26, 0x10, 0x27, // Logical Maximum (10000) + 0x36, 0x00, 0x00, // Physical Minimum (0) + 0x46, 0x10, 0x27, // Physical Maximum (10000) + 0x66, 0x00, 0x00, // UNIT (None) + 0x75, 0x10, // Report Size (16), + 0x95, 0x02, // Report Count (2), + 0x81, 0x02, // Input (Data,Var,Abs) + 0xC0 // END_COLLECTION +}; + +// Last of the descriptor. It appears only once +static const uint8_t _hidReportDescriptorTouchscreen_3[] PROGMEM = { + // define the maximum amount of fingers that the device supports + 0x05, 0x0D, // USAGE_PAGE(Digitizers) + 0x85, _HID_REPORTID_FEATURE, // REPORT_ID (Feature) + 0x09, 0x55, // USAGE (Contact Count Maximum) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0xB1, 0x02, // FEATURE (Data,Var,Abs) + + 0xC0 // END_COLLECTION +}; + + +MultiTouch_::MultiTouch_(void) : PluggableUSBModule(2, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), featureReport((uint8_t *)&_ccmFeature), featureLength(sizeof(_ccmFeature)) +{ + _report.reportID = _HID_REPORTID_TOUCH; + _ccmFeature.reportID = _HID_REPORTID_FEATURE; + _ccmFeature.contactCountMaximum = HID_MULTITOUCH_MAXFINGERS; + epType[0] = EP_TYPE_INTERRUPT_IN; + PluggableUSB().plug(this); +} + +int MultiTouch_::getInterface(uint8_t* interfaceCount) +{ + *interfaceCount += 1; // uses 1 + HIDDescriptor hidInterface = { + D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), + D_HIDREPORT(sizeof(_hidReportDescriptorTouchscreen_1) + sizeof(_hidReportDescriptorTouchscreen_2) * HID_MULTITOUCH_REPORTFINGERS + sizeof(_hidReportDescriptorTouchscreen_3)), + D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) + }; + return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); +} + +int MultiTouch_::getDescriptor(USBSetup& setup) +{ + // Check if this is a HID Class Descriptor request + if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } + if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } + + // In a HID Class Descriptor wIndex cointains the interface number + if (setup.wIndex != pluggedInterface) { return 0; } + + // Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol + // due to the USB specs, but Windows and Linux just assumes its in report mode. + protocol = HID_REPORT_PROTOCOL; + + // Transmit HID descriptor. See comments next to the descriptor parts + int ret = 0; + ret += USB_SendControl(TRANSFER_PGM, _hidReportDescriptorTouchscreen_1, sizeof(_hidReportDescriptorTouchscreen_1)); + for (int i = 0; i < HID_MULTITOUCH_REPORTFINGERS; i++) { + ret += USB_SendControl(TRANSFER_PGM, _hidReportDescriptorTouchscreen_2, sizeof(_hidReportDescriptorTouchscreen_2)); + } + ret += USB_SendControl(TRANSFER_PGM, _hidReportDescriptorTouchscreen_3, sizeof(_hidReportDescriptorTouchscreen_3)); + + return ret; +} + +bool MultiTouch_::setup(USBSetup& setup) +{ + if (pluggedInterface != setup.wIndex) { + return false; + } + + uint8_t request = setup.bRequest; + uint8_t requestType = setup.bmRequestType; + + if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE) + { + if (request == HID_GET_REPORT) { + if(setup.wValueH == HID_REPORT_TYPE_FEATURE){ + // The only feature is Contact Count Maximum + USB_SendControl(0, featureReport, featureLength); + return true; + } + return true; + } + if (request == HID_GET_PROTOCOL) { + // TODO improve +#ifdef __AVR__ + UEDATX = protocol; +#endif + return true; + } + if (request == HID_GET_IDLE) { + // TODO improve +#ifdef __AVR__ + UEDATX = idle; +#endif + return true; + } + } + + if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE) + { + if (request == HID_SET_PROTOCOL) { + protocol = setup.wValueL; + return true; + } + if (request == HID_SET_IDLE) { + idle = setup.wValueL; + return true; + } + if (request == HID_SET_REPORT) + { + // Check if data has the correct length afterwards + int length = setup.wLength; + + // Feature (set feature report) + if(setup.wValueH == HID_REPORT_TYPE_FEATURE){ + // No need to check for negative featureLength values, + // except the host tries to send more then 32k bytes. + // We dont have that much ram anyways. + if (length == featureLength) { + USB_RecvControl(featureReport, featureLength); + return true; + } + // TODO fake clear data? + } + + // Output (not applicable) + else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){ + return true; + } + + // Input (set HID report) + else if(setup.wValueH == HID_REPORT_TYPE_INPUT) + { + if(length == sizeof(_report)){ + USB_RecvControl(&_report, length); + return true; + } + } + } + } + + return false; +} + +uint8_t MultiTouch_::getProtocol() { + return protocol; +} + +int MultiTouch_::_sendReport() { + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &_report, sizeof(_report)); +} + +void MultiTouch_::wakeupHost() { +#ifdef __AVR__ + USBDevice.wakeupHost(); +#endif +} + +MultiTouch_ MultiTouch; diff --git a/src/SingleReport/MultiTouch.h b/src/SingleReport/MultiTouch.h new file mode 100644 index 00000000..a3223991 --- /dev/null +++ b/src/SingleReport/MultiTouch.h @@ -0,0 +1,62 @@ +/* +Copyright (c) 2021 ilufang +See the readme for credit to other people. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +// Include guard +#pragma once + +#include +#include "HID.h" +#include "HID-Settings.h" +#include "../HID-APIs/MultiTouchAPI.h" + + +class MultiTouch_ : public PluggableUSBModule, public MultiTouchAPI +{ +public: + MultiTouch_(); + uint8_t getProtocol(); + void wakeupHost(); + +protected: + virtual int _sendReport() final; + + // Implementation of the PUSBListNode + int getInterface(uint8_t* interfaceCount); + int getDescriptor(USBSetup& setup); + bool setup(USBSetup& setup); + + EPTYPE_DESCRIPTOR_SIZE epType[1]; + uint8_t protocol; + uint8_t idle; + + uint8_t* featureReport; + int featureLength; + +private: + struct { + uint8_t reportID; + uint8_t contactCountMaximum; + } _ccmFeature; +}; + +extern MultiTouch_ MultiTouch; From 1f0097174b8824b64b2d3c2126d4fc484af4724f Mon Sep 17 00:00:00 2001 From: Fang Lu Date: Sat, 19 Jun 2021 20:11:26 -0700 Subject: [PATCH 2/7] Add example for multi-touch --- examples/MultiTouch/MultiTouch.ino | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 examples/MultiTouch/MultiTouch.ino diff --git a/examples/MultiTouch/MultiTouch.ino b/examples/MultiTouch/MultiTouch.ino new file mode 100644 index 00000000..805a8360 --- /dev/null +++ b/examples/MultiTouch/MultiTouch.ino @@ -0,0 +1,39 @@ +/* + Copyright (c) 2021 ilufang + See the readme for credit to other people. + + Multi-touch touchscreen example + Draw 7 parallel lines across the screen. + Open Microsoft Whiteboard, select a brush and press the button. + + See HID Project documentation for more infos + https://github.com/NicoHood/HID/wiki/Gamepad-API +*/ + +#include + +const int pinButton = 2; + +void setup() { + pinMode(pinButton, INPUT_PULLUP); + MultiTouch.begin(); +} + +void loop() { + while(digitalRead(pinButton)); + + int16_t x = 2000, y = 2000; + + for (; x <= 8000; x+=10) { + for (int i = 0; i < 7; i++) { + MultiTouch.setFinger(i, x, y+i*1000, (i+1)*15); + } + MultiTouch.send(); + delay(10); + } + + for (int i = 0; i < 7; i++) { + MultiTouch.releaseFinger(i); + } + MultiTouch.send(); +} From ba4f2d94358d11d3f04807e0baa172109f52bd0c Mon Sep 17 00:00:00 2001 From: Fang Lu Date: Mon, 21 Jun 2021 00:04:57 -0700 Subject: [PATCH 3/7] Touchscreen cleanup --- examples/MultiTouch/MultiTouch.ino | 2 +- src/HID-APIs/MultiTouchAPI.h | 59 +++++++++++----------- src/HID-APIs/MultiTouchAPI.hpp | 36 ++++++++------ src/HID-Settings.h | 10 ++++ src/SingleReport/MultiTouch.cpp | 78 +++++++----------------------- src/SingleReport/MultiTouch.h | 11 ++--- 6 files changed, 81 insertions(+), 115 deletions(-) diff --git a/examples/MultiTouch/MultiTouch.ino b/examples/MultiTouch/MultiTouch.ino index 805a8360..dc3ba8b7 100644 --- a/examples/MultiTouch/MultiTouch.ino +++ b/examples/MultiTouch/MultiTouch.ino @@ -7,7 +7,7 @@ Open Microsoft Whiteboard, select a brush and press the button. See HID Project documentation for more infos - https://github.com/NicoHood/HID/wiki/Gamepad-API + https://github.com/NicoHood/HID/wiki */ #include diff --git a/src/HID-APIs/MultiTouchAPI.h b/src/HID-APIs/MultiTouchAPI.h index 09564011..abcc4810 100644 --- a/src/HID-APIs/MultiTouchAPI.h +++ b/src/HID-APIs/MultiTouchAPI.h @@ -36,37 +36,34 @@ THE SOFTWARE. // fingers identified by Windows will still be MAXFINGERS. More than MAXFINGERS // contacts may be ignored by Windows even with hybrid mode. -#define _MT_STATE_INACTIVE 0 -#define _MT_STATE_CONTACT 1 -#define _MT_STATE_RELEASED 2 + +// Bit-mask flags for 'status' in the HID report +#define HID_MULTITOUCH_TOUCH_CONTACT 0x01 +#define HID_MULTITOUCH_TOUCH_IN_RANGE 0x02 typedef struct ATTRIBUTE_PACKED { - uint8_t reportID; - uint8_t count; + uint8_t status; + uint8_t pressure; + uint16_t x; + uint16_t y; +} HID_MultiTouch_Finger_t; + +typedef union ATTRIBUTE_PACKED { + uint8_t whole8[0]; + uint16_t whole16[0]; + uint32_t whole32[0]; struct ATTRIBUTE_PACKED { - uint8_t identifier; - uint8_t touch; - uint8_t pressure; - uint8_t x1, x0; - uint8_t y1, y0; - } contacts[HID_MULTITOUCH_REPORTFINGERS]; + uint8_t count; + struct ATTRIBUTE_PACKED { + uint8_t identifier; + HID_MultiTouch_Finger_t touch; + } contacts[HID_MULTITOUCH_REPORTFINGERS]; + }; } HID_MultiTouchReport_Data_t; -typedef struct { - uint8_t status; - int8_t pressure; - int16_t x, y; -} _finger_t; - class MultiTouchAPI { public: - MultiTouchAPI() { - _fingers_count = 0; - for (int i = 0; i < HID_MULTITOUCH_MAXFINGERS; i++) { - _fingers[i].status = _MT_STATE_INACTIVE; - } - } inline void begin(); @@ -82,7 +79,7 @@ class MultiTouchAPI * is reported as hovering (in-range) * @return 1 if success. 0 if id is out-of-bounds */ - inline int setFinger(uint8_t id, int16_t x, int16_t y, int8_t pressure=100); + inline int setFinger(uint8_t id, uint16_t x, uint16_t y, uint8_t pressure=100); /** * Release finger in the internal data structure. You must call send @@ -101,17 +98,17 @@ class MultiTouchAPI */ inline int send(); + /// Send generated report. Needs to be implemented in a lower level + virtual int sendReport(void *report, int length) = 0; + virtual int sendReport(HID_MultiTouchReport_Data_t &report) = 0; + protected: - /// Send the generated report. Needs to be implemented in a lower level - virtual int _sendReport() = 0; - /// Internal records of the current touch status - _finger_t _fingers[HID_MULTITOUCH_MAXFINGERS]; + /// Internal records of the current touch statuses. Status in this struct + /// is used only internally and differs from the one in the report + HID_MultiTouch_Finger_t _fingers[HID_MULTITOUCH_MAXFINGERS]; /// Number of active contacts, including just release contacts uint8_t _fingers_count; - - /// HID report to send. Not - HID_MultiTouchReport_Data_t _report; }; // Implementation is inline diff --git a/src/HID-APIs/MultiTouchAPI.hpp b/src/HID-APIs/MultiTouchAPI.hpp index cf00d7da..847d80b1 100644 --- a/src/HID-APIs/MultiTouchAPI.hpp +++ b/src/HID-APIs/MultiTouchAPI.hpp @@ -24,14 +24,17 @@ THE SOFTWARE. // Include guard #pragma once -#define _LSB(v) ((v >> 8) & 0xff) -#define _MSB(v) (v & 0xff) +enum _finger_status_t { + _MT_STATE_INACTIVE = 0, + _MT_STATE_CONTACT, + _MT_STATE_RELEASED +}; void MultiTouchAPI::begin() { send(); } -int MultiTouchAPI::setFinger(uint8_t id, int16_t x, int16_t y, int8_t pressure) { +int MultiTouchAPI::setFinger(uint8_t id, uint16_t x, uint16_t y, uint8_t pressure) { if (id >= HID_MULTITOUCH_MAXFINGERS) { return 0; } @@ -55,30 +58,31 @@ int MultiTouchAPI::releaseFinger(uint8_t id) { int MultiTouchAPI::send() { int ret = 0; + HID_MultiTouchReport_Data_t report; // Craft report(s) - _report.count = _fingers_count; + report.count = _fingers_count; int rptentry=0; for (int i = 0; i < HID_MULTITOUCH_MAXFINGERS; i++) { if (_fingers[i].status == _MT_STATE_INACTIVE) continue; - _report.contacts[rptentry].identifier = i; // valid for first report only + report.contacts[rptentry].identifier = i; // valid for first report only if (_fingers[i].status == _MT_STATE_RELEASED) { // Released contacts need to be reported once with TipSW=0 - _report.contacts[rptentry].touch = {}; + report.contacts[rptentry].touch = {}; _fingers_count--; _fingers[i].status = _MT_STATE_INACTIVE; } else { // Active contacts must be reported even when not moved - _report.contacts[rptentry].touch = _fingers[i].pressure > 0 ? 3 : 1; - _report.contacts[rptentry].x1 = _MSB(_fingers[i].x); - _report.contacts[rptentry].x0 = _LSB(_fingers[i].x); - _report.contacts[rptentry].y1 = _MSB(_fingers[i].y); - _report.contacts[rptentry].y0 = _LSB(_fingers[i].y); - _report.contacts[rptentry].pressure = _fingers[i].pressure; + report.contacts[rptentry].touch.status = HID_MULTITOUCH_TOUCH_IN_RANGE; + if (_fingers[i].pressure > 0) + report.contacts[rptentry].touch.status |= HID_MULTITOUCH_TOUCH_CONTACT; + report.contacts[rptentry].touch.x = _fingers[i].x; + report.contacts[rptentry].touch.y = _fingers[i].y; + report.contacts[rptentry].touch.pressure = _fingers[i].pressure; } rptentry++; @@ -87,18 +91,18 @@ int MultiTouchAPI::send() { // If there are more contacts, they will be sent in subsequent // reports with contact count set to 0 // See "Hybrid Mode" on MSDN docs - ret += _sendReport(); + ret += sendReport(report); rptentry = 0; - _report.count = 0; + report.count = 0; } } if (rptentry != 0) { // Send remaining touches for (; rptentry != HID_MULTITOUCH_REPORTFINGERS; rptentry++) { - _report.contacts[rptentry] = {}; + report.contacts[rptentry] = {}; } - ret += _sendReport(); + ret += sendReport(report); } return ret; diff --git a/src/HID-Settings.h b/src/HID-Settings.h index c05c3764..8fe23b08 100644 --- a/src/HID-Settings.h +++ b/src/HID-Settings.h @@ -73,6 +73,16 @@ THE SOFTWARE. #define HID_REPORTID_SURFACEDIAL 10 #endif +#ifndef HID_REPORTID_MULTITOUCH +#define HID_REPORTID_MULTITOUCH 11 +#endif + +#ifndef HID_REPORTID_MULTITOUCH_FEATURE +#define HID_REPORTID_MULTITOUCH_FEATURE 12 +#endif + + + #if defined(ARDUINO_ARCH_AVR) // Use default alignment for AVR diff --git a/src/SingleReport/MultiTouch.cpp b/src/SingleReport/MultiTouch.cpp index e9c901be..390daaf4 100644 --- a/src/SingleReport/MultiTouch.cpp +++ b/src/SingleReport/MultiTouch.cpp @@ -23,10 +23,6 @@ THE SOFTWARE. #include "MultiTouch.h" -// HID Report identifiers -#define _HID_REPORTID_TOUCH 0x01 -#define _HID_REPORTID_FEATURE 0x05 - // First part of the descriptor. It appears only once static const uint8_t _hidReportDescriptorTouchscreen_1[] PROGMEM = { 0x05, 0x0D, // USAGE_PAGE(Digitizers) @@ -34,7 +30,6 @@ static const uint8_t _hidReportDescriptorTouchscreen_1[] PROGMEM = { 0xA1, 0x01, // COLLECTION(Application) // define the actual amount of fingers that are concurrently touching the screen - 0x85, _HID_REPORTID_TOUCH, // REPORT_ID (Touch) 0x09, 0x54, // USAGE (Contact count) 0x25, 0x7f, // LOGICAL_MAXIMUM (128) 0x95, 0x01, // REPORT_COUNT(1) @@ -95,7 +90,6 @@ static const uint8_t _hidReportDescriptorTouchscreen_2[] PROGMEM = { static const uint8_t _hidReportDescriptorTouchscreen_3[] PROGMEM = { // define the maximum amount of fingers that the device supports 0x05, 0x0D, // USAGE_PAGE(Digitizers) - 0x85, _HID_REPORTID_FEATURE, // REPORT_ID (Feature) 0x09, 0x55, // USAGE (Contact Count Maximum) 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0xB1, 0x02, // FEATURE (Data,Var,Abs) @@ -104,28 +98,27 @@ static const uint8_t _hidReportDescriptorTouchscreen_3[] PROGMEM = { }; -MultiTouch_::MultiTouch_(void) : PluggableUSBModule(2, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1), featureReport((uint8_t *)&_ccmFeature), featureLength(sizeof(_ccmFeature)) -{ - _report.reportID = _HID_REPORTID_TOUCH; - _ccmFeature.reportID = _HID_REPORTID_FEATURE; +MultiTouch_::MultiTouch_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1) { _ccmFeature.contactCountMaximum = HID_MULTITOUCH_MAXFINGERS; epType[0] = EP_TYPE_INTERRUPT_IN; PluggableUSB().plug(this); } -int MultiTouch_::getInterface(uint8_t* interfaceCount) -{ +int MultiTouch_::getInterface(uint8_t* interfaceCount) { *interfaceCount += 1; // uses 1 HIDDescriptor hidInterface = { D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), - D_HIDREPORT(sizeof(_hidReportDescriptorTouchscreen_1) + sizeof(_hidReportDescriptorTouchscreen_2) * HID_MULTITOUCH_REPORTFINGERS + sizeof(_hidReportDescriptorTouchscreen_3)), + D_HIDREPORT( + sizeof(_hidReportDescriptorTouchscreen_1) + + (sizeof(_hidReportDescriptorTouchscreen_2) * HID_MULTITOUCH_REPORTFINGERS) + + sizeof(_hidReportDescriptorTouchscreen_3) + ), D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) }; return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); } -int MultiTouch_::getDescriptor(USBSetup& setup) -{ +int MultiTouch_::getDescriptor(USBSetup& setup) { // Check if this is a HID Class Descriptor request if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } @@ -148,8 +141,7 @@ int MultiTouch_::getDescriptor(USBSetup& setup) return ret; } -bool MultiTouch_::setup(USBSetup& setup) -{ +bool MultiTouch_::setup(USBSetup& setup) { if (pluggedInterface != setup.wIndex) { return false; } @@ -162,23 +154,13 @@ bool MultiTouch_::setup(USBSetup& setup) if (request == HID_GET_REPORT) { if(setup.wValueH == HID_REPORT_TYPE_FEATURE){ // The only feature is Contact Count Maximum - USB_SendControl(0, featureReport, featureLength); + USB_SendControl(0, &_ccmFeature, sizeof(_ccmFeature)); return true; } return true; } if (request == HID_GET_PROTOCOL) { // TODO improve -#ifdef __AVR__ - UEDATX = protocol; -#endif - return true; - } - if (request == HID_GET_IDLE) { - // TODO improve -#ifdef __AVR__ - UEDATX = idle; -#endif return true; } } @@ -193,36 +175,8 @@ bool MultiTouch_::setup(USBSetup& setup) idle = setup.wValueL; return true; } - if (request == HID_SET_REPORT) - { - // Check if data has the correct length afterwards - int length = setup.wLength; - - // Feature (set feature report) - if(setup.wValueH == HID_REPORT_TYPE_FEATURE){ - // No need to check for negative featureLength values, - // except the host tries to send more then 32k bytes. - // We dont have that much ram anyways. - if (length == featureLength) { - USB_RecvControl(featureReport, featureLength); - return true; - } - // TODO fake clear data? - } - - // Output (not applicable) - else if(setup.wValueH == HID_REPORT_TYPE_OUTPUT){ - return true; - } - - // Input (set HID report) - else if(setup.wValueH == HID_REPORT_TYPE_INPUT) - { - if(length == sizeof(_report)){ - USB_RecvControl(&_report, length); - return true; - } - } + if (request == HID_SET_REPORT) { + return true; } } @@ -233,8 +187,12 @@ uint8_t MultiTouch_::getProtocol() { return protocol; } -int MultiTouch_::_sendReport() { - return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &_report, sizeof(_report)); +int MultiTouch_::sendReport(void *report, int length) { + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, report, length); +} + +int MultiTouch_::sendReport(HID_MultiTouchReport_Data_t &report) { + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &report, sizeof(HID_MultiTouchReport_Data_t)); } void MultiTouch_::wakeupHost() { diff --git a/src/SingleReport/MultiTouch.h b/src/SingleReport/MultiTouch.h index a3223991..4d6ad8f0 100644 --- a/src/SingleReport/MultiTouch.h +++ b/src/SingleReport/MultiTouch.h @@ -37,8 +37,10 @@ class MultiTouch_ : public PluggableUSBModule, public MultiTouchAPI uint8_t getProtocol(); void wakeupHost(); + virtual int sendReport(void *report, int length) final; + virtual int sendReport(HID_MultiTouchReport_Data_t &report) final; + protected: - virtual int _sendReport() final; // Implementation of the PUSBListNode int getInterface(uint8_t* interfaceCount); @@ -49,12 +51,7 @@ class MultiTouch_ : public PluggableUSBModule, public MultiTouchAPI uint8_t protocol; uint8_t idle; - uint8_t* featureReport; - int featureLength; - -private: - struct { - uint8_t reportID; + struct ATTRIBUTE_PACKED { uint8_t contactCountMaximum; } _ccmFeature; }; From dfe04b8021bc32327a701f7c9ff0aea685749792 Mon Sep 17 00:00:00 2001 From: Fang Lu Date: Mon, 21 Jun 2021 00:10:08 -0700 Subject: [PATCH 4/7] Touchscreen rename class names --- .../Touchscreen.ino} | 10 +++---- .../{MultiTouchAPI.h => TouchscreenAPI.h} | 24 ++++++++-------- .../{MultiTouchAPI.hpp => TouchscreenAPI.hpp} | 24 ++++++++-------- src/HID-Project.h | 2 +- src/HID-Settings.h | 9 ------ .../{MultiTouch.cpp => Touchscreen.cpp} | 28 +++++++++---------- .../{MultiTouch.h => Touchscreen.h} | 10 +++---- 7 files changed, 49 insertions(+), 58 deletions(-) rename examples/{MultiTouch/MultiTouch.ino => Touchscreen/Touchscreen.ino} (80%) rename src/HID-APIs/{MultiTouchAPI.h => TouchscreenAPI.h} (88%) rename src/HID-APIs/{MultiTouchAPI.hpp => TouchscreenAPI.hpp} (80%) rename src/SingleReport/{MultiTouch.cpp => Touchscreen.cpp} (90%) rename src/SingleReport/{MultiTouch.h => Touchscreen.h} (87%) diff --git a/examples/MultiTouch/MultiTouch.ino b/examples/Touchscreen/Touchscreen.ino similarity index 80% rename from examples/MultiTouch/MultiTouch.ino rename to examples/Touchscreen/Touchscreen.ino index dc3ba8b7..fe774f5d 100644 --- a/examples/MultiTouch/MultiTouch.ino +++ b/examples/Touchscreen/Touchscreen.ino @@ -16,7 +16,7 @@ const int pinButton = 2; void setup() { pinMode(pinButton, INPUT_PULLUP); - MultiTouch.begin(); + Touchscreen.begin(); } void loop() { @@ -26,14 +26,14 @@ void loop() { for (; x <= 8000; x+=10) { for (int i = 0; i < 7; i++) { - MultiTouch.setFinger(i, x, y+i*1000, (i+1)*15); + Touchscreen.setFinger(i, x, y+i*1000, (i+1)*15); } - MultiTouch.send(); + Touchscreen.send(); delay(10); } for (int i = 0; i < 7; i++) { - MultiTouch.releaseFinger(i); + Touchscreen.releaseFinger(i); } - MultiTouch.send(); + Touchscreen.send(); } diff --git a/src/HID-APIs/MultiTouchAPI.h b/src/HID-APIs/TouchscreenAPI.h similarity index 88% rename from src/HID-APIs/MultiTouchAPI.h rename to src/HID-APIs/TouchscreenAPI.h index abcc4810..c7e7deda 100644 --- a/src/HID-APIs/MultiTouchAPI.h +++ b/src/HID-APIs/TouchscreenAPI.h @@ -25,9 +25,9 @@ THE SOFTWARE. #pragma once /// Maximum amount of fingers supported -#define HID_MULTITOUCH_MAXFINGERS 10 +#define HID_TOUCHSCREEN_MAXFINGERS 10 /// Number of fingers in a single report -#define HID_MULTITOUCH_REPORTFINGERS 2 +#define HID_TOUCHSCREEN_REPORTFINGERS 2 // A report will always be the same size, even if you report fewer fingers than // REPORTFINGERS. The unused finger entries will simply be zero. If more fingers @@ -38,15 +38,15 @@ THE SOFTWARE. // Bit-mask flags for 'status' in the HID report -#define HID_MULTITOUCH_TOUCH_CONTACT 0x01 -#define HID_MULTITOUCH_TOUCH_IN_RANGE 0x02 +#define HID_TOUCHSCREEN_TOUCH_CONTACT 0x01 +#define HID_TOUCHSCREEN_TOUCH_IN_RANGE 0x02 typedef struct ATTRIBUTE_PACKED { uint8_t status; uint8_t pressure; uint16_t x; uint16_t y; -} HID_MultiTouch_Finger_t; +} HID_Touchscreen_Finger_t; typedef union ATTRIBUTE_PACKED { uint8_t whole8[0]; @@ -56,12 +56,12 @@ typedef union ATTRIBUTE_PACKED { uint8_t count; struct ATTRIBUTE_PACKED { uint8_t identifier; - HID_MultiTouch_Finger_t touch; - } contacts[HID_MULTITOUCH_REPORTFINGERS]; + HID_Touchscreen_Finger_t touch; + } contacts[HID_TOUCHSCREEN_REPORTFINGERS]; }; -} HID_MultiTouchReport_Data_t; +} HID_TouchscreenReport_Data_t; -class MultiTouchAPI +class TouchscreenAPI { public: @@ -100,16 +100,16 @@ class MultiTouchAPI /// Send generated report. Needs to be implemented in a lower level virtual int sendReport(void *report, int length) = 0; - virtual int sendReport(HID_MultiTouchReport_Data_t &report) = 0; + virtual int sendReport(HID_TouchscreenReport_Data_t &report) = 0; protected: /// Internal records of the current touch statuses. Status in this struct /// is used only internally and differs from the one in the report - HID_MultiTouch_Finger_t _fingers[HID_MULTITOUCH_MAXFINGERS]; + HID_Touchscreen_Finger_t _fingers[HID_TOUCHSCREEN_MAXFINGERS]; /// Number of active contacts, including just release contacts uint8_t _fingers_count; }; // Implementation is inline -#include "MultiTouchAPI.hpp" +#include "TouchscreenAPI.hpp" diff --git a/src/HID-APIs/MultiTouchAPI.hpp b/src/HID-APIs/TouchscreenAPI.hpp similarity index 80% rename from src/HID-APIs/MultiTouchAPI.hpp rename to src/HID-APIs/TouchscreenAPI.hpp index 847d80b1..fac1c54a 100644 --- a/src/HID-APIs/MultiTouchAPI.hpp +++ b/src/HID-APIs/TouchscreenAPI.hpp @@ -30,12 +30,12 @@ enum _finger_status_t { _MT_STATE_RELEASED }; -void MultiTouchAPI::begin() { +void TouchscreenAPI::begin() { send(); } -int MultiTouchAPI::setFinger(uint8_t id, uint16_t x, uint16_t y, uint8_t pressure) { - if (id >= HID_MULTITOUCH_MAXFINGERS) { +int TouchscreenAPI::setFinger(uint8_t id, uint16_t x, uint16_t y, uint8_t pressure) { + if (id >= HID_TOUCHSCREEN_MAXFINGERS) { return 0; } if (_fingers[id].status == _MT_STATE_INACTIVE) { @@ -48,23 +48,23 @@ int MultiTouchAPI::setFinger(uint8_t id, uint16_t x, uint16_t y, uint8_t pressur return 1; } -int MultiTouchAPI::releaseFinger(uint8_t id) { - if (id >= HID_MULTITOUCH_MAXFINGERS) { +int TouchscreenAPI::releaseFinger(uint8_t id) { + if (id >= HID_TOUCHSCREEN_MAXFINGERS) { return 0; } _fingers[id].status = _MT_STATE_RELEASED; return 1; } -int MultiTouchAPI::send() { +int TouchscreenAPI::send() { int ret = 0; - HID_MultiTouchReport_Data_t report; + HID_TouchscreenReport_Data_t report; // Craft report(s) report.count = _fingers_count; int rptentry=0; - for (int i = 0; i < HID_MULTITOUCH_MAXFINGERS; i++) { + for (int i = 0; i < HID_TOUCHSCREEN_MAXFINGERS; i++) { if (_fingers[i].status == _MT_STATE_INACTIVE) continue; @@ -77,16 +77,16 @@ int MultiTouchAPI::send() { _fingers[i].status = _MT_STATE_INACTIVE; } else { // Active contacts must be reported even when not moved - report.contacts[rptentry].touch.status = HID_MULTITOUCH_TOUCH_IN_RANGE; + report.contacts[rptentry].touch.status = HID_TOUCHSCREEN_TOUCH_IN_RANGE; if (_fingers[i].pressure > 0) - report.contacts[rptentry].touch.status |= HID_MULTITOUCH_TOUCH_CONTACT; + report.contacts[rptentry].touch.status |= HID_TOUCHSCREEN_TOUCH_CONTACT; report.contacts[rptentry].touch.x = _fingers[i].x; report.contacts[rptentry].touch.y = _fingers[i].y; report.contacts[rptentry].touch.pressure = _fingers[i].pressure; } rptentry++; - if (rptentry == HID_MULTITOUCH_REPORTFINGERS) { + if (rptentry == HID_TOUCHSCREEN_REPORTFINGERS) { // Report full. Send now. // If there are more contacts, they will be sent in subsequent // reports with contact count set to 0 @@ -99,7 +99,7 @@ int MultiTouchAPI::send() { if (rptentry != 0) { // Send remaining touches - for (; rptentry != HID_MULTITOUCH_REPORTFINGERS; rptentry++) { + for (; rptentry != HID_TOUCHSCREEN_REPORTFINGERS; rptentry++) { report.contacts[rptentry] = {}; } ret += sendReport(report); diff --git a/src/HID-Project.h b/src/HID-Project.h index 0ce8e7bf..0278bc36 100644 --- a/src/HID-Project.h +++ b/src/HID-Project.h @@ -52,6 +52,6 @@ THE SOFTWARE. #include "SingleReport/SingleNKROKeyboard.h" #include "MultiReport/NKROKeyboard.h" #include "MultiReport/SurfaceDial.h" -#include "SingleReport/MultiTouch.h" +#include "SingleReport/Touchscreen.h" // Include Teensy HID afterwards to overwrite key definitions if used diff --git a/src/HID-Settings.h b/src/HID-Settings.h index 8fe23b08..607bfde7 100644 --- a/src/HID-Settings.h +++ b/src/HID-Settings.h @@ -73,15 +73,6 @@ THE SOFTWARE. #define HID_REPORTID_SURFACEDIAL 10 #endif -#ifndef HID_REPORTID_MULTITOUCH -#define HID_REPORTID_MULTITOUCH 11 -#endif - -#ifndef HID_REPORTID_MULTITOUCH_FEATURE -#define HID_REPORTID_MULTITOUCH_FEATURE 12 -#endif - - #if defined(ARDUINO_ARCH_AVR) diff --git a/src/SingleReport/MultiTouch.cpp b/src/SingleReport/Touchscreen.cpp similarity index 90% rename from src/SingleReport/MultiTouch.cpp rename to src/SingleReport/Touchscreen.cpp index 390daaf4..7a5d7ade 100644 --- a/src/SingleReport/MultiTouch.cpp +++ b/src/SingleReport/Touchscreen.cpp @@ -21,7 +21,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "MultiTouch.h" +#include "Touchscreen.h" // First part of the descriptor. It appears only once static const uint8_t _hidReportDescriptorTouchscreen_1[] PROGMEM = { @@ -98,19 +98,19 @@ static const uint8_t _hidReportDescriptorTouchscreen_3[] PROGMEM = { }; -MultiTouch_::MultiTouch_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1) { - _ccmFeature.contactCountMaximum = HID_MULTITOUCH_MAXFINGERS; +Touchscreen_::Touchscreen_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1) { + _ccmFeature.contactCountMaximum = HID_TOUCHSCREEN_MAXFINGERS; epType[0] = EP_TYPE_INTERRUPT_IN; PluggableUSB().plug(this); } -int MultiTouch_::getInterface(uint8_t* interfaceCount) { +int Touchscreen_::getInterface(uint8_t* interfaceCount) { *interfaceCount += 1; // uses 1 HIDDescriptor hidInterface = { D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE), D_HIDREPORT( sizeof(_hidReportDescriptorTouchscreen_1) - + (sizeof(_hidReportDescriptorTouchscreen_2) * HID_MULTITOUCH_REPORTFINGERS) + + (sizeof(_hidReportDescriptorTouchscreen_2) * HID_TOUCHSCREEN_REPORTFINGERS) + sizeof(_hidReportDescriptorTouchscreen_3) ), D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01) @@ -118,7 +118,7 @@ int MultiTouch_::getInterface(uint8_t* interfaceCount) { return USB_SendControl(0, &hidInterface, sizeof(hidInterface)); } -int MultiTouch_::getDescriptor(USBSetup& setup) { +int Touchscreen_::getDescriptor(USBSetup& setup) { // Check if this is a HID Class Descriptor request if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; } if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; } @@ -133,7 +133,7 @@ int MultiTouch_::getDescriptor(USBSetup& setup) { // Transmit HID descriptor. See comments next to the descriptor parts int ret = 0; ret += USB_SendControl(TRANSFER_PGM, _hidReportDescriptorTouchscreen_1, sizeof(_hidReportDescriptorTouchscreen_1)); - for (int i = 0; i < HID_MULTITOUCH_REPORTFINGERS; i++) { + for (int i = 0; i < HID_TOUCHSCREEN_REPORTFINGERS; i++) { ret += USB_SendControl(TRANSFER_PGM, _hidReportDescriptorTouchscreen_2, sizeof(_hidReportDescriptorTouchscreen_2)); } ret += USB_SendControl(TRANSFER_PGM, _hidReportDescriptorTouchscreen_3, sizeof(_hidReportDescriptorTouchscreen_3)); @@ -141,7 +141,7 @@ int MultiTouch_::getDescriptor(USBSetup& setup) { return ret; } -bool MultiTouch_::setup(USBSetup& setup) { +bool Touchscreen_::setup(USBSetup& setup) { if (pluggedInterface != setup.wIndex) { return false; } @@ -183,22 +183,22 @@ bool MultiTouch_::setup(USBSetup& setup) { return false; } -uint8_t MultiTouch_::getProtocol() { +uint8_t Touchscreen_::getProtocol() { return protocol; } -int MultiTouch_::sendReport(void *report, int length) { +int Touchscreen_::sendReport(void *report, int length) { return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, report, length); } -int MultiTouch_::sendReport(HID_MultiTouchReport_Data_t &report) { - return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &report, sizeof(HID_MultiTouchReport_Data_t)); +int Touchscreen_::sendReport(HID_TouchscreenReport_Data_t &report) { + return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &report, sizeof(HID_TouchscreenReport_Data_t)); } -void MultiTouch_::wakeupHost() { +void Touchscreen_::wakeupHost() { #ifdef __AVR__ USBDevice.wakeupHost(); #endif } -MultiTouch_ MultiTouch; +Touchscreen_ Touchscreen; diff --git a/src/SingleReport/MultiTouch.h b/src/SingleReport/Touchscreen.h similarity index 87% rename from src/SingleReport/MultiTouch.h rename to src/SingleReport/Touchscreen.h index 4d6ad8f0..9119c4dd 100644 --- a/src/SingleReport/MultiTouch.h +++ b/src/SingleReport/Touchscreen.h @@ -27,18 +27,18 @@ THE SOFTWARE. #include #include "HID.h" #include "HID-Settings.h" -#include "../HID-APIs/MultiTouchAPI.h" +#include "../HID-APIs/TouchscreenAPI.h" -class MultiTouch_ : public PluggableUSBModule, public MultiTouchAPI +class Touchscreen_ : public PluggableUSBModule, public TouchscreenAPI { public: - MultiTouch_(); + Touchscreen_(); uint8_t getProtocol(); void wakeupHost(); virtual int sendReport(void *report, int length) final; - virtual int sendReport(HID_MultiTouchReport_Data_t &report) final; + virtual int sendReport(HID_TouchscreenReport_Data_t &report) final; protected: @@ -56,4 +56,4 @@ class MultiTouch_ : public PluggableUSBModule, public MultiTouchAPI } _ccmFeature; }; -extern MultiTouch_ MultiTouch; +extern Touchscreen_ Touchscreen; From e41e73233548450874c97970056f44c716117bfc Mon Sep 17 00:00:00 2001 From: Fang Lu Date: Wed, 14 Jul 2021 20:07:13 -0700 Subject: [PATCH 5/7] Touchscreen minor cleanups. Update Readme to include Touchscreen. --- Readme.md | 3 ++- src/HID-APIs/TouchscreenAPI.h | 5 ++++- src/HID-APIs/TouchscreenAPI.hpp | 25 ++++++++++++++++++++++--- src/HID-Settings.h | 1 - src/SingleReport/Touchscreen.cpp | 6 +----- src/SingleReport/Touchscreen.h | 1 - 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Readme.md b/Readme.md index 618363bf..27b9de32 100644 --- a/Readme.md +++ b/Readme.md @@ -32,7 +32,8 @@ The idea is to enable enhanced USB functions to almost all 'standard' Arduino bo * Gamepad (32 buttons, 4 16bit axis, 2 8bit axis, 2 D-Pads) * RawHID * SurfaceDial -* Each device is available as single or multi report device (except RawHID) +* Touchscreen (max 10 touches at the same time) +* Each device is available as single or multi report device (except RawHID and Touchscreen) See the [wiki](https://github.com/NicoHood/HID/wiki/Features) for more information about features etc. diff --git a/src/HID-APIs/TouchscreenAPI.h b/src/HID-APIs/TouchscreenAPI.h index c7e7deda..2edd1bdf 100644 --- a/src/HID-APIs/TouchscreenAPI.h +++ b/src/HID-APIs/TouchscreenAPI.h @@ -65,7 +65,10 @@ class TouchscreenAPI { public: + inline TouchscreenAPI(); + inline void begin(); + inline void end(); /** * Set contact status for a finger in the internal data structure. You must @@ -100,7 +103,7 @@ class TouchscreenAPI /// Send generated report. Needs to be implemented in a lower level virtual int sendReport(void *report, int length) = 0; - virtual int sendReport(HID_TouchscreenReport_Data_t &report) = 0; + inline int sendReport(HID_TouchscreenReport_Data_t &report); protected: diff --git a/src/HID-APIs/TouchscreenAPI.hpp b/src/HID-APIs/TouchscreenAPI.hpp index fac1c54a..1f4cf20c 100644 --- a/src/HID-APIs/TouchscreenAPI.hpp +++ b/src/HID-APIs/TouchscreenAPI.hpp @@ -30,7 +30,18 @@ enum _finger_status_t { _MT_STATE_RELEASED }; +TouchscreenAPI::TouchscreenAPI() : _fingers_count(0), _fingers({}) { + // Empty. Default zero initialization +} + void TouchscreenAPI::begin() { + end(); +} + +void TouchscreenAPI::end() { + for (int i = 0; i < HID_TOUCHSCREEN_MAXFINGERS; i++) { + releaseFinger(i); + } send(); } @@ -52,7 +63,9 @@ int TouchscreenAPI::releaseFinger(uint8_t id) { if (id >= HID_TOUCHSCREEN_MAXFINGERS) { return 0; } - _fingers[id].status = _MT_STATE_RELEASED; + if (_fingers[id].status == _MT_STATE_CONTACT) { + _fingers[id].status = _MT_STATE_RELEASED; + } return 1; } @@ -65,8 +78,9 @@ int TouchscreenAPI::send() { int rptentry=0; for (int i = 0; i < HID_TOUCHSCREEN_MAXFINGERS; i++) { - if (_fingers[i].status == _MT_STATE_INACTIVE) + if (_fingers[i].status == _MT_STATE_INACTIVE) { continue; + } report.contacts[rptentry].identifier = i; // valid for first report only @@ -78,8 +92,9 @@ int TouchscreenAPI::send() { } else { // Active contacts must be reported even when not moved report.contacts[rptentry].touch.status = HID_TOUCHSCREEN_TOUCH_IN_RANGE; - if (_fingers[i].pressure > 0) + if (_fingers[i].pressure > 0) { report.contacts[rptentry].touch.status |= HID_TOUCHSCREEN_TOUCH_CONTACT; + } report.contacts[rptentry].touch.x = _fingers[i].x; report.contacts[rptentry].touch.y = _fingers[i].y; report.contacts[rptentry].touch.pressure = _fingers[i].pressure; @@ -107,3 +122,7 @@ int TouchscreenAPI::send() { return ret; } + +int TouchscreenAPI::sendReport(HID_TouchscreenReport_Data_t &report) { + return sendReport(&report, sizeof(HID_TouchscreenReport_Data_t)); +} diff --git a/src/HID-Settings.h b/src/HID-Settings.h index 607bfde7..c05c3764 100644 --- a/src/HID-Settings.h +++ b/src/HID-Settings.h @@ -73,7 +73,6 @@ THE SOFTWARE. #define HID_REPORTID_SURFACEDIAL 10 #endif - #if defined(ARDUINO_ARCH_AVR) // Use default alignment for AVR diff --git a/src/SingleReport/Touchscreen.cpp b/src/SingleReport/Touchscreen.cpp index 7a5d7ade..1e36d72a 100644 --- a/src/SingleReport/Touchscreen.cpp +++ b/src/SingleReport/Touchscreen.cpp @@ -98,7 +98,7 @@ static const uint8_t _hidReportDescriptorTouchscreen_3[] PROGMEM = { }; -Touchscreen_::Touchscreen_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1) { +Touchscreen_::Touchscreen_() : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1) { _ccmFeature.contactCountMaximum = HID_TOUCHSCREEN_MAXFINGERS; epType[0] = EP_TYPE_INTERRUPT_IN; PluggableUSB().plug(this); @@ -191,10 +191,6 @@ int Touchscreen_::sendReport(void *report, int length) { return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, report, length); } -int Touchscreen_::sendReport(HID_TouchscreenReport_Data_t &report) { - return USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &report, sizeof(HID_TouchscreenReport_Data_t)); -} - void Touchscreen_::wakeupHost() { #ifdef __AVR__ USBDevice.wakeupHost(); diff --git a/src/SingleReport/Touchscreen.h b/src/SingleReport/Touchscreen.h index 9119c4dd..2f8a142d 100644 --- a/src/SingleReport/Touchscreen.h +++ b/src/SingleReport/Touchscreen.h @@ -38,7 +38,6 @@ class Touchscreen_ : public PluggableUSBModule, public TouchscreenAPI void wakeupHost(); virtual int sendReport(void *report, int length) final; - virtual int sendReport(HID_TouchscreenReport_Data_t &report) final; protected: From 87558bee4308691956074cd36eeb88eee4c809b8 Mon Sep 17 00:00:00 2001 From: Fang Lu Date: Thu, 22 Jul 2021 23:16:43 -0700 Subject: [PATCH 6/7] Touchscreen remove constructor zero initializer list --- src/HID-APIs/TouchscreenAPI.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/HID-APIs/TouchscreenAPI.hpp b/src/HID-APIs/TouchscreenAPI.hpp index 1f4cf20c..99f833d5 100644 --- a/src/HID-APIs/TouchscreenAPI.hpp +++ b/src/HID-APIs/TouchscreenAPI.hpp @@ -30,8 +30,8 @@ enum _finger_status_t { _MT_STATE_RELEASED }; -TouchscreenAPI::TouchscreenAPI() : _fingers_count(0), _fingers({}) { - // Empty. Default zero initialization +TouchscreenAPI::TouchscreenAPI() { + // Empty. Default zero initialization at loading. Do not manually instantiate } void TouchscreenAPI::begin() { From 827bf372a72be92fd9cd6ec5b73bf4c6627954a6 Mon Sep 17 00:00:00 2001 From: Fang Lu Date: Fri, 23 Jul 2021 17:28:01 -0700 Subject: [PATCH 7/7] Update Touchscreen.cpp SET_IDLE --- src/SingleReport/Touchscreen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SingleReport/Touchscreen.cpp b/src/SingleReport/Touchscreen.cpp index 1e36d72a..d333b2c2 100644 --- a/src/SingleReport/Touchscreen.cpp +++ b/src/SingleReport/Touchscreen.cpp @@ -172,7 +172,7 @@ bool Touchscreen_::setup(USBSetup& setup) { return true; } if (request == HID_SET_IDLE) { - idle = setup.wValueL; + idle = setup.wValueH; return true; } if (request == HID_SET_REPORT) {