mirror of
https://git.code.sf.net/p/fuse-emulator/fuse
synced 2026-01-27 01:41:34 +03:00
388 lines
11 KiB
C
388 lines
11 KiB
C
/* joystick.c: Joystick emulation support
|
|
Copyright (c) 2001-2016 Russell Marks, Darren Salt, Philip Kendall
|
|
Copyright (c) 2015 Stuart Brady
|
|
|
|
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.,
|
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
Author contact information:
|
|
|
|
E-mail: philip-fuse@shadowmagic.org.uk
|
|
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <libspectrum.h>
|
|
|
|
#include "fuse.h"
|
|
#include "infrastructure/startup_manager.h"
|
|
#include "joystick.h"
|
|
#include "keyboard.h"
|
|
#include "module.h"
|
|
#include "periph.h"
|
|
#include "rzx.h"
|
|
#include "settings.h"
|
|
#include "spectrum.h"
|
|
#include "machine.h"
|
|
#include "ui/ui.h"
|
|
#include "ui/uijoystick.h"
|
|
|
|
/* Number of joysticks known about & initialised */
|
|
int joysticks_supported = 0;
|
|
|
|
/* The bit masks used by the various joysticks. The order is the same
|
|
as the ordering of buttons in joystick.h:joystick_button (left,
|
|
right, up, down, fire ) */
|
|
static const libspectrum_byte kempston_mask[5] =
|
|
{ 0x02, 0x01, 0x08, 0x04, 0x10 };
|
|
static const libspectrum_byte timex_mask[5] =
|
|
{ 0x04, 0x08, 0x01, 0x02, 0x80 };
|
|
|
|
/* The keys used by the Cursor joystick */
|
|
static const keyboard_key_name cursor_key[5] =
|
|
{ KEYBOARD_5, KEYBOARD_8, KEYBOARD_7, KEYBOARD_6, KEYBOARD_0 };
|
|
|
|
/* The keys used by the two Sinclair joysticks */
|
|
static const keyboard_key_name sinclair1_key[5] =
|
|
{ KEYBOARD_6, KEYBOARD_7, KEYBOARD_9, KEYBOARD_8, KEYBOARD_0 };
|
|
static const keyboard_key_name sinclair2_key[5] =
|
|
{ KEYBOARD_1, KEYBOARD_2, KEYBOARD_4, KEYBOARD_3, KEYBOARD_5 };
|
|
|
|
/* The current values for the joysticks we can emulate */
|
|
static libspectrum_byte kempston_value;
|
|
static libspectrum_byte timex1_value;
|
|
static libspectrum_byte timex2_value;
|
|
static libspectrum_byte fuller_value;
|
|
|
|
/* The names of the joysticks we can emulate. Order must correspond to
|
|
that of joystick.h:joystick_type_t */
|
|
const char *joystick_name[ JOYSTICK_TYPE_COUNT ] = {
|
|
"None",
|
|
"Cursor",
|
|
"Kempston",
|
|
"Sinclair 1", "Sinclair 2",
|
|
"Timex 1", "Timex 2",
|
|
"Fuller"
|
|
};
|
|
|
|
const char *joystick_connection[ JOYSTICK_CONN_COUNT ] = {
|
|
"None",
|
|
"Keyboard",
|
|
"Joystick 1",
|
|
"Joystick 2",
|
|
};
|
|
|
|
static void joystick_from_snapshot( libspectrum_snap *snap );
|
|
static void joystick_to_snapshot( libspectrum_snap *snap );
|
|
|
|
static module_info_t joystick_module_info = {
|
|
|
|
/* .reset = */ NULL,
|
|
/* .romcs = */ NULL,
|
|
/* .snapshot_enabled = */ NULL,
|
|
/* .snapshot_from = */ joystick_from_snapshot,
|
|
/* .snapshot_to = */ joystick_to_snapshot,
|
|
|
|
};
|
|
|
|
static const periph_port_t kempston_strict_decoding[] = {
|
|
{ 0x00e0, 0x0000, joystick_kempston_read, NULL },
|
|
{ 0, 0, NULL, NULL }
|
|
};
|
|
|
|
static const periph_t kempston_strict_periph = {
|
|
/* .option = */ &settings_current.joy_kempston,
|
|
/* .ports = */ kempston_strict_decoding,
|
|
/* .hard_reset = */ 0,
|
|
/* .activate = */ NULL,
|
|
};
|
|
|
|
static const periph_port_t kempston_loose_decoding[] = {
|
|
{ 0x0020, 0x0000, joystick_kempston_read, NULL },
|
|
{ 0, 0, NULL, NULL }
|
|
};
|
|
|
|
static const periph_t kempston_loose_periph = {
|
|
/* .option = */ &settings_current.joy_kempston,
|
|
/* .ports = */ kempston_loose_decoding,
|
|
/* .hard_reset = */ 0,
|
|
/* .activate = */ NULL,
|
|
};
|
|
|
|
/* Init/shutdown functions. Errors aren't important here */
|
|
|
|
int
|
|
joystick_init( void *context )
|
|
{
|
|
joysticks_supported = ui_joystick_init();
|
|
kempston_value = timex1_value = timex2_value = 0x00;
|
|
fuller_value = 0xff;
|
|
|
|
module_register( &joystick_module_info );
|
|
periph_register( PERIPH_TYPE_KEMPSTON, &kempston_strict_periph );
|
|
periph_register( PERIPH_TYPE_KEMPSTON_LOOSE, &kempston_loose_periph );
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
joystick_end( void )
|
|
{
|
|
ui_joystick_end();
|
|
}
|
|
|
|
void
|
|
joystick_register_startup( void )
|
|
{
|
|
startup_manager_module dependencies[] = {
|
|
STARTUP_MANAGER_MODULE_LIBSPECTRUM,
|
|
STARTUP_MANAGER_MODULE_SETUID
|
|
};
|
|
startup_manager_register( STARTUP_MANAGER_MODULE_JOYSTICK, dependencies,
|
|
ARRAY_SIZE( dependencies ), joystick_init,
|
|
joystick_end, NULL );
|
|
}
|
|
|
|
int
|
|
joystick_press( int which, joystick_button button, int press )
|
|
{
|
|
joystick_type_t type;
|
|
|
|
switch( which ) {
|
|
case 0: type = settings_current.joystick_1_output; break;
|
|
case 1: type = settings_current.joystick_2_output; break;
|
|
|
|
case JOYSTICK_KEYBOARD:
|
|
type = settings_current.joystick_keyboard_output; break;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
|
|
switch( type ) {
|
|
|
|
case JOYSTICK_TYPE_CURSOR:
|
|
if( press ) {
|
|
keyboard_press( cursor_key[ button ] );
|
|
} else {
|
|
keyboard_release( cursor_key[ button ] );
|
|
}
|
|
return 1;
|
|
|
|
case JOYSTICK_TYPE_KEMPSTON:
|
|
if( press ) {
|
|
kempston_value |= kempston_mask[ button ];
|
|
} else {
|
|
kempston_value &= ~kempston_mask[ button ];
|
|
}
|
|
return 1;
|
|
|
|
case JOYSTICK_TYPE_SINCLAIR_1:
|
|
if( press ) {
|
|
keyboard_press( sinclair1_key[ button ] );
|
|
} else {
|
|
keyboard_release( sinclair1_key[ button ] );
|
|
}
|
|
return 1;
|
|
|
|
case JOYSTICK_TYPE_SINCLAIR_2:
|
|
if( press ) {
|
|
keyboard_press( sinclair2_key[ button ] );
|
|
} else {
|
|
keyboard_release( sinclair2_key[ button ] );
|
|
}
|
|
return 1;
|
|
|
|
case JOYSTICK_TYPE_TIMEX_1:
|
|
if( press ) {
|
|
timex1_value |= timex_mask[ button ];
|
|
} else {
|
|
timex1_value &= ~timex_mask[ button ];
|
|
}
|
|
return 1;
|
|
|
|
case JOYSTICK_TYPE_TIMEX_2:
|
|
if( press ) {
|
|
timex2_value |= timex_mask[ button ];
|
|
} else {
|
|
timex2_value &= ~timex_mask[ button ];
|
|
}
|
|
return 1;
|
|
|
|
case JOYSTICK_TYPE_FULLER:
|
|
if( press ) {
|
|
fuller_value &= ~timex_mask[ button ];
|
|
} else {
|
|
fuller_value |= timex_mask[ button ];
|
|
}
|
|
return 1;
|
|
|
|
case JOYSTICK_TYPE_NONE: return 0;
|
|
}
|
|
|
|
ui_error( UI_ERROR_ERROR, "%s:joystick_press:unknown joystick type %d",
|
|
__FILE__, type );
|
|
fuse_abort();
|
|
}
|
|
|
|
/* Read functions for specific interfaces */
|
|
|
|
libspectrum_byte
|
|
joystick_kempston_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
|
|
{
|
|
*attached = 0xff; /* TODO: check this */
|
|
return kempston_value;
|
|
}
|
|
|
|
libspectrum_byte
|
|
joystick_timex_read( libspectrum_word port GCC_UNUSED, libspectrum_byte which )
|
|
{
|
|
return which ? timex2_value : timex1_value;
|
|
}
|
|
|
|
libspectrum_byte
|
|
joystick_fuller_read( libspectrum_word port GCC_UNUSED, libspectrum_byte *attached )
|
|
{
|
|
*attached = 0xff; /* TODO: check this */
|
|
return fuller_value;
|
|
}
|
|
|
|
static void
|
|
joystick_from_snapshot( libspectrum_snap *snap )
|
|
{
|
|
size_t i;
|
|
size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
|
|
joystick_type_t fuse_type;
|
|
|
|
for( i = 0; i < num_joysticks; i++ ) {
|
|
switch( libspectrum_snap_joystick_list( snap, i ) ) {
|
|
case LIBSPECTRUM_JOYSTICK_CURSOR:
|
|
fuse_type = JOYSTICK_TYPE_CURSOR;
|
|
break;
|
|
case LIBSPECTRUM_JOYSTICK_KEMPSTON:
|
|
fuse_type = JOYSTICK_TYPE_KEMPSTON;
|
|
break;
|
|
case LIBSPECTRUM_JOYSTICK_SINCLAIR_1:
|
|
fuse_type = JOYSTICK_TYPE_SINCLAIR_1;
|
|
break;
|
|
case LIBSPECTRUM_JOYSTICK_SINCLAIR_2:
|
|
fuse_type = JOYSTICK_TYPE_SINCLAIR_2;
|
|
break;
|
|
case LIBSPECTRUM_JOYSTICK_TIMEX_1:
|
|
fuse_type = JOYSTICK_TYPE_TIMEX_1;
|
|
break;
|
|
case LIBSPECTRUM_JOYSTICK_TIMEX_2:
|
|
fuse_type = JOYSTICK_TYPE_TIMEX_2;
|
|
break;
|
|
case LIBSPECTRUM_JOYSTICK_FULLER:
|
|
fuse_type = JOYSTICK_TYPE_FULLER;
|
|
break;
|
|
default:
|
|
ui_error( UI_ERROR_INFO, "Ignoring unsupported joystick in snapshot %s",
|
|
libspectrum_joystick_name( libspectrum_snap_joystick_list( snap, i ) ));
|
|
continue;
|
|
}
|
|
|
|
if( settings_current.joystick_keyboard_output != fuse_type &&
|
|
settings_current.joystick_1_output != fuse_type &&
|
|
settings_current.joystick_2_output != fuse_type &&
|
|
!rzx_playback ) {
|
|
switch( ui_confirm_joystick( libspectrum_snap_joystick_list(snap,i),
|
|
libspectrum_snap_joystick_inputs(snap,i)) ) {
|
|
case UI_CONFIRM_JOYSTICK_KEYBOARD:
|
|
settings_current.joystick_keyboard_output = fuse_type;
|
|
break;
|
|
case UI_CONFIRM_JOYSTICK_JOYSTICK_1:
|
|
settings_current.joystick_1_output = fuse_type;
|
|
break;
|
|
case UI_CONFIRM_JOYSTICK_JOYSTICK_2:
|
|
settings_current.joystick_2_output = fuse_type;
|
|
break;
|
|
case UI_CONFIRM_JOYSTICK_NONE:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* If the snap was configured for a Kempston joystick, enable
|
|
our Kempston emulation in case the snap was reading from
|
|
the joystick to prevent things going haywire */
|
|
if( fuse_type == JOYSTICK_TYPE_KEMPSTON )
|
|
settings_current.joy_kempston = 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
add_joystick( libspectrum_snap *snap, joystick_type_t fuse_type, int inputs )
|
|
{
|
|
size_t i;
|
|
size_t num_joysticks = libspectrum_snap_joystick_active_count( snap );
|
|
libspectrum_joystick libspectrum_type;
|
|
|
|
switch( fuse_type ) {
|
|
case JOYSTICK_TYPE_CURSOR:
|
|
libspectrum_type = LIBSPECTRUM_JOYSTICK_CURSOR;
|
|
break;
|
|
case JOYSTICK_TYPE_KEMPSTON:
|
|
libspectrum_type = LIBSPECTRUM_JOYSTICK_KEMPSTON;
|
|
break;
|
|
case JOYSTICK_TYPE_SINCLAIR_1:
|
|
libspectrum_type = LIBSPECTRUM_JOYSTICK_SINCLAIR_1;
|
|
break;
|
|
case JOYSTICK_TYPE_SINCLAIR_2:
|
|
libspectrum_type = LIBSPECTRUM_JOYSTICK_SINCLAIR_2;
|
|
break;
|
|
case JOYSTICK_TYPE_TIMEX_1:
|
|
libspectrum_type = LIBSPECTRUM_JOYSTICK_TIMEX_1;
|
|
break;
|
|
case JOYSTICK_TYPE_TIMEX_2:
|
|
libspectrum_type = LIBSPECTRUM_JOYSTICK_TIMEX_2;
|
|
break;
|
|
case JOYSTICK_TYPE_FULLER:
|
|
libspectrum_type = LIBSPECTRUM_JOYSTICK_FULLER;
|
|
break;
|
|
|
|
case JOYSTICK_TYPE_NONE:
|
|
default:
|
|
return;
|
|
}
|
|
|
|
for( i = 0; i < num_joysticks; i++ ) {
|
|
if( libspectrum_snap_joystick_list( snap, i ) == libspectrum_type ) {
|
|
libspectrum_snap_set_joystick_inputs( snap, i, inputs |
|
|
libspectrum_snap_joystick_inputs( snap, i ) );
|
|
return;
|
|
}
|
|
}
|
|
|
|
libspectrum_snap_set_joystick_list( snap, num_joysticks, libspectrum_type );
|
|
libspectrum_snap_set_joystick_inputs( snap, num_joysticks, inputs );
|
|
libspectrum_snap_set_joystick_active_count( snap, num_joysticks + 1 );
|
|
}
|
|
|
|
static void
|
|
joystick_to_snapshot( libspectrum_snap *snap )
|
|
{
|
|
if( settings_current.joy_kempston ) {
|
|
add_joystick( snap, JOYSTICK_TYPE_KEMPSTON,
|
|
LIBSPECTRUM_JOYSTICK_INPUT_NONE );
|
|
}
|
|
add_joystick( snap, settings_current.joystick_keyboard_output,
|
|
LIBSPECTRUM_JOYSTICK_INPUT_KEYBOARD );
|
|
add_joystick( snap, settings_current.joystick_1_output,
|
|
LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_1 );
|
|
add_joystick( snap, settings_current.joystick_2_output,
|
|
LIBSPECTRUM_JOYSTICK_INPUT_JOYSTICK_2 );
|
|
}
|