Add 4Play & SNES MAX card support (#946, #972, PR #982)

Support these new cards in slots 3, 4 or 5; based on code from Lukazi.
- extend Configuration's Input prop sheet page.
- add save/load snapshot for both cards.
- add command line switch for alt controller type (for SNES MAX card).
Change to using Registry's 'Configuration\Slot 3' for slot 3 cards (Uthernet, 4Play & SNES MAX).
Update help doc.
This commit is contained in:
TomCh 2021-09-10 13:57:55 +01:00 committed by GitHub
parent 7f2dd9727d
commit 685b93f387
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 1000 additions and 108 deletions

View File

@ -79,6 +79,7 @@
<ClInclude Include="source\DiskImage.h" />
<ClInclude Include="source\DiskImageHelper.h" />
<ClInclude Include="source\DiskLog.h" />
<ClInclude Include="source\FourPlay.h" />
<ClInclude Include="source\FrameBase.h" />
<ClInclude Include="source\Harddisk.h" />
<ClInclude Include="source\Interface.h" />
@ -102,6 +103,7 @@
<ClInclude Include="source\SaveState_Structs_common.h" />
<ClInclude Include="source\SaveState_Structs_v1.h" />
<ClInclude Include="source\SerialComms.h" />
<ClInclude Include="source\SNESMAX.h" />
<ClInclude Include="source\SoundCore.h" />
<ClInclude Include="source\Speaker.h" />
<ClInclude Include="source\Speech.h" />
@ -160,6 +162,7 @@
<ClCompile Include="source\Debugger\Debugger_Disassembler.cpp" />
<ClCompile Include="source\Debugger\Debugger_Win32.cpp" />
<ClCompile Include="source\Disk2CardManager.cpp" />
<ClCompile Include="source\FourPlay.cpp" />
<ClCompile Include="source\FrameBase.cpp" />
<ClCompile Include="source\RGBMonitor.cpp" />
<ClCompile Include="source\SAM.cpp" />
@ -196,6 +199,7 @@
<ClCompile Include="source\Riff.cpp" />
<ClCompile Include="source\SaveState.cpp" />
<ClCompile Include="source\SerialComms.cpp" />
<ClCompile Include="source\SNESMAX.cpp" />
<ClCompile Include="source\SoundCore.cpp" />
<ClCompile Include="source\Speaker.cpp" />
<ClCompile Include="source\Speech.cpp" />
@ -280,9 +284,12 @@
<None Include="resource\Apple2.rom" />
<None Include="resource\Apple2e.rom" />
<None Include="resource\Apple2e_Enhanced.rom" />
<None Include="resource\Apple2_JPlus.rom" />
<None Include="resource\Apple2_JPlus_Video.rom" />
<None Include="resource\Apple2_Plus.rom" />
<None Include="resource\Base64A.rom" />
<None Include="resource\Base64A_German_Video.rom" />
<None Include="resource\Disk2-13sector.rom" />
<None Include="resource\DISK2.rom" />
<None Include="resource\Freezes_Non-autostart_F8_Rom.rom" />
<None Include="resource\Hddrvr.bin" />
@ -313,6 +320,7 @@
<ItemGroup>
<Image Include="resource\Applewin.bmp" />
<Image Include="resource\APPLEWIN.ICO" />
<Image Include="resource\ApplewinLogo.bmp" />
<Image Include="resource\CAPSOFF.BMP" />
<Image Include="resource\CAPSOFF_P8.BMP" />
<Image Include="resource\CAPSON.BMP" />

View File

@ -232,6 +232,12 @@
<ClCompile Include="source\Windows\HookFilter.cpp">
<Filter>Source Files\Windows</Filter>
</ClCompile>
<ClCompile Include="source\FourPlay.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="source\SNESMAX.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\CommonVICE\6510core.h">
@ -546,6 +552,12 @@
<ClInclude Include="source\Windows\HookFilter.h">
<Filter>Source Files\Windows</Filter>
</ClInclude>
<ClInclude Include="source\FourPlay.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="source\SNESMAX.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="resource\Applewin.bmp">
@ -656,6 +668,9 @@
<Image Include="resource\RUNBASE64A.BMP">
<Filter>Resource Files</Filter>
</Image>
<Image Include="resource\ApplewinLogo.bmp">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<None Include="resource\Apple2.rom">
@ -721,6 +736,15 @@
<None Include="resource\Base64A_German_Video.rom">
<Filter>Resource Files</Filter>
</None>
<None Include="resource\Apple2_JPlus.rom">
<Filter>Resource Files</Filter>
</None>
<None Include="resource\Apple2_JPlus_Video.rom">
<Filter>Resource Files</Filter>
</None>
<None Include="resource\Disk2-13sector.rom">
<Filter>Resource Files</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Text Include="docs\CodingConventions.txt">

View File

@ -171,7 +171,9 @@
Support 60Hz(NTSC) video refresh rate and NTSC 1.020MHz base CPU clock (default).<br><br>
-power-on<br>
Force a power-on.<br>
Use to auto power-on when not using -d1, -h1 or -load-state.<br>
Use to auto power-on when not using -d1, -h1 or -load-state.<br><br>
-snes-max-alt-joy1 or -snes-max-alt-joy2<br>
Use alternate button mappings for the SNES MAX card. See <a href="cfg-input.html">Input Settings</a>.<br>
<br>
<P style="FONT-WEIGHT: bold">Debug arguments:

View File

@ -25,5 +25,6 @@
<p style="MARGIN-LEFT: 40px">Iván Izaguirre: Taiwanese Copam Base64A Apple II clone</p>
<p style="MARGIN-LEFT: 40px">Arnaud C: debugger suggestions and help with 6502/6522/video timing issues</p>
<p style="MARGIN-LEFT: 40px">Cyril Lambin: RGB card/monitor rendering, debugger improvements</p>
<p style="MARGIN-LEFT: 40px">Alex Lukacz: 4Play & SNES MAX card support</p>
</body>
</html>

View File

@ -3,7 +3,7 @@
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252"><title>Advanced Settings</title></head>
<body style="background-color: rgb(255, 255, 255); font-family: verdana;" alink="#008000" link="#008000" vlink="#008000">
<h2 style="color: rgb(0, 128, 0);">Advanced Settings</h2>
<hr size="4"><img style="width: 344px; height: 460px; float: right;" src="img/advanced.png" alt="Advanced settings" hspace="5" vspace="5">
<hr size="4"><img style="width: 354px; height: 460px; float: right;" src="img/advanced.png" alt="Advanced settings" hspace="5" vspace="5">
<p><strong>Save State File Name:</strong><br>
This is the file name to use for save-state files. The default
directory is the same as where your AppleWin.exe program is stored.</p>

View File

@ -8,7 +8,7 @@
link="#008000" vlink="#008000">
<h2 style="COLOR: rgb(0,128,0)">Configuration Settings</h2>
<hr size="4">
<img style="FLOAT: right; WIDTH: 344px; HEIGHT: 460px" src="img/config.png" alt="Configuration settings"
<img style="FLOAT: right; WIDTH: 354px; HEIGHT: 460px" src="img/config.png" alt="Configuration settings"
hspace="5" vspace="5">
<strong>Model:</strong><br>

View File

@ -6,7 +6,7 @@
</head>
<body style="background-color: rgb(255, 255, 255); font-family: verdana;" alink="#008000" link="#008000" vlink="#008000">
<h2 style="color: rgb(0, 128, 0);">Disk Settings</h2>
<hr size="4"><img style="width: 344px; height: 460px; float: right;" src="img/disk.png" alt="Disk settings" hspace="5" vspace="5">
<hr size="4"><img style="width: 354px; height: 460px; float: right;" src="img/disk.png" alt="Disk settings" hspace="5" vspace="5">
<h3>Floppy Controller Settings:</h3>
<p><strong>Enhanced disk access speed:</strong><br>

View File

@ -13,7 +13,7 @@
<h2 style="color: rgb(0, 128, 0);">Input Settings</h2>
<hr size="4"><img style="width: 344px; height: 460px; float: right;" src="img/input.png" alt="Input settings" hspace="5" vspace="5">
<hr size="4"><img style="width: 354px; height: 497px; float: right;" src="img/input.png" alt="Input settings" hspace="5" vspace="5">
<strong>Joystick Control:</strong><br>
These options allow you to configure up to two joysticks attached to
@ -38,6 +38,24 @@ then you should leave these values at 0.</li>
<li>Keyboard auto-centering: When keys used for joystick emulation are released then the joystick will return to the central position.</li>
</ul>
<strong>4Play Joystick card:</strong><br>
On real hardware this card allows up to 4 Atari 9-pin joysticks to be connected.<br>
Under emulation, the first 2 Windows-detected controllers will be used, and then for joysticks 3 and 4, use keys: ESDF+ZX and IJKL+NM. Note these keys will also be readable from the keyboard.<br>
<li>The card can be configured in slots 3, 4 or 5.
<li>Since it only uses the slot's DEVICE SELECT space ($C0Bx for slot 3) then it can co-exist with 80-column cards in the Apple //e's AUX slot. NB. For a real PAL Apple //e, then a slot riser card is required for it to fit.<br>
See Lukazi's <a href="https://lukazi.blogspot.com/2016/04/apple-ii-4play-joystick-card.html">4Play card</a> and <a href="https://lukazi.blogspot.com/2017/08/apple-ii-4play-joystick-card-software.html">4Play card software</a> blogs for more information.<br>
<br>
<strong>SNES MAX card:</strong><br>
On real hardware this card allows up to 2 SNES controllers to be connected and all 12 buttons can be read.<br>
Under emulation, the first 2 Windows-detected controllers will be used, ideally with 12 (or more) buttons eg. Logitech F310, PlayStation Dualshock 4, DualSense. Note that for some controllers (eg. 8BitDo NES30 Pro) the buttons need remapping, so use the command line switches -snes-max-alt-joy1 or -snes-max-alt-joy2 to remap.<br>
<li>The card can be configured in slots 3, 4 or 5.
<li>Since it only uses the slot's DEVICE SELECT space ($C0Bx for slot 3) then it can co-exist with 80-column cards in the Apple //e's AUX slot. NB. This card is small, so no slot riser card is required.<br>
See Lukazi's <a href="https://lukazi.blogspot.com/2021/06/game-controller-snes-max-snes.html">SNES MAX</a> blog for more information.<br>
<br>
<br>
<hr>
<strong>Scroll Lock acts as toggle for full-speed CPU:</strong><br>
<ul>
@ -50,13 +68,13 @@ then you should leave these values at 0.</li>
<ul>
<li>Disables joystick emulation with mouse.</li>
<li>Disables Mockingboard/Phasor in slot 4.</li>
<li>Show crosshairs in window's frame:</li>
<li>Show cross-hairs in window's frame:</li>
<ul>
<li>Configure whether you want crosshairs or not</li>
<li>Configure whether you want cross-hairs or not</li>
</ul>
<li>Restrict mouse to Apple window:</li>
<ul>
<li>Resticting is useful for paint applications</li>
<li>Restricting is useful for paint applications</li>
<li>When unrestricted, the emulated mouse is fully integrated with the Window desktop:
moving in and out of the AppleWin window will switch between Windows' and the Apple's mouse cursor.</li>
<li>NB. Even when unrestricted, you won't be able to move the mouse outside the Apple window for GEOS. This is not a bug.</li>

View File

@ -13,7 +13,7 @@
<h2 style="color: rgb(0, 128, 0);">Sound Settings</h2>
<hr size="4"><img style="width: 344px; height: 460px; float: right;" src="img/sound.png" alt="Sound settings" hspace="5" vspace="5"><strong>Sound:</strong><br>
<hr size="4"><img style="width: 354px; height: 460px; float: right;" src="img/sound.png" alt="Sound settings" hspace="5" vspace="5"><strong>Sound:</strong><br>
This option allows you to choose how sound is output for the
system.&nbsp;Your choices are:<br>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -115,12 +115,12 @@ BEGIN
CONTROL "50Hz video",IDC_CHECK_50HZ_VIDEO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,141,51,10
END
IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 210, 215
IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 211, 240
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU
CAPTION "Input"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
BEGIN
GROUPBOX "Joystick Control",IDC_STATIC,5,7,200,101
GROUPBOX "Joystick Control",IDC_STATIC,5,7,200,135
LTEXT "Joystick &1:",IDC_STATIC,12,20,40,8
COMBOBOX IDC_JOYSTICK0,52,18,110,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "Joystick &2:",IDC_STATIC,12,35,40,8
@ -136,17 +136,21 @@ BEGIN
CONTROL "Swap 0/1",IDC_SWAPBUTTONS0AND1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,162,75,41,10
CONTROL "Auto-fire (all 3 buttons)",IDC_AUTOFIRE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,90,89,10
CONTROL "Keyboard auto-centering",IDC_CENTERINGCONTROL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,102,90,96,10
LTEXT "4Play Joystick card:",IDC_STATIC,8,108,84,10
COMBOBOX IDC_FOURPLAY_CONFIG,93,106,55,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
LTEXT "SNES MAX card:",IDC_STATIC,8,123,82,10
COMBOBOX IDC_SNESMAX_CONFIG,93,122,55,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "&Scroll Lock acts as toggle for full-speed CPU",IDC_SCROLLLOCK_TOGGLE,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,113,166,10
CONTROL "&Mouse interface in slot 4",IDC_MOUSE_IN_SLOT4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,127,106,10
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,147,166,10
CONTROL "&Mouse interface in slot 4",IDC_MOUSE_IN_SLOT4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,161,106,10
CONTROL "Show &crosshairs in window's frame",IDC_MOUSE_CROSSHAIR,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,141,159,10
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,175,159,10
CONTROL "&Restrict mouse to Apple window",IDC_MOUSE_RESTRICT_TO_WINDOW,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,155,121,10
LTEXT "Microsoft CP/M SoftCard:",IDC_STATIC,8,170,122,10
COMBOBOX IDC_CPM_CONFIG,93,168,55,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Paste &From Clipboard",IDC_PASTE_FROM_CLIPBOARD,8,192,81,14
LTEXT "(Shift+Insert during emulation)",IDC_STATIC,93,195,111,8
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,189,121,10
LTEXT "Microsoft CP/M SoftCard:",IDC_STATIC,8,204,83,10
COMBOBOX IDC_CPM_CONFIG,93,202,55,60,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Paste &From Clipboard",IDC_PASTE_FROM_CLIPBOARD,8,219,81,14
LTEXT "(Shift+Insert during emulation)",IDC_STATIC,93,222,111,8
END
IDD_PROPPAGE_SOUND DIALOGEX 0, 0, 210, 191
@ -391,7 +395,7 @@ GUIDELINES DESIGNINFO
BEGIN
IDD_PROPPAGE_INPUT, DIALOG
BEGIN
BOTTOMMARGIN, 182
BOTTOMMARGIN, 231
END
IDD_PROPPAGE_DISK, DIALOG

View File

@ -118,6 +118,8 @@
#define IDC_CHECK_50HZ_VIDEO 1084
#define IDC_COMBO_DISK1_SLOT5 1085
#define IDC_COMBO_DISK2_SLOT5 1086
#define IDC_FOURPLAY_CONFIG 1087
#define IDC_SNESMAX_CONFIG 1088
#define IDM_EXIT 40001
#define IDM_HELP 40002
#define IDM_ABOUT 40003

View File

@ -21,6 +21,8 @@ enum SS_CARDTYPE
CT_LanguageCard, // Apple][ or ][+ in slot-0
CT_LanguageCardIIe, // Apple//e LC instance (not a card)
CT_Saturn128K, // Saturn 128K (but may be populated with less RAM, in multiples of 16K)
CT_FourPlay, // 4 port Atari 2600 style digital joystick card
CT_SNESMAX, // 2 port Nintendo NES/SNES controller serial interface card
};
enum SLOTS { SLOT0=0, SLOT1, SLOT2, SLOT3, SLOT4, SLOT5, SLOT6, SLOT7, NUM_SLOTS };

