From 412a0631b04bd6ececf58eb196a64f571f8fe139 Mon Sep 17 00:00:00 2001 From: davidthings Date: Thu, 26 Mar 2015 23:49:16 -0700 Subject: [PATCH 1/7] First pass at getting Multitouch and a decent example --- Adafruit_FT6206.cpp | 49 +++++-- Adafruit_FT6206.h | 12 +- examples/Multitouch/Multitouch.ino | 222 +++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+), 20 deletions(-) create mode 100644 examples/Multitouch/Multitouch.ino diff --git a/Adafruit_FT6206.cpp b/Adafruit_FT6206.cpp index 417730c..cf9f4e0 100644 --- a/Adafruit_FT6206.cpp +++ b/Adafruit_FT6206.cpp @@ -1,8 +1,8 @@ -/*************************************************** +/*************************************************** This is a library for the Adafruit Capacitive Touch Screens ----> http://www.adafruit.com/products/1947 - + Check out the links above for our tutorials and wiring diagrams This chipset uses I2C to communicate @@ -30,7 +30,7 @@ #endif /**************************************************************************/ -/*! +/*! @brief Instantiates a new FT6206 class */ /**************************************************************************/ @@ -40,7 +40,7 @@ Adafruit_FT6206::Adafruit_FT6206() { /**************************************************************************/ -/*! +/*! @brief Setups the HW */ /**************************************************************************/ @@ -49,9 +49,9 @@ boolean Adafruit_FT6206::begin(uint8_t threshhold) { // change threshhold to be higher/lower writeRegister8(FT6206_REG_THRESHHOLD, threshhold); - + if ((readRegister8(FT6206_REG_VENDID) != 17) || (readRegister8(FT6206_REG_CHIPID) != 6)) return false; - /* + /* Serial.print("Vend ID: "); Serial.println(readRegister8(FT6206_REG_VENDID)); Serial.print("Chip ID: "); Serial.println(readRegister8(FT6206_REG_CHIPID)); Serial.print("Firm V: "); Serial.println(readRegister8(FT6206_REG_FIRMVERS)); @@ -79,7 +79,7 @@ void Adafruit_FT6206::autoCalibrate(void) { uint8_t temp; temp = readRegister8(FT6206_REG_MODE); Serial.println(temp, HEX); - //return to normal mode, calibration finish + //return to normal mode, calibration finish if (0x0 == ((temp & 0x70) >> 4)) break; } @@ -96,7 +96,7 @@ void Adafruit_FT6206::autoCalibrate(void) { boolean Adafruit_FT6206::touched(void) { - + uint8_t n = readRegister8(FT6206_REG_NUMTOUCHES); if ((n == 1) || (n == 2)) return true; return false; @@ -108,13 +108,13 @@ void Adafruit_FT6206::readData(uint16_t *x, uint16_t *y) { uint8_t i2cdat[16]; Wire.beginTransmission(FT6206_ADDR); - Wire.write((byte)0); + Wire.write((byte)0); Wire.endTransmission(); Wire.beginTransmission(FT6206_ADDR); Wire.requestFrom((byte)FT6206_ADDR, (byte)32); for (uint8_t i=0; i<16; i++) i2cdat[i] = Wire.read(); - Wire.endTransmission(); + Wire.endTransmission(); /* for (int16_t i=0; i<0x20; i++) { @@ -144,7 +144,7 @@ void Adafruit_FT6206::readData(uint16_t *x, uint16_t *y) { /* Serial.println(); if (i2cdat[0x01] != 0x00) { - Serial.print("Gesture #"); + Serial.print("Gesture #"); Serial.println(i2cdat[0x01]); } */ @@ -153,7 +153,7 @@ void Adafruit_FT6206::readData(uint16_t *x, uint16_t *y) { for (uint8_t i=0; i<2; i++) { touchX[i] = i2cdat[0x03 + i*6] & 0x0F; touchX[i] <<= 8; - touchX[i] |= i2cdat[0x04 + i*6]; + touchX[i] |= i2cdat[0x04 + i*6]; touchY[i] = i2cdat[0x05 + i*6] & 0x0F; touchY[i] <<= 8; touchY[i] |= i2cdat[0x06 + i*6]; @@ -171,6 +171,27 @@ void Adafruit_FT6206::readData(uint16_t *x, uint16_t *y) { *x = touchX[0]; *y = touchY[0]; } +// minimal impact method to read multitouches +uint8_t Adafruit_FT6206::readMultiData(uint8_t *id0, uint16_t *x0, uint16_t *y0, uint8_t *id1, uint16_t *x1, uint16_t *y1 ) { + // save ourselves some trouble if there are no touches + uint8_t n = readRegister8(FT6206_REG_NUMTOUCHES); + if ( n == 0 || n > 2 ) { + *id0 = 0x0F; + *id1 = 0x0F; + return 0; + } + + // call the main data reader... it does the job + readData( x0, y0 ); + *id0 = touchID[ 0 ]; + *id1 = touchID[ 1 ]; + *x1 = touchX[ 1 ]; + *y1 = touchY[ 1 ]; + + // return the number of touches + return n; +} + TS_Point Adafruit_FT6206::getPoint(void) { uint16_t x, y; uint8_t z; @@ -190,9 +211,9 @@ uint8_t Adafruit_FT6206::readRegister8(uint8_t reg) { x = Wire.read(); Wire.endTransmission(); - // Serial.print("$"); Serial.print(reg, HEX); + // Serial.print("$"); Serial.print(reg, HEX); // Serial.print(": 0x"); Serial.println(x, HEX); - + return x; } diff --git a/Adafruit_FT6206.h b/Adafruit_FT6206.h index 4ea06c6..efc4398 100644 --- a/Adafruit_FT6206.h +++ b/Adafruit_FT6206.h @@ -1,8 +1,8 @@ -/*************************************************** +/*************************************************** This is a library for the Adafruit Capacitive Touch Screens ----> http://www.adafruit.com/products/1947 - + Check out the links above for our tutorials and wiring diagrams This chipset uses I2C to communicate @@ -48,7 +48,7 @@ class TS_Point { public: TS_Point(void); TS_Point(int16_t x, int16_t y, int16_t z); - + bool operator==(TS_Point); bool operator!=(TS_Point); @@ -59,13 +59,14 @@ class Adafruit_FT6206 { public: Adafruit_FT6206(void); - boolean begin(uint8_t thresh = FT6206_DEFAULT_THRESSHOLD); + boolean begin(uint8_t thresh = FT6206_DEFAULT_THRESSHOLD); void writeRegister8(uint8_t reg, uint8_t val); uint8_t readRegister8(uint8_t reg); void readData(uint16_t *x, uint16_t *y); - void autoCalibrate(void); + uint8_t readMultiData(uint8_t *id0, uint16_t *x0, uint16_t *y0, uint8_t *id1, uint16_t *x1, uint16_t *y1 ); + void autoCalibrate(void); boolean touched(void); TS_Point getPoint(void); @@ -75,4 +76,3 @@ class Adafruit_FT6206 { uint16_t touchX[2], touchY[2], touchID[2]; }; - diff --git a/examples/Multitouch/Multitouch.ino b/examples/Multitouch/Multitouch.ino new file mode 100644 index 0000000..65edcd4 --- /dev/null +++ b/examples/Multitouch/Multitouch.ino @@ -0,0 +1,222 @@ +/*************************************************** + This is a multitouch example for the Adafruit ILI9341 + captouch shield + ----> http://www.adafruit.com/products/1947 + + Check out the links above for our tutorials and wiring diagrams + + Adafruit invests time and resources providing this open source code, + please support Adafruit and open-source hardware by purchasing + products from Adafruit! + + Written by David Williams + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include // Core graphics library +#include // this is needed for display +#include +#include // this is needed for FT6206 +#include + +// The FT6206 uses hardware I2C (SCL/SDA) +Adafruit_FT6206 ctp = Adafruit_FT6206(); + +// The display also uses hardware SPI, plus #9 & #10 +#define TFT_CS 10 +#define TFT_DC 9 +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); + +#define XSIZE 240 +#define YSIZE 320 +#define COLOR_COUNT 3 + +#define TOUCH_RADIUS 30 +#define TOUCH_TRIANGLE_TOP 40 +#define TOUCH_TRIANGLE_X 32 // 40 * cos( 30 ) = 32 +#define TOUCH_TRIANGLE_Y 20 // 40 * sin( 30 ) = 20 + +int Colors[ ] = { ILI9341_DARKGREEN, ILI9341_BLUE, ILI9341_RED }; +int Touch = ILI9341_DARKGREY; +int Background = ILI9341_BLACK; + +// Going to have a thing +#define OBJECT_SIZE_MINIMUM XSIZE / 32 +#define OBJECT_SIZE_MAXIMUM XSIZE / 2 + +int ObjectX = XSIZE / 2; +int ObjectY = YSIZE / 2; +int ObjectSize = XSIZE / 8; +uint8_t ObjectColor = 0; + +int XOriginal[ 2 ]; +int YOriginal[ 2 ]; +int XCurrent[ 2 ]; +int YCurrent[ 2 ]; +int XPrevious[ 2 ]; +int YPrevious[ 2 ]; + +void setup(void) { + while (!Serial); // used for leonardo debugging + + Serial.begin(115200); + Serial.println(F("Multitouch!")); + + delay(500); + + tft.begin(); + + ctp.begin(40); // pass in 'sensitivity' coefficient + + Serial.println("Capacitive touchscreen started"); + + tft.fillScreen( Background ); + + for ( uint8_t i = 0; i < 2; i++) { + XCurrent[ i ] = -1; + YCurrent[ i ] = -1; + XPrevious[ i ] = -1; + YPrevious[ i ] = -1; + } +} + +bool Dragging = false; +int DraggingOffsetX = 0; +int DraggingOffsetY = 0; + +void touchDown( int x, int y ) { + int dx = x - ObjectX; + int dy = y - ObjectY; + Serial.println( "Touch Down" ); + int d2 = ( dx * dx + dy * dy ); + if ( d2 < ObjectSize * ObjectSize ) { + Serial.println( " Object Hit!" ); + Serial.print( " dx " ); Serial.print( dx ); Serial.print( " dy" ); Serial.println( dy ); + + Dragging = true; + DraggingOffsetX = dx; + DraggingOffsetY = dy; + } +} + +void touchMove( int x, int y ) { + Serial.println( "Touch Move" ); + if ( Dragging ) { + Serial.println( " Object Move" ); + } +} + +void touchUp( int x, int y ) { + Serial.println( "Touch Up" ); + if ( Dragging ) { + Serial.println( " Object Release" ); + Dragging = false; + + int newX = x - DraggingOffsetX; + int newY = y - DraggingOffsetY; + if ( ObjectX != newX || ObjectY != newY ) { + tft.fillCircle( ObjectX, ObjectY, ObjectSize, Background ); + + Serial.print( " x " ); Serial.print( x ); Serial.print( " OY " ); Serial.println( y ); + Serial.print( " Ox " ); Serial.print( ObjectX ); Serial.print( " OY " ); Serial.println( ObjectY ); + ObjectX = x - DraggingOffsetX; + ObjectY = y - DraggingOffsetY; + + Serial.print( " dx " ); Serial.print( DraggingOffsetX ); Serial.print( " dy" ); Serial.println( DraggingOffsetY ); + Serial.print( " Ox " ); Serial.print( ObjectX ); Serial.print( " OY " ); Serial.println( ObjectY ); + + if ( ObjectX < 0 ) ObjectX = 0; + if ( ObjectY < 0 ) ObjectY = 0; + if ( ObjectX >= XSIZE ) ObjectX = XSIZE - 1; + if ( ObjectY >= YSIZE ) ObjectY = YSIZE - 1; + + tft.fillCircle( ObjectX, ObjectY, ObjectSize, Background ); + } + + } +} + +void loop() { + + touch(); + + tft.fillCircle( ObjectX, ObjectY, ObjectSize, Colors[ ObjectColor ] ); + +} + +void touch() { + + uint8_t n, id[ 2 ]; + uint16_t x[ 2 ], y[ 2 ]; + + n = ctp.readMultiData( &id[ 0 ], &x[ 0 ], &y[ 0 ], &id[ 1 ], &x[ 1 ], &y[ 1 ] ); + + if ( n > 0 ){ + for ( uint8_t i = 0; i < n; i++) { + int idi = id[ i ]; + int xi = map(x[ i ], 0, 240, 240, 0); + int yi = map(y[ i ], 0, 320, 320, 0); + //Serial.print( "T" ); Serial.print( i ); Serial.print( " " ); Serial.print( idi ); Serial.print( " " ); Serial.print( xi ); Serial.print( "," ); Serial.println( yi ); + if ( idi == 0 ) { + XCurrent[ 0 ] = xi; + YCurrent[ 0 ] = yi; + if ( n == 1 ) { + XCurrent[ 1 ] = -1; + YCurrent[ 1 ] = -1; + } + } + else { + XCurrent[ 1 ] = xi; + YCurrent[ 1 ] = yi; + if ( n == 1 ) { + XCurrent[ 0 ] = -1; + YCurrent[ 0 ] = -1; + } + } + } + } + + if ( n == 0 ) { + XCurrent[ 0 ] = -1; + YCurrent[ 0 ] = -1; + XCurrent[ 1 ] = -1; + YCurrent[ 1 ] = -1; + } + + if ( XCurrent[ 0 ] != -1 && XPrevious[ 0 ] == -1 ) { + touchDown( XCurrent[ 0 ], YCurrent[ 0 ] ); + XOriginal[ 0 ] = XCurrent[ 0 ]; + YOriginal[ 0 ] = YCurrent[ 0 ]; + } + else { + if ( XCurrent[ 0 ] == -1 && XPrevious[ 0 ] != -1 ) { + touchUp( XPrevious[ 0 ], YPrevious[ 0 ] ); + } else { + if ( XCurrent[ 0 ] != XPrevious[ 0 ] || YCurrent[ 0 ] != YPrevious[ 1 ] ) + touchMove( XCurrent[ 0 ], YCurrent[ 0 ] ); + } + } + + for ( uint8_t i = 0; i < 2; i++) { + int xp = XPrevious[ i ]; + int yp = YPrevious[ i ]; + int xc = XCurrent[ i ]; + int yc = YCurrent[ i ]; + if ( xp != -1 && ( xp != xc || yp != yc ) ) { + if ( i == 0 ) + tft.drawCircle( xp, yp, TOUCH_RADIUS, Background ); + else + tft.drawTriangle( xp, yp - TOUCH_RADIUS, xp - TOUCH_TRIANGLE_X, yp + TOUCH_TRIANGLE_Y, xp + TOUCH_TRIANGLE_X, yp + TOUCH_TRIANGLE_Y, Background ); + } + if ( xc != -1 && ( xp != xc || yp != yc ) ) { + if ( i == 0 ) + tft.drawCircle( xc, yc, TOUCH_RADIUS, Touch ); + else + tft.drawTriangle( xc, yc - TOUCH_RADIUS, xc - TOUCH_TRIANGLE_X, yc + TOUCH_TRIANGLE_Y, xc + TOUCH_TRIANGLE_X, yc + TOUCH_TRIANGLE_Y, Touch ); + } + + XPrevious[ i ] = XCurrent[ i ]; + YPrevious[ i ] = YCurrent[ i ]; + } + +} From eac53940e28f4d578f440cfc86bc9d1d296647b3 Mon Sep 17 00:00:00 2001 From: davidthings Date: Fri, 27 Mar 2015 07:45:47 -0700 Subject: [PATCH 2/7] touch events from both touches --- examples/Multitouch/Multitouch.ino | 34 +++++++++++++++++------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/examples/Multitouch/Multitouch.ino b/examples/Multitouch/Multitouch.ino index 65edcd4..91d8b22 100644 --- a/examples/Multitouch/Multitouch.ino +++ b/examples/Multitouch/Multitouch.ino @@ -47,7 +47,7 @@ int Background = ILI9341_BLACK; int ObjectX = XSIZE / 2; int ObjectY = YSIZE / 2; int ObjectSize = XSIZE / 8; -uint8_t ObjectColor = 0; +uint8_t ObjectColor = 1; int XOriginal[ 2 ]; int YOriginal[ 2 ]; @@ -183,25 +183,28 @@ void touch() { YCurrent[ 1 ] = -1; } - if ( XCurrent[ 0 ] != -1 && XPrevious[ 0 ] == -1 ) { - touchDown( XCurrent[ 0 ], YCurrent[ 0 ] ); - XOriginal[ 0 ] = XCurrent[ 0 ]; - YOriginal[ 0 ] = YCurrent[ 0 ]; - } - else { - if ( XCurrent[ 0 ] == -1 && XPrevious[ 0 ] != -1 ) { - touchUp( XPrevious[ 0 ], YPrevious[ 0 ] ); - } else { - if ( XCurrent[ 0 ] != XPrevious[ 0 ] || YCurrent[ 0 ] != YPrevious[ 1 ] ) - touchMove( XCurrent[ 0 ], YCurrent[ 0 ] ); - } - } - for ( uint8_t i = 0; i < 2; i++) { int xp = XPrevious[ i ]; int yp = YPrevious[ i ]; int xc = XCurrent[ i ]; int yc = YCurrent[ i ]; + + // Create single touch events + if ( xc != -1 && xp == -1 ) { + touchDown( xc, yc ); + XOriginal[ i ] = xc; + YOriginal[ i ] = yc; + } + else { + if ( xc == -1 && xp != -1 ) { + touchUp( xp, yp ); + } else { + if ( xc != xp || yc != yp ) + touchMove( xc, yc ); + } + } + + // Drawing the touch if ( xp != -1 && ( xp != xc || yp != yc ) ) { if ( i == 0 ) tft.drawCircle( xp, yp, TOUCH_RADIUS, Background ); @@ -215,6 +218,7 @@ void touch() { tft.drawTriangle( xc, yc - TOUCH_RADIUS, xc - TOUCH_TRIANGLE_X, yc + TOUCH_TRIANGLE_Y, xc + TOUCH_TRIANGLE_X, yc + TOUCH_TRIANGLE_Y, Touch ); } + // What is new will be old XPrevious[ i ] = XCurrent[ i ]; YPrevious[ i ] = YCurrent[ i ]; } From 407721198aa2122cb14869873f83183abbb9e081 Mon Sep 17 00:00:00 2001 From: davidthings Date: Fri, 27 Mar 2015 08:14:03 -0700 Subject: [PATCH 3/7] convert points etc. to classes --- examples/Multitouch/Multitouch.ino | 107 +++++++++++++++++------------ 1 file changed, 63 insertions(+), 44 deletions(-) diff --git a/examples/Multitouch/Multitouch.ino b/examples/Multitouch/Multitouch.ino index 91d8b22..d3826bf 100644 --- a/examples/Multitouch/Multitouch.ino +++ b/examples/Multitouch/Multitouch.ino @@ -49,12 +49,32 @@ int ObjectY = YSIZE / 2; int ObjectSize = XSIZE / 8; uint8_t ObjectColor = 1; -int XOriginal[ 2 ]; -int YOriginal[ 2 ]; -int XCurrent[ 2 ]; -int YCurrent[ 2 ]; -int XPrevious[ 2 ]; -int YPrevious[ 2 ]; +class CtpPoint { +public: + int x; + int y; + CtpPoint() { clear(); } + CtpPoint( int x_, int y_ ): x( x_ ), y( y_ ) {} + void set( int x_, int y_ ) { x = x_; y = y_; } + void clear() { x = -1; y = -1; } + bool isClear() { return ( ( x == -1 ) && ( y == -1 ) ); } + bool operator==(CtpPoint p) { + return ( ( p.x == x ) && ( p.y == y ) ); + } + bool operator!=(CtpPoint p) { + return ( ( p.x != x ) || ( p.y != y ) ); + } +}; + +class CtpTouch { +public: + CtpTouch() {} + CtpPoint original; + CtpPoint current; + CtpPoint previous; + int touchDownTime; + int touchUpTime; +} CtpTouches[ 2 ]; void setup(void) { while (!Serial); // used for leonardo debugging @@ -73,10 +93,12 @@ void setup(void) { tft.fillScreen( Background ); for ( uint8_t i = 0; i < 2; i++) { - XCurrent[ i ] = -1; - YCurrent[ i ] = -1; - XPrevious[ i ] = -1; - YPrevious[ i ] = -1; + CtpTouch* t = &CtpTouches[ i ]; + t->original.clear(); + t->current.clear(); + t->previous.clear(); + t->touchDownTime = -1; + t->touchUpTime = -1; } } @@ -151,6 +173,7 @@ void touch() { n = ctp.readMultiData( &id[ 0 ], &x[ 0 ], &y[ 0 ], &id[ 1 ], &x[ 1 ], &y[ 1 ] ); + // Extract and update the touch information if ( n > 0 ){ for ( uint8_t i = 0; i < n; i++) { int idi = id[ i ]; @@ -158,69 +181,65 @@ void touch() { int yi = map(y[ i ], 0, 320, 320, 0); //Serial.print( "T" ); Serial.print( i ); Serial.print( " " ); Serial.print( idi ); Serial.print( " " ); Serial.print( xi ); Serial.print( "," ); Serial.println( yi ); if ( idi == 0 ) { - XCurrent[ 0 ] = xi; - YCurrent[ 0 ] = yi; + CtpTouches[ 0 ].current.set( xi, yi ); if ( n == 1 ) { - XCurrent[ 1 ] = -1; - YCurrent[ 1 ] = -1; + CtpTouches[ 1 ].current.clear( ); } } else { - XCurrent[ 1 ] = xi; - YCurrent[ 1 ] = yi; + CtpTouches[ 1 ].current.set( xi, yi ); if ( n == 1 ) { - XCurrent[ 0 ] = -1; - YCurrent[ 0 ] = -1; + CtpTouches[ 0 ].current.clear(); } } } } if ( n == 0 ) { - XCurrent[ 0 ] = -1; - YCurrent[ 0 ] = -1; - XCurrent[ 1 ] = -1; - YCurrent[ 1 ] = -1; + CtpTouches[ 0 ].current.clear(); + CtpTouches[ 1 ].current.clear(); } for ( uint8_t i = 0; i < 2; i++) { - int xp = XPrevious[ i ]; - int yp = YPrevious[ i ]; - int xc = XCurrent[ i ]; - int yc = YCurrent[ i ]; + CtpTouch* t = &CtpTouches[ i ]; // Create single touch events - if ( xc != -1 && xp == -1 ) { - touchDown( xc, yc ); - XOriginal[ i ] = xc; - YOriginal[ i ] = yc; + if ( !t->current.isClear() && t->previous.isClear() ) { + touchDown( t->current.x, t->current.y ); + t->original = t->current; } else { - if ( xc == -1 && xp != -1 ) { - touchUp( xp, yp ); + if ( t->current.isClear() && !t->previous.isClear() ) { + touchUp( t->previous.x, t->previous.y ); } else { - if ( xc != xp || yc != yp ) - touchMove( xc, yc ); + if ( !t->current.isClear() && !t->previous.isClear() ) { + touchMove( t->current.x, t->current.y ); + } } } // Drawing the touch - if ( xp != -1 && ( xp != xc || yp != yc ) ) { + if ( !t->previous.isClear() && t->previous != t->current ) { + int x = t->previous.x; + int y = t->previous.y; if ( i == 0 ) - tft.drawCircle( xp, yp, TOUCH_RADIUS, Background ); - else - tft.drawTriangle( xp, yp - TOUCH_RADIUS, xp - TOUCH_TRIANGLE_X, yp + TOUCH_TRIANGLE_Y, xp + TOUCH_TRIANGLE_X, yp + TOUCH_TRIANGLE_Y, Background ); + tft.drawCircle( x, y, TOUCH_RADIUS, Background ); + else { + tft.drawTriangle( x, y - TOUCH_TRIANGLE_TOP, x - TOUCH_TRIANGLE_X, y + TOUCH_TRIANGLE_Y, x + TOUCH_TRIANGLE_X, y + TOUCH_TRIANGLE_Y, Background ); + } } - if ( xc != -1 && ( xp != xc || yp != yc ) ) { + if ( !t->current.isClear() && t->previous != t->current ) { + int x = t->current.x; + int y = t->current.y; if ( i == 0 ) - tft.drawCircle( xc, yc, TOUCH_RADIUS, Touch ); - else - tft.drawTriangle( xc, yc - TOUCH_RADIUS, xc - TOUCH_TRIANGLE_X, yc + TOUCH_TRIANGLE_Y, xc + TOUCH_TRIANGLE_X, yc + TOUCH_TRIANGLE_Y, Touch ); + tft.drawCircle( x, y, TOUCH_RADIUS, Touch ); + else { + tft.drawTriangle( x, y - TOUCH_TRIANGLE_TOP, x - TOUCH_TRIANGLE_X, y + TOUCH_TRIANGLE_Y, x + TOUCH_TRIANGLE_X, y + TOUCH_TRIANGLE_Y, Touch ); + } } // What is new will be old - XPrevious[ i ] = XCurrent[ i ]; - YPrevious[ i ] = YCurrent[ i ]; + t->previous = t->current; } } From 0c49256e9bbe48be8a9740be95da3511eb1867fe Mon Sep 17 00:00:00 2001 From: davidthings Date: Fri, 27 Mar 2015 12:19:10 -0700 Subject: [PATCH 4/7] Added Tap and Double Tap events --- examples/Multitouch/Multitouch.ino | 65 +++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/examples/Multitouch/Multitouch.ino b/examples/Multitouch/Multitouch.ino index d3826bf..61b65b4 100644 --- a/examples/Multitouch/Multitouch.ino +++ b/examples/Multitouch/Multitouch.ino @@ -27,6 +27,9 @@ Adafruit_FT6206 ctp = Adafruit_FT6206(); #define TFT_DC 9 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +#define TOUCH_TAP_TIME 200 +#define TOUCH_DOUBLE_TAP_TIME 500 + #define XSIZE 240 #define YSIZE 320 #define COLOR_COUNT 3 @@ -44,10 +47,13 @@ int Background = ILI9341_BLACK; #define OBJECT_SIZE_MINIMUM XSIZE / 32 #define OBJECT_SIZE_MAXIMUM XSIZE / 2 +#define OBJECT_TYPE_COUNT 3 + int ObjectX = XSIZE / 2; int ObjectY = YSIZE / 2; int ObjectSize = XSIZE / 8; -uint8_t ObjectColor = 1; +uint8_t ObjectColor = 0; +uint8_t ObjectType = 0; class CtpPoint { public: @@ -72,10 +78,29 @@ public: CtpPoint original; CtpPoint current; CtpPoint previous; - int touchDownTime; - int touchUpTime; + unsigned long touchDownTime; + unsigned long touchUpTime; } CtpTouches[ 2 ]; + +void drawObject( int color = Background ) { + switch ( ObjectType ) { + case 0: + tft.fillCircle( ObjectX, ObjectY, ObjectSize, color ); + break; + case 1: + tft.fillRect( ObjectX - ObjectSize, ObjectY - ObjectSize, 2 * ObjectSize, 2 * ObjectSize, color ); + break; + case 2: + tft.fillTriangle( ObjectX, ObjectY - 3 * ObjectSize / 2, ObjectX - 21 * ObjectSize / 16, ObjectY + 3 * ObjectSize / 4 , ObjectX + 21 * ObjectSize / 16, ObjectY + 3 * ObjectSize / 4, color ); + break; + } +} + +void eraseObject() { + drawObject(); +} + void setup(void) { while (!Serial); // used for leonardo debugging @@ -97,9 +122,11 @@ void setup(void) { t->original.clear(); t->current.clear(); t->previous.clear(); - t->touchDownTime = -1; - t->touchUpTime = -1; + t->touchDownTime = 0; + t->touchUpTime = 0; } + + drawObject( Colors[ ObjectColor ] ); } bool Dragging = false; @@ -137,7 +164,7 @@ void touchUp( int x, int y ) { int newX = x - DraggingOffsetX; int newY = y - DraggingOffsetY; if ( ObjectX != newX || ObjectY != newY ) { - tft.fillCircle( ObjectX, ObjectY, ObjectSize, Background ); + eraseObject(); Serial.print( " x " ); Serial.print( x ); Serial.print( " OY " ); Serial.println( y ); Serial.print( " Ox " ); Serial.print( ObjectX ); Serial.print( " OY " ); Serial.println( ObjectY ); @@ -152,20 +179,31 @@ void touchUp( int x, int y ) { if ( ObjectX >= XSIZE ) ObjectX = XSIZE - 1; if ( ObjectY >= YSIZE ) ObjectY = YSIZE - 1; - tft.fillCircle( ObjectX, ObjectY, ObjectSize, Background ); + drawObject( Colors[ ObjectColor ] ); } } } +void touchTap( int x, int y ) { + Serial.println( "Tap" ); +} + +void touchDoubleTap( int x, int y ) { + Serial.println( "DoubleTap" ); + eraseObject(); + ObjectType = ( ObjectType + 1 ) % OBJECT_TYPE_COUNT; + drawObject( Colors[ ObjectColor ] ); +} + void loop() { touch(); - tft.fillCircle( ObjectX, ObjectY, ObjectSize, Colors[ ObjectColor ] ); - + drawObject( Colors[ ObjectColor ] ); } + void touch() { uint8_t n, id[ 2 ]; @@ -207,10 +245,19 @@ void touch() { if ( !t->current.isClear() && t->previous.isClear() ) { touchDown( t->current.x, t->current.y ); t->original = t->current; + t->touchDownTime = millis(); } else { if ( t->current.isClear() && !t->previous.isClear() ) { touchUp( t->previous.x, t->previous.y ); + unsigned long up = millis(); + if ( ( up - t->touchDownTime ) < TOUCH_TAP_TIME ) { + touchTap( t->current.x, t->current.y ); + if ( ( up - t->touchUpTime ) < TOUCH_DOUBLE_TAP_TIME ) { + touchDoubleTap( t->current.x, t->current.y ); + } + t->touchUpTime = up; + } } else { if ( !t->current.isClear() && !t->previous.isClear() ) { touchMove( t->current.x, t->current.y ); From e410a56557dce7da1f586038e64ff3d4e362c4e0 Mon Sep 17 00:00:00 2001 From: davidthings Date: Sat, 28 Mar 2015 11:03:09 -0700 Subject: [PATCH 5/7] Added Zoom and fixed Tap and Double Tap Locii --- examples/Multitouch/Multitouch.ino | 132 +++++++++++++++++++++++------ 1 file changed, 105 insertions(+), 27 deletions(-) diff --git a/examples/Multitouch/Multitouch.ino b/examples/Multitouch/Multitouch.ino index 61b65b4..03a6ac8 100644 --- a/examples/Multitouch/Multitouch.ino +++ b/examples/Multitouch/Multitouch.ino @@ -27,8 +27,14 @@ Adafruit_FT6206 ctp = Adafruit_FT6206(); #define TFT_DC 9 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); -#define TOUCH_TAP_TIME 200 +#define TOUCH_TAP_TIME 300 #define TOUCH_DOUBLE_TAP_TIME 500 +#define TOUCH_ZOOM_MINIMUM 10 +#define TOUCH_ZOOM_MINIMUM_SQ ( TOUCH_ZOOM_MINIMUM * TOUCH_ZOOM_MINIMUM ) +#define TOUCH_TAP_MAXIMUM_DISTANCE 10 +#define TOUCH_TAP_MAXIMUM_DISTANCE_SQ TOUCH_TAP_MAXIMUM_DISTANCE * TOUCH_TAP_MAXIMUM_DISTANCE +#define TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE 20 +#define TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE_SQ TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE * TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE #define XSIZE 240 #define YSIZE 320 @@ -39,21 +45,22 @@ Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); #define TOUCH_TRIANGLE_X 32 // 40 * cos( 30 ) = 32 #define TOUCH_TRIANGLE_Y 20 // 40 * sin( 30 ) = 20 -int Colors[ ] = { ILI9341_DARKGREEN, ILI9341_BLUE, ILI9341_RED }; +int Colors[ ] = { ILI9341_BLUE, ILI9341_RED }; int Touch = ILI9341_DARKGREY; int Background = ILI9341_BLACK; // Going to have a thing -#define OBJECT_SIZE_MINIMUM XSIZE / 32 +#define OBJECT_SIZE_MINIMUM XSIZE / 6 #define OBJECT_SIZE_MAXIMUM XSIZE / 2 #define OBJECT_TYPE_COUNT 3 int ObjectX = XSIZE / 2; int ObjectY = YSIZE / 2; -int ObjectSize = XSIZE / 8; +int ObjectSize = XSIZE / 4; uint8_t ObjectColor = 0; uint8_t ObjectType = 0; +int ObjectZoom = 0; class CtpPoint { public: @@ -64,17 +71,35 @@ public: void set( int x_, int y_ ) { x = x_; y = y_; } void clear() { x = -1; y = -1; } bool isClear() { return ( ( x == -1 ) && ( y == -1 ) ); } + CtpPoint operator-(CtpPoint p ) { + return CtpPoint( x - p.x, y - p.y ); + } bool operator==(CtpPoint p) { return ( ( p.x == x ) && ( p.y == y ) ); } bool operator!=(CtpPoint p) { return ( ( p.x != x ) || ( p.y != y ) ); } + int lengthSq() { + return x * x + y * y; + } + int length() { + return sqrt( lengthSq() ); + } + int distanceSq( CtpPoint p ) { + int dx = p.x - x; + int dy = p.y - y; + return ( dx * dx ) + ( dy * dy ); + } + int distance( CtpPoint p ) { + return sqrt( distanceSq( p ) ); + } }; class CtpTouch { public: CtpTouch() {} + CtpPoint tap; CtpPoint original; CtpPoint current; CtpPoint previous; @@ -86,13 +111,18 @@ public: void drawObject( int color = Background ) { switch ( ObjectType ) { case 0: - tft.fillCircle( ObjectX, ObjectY, ObjectSize, color ); + tft.drawCircle( ObjectX, ObjectY, ObjectSize, color ); + tft.drawCircle( ObjectX, ObjectY, ObjectSize - 4, color ); break; case 1: - tft.fillRect( ObjectX - ObjectSize, ObjectY - ObjectSize, 2 * ObjectSize, 2 * ObjectSize, color ); + tft.drawRect( ObjectX - ObjectSize, ObjectY - ObjectSize, 2 * ObjectSize, 2 * ObjectSize, color ); + tft.drawRect( ObjectX - ObjectSize + 4, ObjectY - ObjectSize + 4, 2 * ObjectSize - 8, 2 * ObjectSize - 8, color ); break; case 2: - tft.fillTriangle( ObjectX, ObjectY - 3 * ObjectSize / 2, ObjectX - 21 * ObjectSize / 16, ObjectY + 3 * ObjectSize / 4 , ObjectX + 21 * ObjectSize / 16, ObjectY + 3 * ObjectSize / 4, color ); + tft.drawTriangle( ObjectX, ObjectY - 3 * ObjectSize / 2, ObjectX - 21 * ObjectSize / 16, ObjectY + 3 * ObjectSize / 4 , ObjectX + 21 * ObjectSize / 16, ObjectY + 3 * ObjectSize / 4, color ); + tft.drawTriangle( ObjectX, ObjectY - 3 * ObjectSize / 2 + 5, + ObjectX - 21 * ObjectSize / 16 + 5, ObjectY + 3 * ObjectSize / 4 -3, + ObjectX + 21 * ObjectSize / 16 -5, ObjectY + 3 * ObjectSize / 4 -3, color ); break; } } @@ -119,6 +149,7 @@ void setup(void) { for ( uint8_t i = 0; i < 2; i++) { CtpTouch* t = &CtpTouches[ i ]; + t->tap.clear(); t->original.clear(); t->current.clear(); t->previous.clear(); @@ -130,34 +161,36 @@ void setup(void) { } bool Dragging = false; +uint8_t DraggingIndex = 0; int DraggingOffsetX = 0; int DraggingOffsetY = 0; -void touchDown( int x, int y ) { +void touchDown( int x, int y, int i ) { int dx = x - ObjectX; int dy = y - ObjectY; - Serial.println( "Touch Down" ); + //Serial.println( "Touch Down" ); int d2 = ( dx * dx + dy * dy ); - if ( d2 < ObjectSize * ObjectSize ) { + if ( d2 < ObjectSize * ObjectSize && Dragging == false ) { Serial.println( " Object Hit!" ); Serial.print( " dx " ); Serial.print( dx ); Serial.print( " dy" ); Serial.println( dy ); Dragging = true; + DraggingIndex = i; DraggingOffsetX = dx; DraggingOffsetY = dy; } } -void touchMove( int x, int y ) { - Serial.println( "Touch Move" ); +void touchMove( int x, int y, int i ) { + //Serial.println( "Touch Move" ); if ( Dragging ) { Serial.println( " Object Move" ); } } -void touchUp( int x, int y ) { - Serial.println( "Touch Up" ); - if ( Dragging ) { +void touchUp( int x, int y, int i ) { + //Serial.println( "Touch Up" ); + if ( Dragging && DraggingIndex == i) { Serial.println( " Object Release" ); Dragging = false; @@ -168,6 +201,7 @@ void touchUp( int x, int y ) { Serial.print( " x " ); Serial.print( x ); Serial.print( " OY " ); Serial.println( y ); Serial.print( " Ox " ); Serial.print( ObjectX ); Serial.print( " OY " ); Serial.println( ObjectY ); + ObjectX = x - DraggingOffsetX; ObjectY = y - DraggingOffsetY; @@ -179,23 +213,38 @@ void touchUp( int x, int y ) { if ( ObjectX >= XSIZE ) ObjectX = XSIZE - 1; if ( ObjectY >= YSIZE ) ObjectY = YSIZE - 1; + // In case there was a zoom + ObjectSize += ObjectZoom; + if ( ObjectSize < OBJECT_SIZE_MINIMUM ) + ObjectSize = OBJECT_SIZE_MINIMUM; + if ( ObjectSize > OBJECT_SIZE_MAXIMUM ) + ObjectSize = OBJECT_SIZE_MAXIMUM; + ObjectZoom = 0; + drawObject( Colors[ ObjectColor ] ); } } } -void touchTap( int x, int y ) { - Serial.println( "Tap" ); +void touchTap( int x, int y, int i ) { + Serial.print( "Tap" ); } -void touchDoubleTap( int x, int y ) { +void touchDoubleTap( int x, int y, int i ) { Serial.println( "DoubleTap" ); eraseObject(); ObjectType = ( ObjectType + 1 ) % OBJECT_TYPE_COUNT; drawObject( Colors[ ObjectColor ] ); } +void TouchZoom( int d ) { + Serial.print( "ZOOOM " ); + Serial.println( d ); + if ( Dragging ) + ObjectZoom = d; +} + void loop() { touch(); @@ -238,29 +287,58 @@ void touch() { CtpTouches[ 1 ].current.clear(); } + // Two Finger Gestures + CtpTouch *t0 = &CtpTouches[ 0 ]; + CtpTouch *t1 = &CtpTouches[ 1 ]; + if ( n == 2 && ( t0->current != t0->previous || t1->current != t1->previous ) ) { + // Pinch Zoom + int dOriginalSq = t0->original.distanceSq( t1->original ); + int dCurrentSq = t0->current.distanceSq( t1->current ); + int dZoomSq = dCurrentSq - dOriginalSq; + if ( abs( dZoomSq ) > TOUCH_ZOOM_MINIMUM_SQ ) { + TouchZoom( sqrt( dCurrentSq ) - sqrt( dOriginalSq ) ); + } + + // Scroll + CtpPoint d0 = t0->current-t0->previous; + CtpPoint d1 = t0->current-t0->previous; + + } + for ( uint8_t i = 0; i < 2; i++) { CtpTouch* t = &CtpTouches[ i ]; // Create single touch events if ( !t->current.isClear() && t->previous.isClear() ) { - touchDown( t->current.x, t->current.y ); + touchDown( t->current.x, t->current.y, i ); t->original = t->current; t->touchDownTime = millis(); } else { if ( t->current.isClear() && !t->previous.isClear() ) { - touchUp( t->previous.x, t->previous.y ); - unsigned long up = millis(); - if ( ( up - t->touchDownTime ) < TOUCH_TAP_TIME ) { - touchTap( t->current.x, t->current.y ); - if ( ( up - t->touchUpTime ) < TOUCH_DOUBLE_TAP_TIME ) { - touchDoubleTap( t->current.x, t->current.y ); + touchUp( t->previous.x, t->previous.y, i ); + int dSq = t->original.distanceSq( t->previous ); + Serial.print( "Tap Distance Sq " ); + Serial.println( dSq ); + if ( dSq < TOUCH_TAP_MAXIMUM_DISTANCE_SQ ) { + unsigned long up = millis(); + if ( ( up - t->touchDownTime ) < TOUCH_TAP_TIME ) { + touchTap( t->current.x, t->current.y, i ); + if ( ( up - t->touchUpTime ) < TOUCH_DOUBLE_TAP_TIME ) { + int dCSq = t->tap.distanceSq( t->previous ); + Serial.print( "Double Tap Distance Sq " ); + Serial.println( dCSq ); + if ( dCSq < TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE_SQ ) + touchDoubleTap( t->current.x, t->current.y, i ); + up = 0; + } + t->touchUpTime = up; } - t->touchUpTime = up; + t->tap = t->previous; } } else { if ( !t->current.isClear() && !t->previous.isClear() ) { - touchMove( t->current.x, t->current.y ); + touchMove( t->current.x, t->current.y, i ); } } } From 85431ff9b96baae2d4ec4e1607e2eed6ed2b1a58 Mon Sep 17 00:00:00 2001 From: davidthings Date: Sat, 28 Mar 2015 15:48:54 -0700 Subject: [PATCH 6/7] Added Scroll, and cleaned up the code a little. Some comments. --- examples/Multitouch/Multitouch.ino | 208 ++++++++++++++++++++++------- 1 file changed, 157 insertions(+), 51 deletions(-) diff --git a/examples/Multitouch/Multitouch.ino b/examples/Multitouch/Multitouch.ino index 03a6ac8..fabaf87 100644 --- a/examples/Multitouch/Multitouch.ino +++ b/examples/Multitouch/Multitouch.ino @@ -3,13 +3,9 @@ captouch shield ----> http://www.adafruit.com/products/1947 - Check out the links above for our tutorials and wiring diagrams + Check out the link above for tutorials and wiring diagrams - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing - products from Adafruit! - - Written by David Williams + Written by David Williams, based on original by Lady Ada. MIT license, all text above must be included in any redistribution ****************************************************/ @@ -22,11 +18,15 @@ // The FT6206 uses hardware I2C (SCL/SDA) Adafruit_FT6206 ctp = Adafruit_FT6206(); +// Display Section // The display also uses hardware SPI, plus #9 & #10 #define TFT_CS 10 #define TFT_DC 9 Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +#define XSIZE 240 +#define YSIZE 320 +// Touch constants #define TOUCH_TAP_TIME 300 #define TOUCH_DOUBLE_TAP_TIME 500 #define TOUCH_ZOOM_MINIMUM 10 @@ -35,42 +35,55 @@ Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); #define TOUCH_TAP_MAXIMUM_DISTANCE_SQ TOUCH_TAP_MAXIMUM_DISTANCE * TOUCH_TAP_MAXIMUM_DISTANCE #define TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE 20 #define TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE_SQ TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE * TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE +#define TOUCH_SCROLL_COSTHETA 0.8 +#define TOUCH_SCROLL_MINIMUM_DISTANCE 10 -#define XSIZE 240 -#define YSIZE 320 -#define COLOR_COUNT 3 - +// Touch glyphs #define TOUCH_RADIUS 30 #define TOUCH_TRIANGLE_TOP 40 #define TOUCH_TRIANGLE_X 32 // 40 * cos( 30 ) = 32 #define TOUCH_TRIANGLE_Y 20 // 40 * sin( 30 ) = 20 -int Colors[ ] = { ILI9341_BLUE, ILI9341_RED }; -int Touch = ILI9341_DARKGREY; -int Background = ILI9341_BLACK; -// Going to have a thing +// Constants and variables for rendering the main Object +// Rendering constants for the main display #define OBJECT_SIZE_MINIMUM XSIZE / 6 #define OBJECT_SIZE_MAXIMUM XSIZE / 2 +#define COLOR_COUNT 4 + +int Colors[ ] = { ILI9341_BLUE, ILI9341_RED, ILI9341_ORANGE, ILI9341_PINK }; +int Touch = ILI9341_DARKGREY; +int Background = ILI9341_BLACK; + #define OBJECT_TYPE_COUNT 3 +#define OBJECT_SCROLL_THRESHOLD 30 int ObjectX = XSIZE / 2; int ObjectY = YSIZE / 2; int ObjectSize = XSIZE / 4; -uint8_t ObjectColor = 0; +int ObjectColor = 0; uint8_t ObjectType = 0; int ObjectZoom = 0; +int ObjectColorScroll = 0; +// Touch event code records Dragging information here +bool Dragging = false; +uint8_t DraggingIndex = 0; +int DraggingOffsetX = 0; +int DraggingOffsetY = 0; + +// Helper point class with several vector functions +// elements are set to -1 to signify no touch ("released" state) class CtpPoint { public: int x; int y; - CtpPoint() { clear(); } + CtpPoint() { release(); } CtpPoint( int x_, int y_ ): x( x_ ), y( y_ ) {} void set( int x_, int y_ ) { x = x_; y = y_; } - void clear() { x = -1; y = -1; } - bool isClear() { return ( ( x == -1 ) && ( y == -1 ) ); } + void release() { x = -1; y = -1; } + bool isReleased() { return ( ( x == -1 ) && ( y == -1 ) ); } CtpPoint operator-(CtpPoint p ) { return CtpPoint( x - p.x, y - p.y ); } @@ -94,8 +107,18 @@ public: int distance( CtpPoint p ) { return sqrt( distanceSq( p ) ); } + int dotProduct( CtpPoint p ) { + return x * p.x + y * p.y; + } + CtpPoint mean( CtpPoint p ) { + return CtpPoint( (x + p.x )/ 2, ( y + p.y ) / 2 ); + } }; +// Class for recording touch events +// Ordered by touch ID, not location in the touch array +// I.e. if the first (0) slot of the touch array occupies a touch event from touch id 1, it would +// transfer information into CtpTouches[ 1 ], not CtpTouches[ 0 ] class CtpTouch { public: CtpTouch() {} @@ -108,6 +131,8 @@ public: } CtpTouches[ 2 ]; +// Draw our main onscreen object - one of three different shapes, +// in a specified color void drawObject( int color = Background ) { switch ( ObjectType ) { case 0: @@ -127,18 +152,20 @@ void drawObject( int color = Background ) { } } +// To Erase the shape, just draw it again in the background color void eraseObject() { drawObject(); } void setup(void) { - while (!Serial); // used for leonardo debugging + + delay(2000); + + //while (!Serial); // used for leonardo debugging Serial.begin(115200); Serial.println(F("Multitouch!")); - delay(500); - tft.begin(); ctp.begin(40); // pass in 'sensitivity' coefficient @@ -147,24 +174,22 @@ void setup(void) { tft.fillScreen( Background ); + // Set the touch structure up, for ( uint8_t i = 0; i < 2; i++) { CtpTouch* t = &CtpTouches[ i ]; - t->tap.clear(); - t->original.clear(); - t->current.clear(); - t->previous.clear(); + t->tap.release(); + t->original.release(); + t->current.release(); + t->previous.release(); t->touchDownTime = 0; t->touchUpTime = 0; } + // Draw the object for the first time drawObject( Colors[ ObjectColor ] ); } -bool Dragging = false; -uint8_t DraggingIndex = 0; -int DraggingOffsetX = 0; -int DraggingOffsetY = 0; - +// Event called when a touch is detected void touchDown( int x, int y, int i ) { int dx = x - ObjectX; int dy = y - ObjectY; @@ -181,6 +206,7 @@ void touchDown( int x, int y, int i ) { } } +// Event called when a touch point is moving void touchMove( int x, int y, int i ) { //Serial.println( "Touch Move" ); if ( Dragging ) { @@ -188,8 +214,27 @@ void touchMove( int x, int y, int i ) { } } +// Event called when a finger is lifted ioff +// Does quite a lot: +// - changes color if there's been a scroll +// - if there was dragging, move the object +// - if there was zooming, resize the object + void touchUp( int x, int y, int i ) { //Serial.println( "Touch Up" ); + // In case there was a Scroll + if ( ObjectColorScroll != 0 ) { + Serial.print( "Color Shift" ); + Serial.print( ObjectColorScroll ); + Serial.print( " Color " ); + Serial.println( ObjectColor ); + if ( ObjectColorScroll > OBJECT_SCROLL_THRESHOLD ) + ObjectColor = ( ObjectColor + 1 ) % COLOR_COUNT; + if ( ObjectColorScroll < -OBJECT_SCROLL_THRESHOLD ) + ObjectColor = ( ObjectColor - 1 ) % COLOR_COUNT; + ObjectColorScroll = 0; + } + if ( Dragging && DraggingIndex == i) { Serial.println( " Object Release" ); Dragging = false; @@ -227,10 +272,12 @@ void touchUp( int x, int y, int i ) { } } +// Event called when someone taps the screen void touchTap( int x, int y, int i ) { Serial.print( "Tap" ); } +// Event called when someone double taps the screen void touchDoubleTap( int x, int y, int i ) { Serial.println( "DoubleTap" ); eraseObject(); @@ -238,26 +285,40 @@ void touchDoubleTap( int x, int y, int i ) { drawObject( Colors[ ObjectColor ] ); } + +// Called when a Pinch or Zoom Gesture is detected void TouchZoom( int d ) { - Serial.print( "ZOOOM " ); - Serial.println( d ); + //Serial.print( "ZOOOM " ); + //Serial.println( d ); if ( Dragging ) ObjectZoom = d; } -void loop() { +// Called when a Scroll is detected, we'll just attend to the +// scrolls in the X direction +void TouchScroll( int dx, int dy ) { + Serial.print( "SCROLL " ); + Serial.print( dx ); + Serial.print( ", " ); + Serial.println( dy ); + ObjectColorScroll = dx; +} +void loop() { + // Do the touch processing touch(); + // draw the object, for fun, again drawObject( Colors[ ObjectColor ] ); } - +// The meat of the touch() processing void touch() { uint8_t n, id[ 2 ]; uint16_t x[ 2 ], y[ 2 ]; + // Use the new readMultiData() function n = ctp.readMultiData( &id[ 0 ], &x[ 0 ], &y[ 0 ], &id[ 1 ], &x[ 1 ], &y[ 1 ] ); // Extract and update the touch information @@ -267,84 +328,129 @@ void touch() { int xi = map(x[ i ], 0, 240, 240, 0); int yi = map(y[ i ], 0, 320, 320, 0); //Serial.print( "T" ); Serial.print( i ); Serial.print( " " ); Serial.print( idi ); Serial.print( " " ); Serial.print( xi ); Serial.print( "," ); Serial.println( yi ); + // Save the touch data away if ( idi == 0 ) { CtpTouches[ 0 ].current.set( xi, yi ); if ( n == 1 ) { - CtpTouches[ 1 ].current.clear( ); + // if this is the only touch, release the other + CtpTouches[ 1 ].current.release( ); } } else { CtpTouches[ 1 ].current.set( xi, yi ); if ( n == 1 ) { - CtpTouches[ 0 ].current.clear(); + // if this is the only touch, release the other + CtpTouches[ 0 ].current.release(); } } } } + // If there were no touches, release all the current position records if ( n == 0 ) { - CtpTouches[ 0 ].current.clear(); - CtpTouches[ 1 ].current.clear(); + CtpTouches[ 0 ].current.release(); + CtpTouches[ 1 ].current.release(); } // Two Finger Gestures CtpTouch *t0 = &CtpTouches[ 0 ]; CtpTouch *t1 = &CtpTouches[ 1 ]; + // If there are 2 touches, and the position has changed if ( n == 2 && ( t0->current != t0->previous || t1->current != t1->previous ) ) { // Pinch Zoom + // Calculate the distance between the original mouse positions (when fingers were placed) int dOriginalSq = t0->original.distanceSq( t1->original ); + // Calculate the interdigit distance now int dCurrentSq = t0->current.distanceSq( t1->current ); + // WOrk out the difference int dZoomSq = dCurrentSq - dOriginalSq; + // If the change in positions excedes a threshold, call it a Zoom, sending the change in + // distance between finger tips if ( abs( dZoomSq ) > TOUCH_ZOOM_MINIMUM_SQ ) { TouchZoom( sqrt( dCurrentSq ) - sqrt( dOriginalSq ) ); } // Scroll - CtpPoint d0 = t0->current-t0->previous; - CtpPoint d1 = t0->current-t0->previous; + // Find the vectors from each touch's original to current positions + CtpPoint d0 = t0->current-t0->original; + CtpPoint d1 = t1->current-t1->original; + int d0l = d0.length(); + int d1l = d1.length(); + // See if they're in the same direction + float dp = (float)d0.dotProduct( d1 ) / ( d0l * d1l ); + // If so, might be a Scroll + if ( dp > 0.8 ) { + // Work out the mean direction + CtpPoint m = d0.mean( d1 ); + int ml = m.length(); + // If the mean vector is long enough, notify the scroll, sending the current scroll vector + if ( ml > TOUCH_SCROLL_MINIMUM_DISTANCE ) + TouchScroll( m.x, m.y ); + } + Serial.print( "Scroll cos theta " ); + Serial.println( dp ); } + // Now just the regular touch events for ( uint8_t i = 0; i < 2; i++) { CtpTouch* t = &CtpTouches[ i ]; - // Create single touch events - if ( !t->current.isClear() && t->previous.isClear() ) { + // Check for touchDown (previously was released, now not) + if ( !t->current.isReleased() && t->previous.isReleased() ) { touchDown( t->current.x, t->current.y, i ); t->original = t->current; t->touchDownTime = millis(); } else { - if ( t->current.isClear() && !t->previous.isClear() ) { + // Check for touchUp (previously, was not released, now is) + if ( t->current.isReleased() && !t->previous.isReleased() ) { touchUp( t->previous.x, t->previous.y, i ); + + // Check for a Tap event, need to know the distance from the original + // touchDown location to the touchUp location int dSq = t->original.distanceSq( t->previous ); - Serial.print( "Tap Distance Sq " ); - Serial.println( dSq ); + // Serial.print( "Tap Distance Sq " ); + // Serial.println( dSq ); + // For a legit Tap event, the down-up distance has to be small if ( dSq < TOUCH_TAP_MAXIMUM_DISTANCE_SQ ) { + // Also a legit tap event has to occur within a narrow time window unsigned long up = millis(); if ( ( up - t->touchDownTime ) < TOUCH_TAP_TIME ) { + // OK. So that was a tap. touchTap( t->current.x, t->current.y, i ); + // Was that a double tap? + // The second tap needs to occur soon after the firt if ( ( up - t->touchUpTime ) < TOUCH_DOUBLE_TAP_TIME ) { + // And within a short distance from the first int dCSq = t->tap.distanceSq( t->previous ); - Serial.print( "Double Tap Distance Sq " ); - Serial.println( dCSq ); - if ( dCSq < TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE_SQ ) + // Serial.print( "Double Tap Distance Sq " ); + // Serial.println( dCSq ); + if ( dCSq < TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE_SQ ) { + // OK signal teh double tap touchDoubleTap( t->current.x, t->current.y, i ); + } + // Prevent an ongoing sequence of double taps on each subsequent tap up = 0; } + // Save the up time t->touchUpTime = up; } + // Save last tap location for a potential future double tap t->tap = t->previous; } } else { - if ( !t->current.isClear() && !t->previous.isClear() ) { + // Wasn't a TouchDown or TouchUp, was it a touchMove()? + if ( !t->current.isReleased() && !t->previous.isReleased() ) { touchMove( t->current.x, t->current.y, i ); } } } // Drawing the touch - if ( !t->previous.isClear() && t->previous != t->current ) { + // This is just for touch feedback. Normally you wouldn't render the + // touch points at all. + if ( !t->previous.isReleased() && t->previous != t->current ) { int x = t->previous.x; int y = t->previous.y; if ( i == 0 ) @@ -353,7 +459,7 @@ void touch() { tft.drawTriangle( x, y - TOUCH_TRIANGLE_TOP, x - TOUCH_TRIANGLE_X, y + TOUCH_TRIANGLE_Y, x + TOUCH_TRIANGLE_X, y + TOUCH_TRIANGLE_Y, Background ); } } - if ( !t->current.isClear() && t->previous != t->current ) { + if ( !t->current.isReleased() && t->previous != t->current ) { int x = t->current.x; int y = t->current.y; if ( i == 0 ) From 694718c012e11991db81c5a25e718c15ddedc81e Mon Sep 17 00:00:00 2001 From: davidthings Date: Mon, 30 Mar 2015 07:20:09 -0700 Subject: [PATCH 7/7] tuning multitouch --- Adafruit_FT6206.cpp | 8 ++++++++ examples/Multitouch/Multitouch.ino | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Adafruit_FT6206.cpp b/Adafruit_FT6206.cpp index cf9f4e0..be273c1 100644 --- a/Adafruit_FT6206.cpp +++ b/Adafruit_FT6206.cpp @@ -183,6 +183,14 @@ uint8_t Adafruit_FT6206::readMultiData(uint8_t *id0, uint16_t *x0, uint16_t *y0, // call the main data reader... it does the job readData( x0, y0 ); + // readData returns 0 - 0 if there was no touch when it got around to reading it + // -1's might have been another good choice + if ( x0 == 0 && y0 == 0 ) { + *id0 = 0x0F; + *id1 = 0x0F; + return 0; + } + *id0 = touchID[ 0 ]; *id1 = touchID[ 1 ]; *x1 = touchX[ 1 ]; diff --git a/examples/Multitouch/Multitouch.ino b/examples/Multitouch/Multitouch.ino index fabaf87..05e3817 100644 --- a/examples/Multitouch/Multitouch.ino +++ b/examples/Multitouch/Multitouch.ino @@ -418,7 +418,7 @@ void touch() { unsigned long up = millis(); if ( ( up - t->touchDownTime ) < TOUCH_TAP_TIME ) { // OK. So that was a tap. - touchTap( t->current.x, t->current.y, i ); + touchTap( t->previous.x, t->previous.y, i ); // Was that a double tap? // The second tap needs to occur soon after the firt if ( ( up - t->touchUpTime ) < TOUCH_DOUBLE_TAP_TIME ) { @@ -428,7 +428,7 @@ void touch() { // Serial.println( dCSq ); if ( dCSq < TOUCH_DOUBLE_TAP_MAXIMUM_DISTANCE_SQ ) { // OK signal teh double tap - touchDoubleTap( t->current.x, t->current.y, i ); + touchDoubleTap( t->previous.x, t->previous.y, i ); } // Prevent an ongoing sequence of double taps on each subsequent tap up = 0;