Files
RedBear-OS/local/recipes/system/redbear-keymapd/source/src/keymap.rs
T
vasilito c68ace12de feat: relibc S1 — sem_open refcounting + glibc cross-reference assessment
Phase S1 (Critical Correctness):
- sem_open/sem_close: global refcounting via BTreeMap + AtomicUsize
- sem_close: decrements refcount, munmaps only at zero
- sem_open: reuses existing mapping, O_EXCL returns EEXIST
- sem_unlink: marks entry for removal before shm_unlink
- va_list parsing: reads mode_t and value from stack after oflag
- All 11 sem_* functions verified in libc.so T

Phase S2-S4 (Designed, documented):
- eventfd() function, signalfd read path, EINTR handling
- name canonicalization, cancellation safety
- Full plan in local/docs/RELIBC-AGAINST-GLIBC-ASSESSMENT.md

Reference: glibc 2.41 cloned to local/reference/glibc/

Boot verified: greeter ready on VT 3 with refcounted semaphores
2026-05-05 21:12:08 +01:00

728 lines
19 KiB
Rust

use serde::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Clone, Deserialize)]
pub struct KeymapEntry {
pub scancode: u8,
pub normal: char,
pub shifted: char,
#[serde(default)]
pub altgr: char,
#[serde(default)]
pub altgr_shifted: char,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ComposeEntry {
pub sequence: String,
pub result: char,
}
#[derive(Debug, Clone, Deserialize)]
pub struct DeadKeyEntry {
pub dead_key: char,
pub base: char,
pub composed: char,
}
#[derive(Debug, Clone)]
pub struct Keymap {
pub name: String,
pub entries: HashMap<u8, KeymapEntry>,
pub compose: Vec<ComposeEntry>,
pub dead_keys: Vec<DeadKeyEntry>,
}
impl Keymap {
pub fn get_char(&self, scancode: u8, shift: bool, altgr: bool) -> char {
if let Some(entry) = self.entries.get(&scancode) {
if altgr && shift && entry.altgr_shifted != '\0' {
return entry.altgr_shifted;
}
if altgr && entry.altgr != '\0' {
return entry.altgr;
}
if shift {
return entry.shifted;
}
return entry.normal;
}
'\0'
}
pub fn compose(&self, base: char, dead_key: char) -> char {
for entry in &self.dead_keys {
if entry.dead_key == dead_key && entry.base == base {
return entry.composed;
}
}
base
}
pub fn lookup_compose(&self, sequence: &str) -> Option<char> {
for entry in &self.compose {
if entry.sequence == sequence {
return Some(entry.result);
}
}
None
}
pub fn from_json(name: &str, json_str: &str) -> Result<Self, String> {
#[derive(Deserialize)]
struct KeymapFile {
#[serde(default)]
entries: Vec<KeymapEntry>,
#[serde(default)]
compose: Vec<ComposeEntry>,
#[serde(default)]
dead_keys: Vec<DeadKeyEntry>,
}
let file: KeymapFile =
serde_json::from_str(json_str).map_err(|e| format!("parse error: {}", e))?;
let mut map = HashMap::new();
for entry in file.entries {
map.insert(entry.scancode, entry);
}
Ok(Keymap {
name: name.to_string(),
entries: map,
compose: file.compose,
dead_keys: file.dead_keys,
})
}
}
pub struct BuiltinKeymaps {
pub us: Keymap,
pub gb: Keymap,
pub dvorak: Keymap,
pub azerty: Keymap,
pub bepo: Keymap,
pub it: Keymap,
}
impl BuiltinKeymaps {
pub fn new() -> Self {
BuiltinKeymaps {
us: Self::make_us(),
gb: Self::make_gb(),
dvorak: Self::make_dvorak(),
azerty: Self::make_azerty(),
bepo: Self::make_bepo(),
it: Self::make_it(),
}
}
fn common_dead_keys() -> Vec<DeadKeyEntry> {
vec![
DeadKeyEntry {
dead_key: '`',
base: 'a',
composed: 'à',
},
DeadKeyEntry {
dead_key: '`',
base: 'e',
composed: 'è',
},
DeadKeyEntry {
dead_key: '`',
base: 'i',
composed: 'ì',
},
DeadKeyEntry {
dead_key: '`',
base: 'o',
composed: 'ò',
},
DeadKeyEntry {
dead_key: '`',
base: 'u',
composed: 'ù',
},
DeadKeyEntry {
dead_key: '`',
base: 'A',
composed: 'À',
},
DeadKeyEntry {
dead_key: '`',
base: 'E',
composed: 'È',
},
DeadKeyEntry {
dead_key: '`',
base: 'I',
composed: 'Ì',
},
DeadKeyEntry {
dead_key: '`',
base: 'O',
composed: 'Ò',
},
DeadKeyEntry {
dead_key: '`',
base: 'U',
composed: 'Ù',
},
DeadKeyEntry {
dead_key: '\'',
base: 'a',
composed: 'á',
},
DeadKeyEntry {
dead_key: '\'',
base: 'e',
composed: 'é',
},
DeadKeyEntry {
dead_key: '\'',
base: 'i',
composed: 'í',
},
DeadKeyEntry {
dead_key: '\'',
base: 'o',
composed: 'ó',
},
DeadKeyEntry {
dead_key: '\'',
base: 'u',
composed: 'ú',
},
DeadKeyEntry {
dead_key: '\'',
base: 'A',
composed: 'Á',
},
DeadKeyEntry {
dead_key: '\'',
base: 'E',
composed: 'É',
},
DeadKeyEntry {
dead_key: '\'',
base: 'I',
composed: 'Í',
},
DeadKeyEntry {
dead_key: '\'',
base: 'O',
composed: 'Ó',
},
DeadKeyEntry {
dead_key: '\'',
base: 'U',
composed: 'Ú',
},
DeadKeyEntry {
dead_key: '^',
base: 'a',
composed: 'â',
},
DeadKeyEntry {
dead_key: '^',
base: 'e',
composed: 'ê',
},
DeadKeyEntry {
dead_key: '^',
base: 'i',
composed: 'î',
},
DeadKeyEntry {
dead_key: '^',
base: 'o',
composed: 'ô',
},
DeadKeyEntry {
dead_key: '^',
base: 'u',
composed: 'û',
},
DeadKeyEntry {
dead_key: '^',
base: 'A',
composed: 'Â',
},
DeadKeyEntry {
dead_key: '^',
base: 'E',
composed: 'Ê',
},
DeadKeyEntry {
dead_key: '^',
base: 'I',
composed: 'Î',
},
DeadKeyEntry {
dead_key: '^',
base: 'O',
composed: 'Ô',
},
DeadKeyEntry {
dead_key: '^',
base: 'U',
composed: 'Û',
},
DeadKeyEntry {
dead_key: '"',
base: 'a',
composed: 'ä',
},
DeadKeyEntry {
dead_key: '"',
base: 'e',
composed: 'ë',
},
DeadKeyEntry {
dead_key: '"',
base: 'i',
composed: 'ï',
},
DeadKeyEntry {
dead_key: '"',
base: 'o',
composed: 'ö',
},
DeadKeyEntry {
dead_key: '"',
base: 'u',
composed: 'ü',
},
DeadKeyEntry {
dead_key: '"',
base: 'A',
composed: 'Ä',
},
DeadKeyEntry {
dead_key: '"',
base: 'E',
composed: 'Ë',
},
DeadKeyEntry {
dead_key: '"',
base: 'I',
composed: 'Ï',
},
DeadKeyEntry {
dead_key: '"',
base: 'O',
composed: 'Ö',
},
DeadKeyEntry {
dead_key: '"',
base: 'U',
composed: 'Ü',
},
DeadKeyEntry {
dead_key: '~',
base: 'a',
composed: 'ã',
},
DeadKeyEntry {
dead_key: '~',
base: 'n',
composed: 'ñ',
},
DeadKeyEntry {
dead_key: '~',
base: 'o',
composed: 'õ',
},
DeadKeyEntry {
dead_key: '~',
base: 'A',
composed: 'Ã',
},
DeadKeyEntry {
dead_key: '~',
base: 'N',
composed: 'Ñ',
},
DeadKeyEntry {
dead_key: '~',
base: 'O',
composed: 'Õ',
},
]
}
fn make_us() -> Keymap {
let mut entries = HashMap::new();
let bindings: &[(u8, char, char)] = &[
(0x01, '\x1B', '\x1B'),
(0x02, '1', '!'),
(0x03, '2', '@'),
(0x04, '3', '#'),
(0x05, '4', '$'),
(0x06, '5', '%'),
(0x07, '6', '^'),
(0x08, '7', '&'),
(0x09, '8', '*'),
(0x0A, '9', '('),
(0x0B, '0', ')'),
(0x0C, '-', '_'),
(0x0D, '=', '+'),
(0x0E, '\x7F', '\x7F'),
(0x0F, '\t', '\t'),
(0x10, 'q', 'Q'),
(0x11, 'w', 'W'),
(0x12, 'e', 'E'),
(0x13, 'r', 'R'),
(0x14, 't', 'T'),
(0x15, 'y', 'Y'),
(0x16, 'u', 'U'),
(0x17, 'i', 'I'),
(0x18, 'o', 'O'),
(0x19, 'p', 'P'),
(0x1A, '[', '{'),
(0x1B, ']', '}'),
(0x1C, '\n', '\n'),
(0x1E, 'a', 'A'),
(0x1F, 's', 'S'),
(0x20, 'd', 'D'),
(0x21, 'f', 'F'),
(0x22, 'g', 'G'),
(0x23, 'h', 'H'),
(0x24, 'j', 'J'),
(0x25, 'k', 'K'),
(0x26, 'l', 'L'),
(0x27, ';', ':'),
(0x28, '\'', '"'),
(0x29, '`', '~'),
(0x2B, '\\', '|'),
(0x2C, 'z', 'Z'),
(0x2D, 'x', 'X'),
(0x2E, 'c', 'C'),
(0x2F, 'v', 'V'),
(0x30, 'b', 'B'),
(0x31, 'n', 'N'),
(0x32, 'm', 'M'),
(0x33, ',', '<'),
(0x34, '.', '>'),
(0x35, '/', '?'),
(0x39, ' ', ' '),
];
for &(sc, normal, shifted) in bindings {
entries.insert(
sc,
KeymapEntry {
scancode: sc,
normal,
shifted,
altgr: '\0',
altgr_shifted: '\0',
},
);
}
let dead_keys = Self::common_dead_keys();
Keymap {
name: "us".into(),
entries,
compose: Vec::new(),
dead_keys,
}
}
fn make_gb() -> Keymap {
let mut km = Self::make_us();
km.name = "gb".into();
if let Some(e) = km.entries.get_mut(&0x29) {
e.shifted = '¬';
}
if let Some(e) = km.entries.get_mut(&0x2B) {
e.normal = '#';
e.shifted = '~';
}
km
}
fn make_dvorak() -> Keymap {
let mut entries = HashMap::new();
let remap: &[(u8, char, char)] = &[
(0x01, '\x1B', '\x1B'),
(0x02, '1', '!'),
(0x03, '2', '@'),
(0x04, '3', '#'),
(0x05, '4', '$'),
(0x06, '5', '%'),
(0x07, '6', '^'),
(0x08, '7', '&'),
(0x09, '8', '*'),
(0x0A, '9', '('),
(0x0B, '0', ')'),
(0x0C, '[', '{'),
(0x0D, ']', '}'),
(0x0E, '\x7F', '\x7F'),
(0x0F, '\t', '\t'),
(0x10, '\'', '"'),
(0x11, ',', '<'),
(0x12, '.', '>'),
(0x13, 'p', 'P'),
(0x14, 'y', 'Y'),
(0x15, 'f', 'F'),
(0x16, 'g', 'G'),
(0x17, 'c', 'C'),
(0x18, 'r', 'R'),
(0x19, 'l', 'L'),
(0x1A, '/', '?'),
(0x1B, '=', '+'),
(0x1C, '\n', '\n'),
(0x1E, 'a', 'A'),
(0x1F, 'o', 'O'),
(0x20, 'e', 'E'),
(0x21, 'u', 'U'),
(0x22, 'i', 'I'),
(0x23, 'd', 'D'),
(0x24, 'h', 'H'),
(0x25, 't', 'T'),
(0x26, 'n', 'N'),
(0x27, 's', 'S'),
(0x28, '-', '_'),
(0x29, '`', '~'),
(0x2B, '\\', '|'),
(0x2C, ';', ':'),
(0x2D, 'q', 'Q'),
(0x2E, 'j', 'J'),
(0x2F, 'k', 'K'),
(0x30, 'x', 'X'),
(0x31, 'b', 'B'),
(0x32, 'm', 'M'),
(0x33, 'w', 'W'),
(0x34, 'v', 'V'),
(0x35, 'z', 'Z'),
(0x39, ' ', ' '),
];
for &(sc, normal, shifted) in remap {
entries.insert(
sc,
KeymapEntry {
scancode: sc,
normal,
shifted,
altgr: '\0',
altgr_shifted: '\0',
},
);
}
Keymap {
name: "dvorak".into(),
entries,
compose: Vec::new(),
dead_keys: Self::common_dead_keys(),
}
}
fn make_azerty() -> Keymap {
let mut entries = HashMap::new();
let bindings: &[(u8, char, char)] = &[
(0x01, '\x1B', '\x1B'),
(0x02, '&', '1'),
(0x03, 'é', '2'),
(0x04, '"', '3'),
(0x05, '\'', '4'),
(0x06, '(', '5'),
(0x07, '-', '6'),
(0x08, 'è', '7'),
(0x09, '_', '8'),
(0x0A, 'ç', '9'),
(0x0B, 'à', '0'),
(0x0C, ')', '°'),
(0x0D, '=', '+'),
(0x0E, '\x7F', '\x7F'),
(0x0F, '\t', '\t'),
(0x10, 'a', 'A'),
(0x11, 'z', 'Z'),
(0x12, 'e', 'E'),
(0x13, 'r', 'R'),
(0x14, 't', 'T'),
(0x15, 'y', 'Y'),
(0x16, 'u', 'U'),
(0x17, 'i', 'I'),
(0x18, 'o', 'O'),
(0x19, 'p', 'P'),
(0x1A, '^', '¨'),
(0x1B, '$', '£'),
(0x1C, '\n', '\n'),
(0x1E, 'q', 'Q'),
(0x1F, 's', 'S'),
(0x20, 'd', 'D'),
(0x21, 'f', 'F'),
(0x22, 'g', 'G'),
(0x23, 'h', 'H'),
(0x24, 'j', 'J'),
(0x25, 'k', 'K'),
(0x26, 'l', 'L'),
(0x27, 'm', 'M'),
(0x28, 'ù', '%'),
(0x29, '²', '~'),
(0x2B, '*', 'µ'),
(0x2C, 'w', 'W'),
(0x2D, 'x', 'X'),
(0x2E, 'c', 'C'),
(0x2F, 'v', 'V'),
(0x30, 'b', 'B'),
(0x31, 'n', 'N'),
(0x32, ',', '?'),
(0x33, ';', '.'),
(0x34, ':', '/'),
(0x35, '!', '§'),
(0x39, ' ', ' '),
];
for &(sc, normal, shifted) in bindings {
entries.insert(
sc,
KeymapEntry {
scancode: sc,
normal,
shifted,
altgr: '\0',
altgr_shifted: '\0',
},
);
}
let mut dead_keys = Self::common_dead_keys();
dead_keys.push(DeadKeyEntry {
dead_key: '^',
base: ' ',
composed: '^',
});
dead_keys.push(DeadKeyEntry {
dead_key: '¨',
base: ' ',
composed: '¨',
});
Keymap {
name: "azerty".into(),
entries,
compose: Vec::new(),
dead_keys,
}
}
fn make_bepo() -> Keymap {
let mut entries = HashMap::new();
let bindings: &[(u8, char, char)] = &[
(0x01, '\x1B', '\x1B'),
(0x02, '"', '1'),
(0x03, '«', '2'),
(0x04, '»', '3'),
(0x05, '(', '4'),
(0x06, ')', '5'),
(0x07, '@', '6'),
(0x08, '+', '7'),
(0x09, '-', '8'),
(0x0A, '/', '9'),
(0x0B, '*', '0'),
(0x0C, '=', '°'),
(0x0D, '%', '`'),
(0x0E, '\x7F', '\x7F'),
(0x0F, '\t', '\t'),
(0x10, 'b', 'B'),
(0x11, 'é', 'É'),
(0x12, 'p', 'P'),
(0x13, 'o', 'O'),
(0x14, 'è', 'È'),
(0x15, '^', '!'),
(0x16, 'v', 'V'),
(0x17, 'd', 'D'),
(0x18, 'l', 'L'),
(0x19, 'j', 'J'),
(0x1A, 'z', 'Z'),
(0x1B, 'w', 'W'),
(0x1C, '\n', '\n'),
(0x1E, 'a', 'A'),
(0x1F, 'u', 'U'),
(0x20, 'i', 'I'),
(0x21, 'e', 'E'),
(0x22, ',', ';'),
(0x23, 'c', 'C'),
(0x24, 't', 'T'),
(0x25, 's', 'S'),
(0x26, 'r', 'R'),
(0x27, 'n', 'N'),
(0x28, 'm', 'M'),
(0x29, 'ç', 'Ç'),
(0x2B, '\'', '?'),
(0x2C, 'x', 'X'),
(0x2D, 'f', 'F'),
(0x2E, 'h', 'H'),
(0x2F, 'q', 'Q'),
(0x30, 'g', 'G'),
(0x31, 'y', 'Y'),
(0x32, 'k', 'K'),
(0x33, '.', ':'),
(0x34, '/', '§'),
(0x35, 'g', 'G'),
(0x39, ' ', ' '),
];
for &(sc, normal, shifted) in bindings {
entries.insert(
sc,
KeymapEntry {
scancode: sc,
normal,
shifted,
altgr: '\0',
altgr_shifted: '\0',
},
);
}
let mut dead_keys = Self::common_dead_keys();
dead_keys.push(DeadKeyEntry {
dead_key: '^',
base: ' ',
composed: '^',
});
Keymap {
name: "bepo".into(),
entries,
compose: Vec::new(),
dead_keys,
}
}
fn make_it() -> Keymap {
let mut km = Self::make_us();
km.name = "it".into();
if let Some(e) = km.entries.get_mut(&0x29) {
e.normal = '\\';
e.shifted = '|';
}
if let Some(e) = km.entries.get_mut(&0x0C) {
e.normal = '\'';
e.shifted = '?';
}
if let Some(e) = km.entries.get_mut(&0x0D) {
e.normal = 'ì';
e.shifted = '^';
}
if let Some(e) = km.entries.get_mut(&0x1A) {
e.normal = 'è';
e.shifted = 'é';
}
if let Some(e) = km.entries.get_mut(&0x1B) {
e.normal = '+';
e.shifted = '*';
}
if let Some(e) = km.entries.get_mut(&0x27) {
e.normal = 'ò';
e.shifted = 'ç';
}
if let Some(e) = km.entries.get_mut(&0x28) {
e.normal = 'à';
e.shifted = '°';
}
if let Some(e) = km.entries.get_mut(&0x2B) {
e.normal = 'ù';
e.shifted = '§';
}
km
}
}