Make menu accelerator keys work on Windows

This commit is contained in:
2015-02-14 15:21:26 -05:00
parent 7ba874f1d2
commit d977a0f457
7 changed files with 156 additions and 3 deletions

View File

@@ -55,6 +55,7 @@
<ClInclude Include="..\..\tools\gzstream\gzstream.h" />
<ClInclude Include="..\..\tools\map_parse.hpp" />
<ClInclude Include="..\..\tools\mathutil.hpp" />
<ClInclude Include="..\..\tools\menu_accel.win.hpp" />
<ClInclude Include="..\..\tools\porting.hpp" />
<ClInclude Include="..\..\tools\prefs.hpp" />
<ClInclude Include="..\..\tools\resmgr\resmgr.hpp" />
@@ -114,6 +115,7 @@
<ClCompile Include="..\..\tools\gzstream\gzstream.cpp" />
<ClCompile Include="..\..\tools\map_parse.cpp" />
<ClCompile Include="..\..\tools\mathutil.cpp" />
<ClCompile Include="..\..\tools\menu_accel.win.cpp" />
<ClCompile Include="..\..\tools\porting.cpp" />
<ClCompile Include="..\..\tools\prefs.win.cpp" />
<ClCompile Include="..\..\tools\soundtool.cpp" />

View File

@@ -206,6 +206,9 @@
<ClInclude Include="..\..\classes\living.hpp">
<Filter>Classes\Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\tools\menu_accel.win.hpp">
<Filter>Tools\Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\classes\creatlist.cpp">
@@ -361,5 +364,8 @@
<ClCompile Include="..\..\classes\living.cpp">
<Filter>Classes\Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\tools\menu_accel.win.cpp">
<Filter>Tools\Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -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<int,eMenu> 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) {

View File

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

View File

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

View File

@@ -0,0 +1,73 @@
#include "menu_accel.win.hpp"
#include <sstream>
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();
}

View File

@@ -0,0 +1,12 @@
#include <Windows.h>
#include <vector>
struct accel_table_t {
std::vector<ACCEL> table;
HACCEL handle = NULL;
void add(WORD cmd, std::string key);
void build();
void destroy();
~accel_table_t();
};