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.
This commit is contained in:
Doug Brown 2021-11-28 16:09:14 -08:00
parent a5064455cb
commit f1502fb6bd
9 changed files with 113 additions and 0 deletions

View File

@ -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);
}

View File

@ -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[] = {

View File

@ -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);
}

View File

@ -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"},

View File

@ -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,

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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"},

View File

@ -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,