View File

@ -33,8 +33,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Core.h"
#include "Disk.h"
#include "FourPlay.h"
#include "MouseInterface.h"
#include "SerialComms.h"
#include "SNESMAX.h"
void CardManager::Insert(UINT slot, SS_CARDTYPE type)
{
@ -85,6 +87,12 @@ void CardManager::Insert(UINT slot, SS_CARDTYPE type)
case CT_Uthernet:
m_slot[slot] = new DummyCard(type);
break;
case CT_FourPlay:
m_slot[slot] = new FourPlayCard(slot);
break;
case CT_SNESMAX:
m_slot[slot] = new SNESMAXCard(slot);
break;
case CT_LanguageCard:
case CT_Saturn128K:

View File

@ -33,10 +33,10 @@ public:
SS_CARDTYPE QuerySlot(UINT slot) { _ASSERT(slot<NUM_SLOTS); return m_slot[slot]->QueryType(); }
Card& GetRef(UINT slot)
{
SS_CARDTYPE t=QuerySlot(slot); _ASSERT((t==CT_SSC || t==CT_MouseInterface || t==CT_Disk2) && m_slot[slot]);
SS_CARDTYPE t=QuerySlot(slot); _ASSERT((t==CT_SSC || t==CT_MouseInterface || t==CT_Disk2 || t == CT_FourPlay || t == CT_SNESMAX) && m_slot[slot]);
return *m_slot[slot];
}
Card* GetObj(UINT slot) { SS_CARDTYPE t=QuerySlot(slot); _ASSERT(t==CT_SSC || t==CT_MouseInterface || t==CT_Disk2); return m_slot[slot]; }
Card* GetObj(UINT slot) { SS_CARDTYPE t=QuerySlot(slot); _ASSERT(t==CT_SSC || t==CT_MouseInterface || t==CT_Disk2 || t == CT_FourPlay || t == CT_SNESMAX); return m_slot[slot]; }
void InsertAux(SS_CARDTYPE type);
void RemoveAux(void);

View File

@ -510,6 +510,14 @@ bool ProcessCmdLine(LPSTR lpCmdLine)
{
g_cmdLine.bRemoveNoSlotClock = true;
}
else if (strcmp(lpCmdLine, "-snes-max-alt-joy1") == 0)
{
g_cmdLine.snesMaxAltControllerType[0] = true;
}
else if (strcmp(lpCmdLine, "-snes-max-alt-joy2") == 0)
{
g_cmdLine.snesMaxAltControllerType[1] = true;
}
else // unsupported
{
LogFileOutput("Unsupported arg: %s\n", lpCmdLine);

View File

@ -18,6 +18,8 @@ struct CmdLine
bSlot7EmptyOnExit = false;
bSwapButtons0and1 = false;
bRemoveNoSlotClock = false;
snesMaxAltControllerType[0] = false;
snesMaxAltControllerType[1] = false;
szImageName_harddisk[HARDDISK_1] = NULL;
szImageName_harddisk[HARDDISK_2] = NULL;
szSnapshotName = NULL;
@ -53,6 +55,7 @@ struct CmdLine
bool bSlot7EmptyOnExit;
bool bSwapButtons0and1;
bool bRemoveNoSlotClock;
bool snesMaxAltControllerType[2];
SS_CARDTYPE slotInsert[NUM_SLOTS];
LPCSTR szImageName_drive[NUM_SLOTS][NUM_DRIVES];
bool driveConnected[NUM_SLOTS][NUM_DRIVES];

View File

@ -107,7 +107,7 @@ enum AppMode_e
#define REGVALUE_CUSTOM_SPEED "Custom Speed"
#define REGVALUE_EMULATION_SPEED "Emulation Speed"
#define REGVALUE_WINDOW_SCALE "Window Scale"
#define REGVALUE_UTHERNET_ACTIVE "Uthernet Active"
#define REGVALUE_UTHERNET_ACTIVE "Uthernet Active" // GH#977: Deprecated from 1.30.4
#define REGVALUE_UTHERNET_INTERFACE "Uthernet Interface"
#define REGVALUE_SLOT4 "Slot 4" // GH#977: Deprecated from 1.30.4
#define REGVALUE_SLOT5 "Slot 5" // GH#977: Deprecated from 1.30.4

View File

@ -25,7 +25,6 @@ public:
m_Slot[SLOT5] = GetCardMgr().QuerySlot(SLOT5);
m_Slot[SLOT7] = GetCardMgr().QuerySlot(SLOT7);
m_tfeEnabled = get_tfe_enabled();
m_tfeInterface = get_tfe_interface();
}
@ -35,7 +34,6 @@ public:
m_CpuType = other.m_CpuType;
memcpy(m_Slot, other.m_Slot, sizeof(m_Slot));
m_bEnableHDD = other.m_bEnableHDD;
m_tfeEnabled = other.m_tfeEnabled;
m_tfeInterface = other.m_tfeInterface;
m_bEnableTheFreezesF8Rom = other.m_bEnableTheFreezesF8Rom;
m_uSaveLoadStateMsg = other.m_uSaveLoadStateMsg;
@ -49,7 +47,6 @@ public:
m_CpuType == other.m_CpuType &&
memcmp(m_Slot, other.m_Slot, sizeof(m_Slot)) == 0 &&
m_bEnableHDD == other.m_bEnableHDD &&
m_tfeEnabled == other.m_tfeEnabled &&
m_tfeInterface == other.m_tfeInterface &&
m_bEnableTheFreezesF8Rom == other.m_bEnableTheFreezesF8Rom &&
m_uSaveLoadStateMsg == other.m_uSaveLoadStateMsg &&
@ -66,7 +63,6 @@ public:
SS_CARDTYPE m_Slot[NUM_SLOTS]; // 0..7
SS_CARDTYPE m_SlotAux;
bool m_bEnableHDD;
int m_tfeEnabled;
std::string m_tfeInterface;
UINT m_bEnableTheFreezesF8Rom;
UINT m_uSaveLoadStateMsg;

View File

@ -112,6 +112,7 @@ INT_PTR CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPA
case IDC_ETHERNET:
ui_tfe_settings_dialog(hWnd);
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = m_PageConfigTfe.m_tfe_enabled ? CT_Uthernet : CT_Empty;
break;
case IDC_MONOCOLOR:
@ -315,7 +316,6 @@ void CPageConfig::DlgOK(HWND hWnd)
m_PropertySheetHelper.GetConfigNew().m_videoRefreshRate = isNewVideoRate50Hz ? VR_50HZ : VR_60HZ;
}
m_PropertySheetHelper.GetConfigNew().m_tfeEnabled = m_PageConfigTfe.m_tfe_enabled;
m_PropertySheetHelper.GetConfigNew().m_tfeInterface = m_PageConfigTfe.m_tfe_interface_name;
if (bVideoReinit)
@ -376,8 +376,9 @@ void CPageConfig::DlgOK(HWND hWnd)
void CPageConfig::InitOptions(HWND hWnd)
{
// Nothing to do:
// - no changes made on any other pages affect this page
const SS_CARDTYPE slot3 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3];
const BOOL enableUthernetDialog = slot3 == CT_Empty || slot3 == CT_Uthernet;
EnableWindow(GetDlgItem(hWnd, IDC_ETHERNET), enableUthernetDialog);
}
// Config->Computer: Menu item to eApple2Type

