Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Andrea Odetti 2018-08-06 09:08:18 +01:00
commit edc1c366fe
19 changed files with 510 additions and 275 deletions

View file

@ -5,6 +5,7 @@ VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AppleWin", "AppleWinExpress2015.vcxproj", "{0A960136-A00A-4D4B-805F-664D9950D2CA}"
ProjectSection(ProjectDependencies) = postProject
{AA5854AD-2BC7-4EFD-9790-349ADB35E35A} = {AA5854AD-2BC7-4EFD-9790-349ADB35E35A}
{CF5A49BF-62A5-41BB-B10C-F34D556A7A45} = {CF5A49BF-62A5-41BB-B10C-F34D556A7A45}
{0212E0DF-06DA-4080-BD1D-F3B01599F70F} = {0212E0DF-06DA-4080-BD1D-F3B01599F70F}
{509739E7-0AF3-4C09-A1A9-F0B1BC31B39D} = {509739E7-0AF3-4C09-A1A9-F0B1BC31B39D}

View file

@ -1,6 +1,8 @@
#include <windows.h>
static HWND g_hFrameWindow = (HWND)0;
static bool g_bHookAltTab = false;
static bool g_bHookAltGrControl = false;
// NB. __stdcall (or WINAPI) and extern "C":
// . symbol is decorated as _<symbol>@bytes
@ -20,8 +22,20 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc(
UINT newMsg = pKbdLlHookStruct->flags & LLKHF_UP ? WM_KEYUP : WM_KEYDOWN;
LPARAM newlParam = newMsg == WM_KEYUP ? 3<<30 : 0; // b31:transition state, b30:previous key state
//
// NB. Alt Gr (Right-Alt): this normally send 2 WM_KEYDOWN messages for: VK_LCONTROL, then VK_RMENU
// Keyboard scanCodes: LCONTROL=0x1D, LCONTROL_from_RMENU=0x21D
// . For: Microsoft PS/2/Win7-64, VAIO laptop/Win7-64, Microsoft USB/Win10-64
// NB. WM_KEYDOWN also includes a 9/10-bit? scanCode: LCONTROL=0x1D, RCONTROL=0x11D, RMENU=0x1D(not 0x21D)
// . Can't suppress in app, since scanCode is not >= 0x200
if (g_bHookAltGrControl && pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) // GH#558
{
suppress = true;
}
// Suppress alt-tab
if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN))
if (g_bHookAltTab && pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN))
{
PostMessage(g_hFrameWindow, newMsg, VK_TAB, newlParam);
suppress = true;
@ -42,9 +56,12 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc(
}
// Suppress ctrl-escape
bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0;
if (pKbdLlHookStruct->vkCode == VK_ESCAPE && ControlDown)
suppress = true;
if (pKbdLlHookStruct->vkCode == VK_ESCAPE)
{
// But don't suppress CTRL+SHIFT+ESC
if (GetKeyState(VK_CONTROL) < 0 && GetKeyState(VK_SHIFT) >= 0)
suppress = true;
}
// Suppress keys by returning 1
if (suppress)
@ -54,7 +71,9 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc(
return CallNextHookEx(0/*parameter is ignored*/, nCode, wParam, lParam);
}
extern "C" __declspec(dllexport) void __cdecl RegisterHWND(HWND hWnd)
extern "C" __declspec(dllexport) void __cdecl RegisterHWND(HWND hWnd, bool bHookAltTab, bool bHookAltGrControl)
{
g_hFrameWindow = hWnd;
g_bHookAltTab = bHookAltTab;
g_bHookAltGrControl = bHookAltGrControl;
}

View file

@ -8,6 +8,11 @@ https://github.com/AppleWin/AppleWin/issues/new
Tom Charlesworth
1.27.6.0 - 28 Jul 2018
----------------------
. [Bug #570] Fixed lag when repeat-stepping in debugger.
. [Bug #558] Fixed ClosedApple + <key> not working (when using right ALT key).
1.27.5.0 - 24 Jun 2018
----------------------

View file

@ -252,8 +252,8 @@ DISK_ICON ICON "DISK.ICO"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,27,5,0
PRODUCTVERSION 1,27,5,0
FILEVERSION 1,27,6,0
PRODUCTVERSION 1,27,6,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -271,12 +271,12 @@ BEGIN
VALUE "Comments", "https://github.com/AppleWin"
VALUE "CompanyName", "AppleWin"
VALUE "FileDescription", "Apple //e Emulator for Windows"
VALUE "FileVersion", "1, 27, 5, 0"
VALUE "FileVersion", "1, 27, 6, 0"
VALUE "InternalName", "APPLEWIN"
VALUE "LegalCopyright", " 1994-2018 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, 27, 5, 0"
VALUE "ProductVersion", "1, 27, 6, 0"
END
END
BLOCK "VarFileInfo"

View file

@ -79,6 +79,8 @@ TCHAR g_sDebugDir [MAX_PATH] = TEXT(""); // TODO: Not currently used
TCHAR g_sScreenShotDir[MAX_PATH] = TEXT(""); // TODO: Not currently used
bool g_bCapturePrintScreenKey = true;
static bool g_bHookSystemKey = true;
static bool g_bHookAltTab = false;
static bool g_bHookAltGrControl = false;
TCHAR g_sCurrentDir[MAX_PATH] = TEXT(""); // Also Starting Dir. Debugger uses this when load/save
bool g_bRestart = false;
@ -171,6 +173,11 @@ void SetLoadedSaveStateFlag(const bool bFlag)
g_bLoadedSaveState = bFlag;
}
bool GetHookAltGrControl(void)
{
return g_bHookAltGrControl;
}
static void ResetToLogoMode(void)
{
g_nAppMode = MODE_LOGO;
@ -435,7 +442,7 @@ void EnterMessageLoop(void)
else if (g_nAppMode == MODE_PAUSED)
Sleep(1); // Stop process hogging CPU - 1ms, as need to fade-out speaker sound buffer
else if (g_nAppMode == MODE_LOGO)
Sleep(100); // Stop process hogging CPU
Sleep(1); // Stop process hogging CPU (NB. don't delay for too long otherwise key input can be slow in other apps - GH#569)
}
}
}
@ -872,17 +879,20 @@ static void RegisterHotKeys(void)
static HINSTANCE g_hinstDLL = 0;
static HHOOK g_hhook = 0;
static HANDLE g_hHookThread = NULL;
static DWORD g_HookThreadId = 0;
// Pre: g_hFrameWindow must be valid
bool HookFilterForKeyboard()
static bool HookFilterForKeyboard()
{
g_hinstDLL = LoadLibrary(TEXT("HookFilter.dll"));
_ASSERT(g_hFrameWindow);
typedef void (*RegisterHWNDProc)(HWND);
typedef void (*RegisterHWNDProc)(HWND, bool, bool);
RegisterHWNDProc RegisterHWND = (RegisterHWNDProc) GetProcAddress(g_hinstDLL, "RegisterHWND");
if (RegisterHWND)
RegisterHWND(g_hFrameWindow);
RegisterHWND(g_hFrameWindow, g_bHookAltTab, g_bHookAltGrControl);
HOOKPROC hkprcLowLevelKeyboardProc = (HOOKPROC) GetProcAddress(g_hinstDLL, "LowLevelKeyboardProc");
@ -905,12 +915,74 @@ bool HookFilterForKeyboard()
return false;
}
void UnhookFilterForKeyboard()
static void UnhookFilterForKeyboard()
{
UnhookWindowsHookEx(g_hhook);
FreeLibrary(g_hinstDLL);
}
static DWORD WINAPI HookThread(LPVOID lpParameter)
{
if (!HookFilterForKeyboard())
return -1;
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookFilterForKeyboard();
return 0;
}
static bool InitHookThread()
{
g_hHookThread = CreateThread(NULL, // lpThreadAttributes
0, // dwStackSize
(LPTHREAD_START_ROUTINE) HookThread,
0, // lpParameter
0, // dwCreationFlags : 0 = Run immediately
&g_HookThreadId); // lpThreadId
if (g_hHookThread == NULL)
return false;
return true;
}
static void UninitHookThread()
{
if (g_hHookThread)
{
if (!PostThreadMessage(g_HookThreadId, WM_QUIT, 0, 0))
{
_ASSERT(0);
return;
}
do
{
DWORD dwExitCode;
if (GetExitCodeThread(g_hHookThread, &dwExitCode))
{
if(dwExitCode == STILL_ACTIVE)
Sleep(10);
else
break;
}
}
while(1);
CloseHandle(g_hHookThread);
g_hHookThread = NULL;
g_HookThreadId = 0;
}
}
//===========================================================================
LPSTR GetCurrArg(LPSTR lpCmdLine)
@ -1077,12 +1149,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
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);
LogInit();
}
else if (strcmp(lpCmdLine, "-noreg") == 0)
{
@ -1234,6 +1301,14 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
{
g_bHookSystemKey = false;
}
else if (strcmp(lpCmdLine, "-hook-alt-tab") == 0) // GH#556
{
g_bHookAltTab = true;
}
else if (strcmp(lpCmdLine, "-hook-altgr-control") == 0) // GH#556
{
g_bHookAltGrControl = true;
}
else if (strcmp(lpCmdLine, "-spkr-inc") == 0)
{
lpCmdLine = GetCurrArg(lpNextArg);
@ -1428,7 +1503,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
if (g_bHookSystemKey)
{
if (HookFilterForKeyboard()) // needs valid g_hFrameWindow (for message pump)
if (InitHookThread()) // needs valid g_hFrameWindow (for message pump)
LogFileOutput("Main: HookFilterForKeyboard()\n");
}
@ -1540,7 +1615,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
if (g_bHookSystemKey)
{
UnhookFilterForKeyboard();
UninitHookThread();
LogFileOutput("Main: UnhookFilterForKeyboard()\n");
}
}
@ -1559,12 +1634,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int)
tfe_shutdown();
LogFileOutput("Exit: tfe_shutdown()\n");
if (g_fh)
{
fprintf(g_fh,"*** Logging ended\n\n");
fclose(g_fh);
g_fh = NULL;
}
LogDone();
RiffFinishWriteFile();

