From fec52f8c3964c4a5917b96e12e39c8994ffce250 Mon Sep 17 00:00:00 2001 From: sicklittlemonkey Date: Thu, 9 Jul 2015 22:31:04 +1200 Subject: [PATCH] First cut of TCP input --- AppleWinExpress2013.vcxproj | 831 ++++----- resource/Applewin.rc | 931 +++++----- resource/resource.h | 259 +-- source/Applewin.cpp | 2267 +++++++++++------------ source/Applewin.h | 121 +- source/Common.h | 413 ++--- source/Configuration/IPropertySheet.h | 2 + source/Configuration/PageInput.cpp | 3 + source/Configuration/PageInput.h | 4 + source/Configuration/PropertySheet.h | 102 +- source/Disk.cpp | 2395 +++++++++++++------------ source/GenericSocketDriver.cpp | 454 +++++ source/GenericSocketDriver.h | 79 + source/Joystick.cpp | 1763 +++++++++--------- source/Joystick.h | 66 +- source/StdAfx.h | 130 +- 16 files changed, 5269 insertions(+), 4551 deletions(-) create mode 100644 source/GenericSocketDriver.cpp create mode 100644 source/GenericSocketDriver.h diff --git a/AppleWinExpress2013.vcxproj b/AppleWinExpress2013.vcxproj index 21d853f9..9db36a23 100644 --- a/AppleWinExpress2013.vcxproj +++ b/AppleWinExpress2013.vcxproj @@ -1,415 +1,418 @@ - - - - - Debug NoDX - Win32 - - - Debug - Win32 - - - Release NoDX - Win32 - - - Release - Win32 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create - Create - Create - Create - - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - NotUsing - NotUsing - NotUsing - NotUsing - - - - - - - - - - - - - - - - - - - - - - - - {509739e7-0af3-4c09-a1a9-f0b1bc31b39d} - - - {9b32a6e7-1237-4f36-8903-a3fd51df9c4e} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {0A960136-A00A-4D4B-805F-664D9950D2CA} - Win32Proj - AppleWinExpress2013 - AppleWin - - - - Application - true - v120 - MultiByte - - - Application - true - v120 - MultiByte - - - Application - false - v120 - false - MultiByte - - - Application - false - v120 - false - MultiByte - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreadedDebug - - - Windows - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreadedDebug - - - Windows - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreaded - Speed - - - Windows - true - true - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) - true - source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) - MultiThreaded - Speed - - - Windows - true - true - true - htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) - UseLinkTimeCodeGeneration - - - - - + + + + + Debug NoDX + Win32 + + + Debug + Win32 + + + Release NoDX + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Create + Create + Create + Create + + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + NotUsing + NotUsing + NotUsing + NotUsing + + + + + + + + + + + + + + + + + + + + + + + + {509739e7-0af3-4c09-a1a9-f0b1bc31b39d} + + + {9b32a6e7-1237-4f36-8903-a3fd51df9c4e} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {0A960136-A00A-4D4B-805F-664D9950D2CA} + Win32Proj + AppleWinExpress2013 + AppleWin + + + + Application + true + v120 + MultiByte + + + Application + true + v120 + MultiByte + + + Application + false + v120 + false + MultiByte + + + Application + false + v120 + false + MultiByte + + + + + + + + + + + + + + + + + + + true + + + true + + + false + + + false + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + MultiThreadedDebug + true + + + Windows + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + MultiThreadedDebug + + + Windows + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + MultiThreaded + Speed + + + Windows + true + true + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;NO_DSHOW_STRSAFE;NO_DIRECT_X;%(PreprocessorDefinitions) + true + source\cpu;source\emulator;source\debugger;zlib;zip_lib;%(AdditionalIncludeDirectories) + MultiThreaded + Speed + + + Windows + true + true + true + htmlhelp.lib;comctl32.lib;ddraw.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;Advapi32.lib;shell32.lib;Comdlg32.lib;ole32.lib;wsock32.lib;%(AdditionalDependencies) + UseLinkTimeCodeGeneration + + + + + \ No newline at end of file diff --git a/resource/Applewin.rc b/resource/Applewin.rc index fb8c771e..4bbc3620 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -1,465 +1,466 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Bitmap -// - -FULLSCR_BUTTON BITMAP "FULLSCR.BMP" -RUN_BUTTON BITMAP "RUN.BMP" -RUNP_BUTTON BITMAP "RUNP.BMP" -DEBUG_BUTTON BITMAP "DEBUG.BMP" -DRIVE1_BUTTON BITMAP "DRIVE1.BMP" -DRIVE2_BUTTON BITMAP "DRIVE2.BMP" -SETUP_BUTTON BITMAP "SETUP.BMP" -CHARSET40 BITMAP "CHARSET4.BMP" -DISKOFF_BITMAP BITMAP "DISKOFF.BMP" -DISKREAD_BITMAP BITMAP "DISKREAD.BMP" -DISKWRITE_BITMAP BITMAP "DISKWRIT.BMP" -DISKPROT_BITMAP BITMAP "DISKPROT.BMP" -LED_CAPSOFF_BITMAP BITMAP "LED_CAPS_OFF.BMP" -LED_CAPSON_BITMAP BITMAP "LED_CAPS_ON.BMP" -LED_CAPSOFF_P8_BITMAP BITMAP "LED_CAPS_OFF_P8.BMP" -LED_CAPSON_P8_BITMAP BITMAP "LED_CAPS_ON_P8.BMP" -LED_LATOFF_BITMAP BITMAP "LED_CAPS_OFF_LAT.BMP" -LED_LATON_BITMAP BITMAP "LED_CAPS_ON_LAT.BMP" -CHARSET82 BITMAP "CHARSET82.BMP" -CHARSET8M BITMAP "CHARSET8C.BMP" -CHARSET8C BITMAP "CHARSET8C.BMP" -HELP_BUTTON BITMAP "HELP.BMP" -DRIVESWAP_BUTTON BITMAP "DRIVESWAP.BMP" -IDB_APPLEWIN BITMAP "Applewin.bmp" -IDB_DEBUG_FONT_7X8 BITMAP "Debug_Font.bmp" - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_PROPPAGE_CONFIG DIALOGEX 0, 0, 210, 209 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU -CAPTION "Configuration" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - LTEXT "&Model:",IDC_STATIC,5,7,40,8 - COMBOBOX IDC_COMPUTER,45,5,95,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Video",IDC_STATIC,5,22,200,43 - LTEXT "Mo&de:",IDC_STATIC,12,33,33,8 - COMBOBOX IDC_VIDEOTYPE,45,30,95,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Monochrome &Color...",IDC_MONOCOLOR,12,46,80,14 - CONTROL "&50% Scan lines",IDC_CHECK_HALF_SCAN_LINES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,103,48,62,10 - LTEXT "&Serial Port:",IDC_STATIC,5,74,40,8 - COMBOBOX IDC_SERIALPORT,45,72,95,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "&Ethernet Settings...",IDC_ETHERNET,4,90,80,14 - GROUPBOX "Emulation Speed Control",IDC_STATIC,5,115,200,85 - CONTROL "Use &Authentic Machine Speed",IDC_AUTHENTIC_SPEED, - "Button",BS_AUTORADIOBUTTON,15,126,115,10 - CONTROL "Select C&ustom Speed (in MHz)",IDC_CUSTOM_SPEED,"Button",BS_AUTORADIOBUTTON,15,138,115,10 - CONTROL "Generic2",IDC_SLIDER_CPU_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,25,149,160,15 - CTEXT "0.5",IDC_0_5_MHz,23,165,20,10 - CTEXT "1.0",IDC_1_0_MHz,59,165,20,10 - CTEXT "2.0",IDC_2_0_MHz,96,165,20,10 - RTEXT "Fastest",IDC_MAX_MHz,150,165,29,10 - PUSHBUTTON "&Benchmark Emulator",IDC_BENCHMARK,15,179,85,15 -END - -IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 210, 215 -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 - LTEXT "Joystick &1:",IDC_STATIC,12,20,40,8 - COMBOBOX IDC_JOYSTICK0,52,18,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Joystick &2:",IDC_STATIC,12,35,40,8 - COMBOBOX IDC_JOYSTICK1,52,33,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "&X-trim:",IDC_STATIC,13,56,28,8 - CTEXT "0",IDC_STATIC,36,50,24,20,SS_CENTERIMAGE - CONTROL "Spin1",IDC_SPIN_XTRIM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY,59,53,10,14 - LTEXT "&Y-trim:",IDC_STATIC,115,56,28,8 - CTEXT "0",IDC_STATIC,137,49,24,20,SS_CENTERIMAGE - CONTROL "Spin1",IDC_SPIN_YTRIM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY,161,53,10,14 - CONTROL "Allow cursor keys to be read from keyboard ",IDC_CURSORCONTROL, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,75,155,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 - 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 - CONTROL "Show &crosshairs in window's frame",IDC_MOUSE_CROSSHAIR, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,141,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 -END - -IDD_PROPPAGE_SOUND DIALOGEX 0, 0, 210, 191 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU -CAPTION "Sound" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - LTEXT "&Device:",IDC_STATIC,5,7,40,8 - COMBOBOX IDC_SOUNDTYPE,45,5,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - GROUPBOX "Volume Control",IDC_STATIC,5,24,100,89 - LTEXT "&Speaker:",IDC_STATIC,11,39,31,8 - CONTROL "Slider1",IDC_SPKR_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,13,47,28,60 - LTEXT "&Mockingboard:",IDC_STATIC,49,39,51,8 - CONTROL "Slider1",IDC_MB_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,59,47,25,60 - GROUPBOX "Sound Cards",IDC_STATIC,6,122,197,61 - CONTROL "Mockingboards (in slots 4 && 5)",IDC_MB_ENABLE,"Button",BS_AUTORADIOBUTTON,10,136,142,8 - CONTROL "Phasor (in slot 4)",IDC_PHASOR_ENABLE,"Button",BS_AUTORADIOBUTTON,10,149,92,10 - CONTROL "No sound cards",IDC_SOUNDCARD_DISABLE,"Button",BS_AUTORADIOBUTTON,10,163,78,10 -END - -IDD_PROPPAGE_DISK DIALOGEX 0, 0, 210, 190 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU -CAPTION "Disk" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - GROUPBOX "Floppy Disk Drives",IDC_STATIC,5,7,200,73 - LTEXT "&Disk access speed:",IDC_STATIC,12,21,64,8 - COMBOBOX IDC_DISKTYPE,80,18,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Select Disk &1",IDC_DISK1,10,39,70,14 - EDITTEXT IDC_EDIT_DISK1,84,40,115,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Select Disk &2",IDC_DISK2,10,60,70,14 - EDITTEXT IDC_EDIT_DISK2,84,60,115,12,ES_AUTOHSCROLL | ES_READONLY - GROUPBOX "Hard Disk Drives",IDC_STATIC,5,85,200,71 - CONTROL "&Enable hard disk controller in slot 7",IDC_HDD_ENABLE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,98,122,10 - PUSHBUTTON "Select &HDD 1",IDC_HDD1,10,114,70,14 - EDITTEXT IDC_EDIT_HDD1,85,115,115,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "Selec&t HDD 2",IDC_HDD2,10,134,70,14 - EDITTEXT IDC_EDIT_HDD2,85,135,115,12,ES_AUTOHSCROLL | ES_READONLY - LTEXT "&Path to CiderPress:",IDC_STATIC,5,162,74,8 - EDITTEXT IDC_CIDERPRESS_FILENAME,5,172,143,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "&Browse...",IDC_CIDERPRESS_BROWSE,154,171,50,14 -END - -IDD_TFE_SETTINGS_DIALOG DIALOGEX 0, 0, 270, 100 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Ethernet Settings" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - LTEXT "Ethernet",IDC_TFE_SETTINGS_ENABLE_T,9,7,30,8 - COMBOBOX IDC_TFE_SETTINGS_ENABLE,45,5,50,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Interface",IDC_TFE_SETTINGS_INTERFACE_T,9,24,30,8 - COMBOBOX IDC_TFE_SETTINGS_INTERFACE,45,22,200,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "",IDC_TFE_SETTINGS_INTERFACE_NAME,9,44,250,8 - LTEXT "",IDC_TFE_SETTINGS_INTERFACE_DESC,9,60,250,8 - DEFPUSHBUTTON "Ok",IDOK,20,75,50,14 - PUSHBUTTON "Cancel",IDCANCEL,80,75,50,14 -END - -IDD_PROPPAGE_ADVANCED DIALOGEX 0, 0, 210, 217 -STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU -CAPTION "Advanced" -FONT 8, "MS Shell Dlg", 0, 0, 0x0 -BEGIN - GROUPBOX "Save State",IDC_STATIC,5,7,200,86 - LTEXT "&Filename:",IDC_STATIC,12,19,74,8 - EDITTEXT IDC_SAVESTATE_FILENAME,12,30,133,12,ES_AUTOHSCROLL | ES_READONLY - PUSHBUTTON "&Browse...",IDC_SAVESTATE_BROWSE,149,28,50,14 - CONTROL "Save state on e&xit",IDC_SAVESTATE_ON_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,47,74,10 - PUSHBUTTON "Sa&ve State",IDC_SAVESTATE,13,59,85,15 - LTEXT "(F11 during emulation)",IDC_STATIC,107,62,90,8 - PUSHBUTTON "&Load State",IDC_LOADSTATE,13,76,85,15 - LTEXT "(F12 during emulation)",IDC_STATIC,107,79,90,8 - LTEXT "&Printer dump filename:",IDC_STATIC,5,97,74,8 - EDITTEXT IDC_PRINTER_DUMP_FILENAME,5,107,143,12,ES_AUTOHSCROLL - PUSHBUTTON "B&rowse...",IDC_PRINTER_DUMP_FILENAME_BROWSE,154,106,50,14 - CONTROL "&Dump to printer (use with caution)",IDC_DUMPTOPRINTER, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,124,180,10 - CONTROL "&Encoding conversion for clones",IDC_PRINTER_CONVERT_ENCODING, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,135,180,10 - CONTROL "Filter &unprintable characters",IDC_PRINTER_FILTER_UNPRINTABLE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,146,180,10 - CONTROL "&Append to print file",IDC_PRINTER_APPEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,157,120,10 - LTEXT "&Teminate printing after idle (in seconds):",IDC_STATIC,5,171,133,8 - CTEXT "10",IDC_STATIC,140,165,24,20,SS_CENTERIMAGE - CONTROL "Spin1",IDC_SPIN_PRINTER_IDLE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY,172,169,11,14 - LTEXT "&Clone:",IDC_STATIC,5,187,40,8 - COMBOBOX IDC_CLONETYPE,35,185,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - CONTROL "The Free&ze's non-autostart F8 rom (Apple ][ or ][+ only)",IDC_THE_FREEZES_F8_ROM_FW, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,201,194,10 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -APPLEWIN_ICON ICON "APPLEWIN.ICO" -DISK_ICON ICON "DISK.ICO" - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,24,0,0 - PRODUCTVERSION 1,24,0,0 - FILEFLAGSMASK 0x3fL -#ifdef _DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE 0x1L - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "04090000" - BEGIN - VALUE "Comments", "http://applewin.berlios.de" - VALUE "CompanyName", "AppleWin" - VALUE "FileDescription", "Apple //e Emulator for Windows" - VALUE "FileVersion", "1, 24, 0, 0" - VALUE "InternalName", "APPLEWIN" - VALUE "LegalCopyright", " 1994-2014 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis" - VALUE "OriginalFilename", "APPLEWIN.EXE" - VALUE "ProductName", "Apple //e Emulator" - VALUE "ProductVersion", "1, 24, 0, 0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 0 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// Accelerator -// - -IDR_ACCELERATOR1 ACCELERATORS -BEGIN - "/", IDM_ABOUT, ASCII, ALT, NOINVERT - "?", IDM_ABOUT, ASCII, ALT, NOINVERT -END - - -///////////////////////////////////////////////////////////////////////////// -// -// FIRMWARE -// - -IDR_DISK2_FW FIRMWARE "Disk2.rom" -IDR_SSC_FW FIRMWARE "SSC.rom" -IDR_HDDRVR_FW FIRMWARE "Hddrvr.bin" -IDR_PRINTDRVR_FW FIRMWARE "Parallel.rom" -IDR_MOCKINGBOARD_D_FW FIRMWARE "Mockingboard-D.rom" -IDR_MOUSEINTERFACE_FW FIRMWARE "MouseInterface.rom" -IDR_THUNDERCLOCKPLUS_FW FIRMWARE "ThunderClockPlus.rom" - -///////////////////////////////////////////////////////////////////////////// -// -// ROM -// - -IDR_APPLE2_ROM ROM "Apple2.rom" -IDR_APPLE2_PLUS_ROM ROM "Apple2_Plus.rom" -IDR_APPLE2E_ROM ROM "Apple2e.rom" -IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom" -IDR_PRAVETS_82_ROM ROM "Pravets82.rom" -IDR_PRAVETS_8M_ROM ROM "Pravets8M.rom" -IDR_PRAVETS_8C_ROM ROM "Pravets8C.rom" -IDR_FREEZES_F8_ROM ROM "FREEZES_NON-AUTOSTART_F8_ROM.rom" - -///////////////////////////////////////////////////////////////////////////// -// -// Menu -// - -IDR_MENU MENU -BEGIN - POPUP "&File" - BEGIN - MENUITEM "E&xit", IDM_EXIT - END - POPUP "Help" - BEGIN - MENUITEM "&Help", IDM_HELP - MENUITEM "&About", IDM_ABOUT - END -END - -IDR_MENU_DISK_POPUP MENU -BEGIN - POPUP "Disk Menu" - BEGIN - MENUITEM "&Eject", ID_DISKMENU_EJECT - MENUITEM "Read / &Write", ID_DISKMENU_WRITEPROTECTION_OFF - MENUITEM "&Read only", ID_DISKMENU_WRITEPROTECTION_ON - MENUITEM "Send to &CiderPress", ID_DISKMENU_SENDTO_CIDERPRESS - END -END - -IDR_MENU_DISK_CFG_POPUP MENU -BEGIN - POPUP "Disk Menu" - BEGIN - MENUITEM "Eject disk in Drive 1", ID_DISKMENU_EJECT_DISK1 - MENUITEM "Eject disk in Drive 2", ID_DISKMENU_EJECT_DISK2 - MENUITEM "Unplug harddisk-1", ID_DISKMENU_UNPLUG_HARDDISK1 - MENUITEM "Unplug harddisk-2", ID_DISKMENU_UNPLUG_HARDDISK2 - END -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_PROPPAGE_INPUT, DIALOG - BEGIN - BOTTOMMARGIN, 182 - END -END -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE -BEGIN - IDS_TFE_CAPTION "Ethernet Settings" - IDS_TFE_ETHERNET "Ethernet" - IDS_TFE_INTERFACE "Interface" -END - -STRINGTABLE -BEGIN - IDS_OK "OK" - IDS_CANCEL "Cancel" -END - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - -///////////////////////////////////////////////////////////////////////////// -// English (U.K.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_ABOUT DIALOGEX 0, 0, 240, 183 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION -CAPTION "About AppleWin" -FONT 8, "MS Shell Dlg", 400, 0, 0x1 -BEGIN - ICON "",IDC_APPLEWIN_ICON,15,10,21,20 - LTEXT "Static",IDC_APPLEWIN_VERSION,46,17,81,8 - GROUPBOX "GNU General Public License",IDC_GPL_BORDER,7,37,226,111,BS_CENTER | WS_TABSTOP - EDITTEXT IDC_GPL_TEXT,11,57,213,88,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER | WS_VSCROLL - DEFPUSHBUTTON "I accept",IDOK,63,159,48,14 - PUSHBUTTON "I decline",IDCANCEL,123,159,67,14 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_ABOUT, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 233 - TOPMARGIN, 6 - BOTTOMMARGIN, 176 - END -END -#endif // APSTUDIO_INVOKED - -#endif // English (U.K.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +FULLSCR_BUTTON BITMAP "FULLSCR.BMP" +RUN_BUTTON BITMAP "RUN.BMP" +RUNP_BUTTON BITMAP "RUNP.BMP" +DEBUG_BUTTON BITMAP "DEBUG.BMP" +DRIVE1_BUTTON BITMAP "DRIVE1.BMP" +DRIVE2_BUTTON BITMAP "DRIVE2.BMP" +SETUP_BUTTON BITMAP "SETUP.BMP" +CHARSET40 BITMAP "CHARSET4.BMP" +DISKOFF_BITMAP BITMAP "DISKOFF.BMP" +DISKREAD_BITMAP BITMAP "DISKREAD.BMP" +DISKWRITE_BITMAP BITMAP "DISKWRIT.BMP" +DISKPROT_BITMAP BITMAP "DISKPROT.BMP" +LED_CAPSOFF_BITMAP BITMAP "LED_CAPS_OFF.BMP" +LED_CAPSON_BITMAP BITMAP "LED_CAPS_ON.BMP" +LED_CAPSOFF_P8_BITMAP BITMAP "LED_CAPS_OFF_P8.BMP" +LED_CAPSON_P8_BITMAP BITMAP "LED_CAPS_ON_P8.BMP" +LED_LATOFF_BITMAP BITMAP "LED_CAPS_OFF_LAT.BMP" +LED_LATON_BITMAP BITMAP "LED_CAPS_ON_LAT.BMP" +CHARSET82 BITMAP "CHARSET82.BMP" +CHARSET8M BITMAP "CHARSET8C.BMP" +CHARSET8C BITMAP "CHARSET8C.BMP" +HELP_BUTTON BITMAP "HELP.BMP" +DRIVESWAP_BUTTON BITMAP "DRIVESWAP.BMP" +IDB_APPLEWIN BITMAP "Applewin.bmp" +IDB_DEBUG_FONT_7X8 BITMAP "Debug_Font.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_PROPPAGE_CONFIG DIALOGEX 0, 0, 210, 209 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU +CAPTION "Configuration" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "&Model:",IDC_STATIC,5,7,40,8 + COMBOBOX IDC_COMPUTER,45,5,95,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Video",IDC_STATIC,5,22,200,43 + LTEXT "Mo&de:",IDC_STATIC,12,33,33,8 + COMBOBOX IDC_VIDEOTYPE,45,30,95,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Monochrome &Color...",IDC_MONOCOLOR,12,46,80,14 + CONTROL "&50% Scan lines",IDC_CHECK_HALF_SCAN_LINES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,103,48,62,10 + LTEXT "&Serial Port:",IDC_STATIC,5,74,40,8 + COMBOBOX IDC_SERIALPORT,45,72,95,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "&Ethernet Settings...",IDC_ETHERNET,4,90,80,14 + GROUPBOX "Emulation Speed Control",IDC_STATIC,5,115,200,85 + CONTROL "Use &Authentic Machine Speed",IDC_AUTHENTIC_SPEED, + "Button",BS_AUTORADIOBUTTON,15,126,115,10 + CONTROL "Select C&ustom Speed (in MHz)",IDC_CUSTOM_SPEED,"Button",BS_AUTORADIOBUTTON,15,138,115,10 + CONTROL "Generic2",IDC_SLIDER_CPU_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,25,149,160,15 + CTEXT "0.5",IDC_0_5_MHz,23,165,20,10 + CTEXT "1.0",IDC_1_0_MHz,59,165,20,10 + CTEXT "2.0",IDC_2_0_MHz,96,165,20,10 + RTEXT "Fastest",IDC_MAX_MHz,150,165,29,10 + PUSHBUTTON "&Benchmark Emulator",IDC_BENCHMARK,15,179,85,15 +END + +IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 210, 215 +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 + LTEXT "Joystick &1:",IDC_STATIC,12,20,40,8 + COMBOBOX IDC_JOYSTICK0,52,18,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Joystick &2:",IDC_STATIC,12,35,40,8 + COMBOBOX IDC_JOYSTICK1,52,33,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "&X-trim:",IDC_STATIC,13,56,28,8 + CTEXT "0",IDC_STATIC,36,50,24,20,SS_CENTERIMAGE + CONTROL "Spin1",IDC_SPIN_XTRIM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY,59,53,10,14 + LTEXT "&Y-trim:",IDC_STATIC,115,56,28,8 + CTEXT "0",IDC_STATIC,137,49,24,20,SS_CENTERIMAGE + CONTROL "Spin1",IDC_SPIN_YTRIM,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY,161,53,10,14 + CONTROL "Allow cursor keys to be read from keyboard ",IDC_CURSORCONTROL, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,8,75,155,10 + CONTROL "TCP/IP", IDC_TCPIP_JOYSTICK, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 163, 76, 37, 8 + 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 + 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 + CONTROL "Show &crosshairs in window's frame",IDC_MOUSE_CROSSHAIR, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,20,141,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 +END + +IDD_PROPPAGE_SOUND DIALOGEX 0, 0, 210, 191 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU +CAPTION "Sound" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "&Device:",IDC_STATIC,5,7,40,8 + COMBOBOX IDC_SOUNDTYPE,45,5,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + GROUPBOX "Volume Control",IDC_STATIC,5,24,100,89 + LTEXT "&Speaker:",IDC_STATIC,11,39,31,8 + CONTROL "Slider1",IDC_SPKR_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,13,47,28,60 + LTEXT "&Mockingboard:",IDC_STATIC,49,39,51,8 + CONTROL "Slider1",IDC_MB_VOLUME,"msctls_trackbar32",TBS_AUTOTICKS | TBS_VERT | TBS_BOTH | WS_TABSTOP,59,47,25,60 + GROUPBOX "Sound Cards",IDC_STATIC,6,122,197,61 + CONTROL "Mockingboards (in slots 4 && 5)",IDC_MB_ENABLE,"Button",BS_AUTORADIOBUTTON,10,136,142,8 + CONTROL "Phasor (in slot 4)",IDC_PHASOR_ENABLE,"Button",BS_AUTORADIOBUTTON,10,149,92,10 + CONTROL "No sound cards",IDC_SOUNDCARD_DISABLE,"Button",BS_AUTORADIOBUTTON,10,163,78,10 +END + +IDD_PROPPAGE_DISK DIALOGEX 0, 0, 210, 190 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU +CAPTION "Disk" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + GROUPBOX "Floppy Disk Drives",IDC_STATIC,5,7,200,73 + LTEXT "&Disk access speed:",IDC_STATIC,12,21,64,8 + COMBOBOX IDC_DISKTYPE,80,18,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Select Disk &1",IDC_DISK1,10,39,70,14 + EDITTEXT IDC_EDIT_DISK1,84,40,115,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Select Disk &2",IDC_DISK2,10,60,70,14 + EDITTEXT IDC_EDIT_DISK2,84,60,115,12,ES_AUTOHSCROLL | ES_READONLY + GROUPBOX "Hard Disk Drives",IDC_STATIC,5,85,200,71 + CONTROL "&Enable hard disk controller in slot 7",IDC_HDD_ENABLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,98,122,10 + PUSHBUTTON "Select &HDD 1",IDC_HDD1,10,114,70,14 + EDITTEXT IDC_EDIT_HDD1,85,115,115,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "Selec&t HDD 2",IDC_HDD2,10,134,70,14 + EDITTEXT IDC_EDIT_HDD2,85,135,115,12,ES_AUTOHSCROLL | ES_READONLY + LTEXT "&Path to CiderPress:",IDC_STATIC,5,162,74,8 + EDITTEXT IDC_CIDERPRESS_FILENAME,5,172,143,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "&Browse...",IDC_CIDERPRESS_BROWSE,154,171,50,14 +END + +IDD_TFE_SETTINGS_DIALOG DIALOGEX 0, 0, 270, 100 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Ethernet Settings" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + LTEXT "Ethernet",IDC_TFE_SETTINGS_ENABLE_T,9,7,30,8 + COMBOBOX IDC_TFE_SETTINGS_ENABLE,45,5,50,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "Interface",IDC_TFE_SETTINGS_INTERFACE_T,9,24,30,8 + COMBOBOX IDC_TFE_SETTINGS_INTERFACE,45,22,200,80,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + LTEXT "",IDC_TFE_SETTINGS_INTERFACE_NAME,9,44,250,8 + LTEXT "",IDC_TFE_SETTINGS_INTERFACE_DESC,9,60,250,8 + DEFPUSHBUTTON "Ok",IDOK,20,75,50,14 + PUSHBUTTON "Cancel",IDCANCEL,80,75,50,14 +END + +IDD_PROPPAGE_ADVANCED DIALOGEX 0, 0, 210, 217 +STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU +CAPTION "Advanced" +FONT 8, "MS Shell Dlg", 0, 0, 0x0 +BEGIN + GROUPBOX "Save State",IDC_STATIC,5,7,200,86 + LTEXT "&Filename:",IDC_STATIC,12,19,74,8 + EDITTEXT IDC_SAVESTATE_FILENAME,12,30,133,12,ES_AUTOHSCROLL | ES_READONLY + PUSHBUTTON "&Browse...",IDC_SAVESTATE_BROWSE,149,28,50,14 + CONTROL "Save state on e&xit",IDC_SAVESTATE_ON_EXIT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,47,74,10 + PUSHBUTTON "Sa&ve State",IDC_SAVESTATE,13,59,85,15 + LTEXT "(F11 during emulation)",IDC_STATIC,107,62,90,8 + PUSHBUTTON "&Load State",IDC_LOADSTATE,13,76,85,15 + LTEXT "(F12 during emulation)",IDC_STATIC,107,79,90,8 + LTEXT "&Printer dump filename:",IDC_STATIC,5,97,74,8 + EDITTEXT IDC_PRINTER_DUMP_FILENAME,5,107,143,12,ES_AUTOHSCROLL + PUSHBUTTON "B&rowse...",IDC_PRINTER_DUMP_FILENAME_BROWSE,154,106,50,14 + CONTROL "&Dump to printer (use with caution)",IDC_DUMPTOPRINTER, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,124,180,10 + CONTROL "&Encoding conversion for clones",IDC_PRINTER_CONVERT_ENCODING, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,135,180,10 + CONTROL "Filter &unprintable characters",IDC_PRINTER_FILTER_UNPRINTABLE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,146,180,10 + CONTROL "&Append to print file",IDC_PRINTER_APPEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,5,157,120,10 + LTEXT "&Teminate printing after idle (in seconds):",IDC_STATIC,5,171,133,8 + CTEXT "10",IDC_STATIC,140,165,24,20,SS_CENTERIMAGE + CONTROL "Spin1",IDC_SPIN_PRINTER_IDLE,"msctls_updown32",UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY,172,169,11,14 + LTEXT "&Clone:",IDC_STATIC,5,187,40,8 + COMBOBOX IDC_CLONETYPE,35,185,100,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + CONTROL "The Free&ze's non-autostart F8 rom (Apple ][ or ][+ only)",IDC_THE_FREEZES_F8_ROM_FW, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,201,194,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +APPLEWIN_ICON ICON "APPLEWIN.ICO" +DISK_ICON ICON "DISK.ICO" + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,24,0,0 + PRODUCTVERSION 1,24,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "04090000" + BEGIN + VALUE "Comments", "http://applewin.berlios.de" + VALUE "CompanyName", "AppleWin" + VALUE "FileDescription", "Apple //e Emulator for Windows" + VALUE "FileVersion", "1, 24, 0, 0" + VALUE "InternalName", "APPLEWIN" + VALUE "LegalCopyright", " 1994-2014 Michael O'Brien, Oliver Schmidt, Tom Charlesworth, Michael Pohoreski, Nick Westgate, Linards Ticmanis" + VALUE "OriginalFilename", "APPLEWIN.EXE" + VALUE "ProductName", "Apple //e Emulator" + VALUE "ProductVersion", "1, 24, 0, 0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 0 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR1 ACCELERATORS +BEGIN + "/", IDM_ABOUT, ASCII, ALT, NOINVERT + "?", IDM_ABOUT, ASCII, ALT, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// FIRMWARE +// + +IDR_DISK2_FW FIRMWARE "Disk2.rom" +IDR_SSC_FW FIRMWARE "SSC.rom" +IDR_HDDRVR_FW FIRMWARE "Hddrvr.bin" +IDR_PRINTDRVR_FW FIRMWARE "Parallel.rom" +IDR_MOCKINGBOARD_D_FW FIRMWARE "Mockingboard-D.rom" +IDR_MOUSEINTERFACE_FW FIRMWARE "MouseInterface.rom" +IDR_THUNDERCLOCKPLUS_FW FIRMWARE "ThunderClockPlus.rom" + +///////////////////////////////////////////////////////////////////////////// +// +// ROM +// + +IDR_APPLE2_ROM ROM "Apple2.rom" +IDR_APPLE2_PLUS_ROM ROM "Apple2_Plus.rom" +IDR_APPLE2E_ROM ROM "Apple2e.rom" +IDR_APPLE2E_ENHANCED_ROM ROM "Apple2e_Enhanced.rom" +IDR_PRAVETS_82_ROM ROM "Pravets82.rom" +IDR_PRAVETS_8M_ROM ROM "Pravets8M.rom" +IDR_PRAVETS_8C_ROM ROM "Pravets8C.rom" +IDR_FREEZES_F8_ROM ROM "FREEZES_NON-AUTOSTART_F8_ROM.rom" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU MENU +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "Help" + BEGIN + MENUITEM "&Help", IDM_HELP + MENUITEM "&About", IDM_ABOUT + END +END + +IDR_MENU_DISK_POPUP MENU +BEGIN + POPUP "Disk Menu" + BEGIN + MENUITEM "&Eject", ID_DISKMENU_EJECT + MENUITEM "Read / &Write", ID_DISKMENU_WRITEPROTECTION_OFF + MENUITEM "&Read only", ID_DISKMENU_WRITEPROTECTION_ON + MENUITEM "Send to &CiderPress", ID_DISKMENU_SENDTO_CIDERPRESS + END +END + +IDR_MENU_DISK_CFG_POPUP MENU +BEGIN + POPUP "Disk Menu" + BEGIN + MENUITEM "Eject disk in Drive 1", ID_DISKMENU_EJECT_DISK1 + MENUITEM "Eject disk in Drive 2", ID_DISKMENU_EJECT_DISK2 + MENUITEM "Unplug harddisk-1", ID_DISKMENU_UNPLUG_HARDDISK1 + MENUITEM "Unplug harddisk-2", ID_DISKMENU_UNPLUG_HARDDISK2 + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_PROPPAGE_INPUT, DIALOG + BEGIN + BOTTOMMARGIN, 182 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE +BEGIN + IDS_TFE_CAPTION "Ethernet Settings" + IDS_TFE_ETHERNET "Ethernet" + IDS_TFE_INTERFACE "Interface" +END + +STRINGTABLE +BEGIN + IDS_OK "OK" + IDS_CANCEL "Cancel" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOGEX 0, 0, 240, 183 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION +CAPTION "About AppleWin" +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + ICON "",IDC_APPLEWIN_ICON,15,10,21,20 + LTEXT "Static",IDC_APPLEWIN_VERSION,46,17,81,8 + GROUPBOX "GNU General Public License",IDC_GPL_BORDER,7,37,226,111,BS_CENTER | WS_TABSTOP + EDITTEXT IDC_GPL_TEXT,11,57,213,88,ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | NOT WS_BORDER | WS_VSCROLL + DEFPUSHBUTTON "I accept",IDOK,63,159,48,14 + PUSHBUTTON "I decline",IDCANCEL,123,159,67,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 233 + TOPMARGIN, 6 + BOTTOMMARGIN, 176 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/resource/resource.h b/resource/resource.h index 9009b167..60064612 100644 --- a/resource/resource.h +++ b/resource/resource.h @@ -1,129 +1,130 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by APPLEWIN.RC -// -#define IDC_COMPUTER 101 -#define IDC_JOYSTICK0 102 -#define IDC_SOUNDTYPE 103 -#define IDC_SERIALPORT 104 -#define IDR_ACCELERATOR1 105 -#define IDC_VIDEOTYPE 106 -#define IDD_PROPPAGE_INPUT 107 -#define IDC_AUTHENTIC_SPEED 108 -#define IDD_PROPPAGE_CONFIG 109 -#define IDC_CUSTOM_SPEED 110 -#define IDC_SLIDER_CPU_SPEED 111 -#define IDD_PROPPAGE_SOUND 112 -#define IDC_DISKTYPE 113 -#define IDC_JOYSTICK1 115 -#define IDD_PROPPAGE_DISK 116 -#define IDC_BENCHMARK 117 -#define IDC_LOADSTATE 118 -#define IDR_HDDRVR_FW 119 -#define IDC_0_5_MHz 120 -#define IDB_APPLEWIN 121 -#define IDC_1_0_MHz 122 -#define IDC_2_0_MHz 123 -#define IDC_MAX_MHz 124 -#define IDR_MENU 125 -#define IDR_APPLE2_ROM 126 -#define IDR_APPLE2_PLUS_ROM 127 -#define IDR_APPLE2E_ROM 128 -#define IDR_APPLE2E_ENHANCED_ROM 129 -#define IDC_MB_ENABLE 130 -#define IDD_TFE_SETTINGS_DIALOG 131 -#define IDR_PRINTDRVR_FW 132 -#define IDD_PROPPAGE_ADVANCED 132 -#define IDR_DISK2_FW 133 -#define IDR_SSC_FW 134 -#define IDR_MOCKINGBOARD_D_FW 135 -#define IDR_MOUSEINTERFACE_FW 136 -#define IDR_THUNDERCLOCKPLUS_FW 137 -#define IDR_FREEZES_F8_ROM 138 -#define IDR_PRAVETS_82_ROM 139 -#define IDR_PRAVETS_8M_ROM 140 -#define IDR_PRAVETS_8C_ROM 142 -#define IDR_MENU_DISK_POPUP 143 -#define IDR_MENU_DISK_CFG_POPUP 144 -#define IDD_ABOUT 145 -#define IDC_KEYB_BUFFER_ENABLE 1005 -#define IDC_SAVESTATE 1006 -#define IDC_SAVESTATE_ON_EXIT 1007 -#define IDC_SAVESTATE_FILENAME 1008 -#define IDC_SPKR_VOLUME 1009 -#define IDC_MB_VOLUME 1010 -#define IDC_SAVESTATE_BROWSE 1011 -#define IDC_MONOCOLOR 1012 -#define IDC_HDD1 1013 -#define IDC_HDD2 1014 -#define IDC_DISK1 1015 -#define IDC_DISK2 1016 -#define IDC_EDIT_DISK1 1017 -#define IDC_EDIT_DISK2 1018 -#define IDC_PASTE_FROM_CLIPBOARD 1018 -#define IDC_EDIT_HDD1 1019 -#define IDC_EDIT_HDD2 1020 -#define IDC_HDD_ENABLE 1021 -#define IDC_SPIN_XTRIM 1026 -#define IDC_SPIN_YTRIM 1027 -#define IDC_PHASOR_ENABLE 1029 -#define IDC_SOUNDCARD_DISABLE 1030 -#define IDC_TFE_SETTINGS_ENABLE_T 1031 -#define IDC_TFE_SETTINGS_ENABLE 1032 -#define IDC_TFE_SETTINGS_INTERFACE_T 1033 -#define IDC_TFE_SETTINGS_INTERFACE 1034 -#define IDC_TFE_SETTINGS_INTERFACE_NAME 1035 -#define IDC_TFE_SETTINGS_INTERFACE_DESC 1036 -#define IDS_TFE_CAPTION 1037 -#define IDS_TFE_ETHERNET 1038 -#define IDS_TFE_INTERFACE 1039 -#define IDS_OK 1040 -#define IDS_CANCEL 1041 -#define IDC_ETHERNET 1042 -#define IDC_SCROLLLOCK_TOGGLE 1043 -#define IDC_MOUSE_IN_SLOT4 1044 -#define IDC_THE_FREEZES_F8_ROM_FW 1045 -#define IDC_MOUSE_CROSSHAIR 1046 -#define IDC_CLONETYPE 1047 -#define IDC_MOUSE_RESTRICT_TO_WINDOW 1048 -#define IDC_CIDERPRESS_BROWSE 1049 -#define IDC_CIDERPRESS_FILENAME 1050 -#define IDC_CPM_CONFIG 1051 -#define IDC_DUMPTOPRINTER 1052 -#define IDC_PRINTER_DUMP_FILENAME 1053 -#define IDC_PRINTER_DUMP_FILENAME_BROWSE 1054 -#define IDC_PRINTER_CONVERT_ENCODING 1055 -#define IDC_PRINTER_FILTER_UNPRINTABLE 1056 -#define IDC_PRINTER_APPEND 1057 -#define IDC_SPIN_PRINTER_IDLE 1058 -#define IDC_CHECK_HALF_SCAN_LINES 1059 -#define IDC_GPL_TEXT 1061 -#define IDC_GPL_BORDER 1063 -#define IDC_APPLEWIN_VERSION 1064 -#define IDC_APPLEWIN_ICON 1065 -#define IDC_CURSORCONTROL 1066 -#define IDC_AUTOFIRE 1067 -#define IDC_CENTERINGCONTROL 1068 -#define IDM_EXIT 40001 -#define IDM_HELP 40002 -#define IDM_ABOUT 40003 -#define ID_DISKMENU_EJECT 40004 -#define ID_DISKMENU_WRITEPROTECTION_ON 40005 -#define ID_DISKMENU_WRITEPROTECTION_OFF 40006 -#define ID_DISKMENU_SENDTO_CIDERPRESS 40007 -#define ID_DISKMENU_EJECT_DISK1 40008 -#define ID_DISKMENU_EJECT_DISK2 40009 -#define ID_DISKMENU_UNPLUG_HARDDISK1 40010 -#define ID_DISKMENU_UNPLUG_HARDDISK2 40011 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 146 -#define _APS_NEXT_COMMAND_VALUE 40012 -#define _APS_NEXT_CONTROL_VALUE 1069 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by APPLEWIN.RC +// +#define IDC_COMPUTER 101 +#define IDC_JOYSTICK0 102 +#define IDC_SOUNDTYPE 103 +#define IDC_SERIALPORT 104 +#define IDR_ACCELERATOR1 105 +#define IDC_VIDEOTYPE 106 +#define IDD_PROPPAGE_INPUT 107 +#define IDC_AUTHENTIC_SPEED 108 +#define IDD_PROPPAGE_CONFIG 109 +#define IDC_CUSTOM_SPEED 110 +#define IDC_SLIDER_CPU_SPEED 111 +#define IDD_PROPPAGE_SOUND 112 +#define IDC_DISKTYPE 113 +#define IDC_JOYSTICK1 115 +#define IDD_PROPPAGE_DISK 116 +#define IDC_BENCHMARK 117 +#define IDC_LOADSTATE 118 +#define IDR_HDDRVR_FW 119 +#define IDC_0_5_MHz 120 +#define IDB_APPLEWIN 121 +#define IDC_1_0_MHz 122 +#define IDC_2_0_MHz 123 +#define IDC_MAX_MHz 124 +#define IDR_MENU 125 +#define IDR_APPLE2_ROM 126 +#define IDR_APPLE2_PLUS_ROM 127 +#define IDR_APPLE2E_ROM 128 +#define IDR_APPLE2E_ENHANCED_ROM 129 +#define IDC_MB_ENABLE 130 +#define IDD_TFE_SETTINGS_DIALOG 131 +#define IDR_PRINTDRVR_FW 132 +#define IDD_PROPPAGE_ADVANCED 132 +#define IDR_DISK2_FW 133 +#define IDR_SSC_FW 134 +#define IDR_MOCKINGBOARD_D_FW 135 +#define IDR_MOUSEINTERFACE_FW 136 +#define IDR_THUNDERCLOCKPLUS_FW 137 +#define IDR_FREEZES_F8_ROM 138 +#define IDR_PRAVETS_82_ROM 139 +#define IDR_PRAVETS_8M_ROM 140 +#define IDR_PRAVETS_8C_ROM 142 +#define IDR_MENU_DISK_POPUP 143 +#define IDR_MENU_DISK_CFG_POPUP 144 +#define IDD_ABOUT 145 +#define IDC_KEYB_BUFFER_ENABLE 1005 +#define IDC_SAVESTATE 1006 +#define IDC_SAVESTATE_ON_EXIT 1007 +#define IDC_SAVESTATE_FILENAME 1008 +#define IDC_SPKR_VOLUME 1009 +#define IDC_MB_VOLUME 1010 +#define IDC_SAVESTATE_BROWSE 1011 +#define IDC_MONOCOLOR 1012 +#define IDC_HDD1 1013 +#define IDC_HDD2 1014 +#define IDC_DISK1 1015 +#define IDC_DISK2 1016 +#define IDC_EDIT_DISK1 1017 +#define IDC_EDIT_DISK2 1018 +#define IDC_PASTE_FROM_CLIPBOARD 1018 +#define IDC_EDIT_HDD1 1019 +#define IDC_EDIT_HDD2 1020 +#define IDC_HDD_ENABLE 1021 +#define IDC_SPIN_XTRIM 1026 +#define IDC_SPIN_YTRIM 1027 +#define IDC_PHASOR_ENABLE 1029 +#define IDC_SOUNDCARD_DISABLE 1030 +#define IDC_TFE_SETTINGS_ENABLE_T 1031 +#define IDC_TFE_SETTINGS_ENABLE 1032 +#define IDC_TFE_SETTINGS_INTERFACE_T 1033 +#define IDC_TFE_SETTINGS_INTERFACE 1034 +#define IDC_TFE_SETTINGS_INTERFACE_NAME 1035 +#define IDC_TFE_SETTINGS_INTERFACE_DESC 1036 +#define IDS_TFE_CAPTION 1037 +#define IDS_TFE_ETHERNET 1038 +#define IDS_TFE_INTERFACE 1039 +#define IDS_OK 1040 +#define IDS_CANCEL 1041 +#define IDC_ETHERNET 1042 +#define IDC_SCROLLLOCK_TOGGLE 1043 +#define IDC_MOUSE_IN_SLOT4 1044 +#define IDC_THE_FREEZES_F8_ROM_FW 1045 +#define IDC_MOUSE_CROSSHAIR 1046 +#define IDC_CLONETYPE 1047 +#define IDC_MOUSE_RESTRICT_TO_WINDOW 1048 +#define IDC_CIDERPRESS_BROWSE 1049 +#define IDC_CIDERPRESS_FILENAME 1050 +#define IDC_CPM_CONFIG 1051 +#define IDC_DUMPTOPRINTER 1052 +#define IDC_PRINTER_DUMP_FILENAME 1053 +#define IDC_PRINTER_DUMP_FILENAME_BROWSE 1054 +#define IDC_PRINTER_CONVERT_ENCODING 1055 +#define IDC_PRINTER_FILTER_UNPRINTABLE 1056 +#define IDC_PRINTER_APPEND 1057 +#define IDC_SPIN_PRINTER_IDLE 1058 +#define IDC_CHECK_HALF_SCAN_LINES 1059 +#define IDC_GPL_TEXT 1061 +#define IDC_GPL_BORDER 1063 +#define IDC_APPLEWIN_VERSION 1064 +#define IDC_APPLEWIN_ICON 1065 +#define IDC_CURSORCONTROL 1066 +#define IDC_AUTOFIRE 1067 +#define IDC_CENTERINGCONTROL 1068 +#define IDC_TCPIP_JOYSTICK 1069 +#define IDM_EXIT 40001 +#define IDM_HELP 40002 +#define IDM_ABOUT 40003 +#define ID_DISKMENU_EJECT 40004 +#define ID_DISKMENU_WRITEPROTECTION_ON 40005 +#define ID_DISKMENU_WRITEPROTECTION_OFF 40006 +#define ID_DISKMENU_SENDTO_CIDERPRESS 40007 +#define ID_DISKMENU_EJECT_DISK1 40008 +#define ID_DISKMENU_EJECT_DISK2 40009 +#define ID_DISKMENU_UNPLUG_HARDDISK1 40010 +#define ID_DISKMENU_UNPLUG_HARDDISK2 40011 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 146 +#define _APS_NEXT_COMMAND_VALUE 40012 +#define _APS_NEXT_CONTROL_VALUE 1069 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/source/Applewin.cpp b/source/Applewin.cpp index a46aa13a..69c6d991 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1,1131 +1,1136 @@ -/* -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-2009, 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 -*/ - -/* Description: main - * - * Author: Various - */ - -#include "StdAfx.h" -#include "DiskImage.h" -#include "Harddisk.h" - -#include "MouseInterface.h" -#ifdef USE_SPEECH_API -#include "Speech.h" -#endif -#include "Configuration\About.h" -#include "Configuration\PropertySheet.h" -#include "Tfe\Tfe.h" - -char VERSIONSTRING[16] = "xx.yy.zz.ww"; - -TCHAR *g_pAppTitle = TITLE_APPLE_2E_ENHANCED; - -eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; - -DWORD cumulativecycles = 0; // Wraps after ~1hr 9mins -DWORD cyclenum = 0; // Used by SpkrToggle() for non-wave sound -DWORD emulmsec = 0; -static DWORD emulmsec_frac = 0; -bool g_bFullSpeed = false; - -//Pravets 8A/C variables -bool P8CAPS_ON = false; -bool P8Shift = false; -//================================================= - -// Win32 -HINSTANCE g_hInstance = (HINSTANCE)0; - -AppMode_e g_nAppMode = MODE_LOGO; -static bool g_bLoadedSaveState = false; - -static int lastmode = MODE_LOGO; -TCHAR g_sProgramDir[MAX_PATH] = TEXT(""); // Directory of where AppleWin executable resides -TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used -TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used -TCHAR g_sCurrentDir[MAX_PATH] = TEXT(""); // Also Starting Dir. Debugger uses this when load/save -BOOL restart = 0; - -DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar -double g_fCurrentCLK6502 = CLK_6502; // Affected by Config dialog's speed slider bar -static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar - -int g_nCpuCyclesFeedback = 0; -DWORD g_dwCyclesThisFrame = 0; - -FILE* g_fh = NULL; -bool g_bDisableDirectInput = false; -bool g_bDisableDirectSound = false; -bool g_bDisableDirectSoundMockingboard = false; -int g_nMemoryClearType = -1; - -IPropertySheet& sg_PropertySheet = * new CPropertySheet; -CSuperSerialCard sg_SSC; -CMouseInterface sg_Mouse; - -SS_CARDTYPE g_Slot4 = CT_Empty; -SS_CARDTYPE g_Slot5 = CT_Empty; - -eCPU g_ActiveCPU = CPU_6502; - -HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $F800..$FFFF -static bool g_bCustomRomF8Failed = false; // Set if custom ROM file failed - -static bool g_bEnableSpeech = false; -#ifdef USE_SPEECH_API -CSpeech g_Speech; -#endif - -//=========================================================================== - -#define DBG_CALC_FREQ 0 -#if DBG_CALC_FREQ -const UINT MAX_CNT = 256; -double g_fDbg[MAX_CNT]; -UINT g_nIdx = 0; -double g_fMeanPeriod,g_fMeanFreq; -ULONGLONG g_nPerfFreq = 0; -#endif - -//--------------------------------------------------------------------------- - -bool GetLoadedSaveStateFlag(void) -{ - return g_bLoadedSaveState; -} - -void SetLoadedSaveStateFlag(const bool bFlag) -{ - g_bLoadedSaveState = bFlag; -} - -static void ResetToLogoMode(void) -{ - g_nAppMode = MODE_LOGO; - SetLoadedSaveStateFlag(false); -} - -//--------------------------------------------------------------------------- - -static bool g_bPriorityNormal = true; - -// Make APPLEWIN process higher priority -void SetPriorityAboveNormal(void) -{ - if (!g_bPriorityNormal) - return; - - if ( SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS) ) - { - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); - g_bPriorityNormal = false; - } -} - -// Make APPLEWIN process normal priority -void SetPriorityNormal(void) -{ - if (g_bPriorityNormal) - return; - - if ( SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS) ) - { - SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); - g_bPriorityNormal = true; - } -} - -//--------------------------------------------------------------------------- - -void ContinueExecution(void) -{ - const double fUsecPerSec = 1.e6; -#if 1 - const UINT nExecutionPeriodUsec = 1000; // 1.0ms -// const UINT nExecutionPeriodUsec = 100; // 0.1ms - const double fExecutionPeriodClks = g_fCurrentCLK6502 * ((double)nExecutionPeriodUsec / fUsecPerSec); -#else - const double fExecutionPeriodClks = 1800.0; - const UINT nExecutionPeriodUsec = (UINT) (fUsecPerSec * (fExecutionPeriodClks / g_fCurrentCLK6502)); -#endif - - // - - bool bScrollLock_FullSpeed = sg_PropertySheet.GetScrollLockToggle() - ? g_bScrollLock_FullSpeed - : (GetKeyState(VK_SCROLL) < 0); - - g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) || - bScrollLock_FullSpeed || - (DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) ); - - if (g_bFullSpeed) - { - // Don't call Spkr_Mute() - will get speaker clicks - MB_Mute(); - SysClk_StopTimer(); -#ifdef USE_SPEECH_API - g_Speech.Reset(); // TODO: Put this on a timer (in emulated cycles)... otherwise CATALOG cuts out -#endif - - g_nCpuCyclesFeedback = 0; // For the case when this is a big -ve number - - // Switch to normal priority so that APPLEWIN process doesn't hog machine! - //. EG: No disk in Drive-1, and boot Apple: Windows will start to crawl! - SetPriorityNormal(); - } - else - { - // Don't call Spkr_Demute() - MB_Demute(); - SysClk_StartTimerUsec(nExecutionPeriodUsec); - - // Switch to higher priority, eg. for audio (BUG #015394) - SetPriorityAboveNormal(); - } - - // - - int nCyclesToExecute = (int) fExecutionPeriodClks + g_nCpuCyclesFeedback; - if (nCyclesToExecute < 0) - nCyclesToExecute = 0; - - DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute); - g_dwCyclesThisFrame += dwExecutedCycles; - - // - - cyclenum = dwExecutedCycles; - - DiskUpdatePosition(dwExecutedCycles); - JoyUpdatePosition(); - - SpkrUpdate(cyclenum); - sg_SSC.CommUpdate(cyclenum); - PrintUpdate(cyclenum); - - // - - const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; - - emulmsec_frac += dwExecutedCycles; - if (emulmsec_frac > CLKS_PER_MS) - { - emulmsec += emulmsec_frac / CLKS_PER_MS; - emulmsec_frac %= CLKS_PER_MS; - } - - // DETERMINE WHETHER THE SCREEN WAS UPDATED THIS CLOCKTICK - static BOOL anyupdates = 0; - VideoCheckPage(0); // force=0 - anyupdates |= VideoHasRefreshed(); // Only called from here. Returns & clears 'hasrefreshed' flag - - // - - if (g_dwCyclesThisFrame >= dwClksPerFrame) - { - g_dwCyclesThisFrame -= dwClksPerFrame; - VideoUpdateFlash(); - - static BOOL lastupdates[2] = {0,0}; - if (!anyupdates && !lastupdates[0] && !lastupdates[1] && VideoApparentlyDirty()) - { - VideoCheckPage(1); // force=1 - static DWORD lasttime = 0; - DWORD currtime = GetTickCount(); - if ((!g_bFullSpeed) || - (currtime-lasttime >= (DWORD)(g_bGraphicsMode ? 100 : 25))) - { - VideoRefreshScreen(); - lasttime = currtime; - } - } - - lastupdates[1] = lastupdates[0]; - lastupdates[0] = anyupdates; - anyupdates = 0; - - MB_EndOfVideoFrame(); - } - - // - - if (!g_bFullSpeed) - { - SysClk_WaitTimer(); - -#if DBG_CALC_FREQ - if (g_nPerfFreq) - { - QueryPerformanceCounter((LARGE_INTEGER*)&nTime1); - LONGLONG nTimeDiff = nTime1 - nTime0; - double fTime = (double)nTimeDiff / (double)(LONGLONG)g_nPerfFreq; - - g_fDbg[g_nIdx] = fTime; - g_nIdx = (g_nIdx+1) & (MAX_CNT-1); - g_fMeanPeriod = 0.0; - for(UINT n=0; n= A2TYPE_MAX) || (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE)) - dwComputerType = A2TYPE_APPLE2EENHANCED; - - g_Apple2Type = (eApple2Type) dwComputerType; - } - else // Support older AppleWin registry entries - { - REGLOAD(TEXT(REGVALUE_OLD_APPLE2_TYPE), &dwComputerType); - switch (dwComputerType) - { - // NB. No A2TYPE_APPLE2E (this is correct) - case 0: g_Apple2Type = A2TYPE_APPLE2; - case 1: g_Apple2Type = A2TYPE_APPLE2PLUS; - case 2: g_Apple2Type = A2TYPE_APPLE2EENHANCED; - default: g_Apple2Type = A2TYPE_APPLE2EENHANCED; - } - } - - switch (g_Apple2Type) //Sets the character set for the Apple model/clone - { - case A2TYPE_APPLE2: g_nCharsetType = 0; break; - case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break; - case A2TYPE_APPLE2E: g_nCharsetType = 0; break; - case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break; - case A2TYPE_PRAVETS82: g_nCharsetType = 1; break; - case A2TYPE_PRAVETS8A: g_nCharsetType = 2; break; - case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. - } - - // - - if (!REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &joytype[JN_JOYSTICK0])) - LoadConfigOldJoystick(JN_JOYSTICK0); - if (!REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &joytype[JN_JOYSTICK1])) - LoadConfigOldJoystick(JN_JOYSTICK1); - - REGLOAD(TEXT("Sound Emulation") ,&soundtype); - - char aySerialPortName[ CSuperSerialCard::SIZEOF_SERIALCHOICE_ITEM ]; - if (RegLoadString( TEXT("Configuration"), - TEXT(REGVALUE_SERIAL_PORT_NAME), - TRUE, - aySerialPortName, - sizeof(aySerialPortName) ) ) - { - sg_SSC.SetSerialPortName(aySerialPortName); - } - - REGLOAD(TEXT(REGVALUE_EMULATION_SPEED) ,&g_dwSpeed); - REGLOAD(TEXT(REGVALUE_ENHANCE_DISK_SPEED),(DWORD *)&enhancedisk); - - Config_Load_Video(); - - REGLOAD(TEXT("Uthernet Active") ,(DWORD *)&tfe_enabled); - - SetCurrentCLK6502(); - - // - - DWORD dwTmp; - - if(REGLOAD(TEXT(REGVALUE_THE_FREEZES_F8_ROM), &dwTmp)) - sg_PropertySheet.SetTheFreezesF8Rom(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp)) - SpkrSetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); - - if(REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp)) - MB_SetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); - - if(REGLOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp)) - g_bSaveStateOnExit = dwTmp ? true : false; - - - if(REGLOAD(TEXT(REGVALUE_DUMP_TO_PRINTER), &dwTmp)) - g_bDumpToPrinter = dwTmp ? true : false; - - if(REGLOAD(TEXT(REGVALUE_CONVERT_ENCODING), &dwTmp)) - g_bConvertEncoding = dwTmp ? true : false; - - if(REGLOAD(TEXT(REGVALUE_FILTER_UNPRINTABLE), &dwTmp)) - g_bFilterUnprintable = dwTmp ? true : false; - - if(REGLOAD(TEXT(REGVALUE_PRINTER_APPEND), &dwTmp)) - g_bPrinterAppend = dwTmp ? true : false; - - - if(REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) - HD_SetEnabled(dwTmp ? true : false); - - char szHDVPathname[MAX_PATH] = {0}; - if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_1), 1, szHDVPathname, sizeof(szHDVPathname))) - HD_InsertDisk(HARDDISK_1, szHDVPathname); - if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_2), 1, szHDVPathname, sizeof(szHDVPathname))) - HD_InsertDisk(HARDDISK_2, szHDVPathname); - - if(REGLOAD(TEXT(REGVALUE_PDL_XTRIM), &dwTmp)) - JoySetTrim((short)dwTmp, true); - if(REGLOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp)) - JoySetTrim((short)dwTmp, false); - - if(REGLOAD(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), &dwTmp)) - sg_PropertySheet.SetScrollLockToggle(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_CURSOR_CONTROL), &dwTmp)) - sg_PropertySheet.SetJoystickCursorControl(dwTmp); - if(REGLOAD(TEXT(REGVALUE_AUTOFIRE), &dwTmp)) - sg_PropertySheet.SetAutofire(dwTmp); - if(REGLOAD(TEXT(REGVALUE_CENTERING_CONTROL), &dwTmp)) - sg_PropertySheet.SetJoystickCenteringControl(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_MOUSE_CROSSHAIR), &dwTmp)) - sg_PropertySheet.SetMouseShowCrosshair(dwTmp); - if(REGLOAD(TEXT(REGVALUE_MOUSE_RESTRICT_TO_WINDOW), &dwTmp)) - sg_PropertySheet.SetMouseRestrictToWindow(dwTmp); - - if(REGLOAD(TEXT(REGVALUE_SLOT4), &dwTmp)) - g_Slot4 = (SS_CARDTYPE) dwTmp; - if(REGLOAD(TEXT(REGVALUE_SLOT5), &dwTmp)) - g_Slot5 = (SS_CARDTYPE) dwTmp; - - if (g_Slot4 == CT_MockingboardC || g_Slot4 == CT_Phasor) - MB_SetSoundcardType(g_Slot4); - else - MB_SetSoundcardType(CT_Empty); - - // - - char szFilename[MAX_PATH] = {0}; - - // Current/Starting Dir is the "root" of where the user keeps his disk images - RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szFilename, MAX_PATH); - if (szFilename[0] == 0) - GetCurrentDirectory(sizeof(szFilename), szFilename); - SetCurrentImageDir(szFilename); - - Disk_LoadLastDiskImage(DRIVE_1); - Disk_LoadLastDiskImage(DRIVE_2); - - // - - szFilename[0] = 0; - RegLoadString(TEXT(REG_CONFIG),TEXT(REGVALUE_SAVESTATE_FILENAME),1,szFilename,sizeof(szFilename)); - Snapshot_SetFilename(szFilename); // If not in Registry than default will be used (ie. g_sCurrentDir + default filename) - - szFilename[0] = 0; - RegLoadString(TEXT(REG_CONFIG),TEXT(REGVALUE_PRINTER_FILENAME),1,szFilename,sizeof(szFilename)); - Printer_SetFilename(szFilename); // If not in Registry than default will be used - - dwTmp = 10; - REGLOAD(TEXT(REGVALUE_PRINTER_IDLE_LIMIT), &dwTmp); - Printer_SetIdleLimit(dwTmp); - - char szUthernetInt[MAX_PATH] = {0}; - RegLoadString(TEXT(REG_CONFIG),TEXT("Uthernet Interface"),1,szUthernetInt,MAX_PATH); - update_tfe_interface(szUthernetInt,NULL); - - if (REGLOAD(TEXT(REGVALUE_WINDOW_SCALE), &dwTmp)) - SetViewportScale(dwTmp); -} - -//=========================================================================== - -void SetCurrentImageDir(const char* pszImageDir) -{ - strcpy(g_sCurrentDir, pszImageDir); - SetCurrentDirectory(g_sCurrentDir); -} - -//=========================================================================== - -// TODO: Added dialog option of which file extensions to registry -static bool g_bRegisterFileTypes = true; -//static bool g_bRegistryFileBin = false; -static bool g_bRegistryFileDo = true; -static bool g_bRegistryFileDsk = true; -static bool g_bRegistryFileNib = true; -static bool g_bRegistryFilePo = true; - - -void RegisterExtensions(void) -{ - TCHAR szCommandTmp[MAX_PATH]; - GetModuleFileName((HMODULE)0,szCommandTmp,MAX_PATH); - -#ifdef TEST_REG_BUG - TCHAR command[MAX_PATH]; - wsprintf(command, "%s", szCommandTmp); // Wrap path & filename in quotes & null terminate - - TCHAR icon[MAX_PATH]; - wsprintf(icon,TEXT("\"%s,1\""),(LPCTSTR)command); -#endif - - TCHAR command[MAX_PATH]; - wsprintf(command, "\"%s\"", szCommandTmp); // Wrap path & filename in quotes & null terminate - - TCHAR icon[MAX_PATH]; - wsprintf(icon,TEXT("%s,1"),(LPCTSTR)command); - - _tcscat(command,TEXT(" \"%1\"")); // Append "%1" -// _tcscat(command,TEXT("-d1 %1\"")); // Append "%1" -// sprintf(command, "\"%s\" \"-d1 %%1\"", szCommandTmp); // Wrap path & filename in quotes & null terminate - - // NB. Reflect extensions in DELREG.INF -// RegSetValue(HKEY_CLASSES_ROOT,".bin",REG_SZ,"DiskImage",10); // Removed as .bin is too generic - long Res = RegDeleteValue(HKEY_CLASSES_ROOT, ".bin"); // TODO: This isn't working :-/ - - RegSetValue(HKEY_CLASSES_ROOT,".do" ,REG_SZ,"DiskImage",10); - RegSetValue(HKEY_CLASSES_ROOT,".dsk",REG_SZ,"DiskImage",10); - RegSetValue(HKEY_CLASSES_ROOT,".nib",REG_SZ,"DiskImage",10); - RegSetValue(HKEY_CLASSES_ROOT,".po" ,REG_SZ,"DiskImage",10); -// RegSetValue(HKEY_CLASSES_ROOT,".2mg",REG_SZ,"DiskImage",10); // Don't grab this, as not all .2mg images are supported (so defer to CiderPress) -// RegSetValue(HKEY_CLASSES_ROOT,".2img",REG_SZ,"DiskImage",10); // Don't grab this, as not all .2mg images are supported (so defer to CiderPress) -// RegSetValue(HKEY_CLASSES_ROOT,".aws",REG_SZ,"DiskImage",10); // TO DO -// RegSetValue(HKEY_CLASSES_ROOT,".hdv",REG_SZ,"DiskImage",10); // TO DO - - RegSetValue(HKEY_CLASSES_ROOT, - "DiskImage", - REG_SZ,"Disk Image",21); - - RegSetValue(HKEY_CLASSES_ROOT, - "DiskImage\\DefaultIcon", - REG_SZ,icon,_tcslen(icon)+1); - -// This key can interfere.... -// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExt\.dsk - - RegSetValue(HKEY_CLASSES_ROOT, - "DiskImage\\shell\\open\\command", - REG_SZ,command,_tcslen(command)+1); - - RegSetValue(HKEY_CLASSES_ROOT, - "DiskImage\\shell\\open\\ddeexec", - REG_SZ,"%1",3); - - RegSetValue(HKEY_CLASSES_ROOT, - "DiskImage\\shell\\open\\ddeexec\\application", - REG_SZ,"applewin",_tcslen("applewin")+1); -// REG_SZ,szCommandTmp,_tcslen(szCommandTmp)+1); - - RegSetValue(HKEY_CLASSES_ROOT, - "DiskImage\\shell\\open\\ddeexec\\topic", - REG_SZ,"system",_tcslen("system")+1); -} - -//=========================================================================== -void AppleWin_RegisterHotKeys(void) -{ - BOOL bStatus = true; - - bStatus &= RegisterHotKey( - g_hFrameWindow , // HWND hWnd - VK_SNAPSHOT_560 , // int id (user/custom id) - 0 , // UINT fsModifiers - VK_SNAPSHOT // UINT vk = PrintScreen - ); - - bStatus &= RegisterHotKey( - g_hFrameWindow , // HWND hWnd - VK_SNAPSHOT_280, // int id (user/custom id) - MOD_SHIFT , // UINT fsModifiers - VK_SNAPSHOT // UINT vk = PrintScreen - ); - - if (!bStatus && g_bShowPrintScreenWarningDialog) - { - MessageBox( g_hFrameWindow, "Unable to capture PrintScreen key", "Warning", MB_OK ); - } -} - -//=========================================================================== - -LPSTR GetCurrArg(LPSTR lpCmdLine) -{ - if(*lpCmdLine == '\"') - lpCmdLine++; - - return lpCmdLine; -} - -LPSTR GetNextArg(LPSTR lpCmdLine) -{ - int bInQuotes = 0; - - while(*lpCmdLine) - { - if(*lpCmdLine == '\"') - { - bInQuotes ^= 1; - if(!bInQuotes) - { - *lpCmdLine++ = 0x00; // Assume end-quote is end of this arg - continue; - } - } - - if((*lpCmdLine == ' ') && !bInQuotes) - { - *lpCmdLine++ = 0x00; - break; - } - - lpCmdLine++; - } - - return lpCmdLine; -} - -//--------------------------------------------------------------------------- - -static int DoDiskInsert(const int nDrive, LPCSTR szFileName) -{ - string strPathName; - - if (szFileName[0] == '\\' || szFileName[1] == ':') - { - // Abs pathname - strPathName = szFileName; - } - else - { - // Rel pathname - char szCWD[_MAX_PATH] = {0}; - if (!GetCurrentDirectory(sizeof(szCWD), szCWD)) - return false; - - strPathName = szCWD; - strPathName.append("\\"); - strPathName.append(szFileName); - } - - ImageError_e Error = DiskInsert(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); - return Error == eIMAGE_ERROR_NONE; -} - -//--------------------------------------------------------------------------- - -int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) -{ - bool bSetFullScreen = false; - bool bBoot = false; - LPSTR szImageName_drive1 = NULL; - LPSTR szImageName_drive2 = NULL; - const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput - - while (*lpCmdLine) - { - LPSTR lpNextArg = GetNextArg(lpCmdLine); - - if (((strcmp(lpCmdLine, "-l") == 0) || (strcmp(lpCmdLine, "-log") == 0)) && (g_fh == NULL)) - { - g_fh = fopen("AppleWin.log", "a+t"); // Open log file (append & text mode) - setvbuf(g_fh, NULL, _IONBF, 0); // No buffering (so implicit fflush after every fprintf) - CHAR aDateStr[80], aTimeStr[80]; - GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aDateStr, sizeof(aDateStr)); - GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aTimeStr, sizeof(aTimeStr)); - fprintf(g_fh, "*** Logging started: %s %s\n", aDateStr, aTimeStr); - } - else if (strcmp(lpCmdLine, "-noreg") == 0) - { - g_bRegisterFileTypes = false; - } - else if (strcmp(lpCmdLine, "-d1") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - szImageName_drive1 = lpCmdLine; - } - else if (strcmp(lpCmdLine, "-d2") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - szImageName_drive2 = lpCmdLine; - } - else if (strcmp(lpCmdLine, "-f") == 0) - { - bSetFullScreen = true; - } - else if (strcmp(lpCmdLine, "-fs8bit") == 0) - { - SetFullScreen32Bit(false); // Support old v1.24 fullscreen 8-bit palette mode - } - else if (strcmp(lpCmdLine, "-no-di") == 0) - { - g_bDisableDirectInput = true; - } - else if (strcmp(lpCmdLine, "-m") == 0) - { - g_bDisableDirectSound = true; - } - else if (strcmp(lpCmdLine, "-no-mb") == 0) - { - g_bDisableDirectSoundMockingboard = true; - } - else if (strcmp(lpCmdLine, "-memclear") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_nMemoryClearType = atoi(lpCmdLine); - if (g_nMemoryClearType < 0) - g_nMemoryClearType = 0; - else - if (g_nMemoryClearType >= NUM_MIP) - g_nMemoryClearType = NUM_MIP - 1; - } -#ifdef RAMWORKS - else if (strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127] - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_uMaxExPages = atoi(lpCmdLine); - if (g_uMaxExPages > 127) - g_uMaxExPages = 128; - else if (g_uMaxExPages < 1) - g_uMaxExPages = 1; - } -#endif - else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF] - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - g_hCustomRomF8 = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); - if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800)) - g_bCustomRomF8Failed = true; - } - else if (strcmp(lpCmdLine, "-printscreen") == 0) // Turn on display of the last filename print screen was saved to - { - g_bDisplayPrintScreenFileName = true; - } - else if (strcmp(lpCmdLine, "-no-printscreen-dlg") == 0) // Turn off the PrintScreen warning message dialog (if PrintScreen key can't be grabbed) - { - g_bShowPrintScreenWarningDialog = false; - } - else if (strcmp(lpCmdLine, "-spkr-inc") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - const int nErrorInc = atoi(lpCmdLine); - SoundCore_SetErrorInc( nErrorInc ); - } - else if (strcmp(lpCmdLine, "-spkr-max") == 0) - { - lpCmdLine = GetCurrArg(lpNextArg); - lpNextArg = GetNextArg(lpNextArg); - const int nErrorMax = atoi(lpCmdLine); - SoundCore_SetErrorMax( nErrorMax ); - } - else if (strcmp(lpCmdLine, "-use-real-printer") == 0) // Enable control in Advanced config to allow dumping to a real printer - { - g_bEnableDumpToRealPrinter = true; - } - else if (strcmp(lpCmdLine, "-speech") == 0) - { - g_bEnableSpeech = true; - } - else if (strcmp(lpCmdLine, "-multimon") == 0) - { - g_bMultiMon = true; - } - else // unsupported - { - LogFileOutput("Unsupported arg: %s\n", lpCmdLine); - } - - lpCmdLine = lpNextArg; - } - - LogFileOutput("CmdLine: %s\n", strCmdLine.c_str()); - -#if 0 -#ifdef RIFF_SPKR - RiffInitWriteFile("Spkr.wav", SPKR_SAMPLE_RATE, 1); -#endif -#ifdef RIFF_MB - RiffInitWriteFile("Mockingboard.wav", 44100, 2); -#endif -#endif - - //----- - - char szPath[_MAX_PATH]; - - if (0 == GetModuleFileName(NULL, szPath, sizeof(szPath))) - { - strcpy(szPath, __argv[0]); - } - - // Extract application version and store in a global variable - DWORD dwHandle, dwVerInfoSize; - - dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwHandle); - - if (dwVerInfoSize > 0) - { - char* pVerInfoBlock = new char[dwVerInfoSize]; - - if (GetFileVersionInfo(szPath, NULL, dwVerInfoSize, pVerInfoBlock)) - { - VS_FIXEDFILEINFO* pFixedFileInfo; - UINT pFixedFileInfoLen; - - VerQueryValue(pVerInfoBlock, TEXT("\\"), (LPVOID*) &pFixedFileInfo, (PUINT) &pFixedFileInfoLen); - - // Construct version string from fixed file info block - - unsigned long major = pFixedFileInfo->dwFileVersionMS >> 16; - unsigned long minor = pFixedFileInfo->dwFileVersionMS & 0xffff; - unsigned long fix = pFixedFileInfo->dwFileVersionLS >> 16; - unsigned long fix_minor = pFixedFileInfo->dwFileVersionLS & 0xffff; - sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor); // potential buffer overflow - } - } - - LogFileOutput("AppleWin version: %s\n", VERSIONSTRING); - -#if DBG_CALC_FREQ - QueryPerformanceFrequency((LARGE_INTEGER*)&g_nPerfFreq); - if(g_fh) fprintf(g_fh, "Performance frequency = %d\n",g_nPerfFreq); -#endif - - //----- - - // Initialize COM - so we can use CoCreateInstance - // . NB. DSInit() & DIMouse::DirectInputInit are done when g_hFrameWindow is created (WM_CREATE) - HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - LogFileOutput("Init: CoInitializeEx(), hr=0x%08X\n", hr); - - const bool bSysClkOK = SysClk_InitTimer(); - LogFileOutput("Init: SysClk_InitTimer(), res=%d\n", bSysClkOK ? 1:0); -#ifdef USE_SPEECH_API - if (g_bEnableSpeech) - { - const bool bSpeechOK = g_Speech.Init(); - LogFileOutput("Init: SysClk_InitTimer(), res=%d\n", bSpeechOK ? 1:0); - } -#endif - - // DO ONE-TIME INITIALIZATION - g_hInstance = passinstance; - GdiSetBatchLimit(512); - LogFileOutput("Init: GdiSetBatchLimit()\n"); - - GetProgramDirectory(); - LogFileOutput("Init: GetProgramDirectory()\n"); - - if (g_bRegisterFileTypes) - { - RegisterExtensions(); - LogFileOutput("Init: RegisterExtensions()\n"); - } - - FrameRegisterClass(); - LogFileOutput("Init: FrameRegisterClass()\n"); - - ImageInitialize(); - LogFileOutput("Init: ImageInitialize()\n"); - - DiskInitialize(); - LogFileOutput("Init: DiskInitialize()\n"); - - CreateColorMixMap(); // For tv emulation mode - LogFileOutput("Init: CreateColorMixMap()\n"); - - int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error - if (szImageName_drive1) - { - nError = DoDiskInsert(DRIVE_1, szImageName_drive1); - LogFileOutput("Init: DoDiskInsert(D1), res=%d\n", nError); - FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); - bBoot = true; - } - if (szImageName_drive2) - { - nError |= DoDiskInsert(DRIVE_2, szImageName_drive2); - LogFileOutput("Init: DoDiskInsert(D2), res=%d\n", nError); - } - - // - - do - { - // DO INITIALIZATION THAT MUST BE REPEATED FOR A RESTART - restart = 0; - ResetToLogoMode(); - - LoadConfiguration(); - LogFileOutput("Main: LoadConfiguration()\n"); - - DebugInitialize(); - LogFileOutput("Main: DebugInitialize()\n"); - - JoyInitialize(); - LogFileOutput("Main: JoyInitialize()\n"); - - MemInitialize(); - LogFileOutput("Main: MemInitialize()\n"); - - VideoInitialize(); // g_pFramebufferinfo been created now - LogFileOutput("Main: VideoInitialize()\n"); - - LogFileOutput("Main: FrameCreateWindow() - pre\n"); - FrameCreateWindow(); // g_hFrameWindow is now valid - LogFileOutput("Main: FrameCreateWindow() - post\n"); - - char szOldAppleWinVersion[sizeof(VERSIONSTRING)] = {0}; - RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, szOldAppleWinVersion, sizeof(szOldAppleWinVersion)); - - const bool bShowAboutDlg = strcmp(szOldAppleWinVersion, VERSIONSTRING) != 0; - if (bShowAboutDlg) - { - if (!AboutDlg()) - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down - else - RegSaveString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, VERSIONSTRING); // Only save version after user accepts license - } - - // PrintScrn support - AppleWin_RegisterHotKeys(); // needs valid g_hFrameWindow - LogFileOutput("Main: AppleWin_RegisterHotKeys()\n"); - - // Need to test if it's safe to call ResetMachineState(). In the meantime, just call DiskReset(): - DiskReset(); // Switch from a booting A][+ to a non-autostart A][, so need to turn off floppy motor - LogFileOutput("Main: DiskReset()\n"); - - if (!bSysClkOK) - { - MessageBox(g_hFrameWindow, "DirectX failed to create SystemClock instance", TEXT("AppleWin Error"), MB_OK); - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down - } - - if (g_bCustomRomF8Failed) - { - MessageBox(g_hFrameWindow, "Failed to load custom F8 rom (not found or not exactly 2KB)", TEXT("AppleWin Error"), MB_OK); - PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down - } - - tfe_init(); - LogFileOutput("Main: tfe_init()\n"); - - Snapshot_Startup(); // Do this after everything has been init'ed - LogFileOutput("Main: Snapshot_Startup()\n"); - - if (bSetFullScreen) - { - PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); - bSetFullScreen = false; - } - - if (bBoot) - { - PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); - bBoot = false; - } - - // ENTER THE MAIN MESSAGE LOOP - LogFileOutput("Main: EnterMessageLoop()\n"); - EnterMessageLoop(); - LogFileOutput("Main: LeaveMessageLoop()\n"); - - MB_Reset(); - LogFileOutput("Main: MB_Reset()\n"); - - sg_Mouse.Uninitialize(); // Maybe restarting due to switching slot-4 card from MouseCard to Mockingboard - LogFileOutput("Main: sg_Mouse.Uninitialize()\n"); - } - while (restart); - - // Release COM - DSUninit(); - LogFileOutput("Exit: DSUninit()\n"); - - SysClk_UninitTimer(); - LogFileOutput("Exit: SysClk_UninitTimer()\n"); - - CoUninitialize(); - LogFileOutput("Exit: CoUninitialize()\n"); - - tfe_shutdown(); - LogFileOutput("Exit: tfe_shutdown()\n"); - - if (g_fh) - { - fprintf(g_fh,"*** Logging ended\n\n"); - fclose(g_fh); - g_fh = NULL; - } - - RiffFinishWriteFile(); - - if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) - CloseHandle(g_hCustomRomF8); - - return 0; -} +/* +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-2009, 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 +*/ + +/* Description: main + * + * Author: Various + */ + +#include "StdAfx.h" +#include "DiskImage.h" +#include "Harddisk.h" + +#include "MouseInterface.h" +#ifdef USE_SPEECH_API +#include "Speech.h" +#endif +#include "Configuration\About.h" +#include "Configuration\PropertySheet.h" +#include "Tfe\Tfe.h" + +char VERSIONSTRING[16] = "xx.yy.zz.ww"; + +TCHAR *g_pAppTitle = TITLE_APPLE_2E_ENHANCED; + +eApple2Type g_Apple2Type = A2TYPE_APPLE2EENHANCED; + +DWORD cumulativecycles = 0; // Wraps after ~1hr 9mins +DWORD cyclenum = 0; // Used by SpkrToggle() for non-wave sound +DWORD emulmsec = 0; +static DWORD emulmsec_frac = 0; +bool g_bFullSpeed = false; + +//Pravets 8A/C variables +bool P8CAPS_ON = false; +bool P8Shift = false; +//================================================= + +// Win32 +HINSTANCE g_hInstance = (HINSTANCE)0; + +AppMode_e g_nAppMode = MODE_LOGO; +static bool g_bLoadedSaveState = false; + +static int lastmode = MODE_LOGO; +TCHAR g_sProgramDir[MAX_PATH] = TEXT(""); // Directory of where AppleWin executable resides +TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used +TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used +TCHAR g_sCurrentDir[MAX_PATH] = TEXT(""); // Also Starting Dir. Debugger uses this when load/save +BOOL restart = 0; + +DWORD g_dwSpeed = SPEED_NORMAL; // Affected by Config dialog's speed slider bar +double g_fCurrentCLK6502 = CLK_6502; // Affected by Config dialog's speed slider bar +static double g_fMHz = 1.0; // Affected by Config dialog's speed slider bar + +int g_nCpuCyclesFeedback = 0; +DWORD g_dwCyclesThisFrame = 0; +INT64 g_nCyclesTotal = 0; + +FILE* g_fh = NULL; +bool g_bDisableDirectInput = false; +bool g_bDisableDirectSound = false; +bool g_bDisableDirectSoundMockingboard = false; +int g_nMemoryClearType = -1; + +IPropertySheet& sg_PropertySheet = * new CPropertySheet; +CSuperSerialCard sg_SSC; +CMouseInterface sg_Mouse; + +SS_CARDTYPE g_Slot4 = CT_Empty; +SS_CARDTYPE g_Slot5 = CT_Empty; + +eCPU g_ActiveCPU = CPU_6502; + +HANDLE g_hCustomRomF8 = INVALID_HANDLE_VALUE; // Cmd-line specified custom ROM at $F800..$FFFF +static bool g_bCustomRomF8Failed = false; // Set if custom ROM file failed + +static bool g_bEnableSpeech = false; +#ifdef USE_SPEECH_API +CSpeech g_Speech; +#endif + +//=========================================================================== + +#define DBG_CALC_FREQ 0 +#if DBG_CALC_FREQ +const UINT MAX_CNT = 256; +double g_fDbg[MAX_CNT]; +UINT g_nIdx = 0; +double g_fMeanPeriod,g_fMeanFreq; +ULONGLONG g_nPerfFreq = 0; +#endif + +//--------------------------------------------------------------------------- + +bool GetLoadedSaveStateFlag(void) +{ + return g_bLoadedSaveState; +} + +void SetLoadedSaveStateFlag(const bool bFlag) +{ + g_bLoadedSaveState = bFlag; +} + +static void ResetToLogoMode(void) +{ + g_nAppMode = MODE_LOGO; + SetLoadedSaveStateFlag(false); +} + +//--------------------------------------------------------------------------- + +static bool g_bPriorityNormal = true; + +// Make APPLEWIN process higher priority +void SetPriorityAboveNormal(void) +{ + if (!g_bPriorityNormal) + return; + + if ( SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS) ) + { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL); + g_bPriorityNormal = false; + } +} + +// Make APPLEWIN process normal priority +void SetPriorityNormal(void) +{ + if (g_bPriorityNormal) + return; + + if ( SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS) ) + { + SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); + g_bPriorityNormal = true; + } +} + +//--------------------------------------------------------------------------- + +void ContinueExecution(void) +{ + const double fUsecPerSec = 1.e6; +#if 1 + const UINT nExecutionPeriodUsec = 1000; // 1.0ms +// const UINT nExecutionPeriodUsec = 100; // 0.1ms + const double fExecutionPeriodClks = g_fCurrentCLK6502 * ((double)nExecutionPeriodUsec / fUsecPerSec); +#else + const double fExecutionPeriodClks = 1800.0; + const UINT nExecutionPeriodUsec = (UINT) (fUsecPerSec * (fExecutionPeriodClks / g_fCurrentCLK6502)); +#endif + + // + + bool bScrollLock_FullSpeed = sg_PropertySheet.GetScrollLockToggle() + ? g_bScrollLock_FullSpeed + : (GetKeyState(VK_SCROLL) < 0); + + g_bFullSpeed = ( (g_dwSpeed == SPEED_MAX) || + bScrollLock_FullSpeed || + (DiskIsSpinning() && enhancedisk && !Spkr_IsActive() && !MB_IsActive()) ); + + if (g_bFullSpeed) + { + // Don't call Spkr_Mute() - will get speaker clicks + MB_Mute(); + SysClk_StopTimer(); +#ifdef USE_SPEECH_API + g_Speech.Reset(); // TODO: Put this on a timer (in emulated cycles)... otherwise CATALOG cuts out +#endif + + g_nCpuCyclesFeedback = 0; // For the case when this is a big -ve number + + // Switch to normal priority so that APPLEWIN process doesn't hog machine! + //. EG: No disk in Drive-1, and boot Apple: Windows will start to crawl! + SetPriorityNormal(); + } + else + { + // Don't call Spkr_Demute() + MB_Demute(); + SysClk_StartTimerUsec(nExecutionPeriodUsec); + + // Switch to higher priority, eg. for audio (BUG #015394) + SetPriorityAboveNormal(); + } + + // + + int nCyclesToExecute = (int) fExecutionPeriodClks + g_nCpuCyclesFeedback; + if (nCyclesToExecute < 0) + nCyclesToExecute = 0; + + DWORD dwExecutedCycles = CpuExecute(nCyclesToExecute); + g_dwCyclesThisFrame += dwExecutedCycles; + + // + + cyclenum = dwExecutedCycles; + + DiskUpdatePosition(dwExecutedCycles); + JoyUpdatePosition(); + + SpkrUpdate(cyclenum); + sg_SSC.CommUpdate(cyclenum); + PrintUpdate(cyclenum); + TcpIpJoystickUpdate(); + + // + + const DWORD CLKS_PER_MS = (DWORD)g_fCurrentCLK6502 / 1000; + + emulmsec_frac += dwExecutedCycles; + if (emulmsec_frac > CLKS_PER_MS) + { + emulmsec += emulmsec_frac / CLKS_PER_MS; + emulmsec_frac %= CLKS_PER_MS; + } + + // DETERMINE WHETHER THE SCREEN WAS UPDATED THIS CLOCKTICK + static BOOL anyupdates = 0; + VideoCheckPage(0); // force=0 + anyupdates |= VideoHasRefreshed(); // Only called from here. Returns & clears 'hasrefreshed' flag + + // + + if (g_dwCyclesThisFrame >= dwClksPerFrame) + { + g_dwCyclesThisFrame -= dwClksPerFrame; + g_nCyclesTotal += dwClksPerFrame; + VideoUpdateFlash(); + + static BOOL lastupdates[2] = {0,0}; + if (!anyupdates && !lastupdates[0] && !lastupdates[1] && VideoApparentlyDirty()) + { + VideoCheckPage(1); // force=1 + static DWORD lasttime = 0; + DWORD currtime = GetTickCount(); + if ((!g_bFullSpeed) || + (currtime-lasttime >= (DWORD)(g_bGraphicsMode ? 100 : 25))) + { + VideoRefreshScreen(); + lasttime = currtime; + } + } + + lastupdates[1] = lastupdates[0]; + lastupdates[0] = anyupdates; + anyupdates = 0; + + MB_EndOfVideoFrame(); + } + + // + + if (!g_bFullSpeed) + { + SysClk_WaitTimer(); + +#if DBG_CALC_FREQ + if (g_nPerfFreq) + { + QueryPerformanceCounter((LARGE_INTEGER*)&nTime1); + LONGLONG nTimeDiff = nTime1 - nTime0; + double fTime = (double)nTimeDiff / (double)(LONGLONG)g_nPerfFreq; + + g_fDbg[g_nIdx] = fTime; + g_nIdx = (g_nIdx+1) & (MAX_CNT-1); + g_fMeanPeriod = 0.0; + for(UINT n=0; n= A2TYPE_MAX) || (dwComputerType >= A2TYPE_UNDEFINED && dwComputerType < A2TYPE_CLONE)) + dwComputerType = A2TYPE_APPLE2EENHANCED; + + g_Apple2Type = (eApple2Type) dwComputerType; + } + else // Support older AppleWin registry entries + { + REGLOAD(TEXT(REGVALUE_OLD_APPLE2_TYPE), &dwComputerType); + switch (dwComputerType) + { + // NB. No A2TYPE_APPLE2E (this is correct) + case 0: g_Apple2Type = A2TYPE_APPLE2; + case 1: g_Apple2Type = A2TYPE_APPLE2PLUS; + case 2: g_Apple2Type = A2TYPE_APPLE2EENHANCED; + default: g_Apple2Type = A2TYPE_APPLE2EENHANCED; + } + } + + switch (g_Apple2Type) //Sets the character set for the Apple model/clone + { + case A2TYPE_APPLE2: g_nCharsetType = 0; break; + case A2TYPE_APPLE2PLUS: g_nCharsetType = 0; break; + case A2TYPE_APPLE2E: g_nCharsetType = 0; break; + case A2TYPE_APPLE2EENHANCED:g_nCharsetType = 0; break; + case A2TYPE_PRAVETS82: g_nCharsetType = 1; break; + case A2TYPE_PRAVETS8A: g_nCharsetType = 2; break; + case A2TYPE_PRAVETS8M: g_nCharsetType = 3; break; //This charset has a very small difference with the PRAVETS82 one an probably has some misplaced characters. Still the Pravets82 charset is used, because setting charset to 3 results in some problems. + } + + // + + if (!REGLOAD(TEXT(REGVALUE_JOYSTICK0_EMU_TYPE), &joytype[JN_JOYSTICK0])) + LoadConfigOldJoystick(JN_JOYSTICK0); + if (!REGLOAD(TEXT(REGVALUE_JOYSTICK1_EMU_TYPE), &joytype[JN_JOYSTICK1])) + LoadConfigOldJoystick(JN_JOYSTICK1); + + REGLOAD(TEXT("Sound Emulation") ,&soundtype); + + char aySerialPortName[ CSuperSerialCard::SIZEOF_SERIALCHOICE_ITEM ]; + if (RegLoadString( TEXT("Configuration"), + TEXT(REGVALUE_SERIAL_PORT_NAME), + TRUE, + aySerialPortName, + sizeof(aySerialPortName) ) ) + { + sg_SSC.SetSerialPortName(aySerialPortName); + } + + REGLOAD(TEXT(REGVALUE_EMULATION_SPEED) ,&g_dwSpeed); + REGLOAD(TEXT(REGVALUE_ENHANCE_DISK_SPEED),(DWORD *)&enhancedisk); + + Config_Load_Video(); + + REGLOAD(TEXT("Uthernet Active") ,(DWORD *)&tfe_enabled); + + SetCurrentCLK6502(); + + // + + DWORD dwTmp; + + if(REGLOAD(TEXT(REGVALUE_THE_FREEZES_F8_ROM), &dwTmp)) + sg_PropertySheet.SetTheFreezesF8Rom(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_SPKR_VOLUME), &dwTmp)) + SpkrSetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); + + if(REGLOAD(TEXT(REGVALUE_MB_VOLUME), &dwTmp)) + MB_SetVolume(dwTmp, sg_PropertySheet.GetVolumeMax()); + + if(REGLOAD(TEXT(REGVALUE_SAVE_STATE_ON_EXIT), &dwTmp)) + g_bSaveStateOnExit = dwTmp ? true : false; + + + if(REGLOAD(TEXT(REGVALUE_DUMP_TO_PRINTER), &dwTmp)) + g_bDumpToPrinter = dwTmp ? true : false; + + if(REGLOAD(TEXT(REGVALUE_CONVERT_ENCODING), &dwTmp)) + g_bConvertEncoding = dwTmp ? true : false; + + if(REGLOAD(TEXT(REGVALUE_FILTER_UNPRINTABLE), &dwTmp)) + g_bFilterUnprintable = dwTmp ? true : false; + + if(REGLOAD(TEXT(REGVALUE_PRINTER_APPEND), &dwTmp)) + g_bPrinterAppend = dwTmp ? true : false; + + + if(REGLOAD(TEXT(REGVALUE_HDD_ENABLED), &dwTmp)) + HD_SetEnabled(dwTmp ? true : false); + + char szHDVPathname[MAX_PATH] = {0}; + if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_1), 1, szHDVPathname, sizeof(szHDVPathname))) + HD_InsertDisk(HARDDISK_1, szHDVPathname); + if(RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_LAST_HARDDISK_2), 1, szHDVPathname, sizeof(szHDVPathname))) + HD_InsertDisk(HARDDISK_2, szHDVPathname); + + if(REGLOAD(TEXT(REGVALUE_PDL_XTRIM), &dwTmp)) + JoySetTrim((short)dwTmp, true); + if(REGLOAD(TEXT(REGVALUE_PDL_YTRIM), &dwTmp)) + JoySetTrim((short)dwTmp, false); + + if(REGLOAD(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), &dwTmp)) + sg_PropertySheet.SetScrollLockToggle(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_CURSOR_CONTROL), &dwTmp)) + sg_PropertySheet.SetJoystickCursorControl(dwTmp); + if (REGLOAD(TEXT(REGVALUE_TCPIPJOYSTICK), &dwTmp)) + sg_PropertySheet.SetTcpIpJoystock(dwTmp); + if (REGLOAD(TEXT(REGVALUE_AUTOFIRE), &dwTmp)) + sg_PropertySheet.SetAutofire(dwTmp); + if(REGLOAD(TEXT(REGVALUE_CENTERING_CONTROL), &dwTmp)) + sg_PropertySheet.SetJoystickCenteringControl(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_MOUSE_CROSSHAIR), &dwTmp)) + sg_PropertySheet.SetMouseShowCrosshair(dwTmp); + if(REGLOAD(TEXT(REGVALUE_MOUSE_RESTRICT_TO_WINDOW), &dwTmp)) + sg_PropertySheet.SetMouseRestrictToWindow(dwTmp); + + if(REGLOAD(TEXT(REGVALUE_SLOT4), &dwTmp)) + g_Slot4 = (SS_CARDTYPE) dwTmp; + if(REGLOAD(TEXT(REGVALUE_SLOT5), &dwTmp)) + g_Slot5 = (SS_CARDTYPE) dwTmp; + + if (g_Slot4 == CT_MockingboardC || g_Slot4 == CT_Phasor) + MB_SetSoundcardType(g_Slot4); + else + MB_SetSoundcardType(CT_Empty); + + // + + char szFilename[MAX_PATH] = {0}; + + // Current/Starting Dir is the "root" of where the user keeps his disk images + RegLoadString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, szFilename, MAX_PATH); + if (szFilename[0] == 0) + GetCurrentDirectory(sizeof(szFilename), szFilename); + SetCurrentImageDir(szFilename); + + Disk_LoadLastDiskImage(DRIVE_1); + Disk_LoadLastDiskImage(DRIVE_2); + + // + + szFilename[0] = 0; + RegLoadString(TEXT(REG_CONFIG),TEXT(REGVALUE_SAVESTATE_FILENAME),1,szFilename,sizeof(szFilename)); + Snapshot_SetFilename(szFilename); // If not in Registry than default will be used (ie. g_sCurrentDir + default filename) + + szFilename[0] = 0; + RegLoadString(TEXT(REG_CONFIG),TEXT(REGVALUE_PRINTER_FILENAME),1,szFilename,sizeof(szFilename)); + Printer_SetFilename(szFilename); // If not in Registry than default will be used + + dwTmp = 10; + REGLOAD(TEXT(REGVALUE_PRINTER_IDLE_LIMIT), &dwTmp); + Printer_SetIdleLimit(dwTmp); + + char szUthernetInt[MAX_PATH] = {0}; + RegLoadString(TEXT(REG_CONFIG),TEXT("Uthernet Interface"),1,szUthernetInt,MAX_PATH); + update_tfe_interface(szUthernetInt,NULL); + + if (REGLOAD(TEXT(REGVALUE_WINDOW_SCALE), &dwTmp)) + SetViewportScale(dwTmp); +} + +//=========================================================================== + +void SetCurrentImageDir(const char* pszImageDir) +{ + strcpy(g_sCurrentDir, pszImageDir); + SetCurrentDirectory(g_sCurrentDir); +} + +//=========================================================================== + +// TODO: Added dialog option of which file extensions to registry +static bool g_bRegisterFileTypes = true; +//static bool g_bRegistryFileBin = false; +static bool g_bRegistryFileDo = true; +static bool g_bRegistryFileDsk = true; +static bool g_bRegistryFileNib = true; +static bool g_bRegistryFilePo = true; + + +void RegisterExtensions(void) +{ + TCHAR szCommandTmp[MAX_PATH]; + GetModuleFileName((HMODULE)0,szCommandTmp,MAX_PATH); + +#ifdef TEST_REG_BUG + TCHAR command[MAX_PATH]; + wsprintf(command, "%s", szCommandTmp); // Wrap path & filename in quotes & null terminate + + TCHAR icon[MAX_PATH]; + wsprintf(icon,TEXT("\"%s,1\""),(LPCTSTR)command); +#endif + + TCHAR command[MAX_PATH]; + wsprintf(command, "\"%s\"", szCommandTmp); // Wrap path & filename in quotes & null terminate + + TCHAR icon[MAX_PATH]; + wsprintf(icon,TEXT("%s,1"),(LPCTSTR)command); + + _tcscat(command,TEXT(" \"%1\"")); // Append "%1" +// _tcscat(command,TEXT("-d1 %1\"")); // Append "%1" +// sprintf(command, "\"%s\" \"-d1 %%1\"", szCommandTmp); // Wrap path & filename in quotes & null terminate + + // NB. Reflect extensions in DELREG.INF +// RegSetValue(HKEY_CLASSES_ROOT,".bin",REG_SZ,"DiskImage",10); // Removed as .bin is too generic + long Res = RegDeleteValue(HKEY_CLASSES_ROOT, ".bin"); // TODO: This isn't working :-/ + + RegSetValue(HKEY_CLASSES_ROOT,".do" ,REG_SZ,"DiskImage",10); + RegSetValue(HKEY_CLASSES_ROOT,".dsk",REG_SZ,"DiskImage",10); + RegSetValue(HKEY_CLASSES_ROOT,".nib",REG_SZ,"DiskImage",10); + RegSetValue(HKEY_CLASSES_ROOT,".po" ,REG_SZ,"DiskImage",10); +// RegSetValue(HKEY_CLASSES_ROOT,".2mg",REG_SZ,"DiskImage",10); // Don't grab this, as not all .2mg images are supported (so defer to CiderPress) +// RegSetValue(HKEY_CLASSES_ROOT,".2img",REG_SZ,"DiskImage",10); // Don't grab this, as not all .2mg images are supported (so defer to CiderPress) +// RegSetValue(HKEY_CLASSES_ROOT,".aws",REG_SZ,"DiskImage",10); // TO DO +// RegSetValue(HKEY_CLASSES_ROOT,".hdv",REG_SZ,"DiskImage",10); // TO DO + + RegSetValue(HKEY_CLASSES_ROOT, + "DiskImage", + REG_SZ,"Disk Image",21); + + RegSetValue(HKEY_CLASSES_ROOT, + "DiskImage\\DefaultIcon", + REG_SZ,icon,_tcslen(icon)+1); + +// This key can interfere.... +// HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExt\.dsk + + RegSetValue(HKEY_CLASSES_ROOT, + "DiskImage\\shell\\open\\command", + REG_SZ,command,_tcslen(command)+1); + + RegSetValue(HKEY_CLASSES_ROOT, + "DiskImage\\shell\\open\\ddeexec", + REG_SZ,"%1",3); + + RegSetValue(HKEY_CLASSES_ROOT, + "DiskImage\\shell\\open\\ddeexec\\application", + REG_SZ,"applewin",_tcslen("applewin")+1); +// REG_SZ,szCommandTmp,_tcslen(szCommandTmp)+1); + + RegSetValue(HKEY_CLASSES_ROOT, + "DiskImage\\shell\\open\\ddeexec\\topic", + REG_SZ,"system",_tcslen("system")+1); +} + +//=========================================================================== +void AppleWin_RegisterHotKeys(void) +{ + BOOL bStatus = true; + + bStatus &= RegisterHotKey( + g_hFrameWindow , // HWND hWnd + VK_SNAPSHOT_560 , // int id (user/custom id) + 0 , // UINT fsModifiers + VK_SNAPSHOT // UINT vk = PrintScreen + ); + + bStatus &= RegisterHotKey( + g_hFrameWindow , // HWND hWnd + VK_SNAPSHOT_280, // int id (user/custom id) + MOD_SHIFT , // UINT fsModifiers + VK_SNAPSHOT // UINT vk = PrintScreen + ); + + if (!bStatus && g_bShowPrintScreenWarningDialog) + { + MessageBox( g_hFrameWindow, "Unable to capture PrintScreen key", "Warning", MB_OK ); + } +} + +//=========================================================================== + +LPSTR GetCurrArg(LPSTR lpCmdLine) +{ + if(*lpCmdLine == '\"') + lpCmdLine++; + + return lpCmdLine; +} + +LPSTR GetNextArg(LPSTR lpCmdLine) +{ + int bInQuotes = 0; + + while(*lpCmdLine) + { + if(*lpCmdLine == '\"') + { + bInQuotes ^= 1; + if(!bInQuotes) + { + *lpCmdLine++ = 0x00; // Assume end-quote is end of this arg + continue; + } + } + + if((*lpCmdLine == ' ') && !bInQuotes) + { + *lpCmdLine++ = 0x00; + break; + } + + lpCmdLine++; + } + + return lpCmdLine; +} + +//--------------------------------------------------------------------------- + +static int DoDiskInsert(const int nDrive, LPCSTR szFileName) +{ + string strPathName; + + if (szFileName[0] == '\\' || szFileName[1] == ':') + { + // Abs pathname + strPathName = szFileName; + } + else + { + // Rel pathname + char szCWD[_MAX_PATH] = {0}; + if (!GetCurrentDirectory(sizeof(szCWD), szCWD)) + return false; + + strPathName = szCWD; + strPathName.append("\\"); + strPathName.append(szFileName); + } + + ImageError_e Error = DiskInsert(nDrive, strPathName.c_str(), IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); + return Error == eIMAGE_ERROR_NONE; +} + +//--------------------------------------------------------------------------- + +int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) +{ + bool bSetFullScreen = false; + bool bBoot = false; + LPSTR szImageName_drive1 = NULL; + LPSTR szImageName_drive2 = NULL; + const std::string strCmdLine(lpCmdLine); // Keep a copy for log ouput + + while (*lpCmdLine) + { + LPSTR lpNextArg = GetNextArg(lpCmdLine); + + if (((strcmp(lpCmdLine, "-l") == 0) || (strcmp(lpCmdLine, "-log") == 0)) && (g_fh == NULL)) + { + g_fh = fopen("AppleWin.log", "a+t"); // Open log file (append & text mode) + setvbuf(g_fh, NULL, _IONBF, 0); // No buffering (so implicit fflush after every fprintf) + CHAR aDateStr[80], aTimeStr[80]; + GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aDateStr, sizeof(aDateStr)); + GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, (LPTSTR)aTimeStr, sizeof(aTimeStr)); + fprintf(g_fh, "*** Logging started: %s %s\n", aDateStr, aTimeStr); + } + else if (strcmp(lpCmdLine, "-noreg") == 0) + { + g_bRegisterFileTypes = false; + } + else if (strcmp(lpCmdLine, "-d1") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + szImageName_drive1 = lpCmdLine; + } + else if (strcmp(lpCmdLine, "-d2") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + szImageName_drive2 = lpCmdLine; + } + else if (strcmp(lpCmdLine, "-f") == 0) + { + bSetFullScreen = true; + } + else if (strcmp(lpCmdLine, "-fs8bit") == 0) + { + SetFullScreen32Bit(false); // Support old v1.24 fullscreen 8-bit palette mode + } + else if (strcmp(lpCmdLine, "-no-di") == 0) + { + g_bDisableDirectInput = true; + } + else if (strcmp(lpCmdLine, "-m") == 0) + { + g_bDisableDirectSound = true; + } + else if (strcmp(lpCmdLine, "-no-mb") == 0) + { + g_bDisableDirectSoundMockingboard = true; + } + else if (strcmp(lpCmdLine, "-memclear") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_nMemoryClearType = atoi(lpCmdLine); + if (g_nMemoryClearType < 0) + g_nMemoryClearType = 0; + else + if (g_nMemoryClearType >= NUM_MIP) + g_nMemoryClearType = NUM_MIP - 1; + } +#ifdef RAMWORKS + else if (strcmp(lpCmdLine, "-r") == 0) // RamWorks size [1..127] + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_uMaxExPages = atoi(lpCmdLine); + if (g_uMaxExPages > 127) + g_uMaxExPages = 128; + else if (g_uMaxExPages < 1) + g_uMaxExPages = 1; + } +#endif + else if (strcmp(lpCmdLine, "-f8rom") == 0) // Use custom 2K ROM at [$F800..$FFFF] + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + g_hCustomRomF8 = CreateFile(lpCmdLine, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL); + if ((g_hCustomRomF8 == INVALID_HANDLE_VALUE) || (GetFileSize(g_hCustomRomF8, NULL) != 0x800)) + g_bCustomRomF8Failed = true; + } + else if (strcmp(lpCmdLine, "-printscreen") == 0) // Turn on display of the last filename print screen was saved to + { + g_bDisplayPrintScreenFileName = true; + } + else if (strcmp(lpCmdLine, "-no-printscreen-dlg") == 0) // Turn off the PrintScreen warning message dialog (if PrintScreen key can't be grabbed) + { + g_bShowPrintScreenWarningDialog = false; + } + else if (strcmp(lpCmdLine, "-spkr-inc") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + const int nErrorInc = atoi(lpCmdLine); + SoundCore_SetErrorInc( nErrorInc ); + } + else if (strcmp(lpCmdLine, "-spkr-max") == 0) + { + lpCmdLine = GetCurrArg(lpNextArg); + lpNextArg = GetNextArg(lpNextArg); + const int nErrorMax = atoi(lpCmdLine); + SoundCore_SetErrorMax( nErrorMax ); + } + else if (strcmp(lpCmdLine, "-use-real-printer") == 0) // Enable control in Advanced config to allow dumping to a real printer + { + g_bEnableDumpToRealPrinter = true; + } + else if (strcmp(lpCmdLine, "-speech") == 0) + { + g_bEnableSpeech = true; + } + else if (strcmp(lpCmdLine, "-multimon") == 0) + { + g_bMultiMon = true; + } + else // unsupported + { + LogFileOutput("Unsupported arg: %s\n", lpCmdLine); + } + + lpCmdLine = lpNextArg; + } + + LogFileOutput("CmdLine: %s\n", strCmdLine.c_str()); + +#if 0 +#ifdef RIFF_SPKR + RiffInitWriteFile("Spkr.wav", SPKR_SAMPLE_RATE, 1); +#endif +#ifdef RIFF_MB + RiffInitWriteFile("Mockingboard.wav", 44100, 2); +#endif +#endif + + //----- + + char szPath[_MAX_PATH]; + + if (0 == GetModuleFileName(NULL, szPath, sizeof(szPath))) + { + strcpy(szPath, __argv[0]); + } + + // Extract application version and store in a global variable + DWORD dwHandle, dwVerInfoSize; + + dwVerInfoSize = GetFileVersionInfoSize(szPath, &dwHandle); + + if (dwVerInfoSize > 0) + { + char* pVerInfoBlock = new char[dwVerInfoSize]; + + if (GetFileVersionInfo(szPath, NULL, dwVerInfoSize, pVerInfoBlock)) + { + VS_FIXEDFILEINFO* pFixedFileInfo; + UINT pFixedFileInfoLen; + + VerQueryValue(pVerInfoBlock, TEXT("\\"), (LPVOID*) &pFixedFileInfo, (PUINT) &pFixedFileInfoLen); + + // Construct version string from fixed file info block + + unsigned long major = pFixedFileInfo->dwFileVersionMS >> 16; + unsigned long minor = pFixedFileInfo->dwFileVersionMS & 0xffff; + unsigned long fix = pFixedFileInfo->dwFileVersionLS >> 16; + unsigned long fix_minor = pFixedFileInfo->dwFileVersionLS & 0xffff; + sprintf(VERSIONSTRING, "%d.%d.%d.%d", major, minor, fix, fix_minor); // potential buffer overflow + } + } + + LogFileOutput("AppleWin version: %s\n", VERSIONSTRING); + +#if DBG_CALC_FREQ + QueryPerformanceFrequency((LARGE_INTEGER*)&g_nPerfFreq); + if(g_fh) fprintf(g_fh, "Performance frequency = %d\n",g_nPerfFreq); +#endif + + //----- + + // Initialize COM - so we can use CoCreateInstance + // . NB. DSInit() & DIMouse::DirectInputInit are done when g_hFrameWindow is created (WM_CREATE) + HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + LogFileOutput("Init: CoInitializeEx(), hr=0x%08X\n", hr); + + const bool bSysClkOK = SysClk_InitTimer(); + LogFileOutput("Init: SysClk_InitTimer(), res=%d\n", bSysClkOK ? 1:0); +#ifdef USE_SPEECH_API + if (g_bEnableSpeech) + { + const bool bSpeechOK = g_Speech.Init(); + LogFileOutput("Init: SysClk_InitTimer(), res=%d\n", bSpeechOK ? 1:0); + } +#endif + + // DO ONE-TIME INITIALIZATION + g_hInstance = passinstance; + GdiSetBatchLimit(512); + LogFileOutput("Init: GdiSetBatchLimit()\n"); + + GetProgramDirectory(); + LogFileOutput("Init: GetProgramDirectory()\n"); + + if (g_bRegisterFileTypes) + { + RegisterExtensions(); + LogFileOutput("Init: RegisterExtensions()\n"); + } + + FrameRegisterClass(); + LogFileOutput("Init: FrameRegisterClass()\n"); + + ImageInitialize(); + LogFileOutput("Init: ImageInitialize()\n"); + + DiskInitialize(); + LogFileOutput("Init: DiskInitialize()\n"); + + CreateColorMixMap(); // For tv emulation mode + LogFileOutput("Init: CreateColorMixMap()\n"); + + int nError = 0; // TODO: Show error MsgBox if we get a DiskInsert error + if (szImageName_drive1) + { + nError = DoDiskInsert(DRIVE_1, szImageName_drive1); + LogFileOutput("Init: DoDiskInsert(D1), res=%d\n", nError); + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + bBoot = true; + } + if (szImageName_drive2) + { + nError |= DoDiskInsert(DRIVE_2, szImageName_drive2); + LogFileOutput("Init: DoDiskInsert(D2), res=%d\n", nError); + } + + // + + do + { + // DO INITIALIZATION THAT MUST BE REPEATED FOR A RESTART + restart = 0; + ResetToLogoMode(); + + LoadConfiguration(); + LogFileOutput("Main: LoadConfiguration()\n"); + + DebugInitialize(); + LogFileOutput("Main: DebugInitialize()\n"); + + JoyInitialize(); + LogFileOutput("Main: JoyInitialize()\n"); + + MemInitialize(); + LogFileOutput("Main: MemInitialize()\n"); + + VideoInitialize(); // g_pFramebufferinfo been created now + LogFileOutput("Main: VideoInitialize()\n"); + + LogFileOutput("Main: FrameCreateWindow() - pre\n"); + FrameCreateWindow(); // g_hFrameWindow is now valid + LogFileOutput("Main: FrameCreateWindow() - post\n"); + + char szOldAppleWinVersion[sizeof(VERSIONSTRING)] = {0}; + RegLoadString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, szOldAppleWinVersion, sizeof(szOldAppleWinVersion)); + + const bool bShowAboutDlg = strcmp(szOldAppleWinVersion, VERSIONSTRING) != 0; + if (bShowAboutDlg) + { + if (!AboutDlg()) + PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + else + RegSaveString(TEXT(REG_CONFIG), TEXT(REGVALUE_VERSION), 1, VERSIONSTRING); // Only save version after user accepts license + } + + // PrintScrn support + AppleWin_RegisterHotKeys(); // needs valid g_hFrameWindow + LogFileOutput("Main: AppleWin_RegisterHotKeys()\n"); + + // Need to test if it's safe to call ResetMachineState(). In the meantime, just call DiskReset(): + DiskReset(); // Switch from a booting A][+ to a non-autostart A][, so need to turn off floppy motor + LogFileOutput("Main: DiskReset()\n"); + + if (!bSysClkOK) + { + MessageBox(g_hFrameWindow, "DirectX failed to create SystemClock instance", TEXT("AppleWin Error"), MB_OK); + PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + } + + if (g_bCustomRomF8Failed) + { + MessageBox(g_hFrameWindow, "Failed to load custom F8 rom (not found or not exactly 2KB)", TEXT("AppleWin Error"), MB_OK); + PostMessage(g_hFrameWindow, WM_DESTROY, 0, 0); // Close everything down + } + + tfe_init(); + LogFileOutput("Main: tfe_init()\n"); + + Snapshot_Startup(); // Do this after everything has been init'ed + LogFileOutput("Main: Snapshot_Startup()\n"); + + if (bSetFullScreen) + { + PostMessage(g_hFrameWindow, WM_USER_FULLSCREEN, 0, 0); + bSetFullScreen = false; + } + + if (bBoot) + { + PostMessage(g_hFrameWindow, WM_USER_BOOT, 0, 0); + bBoot = false; + } + + // ENTER THE MAIN MESSAGE LOOP + LogFileOutput("Main: EnterMessageLoop()\n"); + EnterMessageLoop(); + LogFileOutput("Main: LeaveMessageLoop()\n"); + + MB_Reset(); + LogFileOutput("Main: MB_Reset()\n"); + + sg_Mouse.Uninitialize(); // Maybe restarting due to switching slot-4 card from MouseCard to Mockingboard + LogFileOutput("Main: sg_Mouse.Uninitialize()\n"); + } + while (restart); + + // Release COM + DSUninit(); + LogFileOutput("Exit: DSUninit()\n"); + + SysClk_UninitTimer(); + LogFileOutput("Exit: SysClk_UninitTimer()\n"); + + CoUninitialize(); + LogFileOutput("Exit: CoUninitialize()\n"); + + tfe_shutdown(); + LogFileOutput("Exit: tfe_shutdown()\n"); + + if (g_fh) + { + fprintf(g_fh,"*** Logging ended\n\n"); + fclose(g_fh); + g_fh = NULL; + } + + RiffFinishWriteFile(); + + if (g_hCustomRomF8 != INVALID_HANDLE_VALUE) + CloseHandle(g_hCustomRomF8); + + return 0; +} diff --git a/source/Applewin.h b/source/Applewin.h index 2621d3ba..9b875926 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -1,60 +1,61 @@ -#pragma once - -void SetCurrentCLK6502(); -void SetCurrentImageDir(const char* pszImageDir); - - -extern char VERSIONSTRING[]; // Constructed in WinMain() - -extern TCHAR *g_pAppTitle; - -extern eApple2Type g_Apple2Type; - -extern DWORD cumulativecycles; -extern DWORD cyclenum; -extern DWORD emulmsec; -extern bool g_bFullSpeed; - -//Pravets 8A/C only variables -extern bool P8CAPS_ON; -extern bool P8Shift; -//=========================================== - -// Win32 -extern HINSTANCE g_hInstance; - -extern AppMode_e g_nAppMode; -bool GetLoadedSaveStateFlag(void); -void SetLoadedSaveStateFlag(const bool bFlag); - -extern TCHAR g_sProgramDir[MAX_PATH]; -extern TCHAR g_sCurrentDir[MAX_PATH]; - -extern BOOL restart; - -extern DWORD g_dwSpeed; -extern double g_fCurrentCLK6502; - -extern int g_nCpuCyclesFeedback; -extern DWORD g_dwCyclesThisFrame; - -extern FILE* g_fh; // Filehandle for log file -extern bool g_bDisableDirectInput; // Cmd line switch: don't init DI (so no DIMouse support) -extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB/Speaker support) -extern bool g_bDisableDirectSoundMockingboard; // Cmd line switch: don't init MB support -extern int g_nMemoryClearType; // Cmd line switch: use specific MIP (Memory Initialization Pattern) - -extern SS_CARDTYPE g_Slot4; // Mockingboard, Z80, Mouse in slot4 -extern SS_CARDTYPE g_Slot5; // Mockingboard, Z80, in slot5 - -extern HANDLE g_hCustomRomF8; // NULL if no custom rom - -enum eCPU {CPU_6502=1, CPU_Z80}; -extern eCPU g_ActiveCPU; - -#ifdef USE_SPEECH_API -class CSpeech; -extern CSpeech g_Speech; -#endif - -extern __interface IPropertySheet& sg_PropertySheet; +#pragma once + +void SetCurrentCLK6502(); +void SetCurrentImageDir(const char* pszImageDir); + + +extern char VERSIONSTRING[]; // Constructed in WinMain() + +extern TCHAR *g_pAppTitle; + +extern eApple2Type g_Apple2Type; + +extern DWORD cumulativecycles; +extern DWORD cyclenum; +extern DWORD emulmsec; +extern bool g_bFullSpeed; + +//Pravets 8A/C only variables +extern bool P8CAPS_ON; +extern bool P8Shift; +//=========================================== + +// Win32 +extern HINSTANCE g_hInstance; + +extern AppMode_e g_nAppMode; +bool GetLoadedSaveStateFlag(void); +void SetLoadedSaveStateFlag(const bool bFlag); + +extern TCHAR g_sProgramDir[MAX_PATH]; +extern TCHAR g_sCurrentDir[MAX_PATH]; + +extern BOOL restart; + +extern DWORD g_dwSpeed; +extern double g_fCurrentCLK6502; + +extern int g_nCpuCyclesFeedback; +extern DWORD g_dwCyclesThisFrame; +extern INT64 g_nCyclesTotal; + +extern FILE* g_fh; // Filehandle for log file +extern bool g_bDisableDirectInput; // Cmd line switch: don't init DI (so no DIMouse support) +extern bool g_bDisableDirectSound; // Cmd line switch: don't init DS (so no MB/Speaker support) +extern bool g_bDisableDirectSoundMockingboard; // Cmd line switch: don't init MB support +extern int g_nMemoryClearType; // Cmd line switch: use specific MIP (Memory Initialization Pattern) + +extern SS_CARDTYPE g_Slot4; // Mockingboard, Z80, Mouse in slot4 +extern SS_CARDTYPE g_Slot5; // Mockingboard, Z80, in slot5 + +extern HANDLE g_hCustomRomF8; // NULL if no custom rom + +enum eCPU {CPU_6502=1, CPU_Z80}; +extern eCPU g_ActiveCPU; + +#ifdef USE_SPEECH_API +class CSpeech; +extern CSpeech g_Speech; +#endif + +extern __interface IPropertySheet& sg_PropertySheet; diff --git a/source/Common.h b/source/Common.h index cd5a36f8..597c8fd8 100644 --- a/source/Common.h +++ b/source/Common.h @@ -1,206 +1,207 @@ -#pragma once - -#define USE_SPEECH_API - -const double _M14 = (157500000.0 / 11.0); // 14.3181818... * 10^6 -const double CLK_6502 = ((_M14 * 65.0) / 912.0); // 65 cycles per 912 14M clocks -//const double CLK_6502 = 23 * 44100; // 1014300 - -// The effective Z-80 clock rate is 2.041MHz -// See: http://www.apple2info.net/hardware/softcard/SC-SWHW_a2in.pdf -const double CLK_Z80 = (CLK_6502 * 2); - -const UINT uCyclesPerLine = 65; // 25 cycles of HBL & 40 cycles of HBL' -const UINT uVisibleLinesPerFrame = 64*3; // 192 -const UINT uLinesPerFrame = 262; // 64 in each third of the screen & 70 in VBL -const DWORD dwClksPerFrame = uCyclesPerLine * uLinesPerFrame; // 17030 - -#define NUM_SLOTS 8 - -#define MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#define RAMWORKS // 8MB RamWorks III support - -// Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample -// Assume base freqs are 44.1KHz & 48KHz -const DWORD SPKR_SAMPLE_RATE = 44100; - -enum AppMode_e -{ - MODE_LOGO = 0 - , MODE_PAUSED - , MODE_RUNNING // 6502 is running at normal speed (Debugger breakpoints may or may not be active) - , MODE_DEBUG // 6502 is paused - , MODE_STEPPING // 6502 is running at full speed (Debugger breakpoints always active) -}; - -#define SPEED_MIN 0 -#define SPEED_NORMAL 10 -#define SPEED_MAX 40 - -#define DRAW_BACKGROUND 1 -#define DRAW_LEDS 2 -#define DRAW_TITLE 4 -#define DRAW_BUTTON_DRIVES 8 - -#define BTN_HELP 0 -#define BTN_RUN 1 -#define BTN_DRIVE1 2 -#define BTN_DRIVE2 3 -#define BTN_DRIVESWAP 4 -#define BTN_FULLSCR 5 -#define BTN_DEBUG 6 -#define BTN_SETUP 7 - -// TODO: Move to StringTable.h -#define TITLE_APPLE_2 TEXT("Apple ][ Emulator") -#define TITLE_APPLE_2_PLUS TEXT("Apple ][+ Emulator") -#define TITLE_APPLE_2E TEXT("Apple //e Emulator") -#define TITLE_APPLE_2E_ENHANCED TEXT("Enhanced Apple //e Emulator") -#define TITLE_APPLE_2C TEXT("Apple //e Emulator") -#define TITLE_APPLE_2D TEXT("Apple )(d Virtual Debug Hardware") -#define TITLE_PRAVETS_82 TEXT("Pravets 82 Emulator") -#define TITLE_PRAVETS_8M TEXT("Pravets 8M Emulator") -#define TITLE_PRAVETS_8A TEXT("Pravets 8A Emulator") - -#define TITLE_PAUSED TEXT("* PAUSED *") -#define TITLE_STEPPING TEXT("Stepping") - -#define REGLOAD(a,b) RegLoadValue(TEXT(REG_CONFIG),a,1,b) -#define REGSAVE(a,b) RegSaveValue(TEXT(REG_CONFIG),a,1,b) - -// Configuration -#define REG_CONFIG "Configuration" -#define REGVALUE_APPLE2_TYPE "Apple2 Type" -#define REGVALUE_OLD_APPLE2_TYPE "Computer Emulation" // Deprecated -#define REGVALUE_SPKR_VOLUME "Speaker Volume" -#define REGVALUE_MB_VOLUME "Mockingboard Volume" -#define REGVALUE_SAVESTATE_FILENAME "Save State Filename" -#define REGVALUE_SAVE_STATE_ON_EXIT "Save State On Exit" -#define REGVALUE_HDD_ENABLED "Harddisk Enable" -#define REGVALUE_JOYSTICK0_EMU_TYPE "Joystick0 Emu Type" // Added at 1.24.0 (previously was "Joystick 0 Emulation") -#define REGVALUE_JOYSTICK1_EMU_TYPE "Joystick1 Emu Type" // Added at 1.24.0 (previously was "Joystick 1 Emulation") -#define REGVALUE_OLD_JOYSTICK0_EMU_TYPE "Joystick 0 Emulation" // Deprecated from 1.24.0 -#define REGVALUE_OLD_JOYSTICK1_EMU_TYPE "Joystick 1 Emulation" // Deprecated from 1.24.0 -#define REGVALUE_PDL_XTRIM "PDL X-Trim" -#define REGVALUE_PDL_YTRIM "PDL Y-Trim" -#define REGVALUE_SCROLLLOCK_TOGGLE "ScrollLock Toggle" -#define REGVALUE_CURSOR_CONTROL "Joystick Cursor Control" -#define REGVALUE_CENTERING_CONTROL "Joystick Centering Control" -#define REGVALUE_AUTOFIRE "Autofire" -#define REGVALUE_MOUSE_CROSSHAIR "Mouse crosshair" -#define REGVALUE_MOUSE_RESTRICT_TO_WINDOW "Mouse restrict to window" -#define REGVALUE_THE_FREEZES_F8_ROM "The Freeze's F8 Rom" -#define REGVALUE_CIDERPRESSLOC "CiderPress Location" -#define REGVALUE_CPM_CONFIG "CPM Config" -#define REGVALUE_DUMP_TO_PRINTER "Dump to printer" -#define REGVALUE_CONVERT_ENCODING "Convert printer encoding for clones" -#define REGVALUE_FILTER_UNPRINTABLE "Filter unprintable characters" -#define REGVALUE_PRINTER_FILENAME "Printer Filename" -#define REGVALUE_PRINTER_APPEND "Append to printer file" -#define REGVALUE_PRINTER_IDLE_LIMIT "Printer idle limit" -#define REGVALUE_VIDEO_MODE "Video Emulation" -#define REGVALUE_VIDEO_HALF_SCAN_LINES "Half Scan Lines" -#define REGVALUE_VIDEO_MONO_COLOR "Monochrome Color" -#define REGVALUE_SERIAL_PORT_NAME "Serial Port Name" -#define REGVALUE_ENHANCE_DISK_SPEED "Enhance Disk Speed" -#define REGVALUE_CUSTOM_SPEED "Custom Speed" -#define REGVALUE_EMULATION_SPEED "Emulation Speed" -#define REGVALUE_WINDOW_SCALE "Window Scale" -#define REGVALUE_SLOT1 "Slot 1" -#define REGVALUE_SLOT2 "Slot 2" -#define REGVALUE_SLOT3 "Slot 3" -#define REGVALUE_SLOT4 "Slot 4" -#define REGVALUE_SLOT5 "Slot 5" -#define REGVALUE_SLOT6 "Slot 6" -#define REGVALUE_SLOT7 "Slot 7" -#define REGVALUE_SLOTAUX "Slot Auxilary" -#define REGVALUE_VERSION "Version" - -// Preferences -#define REG_PREFS "Preferences" -#define REGVALUE_PREF_START_DIR "Starting Directory" -#define REGVALUE_PREF_LAST_DISK_1 "Last Disk Image 1" -#define REGVALUE_PREF_LAST_DISK_2 "Last Disk Image 2" -#define REGVALUE_PREF_WINDOW_X_POS "Window X-Position" -#define REGVALUE_PREF_WINDOW_Y_POS "Window Y-Position" -#define REGVALUE_PREF_HDV_START_DIR "HDV Starting Directory" -#define REGVALUE_PREF_LAST_HARDDISK_1 "Last Harddisk Image 1" -#define REGVALUE_PREF_LAST_HARDDISK_2 "Last Harddisk Image 2" - -#define WM_USER_BENCHMARK WM_USER+1 -#define WM_USER_RESTART WM_USER+2 -#define WM_USER_SAVESTATE WM_USER+3 -#define WM_USER_LOADSTATE WM_USER+4 -#define VK_SNAPSHOT_560 WM_USER+5 -#define VK_SNAPSHOT_280 WM_USER+6 -#define WM_USER_TCP_SERIAL WM_USER+7 -#define WM_USER_BOOT WM_USER+8 -#define WM_USER_FULLSCREEN WM_USER+9 - -// TODO-TC: Refactor codebase by renaming /nCyclesLeft/ to /uExecutedCycles/ -typedef BYTE (__stdcall *iofunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE nWriteValue, ULONG nCyclesLeft); - -typedef struct _IMAGE__ { int unused; } *HIMAGE; // DiskImage's /ImageInfo/ is hidden behind HIMAGE - -enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE}; - -// -#define APPLE2P_MASK 0x01 -/* - ][ 0 - ][+ 1 - //e 10 - //e+ 11 - //c 20 - //d 40 -*/ -#define APPLE2E_MASK 0x10 -#define APPLE2C_MASK 0x20 -#define APPLE2D_MASK 0x40 -#define APPLECLONE_MASK 0x100 - -#define IS_APPLE2 ((g_Apple2Type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) -#define IS_APPLE2E (g_Apple2Type & APPLE2E_MASK) -#define IS_APPLE2C (g_Apple2Type & APPLE2C_MASK) -#define IS_CLONE() (g_Apple2Type & APPLECLONE_MASK) - -// NB. These get persisted to the Registry, so don't change the values for these enums! -enum eApple2Type { - A2TYPE_APPLE2=0, - A2TYPE_APPLE2PLUS, - A2TYPE_APPLE2E=APPLE2E_MASK, - A2TYPE_APPLE2EENHANCED, - A2TYPE_UNDEFINED, - A2TYPE_APPLE2C=APPLE2C_MASK, - A2TYPE_APPLE2D=APPLE2D_MASK, - // - // Clones start here: - A2TYPE_CLONE=APPLECLONE_MASK, - A2TYPE_PRAVETS=APPLECLONE_MASK|APPLE2E_MASK, - A2TYPE_PRAVETS82=A2TYPE_PRAVETS, - A2TYPE_PRAVETS8M, - A2TYPE_PRAVETS8A, - A2TYPE_MAX - }; - -inline bool IsApple2(eApple2Type type) -{ - return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0; -} - -inline bool IsClone(eApple2Type type) -{ - return (type & APPLECLONE_MASK) != 0; -} - -extern eApple2Type g_Apple2Type; -inline bool IsOriginal2E(void) -{ - return (g_Apple2Type == A2TYPE_APPLE2E); -} - -enum eBUTTON {BUTTON0=0, BUTTON1}; - -enum eBUTTONSTATE {BUTTON_UP=0, BUTTON_DOWN}; +#pragma once + +#define USE_SPEECH_API + +const double _M14 = (157500000.0 / 11.0); // 14.3181818... * 10^6 +const double CLK_6502 = ((_M14 * 65.0) / 912.0); // 65 cycles per 912 14M clocks +//const double CLK_6502 = 23 * 44100; // 1014300 + +// The effective Z-80 clock rate is 2.041MHz +// See: http://www.apple2info.net/hardware/softcard/SC-SWHW_a2in.pdf +const double CLK_Z80 = (CLK_6502 * 2); + +const UINT uCyclesPerLine = 65; // 25 cycles of HBL & 40 cycles of HBL' +const UINT uVisibleLinesPerFrame = 64*3; // 192 +const UINT uLinesPerFrame = 262; // 64 in each third of the screen & 70 in VBL +const DWORD dwClksPerFrame = uCyclesPerLine * uLinesPerFrame; // 17030 + +#define NUM_SLOTS 8 + +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#define RAMWORKS // 8MB RamWorks III support + +// Use a base freq so that DirectX (or sound h/w) doesn't have to up/down-sample +// Assume base freqs are 44.1KHz & 48KHz +const DWORD SPKR_SAMPLE_RATE = 44100; + +enum AppMode_e +{ + MODE_LOGO = 0 + , MODE_PAUSED + , MODE_RUNNING // 6502 is running at normal speed (Debugger breakpoints may or may not be active) + , MODE_DEBUG // 6502 is paused + , MODE_STEPPING // 6502 is running at full speed (Debugger breakpoints always active) +}; + +#define SPEED_MIN 0 +#define SPEED_NORMAL 10 +#define SPEED_MAX 40 + +#define DRAW_BACKGROUND 1 +#define DRAW_LEDS 2 +#define DRAW_TITLE 4 +#define DRAW_BUTTON_DRIVES 8 + +#define BTN_HELP 0 +#define BTN_RUN 1 +#define BTN_DRIVE1 2 +#define BTN_DRIVE2 3 +#define BTN_DRIVESWAP 4 +#define BTN_FULLSCR 5 +#define BTN_DEBUG 6 +#define BTN_SETUP 7 + +// TODO: Move to StringTable.h +#define TITLE_APPLE_2 TEXT("Apple ][ Emulator") +#define TITLE_APPLE_2_PLUS TEXT("Apple ][+ Emulator") +#define TITLE_APPLE_2E TEXT("Apple //e Emulator") +#define TITLE_APPLE_2E_ENHANCED TEXT("Enhanced Apple //e Emulator") +#define TITLE_APPLE_2C TEXT("Apple //e Emulator") +#define TITLE_APPLE_2D TEXT("Apple )(d Virtual Debug Hardware") +#define TITLE_PRAVETS_82 TEXT("Pravets 82 Emulator") +#define TITLE_PRAVETS_8M TEXT("Pravets 8M Emulator") +#define TITLE_PRAVETS_8A TEXT("Pravets 8A Emulator") + +#define TITLE_PAUSED TEXT("* PAUSED *") +#define TITLE_STEPPING TEXT("Stepping") + +#define REGLOAD(a,b) RegLoadValue(TEXT(REG_CONFIG),a,1,b) +#define REGSAVE(a,b) RegSaveValue(TEXT(REG_CONFIG),a,1,b) + +// Configuration +#define REG_CONFIG "Configuration" +#define REGVALUE_APPLE2_TYPE "Apple2 Type" +#define REGVALUE_OLD_APPLE2_TYPE "Computer Emulation" // Deprecated +#define REGVALUE_SPKR_VOLUME "Speaker Volume" +#define REGVALUE_MB_VOLUME "Mockingboard Volume" +#define REGVALUE_SAVESTATE_FILENAME "Save State Filename" +#define REGVALUE_SAVE_STATE_ON_EXIT "Save State On Exit" +#define REGVALUE_HDD_ENABLED "Harddisk Enable" +#define REGVALUE_JOYSTICK0_EMU_TYPE "Joystick0 Emu Type" // Added at 1.24.0 (previously was "Joystick 0 Emulation") +#define REGVALUE_JOYSTICK1_EMU_TYPE "Joystick1 Emu Type" // Added at 1.24.0 (previously was "Joystick 1 Emulation") +#define REGVALUE_OLD_JOYSTICK0_EMU_TYPE "Joystick 0 Emulation" // Deprecated from 1.24.0 +#define REGVALUE_OLD_JOYSTICK1_EMU_TYPE "Joystick 1 Emulation" // Deprecated from 1.24.0 +#define REGVALUE_PDL_XTRIM "PDL X-Trim" +#define REGVALUE_PDL_YTRIM "PDL Y-Trim" +#define REGVALUE_SCROLLLOCK_TOGGLE "ScrollLock Toggle" +#define REGVALUE_CURSOR_CONTROL "Joystick Cursor Control" +#define REGVALUE_CENTERING_CONTROL "Joystick Centering Control" +#define REGVALUE_TCPIPJOYSTICK "TCP/IP Joystick" +#define REGVALUE_AUTOFIRE "Autofire" +#define REGVALUE_MOUSE_CROSSHAIR "Mouse crosshair" +#define REGVALUE_MOUSE_RESTRICT_TO_WINDOW "Mouse restrict to window" +#define REGVALUE_THE_FREEZES_F8_ROM "The Freeze's F8 Rom" +#define REGVALUE_CIDERPRESSLOC "CiderPress Location" +#define REGVALUE_CPM_CONFIG "CPM Config" +#define REGVALUE_DUMP_TO_PRINTER "Dump to printer" +#define REGVALUE_CONVERT_ENCODING "Convert printer encoding for clones" +#define REGVALUE_FILTER_UNPRINTABLE "Filter unprintable characters" +#define REGVALUE_PRINTER_FILENAME "Printer Filename" +#define REGVALUE_PRINTER_APPEND "Append to printer file" +#define REGVALUE_PRINTER_IDLE_LIMIT "Printer idle limit" +#define REGVALUE_VIDEO_MODE "Video Emulation" +#define REGVALUE_VIDEO_HALF_SCAN_LINES "Half Scan Lines" +#define REGVALUE_VIDEO_MONO_COLOR "Monochrome Color" +#define REGVALUE_SERIAL_PORT_NAME "Serial Port Name" +#define REGVALUE_ENHANCE_DISK_SPEED "Enhance Disk Speed" +#define REGVALUE_CUSTOM_SPEED "Custom Speed" +#define REGVALUE_EMULATION_SPEED "Emulation Speed" +#define REGVALUE_WINDOW_SCALE "Window Scale" +#define REGVALUE_SLOT1 "Slot 1" +#define REGVALUE_SLOT2 "Slot 2" +#define REGVALUE_SLOT3 "Slot 3" +#define REGVALUE_SLOT4 "Slot 4" +#define REGVALUE_SLOT5 "Slot 5" +#define REGVALUE_SLOT6 "Slot 6" +#define REGVALUE_SLOT7 "Slot 7" +#define REGVALUE_SLOTAUX "Slot Auxilary" +#define REGVALUE_VERSION "Version" + +// Preferences +#define REG_PREFS "Preferences" +#define REGVALUE_PREF_START_DIR "Starting Directory" +#define REGVALUE_PREF_LAST_DISK_1 "Last Disk Image 1" +#define REGVALUE_PREF_LAST_DISK_2 "Last Disk Image 2" +#define REGVALUE_PREF_WINDOW_X_POS "Window X-Position" +#define REGVALUE_PREF_WINDOW_Y_POS "Window Y-Position" +#define REGVALUE_PREF_HDV_START_DIR "HDV Starting Directory" +#define REGVALUE_PREF_LAST_HARDDISK_1 "Last Harddisk Image 1" +#define REGVALUE_PREF_LAST_HARDDISK_2 "Last Harddisk Image 2" + +#define WM_USER_BENCHMARK WM_USER+1 +#define WM_USER_RESTART WM_USER+2 +#define WM_USER_SAVESTATE WM_USER+3 +#define WM_USER_LOADSTATE WM_USER+4 +#define VK_SNAPSHOT_560 WM_USER+5 +#define VK_SNAPSHOT_280 WM_USER+6 +#define WM_USER_TCP_SERIAL WM_USER+7 +#define WM_USER_BOOT WM_USER+8 +#define WM_USER_FULLSCREEN WM_USER+9 + +// TODO-TC: Refactor codebase by renaming /nCyclesLeft/ to /uExecutedCycles/ +typedef BYTE (__stdcall *iofunction)(WORD nPC, WORD nAddr, BYTE nWriteFlag, BYTE nWriteValue, ULONG nCyclesLeft); + +typedef struct _IMAGE__ { int unused; } *HIMAGE; // DiskImage's /ImageInfo/ is hidden behind HIMAGE + +enum eIRQSRC {IS_6522=0, IS_SPEECH, IS_SSC, IS_MOUSE}; + +// +#define APPLE2P_MASK 0x01 +/* + ][ 0 + ][+ 1 + //e 10 + //e+ 11 + //c 20 + //d 40 +*/ +#define APPLE2E_MASK 0x10 +#define APPLE2C_MASK 0x20 +#define APPLE2D_MASK 0x40 +#define APPLECLONE_MASK 0x100 + +#define IS_APPLE2 ((g_Apple2Type & (APPLE2E_MASK|APPLE2C_MASK)) == 0) +#define IS_APPLE2E (g_Apple2Type & APPLE2E_MASK) +#define IS_APPLE2C (g_Apple2Type & APPLE2C_MASK) +#define IS_CLONE() (g_Apple2Type & APPLECLONE_MASK) + +// NB. These get persisted to the Registry, so don't change the values for these enums! +enum eApple2Type { + A2TYPE_APPLE2=0, + A2TYPE_APPLE2PLUS, + A2TYPE_APPLE2E=APPLE2E_MASK, + A2TYPE_APPLE2EENHANCED, + A2TYPE_UNDEFINED, + A2TYPE_APPLE2C=APPLE2C_MASK, + A2TYPE_APPLE2D=APPLE2D_MASK, + // + // Clones start here: + A2TYPE_CLONE=APPLECLONE_MASK, + A2TYPE_PRAVETS=APPLECLONE_MASK|APPLE2E_MASK, + A2TYPE_PRAVETS82=A2TYPE_PRAVETS, + A2TYPE_PRAVETS8M, + A2TYPE_PRAVETS8A, + A2TYPE_MAX + }; + +inline bool IsApple2(eApple2Type type) +{ + return (type & (APPLE2E_MASK|APPLE2C_MASK)) == 0; +} + +inline bool IsClone(eApple2Type type) +{ + return (type & APPLECLONE_MASK) != 0; +} + +extern eApple2Type g_Apple2Type; +inline bool IsOriginal2E(void) +{ + return (g_Apple2Type == A2TYPE_APPLE2E); +} + +enum eBUTTON {BUTTON0=0, BUTTON1}; + +enum eBUTTONSTATE {BUTTON_UP=0, BUTTON_DOWN}; diff --git a/source/Configuration/IPropertySheet.h b/source/Configuration/IPropertySheet.h index c25b2ce8..db47437c 100644 --- a/source/Configuration/IPropertySheet.h +++ b/source/Configuration/IPropertySheet.h @@ -12,6 +12,8 @@ __interface IPropertySheet void SetJoystickCursorControl(UINT uValue); UINT GetJoystickCenteringControl(void); void SetJoystickCenteringControl(UINT uValue); + UINT GetTcpIpJoystock(void); + void SetTcpIpJoystock(UINT uValue); UINT GetAutofire(UINT uButton); void SetAutofire(UINT uValue); UINT GetMouseShowCrosshair(void); diff --git a/source/Configuration/PageInput.cpp b/source/Configuration/PageInput.cpp index 7184ed98..b47e2c8a 100644 --- a/source/Configuration/PageInput.cpp +++ b/source/Configuration/PageInput.cpp @@ -165,6 +165,7 @@ BOOL CPageInput::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPARAM SendDlgItemMessage(hWnd, IDC_SPIN_YTRIM, UDM_SETPOS, 0, MAKELONG(JoyGetTrim(false),0)); CheckDlgButton(hWnd, IDC_CURSORCONTROL, m_uCursorControl ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hWnd, IDC_TCPIP_JOYSTICK, m_uTcpIpJoystick ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hWnd, IDC_AUTOFIRE, m_bmAutofire ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hWnd, IDC_CENTERINGCONTROL, m_uCenteringControl == JOYSTICK_MODE_CENTERING ? BST_CHECKED : BST_UNCHECKED); CheckDlgButton(hWnd, IDC_SCROLLLOCK_TOGGLE, m_uScrollLockToggle ? BST_CHECKED : BST_UNCHECKED); @@ -198,6 +199,7 @@ void CPageInput::DlgOK(HWND hWnd) JoySetTrim((short)SendDlgItemMessage(hWnd, IDC_SPIN_YTRIM, UDM_GETPOS, 0, 0), false); m_uCursorControl = IsDlgButtonChecked(hWnd, IDC_CURSORCONTROL) ? 1 : 0; + m_uTcpIpJoystick = IsDlgButtonChecked(hWnd, IDC_TCPIP_JOYSTICK) ? 1 : 0; m_bmAutofire = IsDlgButtonChecked(hWnd, IDC_AUTOFIRE) ? 7 : 0; // bitmap of 3 bits m_uCenteringControl = IsDlgButtonChecked(hWnd, IDC_CENTERINGCONTROL) ? 1 : 0; m_uMouseShowCrosshair = IsDlgButtonChecked(hWnd, IDC_MOUSE_CROSSHAIR) ? 1 : 0; @@ -207,6 +209,7 @@ void CPageInput::DlgOK(HWND hWnd) REGSAVE(TEXT(REGVALUE_PDL_YTRIM), JoyGetTrim(false)); REGSAVE(TEXT(REGVALUE_SCROLLLOCK_TOGGLE), m_uScrollLockToggle); REGSAVE(TEXT(REGVALUE_CURSOR_CONTROL), m_uCursorControl); + REGSAVE(TEXT(REGVALUE_TCPIPJOYSTICK), m_uTcpIpJoystick); REGSAVE(TEXT(REGVALUE_AUTOFIRE), m_bmAutofire); REGSAVE(TEXT(REGVALUE_CENTERING_CONTROL), m_uCenteringControl); REGSAVE(TEXT(REGVALUE_MOUSE_CROSSHAIR), m_uMouseShowCrosshair); diff --git a/source/Configuration/PageInput.h b/source/Configuration/PageInput.h index b9190df2..7c32d35a 100644 --- a/source/Configuration/PageInput.h +++ b/source/Configuration/PageInput.h @@ -15,6 +15,7 @@ public: m_uScrollLockToggle(0), m_uCursorControl(1), m_uCenteringControl(JOYSTICK_MODE_CENTERING), + m_uTcpIpJoystick(0), m_bmAutofire(0), m_uMouseShowCrosshair(0), m_uMouseRestrictToWindow(0), @@ -32,6 +33,8 @@ public: void SetJoystickCursorControl(UINT uValue){ m_uCursorControl = uValue; } UINT GetJoystickCenteringControl(void){ return m_uCenteringControl; } void SetJoystickCenteringControl(UINT uValue){ m_uCenteringControl = uValue; } + UINT GetTcpIpJoystick(void){ return m_uTcpIpJoystick; } + void SetTcpIpJoystick(UINT uValue){ m_uTcpIpJoystick = uValue; } UINT GetAutofire(UINT uButton) { return (m_bmAutofire >> uButton) & 1; } // Get a specific button void SetAutofire(UINT uValue) { m_bmAutofire = uValue; } // Set all buttons UINT GetMouseShowCrosshair(void){ return m_uMouseShowCrosshair; } @@ -82,6 +85,7 @@ private: UINT m_bmAutofire; // bitmask b2:0 UINT m_uMouseShowCrosshair; UINT m_uMouseRestrictToWindow; + UINT m_uTcpIpJoystick; enum CPMCHOICE {CPM_SLOT4=0, CPM_SLOT5, CPM_UNPLUGGED, CPM_UNAVAILABLE, _CPM_MAX_CHOICES}; TCHAR m_szCPMSlotChoices[_CPM_MAX_CHOICES * MaxMenuChoiceLen]; diff --git a/source/Configuration/PropertySheet.h b/source/Configuration/PropertySheet.h index ba1dc6bb..d184d66e 100644 --- a/source/Configuration/PropertySheet.h +++ b/source/Configuration/PropertySheet.h @@ -1,50 +1,52 @@ -#pragma once - -#include "IPropertySheet.h" -#include "PropertySheetHelper.h" -#include "PageConfig.h" -#include "PageInput.h" -#include "PageSound.h" -#include "PageDisk.h" -#include "PageAdvanced.h" - -class CPropertySheet : public IPropertySheet -{ -public: - CPropertySheet() : - m_PageConfig(m_PropertySheetHelper), - m_PageInput(m_PropertySheetHelper), - m_PageSound(m_PropertySheetHelper), - m_PageDisk(m_PropertySheetHelper), - m_PageAdvanced(m_PropertySheetHelper) - { - } - virtual ~CPropertySheet(){} - - virtual void Init(void); - virtual DWORD GetVolumeMax(void); // TODO:TC: Move out of here - virtual bool SaveStateSelectImage(HWND hWindow, bool bSave); // TODO:TC: Move out of here - - virtual UINT GetScrollLockToggle(void){ return m_PageInput.GetScrollLockToggle(); } - virtual void SetScrollLockToggle(UINT uValue){ m_PageInput.SetScrollLockToggle(uValue); } - virtual UINT GetJoystickCursorControl(void){ return m_PageInput.GetJoystickCursorControl(); } - virtual void SetJoystickCursorControl(UINT uValue){ m_PageInput.SetJoystickCursorControl(uValue); } - virtual UINT GetJoystickCenteringControl(void){ return m_PageInput.GetJoystickCenteringControl(); } - virtual void SetJoystickCenteringControl(UINT uValue){ m_PageInput.SetJoystickCenteringControl(uValue); } - virtual UINT GetAutofire(UINT uButton) { return m_PageInput.GetAutofire(uButton); } - virtual void SetAutofire(UINT uValue) { m_PageInput.SetAutofire(uValue); } - virtual UINT GetMouseShowCrosshair(void){ return m_PageInput.GetMouseShowCrosshair(); } - virtual void SetMouseShowCrosshair(UINT uValue){ m_PageInput.SetMouseShowCrosshair(uValue); } - virtual UINT GetMouseRestrictToWindow(void){ return m_PageInput.GetMouseRestrictToWindow(); } - virtual void SetMouseRestrictToWindow(UINT uValue){ m_PageInput.SetMouseRestrictToWindow(uValue); } - virtual UINT GetTheFreezesF8Rom(void){ return m_PageAdvanced.GetTheFreezesF8Rom(); } - virtual void SetTheFreezesF8Rom(UINT uValue){ m_PageAdvanced.SetTheFreezesF8Rom(uValue); } - -private: - CPropertySheetHelper m_PropertySheetHelper; - CPageConfig m_PageConfig; - CPageInput m_PageInput; - CPageSound m_PageSound; - CPageDisk m_PageDisk; - CPageAdvanced m_PageAdvanced; -}; +#pragma once + +#include "IPropertySheet.h" +#include "PropertySheetHelper.h" +#include "PageConfig.h" +#include "PageInput.h" +#include "PageSound.h" +#include "PageDisk.h" +#include "PageAdvanced.h" + +class CPropertySheet : public IPropertySheet +{ +public: + CPropertySheet() : + m_PageConfig(m_PropertySheetHelper), + m_PageInput(m_PropertySheetHelper), + m_PageSound(m_PropertySheetHelper), + m_PageDisk(m_PropertySheetHelper), + m_PageAdvanced(m_PropertySheetHelper) + { + } + virtual ~CPropertySheet(){} + + virtual void Init(void); + virtual DWORD GetVolumeMax(void); // TODO:TC: Move out of here + virtual bool SaveStateSelectImage(HWND hWindow, bool bSave); // TODO:TC: Move out of here + + virtual UINT GetScrollLockToggle(void){ return m_PageInput.GetScrollLockToggle(); } + virtual void SetScrollLockToggle(UINT uValue){ m_PageInput.SetScrollLockToggle(uValue); } + virtual UINT GetJoystickCursorControl(void){ return m_PageInput.GetJoystickCursorControl(); } + virtual void SetJoystickCursorControl(UINT uValue){ m_PageInput.SetJoystickCursorControl(uValue); } + virtual UINT GetJoystickCenteringControl(void){ return m_PageInput.GetJoystickCenteringControl(); } + virtual void SetJoystickCenteringControl(UINT uValue){ m_PageInput.SetJoystickCenteringControl(uValue); } + virtual UINT GetTcpIpJoystock(void){ return m_PageInput.GetTcpIpJoystick(); } + virtual void SetTcpIpJoystock(UINT uValue){ m_PageInput.SetTcpIpJoystick(uValue); } + virtual UINT GetAutofire(UINT uButton) { return m_PageInput.GetAutofire(uButton); } + virtual void SetAutofire(UINT uValue) { m_PageInput.SetAutofire(uValue); } + virtual UINT GetMouseShowCrosshair(void){ return m_PageInput.GetMouseShowCrosshair(); } + virtual void SetMouseShowCrosshair(UINT uValue){ m_PageInput.SetMouseShowCrosshair(uValue); } + virtual UINT GetMouseRestrictToWindow(void){ return m_PageInput.GetMouseRestrictToWindow(); } + virtual void SetMouseRestrictToWindow(UINT uValue){ m_PageInput.SetMouseRestrictToWindow(uValue); } + virtual UINT GetTheFreezesF8Rom(void){ return m_PageAdvanced.GetTheFreezesF8Rom(); } + virtual void SetTheFreezesF8Rom(UINT uValue){ m_PageAdvanced.SetTheFreezesF8Rom(uValue); } + +private: + CPropertySheetHelper m_PropertySheetHelper; + CPageConfig m_PageConfig; + CPageInput m_PageInput; + CPageSound m_PageSound; + CPageDisk m_PageDisk; + CPageAdvanced m_PageAdvanced; +}; diff --git a/source/Disk.cpp b/source/Disk.cpp index 938bdc00..c820a37c 100644 --- a/source/Disk.cpp +++ b/source/Disk.cpp @@ -1,1187 +1,1208 @@ -/* -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 -*/ - -/* Description: Disk - * - * Author: Various - */ - -#include "StdAfx.h" -#include "DiskImage.h" -#include "..\resource\resource.h" - -#define LOG_DISK_ENABLED 0 - -// __VA_ARGS__ not supported on MSVC++ .NET 7.x -#if (LOG_DISK_ENABLED) - #if !defined(_VC71) - #define LOG_DISK(format, ...) LOG(format, __VA_ARGS__) - #else - #define LOG_DISK LogOutput - #endif -#else - #if !defined(_VC71) - #define LOG_DISK(...) - #else - #define LOG_DISK(x) - #endif -#endif - -// Public _________________________________________________________________________________________ - - BOOL enhancedisk = 1; // TODO: Make static & add accessor funcs - -// Private ________________________________________________________________________________________ - - const int MAX_DISK_IMAGE_NAME = 15; - const int MAX_DISK_FULL_NAME = 127; - - struct Disk_t - { - TCHAR imagename[ MAX_DISK_IMAGE_NAME + 1 ]; // (ie. no extension) - TCHAR fullname [ MAX_DISK_FULL_NAME + 1 ]; // or : This is persisted to the snapshot file - string strDiskPathFilename; - string strFilenameInZip; // 0x00 or - HIMAGE imagehandle; // Init'd by DiskInsert() -> ImageOpen() - int track; - LPBYTE trackimage; - int phase; - int byte; - bool bWriteProtected; - BOOL trackimagedata; - BOOL trackimagedirty; - DWORD spinning; - DWORD writelight; - int nibbles; // Init'd by ReadTrack() -> ImageReadTrack() - - const Disk_t& operator= (const Disk_t& other) - { - memcpy(imagename, other.imagename, sizeof(imagename)); - memcpy(fullname , other.fullname, sizeof(fullname)); - strDiskPathFilename = other.strDiskPathFilename; - strFilenameInZip = other.strFilenameInZip; - imagehandle = other.imagehandle; - track = other.track; - trackimage = other.trackimage; - phase = other.phase; - byte = other.byte; - bWriteProtected = other.bWriteProtected; - trackimagedata = other.trackimagedata; - trackimagedirty = other.trackimagedirty; - spinning = other.spinning; - writelight = other.writelight; - nibbles = other.nibbles; - return *this; - } - }; - -static WORD currdrive = 0; -static BOOL diskaccessed = 0; -static Disk_t g_aFloppyDisk[NUM_DRIVES]; -static BYTE floppylatch = 0; -static BOOL floppymotoron = 0; -static BOOL floppywritemode = 0; -static WORD phases; // state bits for stepper magnet phases 0 - 3 -static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry - -static void CheckSpinning(); -static Disk_Status_e GetDriveLightStatus( const int iDrive ); -static bool IsDriveValid( const int iDrive ); -static void ReadTrack (int drive); -static void RemoveDisk (int drive); -static void WriteTrack (int drive); - -//=========================================================================== - -int DiskGetCurrentDrive(void) { return currdrive; } -int DiskGetCurrentTrack(void) { return g_aFloppyDisk[currdrive].track; } -int DiskGetCurrentPhase(void) { return g_aFloppyDisk[currdrive].phase; } -int DiskGetCurrentOffset(void) { return g_aFloppyDisk[currdrive].byte; } - -const string& DiskGetDiskPathFilename(const int iDrive) -{ - return g_aFloppyDisk[iDrive].strDiskPathFilename; -} - -static void DiskSetDiskPathFilename(const int iDrive, const string strPathName) -{ - g_aFloppyDisk[iDrive].strDiskPathFilename = strPathName; -} - -char* DiskGetCurrentState(void) -{ - if (g_aFloppyDisk[currdrive].imagehandle == NULL) - return "Empty"; - - if (!floppymotoron) - { - if (g_aFloppyDisk[currdrive].spinning > 0) - return "Off (spinning)"; - else - return "Off"; - } - else if (floppywritemode) - { - if (g_aFloppyDisk[currdrive].bWriteProtected) - return "Writing"; - else - return "Writing (write protected)"; - } - else - { - return "Reading"; - } -} - -//=========================================================================== - - void Disk_LoadLastDiskImage(const int iDrive) -{ - _ASSERT(iDrive == DRIVE_1 || iDrive == DRIVE_2); - - char sFilePath[ MAX_PATH + 1]; - sFilePath[0] = 0; - - char *pRegKey = (iDrive == DRIVE_1) - ? REGVALUE_PREF_LAST_DISK_1 - : REGVALUE_PREF_LAST_DISK_2; - - if (RegLoadString(TEXT(REG_PREFS),pRegKey,1,sFilePath,MAX_PATH)) - { - sFilePath[ MAX_PATH ] = 0; - DiskSetDiskPathFilename(iDrive, sFilePath); - -#if _DEBUG -// MessageBox(g_hFrameWindow,pFileName,pRegKey,MB_OK); -#endif - - // _tcscat(imagefilename,TEXT("MASTER.DSK")); // TODO: Should remember last disk by user - g_bSaveDiskImage = false; - // Pass in ptr to local copy of filepath, since RemoveDisk() sets DiskPathFilename = "" - DiskInsert(iDrive, sFilePath, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); - g_bSaveDiskImage = true; - } - //else MessageBox(g_hFrameWindow,"Reg Key/Value not found",pRegKey,MB_OK); -} - -//=========================================================================== - -void Disk_SaveLastDiskImage(const int iDrive) -{ - _ASSERT(iDrive == DRIVE_1 || iDrive == DRIVE_2); - - if (!g_bSaveDiskImage) - return; - - const char *pFileName = DiskGetDiskPathFilename(iDrive).c_str(); - - if (iDrive == DRIVE_1) - RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_1, TRUE, pFileName); - else - RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_2, TRUE, pFileName); -} - -//=========================================================================== - -static void CheckSpinning(void) -{ - DWORD modechange = (floppymotoron && !g_aFloppyDisk[currdrive].spinning); - if (floppymotoron) - g_aFloppyDisk[currdrive].spinning = 20000; - if (modechange) - FrameRefreshStatus(DRAW_LEDS); -} - -//=========================================================================== - -static Disk_Status_e GetDriveLightStatus(const int iDrive) -{ - if (IsDriveValid( iDrive )) - { - Disk_t *pFloppy = & g_aFloppyDisk[ iDrive ]; - - if (pFloppy->spinning) - { - if (pFloppy->bWriteProtected) - return DISK_STATUS_PROT; - - if (pFloppy->writelight) - return DISK_STATUS_WRITE; - else - return DISK_STATUS_READ; - } - else - return DISK_STATUS_OFF; - } - - return DISK_STATUS_OFF; -} - -//=========================================================================== - -static void GetImageTitle(LPCTSTR imagefilename, Disk_t* fptr) -{ - TCHAR imagetitle[ MAX_DISK_FULL_NAME+1 ]; - LPCTSTR startpos = imagefilename; - - // imagetitle = - if (_tcsrchr(startpos,TEXT('\\'))) - startpos = _tcsrchr(startpos,TEXT('\\'))+1; - - _tcsncpy(imagetitle,startpos,MAX_DISK_FULL_NAME); - imagetitle[MAX_DISK_FULL_NAME] = 0; - - // if imagetitle contains a lowercase char, then found=1 (why?) - BOOL found = 0; - int loop = 0; - while (imagetitle[loop] && !found) - { - if (IsCharLower(imagetitle[loop])) - found = 1; - else - loop++; - } - - if ((!found) && (loop > 2)) - CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1)); - - // fptr->fullname = - _tcsncpy( fptr->fullname, imagetitle, MAX_DISK_FULL_NAME ); - fptr->fullname[ MAX_DISK_FULL_NAME ] = 0; - - if (imagetitle[0]) - { - LPTSTR dot = imagetitle; - if (_tcsrchr(dot,TEXT('.'))) - dot = _tcsrchr(dot,TEXT('.')); - if (dot > imagetitle) - *dot = 0; - } - - // fptr->imagename = (ie. no extension) - _tcsncpy( fptr->imagename, imagetitle, MAX_DISK_IMAGE_NAME ); - fptr->imagename[ MAX_DISK_IMAGE_NAME ] = 0; -} - - -//=========================================================================== - -static bool IsDriveValid(const int iDrive) -{ - return (iDrive >= 0 && iDrive < NUM_DRIVES); -} - -//=========================================================================== - -static void AllocTrack(const int iDrive) -{ - Disk_t * fptr = &g_aFloppyDisk[iDrive]; - fptr->trackimage = (LPBYTE)VirtualAlloc(NULL, NIBBLES_PER_TRACK, MEM_COMMIT, PAGE_READWRITE); -} - -//=========================================================================== - -static void ReadTrack(const int iDrive) -{ - if (! IsDriveValid( iDrive )) - return; - - Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; - - if (pFloppy->track >= ImageGetNumTracks(pFloppy->imagehandle)) - { - pFloppy->trackimagedata = 0; - return; - } - - if (! pFloppy->trackimage) - AllocTrack( iDrive ); - - if (pFloppy->trackimage && pFloppy->imagehandle) - { - LOG_DISK("read track %2X%s\r", pFloppy->track, (pFloppy->phase & 1) ? ".5" : ""); - - ImageReadTrack( - pFloppy->imagehandle, - pFloppy->track, - pFloppy->phase, - pFloppy->trackimage, - &pFloppy->nibbles); - - pFloppy->byte = 0; - pFloppy->trackimagedata = (pFloppy->nibbles != 0); - } -} - -//=========================================================================== - -static void RemoveDisk(const int iDrive) -{ - Disk_t *pFloppy = &g_aFloppyDisk[iDrive]; - - if (pFloppy->imagehandle) - { - if (pFloppy->trackimage && pFloppy->trackimagedirty) - WriteTrack( iDrive); - - ImageClose(pFloppy->imagehandle); - pFloppy->imagehandle = (HIMAGE)0; - } - - if (pFloppy->trackimage) - { - VirtualFree(pFloppy->trackimage,0,MEM_RELEASE); - pFloppy->trackimage = NULL; - pFloppy->trackimagedata = 0; - } - - memset( pFloppy->imagename, 0, MAX_DISK_IMAGE_NAME+1 ); - memset( pFloppy->fullname , 0, MAX_DISK_FULL_NAME +1 ); - pFloppy->strFilenameInZip = ""; - DiskSetDiskPathFilename(iDrive, ""); - - Disk_SaveLastDiskImage( iDrive ); - Video_ResetScreenshotCounter( NULL ); -} - -//=========================================================================== - -static void WriteTrack(const int iDrive) -{ - Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; - - if (pFloppy->track >= ImageGetNumTracks(pFloppy->imagehandle)) - return; - - if (pFloppy->bWriteProtected) - return; - - if (pFloppy->trackimage && pFloppy->imagehandle) - ImageWriteTrack( - pFloppy->imagehandle, - pFloppy->track, - pFloppy->phase, - pFloppy->trackimage, - pFloppy->nibbles ); - - pFloppy->trackimagedirty = 0; -} - -// -// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- -// - -//=========================================================================== - -void DiskBoot(void) -{ - // THIS FUNCTION RELOADS A PROGRAM IMAGE IF ONE IS LOADED IN DRIVE ONE. - // IF A DISK IMAGE OR NO IMAGE IS LOADED IN DRIVE ONE, IT DOES NOTHING. - if (g_aFloppyDisk[0].imagehandle && ImageBoot(g_aFloppyDisk[0].imagehandle)) - floppymotoron = 0; -} - -//=========================================================================== - -static BYTE __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG) -{ - floppymotoron = address & 1; - CheckSpinning(); - return MemReturnRandomData(1); -} - -//=========================================================================== - -static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG) -{ - Disk_t * fptr = &g_aFloppyDisk[currdrive]; -#if 1 - int phase = (address >> 1) & 3; - int phase_bit = (1 << phase); - - // update the magnet states - if (address & 1) - { - // phase on - phases |= phase_bit; - LOG_DISK("track %02X phases %X phase %d on address $C0E%X\r", fptr->phase, phases, phase, address & 0xF); - } - else - { - // phase off - phases &= ~phase_bit; - LOG_DISK("track %02X phases %X phase %d off address $C0E%X\r", fptr->phase, phases, phase, address & 0xF); - } - - // check for any stepping effect from a magnet - // - move only when the magnet opposite the cog is off - // - move in the direction of an adjacent magnet if one is on - // - do not move if both adjacent magnets are on - // momentum and timing are not accounted for ... maybe one day! - int direction = 0; - if (phases & (1 << ((fptr->phase + 1) & 3))) - direction += 1; - if (phases & (1 << ((fptr->phase + 3) & 3))) - direction -= 1; - - // apply magnet step, if any - if (direction) - { - fptr->phase = MAX(0, MIN(79, fptr->phase + direction)); - const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); - const int newtrack = (nNumTracksInImage == 0) ? 0 - : MIN(nNumTracksInImage-1, fptr->phase >> 1); // (round half tracks down) - LOG_DISK("newtrack %2X%s\r", newtrack, (fptr->phase & 1) ? ".5" : ""); - if (newtrack != fptr->track) - { - if (fptr->trackimage && fptr->trackimagedirty) - { - WriteTrack(currdrive); - } - fptr->track = newtrack; - fptr->trackimagedata = 0; - } - } -#else // Old 1.13.1 code for Chessmaster 2000 to work! (see bug#18109) - const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); - if (address & 1) { - int phase = (address >> 1) & 3; - int direction = 0; - if (phase == ((fptr->phase+1) & 3)) - direction = 1; - if (phase == ((fptr->phase+3) & 3)) - direction = -1; - if (direction) { - fptr->phase = MAX(0,MIN(79,fptr->phase+direction)); - if (!(fptr->phase & 1)) { - int newtrack = MIN(nNumTracksInImage-1,fptr->phase >> 1); - if (newtrack != fptr->track) { - if (fptr->trackimage && fptr->trackimagedirty) - WriteTrack(currdrive); - fptr->track = newtrack; - fptr->trackimagedata = 0; - } - } - } - } -#endif - return (address == 0xE0) ? 0xFF : MemReturnRandomData(1); -} - -//=========================================================================== - -void DiskDestroy(void) -{ - g_bSaveDiskImage = false; - RemoveDisk(DRIVE_1); - - g_bSaveDiskImage = false; - RemoveDisk(DRIVE_2); - - g_bSaveDiskImage = true; -} - -//=========================================================================== - -static BYTE __stdcall DiskEnable(WORD, WORD address, BYTE, BYTE, ULONG) -{ - currdrive = address & 1; - g_aFloppyDisk[!currdrive].spinning = 0; - g_aFloppyDisk[!currdrive].writelight = 0; - CheckSpinning(); - return 0; -} - -//=========================================================================== - -void DiskEject(const int iDrive) -{ - if (IsDriveValid(iDrive)) - { - RemoveDisk(iDrive); - } -} - -//=========================================================================== - -// Return the file or zip name -// . Used by Property Sheet Page (Disk) -LPCTSTR DiskGetFullName(const int iDrive) -{ - return g_aFloppyDisk[iDrive].fullname; -} - -// Return the filename -// . Used by Drive Buttons' tooltips -LPCTSTR DiskGetFullDiskFilename(const int iDrive) -{ - if (!g_aFloppyDisk[iDrive].strFilenameInZip.empty()) - return g_aFloppyDisk[iDrive].strFilenameInZip.c_str(); - - return DiskGetFullName(iDrive); -} - -// Return the imagename -// . Used by Drive Button's icons & Property Sheet Page (Save snapshot) -LPCTSTR DiskGetBaseName(const int iDrive) -{ - return g_aFloppyDisk[iDrive].imagename; -} -//=========================================================================== - -void DiskGetLightStatus(Disk_Status_e *pDisk1Status_, Disk_Status_e *pDisk2Status_) -{ -// *drive1 = g_aFloppyDisk[0].spinning ? g_aFloppyDisk[0].writelight ? 2 : 1 : 0; -// *drive2 = g_aFloppyDisk[1].spinning ? g_aFloppyDisk[1].writelight ? 2 : 1 : 0; - - if (pDisk1Status_) - *pDisk1Status_ = GetDriveLightStatus( 0 ); - if (pDisk2Status_) - *pDisk2Status_ = GetDriveLightStatus( 1 ); -} - -//=========================================================================== - -void DiskInitialize(void) -{ - int loop = NUM_DRIVES; - while (loop--) - ZeroMemory(&g_aFloppyDisk[loop],sizeof(Disk_t )); - - TCHAR imagefilename[MAX_PATH]; - _tcscpy(imagefilename,g_sProgramDir); -} - -//=========================================================================== - -ImageError_e DiskInsert(const int iDrive, LPCTSTR pszImageFilename, const bool bForceWriteProtected, const bool bCreateIfNecessary) -{ - Disk_t * fptr = &g_aFloppyDisk[iDrive]; - if (fptr->imagehandle) - RemoveDisk(iDrive); - - // Reset the drive's struct, but preserve the physical attributes (bug#18242: Platoon) - // . Changing the disk (in the drive) doesn't affect the drive's head etc. - { - int track = fptr->track; - int phase = fptr->phase; - ZeroMemory(fptr, sizeof(Disk_t)); - fptr->track = track; - fptr->phase = phase; - } - - const DWORD dwAttributes = GetFileAttributes(pszImageFilename); - if(dwAttributes == INVALID_FILE_ATTRIBUTES) - fptr->bWriteProtected = false; // Assume this is a new file to create - else - fptr->bWriteProtected = bForceWriteProtected ? true : (dwAttributes & FILE_ATTRIBUTE_READONLY); - - ImageError_e Error = ImageOpen(pszImageFilename, - &fptr->imagehandle, - &fptr->bWriteProtected, - bCreateIfNecessary, - fptr->strFilenameInZip); - - if (Error == eIMAGE_ERROR_NONE && ImageIsMultiFileZip(fptr->imagehandle)) - { - TCHAR szText[100+MAX_PATH]; - wsprintf(szText, "Only the first file in a multi-file zip is supported\nUse disk image '%s' ?", fptr->strFilenameInZip.c_str()); - int nRes = MessageBox(g_hFrameWindow, szText, TEXT("Multi-Zip Warning"), MB_ICONWARNING | MB_YESNO | MB_SETFOREGROUND); - if (nRes == IDNO) - { - RemoveDisk(iDrive); - Error = eIMAGE_ERROR_REJECTED_MULTI_ZIP; - } - } - - if (Error == eIMAGE_ERROR_NONE) - { - GetImageTitle(pszImageFilename, fptr); - - DiskSetDiskPathFilename(iDrive, pszImageFilename); - - //MessageBox( g_hFrameWindow, imagefilename, fptr->imagename, MB_OK ); - Video_ResetScreenshotCounter( fptr->imagename ); - } - else - { - Video_ResetScreenshotCounter( NULL ); - } - - Disk_SaveLastDiskImage( iDrive ); - - return Error; -} - -//=========================================================================== - -BOOL DiskIsSpinning(void) -{ - return floppymotoron; -} - -//=========================================================================== - -void DiskNotifyInvalidImage(const int iDrive, LPCTSTR pszImageFilename, const ImageError_e Error) -{ - TCHAR szBuffer[MAX_PATH+128]; - - switch (Error) - { - case eIMAGE_ERROR_UNABLE_TO_OPEN: - case eIMAGE_ERROR_UNABLE_TO_OPEN_GZ: - case eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP: - wsprintf( - szBuffer, - TEXT("Unable to open the file %s."), - pszImageFilename); - break; - - case eIMAGE_ERROR_BAD_SIZE: - wsprintf( - szBuffer, - TEXT("Unable to use the file %s\nbecause the ") - TEXT("disk image is an unsupported size."), - pszImageFilename); - break; - - case eIMAGE_ERROR_BAD_FILE: - wsprintf( - szBuffer, - TEXT("Unable to use the file %s\nbecause the ") - TEXT("OS can't access it."), - pszImageFilename); - break; - - case eIMAGE_ERROR_UNSUPPORTED: - wsprintf( - szBuffer, - TEXT("Unable to use the file %s\nbecause the ") - TEXT("disk image format is not recognized."), - pszImageFilename); - break; - - case eIMAGE_ERROR_UNSUPPORTED_HDV: - wsprintf( - szBuffer, - TEXT("Unable to use the file %s\n") - TEXT("because this UniDisk 3.5/Apple IIGS/hard-disk image is not supported.\n") - TEXT("Try inserting as a hard-disk image instead."), - pszImageFilename); - break; - - case eIMAGE_ERROR_UNSUPPORTED_MULTI_ZIP: - wsprintf( - szBuffer, - TEXT("Unable to use the file %s\nbecause the ") - TEXT("first file (%s) in this multi-zip archive is not recognized.\n") - TEXT("Try unzipping and using the disk images directly.\n"), - pszImageFilename, - g_aFloppyDisk[iDrive].strFilenameInZip.c_str()); - break; - - case eIMAGE_ERROR_GZ: - case eIMAGE_ERROR_ZIP: - wsprintf( - szBuffer, - TEXT("Unable to use the compressed file %s\nbecause the ") - TEXT("compressed disk image is corrupt/unsupported."), - pszImageFilename); - break; - - default: - // IGNORE OTHER ERRORS SILENTLY - return; - } - - MessageBox( - g_hFrameWindow, - szBuffer, - g_pAppTitle, - MB_ICONEXCLAMATION | MB_SETFOREGROUND); -} - - -//=========================================================================== - -bool DiskGetProtect(const int iDrive) -{ - if (IsDriveValid(iDrive)) - { - Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; - if (pFloppy->bWriteProtected) - return true; - } - return false; -} - - -//=========================================================================== - -void DiskSetProtect(const int iDrive, const bool bWriteProtect) -{ - if (IsDriveValid( iDrive )) - { - Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; - pFloppy->bWriteProtected = bWriteProtect; - } -} - - -//=========================================================================== - -bool Disk_ImageIsWriteProtected(const int iDrive) -{ - if (!IsDriveValid(iDrive)) - return true; - - Disk_t *pFloppy = &g_aFloppyDisk[iDrive]; - return ImageIsWriteProtected(pFloppy->imagehandle); -} - -//=========================================================================== - -bool Disk_IsDriveEmpty(const int iDrive) -{ - if (!IsDriveValid(iDrive)) - return true; - - Disk_t *pFloppy = &g_aFloppyDisk[iDrive]; - return pFloppy->imagehandle == NULL; -} - -//=========================================================================== - -static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULONG) -{ - Disk_t * fptr = &g_aFloppyDisk[currdrive]; - - diskaccessed = 1; - - if (!fptr->trackimagedata && fptr->imagehandle) - ReadTrack(currdrive); - - if (!fptr->trackimagedata) - return 0xFF; - - BYTE result = 0; - - if (!floppywritemode || !fptr->bWriteProtected) - { - if (floppywritemode) - { - if (floppylatch & 0x80) - { - *(fptr->trackimage+fptr->byte) = floppylatch; - fptr->trackimagedirty = 1; - } - else - { - return 0; - } - } - else - { - result = *(fptr->trackimage+fptr->byte); - } - } - - if (0) - { LOG_DISK("nib %4X = %2X\r", fptr->byte, result); } - - if (++fptr->byte >= fptr->nibbles) - fptr->byte = 0; - - return result; -} - -//=========================================================================== - -void DiskReset(void) -{ - floppymotoron = 0; - phases = 0; -} - -//=========================================================================== - -void DiskSelectImage(const int iDrive, LPSTR pszFilename) -{ - TCHAR directory[MAX_PATH] = TEXT(""); - TCHAR filename[MAX_PATH] = TEXT(""); - TCHAR title[40]; - - strcpy(filename, pszFilename); - - RegLoadString(TEXT(REG_PREFS), REGVALUE_PREF_START_DIR, 1, directory, MAX_PATH); - _tcscpy(title, TEXT("Select Disk Image For Drive ")); - _tcscat(title, iDrive ? TEXT("2") : TEXT("1")); - - _ASSERT(sizeof(OPENFILENAME) == sizeof(OPENFILENAME_NT4)); // Required for Win98/ME support (selected by _WIN32_WINNT=0x0400 in stdafx.h) - - OPENFILENAME ofn; - ZeroMemory(&ofn,sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = g_hFrameWindow; - ofn.hInstance = g_hInstance; - ofn.lpstrFilter = TEXT("All Images\0*.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.zip;*.2mg;*.2img;*.iie;*.apl\0") - TEXT("Disk Images (*.bin,*.do,*.dsk,*.nib,*.po,*.gz,*.zip,*.2mg,*.2img,*.iie)\0*.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.zip;*.2mg;*.2img;*.iie\0") - TEXT("All Files\0*.*\0"); - ofn.lpstrFile = filename; - ofn.nMaxFile = MAX_PATH; - ofn.lpstrInitialDir = directory; - ofn.Flags = OFN_PATHMUSTEXIST; - ofn.lpstrTitle = title; - - if (GetOpenFileName(&ofn)) - { - if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension]) - _tcscat(filename,TEXT(".dsk")); - - ImageError_e Error = DiskInsert(iDrive, filename, ofn.Flags & OFN_READONLY, IMAGE_CREATE); - if (Error == eIMAGE_ERROR_NONE) - { - DiskSetDiskPathFilename(iDrive, filename); - filename[ofn.nFileOffset] = 0; - if (_tcsicmp(directory, filename)) - RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, filename); - } - else - { - DiskNotifyInvalidImage(iDrive, filename, Error); - } - } -} - -//=========================================================================== - -void DiskSelect(const int iDrive) -{ - DiskSelectImage(iDrive, TEXT("")); -} - -//=========================================================================== - -static BYTE __stdcall DiskSetLatchValue(WORD, WORD, BYTE write, BYTE value, ULONG) { - if (write) - floppylatch = value; - return floppylatch; -} - -//=========================================================================== - -static BYTE __stdcall DiskSetReadMode(WORD, WORD, BYTE, BYTE, ULONG) -{ - floppywritemode = 0; - return MemReturnRandomData(g_aFloppyDisk[currdrive].bWriteProtected); -} - -//=========================================================================== - -static BYTE __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG) -{ - floppywritemode = 1; - BOOL modechange = !g_aFloppyDisk[currdrive].writelight; - g_aFloppyDisk[currdrive].writelight = 20000; - if (modechange) - FrameRefreshStatus(DRAW_LEDS); - return MemReturnRandomData(1); -} - -//=========================================================================== - -void DiskUpdatePosition(DWORD cycles) -{ - int loop = NUM_DRIVES; - while (loop--) - { - Disk_t * fptr = &g_aFloppyDisk[loop]; - - if (fptr->spinning && !floppymotoron) { - if (!(fptr->spinning -= MIN(fptr->spinning, (cycles >> 6)))) - FrameRefreshStatus(DRAW_LEDS); - } - - if (floppywritemode && (currdrive == loop) && fptr->spinning) - { - fptr->writelight = 20000; - } - else if (fptr->writelight) - { - if (!(fptr->writelight -= MIN(fptr->writelight, (cycles >> 6)))) - FrameRefreshStatus(DRAW_LEDS); - } - - if ((!enhancedisk) && (!diskaccessed) && fptr->spinning) - { - fptr->byte += (cycles >> 5); - if (fptr->byte >= fptr->nibbles) - fptr->byte -= fptr->nibbles; - } - } - - diskaccessed = 0; -} - -//=========================================================================== - -bool DiskDriveSwap(void) -{ - // Refuse to swap if either Disk][ is active - if(g_aFloppyDisk[0].spinning || g_aFloppyDisk[1].spinning) - return false; - - // Swap disks between drives - // . NB. We swap trackimage ptrs (so don't need to swap the buffers' data) - // . TODO: Consider array of Pointers: Disk_t* g_aDrive[] - swap(g_aFloppyDisk[0], g_aFloppyDisk[1]); - - Disk_SaveLastDiskImage(DRIVE_1); - Disk_SaveLastDiskImage(DRIVE_2); - - FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); - - return true; -} - -//=========================================================================== - -static BYTE __stdcall Disk_IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); -static BYTE __stdcall Disk_IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); - -// TODO: LoadRom_Disk_Floppy() -void DiskLoadRom(LPBYTE pCxRomPeripheral, UINT uSlot) -{ - const UINT DISK2_FW_SIZE = APPLE_SLOT_SIZE; - - HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_DISK2_FW), "FIRMWARE"); - if(hResInfo == NULL) - return; - - DWORD dwResSize = SizeofResource(NULL, hResInfo); - if(dwResSize != DISK2_FW_SIZE) - return; - - HGLOBAL hResData = LoadResource(NULL, hResInfo); - if(hResData == NULL) - return; - - BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource - if(pData == NULL) - return; - - memcpy(pCxRomPeripheral + uSlot*APPLE_SLOT_SIZE, pData, DISK2_FW_SIZE); - - // NB. We used to disable the track stepping delay in the Disk II controller firmware by - // patching $C64C with $A9,$00,$EA. Now not doing this since: - // . Authentic Speed should be authentic - // . Enhanced Speed runs emulation unthrottled, so removing the delay has negligible effect - // . Patching the firmware breaks the ADC checksum used by "The CIA Files" (Tricky Dick) - // . In this case we can patch to compensate for an ADC or EOR checksum but not both - - RegisterIoHandler(uSlot, Disk_IORead, Disk_IOWrite, NULL, NULL, NULL, NULL); -} - -//=========================================================================== - -static BYTE __stdcall Disk_IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) -{ - addr &= 0xFF; - - switch (addr & 0xf) - { - case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); - } - - return 0; -} - -static BYTE __stdcall Disk_IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) -{ - addr &= 0xFF; - - switch (addr & 0xf) - { - case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); - case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); - case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); - case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); - case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); - case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); - case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); - } - - return 0; -} - -//=========================================================================== - -DWORD DiskGetSnapshot(SS_CARD_DISK2* pSS, DWORD dwSlot) -{ - pSS->Hdr.UnitHdr.dwLength = sizeof(SS_CARD_DISK2); - pSS->Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,2); - - pSS->Hdr.dwSlot = dwSlot; - pSS->Hdr.dwType = CT_Disk2; - - pSS->phases = phases; // new in 1.0.0.2 disk snapshots - pSS->currdrive = currdrive; // this was an int in 1.0.0.1 disk snapshots - pSS->diskaccessed = diskaccessed; - pSS->enhancedisk = enhancedisk; - pSS->floppylatch = floppylatch; - pSS->floppymotoron = floppymotoron; - pSS->floppywritemode = floppywritemode; - - for(UINT i=0; iUnit[i].szFileName, g_aFloppyDisk[i].fullname); - pSS->Unit[i].track = g_aFloppyDisk[i].track; - pSS->Unit[i].phase = g_aFloppyDisk[i].phase; - pSS->Unit[i].byte = g_aFloppyDisk[i].byte; - pSS->Unit[i].writeprotected = g_aFloppyDisk[i].bWriteProtected ? TRUE : FALSE; - pSS->Unit[i].trackimagedata = g_aFloppyDisk[i].trackimagedata; - pSS->Unit[i].trackimagedirty = g_aFloppyDisk[i].trackimagedirty; - pSS->Unit[i].spinning = g_aFloppyDisk[i].spinning; - pSS->Unit[i].writelight = g_aFloppyDisk[i].writelight; - pSS->Unit[i].nibbles = g_aFloppyDisk[i].nibbles; - - if(g_aFloppyDisk[i].trackimage) - memcpy(pSS->Unit[i].nTrack, g_aFloppyDisk[i].trackimage, NIBBLES_PER_TRACK); - else - memset(pSS->Unit[i].nTrack, 0, NIBBLES_PER_TRACK); - } - - return 0; -} - -DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD /*dwSlot*/) -{ - if(pSS->Hdr.UnitHdr.dwVersion > MAKE_VERSION(1,0,0,2)) - { - return -1; - } - - phases = pSS->phases; // new in 1.0.0.2 disk snapshots - currdrive = pSS->currdrive; // this was an int in 1.0.0.1 disk snapshots - diskaccessed = pSS->diskaccessed; - enhancedisk = pSS->enhancedisk; - floppylatch = pSS->floppylatch; - floppymotoron = pSS->floppymotoron; - floppywritemode = pSS->floppywritemode; - - // Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1 - for(UINT i=0; iUnit[i].szFileName[0] == 0x00) - continue; - - DWORD dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName); - if(dwAttributes == INVALID_FILE_ATTRIBUTES) - { - // Get user to browse for file - DiskSelectImage(i, pSS->Unit[i].szFileName); - - dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName); - } - - bool bImageError = false; - if(dwAttributes != INVALID_FILE_ATTRIBUTES) - { - if(DiskInsert(i, pSS->Unit[i].szFileName, dwAttributes & FILE_ATTRIBUTE_READONLY, IMAGE_DONT_CREATE) != eIMAGE_ERROR_NONE) - bImageError = true; - - // DiskInsert() sets up: - // . imagename - // . fullname - // . strDiskPathFilename - // . writeprotected - } - - // - -// strcpy(g_aFloppyDisk[i].fullname, pSS->Unit[i].szFileName); - g_aFloppyDisk[i].track = pSS->Unit[i].track; - g_aFloppyDisk[i].phase = pSS->Unit[i].phase; - g_aFloppyDisk[i].byte = pSS->Unit[i].byte; -// g_aFloppyDisk[i].writeprotected = pSS->Unit[i].writeprotected; - g_aFloppyDisk[i].trackimagedata = pSS->Unit[i].trackimagedata; - g_aFloppyDisk[i].trackimagedirty = pSS->Unit[i].trackimagedirty; - g_aFloppyDisk[i].spinning = pSS->Unit[i].spinning; - g_aFloppyDisk[i].writelight = pSS->Unit[i].writelight; - g_aFloppyDisk[i].nibbles = pSS->Unit[i].nibbles; - - // - - if(!bImageError) - { - if((g_aFloppyDisk[i].trackimage == NULL) && g_aFloppyDisk[i].nibbles) - AllocTrack(i); - - if(g_aFloppyDisk[i].trackimage == NULL) - bImageError = true; - else - memcpy(g_aFloppyDisk[i].trackimage, pSS->Unit[i].nTrack, NIBBLES_PER_TRACK); - } - - if(bImageError) - { - g_aFloppyDisk[i].trackimagedata = 0; - g_aFloppyDisk[i].trackimagedirty = 0; - g_aFloppyDisk[i].nibbles = 0; - } - } - - FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); - - return 0; -} +/* +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 +*/ + +/* Description: Disk + * + * Author: Various + */ + +#include "StdAfx.h" +#include "DiskImage.h" +#include "CPU.h" +#include "..\resource\resource.h" + +#define LOG_DISK_ENABLED 0 + +// __VA_ARGS__ not supported on MSVC++ .NET 7.x +#if (LOG_DISK_ENABLED) + #if !defined(_VC71) + #define LOG_DISK(format, ...) LOG(format, __VA_ARGS__) + #else + #define LOG_DISK LogOutput + #endif +#else + #if !defined(_VC71) + #define LOG_DISK(...) + #else + #define LOG_DISK(x) + #endif +#endif + +// Public _________________________________________________________________________________________ + + BOOL enhancedisk = 1; // TODO: Make static & add accessor funcs + +// Private ________________________________________________________________________________________ + + const int MAX_DISK_IMAGE_NAME = 15; + const int MAX_DISK_FULL_NAME = 127; + + struct Disk_t + { + TCHAR imagename[ MAX_DISK_IMAGE_NAME + 1 ]; // (ie. no extension) + TCHAR fullname [ MAX_DISK_FULL_NAME + 1 ]; // or : This is persisted to the snapshot file + string strDiskPathFilename; + string strFilenameInZip; // 0x00 or + HIMAGE imagehandle; // Init'd by DiskInsert() -> ImageOpen() + int track; + LPBYTE trackimage; + int phase; + int byte; + bool bWriteProtected; + BOOL trackimagedata; + BOOL trackimagedirty; + DWORD spinning; + DWORD writelight; + int nibbles; // Init'd by ReadTrack() -> ImageReadTrack() + + const Disk_t& operator= (const Disk_t& other) + { + memcpy(imagename, other.imagename, sizeof(imagename)); + memcpy(fullname , other.fullname, sizeof(fullname)); + strDiskPathFilename = other.strDiskPathFilename; + strFilenameInZip = other.strFilenameInZip; + imagehandle = other.imagehandle; + track = other.track; + trackimage = other.trackimage; + phase = other.phase; + byte = other.byte; + bWriteProtected = other.bWriteProtected; + trackimagedata = other.trackimagedata; + trackimagedirty = other.trackimagedirty; + spinning = other.spinning; + writelight = other.writelight; + nibbles = other.nibbles; + return *this; + } + }; + +static WORD currdrive = 0; +static BOOL diskaccessed = 0; +static Disk_t g_aFloppyDisk[NUM_DRIVES]; +static BYTE floppylatch = 0; +static BOOL floppymotoron = 0; +static BOOL floppywritemode = 0; +static WORD phases; // state bits for stepper magnet phases 0 - 3 +static bool g_bSaveDiskImage = true; // Save the DiskImage name to Registry + +static DWORD nCyclesLastStep = 0; + +static void CheckSpinning(); +static Disk_Status_e GetDriveLightStatus( const int iDrive ); +static bool IsDriveValid( const int iDrive ); +static void ReadTrack (int drive); +static void RemoveDisk (int drive); +static void WriteTrack (int drive); + +//=========================================================================== + +int DiskGetCurrentDrive(void) { return currdrive; } +int DiskGetCurrentTrack(void) { return g_aFloppyDisk[currdrive].track; } +int DiskGetCurrentPhase(void) { return g_aFloppyDisk[currdrive].phase; } +int DiskGetCurrentOffset(void) { return g_aFloppyDisk[currdrive].byte; } + +const string& DiskGetDiskPathFilename(const int iDrive) +{ + return g_aFloppyDisk[iDrive].strDiskPathFilename; +} + +static void DiskSetDiskPathFilename(const int iDrive, const string strPathName) +{ + g_aFloppyDisk[iDrive].strDiskPathFilename = strPathName; +} + +char* DiskGetCurrentState(void) +{ + if (g_aFloppyDisk[currdrive].imagehandle == NULL) + return "Empty"; + + if (!floppymotoron) + { + if (g_aFloppyDisk[currdrive].spinning > 0) + return "Off (spinning)"; + else + return "Off"; + } + else if (floppywritemode) + { + if (g_aFloppyDisk[currdrive].bWriteProtected) + return "Writing"; + else + return "Writing (write protected)"; + } + else + { + return "Reading"; + } +} + +//=========================================================================== + + void Disk_LoadLastDiskImage(const int iDrive) +{ + _ASSERT(iDrive == DRIVE_1 || iDrive == DRIVE_2); + + char sFilePath[ MAX_PATH + 1]; + sFilePath[0] = 0; + + char *pRegKey = (iDrive == DRIVE_1) + ? REGVALUE_PREF_LAST_DISK_1 + : REGVALUE_PREF_LAST_DISK_2; + + if (RegLoadString(TEXT(REG_PREFS),pRegKey,1,sFilePath,MAX_PATH)) + { + sFilePath[ MAX_PATH ] = 0; + DiskSetDiskPathFilename(iDrive, sFilePath); + +#if _DEBUG +// MessageBox(g_hFrameWindow,pFileName,pRegKey,MB_OK); +#endif + + // _tcscat(imagefilename,TEXT("MASTER.DSK")); // TODO: Should remember last disk by user + g_bSaveDiskImage = false; + // Pass in ptr to local copy of filepath, since RemoveDisk() sets DiskPathFilename = "" + DiskInsert(iDrive, sFilePath, IMAGE_USE_FILES_WRITE_PROTECT_STATUS, IMAGE_DONT_CREATE); + g_bSaveDiskImage = true; + } + //else MessageBox(g_hFrameWindow,"Reg Key/Value not found",pRegKey,MB_OK); +} + +//=========================================================================== + +void Disk_SaveLastDiskImage(const int iDrive) +{ + _ASSERT(iDrive == DRIVE_1 || iDrive == DRIVE_2); + + if (!g_bSaveDiskImage) + return; + + const char *pFileName = DiskGetDiskPathFilename(iDrive).c_str(); + + if (iDrive == DRIVE_1) + RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_1, TRUE, pFileName); + else + RegSaveString(TEXT(REG_PREFS), REGVALUE_PREF_LAST_DISK_2, TRUE, pFileName); +} + +//=========================================================================== + +static void CheckSpinning(void) +{ + DWORD modechange = (floppymotoron && !g_aFloppyDisk[currdrive].spinning); + if (floppymotoron) + g_aFloppyDisk[currdrive].spinning = 20000; + if (modechange) + FrameRefreshStatus(DRAW_LEDS); +} + +//=========================================================================== + +static Disk_Status_e GetDriveLightStatus(const int iDrive) +{ + if (IsDriveValid( iDrive )) + { + Disk_t *pFloppy = & g_aFloppyDisk[ iDrive ]; + + if (pFloppy->spinning) + { + if (pFloppy->bWriteProtected) + return DISK_STATUS_PROT; + + if (pFloppy->writelight) + return DISK_STATUS_WRITE; + else + return DISK_STATUS_READ; + } + else + return DISK_STATUS_OFF; + } + + return DISK_STATUS_OFF; +} + +//=========================================================================== + +static void GetImageTitle(LPCTSTR imagefilename, Disk_t* fptr) +{ + TCHAR imagetitle[ MAX_DISK_FULL_NAME+1 ]; + LPCTSTR startpos = imagefilename; + + // imagetitle = + if (_tcsrchr(startpos,TEXT('\\'))) + startpos = _tcsrchr(startpos,TEXT('\\'))+1; + + _tcsncpy(imagetitle,startpos,MAX_DISK_FULL_NAME); + imagetitle[MAX_DISK_FULL_NAME] = 0; + + // if imagetitle contains a lowercase char, then found=1 (why?) + BOOL found = 0; + int loop = 0; + while (imagetitle[loop] && !found) + { + if (IsCharLower(imagetitle[loop])) + found = 1; + else + loop++; + } + + if ((!found) && (loop > 2)) + CharLowerBuff(imagetitle+1,_tcslen(imagetitle+1)); + + // fptr->fullname = + _tcsncpy( fptr->fullname, imagetitle, MAX_DISK_FULL_NAME ); + fptr->fullname[ MAX_DISK_FULL_NAME ] = 0; + + if (imagetitle[0]) + { + LPTSTR dot = imagetitle; + if (_tcsrchr(dot,TEXT('.'))) + dot = _tcsrchr(dot,TEXT('.')); + if (dot > imagetitle) + *dot = 0; + } + + // fptr->imagename = (ie. no extension) + _tcsncpy( fptr->imagename, imagetitle, MAX_DISK_IMAGE_NAME ); + fptr->imagename[ MAX_DISK_IMAGE_NAME ] = 0; +} + + +//=========================================================================== + +static bool IsDriveValid(const int iDrive) +{ + return (iDrive >= 0 && iDrive < NUM_DRIVES); +} + +//=========================================================================== + +static void AllocTrack(const int iDrive) +{ + Disk_t * fptr = &g_aFloppyDisk[iDrive]; + fptr->trackimage = (LPBYTE)VirtualAlloc(NULL, NIBBLES_PER_TRACK, MEM_COMMIT, PAGE_READWRITE); +} + +//=========================================================================== + +static void ReadTrack(const int iDrive) +{ + if (! IsDriveValid( iDrive )) + return; + + Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; + + if (pFloppy->track >= ImageGetNumTracks(pFloppy->imagehandle)) + { + pFloppy->trackimagedata = 0; + return; + } + + if (! pFloppy->trackimage) + AllocTrack( iDrive ); + + if (pFloppy->trackimage && pFloppy->imagehandle) + { + LOG_DISK("track %02X%s read\r", pFloppy->track, (pFloppy->phase & 1) ? ".5" : " "); + + ImageReadTrack( + pFloppy->imagehandle, + pFloppy->track, + pFloppy->phase, + pFloppy->trackimage, + &pFloppy->nibbles); + + pFloppy->byte = 0; + pFloppy->trackimagedata = (pFloppy->nibbles != 0); + } +} + +//=========================================================================== + +static void RemoveDisk(const int iDrive) +{ + Disk_t *pFloppy = &g_aFloppyDisk[iDrive]; + + if (pFloppy->imagehandle) + { + if (pFloppy->trackimage && pFloppy->trackimagedirty) + WriteTrack( iDrive); + + ImageClose(pFloppy->imagehandle); + pFloppy->imagehandle = (HIMAGE)0; + } + + if (pFloppy->trackimage) + { + VirtualFree(pFloppy->trackimage,0,MEM_RELEASE); + pFloppy->trackimage = NULL; + pFloppy->trackimagedata = 0; + } + + memset( pFloppy->imagename, 0, MAX_DISK_IMAGE_NAME+1 ); + memset( pFloppy->fullname , 0, MAX_DISK_FULL_NAME +1 ); + pFloppy->strFilenameInZip = ""; + DiskSetDiskPathFilename(iDrive, ""); + + Disk_SaveLastDiskImage( iDrive ); + Video_ResetScreenshotCounter( NULL ); +} + +//=========================================================================== + +static void WriteTrack(const int iDrive) +{ + Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; + + if (pFloppy->track >= ImageGetNumTracks(pFloppy->imagehandle)) + return; + + if (pFloppy->bWriteProtected) + return; + + if (pFloppy->trackimage && pFloppy->imagehandle) + ImageWriteTrack( + pFloppy->imagehandle, + pFloppy->track, + pFloppy->phase, + pFloppy->trackimage, + pFloppy->nibbles ); + + pFloppy->trackimagedirty = 0; +} + +// +// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- +// + +//=========================================================================== + +void DiskBoot(void) +{ + // THIS FUNCTION RELOADS A PROGRAM IMAGE IF ONE IS LOADED IN DRIVE ONE. + // IF A DISK IMAGE OR NO IMAGE IS LOADED IN DRIVE ONE, IT DOES NOTHING. + if (g_aFloppyDisk[0].imagehandle && ImageBoot(g_aFloppyDisk[0].imagehandle)) + floppymotoron = 0; +} + +//=========================================================================== + +static BYTE __stdcall DiskControlMotor(WORD, WORD address, BYTE, BYTE, ULONG) +{ + floppymotoron = address & 1; + LOG_DISK("motor %s\r", (floppymotoron) ? "on" : "off"); + CheckSpinning(); + return MemReturnRandomData(1); +} + +//=========================================================================== + +static BYTE __stdcall DiskControlStepper(WORD, WORD address, BYTE, BYTE, ULONG) +{ + Disk_t * fptr = &g_aFloppyDisk[currdrive]; + int phase = (address >> 1) & 3; + int phase_bit = (1 << phase); +#if 1 + // update the magnet states + if (address & 1) + { + // phase on + phases |= phase_bit; + } + else + { + // phase off + phases &= ~phase_bit; + } + + // check for any stepping effect from a magnet + // - move only when the magnet opposite the cog is off + // - move in the direction of an adjacent magnet if one is on + // - do not move if both adjacent magnets are on + // momentum and timing are not accounted for ... maybe one day! + int direction = 0; + if (phases & (1 << ((fptr->phase + 1) & 3))) + direction += 1; + if (phases & (1 << ((fptr->phase + 3) & 3))) + direction -= 1; + + // apply magnet step, if any + if (direction) + { + fptr->phase = MAX(0, MIN(79, fptr->phase + direction)); + const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); + const int newtrack = (nNumTracksInImage == 0) ? 0 + : MIN(nNumTracksInImage-1, fptr->phase >> 1); // (round half tracks down) + if (newtrack != fptr->track) + { + if (address & 1 == 0) + LOG_DISK("phase off stepped\r"); + + if (fptr->trackimage && fptr->trackimagedirty) + { + WriteTrack(currdrive); + } + fptr->track = newtrack; + fptr->trackimagedata = 0; + } + } +#else // Old 1.13.1 code for Chessmaster 2000 to work! (see bug#18109) + const int nNumTracksInImage = ImageGetNumTracks(fptr->imagehandle); + if (address & 1) { + int direction = 0; + if (phase == ((fptr->phase+1) & 3)) + direction = 1; + if (phase == ((fptr->phase+3) & 3)) + direction = -1; + if (direction) { + fptr->phase = MAX(0,MIN(79,fptr->phase+direction)); + if (!(fptr->phase & 1)) { + int newtrack = MIN(nNumTracksInImage-1,fptr->phase >> 1); + if (newtrack != fptr->track) { + if (fptr->trackimage && fptr->trackimagedirty) + WriteTrack(currdrive); + fptr->track = newtrack; + fptr->trackimagedata = 0; + } + } + } + } +#endif + if (address & 1) + { + // phase on + phases |= phase_bit; + LOG_DISK("track %02X%s phases %d%d%d%d phase %d on address $C0E%X at %08X\r", + fptr->phase >> 1, (fptr->phase & 1) ? ".5" : " ", phases >> 3, (phases >> 2) & 1, (phases >> 1) & 1, phases & 1, phase, address & 0xF, ((DWORD)g_nCyclesTotal + g_dwCyclesThisFrame) - nCyclesLastStep); + nCyclesLastStep = g_nCyclesTotal + g_dwCyclesThisFrame; + } + else + { + // phase off + phases &= ~phase_bit; + LOG_DISK("track %02X%s phases %d%d%d%d phase %d off address $C0E%X at %08X\r", + fptr->phase >> 1, (fptr->phase & 1) ? ".5" : " ", phases >> 3, (phases >> 2) & 1, (phases >> 1) & 1, phases & 1, phase, address & 0xF, ((DWORD)g_nCyclesTotal + g_dwCyclesThisFrame) - nCyclesLastStep); + nCyclesLastStep = g_nCyclesTotal + g_dwCyclesThisFrame; + } + return (address == 0xE0) ? 0xFF : MemReturnRandomData(1); +} + +//=========================================================================== + +void DiskDestroy(void) +{ + g_bSaveDiskImage = false; + RemoveDisk(DRIVE_1); + + g_bSaveDiskImage = false; + RemoveDisk(DRIVE_2); + + g_bSaveDiskImage = true; +} + +//=========================================================================== + +static BYTE __stdcall DiskEnable(WORD, WORD address, BYTE, BYTE, ULONG) +{ + currdrive = address & 1; + g_aFloppyDisk[!currdrive].spinning = 0; + g_aFloppyDisk[!currdrive].writelight = 0; + CheckSpinning(); + return 0; +} + +//=========================================================================== + +void DiskEject(const int iDrive) +{ + if (IsDriveValid(iDrive)) + { + RemoveDisk(iDrive); + } +} + +//=========================================================================== + +// Return the file or zip name +// . Used by Property Sheet Page (Disk) +LPCTSTR DiskGetFullName(const int iDrive) +{ + return g_aFloppyDisk[iDrive].fullname; +} + +// Return the filename +// . Used by Drive Buttons' tooltips +LPCTSTR DiskGetFullDiskFilename(const int iDrive) +{ + if (!g_aFloppyDisk[iDrive].strFilenameInZip.empty()) + return g_aFloppyDisk[iDrive].strFilenameInZip.c_str(); + + return DiskGetFullName(iDrive); +} + +// Return the imagename +// . Used by Drive Button's icons & Property Sheet Page (Save snapshot) +LPCTSTR DiskGetBaseName(const int iDrive) +{ + return g_aFloppyDisk[iDrive].imagename; +} +//=========================================================================== + +void DiskGetLightStatus(Disk_Status_e *pDisk1Status_, Disk_Status_e *pDisk2Status_) +{ +// *drive1 = g_aFloppyDisk[0].spinning ? g_aFloppyDisk[0].writelight ? 2 : 1 : 0; +// *drive2 = g_aFloppyDisk[1].spinning ? g_aFloppyDisk[1].writelight ? 2 : 1 : 0; + + if (pDisk1Status_) + *pDisk1Status_ = GetDriveLightStatus( 0 ); + if (pDisk2Status_) + *pDisk2Status_ = GetDriveLightStatus( 1 ); +} + +//=========================================================================== + +void DiskInitialize(void) +{ + int loop = NUM_DRIVES; + while (loop--) + ZeroMemory(&g_aFloppyDisk[loop],sizeof(Disk_t )); + + TCHAR imagefilename[MAX_PATH]; + _tcscpy(imagefilename,g_sProgramDir); +} + +//=========================================================================== + +ImageError_e DiskInsert(const int iDrive, LPCTSTR pszImageFilename, const bool bForceWriteProtected, const bool bCreateIfNecessary) +{ + Disk_t * fptr = &g_aFloppyDisk[iDrive]; + if (fptr->imagehandle) + RemoveDisk(iDrive); + + // Reset the drive's struct, but preserve the physical attributes (bug#18242: Platoon) + // . Changing the disk (in the drive) doesn't affect the drive's head etc. + { + int track = fptr->track; + int phase = fptr->phase; + ZeroMemory(fptr, sizeof(Disk_t)); + fptr->track = track; + fptr->phase = phase; + } + + const DWORD dwAttributes = GetFileAttributes(pszImageFilename); + if(dwAttributes == INVALID_FILE_ATTRIBUTES) + fptr->bWriteProtected = false; // Assume this is a new file to create + else + fptr->bWriteProtected = bForceWriteProtected ? true : (dwAttributes & FILE_ATTRIBUTE_READONLY); + + ImageError_e Error = ImageOpen(pszImageFilename, + &fptr->imagehandle, + &fptr->bWriteProtected, + bCreateIfNecessary, + fptr->strFilenameInZip); + + if (Error == eIMAGE_ERROR_NONE && ImageIsMultiFileZip(fptr->imagehandle)) + { + TCHAR szText[100+MAX_PATH]; + wsprintf(szText, "Only the first file in a multi-file zip is supported\nUse disk image '%s' ?", fptr->strFilenameInZip.c_str()); + int nRes = MessageBox(g_hFrameWindow, szText, TEXT("Multi-Zip Warning"), MB_ICONWARNING | MB_YESNO | MB_SETFOREGROUND); + if (nRes == IDNO) + { + RemoveDisk(iDrive); + Error = eIMAGE_ERROR_REJECTED_MULTI_ZIP; + } + } + + if (Error == eIMAGE_ERROR_NONE) + { + GetImageTitle(pszImageFilename, fptr); + + DiskSetDiskPathFilename(iDrive, pszImageFilename); + + //MessageBox( g_hFrameWindow, imagefilename, fptr->imagename, MB_OK ); + Video_ResetScreenshotCounter( fptr->imagename ); + } + else + { + Video_ResetScreenshotCounter( NULL ); + } + + Disk_SaveLastDiskImage( iDrive ); + + return Error; +} + +//=========================================================================== + +BOOL DiskIsSpinning(void) +{ + return floppymotoron; +} + +//=========================================================================== + +void DiskNotifyInvalidImage(const int iDrive, LPCTSTR pszImageFilename, const ImageError_e Error) +{ + TCHAR szBuffer[MAX_PATH+128]; + + switch (Error) + { + case eIMAGE_ERROR_UNABLE_TO_OPEN: + case eIMAGE_ERROR_UNABLE_TO_OPEN_GZ: + case eIMAGE_ERROR_UNABLE_TO_OPEN_ZIP: + wsprintf( + szBuffer, + TEXT("Unable to open the file %s."), + pszImageFilename); + break; + + case eIMAGE_ERROR_BAD_SIZE: + wsprintf( + szBuffer, + TEXT("Unable to use the file %s\nbecause the ") + TEXT("disk image is an unsupported size."), + pszImageFilename); + break; + + case eIMAGE_ERROR_BAD_FILE: + wsprintf( + szBuffer, + TEXT("Unable to use the file %s\nbecause the ") + TEXT("OS can't access it."), + pszImageFilename); + break; + + case eIMAGE_ERROR_UNSUPPORTED: + wsprintf( + szBuffer, + TEXT("Unable to use the file %s\nbecause the ") + TEXT("disk image format is not recognized."), + pszImageFilename); + break; + + case eIMAGE_ERROR_UNSUPPORTED_HDV: + wsprintf( + szBuffer, + TEXT("Unable to use the file %s\n") + TEXT("because this UniDisk 3.5/Apple IIGS/hard-disk image is not supported.\n") + TEXT("Try inserting as a hard-disk image instead."), + pszImageFilename); + break; + + case eIMAGE_ERROR_UNSUPPORTED_MULTI_ZIP: + wsprintf( + szBuffer, + TEXT("Unable to use the file %s\nbecause the ") + TEXT("first file (%s) in this multi-zip archive is not recognized.\n") + TEXT("Try unzipping and using the disk images directly.\n"), + pszImageFilename, + g_aFloppyDisk[iDrive].strFilenameInZip.c_str()); + break; + + case eIMAGE_ERROR_GZ: + case eIMAGE_ERROR_ZIP: + wsprintf( + szBuffer, + TEXT("Unable to use the compressed file %s\nbecause the ") + TEXT("compressed disk image is corrupt/unsupported."), + pszImageFilename); + break; + + default: + // IGNORE OTHER ERRORS SILENTLY + return; + } + + MessageBox( + g_hFrameWindow, + szBuffer, + g_pAppTitle, + MB_ICONEXCLAMATION | MB_SETFOREGROUND); +} + + +//=========================================================================== + +bool DiskGetProtect(const int iDrive) +{ + if (IsDriveValid(iDrive)) + { + Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; + if (pFloppy->bWriteProtected) + return true; + } + return false; +} + + +//=========================================================================== + +void DiskSetProtect(const int iDrive, const bool bWriteProtect) +{ + if (IsDriveValid( iDrive )) + { + Disk_t *pFloppy = &g_aFloppyDisk[ iDrive ]; + pFloppy->bWriteProtected = bWriteProtect; + } +} + + +//=========================================================================== + +bool Disk_ImageIsWriteProtected(const int iDrive) +{ + if (!IsDriveValid(iDrive)) + return true; + + Disk_t *pFloppy = &g_aFloppyDisk[iDrive]; + return ImageIsWriteProtected(pFloppy->imagehandle); +} + +//=========================================================================== + +bool Disk_IsDriveEmpty(const int iDrive) +{ + if (!IsDriveValid(iDrive)) + return true; + + Disk_t *pFloppy = &g_aFloppyDisk[iDrive]; + return pFloppy->imagehandle == NULL; +} + +//=========================================================================== + +static BYTE __stdcall DiskReadWrite (WORD programcounter, WORD, BYTE, BYTE, ULONG) +{ + Disk_t * fptr = &g_aFloppyDisk[currdrive]; + + diskaccessed = 1; + + if (!fptr->trackimagedata && fptr->imagehandle) + ReadTrack(currdrive); + + if (!fptr->trackimagedata) + return 0xFF; + + BYTE result = 0; + + if (!floppywritemode || !fptr->bWriteProtected) + { + if (floppywritemode) + { + if (floppylatch & 0x80) + { + *(fptr->trackimage+fptr->byte) = floppylatch; + fptr->trackimagedirty = 1; + } + else + { + return 0; + } + } + else + { + if (!floppymotoron) + LOG_DISK("reading with motor off at $%04X\r", regs.pc); + + result = *(fptr->trackimage + fptr->byte); + } + } + + if (0) + { LOG_DISK("nib %4X = %2X\r", fptr->byte, result); } + + if (++fptr->byte >= fptr->nibbles) + fptr->byte = 0; + + return result; +} + +//=========================================================================== + +void DiskReset(void) +{ + floppymotoron = 0; + phases = 0; +} + +//=========================================================================== + +void DiskSelectImage(const int iDrive, LPSTR pszFilename) +{ + TCHAR directory[MAX_PATH] = TEXT(""); + TCHAR filename[MAX_PATH] = TEXT(""); + TCHAR title[40]; + + strcpy(filename, pszFilename); + + RegLoadString(TEXT(REG_PREFS), REGVALUE_PREF_START_DIR, 1, directory, MAX_PATH); + _tcscpy(title, TEXT("Select Disk Image For Drive ")); + _tcscat(title, iDrive ? TEXT("2") : TEXT("1")); + + _ASSERT(sizeof(OPENFILENAME) == sizeof(OPENFILENAME_NT4)); // Required for Win98/ME support (selected by _WIN32_WINNT=0x0400 in stdafx.h) + + OPENFILENAME ofn; + ZeroMemory(&ofn,sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = g_hFrameWindow; + ofn.hInstance = g_hInstance; + ofn.lpstrFilter = TEXT("All Images\0*.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.zip;*.2mg;*.2img;*.iie;*.apl\0") + TEXT("Disk Images (*.bin,*.do,*.dsk,*.nib,*.po,*.gz,*.zip,*.2mg,*.2img,*.iie)\0*.bin;*.do;*.dsk;*.nib;*.po;*.gz;*.zip;*.2mg;*.2img;*.iie\0") + TEXT("All Files\0*.*\0"); + ofn.lpstrFile = filename; + ofn.nMaxFile = MAX_PATH; + ofn.lpstrInitialDir = directory; + ofn.Flags = OFN_PATHMUSTEXIST; + ofn.lpstrTitle = title; + + if (GetOpenFileName(&ofn)) + { + if ((!ofn.nFileExtension) || !filename[ofn.nFileExtension]) + _tcscat(filename,TEXT(".dsk")); + + ImageError_e Error = DiskInsert(iDrive, filename, ofn.Flags & OFN_READONLY, IMAGE_CREATE); + if (Error == eIMAGE_ERROR_NONE) + { + DiskSetDiskPathFilename(iDrive, filename); + filename[ofn.nFileOffset] = 0; + if (_tcsicmp(directory, filename)) + RegSaveString(TEXT(REG_PREFS), TEXT(REGVALUE_PREF_START_DIR), 1, filename); + } + else + { + DiskNotifyInvalidImage(iDrive, filename, Error); + } + } +} + +//=========================================================================== + +void DiskSelect(const int iDrive) +{ + DiskSelectImage(iDrive, TEXT("")); +} + +//=========================================================================== + +static BYTE __stdcall DiskSetLatchValue(WORD, WORD, BYTE write, BYTE value, ULONG) { + if (write) + floppylatch = value; + return floppylatch; +} + +//=========================================================================== + +static BYTE __stdcall DiskSetReadMode(WORD, WORD, BYTE, BYTE, ULONG) +{ + floppywritemode = 0; + return MemReturnRandomData(g_aFloppyDisk[currdrive].bWriteProtected); +} + +//=========================================================================== + +static BYTE __stdcall DiskSetWriteMode(WORD, WORD, BYTE, BYTE, ULONG) +{ + floppywritemode = 1; + BOOL modechange = !g_aFloppyDisk[currdrive].writelight; + g_aFloppyDisk[currdrive].writelight = 20000; + if (modechange) + FrameRefreshStatus(DRAW_LEDS); + return MemReturnRandomData(1); +} + +//=========================================================================== + +void DiskUpdatePosition(DWORD cycles) +{ + int loop = NUM_DRIVES; + while (loop--) + { + Disk_t * fptr = &g_aFloppyDisk[loop]; + + if (fptr->spinning && !floppymotoron) { + if (!(fptr->spinning -= MIN(fptr->spinning, (cycles >> 6)))) + FrameRefreshStatus(DRAW_LEDS); + } + + if (floppywritemode && (currdrive == loop) && fptr->spinning) + { + fptr->writelight = 20000; + } + else if (fptr->writelight) + { + if (!(fptr->writelight -= MIN(fptr->writelight, (cycles >> 6)))) + FrameRefreshStatus(DRAW_LEDS); + } + + if ((!enhancedisk) && (!diskaccessed) && fptr->spinning) + { + fptr->byte += (cycles >> 5); + if (fptr->byte >= fptr->nibbles) + fptr->byte -= fptr->nibbles; + } + } + + diskaccessed = 0; +} + +//=========================================================================== + +bool DiskDriveSwap(void) +{ + // Refuse to swap if either Disk][ is active + if(g_aFloppyDisk[0].spinning || g_aFloppyDisk[1].spinning) + return false; + + // Swap disks between drives + // . NB. We swap trackimage ptrs (so don't need to swap the buffers' data) + // . TODO: Consider array of Pointers: Disk_t* g_aDrive[] + swap(g_aFloppyDisk[0], g_aFloppyDisk[1]); + + Disk_SaveLastDiskImage(DRIVE_1); + Disk_SaveLastDiskImage(DRIVE_2); + + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + + return true; +} + +//=========================================================================== + +static BYTE __stdcall Disk_IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); +static BYTE __stdcall Disk_IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); + +// TODO: LoadRom_Disk_Floppy() +void DiskLoadRom(LPBYTE pCxRomPeripheral, UINT uSlot) +{ + const UINT DISK2_FW_SIZE = APPLE_SLOT_SIZE; + + HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(IDR_DISK2_FW), "FIRMWARE"); + if(hResInfo == NULL) + return; + + DWORD dwResSize = SizeofResource(NULL, hResInfo); + if(dwResSize != DISK2_FW_SIZE) + return; + + HGLOBAL hResData = LoadResource(NULL, hResInfo); + if(hResData == NULL) + return; + + BYTE* pData = (BYTE*) LockResource(hResData); // NB. Don't need to unlock resource + if(pData == NULL) + return; + + memcpy(pCxRomPeripheral + uSlot*APPLE_SLOT_SIZE, pData, DISK2_FW_SIZE); + + // NB. We used to disable the track stepping delay in the Disk II controller firmware by + // patching $C64C with $A9,$00,$EA. Now not doing this since: + // . Authentic Speed should be authentic + // . Enhanced Speed runs emulation unthrottled, so removing the delay has negligible effect + // . Patching the firmware breaks the ADC checksum used by "The CIA Files" (Tricky Dick) + // . In this case we can patch to compensate for an ADC or EOR checksum but not both + + RegisterIoHandler(uSlot, Disk_IORead, Disk_IOWrite, NULL, NULL, NULL, NULL); +} + +//=========================================================================== + +static BYTE __stdcall Disk_IORead(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) +{ + addr &= 0xFF; + + switch (addr & 0xf) + { + case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); + case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); + case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); + case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); + case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); + case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); + case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); + case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); + } + + return 0; +} + +static BYTE __stdcall Disk_IOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft) +{ + addr &= 0xFF; + + switch (addr & 0xf) + { + case 0x0: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x1: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x2: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x3: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x4: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x5: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x6: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x7: return DiskControlStepper(pc, addr, bWrite, d, nCyclesLeft); + case 0x8: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); + case 0x9: return DiskControlMotor(pc, addr, bWrite, d, nCyclesLeft); + case 0xA: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); + case 0xB: return DiskEnable(pc, addr, bWrite, d, nCyclesLeft); + case 0xC: return DiskReadWrite(pc, addr, bWrite, d, nCyclesLeft); + case 0xD: return DiskSetLatchValue(pc, addr, bWrite, d, nCyclesLeft); + case 0xE: return DiskSetReadMode(pc, addr, bWrite, d, nCyclesLeft); + case 0xF: return DiskSetWriteMode(pc, addr, bWrite, d, nCyclesLeft); + } + + return 0; +} + +//=========================================================================== + +DWORD DiskGetSnapshot(SS_CARD_DISK2* pSS, DWORD dwSlot) +{ + pSS->Hdr.UnitHdr.dwLength = sizeof(SS_CARD_DISK2); + pSS->Hdr.UnitHdr.dwVersion = MAKE_VERSION(1,0,0,2); + + pSS->Hdr.dwSlot = dwSlot; + pSS->Hdr.dwType = CT_Disk2; + + pSS->phases = phases; // new in 1.0.0.2 disk snapshots + pSS->currdrive = currdrive; // this was an int in 1.0.0.1 disk snapshots + pSS->diskaccessed = diskaccessed; + pSS->enhancedisk = enhancedisk; + pSS->floppylatch = floppylatch; + pSS->floppymotoron = floppymotoron; + pSS->floppywritemode = floppywritemode; + + for(UINT i=0; iUnit[i].szFileName, g_aFloppyDisk[i].fullname); + pSS->Unit[i].track = g_aFloppyDisk[i].track; + pSS->Unit[i].phase = g_aFloppyDisk[i].phase; + pSS->Unit[i].byte = g_aFloppyDisk[i].byte; + pSS->Unit[i].writeprotected = g_aFloppyDisk[i].bWriteProtected ? TRUE : FALSE; + pSS->Unit[i].trackimagedata = g_aFloppyDisk[i].trackimagedata; + pSS->Unit[i].trackimagedirty = g_aFloppyDisk[i].trackimagedirty; + pSS->Unit[i].spinning = g_aFloppyDisk[i].spinning; + pSS->Unit[i].writelight = g_aFloppyDisk[i].writelight; + pSS->Unit[i].nibbles = g_aFloppyDisk[i].nibbles; + + if(g_aFloppyDisk[i].trackimage) + memcpy(pSS->Unit[i].nTrack, g_aFloppyDisk[i].trackimage, NIBBLES_PER_TRACK); + else + memset(pSS->Unit[i].nTrack, 0, NIBBLES_PER_TRACK); + } + + return 0; +} + +DWORD DiskSetSnapshot(SS_CARD_DISK2* pSS, DWORD /*dwSlot*/) +{ + if(pSS->Hdr.UnitHdr.dwVersion > MAKE_VERSION(1,0,0,2)) + { + return -1; + } + + phases = pSS->phases; // new in 1.0.0.2 disk snapshots + currdrive = pSS->currdrive; // this was an int in 1.0.0.1 disk snapshots + diskaccessed = pSS->diskaccessed; + enhancedisk = pSS->enhancedisk; + floppylatch = pSS->floppylatch; + floppymotoron = pSS->floppymotoron; + floppywritemode = pSS->floppywritemode; + + // Eject all disks first in case Drive-2 contains disk to be inserted into Drive-1 + for(UINT i=0; iUnit[i].szFileName[0] == 0x00) + continue; + + DWORD dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName); + if(dwAttributes == INVALID_FILE_ATTRIBUTES) + { + // Get user to browse for file + DiskSelectImage(i, pSS->Unit[i].szFileName); + + dwAttributes = GetFileAttributes(pSS->Unit[i].szFileName); + } + + bool bImageError = false; + if(dwAttributes != INVALID_FILE_ATTRIBUTES) + { + if(DiskInsert(i, pSS->Unit[i].szFileName, dwAttributes & FILE_ATTRIBUTE_READONLY, IMAGE_DONT_CREATE) != eIMAGE_ERROR_NONE) + bImageError = true; + + // DiskInsert() sets up: + // . imagename + // . fullname + // . strDiskPathFilename + // . writeprotected + } + + // + +// strcpy(g_aFloppyDisk[i].fullname, pSS->Unit[i].szFileName); + g_aFloppyDisk[i].track = pSS->Unit[i].track; + g_aFloppyDisk[i].phase = pSS->Unit[i].phase; + g_aFloppyDisk[i].byte = pSS->Unit[i].byte; +// g_aFloppyDisk[i].writeprotected = pSS->Unit[i].writeprotected; + g_aFloppyDisk[i].trackimagedata = pSS->Unit[i].trackimagedata; + g_aFloppyDisk[i].trackimagedirty = pSS->Unit[i].trackimagedirty; + g_aFloppyDisk[i].spinning = pSS->Unit[i].spinning; + g_aFloppyDisk[i].writelight = pSS->Unit[i].writelight; + g_aFloppyDisk[i].nibbles = pSS->Unit[i].nibbles; + + // + + if(!bImageError) + { + if((g_aFloppyDisk[i].trackimage == NULL) && g_aFloppyDisk[i].nibbles) + AllocTrack(i); + + if(g_aFloppyDisk[i].trackimage == NULL) + bImageError = true; + else + memcpy(g_aFloppyDisk[i].trackimage, pSS->Unit[i].nTrack, NIBBLES_PER_TRACK); + } + + if(bImageError) + { + g_aFloppyDisk[i].trackimagedata = 0; + g_aFloppyDisk[i].trackimagedirty = 0; + g_aFloppyDisk[i].nibbles = 0; + } + } + + FrameRefreshStatus(DRAW_LEDS | DRAW_BUTTON_DRIVES); + + return 0; +} diff --git a/source/GenericSocketDriver.cpp b/source/GenericSocketDriver.cpp new file mode 100644 index 00000000..702c8346 --- /dev/null +++ b/source/GenericSocketDriver.cpp @@ -0,0 +1,454 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 - 2012 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 +*/ + +/* This file contains the socket calls */ + +#include "StdAfx.h" +#include "GenericSocketDriver.h" +#define fatal_printf(...) + +#if !(defined _MSC_VER || defined __CYGWIN__) +extern int h_errno; +#else +#define socklen_t int +#endif +int g_wsastartup_called; + +/* Usage: socket_init() called to init socket mode */ +/* At all times, we try to have a listen running on the incoming socket */ +/* If we want to dial out, we close the incoming socket and create a new */ +/* outgoing socket. Any hang-up causes the socket to be closed and it will */ +/* then re-open on a subsequent call to scc_socket_open */ + +void +socket_init(SocketInfo *socket_info_ptr) +{ +#ifdef _WIN32 + WSADATA wsadata; + int ret; + + if(g_wsastartup_called == 0) { + ret = WSAStartup(MAKEWORD(2,0), &wsadata); + printf("WSAStartup ret: %d\n", ret); + g_wsastartup_called = 1; + } +#endif + + socket_info_ptr->host_handle = NULL; + socket_info_ptr->sockfd = -1; /* Indicate no socket open yet */ + socket_info_ptr->rdwrfd = -1; /* Indicate no socket open yet */ + socket_info_ptr->host_addrlen = sizeof(struct sockaddr_in); + socket_info_ptr->host_handle = malloc(socket_info_ptr->host_addrlen); /* Used in accept, freed in shutdown */ + /* Real init will be done when bytes need to be read/write from skt */ + + socket_info_ptr->in_rdptr = 0; + socket_info_ptr->in_wrptr = 0; + socket_info_ptr->out_rdptr = 0; + socket_info_ptr->out_wrptr = 0; +} + +void +socket_shutdown(SocketInfo *socket_info_ptr) +{ + free(socket_info_ptr->host_handle); + socket_info_ptr->host_handle = NULL; +} + +static int +socket_close_handle(SOCKET sockfd) +{ +#if defined(_WIN32) || defined (__OS2__) + return closesocket(sockfd); // a Windows socket handle is not a file descriptor +#else + return close(sockfd); +#endif +} + +void +socket_maybe_open_incoming(SocketInfo *socket_info_ptr, double dcycs) +{ + struct sockaddr_in sa_in; + int on; + int ret; + SOCKET sockfd; + int inc; + + inc = 0; + + if(socket_info_ptr->sockfd != -1) { + /* it's already open, get out */ + return; + } + + if (socket_info_ptr-> listen_tries == 0) { + return; // too many retries + } + + socket_close(socket_info_ptr, dcycs); + memset(socket_info_ptr->host_handle, 0, socket_info_ptr->host_addrlen); + + while(1) { + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if(sockfd == -1) { + printf("socket ret: %d, errno: %d\n", sockfd, errno); + socket_close(socket_info_ptr, dcycs); + return; + } + printf("%s opened socket ret: %d\n", socket_info_ptr->device_name, sockfd); + + on = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)); + if(ret < 0) { + printf("setsockopt REUSEADDR ret: %d, err:%d\n", + ret, errno); + socket_close(socket_info_ptr, dcycs); + return; + } + + memset(&sa_in, 0, sizeof(sa_in)); + sa_in.sin_family = AF_INET; + sa_in.sin_port = htons(socket_info_ptr->listen_port); + sa_in.sin_addr.s_addr = htonl(INADDR_ANY); + + ret = bind(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in)); + + if(ret >= 0) { + ret = listen(sockfd, 1); + break; + } + /* else ret to bind was < 0 */ + printf("bind ret: %d, errno: %d\n", ret, errno); + printf("%s failed to listen on TCP port %d\n", socket_info_ptr->device_name, socket_info_ptr->listen_port); + //inc++; + socket_close_handle(sockfd); + // TODO: add port increment as an option? + //printf("Trying next port: %d\n", SCC_LISTEN_PORT + port); + //if(inc >= 10) { + //printf("Too many retries, quitting\n"); + if (socket_info_ptr->listen_tries > 0) + --socket_info_ptr->listen_tries; + + socket_close(socket_info_ptr, dcycs); + return; + //} + } + + printf("%s listening on TCP port %d\n", socket_info_ptr->device_name, socket_info_ptr->listen_port); + socket_info_ptr->sockfd = sockfd; + socket_make_nonblock(socket_info_ptr, dcycs); +} + +void +socket_open_outgoing(SocketInfo *socket_info_ptr, double dcycs) +{ + struct sockaddr_in sa_in; + struct hostent *hostentptr; + int on; + int ret; + SOCKET sockfd; + + //printf("socket_close being called from socket_open_outgoing\n"); + socket_close(socket_info_ptr, dcycs); + + memset(socket_info_ptr->host_handle, 0, socket_info_ptr->host_addrlen); + + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if(sockfd == -1) { + printf("%s failed to open outgoing socket ret: %d, errno: %d\n", socket_info_ptr->device_name, sockfd, errno); + socket_close(socket_info_ptr, dcycs); + return; + } + printf("%s opened outgoing sockfd ret: %d\n", socket_info_ptr->device_name, sockfd); + + on = 1; + ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)); + if(ret < 0) { + printf("setsockopt REUSEADDR ret: %d, err:%d\n", + ret, errno); + socket_close(socket_info_ptr, dcycs); // TODO: why was this port 1? + return; + } + + memset(&sa_in, 0, sizeof(sa_in)); + sa_in.sin_family = AF_INET; + sa_in.sin_port = htons(23); + hostentptr = gethostbyname((const char*)&socket_info_ptr->hostname[0]); // OG Added Cast + if(hostentptr == 0) { +#if defined(_WIN32) || defined (__OS2__) + fatal_printf("Lookup host %s failed\n", + &socket_info_ptr->hostname[0]); +#else + fatal_printf("Lookup host %s failed, herrno: %d\n", + &socket_info_ptr->hostname[0], h_errno); +#endif + socket_close_handle(sockfd); + socket_close(socket_info_ptr, dcycs); // TODO: why was this port 1? + //x_show_alert(0, 0); + return; + } + memcpy(&sa_in.sin_addr.s_addr, hostentptr->h_addr, + hostentptr->h_length); + /* The above copies the 32-bit internet address into */ + /* sin_addr.s_addr. It's in correct network format */ + + ret = connect(sockfd, (struct sockaddr *)&sa_in, sizeof(sa_in)); + if(ret < 0) { + printf("connect ret: %d, errno: %d\n", ret, errno); + socket_close_handle(sockfd); + socket_close(socket_info_ptr, dcycs); // TODO: why was this port 1? + return; + } + + printf("%s socket is now outgoing to %s\n", socket_info_ptr->device_name, &socket_info_ptr->hostname[0]); + socket_info_ptr->sockfd = sockfd; + socket_make_nonblock(socket_info_ptr, dcycs); + socket_info_ptr->rdwrfd = socket_info_ptr->sockfd; +} + +void +socket_make_nonblock(SocketInfo *socket_info_ptr, double dcycs) +{ + SOCKET sockfd; + int ret; +#if defined(_WIN32) || defined (__OS2__) + u_long flags; +#else + int flags; +#endif + + sockfd = socket_info_ptr->sockfd; + +#if defined(_WIN32) || defined (__OS2__) + flags = 1; + ret = ioctlsocket(sockfd, FIONBIO, &flags); + if(ret != 0) { + printf("ioctlsocket ret: %d\n", ret); + } +#else + flags = fcntl(sockfd, F_GETFL, 0); + if(flags == -1) { + printf("fcntl GETFL ret: %d, errno: %d\n", flags, errno); + socket_close(socket_info_ptr, dcycs); + return; + } + ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + if(ret == -1) { + printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno); + socket_close(socket_info_ptr, dcycs); + return; + } +#endif +} + +void +socket_close(SocketInfo *socket_info_ptr, double dcycs) +{ + int rdwrfd; + SOCKET sockfd; + + rdwrfd = socket_info_ptr->rdwrfd; + if(rdwrfd >= 0) { + printf("socket_close: rdwrfd=%d, closing\n", rdwrfd); + socket_close_handle(rdwrfd); + } + sockfd = socket_info_ptr->sockfd; + if(sockfd != -1) { + printf("socket_close: sockfd=%d, closing\n", sockfd); + socket_close_handle(sockfd); + } + + socket_info_ptr->rdwrfd = -1; + socket_info_ptr->sockfd = -1; +} + +void +socket_accept(SocketInfo *socket_info_ptr, double dcycs) +{ +#ifdef SOCKET_INFO + int flags; + int rdwrfd; + int ret; + + if(socket_info_ptr->sockfd == -1) { + socket_maybe_open_incoming(socket_info_ptr, dcycs); + } + if(socket_info_ptr->sockfd == -1) { + return; /* just give up */ + } + if(socket_info_ptr->rdwrfd == -1) { + rdwrfd = accept(socket_info_ptr->sockfd, (struct sockaddr*)socket_info_ptr->host_handle, + (socklen_t*)&(socket_info_ptr->host_addrlen)); + if(rdwrfd < 0) { + return; + } + + flags = 0; + ret = 0; +#if !defined(_WIN32) && !defined(__OS2__) + /* For Linux, we need to set O_NONBLOCK on the rdwrfd */ + flags = fcntl(rdwrfd, F_GETFL, 0); + if(flags == -1) { + printf("fcntl GETFL ret: %d, errno: %d\n", flags,errno); + return; + } + ret = fcntl(rdwrfd, F_SETFL, flags | O_NONBLOCK); + if(ret == -1) { + printf("fcntl SETFL ret: %d, errno: %d\n", ret, errno); + return; + } +#endif + socket_info_ptr->rdwrfd = rdwrfd; + printf("%s connected on rdwrfd=%d\n", socket_info_ptr->device_name, rdwrfd); + } +#endif +} + +void +socket_fill_readbuf(SocketInfo *socket_info_ptr, int space_left, double dcycs) +{ +#ifdef SOCKET_INFO + byte tmp_buf[256]; + int rdwrfd; + int ret; + int i; + + socket_accept(socket_info_ptr, dcycs); + + rdwrfd = socket_info_ptr->rdwrfd; + if(rdwrfd < 0) { + return; /* just get out */ + } + + /* Try reading some bytes */ + space_left = MIN(space_left, 256); + ret = recv(rdwrfd, (char*)tmp_buf, space_left, 0); // OG Added cast + if(ret > 0) { + for(i = 0; i < ret; i++) { + byte c = tmp_buf[i]; + socket_recvd_char(socket_info_ptr, c, dcycs); + } + } else if(ret == 0) { + /* assume socket close */ + printf("%s disconnecting from rdwrfd=%d (recv got 0)\n", socket_info_ptr->device_name, rdwrfd); + socket_close(socket_info_ptr, dcycs); + } +#endif +} + +void +socket_recvd_char(SocketInfo *socket_info_ptr, int c, double dcycs) +{ + int handled_externally = 0; // TODO: would prefer bool or BOOL, but not sure about non-Windows builds + // TODO: should we add if(socket_info_ptr->sockfd == -1) { + socket_maybe_open_incoming(socket_info_ptr, dcycs); + + if (socket_info_ptr->rx_handler != NULL) { + handled_externally = socket_info_ptr->rx_handler(socket_info_ptr, c); + } + if (!handled_externally) { + // we handle this + // TODO: implement the read buffer + //scc_add_to_readbuf(port, c, dcycs); + } +} + +void +socket_empty_writebuf(SocketInfo *socket_info_ptr, double dcycs) +{ +#ifdef SOCKET_INFO +# if !defined(_WIN32) && !defined(__OS2__) + struct sigaction newact, oldact; +# endif + int rdptr; + int wrptr; + int rdwrfd; + int done; + int ret; + int len; + + /* Try writing some bytes */ + done = 0; + while(!done) { + rdptr = socket_info_ptr->out_rdptr; + wrptr = socket_info_ptr->out_wrptr; + if(rdptr == wrptr) { + done = 1; + break; + } + rdwrfd = socket_info_ptr->rdwrfd; + len = wrptr - rdptr; + if(len < 0) { + len = SOCKET_OUTBUF_SIZE - rdptr; + } + if(len > 32) { + len = 32; + } + if(len <= 0) { + done = 1; + break; + } + + if(rdwrfd == -1) { + socket_maybe_open_incoming(socket_info_ptr, dcycs); + return; + } + +#if defined(_WIN32) || defined (__OS2__) + ret = send(rdwrfd, (const char*)&(socket_info_ptr->out_buf[rdptr]), len, 0); // OG Added Cast +# else + /* ignore SIGPIPE around writes to the socket, so we */ + /* can catch a closed socket and prepare to accept */ + /* a new connection. Otherwise, SIGPIPE kills GSport */ + sigemptyset(&newact.sa_mask); + newact.sa_handler = SIG_IGN; + newact.sa_flags = 0; + sigaction(SIGPIPE, &newact, &oldact); + + ret = send(rdwrfd, &(socket_info_ptr->out_buf[rdptr]), len, 0); + + sigaction(SIGPIPE, &oldact, 0); + /* restore previous SIGPIPE behavior */ +# endif /* WIN32 */ + +#if 0 + printf("sock output: %02x\n", socket_info_ptr->out_buf[rdptr]); +#endif + if(ret == 0) { + done = 1; /* give up for now */ + break; + } else if(ret < 0) { + /* assume socket is dead */ + printf("socket write failed on rdwrfd=%d, closing\n", rdwrfd); + socket_close(socket_info_ptr, dcycs); + done = 1; + break; + } else { + rdptr = rdptr + ret; + if(rdptr >= SOCKET_OUTBUF_SIZE) { + rdptr = rdptr - SOCKET_OUTBUF_SIZE; + } + socket_info_ptr->out_rdptr = rdptr; + } + } +#endif +} diff --git a/source/GenericSocketDriver.h b/source/GenericSocketDriver.h new file mode 100644 index 00000000..392619a4 --- /dev/null +++ b/source/GenericSocketDriver.h @@ -0,0 +1,79 @@ +/* + GSport - an Apple //gs Emulator + Copyright (C) 2010 by GSport contributors + + Based on the KEGS emulator written by and Copyright (C) 2003 Kent Dickey + + 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 +*/ +#ifndef SOCKET_INFO +#define SOCKET_INFO + +#include + +#ifdef _WIN32 +# include +#else +# include +# include +# include +# ifndef SOCKET +# define SOCKET word32 /* for non-windows */ +# endif +#endif + +#define SOCKET_INBUF_SIZE 1024 /* must be a power of 2 */ +#define SOCKET_OUTBUF_SIZE 1024 /* must be a power of 2 */ + +#define MAX_HOSTNAME_SIZE 256 + +typedef struct SocketInfo { + char* device_name; + void* device_data; + SOCKET sockfd; + int listen_port; + int listen_tries; // -1 = infinite + int rdwrfd; + void *host_handle; + int host_addrlen; + + int rx_queue_depth; + byte rx_queue[4]; + BOOL (*rx_handler)(SocketInfo *socket_info_ptr, int c); + + int in_rdptr; + int in_wrptr; + byte in_buf[SOCKET_INBUF_SIZE]; + + int out_rdptr; + int out_wrptr; + byte out_buf[SOCKET_OUTBUF_SIZE]; + + byte hostname[MAX_HOSTNAME_SIZE]; +} SocketInfo; + +/* generic_socket_driver.c */ +void socket_init(SocketInfo *socket_info_ptr); +void socket_shutdown(SocketInfo *socket_info_ptr); +void socket_maybe_open_incoming(SocketInfo *socket_info_ptr, double dcycs); +void socket_open_outgoing(SocketInfo *socket_info_ptr, double dcycs); +void socket_make_nonblock(SocketInfo *socket_info_ptr, double dcycs); +void socket_close(SocketInfo *socket_info_ptr, double dcycs); +void socket_accept(SocketInfo *socket_info_ptr, double dcycs); +void socket_fill_readbuf(SocketInfo *socket_info_ptr, int space_left, double dcycs); +void socket_recvd_char(SocketInfo *socket_info_ptr, int c, double dcycs); +void socket_empty_writebuf(SocketInfo *socket_info_ptr, double dcycs); + +#endif // SOCKET_INFO diff --git a/source/Joystick.cpp b/source/Joystick.cpp index 1d4a2d1d..cb4ac921 100644 --- a/source/Joystick.cpp +++ b/source/Joystick.cpp @@ -1,825 +1,962 @@ -/* -AppleWin : An Apple //e emulator for Windows +/* +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 +*/ + +/* Description: Joystick emulation via keyboard, PC joystick or mouse + * + * Author: Various + */ + +// TC: Extended for 2nd joystick: +// Apple joystick #0 can be emulated with: NONE, JOYSTICKID1, KEYBOARD, MOUSE +// Apple joystick #1 can be emulated with: NONE, JOYSTICKID2, KEYBOARD, MOUSE +// If Apple joystick #0 is using {KEYBOARD | MOUSE} then joystick #1 can't use it. +// If Apple joystick #1 is using KEYBOARD, then disable the standard keys that control Apple switches #0/#1. +// - So that in a 2 player game, player 2 can't cheat by controlling player 1's buttons. +// If Apple joystick #1 is not NONE, then Apple joystick #0 only gets the use of Apple switch #0. +// - When using 2 joysticks, button #1 is used by joystick #1 (Archon). +// Apple joystick #1's button now controls Apple switches #1 and #2. +// - This is because the 2-joystick version of Mario Bros expects the 2nd joystick to control Apple switch #2. + +#include "StdAfx.h" +#include "MouseInterface.h" +#include "Configuration\PropertySheet.h" +#include "GenericSocketDriver.h" + +#define BUTTONTIME 5000 // TODO: Describe this magic number + +enum {DEVICE_NONE=0, DEVICE_JOYSTICK, DEVICE_KEYBOARD, DEVICE_MOUSE}; + +// Indexed by joytype[n] +static const DWORD joyinfo[5] = { DEVICE_NONE, + DEVICE_JOYSTICK, + DEVICE_KEYBOARD, // Cursors (prev: Numpad-Standard) + DEVICE_KEYBOARD, // Numpad (prev: Numpad-Centering) + DEVICE_MOUSE }; + +// Key pad [1..9]; Key pad 0,Key pad '.'; Left ALT,Right ALT +enum JOYKEY { JK_DOWNLEFT=0, + JK_DOWN, + JK_DOWNRIGHT, + JK_LEFT, + JK_CENTRE, + JK_RIGHT, + JK_UPLEFT, + JK_UP, + JK_UPRIGHT, + JK_BUTTON0, + JK_BUTTON1, + JK_OPENAPPLE, + JK_CLOSEDAPPLE, + JK_MAX + }; + +const UINT PDL_MIN = 0; +const UINT PDL_CENTRAL = 127; +const UINT PDL_MAX = 255; + +static BOOL keydown[JK_MAX] = {FALSE}; +static POINT keyvalue[9] = {{PDL_MIN,PDL_MAX}, {PDL_CENTRAL,PDL_MAX}, {PDL_MAX,PDL_MAX}, + {PDL_MIN,PDL_CENTRAL},{PDL_CENTRAL,PDL_CENTRAL},{PDL_MAX,PDL_CENTRAL}, + {PDL_MIN,PDL_MIN}, {PDL_CENTRAL,PDL_MIN}, {PDL_MAX,PDL_MIN}}; + +static DWORD buttonlatch[3] = {0,0,0}; +static BOOL joybutton[3] = {0,0,0}; + +static int joyshrx[2] = {8,8}; +static int joyshry[2] = {8,8}; +static int joysubx[2] = {0,0}; +static int joysuby[2] = {0,0}; + +// Value persisted to Registry for REGVALUE_JOYSTICK0_EMU_TYPE +DWORD joytype[2] = {J0C_JOYSTICK1, J1C_DISABLED}; // Emulation Type for joysticks #0 & #1 + +static BOOL setbutton[3] = {0,0,0}; // Used when a mouse button is pressed/released + +static int xpos[2] = {PDL_CENTRAL,PDL_CENTRAL}; +static int ypos[2] = {PDL_CENTRAL,PDL_CENTRAL}; + +static unsigned __int64 g_nJoyCntrResetCycle = 0; // Abs cycle that joystick counters were reset + +static short g_nPdlTrimX = 0; +static short g_nPdlTrimY = 0; + +enum {JOYPORT_LEFTRIGHT=0, JOYPORT_UPDOWN=1}; + +static UINT g_bJoyportEnabled = 0; // Set to use Joyport to drive the 3 button inputs +static UINT g_uJoyportActiveStick = 0; +static UINT g_uJoyportReadMode = JOYPORT_LEFTRIGHT; + +//=========================================================================== +// TCP/IP Joystick + +static char joystick_device_name[] = "TCP/IP Joystick"; +static SocketInfo TcpIpJoystickSocketInfo[1]; +static int const TcpIpJoystickCommandMaxLength = 1 << 5; // must be a power of 2 +static char TcpIpJoystickCommandBuffer[TcpIpJoystickCommandMaxLength] = "J1 65535 65535 15\n"; // sample data +static int TcpIpJoystickCommandLength = 0; +static bool TcpIpJoystickInitialized = false; + +BOOL TcpIpJoystickSocketRxHandler(SocketInfo *socket_info_ptr, int c) +{ + if (c != '\n') { + TcpIpJoystickCommandBuffer[TcpIpJoystickCommandLength++] = c; + TcpIpJoystickCommandLength &= (TcpIpJoystickCommandMaxLength - 1); + return TRUE; // we handled this + } + + char *token; + int device = 0; + int x = 0, y = 0, buttons = 0; + + TcpIpJoystickCommandBuffer[TcpIpJoystickCommandLength] = '\0'; + TcpIpJoystickCommandLength = 0; + //printf("TCP/IP joystick command=%s\n", TcpIpJoystickCommandBuffer); + token = strtok(TcpIpJoystickCommandBuffer, " "); + if (token != NULL) { + // Device ID: J1, J2, P1, P2, M1 + if (strlen(token) == 2) { + device = token[0] + (token[1] & 0xF); + } + token = strtok(NULL, " "); + } + if (token != NULL) { + x = atoi(token) >> 8; // 0 to 65335 -> 0 to 255 + token = strtok(NULL, " "); + } + if (token != NULL) { + y = atoi(token) >> 8; // 0 to 65335 -> 0 to 255 + token = strtok(NULL, " "); + } + if (token != NULL) { + buttons = atoi(token); // bitfield: 1=SW0 2=SW1 4=SW2 8=SW3 + } + + switch (device) + { + case 'J' + 1: + xpos[0] = x; + ypos[0] = y; + joybutton[0] = buttons & 0x1; + joybutton[1] = buttons & 0x2; + break; + + case 'J' + 2: + xpos[1] = x; + ypos[1] = y; + joybutton[2] = buttons & 0x1; + break; + + case 'P' + 1: + xpos[0] = x; + joybutton[0] = buttons & 0x1; + break; + + case 'P' + 2: + ypos[0] = x; + joybutton[1] = buttons & 0x1; + break; + + case 'M' + 1: + int iX, iMinX, iMaxX; + int iY, iMinY, iMaxY; + sg_Mouse.GetXY(iX, iMinX, iMaxX, iY, iMinY, iMaxY); + float fScaleX = (float)x / (float)255; + float fScaleY = (float)y / (float)255; + int iAppleX = iMinX + (int)(fScaleX * (float)(iMaxX - iMinX)); + int iAppleY = iMinY + (int)(fScaleY * (float)(iMaxY - iMinY)); + sg_Mouse.SetCursorPos(iAppleX, iAppleY); // Set new entry position + sg_Mouse.SetButton(BUTTON0, (buttons & 0x1) ? BUTTON_DOWN : BUTTON_UP); + sg_Mouse.SetButton(BUTTON1, (buttons & 0x2) ? BUTTON_DOWN : BUTTON_UP); + break; + } + return TRUE; // we handled this +} -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 -*/ - -/* Description: Joystick emulation via keyboard, PC joystick or mouse - * - * Author: Various - */ - -// TC: Extended for 2nd joystick: -// Apple joystick #0 can be emulated with: NONE, JOYSTICKID1, KEYBOARD, MOUSE -// Apple joystick #1 can be emulated with: NONE, JOYSTICKID2, KEYBOARD, MOUSE -// If Apple joystick #0 is using {KEYBOARD | MOUSE} then joystick #1 can't use it. -// If Apple joystick #1 is using KEYBOARD, then disable the standard keys that control Apple switches #0/#1. -// - So that in a 2 player game, player 2 can't cheat by controlling player 1's buttons. -// If Apple joystick #1 is not NONE, then Apple joystick #0 only gets the use of Apple switch #0. -// - When using 2 joysticks, button #1 is used by joystick #1 (Archon). -// Apple joystick #1's button now controls Apple switches #1 and #2. -// - This is because the 2-joystick version of Mario Bros expects the 2nd joystick to control Apple switch #2. - -#include "StdAfx.h" -#include "MouseInterface.h" -#include "Configuration\PropertySheet.h" - -#define BUTTONTIME 5000 // TODO: Describe this magic number - -enum {DEVICE_NONE=0, DEVICE_JOYSTICK, DEVICE_KEYBOARD, DEVICE_MOUSE}; - -// Indexed by joytype[n] -static const DWORD joyinfo[5] = { DEVICE_NONE, - DEVICE_JOYSTICK, - DEVICE_KEYBOARD, // Cursors (prev: Numpad-Standard) - DEVICE_KEYBOARD, // Numpad (prev: Numpad-Centering) - DEVICE_MOUSE }; - -// Key pad [1..9]; Key pad 0,Key pad '.'; Left ALT,Right ALT -enum JOYKEY { JK_DOWNLEFT=0, - JK_DOWN, - JK_DOWNRIGHT, - JK_LEFT, - JK_CENTRE, - JK_RIGHT, - JK_UPLEFT, - JK_UP, - JK_UPRIGHT, - JK_BUTTON0, - JK_BUTTON1, - JK_OPENAPPLE, - JK_CLOSEDAPPLE, - JK_MAX - }; - -const UINT PDL_MIN = 0; -const UINT PDL_CENTRAL = 127; -const UINT PDL_MAX = 255; - -static BOOL keydown[JK_MAX] = {FALSE}; -static POINT keyvalue[9] = {{PDL_MIN,PDL_MAX}, {PDL_CENTRAL,PDL_MAX}, {PDL_MAX,PDL_MAX}, - {PDL_MIN,PDL_CENTRAL},{PDL_CENTRAL,PDL_CENTRAL},{PDL_MAX,PDL_CENTRAL}, - {PDL_MIN,PDL_MIN}, {PDL_CENTRAL,PDL_MIN}, {PDL_MAX,PDL_MIN}}; - -static DWORD buttonlatch[3] = {0,0,0}; -static BOOL joybutton[3] = {0,0,0}; - -static int joyshrx[2] = {8,8}; -static int joyshry[2] = {8,8}; -static int joysubx[2] = {0,0}; -static int joysuby[2] = {0,0}; - -// Value persisted to Registry for REGVALUE_JOYSTICK0_EMU_TYPE -DWORD joytype[2] = {J0C_JOYSTICK1, J1C_DISABLED}; // Emulation Type for joysticks #0 & #1 - -static BOOL setbutton[3] = {0,0,0}; // Used when a mouse button is pressed/released - -static int xpos[2] = {PDL_CENTRAL,PDL_CENTRAL}; -static int ypos[2] = {PDL_CENTRAL,PDL_CENTRAL}; - -static unsigned __int64 g_nJoyCntrResetCycle = 0; // Abs cycle that joystick counters were reset - -static short g_nPdlTrimX = 0; -static short g_nPdlTrimY = 0; - -enum {JOYPORT_LEFTRIGHT=0, JOYPORT_UPDOWN=1}; - -static UINT g_bJoyportEnabled = 0; // Set to use Joyport to drive the 3 button inputs -static UINT g_uJoyportActiveStick = 0; -static UINT g_uJoyportReadMode = JOYPORT_LEFTRIGHT; - -//=========================================================================== -void CheckJoystick0() +void TcpIpJoystickShutdown() { - static DWORD lastcheck = 0; - DWORD currtime = GetTickCount(); - if ((currtime-lastcheck >= 10) || joybutton[0] || joybutton[1]) - { - lastcheck = currtime; - JOYINFO info; - if (joyGetPos(JOYSTICKID1,&info) == JOYERR_NOERROR) + if (TcpIpJoystickInitialized) { - if ((info.wButtons & JOY_BUTTON1) && !joybutton[0]) - buttonlatch[0] = BUTTONTIME; - if ((info.wButtons & JOY_BUTTON2) && !joybutton[1] && - (joyinfo[joytype[1]] == DEVICE_NONE) // Only consider 2nd button if NOT emulating a 2nd Apple joystick - ) - buttonlatch[1] = BUTTONTIME; - joybutton[0] = ((info.wButtons & JOY_BUTTON1) != 0); - if (joyinfo[joytype[1]] == DEVICE_NONE) // Only consider 2nd button if NOT emulating a 2nd Apple joystick - joybutton[1] = ((info.wButtons & JOY_BUTTON2) != 0); - - xpos[0] = (info.wXpos-joysubx[0]) >> joyshrx[0]; - ypos[0] = (info.wYpos-joysuby[0]) >> joyshry[0]; - - // NB. This does not work for analogue joysticks (not self-centreing) - except if Trim=0 - if(xpos[0] == 127 || xpos[0] == 128) xpos[0] += g_nPdlTrimX; - if(ypos[0] == 127 || ypos[0] == 128) ypos[0] += g_nPdlTrimY; - } - } + socket_close(&TcpIpJoystickSocketInfo[0], 0); + socket_shutdown(&TcpIpJoystickSocketInfo[0]); + TcpIpJoystickInitialized = false; + } } -void CheckJoystick1() +void TcpIpJoystickInit() { - static DWORD lastcheck = 0; - DWORD currtime = GetTickCount(); - if ((currtime-lastcheck >= 10) || joybutton[2]) - { - lastcheck = currtime; - JOYINFO info; - if (joyGetPos(JOYSTICKID2,&info) == JOYERR_NOERROR) - { - if ((info.wButtons & JOY_BUTTON1) && !joybutton[2]) - { - buttonlatch[2] = BUTTONTIME; - if(joyinfo[joytype[1]] != DEVICE_NONE) - buttonlatch[1] = BUTTONTIME; // Re-map this button when emulating a 2nd Apple joystick - } - - joybutton[2] = ((info.wButtons & JOY_BUTTON1) != 0); - if(joyinfo[joytype[1]] != DEVICE_NONE) - joybutton[1] = ((info.wButtons & JOY_BUTTON1) != 0); // Re-map this button when emulating a 2nd Apple joystick - - xpos[1] = (info.wXpos-joysubx[1]) >> joyshrx[1]; - ypos[1] = (info.wYpos-joysuby[1]) >> joyshry[1]; - - // NB. This does not work for analogue joysticks (not self-centreing) - except if Trim=0 - if(xpos[1] == 127 || xpos[1] == 128) xpos[1] += g_nPdlTrimX; - if(ypos[1] == 127 || ypos[1] == 128) ypos[1] += g_nPdlTrimY; - } - } -} - -// -// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- -// - -//=========================================================================== -void JoyInitialize() -{ - // Emulated joystick #0 can only use JOYSTICKID1 (if no joystick, then use keyboard) - // Emulated joystick #1 can only use JOYSTICKID2 (if no joystick, then disable) - - // - // Init for emulated joystick #0: - // - - if (joyinfo[joytype[0]] == DEVICE_JOYSTICK) - { - JOYCAPS caps; - if (joyGetDevCaps(JOYSTICKID1,&caps,sizeof(JOYCAPS)) == JOYERR_NOERROR) - { - joyshrx[0] = 0; - joyshry[0] = 0; - joysubx[0] = (int)caps.wXmin; - joysuby[0] = (int)caps.wYmin; - UINT xrange = caps.wXmax-caps.wXmin; - UINT yrange = caps.wYmax-caps.wYmin; - while (xrange > 256) - { - xrange >>= 1; - ++joyshrx[0]; - } - while (yrange > 256) - { - yrange >>= 1; - ++joyshry[0]; - } - } - else - { - joytype[0] = J0C_KEYBD_NUMPAD; - } - } - - // - // Init for emulated joystick #1: - // - - if (joyinfo[joytype[1]] == DEVICE_JOYSTICK) - { - JOYCAPS caps; - if (joyGetDevCaps(JOYSTICKID2,&caps,sizeof(JOYCAPS)) == JOYERR_NOERROR) - { - joyshrx[1] = 0; - joyshry[1] = 0; - joysubx[1] = (int)caps.wXmin; - joysuby[1] = (int)caps.wYmin; - UINT xrange = caps.wXmax-caps.wXmin; - UINT yrange = caps.wYmax-caps.wYmin; - while (xrange > 256) - { - xrange >>= 1; - ++joyshrx[1]; - } - while (yrange > 256) - { - yrange >>= 1; - ++joyshry[1]; - } - } - else - { - joytype[1] = J1C_DISABLED; - } - } -} - -//=========================================================================== - -#define SUPPORT_CURSOR_KEYS - -BOOL JoyProcessKey(int virtkey, BOOL extended, BOOL down, BOOL autorep) -{ - static struct - { - UINT32 Left:1; - UINT32 Up:1; - UINT32 Right:1; - UINT32 Down:1; - } CursorKeys = {0}; - - if ( (joyinfo[joytype[0]] != DEVICE_KEYBOARD) && - (joyinfo[joytype[1]] != DEVICE_KEYBOARD) && - (virtkey != VK_MENU) // VK_MENU == ALT Key - ) - { - return 0; - } - - // - - BOOL keychange = 0; - bool bIsCursorKey = false; - - if (virtkey == VK_MENU) // VK_MENU == ALT Key (Button #0 or #1) - { - keychange = 1; - keydown[JK_OPENAPPLE+(extended != 0)] = down; - } - else if (!extended) - { - if (JoyUsingKeyboardNumpad()) - { - keychange = 1; - - if ((virtkey >= VK_NUMPAD1) && (virtkey <= VK_NUMPAD9)) // NumLock on - { - keydown[virtkey-VK_NUMPAD1] = down; - } - else // NumLock off - { - switch (virtkey) - { - case VK_END: keydown[JK_DOWNLEFT] = down; break; - case VK_DOWN: keydown[JK_DOWN] = down; break; - case VK_NEXT: keydown[JK_DOWNRIGHT] = down; break; - case VK_LEFT: keydown[JK_LEFT] = down; break; - case VK_CLEAR: keydown[JK_CENTRE] = down; break; - case VK_RIGHT: keydown[JK_RIGHT] = down; break; - case VK_HOME: keydown[JK_UPLEFT] = down; break; - case VK_UP: keydown[JK_UP] = down; break; - case VK_PRIOR: keydown[JK_UPRIGHT] = down; break; - case VK_NUMPAD0: keydown[JK_BUTTON0] = down; break; - case VK_DECIMAL: keydown[JK_BUTTON1] = down; break; - default: keychange = 0; break; - } - } - } - } -#ifdef SUPPORT_CURSOR_KEYS - else if (extended) - { - if (JoyUsingKeyboardCursors() && (virtkey == VK_LEFT || virtkey == VK_UP || virtkey == VK_RIGHT || virtkey == VK_DOWN)) - { - keychange = 1; // This prevents cursors keys being available to the Apple II (eg. Lode Runner uses cursor left/right for game speed & Ctrl-J/K for joystick/keyboard) - bIsCursorKey = true; - - switch (virtkey) - { - case VK_LEFT: CursorKeys.Left = down; break; - case VK_UP: CursorKeys.Up = down; break; - case VK_RIGHT: CursorKeys.Right = down; break; - case VK_DOWN: CursorKeys.Down = down; break; - } - } - } -#endif - - if (!keychange) - return 0; - - // - - if (virtkey == VK_NUMPAD0) - { - if(down) - { - if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) - { - buttonlatch[0] = BUTTONTIME; - } - else if(joyinfo[joytype[1]] != DEVICE_NONE) - { - buttonlatch[2] = BUTTONTIME; - buttonlatch[1] = BUTTONTIME; // Re-map this button when emulating a 2nd Apple joystick - } - } - } - else if (virtkey == VK_DECIMAL) - { - if(down) - { - if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) - buttonlatch[1] = BUTTONTIME; - } - } - else if ((down && !autorep) || (sg_PropertySheet.GetJoystickCenteringControl() == JOYSTICK_MODE_CENTERING)) - { - int xkeys = 0; - int ykeys = 0; - int xtotal = 0; - int ytotal = 0; - - for (int keynum = JK_DOWNLEFT; keynum <= JK_UPRIGHT; keynum++) - { - if (keydown[keynum]) - { - if ((keynum % 3) != 1) // Not middle col (ie. not VK_DOWN, VK_CLEAR, VK_UP) - { - xkeys++; - xtotal += keyvalue[keynum].x; - } - if ((keynum / 3) != 1) // Not middle row (ie. not VK_LEFT, VK_CLEAR, VK_RIGHT) - { - ykeys++; - ytotal += keyvalue[keynum].y; - } - } - } - - if (CursorKeys.Left) - { - xkeys++; xtotal += keyvalue[JK_LEFT].x; - } - if (CursorKeys.Right) - { - xkeys++; xtotal += keyvalue[JK_RIGHT].x; - } - if (CursorKeys.Up) - { - ykeys++; ytotal += keyvalue[JK_UP].y; - } - if (CursorKeys.Down) - { - ykeys++; ytotal += keyvalue[JK_DOWN].y; - } - - // Joystick # which is being emulated by keyboard - int nJoyNum = (joyinfo[joytype[0]] == DEVICE_KEYBOARD) ? 0 : 1; - - if (xkeys) - xpos[nJoyNum] = xtotal / xkeys; - else - xpos[nJoyNum] = PDL_CENTRAL + g_nPdlTrimX; - - if (ykeys) - ypos[nJoyNum] = ytotal / ykeys; - else - ypos[nJoyNum] = PDL_CENTRAL + g_nPdlTrimY; - } - - if (bIsCursorKey && sg_PropertySheet.GetJoystickCursorControl()) - { - // Allow AppleII keyboard to see this cursor keypress too - return 0; - } - - return 1; -} - -//=========================================================================== - -static void DoAutofire(UINT uButton, BOOL& pressed) -{ - static BOOL toggle[3] = {0}; - static BOOL lastPressed[3] = {0}; - - BOOL nowPressed = pressed; - if (sg_PropertySheet.GetAutofire(uButton) && pressed) - { - toggle[uButton] = (!lastPressed[uButton]) ? TRUE : toggle[uButton] = !toggle[uButton]; - pressed = pressed && toggle[uButton]; - } - lastPressed[uButton] = nowPressed; -} - -BYTE __stdcall JoyportReadButton(WORD address, ULONG nCyclesLeft) -{ - BOOL pressed = 0; - - if (g_uJoyportActiveStick == 0) - { - switch (address) - { - case 0x61: - pressed = (buttonlatch[0] || joybutton[0] || setbutton[0] /*|| keydown[JK_OPENAPPLE]*/); - if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) // BUG? joytype[1] should be [0] ? - pressed = (pressed || keydown[JK_BUTTON0]); - buttonlatch[0] = 0; - break; - - case 0x62: // Left or Up - if (g_uJoyportReadMode == JOYPORT_LEFTRIGHT) // LEFT - { - if (xpos[0] == 0) // TODO: More range for mouse control? - pressed = 1; - } - else // UP - { - if (ypos[0] == 0) // TODO: More range for mouse control? - pressed = 1; - } - break; - - case 0x63: // Right or Down - if (g_uJoyportReadMode == JOYPORT_LEFTRIGHT) // RIGHT - { - if (xpos[0] >= 255) // TODO: More range for mouse control? - pressed = 1; - } - else // DOWN - { - if (ypos[0] >= 255) // TODO: More range for mouse control? - pressed = 1; - } - break; - } - } - else // TODO: stick #1 - { - } - - pressed = pressed ? 0 : 1; // Invert as Joyport signals are active low - - return MemReadFloatingBus(pressed, nCyclesLeft); -} - -BYTE __stdcall JoyReadButton(WORD pc, WORD address, BYTE, BYTE, ULONG nCyclesLeft) -{ - address &= 0xFF; - - if(joyinfo[joytype[0]] == DEVICE_JOYSTICK) - CheckJoystick0(); - if(joyinfo[joytype[1]] == DEVICE_JOYSTICK) - CheckJoystick1(); - - if (g_bJoyportEnabled) - { - // Some extra logic to stop the Joyport forcing a self-test at CTRL+RESET - if ((address != 0x62) || (address == 0x62 && pc != 0xC242 && pc != 0xC2BE)) // Original //e ($C242), Enhanced //e ($C2BE) - return JoyportReadButton(address, nCyclesLeft); - } - - BOOL pressed = 0; - switch (address) - { - case 0x61: - pressed = (buttonlatch[0] || joybutton[0] || setbutton[0] || keydown[JK_OPENAPPLE]); - if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) // BUG? joytype[1] should be [0] ? - pressed = (pressed || keydown[JK_BUTTON0]); - buttonlatch[0] = 0; - DoAutofire(0, pressed); - break; - - case 0x62: - pressed = (buttonlatch[1] || joybutton[1] || setbutton[1] || keydown[JK_CLOSEDAPPLE]); - if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) - pressed = (pressed || keydown[JK_BUTTON1]); - buttonlatch[1] = 0; - DoAutofire(1, pressed); - break; - - case 0x63: - if (IS_APPLE2 && (joyinfo[joytype[1]] == DEVICE_NONE)) - { - // Apple II/II+ with no joystick has the "SHIFT key mod" - // See Sather's Understanding The Apple II p7-36 - pressed = !(GetKeyState(VK_SHIFT) < 0); - } - else - { - pressed = (buttonlatch[2] || joybutton[2] || setbutton[2]); - DoAutofire(2, pressed); - } - buttonlatch[2] = 0; - break; - } - - return MemReadFloatingBus(pressed, nCyclesLeft); -} - -//=========================================================================== - -// PREAD: ; $FB1E -// AD 70 C0 : (4) LDA $C070 -// A0 00 : (2) LDA #$00 -// EA : (2) NOP -// EA : (2) NOP -// Lbl1: ; 11 cycles is the normal duration of the loop -// BD 64 C0 : (4) LDA $C064,X -// 10 04 : (2) BPL Lbl2 ; NB. 3 cycles if branch taken (not likely) -// C8 : (2) INY -// D0 F8 : (3) BNE Lbl1 ; NB. 2 cycles if branch not taken (not likely) -// 88 : (2) DEY -// Lbl2: -// 60 : (6) RTS -// - -static const double PDL_CNTR_INTERVAL = 2816.0 / 255.0; // 11.04 (From KEGS) - -BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, ULONG nCyclesLeft) -{ - int nJoyNum = (address & 2) ? 1 : 0; // $C064..$C067 - - CpuCalcCycles(nCyclesLeft); - - ULONG nPdlPos = (address & 1) ? ypos[nJoyNum] : xpos[nJoyNum]; - - // This is from KEGS. It helps games like Championship Lode Runner & Boulderdash - if(nPdlPos >= 255) - nPdlPos = 280; - - BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL)); - - return MemReadFloatingBus(nPdlCntrActive, nCyclesLeft); -} - -//=========================================================================== -void JoyReset() -{ - int loop = 0; - while (loop < JK_MAX) - keydown[loop++] = FALSE; -} - -//=========================================================================== -BYTE __stdcall JoyResetPosition(WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft) -{ - CpuCalcCycles(nCyclesLeft); - g_nJoyCntrResetCycle = g_nCumulativeCycles; - - if(joyinfo[joytype[0]] == DEVICE_JOYSTICK) - CheckJoystick0(); - if(joyinfo[joytype[1]] == DEVICE_JOYSTICK) - CheckJoystick1(); - - return MemReadFloatingBus(nCyclesLeft); -} - -//=========================================================================== - -// Called when mouse is being used as a joystick && mouse button changes -void JoySetButton(eBUTTON number, eBUTTONSTATE down) -{ - if (number > 1) // Sanity check on mouse button # - return; - - // If 2nd joystick is enabled, then both joysticks only have 1 button - if((joyinfo[joytype[1]] != DEVICE_NONE) && (number != 0)) - return; - - // If it is 2nd joystick that is being emulated with mouse, then re-map button # - if(joyinfo[joytype[1]] == DEVICE_MOUSE) - { - number = BUTTON1; // 2nd joystick controls Apple button #1 - } - - setbutton[number] = down; - - if (down) - buttonlatch[number] = BUTTONTIME; -} - -//=========================================================================== -BOOL JoySetEmulationType(HWND window, DWORD newtype, int nJoystickNumber, const bool bMousecardActive) -{ - if(joytype[nJoystickNumber] == newtype) - return 1; // Already set to this type. Return OK. - - if (joyinfo[newtype] == DEVICE_JOYSTICK) - { - JOYCAPS caps; - unsigned int nJoyID = nJoystickNumber == JN_JOYSTICK0 ? JOYSTICKID1 : JOYSTICKID2; - if (joyGetDevCaps(nJoyID, &caps, sizeof(JOYCAPS)) != JOYERR_NOERROR) - { - MessageBox(window, - TEXT("The emulator is unable to read your PC joystick. ") - TEXT("Ensure that your game port is configured properly, ") - TEXT("that the joystick is firmly plugged in, and that ") - TEXT("you have a joystick driver installed."), - TEXT("Configuration"), - MB_ICONEXCLAMATION | MB_SETFOREGROUND); - return 0; - } - } - else if ((joyinfo[newtype] == DEVICE_MOUSE) && - (joyinfo[joytype[nJoystickNumber]] != DEVICE_MOUSE)) - { - if (bMousecardActive) - { - // Shouldn't be necessary, since Property Sheet's logic should prevent this option being given to the user. - MessageBox(window, - TEXT("Mouse interface card is enabled - unable to use mouse for joystick emulation."), - TEXT("Configuration"), - MB_ICONEXCLAMATION | MB_SETFOREGROUND); - return 0; - } - - MessageBox(window, - TEXT("To begin emulating a joystick with your mouse, move ") - TEXT("the mouse cursor over the emulated screen of a running ") - TEXT("program and click the left mouse button. During the ") - TEXT("time the mouse is emulating a joystick, you will not ") - TEXT("be able to use it to perform mouse functions, and the ") - TEXT("mouse cursor will not be visible. To end joystick ") - TEXT("emulation and regain the mouse cursor, click the left ") - TEXT("mouse button while pressing Ctrl."), - TEXT("Configuration"), - MB_ICONINFORMATION | MB_SETFOREGROUND); - } - else if (joyinfo[newtype] == DEVICE_KEYBOARD) - { - if (newtype == J0C_KEYBD_CURSORS || newtype == J1C_KEYBD_CURSORS) - { - MessageBox(window, - TEXT("Using cursor keys to emulate a joystick can cause conflicts.\n\n") - TEXT("Be aware that 'cursor-up' = CTRL+K, and 'cursor-down' = CTRL+J.\n") - TEXT("EG. Lode Runner uses CTRL+K/J to switch between keyboard/joystick modes ") - TEXT("(and cursor-left/right to control speed).\n\n") - TEXT("Also if cursor keys are blocked from being read from the Apple keyboard ") - TEXT("then even simple AppleSoft command-line editing (cursor left/right) will not work."), - TEXT("Configuration"), - MB_ICONINFORMATION | MB_SETFOREGROUND); - } - } - - joytype[nJoystickNumber] = newtype; - JoyInitialize(); - JoyReset(); - return 1; -} - - -//=========================================================================== - -// Called when mouse is being used as a joystick && mouse position changes -void JoySetPosition(int xvalue, int xrange, int yvalue, int yrange) -{ - int nJoyNum = (joyinfo[joytype[0]] == DEVICE_MOUSE) ? 0 : 1; - xpos[nJoyNum] = (xvalue*255)/xrange; - ypos[nJoyNum] = (yvalue*255)/yrange; -} - -//=========================================================================== -void JoyUpdatePosition() -{ - if (buttonlatch[0]) --buttonlatch[0]; - if (buttonlatch[1]) --buttonlatch[1]; - if (buttonlatch[2]) --buttonlatch[2]; -} - -//=========================================================================== - -BOOL JoyUsingMouse() -{ - return (joyinfo[joytype[0]] == DEVICE_MOUSE) || (joyinfo[joytype[1]] == DEVICE_MOUSE); -} - -BOOL JoyUsingKeyboard() -{ - return (joyinfo[joytype[0]] == DEVICE_KEYBOARD) || (joyinfo[joytype[1]] == DEVICE_KEYBOARD); -} - -BOOL JoyUsingKeyboardCursors() -{ - return (joytype[0] == J0C_KEYBD_CURSORS) || (joytype[1] == J1C_KEYBD_CURSORS); -} - -BOOL JoyUsingKeyboardNumpad() -{ - return (joytype[0] == J0C_KEYBD_NUMPAD) || (joytype[1] == J1C_KEYBD_NUMPAD); -} - -//=========================================================================== - -void JoyDisableUsingMouse() -{ - if (joyinfo[joytype[0]] == DEVICE_MOUSE) - joytype[0] = J0C_DISABLED; - - if (joyinfo[joytype[1]] == DEVICE_MOUSE) - joytype[1] = J1C_DISABLED; -} - -//=========================================================================== - -void JoySetTrim(short nValue, bool bAxisX) -{ - if(bAxisX) - g_nPdlTrimX = nValue; - else - g_nPdlTrimY = nValue; - - int nJoyNum = -1; - - if(joyinfo[joytype[0]] == DEVICE_KEYBOARD) - nJoyNum = 0; - else if(joyinfo[joytype[1]] == DEVICE_KEYBOARD) - nJoyNum = 1; - - if(nJoyNum >= 0) - { - xpos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimX; - ypos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimY; - } -} - -short JoyGetTrim(bool bAxisX) -{ - return bAxisX ? g_nPdlTrimX : g_nPdlTrimY; -} - -//=========================================================================== - -// Joyport truth-table: -// -// AN0 AN1 /PB0 /PB1 /PB2 -// ------------------------------------ -// 0 0 Trigger-1 Left-1 Right-1 -// 0 1 Trigger-1 Up-1 Down-1 -// 1 0 Trigger-2 Left-2 Right-2 -// 1 1 Trigger-2 Up-2 Down-2 - -#if 0 -void JoyportEnable(const bool bEnable) -{ - if (IS_APPLE2C) - g_bJoyportEnabled = false; - else - g_bJoyportEnabled = bEnable ? 1 : 0; -} -#endif - -void JoyportControl(const UINT uControl) -{ - if (!g_bJoyportEnabled) + if (TcpIpJoystickInitialized) return; + + TcpIpJoystickSocketInfo[0].device_name = joystick_device_name; + TcpIpJoystickSocketInfo[0].device_data = NULL; + TcpIpJoystickSocketInfo[0].listen_port = 6503; + TcpIpJoystickSocketInfo[0].listen_tries = 2; + TcpIpJoystickSocketInfo[0].rx_handler = TcpIpJoystickSocketRxHandler; - switch (uControl) - { - case 0: // AN0 clr - g_uJoyportActiveStick = 0; - break; - case 1: // AN0 set - g_uJoyportActiveStick = 1; - break; - case 2: // AN1 clr - g_uJoyportReadMode = JOYPORT_LEFTRIGHT; - break; - case 3: // AN1 set - g_uJoyportReadMode = JOYPORT_UPDOWN; - break; - } + if (sg_PropertySheet.GetTcpIpJoystock()) + { + socket_init(&TcpIpJoystickSocketInfo[0]); + TcpIpJoystickInitialized = true; + } } -//=========================================================================== - -DWORD JoyGetSnapshot(SS_IO_Joystick* pSS) +void TcpIpJoystickUpdate() { - pSS->g_nJoyCntrResetCycle = g_nJoyCntrResetCycle; - return 0; -} - -DWORD JoySetSnapshot(SS_IO_Joystick* pSS) -{ - g_nJoyCntrResetCycle = pSS->g_nJoyCntrResetCycle; - return 0; + if (sg_PropertySheet.GetTcpIpJoystock()) + { + if (TcpIpJoystickInitialized) + socket_fill_readbuf(&TcpIpJoystickSocketInfo[0], 100, 0); + else + TcpIpJoystickInit(); + } + else + { + if (TcpIpJoystickInitialized) + TcpIpJoystickShutdown(); + } } + +//=========================================================================== +void CheckJoystick0() +{ + static DWORD lastcheck = 0; + DWORD currtime = GetTickCount(); + if ((currtime-lastcheck >= 10) || joybutton[0] || joybutton[1]) + { + lastcheck = currtime; + JOYINFO info; + if (joyGetPos(JOYSTICKID1,&info) == JOYERR_NOERROR) + { + if ((info.wButtons & JOY_BUTTON1) && !joybutton[0]) + buttonlatch[0] = BUTTONTIME; + if ((info.wButtons & JOY_BUTTON2) && !joybutton[1] && + (joyinfo[joytype[1]] == DEVICE_NONE) // Only consider 2nd button if NOT emulating a 2nd Apple joystick + ) + buttonlatch[1] = BUTTONTIME; + joybutton[0] = ((info.wButtons & JOY_BUTTON1) != 0); + if (joyinfo[joytype[1]] == DEVICE_NONE) // Only consider 2nd button if NOT emulating a 2nd Apple joystick + joybutton[1] = ((info.wButtons & JOY_BUTTON2) != 0); + + xpos[0] = (info.wXpos-joysubx[0]) >> joyshrx[0]; + ypos[0] = (info.wYpos-joysuby[0]) >> joyshry[0]; + + // NB. This does not work for analogue joysticks (not self-centreing) - except if Trim=0 + if(xpos[0] == 127 || xpos[0] == 128) xpos[0] += g_nPdlTrimX; + if(ypos[0] == 127 || ypos[0] == 128) ypos[0] += g_nPdlTrimY; + } + } +} + +void CheckJoystick1() +{ + static DWORD lastcheck = 0; + DWORD currtime = GetTickCount(); + if ((currtime-lastcheck >= 10) || joybutton[2]) + { + lastcheck = currtime; + JOYINFO info; + if (joyGetPos(JOYSTICKID2,&info) == JOYERR_NOERROR) + { + if ((info.wButtons & JOY_BUTTON1) && !joybutton[2]) + { + buttonlatch[2] = BUTTONTIME; + if(joyinfo[joytype[1]] != DEVICE_NONE) + buttonlatch[1] = BUTTONTIME; // Re-map this button when emulating a 2nd Apple joystick + } + + joybutton[2] = ((info.wButtons & JOY_BUTTON1) != 0); + if(joyinfo[joytype[1]] != DEVICE_NONE) + joybutton[1] = ((info.wButtons & JOY_BUTTON1) != 0); // Re-map this button when emulating a 2nd Apple joystick + + xpos[1] = (info.wXpos-joysubx[1]) >> joyshrx[1]; + ypos[1] = (info.wYpos-joysuby[1]) >> joyshry[1]; + + // NB. This does not work for analogue joysticks (not self-centreing) - except if Trim=0 + if(xpos[1] == 127 || xpos[1] == 128) xpos[1] += g_nPdlTrimX; + if(ypos[1] == 127 || ypos[1] == 128) ypos[1] += g_nPdlTrimY; + } + } +} + +// +// ----- ALL GLOBALLY ACCESSIBLE FUNCTIONS ARE BELOW THIS LINE ----- +// + +//=========================================================================== +void JoyInitialize() +{ + // Emulated joystick #0 can only use JOYSTICKID1 (if no joystick, then use keyboard) + // Emulated joystick #1 can only use JOYSTICKID2 (if no joystick, then disable) + + // + // Init for emulated joystick #0: + // + + if (joyinfo[joytype[0]] == DEVICE_JOYSTICK) + { + JOYCAPS caps; + if (joyGetDevCaps(JOYSTICKID1,&caps,sizeof(JOYCAPS)) == JOYERR_NOERROR) + { + joyshrx[0] = 0; + joyshry[0] = 0; + joysubx[0] = (int)caps.wXmin; + joysuby[0] = (int)caps.wYmin; + UINT xrange = caps.wXmax-caps.wXmin; + UINT yrange = caps.wYmax-caps.wYmin; + while (xrange > 256) + { + xrange >>= 1; + ++joyshrx[0]; + } + while (yrange > 256) + { + yrange >>= 1; + ++joyshry[0]; + } + } + else + { + joytype[0] = J0C_KEYBD_NUMPAD; + } + } + + // + // Init for emulated joystick #1: + // + + if (joyinfo[joytype[1]] == DEVICE_JOYSTICK) + { + JOYCAPS caps; + if (joyGetDevCaps(JOYSTICKID2,&caps,sizeof(JOYCAPS)) == JOYERR_NOERROR) + { + joyshrx[1] = 0; + joyshry[1] = 0; + joysubx[1] = (int)caps.wXmin; + joysuby[1] = (int)caps.wYmin; + UINT xrange = caps.wXmax-caps.wXmin; + UINT yrange = caps.wYmax-caps.wYmin; + while (xrange > 256) + { + xrange >>= 1; + ++joyshrx[1]; + } + while (yrange > 256) + { + yrange >>= 1; + ++joyshry[1]; + } + } + else + { + joytype[1] = J1C_DISABLED; + } + } + + TcpIpJoystickInit(); +} + +//=========================================================================== + +#define SUPPORT_CURSOR_KEYS + +BOOL JoyProcessKey(int virtkey, BOOL extended, BOOL down, BOOL autorep) +{ + static struct + { + UINT32 Left:1; + UINT32 Up:1; + UINT32 Right:1; + UINT32 Down:1; + } CursorKeys = {0}; + + if ( (joyinfo[joytype[0]] != DEVICE_KEYBOARD) && + (joyinfo[joytype[1]] != DEVICE_KEYBOARD) && + (virtkey != VK_MENU) // VK_MENU == ALT Key + ) + { + return 0; + } + + // + + BOOL keychange = 0; + bool bIsCursorKey = false; + + if (virtkey == VK_MENU) // VK_MENU == ALT Key (Button #0 or #1) + { + keychange = 1; + keydown[JK_OPENAPPLE+(extended != 0)] = down; + } + else if (!extended) + { + if (JoyUsingKeyboardNumpad()) + { + keychange = 1; + + if ((virtkey >= VK_NUMPAD1) && (virtkey <= VK_NUMPAD9)) // NumLock on + { + keydown[virtkey-VK_NUMPAD1] = down; + } + else // NumLock off + { + switch (virtkey) + { + case VK_END: keydown[JK_DOWNLEFT] = down; break; + case VK_DOWN: keydown[JK_DOWN] = down; break; + case VK_NEXT: keydown[JK_DOWNRIGHT] = down; break; + case VK_LEFT: keydown[JK_LEFT] = down; break; + case VK_CLEAR: keydown[JK_CENTRE] = down; break; + case VK_RIGHT: keydown[JK_RIGHT] = down; break; + case VK_HOME: keydown[JK_UPLEFT] = down; break; + case VK_UP: keydown[JK_UP] = down; break; + case VK_PRIOR: keydown[JK_UPRIGHT] = down; break; + case VK_NUMPAD0: keydown[JK_BUTTON0] = down; break; + case VK_DECIMAL: keydown[JK_BUTTON1] = down; break; + default: keychange = 0; break; + } + } + } + } +#ifdef SUPPORT_CURSOR_KEYS + else if (extended) + { + if (JoyUsingKeyboardCursors() && (virtkey == VK_LEFT || virtkey == VK_UP || virtkey == VK_RIGHT || virtkey == VK_DOWN)) + { + keychange = 1; // This prevents cursors keys being available to the Apple II (eg. Lode Runner uses cursor left/right for game speed & Ctrl-J/K for joystick/keyboard) + bIsCursorKey = true; + + switch (virtkey) + { + case VK_LEFT: CursorKeys.Left = down; break; + case VK_UP: CursorKeys.Up = down; break; + case VK_RIGHT: CursorKeys.Right = down; break; + case VK_DOWN: CursorKeys.Down = down; break; + } + } + } +#endif + + if (!keychange) + return 0; + + // + + if (virtkey == VK_NUMPAD0) + { + if(down) + { + if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) + { + buttonlatch[0] = BUTTONTIME; + } + else if(joyinfo[joytype[1]] != DEVICE_NONE) + { + buttonlatch[2] = BUTTONTIME; + buttonlatch[1] = BUTTONTIME; // Re-map this button when emulating a 2nd Apple joystick + } + } + } + else if (virtkey == VK_DECIMAL) + { + if(down) + { + if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) + buttonlatch[1] = BUTTONTIME; + } + } + else if ((down && !autorep) || (sg_PropertySheet.GetJoystickCenteringControl() == JOYSTICK_MODE_CENTERING)) + { + int xkeys = 0; + int ykeys = 0; + int xtotal = 0; + int ytotal = 0; + + for (int keynum = JK_DOWNLEFT; keynum <= JK_UPRIGHT; keynum++) + { + if (keydown[keynum]) + { + if ((keynum % 3) != 1) // Not middle col (ie. not VK_DOWN, VK_CLEAR, VK_UP) + { + xkeys++; + xtotal += keyvalue[keynum].x; + } + if ((keynum / 3) != 1) // Not middle row (ie. not VK_LEFT, VK_CLEAR, VK_RIGHT) + { + ykeys++; + ytotal += keyvalue[keynum].y; + } + } + } + + if (CursorKeys.Left) + { + xkeys++; xtotal += keyvalue[JK_LEFT].x; + } + if (CursorKeys.Right) + { + xkeys++; xtotal += keyvalue[JK_RIGHT].x; + } + if (CursorKeys.Up) + { + ykeys++; ytotal += keyvalue[JK_UP].y; + } + if (CursorKeys.Down) + { + ykeys++; ytotal += keyvalue[JK_DOWN].y; + } + + // Joystick # which is being emulated by keyboard + int nJoyNum = (joyinfo[joytype[0]] == DEVICE_KEYBOARD) ? 0 : 1; + + if (xkeys) + xpos[nJoyNum] = xtotal / xkeys; + else + xpos[nJoyNum] = PDL_CENTRAL + g_nPdlTrimX; + + if (ykeys) + ypos[nJoyNum] = ytotal / ykeys; + else + ypos[nJoyNum] = PDL_CENTRAL + g_nPdlTrimY; + } + + if (bIsCursorKey && sg_PropertySheet.GetJoystickCursorControl()) + { + // Allow AppleII keyboard to see this cursor keypress too + return 0; + } + + return 1; +} + +//=========================================================================== + +static void DoAutofire(UINT uButton, BOOL& pressed) +{ + static BOOL toggle[3] = {0}; + static BOOL lastPressed[3] = {0}; + + BOOL nowPressed = pressed; + if (sg_PropertySheet.GetAutofire(uButton) && pressed) + { + toggle[uButton] = (!lastPressed[uButton]) ? TRUE : toggle[uButton] = !toggle[uButton]; + pressed = pressed && toggle[uButton]; + } + lastPressed[uButton] = nowPressed; +} + +BYTE __stdcall JoyportReadButton(WORD address, ULONG nCyclesLeft) +{ + BOOL pressed = 0; + + if (g_uJoyportActiveStick == 0) + { + switch (address) + { + case 0x61: + pressed = (buttonlatch[0] || joybutton[0] || setbutton[0] /*|| keydown[JK_OPENAPPLE]*/); + if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) // BUG? joytype[1] should be [0] ? + pressed = (pressed || keydown[JK_BUTTON0]); + buttonlatch[0] = 0; + break; + + case 0x62: // Left or Up + if (g_uJoyportReadMode == JOYPORT_LEFTRIGHT) // LEFT + { + if (xpos[0] == 0) // TODO: More range for mouse control? + pressed = 1; + } + else // UP + { + if (ypos[0] == 0) // TODO: More range for mouse control? + pressed = 1; + } + break; + + case 0x63: // Right or Down + if (g_uJoyportReadMode == JOYPORT_LEFTRIGHT) // RIGHT + { + if (xpos[0] >= 255) // TODO: More range for mouse control? + pressed = 1; + } + else // DOWN + { + if (ypos[0] >= 255) // TODO: More range for mouse control? + pressed = 1; + } + break; + } + } + else // TODO: stick #1 + { + } + + pressed = pressed ? 0 : 1; // Invert as Joyport signals are active low + + return MemReadFloatingBus(pressed, nCyclesLeft); +} + +BYTE __stdcall JoyReadButton(WORD pc, WORD address, BYTE, BYTE, ULONG nCyclesLeft) +{ + address &= 0xFF; + + TcpIpJoystickUpdate(); + + if(joyinfo[joytype[0]] == DEVICE_JOYSTICK) + CheckJoystick0(); + if(joyinfo[joytype[1]] == DEVICE_JOYSTICK) + CheckJoystick1(); + + if (g_bJoyportEnabled) + { + // Some extra logic to stop the Joyport forcing a self-test at CTRL+RESET + if ((address != 0x62) || (address == 0x62 && pc != 0xC242 && pc != 0xC2BE)) // Original //e ($C242), Enhanced //e ($C2BE) + return JoyportReadButton(address, nCyclesLeft); + } + + BOOL pressed = 0; + switch (address) + { + case 0x61: + pressed = (buttonlatch[0] || joybutton[0] || setbutton[0] || keydown[JK_OPENAPPLE]); + if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) // BUG? joytype[1] should be [0] ? + pressed = (pressed || keydown[JK_BUTTON0]); + buttonlatch[0] = 0; + DoAutofire(0, pressed); + break; + + case 0x62: + pressed = (buttonlatch[1] || joybutton[1] || setbutton[1] || keydown[JK_CLOSEDAPPLE]); + if(joyinfo[joytype[1]] != DEVICE_KEYBOARD) + pressed = (pressed || keydown[JK_BUTTON1]); + buttonlatch[1] = 0; + DoAutofire(1, pressed); + break; + + case 0x63: + if (IS_APPLE2 && (joyinfo[joytype[1]] == DEVICE_NONE)) + { + // Apple II/II+ with no joystick has the "SHIFT key mod" + // See Sather's Understanding The Apple II p7-36 + pressed = !(GetKeyState(VK_SHIFT) < 0); + } + else + { + pressed = (buttonlatch[2] || joybutton[2] || setbutton[2]); + DoAutofire(2, pressed); + } + buttonlatch[2] = 0; + break; + } + + return MemReadFloatingBus(pressed, nCyclesLeft); +} + +//=========================================================================== + +// PREAD: ; $FB1E +// AD 70 C0 : (4) LDA $C070 +// A0 00 : (2) LDA #$00 +// EA : (2) NOP +// EA : (2) NOP +// Lbl1: ; 11 cycles is the normal duration of the loop +// BD 64 C0 : (4) LDA $C064,X +// 10 04 : (2) BPL Lbl2 ; NB. 3 cycles if branch taken (not likely) +// C8 : (2) INY +// D0 F8 : (3) BNE Lbl1 ; NB. 2 cycles if branch not taken (not likely) +// 88 : (2) DEY +// Lbl2: +// 60 : (6) RTS +// + +static const double PDL_CNTR_INTERVAL = 2816.0 / 255.0; // 11.04 (From KEGS) + +BYTE __stdcall JoyReadPosition(WORD programcounter, WORD address, BYTE, BYTE, ULONG nCyclesLeft) +{ + TcpIpJoystickUpdate(); + + int nJoyNum = (address & 2) ? 1 : 0; // $C064..$C067 + + CpuCalcCycles(nCyclesLeft); + + ULONG nPdlPos = (address & 1) ? ypos[nJoyNum] : xpos[nJoyNum]; + + // This is from KEGS. It helps games like Championship Lode Runner & Boulderdash + if(nPdlPos >= 255) + nPdlPos = 280; + + BOOL nPdlCntrActive = g_nCumulativeCycles <= (g_nJoyCntrResetCycle + (unsigned __int64) ((double)nPdlPos * PDL_CNTR_INTERVAL)); + + return MemReadFloatingBus(nPdlCntrActive, nCyclesLeft); +} + +//=========================================================================== +void JoyReset() +{ + int loop = 0; + while (loop < JK_MAX) + keydown[loop++] = FALSE; +} + +//=========================================================================== +BYTE __stdcall JoyResetPosition(WORD, WORD, BYTE, BYTE, ULONG nCyclesLeft) +{ + CpuCalcCycles(nCyclesLeft); + g_nJoyCntrResetCycle = g_nCumulativeCycles; + + if(joyinfo[joytype[0]] == DEVICE_JOYSTICK) + CheckJoystick0(); + if(joyinfo[joytype[1]] == DEVICE_JOYSTICK) + CheckJoystick1(); + + return MemReadFloatingBus(nCyclesLeft); +} + +//=========================================================================== + +// Called when mouse is being used as a joystick && mouse button changes +void JoySetButton(eBUTTON number, eBUTTONSTATE down) +{ + if (number > 1) // Sanity check on mouse button # + return; + + // If 2nd joystick is enabled, then both joysticks only have 1 button + if((joyinfo[joytype[1]] != DEVICE_NONE) && (number != 0)) + return; + + // If it is 2nd joystick that is being emulated with mouse, then re-map button # + if(joyinfo[joytype[1]] == DEVICE_MOUSE) + { + number = BUTTON1; // 2nd joystick controls Apple button #1 + } + + setbutton[number] = down; + + if (down) + buttonlatch[number] = BUTTONTIME; +} + +//=========================================================================== +BOOL JoySetEmulationType(HWND window, DWORD newtype, int nJoystickNumber, const bool bMousecardActive) +{ + if(joytype[nJoystickNumber] == newtype) + return 1; // Already set to this type. Return OK. + + if (joyinfo[newtype] == DEVICE_JOYSTICK) + { + JOYCAPS caps; + unsigned int nJoyID = nJoystickNumber == JN_JOYSTICK0 ? JOYSTICKID1 : JOYSTICKID2; + if (joyGetDevCaps(nJoyID, &caps, sizeof(JOYCAPS)) != JOYERR_NOERROR) + { + MessageBox(window, + TEXT("The emulator is unable to read your PC joystick. ") + TEXT("Ensure that your game port is configured properly, ") + TEXT("that the joystick is firmly plugged in, and that ") + TEXT("you have a joystick driver installed."), + TEXT("Configuration"), + MB_ICONEXCLAMATION | MB_SETFOREGROUND); + return 0; + } + } + else if ((joyinfo[newtype] == DEVICE_MOUSE) && + (joyinfo[joytype[nJoystickNumber]] != DEVICE_MOUSE)) + { + if (bMousecardActive) + { + // Shouldn't be necessary, since Property Sheet's logic should prevent this option being given to the user. + MessageBox(window, + TEXT("Mouse interface card is enabled - unable to use mouse for joystick emulation."), + TEXT("Configuration"), + MB_ICONEXCLAMATION | MB_SETFOREGROUND); + return 0; + } + + MessageBox(window, + TEXT("To begin emulating a joystick with your mouse, move ") + TEXT("the mouse cursor over the emulated screen of a running ") + TEXT("program and click the left mouse button. During the ") + TEXT("time the mouse is emulating a joystick, you will not ") + TEXT("be able to use it to perform mouse functions, and the ") + TEXT("mouse cursor will not be visible. To end joystick ") + TEXT("emulation and regain the mouse cursor, click the left ") + TEXT("mouse button while pressing Ctrl."), + TEXT("Configuration"), + MB_ICONINFORMATION | MB_SETFOREGROUND); + } + else if (joyinfo[newtype] == DEVICE_KEYBOARD) + { + if (newtype == J0C_KEYBD_CURSORS || newtype == J1C_KEYBD_CURSORS) + { + MessageBox(window, + TEXT("Using cursor keys to emulate a joystick can cause conflicts.\n\n") + TEXT("Be aware that 'cursor-up' = CTRL+K, and 'cursor-down' = CTRL+J.\n") + TEXT("EG. Lode Runner uses CTRL+K/J to switch between keyboard/joystick modes ") + TEXT("(and cursor-left/right to control speed).\n\n") + TEXT("Also if cursor keys are blocked from being read from the Apple keyboard ") + TEXT("then even simple AppleSoft command-line editing (cursor left/right) will not work."), + TEXT("Configuration"), + MB_ICONINFORMATION | MB_SETFOREGROUND); + } + } + + joytype[nJoystickNumber] = newtype; + JoyInitialize(); + JoyReset(); + return 1; +} + + +//=========================================================================== + +// Called when mouse is being used as a joystick && mouse position changes +void JoySetPosition(int xvalue, int xrange, int yvalue, int yrange) +{ + int nJoyNum = (joyinfo[joytype[0]] == DEVICE_MOUSE) ? 0 : 1; + xpos[nJoyNum] = (xvalue*255)/xrange; + ypos[nJoyNum] = (yvalue*255)/yrange; +} + +//=========================================================================== +void JoyUpdatePosition() +{ + if (buttonlatch[0]) --buttonlatch[0]; + if (buttonlatch[1]) --buttonlatch[1]; + if (buttonlatch[2]) --buttonlatch[2]; +} + +//=========================================================================== + +BOOL JoyUsingMouse() +{ + return (joyinfo[joytype[0]] == DEVICE_MOUSE) || (joyinfo[joytype[1]] == DEVICE_MOUSE); +} + +BOOL JoyUsingKeyboard() +{ + return (joyinfo[joytype[0]] == DEVICE_KEYBOARD) || (joyinfo[joytype[1]] == DEVICE_KEYBOARD); +} + +BOOL JoyUsingKeyboardCursors() +{ + return (joytype[0] == J0C_KEYBD_CURSORS) || (joytype[1] == J1C_KEYBD_CURSORS); +} + +BOOL JoyUsingKeyboardNumpad() +{ + return (joytype[0] == J0C_KEYBD_NUMPAD) || (joytype[1] == J1C_KEYBD_NUMPAD); +} + +//=========================================================================== + +void JoyDisableUsingMouse() +{ + if (joyinfo[joytype[0]] == DEVICE_MOUSE) + joytype[0] = J0C_DISABLED; + + if (joyinfo[joytype[1]] == DEVICE_MOUSE) + joytype[1] = J1C_DISABLED; +} + +//=========================================================================== + +void JoySetTrim(short nValue, bool bAxisX) +{ + if(bAxisX) + g_nPdlTrimX = nValue; + else + g_nPdlTrimY = nValue; + + int nJoyNum = -1; + + if(joyinfo[joytype[0]] == DEVICE_KEYBOARD) + nJoyNum = 0; + else if(joyinfo[joytype[1]] == DEVICE_KEYBOARD) + nJoyNum = 1; + + if(nJoyNum >= 0) + { + xpos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimX; + ypos[nJoyNum] = PDL_CENTRAL+g_nPdlTrimY; + } +} + +short JoyGetTrim(bool bAxisX) +{ + return bAxisX ? g_nPdlTrimX : g_nPdlTrimY; +} + +//=========================================================================== + +// Joyport truth-table: +// +// AN0 AN1 /PB0 /PB1 /PB2 +// ------------------------------------ +// 0 0 Trigger-1 Left-1 Right-1 +// 0 1 Trigger-1 Up-1 Down-1 +// 1 0 Trigger-2 Left-2 Right-2 +// 1 1 Trigger-2 Up-2 Down-2 + +#if 0 +void JoyportEnable(const bool bEnable) +{ + if (IS_APPLE2C) + g_bJoyportEnabled = false; + else + g_bJoyportEnabled = bEnable ? 1 : 0; +} +#endif + +void JoyportControl(const UINT uControl) +{ + if (!g_bJoyportEnabled) + return; + + switch (uControl) + { + case 0: // AN0 clr + g_uJoyportActiveStick = 0; + break; + case 1: // AN0 set + g_uJoyportActiveStick = 1; + break; + case 2: // AN1 clr + g_uJoyportReadMode = JOYPORT_LEFTRIGHT; + break; + case 3: // AN1 set + g_uJoyportReadMode = JOYPORT_UPDOWN; + break; + } +} + +//=========================================================================== + +DWORD JoyGetSnapshot(SS_IO_Joystick* pSS) +{ + pSS->g_nJoyCntrResetCycle = g_nJoyCntrResetCycle; + return 0; +} + +DWORD JoySetSnapshot(SS_IO_Joystick* pSS) +{ + g_nJoyCntrResetCycle = pSS->g_nJoyCntrResetCycle; + return 0; +} diff --git a/source/Joystick.h b/source/Joystick.h index 32cfeb72..848efe56 100644 --- a/source/Joystick.h +++ b/source/Joystick.h @@ -1,32 +1,34 @@ -#pragma once - -enum JOYNUM {JN_JOYSTICK0=0, JN_JOYSTICK1}; - -enum JOY0CHOICE {J0C_DISABLED=0, J0C_JOYSTICK1, J0C_KEYBD_CURSORS, J0C_KEYBD_NUMPAD, J0C_MOUSE, J0C_MAX}; -enum JOY1CHOICE {J1C_DISABLED=0, J1C_JOYSTICK2, J1C_KEYBD_CURSORS, J1C_KEYBD_NUMPAD, J1C_MOUSE, J1C_MAX}; - -extern DWORD joytype[2]; - -enum {JOYSTICK_MODE_FLOATING=0, JOYSTICK_MODE_CENTERING}; // Joystick centering control - -void JoyInitialize(); -BOOL JoyProcessKey(int,BOOL,BOOL,BOOL); -void JoyReset(); -void JoySetButton(eBUTTON,eBUTTONSTATE); -BOOL JoySetEmulationType(HWND,DWORD,int, const bool bMousecardActive); -void JoySetPosition(int,int,int,int); -void JoyUpdatePosition(); -BOOL JoyUsingMouse(); -BOOL JoyUsingKeyboard(); -BOOL JoyUsingKeyboardCursors(); -BOOL JoyUsingKeyboardNumpad(); -void JoyDisableUsingMouse(); -void JoySetTrim(short nValue, bool bAxisX); -short JoyGetTrim(bool bAxisX); -void JoyportControl(const UINT uControl); -DWORD JoyGetSnapshot(SS_IO_Joystick* pSS); -DWORD JoySetSnapshot(SS_IO_Joystick* pSS); - -BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); -BYTE __stdcall JoyReadPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); -BYTE __stdcall JoyResetPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); +#pragma once + +enum JOYNUM {JN_JOYSTICK0=0, JN_JOYSTICK1}; + +enum JOY0CHOICE {J0C_DISABLED=0, J0C_JOYSTICK1, J0C_KEYBD_CURSORS, J0C_KEYBD_NUMPAD, J0C_MOUSE, J0C_MAX}; +enum JOY1CHOICE {J1C_DISABLED=0, J1C_JOYSTICK2, J1C_KEYBD_CURSORS, J1C_KEYBD_NUMPAD, J1C_MOUSE, J1C_MAX}; + +extern DWORD joytype[2]; + +enum {JOYSTICK_MODE_FLOATING=0, JOYSTICK_MODE_CENTERING}; // Joystick centering control + +void TcpIpJoystickUpdate(); + +void JoyInitialize(); +BOOL JoyProcessKey(int,BOOL,BOOL,BOOL); +void JoyReset(); +void JoySetButton(eBUTTON,eBUTTONSTATE); +BOOL JoySetEmulationType(HWND,DWORD,int, const bool bMousecardActive); +void JoySetPosition(int,int,int,int); +void JoyUpdatePosition(); +BOOL JoyUsingMouse(); +BOOL JoyUsingKeyboard(); +BOOL JoyUsingKeyboardCursors(); +BOOL JoyUsingKeyboardNumpad(); +void JoyDisableUsingMouse(); +void JoySetTrim(short nValue, bool bAxisX); +short JoyGetTrim(bool bAxisX); +void JoyportControl(const UINT uControl); +DWORD JoyGetSnapshot(SS_IO_Joystick* pSS); +DWORD JoySetSnapshot(SS_IO_Joystick* pSS); + +BYTE __stdcall JoyReadButton(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); +BYTE __stdcall JoyReadPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); +BYTE __stdcall JoyResetPosition(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nCyclesLeft); diff --git a/source/StdAfx.h b/source/StdAfx.h index e4305592..584cd7fe 100644 --- a/source/StdAfx.h +++ b/source/StdAfx.h @@ -1,65 +1,67 @@ -//#define WIN32_LEAN_AND_MEAN +//#define WIN32_LEAN_AND_MEAN + +// Required for Win98/ME support: +// . See: http://support.embarcadero.com/article/35754 +// . "GetOpenFileName() fails under Windows 95/98/NT/ME due to incorrect OPENFILENAME structure size" +#define _WIN32_WINNT 0x0400 + +// Mouse Wheel is not supported on Win95. +// If we didn't care about supporting Win95 (compile/run-time errors) +// we would just define the minimum windows version to support. +// #define _WIN32_WINDOWS 0x0401 +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x020A +#endif + +#include -// Required for Win98/ME support: -// . See: http://support.embarcadero.com/article/35754 -// . "GetOpenFileName() fails under Windows 95/98/NT/ME due to incorrect OPENFILENAME structure size" -#define _WIN32_WINNT 0x0400 - -// Mouse Wheel is not supported on Win95. -// If we didn't care about supporting Win95 (compile/run-time errors) -// we would just define the minimum windows version to support. -// #define _WIN32_WINDOWS 0x0401 -#ifndef WM_MOUSEWHEEL -#define WM_MOUSEWHEEL 0x020A -#endif - -// Not needed in VC7.1, but needed in VC Express -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include // WM_MOUSEWHEEL -#include -#include -#include -#include - -#include -#include - -#include "zlib.h" -#include "unzip.h" -#include "zip.h" -#include "iowin32.h" - -#include "Common.h" -#include "Structs.h" - -#include "AppleWin.h" -#include "AY8910.h" -#include "CPU.h" -#include "Video.h" // Debugger needs: VideoUpdateFuncPtr_t -#include "Debug.h" -#include "Disk.h" -#include "Frame.h" -#include "Keyboard.h" -#include "Log.h" -#include "Memory.h" -#include "Mockingboard.h" -#include "ParallelPrinter.h" -#include "Registry.h" -#include "Riff.h" -#include "SaveState.h" -#include "SerialComms.h" -#include "SoundCore.h" -#include "Speaker.h" -#include "Tape.h" +// Not needed in VC7.1, but needed in VC Express +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include // WM_MOUSEWHEEL +#include +#include +#include +#include + +#include +#include + +#include "zlib.h" +#include "unzip.h" +#include "zip.h" +#include "iowin32.h" + +#include "Common.h" +#include "Structs.h" + +#include "AppleWin.h" +#include "AY8910.h" +#include "CPU.h" +#include "Video.h" // Debugger needs: VideoUpdateFuncPtr_t +#include "Debug.h" +#include "Disk.h" +#include "Frame.h" +#include "Keyboard.h" +#include "Log.h" +#include "Memory.h" +#include "Mockingboard.h" +#include "ParallelPrinter.h" +#include "Registry.h" +#include "Riff.h" +#include "SaveState.h" +#include "SerialComms.h" +#include "SoundCore.h" +#include "Speaker.h" +#include "Tape.h"