1
0
mirror of synced 2025-01-11 22:02:17 +01:00
ImHex/lib/libimhex/include/hex/api/shortcut_manager.hpp

305 lines
11 KiB
C++
Raw Normal View History

#pragma once
#include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <functional>
#include <memory>
2023-11-17 14:46:21 +01:00
#include <optional>
#include <set>
#include <string>
#include <GLFW/glfw3.h>
struct ImGuiWindow;
namespace hex {
class View;
2024-12-15 21:44:43 +01:00
enum class Keys : u32 {
2022-02-01 22:09:44 +01:00
Space = GLFW_KEY_SPACE,
Apostrophe = GLFW_KEY_APOSTROPHE,
Comma = GLFW_KEY_COMMA,
Minus = GLFW_KEY_MINUS,
Period = GLFW_KEY_PERIOD,
Slash = GLFW_KEY_SLASH,
Num0 = GLFW_KEY_0,
Num1 = GLFW_KEY_1,
Num2 = GLFW_KEY_2,
Num3 = GLFW_KEY_3,
Num4 = GLFW_KEY_4,
Num5 = GLFW_KEY_5,
Num6 = GLFW_KEY_6,
Num7 = GLFW_KEY_7,
Num8 = GLFW_KEY_8,
Num9 = GLFW_KEY_9,
Semicolon = GLFW_KEY_SEMICOLON,
Equals = GLFW_KEY_EQUAL,
A = GLFW_KEY_A,
B = GLFW_KEY_B,
C = GLFW_KEY_C,
D = GLFW_KEY_D,
E = GLFW_KEY_E,
F = GLFW_KEY_F,
G = GLFW_KEY_G,
H = GLFW_KEY_H,
I = GLFW_KEY_I,
J = GLFW_KEY_J,
K = GLFW_KEY_K,
L = GLFW_KEY_L,
M = GLFW_KEY_M,
N = GLFW_KEY_N,
O = GLFW_KEY_O,
P = GLFW_KEY_P,
Q = GLFW_KEY_Q,
R = GLFW_KEY_R,
S = GLFW_KEY_S,
T = GLFW_KEY_T,
U = GLFW_KEY_U,
V = GLFW_KEY_V,
W = GLFW_KEY_W,
X = GLFW_KEY_X,
Y = GLFW_KEY_Y,
Z = GLFW_KEY_Z,
LeftBracket = GLFW_KEY_LEFT_BRACKET,
Backslash = GLFW_KEY_BACKSLASH,
RightBracket = GLFW_KEY_RIGHT_BRACKET,
GraveAccent = GLFW_KEY_GRAVE_ACCENT,
World1 = GLFW_KEY_WORLD_1,
World2 = GLFW_KEY_WORLD_2,
Escape = GLFW_KEY_ESCAPE,
Enter = GLFW_KEY_ENTER,
Tab = GLFW_KEY_TAB,
Backspace = GLFW_KEY_BACKSPACE,
Insert = GLFW_KEY_INSERT,
Delete = GLFW_KEY_DELETE,
Right = GLFW_KEY_RIGHT,
Left = GLFW_KEY_LEFT,
Down = GLFW_KEY_DOWN,
Up = GLFW_KEY_UP,
PageUp = GLFW_KEY_PAGE_UP,
PageDown = GLFW_KEY_PAGE_DOWN,
Home = GLFW_KEY_HOME,
End = GLFW_KEY_END,
CapsLock = GLFW_KEY_CAPS_LOCK,
ScrollLock = GLFW_KEY_SCROLL_LOCK,
NumLock = GLFW_KEY_NUM_LOCK,
PrintScreen = GLFW_KEY_PRINT_SCREEN,
Pause = GLFW_KEY_PAUSE,
F1 = GLFW_KEY_F1,
F2 = GLFW_KEY_F2,
F3 = GLFW_KEY_F3,
F4 = GLFW_KEY_F4,
F5 = GLFW_KEY_F5,
F6 = GLFW_KEY_F6,
F7 = GLFW_KEY_F7,
F8 = GLFW_KEY_F8,
F9 = GLFW_KEY_F9,
F10 = GLFW_KEY_F10,
F11 = GLFW_KEY_F11,
F12 = GLFW_KEY_F12,
F13 = GLFW_KEY_F13,
F14 = GLFW_KEY_F14,
F15 = GLFW_KEY_F15,
F16 = GLFW_KEY_F16,
F17 = GLFW_KEY_F17,
F18 = GLFW_KEY_F18,
F19 = GLFW_KEY_F19,
F20 = GLFW_KEY_F20,
F21 = GLFW_KEY_F21,
F22 = GLFW_KEY_F22,
F23 = GLFW_KEY_F23,
F24 = GLFW_KEY_F24,
F25 = GLFW_KEY_F25,
KeyPad0 = GLFW_KEY_KP_0,
KeyPad1 = GLFW_KEY_KP_1,
KeyPad2 = GLFW_KEY_KP_2,
KeyPad3 = GLFW_KEY_KP_3,
KeyPad4 = GLFW_KEY_KP_4,
KeyPad5 = GLFW_KEY_KP_5,
KeyPad6 = GLFW_KEY_KP_6,
KeyPad7 = GLFW_KEY_KP_7,
KeyPad8 = GLFW_KEY_KP_8,
KeyPad9 = GLFW_KEY_KP_9,
KeyPadDecimal = GLFW_KEY_KP_DECIMAL,
KeyPadDivide = GLFW_KEY_KP_DIVIDE,
KeyPadMultiply = GLFW_KEY_KP_MULTIPLY,
KeyPadSubtract = GLFW_KEY_KP_SUBTRACT,
2022-02-01 22:09:44 +01:00
KeyPadAdd = GLFW_KEY_KP_ADD,
KeyPadEnter = GLFW_KEY_KP_ENTER,
KeyPadEqual = GLFW_KEY_KP_EQUAL,
Menu = GLFW_KEY_MENU,
};
class Key {
public:
2023-11-17 14:46:21 +01:00
constexpr Key() = default;
constexpr Key(Keys key) : m_key(static_cast<u32>(key)) { }
auto operator<=>(const Key &) const = default;
2023-12-19 13:10:25 +01:00
[[nodiscard]] constexpr u32 getKeyCode() const { return m_key; }
private:
2023-11-17 14:46:21 +01:00
u32 m_key = 0;
};
constexpr static auto CTRL = Key(static_cast<Keys>(0x0100'0000));
constexpr static auto ALT = Key(static_cast<Keys>(0x0200'0000));
constexpr static auto SHIFT = Key(static_cast<Keys>(0x0400'0000));
constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000));
constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000));
constexpr static auto AllowWhileTyping = Key(static_cast<Keys>(0x2000'0000));
#if defined (OS_MACOS)
constexpr static auto CTRLCMD = SUPER;
#else
constexpr static auto CTRLCMD = CTRL;
#endif
class Shortcut {
public:
Shortcut() = default;
Shortcut(Keys key) : m_keys({ key }) { }
2023-11-17 14:46:21 +01:00
explicit Shortcut(std::set<Key> keys) : m_keys(std::move(keys)) { }
Shortcut(const Shortcut &other) = default;
Shortcut(Shortcut &&) noexcept = default;
Shortcut& operator=(const Shortcut &other) = default;
Shortcut& operator=(Shortcut &&) noexcept = default;
2023-11-10 20:47:08 +01:00
constexpr static inline auto None = Keys(0);
Shortcut operator+(const Key &other) const {
Shortcut result = *this;
result.m_keys.insert(other);
return result;
}
Shortcut &operator+=(const Key &other) {
2023-12-19 13:10:25 +01:00
m_keys.insert(other);
return *this;
}
bool operator<(const Shortcut &other) const {
2024-12-15 21:44:43 +01:00
u64 left = 0;
for (const auto &key : m_keys)
left |= key.getKeyCode();
u64 right = 0;
for (const auto &key : other.m_keys)
right |= key.getKeyCode();
return left < right;
}
bool operator==(const Shortcut &other) const {
2024-12-15 21:44:43 +01:00
u64 left = 0;
for (const auto &key : m_keys)
left |= key.getKeyCode();
2024-12-15 21:44:43 +01:00
u64 right = 0;
for (const auto &key : other.m_keys)
right |= key.getKeyCode();
2024-12-15 21:44:43 +01:00
return left == right;
}
bool isLocal() const {
2023-12-19 13:10:25 +01:00
return m_keys.contains(CurrentView);
}
2024-12-15 21:44:43 +01:00
std::string toString() const;
2023-12-19 13:10:25 +01:00
const std::set<Key>& getKeys() const { return m_keys; }
2023-11-17 14:46:21 +01:00
private:
friend Shortcut operator+(const Key &lhs, const Key &rhs);
std::set<Key> m_keys;
};
inline Shortcut operator+(const Key &lhs, const Key &rhs) {
Shortcut result;
result.m_keys = { lhs, rhs };
return result;
}
/**
* @brief The ShortcutManager handles global and view-specific shortcuts.
* New shortcuts can be constructed using the + operator on Key objects. For example: CTRL + ALT + Keys::A
*/
class ShortcutManager {
public:
2023-11-17 14:46:21 +01:00
using Callback = std::function<void()>;
struct ShortcutEntry {
Shortcut shortcut;
std::vector<UnlocalizedString> unlocalizedName;
2023-11-17 14:46:21 +01:00
Callback callback;
};
/**
* @brief Add a global shortcut. Global shortcuts can be triggered regardless of what view is currently focused
* @param shortcut The shortcut to add.
2023-11-17 14:46:21 +01:00
* @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered.
*/
static void addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
/**
* @brief Add a view-specific shortcut. View-specific shortcuts can only be triggered when the specified view is focused.
* @param view The view to add the shortcut to.
* @param shortcut The shortcut to add.
2023-11-17 14:46:21 +01:00
* @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered.
*/
static void addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
/**
* @brief Process a key event. This should be called from the main loop.
* @param currentView Current view to process
* @param ctrl Whether the CTRL key is pressed
* @param alt Whether the ALT key is pressed
* @param shift Whether the SHIFT key is pressed
* @param super Whether the SUPER key is pressed
* @param focused Whether the current view is focused
* @param keyCode The key code of the key that was pressed
*/
static void process(const View *currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode);
/**
* @brief Process a key event. This should be called from the main loop.
* @param ctrl Whether the CTRL key is pressed
* @param alt Whether the ALT key is pressed
* @param shift Whether the SHIFT key is pressed
* @param super Whether the SUPER key is pressed
* @param keyCode The key code of the key that was pressed
*/
static void processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode);
/**
* @brief Clear all shortcuts
*/
static void clearShortcuts();
2023-11-17 14:46:21 +01:00
static void resumeShortcuts();
static void pauseShortcuts();
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
2023-11-17 14:46:21 +01:00
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
2023-12-27 16:33:49 +01:00
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(const View *view);
2023-11-17 14:46:21 +01:00
[[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view = nullptr);
};
}