summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/q2pro.mk4
-rwxr-xr-xconfigure8
-rw-r--r--src/in_evdev.c175
3 files changed, 158 insertions, 29 deletions
diff --git a/build/q2pro.mk b/build/q2pro.mk
index 670e4e6..9d89f01 100644
--- a/build/q2pro.mk
+++ b/build/q2pro.mk
@@ -126,6 +126,10 @@ ifdef USE_DINPUT
SRCFILES+=in_evdev.c
endif
+ifdef USE_UDEV
+LDFLAGS+=-ludev
+endif
+
ifdef USE_LIRC
SRCFILES+=in_lirc.c
LDFLAGS+=-llirc_client
diff --git a/configure b/configure
index 64c038c..7b7f440 100755
--- a/configure
+++ b/configure
@@ -83,6 +83,7 @@ use_snddma="yes"
use_openal="no"
use_dsound="no"
use_dinput="no"
+use_udev="no"
use_lirc="no"
use_zlib="yes"
use_curl="no"
@@ -296,6 +297,7 @@ Linux)
use_dl="yes"
have_endian_h="yes"
[ "$use_icmp" = "no" ] || use_icmp="yes"
+[ "$use_dinput" = "yes" ] && use_udev="yes"
;;
esac
@@ -437,6 +439,7 @@ else
use_openal="no"
use_dsound="no"
use_dinput="no"
+ use_udev="no"
use_lirc="no"
use_curl="no"
use_tga="no"
@@ -633,6 +636,11 @@ if [ "$use_dinput" = "yes" ]; then
echo "#define USE_DINPUT 1" >> $config_h
fi
+if [ "$use_udev" = "yes" ]; then
+ echo "USE_UDEV=yes" >> $config_mk
+ echo "#define USE_UDEV 1" >> $config_h
+fi
+
if [ "$use_lirc" = "yes" ]; then
echo "USE_LIRC=yes" >> $config_mk
echo "#define USE_LIRC 1" >> $config_h
diff --git a/src/in_evdev.c b/src/in_evdev.c
index 9c1766e..5d38503 100644
--- a/src/in_evdev.c
+++ b/src/in_evdev.c
@@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "in_public.h"
#include "cl_public.h"
#include "io_sleep.h"
+#include "q_list.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -35,38 +36,57 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include <SDL.h>
#endif
-static cvar_t *in_device;
+#if USE_UDEV
+#include <libudev.h>
+#endif
+
+#define FOR_EACH_EVDEV( dev ) \
+ LIST_FOR_EACH( evdev_t, dev, &evdev.devices, entry )
+#define FOR_EACH_EVDEV_SAFE( dev, next ) \
+ LIST_FOR_EACH_SAFE( evdev_t, dev, next, &evdev.devices, entry )
+
+typedef struct {
+ list_t entry;
+ int fd;
+ ioentry_t *io;
+} evdev_t;
static struct {
qboolean initialized;
grab_t grabbed;
- int fd;
+ list_t devices;
int dx, dy;
- ioentry_t *io;
} evdev;
#define MAX_EVENTS 64
#define EVENT_SIZE sizeof( struct input_event )
-static void ShutdownMouse( void );
+static void evdev_remove( evdev_t *dev ) {
+ IO_Remove( dev->fd );
+ close( dev->fd );
+ List_Remove( &dev->entry );
+ Z_Free( dev );
+}
-static void GetMouseEvents( void ) {
+static void evdev_read( evdev_t *dev ) {
struct input_event ev[MAX_EVENTS];
ssize_t bytes;
size_t i, count;
unsigned button, time;
- if( !evdev.initialized || !evdev.grabbed /*|| !evdev.io->canread*/ ) {
+#if 0
+ if( !dev->io->canread ) {
return;
}
+#endif
- bytes = read( evdev.fd, ev, EVENT_SIZE * MAX_EVENTS );
+ bytes = read( dev->fd, ev, EVENT_SIZE * MAX_EVENTS );
if( bytes == -1 ) {
if( errno == EAGAIN || errno == EINTR ) {
return;
}
Com_EPrintf( "Couldn't read event: %s\n", strerror( errno ) );
- ShutdownMouse();
+ evdev_remove( dev );
return;
}
@@ -120,10 +140,23 @@ static void GetMouseEvents( void ) {
}
}
+static void GetMouseEvents( void ) {
+ evdev_t *dev, *next;
+
+ if( !evdev.initialized || !evdev.grabbed ) {
+ return;
+ }
+
+ FOR_EACH_EVDEV_SAFE( dev, next ) {
+ evdev_read( dev );
+ }
+}
+
static qboolean GetMouseMotion( int *dx, int *dy ) {
if( !evdev.initialized || !evdev.grabbed ) {
return qfalse;
}
+
*dx = evdev.dx;
*dy = evdev.dy;
evdev.dx = 0;
@@ -132,12 +165,15 @@ static qboolean GetMouseMotion( int *dx, int *dy ) {
}
static void ShutdownMouse( void ) {
+ evdev_t *dev, *next;
+
if( !evdev.initialized ) {
return;
}
- IO_Remove( evdev.fd );
- close( evdev.fd );
+ FOR_EACH_EVDEV_SAFE( dev, next ) {
+ evdev_remove( dev );
+ }
#if USE_SDL
SDL_ShowCursor( SDL_ENABLE );
@@ -148,30 +184,109 @@ static void ShutdownMouse( void ) {
memset( &evdev, 0, sizeof( evdev ) );
}
-static qboolean InitMouse( void ) {
- in_device = Cvar_Get( "in_device", "", 0 );
- if( !in_device->string[0] ) {
- Com_WPrintf( "No evdev input device specified.\n" );
- return qfalse;
+static evdev_t *evdev_add( const char *path ) {
+ evdev_t *dev;
+ int fd;
+
+ fd = open( path, O_RDONLY );
+ if( fd == -1 ) {
+ Com_EPrintf( "Couldn't open %s: %s\n", path, strerror( errno ) );
+ return NULL;
}
+
+ Com_DPrintf( "Adding device %s\n", path );
+
+ fcntl( fd, F_SETFL, fcntl( fd, F_GETFL, 0 ) | FNDELAY );
+
+ dev = Z_Malloc( sizeof( *dev ) );
+ dev->fd = fd;
+ dev->io = IO_Add( fd );
+ List_Append( &evdev.devices, &dev->entry );
+
+ return dev;
+}
+
+#if USE_UDEV
+static void auto_add_devices( void ) {
+ struct udev *udev;
+ struct udev_enumerate *enumerate;
+ struct udev_list_entry *list, *entry;
+ struct udev_device *dev;
+ const char *path;
+
+ udev = udev_new();
+ if( !udev ) {
+ Com_EPrintf( "Couldn't create udev handle\n" );
+ return;
+ }
+
+ enumerate = udev_enumerate_new( udev );
+ udev_enumerate_add_match_subsystem( enumerate, "input" );
+ udev_enumerate_add_match_sysname( enumerate, "event[0-9]*" );
+ udev_enumerate_add_match_property( enumerate, "ID_INPUT_MOUSE", "1" );
+ udev_enumerate_scan_devices( enumerate );
+ list = udev_enumerate_get_list_entry( enumerate );
+ udev_list_entry_foreach( entry, list ) {
+ path = udev_list_entry_get_name( entry );
+ dev = udev_device_new_from_syspath( udev, path );
+ if( dev ) {
+ path = udev_device_get_devnode( dev );
+ if( path ) {
+ evdev_add( path );
+ }
+ udev_device_unref( dev );
+ }
+ }
+
+ udev_enumerate_unref( enumerate );
+ udev_unref( udev );
+}
+#endif
+
+static qboolean InitMouse( void ) {
+ cvar_t *var;
+
+ List_Init( &evdev.devices );
+
+ var = Cvar_Get( "in_device", "", 0 );
- evdev.fd = open( in_device->string, O_RDONLY );
- if( evdev.fd == -1 ) {
- Com_EPrintf( "Couldn't open %s: %s\n", in_device->string,
- strerror( errno ) );
+ if( var->string[0] ) {
+ // add user specified device
+ if( !evdev_add( var->string ) ) {
+ return qfalse;
+ }
+ } else {
+#if USE_UDEV
+ // find devices automatically
+ auto_add_devices();
+
+ if( LIST_EMPTY( &evdev.devices ) ) {
+ Com_EPrintf(
+ "Automatic libudev scan was unable to find any "
+ "usable mouse device. You may need to set the "
+ "'in_device' variable manually before direct "
+ "mouse input can be used.\n" );
+ return qfalse;
+ }
+#else
+ Com_EPrintf(
+ "No input device specified, and libudev support "
+ "is not compiled in. Please set the 'in_device' variable "
+ "manually before direct mouse input can be used.\n" );
return qfalse;
+#endif
}
-
- fcntl( evdev.fd, F_SETFL, fcntl( evdev.fd, F_GETFL, 0 ) | FNDELAY );
- evdev.io = IO_Add( evdev.fd );
- Com_Printf( "Evdev interface initialized.\n" );
+ Com_Printf( "Evdev mouse initialized.\n" );
evdev.initialized = qtrue;
return qtrue;
}
static void GrabMouse( grab_t grab ) {
+ struct input_event ev;
+ evdev_t *dev;
+
if( !evdev.initialized ) {
return;
}
@@ -188,7 +303,6 @@ static void GrabMouse( grab_t grab ) {
SDL_WM_SetCaption( "[" PRODUCT "]", APPLICATION );
SDL_ShowCursor( SDL_DISABLE );
#endif
- evdev.io->wantread = qtrue;
} else {
#if USE_SDL
if( evdev.grabbed == IN_GRAB ) {
@@ -201,14 +315,17 @@ static void GrabMouse( grab_t grab ) {
SDL_ShowCursor( SDL_ENABLE );
}
#endif
- evdev.io->wantread = !!grab;
}
- // pump pending events
- if( grab ) {
- struct input_event ev;
+ FOR_EACH_EVDEV( dev ) {
+ if( !grab ) {
+ dev->io->wantread = qfalse;
+ continue;
+ }
- while( read( evdev.fd, &ev, EVENT_SIZE ) == EVENT_SIZE )
+ // pump pending events
+ dev->io->wantread = qtrue;
+ while( read( dev->fd, &ev, EVENT_SIZE ) == EVENT_SIZE )
;
}