View File

@ -144,10 +144,7 @@ int CPageConfigTfe::gray_ungray_items(HWND hwnd)
int enable;
int number;
//resources_get_value("ETHERNET_DISABLED", (void *)&disabled);
DWORD dwDisabled;
REGLOAD_DEFAULT(TEXT("Uthernet Disabled"), &dwDisabled, 0);
int disabled = dwDisabled ? 1 : 0;
int disabled = 0;
get_disabled_state(&disabled);
if (disabled)
@ -274,7 +271,7 @@ void CPageConfigTfe::save_tfe_dialog(HWND hwnd)
{
m_tfe_interface_name = buffer;
active_value = SendMessage(GetDlgItem(hwnd, IDC_TFE_SETTINGS_ENABLE), CB_GETCURSEL, 0, 0);
m_tfe_enabled = active_value >= 1 ? 1 : 0;
m_tfe_enabled = active_value > 0 ? 1 : 0;
}
else
{

View File

@ -63,6 +63,17 @@ const TCHAR CPageInput::m_szCPMSlotChoice_Slot5[] = TEXT("Slot 5\0");
const TCHAR CPageInput::m_szCPMSlotChoice_Unplugged[] = TEXT("Unplugged\0");
const TCHAR CPageInput::m_szCPMSlotChoice_Unavailable[] = TEXT("Unavailable\0");
const TCHAR CPageInput::m_szFourPlaySlotChoice_Slot3[] = TEXT("Slot 3\0");
const TCHAR CPageInput::m_szFourPlaySlotChoice_Slot4[] = TEXT("Slot 4\0");
const TCHAR CPageInput::m_szFourPlaySlotChoice_Slot5[] = TEXT("Slot 5\0");
const TCHAR CPageInput::m_szFourPlaySlotChoice_Unplugged[] = TEXT("Unplugged\0");
const TCHAR CPageInput::m_szFourPlaySlotChoice_Unavailable[] = TEXT("Unavailable\0");
const TCHAR CPageInput::m_szSNESMAXSlotChoice_Slot3[] = TEXT("Slot 3\0");
const TCHAR CPageInput::m_szSNESMAXSlotChoice_Slot4[] = TEXT("Slot 4\0");
const TCHAR CPageInput::m_szSNESMAXSlotChoice_Slot5[] = TEXT("Slot 5\0");
const TCHAR CPageInput::m_szSNESMAXSlotChoice_Unplugged[] = TEXT("Unplugged\0");
const TCHAR CPageInput::m_szSNESMAXSlotChoice_Unavailable[] = TEXT("Unavailable\0");
INT_PTR CALLBACK CPageInput::DlgProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
@ -124,20 +135,20 @@ INT_PTR CPageInput::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPAR
switch (LOWORD(wparam))
{
case IDC_JOYSTICK0:
if(HIWORD(wparam) == CBN_SELCHANGE)
if (HIWORD(wparam) == CBN_SELCHANGE)
{
DWORD dwNewJoyType = (DWORD)SendDlgItemMessage(hWnd, IDC_JOYSTICK0, CB_GETCURSEL, 0, 0);
const bool bIsSlot4Mouse = m_PropertySheetHelper.GetConfigNew().m_Slot[4] == CT_MouseInterface;
const bool bIsSlot4Mouse = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] == CT_MouseInterface;
JoySetEmulationType(hWnd, m_nJoy0ChoiceTranlationTbl[dwNewJoyType], JN_JOYSTICK0, bIsSlot4Mouse);
InitOptions(hWnd);
}
break;
case IDC_JOYSTICK1:
if(HIWORD(wparam) == CBN_SELCHANGE)
if (HIWORD(wparam) == CBN_SELCHANGE)
{
DWORD dwNewJoyType = (DWORD)SendDlgItemMessage(hWnd, IDC_JOYSTICK1, CB_GETCURSEL, 0, 0);
const bool bIsSlot4Mouse = m_PropertySheetHelper.GetConfigNew().m_Slot[4] == CT_MouseInterface;
const bool bIsSlot4Mouse = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] == CT_MouseInterface;
JoySetEmulationType(hWnd, m_nJoy1ChoiceTranlationTbl[dwNewJoyType], JN_JOYSTICK1, bIsSlot4Mouse);
InitOptions(hWnd);
}
@ -150,14 +161,14 @@ INT_PTR CPageInput::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPAR
case IDC_MOUSE_IN_SLOT4:
{
const UINT uNewState = IsDlgButtonChecked(hWnd, IDC_MOUSE_IN_SLOT4) ? 1 : 0;
m_PropertySheetHelper.GetConfigNew().m_Slot[4] = uNewState ? CT_MouseInterface : CT_Empty;
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] = uNewState ? CT_MouseInterface : CT_Empty;
InitOptions(hWnd); // re-init
}
break;
case IDC_CPM_CONFIG:
if(HIWORD(wparam) == CBN_SELCHANGE)
if (HIWORD(wparam) == CBN_SELCHANGE)
{
const DWORD NewCPMChoiceItem = (DWORD) SendDlgItemMessage(hWnd, IDC_CPM_CONFIG, CB_GETCURSEL, 0, 0);
const CPMCHOICE NewCPMChoice = m_CPMComboItemToChoice[NewCPMChoiceItem];
@ -165,18 +176,80 @@ INT_PTR CPageInput::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPAR
break;
// Whatever has changed, the old slot will now be empty
const SS_CARDTYPE Slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[4];
const SS_CARDTYPE Slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[5];
if (Slot4 == CT_Z80)
m_PropertySheetHelper.GetConfigNew().m_Slot[4] = CT_Empty;
else if (Slot5 == CT_Z80)
m_PropertySheetHelper.GetConfigNew().m_Slot[5] = CT_Empty;
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4];
const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5];
if (slot4 == CT_Z80)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] = CT_Empty;
else if (slot5 == CT_Z80)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5] = CT_Empty;
// Insert CP/M card into new slot (or leave slot empty)
if (NewCPMChoice == CPM_SLOT4)
m_PropertySheetHelper.GetConfigNew().m_Slot[4] = CT_Z80;
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] = CT_Z80;
else if (NewCPMChoice == CPM_SLOT5)
m_PropertySheetHelper.GetConfigNew().m_Slot[5] = CT_Z80;
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5] = CT_Z80;
InitOptions(hWnd); // re-init
}
break;
case IDC_FOURPLAY_CONFIG:
if (HIWORD(wparam) == CBN_SELCHANGE)
{
const DWORD NewFourPlayChoiceItem = (DWORD) SendDlgItemMessage(hWnd, IDC_FOURPLAY_CONFIG, CB_GETCURSEL, 0, 0);
const FOURPLAYCHOICE NewFourPlayChoice = m_FourPlayComboItemToChoice[NewFourPlayChoiceItem];
if (NewFourPlayChoice == m_FourPlayChoice)
break;
// Whatever has changed, the old slot will now be empty
const SS_CARDTYPE slot3 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3];
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4];
const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5];
if (slot3 == CT_FourPlay)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = CT_Empty;
else if (slot4 == CT_FourPlay)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] = CT_Empty;
else if (slot5 == CT_FourPlay)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5] = CT_Empty;
// Insert 4Play card into new slot (or leave slot empty)
if (NewFourPlayChoice == FOURPLAY_SLOT3)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = CT_FourPlay;
else if (NewFourPlayChoice == FOURPLAY_SLOT4)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] = CT_FourPlay;
else if (NewFourPlayChoice == FOURPLAY_SLOT5)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5] = CT_FourPlay;
InitOptions(hWnd); // re-init
}
break;
case IDC_SNESMAX_CONFIG:
if (HIWORD(wparam) == CBN_SELCHANGE)
{
const DWORD NewSNESMAXChoiceItem = (DWORD) SendDlgItemMessage(hWnd, IDC_SNESMAX_CONFIG, CB_GETCURSEL, 0, 0);
const SNESMAXCHOICE NewSNESMAXChoice = m_SNESMAXComboItemToChoice[NewSNESMAXChoiceItem];
if (NewSNESMAXChoice == m_SNESMAXChoice)
break;
// Whatever has changed, the old slot will now be empty
const SS_CARDTYPE slot3 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3];
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4];
const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5];
if (slot3 == CT_SNESMAX)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = CT_Empty;
else if (slot4 == CT_SNESMAX)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] = CT_Empty;
else if (slot5 == CT_SNESMAX)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5] = CT_Empty;
// Insert SNES MAX card into new slot (or leave slot empty)
if (NewSNESMAXChoice == SNESMAX_SLOT3)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = CT_SNESMAX;
else if (NewSNESMAXChoice == SNESMAX_SLOT4)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4] = CT_SNESMAX;
else if (NewSNESMAXChoice == SNESMAX_SLOT5)
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5] = CT_SNESMAX;
InitOptions(hWnd); // re-init
}
@ -268,7 +341,7 @@ void CPageInput::InitJoystickChoices(HWND hWnd, int nJoyNum, int nIdcValue)
TCHAR** ppszJoyChoices;
int nOtherJoyNum = nJoyNum == JN_JOYSTICK0 ? JN_JOYSTICK1 : JN_JOYSTICK0;
if(nJoyNum == JN_JOYSTICK0)
if (nJoyNum == JN_JOYSTICK0)
{
pnzJoystickChoices = m_joystick0choices;
pnJoyTranslationTbl = m_nJoy0ChoiceTranlationTbl;
@ -347,19 +420,21 @@ void CPageInput::InitJoystickChoices(HWND hWnd, int nJoyNum, int nIdcValue)
void CPageInput::InitSlotOptions(HWND hWnd)
{
const SS_CARDTYPE Slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[4];
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4];
const bool bIsSlot4Mouse = Slot4 == CT_MouseInterface;
const bool bIsSlot4Mouse = slot4 == CT_MouseInterface;
CheckDlgButton(hWnd, IDC_MOUSE_IN_SLOT4, bIsSlot4Mouse ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hWnd, IDC_MOUSE_CROSSHAIR, m_uMouseShowCrosshair ? BST_CHECKED : BST_UNCHECKED);
CheckDlgButton(hWnd, IDC_MOUSE_RESTRICT_TO_WINDOW, m_uMouseRestrictToWindow ? BST_CHECKED : BST_UNCHECKED);
const bool bIsSlot4Empty = Slot4 == CT_Empty;
const bool bIsSlot4Empty = slot4 == CT_Empty;
EnableWindow(GetDlgItem(hWnd, IDC_MOUSE_IN_SLOT4), ((bIsSlot4Mouse || bIsSlot4Empty) && !JoyUsingMouse()) ? TRUE : FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_MOUSE_CROSSHAIR), bIsSlot4Mouse ? TRUE : FALSE);
EnableWindow(GetDlgItem(hWnd, IDC_MOUSE_RESTRICT_TO_WINDOW), bIsSlot4Mouse ? TRUE : FALSE);
InitCPMChoices(hWnd);
InitFourPlayChoices(hWnd);
InitSNESMAXChoices(hWnd);
InitJoystickChoices(hWnd, JN_JOYSTICK0, IDC_JOYSTICK0);
InitJoystickChoices(hWnd, JN_JOYSTICK1, IDC_JOYSTICK1);
@ -370,11 +445,11 @@ void CPageInput::InitSlotOptions(HWND hWnd)
void CPageInput::InitCPMChoices(HWND hWnd)
{
const SS_CARDTYPE Slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[4];
const SS_CARDTYPE Slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[5];
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4];
const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5];
if (Slot4 == CT_Z80) m_CPMChoice = CPM_SLOT4;
else if (Slot5 == CT_Z80) m_CPMChoice = CPM_SLOT5;
if (slot4 == CT_Z80) m_CPMChoice = CPM_SLOT4;
else if (slot5 == CT_Z80) m_CPMChoice = CPM_SLOT5;
else m_CPMChoice = CPM_UNPLUGGED;
for (UINT i=0; i<_CPM_MAX_CHOICES; i++)
@ -383,10 +458,10 @@ void CPageInput::InitCPMChoices(HWND hWnd)
UINT uStringOffset = 0;
UINT uComboItemIdx = 0;
const bool bIsSlot4Empty = Slot4 == CT_Empty;
const bool bIsSlot4CPM = Slot4 == CT_Z80;
const bool bIsSlot5Empty = Slot5 == CT_Empty;
const bool bIsSlot5CPM = Slot5 == CT_Z80;
const bool bIsSlot4Empty = slot4 == CT_Empty;
const bool bIsSlot4CPM = slot4 == CT_Z80;
const bool bIsSlot5Empty = slot5 == CT_Empty;
const bool bIsSlot5CPM = slot5 == CT_Z80;
if (bIsSlot4Empty || bIsSlot4CPM)
{
@ -440,3 +515,175 @@ void CPageInput::InitCPMChoices(HWND hWnd)
m_PropertySheetHelper.FillComboBox(hWnd, IDC_CPM_CONFIG, m_szCPMSlotChoices, uCurrentChoice);
}
void CPageInput::InitFourPlayChoices(HWND hWnd)
{
const SS_CARDTYPE slot3 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3];
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4];
const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5];
if (slot3 == CT_FourPlay) m_FourPlayChoice = FOURPLAY_SLOT3;
else if (slot4 == CT_FourPlay) m_FourPlayChoice = FOURPLAY_SLOT4;
else if (slot5 == CT_FourPlay) m_FourPlayChoice = FOURPLAY_SLOT5;
else m_FourPlayChoice = FOURPLAY_UNPLUGGED;
for (UINT i=0; i<_FOURPLAY_MAX_CHOICES; i++)
m_FourPlayComboItemToChoice[i] = FOURPLAY_UNAVAILABLE;
UINT uStringOffset = 0;
UINT uComboItemIdx = 0;
const bool bIsSlot3Empty = slot3 == CT_Empty;
const bool bIsSlot3FourPlay = slot3 == CT_FourPlay;
const bool bIsSlot4Empty = slot4 == CT_Empty;
const bool bIsSlot4FourPlay = slot4 == CT_FourPlay;
const bool bIsSlot5Empty = slot5 == CT_Empty;
const bool bIsSlot5FourPlay = slot5 == CT_FourPlay;
if (bIsSlot3Empty || bIsSlot3FourPlay)
{
const UINT uStrLen = strlen(m_szFourPlaySlotChoice_Slot3) + 1;
memcpy(&m_szFourPlaySlotChoices[uStringOffset], m_szFourPlaySlotChoice_Slot3, uStrLen);
uStringOffset += uStrLen;
m_FourPlayComboItemToChoice[uComboItemIdx++] = FOURPLAY_SLOT3;
}
if (bIsSlot4Empty || bIsSlot4FourPlay)
{
const UINT uStrLen = strlen(m_szFourPlaySlotChoice_Slot4)+1;
memcpy(&m_szFourPlaySlotChoices[uStringOffset], m_szFourPlaySlotChoice_Slot4, uStrLen);
uStringOffset += uStrLen;
m_FourPlayComboItemToChoice[uComboItemIdx++] = FOURPLAY_SLOT4;
}
if (bIsSlot5Empty || bIsSlot5FourPlay)
{
const UINT uStrLen = strlen(m_szFourPlaySlotChoice_Slot5)+1;
memcpy(&m_szFourPlaySlotChoices[uStringOffset], m_szFourPlaySlotChoice_Slot5, uStrLen);
uStringOffset += uStrLen;
m_FourPlayComboItemToChoice[uComboItemIdx++] = FOURPLAY_SLOT5;
}
if (uStringOffset)
{
const UINT uStrLen = strlen(m_szFourPlaySlotChoice_Unplugged)+1;
memcpy(&m_szFourPlaySlotChoices[uStringOffset], m_szFourPlaySlotChoice_Unplugged, uStrLen);
uStringOffset += uStrLen;
m_FourPlayComboItemToChoice[uComboItemIdx] = FOURPLAY_UNPLUGGED;
}
else
{
const UINT uStrLen = strlen(m_szFourPlaySlotChoice_Unavailable)+1;
memcpy(&m_szFourPlaySlotChoices[uStringOffset], m_szFourPlaySlotChoice_Unavailable, uStrLen);
uStringOffset += uStrLen;
m_FourPlayChoice = FOURPLAY_UNAVAILABLE; // Force this
m_FourPlayComboItemToChoice[uComboItemIdx] = FOURPLAY_UNAVAILABLE;
}
m_szFourPlaySlotChoices[uStringOffset] = 0; // Doubly null terminated
//
UINT uCurrentChoice = uComboItemIdx; // Default to last item (either UNPLUGGED or UNAVAILABLE)
for (UINT i=0; i<=uComboItemIdx; i++)
{
if (m_FourPlayComboItemToChoice[i] == m_FourPlayChoice)
{
uCurrentChoice = i;
break;
}
}
m_PropertySheetHelper.FillComboBox(hWnd, IDC_FOURPLAY_CONFIG, m_szFourPlaySlotChoices, uCurrentChoice);
}
void CPageInput::InitSNESMAXChoices(HWND hWnd)
{
const SS_CARDTYPE slot3 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3];
const SS_CARDTYPE slot4 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT4];
const SS_CARDTYPE slot5 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT5];
if (slot3 == CT_SNESMAX) m_SNESMAXChoice = SNESMAX_SLOT3;
else if (slot4 == CT_SNESMAX) m_SNESMAXChoice = SNESMAX_SLOT4;
else if (slot5 == CT_SNESMAX) m_SNESMAXChoice = SNESMAX_SLOT5;
else m_SNESMAXChoice = SNESMAX_UNPLUGGED;
for (UINT i=0; i<_SNESMAX_MAX_CHOICES; i++)
m_SNESMAXComboItemToChoice[i] = SNESMAX_UNAVAILABLE;
UINT uStringOffset = 0;
UINT uComboItemIdx = 0;
const bool bIsSlot3Empty = slot3 == CT_Empty;
const bool bIsSlot3SNESMAX = slot3 == CT_SNESMAX;
const bool bIsSlot4Empty = slot4 == CT_Empty;
const bool bIsSlot4SNESMAX = slot4 == CT_SNESMAX;
const bool bIsSlot5Empty = slot5 == CT_Empty;
const bool bIsSlot5SNESMAX = slot5 == CT_SNESMAX;
if (bIsSlot3Empty || bIsSlot3SNESMAX)
{
const UINT uStrLen = strlen(m_szSNESMAXSlotChoice_Slot3) + 1;
memcpy(&m_szSNESMAXSlotChoices[uStringOffset], m_szSNESMAXSlotChoice_Slot3, uStrLen);
uStringOffset += uStrLen;
m_SNESMAXComboItemToChoice[uComboItemIdx++] = SNESMAX_SLOT3;
}
if (bIsSlot4Empty || bIsSlot4SNESMAX)
{
const UINT uStrLen = strlen(m_szSNESMAXSlotChoice_Slot4)+1;
memcpy(&m_szSNESMAXSlotChoices[uStringOffset], m_szSNESMAXSlotChoice_Slot4, uStrLen);
uStringOffset += uStrLen;
m_SNESMAXComboItemToChoice[uComboItemIdx++] = SNESMAX_SLOT4;
}
if (bIsSlot5Empty || bIsSlot5SNESMAX)
{
const UINT uStrLen = strlen(m_szSNESMAXSlotChoice_Slot5)+1;
memcpy(&m_szSNESMAXSlotChoices[uStringOffset], m_szSNESMAXSlotChoice_Slot5, uStrLen);
uStringOffset += uStrLen;
m_SNESMAXComboItemToChoice[uComboItemIdx++] = SNESMAX_SLOT5;
}
if (uStringOffset)
{
const UINT uStrLen = strlen(m_szSNESMAXSlotChoice_Unplugged)+1;
memcpy(&m_szSNESMAXSlotChoices[uStringOffset], m_szSNESMAXSlotChoice_Unplugged, uStrLen);
uStringOffset += uStrLen;
m_SNESMAXComboItemToChoice[uComboItemIdx] = SNESMAX_UNPLUGGED;
}
else
{
const UINT uStrLen = strlen(m_szSNESMAXSlotChoice_Unavailable)+1;
memcpy(&m_szSNESMAXSlotChoices[uStringOffset], m_szSNESMAXSlotChoice_Unavailable, uStrLen);
uStringOffset += uStrLen;
m_SNESMAXChoice = SNESMAX_UNAVAILABLE; // Force this
m_SNESMAXComboItemToChoice[uComboItemIdx] = SNESMAX_UNAVAILABLE;
}
m_szSNESMAXSlotChoices[uStringOffset] = 0; // Doubly null terminated
//
UINT uCurrentChoice = uComboItemIdx; // Default to last item (either UNPLUGGED or UNAVAILABLE)
for (UINT i=0; i<=uComboItemIdx; i++)
{
if (m_SNESMAXComboItemToChoice[i] == m_SNESMAXChoice)
{
uCurrentChoice = i;
break;
}
}
m_PropertySheetHelper.FillComboBox(hWnd, IDC_SNESMAX_CONFIG, m_szSNESMAXSlotChoices, uCurrentChoice);
}

