// CAUTION: This code might crash your X session - save your data before executing this! // It also needs uinput - run "modprobe uinput" to load it if necessary. #include #include #include #include #include #include #include #include #include #include #include #include #define ERROR_IF( condition ) \ if( condition ) \ error_at_line( condition, errno, __FILE__, __LINE__, #condition ) static int xioctl( int fd, unsigned long int request, ... ) { va_list ap; void * arg; va_start( ap, request ); arg = va_arg( ap, void * ); va_end( ap ); int r; do r = ioctl( fd, request, arg ); while( -1 == r && EINTR == errno ); return r; } #define sendEvent( fd, type, code, value ) \ printf( "Sending event type=%s, code=%s, value=%d\n", #type, #code, value ); \ fflush( stdout ); \ sendEvent_real( fd, type, code, value ); static void sendEvent_real( int fd, __u16 type, __u16 code, __s16 value ) { struct input_event ev = {}; ev.type = type; ev.code = code; ev.value = value; ERROR_IF( write( fd, &ev, sizeof(ev) ) != sizeof( struct input_event ) ); } int main( int argc, char ** argv ) { int fd; ERROR_IF( (fd = open( "/dev/uinput", O_WRONLY | O_NONBLOCK )) < 0 ); // setup device information struct uinput_user_dev uidev = {}; snprintf( uidev.name, UINPUT_MAX_NAME_SIZE, "MTSlotBugInducer" ); uidev.id.bustype = BUS_VIRTUAL; uidev.id.vendor = 0x1; uidev.id.product = 0x1; uidev.id.version = 1; uidev.absmax[ABS_MT_POSITION_X] = 4096; uidev.absmax[ABS_MT_POSITION_Y] = 4096; uidev.absmin[ABS_MT_POSITION_X] = 0; uidev.absmin[ABS_MT_POSITION_Y] = 0; uidev.absfuzz[ABS_MT_POSITION_X] = 0; uidev.absflat[ABS_MT_POSITION_X] = 0; uidev.absfuzz[ABS_MT_POSITION_Y] = 0; uidev.absflat[ABS_MT_POSITION_Y] = 0; uidev.absmax[ABS_X] = 4096; uidev.absmax[ABS_Y] = 4096; uidev.absmin[ABS_X] = 0; uidev.absmin[ABS_Y] = 0; uidev.absfuzz[ABS_X] = 0; uidev.absflat[ABS_X] = 0; uidev.absfuzz[ABS_Y] = 0; uidev.absflat[ABS_Y] = 0; ERROR_IF( xioctl( fd, UI_SET_EVBIT, EV_SYN ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_EVBIT, EV_KEY ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_KEYBIT, BTN_TOUCH ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_EVBIT, EV_ABS ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_ABSBIT, ABS_MT_POSITION_X ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_ABSBIT, ABS_X ) == -1 ); ERROR_IF( xioctl( fd, UI_SET_ABSBIT, ABS_Y ) == -1 ); // create ERROR_IF( write( fd, &uidev, sizeof(uidev) ) != sizeof(uidev) ); ERROR_IF( xioctl( fd, UI_DEV_CREATE ) == -1 ); sendEvent( fd, EV_SYN, SYN_MT_REPORT, 0 ); sendEvent( fd, EV_SYN, SYN_REPORT, 0 ); // send random touches for a few seconds int j; for( j = 0; j < 10; j++ ) { // send 32 random simultaneous touches int i; for( i = 0; i < 32; i++ ) { sendEvent( fd, EV_ABS, ABS_MT_POSITION_X, rand()%4096 ); sendEvent( fd, EV_ABS, ABS_MT_POSITION_Y, rand()%4096 ); sendEvent( fd, EV_SYN, SYN_MT_REPORT, 0 ); } sendEvent( fd, EV_SYN, SYN_REPORT, 0 ); sleep( 1 ); } // clean up ERROR_IF( xioctl( fd, UI_DEV_DESTROY ) == -1 ); ERROR_IF( close( fd ) == -1 ); return 0; }