From 9adf0fdcc437830de6245de568eaabdd4501cdd5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 19 Jul 2021 02:27:22 +0200 Subject: [PATCH] Added the ability for keyboard to require capture, in order for 86Box keyboard input to operate like VMWare, closes #829. --- src/config.c | 7 ++ src/include/86box/plat.h | 2 + src/include/86box/resource.h | 21 ++--- src/win/86Box.rc | 1 + src/win/win_keyboard.c | 153 ++++++++++++++++++----------------- src/win/win_ui.c | 22 +++-- 6 files changed, 114 insertions(+), 92 deletions(-) diff --git a/src/config.c b/src/config.c index d7ed15b3c..0d4490025 100644 --- a/src/config.c +++ b/src/config.c @@ -513,6 +513,7 @@ load_general(void) } sound_gain = config_get_int(cat, "sound_gain", 0); + kbd_req_capture = config_get_int(cat, "kbd_req_capture", 0); confirm_reset = config_get_int(cat, "confirm_reset", 1); confirm_exit = config_get_int(cat, "confirm_exit", 1); @@ -1811,6 +1812,7 @@ config_load(void) #ifdef USE_LANGUAGE plat_langid = 0x0409; #endif + kbd_req_capture = 0; scale = 1; machine = machine_get_machine_from_internal_name("ibmpc"); fpu_type = fpu_get_type(cpu_f, cpu, "none"); @@ -1970,6 +1972,11 @@ save_general(void) else config_delete_var(cat, "sound_gain"); + if (kbd_req_capture != 0) + config_set_int(cat, "kbd_req_capture", kbd_req_capture); + else + config_delete_var(cat, "kbd_req_capture"); + if (confirm_reset != 1) config_set_int(cat, "confirm_reset", confirm_reset); else diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index a44f4924c..4eb6d6a80 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -80,6 +80,8 @@ extern int update_icons; extern int unscaled_size_x, /* current unscaled size X */ unscaled_size_y; /* current unscaled size Y */ +extern int kbd_req_capture; + /* System-related functions. */ extern char *fix_exe_path(char *str); extern FILE *plat_fopen(const char *path, const char *mode); diff --git a/src/include/86box/resource.h b/src/include/86box/resource.h index c02e1d7ac..64ea4690a 100644 --- a/src/include/86box/resource.h +++ b/src/include/86box/resource.h @@ -285,17 +285,18 @@ #define IDM_ABOUT 40001 #define IDC_ABOUT_ICON 65535 -#define IDM_ACTION_RCTRL_IS_LALT 40010 -#define IDM_ACTION_SCREENSHOT 40011 -#define IDM_ACTION_HRESET 40012 -#define IDM_ACTION_RESET_CAD 40013 -#define IDM_ACTION_EXIT 40014 -#define IDM_ACTION_CTRL_ALT_ESC 40015 -#define IDM_ACTION_PAUSE 40016 +#define IDM_ACTION_KBD_REQ_CAPTURE 40010 +#define IDM_ACTION_RCTRL_IS_LALT 40011 +#define IDM_ACTION_SCREENSHOT 40012 +#define IDM_ACTION_HRESET 40013 +#define IDM_ACTION_RESET_CAD 40014 +#define IDM_ACTION_EXIT 40015 +#define IDM_ACTION_CTRL_ALT_ESC 40016 +#define IDM_ACTION_PAUSE 40017 #ifdef MTR_ENABLED -#define IDM_ACTION_BEGIN_TRACE 40017 -#define IDM_ACTION_END_TRACE 40018 -#define IDM_ACTION_TRACE 40019 +#define IDM_ACTION_BEGIN_TRACE 40018 +#define IDM_ACTION_END_TRACE 40019 +#define IDM_ACTION_TRACE 40020 #endif #define IDM_CONFIG 40020 #define IDM_CONFIG_LOAD 40021 diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 145c90f5a..8ba956285 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -45,6 +45,7 @@ MainMenu MENU DISCARDABLE BEGIN POPUP "&Action" BEGIN + MENUITEM "&Keyboard requires capture", IDM_ACTION_KBD_REQ_CAPTURE MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT MENUITEM SEPARATOR MENUITEM "&Hard Reset", IDM_ACTION_HRESET diff --git a/src/win/win_keyboard.c b/src/win/win_keyboard.c index 8d286e297..e60da87d4 100644 --- a/src/win/win_keyboard.c +++ b/src/win/win_keyboard.c @@ -114,89 +114,92 @@ keyboard_handle(PRAWINPUT raw) static int recv_lalt = 0, recv_ralt = 0, recv_tab = 0; RAWKEYBOARD rawKB = raw->data.keyboard; - scancode = rawKB.MakeCode; + scancode = rawKB.MakeCode; - /* If it's not a scan code that starts with 0xE1 */ - if (!(rawKB.Flags & RI_KEY_E1)) { - if (rawKB.Flags & RI_KEY_E0) - scancode |= 0x100; + if (kbd_req_capture && !mouse_capture && !video_fullscreen) + return; - /* Translate the scan code to 9-bit */ - scancode = convert_scan_code(scancode); + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) { + if (rawKB.Flags & RI_KEY_E0) + scancode |= 0x100; - /* Remap it according to the list from the Registry */ - if (scancode != scancode_map[scancode]) - pclog("Scan code remap: %03X -> %03X\n", scancode, scancode); - scancode = scancode_map[scancode]; + /* Translate the scan code to 9-bit */ + scancode = convert_scan_code(scancode); - /* If it's not 0xFFFF, send it to the emulated - keyboard. - We use scan code 0xFFFF to mean a mapping that - has a prefix other than E0 and that is not E1 1D, - which is, for our purposes, invalid. */ - if ((scancode == 0x00F) && - !(rawKB.Flags & RI_KEY_BREAK) && - (recv_lalt || recv_ralt) && - !mouse_capture) { - /* We received a TAB while ALT was pressed, while the mouse - is not captured, suppress the TAB and send an ALT key up. */ - if (recv_lalt) { - keyboard_input(0, 0x038); - /* Extra key press and release so the guest is not stuck in the - menu bar. */ - keyboard_input(1, 0x038); - keyboard_input(0, 0x038); - recv_lalt = 0; - } - if (recv_ralt) { - keyboard_input(0, 0x138); - /* Extra key press and release so the guest is not stuck in the - menu bar. */ - keyboard_input(1, 0x138); - keyboard_input(0, 0x138); - recv_ralt = 0; - } - } else if (((scancode == 0x038) || (scancode == 0x138)) && - !(rawKB.Flags & RI_KEY_BREAK) && - recv_tab && - !mouse_capture) { - /* We received an ALT while TAB was pressed, while the mouse - is not captured, suppress the ALT and send a TAB key up. */ - keyboard_input(0, 0x00F); - recv_tab = 0; - } else { - switch(scancode) { - case 0x00F: - recv_tab = !(rawKB.Flags & RI_KEY_BREAK); - break; - case 0x038: - recv_lalt = !(rawKB.Flags & RI_KEY_BREAK); - break; - case 0x138: - recv_ralt = !(rawKB.Flags & RI_KEY_BREAK); - break; - } + /* Remap it according to the list from the Registry */ + if (scancode != scancode_map[scancode]) + pclog("Scan code remap: %03X -> %03X\n", scancode, scancode); + scancode = scancode_map[scancode]; - /* Translate right CTRL to left ALT if the user has so - chosen. */ - if ((scancode == 0x11D) && rctrl_is_lalt) - scancode = 0x038; - - /* Normal scan code pass through, pass it through as is if - it's not an invalid scan code. */ - if (scancode != 0xFFFF) - keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + /* If it's not 0xFFFF, send it to the emulated + keyboard. + We use scan code 0xFFFF to mean a mapping that + has a prefix other than E0 and that is not E1 1D, + which is, for our purposes, invalid. */ + if ((scancode == 0x00F) && + !(rawKB.Flags & RI_KEY_BREAK) && + (recv_lalt || recv_ralt) && + !mouse_capture) { + /* We received a TAB while ALT was pressed, while the mouse + is not captured, suppress the TAB and send an ALT key up. */ + if (recv_lalt) { + keyboard_input(0, 0x038); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x038); + keyboard_input(0, 0x038); + recv_lalt = 0; } + if (recv_ralt) { + keyboard_input(0, 0x138); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x138); + keyboard_input(0, 0x138); + recv_ralt = 0; + } + } else if (((scancode == 0x038) || (scancode == 0x138)) && + !(rawKB.Flags & RI_KEY_BREAK) && + recv_tab && + !mouse_capture) { + /* We received an ALT while TAB was pressed, while the mouse + is not captured, suppress the ALT and send a TAB key up. */ + keyboard_input(0, 0x00F); + recv_tab = 0; } else { - if (rawKB.MakeCode == 0x1D) { - scancode = scancode_map[0x100]; /* Translate E1 1D to 0x100 (which would - otherwise be E0 00 but that is invalid - anyway). - Also, take a potential mapping into - account. */ - } else - scancode = 0xFFFF; + switch(scancode) { + case 0x00F: + recv_tab = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x038: + recv_lalt = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x138: + recv_ralt = !(rawKB.Flags & RI_KEY_BREAK); + break; + } + + /* Translate right CTRL to left ALT if the user has so + chosen. */ + if ((scancode == 0x11D) && rctrl_is_lalt) + scancode = 0x038; + + /* Normal scan code pass through, pass it through as is if + it's not an invalid scan code. */ if (scancode != 0xFFFF) keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); } + } else { + if (rawKB.MakeCode == 0x1D) { + scancode = scancode_map[0x100]; /* Translate E1 1D to 0x100 (which would + otherwise be E0 00 but that is invalid + anyway). + Also, take a potential mapping into + account. */ + } else + scancode = 0xFFFF; + if (scancode != 0xFFFF) + keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + } } diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 3773d369c..85595fe62 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -67,6 +67,7 @@ int infocus = 1, button_down = 0; int rctrl_is_lalt = 0; int user_resize = 0; int fixed_size_x = 0, fixed_size_y = 0; +int kbd_req_capture = 0; extern char openfilestring[512]; extern WCHAR wopenfilestring[512]; @@ -80,11 +81,9 @@ static int hook_enabled = 0; #endif static int manager_wm = 0; static int save_window_pos = 0, pause_state = 0; -static int dpi = 96; -static int padded_frame = 0; - - -static int vis = -1; +static int dpi = 96; +static int padded_frame = 0; +static int vis = -1; /* Per Monitor DPI Aware v2 APIs, Windows 10 v1703+ */ void* user32_handle = NULL; @@ -263,6 +262,7 @@ ResetAllMenus(void) #endif CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_ACTION_KBD_REQ_CAPTURE, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_UPDATE_ICONS, MF_UNCHECKED); @@ -328,6 +328,7 @@ ResetAllMenus(void) CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+4, MF_UNCHECKED); CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_ACTION_KBD_REQ_CAPTURE, kbd_req_capture ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(menuMain, IDM_UPDATE_ICONS, update_icons ? MF_CHECKED : MF_UNCHECKED); @@ -406,7 +407,8 @@ LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) BOOL bControlKeyDown; KBDLLHOOKSTRUCT *p; - if (nCode < 0 || nCode != HC_ACTION || (!mouse_capture && !video_fullscreen)) + if (nCode < 0 || nCode != HC_ACTION || + (!mouse_capture && !video_fullscreen) || (kbd_req_capture && !mouse_capture && !video_fullscreen)) return(CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)); p = (KBDLLHOOKSTRUCT*)lParam; @@ -671,6 +673,12 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) config_save(); break; + case IDM_ACTION_KBD_REQ_CAPTURE: + kbd_req_capture ^= 1; + CheckMenuItem(hmenu, IDM_ACTION_KBD_REQ_CAPTURE, kbd_req_capture ? MF_CHECKED : MF_UNCHECKED); + config_save(); + break; + case IDM_ACTION_PAUSE: plat_pause(dopause ^ 1); CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); @@ -1688,7 +1696,7 @@ plat_mouse_capture(int on) { RECT rect; - if (mouse_type == MOUSE_TYPE_NONE) + if (!kbd_req_capture && (mouse_type == MOUSE_TYPE_NONE)) return; if (on && !mouse_capture) {