Sokol keyboard event coalescing library.
  • C 66.7%
  • Zig 21.4%
  • Python 5.8%
  • Starlark 4.6%
  • Shell 0.5%
  • Other 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Mikael Säker f709b87472 deps: track sokol 261ddd4, which owns its CAMetalLayer
The fork stopped over-releasing the Metal layer, which crashed every quit
from a hidden (closed-to-background) window. Moved in reveal, dvui-sokol,
sokol-capture and sokey together: two sokol pins are two gfx.Image types.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 09:22:43 +02:00
scripts Migrate to Zig 0.17 2026-10-06 15:44:30 +02:00
src zig fmt (0.17) 2026-10-06 15:44:40 +02:00
zig-pkg deps: track sokol e18efdd (reopen-shows-window opt-in) 2026-08-06 01:41:41 +02:00
.gitignore scripts: setup-tools, the one every repo shares 2026-09-22 21:06:15 +02:00
build.zig Initial sokey: sokol keyboard event coalescing with layout-aware logical keys 2026-04-29 07:40:11 +02:00
build.zig.zon deps: track sokol 261ddd4, which owns its CAMetalLayer 2026-10-07 09:22:43 +02:00
LICENSE Add MIT license 2026-07-25 12:00:20 +02:00
README.md Initial sokey: sokol keyboard event coalescing with layout-aware logical keys 2026-04-29 07:40:11 +02:00

sokey

Sokol keyboard event coalescing with layout-aware logical keys.

What it does

sokol_app delivers keyboard input as three separate event types (KEY_DOWN, CHAR, KEY_UP). sokey coalesces them into a single KeyEvent per logical press/release that carries:

  • physical — sokol's positional keycode (right answer for arrows, F-keys, modifier-only chords like Cmd+Q)
  • logical — layout-aware unmodified key (right answer for game action bindings and vim-style commands; matches the cap the user sees with the active layout)
  • text — UTF-8 of what the OS would type into a text field (right answer for in-game text input, with shift, dead-keys, IME applied)
  • mods — modifier state at event time
  • kind — down / up / repeat

Both game-style action mapping and text input read from the same stream; each consumer picks the field it needs.

Status

  • macOS: layout-aware via Carbon's TIS / UCKeyTranslate.
  • Windows: stub — logical returns null. Falls back to positional.
  • Linux: stub — same.

Usage

const sapp = @import("sokol").app;
const sokey = @import("sokey");

export fn event(ev_ptr: [*c]const sapp.Event) void {
    sokey.feed(&ev_ptr[0]);
}

fn frame() void {
    sokey.flushPending();
    while (sokey.poll()) |ke| {
        // ke.physical, ke.logical, ke.text(), ke.mods, ke.kind
    }
}

pub fn main() void {
    sokey.disablePressAndHold(); // macOS QoL: hold-to-repeat
    sapp.run(.{ .event_cb = event, .frame_cb = frame, … });
}

Tests

zig build test