kblayouts/kbtrans/generate_xkb.py
2023-11-09 14:16:16 +01:00

145 lines
4.5 KiB
Python

from typing import Set
import sys
import kb
import kc
import mac_parser
IN_PATH = sys.argv[1]
OUT_PATH = sys.argv[2]
mac_kb = mac_parser.parse_keyboard_layout(IN_PATH)
keyboard = kb.from_mac(mac_kb)
with open(OUT_PATH, "w") as out_file:
out_file.write("xkb_keymap {\n")
out_file.write(' xkb_keycodes "mjaucodes"{\n')
for knr, name in kc.MAC_KEY_NAMES.items():
key = kc.KeyCode(knr)
for lin_n, lin_name in key.linux_keycodes():
out_file.write(f' {lin_name} = {lin_n}; // {key}\n')
out_file.write(' <BKSP> = 22; // Backspace\n')
out_file.write(' <LSHF> = 50; // Left shift\n')
out_file.write(' <RSHF> = 62; // Right alt\n')
out_file.write(' <LALT> = 64; // Left alt\n')
out_file.write(' <RALT> = 108; // Right alt\n')
out_file.write(' <ESC> = 9; // Escape\n')
out_file.write(' <TAB> = 23; // Tab\n')
out_file.write(' <RET> = 36; // Return\n')
out_file.write(' <LCTR> = 37; // Left Control\n')
out_file.write(' <RCTR> = 105; // Right Control\n')
out_file.write(' <UP> = 111; // Arrow up\n')
out_file.write(' <DOWN> = 116; // Arrow down\n')
out_file.write(' <LEFT> = 113; // Arrow left\n')
out_file.write(' <RGHT> = 114; // Arrow right\n')
out_file.write(' <CAPS> = 66; // Caps lock\n')
out_file.write(' };\n')
out_file.write('''\
xkb_types "mjautypes" {
virtual_modifiers NumLock,Alt,LevelThree,LAlt,RAlt,RControl,LControl,ScrollLock,LevelFive,AltGr,Meta,Super,Hyper;
type "ONE_LEVEL" {
modifiers= none;
level_name[Level1]= "Any";
};
type "ALPHABETIC" {
modifiers= Shift+Lock;
map[Shift]= Level2;
map[Lock]= Level2;
level_name[Level1]= "Base";
level_name[Level2]= "Caps";
};
type "ALTABLE" {
modifiers= Shift+Mod2;
map[Shift]= Level2;
map[Mod2]= Level3;
map[Shift+Mod2]= Level4;
level_name[Level1]= "Base";
level_name[Level2]= "Shift";
level_name[Level3]= "Alt Base";
level_name[Level4]= "Shift Alt";
};
};
xkb_compatibility "mjaucomp" {
virtual_modifiers NumLock,Alt,LevelThree,LAlt,RAlt,RControl,LControl,ScrollLock,LevelFive,AltGr,Meta,Super,Hyper;
interpret.useModMapMods= AnyLevel;
interpret.repeat= False;
interpret.locking= False;
interpret LSHF+AnyOfOrNone(all) {
action= SetMods(modifiers=Shift,clearLocks);
};
interpret LSHF+AnyOfOrNone(all) {
action= SetMods(modifiers=Shift,clearLocks);
};
interpret LALT+AnyOf(all) {
action= SetMods(modifiers=Mod2,clearLocks);
};
interpret RALT+AnyOf(all) {
action= SetMods(modifiers=modMapMode,clearLocks);
};
};
''')
out_file.write('''\
xkb_symbols "mjau"{
key <LALT> { [ Alt_L ] };
key <RALT> { [ Alt_R ] };
key <LSHF> { [ Shift_L ] };
key <RSHF> { [ Shift_R ] };
key <LCTR> { [ Control_L ] };
key <RCTR> { [ Control_R ] };
key <BKSP> { [ BackSpace ] };
key <TAB> { [ Tab ] };
key <ESC> { [ Escape ] };
key <CAPS> { [ Escape ] };
key <RET> { [ Return ] };
key <UP> { [ Up ] };
key <DOWN> { [ Down ] };
key <LEFT> { [ Left ] };
key <RGHT> { [ Right ] };
modifier_map Control { <LCTR> };
modifier_map Control { <RCTR> };
modifier_map Mod1 { <RALT> };
modifier_map Mod2 { <LALT> };
''')
def get_output(layer: kb.Layer, kc: kb.KeyCode, mods: Set[kb.Modifier]) -> str:
key = kb.Key(kc, mods)
if key not in layer.buttons:
return "none"
press = layer.buttons[key]
if not isinstance(press, kb.Output):
return "none"
if len(press.output) != 1:
print(f"Ignoring multi-output key {kc}+{mods}")
return "none"
return "U" + hex(ord(press.output[0]))[2:].rjust(4, "0")
layer = keyboard.layers[keyboard.default_layer]
for keycode in kc.KEYCODES:
none = get_output(layer, keycode, set())
shifted = get_output(layer, keycode, set([kb.Modifier.SHIFT]))
alted = get_output(layer, keycode, set([kb.Modifier.OPTION]))
shalted = get_output(layer, keycode, set([kb.Modifier.SHIFT, kb.Modifier.OPTION]))
if none == shifted == alted == shalted == "none":
continue
for _, lin_name in keycode.linux_keycodes():
out_file.write(f' key {lin_name} {{ type = "ALTABLE", symbols[Group1]= [ {none}, {shifted}, {alted}, {shalted} ] }}; // {keycode}\n')
out_file.write(' };\n')
out_file.write(' xkb_geometry "mjauometry" {};\n')
out_file.write("};\n")
print("Wrote to", OUT_PATH)