View file

@ -30,6 +30,7 @@ extern HINSTANCE g_hInstance;
extern AppMode_e g_nAppMode;
bool GetLoadedSaveStateFlag(void);
void SetLoadedSaveStateFlag(const bool bFlag);
bool GetHookAltGrControl(void);
extern TCHAR g_sProgramDir[MAX_PATH];
extern TCHAR g_sCurrentDir[MAX_PATH];

View file

@ -780,7 +780,7 @@ Update_t CmdBenchmarkStop (int nArgs)
DWORD currtime = GetTickCount();
while ((extbench = GetTickCount()) != currtime)
; // intentional busy-waiting
KeybQueueKeypress(TEXT(' '),1);
KeybQueueKeypress(TEXT(' ') ,ASCII);
return UPDATE_ALL; // 0;
}
@ -2096,7 +2096,7 @@ Update_t CmdUnassemble (int nArgs)
Update_t CmdKey (int nArgs)
{
KeybQueueKeypress(
nArgs ? g_aArgs[1].nValue ? g_aArgs[1].nValue : g_aArgs[1].sArg[0] : TEXT(' '), 1); // FIXME!!!
nArgs ? g_aArgs[1].nValue ? g_aArgs[1].nValue : g_aArgs[1].sArg[0] : TEXT(' '), ASCII); // FIXME!!!
return UPDATE_CONSOLE_DISPLAY;
}
@ -9680,7 +9680,7 @@ void DebuggerCursorUpdate()
}
else
{
Sleep(10); // Stop process hogging CPU
Sleep(1); // Stop process hogging CPU
}
}
@ -9709,11 +9709,11 @@ void DebuggerMouseClick( int x, int y )
if (g_nAppMode != MODE_DEBUG)
return;
// NOTE: KeybUpdateCtrlShiftStatus() should be called before
KeybUpdateCtrlShiftStatus();
int iAltCtrlShift = 0;
iAltCtrlShift |= (g_bAltKey & 1) << 0;
iAltCtrlShift |= (g_bCtrlKey & 1) << 1;
iAltCtrlShift |= (g_bShiftKey & 1) << 2;
iAltCtrlShift |= KeybGetAltStatus() ? 1<<0 : 0;
iAltCtrlShift |= KeybGetCtrlStatus() ? 1<<1 : 0;
iAltCtrlShift |= KeybGetShiftStatus() ? 1<<2 : 0;
// GH#462 disasm click #
if (iAltCtrlShift != g_bConfigDisasmClick)

View file