View File

@ -19,7 +19,9 @@ public:
m_bSwapButtons0and1(false),
m_uMouseShowCrosshair(0),
m_uMouseRestrictToWindow(0),
m_CPMChoice(CPM_UNPLUGGED)
m_CPMChoice(CPM_UNPLUGGED),
m_FourPlayChoice(FOURPLAY_UNPLUGGED),
m_SNESMAXChoice(SNESMAX_UNPLUGGED)
{
CPageInput::ms_this = this;
}
@ -53,6 +55,8 @@ private:
void InitJoystickChoices(HWND hWnd, int nJoyNum, int nIdcValue);
void InitSlotOptions(HWND hWnd);
void InitCPMChoices(HWND hWnd);
void InitFourPlayChoices(HWND hWnd);
void InitSNESMAXChoices(HWND hWnd);
static CPageInput* ms_this;
static const UINT MaxMenuChoiceLen = 40;
@ -72,6 +76,18 @@ private:
static const TCHAR m_szCPMSlotChoice_Unplugged[];
static const TCHAR m_szCPMSlotChoice_Unavailable[];
static const TCHAR m_szFourPlaySlotChoice_Slot3[];
static const TCHAR m_szFourPlaySlotChoice_Slot4[];
static const TCHAR m_szFourPlaySlotChoice_Slot5[];
static const TCHAR m_szFourPlaySlotChoice_Unplugged[];
static const TCHAR m_szFourPlaySlotChoice_Unavailable[];
static const TCHAR m_szSNESMAXSlotChoice_Slot3[];
static const TCHAR m_szSNESMAXSlotChoice_Slot4[];
static const TCHAR m_szSNESMAXSlotChoice_Slot5[];
static const TCHAR m_szSNESMAXSlotChoice_Unplugged[];
static const TCHAR m_szSNESMAXSlotChoice_Unavailable[];
int m_nJoy0ChoiceTranlationTbl[J0C_MAX];
TCHAR m_joystick0choices[J0C_MAX * MaxMenuChoiceLen];
int m_nJoy1ChoiceTranlationTbl[J1C_MAX];
@ -92,4 +108,14 @@ private:
TCHAR m_szCPMSlotChoices[_CPM_MAX_CHOICES * MaxMenuChoiceLen];
CPMCHOICE m_CPMChoice;
CPMCHOICE m_CPMComboItemToChoice[_CPM_MAX_CHOICES];
enum FOURPLAYCHOICE {FOURPLAY_SLOT3=0, FOURPLAY_SLOT4, FOURPLAY_SLOT5, FOURPLAY_UNPLUGGED, FOURPLAY_UNAVAILABLE, _FOURPLAY_MAX_CHOICES};
TCHAR m_szFourPlaySlotChoices[_FOURPLAY_MAX_CHOICES * MaxMenuChoiceLen];
FOURPLAYCHOICE m_FourPlayChoice;
FOURPLAYCHOICE m_FourPlayComboItemToChoice[_FOURPLAY_MAX_CHOICES];
enum SNESMAXCHOICE {SNESMAX_SLOT3=0, SNESMAX_SLOT4, SNESMAX_SLOT5, SNESMAX_UNPLUGGED, SNESMAX_UNAVAILABLE, _SNESMAX_MAX_CHOICES};
TCHAR m_szSNESMAXSlotChoices[_SNESMAX_MAX_CHOICES * MaxMenuChoiceLen];
SNESMAXCHOICE m_SNESMAXChoice;
SNESMAXCHOICE m_SNESMAXComboItemToChoice[_SNESMAX_MAX_CHOICES];
};

