keybindings.cpp

来自「这是整套横扫千军3D版游戏的源码」· C++ 代码 · 共 816 行 · 第 1/2 页

CPP
816
字号
#include "StdAfx.h"
// CKeyBindings.cpp: implementation of the CKeyBindings class.
//
//////////////////////////////////////////////////////////////////////

#include "KeyBindings.h"
#include <stdio.h>
#include <cctype>
#include "SDL_keysym.h"
#include "KeyCodes.h"
#include "KeySet.h"
#include "KeyAutoBinder.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Units/UnitDefHandler.h"
#include "System/Platform/errorhandler.h"
#include "System/FileSystem/FileHandler.h"
#include "System/FileSystem/SimpleParser.h"
#include "System/LogOutput.h"


CKeyBindings* keyBindings = NULL;


static const struct DefaultBinding {
	const char* key;
	const char* action;
}
defaultBindings[] = {

	{       "esc", "quitwarn" },
	{ "Shift+esc", "quit"     },

	{ "Any+pause", "pause" },

	{ "Any+b", "debug"                },
	{ "Any+o", "singlestep"           },
	{ "Any+c", "controlunit"          },
	{ "Any+h", "sharedialog"          },
	{ "Any+l", "togglelos"            },
	{ "Any+;", "toggleradarandjammer" },

	{ "Any+tab", "toggleoverview" },

	{ "Any+j",         "mouse2" },
	{ "Any+backspace", "mousestate" },

	{ "Any+i", "gameinfo" },

	{   "Any+enter", "chat"           },
	{  "Ctrl+enter", "chatall"        },
	{  "Ctrl+enter", "chatswitchall"  },
	{   "Alt+enter", "chatally"       },
	{   "Alt+enter", "chatswitchally" },
	{ "Shift+enter", "chatspec"       },
	{ "Shift+enter", "chatswitchspec" },

	{       "Any+tab", "edit_complete"  },
	{ "Any+backspace", "edit_backspace" },
	{    "Any+delete", "edit_delete"    },
	{      "Any+home", "edit_home"      },
	{      "Alt+left", "edit_home"      },
	{       "Any+end", "edit_end"       },
	{     "Alt+right", "edit_end"       },
	{        "Any+up", "edit_prev_line" },
	{      "Any+down", "edit_next_line" },
	{      "Any+left", "edit_prev_char" },
	{     "Any+right", "edit_next_char" },
	{     "Ctrl+left", "edit_prev_word" },
	{    "Ctrl+right", "edit_next_word" },
	{     "Any+enter", "edit_return"    },
	{    "Any+escape", "edit_escape"    },

	{ "Ctrl+v", "pastetext" },

	{ "Any+home", "increaseViewRadius" },
	{ "Any+end",  "decreaseViewRadius" },

	{ "Ctrl+insert", "hotbind"   },
	{ "Ctrl+delete", "hotunbind" },

	{ "Any+insert",  "speedup"  },
	{ "Any+delete",  "slowdown" },
	{ "Any+=",       "speedup"  },
	{ "Any++",       "speedup"  },
	{ "Any+-",       "slowdown" },
	{ "Any+numpad+", "speedup"  },
	{ "Any+numpad-", "slowdown" },

	{       ",", "prevmenu" },
	{       ".", "nextmenu" },
	{ "Shift+,", "decguiopacity" },
	{ "Shift+.", "incguiopacity" },

	{      "1", "specteam 0"  },
	{      "2", "specteam 1"  },
	{      "3", "specteam 2"  },
	{      "4", "specteam 3"  },
	{      "5", "specteam 4"  },
	{      "6", "specteam 5"  },
	{      "7", "specteam 6"  },
	{      "8", "specteam 7"  },
	{      "9", "specteam 8"  },
	{      "0", "specteam 9"  },
	{ "Ctrl+1", "specteam 10" },
	{ "Ctrl+2", "specteam 11" },
	{ "Ctrl+3", "specteam 12" },
	{ "Ctrl+4", "specteam 13" },
	{ "Ctrl+5", "specteam 14" },
	{ "Ctrl+6", "specteam 15" },
	{ "Ctrl+7", "specteam 16" },
	{ "Ctrl+8", "specteam 17" },
	{ "Ctrl+9", "specteam 18" },
	{ "Ctrl+0", "specteam 19" },

	{ "Any+0", "group0" },
	{ "Any+1", "group1" },
	{ "Any+2", "group2" },
	{ "Any+3", "group3" },
	{ "Any+4", "group4" },
	{ "Any+5", "group5" },
	{ "Any+6", "group6" },
	{ "Any+7", "group7" },
	{ "Any+8", "group8" },
	{ "Any+9", "group9" },

	{ "Any+c", "controlunit" },

	{       "[", "buildfacing inc"  },
	{ "Shift+[", "buildfacing inc"  },
	{       "]", "buildfacing dec"  },
	{ "Shift+]", "buildfacing dec"  },
	{   "Any+z", "buildspacing inc" },
	{   "Any+x", "buildspacing dec" },

	{            "d", "dgun"         },
	{      "Shift+d", "dgun"         },
	{       "Ctrl+d", "selfd"        },
	{ "Ctrl+Shift+d", "selfd queued" },
	{            "s", "stop"         },
	{      "Shift+s", "stop"         },
	{            "w", "wait"         },
	{      "Shift+w", "wait queued"  },
	{            "m", "move"         },
	{      "Shift+m", "move"         },
	{            "a", "attack"       },
	{      "Shift+a", "attack"       },
	{        "Alt+a", "areaattack"   },
	{  "Alt+Shift+a", "areaattack"   },
	{            "f", "fight"        },
	{      "Shift+f", "fight"        },
	{            "p", "patrol"       },
	{      "Shift+p", "patrol"       },
	{            "g", "guard"        },
	{      "Shift+g", "guard"        },
	{            "e", "reclaim"      },
	{      "Shift+e", "reclaim"      },
	{            "r", "repair"       },
	{      "Shift+r", "repair"       },
	{            "l", "loadunits"    },
	{      "Shift+l", "loadunits"    },
	{            "u", "unloadunits"  },
	{      "Shift+u", "unloadunits"  },
	{            "k", "cloak"        },
	{      "Shift+k", "cloak"        },
	{            "x", "onoff"        },
	{      "Shift+x", "onoff"        },

	{       "q", "groupselect" },
	{       "q", "groupadd"    },
	{  "Ctrl+q", "aiselect"    },
	{ "Shift+q", "groupclear"  },

	{  "Ctrl+t", "trackmode" },
	{   "Any+t", "track" },

	{ "Ctrl+f1", "viewfps"  },
	{ "Ctrl+f2", "viewta"   },
	{ "Ctrl+f3", "viewtw"   },
	{ "Ctrl+f4", "viewrot"  },
	{ "Ctrl+f5", "viewfree" },

	{ "Any+f1",  "showElevation"  },
	{ "Any+f2",  "ShowPathMap"    },
	{ "Any+f3",  "LastMsgPos"     },
	{ "Any+f4",  "ShowMetalMap"   },
	{ "Any+f5",  "hideinterface"  },
	{ "Any+f6",  "NoSound"        },
	{ "Any+f7",  "dynamicSky"     },
	{ "Ctrl+Shift+f8", "savegame" },
	{ "Any+f9",  "showhealthbars" },
	{ "Ctrl+Shift+f10", "createvideo" },
	{ "Any+f11", "screenshot"     },
	{ "Any+f12", "screenshot"     },

	// NOTE: Up bindings are currently converted to press bindings
	//       (see KeySet.cpp / DISALLOW_RELEASE_BINDINGS)

	{    "Any+`",    "drawinmap"  },
	{ "Up+Any+`",    "drawinmap"  },
	{    "Any+\\",   "drawinmap"  },
	{ "Up+Any+\\",   "drawinmap"  },
	{    "Any+0xa7", "drawinmap"  },
	{ "Up+Any+0xa7", "drawinmap"  },

	{    "Any+up",       "moveforward"  },
	{ "Up+Any+up",       "moveforward"  },
	{    "Any+down",     "moveback"     },
	{ "Up+Any+down",     "moveback"     },
	{    "Any+right",    "moveright"    },
	{ "Up+Any+right",    "moveright"    },
	{    "Any+left",     "moveleft"     },
	{ "Up+Any+left",     "moveleft"     },
	{    "Any+pageup",   "moveup"       },
	{ "Up+Any+pageup",   "moveup"       },
	{    "Any+pagedown", "movedown"     },
	{ "Up+Any+pagedown", "movedown"     },

	{    "Any+ctrl",     "moveslow"     },
	{ "Up+Any+ctrl",     "moveslow"     },
	{    "Any+shift",    "movefast"     },
	{ "Up+Any+shift",    "movefast"     }
};


