diff --git a/src/openrct2-ui/input/KeyboardShortcut.cpp b/src/openrct2-ui/input/KeyboardShortcut.cpp index 4ae4a1f8ca..4aae32669d 100644 --- a/src/openrct2-ui/input/KeyboardShortcut.cpp +++ b/src/openrct2-ui/input/KeyboardShortcut.cpp @@ -1133,6 +1133,8 @@ namespace #pragma endregion +using namespace OpenRCT2::Ui; + void ShortcutManager::RegisterDefaultShortcuts() { // clang-format off @@ -1170,19 +1172,28 @@ void ShortcutManager::RegisterDefaultShortcuts() RegisterShortcut(RegisteredShortcut("interface.zoom_in", STR_SHORTCUT_ZOOM_VIEW_IN, "PAGEDOWN", []() { main_window_zoom(true, false); })); - RegisterShortcut(RegisteredShortcut("interface.rotate_clockwise", STR_SHORTCUT_ROTATE_VIEW_CLOCKWISE, "RETURN", []() { + RegisterShortcut(RegisteredShortcut("interface.rotate_clockwise", STR_SHORTCUT_ROTATE_VIEW_CLOCKWISE, "RETURN", "MOUSE:5", []() { if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) return; rct_window* w = window_get_main(); window_rotate_camera(w, 1); })); - RegisterShortcut(RegisteredShortcut("interface.rotate_anticlockwise", STR_SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE, "SHIFT+RETURN", []() { + RegisterShortcut(RegisteredShortcut("interface.rotate_anticlockwise", STR_SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE, "SHIFT+RETURN", "MOUSE:4", []() { if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) return; rct_window* w = window_get_main(); window_rotate_camera(w, -1); })); + RegisterShortcut(RegisteredShortcut("interface.rotate_construction", STR_SHORTCUT_ROTATE_CONSTRUCTION_OBJECT, "Z", []() { + ShortcutRotateConstructionObject(); + })); + RegisterShortcut(RegisteredShortcut("view.underground_view_toggle", STR_SHORTCUT_UNDERGROUND_VIEW_TOGGLE, "1", []() { + if (gScreenFlags & SCREEN_FLAGS_TITLE_DEMO) + return; + + ToggleViewFlag(VIEWPORT_FLAG_UNDERGROUND_INSIDE); + })); // clang-format on } diff --git a/src/openrct2-ui/input/ShortcutManager.cpp b/src/openrct2-ui/input/ShortcutManager.cpp index 0433ed6747..1749249db9 100644 --- a/src/openrct2-ui/input/ShortcutManager.cpp +++ b/src/openrct2-ui/input/ShortcutManager.cpp @@ -10,9 +10,117 @@ #include "ShortcutManager.h" #include +#include #include -std::string RegisteredShortcut::GetKeyText() +using namespace OpenRCT2::Ui; + +static uint32_t ParseModifier(const std::string_view& text) +{ + if (String::Equals(text, "CTRL", true)) + { + return KMOD_CTRL; + } + else if (String::Equals(text, "LCTRL", true)) + { + return KMOD_LCTRL; + } + else if (String::Equals(text, "RCTRL", true)) + { + return KMOD_RCTRL; + } + else if (String::Equals(text, "SHIFT", true)) + { + return KMOD_SHIFT; + } + else if (String::Equals(text, "LSHIFT", true)) + { + return KMOD_LSHIFT; + } + else if (String::Equals(text, "RSHIFT", true)) + { + return KMOD_RSHIFT; + } + else if (String::Equals(text, "ALT", true)) + { + return KMOD_ALT; + } + else if (String::Equals(text, "LALT", true)) + { + return KMOD_LALT; + } + else if (String::Equals(text, "RALT", true)) + { + return KMOD_RALT; + } + else if (String::Equals(text, "GUI", true)) + { + return KMOD_GUI; + } + else if (String::Equals(text, "LCTRL", true)) + { + return KMOD_LGUI; + } + else if (String::Equals(text, "RGUI", true)) + { + return KMOD_RGUI; + } + else + { + return 0; + } +} + +static uint32_t ParseKey(const std::string_view& text) +{ + char buffer[128]{}; + std::strncpy(buffer, text.data(), sizeof(buffer) - 1); + auto keyCode = SDL_GetKeyFromName(buffer); + if (keyCode != SDLK_UNKNOWN) + { + return keyCode; + } + return 0; +} + +ShortcutInput::ShortcutInput(const std::string_view& value) +{ + uint32_t modifiers = 0; + size_t index = 0; + auto sepIndex = value.find('+', index); + while (sepIndex != std::string::npos) + { + auto text = value.substr(index, sepIndex); + auto mod = ParseModifier(text); + modifiers |= mod; + index = sepIndex + 1; + sepIndex = value.find('+', index); + } + + auto kind = ShortcutInputKind::Keyboard; + auto key = 0u; + auto colonIndex = value.find(':', index); + if (colonIndex != std::string::npos) + { + auto device = value.substr(index, colonIndex - index); + if (device == "MOUSE") + { + auto rem = std::string(value.substr(colonIndex + 1)); + kind = ShortcutInputKind::Mouse; + key = atoi(rem.c_str()); + } + } + else + { + key = ParseKey(value.substr(index)); + } + + Kind = kind; + Modifiers = modifiers; + Key = key; +} + +std::string ShortcutInput::ToString() const { std::string result; AppendModifier(result, "SHIFT", KMOD_LSHIFT, KMOD_RSHIFT); @@ -20,21 +128,68 @@ std::string RegisteredShortcut::GetKeyText() AppendModifier(result, "ALT", KMOD_LALT, KMOD_RALT); AppendModifier(result, "GUI", KMOD_LGUI, KMOD_RGUI); - if (Key & SDLK_SCANCODE_MASK) + if (Kind == ShortcutInputKind::Keyboard) { - auto name = SDL_GetScancodeName(static_cast(Key & ~SDLK_SCANCODE_MASK)); - result += name; + switch (Key) + { + case 0: + break; + case SDLK_BACKSPACE: + result += "BACKSPACE"; + break; + case SDLK_ESCAPE: + result += "ESCAPE"; + break; + case SDLK_SPACE: + result += "SPACE"; + break; + case SDLK_TAB: + result += "TAB"; + break; + case SDLK_RETURN: + result += "RETURN"; + break; + case SDLK_PAGEUP: + result += "PAGE UP"; + break; + case SDLK_PAGEDOWN: + result += "PAGE DOWN"; + break; + default: + if (Key & SDLK_SCANCODE_MASK) + { + auto name = SDL_GetScancodeName(static_cast(Key & ~SDLK_SCANCODE_MASK)); + result += name; + } + else + { + char buffer[8]{}; + utf8_write_codepoint(buffer, Key); + result += buffer; + } + break; + } } - else + else if (Kind == ShortcutInputKind::Mouse) { - char buffer[8]{}; - utf8_write_codepoint(buffer, Key); - result += buffer; + switch (Key) + { + case 0: + result += "LMB"; + break; + case 1: + result += "RMB"; + break; + default: + result += "MOUSE "; + result += std::to_string(Key); + break; + } } return result; } -bool RegisteredShortcut::AppendModifier(std::string& s, const std::string_view& text, uint32_t left, uint32_t right) +bool ShortcutInput::AppendModifier(std::string& s, const std::string_view& text, uint32_t left, uint32_t right) const { if ((Modifiers & (left | right)) == (left | right)) { @@ -59,7 +214,29 @@ bool RegisteredShortcut::AppendModifier(std::string& s, const std::string_view& return false; } +std::string_view RegisteredShortcut::GetGroup() const +{ + auto fullstopIndex = Id.find('.'); + if (fullstopIndex != std::string::npos) + { + return std::string_view(Id.c_str(), fullstopIndex); + } + return {}; +} + +ShortcutManager::ShortcutManager() +{ + RegisterDefaultShortcuts(); +} + void ShortcutManager::RegisterShortcut(RegisteredShortcut&& shortcut) { Shortcuts.push_back(shortcut); } + +static ShortcutManager _shortcutManager; + +ShortcutManager& OpenRCT2::Ui::GetShortcutManager() +{ + return _shortcutManager; +} diff --git a/src/openrct2-ui/input/ShortcutManager.h b/src/openrct2-ui/input/ShortcutManager.h index 525fd84498..480922a264 100644 --- a/src/openrct2-ui/input/ShortcutManager.h +++ b/src/openrct2-ui/input/ShortcutManager.h @@ -16,35 +16,78 @@ #include #include -class RegisteredShortcut +namespace OpenRCT2::Ui { -public: - std::string Id; - rct_string_id LocalisedName = STR_NONE; - uint32_t Modifiers{}; - uint32_t Key{}; - std::function Action; - - RegisteredShortcut() = default; - RegisteredShortcut( - const std::string_view& id, rct_string_id localisedName, const std::string_view& shortcut, - const std::function& action) - : Id(id) - , LocalisedName(localisedName) - , Action(action) + enum class ShortcutInputKind { - } + Keyboard, + Mouse, + }; - std::string GetKeyText(); + struct ShortcutInput + { + public: + ShortcutInputKind Kind{}; + uint32_t Modifiers{}; + uint32_t Key{}; -private: - bool AppendModifier(std::string& s, const std::string_view& text, uint32_t left, uint32_t right); -}; + ShortcutInput() = default; + ShortcutInput(const std::string_view& value); + std::string ToString() const; -class ShortcutManager -{ - std::vector Shortcuts; + private: + bool AppendModifier(std::string& s, const std::string_view& text, uint32_t left, uint32_t right) const; + }; - void RegisterShortcut(RegisteredShortcut&& shortcut); - void RegisterDefaultShortcuts(); -}; + class RegisteredShortcut + { + public: + std::string Id; + rct_string_id LocalisedName = STR_NONE; + std::vector Default; + std::vector Current; + std::function Action; + + RegisteredShortcut() = default; + RegisteredShortcut( + const std::string_view& id, rct_string_id localisedName, const std::string_view& defaultChord, + const std::function& action) + : Id(id) + , LocalisedName(localisedName) + , Default({ defaultChord }) + , Current(Default) + , Action(action) + { + } + + RegisteredShortcut( + const std::string_view& id, rct_string_id localisedName, const std::string_view& defaultChordA, + const std::string_view& defaultChordB, const std::function& action) + : Id(id) + , LocalisedName(localisedName) + , Default({ defaultChordA, defaultChordB }) + , Current(Default) + , Action(action) + { + } + + std::string_view GetGroup() const; + + private: + }; + + class ShortcutManager + { + public: + std::vector Shortcuts; + + ShortcutManager(); + ShortcutManager(const ShortcutManager&) = delete; + + void RegisterShortcut(RegisteredShortcut&& shortcut); + void RegisterDefaultShortcuts(); + }; + + ShortcutManager& GetShortcutManager(); + +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/windows/ShortcutKeyChange.cpp b/src/openrct2-ui/windows/ShortcutKeyChange.cpp index 1e391a4fae..9287ba2081 100644 --- a/src/openrct2-ui/windows/ShortcutKeyChange.cpp +++ b/src/openrct2-ui/windows/ShortcutKeyChange.cpp @@ -45,21 +45,23 @@ static rct_window_event_list window_shortcut_change_events([](auto& events) static rct_string_id CurrentShortcutKeyStringId{}; -rct_window* window_shortcut_change_open(OpenRCT2::Input::Shortcut shortcut, rct_string_id key_string_id) +rct_window* window_shortcut_change_open(const std::string_view& shortcutId) { - // Move this to window_shortcut_change_open - window_close_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); + return nullptr; - // Save the item we are selecting for new window - gKeyboardShortcutChangeId = shortcut; - CurrentShortcutKeyStringId = key_string_id; - - rct_window* w = WindowCreateCentred(WW, WH, &window_shortcut_change_events, WC_CHANGE_KEYBOARD_SHORTCUT, 0); - - w->widgets = window_shortcut_change_widgets; - w->enabled_widgets = (1ULL << WIDX_CLOSE); - WindowInitScrollWidgets(w); - return w; +// // Move this to window_shortcut_change_open +// window_close_by_class(WC_CHANGE_KEYBOARD_SHORTCUT); +// +// // Save the item we are selecting for new window +// gKeyboardShortcutChangeId = selected_key; +// CurrentShortcutKeyStringId = key_string_id; +// +// rct_window* w = window_create_centred(WW, WH, &window_shortcut_change_events, WC_CHANGE_KEYBOARD_SHORTCUT, 0); +// +// w->widgets = window_shortcut_change_widgets; +// w->enabled_widgets = (1ULL << WIDX_CLOSE); +// window_init_scroll_widgets(w); +// return w; } /** diff --git a/src/openrct2-ui/windows/ShortcutKeys.cpp b/src/openrct2-ui/windows/ShortcutKeys.cpp index 6ba58c99ea..4bbc9e8864 100644 --- a/src/openrct2-ui/windows/ShortcutKeys.cpp +++ b/src/openrct2-ui/windows/ShortcutKeys.cpp @@ -7,14 +7,18 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ +#include "../input/ShortcutManager.h" #include "Window.h" #include #include #include +#include #include #include +using namespace OpenRCT2::Ui; + static constexpr const rct_string_id WINDOW_TITLE = STR_SHORTCUTS_TITLE; static constexpr const int32_t WW = 420; static constexpr const int32_t WH = 280; @@ -64,135 +68,67 @@ static rct_window_event_list window_shortcut_events([](auto& events) struct ShortcutStringPair { - Input::Shortcut ShortcutId; - rct_string_id StringId; + size_t ShortcutIndex; + std::string ShortcutId; + rct_string_id StringId = STR_NONE; }; -static const ShortcutStringPair ShortcutList[] = +static std::vector _shortcutList; + +static void InitialiseShortcutList() { - { Input::Shortcut::CloseTopMostWindow, STR_SHORTCUT_CLOSE_TOP_MOST_WINDOW }, - { Input::Shortcut::CloseAllFloatingWindows, STR_SHORTCUT_CLOSE_ALL_FLOATING_WINDOWS }, - { Input::Shortcut::CancelConstructionMode, STR_SHORTCUT_CANCEL_CONSTRUCTION_MODE }, - { Input::Shortcut::RemoveTopBottomToolbarToggle, STR_SHORTCUT_TOGGLE_VISIBILITY_OF_TOOLBARS }, + _shortcutList.clear(); - { Input::Shortcut::Undefined, STR_NONE }, + size_t index = 0; + std::string group; + auto& shortcutManager = GetShortcutManager(); + for (auto& shortcut : shortcutManager.Shortcuts) + { + if (group.empty()) + { + group = shortcut.GetGroup(); + } + else + { + auto groupName = shortcut.GetGroup(); + if (group != groupName) + { + // Add separator + group = groupName; + _shortcutList.emplace_back(); + } + } - { Input::Shortcut::PauseGame, STR_SHORTCUT_PAUSE_GAME }, - { Input::Shortcut::ReduceGameSpeed, STR_SHORTCUT_REDUCE_GAME_SPEED }, - { Input::Shortcut::IncreaseGameSpeed, STR_SHORTCUT_INCREASE_GAME_SPEED }, - { Input::Shortcut::LoadGame, STR_LOAD_GAME }, - { Input::Shortcut::QuickSaveGame, STR_SHORTCUT_QUICK_SAVE_GAME }, - { Input::Shortcut::ShowOptions, STR_SHORTCUT_SHOW_OPTIONS }, - { Input::Shortcut::Screenshot, STR_SHORTCUT_SCREENSHOT }, - { Input::Shortcut::MuteSound, STR_SHORTCUT_MUTE_SOUND }, + ShortcutStringPair ssp; + ssp.ShortcutIndex = index; + ssp.ShortcutId = shortcut.Id; + ssp.StringId = shortcut.LocalisedName; + _shortcutList.push_back(std::move(ssp)); + index++; + } +} - { Input::Shortcut::Undefined, STR_NONE }, +static void FormatKeyChordsString(size_t index, char* dst, size_t dstLen) +{ + if (dstLen == 0) + return; - { Input::Shortcut::OpenCheatWindow, STR_SHORTCUT_OPEN_CHEATS_WINDOW }, - { Input::Shortcut::ToggleClearanceChecks, STR_SHORTCUT_TOGGLE_CLEARANCE_CHECKS }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::ZoomViewOut, STR_SHORTCUT_ZOOM_VIEW_OUT }, - { Input::Shortcut::ZoomViewIn, STR_SHORTCUT_ZOOM_VIEW_IN }, - { Input::Shortcut::RotateViewClockwise, STR_SHORTCUT_ROTATE_VIEW_CLOCKWISE }, - { Input::Shortcut::RotateViewAnticlockwise, STR_SHORTCUT_ROTATE_VIEW_ANTICLOCKWISE }, - { Input::Shortcut::ShowMap, STR_SHORTCUT_SHOW_MAP }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::ClearScenery, STR_SHORTCUT_CLEAR_SCENERY }, - { Input::Shortcut::AdjustLand, STR_SHORTCUT_ADJUST_LAND }, - { Input::Shortcut::AdjustWater, STR_SHORTCUT_ADJUST_WATER }, - { Input::Shortcut::BuildScenery, STR_SHORTCUT_BUILD_SCENERY }, - { Input::Shortcut::BuildPaths, STR_SHORTCUT_BUILD_PATHS }, - { Input::Shortcut::BuildNewRide, STR_SHORTCUT_BUILD_NEW_RIDE }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::ShowFinancialInformation, STR_SHORTCUT_SHOW_FINANCIAL_INFORMATION }, - { Input::Shortcut::ShowResearchInformation, STR_SHORTCUT_SHOW_RESEARCH_INFORMATION }, - { Input::Shortcut::ShowRidesList, STR_SHORTCUT_SHOW_RIDES_LIST }, - { Input::Shortcut::ShowParkInformation, STR_SHORTCUT_SHOW_PARK_INFORMATION }, - { Input::Shortcut::ShowGuestList, STR_SHORTCUT_SHOW_GUEST_LIST }, - { Input::Shortcut::ShowStaffList, STR_SHORTCUT_SHOW_STAFF_LIST }, - { Input::Shortcut::ShowRecentMessages, STR_SHORTCUT_SHOW_RECENT_MESSAGES }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::ShowMultiplayer, STR_SHORTCUT_SHOW_MULTIPLAYER }, - { Input::Shortcut::OpenChatWindow, STR_SEND_MESSAGE }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::UndergroundViewToggle, STR_SHORTCUT_UNDERGROUND_VIEW_TOGGLE }, - { Input::Shortcut::RemoveBaseLandToggle, STR_SHORTCUT_REMOVE_BASE_LAND_TOGGLE }, - { Input::Shortcut::RemoveVerticalLandToggle, STR_SHORTCUT_REMOVE_VERTICAL_LAND_TOGGLE }, - { Input::Shortcut::SeeThroughRidesToggle, STR_SHORTCUT_SEE_THROUGH_RIDES_TOGGLE }, - { Input::Shortcut::SeeThroughSceneryToggle, STR_SHORTCUT_SEE_THROUGH_SCENERY_TOGGLE }, - { Input::Shortcut::SeeThroughPathsToggle, STR_SHORTCUT_SEE_THROUGH_PATHS_TOGGLE }, - { Input::Shortcut::InvisibleSupportsToggle, STR_SHORTCUT_INVISIBLE_SUPPORTS_TOGGLE }, - { Input::Shortcut::InvisiblePeopleToggle, STR_SHORTCUT_INVISIBLE_PEOPLE_TOGGLE }, - { Input::Shortcut::HeightMarksOnLandToggle, STR_SHORTCUT_HEIGHT_MARKS_ON_LAND_TOGGLE }, - { Input::Shortcut::HeightMarksOnRideTracksToggle, STR_SHORTCUT_HEIGHT_MARKS_ON_RIDE_TRACKS_TOGGLE }, - { Input::Shortcut::HeightMarksOnPathsToggle, STR_SHORTCUT_HEIGHT_MARKS_ON_PATHS_TOGGLE }, - { Input::Shortcut::ViewClipping, STR_SHORTCUT_VIEW_CLIPPING }, - { Input::Shortcut::HighlightPathIssuesToggle, STR_SHORTCUT_HIGHLIGHT_PATH_ISSUES_TOGGLE }, - { Input::Shortcut::GridlinesDisplayToggle, STR_SHORTCUT_GRIDLINES_DISPLAY_TOGGLE }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::SceneryPicker, STR_SHORTCUT_OPEN_SCENERY_PICKER }, - { Input::Shortcut::RotateConstructionObject, STR_SHORTCUT_ROTATE_CONSTRUCTION_OBJECT }, - { Input::Shortcut::RideConstructionTurnLeft, STR_SHORTCUT_RIDE_CONSTRUCTION_TURN_LEFT }, - { Input::Shortcut::RideConstructionTurnRight, STR_SHORTCUT_RIDE_CONSTRUCTION_TURN_RIGHT }, - { Input::Shortcut::RideConstructionUseTrackDefault, STR_SHORTCUT_RIDE_CONSTRUCTION_USE_TRACK_DEFAULT }, - { Input::Shortcut::RideConstructionSlopeDown, STR_SHORTCUT_RIDE_CONSTRUCTION_SLOPE_DOWN }, - { Input::Shortcut::RideConstructionSlopeUp, STR_SHORTCUT_RIDE_CONSTRUCTION_SLOPE_UP }, - { Input::Shortcut::RideConstructionChainLiftToggle, STR_SHORTCUT_RIDE_CONSTRUCTION_CHAIN_LIFT_TOGGLE }, - { Input::Shortcut::RideConstructionBankLeft, STR_SHORTCUT_RIDE_CONSTRUCTION_BANK_LEFT }, - { Input::Shortcut::RideConstructionBankRight, STR_SHORTCUT_RIDE_CONSTRUCTION_BANK_RIGHT }, - { Input::Shortcut::RideConstructionPreviousTrack, STR_SHORTCUT_RIDE_CONSTRUCTION_PREVIOUS_TRACK }, - { Input::Shortcut::RideConstructionNextTrack, STR_SHORTCUT_RIDE_CONSTRUCTION_NEXT_TRACK }, - { Input::Shortcut::RideConstructionBuildCurrent, STR_SHORTCUT_RIDE_CONSTRUCTION_BUILD_CURRENT }, - { Input::Shortcut::RideConstructionDemolishCurrent, STR_SHORTCUT_RIDE_CONSTRUCTION_DEMOLISH_CURRENT }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::ScrollMapUp, STR_SHORTCUT_SCROLL_MAP_UP }, - { Input::Shortcut::ScrollMapLeft, STR_SHORTCUT_SCROLL_MAP_LEFT }, - { Input::Shortcut::ScrollMapDown, STR_SHORTCUT_SCROLL_MAP_DOWN }, - { Input::Shortcut::ScrollMapRight, STR_SHORTCUT_SCROLL_MAP_RIGHT }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::WindowedModeToggle, STR_SHORTCUT_WINDOWED_MODE_TOGGLE }, - { Input::Shortcut::ScaleUp, STR_SHORTCUT_SCALE_UP }, - { Input::Shortcut::ScaleDown, STR_SHORTCUT_SCALE_DOWN }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::TileInspector, STR_SHORTCUT_OPEN_TILE_INSPECTOR }, - { Input::Shortcut::InsertCorruptElement, STR_SHORTCUT_INSERT_CORRPUT_ELEMENT }, - { Input::Shortcut::CopyElement, STR_SHORTCUT_COPY_ELEMENT }, - { Input::Shortcut::PasteElement, STR_SHORTCUT_PASTE_ELEMENT }, - { Input::Shortcut::RemoveElement, STR_SHORTCUT_REMOVE_ELEMENT }, - { Input::Shortcut::MoveElementUp, STR_SHORTCUT_MOVE_ELEMENT_UP }, - { Input::Shortcut::MoveElementDown, STR_SHORTCUT_MOVE_ELEMENT_DOWN }, - { Input::Shortcut::IncreaseXCoord, STR_SHORTCUT_INCREASE_X_COORD }, - { Input::Shortcut::DecreaseXCoord, STR_SHORTCUT_DECREASE_X_COORD }, - { Input::Shortcut::IncreaseYCoord, STR_SHORTCUT_INCREASE_Y_COORD }, - { Input::Shortcut::DecreaseYCoord, STR_SHORTCUT_DECREASE_Y_COORD }, - { Input::Shortcut::IncreaseElementHeight, STR_SHORTCUT_INCREASE_ELEM_HEIGHT }, - { Input::Shortcut::DecreaseElementHeight, STR_SHORTCUT_DECREASE_ELEM_HEIGHT }, - - { Input::Shortcut::Undefined, STR_NONE }, - - { Input::Shortcut::AdvanceToNextTick, STR_ADVANCE_TO_NEXT_TICK }, - { Input::Shortcut::PaintOriginalToggle, STR_SHORTCUT_PAINT_ORIGINAL }, - { Input::Shortcut::DebugPaintToggle, STR_SHORTCUT_DEBUG_PAINT_TOGGLE }, -}; -// clang-format on + auto& shortcutManager = GetShortcutManager(); + auto shortcutIndex = _shortcutList[index].ShortcutIndex; + const auto& shortcut = shortcutManager.Shortcuts[shortcutIndex]; + auto numChords = shortcut.Current.size(); + *dst = '\0'; + for (size_t i = 0; i < numChords; i++) + { + const auto &kc = shortcut.Current[i]; + auto szkc = kc.ToString(); + String::Append(dst, dstLen, szkc.c_str()); + if (i < numChords - 1) + { + String::Append(dst, dstLen, " or "); + } + } +} /** * @@ -203,13 +139,15 @@ rct_window* window_shortcut_keys_open() rct_window* w = window_bring_to_front_by_class(WC_KEYBOARD_SHORTCUT_LIST); if (w == nullptr) { + InitialiseShortcutList(); + w = WindowCreateAutoPos(WW, WH, &window_shortcut_events, WC_KEYBOARD_SHORTCUT_LIST, WF_RESIZABLE); w->widgets = window_shortcut_widgets; w->enabled_widgets = (1 << WIDX_CLOSE) | (1 << WIDX_RESET); WindowInitScrollWidgets(w); - w->no_list_items = static_cast(std::size(ShortcutList)); + w->no_list_items = static_cast(_shortcutList.size()); w->selected_list_item = -1; w->min_width = WW; w->min_height = WH; @@ -285,11 +223,11 @@ static void window_shortcut_scrollmousedown(rct_window* w, int32_t scrollIndex, return; // Is this a separator? - if (ShortcutList[selected_item].ShortcutId == Input::Shortcut::Undefined) + if (_shortcutList[selected_item].ShortcutId.empty()) return; - auto& shortcut = ShortcutList[selected_item]; - window_shortcut_change_open(shortcut.ShortcutId, shortcut.StringId); + auto& shortcut = _shortcutList[selected_item]; + window_shortcut_change_open(shortcut.ShortcutId); } /** @@ -335,7 +273,7 @@ static void window_shortcut_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, i } // Is this a separator? - if (ShortcutList[i].ShortcutId == Input::Shortcut::Undefined) + if (_shortcutList[i].ShortcutId.empty()) { const int32_t top = y + (SCROLLABLE_ROW_HEIGHT / 2) - 1; gfx_fill_rect(dpi, { { 0, top }, { scrollWidth, top } }, ColourMapA[w->colours[0]].mid_dark); @@ -353,11 +291,11 @@ static void window_shortcut_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, i const int32_t bindingOffset = scrollWidth - 150; auto ft = Formatter(); ft.Add(STR_SHORTCUT_ENTRY_FORMAT); - ft.Add(ShortcutList[i].StringId); + ft.Add(_shortcutList[i].StringId); DrawTextEllipsised(dpi, { 0, y - 1 }, bindingOffset, format, ft, COLOUR_BLACK); char keybinding[128]; - KeyboardShortcutsFormatString(keybinding, 128, static_cast(ShortcutList[i].ShortcutId)); + FormatKeyChordsString(i, keybinding, sizeof(keybinding)); if (strlen(keybinding) > 0) { diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 02191b58c1..8a62957b27 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -64,7 +64,7 @@ rct_window* window_save_prompt_open(); rct_window* window_server_list_open(); rct_window* window_server_start_open(); #endif -rct_window* window_shortcut_change_open(OpenRCT2::Input::Shortcut shortcut, rct_string_id key_string_id); +rct_window* window_shortcut_change_open(const std::string_view& shortcutId); rct_window* window_shortcut_keys_open(); rct_window* window_staff_list_open(); rct_window* window_staff_open(Peep* peep); diff --git a/src/openrct2/core/String.cpp b/src/openrct2/core/String.cpp index 65cf4687fe..96d26cf746 100644 --- a/src/openrct2/core/String.cpp +++ b/src/openrct2/core/String.cpp @@ -199,7 +199,42 @@ namespace String bool Equals(const std::string& a, const std::string& b, bool ignoreCase) { - return Equals(a.c_str(), b.c_str(), ignoreCase); + if (a.size() != b.size()) + return false; + + if (ignoreCase) + { + for (size_t i = 0; i < a.size(); i++) + { + auto ai = a[i]; + auto bi = b[i]; + + // Only do case insensitive comparison on ASCII characters + if ((ai & 0x80) != 0 || (bi & 0x80) != 0) + { + if (a[i] != b[i]) + { + return false; + } + } + else if (tolower(ai) != tolower(bi)) + { + return false; + } + } + } + else + { + for (size_t i = 0; i < a.size(); i++) + { + if (a[i] != b[i]) + { + return false; + } + } + } + + return true; } bool Equals(const utf8* a, const utf8* b, bool ignoreCase)