View File

@ -336,21 +336,33 @@ void CPropertySheetHelper::ApplyNewConfig(const CConfigNeedingRestart& ConfigNew
SaveCpuType(ConfigNew.m_CpuType);
}
UINT slot = 4;
UINT slot = SLOT3;
if (CONFIG_CHANGED_LOCAL(m_Slot[slot]))
{
SetSlot(slot, ConfigNew.m_Slot[slot]);
if (ConfigNew.m_Slot[slot] == CT_Uthernet) // TODO: move this to UthernetCard object
{
std::string& regSection = RegGetConfigSlotSection(slot);
RegSaveString(regSection.c_str(), REGVALUE_UTHERNET_INTERFACE, 1, ConfigNew.m_tfeInterface);
}
}
slot = SLOT4;
if (CONFIG_CHANGED_LOCAL(m_Slot[slot]))
SetSlot(slot, ConfigNew.m_Slot[slot]);
slot = 5;
slot = SLOT5;
if (CONFIG_CHANGED_LOCAL(m_Slot[slot]))
SetSlot(slot, ConfigNew.m_Slot[slot]);
// slot = 7;
// slot = SLOT7;
// if (CONFIG_CHANGED_LOCAL(m_Slot[slot]))
// SetSlot(slot, ConfigNew.m_Slot[slot]);
if (CONFIG_CHANGED_LOCAL(m_bEnableHDD))
{
REGSAVE(TEXT(REGVALUE_HDD_ENABLED), ConfigNew.m_bEnableHDD ? 1 : 0); // TODO: Change to REGVALUE_SLOT7
REGSAVE(TEXT(REGVALUE_HDD_ENABLED), ConfigNew.m_bEnableHDD ? 1 : 0);
}
if (CONFIG_CHANGED_LOCAL(m_bEnableTheFreezesF8Rom))
@ -362,17 +374,6 @@ void CPropertySheetHelper::ApplyNewConfig(const CConfigNeedingRestart& ConfigNew
{
REGSAVE(TEXT(REGVALUE_VIDEO_REFRESH_RATE), ConfigNew.m_videoRefreshRate);
}
if (CONFIG_CHANGED_LOCAL(m_tfeEnabled))
{
REGSAVE(TEXT(REGVALUE_UTHERNET_ACTIVE), ConfigNew.m_tfeEnabled);
}
if (CONFIG_CHANGED_LOCAL(m_tfeInterface))
{
RegSaveString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, ConfigNew.m_tfeInterface);
}
}
void CPropertySheetHelper::ApplyNewConfig(void)
@ -385,13 +386,13 @@ void CPropertySheetHelper::SaveCurrentConfig(void)
// NB. clone-type is encoded in g_Apple2Type
m_ConfigOld.m_Apple2Type = GetApple2Type();
m_ConfigOld.m_CpuType = GetMainCpu();
m_ConfigOld.m_Slot[SLOT3] = GetCardMgr().QuerySlot(SLOT3);
m_ConfigOld.m_Slot[SLOT4] = GetCardMgr().QuerySlot(SLOT4);
m_ConfigOld.m_Slot[SLOT5] = GetCardMgr().QuerySlot(SLOT5);
m_ConfigOld.m_Slot[SLOT6] = GetCardMgr().QuerySlot(SLOT6); // CPageDisk::HandleFloppyDriveCombo() needs this to be CT_Disk2 (temp, as will replace with PR #955)
m_ConfigOld.m_bEnableHDD = HD_CardIsEnabled();
m_ConfigOld.m_bEnableTheFreezesF8Rom = GetPropertySheet().GetTheFreezesF8Rom();
m_ConfigOld.m_videoRefreshRate = GetVideo().GetVideoRefreshRate();
m_ConfigOld.m_tfeEnabled = get_tfe_enabled();
m_ConfigOld.m_tfeInterface = get_tfe_interface();
// Reset flags each time:
@ -407,6 +408,7 @@ void CPropertySheetHelper::RestoreCurrentConfig(void)
// NB. clone-type is encoded in g_Apple2Type
SetApple2Type(m_ConfigOld.m_Apple2Type);
SetMainCpu(m_ConfigOld.m_CpuType);
SetSlot(SLOT3, m_ConfigOld.m_Slot[SLOT3]);
SetSlot(SLOT4, m_ConfigOld.m_Slot[SLOT4]);
SetSlot(SLOT5, m_ConfigOld.m_Slot[SLOT5]);
HD_SetEnabled(m_ConfigOld.m_bEnableHDD);
@ -465,20 +467,20 @@ bool CPropertySheetHelper::HardwareConfigChanged(HWND hWnd)
if (CONFIG_CHANGED(m_videoRefreshRate))
strMsgMain += ". Video refresh rate has changed\n";
if (CONFIG_CHANGED(m_Slot[4]))
strMsgMain += GetSlot(4);
if (CONFIG_CHANGED(m_Slot[SLOT3]))
strMsgMain += GetSlot(SLOT3);
if (CONFIG_CHANGED(m_Slot[5]))
strMsgMain += GetSlot(5);
if (CONFIG_CHANGED(m_Slot[SLOT4]))
strMsgMain += GetSlot(SLOT4);
if (CONFIG_CHANGED(m_Slot[SLOT5]))
strMsgMain += GetSlot(SLOT5);
if (CONFIG_CHANGED(m_bEnableHDD))
strMsgMain += ". Harddisk(s) have been plugged/unplugged\n";
if (CONFIG_CHANGED(m_bEnableTheFreezesF8Rom))
strMsgMain += ". F8 ROM changed (The Freeze's F8 Rom)\n";
if (CONFIG_CHANGED(m_tfeEnabled) || CONFIG_CHANGED(m_tfeInterface))
strMsgMain += ". Ethernet (TFE) Options\n";
}
std::string strMsgPost("\n");
@ -559,6 +561,12 @@ std::string CPropertySheetHelper::GetCardName(const SS_CARDTYPE CardType)
return "Echo";
case CT_SAM: // Soundcard: Software Automated Mouth
return "SAM";
case CT_Uthernet:
return "Uthernet";
case CT_FourPlay:
return "4Play";
case CT_SNESMAX:
return "SNES MAX";
default:
return "Unknown";
}

