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
This commit is contained in:
@@ -79,8 +79,8 @@ impl Keymap {
|
||||
dead_keys: Vec<DeadKeyEntry>,
|
||||
}
|
||||
|
||||
let file: KeymapFile = serde_json::from_str(json_str)
|
||||
.map_err(|e| format!("parse error: {}", e))?;
|
||||
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 {
|
||||
@@ -119,192 +119,609 @@ impl BuiltinKeymaps {
|
||||
|
||||
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: 'Õ' },
|
||||
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, '/', '?'),
|
||||
(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' });
|
||||
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 }
|
||||
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 = '~'; }
|
||||
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'),
|
||||
(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' });
|
||||
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(),
|
||||
}
|
||||
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, '!', '§'),
|
||||
(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' });
|
||||
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 }
|
||||
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'),
|
||||
(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' });
|
||||
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 }
|
||||
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 = '§'; }
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ mod xkb;
|
||||
|
||||
use std::env;
|
||||
use std::io::Write;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use scheme::KeymapScheme;
|
||||
|
||||
@@ -24,13 +22,33 @@ fn main() {
|
||||
Err(_) => "/etc/keymaps".to_string(),
|
||||
};
|
||||
if let Err(e) = scheme.load_from_dir(&keymap_dir) {
|
||||
log_msg("ERROR", &format!("failed to load keymaps from {}: {}", keymap_dir, e));
|
||||
log_msg(
|
||||
"ERROR",
|
||||
&format!("failed to load keymaps from {}: {}", keymap_dir, e),
|
||||
);
|
||||
}
|
||||
|
||||
log_msg("INFO", &format!("loaded {} keymap(s)", scheme.keymap_count()));
|
||||
if let Ok(xkb_root) = env::var("XKB_CONFIG_ROOT") {
|
||||
let layout = env::var("XKB_DEFAULT_LAYOUT").unwrap_or_else(|_| "us".to_string());
|
||||
let variant = env::var("XKB_DEFAULT_VARIANT").ok();
|
||||
if let Err(e) = scheme.load_xkb(&xkb_root, &layout, variant.as_deref()) {
|
||||
log_msg(
|
||||
"ERROR",
|
||||
&format!(
|
||||
"failed to load XKB keymap {} from {}: {}",
|
||||
layout, xkb_root, e
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let socket = redox_scheme::Socket::nonblock("keymap")
|
||||
.expect("keymapd: failed to register scheme:keymap");
|
||||
log_msg(
|
||||
"INFO",
|
||||
&format!("loaded {} keymap(s)", scheme.keymap_count()),
|
||||
);
|
||||
|
||||
let socket =
|
||||
redox_scheme::Socket::create("keymap").expect("keymapd: failed to register scheme:keymap");
|
||||
log_msg("INFO", "registered scheme:keymap");
|
||||
|
||||
loop {
|
||||
@@ -41,15 +59,16 @@ fn main() {
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
log_msg("WARN", &format!("scheme read error (ignoring): {}", e));
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
continue;
|
||||
log_msg("ERROR", &format!("scheme read error: {}", e));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
match request.handle_scheme_block_mut(&mut scheme) {
|
||||
Ok(response) => {
|
||||
if let Err(e) = socket.write_response(response, redox_scheme::SignalBehavior::Restart) {
|
||||
if let Err(e) =
|
||||
socket.write_response(response, redox_scheme::SignalBehavior::Restart)
|
||||
{
|
||||
log_msg("ERROR", &format!("failed to write response: {}", e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use syscall::flag::{MODE_DIR, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
|
||||
use crate::keymap::Keymap;
|
||||
|
||||
#[derive(Clone)]
|
||||
enum HandleKind {
|
||||
Root,
|
||||
Active,
|
||||
@@ -69,7 +70,12 @@ impl KeymapScheme {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_xkb(&mut self, xkb_dir: &str, layout: &str, variant: Option<&str>) -> io::Result<()> {
|
||||
pub fn load_xkb(
|
||||
&mut self,
|
||||
xkb_dir: &str,
|
||||
layout: &str,
|
||||
variant: Option<&str>,
|
||||
) -> io::Result<()> {
|
||||
let km = crate::xkb::load_xkb_keymap(xkb_dir, layout, variant)
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
|
||||
let name = match variant {
|
||||
@@ -136,9 +142,12 @@ impl redox_scheme::SchemeBlockMut for KeymapScheme {
|
||||
}
|
||||
|
||||
fn read(&mut self, id: usize, buf: &mut [u8]) -> Result<Option<usize>> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let (kind, offset) = {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
(handle.kind.clone(), handle.offset)
|
||||
};
|
||||
|
||||
let content: Vec<u8> = match &handle.kind {
|
||||
let content: Vec<u8> = match &kind {
|
||||
HandleKind::Root => {
|
||||
let mut listing = String::new();
|
||||
listing.push_str("active\nlist\n");
|
||||
@@ -147,7 +156,12 @@ impl redox_scheme::SchemeBlockMut for KeymapScheme {
|
||||
}
|
||||
listing.into_bytes()
|
||||
}
|
||||
HandleKind::Active => self.active_keymap.clone().into_bytes(),
|
||||
HandleKind::Active => format!(
|
||||
"name={}\nsample_scancode_30={}\n",
|
||||
self.active_keymap,
|
||||
self.translate(0x1E, false, false),
|
||||
)
|
||||
.into_bytes(),
|
||||
HandleKind::List => {
|
||||
let mut listing = String::new();
|
||||
for (i, name) in self.keymaps.keys().enumerate() {
|
||||
@@ -162,20 +176,25 @@ impl redox_scheme::SchemeBlockMut for KeymapScheme {
|
||||
HandleKind::Keymap { name } => {
|
||||
let km = self.keymaps.get(name).ok_or(Error::new(ENOENT))?;
|
||||
format!(
|
||||
"name={}\nentries={}\ncompose={}\ndead_keys={}\n",
|
||||
"name={}\nentries={}\ncompose={}\ndead_keys={}\nsample_scancode_30={}\nsample_altgr_scancode_30={}\nsample_compose_a_acute={}\nsample_compose_sequence={}\n",
|
||||
km.name,
|
||||
km.entries.len(),
|
||||
km.compose.len(),
|
||||
km.dead_keys.len()
|
||||
km.dead_keys.len(),
|
||||
km.get_char(0x1E, false, false),
|
||||
km.get_char(0x1E, false, true),
|
||||
km.compose('a', '\''),
|
||||
km.lookup_compose("compose").unwrap_or('\0'),
|
||||
)
|
||||
.into_bytes()
|
||||
}
|
||||
};
|
||||
|
||||
if handle.offset >= content.len() {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
if offset >= content.len() {
|
||||
return Ok(Some(0));
|
||||
}
|
||||
let remaining = &content[handle.offset..];
|
||||
let remaining = &content[offset..];
|
||||
let to_copy = remaining.len().min(buf.len());
|
||||
buf[..to_copy].copy_from_slice(&remaining[..to_copy]);
|
||||
handle.offset += to_copy;
|
||||
|
||||
@@ -210,10 +210,22 @@ struct XkbKeyEntry {
|
||||
}
|
||||
|
||||
fn parse_keysyms(syms: &[&str]) -> (char, char, char, char) {
|
||||
let normal = syms.get(0).map(|s| keysym_to_char(s.trim())).unwrap_or('\0');
|
||||
let shifted = syms.get(1).map(|s| keysym_to_char(s.trim())).unwrap_or('\0');
|
||||
let altgr = syms.get(2).map(|s| keysym_to_char(s.trim())).unwrap_or('\0');
|
||||
let altgr_shifted = syms.get(3).map(|s| keysym_to_char(s.trim())).unwrap_or('\0');
|
||||
let normal = syms
|
||||
.get(0)
|
||||
.map(|s| keysym_to_char(s.trim()))
|
||||
.unwrap_or('\0');
|
||||
let shifted = syms
|
||||
.get(1)
|
||||
.map(|s| keysym_to_char(s.trim()))
|
||||
.unwrap_or('\0');
|
||||
let altgr = syms
|
||||
.get(2)
|
||||
.map(|s| keysym_to_char(s.trim()))
|
||||
.unwrap_or('\0');
|
||||
let altgr_shifted = syms
|
||||
.get(3)
|
||||
.map(|s| keysym_to_char(s.trim()))
|
||||
.unwrap_or('\0');
|
||||
(normal, shifted, altgr, altgr_shifted)
|
||||
}
|
||||
|
||||
@@ -242,15 +254,15 @@ pub fn parse_xkb_symbols(content: &str, variant: Option<&str>) -> Result<Keymap,
|
||||
}
|
||||
if inner.starts_with("key <") {
|
||||
if let Some(entry) = parse_key_line(inner) {
|
||||
entries.entry(entry.scancode).or_insert_with(|| {
|
||||
KeymapEntry {
|
||||
entries
|
||||
.entry(entry.scancode)
|
||||
.or_insert_with(|| KeymapEntry {
|
||||
scancode: entry.scancode,
|
||||
normal: entry.normal,
|
||||
shifted: entry.shifted,
|
||||
altgr: entry.altgr,
|
||||
altgr_shifted: entry.altgr_shifted,
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
@@ -260,7 +272,10 @@ pub fn parse_xkb_symbols(content: &str, variant: Option<&str>) -> Result<Keymap,
|
||||
}
|
||||
|
||||
if !found_variant {
|
||||
return Err(format!("variant '{}' not found in XKB symbols file", target_variant));
|
||||
return Err(format!(
|
||||
"variant '{}' not found in XKB symbols file",
|
||||
target_variant
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Keymap {
|
||||
@@ -316,7 +331,11 @@ fn parse_key_line(line: &str) -> Option<XkbKeyEntry> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn load_xkb_keymap(xkb_dir: &str, layout: &str, variant: Option<&str>) -> Result<Keymap, String> {
|
||||
pub fn load_xkb_keymap(
|
||||
xkb_dir: &str,
|
||||
layout: &str,
|
||||
variant: Option<&str>,
|
||||
) -> Result<Keymap, String> {
|
||||
let file_path = format!("{}/symbols/{}", xkb_dir, layout);
|
||||
let content = std::fs::read_to_string(&file_path)
|
||||
.map_err(|e| format!("failed to read XKB symbols file '{}': {}", file_path, e))?;
|
||||
|
||||
Reference in New Issue
Block a user