diff --git a/source/graphics/GameView.cpp b/source/graphics/GameView.cpp index c675814bb2..8a367e7c8d 100644 --- a/source/graphics/GameView.cpp +++ b/source/graphics/GameView.cpp @@ -601,19 +601,19 @@ void CGameView::Update(float DeltaTime) mouse_last_x = g_mouse_x; mouse_last_y = g_mouse_y; - if (hotkeys[HOTKEY_CAMERA_ROTATE_CW]) + if (HotkeyIsPressed("camera.rotate.cw")) m->RotateY.AddSmoothly(m->ViewRotateYSpeed * DeltaTime); - if (hotkeys[HOTKEY_CAMERA_ROTATE_CCW]) + if (HotkeyIsPressed("camera.rotate.ccw")) m->RotateY.AddSmoothly(-m->ViewRotateYSpeed * DeltaTime); - if (hotkeys[HOTKEY_CAMERA_ROTATE_UP]) + if (HotkeyIsPressed("camera.rotate.up")) m->RotateX.AddSmoothly(-m->ViewRotateXSpeed * DeltaTime); - if (hotkeys[HOTKEY_CAMERA_ROTATE_DOWN]) + if (HotkeyIsPressed("camera.rotate.down")) m->RotateX.AddSmoothly(m->ViewRotateXSpeed * DeltaTime); float moveRightward = 0.f; float moveForward = 0.f; - if (hotkeys[HOTKEY_CAMERA_PAN]) + if (HotkeyIsPressed("camera.pan")) { moveRightward += m->ViewDragSpeed * mouse_dx; moveForward += m->ViewDragSpeed * -mouse_dy; @@ -632,15 +632,15 @@ void CGameView::Update(float DeltaTime) moveForward += m->ViewScrollSpeed * DeltaTime; } - if (hotkeys[HOTKEY_CAMERA_PAN_KEYBOARD]) + if (HotkeyIsPressed("camera.pan.keyboard")) { - if (hotkeys[HOTKEY_CAMERA_RIGHT]) + if (HotkeyIsPressed("camera.right")) moveRightward += m->ViewScrollSpeed * DeltaTime; - if (hotkeys[HOTKEY_CAMERA_LEFT]) + if (HotkeyIsPressed("camera.left")) moveRightward -= m->ViewScrollSpeed * DeltaTime; - if (hotkeys[HOTKEY_CAMERA_UP]) + if (HotkeyIsPressed("camera.up")) moveForward += m->ViewScrollSpeed * DeltaTime; - if (hotkeys[HOTKEY_CAMERA_DOWN]) + if (HotkeyIsPressed("camera.down")) moveForward -= m->ViewScrollSpeed * DeltaTime; } @@ -688,9 +688,9 @@ void CGameView::Update(float DeltaTime) } } - if (hotkeys[HOTKEY_CAMERA_ZOOM_IN]) + if (HotkeyIsPressed("camera.zoom.in")) m->Zoom.AddSmoothly(m->ViewZoomSpeed * DeltaTime); - if (hotkeys[HOTKEY_CAMERA_ZOOM_OUT]) + if (HotkeyIsPressed("camera.zoom.out")) m->Zoom.AddSmoothly(-m->ViewZoomSpeed * DeltaTime); float zoomDelta = m->Zoom.Update(DeltaTime); @@ -894,9 +894,10 @@ InReaction CGameView::HandleEvent(const SDL_Event_* ev) { case SDL_HOTKEYDOWN: - switch(ev->ev.user.code) + std::string hotkey = static_cast(ev->ev.user.data1); + + if (hotkey == "wireframe") { - case HOTKEY_WIREFRAME: if (g_Renderer.GetModelRenderMode() == SOLID) { g_Renderer.SetTerrainRenderMode(EDGED_FACES); @@ -913,27 +914,32 @@ InReaction CGameView::HandleEvent(const SDL_Event_* ev) g_Renderer.SetModelRenderMode(SOLID); } return IN_HANDLED; - + } // Mouse wheel must be treated using events instead of polling, // because SDL auto-generates a sequence of mousedown/mouseup events // and we never get to see the "down" state inside Update(). - case HOTKEY_CAMERA_ZOOM_WHEEL_IN: + else if (hotkey == "camera.zoom.wheel.in") + { m->Zoom.AddSmoothly(m->ViewZoomSpeedWheel); return IN_HANDLED; - - case HOTKEY_CAMERA_ZOOM_WHEEL_OUT: + } + else if (hotkey == "camera.zoom.wheel.out") + { m->Zoom.AddSmoothly(-m->ViewZoomSpeedWheel); return IN_HANDLED; - - case HOTKEY_CAMERA_ROTATE_WHEEL_CW: + } + else if (hotkey == "camera.rotate.wheel.cw") + { m->RotateY.AddSmoothly(m->ViewRotateYSpeedWheel); return IN_HANDLED; - - case HOTKEY_CAMERA_ROTATE_WHEEL_CCW: + } + else if (hotkey == "camera.rotate.wheel.ccw") + { m->RotateY.AddSmoothly(-m->ViewRotateYSpeedWheel); return IN_HANDLED; - - case HOTKEY_CAMERA_RESET: + } + else if (hotkey == "camera.reset") + { ResetCameraAngleZoom(); return IN_HANDLED; } diff --git a/source/gui/CGUI.cpp b/source/gui/CGUI.cpp index 521ae242da..d775a6b04a 100644 --- a/source/gui/CGUI.cpp +++ b/source/gui/CGUI.cpp @@ -75,18 +75,17 @@ InReaction CGUI::HandleEvent(const SDL_Event_* ev) { InReaction ret = IN_PASS; - if (ev->ev.type == SDL_GUIHOTKEYPRESS) + if (ev->ev.type == SDL_HOTKEYDOWN) { - const CStr& objectName = *(CStr*) ev->ev.user.data1; - IGUIObject* object = FindObjectByName(objectName); - if (! object) + const char* hotkey = static_cast(ev->ev.user.data1); + std::map >::iterator it = m_HotkeyObjects.find(hotkey); + if (it != m_HotkeyObjects.end()) { - LOG(CLogger::Error, LOG_CATEGORY, L"Cannot find hotkeyed object '%hs'", objectName.c_str()); - } - else - { - object->HandleMessage( SGUIMessage( GUIM_PRESSED ) ); - object->ScriptEvent("press"); + for (size_t i = 0; i < it->second.size(); ++i) + { + it->second[i]->HandleMessage(SGUIMessage(GUIM_PRESSED)); + it->second[i]->ScriptEvent("press"); + } } } @@ -1226,7 +1225,7 @@ void CGUI::Xeromyces_ReadObject(XMBElement Element, CXeromyces* pFile, IGUIObjec // Attempt to register the hotkey tag, if one was provided if (! hotkeyTag.empty()) - HotkeyRegisterGuiObject(object->GetName(), hotkeyTag); + m_HotkeyObjects[hotkeyTag].push_back(object); CStrW caption (Element.GetText()); if (! caption.empty()) diff --git a/source/gui/CGUI.h b/source/gui/CGUI.h index 816182456c..7ca3be2d62 100644 --- a/source/gui/CGUI.h +++ b/source/gui/CGUI.h @@ -651,6 +651,15 @@ private: */ std::map m_ObjectTypes; + /** + * Map from hotkey names to objects that listen to the hotkey. + * (This is an optimisation to avoid recursing over the whole GUI + * tree every time a hotkey is pressed). + * Currently this is only set at load time - dynamic changes to an + * object's hotkey property will be ignored. + */ + std::map > m_HotkeyObjects; + //-------------------------------------------------------- // Databases //-------------------------------------------------------- diff --git a/source/gui/CInput.cpp b/source/gui/CInput.cpp index abbc8ebddc..355c0bdf49 100644 --- a/source/gui/CInput.cpp +++ b/source/gui/CInput.cpp @@ -79,7 +79,8 @@ InReaction CInput::ManuallyHandleEvent(const SDL_Event_* ev) if (ev->ev.type == SDL_HOTKEYDOWN) { - if (ev->ev.user.code == HOTKEY_CONSOLE_PASTE) + std::string hotkey = static_cast(ev->ev.user.data1); + if (hotkey == "console.paste") { wchar_t* text = sys_clipboard_get(); if (text) diff --git a/source/gui/GUIManager.cpp b/source/gui/GUIManager.cpp index eb40fb98aa..5c0423817b 100644 --- a/source/gui/GUIManager.cpp +++ b/source/gui/GUIManager.cpp @@ -37,8 +37,6 @@ CGUIManager* g_GUI = NULL; // A lot of the CGUI data could (and should) be shared between // multiple pages, instead of treating them as completely independent, to save // memory and loading time. -// -// Hotkeys are not unregistered when a page is unloaded. // called from main loop when (input) events are received. diff --git a/source/gui/scripting/GuiScriptConversions.cpp b/source/gui/scripting/GuiScriptConversions.cpp index 8bc89ed765..be30568833 100644 --- a/source/gui/scripting/GuiScriptConversions.cpp +++ b/source/gui/scripting/GuiScriptConversions.cpp @@ -43,7 +43,6 @@ template<> jsval ScriptInterface::ToJSVal(JSContext* cx, SDL_Event_ case SDL_MOUSEBUTTONUP: typeName = "mousebuttonup"; break; case SDL_HOTKEYDOWN: typeName = "hotkeydown"; break; case SDL_HOTKEYUP: typeName = "hotkeyup"; break; - case SDL_GUIHOTKEYPRESS: typeName = "guihotkeypress"; break; default: typeName = "(unknown)"; break; } @@ -117,14 +116,7 @@ template<> jsval ScriptInterface::ToJSVal(JSContext* cx, SDL_Event_ case SDL_HOTKEYDOWN: case SDL_HOTKEYUP: { - CStr name = HotkeyGetName(val.ev.user.code); - SET(obj, "hotkey", name.c_str()); - break; - } - case SDL_GUIHOTKEYPRESS: - { - CStr* name = static_cast(val.ev.user.data1); - SET(obj, "object", name->c_str()); + SET(obj, "hotkey", static_cast(val.ev.user.data1)); break; } } diff --git a/source/main.cpp b/source/main.cpp index 04c8f6176a..b2cb1797ce 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -100,26 +100,26 @@ static InReaction MainInputHandler(const SDL_Event_* ev) break; case SDL_HOTKEYDOWN: - switch(ev->ev.user.code) + std::string hotkey = static_cast(ev->ev.user.data1); + if (hotkey == "exit") { - case HOTKEY_EXIT: kill_mainloop(); return IN_HANDLED; - - case HOTKEY_SCREENSHOT: + } + else if (hotkey == "screenshot") + { WriteScreenshot(L".png"); return IN_HANDLED; - - case HOTKEY_BIGSCREENSHOT: + } + else if (hotkey == "bigscreenshot") + { WriteBigScreenshot(L".bmp", 10); return IN_HANDLED; - - case HOTKEY_TOGGLEFULLSCREEN: + } + else if (hotkey == "togglefullscreen") + { g_VideoMode.ToggleFullscreen(); return IN_HANDLED; - - default: - break; } break; } diff --git a/source/ps/CConsole.cpp b/source/ps/CConsole.cpp index bdb8148b0c..eaaa52c0db 100644 --- a/source/ps/CConsole.cpp +++ b/source/ps/CConsole.cpp @@ -759,17 +759,19 @@ InReaction conInputHandler(const SDL_Event_* ev) { if( ev->ev.type == SDL_HOTKEYDOWN ) { - if( ev->ev.user.code == HOTKEY_CONSOLE_TOGGLE ) + std::string hotkey = static_cast(ev->ev.user.data1); + + if( hotkey == "console.toggle" ) { g_Console->ToggleVisible(); return IN_HANDLED; } - else if( ev->ev.user.code == HOTKEY_CONSOLE_COPY ) + else if( hotkey == "console.copy" ) { sys_clipboard_set( g_Console->GetBuffer() ); return IN_HANDLED; } - else if( ev->ev.user.code == HOTKEY_CONSOLE_PASTE ) + else if( hotkey == "console.paste" ) { wchar_t* text = sys_clipboard_get(); if(text) @@ -794,7 +796,7 @@ InReaction conInputHandler(const SDL_Event_* ev) // Stop unprintable characters (ctrl+, alt+ and escape), // also prevent ` and/or ~ appearing in console every time it's toggled. if( !isUnprintableChar(ev->ev.key.keysym) && - !hotkeys[HOTKEY_CONSOLE_TOGGLE] ) + !HotkeyIsPressed("console.toggle") ) g_Console->InsertChar(sym, (wchar_t)ev->ev.key.keysym.unicode ); return IN_PASS; diff --git a/source/ps/ConfigDB.cpp b/source/ps/ConfigDB.cpp index 9e16cb0161..88876750b5 100644 --- a/source/ps/ConfigDB.cpp +++ b/source/ps/ConfigDB.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -24,6 +24,8 @@ #include "Filesystem.h" #include "scripting/ScriptingHost.h" +#include + typedef std::map TConfigMap; TConfigMap CConfigDB::m_Map[CFG_LAST]; CStrW CConfigDB::m_ConfigFile[CFG_LAST]; @@ -213,7 +215,7 @@ CConfigValue *CConfigDB::GetValue(EConfigNamespace ns, const CStr& name) return &( (*values)[0] ); } -CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name ) +CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name) { if (ns < 0 || ns >= CFG_LAST) { @@ -235,6 +237,34 @@ CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name ) return( NULL ); } +std::vector > CConfigDB::GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix) +{ + std::vector > ret; + + if (ns < 0 || ns >= CFG_LAST) + { + debug_warn(L"CConfigDB: Invalid ns value"); + return ret; + } + + for (TConfigMap::iterator it = m_Map[CFG_COMMAND].begin(); it != m_Map[CFG_COMMAND].end(); ++it) + { + if (boost::algorithm::starts_with(it->first, prefix)) + ret.push_back(std::make_pair(it->first, it->second)); + } + + for (int search_ns = ns; search_ns >= 0; search_ns--) + { + for (TConfigMap::iterator it = m_Map[search_ns].begin(); it != m_Map[search_ns].end(); ++it) + { + if (boost::algorithm::starts_with(it->first, prefix)) + ret.push_back(std::make_pair(it->first, it->second)); + } + } + + return ret; +} + CConfigValue *CConfigDB::CreateValue(EConfigNamespace ns, const CStr& name) { if (ns < 0 || ns >= CFG_LAST) diff --git a/source/ps/ConfigDB.h b/source/ps/ConfigDB.h index d129ce24d4..7f145c7418 100644 --- a/source/ps/ConfigDB.h +++ b/source/ps/ConfigDB.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -83,57 +83,70 @@ public: // the JS interface can be registered. CConfigDB(); - // GetValue() - // Attempt to find a config variable with the given name; will search all - // namespaces from system up to the specified namespace. - // - // Returns a pointer to the config value structure for the variable, or - // NULL if such a variable could not be found + /** + * Attempt to find a config variable with the given name; will search all + * namespaces from system up to the specified namespace. + * + * Returns a pointer to the config value structure for the variable, or + * NULL if such a variable could not be found + */ CConfigValue *GetValue(EConfigNamespace ns, const CStr& name); - // GetValues() - // Attempt to retrieve a vector of values corresponding to the given setting; - // will search all namespaces from system up to the specified namespace. - // - // Returns a pointer to the vector, or NULL if the setting could not be found. + /** + * Attempt to retrieve a vector of values corresponding to the given setting; + * will search all namespaces from system up to the specified namespace. + * + * Returns a pointer to the vector, or NULL if the setting could not be found. + */ CConfigValueSet *GetValues(EConfigNamespace ns, const CStr& name); - // CreateValue() - // Create a new config value in the specified namespace. If such a - // variable already exists, the old value is returned and the effect is - // exactly the same as that of GetValue() - // - // Returns a pointer to the value of the newly created config variable, or - // that of the already existing config variable. + /** + * Retrieve a vector of values corresponding to settings whose names begin + * with the given prefix; + * will search all namespaces from system up to the specified namespace. + */ + std::vector > GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix); + + /** + * Create a new config value in the specified namespace. If such a + * variable already exists, the old value is returned and the effect is + * exactly the same as that of GetValue() + * + * Returns a pointer to the value of the newly created config variable, or + * that of the already existing config variable. + */ CConfigValue *CreateValue(EConfigNamespace ns, const CStr& name); - // SetConfigFile() - // Set the path to the config file used to populate the specified namespace - // Note that this function does not actually load the config file. Use - // the Reload() method if you want to read the config file at the same time. - // - // 'path': The path to the config file. - // VFS: relative to VFS root - // non-VFS: relative to current working directory (binaries/data/) - // 'useVFS': true if the path is a VFS path, false if it is a real path + /** + * Set the path to the config file used to populate the specified namespace + * Note that this function does not actually load the config file. Use + * the Reload() method if you want to read the config file at the same time. + * + * 'path': The path to the config file. + * VFS: relative to VFS root + * non-VFS: relative to current working directory (binaries/data/) + * 'useVFS': true if the path is a VFS path, false if it is a real path + */ void SetConfigFile(EConfigNamespace ns, bool useVFS, const CStrW& path); - // Reload() - // Reload the config file associated with the specified config namespace - // (the last config file path set with SetConfigFile) - // - // Returns: - // true: if the reload succeeded, - // false: if the reload failed + /** + * Reload the config file associated with the specified config namespace + * (the last config file path set with SetConfigFile) + * + * Returns: + * true: if the reload succeeded, + * false: if the reload failed + */ bool Reload(EConfigNamespace); - // WriteFile() - // Write the current state of the specified config namespace to the file - // specified by 'path' - // - // Returns: - // true: if the config namespace was successfully written to the file - // false: if an error occured + /** + * Write the current state of the specified config namespace to the file + * specified by 'path' + * + * Returns: + * true: if the config namespace was successfully written to the file + * false: if an error occurred + */ bool WriteFile(EConfigNamespace ns, bool useVFS, const CStrW& path); }; diff --git a/source/ps/Hotkey.cpp b/source/ps/Hotkey.cpp index 7eb15d9eab..5511653e1d 100644 --- a/source/ps/Hotkey.cpp +++ b/source/ps/Hotkey.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,161 +26,51 @@ #include "ps/Globals.h" #include "KeyName.h" -extern CConsole* g_Console; +static bool unified[UNIFIED_LAST - UNIFIED_SHIFT]; -static bool unified[5]; - -/* SDL-type */ +struct SKey +{ + SDLKey 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 { - int mapsTo; - bool negation; - std::vector requires; - SHotkeyMapping() : mapsTo(-1) {} + CStr name; // name of the hotkey + bool negated; // whether the primary key must be pressed (false) or unpressed (true) + std::vector requires; // list of non-primary keys that must also be active }; typedef std::vector KeyMapping; -/** - * HK_MAX_KEYCODES: Global maximum number of keycodes, including our "fake" keycodes for - * mouse buttons and unified modifiers. - */ -const int HK_MAX_KEYCODES = UNIFIED_SUPER + 1; +// 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 g_HotkeyMap; -// A mapping of keycodes onto sets of SDL event codes -static KeyMapping hotkeyMap[HK_MAX_KEYCODES]; +// The current pressed status of hotkeys +std::map g_HotkeyStatus; -// An array of the status of virtual keys -bool hotkeys[HOTKEY_LAST]; - - -struct SHotkeyInfo -{ - int code; - const char* name; - int defaultmapping1, defaultmapping2; -}; - -// Will phase out the default shortcuts at sometime in the near future -// (or, failing that, will update them so they can do the tricky stuff -// the config file can.) - -static SHotkeyInfo hotkeyInfo[] = -{ - { HOTKEY_EXIT, "exit", SDLK_ESCAPE, 0 }, - { HOTKEY_SCREENSHOT, "screenshot", SDLK_PRINT, 0 }, - { HOTKEY_BIGSCREENSHOT, "bigscreenshot", 0, 0 }, - { HOTKEY_WIREFRAME, "wireframe", SDLK_w, 0 }, - { HOTKEY_TOGGLEFULLSCREEN, "togglefullscreen", 0, 0 }, - { HOTKEY_CAMERA_RESET, "camera.reset", 0, 0 }, - { HOTKEY_CAMERA_FOLLOW, "camera.follow", 0, 0 }, - { HOTKEY_CAMERA_ZOOM_IN, "camera.zoom.in", SDLK_PLUS, SDLK_KP_PLUS }, - { HOTKEY_CAMERA_ZOOM_OUT, "camera.zoom.out", SDLK_MINUS, SDLK_KP_MINUS }, - { HOTKEY_CAMERA_ZOOM_WHEEL_IN, "camera.zoom.wheel.in", MOUSE_WHEELUP, 0 }, - { HOTKEY_CAMERA_ZOOM_WHEEL_OUT, "camera.zoom.wheel.out", MOUSE_WHEELDOWN, 0 }, - { HOTKEY_CAMERA_ROTATE_CW, "camera.rotate.cw", 0, 0 }, - { HOTKEY_CAMERA_ROTATE_CCW, "camera.rotate.ccw", 0, 0 }, - { HOTKEY_CAMERA_ROTATE_UP, "camera.rotate.up", 0, 0 }, - { HOTKEY_CAMERA_ROTATE_DOWN, "camera.rotate.down", 0, 0 }, - { HOTKEY_CAMERA_ROTATE_WHEEL_CW, "camera.rotate.wheel.cw", 0, 0 }, - { HOTKEY_CAMERA_ROTATE_WHEEL_CCW, "camera.rotate.wheel.ccw", 0, 0 }, - { HOTKEY_CAMERA_PAN, "camera.pan", MOUSE_MIDDLE, 0 }, - { HOTKEY_CAMERA_PAN_KEYBOARD, "camera.pan.keyboard", 0, 0 }, - { HOTKEY_CAMERA_LEFT, "camera.left", SDLK_LEFT, 0 }, - { HOTKEY_CAMERA_RIGHT, "camera.right", SDLK_RIGHT, 0 }, - { HOTKEY_CAMERA_UP, "camera.up", SDLK_UP, 0 }, - { HOTKEY_CAMERA_DOWN, "camera.down", SDLK_DOWN, 0 }, - { HOTKEY_CAMERA_CINEMA_ADD, "camera.cinema.add", SDLK_l, 0 }, - { HOTKEY_CAMERA_CINEMA_DELETE, "camera.cinema.delete", SDLK_u, 0 }, - { HOTKEY_CAMERA_CINEMA_DELETE_ALL, "camera.cinema.delete.all", SDLK_r, 0 }, - { HOTKEY_CAMERA_CINEMA_QUEUE, "camera.cinema.write", SDLK_i, 0}, - { HOTKEY_CONSOLE_TOGGLE, "console.toggle", SDLK_F1, 0 }, - { HOTKEY_CONSOLE_COPY, "console.copy", 0, 0 }, - { HOTKEY_CONSOLE_PASTE, "console.paste", 0, 0 }, - { HOTKEY_SELECTION_ADD, "selection.add", SDLK_LSHIFT, SDLK_RSHIFT }, - { HOTKEY_SELECTION_REMOVE, "selection.remove", SDLK_LCTRL, SDLK_RCTRL }, - { HOTKEY_SELECTION_GROUP_0, "selection.group.0", SDLK_0, 0, }, - { HOTKEY_SELECTION_GROUP_1, "selection.group.1", SDLK_1, 0, }, - { HOTKEY_SELECTION_GROUP_2, "selection.group.2", SDLK_2, 0, }, - { HOTKEY_SELECTION_GROUP_3, "selection.group.3", SDLK_3, 0, }, - { HOTKEY_SELECTION_GROUP_4, "selection.group.4", SDLK_4, 0, }, - { HOTKEY_SELECTION_GROUP_5, "selection.group.5", SDLK_5, 0, }, - { HOTKEY_SELECTION_GROUP_6, "selection.group.6", SDLK_6, 0, }, - { HOTKEY_SELECTION_GROUP_7, "selection.group.7", SDLK_7, 0, }, - { HOTKEY_SELECTION_GROUP_8, "selection.group.8", SDLK_8, 0, }, - { HOTKEY_SELECTION_GROUP_9, "selection.group.9", SDLK_9, 0, }, - { HOTKEY_SELECTION_GROUP_10, "selection.group.10", 0, 0, }, - { HOTKEY_SELECTION_GROUP_11, "selection.group.11", 0, 0, }, - { HOTKEY_SELECTION_GROUP_12, "selection.group.12", 0, 0, }, - { HOTKEY_SELECTION_GROUP_13, "selection.group.13", 0, 0, }, - { HOTKEY_SELECTION_GROUP_14, "selection.group.14", 0, 0, }, - { HOTKEY_SELECTION_GROUP_15, "selection.group.15", 0, 0, }, - { HOTKEY_SELECTION_GROUP_16, "selection.group.16", 0, 0, }, - { HOTKEY_SELECTION_GROUP_17, "selection.group.17", 0, 0, }, - { HOTKEY_SELECTION_GROUP_18, "selection.group.18", 0, 0, }, - { HOTKEY_SELECTION_GROUP_19, "selection.group.19", 0, 0, }, - { HOTKEY_SELECTION_GROUP_ADD, "selection.group.add", SDLK_LSHIFT, SDLK_RSHIFT }, - { HOTKEY_SELECTION_GROUP_SAVE, "selection.group.save", SDLK_LCTRL, SDLK_RCTRL }, - { HOTKEY_SELECTION_GROUP_SNAP, "selection.group.snap", SDLK_LALT, SDLK_RALT }, - { HOTKEY_SELECTION_SNAP, "selection.snap", SDLK_HOME, 0 }, - { HOTKEY_ORDER_QUEUE, "order.queue", SDLK_LSHIFT, SDLK_RSHIFT }, - { HOTKEY_CONTEXTORDER_NEXT, "contextorder.next", SDLK_RIGHTBRACKET, 0 }, - { HOTKEY_CONTEXTORDER_PREVIOUS, "contextorder.previous", SDLK_LEFTBRACKET, 0 }, - { HOTKEY_HIGHLIGHTALL, "highlightall", SDLK_o, 0 }, - { HOTKEY_PROFILE_TOGGLE, "profile.toggle", SDLK_F11, 0 }, - { HOTKEY_PROFILE_SAVE, "profile.save", 0, 0 }, - { HOTKEY_PLAYMUSIC, "playmusic", SDLK_p, 0 }, - { HOTKEY_PAUSE, "pause", SDLK_PAUSE, 0 }, - { HOTKEY_SPEED_INCREASE, "speed.increase", 0, 0 }, - { HOTKEY_SPEED_DECREASE, "speed.decrease", 0, 0 }, - { HOTKEY_KILL, "killUnit", 0, 0 }, - { HOTKEY_CHAT, "chat", 0, 0 } -}; - -/* SDL-type ends */ - -/* GUI-type */ - -struct SHotkeyMappingGui -{ - CStr mapsTo; - bool negation; - std::vector requires; - SHotkeyMappingGui() : mapsTo(-1) {} -}; - -typedef std::vector GuiMapping; - -// A mapping of keycodes onto sets of hotkey name strings (e.g. '[hotkey.]camera.reset') -static GuiMapping hotkeyMapGui[HK_MAX_KEYCODES]; - -typedef std::vector GuiObjectList; // A list of GUI objects -typedef std::map GuiHotkeyMap; // A mapping of name strings to lists of GUI objects that they trigger - -static GuiHotkeyMap guiHotkeyMap; - -// Look up a 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. -static void setBindings( const CStr& hotkeyName, int integerMapping = -1 ) +static void LoadConfigBindings() { - CConfigValueSet* binding = g_ConfigDB.GetValues( CFG_USER, CStr( "hotkey." ) + hotkeyName ); - if( binding ) + std::vector > bindings = g_ConfigDB.GetValuesWithPrefix( CFG_USER, CStr( "hotkey." )); + + CParser multikeyParser; + multikeyParser.InputTaskType( "multikey", "<[~$arg(_negate)]$value_+_>_[~$arg(_negate)]$value" ); + + for( std::vector >::iterator bindingsIt = bindings.begin(); bindingsIt != bindings.end(); ++bindingsIt ) { - int mapping; - - CConfigValueSet::iterator it; - CParser multikeyParser; - multikeyParser.InputTaskType( "multikey", "<[!$arg(_negate)][~$arg(_negate)]$value_+_>_[!$arg(_negate)][~$arg(_negate)]$value" ); + std::string hotkeyName = bindingsIt->first.substr(7); // strip the "hotkey." prefix - // Iterate through the bindings for this event... - - for( it = binding->begin(); it != binding->end(); it++ ) + for( CConfigValueSet::iterator it = bindingsIt->second.begin(); it != bindingsIt->second.end(); ++it ) { std::string hotkey; if( it->GetString( hotkey ) ) { - std::vector keyCombination; + std::vector keyCombination; CParserLine multikeyIdentifier; multikeyIdentifier.ParseString( multikeyParser, hotkey ); @@ -191,7 +81,7 @@ static void setBindings( const CStr& hotkeyName, int integerMapping = -1 ) for( size_t t = 0; t < multikeyIdentifier.GetArgCount(); t++ ) { - + if( multikeyIdentifier.GetArgString( (int)t, hotkey ) ) { if( hotkey == "_negate" ) @@ -201,123 +91,81 @@ static void setBindings( const CStr& hotkeyName, int integerMapping = -1 ) } // Attempt decode as key name - mapping = FindKeyCode( hotkey ); + int mapping = FindKeyCode( hotkey ); // Attempt to decode as a negation of a keyname // Yes, it's going a bit far, perhaps. // Too powerful for most uses, probably. // However, it got some hardcoding out of the engine. // Thus it makes me happy. - - if( !mapping ) - if( !it->GetInt( mapping ) ) // Attempt decode as key code - { - LOG(CLogger::Warning, L"hotkey", L"Couldn't map '%hs'", hotkey.c_str() ); - continue; - } - if( negateNext ) mapping |= HOTKEY_NEGATION_FLAG; + if( !mapping ) + { + LOGWARNING(L"Hotkey mapping used invalid key '%hs'", hotkey.c_str() ); + continue; + } + + SKey key = { (SDLKey)mapping, negateNext }; + keyCombination.push_back(key); negateNext = false; - keyCombination.push_back( mapping ); } } - - std::vector::iterator itKey, itKey2; - SHotkeyMapping bindCode; - SHotkeyMappingGui bindName; + std::vector::iterator itKey, itKey2; for( itKey = keyCombination.begin(); itKey != keyCombination.end(); itKey++ ) { - bindName.mapsTo = hotkeyName; - bindName.negation = ( ( *itKey & HOTKEY_NEGATION_FLAG ) ? true : false ); - bindName.requires.clear(); - if( integerMapping != -1 ) - { - bindCode.mapsTo = integerMapping; - bindCode.negation = ( ( *itKey & HOTKEY_NEGATION_FLAG ) ? true : false ); - bindCode.requires.clear(); - } + SHotkeyMapping bindCode; + + bindCode.name = hotkeyName; + bindCode.negated = itKey->negated; + for( itKey2 = keyCombination.begin(); itKey2 != keyCombination.end(); itKey2++ ) { // Push any auxiliary keys. if( itKey != itKey2 ) - { - bindName.requires.push_back( *itKey2 ); - if( integerMapping != -1 ) - bindCode.requires.push_back( *itKey2 ); - } + bindCode.requires.push_back( *itKey2 ); } - hotkeyMapGui[*itKey & ~HOTKEY_NEGATION_FLAG].push_back( bindName ); - if( integerMapping != -1 ) - hotkeyMap[*itKey & ~HOTKEY_NEGATION_FLAG].push_back( bindCode ); + g_HotkeyMap[itKey->code].push_back( bindCode ); } } } } - else if( integerMapping != -1 ) - { - SHotkeyMapping bind[2]; - bind[0].mapsTo = integerMapping; - bind[1].mapsTo = integerMapping; - bind[0].requires.clear(); - bind[1].requires.clear(); - bind[0].negation = false; - bind[1].negation = false; - hotkeyMap[ hotkeyInfo[integerMapping].defaultmapping1 ].push_back( bind[0] ); - if( hotkeyInfo[integerMapping].defaultmapping2 ) - hotkeyMap[ hotkeyInfo[integerMapping].defaultmapping2 ].push_back( bind[1] ); - } } + void LoadHotkeys() { InitKeyNameMap(); - for(int i = 0; i < HOTKEY_LAST; i++ ) - setBindings( hotkeyInfo[i].name, i ); - + LoadConfigBindings(); + // Set up the state of the hotkeys given no key is down. // i.e. find those hotkeys triggered by all negations. - std::vector::iterator it; - std::vector::iterator j; - bool allNegated; - - for(int i = 1; i < HK_MAX_KEYCODES; i++ ) + for( std::map::iterator mapIt = g_HotkeyMap.begin(); mapIt != g_HotkeyMap.end(); ++mapIt ) { - for( it = hotkeyMap[i].begin(); it != hotkeyMap[i].end(); it++ ) + KeyMapping& hotkeyMap = mapIt->second; + + for( std::vector::iterator it = hotkeyMap.begin(); it != hotkeyMap.end(); it++ ) { - if( !it->negation ) + if( !it->negated ) continue; - allNegated = true; + bool allNegated = true; - for( j = it->requires.begin(); j != it->requires.end(); j++ ) - if( !( *j & HOTKEY_NEGATION_FLAG ) ) + for( std::vector::iterator j = it->requires.begin(); j != it->requires.end(); j++ ) + if( !j->negated ) allNegated = false; - debug_assert((size_t)it->mapsTo < ARRAY_SIZE(hotkeys)); - if( allNegated ) - hotkeys[it->mapsTo] = true; + g_HotkeyStatus[it->name] = true; } } } -void HotkeyRegisterGuiObject( const CStr& objName, const CStr& hotkeyName ) -{ - GuiObjectList& boundTo = guiHotkeyMap[hotkeyName]; - if( boundTo.empty() ) - { - // Load keybindings from the config file - setBindings( hotkeyName ); - } - boundTo.push_back( objName ); -} - InReaction HotkeyInputHandler( const SDL_Event_* ev ) { int keycode = 0; @@ -377,11 +225,15 @@ InReaction HotkeyInputHandler( const SDL_Event_* ev ) HotkeyInputHandler( &phantom ); } + // Check whether we have any hotkeys registered for this particular keycode + if( g_HotkeyMap.find(keycode) == g_HotkeyMap.end() ) + return( IN_PASS ); + // Inhibit the dispatch of hotkey events caused by printable or control keys // while the console is up. (But allow multiple-key - 'Ctrl+F' events, and whatever // key toggles the console.) - bool consoleCapture = false, isCapturable; + bool consoleCapture = false; if( g_Console->IsActive() && ( ( keycode == 8 ) || ( keycode == 9 ) || ( keycode == 13 ) || /* Editing */ @@ -390,11 +242,6 @@ InReaction HotkeyInputHandler( const SDL_Event_* ev ) ( keycode != SDLK_INSERT ) ) ) ) /* keys (<282) except insert */ consoleCapture = true; - std::vector::iterator it; - std::vector::iterator itGUI; - - SDL_Event hotkeyNotification; - // Here's an interesting bit: // If you have an event bound to, say, 'F', and another to, say, 'Ctrl+F', pressing // 'F' while control is down would normally fire off both. @@ -409,66 +256,53 @@ InReaction HotkeyInputHandler( const SDL_Event_* ev ) // -- KEYDOWN SECTION -- - // SDL-events bit - - size_t closestMap = 0; // avoid "uninitialized" warning + const char* closestMapName = NULL; size_t closestMapMatch = 0; - for( it = hotkeyMap[keycode].begin(); it < hotkeyMap[keycode].end(); it++ ) + for( std::vector::iterator it = g_HotkeyMap[keycode].begin(); it < g_HotkeyMap[keycode].end(); it++ ) { // If a key has been pressed, and this event triggers on it's release, skip it. // Similarly, if the key's been released and the event triggers on a keypress, skip it. - if( it->negation == typeKeyDown ) + if( it->negated == typeKeyDown ) continue; // Check to see if all auxiliary keys are down - std::vector::iterator itKey; bool accept = true; - isCapturable = true; + bool isCapturable = true; - for( itKey = it->requires.begin(); itKey != it->requires.end(); itKey++ ) + for( std::vector::iterator itKey = it->requires.begin(); itKey != it->requires.end(); itKey++ ) { - int keyCode = *itKey & ~HOTKEY_NEGATION_FLAG; // Clear the negation-modifier bit - bool rqdState = ( *itKey & HOTKEY_NEGATION_FLAG ) == 0; + bool rqdState = !itKey->negated; - // debug_assert( !rqdState ); - - if( keyCode < SDLK_LAST ) + if( (int)itKey->code < SDLK_LAST ) { - if( g_keys[keyCode] != rqdState ) accept = false; + if( g_keys[itKey->code] != rqdState ) accept = false; } - else if( keyCode < UNIFIED_SHIFT ) + else if( (int)itKey->code < UNIFIED_SHIFT ) { - if( g_mouse_buttons[keyCode-SDLK_LAST] != rqdState ) accept = false; + if( g_mouse_buttons[itKey->code - SDLK_LAST] != rqdState ) accept = false; } - else if( (size_t)(keyCode-UNIFIED_SHIFT) < ARRAY_SIZE(unified) ) + else if( (int)itKey->code < UNIFIED_LAST ) { - if( unified[keyCode-UNIFIED_SHIFT] != rqdState ) accept = false; - } - else - { - debug_printf(L"keyCode = %i\n", keyCode); - debug_warn(L"keyCode out of range in GUI hotkey requirements"); + if( unified[itKey->code - UNIFIED_SHIFT] != rqdState ) accept = false; } // If this event requires a multiple keypress (with the exception // of shift+key combinations) the console won't inhibit it. - if( rqdState && ( *itKey != SDLK_RSHIFT ) && ( *itKey != SDLK_LSHIFT ) ) + if( rqdState && ( itKey->code != SDLK_RSHIFT ) && ( itKey->code != SDLK_LSHIFT ) ) isCapturable = false; } - if( it->mapsTo == HOTKEY_CONSOLE_TOGGLE ) isCapturable = false; // Because that would be silly. + if( it->name == "console.toggle" ) isCapturable = false; // Because that would be silly. - debug_assert((size_t)it->mapsTo < ARRAY_SIZE(hotkeys)); - if( accept && !( isCapturable && consoleCapture ) ) { - hotkeys[it->mapsTo] = true; + g_HotkeyStatus[it->name] = true; if( it->requires.size() >= closestMapMatch ) { // Only if it's a more precise match, and it either isn't capturable or the console won't capture it. - closestMap = it->mapsTo; + closestMapName = it->name.c_str(); closestMapMatch = it->requires.size() + 1; } } @@ -476,125 +310,51 @@ InReaction HotkeyInputHandler( const SDL_Event_* ev ) if( closestMapMatch ) { + SDL_Event hotkeyNotification; hotkeyNotification.type = SDL_HOTKEYDOWN; - hotkeyNotification.user.code = (int)closestMap; + hotkeyNotification.user.data1 = const_cast(closestMapName); SDL_PushEvent( &hotkeyNotification ); } - // GUI bit... could do with some optimization later. - - CStr closestMapName = -1; - closestMapMatch = 0; - - for( itGUI = hotkeyMapGui[keycode].begin(); itGUI != hotkeyMapGui[keycode].end(); itGUI++ ) - { - // If a key has been pressed, and this event triggers on it's release, skip it. - // Similarly, if the key's been released and the event triggers on a keypress, skip it. - if( itGUI->negation == typeKeyDown ) - continue; - - // Check to see if all auxiliary keys are down - - std::vector::iterator itKey; - bool accept = true; - isCapturable = true; - - for( itKey = itGUI->requires.begin(); itKey != itGUI->requires.end(); itKey++ ) - { - int keyCode = *itKey & ~HOTKEY_NEGATION_FLAG; // Clear the negation-modifier bit - bool rqdState = ( *itKey & HOTKEY_NEGATION_FLAG ) == 0; - - if( keyCode < SDLK_LAST ) - { - if( g_keys[keyCode] != rqdState ) accept = false; - } - else if( keyCode < UNIFIED_SHIFT ) - { - if( g_mouse_buttons[keyCode-SDLK_LAST] != rqdState ) accept = false; - } - else if( (size_t)(keyCode-UNIFIED_SHIFT) < ARRAY_SIZE(unified) ) - { - if( unified[keyCode-UNIFIED_SHIFT] != rqdState ) accept = false; - } - else - { - debug_printf(L"keyCode = %i\n", keyCode); - debug_warn(L"keyCode out of range in GUI hotkey requirements"); - } - - // If this event requires a multiple keypress (with the exception - // of shift+key combinations) the console won't inhibit it. - if( rqdState && ( *itKey != SDLK_RSHIFT ) && ( *itKey != SDLK_LSHIFT ) ) - isCapturable = false; - } - - if( accept && !( isCapturable && consoleCapture ) ) - { - if( itGUI->requires.size() >= closestMapMatch ) - { - closestMapName = itGUI->mapsTo; - closestMapMatch = itGUI->requires.size() + 1; - } - } - } - // GUI-objects bit - // This fragment is an obvious candidate for rewriting when speed becomes an issue. - - if( closestMapMatch ) - { - GuiHotkeyMap::iterator map_it; - GuiObjectList::iterator obj_it; - map_it = guiHotkeyMap.find( closestMapName ); - if( map_it != guiHotkeyMap.end() ) - { - GuiObjectList& targets = map_it->second; - for( obj_it = targets.begin(); obj_it != targets.end(); obj_it++ ) - { - hotkeyNotification.type = SDL_GUIHOTKEYPRESS; - hotkeyNotification.user.data1 = &(*obj_it); - SDL_PushEvent( &hotkeyNotification ); - } - } - } // -- KEYUP SECTION -- - for( it = hotkeyMap[keycode].begin(); it < hotkeyMap[keycode].end(); it++ ) + for( std::vector::iterator it = g_HotkeyMap[keycode].begin(); it < g_HotkeyMap[keycode].end(); it++ ) { // If it's a keydown event, won't cause HotKeyUps in anything that doesn't // use this key negated => skip them // If it's a keyup event, won't cause HotKeyUps in anything that does use // this key negated => skip them too. - if( it->negation != typeKeyDown ) + if( it->negated != typeKeyDown ) continue; // Check to see if all auxiliary keys are down - std::vector::iterator itKey; bool accept = true; - for( itKey = it->requires.begin(); itKey != it->requires.end(); itKey++ ) + for( std::vector::iterator itKey = it->requires.begin(); itKey != it->requires.end(); itKey++ ) { - if( *itKey < SDLK_LAST ) + bool rqdState = !itKey->negated; + + if( (int)itKey->code < SDLK_LAST ) { - if( !g_keys[*itKey] ) accept = false; + if( g_keys[itKey->code] != rqdState ) accept = false; } - else if( *itKey < UNIFIED_SHIFT ) + else if( (int)itKey->code < UNIFIED_SHIFT ) { - if( !g_mouse_buttons[(*itKey)-SDLK_LAST] ) accept = false; + if( g_mouse_buttons[itKey->code - SDLK_LAST] != rqdState ) accept = false; } - else if( *itKey < HOTKEY_NEGATION_FLAG ) + else if( (int)itKey->code < UNIFIED_LAST ) { - if( !unified[(*itKey)-UNIFIED_SHIFT] ) accept = false; + if( unified[itKey->code - UNIFIED_SHIFT] != rqdState ) accept = false; } } - debug_assert((size_t)it->mapsTo < ARRAY_SIZE(hotkeys)); - if( accept ) { - hotkeys[it->mapsTo] = false; + g_HotkeyStatus[it->name] = false; + SDL_Event hotkeyNotification; hotkeyNotification.type = SDL_HOTKEYUP; - hotkeyNotification.user.code = it->mapsTo; + hotkeyNotification.user.data1 = const_cast(it->name.c_str()); SDL_PushEvent( &hotkeyNotification ); } } @@ -602,23 +362,7 @@ InReaction HotkeyInputHandler( const SDL_Event_* ev ) return( IN_PASS ); } -CStr HotkeyGetName(int hotkey) -{ - if (hotkey < 0 || hotkey >= HOTKEY_LAST) - return ""; - return hotkeyInfo[hotkey].name; -} - -bool HotkeyRespondsTo(int hotkey, int sdlkey) -{ - for (KeyMapping::iterator it = hotkeyMap[sdlkey].begin(); it != hotkeyMap[sdlkey].end(); ++it) - if (it->mapsTo == hotkey) - return true; - return false; -} - - bool HotkeyIsPressed(const CStr& keyname) { - return hotkeys[FindKeyCode(keyname)]; + return g_HotkeyStatus[keyname]; } diff --git a/source/ps/Hotkey.h b/source/ps/Hotkey.h index 8e68ce9e0b..127ef8027f 100644 --- a/source/ps/Hotkey.h +++ b/source/ps/Hotkey.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2009 Wildfire Games. +/* Copyright (C) 2010 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -15,25 +15,20 @@ * along with 0 A.D. If not, see . */ -#ifndef PS_HOTKEY_H -#define PS_HOTKEY_H +#ifndef INCLUDED_HOTKEY +#define INCLUDED_HOTKEY -// Hotkey.h -// -// Constant definitions and a couple of exports for the hotkey processor -// -// Hotkeys can be mapped onto SDL events (for use internal to the engine), -// or used to trigger activation of GUI buttons. -// -// Adding a hotkey (SDL event type): -// -// - Define your constant in the enum, just below; -// - Add an entry to hotkeyInfo[], in Hotkey.cpp -// first column is this constant, second is the config string (minus 'hotkey.') it maps to -// third and fourth are the default keys, used if the config file doesn't contain that string. -// - Create an input handler for SDL_HOTKEYDOWN, SDL_HOTKEYUP, or poll the hotkeys[] array. -// For SDL_HOTKEYDOWN, SDL_HOTKEYUP, the constant is passed in as ev->ev.user.code. -// - Add some bindings to the config file. +/** + * @file + * Hotkey system. + * + * Hotkeys consist of a name (an arbitrary string), and a key mapping. + * The names and mappings are loaded from the config system (any + * config setting with the name prefix "hotkey."). + * When a hotkey is pressed or released, SDL_HOTKEYDOWN and SDL_HOTKEYUP + * events are triggered, with the hotkey name stored in ev.user.data1 + * as a const char*. + */ #include "CStr.h" #include "lib/input.h" @@ -45,105 +40,10 @@ const int SDL_HOTKEYDOWN = SDL_USEREVENT; const int SDL_HOTKEYUP = SDL_USEREVENT + 1; -const int SDL_GUIHOTKEYPRESS = SDL_USEREVENT + 2; - -enum -{ - HOTKEY_EXIT, - HOTKEY_SCREENSHOT, - HOTKEY_BIGSCREENSHOT, - HOTKEY_WIREFRAME, - HOTKEY_TOGGLEFULLSCREEN, - HOTKEY_CAMERA_RESET, - HOTKEY_CAMERA_FOLLOW, - HOTKEY_CAMERA_ZOOM_IN, - HOTKEY_CAMERA_ZOOM_OUT, - HOTKEY_CAMERA_ZOOM_WHEEL_IN, - HOTKEY_CAMERA_ZOOM_WHEEL_OUT, - HOTKEY_CAMERA_ROTATE_CW, - HOTKEY_CAMERA_ROTATE_CCW, - HOTKEY_CAMERA_ROTATE_UP, - HOTKEY_CAMERA_ROTATE_DOWN, - HOTKEY_CAMERA_ROTATE_WHEEL_CW, - HOTKEY_CAMERA_ROTATE_WHEEL_CCW, - HOTKEY_CAMERA_PAN, - HOTKEY_CAMERA_PAN_KEYBOARD, - HOTKEY_CAMERA_LEFT, - HOTKEY_CAMERA_RIGHT, - HOTKEY_CAMERA_UP, - HOTKEY_CAMERA_DOWN, - HOTKEY_CAMERA_CINEMA_ADD, - HOTKEY_CAMERA_CINEMA_DELETE, - HOTKEY_CAMERA_CINEMA_DELETE_ALL, - HOTKEY_CAMERA_CINEMA_QUEUE, - HOTKEY_CONSOLE_TOGGLE, - HOTKEY_CONSOLE_COPY, - HOTKEY_CONSOLE_PASTE, - HOTKEY_SELECTION_ADD, - HOTKEY_SELECTION_REMOVE, - HOTKEY_SELECTION_GROUP_0, - HOTKEY_SELECTION_GROUP_1, - HOTKEY_SELECTION_GROUP_2, - HOTKEY_SELECTION_GROUP_3, - HOTKEY_SELECTION_GROUP_4, - HOTKEY_SELECTION_GROUP_5, - HOTKEY_SELECTION_GROUP_6, - HOTKEY_SELECTION_GROUP_7, - HOTKEY_SELECTION_GROUP_8, - HOTKEY_SELECTION_GROUP_9, - HOTKEY_SELECTION_GROUP_10, - HOTKEY_SELECTION_GROUP_11, - HOTKEY_SELECTION_GROUP_12, - HOTKEY_SELECTION_GROUP_13, - HOTKEY_SELECTION_GROUP_14, - HOTKEY_SELECTION_GROUP_15, - HOTKEY_SELECTION_GROUP_16, - HOTKEY_SELECTION_GROUP_17, - HOTKEY_SELECTION_GROUP_18, - HOTKEY_SELECTION_GROUP_19, - HOTKEY_SELECTION_GROUP_ADD, - HOTKEY_SELECTION_GROUP_SAVE, - HOTKEY_SELECTION_GROUP_SNAP, - HOTKEY_SELECTION_SNAP, - HOTKEY_ORDER_QUEUE, - HOTKEY_CONTEXTORDER_NEXT, - HOTKEY_CONTEXTORDER_PREVIOUS, - HOTKEY_HIGHLIGHTALL, - HOTKEY_PROFILE_TOGGLE, - HOTKEY_PROFILE_SAVE, - HOTKEY_PLAYMUSIC, - HOTKEY_PAUSE, - HOTKEY_SPEED_INCREASE, - HOTKEY_SPEED_DECREASE, - HOTKEY_KILL, - HOTKEY_CHAT, - - HOTKEY_LAST, - - HOTKEY_NEGATION_FLAG = 65536 -}; extern void LoadHotkeys(); extern InReaction HotkeyInputHandler(const SDL_Event_* ev); -extern void HotkeyRegisterGuiObject(const CStr& objName, const CStr& hotkeyName); -/** - * @return the name of the specified HOTKEY_*, or empty string if not defined - **/ -extern CStr HotkeyGetName(int hotkey); - -/** - * @return whether the specified HOTKEY_* responds to the specified SDLK_* - * (mainly for the screenshot system to know whether it needs to override - * the printscreen screen). Ignores modifier keys. - **/ -extern bool HotkeyRespondsTo(int hotkey, int sdlkey); - -/** - * @return whether one of the key combinations for the given hotkey is pressed - **/ extern bool HotkeyIsPressed(const CStr& keyname); -extern bool hotkeys[HOTKEY_LAST]; - -#endif // PS_HOTKEY_H +#endif // INCLUDED_HOTKEY diff --git a/source/ps/KeyName.h b/source/ps/KeyName.h index a503b18670..e77b53ae32 100644 --- a/source/ps/KeyName.h +++ b/source/ps/KeyName.h @@ -40,7 +40,8 @@ enum { UNIFIED_CTRL, UNIFIED_ALT, UNIFIED_META, - UNIFIED_SUPER + UNIFIED_SUPER, + UNIFIED_LAST }; #endif // #ifndef INCLUDED_KEYNAME diff --git a/source/ps/ProfileViewer.cpp b/source/ps/ProfileViewer.cpp index 0fb3ae662a..f7787ed86b 100644 --- a/source/ps/ProfileViewer.cpp +++ b/source/ps/ProfileViewer.cpp @@ -286,7 +286,9 @@ InReaction CProfileViewer::Input(const SDL_Event_* ev) break; } case SDL_HOTKEYDOWN: - if( ev->ev.user.code == HOTKEY_PROFILE_TOGGLE ) + std::string hotkey = static_cast(ev->ev.user.data1); + + if( hotkey == "profile.toggle" ) { if (!m->profileVisible) { @@ -319,7 +321,7 @@ InReaction CProfileViewer::Input(const SDL_Event_* ev) } return( IN_HANDLED ); } - else if( ev->ev.user.code == HOTKEY_PROFILE_SAVE ) + else if( hotkey == "profile.save" ) { SaveToFile(); return( IN_HANDLED );