155
source/FourPlay.cpp Normal file
View File

@ -0,0 +1,155 @@
/*
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 = Trigger 2, Active High
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 "Memory.h"
#include "YamlHelper.h"
BYTE __stdcall FourPlayCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
BYTE nOutput = MemReadFloatingBus(nExecutedCycles);
BOOL up = 0;
BOOL down = 0;
BOOL left = 0;
BOOL right = 0;
BOOL trigger1 = 0;
BOOL trigger2 = 0;
BOOL trigger3 = 0;
BOOL alwaysHigh = 1;
UINT xAxis = 0;
UINT yAxis = 0;
JOYINFOEX infoEx;
MMRESULT result = 0;
infoEx.dwSize = sizeof(infoEx);
infoEx.dwFlags = JOY_RETURNPOV | JOY_RETURNBUTTONS;
switch (addr & 0xF)
{
case 0: // Joystick 1
result = joyGetPosEx(JOYSTICKID1, &infoEx);
if (result == JOYERR_NOERROR)
{
xAxis = (infoEx.dwXpos >> 8) & 0xFF;
yAxis = (infoEx.dwYpos >> 8) & 0xFF;
trigger1 = infoEx.dwButtons & 0x01;
trigger2 = (infoEx.dwButtons & 0x02) >> 1;
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);
}
nOutput = up | (down << 1) | (left << 2) | (right << 3) | (alwaysHigh << 5) | (trigger2 << 6) | (trigger1 << 7);
break;
case 1: // Joystick 2
result = joyGetPosEx(JOYSTICKID2, &infoEx);
if (result == JOYERR_NOERROR)
{
xAxis = (infoEx.dwXpos >> 8) & 0xFF;
yAxis = (infoEx.dwYpos >> 8) & 0xFF;
trigger1 = infoEx.dwButtons & 0x01;
trigger2 = (infoEx.dwButtons & 0x02) >> 1;
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);
}
nOutput = up | (down << 1) | (left << 2) | (right << 3) | (alwaysHigh << 5) | (trigger2 << 6) | (trigger1 << 7);
break;
case 2: // Joystick 3
nOutput = FourPlayCard::JOYSTICKSTATIONARY; // esdf - direction buttons, zx - trigger buttons
nOutput = nOutput | (MyGetAsyncKeyState('E') | (MyGetAsyncKeyState('D') << 1) | (MyGetAsyncKeyState('S') << 2) | (MyGetAsyncKeyState('F') << 3) | (MyGetAsyncKeyState('X') << 6) | (MyGetAsyncKeyState('Z') << 7));
break;
case 3: // Joystick 4
nOutput = FourPlayCard::JOYSTICKSTATIONARY; // ijkl - direction buttons, nm - trigger buttons
nOutput = nOutput | (MyGetAsyncKeyState('I') | (MyGetAsyncKeyState('K') << 1) | (MyGetAsyncKeyState('J') << 2) | (MyGetAsyncKeyState('L') << 3) | (MyGetAsyncKeyState('M') << 6) | (MyGetAsyncKeyState('N') << 7));
break;
default:
break;
}
return nOutput;
}
BYTE FourPlayCard::MyGetAsyncKeyState(int vKey)
{
return GetAsyncKeyState(vKey) < 0 ? 1 : 0;
}
void FourPlayCard::InitializeIO(LPBYTE pCxRomPeripheral, UINT slot)
{
RegisterIoHandler(slot, &FourPlayCard::IORead, IO_Null, IO_Null, IO_Null, this, NULL);
}
//===========================================================================
static const UINT kUNIT_VERSION = 1;
std::string FourPlayCard::GetSnapshotCardName(void)
{
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 slot, UINT version)
{
if (version < 1 || version > kUNIT_VERSION)
throw std::string("Card: wrong version");
return true;
}

32
source/FourPlay.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "Card.h"
class FourPlayCard : public Card
{
public:
FourPlayCard(UINT slot) :
Card(CT_FourPlay),
m_slot(slot)
{
}
virtual ~FourPlayCard(void) {}
virtual void Init(void) {};
virtual void Reset(const bool powerCycle) {};
void InitializeIO(LPBYTE pCxRomPeripheral, UINT slot);
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
static std::string GetSnapshotCardName(void);
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);
static const UINT JOYSTICKSTATIONARY = 0x20;
private:
static BYTE MyGetAsyncKeyState(int vKey);
UINT m_slot;
};

View File

@ -49,6 +49,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "ParallelPrinter.h"
#include "Registry.h"
#include "SAM.h"
#include "FourPlay.h"
#include "SNESMAX.h"
#include "SerialComms.h"
#include "Speaker.h"
#include "Tape.h"
@ -1727,6 +1729,14 @@ void MemInitializeIO(void)
// . Uthernet card has no ROM and only IO mapped at $C0Bx
// NB. I/O handlers setup via tfe_init() & update_tfe_interface()
}
else if (GetCardMgr().QuerySlot(SLOT3) == CT_FourPlay)
{
dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(SLOT3)).InitializeIO(pCxRomPeripheral, SLOT3);
}
else if (GetCardMgr().QuerySlot(SLOT3) == CT_SNESMAX)
{
dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(SLOT3)).InitializeIO(pCxRomPeripheral, SLOT3);
}
// Apple//e: Auxiliary slot contains Extended 80 Column card or RamWorksIII card
@ -1746,6 +1756,14 @@ void MemInitializeIO(void)
// {
// LoadRom_Clock_Generic(pCxRomPeripheral, SLOT4);
// }
else if (GetCardMgr().QuerySlot(SLOT4) == CT_FourPlay)
{
dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(SLOT4)).InitializeIO(pCxRomPeripheral, SLOT4);
}
else if (GetCardMgr().QuerySlot(SLOT4) == CT_SNESMAX)
{
dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(SLOT4)).InitializeIO(pCxRomPeripheral, SLOT4);
}
if (GetCardMgr().QuerySlot(SLOT5) == CT_Z80)
{
@ -1753,7 +1771,15 @@ void MemInitializeIO(void)
}
else if (GetCardMgr().QuerySlot(SLOT5) == CT_SAM)
{
ConfigureSAM(pCxRomPeripheral, SLOT5); // $C500 : Z80 card
ConfigureSAM(pCxRomPeripheral, SLOT5); // $C500 : SAM card
}
else if (GetCardMgr().QuerySlot(SLOT5) == CT_FourPlay)
{
dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(SLOT5)).InitializeIO(pCxRomPeripheral, SLOT5);
}
else if (GetCardMgr().QuerySlot(SLOT5) == CT_SNESMAX)
{
dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(SLOT5)).InitializeIO(pCxRomPeripheral, SLOT5);
}
else if (GetCardMgr().QuerySlot(SLOT5) == CT_Disk2)
{

View File

@ -195,7 +195,8 @@ void RegDeleteConfigSlotSection(UINT slot)
if (status == ERROR_SUCCESS)
{
std::string& keySlot = RegGetSlotSection(slot);
if (RegDeleteKey(keyhandle, keySlot.c_str()) != ERROR_SUCCESS)
LSTATUS status2 = RegDeleteKey(keyhandle, keySlot.c_str());
if (status2 != ERROR_SUCCESS && status2 != ERROR_FILE_NOT_FOUND)
_ASSERT(0);
}

238
source/SNESMAX.cpp Normal file
View File

@ -0,0 +1,238 @@
/*
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
*/
/*
SNESMAX.CPP
Emulate a SNES MAX controller serial interface card
2 ports (one for each of the two possible joysticks)
Latch = write any data to C0n0
Clock = write any data to C0n1
Data = read from C0n0
n = 8 + slot number
Data
Bit 0 = Not Used
Bit 1 = Not Used
Bit 2 = Not Used
Bit 3 = Not Used
Bit 4 = Not Used
Bit 5 = Not Used
Bit 6 = Controller 2, Active Low
Bit 7 = Controller 1, Active Low
Once data is read, button presses (for each controller) should be stored in the following structure
Byte 0: B:Y:Sl:St:U:D:L:R
Byte 1: A:X:Fl:Fr:x:x:x:x
The variable controllerXButtons will stored in the reverse order.
Alex Lukacz Aug 2021
*/
#include "StdAfx.h"
#include "SNESMAX.h"
#include "Memory.h"
#include "YamlHelper.h"
BYTE __stdcall SNESMAXCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
const UINT slot = ((addr & 0xff) >> 4) - 8;
SNESMAXCard* pCard = (SNESMAXCard*)MemGetSlotParameters(slot);
BYTE output = MemReadFloatingBus(nExecutedCycles);
switch (addr & 0xF)
{
case 0:
output = (output & 0x3F) | ((pCard->controller2Buttons & 0x1) << 6) | ((pCard->controller1Buttons & 0x1) << 7);
break;
default:
break;
}
return output;
}
BYTE __stdcall SNESMAXCard::IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
const UINT slot = ((addr & 0xff) >> 4) - 8;
SNESMAXCard* pCard = (SNESMAXCard*)MemGetSlotParameters(slot);
UINT xAxis = 0;
UINT yAxis = 0;
JOYINFOEX infoEx;
MMRESULT result = 0;
infoEx.dwSize = sizeof(infoEx);
infoEx.dwFlags = JOY_RETURNPOV | JOY_RETURNBUTTONS;
UINT& controller1Buttons = pCard->controller1Buttons; // ref to object's controller1Buttons
UINT& controller2Buttons = pCard->controller2Buttons; // ref to object's controller2Buttons
switch (addr & 0xF)
{
case 0: // Latch
pCard->buttonIndex = 0;
controller1Buttons = 0;
controller2Buttons = 0;
result = joyGetPosEx(JOYSTICKID1, &infoEx);
if (result == JOYERR_NOERROR)
{
xAxis = (infoEx.dwXpos >> 8) & 0xFF;
yAxis = (infoEx.dwYpos >> 8) & 0xFF;
controller1Buttons = controller1Buttons | ((yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500) << 4); // U Button
controller1Buttons = controller1Buttons | ((yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500)) << 5); // D Button
controller1Buttons = controller1Buttons | ((xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500)) << 6); // L Button
controller1Buttons = controller1Buttons | ((xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500)) << 7); // R Button
// controller1Buttons = controller1Buttons | 0 * 0x1000; // spare Button
// controller1Buttons = controller1Buttons | 0 * 0x2000; // spare Button
// controller1Buttons = controller1Buttons | 0 * 0x4000; // spare Button
// controller1Buttons = controller1Buttons | 0 * 0x8000; // spare Button
if (pCard->m_altControllerType[0])
{
// 8BitDo NES30 PRO
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0010) >> 3); // Y Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0400) >> 8); // Sl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0800) >> 8); // St Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0001) << 8); // A Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0100) << 2) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0200) << 2) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
else
{
// Logitech F310, Dualshock 4
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0001) << 1); // Y Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0100) >> 6); // Sl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0200) >> 6); // St Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0004) << 6); // A Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0010) << 6) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller1Buttons = controller1Buttons | ((infoEx.dwButtons & 0x0020) << 6) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
controller1Buttons = controller1Buttons | 0x10000; // Controller plugged in status.
}
controller1Buttons = ~controller1Buttons;
result = joyGetPosEx(JOYSTICKID2, &infoEx);
if (result == JOYERR_NOERROR)
{
xAxis = (infoEx.dwXpos >> 8) & 0xFF;
yAxis = (infoEx.dwYpos >> 8) & 0xFF;
controller2Buttons = controller2Buttons | ((yAxis < 103 || infoEx.dwPOV == 0 || infoEx.dwPOV == 4500 || infoEx.dwPOV == 31500) << 4); // U Button
controller2Buttons = controller2Buttons | ((yAxis > 153 || (infoEx.dwPOV >= 13500 && infoEx.dwPOV <= 22500)) << 5); // D Button
controller2Buttons = controller2Buttons | ((xAxis < 103 || (infoEx.dwPOV >= 22500 && infoEx.dwPOV <= 31500)) << 6); // L Button
controller2Buttons = controller2Buttons | ((xAxis > 153 || (infoEx.dwPOV >= 4500 && infoEx.dwPOV <= 13500)) << 7); // R Button
// controller2Buttons = controller2Buttons | 0 * 0x1000; // spare Button
// controller2Buttons = controller2Buttons | 0 * 0x2000; // spare Button
// controller2Buttons = controller2Buttons | 0 * 0x4000; // spare Button
// controller2Buttons = controller2Buttons | 0 * 0x8000; // spare Button
if (pCard->m_altControllerType[1])
{
// 8BitDo NES30 PRO
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0010) >> 3); // Y Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0400) >> 8); // Sl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0800) >> 8); // St Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0001) << 8); // A Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0100) << 2) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0200) << 2) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
else
{
// Logitech F310, Dualshock 4
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0002) >> 1); // B Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0001) << 1); // Y Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0100) >> 6); // Sl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0200) >> 6); // St Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0004) << 6); // A Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0008) << 6); // X Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0010) << 6) | ((infoEx.dwButtons & 0x0040) << 4); // Fl Button
controller2Buttons = controller2Buttons | ((infoEx.dwButtons & 0x0020) << 6) | ((infoEx.dwButtons & 0x0080) << 4); // Fr Button
}
controller2Buttons = controller2Buttons | 0x10000; // Controller plugged in status.
}
controller2Buttons = ~controller2Buttons;
break;
case 1: // Clock
if (pCard->buttonIndex <= 16)
{
pCard->buttonIndex++;
controller1Buttons = controller1Buttons >> 1;
controller2Buttons = controller2Buttons >> 1;
}
break;
default:
break;
}
return 0;
}
void SNESMAXCard::InitializeIO(LPBYTE pCxRomPeripheral, UINT slot)
{
RegisterIoHandler(slot, &SNESMAXCard::IORead, &SNESMAXCard::IOWrite, IO_Null, IO_Null, this, NULL);
}
//===========================================================================
static const UINT kUNIT_VERSION = 1;
#define SS_YAML_KEY_BUTTON_INDEX "Button Index"
std::string SNESMAXCard::GetSnapshotCardName(void)
{
static const std::string name("SNES MAX");
return name;
}
void SNESMAXCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveUint(SS_YAML_KEY_BUTTON_INDEX, buttonIndex);
}
bool SNESMAXCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version)
{
if (version < 1 || version > kUNIT_VERSION)
throw std::string("Card: wrong version");
buttonIndex = yamlLoadHelper.LoadUint(SS_YAML_KEY_BUTTON_INDEX);
return true;
}

