2003-07-31 21:34:46 +02:00
/**
* Copyright ( C ) 2003 Jeremy Booth ( jeremy @ newdawnsoftware . com )
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
*
* Redistributions of source code must retain the above copyright notice , this
* list of conditions and the following disclaimer . Redistributions in binary
* form must reproduce the above copyright notice , this list of conditions and
* the following disclaimer in the documentation and / or other materials provided
* with the distribution .
* The name of the author may not be used to endorse or promote products derived
* from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED
* WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
* SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ;
* OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ,
* WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR
* OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*/
# include "eventInterfaceTypes.h"
# include "EventDevice.h"
# include <stdio.h>
# include <linux/input.h>
# include <fcntl.h>
# include <unistd.h>
# include <string.h>
# include <malloc.h>
# include <errno.h>
2004-04-21 11:48:55 +02:00
# include "logger.h"
2003-07-31 21:34:46 +02:00
EventDevice : : EventDevice ( char * deviceFileName ) {
char tempName [ Device : : MAX_NAME_LENGTH - 1 ] = " Unknown " ;
int i ;
fd = open ( deviceFileName , O_RDWR | O_NONBLOCK ) ;
if ( fd < 0 ) {
2003-10-04 14:48:51 +02:00
/*char errorMessage[512];
2003-07-31 21:34:46 +02:00
sprintf ( errorMessage , " Error opening device %s \n " , deviceFileName ) ;
2003-10-04 14:48:51 +02:00
perror ( errorMessage ) ; */
inited = 0 ;
return ;
2003-07-31 21:34:46 +02:00
}
if ( ioctl ( fd , EVIOCGNAME ( sizeof ( tempName ) ) , tempName ) < 0 ) {
char errorMessage [ 512 ] ;
sprintf ( errorMessage , " Error reading device %s \n " , deviceFileName ) ;
perror ( errorMessage ) ;
}
int namelength = strlen ( tempName ) ;
name = ( char * ) malloc ( namelength + 1 ) ;
strncpy ( name , tempName , namelength + 1 ) ;
2004-04-21 11:48:55 +02:00
LOG_TRACE ( " Device name for device file %s is %s \n " , deviceFileName , name ) ;
2003-07-31 21:34:46 +02:00
uint8_t evtype_bitmask [ EV_MAX / 8 + 1 ] ;
memset ( evtype_bitmask , 0 , sizeof ( evtype_bitmask ) ) ;
if ( ioctl ( fd , EVIOCGBIT ( 0 , EV_MAX ) , evtype_bitmask ) < 0 ) {
char errorMessage [ 512 ] ;
sprintf ( errorMessage , " Error reading device %s \n " , deviceFileName ) ;
perror ( errorMessage ) ;
}
struct input_devinfo deviceInfo ;
if ( ioctl ( fd , EVIOCGID , & deviceInfo ) < 0 ) {
char errorMessage [ 512 ] ;
sprintf ( errorMessage , " Error reading device %s \n " , deviceFileName ) ;
perror ( errorMessage ) ;
}
bustype = deviceInfo . bustype ;
vendor = deviceInfo . vendor ;
product = deviceInfo . product ;
version = deviceInfo . version ;
numButtons = - 1 ;
numAbsAxes = - 1 ;
numRelAxes = - 1 ;
if ( ! ( getBit ( EV_KEY , evtype_bitmask ) ) ) {
numButtons = 0 ;
}
if ( ! ( getBit ( EV_REL , evtype_bitmask ) ) ) {
numRelAxes = 0 ;
}
if ( ! ( getBit ( EV_ABS , evtype_bitmask ) ) ) {
numAbsAxes = 0 ;
}
if ( getBit ( EV_FF , evtype_bitmask ) ) {
ffSupported = 1 ;
} else {
ffSupported = 0 ;
}
if ( numButtons < 0 ) {
// This device supports keys, deal with it.
if ( ioctl ( fd , EVIOCGBIT ( EV_KEY , sizeof ( key_bitmask ) ) , key_bitmask ) < 0 ) {
char errorMessage [ 512 ] ;
sprintf ( errorMessage , " Error reading device %s \n " , deviceFileName ) ;
perror ( errorMessage ) ;
}
for ( i = 0 ; i < KEY_MAX ; i + + ) {
buttonLookup [ i ] = - 1 ;
}
short tempSupportedButtons [ KEY_MAX ] ;
numButtons = 0 ;
for ( i = 0 ; i < KEY_MAX ; i + + ) {
if ( getBit ( i , key_bitmask ) ) {
tempSupportedButtons [ numButtons ] = i ;
numButtons + + ;
}
}
supportedButtons = ( short * ) malloc ( numButtons * sizeof ( short ) ) ;
buttonData = ( uint8_t * ) malloc ( numButtons * sizeof ( uint8_t ) ) ;
for ( i = 0 ; i < numButtons ; i + + ) {
buttonData [ i ] = 0 ;
supportedButtons [ i ] = tempSupportedButtons [ i ] ;
buttonLookup [ supportedButtons [ i ] ] = i ;
}
}
if ( numRelAxes < 0 ) {
// This device supports axes, deal with it.
if ( ioctl ( fd , EVIOCGBIT ( EV_REL , sizeof ( rel_bitmask ) ) , rel_bitmask ) < 0 ) {
char errorMessage [ 512 ] ;
sprintf ( errorMessage , " Error reading device %s \n " , deviceFileName ) ;
perror ( errorMessage ) ;
}
for ( i = 0 ; i < REL_MAX ; i + + ) {
relAxisLookup [ i ] = - 1 ;
}
short tempSupportedAxes [ REL_MAX ] ;
numRelAxes = 0 ;
for ( i = 0 ; i < REL_MAX ; i + + ) {
if ( getBit ( i , rel_bitmask ) ) {
tempSupportedAxes [ numRelAxes ] = i ;
numRelAxes + + ;
}
}
relAxesData = ( int * ) malloc ( numRelAxes * sizeof ( int ) ) ;
supportedRelAxes = ( short * ) malloc ( numRelAxes * sizeof ( short ) ) ;
for ( i = 0 ; i < numRelAxes ; i + + ) {
relAxesData [ i ] = 0 ;
supportedRelAxes [ i ] = tempSupportedAxes [ i ] ;
relAxisLookup [ supportedRelAxes [ i ] ] = i ;
}
}
if ( numAbsAxes < 0 ) {
if ( ioctl ( fd , EVIOCGBIT ( EV_ABS , sizeof ( abs_bitmask ) ) , abs_bitmask ) < 0 ) {
char errorMessage [ 512 ] ;
sprintf ( errorMessage , " Error reading device %s \n " , deviceFileName ) ;
perror ( errorMessage ) ;
}
for ( i = 0 ; i < ABS_MAX ; i + + ) {
absAxisLookup [ i ] = - 1 ;
}
short tempSupportedAxes [ ABS_MAX ] ;
numAbsAxes = 0 ;
for ( i = 0 ; i < ABS_MAX ; i + + ) {
if ( getBit ( i , abs_bitmask ) ) {
tempSupportedAxes [ numAbsAxes ] = i ;
numAbsAxes + + ;
}
}
absAxesData = ( int * ) malloc ( numAbsAxes * sizeof ( int ) ) ;
supportedAbsAxes = ( short * ) malloc ( numAbsAxes * sizeof ( short ) ) ;
for ( i = 0 ; i < numAbsAxes ; i + + ) {
supportedAbsAxes [ i ] = tempSupportedAxes [ i ] ;
absAxisLookup [ supportedAbsAxes [ i ] ] = i ;
}
abs_features = ( struct input_absinfo * ) malloc ( numAbsAxes * sizeof ( struct input_absinfo ) ) ;
for ( i = 0 ; i < numAbsAxes ; i + + ) {
if ( ioctl ( fd , EVIOCGABS ( supportedAbsAxes [ i ] ) , & ( abs_features [ i ] ) ) ) {
char errorMessage [ 512 ] ;
sprintf ( errorMessage , " Error reading device %s \n " , deviceFileName ) ;
perror ( errorMessage ) ;
}
absAxesData [ i ] = abs_features [ i ] . curr_value ;
}
}
inited = 1 ;
}
2003-10-04 14:48:51 +02:00
int EventDevice : : isValidDevice ( ) {
return inited ;
}
2003-07-31 21:34:46 +02:00
int EventDevice : : getNumberRelAxes ( ) {
if ( inited ! = 1 ) return - 1 ;
return numRelAxes ;
}
int EventDevice : : getNumberAbsAxes ( ) {
if ( inited ! = 1 ) return - 1 ;
return numAbsAxes ;
}
int EventDevice : : getNumberButtons ( ) {
if ( inited ! = 1 ) return - 1 ;
return numButtons ;
}
const char * EventDevice : : getName ( ) {
2004-04-21 11:48:55 +02:00
LOG_TRACE ( " EventDevice::getName() \n " ) ;
2003-07-31 21:34:46 +02:00
return name ;
}
int EventDevice : : getBusType ( ) {
if ( inited ! = 1 ) return - 1 ;
return bustype ;
}
int EventDevice : : getVendorID ( ) {
if ( inited ! = 1 ) return - 1 ;
return vendor ;
}
int EventDevice : : getProductID ( ) {
if ( inited ! = 1 ) return - 1 ;
return product ;
}
int EventDevice : : getVersion ( ) {
if ( inited ! = 1 ) return - 1 ;
return version ;
}
void EventDevice : : getSupportedRelAxes ( int supportedAxis [ ] ) {
int i ;
if ( inited ! = 1 ) return ;
for ( i = 0 ; i < numRelAxes ; i + + ) {
( supportedAxis ) [ i ] = supportedRelAxes [ i ] ;
}
}
void EventDevice : : getSupportedAbsAxes ( int supportedAxis [ ] ) {
int i ;
if ( inited ! = 1 ) return ;
for ( i = 0 ; i < numAbsAxes ; i + + ) {
( supportedAxis ) [ i ] = supportedAbsAxes [ i ] ;
}
}
void EventDevice : : getSupportedButtons ( int supportedButtons [ ] ) {
int i ;
if ( inited ! = 1 ) return ;
for ( i = 0 ; i < numButtons ; i + + ) {
( supportedButtons ) [ i ] = this - > supportedButtons [ i ] ;
}
}
/**
* A return value of - 1 means error , 0 means ok , but no change
* a return of > 0 means the data for this device has changed
*/
int EventDevice : : poll ( ) {
size_t read_bytes ;
struct input_event events [ 64 ] ;
int dataChanged = 0 ;
if ( inited ! = 1 ) return - 1 ;
// first thing to do is reset all relative axis as mice never seem to do it
int i ;
for ( i = 0 ; i < numRelAxes ; i + + ) {
if ( relAxesData [ i ] ! = 0 ) {
dataChanged = 1 ;
relAxesData [ i ] = 0 ;
}
}
read_bytes = read ( fd , events , sizeof ( struct input_event ) * 64 ) ;
if ( read_bytes = = 0 ) {
// no sweat, just return;
return 0 ;
}
if ( read_bytes = = - 1 ) {
if ( errno = = EAGAIN ) {
// No worries, we are in non blocking and noting is ready
return 0 ;
} else {
perror ( " Error reading events: " ) ;
return - 1 ;
}
}
if ( read_bytes < ( int ) sizeof ( struct input_event ) ) {
perror ( " Error reading events: " ) ;
return - 1 ;
}
int numEventsRead = ( int ) ( read_bytes / sizeof ( struct input_event ) ) ;
for ( i = 0 ; i < numEventsRead ; i + + ) {
switch ( events [ i ] . type ) {
case EV_KEY : {
dataChanged = 1 ;
int buttonIndex = buttonLookup [ events [ i ] . code ] ;
buttonData [ buttonIndex ] = events [ i ] . value ;
//printf("button %d translates to button %d on this device\n", events[i].code, buttonIndex);
break ;
}
case EV_REL : {
dataChanged = 1 ;
int axisIndex = relAxisLookup [ events [ i ] . code ] ;
relAxesData [ axisIndex ] + = events [ i ] . value ;
//printf("rel axis %d translates to rel axis %d on this device\n", events[i].code, axisIndex);
break ;
}
case EV_ABS : {
dataChanged = 1 ;
int axisIndex = absAxisLookup [ events [ i ] . code ] ;
absAxesData [ axisIndex ] = events [ i ] . value ;
//printf("abs axis %d translates to abs axis %d on this device\n", events[i].code, axisIndex);
break ;
}
case EV_RST :
// not sure what to do here, doing nothing seems to work :)
break ;
case EV_LED :
// reveiced for things like numlock led change
break ;
default :
2004-04-21 11:48:55 +02:00
fprintf ( stderr , " Received event of type 0x%02X from %s, which I wasn't expecting, please report it to jinput forum at www.javagaming.org \n " , events [ i ] . type , name ) ;
2003-07-31 21:34:46 +02:00
}
}
return dataChanged ;
}
void EventDevice : : getPolledData ( int relAxesData [ ] , int absAxesData [ ] , int buttonData [ ] ) {
int i ;
if ( inited ! = 1 ) return ;
for ( i = 0 ; i < numRelAxes ; i + + ) {
( relAxesData ) [ i ] = this - > relAxesData [ i ] ;
}
for ( i = 0 ; i < numAbsAxes ; i + + ) {
( absAxesData ) [ i ] = this - > absAxesData [ i ] ;
}
for ( i = 0 ; i < numButtons ; i + + ) {
( buttonData ) [ i ] = this - > buttonData [ i ] ;
}
}
int EventDevice : : getAbsAxisMinimum ( int axisNumber ) {
return abs_features [ axisNumber ] . min_value ;
}
int EventDevice : : getAbsAxisMaximum ( int axisNumber ) {
return abs_features [ axisNumber ] . max_value ;
}
int EventDevice : : getAbsAxisFuzz ( int axisNumber ) {
return abs_features [ axisNumber ] . fuzz ;
}