Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/windowing/StarKeyBindings.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/windowing/StarKeyBindings.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/windowing/StarKeyBindings.cpp')
-rw-r--r--source/windowing/StarKeyBindings.cpp212
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; }));
+}
+
+}