From f1502fb6bdebff582ab596051aa2d6023c219d33 Mon Sep 17 00:00:00 2001 From: Doug Brown Date: Sun, 28 Nov 2021 16:09:14 -0800 Subject: [PATCH] Add optional ability to intercept Windows key This allows you to use the Windows key as your option key, bypassing Windows' various uses of the key for the start menu and keyboard shortcuts. This is enabled with the "reservewindowskey" setting in the prefs file, and a checkbox has been added to the settings GUI. --- BasiliskII/src/Windows/main_windows.cpp | 48 +++++++++++++++++++ BasiliskII/src/Windows/prefs_editor_gtk.cpp | 8 ++++ BasiliskII/src/Windows/prefs_windows.cpp | 3 ++ .../src/Windows/user_strings_windows.cpp | 1 + BasiliskII/src/Windows/user_strings_windows.h | 1 + SheepShaver/src/Windows/main_windows.cpp | 48 +++++++++++++++++++ SheepShaver/src/Windows/prefs_windows.cpp | 2 + .../src/Windows/user_strings_windows.cpp | 1 + .../src/Windows/user_strings_windows.h | 1 + 9 files changed, 113 insertions(+) diff --git a/BasiliskII/src/Windows/main_windows.cpp b/BasiliskII/src/Windows/main_windows.cpp index e8d39095..77e2db5d 100755 --- a/BasiliskII/src/Windows/main_windows.cpp +++ b/BasiliskII/src/Windows/main_windows.cpp @@ -98,11 +98,14 @@ uint8 *ScratchMem = NULL; // Scratch memory for Mac ROM writes static bool lm_area_mapped = false; // Flag: Low Memory area mmap()ped #endif +static HHOOK keyboard_hook; // Hook for intercepting windows key events + // Prototypes static int xpram_func(void *arg); static int tick_func(void *arg); static void one_tick(...); +static LRESULT CALLBACK low_level_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam); /* @@ -283,6 +286,12 @@ int main(int argc, char **argv) QuitEmulator(); #endif + // Install keyboard hook to block Windows key if enabled in prefs + if (PrefsFindBool("reservewindowskey")) + { + keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, low_level_keyboard_hook, GetModuleHandle(NULL), 0); + } + // Initialize SDL system int sdl_flags = 0; #ifdef USE_SDL_VIDEO @@ -711,3 +720,42 @@ bool ChoiceAlert(const char *text, const char *pos, const char *neg) printf(GetString(STR_SHELL_WARNING_PREFIX), text); return false; //!! } + +/* + * Low level keyboard hook allowing us to intercept events involving the Windows key + */ +static LRESULT CALLBACK low_level_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam) +{ + // Not a relevant event, immediately pass it on + if (nCode != HC_ACTION) + return CallNextHookEx(keyboard_hook, nCode, wParam, lParam); + + KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam; + switch (wParam) { + case WM_KEYDOWN: + case WM_KEYUP: + // Intercept left/right windows keys when we have keyboard focus so Windows doesn't handle them + if (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN) { + bool intercept_event = false; +#ifdef USE_SDL_VIDEO + if (sdl_window && (SDL_GetWindowFlags(sdl_window) & SDL_WINDOW_INPUT_FOCUS)) { + intercept_event = true; + } +#endif + + // If we've determined we should intercept the event, intercept it. But pass the event onto SDL so Basilisk handles it. + if (intercept_event) { + SDL_Event e; + memset(&e, 0, sizeof(e)); + e.type = (wParam == WM_KEYDOWN) ? SDL_KEYDOWN : SDL_KEYUP; + e.key.keysym.sym = (p->vkCode == VK_LWIN) ? SDLK_LGUI : SDLK_RGUI; + SDL_PushEvent(&e); + return 1; + } + } + break; + } + + // If we fall here, we weren't supposed to intercept it. + return CallNextHookEx(keyboard_hook, nCode, wParam, lParam); +} diff --git a/BasiliskII/src/Windows/prefs_editor_gtk.cpp b/BasiliskII/src/Windows/prefs_editor_gtk.cpp index 50e8d9f8..b1cc44dc 100644 --- a/BasiliskII/src/Windows/prefs_editor_gtk.cpp +++ b/BasiliskII/src/Windows/prefs_editor_gtk.cpp @@ -1298,6 +1298,12 @@ static void tb_keycodes(GtkWidget *widget) set_input_sensitive(); } +// "Reserve Windows Key" button toggled +static void tb_reservewindowskey(GtkWidget *widget) +{ + PrefsReplaceBool("reservewindowskey", GTK_TOGGLE_BUTTON(widget)->active); +} + // "Mouse Wheel Mode" selected static void mn_wheel_page(...) {PrefsReplaceInt32("mousewheelmode", 0); set_input_sensitive();} static void mn_wheel_cursor(...) {PrefsReplaceInt32("mousewheelmode", 1); set_input_sensitive();} @@ -1345,6 +1351,8 @@ static void create_input_pane(GtkWidget *top) gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 0); g_object_set_data(G_OBJECT(w_keycode_file), "chooser_button", button); + make_checkbox(box, STR_RESERVE_WINDOWS_KEY_CTRL, "reservewindowskey", GTK_SIGNAL_FUNC(tb_reservewindowskey)); + make_separator(box); static const opt_desc options[] = { diff --git a/BasiliskII/src/Windows/prefs_windows.cpp b/BasiliskII/src/Windows/prefs_windows.cpp index 527dcbfc..4404c12c 100755 --- a/BasiliskII/src/Windows/prefs_windows.cpp +++ b/BasiliskII/src/Windows/prefs_windows.cpp @@ -53,6 +53,8 @@ prefs_desc platform_prefs_items[] = { {"sdlrender", TYPE_STRING, false, "SDL_Renderer driver (\"auto\", \"software\" (may be faster), etc.)"}, {"sdl_vsync", TYPE_BOOLEAN, false, "Make SDL_Renderer vertical sync frames to host (eg. with software renderer)"}, #endif + {"reservewindowskey", TYPE_BOOLEAN, false, "block Windows key from activating start menu"}, + {NULL, TYPE_END, false, NULL} // End of list }; @@ -136,4 +138,5 @@ void AddPlatformPrefsDefaults(void) PrefsReplaceString("sdlrender", "software"); PrefsReplaceBool("sdl_vsync", false); #endif + PrefsAddBool("reservewindowskey", false); } diff --git a/BasiliskII/src/Windows/user_strings_windows.cpp b/BasiliskII/src/Windows/user_strings_windows.cpp index dc2993da..2b3c3c6b 100755 --- a/BasiliskII/src/Windows/user_strings_windows.cpp +++ b/BasiliskII/src/Windows/user_strings_windows.cpp @@ -56,6 +56,7 @@ user_string_def platform_strings[] = { {STR_INPUT_PANE_TITLE, "Keyboard/Mouse"}, {STR_KEYCODES_CTRL, "Use Raw Keycodes"}, {STR_KEYCODE_FILE_CTRL, "Keycode Translation File"}, + {STR_RESERVE_WINDOWS_KEY_CTRL, "Reserve Windows Key"}, {STR_MOUSEWHEELMODE_CTRL, "Mouse Wheel Function"}, {STR_MOUSEWHEELMODE_PAGE_LAB, "Page Up/Down"}, {STR_MOUSEWHEELMODE_CURSOR_LAB, "Cursor Up/Down"}, diff --git a/BasiliskII/src/Windows/user_strings_windows.h b/BasiliskII/src/Windows/user_strings_windows.h index c8e21e31..7daea7a1 100755 --- a/BasiliskII/src/Windows/user_strings_windows.h +++ b/BasiliskII/src/Windows/user_strings_windows.h @@ -58,6 +58,7 @@ enum { STR_INPUT_PANE_TITLE, STR_KEYCODES_CTRL, STR_KEYCODE_FILE_CTRL, + STR_RESERVE_WINDOWS_KEY_CTRL, STR_MOUSEWHEELMODE_CTRL, STR_MOUSEWHEELMODE_PAGE_LAB, STR_MOUSEWHEELMODE_CURSOR_LAB, diff --git a/SheepShaver/src/Windows/main_windows.cpp b/SheepShaver/src/Windows/main_windows.cpp index 0683c471..0ee65b12 100755 --- a/SheepShaver/src/Windows/main_windows.cpp +++ b/SheepShaver/src/Windows/main_windows.cpp @@ -105,6 +105,8 @@ uintptr SheepMem::base = 0x60000000; // Address of SheepShaver data uintptr SheepMem::proc; // Bottom address of SheepShave procedures uintptr SheepMem::data; // Top of SheepShaver data (stack like storage) +static HHOOK keyboard_hook; // Hook for intercepting windows key events + // Prototypes static bool kernel_data_init(void); @@ -118,6 +120,7 @@ extern void emul_ppc(uint32 start); extern void init_emul_ppc(void); extern void exit_emul_ppc(void); sigsegv_return_t sigsegv_handler(sigsegv_info_t *sip); +static LRESULT CALLBACK low_level_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam); /* @@ -210,6 +213,12 @@ int main(int argc, char **argv) // // Load win32 libraries // KernelInit(); + // Install keyboard hook to block Windows key if enabled in prefs + if (PrefsFindBool("reservewindowskey")) + { + keyboard_hook = SetWindowsHookEx(WH_KEYBOARD_LL, low_level_keyboard_hook, GetModuleHandle(NULL), 0); + } + // Initialize SDL system int sdl_flags = 0; #ifdef USE_SDL_VIDEO @@ -839,3 +848,42 @@ bool ChoiceAlert(const char *text, const char *pos, const char *neg) printf(GetString(STR_SHELL_WARNING_PREFIX), text); return false; //!! } + +/* + * Low level keyboard hook allowing us to intercept events involving the Windows key + */ +static LRESULT CALLBACK low_level_keyboard_hook(int nCode, WPARAM wParam, LPARAM lParam) +{ + // Not a relevant event, immediately pass it on + if (nCode != HC_ACTION) + return CallNextHookEx(keyboard_hook, nCode, wParam, lParam); + + KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *)lParam; + switch (wParam) { + case WM_KEYDOWN: + case WM_KEYUP: + // Intercept left/right windows keys when we have keyboard focus so Windows doesn't handle them + if (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN) { + bool intercept_event = false; +#ifdef USE_SDL_VIDEO + if (sdl_window && (SDL_GetWindowFlags(sdl_window) & SDL_WINDOW_INPUT_FOCUS)) { + intercept_event = true; + } +#endif + + // If we've determined we should intercept the event, intercept it. But pass the event onto SDL so SheepShaver handles it. + if (intercept_event) { + SDL_Event e; + memset(&e, 0, sizeof(e)); + e.type = (wParam == WM_KEYDOWN) ? SDL_KEYDOWN : SDL_KEYUP; + e.key.keysym.sym = (p->vkCode == VK_LWIN) ? SDLK_LGUI : SDLK_RGUI; + SDL_PushEvent(&e); + return 1; + } + } + break; + } + + // If we fall here, we weren't supposed to intercept it. + return CallNextHookEx(keyboard_hook, nCode, wParam, lParam); +} diff --git a/SheepShaver/src/Windows/prefs_windows.cpp b/SheepShaver/src/Windows/prefs_windows.cpp index 9c3865bf..b0b5d632 100755 --- a/SheepShaver/src/Windows/prefs_windows.cpp +++ b/SheepShaver/src/Windows/prefs_windows.cpp @@ -58,6 +58,7 @@ prefs_desc platform_prefs_items[] = { {"sdlrender", TYPE_STRING, false, "SDL_Renderer driver (\"auto\", \"software\" (may be faster), etc.)"}, {"sdl_vsync", TYPE_BOOLEAN, false, "Make SDL_Renderer vertical sync frames to host (eg. with software renderer)"}, #endif + {"reservewindowskey", TYPE_BOOLEAN, false, "block Windows key from activating start menu"}, {NULL, TYPE_END, false, NULL} // End of list }; @@ -145,4 +146,5 @@ void AddPlatformPrefsDefaults(void) PrefsReplaceString("sdlrender", "software"); PrefsReplaceBool("sdl_vsync", false); #endif + PrefsAddBool("reservewindowskey", false); } diff --git a/SheepShaver/src/Windows/user_strings_windows.cpp b/SheepShaver/src/Windows/user_strings_windows.cpp index eb12de57..f4dbb585 100755 --- a/SheepShaver/src/Windows/user_strings_windows.cpp +++ b/SheepShaver/src/Windows/user_strings_windows.cpp @@ -63,6 +63,7 @@ user_string_def platform_strings[] = { {STR_INPUT_PANE_TITLE, "Keyboard/Mouse"}, {STR_KEYCODES_CTRL, "Use Raw Keycodes"}, {STR_KEYCODE_FILE_CTRL, "Keycode Translation File"}, + {STR_RESERVE_WINDOWS_KEY_CTRL, "Reserve Windows Key"}, {STR_MOUSEWHEELMODE_CTRL, "Mouse Wheel Function"}, {STR_MOUSEWHEELMODE_PAGE_LAB, "Page Up/Down"}, {STR_MOUSEWHEELMODE_CURSOR_LAB, "Cursor Up/Down"}, diff --git a/SheepShaver/src/Windows/user_strings_windows.h b/SheepShaver/src/Windows/user_strings_windows.h index 7db10a74..2a606fe6 100755 --- a/SheepShaver/src/Windows/user_strings_windows.h +++ b/SheepShaver/src/Windows/user_strings_windows.h @@ -57,6 +57,7 @@ enum { STR_INPUT_PANE_TITLE, STR_KEYCODES_CTRL, STR_KEYCODE_FILE_CTRL, + STR_RESERVE_WINDOWS_KEY_CTRL, STR_MOUSEWHEELMODE_CTRL, STR_MOUSEWHEELMODE_PAGE_LAB, STR_MOUSEWHEELMODE_CURSOR_LAB,