Skip to content

[Audit][Medium] text_input.zig letter key mapping ignores shift for uppercase ASCII #708

@MichaelFisher1997

Description

@MichaelFisher1997

🔍 Module Scanned

modules/game-core/src/ (automated audit scan)

📝 Summary

The handleTextTyping function in text_input.zig has a bug where it converts key enum values to uppercase ASCII characters via direct casting, ignoring the actual character values of the key enums. Since Key.a = 'a' (lowercase), the shift conversion produces lowercase letters instead of uppercase.

📍 Location

  • File: modules/game-core/src/text_input.zig:11-14
  • Function/Scope: handleTextTyping

🔴 Severity: Medium

  • Medium: Performance degradation, missing error handling, suboptimal patterns

💥 Impact

When a user holds Shift and types letters (a-z), the text input receives lowercase letters instead of uppercase. This affects:

  • World naming (when creating new worlds)
  • Seed text input fields
  • Any text input requiring uppercase letters

The bug only affects letters; numbers, space, and backspace work correctly.

🔎 Evidence

const letters = [_]Key{ .a, .b, .c, .d, .e, .f, .g, .h, .i, .j, .k, .l, .m, .n, .o, .p, .q, .r, .s, .t, .u, .v, .w, .x, .y, .z };
inline for (letters) |key| if (input.isKeyPressed(key) and text_input.items.len < max_len) {
    var ch: u8 = @intCast(@intFromEnum(key));  // BUG: This is 'a' (97), not 'A' (65)
    if (shift) ch = std.ascii.toUpper(ch);      // toUpper('a') = 'a' (no change!)
    try text_input.append(allocator, ch);
};

Root cause: Key.a = 'a' (lowercase, value 97). std.ascii.toUpper('a') returns 'a' (no change) since 'a' is already lowercase. The intent was to produce 'A' (65) when shift is held.

Expected behavior: When shift is held, typing 'a' should produce 'A'.

Compare to correct code in input_mapper.zig line 42-50:

bindings[@intFromEnum(GameAction.slot_1)] = ActionBinding.init(.{ .key = .@"1" });
bindings[@intFromEnum(GameAction.slot_2)] = ActionBinding.init(.{ .key = .@"2" });
// ... numbers work correctly because .@"1" = '1' (49) and '1'-'9' have no case

🛠️ Proposed Fix

Replace the key-to-char conversion with character constants:

const shift = input.isKeyDown(.left_shift) or input.isKeyDown(.right_shift);
const letters = [_]u8{ 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' };
inline for (letters, 0..) |letter, idx| {
    const key = @as(Key, @enumFromInt(letter));
    if (input.isKeyPressed(key) and text_input.items.len < max_len) {
        var ch = letter;
        if (shift) ch = std.ascii.toUpper(ch);
        try text_input.append(allocator, ch);
    }
}

Or simplify further by removing the array:

const letters = "abcdefghijklmnopqrstuvwxyz";
for (letters) |letter| {
    const key = @as(Key, @enumFromInt(letter));
    if (input.isKeyPressed(key) and text_input.items.len < max_len) {
        var ch = letter;
        if (shift) ch = std.ascii.toUpper(ch);
        try text_input.append(allocator, ch);
    }
}

✅ Acceptance Criteria

  • nix develop --command zig build test passes
  • Typing 'a' with Shift produces 'A' in text input
  • Typing 'z' with Shift produces 'Z' in text input
  • Lowercase letters still work when Shift is not held
  • Numbers and space continue to work correctly

📚 References

  • Key enum definition in modules/engine-core/src/interfaces.zig:186-271
  • std.ascii.toUpper behavior: toUpper('a') = 'a' (unchanged since already lowercase)
  • Shift modifier handling is correct (line 9)

Metadata

Metadata

Assignees

No one assigned

    Labels

    automated-auditIssues found by automated opencode audit scansbugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions