diff options
author | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
---|---|---|
committer | Kae <80987908+Novaenia@users.noreply.github.com> | 2023-06-20 14:33:09 +1000 |
commit | 6352e8e3196f78388b6c771073f9e03eaa612673 (patch) | |
tree | e23772f79a7fbc41bc9108951e9e136857484bf4 /source/windowing/StarKeyBindings.cpp | |
parent | 6741a057e5639280d85d0f88ba26f000baa58f61 (diff) |
everything everywhere
all at once
Diffstat (limited to 'source/windowing/StarKeyBindings.cpp')
-rw-r--r-- | source/windowing/StarKeyBindings.cpp | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/source/windowing/StarKeyBindings.cpp b/source/windowing/StarKeyBindings.cpp new file mode 100644 index 0000000..e93a1af --- /dev/null +++ b/source/windowing/StarKeyBindings.cpp @@ -0,0 +1,212 @@ +#include "StarKeyBindings.hpp" +#include "StarRoot.hpp" +#include "StarConfiguration.hpp" +#include "StarLogging.hpp" +#include "StarJsonExtra.hpp" + +#include <bitset> + +namespace Star { + +HashMap<Key, KeyMod> const KeyChordMods{ + {Key::LShift, KeyMod::LShift}, + {Key::RShift, KeyMod::RShift}, + {Key::LCtrl, KeyMod::LCtrl}, + {Key::RCtrl, KeyMod::RCtrl}, + {Key::LAlt, KeyMod::LAlt}, + {Key::RAlt, KeyMod::RAlt}, + {Key::LGui, KeyMod::LGui}, + {Key::RGui, KeyMod::RGui}, + {Key::AltGr, KeyMod::AltGr} +}; + +EnumMap<InterfaceAction> const InterfaceActionNames{ + {InterfaceAction::None, "None"}, + {InterfaceAction::PlayerUp, "PlayerUp"}, + {InterfaceAction::PlayerDown, "PlayerDown"}, + {InterfaceAction::PlayerLeft, "PlayerLeft"}, + {InterfaceAction::PlayerRight, "PlayerRight"}, + {InterfaceAction::PlayerJump, "PlayerJump"}, + {InterfaceAction::PlayerMainItem, "PlayerMainItem"}, + {InterfaceAction::PlayerAltItem, "PlayerAltItem"}, + {InterfaceAction::PlayerDropItem, "PlayerDropItem"}, + {InterfaceAction::PlayerInteract, "PlayerInteract"}, + {InterfaceAction::PlayerShifting, "PlayerShifting"}, + {InterfaceAction::PlayerTechAction1, "PlayerTechAction1"}, + {InterfaceAction::PlayerTechAction2, "PlayerTechAction2"}, + {InterfaceAction::PlayerTechAction3, "PlayerTechAction3"}, + {InterfaceAction::EmoteBlabbering, "EmoteBlabbering"}, + {InterfaceAction::EmoteShouting, "EmoteShouting"}, + {InterfaceAction::EmoteHappy, "EmoteHappy"}, + {InterfaceAction::EmoteSad, "EmoteSad"}, + {InterfaceAction::EmoteNeutral, "EmoteNeutral"}, + {InterfaceAction::EmoteLaugh, "EmoteLaugh"}, + {InterfaceAction::EmoteAnnoyed, "EmoteAnnoyed"}, + {InterfaceAction::EmoteOh, "EmoteOh"}, + {InterfaceAction::EmoteOooh, "EmoteOooh"}, + {InterfaceAction::EmoteBlink, "EmoteBlink"}, + {InterfaceAction::EmoteWink, "EmoteWink"}, + {InterfaceAction::EmoteEat, "EmoteEat"}, + {InterfaceAction::EmoteSleep, "EmoteSleep"}, + {InterfaceAction::ShowLabels, "ShowLabels"}, + {InterfaceAction::CameraShift, "CameraShift"}, + {InterfaceAction::TitleBack, "TitleBack"}, + {InterfaceAction::CinematicSkip, "CinematicSkip"}, + {InterfaceAction::CinematicNext, "CinematicNext"}, + {InterfaceAction::GuiClose, "GuiClose"}, + {InterfaceAction::GuiShifting, "GuiShifting"}, + {InterfaceAction::KeybindingClear, "KeybindingClear"}, + {InterfaceAction::KeybindingCancel, "KeybindingCancel"}, + {InterfaceAction::ChatPageUp, "ChatPageUp"}, + {InterfaceAction::ChatPageDown, "ChatPageDown"}, + {InterfaceAction::ChatPreviousLine, "ChatPreviousLine"}, + {InterfaceAction::ChatNextLine, "ChatNextLine"}, + {InterfaceAction::ChatSendLine, "ChatSendLine"}, + {InterfaceAction::ChatBegin, "ChatBegin"}, + {InterfaceAction::ChatBeginCommand, "ChatBeginCommand"}, + {InterfaceAction::ChatStop, "ChatStop"}, + {InterfaceAction::InterfaceShowHelp, "InterfaceShowHelp"}, + {InterfaceAction::InterfaceHideHud, "InterfaceHideHud"}, + {InterfaceAction::InterfaceChangeBarGroup, "InterfaceChangeBarGroup"}, + {InterfaceAction::InterfaceDeselectHands, "InterfaceDeselectHands"}, + {InterfaceAction::InterfaceBar1, "InterfaceBar1"}, + {InterfaceAction::InterfaceBar2, "InterfaceBar2"}, + {InterfaceAction::InterfaceBar3, "InterfaceBar3"}, + {InterfaceAction::InterfaceBar4, "InterfaceBar4"}, + {InterfaceAction::InterfaceBar5, "InterfaceBar5"}, + {InterfaceAction::InterfaceBar6, "InterfaceBar6"}, + {InterfaceAction::InterfaceBar7, "InterfaceBar7"}, + {InterfaceAction::InterfaceBar8, "InterfaceBar8"}, + {InterfaceAction::InterfaceBar9, "InterfaceBar9"}, + {InterfaceAction::InterfaceBar10, "InterfaceBar10"}, + {InterfaceAction::EssentialBar1, "EssentialBar1"}, + {InterfaceAction::EssentialBar2, "EssentialBar2"}, + {InterfaceAction::EssentialBar3, "EssentialBar3"}, + {InterfaceAction::EssentialBar4, "EssentialBar4"}, + {InterfaceAction::InterfaceRepeatCommand, "InterfaceRepeatCommand"}, + {InterfaceAction::InterfaceToggleFullscreen, "InterfaceToggleFullscreen"}, + {InterfaceAction::InterfaceReload, "InterfaceReload"}, + {InterfaceAction::InterfaceEscapeMenu, "InterfaceEscapeMenu"}, + {InterfaceAction::InterfaceInventory, "InterfaceInventory"}, + {InterfaceAction::InterfaceCodex, "InterfaceCodex"}, + {InterfaceAction::InterfaceQuest, "InterfaceQuest"}, + {InterfaceAction::InterfaceCrafting, "InterfaceCrafting"}, +}; + +bool KeyChord::operator<(KeyChord const& rhs) const { + return tie(key, mods) < tie(rhs.key, rhs.mods); +} + +KeyChord inputDescriptorFromJson(Json const& json) { + Key key; + auto type = json.getString("type"); + if (type == "key") { + auto value = json.get("value"); + if (value.isType(Json::Type::String)) { + key = KeyNames.getLeft(value.toString()); + } else if (value.canConvert(Json::Type::Int)) { + key = (Key)value.toUInt(); + } else { + throw StarException::format("Improper key value '%s'", value); + } + } else { + throw StarException::format("Improper bindings type '%s'", type); + } + + KeyMod mods = KeyMod::NoMod; + for (auto mod : json.get("mods").iterateArray()) + mods |= KeyModNames.getLeft(mod.toString()); + + return {key, mods}; +} + +Json inputDescriptorToJson(KeyChord const& chord) { + JsonArray modNames; + for (auto const& p : KeyModNames) { + if ((chord.mods & p.first) != KeyMod::NoMod) + modNames.append(p.second); + } + return JsonObject{ + {"type", "key"}, + {"value", KeyNames.getRight(chord.key)}, + {"mods", modNames} + }; +} + +String printInputDescriptor(KeyChord chord) { + StringList modNames; + for (auto const& p : KeyModNames) { + if ((chord.mods & p.first) != KeyMod::NoMod) + modNames.append(p.second); + } + + return String::joinWith(" + ", modNames.join(" + "), KeyNames.getRight(chord.key)); +} + +KeyBindings::KeyBindings() {} + +KeyBindings::KeyBindings(Json const& json) { + Map<Key, List<pair<KeyMod, InterfaceAction>>> actions; + try { + for (auto const& kvpair : json.iterateObject()) { + InterfaceAction action = InterfaceActionNames.getLeft(kvpair.first); + + for (auto const& input : kvpair.second.iterateArray()) { + try { + auto chord = inputDescriptorFromJson(input); + actions[chord.key].append({chord.mods, action}); + } catch (StarException const& e) { + Logger::warn("Could not load keybinding for %s: %s\n", + InterfaceActionNames.getRight(action), + outputException(e, false)); + } + } + } + + m_actions = move(actions); + } catch (StarException const& e) { + throw StarException(strf("Could not set keybindings from configuration. %s", outputException(e, false))); + } +} + +Set<InterfaceAction> KeyBindings::actions(Key key) const { + return actions(KeyChord{key, KeyMod::NoMod}); +} + +Set<InterfaceAction> KeyBindings::actions(InputEvent const& event) const { + if (auto keyDown = event.ptr<KeyDownEvent>()) + return actions(KeyChord{keyDown->key, keyDown->mods}); + return {}; +} + +Set<InterfaceAction> KeyBindings::actions(KeyChord chord) const { + size_t mostMatchedMods = 0; + Set<InterfaceAction> matching; + for (auto const& pair : m_actions.value(chord.key)) { + // first make sure that all required mods for the binding are held + if ((pair.first & chord.mods) == pair.first) { + // now count the number of mods in the binding + size_t matchedMods = 0; + for (auto modPair : KeyChordMods) { + if ((modPair.second & pair.first) == modPair.second) + ++matchedMods; + } + + if (matchedMods > mostMatchedMods) { + matching.clear(); + mostMatchedMods = matchedMods; + } + + // only activate the binding(s) with the most mods + if (matchedMods == mostMatchedMods) + matching.add(pair.second); + } + } + return matching; +} + +Set<InterfaceAction> KeyBindings::actionsForKey(Key key) const { + return Set<InterfaceAction>::from(m_actions.value(key).transformed([](auto p){ return p.second; })); +} + +} |