/******************************************************************************/
//
// CKeyBindings::Action
//

CKeyBindings::Action::Action(const string& line)
{
	rawline = line;
	command = "";
	extra = "";
	vector<string> words = CSimpleParser::Tokenize(line, 1);
	if (words.size() > 0) {
		command = StringToLower(words[0]);
	}
	if (words.size() > 1) {
		extra = words[1];
	}
}


/******************************************************************************/
//
// CKeyBindings
//

CKeyBindings::CKeyBindings()
{
	debug = 0;
	fakeMetaKey = -1;
	userCommand = true;

	statefulCommands.insert("drawinmap");
	statefulCommands.insert("moveforward");
	statefulCommands.insert("moveback");
	statefulCommands.insert("moveright");
	statefulCommands.insert("moveleft");
	statefulCommands.insert("moveup");
	statefulCommands.insert("movedown");
	statefulCommands.insert("moveslow");
	statefulCommands.insert("movefast");
}


CKeyBindings::~CKeyBindings()
{
}


/******************************************************************************/

const CKeyBindings::ActionList&
	CKeyBindings::GetActionList(const CKeySet& ks) const
{
	static const ActionList empty;
	const ActionList* alPtr = NULL;

	if (ks.AnyMod()) {
		KeyMap::const_iterator it = bindings.find(ks);
		if (it == bindings.end()) {
			alPtr = &empty;
		} else {
			alPtr = &(it->second);
		}
	}
	else {
		// have to check for an AnyMod keyset as well as the normal one
		CKeySet anyMod = ks;
		anyMod.SetAnyBit();
		KeyMap::const_iterator nit = bindings.find(ks);
		KeyMap::const_iterator ait = bindings.find(anyMod);
		const bool haveNormal = (nit != bindings.end());
		const bool haveAnyMod = (ait != bindings.end());
		if (!haveNormal && !haveAnyMod) {
			alPtr = &empty;
		}
		else if (haveNormal && !haveAnyMod) {
			alPtr = &(nit->second);
		}
		else if (!haveNormal && haveAnyMod) {
			alPtr = &(ait->second);
		}
		else {
			// combine the two lists (normal first)
			static ActionList merged;
			merged = nit->second;
			const ActionList& aal = ait->second;
			for (int i = 0; i < (int)aal.size(); ++i) {
				merged.push_back(aal[i]);
			}
			alPtr = &merged;
		}
	}

	if (debug > 0) {
		char buf[256];
		SNPRINTF(buf, sizeof(buf), "GetAction: %s (0x%03X)",
		         ks.GetString(false).c_str(), ks.Key());
		if (alPtr == &empty) {
			strncat(buf, "  EMPTY", sizeof(buf));
			logOutput.Print("%s", buf);
		}
		else {
			logOutput.Print("%s", buf);
			const ActionList& al = *alPtr;
			for (int i = 0; i < (int)al.size(); ++i) {
				SNPRINTF(buf, sizeof(buf), "  %s  \"%s\"",
				         al[i].command.c_str(), al[i].rawline.c_str());
				logOutput.Print("%s", buf);
			}
		}
	}

	return *alPtr;
}


