#include "fcntl.h" #include "dirent.h" #include "stdio.h" #include "stdlib.h" #include "unistd.h" #include "string.h" #include "sys/stat.h" #include "sys/kd.h" #include #include #include "input33.h" #include "logger33.h" #include "strings33.h" #define _INPUT_DEVICES_MAX 8 #define _POLL_EVENTS_MAX 16 Input33 __input = {0}; static int _is_char_device( const struct dirent *f ); static Boolean _is_keyboard( Size fd ); static Boolean _is_mouse( Size fd ); static Size _has_key( Size fd, unsigned int event ); static Size _has_rel( Size fd, unsigned int event ); static u64 _has_evbits( Size fd, unsigned int type ); Error input33_init( void ) { Size i, deviceCount; Boolean hasKeyboard = E33_FALSE; Boolean hasMouse = E33_FALSE; struct dirent **evfs; deviceCount = scandir( "/dev/input", &evfs, _is_char_device, 0 ); if( deviceCount <= 0 ) { LOGE( "No valid character devices found." ); return E33_EXIT_FAILURE; } for( i = 0; i < deviceCount; ++i ) { Size j; Size devFd; char path[ _STRING_MAX ]; snprintf( path, _STRING_MAX , "%s%s", "/dev/input/", evfs[i]->d_name ); free( evfs[i] ); devFd = open( path, O_RDONLY | O_NONBLOCK ); if( devFd == -1 ) { continue; } if( _is_keyboard( devFd ) ) { hasKeyboard = E33_TRUE; __input.devices[ __input.deviceCount++ ] = devFd; } else if( _is_mouse(devFd) ) { hasMouse = E33_TRUE; __input.devices[ __input.deviceCount++ ] = devFd; ioctl( devFd, EVIOCGRAB, 1 ); } else { close( devFd ); } if( __input.deviceCount == _INPUT_DEVICES_MAX ){ break; } } free( evfs ); if( (hasKeyboard == E33_TRUE) && (hasMouse == E33_TRUE) ) { return E33_EXIT_SUCCESS; } return E33_EXIT_FAILURE; } void input33_poll( void ) { u16 i; for( i = 0; i < __input.deviceCount; ++i ) { Size j; Size readBytes; Size eventCount; struct input_event events[ _POLL_EVENTS_MAX ]; __input.relStates[REL_X] = 0; __input.relStates[REL_Y] = 0; __input.relStates[REL_WHEEL] = 0; readBytes = read( __input.devices[i], events, sizeof(struct input_event) * _POLL_EVENTS_MAX ); if( readBytes == -1 ) { continue; } eventCount = readBytes / sizeof( struct input_event ); for( j = 0; j < eventCount; ++j ) { switch( events[j].type ) { case EV_KEY: __input.keyStates[ events[j].code ] = events[j].value; if( (events[j].value == _PRESS) || (events[j].value == _REPEAT) ) { __input.buffer[__input.tail++] = events[j].code; __input.tail &= (_KBBUFF_LEN - 1); if( __input.tail == __input.head ) { ++__input.head; __input.head &= (_KBBUFF_LEN - 1); } } break; case EV_REL: __input.relStates[ events[j].code ] = events[j].value; break; } } } __input.modFlags = 6; ioctl( 0, TIOCLINUX, &__input.modFlags ); ioctl( 0, KDGKBLED, &__input.cnsFlags ); } void input33_term( void ) { Size i; for( i = 0; i < __input.deviceCount; ++i ) { close( __input.devices[i] ); } } static u64 _has_evbits( Size fd, unsigned int type ) { u64 kbb; if( ioctl( fd, EVIOCGBIT( 0, (int)sizeof(kbb) ), &kbb ) == -1 ) { return 0; } return (kbb & (1 << type)); } static Size _has_key( Size fd, unsigned int event ) { unsigned char bits[ (KEY_MAX >> 3) + 1 ]; if( ioctl( fd, EVIOCGBIT(EV_KEY, (int)sizeof(bits)), &bits ) == -1 ) { return 0; } return ( (bits[event >> 3] & (1 << (event % 8))) > 0 ); } static Size _has_rel( Size fd, unsigned int event ) { unsigned char bits[ (REL_MAX >> 3) + 1 ]; if( ioctl( fd, EVIOCGBIT(EV_REL, (int)sizeof(bits)), &bits ) == -1 ) { return 0; } return ( (bits[event >> 3] & (1 << (event % 8))) > 0 ); } static Boolean _is_mouse( Size fd ) { if( _has_evbits( fd, EV_KEY ) && _has_evbits( fd, EV_REL ) ) { return( _has_rel( fd, REL_X ) & _has_rel( fd, REL_Y ) & _has_key( fd, BTN_LEFT ) & _has_key( fd, BTN_RIGHT ) & 1 ); } return E33_FALSE; } static Boolean _is_keyboard( Size fd ) { if( _has_evbits( fd, EV_KEY ) ) { return( _has_key( fd, KEY_W ) & _has_key( fd, KEY_SPACE ) & _has_key( fd, KEY_LEFTSHIFT ) & _has_key( fd, KEY_I ) & 1 ); } return E33_FALSE; } static int _is_char_device( const struct dirent *f ) { struct stat fstat; char path[512]; if( strncmp( f->d_name, "event", 5 ) ) { return 0; } snprintf( path, 512, "%s%s", "/dev/input/", f->d_name ); if( stat( path, &fstat ) ) { return 0; } return S_ISCHR( fstat.st_mode ); }