/* uijoystick.c: Joystick emulation (using libjsw) Copyright (c) 2003-2004 Darren Salt, Philip Kendall $Id: uijoystick.c,v 1.12 2007/02/02 16:21:55 pak21 Exp $ This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Author contact information: E-mail: philip-fuse@shadowmagic.org.uk Darren: linux@youmustbejoking.demon.co.uk */ /* Usage note: build this from within a specific UI unless that UI implements * its own joystick support using some other library. * Inclusion as follows: * #if !defined USE_JOYSTICK || defined HAVE_JSW_H * # include "../uijoystick.c" * #else * // UI-specific code implementing the following (exported) functions * #endif */ #include #include "input.h" #include "joystick.h" #include "uijoystick.h" #if defined USE_JOYSTICK && defined HAVE_JSW_H #include #include #include #include #include #include "fuse.h" #include "keyboard.h" #include "settings.h" #include "spectrum.h" #include "machine.h" #include "ui/ui.h" #include "utils.h" static js_data_struct jsd[2]; static void poll_joystick( int which ); static void do_axis( int which, double position, input_joystick_button negative, input_joystick_button positive ); static int init_stick( int which, const char *const device, const char *const calibration ) { switch( JSInit( &jsd[which], device, calibration, JSFlagNonBlocking ) ) { case JSSuccess: if( JSLoadCalibrationUNIX( &jsd[which] ) && errno != ENOENT ) { ui_error( UI_ERROR_ERROR, "failed to read calibration for joystick %i: %s", which + 1, strerror( errno ) ); break; } if( jsd[which].total_axises < 2 || jsd[which].total_buttons < 1 ) { ui_error( UI_ERROR_ERROR, "sorry, joystick %i (%s) is inadequate!", which + 1, device ); break; } return 0; case JSBadValue: ui_error( UI_ERROR_ERROR, "failed to initialise joystick %i: %s", which + 1, "invalid parameter/value"); break; case JSNoAccess: /* FIXME: why is this commented out? */ /* ui_error (UI_ERROR_ERROR, "failed to initialise joystick %i: %s", which + 1, "cannot access device"); */ break; case JSNoBuffers: ui_error( UI_ERROR_ERROR, "failed to initialise joystick %i: %s", which + 1, "not enough memory" ); break; default: ui_error( UI_ERROR_ERROR, "failed to initialise joystick %i", which + 1 ); break; } JSClose( &jsd[which] ); return 1; } static int open_joystick( int which, const char *device, const char *calibration ) { char path[ PATH_MAX ]; /* If we were given an explicit device to use for this joystick, try only that */ if( device && device[0] ) return init_stick( which, device, calibration ); /* Otherwise try /dev/input/js and /dev/js */ snprintf( path, PATH_MAX, "/dev/input/js%d", which ); if( !init_stick( which, path, calibration ) ) return 0; snprintf( path, PATH_MAX, "/dev/js%d", which ); if( !init_stick( which, path, calibration ) ) return 0; /* Couldn't find this joystick */ return 1; } int ui_joystick_init( void ) { const char *home; char *calibration; int error; home = utils_get_home_path(); if( !home ) return 1; /* Default calibration file is ~/.joystick */ calibration = malloc( strlen( home ) + strlen( JSDefaultCalibration ) + 2 ); if( !calibration ) { ui_error( UI_ERROR_ERROR, "failed to initialise joystick: %s", "not enough memory" ); return 0; } sprintf( calibration, "%s/%s", home, JSDefaultCalibration ); /* If we can't init the first, don't try the second */ error = open_joystick( 0, settings_current.joystick_1, calibration ); if( error ) return 0; error = open_joystick( 1, settings_current.joystick_2, calibration ); if( error ) return 1; return 2; } void ui_joystick_end( void ) { int i; for( i = 0; i < joysticks_supported; i++ ) JSClose( &jsd[i] ); } void ui_joystick_poll( void ) { int i; for( i = 0; i < joysticks_supported; i++ ) poll_joystick( i ); } static void poll_joystick( int which ) { js_data_struct *joystick; double position; int fire, buttons; input_event_t event; size_t i; joystick = &jsd[which]; if( JSUpdate( joystick ) != JSGotEvent ) return; position = JSGetAxisCoeffNZ( joystick, 0 ); do_axis( which, position, INPUT_JOYSTICK_LEFT, INPUT_JOYSTICK_RIGHT ); position = JSGetAxisCoeffNZ( joystick, 1 ); do_axis( which, position, INPUT_JOYSTICK_UP, INPUT_JOYSTICK_DOWN ); event.types.joystick.which = which; buttons = joystick->total_buttons; if( buttons > 10 ) buttons = 10; /* We support 'only' 10 fire buttons */ for( i = 0; i < buttons; i++ ) { fire = JSGetButtonState( joystick, i ); if( fire == JSButtonStateOn ) { event.type = INPUT_EVENT_JOYSTICK_PRESS; } else { event.type = INPUT_EVENT_JOYSTICK_RELEASE; } event.types.joystick.button = INPUT_JOYSTICK_FIRE_1 + i; } input_event( &event ); } static void do_axis( int which, double position, input_joystick_button negative, input_joystick_button positive ) { input_event_t event1, event2; event1.types.joystick.which = event2.types.joystick.which = which; event1.types.joystick.button = positive; event2.types.joystick.button = negative; if( position == 0.0 ) { event1.type = INPUT_EVENT_JOYSTICK_RELEASE; event2.type = INPUT_EVENT_JOYSTICK_RELEASE; } else if( position > 0.0 ) { event1.type = INPUT_EVENT_JOYSTICK_PRESS; event2.type = INPUT_EVENT_JOYSTICK_RELEASE; } else { event1.type = INPUT_EVENT_JOYSTICK_RELEASE; event2.type = INPUT_EVENT_JOYSTICK_PRESS; } input_event( &event1 ); input_event( &event2 ); } #else /* #if defined USE_JOYSTICK && defined HAVE_JSW_H */ /* No joystick library */ int ui_joystick_init( void ) { return 0; } void ui_joystick_end( void ) { } void ui_joystick_poll( void ) { } #endif /* #if defined USE_JOYSTICK && defined HAVE_JSW_H */