v1.4.4
This commit is contained in:
commit
9c94d113d3
10260 changed files with 1237388 additions and 0 deletions
212
source/windowing/StarKeyBindings.cpp
Normal file
212
source/windowing/StarKeyBindings.cpp
Normal file
|
@ -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; }));
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue