MCUME/MCUME_teensy41/teensysnes/controls.cpp
2022-04-24 20:50:09 +02:00

447 lines
9.4 KiB
C++

/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
This file is licensed under the Snes9x License.
For further information, consult the LICENSE file in the root directory.
\*****************************************************************************/
#include "snes9x.h"
#include "memory.h"
#include "apu.h"
//#include "snapshot.h"
#include "controls.h"
static s9xcommand_t keymap[MaxControlID + 1];
static int FLAG_LATCH = FALSE;
static struct {
uint32 read_idx;
uint32 buttons;
} joypads[2];
// Note: these should be in asciibetical order!
#define THE_COMMANDS \
S(Debugger), \
S(DecFrameRate), \
S(EmuTurbo), \
S(ExitEmu), \
S(IncFrameRate), \
S(LoadFreezeFile), \
S(Pause), \
S(Reset), \
S(SaveFreezeFile), \
S(SoftReset), \
S(SoundChannel0), \
S(SoundChannel1), \
S(SoundChannel2), \
S(SoundChannel3), \
S(SoundChannel4), \
S(SoundChannel5), \
S(SoundChannel6), \
S(SoundChannel7), \
S(SoundChannelsOn), \
S(ToggleBG0), \
S(ToggleBG1), \
S(ToggleBG2), \
S(ToggleBG3), \
S(ToggleEmuTurbo), \
S(ToggleSprites), \
S(ToggleTransparency) \
#define S(x) x
enum command_numbers
{
THE_COMMANDS,
LAST_COMMAND
};
#undef S
#define S(x) #x
static const char *command_names[LAST_COMMAND + 1] =
{
THE_COMMANDS,
NULL
};
#undef S
#undef THE_COMMANDS
static void DisplayStateChange (const char *str, bool8 on)
{
snprintf(String, sizeof(String), "%s: %s", str, on ? "on":"off");
S9xMessage(S9X_INFO, 0, String);
}
void S9xControlsReset (void)
{
memset(&joypads, 0, sizeof(joypads));
FLAG_LATCH = FALSE;
}
void S9xUnmapAllControls (void)
{
memset(&keymap, 0, sizeof(keymap));
S9xControlsReset();
}
s9xcommand_t S9xGetCommandT (const char *name)
{
s9xcommand_t cmd ;
cmd.type = S9xBadMapping;
cmd.button_norpt = 0;
cmd.command = 0;
//s9xcommand_t cmd = {
// .type = S9xBadMapping,
// .button_norpt = 0,
// .command = 0,
//};
if (!name)
cmd.type = S9xBadMapping;
else
if (!strcmp(name, "None"))
cmd.type = S9xNoMapping;
else
if (!strncmp(name, "Joypad", 6))
{
if (((int)name[6] - '1') <= 0)
cmd.type = S9xButtonJoypad0;
else
cmd.type = S9xButtonJoypad1;
const char *s = name + 7;
int i = 0;
while (s[0] == ' ')
s++;
if (!strncmp(s, "Up", 2)) { i |= SNES_UP_MASK; s += 2; if (*s == '+') s++; }
if (!strncmp(s, "Down", 4)) { i |= SNES_DOWN_MASK; s += 4; if (*s == '+') s++; }
if (!strncmp(s, "Left", 4)) { i |= SNES_LEFT_MASK; s += 4; if (*s == '+') s++; }
if (!strncmp(s, "Right", 5)) { i |= SNES_RIGHT_MASK; s += 5; if (*s == '+') s++; }
if (*s == 'A') { i |= SNES_A_MASK; s++; if (*s == '+') s++; }
if (*s == 'B') { i |= SNES_B_MASK; s++; if (*s == '+') s++; }
if (*s == 'X') { i |= SNES_X_MASK; s++; if (*s == '+') s++; }
if (*s == 'Y') { i |= SNES_Y_MASK; s++; if (*s == '+') s++; }
if (*s == 'L') { i |= SNES_TL_MASK; s++; if (*s == '+') s++; }
if (*s == 'R') { i |= SNES_TR_MASK; s++; if (*s == '+') s++; }
if (!strncmp(s, "Start", 5)) { i |= SNES_START_MASK; s += 5; if (*s == '+') s++; }
if (!strncmp(s, "Select", 6)) { i |= SNES_SELECT_MASK; s += 6; }
if (i == 0 || *s != 0 || *(s - 1) == '+')
return (cmd);
cmd.buttons = i;
}
else
{
for (int i = 0; i < LAST_COMMAND; i++)
{
if (strcasecmp(command_names[i], name) == 0)
{
cmd.type = S9xButtonCommand;
cmd.command = i;
break;
}
}
}
return (cmd);
}
s9xcommand_t S9xGetMapping (uint32 id)
{
if (id > MaxControlID)
{
s9xcommand_t dummy = {0};
return dummy;
}
return (keymap[id]);
}
void S9xUnmapButton (uint32 id)
{
if (id > MaxControlID)
{
printf("WARNING: Invalid Control ID %d, should be between 0 and %d\n", id, MaxControlID);
return;
}
memset(&keymap[id], 0, sizeof(s9xcommand_t));
}
bool S9xMapButtonT (uint32 id, const char *command)
{
s9xcommand_t cmd = S9xGetCommandT(command);
if (cmd.type == S9xBadMapping)
{
printf("WARNING: Invalid command '%s'\n", command);
return (false);
}
return S9xMapButton(id, cmd);
}
bool S9xMapButton (uint32 id, s9xcommand_t mapping)
{
if (id > MaxControlID)
{
printf("WARNING: Invalid Control ID %d, should be between 0 and %d\n", id, MaxControlID);
return (false);
}
if (mapping.type == S9xNoMapping)
{
S9xUnmapButton(id);
return (true);
}
if (keymap[id].type != S9xNoMapping)
fprintf(stderr, "WARNING: Remapping ID %d\n", id);
keymap[id] = mapping;
return (true);
}
void S9xReportButton (uint32 id, bool pressed)
{
if (id > MaxControlID)
return;
// skips the "already-pressed check" unless it's a command, as a hack to work around the following problem:
// FIXME: this makes the controls "stick" after loading a savestate while recording a movie and holding any button
if (keymap[id].type == S9xButtonCommand && keymap[id].button_norpt)
return;
keymap[id].button_norpt = pressed;
S9xApplyCommand(keymap[id], pressed);
}
void S9xApplyCommand (s9xcommand_t cmd, int data1)
{
switch (cmd.type)
{
case S9xNoMapping:
return;
case S9xButtonJoypad0:
if (data1)
joypads[0].buttons |= cmd.buttons;
else
joypads[0].buttons &= ~cmd.buttons;
return;
case S9xButtonJoypad1:
if (data1)
joypads[1].buttons |= cmd.buttons;
else
joypads[1].buttons &= ~cmd.buttons;
return;
case S9xButtonCommand:
if (!data1)
{
switch (cmd.command)
{
case EmuTurbo:
Settings.TurboMode = FALSE;
break;
default:
fprintf(stderr, "Unknown command %04x\n", cmd.command);
}
}
else
{
switch (cmd.command)
{
case ExitEmu:
S9xExit();
break;
case Reset:
S9xReset();
break;
case SoftReset:
S9xSoftReset();
break;
case EmuTurbo:
Settings.TurboMode = TRUE;
break;
case ToggleEmuTurbo:
Settings.TurboMode = !Settings.TurboMode;
DisplayStateChange("Turbo mode", Settings.TurboMode);
break;
case Debugger:
#ifdef DEBUGGER
CPU.Flags |= DEBUG_MODE_FLAG;
#endif
break;
case IncFrameRate:
if (Settings.SkipFrames == AUTO_FRAMERATE)
Settings.SkipFrames = 1;
else
if (Settings.SkipFrames < 10)
Settings.SkipFrames++;
if (Settings.SkipFrames == AUTO_FRAMERATE)
S9xMessage(S9X_INFO, 0, "Auto frame skip");
else
{
sprintf(String, "Frame skip: %d", Settings.SkipFrames - 1);
S9xMessage(S9X_INFO, 0, String);
}
break;
case DecFrameRate:
if (Settings.SkipFrames <= 1)
Settings.SkipFrames = AUTO_FRAMERATE;
else
if (Settings.SkipFrames != AUTO_FRAMERATE)
Settings.SkipFrames--;
if (Settings.SkipFrames == AUTO_FRAMERATE)
S9xMessage(S9X_INFO, 0, "Auto frame skip");
else
{
sprintf(String, "Frame skip: %d", Settings.SkipFrames - 1);
S9xMessage(S9X_INFO, 0, String);
}
break;
case LoadFreezeFile:
// S9xUnfreezeGame(S9xChooseFilename(TRUE));
break;
case SaveFreezeFile:
// S9xFreezeGame(S9xChooseFilename(FALSE));
break;
case Pause:
Settings.Paused = !Settings.Paused;
DisplayStateChange("Pause", Settings.Paused);
break;
case SoundChannel0:
case SoundChannel1:
case SoundChannel2:
case SoundChannel3:
case SoundChannel4:
case SoundChannel5:
case SoundChannel6:
case SoundChannel7:
S9xToggleSoundChannel((int)cmd.command - SoundChannel0);
sprintf(String, "Sound channel %d toggled", (int)cmd.command - SoundChannel0);
S9xMessage(S9X_INFO, 0, String);
break;
case SoundChannelsOn:
S9xToggleSoundChannel(8);
S9xMessage(S9X_INFO, 0, "All sound channels on");
break;
case ToggleBG0:
Settings.BG_Forced ^= 1;
DisplayStateChange("BG#0", !(Settings.BG_Forced & 1));
break;
case ToggleBG1:
Settings.BG_Forced ^= 2;
DisplayStateChange("BG#1", !(Settings.BG_Forced & 2));
break;
case ToggleBG2:
Settings.BG_Forced ^= 4;
DisplayStateChange("BG#2", !(Settings.BG_Forced & 4));
break;
case ToggleBG3:
Settings.BG_Forced ^= 8;
DisplayStateChange("BG#3", !(Settings.BG_Forced & 8));
break;
case ToggleSprites:
Settings.BG_Forced ^= 16;
DisplayStateChange("Sprites", !(Settings.BG_Forced & 16));
break;
case ToggleTransparency:
Settings.Transparency = !Settings.Transparency;
DisplayStateChange("Transparency effects", Settings.Transparency);
break;
case LAST_COMMAND:
break;
default:
fprintf(stderr, "Unknown command %04x\n", cmd.command);
}
}
return;
default:
fprintf(stderr, "WARNING: Unknown command type %d\n", cmd.type);
return;
}
}
void S9xSetJoypadLatch (bool latch)
{
if (latch && !FLAG_LATCH)
{
joypads[0].read_idx = 0;
joypads[1].read_idx = 0;
}
FLAG_LATCH = latch;
}
uint8 S9xReadJOYSERn (int n)
{
n &= 1;
int bits = (OpenBus & ~3) | ((n == 1) ? 0x1c : 0);
if (FLAG_LATCH)
{
return (bits | ((joypads[n].buttons >> 15) & 1));
}
else
{
if (joypads[n].read_idx < 16)
{
return (bits | ((joypads[n].buttons >> (15 - joypads[n].read_idx++)) & 1));
}
else
{
return (bits | 1);
}
}
}
void S9xDoAutoJoypad (void)
{
S9xSetJoypadLatch(1);
S9xSetJoypadLatch(0);
for (int n = 0; n < 2; n++)
{
joypads[n].read_idx = 16;
WRITE_WORD(Memory.CPU_IO + 0x218 + n * 2, joypads[n].buttons);
WRITE_WORD(Memory.CPU_IO + 0x21c + n * 2, 0);
}
}