2014-03-28 02:50:40 +01:00
using System ;
2017-04-30 15:42:09 +02:00
2015-02-08 22:51:52 +01:00
namespace DS4Windows
2014-03-28 02:50:40 +01:00
{
public class TouchpadEventArgs : EventArgs
{
public readonly Touch [ ] touches = null ;
2017-06-05 10:31:29 +02:00
public readonly DateTime timeStamp ;
2014-03-28 02:50:40 +01:00
public readonly bool touchButtonPressed ;
2017-06-05 10:31:29 +02:00
public TouchpadEventArgs ( DateTime utcTimestamp , bool tButtonDown , Touch t0 , Touch t1 = null )
2014-03-28 02:50:40 +01:00
{
if ( t1 ! = null )
{
touches = new Touch [ 2 ] ;
touches [ 0 ] = t0 ;
touches [ 1 ] = t1 ;
}
else if ( t0 ! = null )
{
touches = new Touch [ 1 ] ;
touches [ 0 ] = t0 ;
}
2017-06-05 10:31:29 +02:00
2014-03-28 02:50:40 +01:00
touchButtonPressed = tButtonDown ;
2017-06-05 10:31:29 +02:00
timeStamp = utcTimestamp ;
2014-03-28 02:50:40 +01:00
}
}
public class Touch
{
2017-12-22 09:31:14 +01:00
public int hwX , hwY , deltaX , deltaY ;
public byte touchID ;
public Touch previousTouch ;
internal Touch ( int X , int Y , byte tID , Touch prevTouch = null )
{
populate ( X , Y , tID , prevTouch ) ;
}
internal void populate ( int X , int Y , byte tID , Touch prevTouch = null )
2014-03-28 02:50:40 +01:00
{
hwX = X ;
hwY = Y ;
touchID = tID ;
previousTouch = prevTouch ;
if ( previousTouch ! = null )
{
deltaX = X - previousTouch . hwX ;
deltaY = Y - previousTouch . hwY ;
}
}
}
public class DS4Touchpad
{
2014-03-29 06:29:08 +01:00
public event EventHandler < TouchpadEventArgs > TouchesBegan = null ; // finger one or two landed (or both, or one then two, or two then one; any touches[] count increase)
public event EventHandler < TouchpadEventArgs > TouchesMoved = null ; // deltaX/deltaY are set because one or both fingers were already down on a prior sensor reading
public event EventHandler < TouchpadEventArgs > TouchesEnded = null ; // all fingers lifted
public event EventHandler < TouchpadEventArgs > TouchButtonDown = null ; // touchpad pushed down until the button clicks
public event EventHandler < TouchpadEventArgs > TouchButtonUp = null ; // touchpad button released
public event EventHandler < EventArgs > TouchUnchanged = null ; // no status change for the touchpad itself... but other sensors may have changed, or you may just want to do some processing
2017-06-05 10:31:29 +02:00
public event EventHandler < EventArgs > PreTouchProcess = null ; // used to publish that a touch packet is about to be processed
2014-03-29 06:29:08 +01:00
2014-03-28 02:50:40 +01:00
public readonly static int TOUCHPAD_DATA_OFFSET = 35 ;
2014-03-29 06:29:08 +01:00
internal int lastTouchPadX1 , lastTouchPadY1 ,
2014-03-28 02:50:40 +01:00
lastTouchPadX2 , lastTouchPadY2 ; // tracks 0, 1 or 2 touches; we maintain touch 1 and 2 separately
2014-03-29 06:29:08 +01:00
internal bool lastTouchPadIsDown ;
internal bool lastIsActive1 , lastIsActive2 ;
internal byte lastTouchID1 , lastTouchID2 ;
internal byte [ ] previousPacket = new byte [ 8 ] ;
2017-12-22 09:31:14 +01:00
private Touch tPrev0 , tPrev1 , t0 , t1 ;
public DS4Touchpad ( )
{
tPrev0 = new Touch ( 0 , 0 , 0 ) ;
tPrev1 = new Touch ( 0 , 0 , 0 ) ;
t0 = new Touch ( 0 , 0 , 0 ) ;
t1 = new Touch ( 0 , 0 , 0 ) ;
}
2014-03-28 02:50:40 +01:00
2014-03-29 06:29:08 +01:00
// We check everything other than the not bothering with not-very-useful TouchPacketCounter.
private bool PacketChanged ( byte [ ] data , int touchPacketOffset )
{
bool changed = false ;
2017-12-15 03:54:32 +01:00
for ( int i = 0 , arLen = previousPacket . Length ; ! changed & & i < arLen ; i + + )
2014-03-29 06:29:08 +01:00
{
byte oldValue = previousPacket [ i ] ;
previousPacket [ i ] = data [ i + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] ;
if ( previousPacket [ i ] ! = oldValue )
changed = true ;
}
2017-06-05 10:31:29 +02:00
2014-03-29 06:29:08 +01:00
return changed ;
}
public void handleTouchpad ( byte [ ] data , DS4State sensors , int touchPacketOffset = 0 )
2014-03-28 02:50:40 +01:00
{
2017-06-05 10:31:29 +02:00
PreTouchProcess ? . Invoke ( this , EventArgs . Empty ) ;
2014-03-28 02:50:40 +01:00
bool touchPadIsDown = sensors . TouchButton ;
2014-03-29 06:29:08 +01:00
if ( ! PacketChanged ( data , touchPacketOffset ) & & touchPadIsDown = = lastTouchPadIsDown )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( TouchUnchanged ! = null )
TouchUnchanged ( this , EventArgs . Empty ) ;
return ;
}
2017-06-05 10:31:29 +02:00
2014-03-29 06:29:08 +01:00
byte touchID1 = ( byte ) ( data [ 0 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] & 0x7F ) ;
byte touchID2 = ( byte ) ( data [ 4 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] & 0x7F ) ;
2017-07-27 12:41:44 +02:00
int currentX1 = ( ( data [ 2 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] & 0x0F ) < < 8 ) | data [ 1 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] ;
int currentY1 = ( data [ 3 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] < < 4 ) | ( ( data [ 2 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] & 0xF0 ) > > 4 ) ;
int currentX2 = ( ( data [ 6 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] & 0x0F ) < < 8 ) | data [ 5 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] ;
int currentY2 = ( data [ 7 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] < < 4 ) | ( ( data [ 6 + TOUCHPAD_DATA_OFFSET + touchPacketOffset ] & 0xF0 ) > > 4 ) ;
2014-03-29 06:29:08 +01:00
TouchpadEventArgs args ;
if ( sensors . Touch1 | | sensors . Touch2 )
{
if ( ( sensors . Touch1 & & ! lastIsActive1 ) | | ( sensors . Touch2 & & ! lastIsActive2 ) )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( TouchesBegan ! = null )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( sensors . Touch1 & & sensors . Touch2 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX1 , currentY1 , touchID1 ) ; t1 . populate ( currentX2 , currentY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 , t1 ) ;
}
2014-03-29 06:29:08 +01:00
else if ( sensors . Touch1 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX1 , currentY1 , touchID1 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-29 06:29:08 +01:00
else
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX2 , currentY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-29 06:29:08 +01:00
TouchesBegan ( this , args ) ;
2014-03-28 02:50:40 +01:00
}
}
2014-03-29 06:29:08 +01:00
else if ( sensors . Touch1 = = lastIsActive1 & & sensors . Touch2 = = lastIsActive2 & & TouchesMoved ! = null )
2014-03-28 02:50:40 +01:00
{
2017-12-22 09:31:14 +01:00
Touch currentT0 , currentT1 ;
2014-03-29 06:29:08 +01:00
if ( sensors . Touch1 & & sensors . Touch2 )
2014-03-28 02:50:40 +01:00
{
2017-12-22 09:31:14 +01:00
tPrev0 . populate ( lastTouchPadX1 , lastTouchPadY1 , lastTouchID1 ) ;
t0 . populate ( currentX1 , currentY1 , touchID1 , tPrev0 ) ;
currentT0 = t0 ;
tPrev1 . populate ( lastTouchPadX2 , lastTouchPadY2 , lastTouchID2 ) ;
t1 . populate ( currentX2 , currentY2 , touchID2 , tPrev1 ) ;
currentT1 = t1 ;
2014-03-29 06:29:08 +01:00
}
else if ( sensors . Touch1 )
{
2017-12-22 09:31:14 +01:00
tPrev0 . populate ( lastTouchPadX1 , lastTouchPadY1 , lastTouchID1 ) ;
t0 . populate ( currentX1 , currentY1 , touchID1 , tPrev0 ) ;
currentT0 = t0 ;
currentT1 = null ;
2014-03-28 02:50:40 +01:00
}
else
2014-03-29 06:29:08 +01:00
{
2017-12-22 09:31:14 +01:00
tPrev0 . populate ( lastTouchPadX2 , lastTouchPadY2 , lastTouchID2 ) ;
t0 . populate ( currentX2 , currentY2 , touchID2 , tPrev0 ) ;
currentT0 = t0 ;
currentT1 = null ;
2014-03-29 06:29:08 +01:00
}
2017-06-05 10:31:29 +02:00
2017-12-22 09:31:14 +01:00
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , currentT0 , currentT1 ) ;
2014-03-29 06:29:08 +01:00
TouchesMoved ( this , args ) ;
2014-03-28 02:50:40 +01:00
}
2014-03-29 06:29:08 +01:00
if ( ! lastTouchPadIsDown & & touchPadIsDown & & TouchButtonDown ! = null )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( sensors . Touch1 & & sensors . Touch2 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX1 , currentY1 , touchID1 ) ;
t1 . populate ( currentX2 , currentY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 , t1 ) ;
}
2014-03-29 06:29:08 +01:00
else if ( sensors . Touch1 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX1 , currentY1 , touchID1 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-28 02:50:40 +01:00
else
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX2 , currentY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-29 06:29:08 +01:00
TouchButtonDown ( this , args ) ;
2014-03-28 02:50:40 +01:00
}
2014-03-29 06:29:08 +01:00
else if ( lastTouchPadIsDown & & ! touchPadIsDown & & TouchButtonUp ! = null )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( sensors . Touch1 & & sensors . Touch2 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX1 , currentY1 , touchID1 ) ;
t1 . populate ( currentX2 , currentY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 , t1 ) ;
}
2014-03-29 06:29:08 +01:00
else if ( sensors . Touch1 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX1 , currentY1 , touchID1 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-29 06:29:08 +01:00
else
2017-12-22 09:31:14 +01:00
{
t0 . populate ( currentX2 , currentY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-28 02:50:40 +01:00
2014-03-29 06:29:08 +01:00
TouchButtonUp ( this , args ) ;
2014-03-28 02:50:40 +01:00
}
2014-03-29 06:29:08 +01:00
if ( sensors . Touch1 )
{
lastTouchPadX1 = currentX1 ;
lastTouchPadY1 = currentY1 ;
}
if ( sensors . Touch2 )
{
lastTouchPadX2 = currentX2 ;
lastTouchPadY2 = currentY2 ;
}
2017-06-05 10:31:29 +02:00
2014-03-28 02:50:40 +01:00
lastTouchPadIsDown = touchPadIsDown ;
}
else
{
2014-03-29 06:29:08 +01:00
if ( touchPadIsDown & & ! lastTouchPadIsDown )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( TouchButtonDown ! = null )
TouchButtonDown ( this , new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , null , null ) ) ;
2014-03-28 02:50:40 +01:00
}
2014-03-29 06:29:08 +01:00
else if ( ! touchPadIsDown & & lastTouchPadIsDown )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( TouchButtonUp ! = null )
TouchButtonUp ( this , new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , null , null ) ) ;
2014-03-28 02:50:40 +01:00
}
2014-03-29 06:29:08 +01:00
if ( ( lastIsActive1 | | lastIsActive2 ) & & TouchesEnded ! = null )
2014-03-28 02:50:40 +01:00
{
2014-03-29 06:29:08 +01:00
if ( lastIsActive1 & & lastIsActive2 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( lastTouchPadX1 , lastTouchPadY1 , touchID1 ) ;
t1 . populate ( lastTouchPadX2 , lastTouchPadY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 , t1 ) ;
}
2014-03-29 06:29:08 +01:00
else if ( lastIsActive1 )
2017-12-22 09:31:14 +01:00
{
t0 . populate ( lastTouchPadX1 , lastTouchPadY1 , touchID1 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-29 06:29:08 +01:00
else
2017-12-22 09:31:14 +01:00
{
t0 . populate ( lastTouchPadX2 , lastTouchPadY2 , touchID2 ) ;
args = new TouchpadEventArgs ( sensors . ReportTimeStamp , sensors . TouchButton , t0 ) ;
}
2014-03-29 06:29:08 +01:00
TouchesEnded ( this , args ) ;
2014-03-28 02:50:40 +01:00
}
}
2014-03-29 06:29:08 +01:00
lastIsActive1 = sensors . Touch1 ;
2014-03-28 02:50:40 +01:00
lastIsActive2 = sensors . Touch2 ;
2014-03-29 06:29:08 +01:00
lastTouchID1 = touchID1 ;
2014-03-28 02:50:40 +01:00
lastTouchID2 = touchID2 ;
lastTouchPadIsDown = touchPadIsDown ;
}
}
}