Skip to content

Commit

Permalink
keybinds add modifiers matcher
Browse files Browse the repository at this point in the history
  • Loading branch information
malytomas committed Jan 30, 2025
1 parent fb25e40 commit e52da8a
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 31 deletions.
11 changes: 7 additions & 4 deletions sources/include/cage-engine/keybinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ namespace cage
{
None = 0,
Keyboard = 1 << 0,
Mouse = 1 << 1,
WheelRoll = 1 << 2, // tracks wheel up and down as separate events (as if buttons)
WheelScroll = 1 << 3, // tracks wheel uniformly as one event
Modifiers = 1 << 1,
Mouse = 1 << 2,
WheelRoll = 1 << 3, // tracks wheel up and down as separate events (as if buttons)
WheelScroll = 1 << 4, // tracks wheel uniformly as one event
// todo controller
};
GCHL_ENUM_BITS(KeybindDevicesFlags);
Expand All @@ -58,7 +59,6 @@ namespace cage
EngineTick = 1 << 9,
};
GCHL_ENUM_BITS(KeybindModesFlags);
CAGE_ENGINE_API KeybindModesFlags keybindMode(const GenericInput &in);

struct CAGE_ENGINE_API KeybindCreateConfig
{
Expand Down Expand Up @@ -90,6 +90,9 @@ namespace cage

CAGE_ENGINE_API Holder<Ini> keybindsExport();
CAGE_ENGINE_API void keybindsImport(const Ini *ini);

CAGE_ENGINE_API KeybindModesFlags inputKeybindMode(const GenericInput &in);
CAGE_ENGINE_API ModifiersFlags inputModifiersFlags(const GenericInput &in);
}

#endif
95 changes: 68 additions & 27 deletions sources/libengine/keybinds.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ namespace cage
CAGE_FORCE_INLINE KeybindModesFlags match(const GenericInput &input) const
{
if (input.has<T>())
return matchImpl(input.get<T>(), keybindMode(input));
return matchImpl(input.get<T>(), inputKeybindMode(input));
return KeybindModesFlags::None;
}

Expand All @@ -63,6 +63,18 @@ namespace cage
CAGE_FORCE_INLINE String value() const { return finishName(Stringizer() + getModifiersNames(requiredFlags) + " " + getKeyName(key)); }
};

struct ModifiersMatcher : public MatcherBase
{
CAGE_FORCE_INLINE KeybindModesFlags match(const GenericInput &input) const
{
// todo this is wrong
// i need to explicitly check for key press and release of the particular keys
return checkFlags(inputModifiersFlags(input)) ? KeybindModesFlags::KeyPress : KeybindModesFlags::KeyRelease;
}

CAGE_FORCE_INLINE String value() const { return finishName(getModifiersNames(requiredFlags)); }
};

struct MouseMatcher : public MatcherBase
{
MouseButtonsFlags button = MouseButtonsFlags::None;
Expand All @@ -78,7 +90,7 @@ namespace cage
CAGE_FORCE_INLINE KeybindModesFlags match(const GenericInput &input) const
{
if (input.has<T>())
return matchImpl(input.get<T>(), keybindMode(input));
return matchImpl(input.get<T>(), inputKeybindMode(input));
return KeybindModesFlags::None;
}

Expand Down Expand Up @@ -121,7 +133,7 @@ namespace cage
}
};

using Matcher = std::variant<std::monostate, KeyboardMatcher, MouseMatcher, WheelMatcher>;
using Matcher = std::variant<std::monostate, KeyboardMatcher, ModifiersMatcher, MouseMatcher, WheelMatcher>;

CAGE_FORCE_INLINE KeybindModesFlags matches(const GenericInput &input, const Matcher &matcher)
{
Expand Down Expand Up @@ -193,6 +205,8 @@ namespace cage

CAGE_FORCE_INLINE void make(const GenericInput &input)
{
if (config.devices == KeybindDevicesFlags::Modifiers)
return makeModifiersMatcher(input);
make<input::KeyPress>(input);
make<input::KeyRepeat>(input);
make<input::KeyRelease>(input);
Expand All @@ -201,6 +215,16 @@ namespace cage
make<input::MouseRelease>(input);
make<input::MouseWheel>(input);
}

CAGE_FORCE_INLINE void makeModifiersMatcher(const GenericInput &input)
{
if (input.has<input::KeyPress>())
{
const input::KeyPress in = input.get<input::KeyPress>();
if (none(in.mods & config.forbiddenFlags))
result = ModifiersMatcher{ base(in.mods) };
}
}
};

