From 6ed354714e2ecdc1f3beb7e3b00794925c1ded85 Mon Sep 17 00:00:00 2001 From: TomCh Date: Fri, 27 Jul 2018 21:55:53 +0100 Subject: [PATCH] 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;