42
source/SNESMAX.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include "Card.h"
#include "CmdLine.h"
class SNESMAXCard : public Card
{
public:
SNESMAXCard(UINT slot) :
Card(CT_SNESMAX),
m_slot(slot)
{
buttonIndex = 0;
controller1Buttons = 0;
controller2Buttons = 0;
m_altControllerType[0] = g_cmdLine.snesMaxAltControllerType[0];
m_altControllerType[1] = g_cmdLine.snesMaxAltControllerType[1];
}
virtual ~SNESMAXCard(void) {}
virtual void Init(void) {};
virtual void Reset(const bool powerCycle) {};
void InitializeIO(LPBYTE pCxRomPeripheral, UINT slot);
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
static BYTE __stdcall IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
static std::string GetSnapshotCardName(void);
void SaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
bool LoadSnapshot(class YamlLoadHelper& yamlLoadHelper, UINT slot, UINT version);
private:
UINT m_slot;
UINT buttonIndex;
UINT controller1Buttons;
UINT controller2Buttons;
bool m_altControllerType[2];
};

View File

@ -36,6 +36,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "CPU.h"
#include "Debug.h"
#include "Disk.h"
#include "FourPlay.h"
#include "Joystick.h"
#include "Keyboard.h"
#include "LanguageCard.h"
@ -45,6 +46,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "ParallelPrinter.h"
#include "Pravets.h"
#include "SerialComms.h"
#include "SNESMAX.h"
#include "Speaker.h"
#include "Speech.h"
#include "z80emu.h"
@ -314,7 +316,7 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT unitVersion)
std::string card = yamlLoadHelper.LoadString(SS_YAML_KEY_CARD);
UINT cardVersion = yamlLoadHelper.LoadUint(SS_YAML_KEY_VERSION);
if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE)))
if (!yamlLoadHelper.GetSubMap(std::string(SS_YAML_KEY_STATE), true)) // NB. For some cards, State can be null
throw std::string(SS_YAML_KEY_UNIT ": Expected sub-map name: " SS_YAML_KEY_STATE);
SS_CARDTYPE type = CT_Empty;
@ -378,6 +380,18 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT unitVersion)
CreateLanguageCard();
bRes = GetLanguageCard()->LoadSnapshot(yamlLoadHelper, slot, cardVersion);
}
else if (card == FourPlayCard::GetSnapshotCardName())
{
type = CT_FourPlay;
GetCardMgr().Insert(slot, type);
bRes = dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(slot)).LoadSnapshot(yamlLoadHelper, slot, cardVersion);
}
else if (card == SNESMAXCard::GetSnapshotCardName())
{
type = CT_SNESMAX;
GetCardMgr().Insert(slot, type);
bRes = dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(slot)).LoadSnapshot(yamlLoadHelper, slot, cardVersion);
}
else
{
throw std::string("Slots: Unknown card: " + card); // todo: don't throw - just ignore & continue
@ -635,6 +649,14 @@ void Snapshot_SaveState(void)
if (GetCardMgr().QuerySlot(SLOT7) == CT_GenericHDD)
HD_SaveSnapshot(yamlSaveHelper);
for (UINT slot = SLOT3; slot <= SLOT5; slot++)
{
if (GetCardMgr().QuerySlot(slot) == CT_FourPlay)
dynamic_cast<FourPlayCard&>(GetCardMgr().GetRef(slot)).SaveSnapshot(yamlSaveHelper);
else if (GetCardMgr().QuerySlot(slot) == CT_SNESMAX)
dynamic_cast<SNESMAXCard&>(GetCardMgr().GetRef(slot)).SaveSnapshot(yamlSaveHelper);
}
}
// Miscellaneous

