sdl-keybridge 0.1.0

Universal Rosetta Stone for SDL keyboards: scancode ↔ keycode ↔ localized glyph across layouts and platforms.
Documentation
  • Coverage
  • 13.92%
    65 out of 467 items documented2 out of 49 items with examples
  • Size
  • Source code size: 188.56 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 10.28 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 44s Average build duration of successful builds.
  • all releases: 1m 6s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Le-Syl21/sdl-keybridge
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • Le-Syl21

sdl-keybridge

CI Crates.io Docs.rs License: MIT OR Apache-2.0

The universal Rosetta Stone for SDL keyboards.

A static correspondence table that exposes, for every key press, all of its parallel representations — physical scancode, logical keycode, textual or symbolic glyph, localized label — across all the layout × platform combinations supported by SDL.

No other Rust crate combines layout-awareness (AZERTY/QWERTZ/JCUKEN), i18n of named keys (Escape → Échap/Esc/エスケープ), and a cross-layout binding bridge via scancode as a universal pivot.

Philosophy: Rosette, not Champollion

This crate is a static lookup table (Rosette). It exposes parallel data and individual labels. It does not interpret and does not package presentation conventions.

Anything that interprets — formatting a Ctrl+Shift+A combo, serializing a binding, rebasing a config from one layout to another — is Champollion territory: the job of the consuming application. The Rosette gives you the raw correspondence data; you pick the separator, the ordering, the storage format.

The four public functions

use sdl_keybridge::{
    resolve, scancode_for, modifier_label, keycode_from_name,
    KeyMod, Keycode, LabelStyle, Modifier, MultiLocalizer, Platform, Scancode,
};

let loc = MultiLocalizer::new();

// 1. Forward lookup — every parallel representation in one pass.
let r = resolve(
    Scancode::A,
    KeyMod::LSHIFT,
    "linux/fr-t-k0-azerty",  // layout id
    "fr",                     // UI locale
    LabelStyle::Textual,
    &loc,
);
assert_eq!(r.character, Some('Q'));  // Shift+A on AZERTY → 'Q'

// 2. Reverse lookup — find the scancode for a keycode in a layout.
let sc = scancode_for(Keycode::from('ф'), "linux/ru-t-k0-jcuken");
assert_eq!(sc, Some(Scancode::A));

// 3. Platform-aware modifier label.
let s = modifier_label(Modifier::Gui, Platform::Mac, "fr", LabelStyle::Textual, &loc);
assert_eq!(s.as_ref(), "Commande");

// 4. Parse a textual key name back into a keycode.
assert_eq!(keycode_from_name("Left Shift"), Some(Keycode::LSHIFT));

Cross-layout binding bridge

Two lines of consumer code translate a binding from one layout to another through scancode-as-pivot:

use sdl_keybridge::{resolve, scancode_for, KeyMod, Keycode, LabelStyle, MultiLocalizer};

# let keycode_ru = Keycode::from('ф');
let loc = MultiLocalizer::new();
let sc = scancode_for(keycode_ru, "windows/ru-t-k0-jcuken").unwrap();
let r = resolve(sc, KeyMod::NONE, "windows/fr-t-k0-azerty", "fr", LabelStyle::Textual, &loc);
// r.glyph_local is what the user sees on their French AZERTY keyboard.

Combo formatting (consumer-side)

There is no format_combo() in this crate — the separator and ordering are yours. Assemble the individual labels the way your UI expects:

use sdl_keybridge::{resolve, modifier_label, KeyMod, LabelStyle, MultiLocalizer, Modifier, Platform, Scancode};

# let loc = MultiLocalizer::new();
# let layout = "linux/fr-t-k0-azerty";
# let locale = "fr";
# let style = LabelStyle::Textual;
let ctrl = modifier_label(Modifier::Ctrl, Platform::Linux, locale, style, &loc);
let r = resolve(Scancode::A, KeyMod::LCTRL, layout, locale, style, &loc);
let combo = format!("{}+{}", ctrl, r.glyph_local);  // "Ctrl+q" on AZERTY

SDL2 + SDL3 compatibility

There are no sdl2 / sdl3 feature flags. The API takes primitive types (u32 for scancodes / keycodes, u16 for the modifier bitmask), whose numeric values are identical between SDL2 and SDL3 for every constant exposed here. Use the same crate regardless of your SDL binding.

Locales

26 locales available as individual Cargo features:

Code Language Code Language Code Language
en (default) English fr Français de Deutsch
es Español it Italiano pt Português
nl Nederlands sv Svenska fi Suomi
pl Polski cs Čeština sk Slovenčina
tr Türkçe ru Русский ar العربية
hi हिन्दी bn বাংলা ur اردو
zh-hans 简体中文 zh-hant 繁體中文 ja 日本語
ko 한국어 id Bahasa Indonesia sw Kiswahili
vi Tiếng Việt th ภาษาไทย

Enable only what you need; use the aggregate all-locales feature to pull them all in.

[dependencies]
sdl-keybridge = { version = "0.1", features = ["fr", "de", "ja"] }

Layouts

v0.1 ships hand-curated layouts for US QWERTY, French AZERTY, German QWERTZ, Russian JCUKEN and US Dvorak — each available for macOS, Windows and Linux. Layout ids follow the BCP 47 + CLDR keyboard extension convention:

  • mac/en-US-t-k0-qwerty, windows/en-US-t-k0-qwerty, linux/en-US-t-k0-qwerty
  • mac/fr-t-k0-azerty, windows/fr-t-k0-azerty, linux/fr-t-k0-azerty
  • mac/de-t-k0-qwertz, windows/de-t-k0-qwertz, linux/de-t-k0-qwertz
  • windows/ru-t-k0-jcuken, linux/ru-t-k0-jcuken, mac/ru-t-k0-jcuken
  • mac/en-US-t-k0-dvorak, windows/en-US-t-k0-dvorak, linux/en-US-t-k0-dvorak

Full Unicode CLDR keyboard data import is on the roadmap — see CONTRIBUTING.md.

What this crate will not do (non-goals)

  • Detect the current OS layout — the caller provides the BCP 47 id. No Rust solution reliably covers all five SDL platforms.
  • Dead keys / text composition — a scancode + modifiers resolves to one glyph. Composition (e.g. ^ + eê) is the OS/IME's job, triggered by SDL_StartTextInput, not by us.
  • Package a format_combo() — presentation conventions vary; the consumer assembles the labels it receives.
  • Package a binding serializer — config format is yours (JSON, INI, RON, binary, …).

License

Dual-licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.