summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-10-02 10:46:05 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-10-02 10:46:05 -0400
commit22062b43dbfeb78bdabf8f2693fcf880349d9cde (patch)
treea3cab35ff4fd5542f59095f4b6e54e8cc9577f17 /src
parent3dd940cc0a9f985f7c7520f5064840cf7a25d5c9 (diff)
pke: input: fifo enforcement + track mouse pos
Diffstat (limited to 'src')
-rw-r--r--src/player-input.cpp222
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 = &registeredCursorEnterEvents[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 = &registeredCursorPosEvents[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 = &registeredKeyEvents[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 = &registeredMouseButtonEvents[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 = &registeredScrollEvents[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 = &registeredWindowFocusEvents[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(&registeredCursorEnterEvents, 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(&registeredWindowFocusEvents, 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(&registeredCursorEnterEvents, 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);