# include <stdio.h>
# include <stdlib.h>
# include <stdbool.h>
# include <assert.h>
# include <unistd.h>
# include <fcntl.h>
# include <dirent.h>
# include <sys/poll.h>
# include <linux/input.h>
# include "touch.h"
/* this macro is used to tell if "bit" is set in "array"
* it selects a byte from the array , and does a boolean AND
* operation with a byte that only has the relevant bit set .
* eg . to check for the 12 th bit , we do ( array [ 1 ] & 1 < < 4 )
*/
# define test_bit(bit, array) (array[bit / 8] & (1<<(bit%8)))
static int find_dev ( ) {
int err ;
int ret = - 1 ;
DIR * dir = opendir ( " /dev/input " ) ;
assert ( dir ) ;
struct dirent * de = NULL ;
while ( ( de = readdir ( dir ) ) ) {
if ( strncmp ( de - > d_name , " event " , 5 ) ) continue ;
int fd = openat ( dirfd ( dir ) , de - > d_name , O_RDONLY ) ;
assert ( fd > = 0 ) ;
unsigned char ev_bits [ KEY_MAX / 8 + 1 ] ;
err = ioctl ( fd , EVIOCGBIT ( EV_ABS , sizeof ( ev_bits ) ) , ev_bits ) ;
assert ( err > = 0 ) ;
if ( test_bit ( ABS_MT_POSITION_X , ev_bits ) & & test_bit ( ABS_MT_POSITION_Y , ev_bits ) ) {
ret = fd ;
break ;
}
close ( fd ) ;
}
closedir ( dir ) ;
return ret ;
}
void touch_init ( TouchState * s ) {
s - > fd = find_dev ( ) ;
assert ( s - > fd > = 0 ) ;
}
int touch_poll ( TouchState * s , int * out_x , int * out_y , int timeout ) {
assert ( out_x & & out_y ) ;
bool up = false ;
while ( true ) {
struct pollfd polls [ ] = { {
. fd = s - > fd ,
. events = POLLIN ,
} } ;
int err = poll ( polls , 1 , timeout ) ;
if ( err < 0 ) {
return - 1 ;
}
if ( ! ( polls [ 0 ] . revents & POLLIN ) ) {
break ;
}
struct input_event event ;
err = read ( polls [ 0 ] . fd , & event , sizeof ( event ) ) ;
if ( err < sizeof ( event ) ) {
return - 1 ;
}
switch ( event . type ) {
case EV_ABS :
if ( event . code = = ABS_MT_POSITION_X ) {
s - > last_x = event . value ;
} else if ( event . code = = ABS_MT_POSITION_Y ) {
s - > last_y = event . value ;
} else if ( event . code = = ABS_MT_TRACKING_ID & & event . value ! = - 1 ) {
up = true ;
}
break ;
default :
break ;
}
}
if ( up ) {
// adjust for flippening
* out_x = s - > last_y ;
* out_y = 1080 - s - > last_x ;
}
return up ;
}