@ -57,6 +57,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Debugger/Debug.h"
//#define ENABLE_MENU 0
#define DEBUG_KEY_MESSAGES 0
// 3D border around the 560x384 Apple II display
#define VIEWPORTX 5
@ -1091,25 +1092,32 @@ LRESULT CALLBACK FrameWndProc (
g_TimerIDEvent_100msec = 0;
}
LogFileOutput("WM_CLOSE (done)\n");
// Exit via DefWindowProc(), which does the default action for WM_CLOSE, which is to call DestroyWindow(), posting WM_DESTROY
break;
case WM_CHAR:
if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING) || (g_nAppMode == MODE_LOGO))
{
if( !g_bDebuggerEatKey )
{
KeybQueueKeypress((int)wparam, ASCII);
}
else
{
g_bDebuggerEatKey = false;
}
}
else if (g_nAppMode == MODE_DEBUG)
{
DebuggerInputConsoleChar((TCHAR)wparam);
}
break;
case WM_DESTROY:
LogFileOutput("WM_DESTROY\n");
DragAcceptFiles(window,0);
if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart)
Snapshot_Shutdown();
DebugDestroy();
if (!g_bRestart) {
DiskDestroy();
ImageDestroy();
HD_Destroy();
}
PrintDestroy();
sg_SSC.CommDestroy();
CpuDestroy();
MemDestroy();
SpkrDestroy();
VideoDestroy();
MB_Destroy();
DeleteGdiObjects();
DIMouse::DirectInputUninit(window); // NB. do before window is destroyed
PostQuitMessage(0); // Post WM_QUIT message to the thread's message queue
LogFileOutput("WM_DESTROY (done)\n");
break;
case WM_CREATE:
LogFileOutput("WM_CREATE\n");
@ -1169,29 +1177,6 @@ LRESULT CALLBACK FrameWndProc (
break;
}
case WM_DESTROY:
LogFileOutput("WM_DESTROY\n");
DragAcceptFiles(window,0);
Snapshot_Shutdown();
DebugDestroy();
if (!g_bRestart) {
DiskDestroy();
ImageDestroy();
HD_Destroy();
}
PrintDestroy();
sg_SSC.CommDestroy();
CpuDestroy();
MemDestroy();
SpkrDestroy();
VideoDestroy();
MB_Destroy();
DeleteGdiObjects();
DIMouse::DirectInputUninit(window); // NB. do before window is destroyed
PostQuitMessage(0); // Post WM_QUIT message to the thread's message queue
LogFileOutput("WM_DESTROY (done)\n");
break;
case WM_DISPLAYCHANGE:
VideoReinitialize();
break;
@ -1289,19 +1274,19 @@ LRESULT CALLBACK FrameWndProc (
// CTRL+SHIFT+F9 Toggle 50% Scan Lines
// ALT+F9 Can't use Alt-F9 as Alt is Open-Apple = Joystick Button #1
if ( !g_bCtrlKey && !g_bShiftKey ) // F9
if ( !KeybGetCtrlStatus() && !KeybGetShiftStatus() ) // F9
{
g_eVideoType++;
if (g_eVideoType >= NUM_VIDEO_MODES)
g_eVideoType = 0;
}
else if ( !g_bCtrlKey && g_bShiftKey ) // SHIFT+F9
else if ( !KeybGetCtrlStatus() && KeybGetShiftStatus() ) // SHIFT+F9
{
if (g_eVideoType <= 0)
g_eVideoType = NUM_VIDEO_MODES;
g_eVideoType--;
}
else if ( g_bCtrlKey && g_bShiftKey ) // CTRL+SHIFT+F9
else if ( KeybGetCtrlStatus() && KeybGetShiftStatus() ) // CTRL+SHIFT+F9
{
g_uHalfScanLines = !g_uHalfScanLines;
}
@ -1330,7 +1315,7 @@ LRESULT CALLBACK FrameWndProc (
}
else if (wparam == VK_F10)
{
if (g_Apple2Type == A2TYPE_PRAVETS8A && !g_bCtrlKey)
if (g_Apple2Type == A2TYPE_PRAVETS8A && !KeybGetCtrlStatus())
{
KeybToggleP8ACapsLock (); // F10: Toggles P8 Capslock
}
@ -1339,7 +1324,7 @@ LRESULT CALLBACK FrameWndProc (
SetUsingCursor(FALSE); // Ctrl+F10
}
}
else if (wparam == VK_F11 && !g_bCtrlKey) // Save state (F11)
else if (wparam == VK_F11 && !KeybGetCtrlStatus()) // Save state (F11)
{
SoundCore_SetFade(FADE_OUT);
if(sg_PropertySheet.SaveStateSelectImage(window, true))
@ -1391,17 +1376,20 @@ LRESULT CALLBACK FrameWndProc (
}
else if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_LOGO) || (g_nAppMode == MODE_STEPPING))
{
// Note about Alt Gr (Right-Alt):
// . WM_KEYDOWN[Left-Control], then:
// . WM_KEYDOWN[Right-Alt]
// NB. Alt Gr (Right-Alt): this normally send 2 WM_KEYDOWN messages for: VK_LCONTROL, then VK_RMENU
// . NB. The keyboard hook filter now suppresses VK_LCONTROL
bool extended = (HIWORD(lparam) & KF_EXTENDED) != 0;
BOOL down = 1;
BOOL autorep = (HIWORD(lparam) & KF_REPEAT) != 0;
BOOL IsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep);
if (!IsJoyKey && (g_nAppMode != MODE_LOGO))
#if DEBUG_KEY_MESSAGES
LogOutput("WM_KEYDOWN: %08X (scanCode=%04X)\n", wparam, (lparam>>16)&0xfff);
#endif
if (!IsJoyKey &&
(g_nAppMode != MODE_LOGO)) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard
{
KeybQueueKeypress((int)wparam, NOT_ASCII);
KeybQueueKeypress(wparam, NOT_ASCII);
if (!autorep)
KeybAnyKeyDown(WM_KEYDOWN, wparam, extended);
@ -1413,6 +1401,26 @@ LRESULT CALLBACK FrameWndProc (
}
break;
case WM_CHAR:
if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING) || (g_nAppMode == MODE_LOGO))
{
if (!g_bDebuggerEatKey)
{
#if DEBUG_KEY_MESSAGES
LogOutput("WM_CHAR: %08X\n", wparam);
#endif
if (g_nAppMode != MODE_LOGO) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard
KeybQueueKeypress(wparam, ASCII);
}
g_bDebuggerEatKey = false;
}
else if (g_nAppMode == MODE_DEBUG)
{
DebuggerInputConsoleChar((TCHAR)wparam);
}
break;
case WM_KEYUP:
// Process is done in WM_KEYUP: VK_F1 VK_F2 VK_F3 VK_F4 VK_F5 VK_F6 VK_F7 VK_F8
if ((wparam >= VK_F1) && (wparam <= VK_F8) && (buttondown == (int)wparam-VK_F1))
@ -1431,6 +1439,9 @@ LRESULT CALLBACK FrameWndProc (
BOOL autorep = 0;
BOOL bIsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep);
#if DEBUG_KEY_MESSAGES
LogOutput("WM_KEYUP: %08X\n", wparam);
#endif
if (!bIsJoyKey)
KeybAnyKeyDown(WM_KEYUP, wparam, extended);
}
@ -1747,7 +1758,7 @@ LRESULT CALLBACK FrameWndProc (
// http://msdn.microsoft.com/en-us/library/windows/desktop/gg153546(v=vs.85).aspx
// v1.25.0: Alt-Return Alt-Enter toggle fullscreen
if (g_bAltEnter_ToggleFullScreen && g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
return 0; // NOP -- eat key
PostMessage(window,WM_KEYDOWN,wparam,lparam);
@ -1761,7 +1772,7 @@ LRESULT CALLBACK FrameWndProc (
KeybUpdateCtrlShiftStatus();
// v1.25.0: Alt-Return Alt-Enter toggle fullscreen
if (g_bAltEnter_ToggleFullScreen && g_bAltKey && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
if (g_bAltEnter_ToggleFullScreen && KeybGetAltStatus() && (wparam == VK_RETURN)) // NB. VK_RETURN = 0x0D; Normally WM_CHAR will be 0x0A but ALT key triggers as WM_SYSKEYDOWN and VK_MENU
ScreenWindowResize(false);
else
PostMessage(window,WM_KEYUP,wparam,lparam);
@ -1784,10 +1795,7 @@ LRESULT CALLBACK FrameWndProc (
}
case WM_USER_RESTART:
// . Changed Apple computer type (][+ or //e)
// . Changed slot configuration
// . Changed disk speed (normal or enhanced)
// . Changed Freeze F8 rom setting
// Changed h/w config, eg. Apple computer type (][+ or //e), slot configuration, etc.
g_bRestart = true;
PostMessage(window,WM_CLOSE,0,0);
break;
@ -1944,7 +1952,7 @@ static void ProcessButtonClick(int button, bool bFromButtonUI /*=false*/)
case BTN_RUN:
KeybUpdateCtrlShiftStatus();
if( g_bCtrlKey )
if( KeybGetCtrlStatus() )
{
CtrlReset();
if (g_nAppMode == MODE_DEBUG)
@ -1988,7 +1996,7 @@ static void ProcessButtonClick(int button, bool bFromButtonUI /*=false*/)
case BTN_FULLSCR:
KeybUpdateCtrlShiftStatus();
ScreenWindowResize(g_bCtrlKey);
ScreenWindowResize( KeybGetCtrlStatus() );
break;
case BTN_DEBUG:

View file

@ -3,9 +3,6 @@
// 1.19.0.0 Hard Disk Status/Indicator Light
#define HD_LED 1
// Keyboard -- keystroke type
enum {NOT_ASCII=0, ASCII};
// Win32
extern HWND g_hFrameWindow;

View file

@ -35,10 +35,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Tape.h"
#include "YamlHelper.h"
#include "Video.h" // Needed by TK3000 //e, to refresh the frame at each |Mode| change
#include "Log.h"
static BYTE asciicode[2][10] = {
{0x08,0x0D,0x15,0x2F,0x00,0x00,0x00,0x00,0x00,0x00},
{0x08,0x0B,0x15,0x0A,0x00,0x00,0x00,0x00,0x00,0x7F}
// VK_LEFT/UP/RIGHT/DOWN/SELECT, VK_PRINT/EXECUTE/SNAPSHOT/INSERT/DELETE
{0x08,0x0D,0x15,0x2F,0x00, 0x00,0x00,0x00,0x00,0x00}, // Apple II
{0x08,0x0B,0x15,0x0A,0x00, 0x00,0x00,0x00,0x00,0x7F} // Apple //e
}; // Convert PC arrow keys to Apple keycodes
bool g_bShiftKey = false;
@ -49,7 +51,6 @@ static bool g_bTK3KModeKey = false; //TK3000 //e |Mode| key
static bool g_bCapsLock = true; //Caps lock key for Apple2 and Lat/Cyr lock for Pravets8
static bool g_bP8CapsLock = true; //Caps lock key of Pravets 8A/C
static int lastvirtkey = 0; // Current PC keycode
static BYTE keycode = 0; // Current Apple keycode
static BOOL keywaiting = 0;
@ -65,36 +66,31 @@ void KeybReset()
}
//===========================================================================
bool KeybGetAltStatus ()
{
return g_bAltKey;
}
//===========================================================================
bool KeybGetCapsStatus ()
bool KeybGetCapsStatus()
{
return g_bCapsLock;
}
//===========================================================================
bool KeybGetP8CapsStatus()
{
return g_bP8CapsLock;
}
//===========================================================================
/*
bool KeybGetCapsAllowed() //For Pravets 8A/C only
bool KeybGetAltStatus()
{
return g_CapsLockAllowed;
return g_bAltKey;
}
*/
//===========================================================================
bool KeybGetCtrlStatus ()
bool KeybGetCtrlStatus()
{
return g_bCtrlKey;
}
//===========================================================================
bool KeybGetShiftStatus ()
bool KeybGetShiftStatus()
{
return g_bShiftKey;
}
@ -102,19 +98,22 @@ bool KeybGetShiftStatus ()
//===========================================================================
void KeybUpdateCtrlShiftStatus()
{
g_bShiftKey = (GetKeyState( VK_SHIFT ) & KF_UP) ? true : false; // 0x8000 KF_UP
g_bCtrlKey = (GetKeyState( VK_CONTROL) & KF_UP) ? true : false;
g_bAltKey = (GetKeyState( VK_MENU ) & KF_UP) ? true : false;
g_bAltKey = (GetKeyState( VK_MENU ) < 0) ? true : false; // L or R alt
g_bCtrlKey = (GetKeyState( VK_CONTROL) < 0) ? true : false; // L or R ctrl
g_bShiftKey = (GetKeyState( VK_SHIFT ) < 0) ? true : false; // L or R shift
}
//===========================================================================
BYTE KeybGetKeycode () // Used by MemCheckPaging() & VideoCheckMode()
BYTE KeybGetKeycode () // Used by IORead_C01x() and TapeRead() for Pravets8A
{
return keycode;
}
//===========================================================================
void KeybQueueKeypress (int key, BOOL bASCII)
bool IsVirtualKeyAnAppleIIKey(WPARAM wparam);
void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII)
{
if (bASCII == ASCII) // WM_CHAR
{
@ -205,7 +204,7 @@ void KeybQueueKeypress (int key, BOOL bASCII)
}
else //i.e. latin letters
{
if (GetCapsLockAllowed() == false)
if (GetCapsLockAllowed() == false)
{
if (key == '{') keycode = '[';
if (key == '}') keycode = ']';
@ -271,8 +270,6 @@ void KeybQueueKeypress (int key, BOOL bASCII)
keycode = key;
}
}
lastvirtkey = LOBYTE(VkKeyScan(key));
}
else //(bASCII != ASCII) // WM_KEYDOWN
{
@ -299,13 +296,42 @@ void KeybQueueKeypress (int key, BOOL bASCII)
FrameRefreshStatus(DRAW_LEDS); // TODO: Implement |Mode| LED in the UI; make it appear only when in TK3000 mode
VideoRedrawScreen(); // TODO: Still need to implement page mode switching and 'whatnot'
}
return;
}
if (!((key >= VK_LEFT) && (key <= VK_DELETE) && asciicode[IS_APPLE2 ? 0 : 1][key - VK_LEFT]))
return;
if (key >= VK_LEFT && key <= VK_DELETE)
{
BYTE n = asciicode[IS_APPLE2 ? 0 : 1][key - VK_LEFT]; // Convert to Apple arrow keycode
if (!n)
return;
keycode = n;
}
else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) - GH#558
{
if (IsVirtualKeyAnAppleIIKey(key))
{
// When Alt Gr is down, then WM_CHAR is not posted - so fix this.
// NB. Still get WM_KEYDOWN/WM_KEYUP for the virtual key, so AKD works.
WPARAM newKey = key;
keycode = asciicode[IS_APPLE2 ? 0 : 1][key - VK_LEFT]; // Convert to Apple arrow keycode
lastvirtkey = key;
// Translate if shift or ctrl is down
if (key >= 'A' && key <= 'Z')
{
if ( (GetKeyState(VK_SHIFT) >= 0) && !g_bCapsLock )
newKey += 'a' - 'A'; // convert to lowercase key
else if (GetHookAltGrControl() && GetKeyState(VK_CONTROL) < 0)
newKey -= 'A' - 1; // convert to control-key
}
PostMessage(g_hFrameWindow, WM_CHAR, newKey, 0);
}
return;
}
else
{
return;
}
}
keywaiting = 1;
@ -391,16 +417,8 @@ const UINT kAKDNumElements = 256/64;
static uint64_t g_AKDFlags[2][kAKDNumElements] = { {0,0,0,0}, // normal
{0,0,0,0}}; // extended
// NB. Don't need to be concerned about if numpad/cursors are used for joystick,
// since parent calls JoyProcessKey() just before this.
void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended)
static bool IsVirtualKeyAnAppleIIKey(WPARAM wparam)
{
if (wparam > 255)
{
_ASSERT(0);
return;
}
if (wparam == VK_BACK ||
wparam == VK_TAB ||
wparam == VK_RETURN ||
@ -415,6 +433,24 @@ void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended)
(wparam >= VK_OEM_1 && wparam <= VK_OEM_3) || // 7 in total
(wparam >= VK_OEM_4 && wparam <= VK_OEM_8) || // 5 in total
(wparam == VK_OEM_102))
{
return true;
}
return false;
}
// NB. Don't need to be concerned about if numpad/cursors are used for joystick,
// since parent calls JoyProcessKey() just before this.
void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended)
{
if (wparam > 255)
{
_ASSERT(0);
return;
}
if (IsVirtualKeyAnAppleIIKey(wparam))
{
UINT offset = wparam >> 6;
UINT bit = wparam & 0x3f;
@ -440,7 +476,7 @@ static bool IsAKD(void)
//===========================================================================
BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG)
BYTE KeybReadData (void)
{
LogFileTimeUntilFirstKeyRead();
@ -462,7 +498,7 @@ BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG)
//===========================================================================
BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG)
BYTE KeybReadFlag (void)
{
if (g_bPasteFromClipboard)
ClipboardInit();

View file

@ -1,28 +1,23 @@
#pragma once
enum Keystroke_e {NOT_ASCII=0, ASCII};
void ClipboardInitiatePaste();
void KeybReset();
bool KeybGetAltStatus();
bool KeybGetCapsStatus();
bool KeybGetP8CapsStatus();
bool KeybGetAltStatus();
bool KeybGetCtrlStatus();
bool KeybGetShiftStatus();
bool KeybGetCapsAllowed(); //For Pravets8A/C only
void KeybUpdateCtrlShiftStatus();
BYTE KeybGetKeycode ();
void KeybQueueKeypress (int,BOOL);
void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII);
void KeybToggleCapsLock ();
void KeybToggleP8ACapsLock ();
void KeybAnyKeyDown(UINT message, WPARAM wparam, bool bIsExtended);
BYTE KeybReadData (void);
BYTE KeybReadFlag (void);
void KeybSetSnapshot_v1(const BYTE LastKey);
void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper);
void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper);
BYTE __stdcall KeybReadData (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE __stdcall KeybReadFlag (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE __stdcall KbdAllow8Bit (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles); //For Pravets A/C only
extern bool g_bShiftKey;
extern bool g_bCtrlKey;
extern bool g_bAltKey;

View file

@ -32,6 +32,31 @@ FILE* g_fh = NULL;
//---------------------------------------------------------------------------
void LogInit(void)
{
if (g_fh)
return;
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);
}
void LogDone(void)
{
if (!g_fh)
return;
fprintf(g_fh,"*** Logging ended\n\n");
fclose(g_fh);
g_fh = NULL;
}
//---------------------------------------------------------------------------
void LogOutput(LPCTSTR format, ...)
{
TCHAR output[256];

View file

@ -10,5 +10,7 @@
extern FILE* g_fh; // Filehandle for log file
extern void LogOutput(LPCTSTR format, ...);
extern void LogFileOutput(LPCTSTR format, ...);
void LogInit(void);
void LogDone(void);
void LogOutput(LPCTSTR format, ...);
void LogFileOutput(LPCTSTR format, ...);

View file

@ -209,7 +209,7 @@ BYTE __stdcall IO_Annunciator(WORD programcounter, WORD address, BYTE write, BYT
static BYTE __stdcall IORead_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
{
return KeybReadData(pc, addr, bWrite, d, nExecutedCycles);
return KeybReadData();
}
static BYTE __stdcall IOWrite_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
@ -224,32 +224,36 @@ static BYTE __stdcall IOWrite_C00x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON
static BYTE __stdcall IORead_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
{
if (IS_APPLE2) // Include Pravets machines too?
return KeybReadFlag();
bool res = false;
switch (addr & 0xf)
{
case 0x0: return KeybReadFlag(pc, addr, bWrite, d, nExecutedCycles);
case 0x1: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x2: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x3: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x4: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x5: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x6: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x7: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x8: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0x9: return VideoCheckVbl(nExecutedCycles);
case 0xA: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles);
case 0xB: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles);
case 0xC: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0xD: return MemCheckPaging(pc, addr, bWrite, d, nExecutedCycles);
case 0xE: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles);
case 0xF: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles);
case 0x0: return KeybReadFlag();
case 0x1: res = SW_BANK2 ? true : false; break;
case 0x2: res = SW_HIGHRAM ? true : false; break;
case 0x3: res = SW_AUXREAD ? true : false; break;
case 0x4: res = SW_AUXWRITE ? true : false; break;
case 0x5: res = SW_INTCXROM ? true : false; break;
case 0x6: res = SW_ALTZP ? true : false; break;
case 0x7: res = SW_SLOTC3ROM ? true : false; break;
case 0x8: res = SW_80STORE ? true : false; break;
case 0x9: res = VideoGetVblBar(nExecutedCycles); break;
case 0xA: res = VideoGetSWTEXT(); break;
case 0xB: res = VideoGetSWMIXED(); break;
case 0xC: res = SW_PAGE2 ? true : false; break;
case 0xD: res = VideoGetSWHIRES(); break;
case 0xE: res = VideoGetSWAltCharSet(); break;
case 0xF: res = VideoGetSW80COL(); break;
}
return 0;
return KeybGetKeycode() | (res ? 0x80 : 0);
}
static BYTE __stdcall IOWrite_C01x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
{
return KeybReadFlag(pc, addr, bWrite, d, nExecutedCycles);
return KeybReadFlag();
}
//-------------------------------------
@ -344,8 +348,6 @@ static BYTE __stdcall IOWrite_C05x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULON
static BYTE __stdcall IORead_C06x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
{
static byte CurrentKestroke = 0;
CurrentKestroke = KeybGetKeycode();
switch (addr & 0x7) // address bit 4 is ignored (UTAIIe:7-5)
{
//In Pravets8A/C if SETMODE (8bit character encoding) is enabled, bit6 in $C060 is 0; Else it is 1
@ -399,7 +401,7 @@ static BYTE __stdcall IORead_C07x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG
case 0xC: return IO_Null(pc, addr, bWrite, d, nExecutedCycles);
case 0xD: return IO_Null(pc, addr, bWrite, d, nExecutedCycles);
case 0xE: return IO_Null(pc, addr, bWrite, d, nExecutedCycles);
case 0xF: return VideoCheckMode(pc, addr, bWrite, d, nExecutedCycles);
case 0xF: return MemReadFloatingBus(VideoGetSWDHIRES(), nExecutedCycles);
}
return 0;
@ -1016,29 +1018,6 @@ static void UpdatePaging(BOOL initialize)
//===========================================================================
// TODO: >= Apple2e only?
BYTE __stdcall MemCheckPaging(WORD, WORD address, BYTE, BYTE, ULONG)
{
address &= 0xFF;
BOOL result = 0;
switch (address)
{
case 0x11: result = SW_BANK2; break;
case 0x12: result = SW_HIGHRAM; break;
case 0x13: result = SW_AUXREAD; break;
case 0x14: result = SW_AUXWRITE; break;
case 0x15: result = SW_INTCXROM; break;
case 0x16: result = SW_ALTZP; break;
case 0x17: result = SW_SLOTC3ROM; break;
case 0x18: result = SW_80STORE; break;
case 0x1C: result = SW_PAGE2; break;
case 0x1D: result = SW_HIRES; break;
}
return KeybGetKeycode() | (result ? 0x80 : 0);
}
//===========================================================================
void MemDestroy()
{
VirtualFree(memaux ,0,MEM_RELEASE);
@ -1639,7 +1618,6 @@ void MemReset()
BYTE MemReadFloatingBus(const ULONG uExecutedCycles)
{
// return mem[ VideoGetScannerAddress(NULL, uExecutedCycles) ]; // NG: ANSI STORY (End Credits) - repro by running from "Turn the disk over"
return mem[ NTSC_VideoGetScannerAddress(uExecutedCycles) ]; // OK: This does the 2-cycle adjust for ANSI STORY (End Credits)
}
@ -1648,7 +1626,7 @@ BYTE MemReadFloatingBus(const ULONG uExecutedCycles)
BYTE MemReadFloatingBus(const BYTE highbit, const ULONG uExecutedCycles)
{
BYTE r = MemReadFloatingBus(uExecutedCycles);
return (r & ~0x80) | ((highbit) ? 0x80 : 0);
return (r & ~0x80) | (highbit ? 0x80 : 0);
}
//===========================================================================
@ -1852,6 +1830,7 @@ _done_saturn:
UpdatePaging(0); // Initialize=0
}
// Replicate 80STORE, PAGE2 and HIRES to video sub-system
if ((address <= 1) || ((address >= 0x54) && (address <= 0x57)))
return VideoSetMode(programcounter,address,write,value,nExecutedCycles);

View file

@ -99,5 +99,4 @@ bool MemLoadSnapshotAux(class YamlLoadHelper& yamlLoadHelper, UINT version);
BYTE __stdcall IO_Null(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);
BYTE __stdcall MemCheckPaging (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);
BYTE __stdcall MemSetPaging(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles);

View file

@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Includes
#include "StdAfx.h"
#include "Applewin.h"
#include "CPU.h"
#include "CPU.h" // CpuGetCyclesThisVideoFrame()
#include "Frame.h" // FRAMEBUFFER_W FRAMEBUFFER_H
#include "Memory.h" // MemGetMainPtr() MemGetBankPtr()
#include "Video.h" // g_pFramebufferbits
@ -41,9 +41,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "ntsc_rgb.h"
#endif
//LPBYTE MemGetMainPtr(const WORD);
//LPBYTE MemGetBankPtr(const UINT nBank);
// Defines
#define HGR_TEST_PATTERN 0
@ -136,7 +133,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static const UINT g_kFrameBufferWidth = GetFrameBufferWidth();
static unsigned (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0;
static unsigned short (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0;
typedef void (*UpdateScreenFunc_t)(long);
static UpdateScreenFunc_t g_apFuncVideoUpdateScanline[VIDEO_SCANNER_Y_DISPLAY];
@ -199,7 +196,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define SIGNAL_1 0.7465656072f
// Tables
static unsigned g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] =
// Video scanner tables are now runtime-generated using UTAIIe logic
static unsigned short g_aClockVertOffsetsHGR[VIDEO_SCANNER_MAX_VERT];
static unsigned short g_aClockVertOffsetsTXT[33];
static unsigned short APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ];
static unsigned short APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ];
#ifdef _DEBUG
static unsigned short g_kClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ] =
{
0x0000,0x0400,0x0800,0x0C00,0x1000,0x1400,0x1800,0x1C00,0x0080,0x0480,0x0880,0x0C80,0x1080,0x1480,0x1880,0x1C80,
0x0100,0x0500,0x0900,0x0D00,0x1100,0x1500,0x1900,0x1D00,0x0180,0x0580,0x0980,0x0D80,0x1180,0x1580,0x1980,0x1D80,
@ -224,7 +228,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80
};
static unsigned g_aClockVertOffsetsTXT[33] =
static unsigned short g_kClockVertOffsetsTXT[33] =
{
0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380,
@ -234,7 +238,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0x380
};
static unsigned APPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
static unsigned short kAPPLE_IIP_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
{
{0x1068,0x1068,0x1069,0x106A,0x106B,0x106C,0x106D,0x106E,0x106F,
0x1070,0x1071,0x1072,0x1073,0x1074,0x1075,0x1076,0x1077,
@ -282,7 +286,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}
};
static unsigned APPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
static unsigned short kAPPLE_IIE_HORZ_CLOCK_OFFSET[5][VIDEO_SCANNER_MAX_HORZ] =
{
{0x0068,0x0068,0x0069,0x006A,0x006B,0x006C,0x006D,0x006E,0x006F,
0x0070,0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,
@ -329,6 +333,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0x0010,0x0011,0x0012,0x0013,0x0014,0x0015,0x0016,0x0017,
0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F}
};
#endif
/*
http://www.kreativekorp.com/miscpages/a2info/munafo.shtml
@ -389,11 +394,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static csbits_t csbits; // charset, optionally followed by alt charset
// Prototypes
// prototype from CPU.h
//unsigned char CpuRead(unsigned short addr, unsigned long uExecutedCycles);
// prototypes from Memory.h
//unsigned char * MemGetAuxPtr (unsigned short);
//unsigned char * MemGetMainPtr (unsigned short);
INLINE float clampZeroOne( const float & x );
INLINE uint8_t getCharSetBits( const int iChar );
INLINE uint16_t getLoResBits( uint8_t iByte );
@ -411,8 +411,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
INLINE void updatePixels( uint16_t bits );
INLINE void updateVideoScannerHorzEOL();
INLINE void updateVideoScannerAddress();
INLINE uint16_t updateVideoScannerAddressTXT();
INLINE uint16_t updateVideoScannerAddressHGR();
INLINE uint16_t getVideoScannerAddressTXT();
INLINE uint16_t getVideoScannerAddressHGR();
static void initChromaPhaseTables();
static real initFilterChroma (real z);
@ -767,16 +767,16 @@ inline void updateVideoScannerAddress()
}
//===========================================================================
INLINE uint16_t updateVideoScannerAddressTXT()
INLINE uint16_t getVideoScannerAddressTXT()
{
return (g_aClockVertOffsetsTXT[g_nVideoClockVert/8] +
g_pHorzClockOffset [g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nTextPage * 0x400));
}
//===========================================================================
INLINE uint16_t updateVideoScannerAddressHGR()
INLINE uint16_t getVideoScannerAddressHGR()
{
// BUG? g_pHorzClockOffset
// NB. For both A2 and //e use APPLE_IIE_HORZ_CLOCK_OFFSET - see VideoGetScannerAddress() where only TEXT mode adds $1000
return (g_aClockVertOffsetsHGR[g_nVideoClockVert ] +
APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000));
}
@ -1134,7 +1134,7 @@ void updateScreenDoubleHires40 (long cycles6502) // wsUpdateVideoHires0
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressHGR();
uint16_t addr = getVideoScannerAddressHGR();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
@ -1165,7 +1165,7 @@ void updateScreenDoubleHires80 (long cycles6502 ) // wsUpdateVideoDblHires
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressHGR();
uint16_t addr = getVideoScannerAddressHGR();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
@ -1202,7 +1202,7 @@ void updateScreenDoubleLores40 (long cycles6502) // wsUpdateVideo7MLores
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressTXT();
uint16_t addr = getVideoScannerAddressTXT();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
@ -1234,7 +1234,7 @@ void updateScreenDoubleLores80 (long cycles6502) // wsUpdateVideoDblLores
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressTXT();
uint16_t addr = getVideoScannerAddressTXT();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
@ -1275,7 +1275,7 @@ void updateScreenSingleHires40 (long cycles6502)
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressHGR();
uint16_t addr = getVideoScannerAddressHGR();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
@ -1316,7 +1316,7 @@ void updateScreenSingleLores40 (long cycles6502)
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressTXT();
uint16_t addr = getVideoScannerAddressTXT();
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY)
{
@ -1342,7 +1342,7 @@ void updateScreenText40 (long cycles6502)
{
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressTXT();
uint16_t addr = getVideoScannerAddressTXT();
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
@ -1374,7 +1374,7 @@ void updateScreenText80 (long cycles6502)
{
for (; cycles6502 > 0; --cycles6502)
{
uint16_t addr = updateVideoScannerAddressTXT();
uint16_t addr = getVideoScannerAddressTXT();
if ((g_nVideoClockHorz < VIDEO_SCANNER_HORZ_COLORBURST_END) && (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_COLORBURST_BEG))
{
@ -1469,9 +1469,9 @@ uint16_t NTSC_VideoGetScannerAddress ( const ULONG uExecutedCycles )
uint16_t addr;
bool bHires = (g_uVideoMode & VF_HIRES) && !(g_uVideoMode & VF_TEXT); // SW_HIRES && !SW_TEXT
if( bHires )
addr = updateVideoScannerAddressHGR();
addr = getVideoScannerAddressHGR();
else
addr = updateVideoScannerAddressTXT();
addr = getVideoScannerAddressTXT();
g_nVideoClockVert = currVideoClockVert;
g_nVideoClockHorz = currVideoClockHorz;
@ -1629,9 +1629,12 @@ _mono:
}
//===========================================================================
void GenerateVideoTables( void );
void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit
{
make_csbits();
GenerateVideoTables();
initPixelDoubleMasks();
initChromaPhaseTables();
updateMonochromeTables( 0xFF, 0xFF, 0xFF );
@ -1826,3 +1829,112 @@ bool NTSC_GetColorBurst( void )
{
return (g_nColorBurstPixels < 2) ? false : true;
}
//===========================================================================
static bool CheckVideoTables2( eApple2Type type, uint32_t mode )
{
SetApple2Type(type);
NTSC_VideoInitAppleType();
g_uVideoMode = mode;
g_dwCyclesThisFrame = 0;
g_nVideoClockHorz = g_nVideoClockVert = 0;
for (DWORD cycles=0; cycles<VIDEO_SCANNER_MAX_VERT*VIDEO_SCANNER_MAX_HORZ; cycles++)
{
WORD addr1 = VideoGetScannerAddress(cycles);
WORD addr2 = g_uVideoMode & VF_TEXT ? getVideoScannerAddressTXT()
: getVideoScannerAddressHGR();
_ASSERT(addr1 == addr2);
if (addr1 != addr2)
{
char str[80];
sprintf(str, "vpos=%04X, hpos=%02X, Video_adr=$%04X, NTSC_adr=$%04X\n", g_nVideoClockVert, g_nVideoClockHorz, addr1, addr2);
OutputDebugString(str);
return false;
}
g_nVideoClockHorz++;
if (g_nVideoClockHorz == VIDEO_SCANNER_MAX_HORZ)
{
g_nVideoClockHorz = 0;
g_nVideoClockVert++;
}
}
return true;
}
static void CheckVideoTables( void )
{
CheckVideoTables2(A2TYPE_APPLE2PLUS, VF_HIRES);
CheckVideoTables2(A2TYPE_APPLE2PLUS, VF_TEXT);
CheckVideoTables2(A2TYPE_APPLE2E, VF_HIRES);
CheckVideoTables2(A2TYPE_APPLE2E, VF_TEXT);
}
static void GenerateVideoTables( void )
{
eApple2Type currentApple2Type = GetApple2Type();
//
// g_aClockVertOffsetsHGR[]
//
g_uVideoMode = VF_HIRES;
for (UINT i=0, cycle=VIDEO_SCANNER_HORZ_START; i<VIDEO_SCANNER_MAX_VERT; i++, cycle+=VIDEO_SCANNER_MAX_HORZ)
{
g_aClockVertOffsetsHGR[i] = VideoGetScannerAddressPartialV(cycle);
_ASSERT(g_aClockVertOffsetsHGR[i] == g_kClockVertOffsetsHGR[i]);
}
//
// g_aClockVertOffsetsTXT[]
//
g_uVideoMode = VF_TEXT;
for (UINT i=0, cycle=VIDEO_SCANNER_HORZ_START; i<(256+8)/8; i++, cycle+=VIDEO_SCANNER_MAX_HORZ*8)
{
g_aClockVertOffsetsTXT[i] = VideoGetScannerAddressPartialV(cycle);
_ASSERT(g_aClockVertOffsetsTXT[i] == g_kClockVertOffsetsTXT[i]);
}
//
// APPLE_IIP_HORZ_CLOCK_OFFSET[]
//
g_uVideoMode = VF_TEXT;
SetApple2Type(A2TYPE_APPLE2PLUS);
for (UINT j=0; j<5; j++)
{
for (UINT i=0, cycle=j*64*VIDEO_SCANNER_MAX_HORZ; i<VIDEO_SCANNER_MAX_HORZ; i++, cycle++)
{
APPLE_IIP_HORZ_CLOCK_OFFSET[j][i] = VideoGetScannerAddressPartialH(cycle);
_ASSERT(APPLE_IIP_HORZ_CLOCK_OFFSET[j][i] == kAPPLE_IIP_HORZ_CLOCK_OFFSET[j][i]);
}
}
//
// APPLE_IIE_HORZ_CLOCK_OFFSET[]
//
g_uVideoMode = VF_TEXT;
SetApple2Type(A2TYPE_APPLE2E);
for (UINT j=0; j<5; j++)
{
for (UINT i=0, cycle=j*64*VIDEO_SCANNER_MAX_HORZ; i<VIDEO_SCANNER_MAX_HORZ; i++, cycle++)
{
APPLE_IIE_HORZ_CLOCK_OFFSET[j][i] = VideoGetScannerAddressPartialH(cycle);
_ASSERT(APPLE_IIE_HORZ_CLOCK_OFFSET[j][i] == kAPPLE_IIE_HORZ_CLOCK_OFFSET[j][i]);
}
}
//
CheckVideoTables();
VideoResetState();
SetApple2Type(currentApple2Type);
}

View file

@ -639,17 +639,19 @@ void Snapshot_Startup()
Snapshot_LoadState();
bDone = true;
bDone = true; // Prevents a g_bRestart from loading an old save-state
}
void Snapshot_Shutdown()
{
static bool bDone = false;
_ASSERT(!bDone);
_ASSERT(!g_bRestart);
if(!g_bSaveStateOnExit || bDone)
return;
Snapshot_SaveState();
bDone = true;
bDone = true; // Debug flag: this func should only be called once, and never on a g_bRestart
}

View file

@ -338,34 +338,6 @@ void VideoBenchmark () {
MB_ICONINFORMATION | MB_SETFOREGROUND);
}
//===========================================================================
BYTE VideoCheckMode (WORD, WORD address, BYTE, BYTE, ULONG uExecutedCycles)
{
address &= 0xFF;
if (address == 0x7F)
return MemReadFloatingBus(SW_DHIRES != 0, uExecutedCycles);
else {
BOOL result = 0;
switch (address) {
case 0x1A: result = SW_TEXT; break;
case 0x1B: result = SW_MIXED; break;
case 0x1D: result = SW_HIRES; break;
case 0x1E: result = g_nAltCharSetOffset; break;
case 0x1F: result = SW_80COL; break;
case 0x7F: result = SW_DHIRES; break;
}
return KeybGetKeycode() | (result ? 0x80 : 0);
}
}
//===========================================================================
BYTE VideoCheckVbl ( ULONG uExecutedCycles )
{
bool bVblBar = VideoGetVblBar(uExecutedCycles);
BYTE r = KeybGetKeycode();
return (r & ~0x80) | (bVblBar ? 0x80 : 0);
}
// This is called from PageConfig
//===========================================================================
void VideoChooseMonochromeColor ()
@ -798,12 +770,23 @@ void VideoLoadSnapshot(YamlLoadHelper& yamlLoadHelper)
// References to Jim Sather's books are given as eg:
// UTAIIe:5-7,P3 (Understanding the Apple IIe, chapter 5, page 7, Paragraph 3)
//
WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
{
// get video scanner position
//
int nCycles = CpuGetCyclesThisVideoFrame(uExecutedCycles);
static WORD g_PartialV=0, g_PartialH=0;
WORD VideoGetScannerAddressPartialV(DWORD nCycles)
{
VideoGetScannerAddress(nCycles);
return g_PartialV;
}
WORD VideoGetScannerAddressPartialH(DWORD nCycles)
{
VideoGetScannerAddress(nCycles);
return g_PartialH;
}
WORD VideoGetScannerAddress(DWORD nCycles)
{
// machine state switches
//
int nHires = (SW_HIRES && !SW_TEXT) ? 1 : 0;
@ -836,7 +819,7 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
//
int nVLine = nCycles / kHClocks; // which vertical scanning line
int nVState = kVLine0State + nVLine; // V state bits
if ((nVLine >= kVPresetLine)) // check for previous vertical state preset
if (nVLine >= kVPresetLine) // check for previous vertical state preset
{
nVState -= nScanLines; // compensate for preset
}
@ -867,6 +850,8 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
nAddress |= h_1 << 1; // a1
nAddress |= h_2 << 2; // a2
nAddress |= nSum << 3; // a3 - a6
g_PartialH = nAddress;
nAddress |= v_0 << 7; // a7
nAddress |= v_1 << 8; // a8
nAddress |= v_2 << 9; // a9
@ -881,6 +866,8 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
nAddress |= v_A << 10; // a10
nAddress |= v_B << 11; // a11
nAddress |= v_C << 12; // a12
g_PartialV = nAddress - g_PartialH;
nAddress |= p2a << 13; // a13
nAddress |= p2b << 14; // a14
}
@ -888,24 +875,23 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles)
{
// N: insert text-only address bits
//
nAddress |= p2a << 10; // a10
nAddress |= p2b << 11; // a11
g_PartialV = nAddress - g_PartialH;
// Apple ][ (not //e) and HBL?
//
if (IS_APPLE2 && // Apple II only (UTAIIe:I-4,#5)
!h_5 && (!h_4 || !h_3)) // HBL (UTAIIe:8-10,F8.5)
{
nAddress |= 1 << 12; // Y: a12 (add $1000 to address!)
nAddress |= 1 << 12; // Y: a12 (add $1000 to address!)
g_PartialH |= 1 << 12;
}
}
// update VBL' state
//
if (pbVblBar_OUT != NULL)
{
*pbVblBar_OUT = !v_4 || !v_3; // VBL' = (v_4 & v_3)' (UTAIIe:5-10,#3)
nAddress |= p2a << 10; // a10
nAddress |= p2b << 11; // a11
}
// VBL' = v_4' | v_3' = (v_4 & v_3)' (UTAIIe:5-10,#3)
return static_cast<WORD>(nAddress);
}

View file

@ -169,7 +169,9 @@ void VideoRedrawScreen (void);
void VideoRefreshScreen (uint32_t uRedrawWholeScreenVideoMode = 0, bool bRedrawWholeScreen = false);
void VideoReinitialize ();
void VideoResetState ();
WORD VideoGetScannerAddress(bool* pbVblBar_OUT, const DWORD uExecutedCycles);
WORD VideoGetScannerAddressPartialV(DWORD nCycles);
WORD VideoGetScannerAddressPartialH(DWORD nCycles);
WORD VideoGetScannerAddress(DWORD nCycles);
bool VideoGetVblBar(DWORD uExecutedCycles);
bool VideoGetSW80COL(void);
@ -197,10 +199,6 @@ enum VideoScreenShot_e
void Video_TakeScreenShot( VideoScreenShot_e iScreenShotType );
void Video_SetBitmapHeader( WinBmpHeader_t *pBmp, int nWidth, int nHeight, int nBitsPerPixel );
// Win32/MSVC: __stdcall
BYTE VideoCheckMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
BYTE VideoCheckVbl ( ULONG uExecutedCycles );
BYTE VideoSetMode (WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG uExecutedCycles);
void Config_Load_Video(void);