2021-08-27 09:09:32 -07:00
# include <errno.h>
2021-08-26 10:26:53 -07:00
# include <fcntl.h>
# include <stdio.h>
# include <stdlib.h>
# include <time.h>
# include <unistd.h>
2021-08-27 09:09:32 -07:00
2021-08-26 10:26:53 -07:00
# include <linux/input.h>
2021-08-27 09:09:32 -07:00
# include <sys/epoll.h>
# define MAX_EVENTS 16
# define CONTENT_BUFFER_SIZE 32
static char * KEYBOARD = " k " ;
static char * MOUSE = " m " ;
2021-08-26 10:26:53 -07:00
2021-09-01 03:37:08 -07:00
int dump_event ( struct timespec * start , struct input_event * event , char * type ) ;
2021-08-27 09:09:32 -07:00
int event_content_keyboard ( char * buffer , int buffer_size , struct input_event * event ) ;
int event_content_mouse ( char * buffer , int buffer_size , struct input_event * event ) ;
2021-09-01 03:37:08 -07:00
int stream_events ( char * mouse_path , char * keyboard_path , int hotkey_scancode ) ;
2021-08-26 10:26:53 -07:00
static inline void timespec_diff ( struct timespec * a , struct timespec * b , struct timespec * result ) {
result - > tv_sec = a - > tv_sec - b - > tv_sec ;
result - > tv_nsec = a - > tv_nsec - b - > tv_nsec ;
if ( result - > tv_nsec < 0 ) {
- - result - > tv_sec ;
result - > tv_nsec + = 1000000000L ;
}
}
2021-09-01 03:37:08 -07:00
static inline void timeval_diff ( struct timeval * a , struct timeval * b , struct timeval * result ) {
result - > tv_sec = a - > tv_sec - b - > tv_sec ;
result - > tv_usec = a - > tv_usec - b - > tv_usec ;
if ( result - > tv_usec < 0 ) {
- - result - > tv_sec ;
result - > tv_usec + = 1000000L ;
}
}
static inline void time_diff ( struct timeval * a , struct timespec * b , struct timeval * result ) {
result - > tv_sec = a - > tv_sec - b - > tv_sec ;
result - > tv_usec = a - > tv_usec - ( b - > tv_nsec / 1000 ) ;
if ( result - > tv_usec < 0 ) {
- - result - > tv_sec ;
result - > tv_usec + = 1000000L ;
}
}
2021-08-26 10:26:53 -07:00
2021-09-01 03:37:08 -07:00
int dump_event ( struct timespec * start , struct input_event * event , char * type ) {
2021-08-26 10:26:53 -07:00
struct timespec now ;
struct timespec diff ;
2021-08-27 09:09:32 -07:00
char content_buffer [ CONTENT_BUFFER_SIZE ] ;
2021-08-26 10:26:53 -07:00
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
timespec_diff ( & now , start , & diff ) ;
2021-09-01 03:37:08 -07:00
// time_diff(&(event.time), start, &diff);
2021-08-26 10:26:53 -07:00
2021-08-27 09:09:32 -07:00
if ( type = = MOUSE ) {
2021-09-01 03:37:08 -07:00
if ( event_content_mouse ( content_buffer , CONTENT_BUFFER_SIZE , event ) ) {
2021-08-27 09:09:32 -07:00
return 1 ;
}
} else if ( type = = KEYBOARD ) {
2021-08-27 09:33:08 -07:00
// Ignore all but EV_KEY events on keyboard, they have no useful content.
2021-09-01 03:37:08 -07:00
if ( event - > type ! = EV_KEY ) {
2021-08-27 09:09:32 -07:00
return 0 ;
}
2021-09-01 03:37:08 -07:00
if ( event_content_keyboard ( content_buffer , CONTENT_BUFFER_SIZE , event ) ) {
2021-08-27 09:09:32 -07:00
return 1 ;
}
} else {
fprintf ( stderr , " Unknown event type. \n " ) ;
return 1 ;
}
2022-09-07 16:18:47 -07:00
start - > tv_sec = now . tv_sec ;
start - > tv_nsec = now . tv_nsec ;
2021-08-27 09:09:32 -07:00
2021-08-27 11:44:14 -07:00
printf ( " %ld %ld,%s,%s \n " ,
2021-08-27 09:09:32 -07:00
diff . tv_sec ,
diff . tv_nsec ,
type ,
content_buffer ) ;
2021-08-27 10:10:53 -07:00
fflush ( stdout ) ;
2021-08-27 09:09:32 -07:00
return 0 ;
}
int event_content_keyboard ( char * buffer , int buffer_size , struct input_event * event ) {
2021-08-27 09:33:08 -07:00
sprintf ( buffer , " %d,%d,%d " ,
event - > type ,
event - > code ,
event - > value ) ;
2021-08-27 09:09:32 -07:00
return 0 ;
}
int event_content_mouse ( char * buffer , int buffer_size , struct input_event * event ) {
unsigned char button , bLeft , bMiddle , bRight ;
unsigned char * ptr = ( unsigned char * ) event ;
int i ;
char x , y ;
2021-08-26 10:26:53 -07:00
button = ptr [ 0 ] ;
bLeft = button & 0x1 ;
bMiddle = ( button & 0x4 ) > 0 ;
bRight = ( button & 0x2 ) > 0 ;
2021-08-27 09:09:32 -07:00
x = ( char ) ptr [ 1 ] ;
y = ( char ) ptr [ 2 ] ;
int chars = sprintf ( buffer , " l%d,m%d,r%d,x%d,y%d " ,
2021-08-26 10:26:53 -07:00
bLeft , bMiddle , bRight , x , y ) ;
2021-08-27 09:09:32 -07:00
return chars < 0 ;
2021-08-26 10:26:53 -07:00
}
2021-08-27 09:09:32 -07:00
2021-08-26 10:26:53 -07:00
int main ( int argc , char * argv [ ] ) {
2021-09-01 03:37:08 -07:00
int hotkey_scancode ;
2021-08-26 10:26:53 -07:00
if ( argc < 2 ) {
fprintf ( stderr , " You must specify a mouse input to track like /dev/input/mouse1. " ) ;
exit ( EXIT_FAILURE ) ;
}
2021-08-27 09:09:32 -07:00
if ( argc < 3 ) {
fprintf ( stderr , " You must specify a keyboard input to track like /dev/input/event3. If you're not sure which to use read through /proc/bus/input/devices and look for 'Handlers=eventX' " ) ;
exit ( EXIT_FAILURE ) ;
}
2021-09-01 03:37:08 -07:00
if ( argc < 4 ) {
fprintf ( stderr , " You must specify a character to indicate when to start and stop capture. 53 for 'z'. \n " ) ;
exit ( EXIT_FAILURE ) ;
}
int matched = sscanf ( argv [ 3 ] , " %d " , & hotkey_scancode ) ;
if ( matched ! = 1 ) {
fprintf ( stderr , " Failed to read hotkey scancode. \n " ) ;
exit ( EXIT_FAILURE ) ;
}
int result = stream_events ( argv [ 1 ] , argv [ 2 ] , hotkey_scancode ) ;
2021-08-26 10:26:53 -07:00
exit ( result ) ;
}
2021-09-01 03:37:08 -07:00
int stream_events ( char * mouse_path , char * keyboard_path , int hotkey_scancode ) {
2021-08-27 09:09:32 -07:00
int keyboard_fd , mouse_fd ;
2021-08-26 10:26:53 -07:00
struct timespec start ;
2021-09-01 03:37:08 -07:00
struct epoll_event e_event , events [ MAX_EVENTS ] ;
2021-08-27 09:09:32 -07:00
2021-09-01 03:37:08 -07:00
int has_seen_hotkey = 0 ;
2021-08-27 09:09:32 -07:00
int running = 1 ;
int epoll_fd = epoll_create1 ( 0 ) ;
if ( epoll_fd < 0 ) {
fprintf ( stderr , " Failed to initialize epoll fd: %d " , errno ) ;
return 1 ;
}
if ( ( mouse_fd = open ( mouse_path , O_RDONLY ) ) = = - 1 ) {
fprintf ( stderr , " Failed to open %s. Are you running as root? \n " , mouse_path ) ;
2021-08-26 10:26:53 -07:00
return 1 ;
}
else {
2021-08-27 09:09:32 -07:00
fprintf ( stderr , " %s open OK \n " , mouse_path ) ;
2021-08-26 10:26:53 -07:00
}
2021-08-27 09:09:32 -07:00
if ( ( keyboard_fd = open ( keyboard_path , O_RDONLY ) ) = = - 1 ) {
fprintf ( stderr , " Failed to open %s. Are you running as root? \n " , keyboard_path ) ;
return 1 ;
}
else {
fprintf ( stderr , " %s open OK \n " , keyboard_path ) ;
}
2021-09-01 03:37:08 -07:00
e_event . events = EPOLLIN ;
2021-08-27 09:09:32 -07:00
2021-09-01 03:37:08 -07:00
e_event . data . fd = keyboard_fd ;
if ( epoll_ctl ( epoll_fd , EPOLL_CTL_ADD , keyboard_fd , & e_event ) ) {
2021-08-27 09:09:32 -07:00
fprintf ( stderr , " Failed to add keyboard file descriptor \n " ) ;
close ( epoll_fd ) ;
return 1 ;
}
2021-09-01 03:37:08 -07:00
e_event . data . fd = mouse_fd ;
if ( epoll_ctl ( epoll_fd , EPOLL_CTL_ADD , mouse_fd , & e_event ) ) {
2021-08-27 09:09:32 -07:00
fprintf ( stderr , " Failed to add mouse file descriptor \n " ) ;
close ( epoll_fd ) ;
return 1 ;
}
2021-09-01 03:37:08 -07:00
fprintf ( stderr , " Waiting for hotkey \n " ) ;
struct input_event i_event ;
2021-08-27 09:09:32 -07:00
while ( running ) {
int event_count = epoll_wait ( epoll_fd , events , MAX_EVENTS , - 1 ) ;
char * type ;
for ( int i = 0 ; i < event_count ; i + + ) {
2021-09-01 03:37:08 -07:00
int result = read ( events [ i ] . data . fd , & i_event , sizeof ( struct input_event ) ) ;
if ( result < 0 ) {
2022-09-07 16:19:47 -07:00
perror ( " Failed to read an event " ) ;
2021-09-01 03:37:08 -07:00
return 1 ;
}
2021-08-27 09:09:32 -07:00
if ( events [ i ] . data . fd = = keyboard_fd ) {
type = KEYBOARD ;
2021-09-01 03:37:08 -07:00
if ( i_event . type = = EV_KEY & & i_event . code = = hotkey_scancode & & i_event . value = = 1 ) {
if ( has_seen_hotkey ) {
fprintf ( stderr , " Stop capture \n " ) ;
return 0 ;
} else {
has_seen_hotkey = 1 ;
fprintf ( stderr , " Start capture \n " ) ;
clock_gettime ( CLOCK_MONOTONIC , & start ) ;
continue ;
}
2022-08-30 17:35:12 -07:00
} else if ( i_event . value = = 2 ) {
continue ;
2021-09-01 03:37:08 -07:00
}
2021-08-27 09:09:32 -07:00
} else if ( events [ i ] . data . fd = = mouse_fd ) {
type = MOUSE ;
} else {
fprintf ( stderr , " Unknown fd " ) ;
return 1 ;
}
2021-09-01 03:37:08 -07:00
// Wait for the hotkey to start capture
if ( has_seen_hotkey & & dump_event ( & start , & i_event , type ) ) {
2021-08-27 09:09:32 -07:00
return 1 ;
}
}
2021-08-26 10:26:53 -07:00
}
}