From 34a31f8a1c3be0abe6b8fcbb317555574b5d26bc Mon Sep 17 00:00:00 2001 From: Dwedit Date: Mon, 28 Dec 2020 16:39:39 -0500 Subject: [PATCH 1/3] ui_win32_application.c: Add support for accelerators to main win32 message loop rarch.rc: Add accelerators for Open (Ctrl+O) and Fullscreen (Alt+Enter) ui_win32_resource.h: Add accelerator resource ID definition win32_common.c: Load accelerators, Localize Win32 menu items to current language, and display shortcut keys --- gfx/common/win32_common.c | 215 +++++++++++++++++++++++- media/rarch.rc | 11 ++ ui/drivers/ui_win32_resource.h | 1 + ui/drivers/win32/ui_win32_application.c | 14 +- 4 files changed, 237 insertions(+), 4 deletions(-) diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index 676f8e360c..1d3b53e2c0 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -56,11 +56,15 @@ #include #include +#include "../../input/input_driver.h" #include "../../input/input_keymaps.h" #include #ifdef HAVE_MENU #include "../../menu/menu_driver.h" +#include "../../msg_hash.h" +#include "../../ui/drivers/ui_win32_resource.h" +#include "../../input/input_defines.h" #endif #include @@ -230,6 +234,8 @@ typedef struct DISPLAYCONFIG_PATH_INFO_CUSTOM typedef LONG (WINAPI *QUERYDISPLAYCONFIG)(UINT32, UINT32*, DISPLAYCONFIG_PATH_INFO_CUSTOM*, UINT32*, DISPLAYCONFIG_MODE_INFO_CUSTOM*, UINT32*); typedef LONG (WINAPI *GETDISPLAYCONFIGBUFFERSIZES)(UINT32, UINT32*, UINT32*); +HACCEL window_accelerators; + /* Power Request APIs */ #if !defined(_XBOX) && (_MSC_VER == 1310) @@ -1370,6 +1376,8 @@ bool win32_window_create(void *data, unsigned style, if (!main_window.hwnd) return false; + window_accelerators = LoadAcceleratorsA(GetModuleHandleA(NULL), MAKEINTRESOURCE(IDR_ACCELERATOR1)); + #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500 /* 2K */ g_win32->taskbar_message = RegisterWindowMessage("TaskbarButtonCreated"); @@ -1688,6 +1696,206 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, #endif } +#ifdef HAVE_MENU + +enum msg_hash_enums menu_id_to_label_enum(unsigned int menuId) +{ + switch (menuId) + { + case ID_M_LOAD_CONTENT: return MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST; + case ID_M_RESET: return MENU_ENUM_LABEL_VALUE_RESTART_CONTENT; + case ID_M_QUIT: return MENU_ENUM_LABEL_VALUE_INPUT_META_QUIT_KEY; + case ID_M_MENU_TOGGLE: return MENU_ENUM_LABEL_VALUE_INPUT_META_MENU_TOGGLE; + case ID_M_PAUSE_TOGGLE: return MENU_ENUM_LABEL_VALUE_INPUT_META_PAUSE_TOGGLE; + case ID_M_LOAD_CORE: return MENU_ENUM_LABEL_VALUE_CORE_LIST; + case ID_M_LOAD_STATE: return MENU_ENUM_LABEL_VALUE_LOAD_STATE; + case ID_M_SAVE_STATE: return MENU_ENUM_LABEL_VALUE_SAVE_STATE; + case ID_M_DISK_CYCLE: return MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_EJECT_TOGGLE; + case ID_M_DISK_NEXT: return MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_NEXT; + case ID_M_DISK_PREV: return MENU_ENUM_LABEL_VALUE_INPUT_META_DISK_PREV; + case ID_M_WINDOW_SCALE_1X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_2X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_3X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_4X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_5X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_6X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_7X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_8X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_9X: return MSG_UNKNOWN; + case ID_M_WINDOW_SCALE_10X: return MSG_UNKNOWN; + case ID_M_FULL_SCREEN: return MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY; + case ID_M_MOUSE_GRAB: return MENU_ENUM_LABEL_VALUE_INPUT_META_GRAB_MOUSE_TOGGLE; + case ID_M_STATE_INDEX_AUTO: return MSG_UNKNOWN; + case ID_M_TAKE_SCREENSHOT: return MENU_ENUM_LABEL_VALUE_INPUT_META_SCREENSHOT; + case ID_M_MUTE_TOGGLE: return MENU_ENUM_LABEL_VALUE_INPUT_META_MUTE; + default: return MSG_UNKNOWN; + } +} + +unsigned int menu_id_to_meta_key(unsigned int menuId) +{ + switch (menuId) + { + case ID_M_LOAD_CONTENT: return 0; + case ID_M_RESET: return RARCH_RESET; + case ID_M_QUIT: return RARCH_QUIT_KEY; + case ID_M_MENU_TOGGLE: return RARCH_MENU_TOGGLE; + case ID_M_PAUSE_TOGGLE: return RARCH_PAUSE_TOGGLE; + case ID_M_LOAD_CORE: return 0; + case ID_M_LOAD_STATE: return RARCH_LOAD_STATE_KEY; + case ID_M_SAVE_STATE: return RARCH_SAVE_STATE_KEY; + case ID_M_DISK_CYCLE: return RARCH_DISK_EJECT_TOGGLE; + case ID_M_DISK_NEXT: return RARCH_DISK_NEXT; + case ID_M_DISK_PREV: return RARCH_DISK_PREV; + case ID_M_WINDOW_SCALE_1X: return 0; + case ID_M_WINDOW_SCALE_2X: return 0; + case ID_M_WINDOW_SCALE_3X: return 0; + case ID_M_WINDOW_SCALE_4X: return 0; + case ID_M_WINDOW_SCALE_5X: return 0; + case ID_M_WINDOW_SCALE_6X: return 0; + case ID_M_WINDOW_SCALE_7X: return 0; + case ID_M_WINDOW_SCALE_8X: return 0; + case ID_M_WINDOW_SCALE_9X: return 0; + case ID_M_WINDOW_SCALE_10X: return 0; + case ID_M_FULL_SCREEN: return RARCH_FULLSCREEN_TOGGLE_KEY; + case ID_M_MOUSE_GRAB: return RARCH_GRAB_MOUSE_TOGGLE; + case ID_M_STATE_INDEX_AUTO: return 0; + case ID_M_TAKE_SCREENSHOT: return RARCH_SCREENSHOT; + case ID_M_MUTE_TOGGLE: return RARCH_MUTE; + default: return 0; + } +} + +const char* meta_key_to_name(unsigned int metaKey) +{ + if (metaKey == 0) + { + return NULL; + } + else + { + int i = 0; + const struct retro_keybind* key = &input_config_binds[0][metaKey]; + int keyCode = key->key; + while (true) + { + const struct input_key_map* entry = &input_config_key_map[i]; + if (entry->str == NULL) break; + if (entry->key == keyCode) + { + return entry->str; + } + i++; + } + if (keyCode >= 32 && keyCode < 127) + { + static char singleChar[2] = "A"; + singleChar[0] = keyCode; + return singleChar; + } + return NULL; + } +} + +void win32_localize_menu(HMENU menu) +{ + int index = 0; +#ifndef LEGACY_WIN32 + MENUITEMINFOW menuItemInfo; +#else + MENUITEMINFOA menuItemInfo; +#endif + while (true) + { + BOOL okay; + enum msg_hash_enums labelEnum; + memset(&menuItemInfo, 0, sizeof(menuItemInfo)); + menuItemInfo.cbSize = sizeof(menuItemInfo); + menuItemInfo.dwTypeData = NULL; + menuItemInfo.fMask = MIIM_STRING | MIIM_FTYPE | MIIM_ID | MIIM_STATE | MIIM_SUBMENU; + +#ifndef LEGACY_WIN32 + okay = GetMenuItemInfoW(menu, index, true, &menuItemInfo); +#else + okay = GetMenuItemInfoA(menu, index, true, &menuItemInfo); +#endif + if (!okay) break; + + if (menuItemInfo.hSubMenu != NULL) + { + win32_localize_menu(menuItemInfo.hSubMenu); + } + + labelEnum = menu_id_to_label_enum(menuItemInfo.wID); + if (labelEnum != MSG_UNKNOWN) + { + const char* newLabel = msg_hash_to_str(labelEnum); + unsigned int metaKey = menu_id_to_meta_key(menuItemInfo.wID); + const char* metaKeyName = meta_key_to_name(metaKey); + //specific replacements: Load Content = "Ctrl+O", Fullscreen = "Alt+Enter" (these are defined in the Acceleator resources) + if (labelEnum == MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST) + { + metaKeyName = "Ctrl+O"; + } + if (labelEnum == MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY) + { + metaKeyName = "Alt+Enter"; + } + const char* newLabel2 = newLabel; + char* newLabelText = NULL; +#ifndef LEGACY_WIN32 + wchar_t* newLabel_unicode; +#else + char* newLabel_ansi; +#endif + int len; + + if (metaKeyName != NULL && 0 != strcmp(metaKeyName, "nul")) + { + int len1 = strlen(newLabel); + int len2 = strlen(metaKeyName); + int bufSize = len1 + len2 + 2; + newLabelText = (char*)malloc(bufSize); + newLabel2 = newLabelText; + strcpy(newLabelText, newLabel); + strcat(newLabelText, "\t"); + strcat(newLabelText, metaKeyName); + newLabelText[len1 + 1] = toupper(newLabelText[len1 + 1]); + } + +#ifndef LEGACY_WIN32 + newLabel_unicode = utf8_to_utf16_string_alloc(newLabel2); + len = wcslen(newLabel_unicode); + menuItemInfo.cch = len; + menuItemInfo.dwTypeData = newLabel_unicode; + SetMenuItemInfoW(menu, index, true, &menuItemInfo); + free(newLabel_unicode); +#else + newLabel_ansi = utf8_to_local_string_alloc(newLabel2); + len = strlen(newLabel_ansi); + menuItemInfo.cch = len; + menuItemInfo.dwTypeData = newLabel_ansi; + SetMenuItemInfoA(menu, index, true, &menuItemInfo); + free(newLabel_ansi); +#endif + if (newLabelText) + { + free(newLabelText); + } + } + index++; + } +} + +#else + +void win32_localize_menu(HMENU menu) +{ + +} + +#endif + void win32_set_window(unsigned *width, unsigned *height, bool fullscreen, bool windowed_full, void *rect_data) { @@ -1702,14 +1910,17 @@ void win32_set_window(unsigned *width, unsigned *height, if (!fullscreen && ui_menubar_enable) { + HMENU menuItem; RECT rc_temp; rc_temp.left = 0; rc_temp.top = 0; rc_temp.right = (LONG)*height; rc_temp.bottom = 0x7FFF; - SetMenu(main_window.hwnd, - LoadMenu(GetModuleHandle(NULL),MAKEINTRESOURCE(IDR_MENU))); + menuItem = LoadMenuA(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MENU)); + win32_localize_menu(menuItem); + + SetMenu(main_window.hwnd, menuItem); SendMessage(main_window.hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rc_temp); g_win32_resize_height = *height += rc_temp.top + rect->top; SetWindowPos(main_window.hwnd, NULL, 0, 0, *width, *height, SWP_NOMOVE); diff --git a/media/rarch.rc b/media/rarch.rc index fb7af6e78b..456de2af81 100644 --- a/media/rarch.rc +++ b/media/rarch.rc @@ -102,6 +102,17 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL 2 RT_MANIFEST "rarch.manifest" + +// +// Accelerator +// + +IDR_ACCELERATOR1 ACCELERATORS +BEGIN +"O", ID_M_LOAD_CONTENT, VIRTKEY, CONTROL, NOINVERT +VK_RETURN, ID_M_FULL_SCREEN, VIRTKEY, ALT, NOINVERT +END + // Per the documentation, this should be used before including resource files. // https://docs.microsoft.com/en-us/windows/desktop/menurc/pragma-directives #pragma code_page(932) diff --git a/ui/drivers/ui_win32_resource.h b/ui/drivers/ui_win32_resource.h index 0238c5e94a..d47b1f1e17 100644 --- a/ui/drivers/ui_win32_resource.h +++ b/ui/drivers/ui_win32_resource.h @@ -29,3 +29,4 @@ #define ID_M_TAKE_SCREENSHOT 40025 #define ID_M_MUTE_TOGGLE 40026 #define ID_M_TOGGLE_DESKTOP 40027 +#define IDR_ACCELERATOR1 104 diff --git a/ui/drivers/win32/ui_win32_application.c b/ui/drivers/win32/ui_win32_application.c index df88f2fb05..12c04012ea 100644 --- a/ui/drivers/win32/ui_win32_application.c +++ b/ui/drivers/win32/ui_win32_application.c @@ -22,6 +22,10 @@ #include #include "../../ui_companion_driver.h" +#include "../ui_win32.h" + +extern ui_window_win32_t main_window; +extern HACCEL window_accelerators; static void* ui_application_win32_initialize(void) { @@ -33,8 +37,14 @@ static void ui_application_win32_process_events(void) MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { - TranslateMessage(&msg); - DispatchMessage (&msg); + bool translatedAcceleator = false; + translatedAcceleator = main_window.hwnd == msg.hwnd && TranslateAccelerator(msg.hwnd, window_accelerators, &msg) != 0; + + if (!translatedAcceleator) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } } } From 217b6d2f9ddc843eaeaeb06567e36b7fe902960b Mon Sep 17 00:00:00 2001 From: Dwedit Date: Mon, 28 Dec 2020 16:45:33 -0500 Subject: [PATCH 2/3] Restored missing comments and fixes --- gfx/common/win32_common.c | 50 ++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/gfx/common/win32_common.c b/gfx/common/win32_common.c index 1d3b53e2c0..fff3f04e2f 100644 --- a/gfx/common/win32_common.c +++ b/gfx/common/win32_common.c @@ -56,15 +56,11 @@ #include #include -#include "../../input/input_driver.h" #include "../../input/input_keymaps.h" #include #ifdef HAVE_MENU #include "../../menu/menu_driver.h" -#include "../../msg_hash.h" -#include "../../ui/drivers/ui_win32_resource.h" -#include "../../input/input_defines.h" #endif #include @@ -1698,6 +1694,7 @@ void win32_set_style(MONITORINFOEX *current_mon, HMONITOR *hm_to_use, #ifdef HAVE_MENU +/* Given a Win32 Resource ID, return a RetroArch menu ID (for renaming the menu item) */ enum msg_hash_enums menu_id_to_label_enum(unsigned int menuId) { switch (menuId) @@ -1732,6 +1729,7 @@ enum msg_hash_enums menu_id_to_label_enum(unsigned int menuId) } } +/* Given a RetroArch menu ID, get its shortcut key (meta key) */ unsigned int menu_id_to_meta_key(unsigned int menuId) { switch (menuId) @@ -1766,6 +1764,8 @@ unsigned int menu_id_to_meta_key(unsigned int menuId) } } +/* Given a short key (meta key), get its name as a string */ +/* For single character results, may return same pointer with different data inside (modifying the old result) */ const char* meta_key_to_name(unsigned int metaKey) { if (metaKey == 0) @@ -1797,6 +1797,7 @@ const char* meta_key_to_name(unsigned int metaKey) } } +/* Replaces Menu Item text with localized menu text, and displays the current shortcut key */ void win32_localize_menu(HMENU menu) { int index = 0; @@ -1823,6 +1824,7 @@ void win32_localize_menu(HMENU menu) if (menuItemInfo.hSubMenu != NULL) { + /* Recursion - call this on submenu items too */ win32_localize_menu(menuItemInfo.hSubMenu); } @@ -1832,15 +1834,6 @@ void win32_localize_menu(HMENU menu) const char* newLabel = msg_hash_to_str(labelEnum); unsigned int metaKey = menu_id_to_meta_key(menuItemInfo.wID); const char* metaKeyName = meta_key_to_name(metaKey); - //specific replacements: Load Content = "Ctrl+O", Fullscreen = "Alt+Enter" (these are defined in the Acceleator resources) - if (labelEnum == MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST) - { - metaKeyName = "Ctrl+O"; - } - if (labelEnum == MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY) - { - metaKeyName = "Alt+Enter"; - } const char* newLabel2 = newLabel; char* newLabelText = NULL; #ifndef LEGACY_WIN32 @@ -1850,19 +1843,37 @@ void win32_localize_menu(HMENU menu) #endif int len; + /* specific replacements: + Load Content = "Ctrl+O" + Fullscreen = "Alt+Enter" */ + if (labelEnum == MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST) + { + metaKeyName = "Ctrl+O"; + } + if (labelEnum == MENU_ENUM_LABEL_VALUE_INPUT_META_FULLSCREEN_TOGGLE_KEY) + { + metaKeyName = "Alt+Enter"; + } + + /* Append localized name, tab character, and Shortcut Key */ if (metaKeyName != NULL && 0 != strcmp(metaKeyName, "nul")) { int len1 = strlen(newLabel); int len2 = strlen(metaKeyName); int bufSize = len1 + len2 + 2; newLabelText = (char*)malloc(bufSize); - newLabel2 = newLabelText; - strcpy(newLabelText, newLabel); - strcat(newLabelText, "\t"); - strcat(newLabelText, metaKeyName); - newLabelText[len1 + 1] = toupper(newLabelText[len1 + 1]); + if (newLabelText != NULL) + { + newLabel2 = newLabelText; + strcpy(newLabelText, newLabel); + strcat(newLabelText, "\t"); + strcat(newLabelText, metaKeyName); + /* Make first character of shortcut name uppercase */ + newLabelText[len1 + 1] = toupper(newLabelText[len1 + 1]); + } } + /* convert string from UTF-8, then assign menu text */ #ifndef LEGACY_WIN32 newLabel_unicode = utf8_to_utf16_string_alloc(newLabel2); len = wcslen(newLabel_unicode); @@ -1878,7 +1889,7 @@ void win32_localize_menu(HMENU menu) SetMenuItemInfoA(menu, index, true, &menuItemInfo); free(newLabel_ansi); #endif - if (newLabelText) + if (newLabelText != NULL) { free(newLabelText); } @@ -1889,6 +1900,7 @@ void win32_localize_menu(HMENU menu) #else +/* Blank version in case RetroArch was built with Win32 Menu but not the menu system (this should never happen) */ void win32_localize_menu(HMENU menu) { From b0e150ba2ddc2e05c1bbce0921d3adc201863a11 Mon Sep 17 00:00:00 2001 From: Dwedit Date: Mon, 28 Dec 2020 17:02:29 -0500 Subject: [PATCH 3/3] Fix Typo --- ui/drivers/win32/ui_win32_application.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui/drivers/win32/ui_win32_application.c b/ui/drivers/win32/ui_win32_application.c index 12c04012ea..b4ae39ab94 100644 --- a/ui/drivers/win32/ui_win32_application.c +++ b/ui/drivers/win32/ui_win32_application.c @@ -37,10 +37,10 @@ static void ui_application_win32_process_events(void) MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { - bool translatedAcceleator = false; - translatedAcceleator = main_window.hwnd == msg.hwnd && TranslateAccelerator(msg.hwnd, window_accelerators, &msg) != 0; + bool translatedAccelerator = false; + translatedAccelerator = main_window.hwnd == msg.hwnd && TranslateAccelerator(msg.hwnd, window_accelerators, &msg) != 0; - if (!translatedAcceleator) + if (!translatedAccelerator) { TranslateMessage(&msg); DispatchMessage(&msg);