145 lines
4.5 KiB
Python
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)
|
||
|
|