/* =========================================================================== Copyright (C) 1999-2005 Id Software, Inc. This file is part of Quake III Arena source code. Quake III Arena source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Quake III Arena source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Quake III Arena source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ /* ** linux_joystick.c ** ** This file contains ALL Linux specific stuff having to do with the ** Joystick input. When a port is being made the following functions ** must be implemented by the port: ** ** Authors: mkv, bk ** */ #if !USE_SDL_VIDEO #ifdef __linux__ #include #elif defined(__FreeBSD__) #include #endif #include #include #include #include // bk001204 #include "../client/client.h" #include "linux_local.h" /* We translate axes movement into keypresses. */ int joy_keys[16] = { K_LEFTARROW, K_RIGHTARROW, K_UPARROW, K_DOWNARROW, K_JOY16, K_JOY17, K_JOY18, K_JOY19, K_JOY20, K_JOY21, K_JOY22, K_JOY23, K_JOY24, K_JOY25, K_JOY26, K_JOY27 }; /* Our file descriptor for the joystick device. */ static int joy_fd = -1; // bk001130 - from linux_glimp.c extern cvar_t * in_joystick; extern cvar_t * in_joystickDebug; extern cvar_t * joy_threshold; /**********************************************/ /* Joystick routines. */ /**********************************************/ // bk001130 - from cvs1.17 (mkv), removed from linux_glimp.c void IN_StartupJoystick( void ) { int i = 0; joy_fd = -1; if( !in_joystick->integer ) { Com_Printf( "Joystick is not active.\n" ); return; } for( i = 0; i < 4; i++ ) { char filename[PATH_MAX]; #ifdef __linux__ snprintf( filename, PATH_MAX, "/dev/js%d", i ); #elif defined(__FreeBSD__) snprintf( filename, PATH_MAX, "/dev/joy%d", i ); #endif joy_fd = open( filename, O_RDONLY | O_NONBLOCK ); if( joy_fd != -1 ) { #ifdef __linux__ struct js_event event; char axes = 0; char buttons = 0; char name[128]; int n = -1; #endif Com_Printf( "Joystick %s found\n", filename ); #ifdef __linux__ /* Get rid of initialization messages. */ do { n = read( joy_fd, &event, sizeof( event ) ); if( n == -1 ) { break; } } while( ( event.type & JS_EVENT_INIT ) ); /* Get joystick statistics. */ ioctl( joy_fd, JSIOCGAXES, &axes ); ioctl( joy_fd, JSIOCGBUTTONS, &buttons ); if( ioctl( joy_fd, JSIOCGNAME( sizeof( name ) ), name ) < 0 ) { strncpy( name, "Unknown", sizeof( name ) ); } Com_Printf( "Name: %s\n", name ); Com_Printf( "Axes: %d\n", axes ); Com_Printf( "Buttons: %d\n", buttons ); #endif /* Our work here is done. */ return; } } /* No soup for you. */ if( joy_fd == -1 ) { Com_Printf( "No joystick found.\n" ); return; } } void IN_JoyMove( void ) { /* Store instantaneous joystick state. Hack to get around * event model used in Linux joystick driver. */ static int axes_state[16]; /* Old bits for Quake-style input compares. */ static unsigned int old_axes = 0; /* Our current goodies. */ unsigned int axes = 0; int i = 0; #ifdef __FreeBSD__ struct joystick event; #endif if( joy_fd == -1 ) { return; } #ifdef __linux__ /* Empty the queue, dispatching button presses immediately * and updating the instantaneous state for the axes. */ do { int n = -1; struct js_event event; n = read( joy_fd, &event, sizeof( event ) ); if( n == -1 ) { /* No error, we're non-blocking. */ break; } if( event.type & JS_EVENT_BUTTON ) { Sys_QueEvent( 0, SE_KEY, K_JOY1 + event.number, event.value, 0, NULL ); } else if( event.type & JS_EVENT_AXIS ) { if( event.number >= 16 ) { continue; } axes_state[event.number] = event.value; } else { Com_Printf( "Unknown joystick event type\n" ); } } while( 1 ); #elif defined(__FreeBSD__) /* * FreeBSD does not fully support multi-buttoned joysticks. */ if (read(joy_fd, &event, sizeof(struct joystick)) != -1) { if (event.b1) Sys_QueEvent(0, SE_KEY, K_JOY1, 1, 0, NULL); if (event.b2) Sys_QueEvent(0, SE_KEY, K_JOY2, 1, 0, NULL); axes_state[0] = event.x; axes_state[1] = event.y; } #endif /* Translate our instantaneous state to bits. */ for( i = 0; i < 16; i++ ) { float f = ( (float) axes_state[i] ) / 32767.0f; if( f < -joy_threshold->value ) { axes |= ( 1 << ( i * 2 ) ); } else if( f > joy_threshold->value ) { axes |= ( 1 << ( ( i * 2 ) + 1 ) ); } } /* Time to update axes state based on old vs. new. */ for( i = 0; i < 16; i++ ) { if( ( axes & ( 1 << i ) ) && !( old_axes & ( 1 << i ) ) ) { Sys_QueEvent( 0, SE_KEY, joy_keys[i], qtrue, 0, NULL ); } if( !( axes & ( 1 << i ) ) && ( old_axes & ( 1 << i ) ) ) { Sys_QueEvent( 0, SE_KEY, joy_keys[i], qfalse, 0, NULL ); } } /* Save for future generations. */ old_axes = axes; } #endif // !USE_SDL_VIDEO