diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-02 10:46:05 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-02 10:46:05 -0400 |
| commit | 22062b43dbfeb78bdabf8f2693fcf880349d9cde (patch) | |
| tree | a3cab35ff4fd5542f59095f4b6e54e8cc9577f17 | |
| parent | 3dd940cc0a9f985f7c7520f5064840cf7a25d5c9 (diff) | |
pke: input: fifo enforcement + track mouse pos
| -rw-r--r-- | src/player-input.cpp | 222 |
1 files changed, 102 insertions, 120 deletions
diff --git a/src/player-input.cpp b/src/player-input.cpp index cc9d109..6eb157c 100644 --- a/src/player-input.cpp +++ b/src/player-input.cpp @@ -6,6 +6,23 @@ #include <GLFW/glfw3.h> +/* pke_input is weird. + * We are trying to enforce FIFO for both: + * - activate/deactivate + * - register/unregister + * However, this may or may not be practical (for each individually). + * If this does becomes impractical, I believe the solution will be to convert + * most of this file to pk_bkt_arr's. + * However, this will cause some annoyances with precedence. + * Currently, a `pke_input_action` tracks its event index when activated. + * Currently, When searching for the most recently registered input, we + * assume the last is the most recent. + * If we switch to a pk_bkt_arr, then the "newest" item won't be at the end + * and will require a new method to find the most-recent. + * If we stick with arrays and an object in the middle is removed, an + * extensive search would be required to fix all proceeding indexes. + */ + struct pke_input_unhandled_event { pke_input_event_hash type; union pke_input_unhandled_event_data { @@ -108,70 +125,9 @@ template<pke_input_event_hash T, typename S> pke_input_event_hash FindActivepke_ } return pke_input_event_hash{0}; } -/* -template<pke_input_event_hash T, typename S> pke_input_event_hash FindActivepke_input_action_ByName(const char *actionName, S *&activeEvent) { - activeEvent = nullptr; - bool any = false; - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != pke_input_event_hash{0}) { - any = any || bool(registeredCursorEnterEvents.next); - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != pke_input_event_hash{0}) { - any = any || bool(registeredCursorPosEvents.next); - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != pke_input_event_hash{0}) { - any = any || bool(registeredKeyEvents.next); - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != pke_input_event_hash{0}) { - any = any || bool(registeredMouseButtonEvents.next); - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != pke_input_event_hash{0}) { - any = any || bool(registeredScrollEvents.next); - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != pke_input_event_hash{0}) { - any = any || bool(registeredWindowFocusEvents.next); - } - if (any == false) return pke_input_event_hash{0}; - uint32_t count = activeInputSetStack.next; - for (uint32_t i = count; i > 0; --i) { - pke_input_action_set_handle handle = activeInputSetStack[i-1]; - pke_input_action_set_handle_T index = static_cast<pke_input_action_set_handle_T>(handle); - pke_input_set &set = registeredInputSets[index]; - for (int64_t k = 0; k < set.actionCount; ++k) { - pke_input_action &inputAction = set.actions[k]; - if (strcmp(actionName, inputAction.name) != 0) { - continue; - }; - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != pke_input_event_hash{0}) { - activeEvent = ®isteredCursorEnterEvents[inputAction.eventIndex]; - return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER; - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != pke_input_event_hash{0}) { - activeEvent = ®isteredCursorPosEvents[inputAction.eventIndex]; - return PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS; - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_KEY) != pke_input_event_hash{0}) { - activeEvent = ®isteredKeyEvents[inputAction.eventIndex]; - return PKE_INPUT_HASH_EVENT_TYPE_KEY; - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != pke_input_event_hash{0}) { - activeEvent = ®isteredMouseButtonEvents[inputAction.eventIndex]; - return PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON; - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != pke_input_event_hash{0}) { - activeEvent = ®isteredScrollEvents[inputAction.eventIndex]; - return PKE_INPUT_HASH_EVENT_TYPE_SCROLL; - } - if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != pke_input_event_hash{0}) { - activeEvent = ®isteredWindowFocusEvents[inputAction.eventIndex]; - return PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS; - } - } - } - return pke_input_event_hash{0}; -} -*/ template<pke_input_event_hash T> pke_input_event_hash FindActivepke_input_action_ByType(const pke_input_event_mask &mask, pke_input_event *&activeEvent) { - uint32_t count, i; + uint32_t i; + int64_t k,l; activeEvent = nullptr; bool any = false; if constexpr((T & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != pke_input_event_hash{0}) { @@ -193,15 +149,14 @@ template<pke_input_event_hash T> pke_input_event_hash FindActivepke_input_action any = any || bool(registeredWindowFocusEvents.next); } if (any == false) return pke_input_event_hash{0}; - count = activeInputSetStack.next; - for (i = count; i > 0; --i) { + for (i = activeInputSetStack.next; i > 0; --i) { pke_input_action_set_handle handle = activeInputSetStack[i-1]; if (handle == pke_input_action_set_handle_MAX) continue; pke_input_action_set_handle_T index = static_cast<pke_input_action_set_handle_T>(handle); pke_input_set &set = registeredInputSets[index]; - for (int64_t k = 0; k < set.actionCount; ++k) { + for (k = 0; k < set.actionCount; ++k) { pke_input_action &inputAction = set.actions[k]; - for (int64_t l = 0; l < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++l) { + for (l = 0; l < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++l) { pke_input_event_mask &evMask = inputAction.masks[l]; if ((evMask.computedHash & mask.computedHash) == pke_input_event_hash{0}) { continue; @@ -249,6 +204,7 @@ template<pke_input_event_hash T> pke_input_event_hash FindActivepke_input_action } } } + fprintf(stderr, "[pke_input][FindActivepke_input_action_ByType] hash: %hu had events but found 0.\n", static_cast<pke_input_event_hash_T>(T)); return pke_input_event_hash{0}; } constexpr auto FindActivepke_input_action_CursorEnter_ByType = FindActivepke_input_action_ByType<PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER>; @@ -268,32 +224,28 @@ constexpr auto FindActivepke_input_action_WindowFocus_ByType = FindActivepke_inp void pke_input_tick(double delta) { (void)delta; - uint32_t count, i; + uint32_t i; // reset everything // @performance could happen concurrently { - count = registeredCursorPosEvents.next; - for (i = 0; i < count; ++i) { + for (i = 0; i < registeredCursorPosEvents.next; ++i) { auto &ev = registeredCursorPosEvents[i]; ev.data.cursor_pos.xMotion = 0; ev.data.cursor_pos.yMotion = 0; } - count = registeredKeyEvents.next; - for (i = 0; i < count; ++i) { + for (i = 0; i < registeredKeyEvents.next; ++i) { auto &ev = registeredKeyEvents[i]; // TODO the idea here was right, but wrong place and too wide a swath // if (i < count - 1) ev.isPressed = false; ev.data.key.thisTick = false; } - count = registeredMouseButtonEvents.next; - for (i = 0; i < count; ++i) { + for (i = 0; i < registeredMouseButtonEvents.next; ++i) { auto &ev = registeredMouseButtonEvents[i]; // TODO the idea here was right, but wrong place and too wide a swath // if (i < count - 1) ev.isPressed = false; ev.data.mouse_button.thisTick = false; } - count = registeredScrollEvents.next; - for (i = 0; i < count; ++i) { + for (i = 0; i < registeredScrollEvents.next; ++i) { auto &ev = registeredScrollEvents[i]; ev.data.scroll.xMotion = 0; ev.data.scroll.yMotion = 0; @@ -303,6 +255,13 @@ void pke_input_tick(double delta) { // handle unhandled events // @performance cache action->event results // 2025-07-23 JCB I'm not sure what this perf message means. + // 2025-10-01 JCB + // It means hold on to the "last" event per-hash so we don't + // have to keep looking it up. + // Might be tricky for keys, but for all other events we could hold a global + // pointer, updated on register/unregister; no more searching. + // A Dictionary/Map would be a good candidate, but we do not currently have a + // performant option. pke_input_event *primary_event = nullptr; for (i = 0; i < unhandled_events.next; ++i) { pke_input_unhandled_event &uh_ev = unhandled_events[i]; @@ -311,17 +270,19 @@ void pke_input_tick(double delta) { FindActivepke_input_action_CursorEnter_ByType(pke_input_event_mask { .computedHash = PKE_INPUT_HASH_ALL_CURSOR_ENTER_EVENTS }, primary_event); - if (primary_event == nullptr) continue; - primary_event->data.cursor_enter.isEntered = uh_ev.data.cursor_enter.entered; + if (primary_event != nullptr) { + primary_event->data.cursor_enter.isEntered = uh_ev.data.cursor_enter.entered; + } lastCursorEntered = uh_ev.data.cursor_enter.entered; break; case PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS: FindActivepke_input_action_CursorPos_ByType(pke_input_event_mask { .computedHash = PKE_INPUT_HASH_ALL_CURSOR_POS_EVENTS }, primary_event); - if (primary_event == nullptr) continue; - primary_event->data.cursor_pos.xMotion += uh_ev.data.cursor_pos.x - lastMousePos.x; - primary_event->data.cursor_pos.yMotion += uh_ev.data.cursor_pos.y - lastMousePos.y; + if (primary_event != nullptr) { + primary_event->data.cursor_pos.xMotion += uh_ev.data.cursor_pos.x - lastMousePos.x; + primary_event->data.cursor_pos.yMotion += uh_ev.data.cursor_pos.y - lastMousePos.y; + } lastMousePos.x = uh_ev.data.cursor_pos.x; lastMousePos.y = uh_ev.data.cursor_pos.y; break; @@ -370,12 +331,13 @@ void pke_input_tick(double delta) { FindActivepke_input_action_WindowFocus_ByType(pke_input_event_mask { .computedHash = PKE_INPUT_HASH_ALL_WINDOW_FOCUS_EVENTS }, primary_event); - if (primary_event == nullptr) continue; - primary_event->data.window_focus.isFocused = uh_ev.data.window_focus.focused; + if (primary_event != nullptr) { + primary_event->data.window_focus.isFocused = uh_ev.data.window_focus.focused; + } lastWindowFocus = uh_ev.data.window_focus.focused; break; default: - fprintf(stderr, "[pke_input_tick] Unknown unhandled input type: %i", pke_input_event_hash_T(uh_ev.type)); + fprintf(stderr, "[pke_input_tick] Unknown \"unhandled input\" type: %i", pke_input_event_hash_T(uh_ev.type)); break; } } @@ -386,21 +348,18 @@ void pke_input_tick(double delta) { // unregistered, the appropriate values are propagated // - theoretically this scenario could be handled on unregister, // but I'm not sure which would be more performant - // JCB 2025-05-21 - // I'm refactoring this and it seems to skip the last element. - // At a glance, I'm not sure if this is intentional or a bug. - // I'm going to preserve this logic in my refactor. - // Update this comment as needed and make sure to document the purpose. + // JCB 2025-10-01 + // Skipping the last element is intentional. + // The "last" element was already handled in the above logic. + // Consider testing handling this on un-register instead. { - count = registeredCursorEnterEvents.next; - for (i = 0; i < count; ++i) { + for (i = 0; i < registeredCursorEnterEvents.next; ++i) { registeredCursorEnterEvents[i].data.cursor_enter.isEntered = lastCursorEntered; - if (i == count-2) break; + if (i == registeredCursorEnterEvents.next-2) break; } - count = registeredWindowFocusEvents.next; - for (i = 0; i < count; ++i) { + for (i = 0; i < registeredWindowFocusEvents.next; ++i) { registeredWindowFocusEvents[i].data.window_focus.isFocused = lastWindowFocus; - if (i == count-2) break; + if (i == registeredWindowFocusEvents.next-2) break; } } } @@ -487,18 +446,17 @@ void CursorEnterCallback(GLFWwindow *window, int entered) { } void CursorPosCallback(GLFWwindow *window, double xPos, double yPos) { - if (registeredCursorPosEvents.next) { - pk_arr_append_t(&unhandled_events, - { - .type = PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS, - .data = { - .cursor_pos = { - .x = xPos, - .y = yPos, - }, + // always handle cursor pos. Used by UI. + pk_arr_append_t(&unhandled_events, + { + .type = PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS, + .data = { + .cursor_pos = { + .x = xPos, + .y = yPos, }, - }); - } + }, + }); if (prevCursorPosCallback) { prevCursorPosCallback(window, xPos, yPos); } @@ -590,24 +548,44 @@ pke_input_action_set_handle pke_input_register_set(const pke_input_set &&set) { void pke_input_activate_set(pke_input_action_set_handle handle) { pke_input_action_set_handle_T index{static_cast<pke_input_action_set_handle_T>(handle)}; + int64_t found_index = -1; + uint32_t before_cursor_enter_count = registeredCursorEnterEvents.next; + uint32_t before_cursor_pos_count = registeredCursorPosEvents.next; + uint32_t before_key_ev_count = registeredKeyEvents.next; + uint32_t before_mb_ev_count = registeredMouseButtonEvents.next; + uint32_t before_scroll_ev_count = registeredScrollEvents.next; + uint32_t before_win_focus_count = registeredWindowFocusEvents.next; + uint32_t i; + for (i = 0; i < activeInputSetStack.next; ++i) { + if (activeInputSetStack[i] == handle) { + found_index = (int64_t)i; + break; + } + } + if (found_index != -1) { + fprintf(stderr, "[pke_input] Attempt to activate an already active set!\n"); + return; + } pk_arr_append_t(&activeInputSetStack, handle); auto &set = registeredInputSets[index]; + fprintf(stdout, "[pke_input] Activating set %hhu \"%s\"\n", static_cast<pke_input_action_set_handle_T>(handle), set.title); for (int64_t i = 0; i < set.actionCount; ++i) { pke_input_action &action = set.actions[i]; for (int k = 0; k < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++k) { + pke_input_event ev {}; + ev.sourceSet = handle; pke_input_event_mask event_mask = action.masks[k]; + if (event_mask.computedHash == pke_input_event_hash{0}) { + continue; + } if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != pke_input_event_hash{0}) { action.event_indices[k] = registeredCursorEnterEvents.next; - pke_input_event ev{}; - ev.sourceSet = handle; ev.type = PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER; ev.data.cursor_enter.isEntered = lastCursorEntered; pk_arr_append_t(®isteredCursorEnterEvents, ev); } if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS) != pke_input_event_hash{0}) { action.event_indices[k] = registeredCursorPosEvents.next; - pke_input_event ev {}; - ev.sourceSet = handle; ev.type = PKE_INPUT_HASH_EVENT_TYPE_CURSOR_POS; ev.data.cursor_pos.xMotion = 0; ev.data.cursor_pos.yMotion = 0; @@ -616,8 +594,6 @@ void pke_input_activate_set(pke_input_action_set_handle handle) { } if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_KEY) != pke_input_event_hash{0}) { action.event_indices[k] = registeredKeyEvents.next; - pke_input_event ev{}; - ev.sourceSet = handle; ev.type = PKE_INPUT_HASH_EVENT_TYPE_KEY; ev.data.key.button = event_mask.button; ev.data.key.mods = event_mask.mods; @@ -625,8 +601,6 @@ void pke_input_activate_set(pke_input_action_set_handle handle) { } if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON) != pke_input_event_hash{0}) { action.event_indices[k] = registeredMouseButtonEvents.next; - pke_input_event ev{}; - ev.sourceSet = handle; ev.type = PKE_INPUT_HASH_EVENT_TYPE_MOUSE_BUTTON; ev.data.mouse_button.button = event_mask.button; ev.data.mouse_button.mods = event_mask.mods; @@ -634,8 +608,6 @@ void pke_input_activate_set(pke_input_action_set_handle handle) { } if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_SCROLL) != pke_input_event_hash{0}) { action.event_indices[k] = registeredScrollEvents.next; - pke_input_event ev{}; - ev.sourceSet = handle; ev.type = PKE_INPUT_HASH_EVENT_TYPE_SCROLL; ev.data.scroll.xMotion = 0; ev.data.scroll.yMotion = 0; @@ -643,14 +615,18 @@ void pke_input_activate_set(pke_input_action_set_handle handle) { } if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS) != pke_input_event_hash{0}) { action.event_indices[k] = registeredWindowFocusEvents.next; - pke_input_event ev{}; - ev.sourceSet = handle; ev.type = PKE_INPUT_HASH_EVENT_TYPE_WINDOW_FOCUS; ev.data.window_focus.isFocused = lastWindowFocus; pk_arr_append_t(®isteredWindowFocusEvents, ev); } } } + fprintf(stdout, "[pke_event] activate set %s change: %u\n", "registeredCursorEnterEvents", registeredCursorEnterEvents.next - before_cursor_enter_count); + fprintf(stdout, "[pke_event] activate set %s change: %u\n", "registeredCursorPosEvents", registeredCursorPosEvents.next - before_cursor_pos_count); + fprintf(stdout, "[pke_event] activate set %s change: %u\n", "registeredKeyEvents", registeredKeyEvents.next - before_key_ev_count); + fprintf(stdout, "[pke_event] activate set %s change: %u\n", "registeredMouseButtonEvents", registeredMouseButtonEvents.next - before_mb_ev_count); + fprintf(stdout, "[pke_event] activate set %s change: %u\n", "registeredScrollEvents", registeredScrollEvents.next - before_scroll_ev_count); + fprintf(stdout, "[pke_event] activate set %s change: %u\n", "registeredWindowFocusEvents", registeredWindowFocusEvents.next - before_win_focus_count); } void pke_input_deactivate_set(pke_input_action_set_handle handle) { @@ -663,16 +639,22 @@ void pke_input_deactivate_set(pke_input_action_set_handle handle) { break; } } - if (index == 0) { + if (index != -1) { fprintf(stderr, "[pke_input] Attempt to deactivate a non-active set.\n"); return; } + if (index != activeInputSetStack.next-1) { + assert(false && "[pke_input] Attempt to deactivate an active set that was not the last activated (FIFO enforcement).\n"); + } pke_input_action_set_handle_T handleIndex{static_cast<pke_input_action_set_handle_T>(handle)}; auto &set = registeredInputSets[handleIndex]; for (int64_t i = set.actionCount - 1; i >= 0; --i) { pke_input_action &action = set.actions[i]; for (int k = 0; k < PKE_INPUT_ACTION_MASK_INDEX_COUNT; ++k) { pke_input_event_mask event_mask = action.masks[k]; + if (event_mask.computedHash == pke_input_event_hash{0}) { + continue; + } if ((event_mask.computedHash & PKE_INPUT_HASH_EVENT_TYPE_CURSOR_ENTER) != pke_input_event_hash{0}) { pk_arr_remove_at(®isteredCursorEnterEvents, action.event_indices[k]); } @@ -702,7 +684,7 @@ bool PkeInput_pke_arr_find_first_handle(void *search_handle, void *list_handle) void pke_input_unregister_set(pke_input_action_set_handle handle) { pke_input_action_set_handle_T index{static_cast<pke_input_action_set_handle_T>(handle)}; - assert(index == registeredInputSets.next - 1 && "pke_input_unregister_set - expected InputActionSet to be the last set registered"); + assert(index == registeredInputSets.next - 1 && "pke_input_unregister_set - expected InputActionSet to be the last set registered (fifo enforcement)"); const auto &set = registeredInputSets[index]; if (pk_arr_find_first_index(&activeInputSetStack, &handle, PkeInput_pke_arr_find_first_handle) != uint32_t(-1)) { pke_input_deactivate_set(handle); |
