Files
AppleWin/source/FourPlay.cpp
2026-07-26 21:49:53 +01:00

175 lines
5.2 KiB
C++

/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2007, Tom Charlesworth, Michael Pohoreski
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
FourPlay.CPP
Emulate a 4Play Joystick card
4 ports (one for each of the four possible joysticks)
Each port
Bit 0 = Up, Active High
Bit 1 = Down, Active High
Bit 2 = Left, Active High
Bit 3 = Right, Active High
Bit 4 = Not Used, Always Low
Bit 5 = Not Used, Always High
Bit 6 = Trigger 2, Active High
Bit 7 = Trigger 1, Active High
Address = C0nx
n = 8 + slot number
x = 0 - Joystick 1
1 - Joystick 2
2 - Joystick 3
3 - Joystick 4
Alex Lukacz Aug 2021
*/
#include "StdAfx.h"
#include "FourPlay.h"
#include "Joystick.h"
#include "Memory.h"
#include "YamlHelper.h"
inline static int bool_to_bit(bool b, int shift)
{
return b ? (1 << shift) : 0;
}
BYTE FourPlayCard::MakeByte(bool up, bool down, bool left, bool right, bool trigger1, bool trigger2)
{
const int byte = bool_to_bit(up, 0)
| bool_to_bit(down, 1)
| bool_to_bit(left, 2)
| bool_to_bit(right, 3)
| bool_to_bit(false, 4)
| bool_to_bit(true, 5)
| bool_to_bit(trigger2, 6)
| bool_to_bit(trigger1, 7);
return byte;
}
BYTE __stdcall FourPlayCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
bool up = false;
bool down = false;
bool left = false;
bool right = false;
bool trigger1 = false;
bool trigger2 = false;
JOYINFOEX infoEx;
infoEx.dwSize = sizeof(infoEx);
infoEx.dwFlags = JOY_RETURNPOV | JOY_RETURNBUTTONS;
switch (addr & 0xF)
{
case 0: // Joystick 1
if (GetJoystick1() >= 0 && joyGetPosEx(GetJoystick1(), &infoEx) == JOYERR_NOERROR)
{
UINT xAxis = (infoEx.dwXpos >> 8) & 0xFF;
UINT yAxis = (infoEx.dwYpos >> 8) & 0xFF;
trigger1 = (infoEx.dwButtons & 0x01);
trigger2 = (infoEx.dwButtons & 0x02);
up = yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500;
down = yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500);
left = xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500);
right = xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500);
}
break;
case 1: // Joystick 2
if (GetJoystick2() >= 0 && joyGetPosEx(GetJoystick2(), &infoEx) == JOYERR_NOERROR)
{
UINT xAxis = (infoEx.dwXpos >> 8) & 0xFF;
UINT yAxis = (infoEx.dwYpos >> 8) & 0xFF;
trigger1 = (infoEx.dwButtons & 0x01);
trigger2 = (infoEx.dwButtons & 0x02);
up = yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500;
down = yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500);
left = xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500);
right = xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500);
}
break;
case 2: // Joystick 3
// esdf - direction buttons, zx - trigger buttons
trigger1 = MyGetAsyncKeyState('Z');
trigger2 = MyGetAsyncKeyState('X');
up = MyGetAsyncKeyState('E');
down = MyGetAsyncKeyState('D');
left = MyGetAsyncKeyState('S');
right = MyGetAsyncKeyState('F');
break;
case 3: // Joystick 4
// ijkl - direction buttons, nm - trigger buttons
trigger1 = MyGetAsyncKeyState('N');
trigger2 = MyGetAsyncKeyState('M');
up = MyGetAsyncKeyState('I');
down = MyGetAsyncKeyState('K');
left = MyGetAsyncKeyState('J');
right = MyGetAsyncKeyState('L');
break;
default:
return MemReadFloatingBus(nExecutedCycles);
}
return MakeByte(up, down, left, right, trigger1, trigger2);
}
bool FourPlayCard::MyGetAsyncKeyState(int vKey)
{
return (GetAsyncKeyState(vKey) < 0);
}
void FourPlayCard::InitializeIO(LPBYTE pCxRomPeripheral)
{
RegisterIoHandler(m_slot, &FourPlayCard::IORead, IO_Null, IO_Null, IO_Null, this, NULL);
}
//===========================================================================
static const UINT kUNIT_VERSION = 1;
const std::string& FourPlayCard::GetSnapshotCardName()
{
static const std::string name("4Play");
return name;
}
void FourPlayCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
YamlSaveHelper::Label unit(yamlSaveHelper, "%s: null\n", SS_YAML_KEY_STATE);
// NB. No state for this card
}
bool FourPlayCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
{
if (version < 1 || version > kUNIT_VERSION)
ThrowErrorInvalidVersion(version);
return true;
}