const CKeyBindings::HotkeyList&
	CKeyBindings::GetHotkeys(const string& action) const
{
	ActionMap::const_iterator it = hotkeys.find(action);
	if (it == hotkeys.end()) {
		static HotkeyList empty;
		return empty;
	}
	const HotkeyList& hl = it->second;
	return hl;
}


/******************************************************************************/

bool CKeyBindings::Bind(const string& keystr, const string& line)
{
	CKeySet ks;
	if (!ParseKeySet(keystr, ks)) {
		logOutput.Print("Bind: could not parse key: %s\n", keystr.c_str());
		return false;
	}
	Action action(line);
	action.boundWith = keystr;
	if (action.command.empty()) {
		logOutput.Print("Bind: empty action: %s\n", line.c_str());
		return false;
	}

	// Try to be safe, force AnyMod mode for stateful commands
	if (statefulCommands.find(action.command) != statefulCommands.end()) {
		ks.SetAnyBit();
	}

	KeyMap::iterator it = bindings.find(ks);
	if (it == bindings.end()) {
		// new entry, push it
		ActionList& al = bindings[ks];
		al.push_back(action);
	} else {
		if (it->first != ks) {
			// not a match, push it
			ActionList& al = it->second;
			al.push_back(action);
		}
		else {
			// an exact keyset match, check the command
			ActionList& al = it->second;
			int i;
			for (i = 0; i < (int)al.size(); i++) {
				if (action.command == al[i].command) {
					break;
				}
			}
			if (i == (int)al.size()) {
				// not a match, push it
				al.push_back(action);
			}
		}
	}

	return true;
}


bool CKeyBindings::UnBind(const string& keystr, const string& command)
{
	CKeySet ks;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?