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