From 3541b4e8f7fd94cd0c6dc1fac185228a1f44a635 Mon Sep 17 00:00:00 2001 From: Lars-Dominik Braun Date: Sun, 29 Sep 2019 15:00:33 +0200 Subject: render: Add basic keyman support Works for simple keyboards only. --- lulua/keyboard.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lulua/render.py | 36 ++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/lulua/keyboard.py b/lulua/keyboard.py index 8fb7913..bd1d449 100644 --- a/lulua/keyboard.py +++ b/lulua/keyboard.py @@ -91,6 +91,72 @@ _buttonToXorgKeycode = { 'Fr_ctrl': 105, } +_buttonToKeyman = { + 'Bl1': 'K_BKSLASH', + 'Bl2': 'K_1', + 'Bl3': 'K_2', + 'Bl4': 'K_3', + 'Bl5': 'K_4', + 'Bl6': 'K_5', + 'Bl7': 'K_6', + 'Br6': 'K_7', + 'Br5': 'K_8', + 'Br4': 'K_9', + 'Br3': 'K_0', + 'Br2': 'K_LBRKT', + 'Br1': 'K_RBRKT', + 'Br_bs': 'K_BKSP', + 'Cl_tab': 'K_TAB', + 'Cl1': 'K_Q', + 'Cl2': 'K_W', + 'Cl3': 'K_E', + 'Cl4': 'K_R', + 'Cl5': 'K_T', + 'Cr7': 'K_Z', + 'Cr6': 'K_U', + 'Cr5': 'K_I', + 'Cr4': 'K_O', + 'Cr3': 'K_P', + 'Cr2': 'K_COLON', + 'Cr1': 'K_EQUAL', + 'CD_ret': 'K_ENTER', + 'Dl_caps': 'CAPS', + 'Dl1': 'K_A', + 'Dl2': 'K_S', + 'Dl3': 'K_D', + 'Dl4': 'K_F', + 'Dl5': 'K_G', + 'Dr7': 'K_H', + 'Dr6': 'K_J', + 'Dr5': 'K_K', + 'Dr4': 'K_L', + 'Dr3': 'K_BKQUOTE', + 'Dr2': 'K_QUOTE', + 'Dr1': 'K_SLASH', + 'El_shift': 'SHIFT', # XXX: there is no distinction between left/right + 'El1': 'K_oE2', + 'El2': 'K_Y', + 'El3': 'K_X', + 'El4': 'K_C', + 'El5': 'K_V', + 'El6': 'K_B', + 'Er5': 'K_N', + 'Er4': 'K_M', + 'Er3': 'K_COMMA', + 'Er2': 'K_PERIOD', + 'Er1': 'K_HYPHEN', + 'Er_shift': 'SHIFT', + 'Fl_ctrl': 'LCTRL', + 'Fl_win': 'K_?5B', + 'Fl_alt': 'LALT', + 'Fl_space': 'K_SPACE', + 'Fr_space': 'K_SPACE', + 'Fr_altgr': 'RALT', + 'Fr_win': 'K_?5C', + 'Fr_menu': 'K_?5D', + 'Fr_ctrl': 'RCTRL', + } + class Button: __slots__ = ('width', 'isMarked', 'i') _idToName : Dict[int, Text] = {} @@ -129,6 +195,10 @@ class Button: def xorgKeycode (self): return _buttonToXorgKeycode[self.name] + @property + def keymanCode (self): + return _buttonToKeyman[self.name] + @classmethod def deserialize (self, data: Dict): kindMap = {'standard': Button, 'letter': LetterButton, 'multi': MultiRowButton} diff --git a/lulua/render.py b/lulua/render.py index 9aa7204..dce8961 100644 --- a/lulua/render.py +++ b/lulua/render.py @@ -325,6 +325,40 @@ def renderXmodmap (args): fd.write (f'!! {btn.name}\nkeycode {btn.xorgKeycode} = {v}\n') fd.write ('\n'.join (['add Mod3 = ISO_First_Group', 'add Mod5 = ISO_Level3_Shift', ''])) +def renderKeyman (args): + """ Rudimentary keyman script generation. Note that keyman is somewhat + unflexible when it comes to shift states and therefore layouts with + non-standard shift keys/states won’t work. """ + + keyboard = defaultKeyboards[args.keyboard] + layout = defaultLayouts[args.layout].specialize (keyboard) + + with open (args.output, 'w') as fd: + fd.write ('\n'.join ([ + 'c Auto-generated file for Keyman 11.0', + f'c layout: {layout.name}', + f'c generated: {datetime.utcnow ()}', + '', + 'store(&version) "9.0"', + f'store(&name) "{layout.name}"', + 'store(&mnemoniclayout) "0"', + 'store(&targets) "any"', + '', + 'begin Unicode > use(main)', + 'group(main) using keys', + '', + ])) + for i, l in enumerate (layout.layers): + for m in l.modifier: + for x in m: + if x.keymanCode.startswith ('K_') or x.keymanCode == 'CAPS': + logging.error (f'Keyman does not support custom modifier like {m}. Your layout will not work correctly.') + break + for btn, text in l.layout.items (): + comb = ' '.join ([x.keymanCode for x in m] + [btn.keymanCode]) + text = ' '.join ([f'U+{ord (x):04X}' for x in text]) + fd.write (f'+ [{comb}] > {text}\n') + def render (): parser = argparse.ArgumentParser(description='Render keyboard into output format.') parser.add_argument('-l', '--layout', metavar='LAYOUT', help='Keyboard layout name') @@ -335,6 +369,8 @@ def render (): sp.set_defaults (func=renderSvg) sp = subparsers.add_parser('xmodmap') sp.set_defaults (func=renderXmodmap) + sp = subparsers.add_parser('keyman') + sp.set_defaults (func=renderKeyman) parser.add_argument('output', metavar='FILE', help='Output file') logging.basicConfig (level=logging.INFO) -- cgit v1.2.3