From a201c80c8bab35cf1af881ee670864340d5687e2 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:04:33 -0500 Subject: [PATCH 01/24] InputSource: add dep to DynamicOutput --- deps/first/Input/xmake.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/first/Input/xmake.lua b/deps/first/Input/xmake.lua index 2411a4804..1e4faf280 100644 --- a/deps/first/Input/xmake.lua +++ b/deps/first/Input/xmake.lua @@ -9,4 +9,4 @@ target(projectName) add_includedirs("include", { public = true }) add_headerfiles("include/**.hpp") - add_files("src/**.cpp") \ No newline at end of file + add_deps("DynamicOutput") From 003ab956acccc3f834d95ef91b0cb43444cbee5b Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:05:57 -0500 Subject: [PATCH 02/24] Input Source: add windows platform code --- deps/first/Input/xmake.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/deps/first/Input/xmake.lua b/deps/first/Input/xmake.lua index 1e4faf280..a1231bea7 100644 --- a/deps/first/Input/xmake.lua +++ b/deps/first/Input/xmake.lua @@ -9,4 +9,12 @@ target(projectName) add_includedirs("include", { public = true }) add_headerfiles("include/**.hpp") + add_files("src/**.cpp|Platform/**.cpp") + add_deps("DynamicOutput") + + if is_plat("windows") then + add_files("src/Platform/Win32AsyncInputSource.cpp") + add_files("src/Platform/GLFW3InputSource.cpp") + add_files("src/Platform/QueueInputSource.cpp") + end From 224f7446b9609c35be0319afc4027c0e1459c564 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:06:48 -0500 Subject: [PATCH 03/24] Input Source: add SPSC ring buffer for key queue --- deps/first/Input/include/Input/RingBuffer.hpp | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 deps/first/Input/include/Input/RingBuffer.hpp diff --git a/deps/first/Input/include/Input/RingBuffer.hpp b/deps/first/Input/include/Input/RingBuffer.hpp new file mode 100644 index 000000000..923d36ec9 --- /dev/null +++ b/deps/first/Input/include/Input/RingBuffer.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +namespace RC::Input +{ + /// SAFETY: This is ONLY a single producer, single consumer lock-free queue + template + struct RingBufferSPSC + { + T m_queue[max_buffer]; + std::atomic m_head{0}; + std::atomic m_tail{0}; + + // tail belongs to the producer + auto push(const T& event) -> bool + { + auto current_tail = m_tail.load(std::memory_order_relaxed); + int next_tail = (current_tail + 1) % max_buffer; + if (next_tail == m_head.load(std::memory_order_acquire)) + { + // Queue is full + return false; + } + + m_queue[current_tail] = event; + m_tail.store(next_tail, std::memory_order_release); + return true; + } + + // head belongs to the consumer + auto pop() -> std::optional + { + auto current_head = m_head.load(std::memory_order_relaxed); + if (current_head == m_tail.load(std::memory_order_acquire)) + { + // Queue is empty + return std::nullopt; + } + + T event = m_queue[current_head]; + m_head.store((current_head + 1) % max_buffer, std::memory_order_release); + return event; + } + }; +} // namespace RC::Input From 033d7718a13aca1001b2d1b0013b6acc3a595f06 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:08:37 -0500 Subject: [PATCH 04/24] Remove old code to refactor Store ModifierKeys in a uint32_t --- deps/first/Input/include/Input/Handler.hpp | 88 +++++++++++++--------- deps/first/Input/include/Input/KeyDef.hpp | 61 +++++++++++++-- 2 files changed, 107 insertions(+), 42 deletions(-) diff --git a/deps/first/Input/include/Input/Handler.hpp b/deps/first/Input/include/Input/Handler.hpp index 784a19890..0eca08862 100644 --- a/deps/first/Input/include/Input/Handler.hpp +++ b/deps/first/Input/include/Input/Handler.hpp @@ -7,6 +7,9 @@ #include #include #include +#include +#include +#include #include #include @@ -15,12 +18,16 @@ namespace RC::Input { using EventCallbackCallable = std::function; - auto is_modifier_key_required(ModifierKey, std::vector) -> bool; + struct InputEvent + { + Key key; + ModifierKeys modifier_keys{}; + }; struct KeyData { - std::vector required_modifier_keys{}; - std::vector callbacks{}; + ModifierKeys required_modifier_keys{}; + EventCallbackCallable callback{}; uint8_t custom_data{}; void* custom_data2{}; bool requires_modifier_keys{}; @@ -32,48 +39,30 @@ namespace RC::Input std::unordered_map> key_data; }; + class PlatformInputSource; class RC_INPUT_API Handler { private: - std::vector m_active_window_classes{}; - std::vector m_key_sets{}; - std::unordered_map m_modifier_keys_down{}; - bool m_any_keys_are_down{}; + // std::vector m_key_sets{}; + KeySet m_key_set{}; bool m_allow_input{true}; + std::array m_subscribed_keys{}; - public: - Handler() = delete; - template - explicit Handler(WindowClasses... window_classes) - { - static_assert(std::conjunction...>::value, "WindowClasses must be of type const wchar_t*"); - - m_modifier_keys_down.emplace(ModifierKey::SHIFT, false); - m_modifier_keys_down.emplace(ModifierKey::CONTROL, false); - m_modifier_keys_down.emplace(ModifierKey::ALT, false); - - register_window_classes(window_classes...); - } + std::shared_ptr m_platform_handler; + std::mutex m_event_mutex; - private: - template - auto register_window_classes(WindowClass window_class) -> void - { - m_active_window_classes.emplace_back(window_class); - } - - template - auto register_window_classes(WindowClass window_class, WindowClasses... window_classes) -> void - { - m_active_window_classes.emplace_back(window_class); - register_window_classes(window_classes...); - } - - auto are_modifier_keys_down(const std::vector&) -> bool; - auto is_program_focused() -> bool; + public: + Handler(){}; + // Input source and event processing public: + auto set_input_source(std::string source) -> bool; auto process_event() -> void; + + // Interfaces for UE4SS and ModSystem for event registration + public: + auto init() -> void; + auto register_keydown_event(Input::Key, EventCallbackCallable, uint8_t custom_data = 0, void* custom_data2 = nullptr) -> void; using ModifierKeyArray = std::array; @@ -82,9 +71,34 @@ namespace RC::Input auto is_keydown_event_registered(Input::Key) -> bool; auto is_keydown_event_registered(Input::Key, const ModifierKeyArray&) -> bool; - auto get_events() -> std::vector&; + auto get_events_safe(std::function) -> void; + auto clear_subscribed_keys() -> void; + auto clear_subscribed_key(Key k) -> void; + + auto has_event_on_key(Input::Key key) -> bool; + auto get_subscribed_keys() const -> const std::array& + { + return m_subscribed_keys; + } + auto get_allow_input() -> bool; auto set_allow_input(bool new_value) -> void; + + auto get_current_input_source() -> std::string; + + private: + static std::unordered_map> m_input_sources_store; + static auto register_input_source(std::shared_ptr input_source) -> void; + + public: + static auto get_input_source(std::string source) -> std::shared_ptr + { + if (m_input_sources_store.find(source) != m_input_sources_store.end()) + { + return m_input_sources_store[source]; + } + return nullptr; + } }; } // namespace RC::Input diff --git a/deps/first/Input/include/Input/KeyDef.hpp b/deps/first/Input/include/Input/KeyDef.hpp index 66006e58c..4ff7101fb 100644 --- a/deps/first/Input/include/Input/KeyDef.hpp +++ b/deps/first/Input/include/Input/KeyDef.hpp @@ -1,13 +1,13 @@ #pragma once #include - +#include +#include namespace RC::Input { static constexpr uint32_t max_callbacks_per_event = 30; static constexpr uint8_t max_keys = 0xFF; -#ifdef _WIN32 enum Key : uint8_t { RESERVED_START_OF_ENUM = 0x0, @@ -244,11 +244,62 @@ namespace RC::Input MODIFIER_KEYS_MAX, }; + static inline bool is_modify_key_valid(ModifierKey key) + { + return (key < MODIFIER_KEYS_MAX) && (key > MOD_KEY_START_OF_ENUM); + } + + struct ModifierKeys + { + /// SAFETY: This is a bitfield, following static_assert ensures that the bitfield is not larger than 32 bits + uint32_t keys; + + // allow ops between keys + + auto operator|(const ModifierKeys& key) -> ModifierKeys&; + auto operator|=(const ModifierKeys& key) -> ModifierKeys&; + auto operator|(const ModifierKey& key) -> ModifierKeys&; + auto operator|=(const ModifierKey& key) -> ModifierKeys&; + + auto operator==(const ModifierKeys& key) const -> bool; + auto operator!=(const ModifierKeys& key) const -> bool; + + auto operator<(const ModifierKeys& key) const -> bool; + auto operator>(const ModifierKeys& key) const -> bool; + + ModifierKeys(const ModifierKey key) : keys{is_modify_key_valid(key) ? (1u << key) : 0} {}; + ModifierKeys(const ModifierKeys& other) : keys{other.keys} {}; + + ModifierKeys() : keys{0} {}; + + template + ModifierKeys(ModifierKey key, Args... args) : keys{(is_modify_key_valid(key) ? (1 << key) : 0) | ModifierKeys(args...).keys} {}; + + ModifierKeys(std::initializer_list keys); + + template + ModifierKeys(const TArray& keys) : keys{0} + { + for (auto key : keys) + { + if (is_modify_key_valid(key)) + { + this->keys |= (1 << key); + } + } + } + + bool empty() const + { + return keys == 0; + } + }; + static constexpr uint8_t max_modifier_keys = MODIFIER_KEYS_MAX; + static_assert(max_modifier_keys < 32, "Modifier keys cannot exceed 32"); -#else - static_assert(false, "The input library only works on Windows."); -#endif + auto operator&(const ModifierKeys& keys, const ModifierKey& key) -> bool; + auto operator&(const ModifierKeys& keys, const ModifierKeys& key) -> bool; auto operator++(Input::Key& key) -> Input::Key&; } // namespace RC::Input From e5fa3290f257f0e042234f1a9c778091fde00155 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:10:01 -0500 Subject: [PATCH 05/24] Input Source: GLFW3 --- .../Input/Platform/GLFW3InputSource.hpp | 28 ++ .../Input/src/Platform/GLFW3InputSource.cpp | 349 ++++++++++++++++++ 2 files changed, 377 insertions(+) create mode 100644 deps/first/Input/include/Input/Platform/GLFW3InputSource.hpp create mode 100644 deps/first/Input/src/Platform/GLFW3InputSource.cpp diff --git a/deps/first/Input/include/Input/Platform/GLFW3InputSource.hpp b/deps/first/Input/include/Input/Platform/GLFW3InputSource.hpp new file mode 100644 index 000000000..333673b5f --- /dev/null +++ b/deps/first/Input/include/Input/Platform/GLFW3InputSource.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +namespace RC::Input +{ + + class GLFW3InputSource : public QueueInputSource + { + public: + auto begin_frame() -> void; + auto receive_input(int key, int action, int mods) -> void; + auto end_frame() -> void; + + private: + Key m_translate_key[512]; + + public: + auto is_available() -> bool override; + const char* get_name() override + { + return "GLFW3"; + } + GLFW3InputSource(); + }; + +} // namespace RC::Input diff --git a/deps/first/Input/src/Platform/GLFW3InputSource.cpp b/deps/first/Input/src/Platform/GLFW3InputSource.cpp new file mode 100644 index 000000000..776276513 --- /dev/null +++ b/deps/first/Input/src/Platform/GLFW3InputSource.cpp @@ -0,0 +1,349 @@ +#include + +#define GLFW_KEY_SPACE 32 + +#define GLFW_KEY_APOSTROPHE 39 /* ' */ + +#define GLFW_KEY_COMMA 44 /* , */ + +#define GLFW_KEY_MINUS 45 /* - */ + +#define GLFW_KEY_PERIOD 46 /* . */ + +#define GLFW_KEY_SLASH 47 /* / */ + +#define GLFW_KEY_0 48 + +#define GLFW_KEY_1 49 + +#define GLFW_KEY_2 50 + +#define GLFW_KEY_3 51 + +#define GLFW_KEY_4 52 + +#define GLFW_KEY_5 53 + +#define GLFW_KEY_6 54 + +#define GLFW_KEY_7 55 + +#define GLFW_KEY_8 56 + +#define GLFW_KEY_9 57 + +#define GLFW_KEY_SEMICOLON 59 /* ; */ + +#define GLFW_KEY_EQUAL 61 /* = */ + +#define GLFW_KEY_A 65 + +#define GLFW_KEY_B 66 + +#define GLFW_KEY_C 67 + +#define GLFW_KEY_D 68 + +#define GLFW_KEY_E 69 + +#define GLFW_KEY_F 70 + +#define GLFW_KEY_G 71 + +#define GLFW_KEY_H 72 + +#define GLFW_KEY_I 73 + +#define GLFW_KEY_J 74 + +#define GLFW_KEY_K 75 + +#define GLFW_KEY_L 76 + +#define GLFW_KEY_M 77 + +#define GLFW_KEY_N 78 + +#define GLFW_KEY_O 79 + +#define GLFW_KEY_P 80 + +#define GLFW_KEY_Q 81 + +#define GLFW_KEY_R 82 + +#define GLFW_KEY_S 83 + +#define GLFW_KEY_T 84 + +#define GLFW_KEY_U 85 + +#define GLFW_KEY_V 86 + +#define GLFW_KEY_W 87 + +#define GLFW_KEY_X 88 + +#define GLFW_KEY_Y 89 + +#define GLFW_KEY_Z 90 + +#define GLFW_KEY_LEFT_BRACKET 91 /* [ */ + +#define GLFW_KEY_BACKSLASH 92 /* \ */ + +#define GLFW_KEY_RIGHT_BRACKET 93 /* ] */ + +#define GLFW_KEY_GRAVE_ACCENT 96 /* ` */ + +#define GLFW_KEY_WORLD_1 161 /* non-US #1 */ + +#define GLFW_KEY_WORLD_2 162 /* non-US #2 */ + +#define GLFW_KEY_ESCAPE 256 + +#define GLFW_KEY_ENTER 257 + +#define GLFW_KEY_TAB 258 + +#define GLFW_KEY_BACKSPACE 259 + +#define GLFW_KEY_INSERT 260 + +#define GLFW_KEY_DELETE 261 + +#define GLFW_KEY_RIGHT 262 + +#define GLFW_KEY_LEFT 263 + +#define GLFW_KEY_DOWN 264 + +#define GLFW_KEY_UP 265 + +#define GLFW_KEY_PAGE_UP 266 + +#define GLFW_KEY_PAGE_DOWN 267 + +#define GLFW_KEY_HOME 268 + +#define GLFW_KEY_END 269 + +#define GLFW_KEY_CAPS_LOCK 280 + +#define GLFW_KEY_SCROLL_LOCK 281 + +#define GLFW_KEY_NUM_LOCK 282 + +#define GLFW_KEY_PRINT_SCREEN 283 + +#define GLFW_KEY_PAUSE 284 + +#define GLFW_KEY_F1 290 + +#define GLFW_KEY_F2 291 + +#define GLFW_KEY_F3 292 + +#define GLFW_KEY_F4 293 + +#define GLFW_KEY_F5 294 + +#define GLFW_KEY_F6 295 + +#define GLFW_KEY_F7 296 + +#define GLFW_KEY_F8 297 + +#define GLFW_KEY_F9 298 + +#define GLFW_KEY_F10 299 + +#define GLFW_KEY_F11 300 + +#define GLFW_KEY_F12 301 + +#define GLFW_KEY_F13 302 + +#define GLFW_KEY_F14 303 + +#define GLFW_KEY_F15 304 + +#define GLFW_KEY_F16 305 + +#define GLFW_KEY_F17 306 + +#define GLFW_KEY_F18 307 + +#define GLFW_KEY_F19 308 + +#define GLFW_KEY_F20 309 + +#define GLFW_KEY_F21 310 + +#define GLFW_KEY_F22 311 + +#define GLFW_KEY_F23 312 + +#define GLFW_KEY_F24 313 + +#define GLFW_KEY_F25 314 + +#define GLFW_KEY_KP_0 320 + +#define GLFW_KEY_KP_1 321 + +#define GLFW_KEY_KP_2 322 + +#define GLFW_KEY_KP_3 323 + +#define GLFW_KEY_KP_4 324 + +#define GLFW_KEY_KP_5 325 + +#define GLFW_KEY_KP_6 326 + +#define GLFW_KEY_KP_7 327 + +#define GLFW_KEY_KP_8 328 + +#define GLFW_KEY_KP_9 329 + +#define GLFW_KEY_KP_DECIMAL 330 + +#define GLFW_KEY_KP_DIVIDE 331 + +#define GLFW_KEY_KP_MULTIPLY 332 + +#define GLFW_KEY_KP_SUBTRACT 333 + +#define GLFW_KEY_KP_ADD 334 + +#define GLFW_KEY_KP_ENTER 335 + +#define GLFW_KEY_KP_EQUAL 336 + +#define GLFW_KEY_LEFT_SHIFT 340 + +#define GLFW_KEY_LEFT_CONTROL 341 + +#define GLFW_KEY_LEFT_ALT 342 + +#define GLFW_KEY_LEFT_SUPER 343 + +#define GLFW_KEY_RIGHT_SHIFT 344 + +#define GLFW_KEY_RIGHT_CONTROL 345 + +#define GLFW_KEY_RIGHT_ALT 346 + +#define GLFW_KEY_RIGHT_SUPER 347 + +#define GLFW_KEY_MENU 348 + +#define GLFW_KEY_LAST GLFW_KEY_MENU + +#define GLFW_MOD_SHIFT 0x0001 +#define GLFW_MOD_CONTROL 0x0002 +#define GLFW_MOD_ALT 0x0004 + +#define GLFW_RELEASE 0 +#define GLFW_PRESS 1 +#define GLFW_REPEAT 2 + +namespace RC::Input +{ + auto GLFW3InputSource::begin_frame() -> void + { + } + + auto GLFW3InputSource::receive_input(int key, int action, int mods) -> void + { + auto modifier_keys = ModifierKeys{}; + modifier_keys |= (mods & GLFW_MOD_CONTROL ? ModifierKey::CONTROL : ModifierKey::MOD_KEY_START_OF_ENUM); + modifier_keys |= (mods & GLFW_MOD_SHIFT ? ModifierKey::SHIFT : ModifierKey::MOD_KEY_START_OF_ENUM); + modifier_keys |= (mods & GLFW_MOD_ALT ? ModifierKey::ALT : ModifierKey::MOD_KEY_START_OF_ENUM); + if (action == GLFW_PRESS) + { + // translate key + Key input = m_translate_key[key]; + if (input != RESERVED_START_OF_ENUM) + { + push_input_event({input, modifier_keys}); + } + } + } + + auto GLFW3InputSource::end_frame() -> void + { + } + + auto GLFW3InputSource::is_available() -> bool + { + return true; + } + + GLFW3InputSource::GLFW3InputSource() + { + // init to 0 + for (int i = 0; i < 512; ++i) + { + m_translate_key[i] = static_cast(0); + } + // Alphanumeric keys + for (int key = GLFW_KEY_A; key <= GLFW_KEY_Z; ++key) + { + m_translate_key[key] = static_cast(key); + } + for (int key = GLFW_KEY_0; key <= GLFW_KEY_9; ++key) + { + m_translate_key[key] = static_cast(key + 22); + } + + // Symbol keys + m_translate_key[GLFW_KEY_SPACE] = Key::SPACE; + m_translate_key[GLFW_KEY_APOSTROPHE] = Key::OEM_SEVEN; + m_translate_key[GLFW_KEY_COMMA] = Key::OEM_COMMA; + m_translate_key[GLFW_KEY_MINUS] = Key::OEM_MINUS; + m_translate_key[GLFW_KEY_PERIOD] = Key::OEM_PERIOD; + m_translate_key[GLFW_KEY_SLASH] = Key::OEM_TWO; + m_translate_key[GLFW_KEY_SEMICOLON] = Key::OEM_ONE; + m_translate_key[GLFW_KEY_EQUAL] = Key::OEM_PLUS; + m_translate_key[GLFW_KEY_LEFT_BRACKET] = Key::OEM_FOUR; + m_translate_key[GLFW_KEY_BACKSLASH] = Key::OEM_FIVE; + m_translate_key[GLFW_KEY_RIGHT_BRACKET] = Key::OEM_SIX; + m_translate_key[GLFW_KEY_GRAVE_ACCENT] = Key::OEM_THREE; + + // Control keys + m_translate_key[GLFW_KEY_ESCAPE] = Key::ESCAPE; + m_translate_key[GLFW_KEY_ENTER] = Key::RETURN; + m_translate_key[GLFW_KEY_TAB] = Key::TAB; + m_translate_key[GLFW_KEY_BACKSPACE] = Key::BACKSPACE; + m_translate_key[GLFW_KEY_INSERT] = Key::INS; + m_translate_key[GLFW_KEY_DELETE] = Key::DEL; + m_translate_key[GLFW_KEY_RIGHT] = Key::RIGHT_ARROW; + m_translate_key[GLFW_KEY_LEFT] = Key::LEFT_ARROW; + m_translate_key[GLFW_KEY_DOWN] = Key::DOWN_ARROW; + m_translate_key[GLFW_KEY_UP] = Key::UP_ARROW; + m_translate_key[GLFW_KEY_PAGE_UP] = Key::PAGE_UP; + m_translate_key[GLFW_KEY_PAGE_DOWN] = Key::PAGE_DOWN; + m_translate_key[GLFW_KEY_HOME] = Key::HOME; + m_translate_key[GLFW_KEY_END] = Key::END; + m_translate_key[GLFW_KEY_CAPS_LOCK] = Key::CAPS_LOCK; + m_translate_key[GLFW_KEY_SCROLL_LOCK] = Key::SCROLL_LOCK; + m_translate_key[GLFW_KEY_NUM_LOCK] = Key::NUM_LOCK; + m_translate_key[GLFW_KEY_PRINT_SCREEN] = Key::PRINT_SCREEN; + m_translate_key[GLFW_KEY_PAUSE] = Key::PAUSE; + + // Function keys + for (int key = GLFW_KEY_F1; key <= GLFW_KEY_F25; ++key) + { + m_translate_key[key] = static_cast(key + 111); + } + + // Numeric keypad + for (int key = GLFW_KEY_KP_0; key <= GLFW_KEY_KP_EQUAL; ++key) + { + m_translate_key[key] = static_cast(key + 208); + } + } +} // namespace RC::Input \ No newline at end of file From c1970508cc4537f6992217c6a2e7fc7e006da75b Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:10:17 -0500 Subject: [PATCH 06/24] Input Source: Win32 Async --- .../Input/Platform/Win32AsyncInputSource.hpp | 86 +++++++++++++++ .../src/Platform/Win32AsyncInputSource.cpp | 102 ++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 deps/first/Input/include/Input/Platform/Win32AsyncInputSource.hpp create mode 100644 deps/first/Input/src/Platform/Win32AsyncInputSource.cpp diff --git a/deps/first/Input/include/Input/Platform/Win32AsyncInputSource.hpp b/deps/first/Input/include/Input/Platform/Win32AsyncInputSource.hpp new file mode 100644 index 000000000..0564de08a --- /dev/null +++ b/deps/first/Input/include/Input/Platform/Win32AsyncInputSource.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace RC::Input +{ + class Win32AsyncInputSource : public PlatformInputSource + { + private: + std::vector m_active_window_classes{}; + std::unordered_map m_modifier_keys_down{}; + bool m_any_keys_are_down{}; + bool m_activated{false}; + std::array m_key_down{}; + + private: + /// SAFETY: Only update and return m_input_events + /// in the process_event function + std::vector m_input_events{}; + + public: + template + explicit Win32AsyncInputSource(WindowClasses... window_classes) + { + static_assert(std::conjunction...>::value, "WindowClasses must be of type const wchar_t*"); + + m_modifier_keys_down.emplace(ModifierKey::SHIFT, false); + m_modifier_keys_down.emplace(ModifierKey::CONTROL, false); + m_modifier_keys_down.emplace(ModifierKey::ALT, false); + + register_window_classes(window_classes...); + } + + private: + template + auto register_window_classes(WindowClass window_class) -> void + { + m_active_window_classes.emplace_back(window_class); + } + + template + auto register_window_classes(WindowClass window_class, WindowClasses... window_classes) -> void + { + m_active_window_classes.emplace_back(window_class); + register_window_classes(window_classes...); + } + + auto are_modifier_keys_down(const std::vector&) -> bool; + auto is_program_focused() -> bool; + + public: + bool is_available() override + { + return true; + }; + + bool activate() override + { + m_key_down.fill(false); + return m_activated = true; + }; + + bool deactivate() override + { + m_activated = false; + return true; + }; + + std::vector& process_event(Handler* handler) override; + ~Win32AsyncInputSource() = default; + int source_priority() override + { + return 0; + } + + const char* get_name() override + { + return "Win32Async"; + } + }; +}; // namespace RC::Input diff --git a/deps/first/Input/src/Platform/Win32AsyncInputSource.cpp b/deps/first/Input/src/Platform/Win32AsyncInputSource.cpp new file mode 100644 index 000000000..7169ae55f --- /dev/null +++ b/deps/first/Input/src/Platform/Win32AsyncInputSource.cpp @@ -0,0 +1,102 @@ +#include +#include +#include +#include + +#define NOMINMAX +#include + +namespace RC::Input +{ + + auto Win32AsyncInputSource::is_program_focused() -> bool + { + HWND hwnd = GetForegroundWindow(); + if (!hwnd) return false; + wchar_t current_window_class_name[MAX_PATH]; + if (!GetClassNameW(hwnd, current_window_class_name, MAX_PATH)) return false; + for (const auto& active_window_class : m_active_window_classes) + { + if (wcscmp(current_window_class_name, active_window_class) == 0) + { + return true; + } + } + return false; + } + + std::vector& Win32AsyncInputSource::process_event(Handler* handler) + { + m_input_events.clear(); + + if (!is_program_focused()) + { + return m_input_events; + } + + if (!m_activated) + { + return m_input_events; + } + + bool skip_this_frame = !handler->get_allow_input(); + + if (m_any_keys_are_down) + { + skip_this_frame = true; + } + + bool any_keys_are_down = false; + + // Check if any modifier keys are down + ModifierKeys modifier_keys{}; + for (auto& [modifier_key, key_is_down] : m_modifier_keys_down) + { + if (GetAsyncKeyState(modifier_key)) + { + modifier_keys |= modifier_key; + key_is_down = true; + } + else + { + key_is_down = false; + } + } + + auto& subscribed_keys = handler->get_subscribed_keys(); + + for (int key = 0; key < max_keys; ++key) + { + if (subscribed_keys[key]) + { + auto keyed = GetAsyncKeyState(key); + if (keyed && !m_key_down[key]) + { + any_keys_are_down = true; + m_key_down[key] = true; + m_input_events.emplace_back(InputEvent{static_cast(key), modifier_keys}); + } + else if (!keyed && m_key_down[key]) + { + m_key_down[key] = false; + } + } + } + + if (any_keys_are_down) + { + m_any_keys_are_down = true; + } + else + { + m_any_keys_are_down = false; + } + + if (skip_this_frame) + { + m_input_events.clear(); + } + return m_input_events; + } + +} // namespace RC::Input From 863d93ed35d21770aa45a48d37bc4bc78bb2d387 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:10:53 -0500 Subject: [PATCH 07/24] Input Source: Common Queued Source --- .../Input/Platform/QueueInputSource.hpp | 61 +++++++++++++++++++ .../Input/src/Platform/QueueInputSource.cpp | 46 ++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 deps/first/Input/include/Input/Platform/QueueInputSource.hpp create mode 100644 deps/first/Input/src/Platform/QueueInputSource.cpp diff --git a/deps/first/Input/include/Input/Platform/QueueInputSource.hpp b/deps/first/Input/include/Input/Platform/QueueInputSource.hpp new file mode 100644 index 000000000..b184cc9e3 --- /dev/null +++ b/deps/first/Input/include/Input/Platform/QueueInputSource.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include +#include + +#include + +namespace RC::Input +{ + class QueueInputSource : public PlatformInputSource + { + private: + static constexpr int max_inputs = 256; + RingBufferSPSC m_input_queue; + + protected: + bool m_activated{false}; + + private: + /// SAFETY: Only update and return m_input_events + /// in process_event and flush_events functions + std::vector m_input_events; + + public: + ~QueueInputSource() = default; + + // QueeueInputSource is not a implemented input source + // and should not be used directly + bool is_available() override + { + return false; + }; + + bool activate() override + { + return m_activated = true; + }; + + bool deactivate() override + { + m_activated = false; + return true; + }; + + std::vector& process_event(Handler* handler) override; + + int source_priority() override + { + return 0; + } + + const char* get_name() override + { + return "Queue"; + } + + public: + auto push_input_event(const InputEvent& event) -> void; + }; + +}; // namespace RC::Input \ No newline at end of file diff --git a/deps/first/Input/src/Platform/QueueInputSource.cpp b/deps/first/Input/src/Platform/QueueInputSource.cpp new file mode 100644 index 000000000..f7170101e --- /dev/null +++ b/deps/first/Input/src/Platform/QueueInputSource.cpp @@ -0,0 +1,46 @@ +#include +#include + +#include + +namespace RC::Input +{ + auto QueueInputSource::push_input_event(const InputEvent& event) -> void + { + if (m_activated) + { + m_input_queue.push(event); + Output::send(SYSSTR("QueueInputSource::push_input_event: {}"), (int)event.key); + } + } + + // even if not activated, we still consume the remaining events in the queue + std::vector& QueueInputSource::process_event(Handler* handler) + { + m_input_events.clear(); + + auto event = m_input_queue.pop(); + auto& key_set = handler->get_subscribed_keys(); + while (event) + { + Output::send(SYSSTR("QueueInputSource::reveive key event: {}"), (int)event->key); + if (key_set[event->key]) + { + m_input_events.emplace_back(*event); + } + event = m_input_queue.pop(); + } + + if (!m_activated) + { + m_input_events.clear(); + } + + if (!handler->get_allow_input()) + { + m_input_events.clear(); + } + + return m_input_events; + } +}; // namespace RC::Input From bd22994f5829406ba9ce59c27df0f02ddc81975b Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:11:27 -0500 Subject: [PATCH 08/24] Input Source: ModifierKeys ops --- deps/first/Input/src/KeyDef.cpp | 68 +++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/deps/first/Input/src/KeyDef.cpp b/deps/first/Input/src/KeyDef.cpp index 5e73dbbc1..9057adc0f 100644 --- a/deps/first/Input/src/KeyDef.cpp +++ b/deps/first/Input/src/KeyDef.cpp @@ -1,4 +1,5 @@ #include +#include namespace RC::Input { @@ -14,4 +15,71 @@ namespace RC::Input return key; } + + auto ModifierKeys::operator|(const ModifierKeys& rkeys) -> ModifierKeys& + { + keys |= rkeys.keys; + return *this; + } + + auto ModifierKeys::operator|(const ModifierKey& key) -> ModifierKeys& + { + if (is_modify_key_valid(key)) + { + keys |= (1 << key); + } + return *this; + } + + auto ModifierKeys::operator|=(const ModifierKeys& rkeys) -> ModifierKeys& + { + return *this = *this | rkeys; + } + + auto ModifierKeys::operator|=(const ModifierKey& key) -> ModifierKeys& + { + return *this = *this | key; + } + + auto ModifierKeys::operator==(const ModifierKeys& key) const -> bool + { + return keys == key.keys; + } + + auto ModifierKeys::operator<(const ModifierKeys& rkeys) const -> bool + { + return keys < rkeys.keys; + } + + auto ModifierKeys::operator>(const ModifierKeys& rkeys) const -> bool + { + return keys > rkeys.keys; + } + + auto ModifierKeys::operator!=(const ModifierKeys& key) const -> bool + { + return keys != key.keys; + } + + ModifierKeys::ModifierKeys(std::initializer_list keys) + { + for (auto key : keys) + { + if (is_modify_key_valid(key)) + { + this->keys |= (1 << key); + } + } + } + + auto operator&(const ModifierKeys& keys, const ModifierKey& key) -> bool + { + return !!(keys.keys & (1 << key)); + } + + auto operator&(const ModifierKeys& keys, const ModifierKeys& key) -> bool + { + return !!(keys.keys & key.keys); + } + } // namespace RC::Input From cd1f88bc9683dbe4048d44264355da62cb49d493 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:12:31 -0500 Subject: [PATCH 09/24] Input Source: Platform Init for input sources --- deps/first/Input/src/PlatformInit.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 deps/first/Input/src/PlatformInit.cpp diff --git a/deps/first/Input/src/PlatformInit.cpp b/deps/first/Input/src/PlatformInit.cpp new file mode 100644 index 000000000..8bc45515a --- /dev/null +++ b/deps/first/Input/src/PlatformInit.cpp @@ -0,0 +1,12 @@ +#include +#include +#include + +namespace RC::Input +{ + auto Handler::init() -> void + { + register_input_source(std::make_shared(L"ConsoleWindowClass", L"UnrealWindow")); + register_input_source(std::make_shared()); + } +} // namespace RC::Input \ No newline at end of file From 2b4d02bd052aa2df1a4b461cea13adcf16d611df Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:12:58 -0500 Subject: [PATCH 10/24] Input Source: Platform Input Abstract --- .../include/Input/PlatformInputSource.hpp | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 deps/first/Input/include/Input/PlatformInputSource.hpp diff --git a/deps/first/Input/include/Input/PlatformInputSource.hpp b/deps/first/Input/include/Input/PlatformInputSource.hpp new file mode 100644 index 000000000..387311b9a --- /dev/null +++ b/deps/first/Input/include/Input/PlatformInputSource.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include +#include + +namespace RC::Input +{ + + class PlatformInputSource + { + public: + /// Check if the input source is available + virtual bool is_available() + { + return false; + }; + + /// Initialize the input source + virtual bool activate() + { + return false; + }; + + /// Initialize the input source + virtual bool deactivate() + { + return false; + }; + + /// Get the priority of the input source, smaller number means higher priority + virtual int source_priority() + { + return 999; + }; + + /// Process the event and return the input events in the frame + virtual std::vector& process_event(Handler* handler) = 0; + + virtual ~PlatformInputSource() = default; + + virtual const char* get_name() + { + return "Unknown"; + } + }; + +}; // namespace RC::Input From 3dd7e8cd712638c765f73ad14c6290ee7d2a263b Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:13:30 -0500 Subject: [PATCH 11/24] Input Source: Refactor Input Source Handler --- deps/first/Input/src/Handler.cpp | 398 ++++++++++--------------------- 1 file changed, 131 insertions(+), 267 deletions(-) diff --git a/deps/first/Input/src/Handler.cpp b/deps/first/Input/src/Handler.cpp index 8533a9aec..0165e16ff 100644 --- a/deps/first/Input/src/Handler.cpp +++ b/deps/first/Input/src/Handler.cpp @@ -1,345 +1,209 @@ #include +#include +#include #include - -#define NOMINMAX -#include - +#include namespace RC::Input { - auto is_modifier_key_required(ModifierKey modifier_key, std::vector modifier_keys) -> bool - { - for (const auto& required_modifier_key : modifier_keys) - { - if (required_modifier_key == ModifierKey::MOD_KEY_START_OF_ENUM) - { - continue; - } - - if (modifier_key == required_modifier_key) - { - return true; - } - } - - return false; - } - - auto Handler::are_modifier_keys_down(const std::vector& required_modifier_keys) -> bool - { - bool are_required_modifier_keys_down = true; - - for (const auto& [modifier_key, modifier_key_is_down] : m_modifier_keys_down) - { - for (const auto& required_modifier_key : required_modifier_keys) - { - if (modifier_key == required_modifier_key && !modifier_key_is_down) - { - are_required_modifier_keys_down = false; - } - - if (modifier_key != required_modifier_key && modifier_key_is_down && !is_modifier_key_required(modifier_key, required_modifier_keys)) - { - return false; - } - } - } - - return are_required_modifier_keys_down; - } - - auto Handler::is_program_focused() -> bool - { - HWND hwnd = GetForegroundWindow(); - if (!hwnd) return false; - - wchar_t current_window_class_name[MAX_PATH]; - if (!GetClassNameW(hwnd, current_window_class_name, MAX_PATH)) return false; - - for (const auto& active_window_class : m_active_window_classes) - { - if (wcscmp(current_window_class_name, active_window_class) == 0) - { - return true; - } - } - - return false; - } + std::unordered_map> Handler::m_input_sources_store; auto Handler::process_event() -> void { - if (!is_program_focused()) + if (m_platform_handler == nullptr) { return; } std::vector callbacks_to_call{}; - bool skip_this_frame = !get_allow_input(); - bool is_any_modifier_keys_down = false; - bool any_keys_are_down = false; + auto events = m_platform_handler->process_event(this); - if (m_any_keys_are_down) { - skip_this_frame = true; - } - - // Check if any modifier keys are down - for (auto& [modifier_key, key_is_down] : m_modifier_keys_down) - { - if (GetAsyncKeyState(modifier_key)) - { - is_any_modifier_keys_down = true; - key_is_down = true; - } - else + // Lock the event mutex to access the key_set + auto event_update_lock = std::lock_guard(m_event_mutex); + for (auto& event : events) { - key_is_down = false; - } - } - - for (auto& key_set_data : m_key_sets) - { - for (auto& [key, key_data_array] : key_set_data.key_data) - { - for (auto& key_data : key_data_array) + auto key_set_array = m_key_set.key_data[event.key]; + for (auto& key_data : key_set_array) { - if (GetAsyncKeyState(key) && !key_data.is_down) + if (key_data.required_modifier_keys == event.modifier_keys) { - any_keys_are_down = true; - bool should_propagate = true; - - if (key_data.requires_modifier_keys) - { - if (!are_modifier_keys_down(key_data.required_modifier_keys)) - { - should_propagate = false; - } - } - - if (!key_data.requires_modifier_keys && is_any_modifier_keys_down) - { - should_propagate = false; - } - - if (should_propagate) - { - key_data.is_down = true; - for (const auto& callback : key_data.callbacks) - { - callbacks_to_call.emplace_back(callback); - } - } - } - else if (!GetAsyncKeyState(key) && key_data.is_down) - { - key_data.is_down = false; + callbacks_to_call.emplace_back(key_data.callback); } } } } - if (any_keys_are_down) - { - m_any_keys_are_down = true; - } - else - { - m_any_keys_are_down = false; - } - + // No need to lock the event mutex to call the callbacks + // this avoids key registration inside the callback for (const auto& callback : callbacks_to_call) { - if (skip_this_frame) - { - return; - } callback(); } } auto Handler::register_keydown_event(Input::Key key, EventCallbackCallable callback, uint8_t custom_data, void* custom_data2) -> void { - KeySet& key_set = [&]() -> KeySet& { - for (auto& key_set : m_key_sets) - { - if (key_set.key_data.contains(key)) - { - return key_set; - } - } - - return m_key_sets.emplace_back(KeySet{}); - }(); - - KeyData& key_data = key_set.key_data[key].emplace_back(); - key_data.callbacks.emplace_back(callback); + auto event_update_lock = std::lock_guard(m_event_mutex); + KeyData& key_data = m_key_set.key_data[key].emplace_back(); + key_data.callback = callback; key_data.custom_data = custom_data; key_data.custom_data2 = custom_data2; + m_subscribed_keys[key] = true; } auto Handler::register_keydown_event( Input::Key key, const ModifierKeyArray& modifier_keys, const EventCallbackCallable& callback, uint8_t custom_data, void* custom_data2) -> void { - KeySet& key_set = [&]() -> KeySet& { - for (auto& key_set : m_key_sets) - { - if (key_set.key_data.contains(key)) - { - return key_set; - } - } - - return m_key_sets.emplace_back(KeySet{}); - }(); - - KeyData& key_data = key_set.key_data[key].emplace_back(); - key_data.callbacks.emplace_back(callback); + auto event_update_lock = std::lock_guard(m_event_mutex); + KeyData& key_data = m_key_set.key_data[key].emplace_back(); + key_data.callback = callback; key_data.custom_data = custom_data; key_data.custom_data2 = custom_data2; key_data.requires_modifier_keys = true; + key_data.required_modifier_keys = modifier_keys; + m_subscribed_keys[key] = true; + } - for (const auto& modifier_key : modifier_keys) + auto Handler::is_keydown_event_registered(Input::Key key) -> bool + { + auto event_update_lock = std::lock_guard(m_event_mutex); + auto key_data = m_key_set.key_data.find(key); + if (key_data == m_key_set.key_data.end()) { - if (modifier_key != ModifierKey::MOD_KEY_START_OF_ENUM) + return false; + } + for (const auto& key_data_container : key_data->second) + { + if (key_data_container.required_modifier_keys.empty()) { - key_data.required_modifier_keys.emplace_back(modifier_key); + return true; } } + return false; } - auto Handler::is_keydown_event_registered(Input::Key key) -> bool + auto Handler::is_keydown_event_registered(Input::Key key, const ModifierKeyArray& modifier_keys_array) -> bool { - bool is_key_registered{}; - bool is_key_registered_with_no_modifier_keys = true; - for (const auto& key_set : m_key_sets) + auto event_update_lock = std::lock_guard(m_event_mutex); + auto key_data = m_key_set.key_data.find(key); + auto modifier_keys = ModifierKeys(modifier_keys_array); + if (key_data == m_key_set.key_data.end()) { - for (const auto& [key_registered, key_data_container] : key_set.key_data) - { - if (key_registered == key) - { - is_key_registered = true; - } - else - { - continue; - } - - for (const auto& key_data : key_data_container) - { - if (key_data.requires_modifier_keys) - { - is_key_registered_with_no_modifier_keys = false; - break; - } - } - - if (!is_key_registered_with_no_modifier_keys) - { - break; - } - } - - if (!is_key_registered_with_no_modifier_keys) + return false; + } + for (const auto& key_data_container : key_data->second) + { + if (key_data_container.required_modifier_keys == modifier_keys) { - break; + return true; } } - - return is_key_registered && is_key_registered_with_no_modifier_keys; + return false; } - auto Handler::is_keydown_event_registered(Input::Key key, const ModifierKeyArray& modifier_keys) -> bool + auto Handler::has_event_on_key(Input::Key key) -> bool { - bool is_key_registered{}; - bool all_modifier_keys_match{}; - for (const auto& key_set : m_key_sets) - { - for (const auto& [key_registered, key_data_container] : key_set.key_data) - { - if (key_registered == key) - { - is_key_registered = true; - } - else - { - continue; - } + return m_subscribed_keys[key]; + } - all_modifier_keys_match = false; - for (const auto& key_data : key_data_container) - { - if (!key_data.requires_modifier_keys && !modifier_keys.empty()) - { - all_modifier_keys_match = false; - continue; - } + auto Handler::get_events_safe(std::function callback) -> void + { + auto event_update_lock = std::lock_guard(m_event_mutex); + callback(m_key_set); + } - if (!key_data.requires_modifier_keys && modifier_keys.empty()) - { - all_modifier_keys_match = true; - break; - } + auto Handler::clear_subscribed_keys() -> void + { + m_subscribed_keys.fill(false); + } - for (const auto& modifier_key : key_data.required_modifier_keys) - { - for (const auto modifier_key_to_check : modifier_keys) - { - if (modifier_key_to_check == ModifierKey::MOD_KEY_START_OF_ENUM) - { - continue; - } + auto Handler::clear_subscribed_key(Key k) -> void + { + m_subscribed_keys[k] = false; + } - if (modifier_key_to_check == modifier_key) - { - all_modifier_keys_match = true; - } - else - { - all_modifier_keys_match = false; - } - } + auto Handler::get_allow_input() -> bool + { + return m_allow_input; + } - if (all_modifier_keys_match) - { - break; - } - } + auto Handler::set_allow_input(bool new_value) -> void + { + m_allow_input = new_value; + } - if (all_modifier_keys_match) - { - break; - } + /// Set the input source to the given source + /// SAFETY: Only call this function from the main thread + auto Handler::set_input_source(std::string source) -> bool + { + auto event_update_lock = std::lock_guard(m_event_mutex); + std::shared_ptr next_input_source = nullptr; + if (source == "Default") + { + // find the highest priority input source + int highest_priority = INT_MAX; + for (auto& input_source : m_input_sources_store) + { + if (!input_source.second->is_available()) + { + continue; } - - if (all_modifier_keys_match) + auto priority = input_source.second->source_priority(); + if (priority < highest_priority) { - break; + next_input_source = input_source.second; + highest_priority = priority; } } - - if (all_modifier_keys_match) + if (highest_priority == INT_MAX) { - break; + return false; } } - - return is_key_registered && all_modifier_keys_match; - } - - auto Handler::get_events() -> std::vector& - { - return m_key_sets; + else + { + auto input_source = m_input_sources_store.find(source); + if (input_source == m_input_sources_store.end()) + { + return false; + } + next_input_source = input_source->second; + if (!next_input_source->is_available()) + { + return false; + } + } + if (next_input_source != m_platform_handler) + { + if (m_platform_handler != nullptr) + { + m_platform_handler->deactivate(); + } + next_input_source->activate(); + m_platform_handler = next_input_source; + return true; + } + return true; } - auto Handler::get_allow_input() -> bool + // register the input source to the input source store + auto Handler::register_input_source(std::shared_ptr input_source) -> void { - return m_allow_input; + std::string name = input_source->get_name(); + if (m_input_sources_store.find(name) == m_input_sources_store.end()) + { + m_input_sources_store[name] = input_source; + } } - auto Handler::set_allow_input(bool new_value) -> void + auto Handler::get_current_input_source() -> std::string { - m_allow_input = new_value; + if (m_platform_handler == nullptr) + { + return "None"; + } + return m_platform_handler->get_name(); } } // namespace RC::Input From 4dd83b6879d9242c2b5df03154e7ea02f534ada8 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 07:20:26 +0200 Subject: [PATCH 12/24] Input Source: Input Handler in UE4SS * Use HAS_INPUT macro with --ue4ssInput option * Init InputSource System * Set Input Source according to the settings * Use thread safe get_events_safe callback --- UE4SS/include/UE4SSProgram.hpp | 15 ++++++++++- UE4SS/src/UE4SSProgram.cpp | 47 ++++++++++++++++++++++++---------- UE4SS/xmake.lua | 12 +++++++-- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/UE4SS/include/UE4SSProgram.hpp b/UE4SS/include/UE4SSProgram.hpp index cbe56052a..87352bd60 100644 --- a/UE4SS/include/UE4SSProgram.hpp +++ b/UE4SS/include/UE4SSProgram.hpp @@ -11,7 +11,10 @@ #include #include #include +#ifdef HAS_INPUT #include +#endif + #include #include #include @@ -98,7 +101,9 @@ namespace RC bool m_is_program_started; protected: - Input::Handler m_input_handler{L"ConsoleWindowClass", L"UnrealWindow"}; +#ifdef HAS_INPUT + Input::Handler m_input_handler; +#endif std::jthread m_event_loop; public: @@ -221,6 +226,12 @@ namespace RC RC_UE4SS_API auto generate_uht_compatible_headers() -> void; RC_UE4SS_API auto generate_cxx_headers(const std::filesystem::path& output_dir) -> void; RC_UE4SS_API auto generate_lua_types(const std::filesystem::path& output_dir) -> void; +#ifdef HAS_INPUT + auto get_input_handler() -> Input::Handler& + { + return m_input_handler; + } +#endif auto get_debugging_ui() -> GUI::DebuggingGUI& { return m_debugging_gui; @@ -244,6 +255,7 @@ namespace RC } public: +#ifdef HAS_INPUT // API pass-through for use outside the private scope of UE4SSProgram RC_UE4SS_API auto register_keydown_event(Input::Key, const Input::EventCallbackCallable&, uint8_t custom_data = 0, void* custom_data2 = nullptr) -> void; RC_UE4SS_API auto register_keydown_event(Input::Key, @@ -253,6 +265,7 @@ namespace RC void* custom_data2 = nullptr) -> void; RC_UE4SS_API auto is_keydown_event_registered(Input::Key) -> bool; RC_UE4SS_API auto is_keydown_event_registered(Input::Key, const Input::Handler::ModifierKeyArray&) -> bool; +#endif private: static auto install_cpp_mods() -> void; diff --git a/UE4SS/src/UE4SSProgram.cpp b/UE4SS/src/UE4SSProgram.cpp index 63f88ca9c..dbbc22771 100644 --- a/UE4SS/src/UE4SSProgram.cpp +++ b/UE4SS/src/UE4SSProgram.cpp @@ -824,7 +824,7 @@ namespace RC { m_debugging_gui.get_live_view().set_listeners_allowed(false); } - +#ifdef HAS_INPUT m_input_handler.register_keydown_event(Input::Key::O, {Input::ModifierKey::CONTROL}, [&]() { TRY([&] { auto was_gui_open = get_debugging_ui().is_open(); @@ -836,6 +836,7 @@ namespace RC } }); }); +#endif } #ifdef TIME_FUNCTION_MACRO_ENABLED @@ -856,7 +857,7 @@ namespace RC TRY([&] { ObjectDumper::init(); - +#ifdef HAS_INPUT if (settings_manager.General.EnableHotReloadSystem) { m_input_handler.register_keydown_event(Input::Key::R, {Input::ModifierKey::CONTROL}, [&]() { @@ -865,7 +866,7 @@ namespace RC }); }); } - +#endif if ((settings_manager.ObjectDumper.LoadAllAssetsBeforeDumpingObjects || settings_manager.CXXHeaderGenerator.LoadAllAssetsBeforeGeneratingCXXHeaders) && Unreal::Version::IsBelow(4, 17)) { @@ -878,18 +879,34 @@ namespace RC STR("FAssetData not available, ignoring 'LoadAllAssetsBeforeDumpingObjects' & 'LoadAllAssetsBeforeGeneratingCXXHeaders'.")); } +#ifdef HAS_INPUT + if (!settings_manager.General.InputSource.empty()) + { + if (m_input_handler.set_input_source(to_string(settings_manager.General.InputSource))) + { + Output::send(SYSSTR("Input source set to: {}\n"), m_input_handler.get_current_input_source()); + } + else + { + Output::send(SYSSTR("Failed to set input source to: {}\n"), settings_manager.General.InputSource); + } + } +#endif + install_lua_mods(); LuaMod::on_program_start(); fire_program_start_for_cpp_mods(); start_lua_mods(); }); +#ifdef HAS_INPUT if (settings_manager.General.EnableDebugKeyBindings) { m_input_handler.register_keydown_event(Input::Key::NUM_NINE, {Input::ModifierKey::CONTROL}, [&]() { generate_uht_compatible_headers(); }); } +#endif } auto UE4SSProgram::update() -> void @@ -948,9 +965,9 @@ namespace RC } } //*/ - +#ifdef HAS_INPUT m_input_handler.process_event(); - +#endif { ProfilerScopeNamed("mod update processing"); @@ -1318,13 +1335,13 @@ namespace RC uninstall_mods(); - // Remove key binds that were set from Lua scripts - auto& key_events = m_input_handler.get_events(); - std::erase_if(key_events, [](Input::KeySet& input_event) -> bool { - bool were_all_events_registered_from_lua = true; - for (auto& [key, vector_of_key_data] : input_event.key_data) - { - std::erase_if(vector_of_key_data, [&](Input::KeyData& key_data) -> bool { +// Remove key binds that were set from Lua scripts +#ifdef HAS_INPUT + m_input_handler.get_events_safe([&](auto& key_set) { + std::erase_if(key_set.key_data, [&](auto& item) -> bool { + auto& [_, key_data] = item; + bool were_all_events_registered_from_lua = true; + std::erase_if(key_data, [&](Input::KeyData& key_data) -> bool { // custom_data == 1: Bind came from Lua, and custom_data2 is nullptr. // custom_data == 2: Bind came from C++, and custom_data2 is a pointer to KeyDownEventData. Must free it. if (key_data.custom_data == 1) @@ -1337,10 +1354,11 @@ namespace RC return false; } }); - } - return were_all_events_registered_from_lua; + return were_all_events_registered_from_lua; + }); }); +#endif // Remove all custom properties // Uncomment when custom properties are working @@ -1507,6 +1525,7 @@ namespace RC return m_queued_events.empty(); } +#ifdef HAS_INPUT auto UE4SSProgram::register_keydown_event(Input::Key key, const Input::EventCallbackCallable& callback, uint8_t custom_data, void* custom_data2) -> void { m_input_handler.register_keydown_event(key, callback, custom_data, custom_data2); diff --git a/UE4SS/xmake.lua b/UE4SS/xmake.lua index bcc66eb23..aeb7085a2 100644 --- a/UE4SS/xmake.lua +++ b/UE4SS/xmake.lua @@ -34,6 +34,14 @@ option("versionCheck") set_description("Will xmake check the installed MSVC and Rust versions on configuration step") +option("ue4ssInput") + set_default(true) + set_showmenu(true) + + add_defines("HAS_INPUT") + + set_description("Enable the input system.") + local projectName = "UE4SS" local function parse_version_string(str) @@ -58,7 +66,7 @@ target(projectName) set_default(true) add_rules("ue4ss.defines.exports") add_rules("ue4ss.check.minimum.version") - add_options("ue4ssBetaIsStarted", "ue4ssIsBeta", "allowAllVersions") + add_options("ue4ssBetaIsStarted", "ue4ssIsBeta", "allowAllVersions", "ue4ssInput") add_includedirs("include", { public = true }) add_includedirs("generated_include", { public = true }) add_headerfiles("include/**.hpp") @@ -74,7 +82,7 @@ target(projectName) "ScopedTimer", "Profiler", "patternsleuth_bind", "glad", { public = true } ) - + add_packages("fmt", { public = true }) add_packages("imgui", "ImGuiTextEdit", "IconFontCppHeaders", "glfw", "opengl", { public = true }) From 943a9cd9fff47dab234ee52e2e69c50644538885 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:22:41 -0500 Subject: [PATCH 13/24] Input Source: Apply HAS_INPUT macro --- UE4SS/src/Mod/LuaMod.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/UE4SS/src/Mod/LuaMod.cpp b/UE4SS/src/Mod/LuaMod.cpp index 0bde48165..ebe6375e3 100644 --- a/UE4SS/src/Mod/LuaMod.cpp +++ b/UE4SS/src/Mod/LuaMod.cpp @@ -11,7 +11,11 @@ #include #include #include + +#ifdef HAS_INPUT #include +#endif + #include #include #include @@ -1050,6 +1054,7 @@ No overload found for function 'FindAllOf'. if (is_true_mod == Mod::IsTrueMod::Yes) { +#ifdef HAS_INPUT lua.register_function("IsKeyBindRegistered", [](const LuaMadeSimple::Lua& lua) -> int { std::string error_overload_not_found{R"( No overload found for function 'IsKeyBindRegistered'. @@ -1347,6 +1352,7 @@ No overload found for function 'RegisterKeyBind'. return 0; }); +#endif lua.register_function("UnregisterHook", [](const LuaMadeSimple::Lua& lua) -> int { std::lock_guard guard{LuaMod::m_thread_actions_mutex}; From 3ed1d50f14e8145c8e69bd5b63e8f39d2b34b9ea Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 00:24:19 -0500 Subject: [PATCH 14/24] Input Source: Use safe getter for input event --- UE4SS/src/Mod/CppUserModBase.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/UE4SS/src/Mod/CppUserModBase.cpp b/UE4SS/src/Mod/CppUserModBase.cpp index 26be6a05b..465ee2625 100644 --- a/UE4SS/src/Mod/CppUserModBase.cpp +++ b/UE4SS/src/Mod/CppUserModBase.cpp @@ -3,6 +3,8 @@ #include #include +#include + namespace RC { CppUserModBase::CppUserModBase() @@ -24,12 +26,11 @@ namespace RC } GUITabs.clear(); - auto& key_events = UE4SSProgram::get_program().m_input_handler.get_events(); - std::erase_if(key_events, [&](Input::KeySet& input_event) -> bool { - bool were_all_events_registered_from_this_mod = true; - for (auto& [key, vector_of_key_data] : input_event.key_data) - { - std::erase_if(vector_of_key_data, [&](Input::KeyData& key_data) -> bool { + UE4SSProgram::get_program().m_input_handler.get_events_safe([&](auto& key_set) { + std::erase_if(key_set.key_data, [&](auto& item) -> bool { + auto& [_, key_data] = item; + bool were_all_events_registered_from_this_mod = true; + std::erase_if(key_data, [&](Input::KeyData& key_data) -> bool { // custom_data == 1: Bind came from Lua, and custom_data2 is nullptr. // custom_data == 2: Bind came from C++, and custom_data2 is a pointer to KeyDownEventData. Must free it. auto event_data = static_cast(key_data.custom_data2); @@ -44,9 +45,9 @@ namespace RC return false; } }); - } - return were_all_events_registered_from_this_mod; + return were_all_events_registered_from_this_mod; + }); }); } From 9a84288afe6a1190a5d9181bb91d46ddf820a76d Mon Sep 17 00:00:00 2001 From: UE4SS Date: Wed, 8 Jan 2025 18:42:04 +0100 Subject: [PATCH 15/24] Removed SYSSTR usages --- UE4SS/src/UE4SSProgram.cpp | 4 ++-- deps/first/Input/src/Platform/QueueInputSource.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/UE4SS/src/UE4SSProgram.cpp b/UE4SS/src/UE4SSProgram.cpp index dbbc22771..f48e20d42 100644 --- a/UE4SS/src/UE4SSProgram.cpp +++ b/UE4SS/src/UE4SSProgram.cpp @@ -884,11 +884,11 @@ namespace RC { if (m_input_handler.set_input_source(to_string(settings_manager.General.InputSource))) { - Output::send(SYSSTR("Input source set to: {}\n"), m_input_handler.get_current_input_source()); + Output::send(STR("Input source set to: {}\n"), m_input_handler.get_current_input_source()); } else { - Output::send(SYSSTR("Failed to set input source to: {}\n"), settings_manager.General.InputSource); + Output::send(STR("Failed to set input source to: {}\n"), settings_manager.General.InputSource); } } #endif diff --git a/deps/first/Input/src/Platform/QueueInputSource.cpp b/deps/first/Input/src/Platform/QueueInputSource.cpp index f7170101e..c524a7200 100644 --- a/deps/first/Input/src/Platform/QueueInputSource.cpp +++ b/deps/first/Input/src/Platform/QueueInputSource.cpp @@ -10,7 +10,7 @@ namespace RC::Input if (m_activated) { m_input_queue.push(event); - Output::send(SYSSTR("QueueInputSource::push_input_event: {}"), (int)event.key); + Output::send(STR("QueueInputSource::push_input_event: {}"), (int)event.key); } } @@ -23,7 +23,7 @@ namespace RC::Input auto& key_set = handler->get_subscribed_keys(); while (event) { - Output::send(SYSSTR("QueueInputSource::reveive key event: {}"), (int)event->key); + Output::send(STR("QueueInputSource::reveive key event: {}"), (int)event->key); if (key_set[event->key]) { m_input_events.emplace_back(*event); From 6dbf1175b1d81f0d94d703b14518a3f5653d07b6 Mon Sep 17 00:00:00 2001 From: UE4SS Date: Wed, 8 Jan 2025 19:07:46 +0100 Subject: [PATCH 16/24] Various fixes, probably from broken cherry-pick --- UE4SS/include/SettingsManager.hpp | 1 + UE4SS/src/UE4SSProgram.cpp | 4 +++- deps/first/Input/src/Handler.cpp | 3 +++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/UE4SS/include/SettingsManager.hpp b/UE4SS/include/SettingsManager.hpp index 880c025fd..fd59293a1 100644 --- a/UE4SS/include/SettingsManager.hpp +++ b/UE4SS/include/SettingsManager.hpp @@ -25,6 +25,7 @@ namespace RC bool EnableDebugKeyBindings{false}; int64_t SecondsToScanBeforeGivingUp{30}; bool UseUObjectArrayCache{true}; + StringType InputSource{STR("Default")}; } General; struct SectionEngineVersionOverride diff --git a/UE4SS/src/UE4SSProgram.cpp b/UE4SS/src/UE4SSProgram.cpp index f48e20d42..0161f67ba 100644 --- a/UE4SS/src/UE4SSProgram.cpp +++ b/UE4SS/src/UE4SSProgram.cpp @@ -880,11 +880,12 @@ namespace RC } #ifdef HAS_INPUT + m_input_handler.init(); if (!settings_manager.General.InputSource.empty()) { if (m_input_handler.set_input_source(to_string(settings_manager.General.InputSource))) { - Output::send(STR("Input source set to: {}\n"), m_input_handler.get_current_input_source()); + Output::send(STR("Input source set to: {}\n"), to_generic_string(m_input_handler.get_current_input_source())); } else { @@ -1549,6 +1550,7 @@ namespace RC { return m_input_handler.is_keydown_event_registered(key, modifier_keys); } +#endif auto UE4SSProgram::find_mod_by_name_internal(StringViewType mod_name, IsInstalled is_installed, IsStarted is_started, FMBNI_ExtraPredicate extra_predicate) -> Mod* { diff --git a/deps/first/Input/src/Handler.cpp b/deps/first/Input/src/Handler.cpp index 0165e16ff..abc7c0442 100644 --- a/deps/first/Input/src/Handler.cpp +++ b/deps/first/Input/src/Handler.cpp @@ -4,6 +4,8 @@ #include #include +#include + namespace RC::Input { std::unordered_map> Handler::m_input_sources_store; @@ -159,6 +161,7 @@ namespace RC::Input } if (highest_priority == INT_MAX) { + Output::send(STR("Input source: Source not found\n")); return false; } } From 4c6676cb506c157d394813d776ae1e201decf285 Mon Sep 17 00:00:00 2001 From: UE4SS Date: Wed, 8 Jan 2025 19:09:41 +0100 Subject: [PATCH 17/24] Input: clang-format --- deps/first/Input/include/Input/Handler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/first/Input/include/Input/Handler.hpp b/deps/first/Input/include/Input/Handler.hpp index 0eca08862..16219c536 100644 --- a/deps/first/Input/include/Input/Handler.hpp +++ b/deps/first/Input/include/Input/Handler.hpp @@ -52,7 +52,7 @@ namespace RC::Input std::mutex m_event_mutex; public: - Handler(){}; + Handler() {}; // Input source and event processing public: From e0d7f684535e50fd4c1df1751892951ee2233881 Mon Sep 17 00:00:00 2001 From: Yangff Date: Tue, 11 Jun 2024 07:32:33 +0200 Subject: [PATCH 18/24] Input Source: use new input_handler in UVTD --- UVTD/src/UVTD.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UVTD/src/UVTD.cpp b/UVTD/src/UVTD.cpp index c1d28f83f..5dc72bba4 100644 --- a/UVTD/src/UVTD.cpp +++ b/UVTD/src/UVTD.cpp @@ -27,7 +27,7 @@ namespace RC::UVTD { bool processing_events{false}; - Input::Handler input_handler{STR("ConsoleWindowClass"), STR("UnrealWindow")}; + Input::Handler input_handler{}; auto static event_loop_update() -> void { @@ -40,6 +40,8 @@ namespace RC::UVTD auto main(DumpSettings dump_settings) -> void { + input_handler.init(); + input_handler.set_input_source("Win32Async"); static std::vector pdbs_to_dump{ "PDBs/4_10.pdb", "PDBs/4_11.pdb", From 8f64196d847b46b52379cee7bf1c598fdc9f0601 Mon Sep 17 00:00:00 2001 From: UE4SS Date: Wed, 8 Jan 2025 20:11:22 +0100 Subject: [PATCH 19/24] Input: Fix UVTD --- UE4SS/xmake.lua | 8 -------- UVTD/include/UVTD/UVTD.hpp | 1 - UVTD/src/UVTD.cpp | 12 ------------ xmake.lua | 8 ++++++++ 4 files changed, 8 insertions(+), 21 deletions(-) diff --git a/UE4SS/xmake.lua b/UE4SS/xmake.lua index aeb7085a2..f26df6354 100644 --- a/UE4SS/xmake.lua +++ b/UE4SS/xmake.lua @@ -34,14 +34,6 @@ option("versionCheck") set_description("Will xmake check the installed MSVC and Rust versions on configuration step") -option("ue4ssInput") - set_default(true) - set_showmenu(true) - - add_defines("HAS_INPUT") - - set_description("Enable the input system.") - local projectName = "UE4SS" local function parse_version_string(str) diff --git a/UVTD/include/UVTD/UVTD.hpp b/UVTD/include/UVTD/UVTD.hpp index 4e41dd47c..efcf459ff 100644 --- a/UVTD/include/UVTD/UVTD.hpp +++ b/UVTD/include/UVTD/UVTD.hpp @@ -15,7 +15,6 @@ namespace RC::UVTD { extern bool processing_events; - extern Input::Handler input_handler; auto main(DumpSettings) -> void; } // namespace RC::UVTD diff --git a/UVTD/src/UVTD.cpp b/UVTD/src/UVTD.cpp index 5dc72bba4..3b3bd09d1 100644 --- a/UVTD/src/UVTD.cpp +++ b/UVTD/src/UVTD.cpp @@ -27,21 +27,9 @@ namespace RC::UVTD { bool processing_events{false}; - Input::Handler input_handler{}; - - auto static event_loop_update() -> void - { - for (processing_events = true; processing_events;) - { - input_handler.process_event(); - std::this_thread::sleep_for(std::chrono::milliseconds(5)); - } - } auto main(DumpSettings dump_settings) -> void { - input_handler.init(); - input_handler.set_input_source("Win32Async"); static std::vector pdbs_to_dump{ "PDBs/4_10.pdb", "PDBs/4_11.pdb", diff --git a/xmake.lua b/xmake.lua index fc7c028b7..96a994447 100644 --- a/xmake.lua +++ b/xmake.lua @@ -65,3 +65,11 @@ option("ue4ssCross") set_values("msvc-wine", "None") set_description("Which cross-compiling toolchain to use", "msvc-wine", "None") + +option("ue4ssInput") + set_default(true) + set_showmenu(true) + + add_defines("HAS_INPUT") + + set_description("Enable the input system.") From 22b739938c98967e0e8a61c52f541408522d50be Mon Sep 17 00:00:00 2001 From: UE4SS Date: Thu, 9 Jan 2025 19:25:19 +0100 Subject: [PATCH 20/24] Make public APIs not disappear if HAS_INPUT isn't defined --- UE4SS/include/UE4SSProgram.hpp | 10 ++------ UE4SS/src/Mod/LuaMod.cpp | 4 ++-- UE4SS/src/UE4SSProgram.cpp | 28 ++++++++++++---------- deps/first/Input/include/Input/Handler.hpp | 23 ------------------ deps/first/Input/include/Input/KeyDef.hpp | 25 +++++++++++++++++++ 5 files changed, 45 insertions(+), 45 deletions(-) diff --git a/UE4SS/include/UE4SSProgram.hpp b/UE4SS/include/UE4SSProgram.hpp index 87352bd60..44dd4e7c9 100644 --- a/UE4SS/include/UE4SSProgram.hpp +++ b/UE4SS/include/UE4SSProgram.hpp @@ -13,6 +13,8 @@ #include #ifdef HAS_INPUT #include +#else +#include #endif #include @@ -226,12 +228,6 @@ namespace RC RC_UE4SS_API auto generate_uht_compatible_headers() -> void; RC_UE4SS_API auto generate_cxx_headers(const std::filesystem::path& output_dir) -> void; RC_UE4SS_API auto generate_lua_types(const std::filesystem::path& output_dir) -> void; -#ifdef HAS_INPUT - auto get_input_handler() -> Input::Handler& - { - return m_input_handler; - } -#endif auto get_debugging_ui() -> GUI::DebuggingGUI& { return m_debugging_gui; @@ -255,7 +251,6 @@ namespace RC } public: -#ifdef HAS_INPUT // API pass-through for use outside the private scope of UE4SSProgram RC_UE4SS_API auto register_keydown_event(Input::Key, const Input::EventCallbackCallable&, uint8_t custom_data = 0, void* custom_data2 = nullptr) -> void; RC_UE4SS_API auto register_keydown_event(Input::Key, @@ -265,7 +260,6 @@ namespace RC void* custom_data2 = nullptr) -> void; RC_UE4SS_API auto is_keydown_event_registered(Input::Key) -> bool; RC_UE4SS_API auto is_keydown_event_registered(Input::Key, const Input::Handler::ModifierKeyArray&) -> bool; -#endif private: static auto install_cpp_mods() -> void; diff --git a/UE4SS/src/Mod/LuaMod.cpp b/UE4SS/src/Mod/LuaMod.cpp index ebe6375e3..e1a0f79db 100644 --- a/UE4SS/src/Mod/LuaMod.cpp +++ b/UE4SS/src/Mod/LuaMod.cpp @@ -14,6 +14,8 @@ #ifdef HAS_INPUT #include +#else +#include #endif #include @@ -1054,7 +1056,6 @@ No overload found for function 'FindAllOf'. if (is_true_mod == Mod::IsTrueMod::Yes) { -#ifdef HAS_INPUT lua.register_function("IsKeyBindRegistered", [](const LuaMadeSimple::Lua& lua) -> int { std::string error_overload_not_found{R"( No overload found for function 'IsKeyBindRegistered'. @@ -1352,7 +1353,6 @@ No overload found for function 'RegisterKeyBind'. return 0; }); -#endif lua.register_function("UnregisterHook", [](const LuaMadeSimple::Lua& lua) -> int { std::lock_guard guard{LuaMod::m_thread_actions_mutex}; diff --git a/UE4SS/src/UE4SSProgram.cpp b/UE4SS/src/UE4SSProgram.cpp index 0161f67ba..cc9089017 100644 --- a/UE4SS/src/UE4SSProgram.cpp +++ b/UE4SS/src/UE4SSProgram.cpp @@ -824,8 +824,7 @@ namespace RC { m_debugging_gui.get_live_view().set_listeners_allowed(false); } -#ifdef HAS_INPUT - m_input_handler.register_keydown_event(Input::Key::O, {Input::ModifierKey::CONTROL}, [&]() { + register_keydown_event(Input::Key::O, {Input::ModifierKey::CONTROL}, [&]() { TRY([&] { auto was_gui_open = get_debugging_ui().is_open(); stop_render_thread(); @@ -836,11 +835,10 @@ namespace RC } }); }); -#endif } #ifdef TIME_FUNCTION_MACRO_ENABLED - m_input_handler.register_keydown_event(Input::Key::Y, {Input::ModifierKey::CONTROL}, [&]() { + register_keydown_event(Input::Key::Y, {Input::ModifierKey::CONTROL}, [&]() { if (FunctionTimerFrame::s_timer_enabled) { FunctionTimerFrame::stop_profiling(); @@ -857,16 +855,14 @@ namespace RC TRY([&] { ObjectDumper::init(); -#ifdef HAS_INPUT if (settings_manager.General.EnableHotReloadSystem) { - m_input_handler.register_keydown_event(Input::Key::R, {Input::ModifierKey::CONTROL}, [&]() { + register_keydown_event(Input::Key::R, {Input::ModifierKey::CONTROL}, [&]() { TRY([&] { reinstall_mods(); }); }); } -#endif if ((settings_manager.ObjectDumper.LoadAllAssetsBeforeDumpingObjects || settings_manager.CXXHeaderGenerator.LoadAllAssetsBeforeGeneratingCXXHeaders) && Unreal::Version::IsBelow(4, 17)) { @@ -900,14 +896,12 @@ namespace RC start_lua_mods(); }); -#ifdef HAS_INPUT if (settings_manager.General.EnableDebugKeyBindings) { - m_input_handler.register_keydown_event(Input::Key::NUM_NINE, {Input::ModifierKey::CONTROL}, [&]() { + register_keydown_event(Input::Key::NUM_NINE, {Input::ModifierKey::CONTROL}, [&]() { generate_uht_compatible_headers(); }); } -#endif } auto UE4SSProgram::update() -> void @@ -1526,10 +1520,11 @@ namespace RC return m_queued_events.empty(); } -#ifdef HAS_INPUT auto UE4SSProgram::register_keydown_event(Input::Key key, const Input::EventCallbackCallable& callback, uint8_t custom_data, void* custom_data2) -> void { +#ifdef HAS_INPUT m_input_handler.register_keydown_event(key, callback, custom_data, custom_data2); +#endif } auto UE4SSProgram::register_keydown_event(Input::Key key, @@ -1538,19 +1533,28 @@ namespace RC uint8_t custom_data, void* custom_data2) -> void { +#ifdef HAS_INPUT m_input_handler.register_keydown_event(key, modifier_keys, callback, custom_data, custom_data2); +#endif } auto UE4SSProgram::is_keydown_event_registered(Input::Key key) -> bool { +#ifdef HAS_INPUT return m_input_handler.is_keydown_event_registered(key); +#else + return false; +#endif } auto UE4SSProgram::is_keydown_event_registered(Input::Key key, const Input::Handler::ModifierKeyArray& modifier_keys) -> bool { +#ifdef HAS_INPUT return m_input_handler.is_keydown_event_registered(key, modifier_keys); - } +#else + return false; #endif + } auto UE4SSProgram::find_mod_by_name_internal(StringViewType mod_name, IsInstalled is_installed, IsStarted is_started, FMBNI_ExtraPredicate extra_predicate) -> Mod* { diff --git a/deps/first/Input/include/Input/Handler.hpp b/deps/first/Input/include/Input/Handler.hpp index 16219c536..d9984273b 100644 --- a/deps/first/Input/include/Input/Handler.hpp +++ b/deps/first/Input/include/Input/Handler.hpp @@ -16,29 +16,6 @@ namespace RC::Input { - using EventCallbackCallable = std::function; - - struct InputEvent - { - Key key; - ModifierKeys modifier_keys{}; - }; - - struct KeyData - { - ModifierKeys required_modifier_keys{}; - EventCallbackCallable callback{}; - uint8_t custom_data{}; - void* custom_data2{}; - bool requires_modifier_keys{}; - bool is_down{}; - }; - - struct KeySet - { - std::unordered_map> key_data; - }; - class PlatformInputSource; class RC_INPUT_API Handler { diff --git a/deps/first/Input/include/Input/KeyDef.hpp b/deps/first/Input/include/Input/KeyDef.hpp index 4ff7101fb..104c27598 100644 --- a/deps/first/Input/include/Input/KeyDef.hpp +++ b/deps/first/Input/include/Input/KeyDef.hpp @@ -3,6 +3,8 @@ #include #include #include +#include + namespace RC::Input { static constexpr uint32_t max_callbacks_per_event = 30; @@ -302,4 +304,27 @@ namespace RC::Input auto operator&(const ModifierKeys& keys, const ModifierKeys& key) -> bool; auto operator++(Input::Key& key) -> Input::Key&; + + using EventCallbackCallable = std::function; + + struct InputEvent + { + Key key; + ModifierKeys modifier_keys{}; + }; + + struct KeyData + { + ModifierKeys required_modifier_keys{}; + EventCallbackCallable callback{}; + uint8_t custom_data{}; + void* custom_data2{}; + bool requires_modifier_keys{}; + bool is_down{}; + }; + + struct KeySet + { + std::unordered_map> key_data; + }; } // namespace RC::Input From 1b939bbf36a58edb8f40434b874f1f702e31550f Mon Sep 17 00:00:00 2001 From: UE4SS Date: Thu, 9 Jan 2025 19:42:56 +0100 Subject: [PATCH 21/24] Made Handler.hpp always be the correct header to include --- UE4SS/include/UE4SSProgram.hpp | 4 ---- UE4SS/src/Mod/LuaMod.cpp | 4 ---- deps/first/Input/include/Input/Handler.hpp | 11 ++++++++++- deps/first/Input/xmake.lua | 1 + 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/UE4SS/include/UE4SSProgram.hpp b/UE4SS/include/UE4SSProgram.hpp index 44dd4e7c9..f132292c3 100644 --- a/UE4SS/include/UE4SSProgram.hpp +++ b/UE4SS/include/UE4SSProgram.hpp @@ -11,11 +11,7 @@ #include #include #include -#ifdef HAS_INPUT #include -#else -#include -#endif #include #include diff --git a/UE4SS/src/Mod/LuaMod.cpp b/UE4SS/src/Mod/LuaMod.cpp index e1a0f79db..a113ea031 100644 --- a/UE4SS/src/Mod/LuaMod.cpp +++ b/UE4SS/src/Mod/LuaMod.cpp @@ -12,11 +12,7 @@ #include #include -#ifdef HAS_INPUT #include -#else -#include -#endif #include #include diff --git a/deps/first/Input/include/Input/Handler.hpp b/deps/first/Input/include/Input/Handler.hpp index d9984273b..ccf0655f3 100644 --- a/deps/first/Input/include/Input/Handler.hpp +++ b/deps/first/Input/include/Input/Handler.hpp @@ -16,6 +16,8 @@ namespace RC::Input { + using ModifierKeyArray = std::array; +#ifdef HAS_INPUT class PlatformInputSource; class RC_INPUT_API Handler { @@ -42,7 +44,7 @@ namespace RC::Input auto register_keydown_event(Input::Key, EventCallbackCallable, uint8_t custom_data = 0, void* custom_data2 = nullptr) -> void; - using ModifierKeyArray = std::array; + using ModifierKeyArray = Input::ModifierKeyArray; auto register_keydown_event(Input::Key, const ModifierKeyArray&, const EventCallbackCallable&, uint8_t custom_data = 0, void* custom_data2 = nullptr) -> void; auto is_keydown_event_registered(Input::Key) -> bool; @@ -77,6 +79,13 @@ namespace RC::Input return nullptr; } }; +#else + class Handler + { + public: + using ModifierKeyArray = Input::ModifierKeyArray; + }; +#endif // HAS_INPUT } // namespace RC::Input #endif // IO_INPUT_HANDLER_HPP diff --git a/deps/first/Input/xmake.lua b/deps/first/Input/xmake.lua index a1231bea7..2f9297dc7 100644 --- a/deps/first/Input/xmake.lua +++ b/deps/first/Input/xmake.lua @@ -5,6 +5,7 @@ target(projectName) set_languages("cxx23") set_exceptions("cxx") add_rules("ue4ss.dependency") + add_options("ue4ssInput") add_includedirs("include", { public = true }) add_headerfiles("include/**.hpp") From 0d833739081ac7673af64171f06e2f30fffc3c7e Mon Sep 17 00:00:00 2001 From: UE4SS Date: Thu, 9 Jan 2025 19:53:24 +0100 Subject: [PATCH 22/24] Fixed build when --ue4ssInput=n --- UE4SS/src/Mod/CppUserModBase.cpp | 2 ++ deps/first/Input/xmake.lua | 12 ++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/UE4SS/src/Mod/CppUserModBase.cpp b/UE4SS/src/Mod/CppUserModBase.cpp index 465ee2625..2cacc2dc8 100644 --- a/UE4SS/src/Mod/CppUserModBase.cpp +++ b/UE4SS/src/Mod/CppUserModBase.cpp @@ -26,6 +26,7 @@ namespace RC } GUITabs.clear(); +#ifdef HAS_INPUT UE4SSProgram::get_program().m_input_handler.get_events_safe([&](auto& key_set) { std::erase_if(key_set.key_data, [&](auto& item) -> bool { auto& [_, key_data] = item; @@ -49,6 +50,7 @@ namespace RC return were_all_events_registered_from_this_mod; }); }); +#endif } auto CppUserModBase::register_tab(StringViewType tab_name, GUI::GUITab::RenderFunctionType render_function) -> void diff --git a/deps/first/Input/xmake.lua b/deps/first/Input/xmake.lua index 2f9297dc7..c84cf2352 100644 --- a/deps/first/Input/xmake.lua +++ b/deps/first/Input/xmake.lua @@ -10,12 +10,16 @@ target(projectName) add_includedirs("include", { public = true }) add_headerfiles("include/**.hpp") - add_files("src/**.cpp|Platform/**.cpp") + if get_config("ue4ssInput") then + add_files("src/**.cpp|Platform/**.cpp") + end add_deps("DynamicOutput") if is_plat("windows") then - add_files("src/Platform/Win32AsyncInputSource.cpp") - add_files("src/Platform/GLFW3InputSource.cpp") - add_files("src/Platform/QueueInputSource.cpp") + if get_config("ue4ssInput") then + add_files("src/Platform/Win32AsyncInputSource.cpp") + add_files("src/Platform/GLFW3InputSource.cpp") + add_files("src/Platform/QueueInputSource.cpp") + end end From 0524dc856891286ada20ab4992fc2f09a0b149c6 Mon Sep 17 00:00:00 2001 From: UE4SS Date: Thu, 9 Jan 2025 19:55:37 +0100 Subject: [PATCH 23/24] Moved back various definitions from KeyDef.hpp to Handler.hpp --- deps/first/Input/include/Input/Handler.hpp | 24 ++++++++++++++++++++++ deps/first/Input/include/Input/KeyDef.hpp | 24 ---------------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/deps/first/Input/include/Input/Handler.hpp b/deps/first/Input/include/Input/Handler.hpp index ccf0655f3..8e68ee78c 100644 --- a/deps/first/Input/include/Input/Handler.hpp +++ b/deps/first/Input/include/Input/Handler.hpp @@ -16,7 +16,31 @@ namespace RC::Input { + using EventCallbackCallable = std::function; + + struct InputEvent + { + Key key; + ModifierKeys modifier_keys{}; + }; + + struct KeyData + { + ModifierKeys required_modifier_keys{}; + EventCallbackCallable callback{}; + uint8_t custom_data{}; + void* custom_data2{}; + bool requires_modifier_keys{}; + bool is_down{}; + }; + + struct KeySet + { + std::unordered_map> key_data; + }; + using ModifierKeyArray = std::array; + #ifdef HAS_INPUT class PlatformInputSource; class RC_INPUT_API Handler diff --git a/deps/first/Input/include/Input/KeyDef.hpp b/deps/first/Input/include/Input/KeyDef.hpp index 104c27598..6f6373667 100644 --- a/deps/first/Input/include/Input/KeyDef.hpp +++ b/deps/first/Input/include/Input/KeyDef.hpp @@ -3,7 +3,6 @@ #include #include #include -#include namespace RC::Input { @@ -304,27 +303,4 @@ namespace RC::Input auto operator&(const ModifierKeys& keys, const ModifierKeys& key) -> bool; auto operator++(Input::Key& key) -> Input::Key&; - - using EventCallbackCallable = std::function; - - struct InputEvent - { - Key key; - ModifierKeys modifier_keys{}; - }; - - struct KeyData - { - ModifierKeys required_modifier_keys{}; - EventCallbackCallable callback{}; - uint8_t custom_data{}; - void* custom_data2{}; - bool requires_modifier_keys{}; - bool is_down{}; - }; - - struct KeySet - { - std::unordered_map> key_data; - }; } // namespace RC::Input From e6ccaad32de9137b6169055ddb7206a5322e39e1 Mon Sep 17 00:00:00 2001 From: UE4SS Date: Thu, 9 Jan 2025 22:51:19 +0100 Subject: [PATCH 24/24] Replaced include-guard with #pragma once for Handler.hpp --- deps/first/Input/include/Input/Handler.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/deps/first/Input/include/Input/Handler.hpp b/deps/first/Input/include/Input/Handler.hpp index 8e68ee78c..e4f0366c2 100644 --- a/deps/first/Input/include/Input/Handler.hpp +++ b/deps/first/Input/include/Input/Handler.hpp @@ -1,5 +1,4 @@ -#ifndef IO_INPUT_HANDLER_HPP -#define IO_INPUT_HANDLER_HPP +#pragma once // TODO: Abstract more... need to get rid of Windows.h from InputHandler.cpp @@ -111,5 +110,3 @@ namespace RC::Input }; #endif // HAS_INPUT } // namespace RC::Input - -#endif // IO_INPUT_HANDLER_HPP