Matcher makeMatcher(const KeybindCreateConfig &config, const GenericInput &input)
Expand Down Expand Up @@ -228,6 +252,7 @@ namespace cage
CAGE_ASSERT(none(config.requiredFlags & config.forbiddenFlags));
CAGE_ASSERT(any(config.devices));
CAGE_ASSERT(none(config.devices & KeybindDevicesFlags::WheelRoll) || none(config.devices & KeybindDevicesFlags::WheelScroll)); // these two flags are mutually exclusive
CAGE_ASSERT(none(config.devices & KeybindDevicesFlags::Modifiers) || config.devices == KeybindDevicesFlags::Modifiers); // modifiers is exclusive with all other flags
CAGE_ASSERT(any(config.modes));
reset(); // make matchers from the defaults
this->event = event;
Expand Down Expand Up @@ -351,7 +376,7 @@ namespace cage
}
if (in.has<input::KeyRelease>() || in.has<input::KeyRepeat>())
return false;
if (in.has<input::KeyPress>())
if (in.has<input::KeyPress>() && config.devices != KeybindDevicesFlags::Modifiers)
{
const input::KeyPress k = in.get<input::KeyPress>();
switch (k.key)
Expand Down Expand Up @@ -518,29 +543,6 @@ namespace cage
CAGE_ASSERT(impl->matchers.size() == impl->defaults.size());
}

KeybindModesFlags keybindMode(const GenericInput &in)
{
if (in.has<input::KeyPress>())
return KeybindModesFlags::KeyPress;
if (in.has<input::KeyRepeat>())
return KeybindModesFlags::KeyRepeat;
if (in.has<input::KeyRelease>())
return KeybindModesFlags::KeyRelease;
if (in.has<input::MousePress>())
return KeybindModesFlags::MousePress;
if (in.has<input::MouseDoublePress>())
return KeybindModesFlags::MouseDouble;
if (in.has<input::MouseRelease>())
return KeybindModesFlags::MouseRelease;
if (in.has<input::MouseWheel>())
return KeybindModesFlags::WheelScroll;
if (in.has<input::GameTick>())
return KeybindModesFlags::GameTick;
if (in.has<input::EngineTick>())
return KeybindModesFlags::EngineTick;
return KeybindModesFlags::None;
}

Holder<Keybind> newKeybind(const KeybindCreateConfig &config, const GenericInput &defaults, Delegate<bool(const GenericInput &)> event)
{
return newKeybind(config, PointerRange(&defaults, &defaults + 1), event);
Expand Down Expand Up @@ -609,4 +611,43 @@ namespace cage
{
// todo
}

KeybindModesFlags inputKeybindMode(const GenericInput &in)
{
if (in.has<input::KeyPress>())
return KeybindModesFlags::KeyPress;
if (in.has<input::KeyRepeat>())
return KeybindModesFlags::KeyRepeat;
if (in.has<input::KeyRelease>())
return KeybindModesFlags::KeyRelease;
if (in.has<input::MousePress>())
return KeybindModesFlags::MousePress;
if (in.has<input::MouseDoublePress>())
return KeybindModesFlags::MouseDouble;
if (in.has<input::MouseRelease>())
return KeybindModesFlags::MouseRelease;
if (in.has<input::MouseWheel>())
return KeybindModesFlags::WheelScroll;
if (in.has<input::GameTick>())
return KeybindModesFlags::GameTick;
if (in.has<input::EngineTick>())
return KeybindModesFlags::EngineTick;
return KeybindModesFlags::None;
}

namespace
{
template<class T>
CAGE_FORCE_INLINE ModifiersFlags inputModifiersImpl(const GenericInput &input)
{
if (input.has<T>())
return input.get<T>().mods;
return ModifiersFlags::None;
}
}

ModifiersFlags inputModifiersFlags(const GenericInput &in)
{
return inputModifiersImpl<input::KeyPress>(in) | inputModifiersImpl<input::KeyRepeat>(in) | inputModifiersImpl<input::KeyRelease>(in) | inputModifiersImpl<input::MousePress>(in) | inputModifiersImpl<input::MouseDoublePress>(in) | inputModifiersImpl<input::MouseRelease>(in) | inputModifiersImpl<input::MouseWheel>(in) | inputModifiersImpl<input::MouseMove>(in) | inputModifiersImpl<input::MouseRelativeMove>(in);
}
}

0 comments on commit e52da8a

Please sign in to comment.