Changeset View
Changeset View
Standalone View
Standalone View
source/ps/Hotkey.cpp
Show All 14 Lines | |||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "precompiled.h" | #include "precompiled.h" | ||||
#include "Hotkey.h" | #include "Hotkey.h" | ||||
#include <boost/tokenizer.hpp> | #include <boost/tokenizer.hpp> | ||||
#include "lib/external_libraries/libsdl.h" | |||||
#include "ps/CConsole.h" | #include "ps/CConsole.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/CStr.h" | #include "ps/CStr.h" | ||||
#include "ps/ConfigDB.h" | #include "ps/ConfigDB.h" | ||||
#include "ps/Globals.h" | #include "ps/Globals.h" | ||||
#include "ps/KeyName.h" | #include "ps/KeyName.h" | ||||
static bool unified[UNIFIED_LAST - UNIFIED_SHIFT]; | static bool unified[UNIFIED_LAST - UNIFIED_SHIFT]; | ||||
struct SKey | std::map<int, KeyMapping> g_HotkeyMap; | ||||
Stan: ? | |||||
Not Done Inline ActionsDo we need sorting ? Stan: Do we need sorting ? | |||||
Not Done Inline Actions? Stan: ? | |||||
{ | |||||
SDL_Keycode code; // keycode or MOUSE_ or UNIFIED_ value | |||||
bool negated; // whether the key must be pressed (false) or unpressed (true) | |||||
}; | |||||
// Hotkey data associated with an externally-specified 'primary' keycode | |||||
struct SHotkeyMapping | |||||
{ | |||||
CStr name; // name of the hotkey | |||||
bool negated; // whether the primary key must be pressed (false) or unpressed (true) | |||||
std::vector<SKey> requires; // list of non-primary keys that must also be active | |||||
}; | |||||
typedef std::vector<SHotkeyMapping> KeyMapping; | |||||
// A mapping of keycodes onto the hotkeys that are associated with that key. | |||||
// (A hotkey triggered by a combination of multiple keys will be in this map | |||||
// multiple times.) | |||||
static std::map<int, KeyMapping> g_HotkeyMap; | |||||
// The current pressed status of hotkeys | |||||
std::map<std::string, bool> g_HotkeyStatus; | std::map<std::string, bool> g_HotkeyStatus; | ||||
static_assert(std::is_same<SDL_Keycode_, SDL_Keycode>::value, "SDL_Keycode_ is not the same type as the real SDL_Keycode"); | |||||
static_assert(SDL_USEREVENT_ == SDL_USEREVENT, "SDL_USEREVENT_ is not the same type as the real SDL_USEREVENT"); | |||||
// Look up each key binding in the config file and set the mappings for | // Look up each key binding in the config file and set the mappings for | ||||
// all key combinations that trigger it. | // all key combinations that trigger it. | ||||
static void LoadConfigBindings() | static void LoadConfigBindings() | ||||
{ | { | ||||
for (const std::pair<CStr, CConfigValueSet>& configPair : g_ConfigDB.GetValuesWithPrefix(CFG_COMMAND, "hotkey.")) | for (const std::pair<CStr, CConfigValueSet>& configPair : g_ConfigDB.GetValuesWithPrefix(CFG_COMMAND, "hotkey.")) | ||||
{ | { | ||||
std::string hotkeyName = configPair.first.substr(7); // strip the "hotkey." prefix | std::string hotkeyName = configPair.first.substr(7); // strip the "hotkey." prefix | ||||
for (const CStr& hotkey : configPair.second) | for (const CStr& hotkey : configPair.second) | ||||
{ | { | ||||
if (hotkey.LowerCase() == "unused") | if (hotkey.LowerCase() == "unused") | ||||
continue; | continue; | ||||
std::vector<SKey> keyCombination; | std::vector<SKey> keyCombination; | ||||
// Iterate through multiple-key bindings (e.g. Ctrl+I) | // Iterate through multiple-key bindings (e.g. Ctrl+I) | ||||
boost::char_separator<char> sep("+"); | boost::char_separator<char> sep("+"); | ||||
typedef boost::tokenizer<boost::char_separator<char> > tokenizer; | typedef boost::tokenizer<boost::char_separator<char> > tokenizer; | ||||
tokenizer tok(hotkey, sep); | tokenizer tok(hotkey, sep); | ||||
for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it) | for (tokenizer::iterator it = tok.begin(); it != tok.end(); ++it) | ||||
{ | { | ||||
CStrW t = hotkey.FromUTF8(); | |||||
Not Done Inline ActionsIs it used ? Stan: Is it used ? | |||||
// Attempt decode as key name | // Attempt decode as key name | ||||
int mapping = FindKeyCode(*it); | int mapping = FindKeyCode(*it); | ||||
if (!mapping) | |||||
mapping = SDL_GetKeyFromName(it->c_str()); | // If the setting is a default setting, interpret it as a QWERTY scancode | ||||
Done Inline ActionsReverts D303 by moving it to KeyName wraitii: Reverts D303 by moving it to KeyName | |||||
// and map that automatically to whatever the local keyboard would use instead. | |||||
if (g_ConfigDB.GetValueNamespace(CFG_USER, configPair.first) < CFG_USER) | |||||
{ | |||||
SDL_Scancode scanCode = SDL_GetScancodeFromName(it->c_str()); | |||||
if (scanCode != SDL_SCANCODE_UNKNOWN) | |||||
mapping = SDL_GetKeyFromScancode(scanCode); | |||||
} | |||||
if (!mapping) | if (!mapping) | ||||
{ | { | ||||
LOGWARNING("Hotkey mapping used invalid key '%s'", hotkey.c_str()); | LOGWARNING("Hotkey mapping used invalid key '%s'", hotkey.c_str()); | ||||
continue; | continue; | ||||
} | } | ||||
SKey key = { (SDL_Keycode)mapping, false }; | SKey key = { (SDL_Keycode)mapping, false }; | ||||
keyCombination.push_back(key); | keyCombination.push_back(key); | ||||
▲ Show 20 Lines • Show All 70 Lines • ▼ Show 20 Lines | if (ev->ev.type == SDL_HOTKEYPRESS) | ||||
g_HotkeyStatus[static_cast<const char*>(ev->ev.user.data1)] = true; | g_HotkeyStatus[static_cast<const char*>(ev->ev.user.data1)] = true; | ||||
else if (ev->ev.type == SDL_HOTKEYUP) | else if (ev->ev.type == SDL_HOTKEYUP) | ||||
g_HotkeyStatus[static_cast<const char*>(ev->ev.user.data1)] = false; | g_HotkeyStatus[static_cast<const char*>(ev->ev.user.data1)] = false; | ||||
return IN_PASS; | return IN_PASS; | ||||
} | } | ||||
InReaction HotkeyInputHandler(const SDL_Event_* ev) | InReaction HotkeyInputHandler(const SDL_Event_* ev) | ||||
{ | { | ||||
int keycode = 0; | int keycode = 0; | ||||
Not Done Inline ActionsSDL_Scancode Stan: SDL_Scancode | |||||
Done Inline Actionseasier to have int here, since SDL_Scancode converts to int without casting but not the opposite, and the MOUSE_X below are integer. wraitii: easier to have int here, since SDL_Scancode converts to int without casting but not the… | |||||
switch(ev->ev.type) | switch(ev->ev.type) | ||||
{ | { | ||||
case SDL_KEYDOWN: | case SDL_KEYDOWN: | ||||
case SDL_KEYUP: | case SDL_KEYUP: | ||||
keycode = (int)ev->ev.key.keysym.sym; | keycode = (int)ev->ev.key.keysym.sym; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 191 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
?