diff --git a/src/BoE.vsproj/Common/Common.vcxproj b/src/BoE.vsproj/Common/Common.vcxproj index 129b1361..4f207615 100644 --- a/src/BoE.vsproj/Common/Common.vcxproj +++ b/src/BoE.vsproj/Common/Common.vcxproj @@ -55,6 +55,7 @@ + @@ -114,6 +115,7 @@ + diff --git a/src/BoE.vsproj/Common/Common.vcxproj.filters b/src/BoE.vsproj/Common/Common.vcxproj.filters index 5b1fdeb2..ffa5faa6 100644 --- a/src/BoE.vsproj/Common/Common.vcxproj.filters +++ b/src/BoE.vsproj/Common/Common.vcxproj.filters @@ -206,6 +206,9 @@ Classes\Header Files + + Tools\Header Files + @@ -361,5 +364,8 @@ Classes\Source Files + + Tools\Source Files + \ No newline at end of file diff --git a/src/boe.menus.win.cpp b/src/boe.menus.win.cpp index 10145d55..1402421c 100644 --- a/src/boe.menus.win.cpp +++ b/src/boe.menus.win.cpp @@ -10,6 +10,7 @@ #include "boe.consts.h" #include "spell.hpp" #include "winutil.hpp" +#include "menu_accel.win.hpp" // Include this last because some #defines in the Windows headers cause compile errors in my headers. // Fortunately they're on symbols not used in this file, so this should work. @@ -38,17 +39,29 @@ extern eGameMode overall_mode; extern sf::RenderWindow mainPtr; LONG_PTR mainProc; HMENU menuHandle = NULL; +accel_table_t accel; std::map menuChoices; LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam); void setMenuCommand(HMENU& menu, int i, eMenu cmd) { + static char title[256]; MENUITEMINFOA item; item.cbSize = sizeof(MENUITEMINFOA); - item.fMask = MIIM_ID | MIIM_FTYPE; + item.cch = 255; + item.dwTypeData = title; + item.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING; GetMenuItemInfoA(menu, i++, true, &item); if(item.fType == MFT_SEPARATOR) return; menuChoices[item.wID] = cmd; + // Now set up the accelerator, if any + std::string item_name = item.dwTypeData; + size_t pos = item_name.find_last_of('\t'); + if(pos == std::string::npos) return; + pos++; + if(pos >= item_name.size()) return; + std::string key_name = item_name.substr(pos); + accel.add(item.wID, key_name); } void init_menubar() { @@ -117,6 +130,8 @@ void init_menubar() { menuChoices[IDM_MAGE_ABOUT] = eMenu::ABOUT_MAGE; menuChoices[IDM_PRIEST_ABOUT] = eMenu::ABOUT_PRIEST; menuChoices[IDM_MONSTERS_ABOUT] = eMenu::ABOUT_MONSTERS; + + accel.build(); } void adjust_monst_menu() { @@ -275,6 +290,11 @@ void showMenuBar() { #include "cursors.hpp" LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) { + MSG msg = {handle, message, wParam, lParam}; + if(HIWORD(wParam) != 1 || message != WM_COMMAND) { + if(TranslateAccelerator(handle, accel.handle, &msg)) + return 0; + } if(message == WM_COMMAND) { int cmd = LOWORD(wParam); if(cmd >= 1000 && cmd < 2000) { diff --git a/src/pcedit/pc.menus.win.cpp b/src/pcedit/pc.menus.win.cpp index 94fde2f8..2a3b9c26 100644 --- a/src/pcedit/pc.menus.win.cpp +++ b/src/pcedit/pc.menus.win.cpp @@ -5,6 +5,7 @@ #include "Resource.h" #include "universe.h" #include "winutil.hpp" +#include "menu_accel.win.hpp" // Include this last because some #defines in the Windows headers cause compile errors in my headers. // Fortunately they're on symbols not used in this file, so this should work. @@ -25,17 +26,29 @@ extern bool scen_items_loaded; extern fs::path file_in_mem; LONG_PTR mainProc; HMENU menuHandle = NULL; +accel_table_t accel; std::map menuChoices; LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam); void setMenuCommand(HMENU& menu, int i, eMenu cmd) { + static char title[256]; MENUITEMINFOA item; item.cbSize = sizeof(MENUITEMINFOA); - item.fMask = MIIM_ID | MIIM_FTYPE; + item.cch = 255; + item.dwTypeData = title; + item.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING; GetMenuItemInfoA(menu, i++, true, &item); if(item.fType == MFT_SEPARATOR) return; menuChoices[item.wID] = cmd; + // Now set up the accelerator, if any + std::string item_name = item.dwTypeData; + size_t pos = item_name.find_last_of('\t'); + if(pos == std::string::npos) return; + pos++; + if(pos >= item_name.size()) return; + std::string key_name = item_name.substr(pos); + accel.add(item.wID, key_name); } void init_menubar() { @@ -93,6 +106,8 @@ void init_menubar() { i = 0; for(eMenu opt : help_choices) setMenuCommand(help_menu, i++, opt); + + accel.build(); } void update_item_menu() { @@ -137,6 +152,11 @@ void menu_activate() { #include "cursors.hpp" LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) { + MSG msg = {handle, message, wParam, lParam}; + if(HIWORD(wParam) != 1 || message != WM_COMMAND) { + if(TranslateAccelerator(handle, accel.handle, &msg)) + return 0; + } if(message == WM_COMMAND) { int cmd = LOWORD(wParam); if(cmd >= 1000) { // Item menus diff --git a/src/scenedit/scen.menus.win.cpp b/src/scenedit/scen.menus.win.cpp index 8ed28797..7f357eb2 100644 --- a/src/scenedit/scen.menus.win.cpp +++ b/src/scenedit/scen.menus.win.cpp @@ -5,6 +5,7 @@ #include "Resource.h" #include "scenario.h" #include "winutil.hpp" +#include "menu_accel.win.hpp" // Include this last because some #defines in the Windows headers cause compile errors in my headers. // Fortunately they're on symbols not used in this file, so this should work. @@ -27,17 +28,29 @@ extern sf::RenderWindow mainPtr; extern cScenario scenario; LONG_PTR mainProc; HMENU menuHandle = NULL; +accel_table_t accel; std::map menuChoices; LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam); void setMenuCommand(HMENU& menu, int i, eMenu cmd) { + static char title[256]; MENUITEMINFOA item; item.cbSize = sizeof(MENUITEMINFOA); - item.fMask = MIIM_ID | MIIM_FTYPE; + item.cch = 255; + item.dwTypeData = title; + item.fMask = MIIM_ID | MIIM_FTYPE | MIIM_STRING; GetMenuItemInfoA(menu, i++, true, &item); if(item.fType == MFT_SEPARATOR) return; menuChoices[item.wID] = cmd; + // Now set up the accelerator, if any + std::string item_name = item.dwTypeData; + size_t pos = item_name.find_last_of('\t'); + if(pos == std::string::npos) return; + pos++; + if(pos >= item_name.size()) return; + std::string key_name = item_name.substr(pos); + accel.add(item.wID, key_name); } void init_menubar() { @@ -113,6 +126,8 @@ void init_menubar() { i = 0; for(eMenu opt : help_choices) setMenuCommand(help_menu, i++, opt); + + accel.build(); } void update_item_menu() { @@ -214,6 +229,11 @@ void shut_down_menus(short mode) { #include "cursors.hpp" LRESULT CALLBACK menuProc(HWND handle, UINT message, WPARAM wParam, LPARAM lParam) { + MSG msg = {handle, message, wParam, lParam}; + if(HIWORD(wParam) != 1 || message != WM_COMMAND) { + if(TranslateAccelerator(handle, accel.handle, &msg)) + return 0; + } if(message == WM_COMMAND) { int cmd = LOWORD(wParam); if(cmd >= 10000 && cmd < 20000) { // Item menus diff --git a/src/tools/menu_accel.win.cpp b/src/tools/menu_accel.win.cpp new file mode 100644 index 00000000..f16970a5 --- /dev/null +++ b/src/tools/menu_accel.win.cpp @@ -0,0 +1,73 @@ + +#include "menu_accel.win.hpp" +#include + +void accel_table_t::add(WORD cmd, std::string key) { + size_t pos = 0; + bool ctrl = false, alt = false, shift = false; + while(true) { + if(key.substr(pos, 5) == "Ctrl+") { + ctrl = true; + pos += 5; + } else if(key.substr(pos, 4) == "Alt+") { + alt = true; + pos += 4; + } else if(key.substr(pos, 6) == "Shift+") { + shift = true; + pos += 6; + } else if(pos >= key.size()) return; + else break; + } + WORD keycode; + key = key.substr(pos); + if(key.length() == 0) return; + else if(key.length() == 1) { + SHORT virtkey = VkKeyScanA(key[0]); + keycode = LOBYTE(virtkey); + } else if(key[0] == 'F') { + std::istringstream parse; + parse.str(key.substr(1)); + int fkey = -1; + parse >> fkey; + // We allow for 24 F-keys because that's how many VK_Fx constants there are + if(fkey <= 0 || fkey > 24) + return; + keycode = VK_F1 + fkey - 1; + } else if(key == "Backsp") keycode = VK_BACK; + else if(key == "Enter") keycode = VK_RETURN; + else if(key == "Tab") keycode = VK_TAB; + else if(key == "Esc") keycode = VK_ESCAPE; + else if(key == "PgUp") keycode = VK_PRIOR; + else if(key == "PgDn") keycode = VK_NEXT; + else if(key == "End") keycode = VK_END; + else if(key == "Home") keycode = VK_HOME; + else if(key == "Left") keycode = VK_LEFT; + else if(key == "Right") keycode = VK_RIGHT; + else if(key == "Up") keycode = VK_UP; + else if(key == "Down") keycode = VK_DOWN; + else if(key == "Del") keycode = VK_DELETE; + else return; + ACCEL accel; + accel.cmd = cmd; + accel.key = keycode; + accel.fVirt = FVIRTKEY; + if(ctrl) accel.fVirt |= FCONTROL; + if(alt) accel.fVirt |= FALT; + if(shift) accel.fVirt |= FSHIFT; + table.push_back(accel); +} + +void accel_table_t::build() { + if(handle == NULL) + handle = CreateAcceleratorTable(table.data(), table.size()); +} + +void accel_table_t::destroy() { + if(handle != NULL) + DestroyAcceleratorTable(handle); + handle = NULL; +} + +accel_table_t::~accel_table_t() { + destroy(); +} \ No newline at end of file diff --git a/src/tools/menu_accel.win.hpp b/src/tools/menu_accel.win.hpp new file mode 100644 index 00000000..742773b2 --- /dev/null +++ b/src/tools/menu_accel.win.hpp @@ -0,0 +1,12 @@ + +#include +#include + +struct accel_table_t { + std::vector table; + HACCEL handle = NULL; + void add(WORD cmd, std::string key); + void build(); + void destroy(); + ~accel_table_t(); +}; \ No newline at end of file