From 9cacf8d90df019c73d76446349f5fa4372918b47 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 30 Jun 2018 14:30:30 +0100 Subject: [PATCH 01/14] Small refactor for reading $C01x soft switch status flags Prevent Apple II from reading $C01x/$C07F soft switch status flags --- source/Keyboard.cpp | 6 ++-- source/Keyboard.h | 6 ++-- source/Memory.cpp | 71 ++++++++++++++++----------------------------- source/Memory.h | 1 - source/Video.cpp | 28 ------------------ source/Video.h | 4 --- 6 files changed, 30 insertions(+), 86 deletions(-) diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 14341ec4..b9734da3 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -108,7 +108,7 @@ void KeybUpdateCtrlShiftStatus() } //=========================================================================== -BYTE KeybGetKeycode () // Used by MemCheckPaging() & VideoCheckMode() +BYTE KeybGetKeycode () // Used by IORead_C01x() and TapeRead() for Pravets8A { return keycode; } @@ -440,7 +440,7 @@ static bool IsAKD(void) //=========================================================================== -BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) +BYTE KeybReadData (void) { LogFileTimeUntilFirstKeyRead(); @@ -462,7 +462,7 @@ BYTE __stdcall KeybReadData (WORD, WORD, BYTE, BYTE, ULONG) //=========================================================================== -BYTE __stdcall KeybReadFlag (WORD, WORD, BYTE, BYTE, ULONG) +BYTE KeybReadFlag (void) { if (g_bPasteFromClipboard) ClipboardInit(); diff --git a/source/Keyboard.h b/source/Keyboard.h index d6236b56..c5518620 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -15,14 +15,12 @@ void KeybQueueKeypress (int,BOOL); 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; diff --git a/source/Memory.cpp b/source/Memory.cpp index a0bb58da..d7537bc3 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -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); @@ -1648,7 +1627,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); } //=========================================================================== diff --git a/source/Memory.h b/source/Memory.h index 9b75730b..191a5b26 100644 --- a/source/Memory.h +++ b/source/Memory.h @@ -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); diff --git a/source/Video.cpp b/source/Video.cpp index da2dd2a8..4ce1b145 100644 --- a/source/Video.cpp +++ b/source/Video.cpp @@ -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 () diff --git a/source/Video.h b/source/Video.h index dbae4172..1e133a11 100644 --- a/source/Video.h +++ b/source/Video.h @@ -197,10 +197,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); From 881e51874b9723f0280792c78f2217e4ed37f2bf Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 30 Jun 2018 18:21:28 +0100 Subject: [PATCH 02/14] Fix for other apps having sluggish key response - fixes #569 --- source/Applewin.cpp | 2 +- source/Memory.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index de24d066..356a869c 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -435,7 +435,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) } } } diff --git a/source/Memory.cpp b/source/Memory.cpp index d7537bc3..79357f8d 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1831,6 +1831,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); From c457241229c8249f5582a6cff76fae23f99bfa81 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 15 Jul 2018 15:38:37 +0100 Subject: [PATCH 03/14] Keyboard: . When in MODE_LOGO, don't pass WM_CHAR to Apple II keyboard (now consistent with WM_KEYDOWN) . Small refactor for Apple II keyboard's WM_KEYDOWN handler Move code for log init & done to Log.cpp --- source/Applewin.cpp | 14 ++------------ source/Frame.cpp | 6 ++++-- source/Keyboard.cpp | 29 +++++++++++++++++++---------- source/Log.cpp | 25 +++++++++++++++++++++++++ source/Log.h | 6 ++++-- 5 files changed, 54 insertions(+), 26 deletions(-) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 356a869c..dc1c9315 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -1077,12 +1077,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) { @@ -1559,12 +1554,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(); diff --git a/source/Frame.cpp b/source/Frame.cpp index 245245bf..3b4803b5 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1098,7 +1098,8 @@ LRESULT CALLBACK FrameWndProc ( { if( !g_bDebuggerEatKey ) { - KeybQueueKeypress((int)wparam, ASCII); + if (g_nAppMode != MODE_LOGO) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard + KeybQueueKeypress((int)wparam, ASCII); } else { @@ -1399,7 +1400,8 @@ LRESULT CALLBACK FrameWndProc ( BOOL autorep = (HIWORD(lparam) & KF_REPEAT) != 0; BOOL IsJoyKey = JoyProcessKey((int)wparam, extended, down, autorep); - if (!IsJoyKey && (g_nAppMode != MODE_LOGO)) + if (!IsJoyKey && + (g_nAppMode != MODE_LOGO)) // !MODE_LOGO - not emulating so don't pass to the VM's keyboard { KeybQueueKeypress((int)wparam, NOT_ASCII); diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index b9734da3..bd1bb24a 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -37,8 +37,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "Video.h" // Needed by TK3000 //e, to refresh the frame at each |Mode| change 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 +50,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; @@ -102,7 +102,7 @@ bool KeybGetShiftStatus () //=========================================================================== void KeybUpdateCtrlShiftStatus() { - g_bShiftKey = (GetKeyState( VK_SHIFT ) & KF_UP) ? true : false; // 0x8000 KF_UP + g_bShiftKey = (GetKeyState( VK_SHIFT ) & KF_UP) ? true : false; g_bCtrlKey = (GetKeyState( VK_CONTROL) & KF_UP) ? true : false; g_bAltKey = (GetKeyState( VK_MENU ) & KF_UP) ? true : false; } @@ -271,8 +271,6 @@ void KeybQueueKeypress (int key, BOOL bASCII) keycode = key; } } - - lastvirtkey = LOBYTE(VkKeyScan(key)); } else //(bASCII != ASCII) // WM_KEYDOWN { @@ -299,13 +297,24 @@ 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])) + 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 ) & KF_UP)) // Right ALT + { + // + } + else + { return; - - keycode = asciicode[IS_APPLE2 ? 0 : 1][key - VK_LEFT]; // Convert to Apple arrow keycode - lastvirtkey = key; + } } keywaiting = 1; diff --git a/source/Log.cpp b/source/Log.cpp index 3c8753be..15f9dade 100644 --- a/source/Log.cpp +++ b/source/Log.cpp @@ -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]; diff --git a/source/Log.h b/source/Log.h index d97224de..d952e69a 100644 --- a/source/Log.h +++ b/source/Log.h @@ -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, ...); From 97b07eaee40ba9c774ae12a4e5e7af82f79259ef Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 15 Jul 2018 21:00:01 +0100 Subject: [PATCH 04/14] Keyboard hook filter: . Created a dedicated thread with message loop (#570) HookFilter dll: Only call GetKeyState() if keycode is ESC (instead of every time) DebuggerCursorUpdate(): reduce sleep from 10ms to 1ms --- HookFilter/HookFilter.cpp | 9 +++-- source/Applewin.cpp | 73 ++++++++++++++++++++++++++++++++++++--- source/Debugger/Debug.cpp | 2 +- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index fcf3bf33..d7e9602d 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -42,9 +42,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) + { + bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0; + if (ControlDown) + suppress = true; + } // Suppress keys by returning 1 if (suppress) diff --git a/source/Applewin.cpp b/source/Applewin.cpp index dc1c9315..9c64d904 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -872,8 +872,11 @@ 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")); @@ -905,12 +908,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) @@ -1423,7 +1488,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"); } @@ -1535,7 +1600,7 @@ int APIENTRY WinMain(HINSTANCE passinstance, HINSTANCE, LPSTR lpCmdLine, int) if (g_bHookSystemKey) { - UnhookFilterForKeyboard(); + UninitHookThread(); LogFileOutput("Main: UnhookFilterForKeyboard()\n"); } } diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index c57f55ae..404b570a 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -9680,7 +9680,7 @@ void DebuggerCursorUpdate() } else { - Sleep(10); // Stop process hogging CPU + Sleep(1); // Stop process hogging CPU } } From 5e13bef808d62b5186fd8aad2df54e949df9f126 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 23 Jul 2018 22:14:54 +0100 Subject: [PATCH 05/14] VS2015: Add missing Hook Filter dependency --- AppleWinExpress2015.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/AppleWinExpress2015.sln b/AppleWinExpress2015.sln index 803daee0..19114355 100644 --- a/AppleWinExpress2015.sln +++ b/AppleWinExpress2015.sln @@ -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} From 1afa2490c54ba69015162ce690f84f09b8538146 Mon Sep 17 00:00:00 2001 From: tomcw Date: Mon, 23 Jul 2018 22:27:33 +0100 Subject: [PATCH 06/14] Keyboard: Refactor for GetKeyState() --- source/Debugger/Debug.cpp | 4 ++-- source/Frame.h | 3 --- source/Keyboard.cpp | 11 ++++++----- source/Keyboard.h | 4 +++- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index 404b570a..b38f40d8 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -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; } diff --git a/source/Frame.h b/source/Frame.h index 672b95e9..f5cace2d 100644 --- a/source/Frame.h +++ b/source/Frame.h @@ -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; diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index bd1bb24a..c890c4e2 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -102,9 +102,9 @@ bool KeybGetShiftStatus () //=========================================================================== void KeybUpdateCtrlShiftStatus() { - g_bShiftKey = (GetKeyState( VK_SHIFT ) & KF_UP) ? true : false; - g_bCtrlKey = (GetKeyState( VK_CONTROL) & KF_UP) ? true : false; - g_bAltKey = (GetKeyState( VK_MENU ) & KF_UP) ? true : false; + g_bShiftKey = (GetKeyState( VK_SHIFT ) < 0) ? true : false; // L or R shift + g_bCtrlKey = (GetKeyState( VK_CONTROL) < 0) ? true : false; // L or R ctrl + g_bAltKey = (GetKeyState( VK_MENU ) < 0) ? true : false; // L or R alt } //=========================================================================== @@ -114,7 +114,7 @@ BYTE KeybGetKeycode () // Used by IORead_C01x() and TapeRead() for Pravets8A } //=========================================================================== -void KeybQueueKeypress (int key, BOOL bASCII) +void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) { if (bASCII == ASCII) // WM_CHAR { @@ -307,9 +307,10 @@ void KeybQueueKeypress (int key, BOOL bASCII) return; keycode = n; } - else if ((GetKeyState( VK_RMENU ) & KF_UP)) // Right ALT + else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) { // + return; } else { diff --git a/source/Keyboard.h b/source/Keyboard.h index c5518620..802903fc 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -1,5 +1,7 @@ #pragma once +enum Keystroke_e {NOT_ASCII=0, ASCII}; + void ClipboardInitiatePaste(); void KeybReset(); @@ -11,7 +13,7 @@ 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); From 6ed354714e2ecdc1f3beb7e3b00794925c1ded85 Mon Sep 17 00:00:00 2001 From: TomCh Date: Fri, 27 Jul 2018 21:55:53 +0100 Subject: [PATCH 07/14] Support ClosedApple+key with Alt Gr when combined with a regular keyboard key: . When Alt Gr is pressed, then manually post WM_CHAR message on receiving a WM_KEYDOWN (manually translate and account for shift/control/caps-lock) . Hook filter: suppress Alt Gr's (ie. RMENU's) fake LCONTROL messages Also: . Hook filter: allow Ctrl+Shift+Esc (for Task Manager) . Keyboard: refactor only use accessor functions to get the Alt/Control/Shift state --- HookFilter/HookFilter.cpp | 16 +++++++- source/Debugger/Debug.cpp | 8 ++-- source/Frame.cpp | 45 ++++++++++++--------- source/Keyboard.cpp | 83 ++++++++++++++++++++++++++------------- source/Keyboard.h | 7 +--- 5 files changed, 101 insertions(+), 58 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index d7e9602d..e21ee760 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -20,6 +20,18 @@ 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 (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) + { + suppress = true; + } + // Suppress alt-tab if (pKbdLlHookStruct->vkCode == VK_TAB && (pKbdLlHookStruct->flags & LLKHF_ALTDOWN)) { @@ -44,8 +56,8 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( // Suppress ctrl-escape if (pKbdLlHookStruct->vkCode == VK_ESCAPE) { - bool ControlDown = (GetKeyState(VK_CONTROL) & 0x8000) != 0; - if (ControlDown) + // But don't suppress CTRL+SHIFT+ESC + if (GetKeyState(VK_CONTROL) < 0 && GetKeyState(VK_SHIFT) >= 0) suppress = true; } diff --git a/source/Debugger/Debug.cpp b/source/Debugger/Debug.cpp index b38f40d8..8f2b6a64 100644 --- a/source/Debugger/Debug.cpp +++ b/source/Debugger/Debug.cpp @@ -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) diff --git a/source/Frame.cpp b/source/Frame.cpp index 3b4803b5..7a6a255d 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -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 @@ -1096,15 +1097,16 @@ LRESULT CALLBACK FrameWndProc ( case WM_CHAR: if ((g_nAppMode == MODE_RUNNING) || (g_nAppMode == MODE_STEPPING) || (g_nAppMode == MODE_LOGO)) { - if( !g_bDebuggerEatKey ) + 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((int)wparam, ASCII); - } - else - { - g_bDebuggerEatKey = false; + KeybQueueKeypress(wparam, ASCII); } + + g_bDebuggerEatKey = false; } else if (g_nAppMode == MODE_DEBUG) { @@ -1290,19 +1292,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; } @@ -1331,7 +1333,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 } @@ -1340,7 +1342,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)) @@ -1392,18 +1394,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 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); @@ -1433,6 +1437,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); } @@ -1749,7 +1756,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); @@ -1763,7 +1770,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); @@ -1946,7 +1953,7 @@ static void ProcessButtonClick(int button, bool bFromButtonUI /*=false*/) case BTN_RUN: KeybUpdateCtrlShiftStatus(); - if( g_bCtrlKey ) + if( KeybGetCtrlStatus() ) { CtrlReset(); if (g_nAppMode == MODE_DEBUG) @@ -1990,7 +1997,7 @@ static void ProcessButtonClick(int button, bool bFromButtonUI /*=false*/) case BTN_FULLSCR: KeybUpdateCtrlShiftStatus(); - ScreenWindowResize(g_bCtrlKey); + ScreenWindowResize( KeybGetCtrlStatus() ); break; case BTN_DEBUG: diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index c890c4e2..c23190e6 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -35,6 +35,7 @@ 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] = { // VK_LEFT/UP/RIGHT/DOWN/SELECT, VK_PRINT/EXECUTE/SNAPSHOT/INSERT/DELETE @@ -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,9 +98,9 @@ bool KeybGetShiftStatus () //=========================================================================== void KeybUpdateCtrlShiftStatus() { - g_bShiftKey = (GetKeyState( VK_SHIFT ) < 0) ? true : false; // L or R shift - g_bCtrlKey = (GetKeyState( VK_CONTROL) < 0) ? true : false; // L or R ctrl 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 } //=========================================================================== @@ -114,7 +110,10 @@ BYTE KeybGetKeycode () // Used by IORead_C01x() and TapeRead() for Pravets8A } //=========================================================================== -void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) + +bool IsVirtualKeyAnAppleIIKey(WPARAM wparam); + +void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) { if (bASCII == ASCII) // WM_CHAR { @@ -205,7 +204,7 @@ void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) } else //i.e. latin letters { - if (GetCapsLockAllowed() == false) + if (GetCapsLockAllowed() == false) { if (key == '{') keycode = '['; if (key == '}') keycode = ']'; @@ -309,7 +308,27 @@ void KeybQueueKeypress(WPARAM key, Keystroke_e bASCII) } else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) { - // + 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; + + // 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 (GetKeyState(VK_CONTROL) < 0) + { + LogOutput("L-Control=%d, R-Control=%d\n", GetKeyState(VK_LCONTROL), GetKeyState(VK_RCONTROL)); + newKey -= 'A' - 1; // convert to control-key + } + } + + PostMessage(g_hFrameWindow, WM_CHAR, newKey, 0); + } + return; } else @@ -401,16 +420,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 || @@ -425,6 +436,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; diff --git a/source/Keyboard.h b/source/Keyboard.h index 802903fc..65920f39 100644 --- a/source/Keyboard.h +++ b/source/Keyboard.h @@ -5,12 +5,11 @@ 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(WPARAM key, Keystroke_e bASCII); @@ -22,7 +21,3 @@ BYTE KeybReadFlag (void); void KeybSetSnapshot_v1(const BYTE LastKey); void KeybSaveSnapshot(class YamlSaveHelper& yamlSaveHelper); void KeybLoadSnapshot(class YamlLoadHelper& yamlLoadHelper); - -extern bool g_bShiftKey; -extern bool g_bCtrlKey; -extern bool g_bAltKey; From a4f225555fa68fd7ac619b215998c18f43d37ef3 Mon Sep 17 00:00:00 2001 From: tomcw Date: Fri, 27 Jul 2018 22:05:59 +0100 Subject: [PATCH 08/14] Keyboard: added comment for GH558 and removed some debug logging --- HookFilter/HookFilter.cpp | 2 +- source/Keyboard.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index e21ee760..6a4525d9 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -27,7 +27,7 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( // . 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 (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) + if (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) // GH#558 { suppress = true; } diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index c23190e6..7ad5af59 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -306,7 +306,7 @@ void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) return; keycode = n; } - else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) + else if ((GetKeyState(VK_RMENU) < 0)) // Right Alt (aka Alt Gr) - GH#558 { if (IsVirtualKeyAnAppleIIKey(key)) { @@ -320,10 +320,7 @@ void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) if ( (GetKeyState(VK_SHIFT) >= 0) && !g_bCapsLock ) newKey += 'a' - 'A'; // convert to lowercase key else if (GetKeyState(VK_CONTROL) < 0) - { - LogOutput("L-Control=%d, R-Control=%d\n", GetKeyState(VK_LCONTROL), GetKeyState(VK_RCONTROL)); newKey -= 'A' - 1; // convert to control-key - } } PostMessage(g_hFrameWindow, WM_CHAR, newKey, 0); From b069614a2569d7e92e87627c03943fffd05ce3b4 Mon Sep 17 00:00:00 2001 From: tomcw Date: Sat, 28 Jul 2018 10:44:12 +0100 Subject: [PATCH 09/14] 1.27.6: Bump version & update History.txt --- bin/History.txt | 5 +++++ resource/Applewin.rc | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/bin/History.txt b/bin/History.txt index 4c2ec95e..9bbe234a 100644 --- a/bin/History.txt +++ b/bin/History.txt @@ -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 + not working (when using right ALT key). + 1.27.5.0 - 24 Jun 2018 ---------------------- diff --git a/resource/Applewin.rc b/resource/Applewin.rc index c207be7c..a71c4458 100644 --- a/resource/Applewin.rc +++ b/resource/Applewin.rc @@ -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" From 140d505fe96ff36223cd24afaab53b8cf9a6041d Mon Sep 17 00:00:00 2001 From: tomcw Date: Sun, 29 Jul 2018 22:34:09 +0100 Subject: [PATCH 10/14] Keyboard: . reverted default so that ALT+TAB is not hooked (#556) . reverted default so that ALT GR's fake LCONTROL is not hooked (#558) . added new switches: -hook-alt-tab and -hook-altgr-control to support hooking these key combo's (#556) --- HookFilter/HookFilter.cpp | 10 +++++++--- source/Applewin.cpp | 19 +++++++++++++++++-- source/Applewin.h | 1 + source/Keyboard.cpp | 2 +- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/HookFilter/HookFilter.cpp b/HookFilter/HookFilter.cpp index 6a4525d9..fe3a045d 100644 --- a/HookFilter/HookFilter.cpp +++ b/HookFilter/HookFilter.cpp @@ -1,6 +1,8 @@ #include 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 _@bytes @@ -27,13 +29,13 @@ extern "C" __declspec(dllexport) LRESULT CALLBACK LowLevelKeyboardProc( // . 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 (pKbdLlHookStruct->vkCode == VK_LCONTROL && pKbdLlHookStruct->scanCode >= 0x200) // GH#558 + 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; @@ -69,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; } diff --git a/source/Applewin.cpp b/source/Applewin.cpp index 9c64d904..46cfbda8 100644 --- a/source/Applewin.cpp +++ b/source/Applewin.cpp @@ -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; @@ -882,10 +889,10 @@ static bool HookFilterForKeyboard() _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"); @@ -1294,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); diff --git a/source/Applewin.h b/source/Applewin.h index 43a6937b..a3732ecc 100644 --- a/source/Applewin.h +++ b/source/Applewin.h @@ -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]; diff --git a/source/Keyboard.cpp b/source/Keyboard.cpp index 7ad5af59..c28afd46 100644 --- a/source/Keyboard.cpp +++ b/source/Keyboard.cpp @@ -319,7 +319,7 @@ void KeybQueueKeypress (WPARAM key, Keystroke_e bASCII) { if ( (GetKeyState(VK_SHIFT) >= 0) && !g_bCapsLock ) newKey += 'a' - 'A'; // convert to lowercase key - else if (GetKeyState(VK_CONTROL) < 0) + else if (GetHookAltGrControl() && GetKeyState(VK_CONTROL) < 0) newKey -= 'A' - 1; // convert to control-key } From 898f30f08a8710abaa29529c9ce937a1f515d88f Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 31 Jul 2018 18:06:53 +0100 Subject: [PATCH 11/14] Fixed save-state on exit not working if there was a VM restart (eg. config h/w change). Fixes #564 --- source/Frame.cpp | 4 +++- source/SaveState.cpp | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 7a6a255d..4afb1e82 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1092,6 +1092,7 @@ 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: @@ -1175,7 +1176,8 @@ LRESULT CALLBACK FrameWndProc ( case WM_DESTROY: LogFileOutput("WM_DESTROY\n"); DragAcceptFiles(window,0); - Snapshot_Shutdown(); + if (!g_bRestart) // GH#564: Only save-state on shutdown (not on a restart) + Snapshot_Shutdown(); DebugDestroy(); if (!g_bRestart) { DiskDestroy(); diff --git a/source/SaveState.cpp b/source/SaveState.cpp index d067a381..ff2c7a96 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -637,17 +637,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: should only be called once, and never on a g_bRestart } From e4bd6162c50760239f74148bd90fb3c066247b87 Mon Sep 17 00:00:00 2001 From: tomcw Date: Tue, 31 Jul 2018 18:17:42 +0100 Subject: [PATCH 12/14] Refactor: move code for WM_CLOSE next to WM_DESTROY, and WM_KEYDOWN next to WM_CHAR --- source/Frame.cpp | 91 +++++++++++++++++++++----------------------- source/SaveState.cpp | 2 +- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/source/Frame.cpp b/source/Frame.cpp index 4afb1e82..b58379c0 100644 --- a/source/Frame.cpp +++ b/source/Frame.cpp @@ -1095,25 +1095,29 @@ LRESULT CALLBACK FrameWndProc ( // 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) - { -#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_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"); @@ -1173,30 +1177,6 @@ LRESULT CALLBACK FrameWndProc ( 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_DISPLAYCHANGE: VideoReinitialize(); break; @@ -1421,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)) @@ -1795,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; diff --git a/source/SaveState.cpp b/source/SaveState.cpp index ff2c7a96..4870e9d6 100644 --- a/source/SaveState.cpp +++ b/source/SaveState.cpp @@ -651,5 +651,5 @@ void Snapshot_Shutdown() Snapshot_SaveState(); - bDone = true; // Debug flag: should only be called once, and never on a g_bRestart + bDone = true; // Debug flag: this func should only be called once, and never on a g_bRestart } From 5e02eaee531032cfd9ff5c1f77a269303d26de14 Mon Sep 17 00:00:00 2001 From: tomcw Date: Thu, 2 Aug 2018 22:37:20 +0100 Subject: [PATCH 13/14] Use VideoGetScannerAddress() to generate the NTSC video lookup tables --- source/Memory.cpp | 1 - source/NTSC.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++--- source/Video.cpp | 6 +-- 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/source/Memory.cpp b/source/Memory.cpp index 79357f8d..70e308ea 100644 --- a/source/Memory.cpp +++ b/source/Memory.cpp @@ -1618,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) } diff --git a/source/NTSC.cpp b/source/NTSC.cpp index ec480f67..72f045a4 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -136,7 +136,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 +199,9 @@ 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 ] = + static unsigned short g_aClockVertOffsetsHGR[ VIDEO_SCANNER_MAX_VERT ]; + + 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 +226,9 @@ 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_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,9 @@ 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 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 +288,9 @@ 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 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, @@ -776,7 +784,7 @@ INLINE uint16_t updateVideoScannerAddressTXT() //=========================================================================== INLINE uint16_t updateVideoScannerAddressHGR() { - // BUG? g_pHorzClockOffset + // NB. Not a bug: For both A2 and //e then 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)); } @@ -1629,9 +1637,12 @@ _mono: } //=========================================================================== +void GenerateVideoTables( void ); + void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit { make_csbits(); + GenerateVideoTables(); initPixelDoubleMasks(); initChromaPhaseTables(); updateMonochromeTables( 0xFF, 0xFF, 0xFF ); @@ -1826,3 +1837,73 @@ bool NTSC_GetColorBurst( void ) { return (g_nColorBurstPixels < 2) ? false : true; } + +//=========================================================================== +void GenerateVideoTables( void ) +{ + eApple2Type currentApple2Type = GetApple2Type(); + + g_uVideoMode = VF_HIRES; + for (UINT i=0, cycle=VIDEO_SCANNER_HORZ_START; i<256; i++, cycle+=VIDEO_SCANNER_MAX_HORZ) + { + if (i % 64 == 0) cycle=VIDEO_SCANNER_HORZ_START; // repeat every 64th scanline + g_aClockVertOffsetsHGR[i] = VideoGetScannerAddress(NULL, cycle) - 0x2000; + _ASSERT(g_aClockVertOffsetsHGR[i] == g_kClockVertOffsetsHGR[i]); + } + + // Repeat last 6 entries for scanlines [256...261] + const UINT kLine256 = 64 - (VIDEO_SCANNER_MAX_VERT - 256); + for (UINT i=256, cycle=kLine256*VIDEO_SCANNER_MAX_HORZ+VIDEO_SCANNER_HORZ_START; i Date: Sun, 5 Aug 2018 22:19:51 +0100 Subject: [PATCH 14/14] Improve VideoGetScannerAddress() to generate NTSC tables; and check tables with all video cycles --- source/NTSC.cpp | 147 ++++++++++++++++++++++++++++------------------- source/Video.cpp | 40 +++++++++---- source/Video.h | 4 +- 3 files changed, 121 insertions(+), 70 deletions(-) diff --git a/source/NTSC.cpp b/source/NTSC.cpp index 72f045a4..b97b5b6b 100644 --- a/source/NTSC.cpp +++ b/source/NTSC.cpp @@ -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 @@ -199,8 +196,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define SIGNAL_1 0.7465656072f // Tables - static unsigned short 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, @@ -226,8 +228,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0B80,0x0F80,0x1380,0x1780,0x1B80,0x1F80 }; - static unsigned short g_aClockVertOffsetsTXT[33]; - static unsigned short g_kClockVertOffsetsTXT[33] = { 0x0000,0x0080,0x0100,0x0180,0x0200,0x0280,0x0300,0x0380, @@ -238,8 +238,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x380 }; - static unsigned short 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, @@ -288,8 +286,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0x0018,0x0019,0x001A,0x001B,0x001C,0x001D,0x001E,0x001F} }; - static unsigned short 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, @@ -337,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 @@ -397,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 ); @@ -419,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); @@ -775,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() { - // NB. Not a bug: For both A2 and //e then use APPLE_IIE_HORZ_CLOCK_OFFSET - see VideoGetScannerAddress() where only TEXT mode adds $1000 + // 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)); } @@ -1142,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) { @@ -1173,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) { @@ -1210,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) { @@ -1242,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) { @@ -1283,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) { @@ -1324,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) { @@ -1350,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)) { @@ -1382,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)) { @@ -1477,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; @@ -1839,55 +1831,93 @@ bool NTSC_GetColorBurst( void ) } //=========================================================================== -void GenerateVideoTables( void ) + +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= kVPresetLine)) // check for previous vertical state preset + if (nVLine >= kVPresetLine) // check for previous vertical state preset { nVState -= nScanLines; // compensate for preset } @@ -835,6 +850,8 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, DWORD nCycles) 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 @@ -849,6 +866,8 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, DWORD nCycles) 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 } @@ -856,24 +875,23 @@ WORD VideoGetScannerAddress(bool* pbVblBar_OUT, DWORD nCycles) { // 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(nAddress); } diff --git a/source/Video.h b/source/Video.h index 1e133a11..3bacb655 100644 --- a/source/Video.h +++ b/source/Video.h @@ -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);