**The Goal:** Track keyboard input with two modes - "held down" and "just pressed" (transition detection). **The Tool:** `SDL_GetKeyboardState(NULL)` returns a pointer to an internal array indexed by scancode. Each entry is `true` or `false` representing the current key state. --- ### Breakpoint #1: The Return Type Ambiguity `const bool *SDL_GetKeyboardState(int *numkeys);` That `const bool *` could mean anything - a single value, an array, the first element of a larger structure. The type system doesn't tell you the contract. You learn it from the docs. In Rust, the same function might look like: ``` fn get_keyboard_state(&self) -> &[u8] // Borrowed slice, length known // or fn get_keyboard_state(&self) -> &[u8; 512] // Fixed-size array, compile-time size ``` Either way, the type communicates something: slice (length known at runtime), or fixed array (size encoded in the type). You don't have to read documentation to understand what you're getting back. C's `bool *` tells you nothing except "there's a bool somewhere in memory pointed to by this address." Rust's `&[T]` or `[T; N]` tells you "this is a collection, here's how many elements." The difference isn't correctness - it's discoverability. C puts the burden on you to read the docs. Rust puts the burden on the compiler to verify the contract. --- ### Breakpoint #2: Frame Boundary Sequencing You can't detect transitions from one snapshot. You need two frames: 1. Grab new snapshot 2. Compare current vs previous 3. Overwrite previous with current Order matters. Copy first? You lose all transitions. --- ### Breakpoint #3: Terminal goes brrrrr After some debugging using the best debugging tool - `printf` - comparing `current` and `previous` values revealed that `W Just released` never triggered. ``` if (!input_state->current[SDL_SCANCODE_W] && input_state->previous[SDL_SCANCODE_W]) { printf("W Just released\n"); } if (input_state->current[SDL_SCANCODE_W] && !input_state->previous[SDL_SCANCODE_W]) { printf("W Just pressed\n"); } ``` The game loop was running uncapped - well above 60fps - flooding the terminal with output. My first hypothesis: the "just released" message was getting lost in the buffer due to sheer volume. Adding VSync to the renderer capped the loop to the monitor's refresh rate: `SDL_SetRenderVSync(engine->renderer, 1);` Output became readable. But "just released" still didn't fire. Speed wasn't the cause - the `previous` array was never updating at all. The debug output confirmed it: ``` current[W]=1 previous[W]=0 current[W]=1 previous[W]=0 current[W]=1 previous[W]=0 current[W]=0 previous[W]=0 ``` `previous[W]` stayed at `0` regardless of what `current[W]` showed. The `memcpy` at the end of `input_update` wasn't copying anything. This pointed straight to the struct definition - which became Breakpoint #4. --- ### Breakpoint #4: The `bool *` vs `bool[]` Confusion ``` // Wrong typedef struct InputState { const bool *current; bool *previousi[SDL_SCANCODE_COUNT]; // ← Pointer, not array } InputState; // Right typedef struct InputState { const bool *current; // SDL's internal pointer bool previous[SDL_SCANCODE_COUNT]; // Your own array } InputState; ``` Mixing them up caused `memcpy` to write nowhere. Silent corruption. Compiler warnings ignored. Debugger output lying to me until I added explicit tests. The `incompatible integer to pointer conversion` error should have been the first stop at this breakpoint. --- ### What Ships - `InputState` with `current` (pointer) and `previous` (array) - `input_update()` handles snapshot, compare, advance - `input_is_down()` and `input_just_pressed()` expose transitions - `memcpy()` copies state at frame boundary --- ### The Rust Comparison Rust catches these at compile time. C catches them at runtime. The difference is when the pain arrives, not whether it arrives. --- **Next:** Game struct + scaffolding. --- _[[email protected]](mailto:[email protected]) | Previous: [[0x2004_Issue 0x1 - Timer]] → Next: [[0x2006_Issue 0x3 - TBD]]_ >_Transparency note: I use Lumo as a technical reviewer for these posts — checking C semantics, verifying claims, and catching formatting issues. The ideas, mistakes, and fixes are my own._