View File

@ -1500,9 +1500,7 @@ return ret;
void get_disabled_state(int * param)
{
*param = tfe_cannot_use;
*param = tfe_cannot_use;
}
int update_tfe_interface(const std::string & name)

View File

@ -256,6 +256,12 @@ void LoadConfiguration(void)
if(REGLOAD(TEXT(REGVALUE_MOUSE_RESTRICT_TO_WINDOW), &dwTmp))
GetPropertySheet().SetMouseRestrictToWindow(dwTmp);
//
TCHAR szFilename[MAX_PATH];
//
for (UINT slot = SLOT0; slot <= SLOT7; slot++)
{
std::string& regSection = RegGetConfigSlotSection(slot);
@ -263,10 +269,38 @@ void LoadConfiguration(void)
if (RegLoadValue(regSection.c_str(), REGVALUE_CARD_TYPE, TRUE, &dwTmp))
{
GetCardMgr().Insert(slot, (SS_CARDTYPE)dwTmp);
if (slot == SLOT3)
{
if ((SS_CARDTYPE)dwTmp == CT_Uthernet) // TODO: move this to when UthernetCard object is instantiated
{
tfe_enabled = 1;
std::string& regSection = RegGetConfigSlotSection(slot);
if (RegLoadString(regSection.c_str(), REGVALUE_UTHERNET_INTERFACE, TRUE, szFilename, MAX_PATH, TEXT("")))
update_tfe_interface(szFilename);
}
else
{
tfe_enabled = 0;
}
}
}
else // legacy (AppleWin 1.30.3 or earlier)
{
if (slot == SLOT4 && REGLOAD(TEXT(REGVALUE_SLOT4), &dwTmp))
if (slot == SLOT3)
{
DWORD tfeEnabled;
REGLOAD_DEFAULT(TEXT(REGVALUE_UTHERNET_ACTIVE), &tfeEnabled, 0);
tfe_enabled = tfeEnabled ? 1 : 0;
GetCardMgr().Insert(SLOT3, get_tfe_enabled() ? CT_Uthernet : CT_Empty);
// TODO: move this to when UthernetCard object is instantiated
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, szFilename, MAX_PATH, TEXT(""));
update_tfe_interface(szFilename);
}
else if (slot == SLOT4 && REGLOAD(TEXT(REGVALUE_SLOT4), &dwTmp))
GetCardMgr().Insert(SLOT4, (SS_CARDTYPE)dwTmp);
else if (slot == SLOT5 && REGLOAD(TEXT(REGVALUE_SLOT5), &dwTmp))
GetCardMgr().Insert(SLOT5, (SS_CARDTYPE)dwTmp);
@ -277,8 +311,6 @@ void LoadConfiguration(void)
//
TCHAR szFilename[MAX_PATH];
// Load save-state pathname *before* inserting any harddisk/disk images (for both init & reinit cases)
// NB. inserting harddisk/disk can change snapshot pathname
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_SAVESTATE_FILENAME), 1, szFilename, MAX_PATH, TEXT("")); // Can be pathname or just filename
@ -306,15 +338,6 @@ void LoadConfiguration(void)
//
DWORD dwTfeEnabled;
REGLOAD_DEFAULT(TEXT(REGVALUE_UTHERNET_ACTIVE), &dwTfeEnabled, 0);
tfe_enabled = dwTfeEnabled ? 1 : 0;
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_UTHERNET_INTERFACE), 1, szFilename, MAX_PATH, TEXT(""));
update_tfe_interface(szFilename);
//
RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_PRINTER_FILENAME), 1, szFilename, MAX_PATH, TEXT(""));
Printer_SetFilename(szFilename); // If not in Registry than default will be used

View File

@ -192,10 +192,10 @@ std::string YamlHelper::GetMapValue(MapYaml& mapYaml, const std::string& key, bo
return value;
}
bool YamlHelper::GetSubMap(MapYaml** mapYaml, const std::string& key)
bool YamlHelper::GetSubMap(MapYaml** mapYaml, const std::string& key, const bool canBeNull = false)
{
MapYaml::const_iterator iter = (*mapYaml)->find(key);
if (iter == (*mapYaml)->end() || iter->second.subMap == NULL)
if (iter == (*mapYaml)->end() || (!canBeNull && iter->second.subMap == NULL))
{
return false; // not found
}

View File

@ -50,7 +50,7 @@ private:
int ParseMap(MapYaml& mapYaml);
std::string GetMapValue(MapYaml& mapYaml, const std::string &key, bool& bFound);
UINT LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize);
bool GetSubMap(MapYaml** mapYaml, const std::string &key);
bool GetSubMap(MapYaml** mapYaml, const std::string &key, const bool canBeNull /*= false*/);
void GetMapRemainder(std::string& mapName, MapYaml& mapYaml);
void MakeAsciiToHexTable(void);
@ -103,11 +103,11 @@ public:
void LoadMemory(const LPBYTE pMemBase, const size_t size);
void LoadMemory(std::vector<BYTE>& memory, const size_t size);
bool GetSubMap(const std::string & key)
bool GetSubMap(const std::string & key, const bool canBeNull=false)
{
YamlStackItem item = {m_pMapYaml, m_currentMapName};
m_stackMap.push(item);
bool res = m_yamlHelper.GetSubMap(&m_pMapYaml, key);
bool res = m_yamlHelper.GetSubMap(&m_pMapYaml, key, canBeNull);
if (!res)
m_stackMap.pop();
else