|
1 | 1 | #!/usr/bin/env python |
2 | 2 | # -*- coding: utf-8 -*- |
3 | 3 |
|
4 | | -# Quick and dirty keyboard configurator for ~/.xinitrc |
| 4 | +# loadkeys to setxkbmap helper |
| 5 | +# |
| 6 | +# Given a keyboard.map file, finds an associated Xorg keyboard model, |
| 7 | +# layout, and variant, and writes it down to the user's .xinitrc file. |
| 8 | +# |
| 9 | +# Written by Lucas C. Villa Real <lucasvr@gobolinux.org> |
| 10 | +# |
| 11 | +# Released under the GNU GPL version 2 or above |
5 | 12 |
|
6 | 13 | import os |
| 14 | +import sys |
| 15 | +import libxml2 |
| 16 | +import subprocess |
7 | 17 |
|
8 | | -if len(os.sys.argv) != 2 : |
9 | | - print "Syntax: %s <KeymapLayout>" %os.sys.argv[0] |
10 | | - os.sys.exit(1) |
11 | | - |
12 | | -KeymapLayout = os.sys.argv[1] |
13 | | - |
14 | | -xinitrc = os.getenv("HOME") + "/.xinitrc" |
15 | | -if not os.path.exists(xinitrc) : |
16 | | - print "Error: %s does not exist." %xinitrc |
17 | | - os.sys.exit(1) |
18 | | - |
19 | | - |
20 | | -def getKeyboardSettings() : |
21 | | - XkbModel = "default" |
22 | | - XkbLayout = "us" |
23 | | - XkbVariant = "basic" |
24 | | - if KeymapLayout == "be-latin1" : |
25 | | - XkbModel = "pc104" |
26 | | - XkbLayout = "be" |
27 | | - elif KeymapLayout == "br-abnt2" : |
28 | | - XkbModel = "abnt2" |
29 | | - XkbLayout = "br" |
30 | | - elif KeymapLayout == "br-abnt" : |
31 | | - XkbModel = "abnt" |
32 | | - XkbLayout = "br" |
33 | | - elif KeymapLayout == "fr-latin9" : |
34 | | - XkbModel = "pc105" |
35 | | - XkbVariant = "latin9" |
36 | | - XkbLayout = "fr" |
37 | | - elif KeymapLayout == "us-acentos" : |
38 | | - XkbModel = "pc105" |
39 | | - XkbLayout = "us_intl" |
40 | | - elif KeymapLayout == "sv-latin1" : |
41 | | - XkbModel = "pc105" |
42 | | - XkbLayout = "se" |
43 | | - elif KeymapLayout == "us" : |
44 | | - XkbModel = "pc104" |
45 | | - XkbLayout = "us" |
46 | | - elif KeymapLayout == "dvorak" : |
47 | | - XkbModel = "pc105" |
48 | | - XkbLayout = "dvorak" |
49 | | - else : |
50 | | - XkbModel = "pc104" |
51 | | - XkbLayout = KeymapLayout |
52 | | - return XkbModel, XkbLayout, XkbVariant |
53 | | - |
54 | | - |
55 | | -XkbModel, XkbLayout, XkbVariant = getKeyboardSettings() |
56 | | -kbd_settings = "-model %s -layout %s" %(XkbModel, XkbLayout) |
57 | | -if XkbVariant != "basic": |
58 | | - kbd_settings += " -variant %s" %XkbVariant |
59 | | - |
60 | | -oldFile = open(xinitrc) |
61 | | -newFile = open(xinitrc + ".new", "w") |
62 | | -newFile.write("setxkbmap %s\n" %kbd_settings) |
63 | | -for line in oldFile.readlines() : |
64 | | - newFile.write(line) |
65 | | -oldFile.close() |
66 | | -newFile.close() |
67 | | -os.unlink(xinitrc) |
68 | | -os.rename(xinitrc+".new", xinitrc) |
| 18 | + |
| 19 | +class KeyboardSettings: |
| 20 | + def __init__(self, keymap=None, x11_layout=None, x11_variant=None): |
| 21 | + self.keymap = keymap |
| 22 | + self.x11_model = "pc104" |
| 23 | + self.x11_layout = "us" if x11_layout is None else x11_layout |
| 24 | + self.x11_variant = x11_variant |
| 25 | + |
| 26 | + if keymap == "be-latin1" : |
| 27 | + self.x11_model = "pc104" |
| 28 | + self.x11_layout = "be" |
| 29 | + elif keymap == "br-abnt2" : |
| 30 | + self.x11_model = "abnt2" |
| 31 | + self.x11_layout = "br" |
| 32 | + elif keymap == "br-abnt" : |
| 33 | + self.x11_model = "abnt" |
| 34 | + self.x11_layout = "br" |
| 35 | + elif keymap == "fr-latin9" : |
| 36 | + self.x11_model = "pc105" |
| 37 | + self.x11_layout = "fr" |
| 38 | + elif keymap == "us-acentos" : |
| 39 | + self.x11_model = "pc105" |
| 40 | + self.x11_layout = "us_intl" |
| 41 | + elif keymap == "sv-latin1" : |
| 42 | + self.x11_model = "pc105" |
| 43 | + self.x11_layout = "se" |
| 44 | + elif keymap == "us" : |
| 45 | + self.x11_model = "pc104" |
| 46 | + self.x11_layout = "us" |
| 47 | + elif keymap == "dvorak" : |
| 48 | + self.x11_model = "pc105" |
| 49 | + self.x11_layout = "dvorak" |
| 50 | + |
| 51 | + def __getkbmap(self): |
| 52 | + cmd = "setxkbmap -model {0} -layout {1}".format(self.x11_model, self.x11_layout) |
| 53 | + if self.x11_variant: |
| 54 | + cmd += " -variant {0}".format(self.x11_variant) |
| 55 | + return cmd |
| 56 | + |
| 57 | + def write(self, xinitrc): |
| 58 | + oldFile = open(xinitrc) |
| 59 | + newFile = open(xinitrc + ".new", "w") |
| 60 | + newFile.write(self.__getkbmap() + "\n") |
| 61 | + for line in oldFile.readlines() : |
| 62 | + newFile.write(line) |
| 63 | + oldFile.close() |
| 64 | + newFile.close() |
| 65 | + os.unlink(xinitrc) |
| 66 | + os.rename(xinitrc+".new", xinitrc) |
| 67 | + |
| 68 | + def test(self): |
| 69 | + if subprocess.call(self.__getkbmap().split()) != 0: |
| 70 | + print("Error evaluating '{0}', please check.".format(cmd)) |
| 71 | + |
| 72 | + |
| 73 | +class XKB: |
| 74 | + def __init__(self): |
| 75 | + self.rulesfile = "/usr/share/X11/xkb/rules/base.xml" |
| 76 | + self.layouts = {} |
| 77 | + |
| 78 | + def parseRules(self): |
| 79 | + doc = libxml2.parseFile(self.rulesfile) |
| 80 | + ctxt = doc.xpathNewContext() |
| 81 | + layouts = ctxt.xpathEval("/xkbConfigRegistry/layoutList/layout/configItem/name") |
| 82 | + self.layouts = dict((x.content, x) for x in layouts) |
| 83 | + for layout in self.layouts.keys(): |
| 84 | + configitem = self.layouts[layout].get_parent() |
| 85 | + variants = configitem.xpathEval("../variantList/variant/configItem/name") |
| 86 | + self.layouts[layout] = [x.content for x in variants] |
| 87 | + return self.layouts |
| 88 | + |
| 89 | + def x11Layout(self, keymap): |
| 90 | + if self.layouts.has_key(keymap): |
| 91 | + return keymap |
| 92 | + keymap_two = "-".join(keymap.split("-")[0:2]) |
| 93 | + if self.layouts.has_key(keymap_two): |
| 94 | + return keymap_two |
| 95 | + keymap_one = keymap.split("-")[0] |
| 96 | + if self.layouts.has_key(keymap_one): |
| 97 | + return keymap_one |
| 98 | + return None |
| 99 | + |
| 100 | + def x11Variant(self, keymap, layout): |
| 101 | + if layout is None: |
| 102 | + return None |
| 103 | + keymap = keymap[len(layout):].strip("-") |
| 104 | + for variant in self.layouts[layout]: |
| 105 | + if keymap in self.layouts[layout]: |
| 106 | + return keymap |
| 107 | + keymap_two = "-".join(keymap.split("-")[-2:]) |
| 108 | + if keymap_two in self.layouts[layout]: |
| 109 | + return keymap_two |
| 110 | + keymap_one = keymap.split("-")[-1] |
| 111 | + if keymap_one in self.layouts[layout]: |
| 112 | + return keymap_one |
| 113 | + return None |
| 114 | + |
| 115 | + |
| 116 | +def main(): |
| 117 | + if len(sys.argv) != 2: |
| 118 | + print("Syntax: {0} <KeymapLayout>".format(sys.argv[0])) |
| 119 | + sys.exit(1) |
| 120 | + |
| 121 | + xinitrc = os.getenv("HOME") + "/.xinitrc" |
| 122 | + if not os.path.exists(xinitrc) : |
| 123 | + print("Error: {0} does not exist.".format(xinitrc)) |
| 124 | + sys.exit(1) |
| 125 | + |
| 126 | + rules = XKB() |
| 127 | + rules.parseRules() |
| 128 | + keymap = sys.argv[1] |
| 129 | + |
| 130 | + x11_layout = rules.x11Layout(keymap) |
| 131 | + x11_variant = rules.x11Variant(keymap, x11_layout) |
| 132 | + settings = KeyboardSettings(keymap, x11_layout, x11_variant) |
| 133 | + settings.write(xinitrc) |
| 134 | + |
| 135 | + |
| 136 | +def main_debug_all(): |
| 137 | + loadkeys_keymaps = ''' |
| 138 | + dvorak.map |
| 139 | + azerty.map |
| 140 | + be-latin1.map |
| 141 | + fr-latin1.map |
| 142 | + fr-latin9.map |
| 143 | + fr-pc.map |
| 144 | + fr.map |
| 145 | + wangbe.map |
| 146 | + wangbe2.map |
| 147 | + ANSI-dvorak.map |
| 148 | + dvorak-l.map |
| 149 | + dvorak-r.map |
| 150 | + dvorak.map |
| 151 | + tr_f-latin5.map |
| 152 | + trf.map |
| 153 | + bg-cp1251.map |
| 154 | + bg-cp855.map |
| 155 | + bg_bds-cp1251.map |
| 156 | + bg_bds-utf8.map |
| 157 | + bg_pho-cp1251.map |
| 158 | + bg_pho-utf8.map |
| 159 | + br-abnt.map |
| 160 | + br-abnt2.map |
| 161 | + br-latin1-abnt2.map |
| 162 | + br-latin1-us.map |
| 163 | + by.map |
| 164 | + cf.map |
| 165 | + cz-cp1250.map |
| 166 | + cz-lat2-prog.map |
| 167 | + cz-lat2.map |
| 168 | + cz.map |
| 169 | + defkeymap.map |
| 170 | + defkeymap_V1.0.map |
| 171 | + dk-latin1.map |
| 172 | + dk.map |
| 173 | + emacs.map |
| 174 | + emacs2.map |
| 175 | + es-cp850.map |
| 176 | + es.map |
| 177 | + et-nodeadkeys.map |
| 178 | + et.map |
| 179 | + fi-latin1.map |
| 180 | + fi-latin9.map |
| 181 | + fi.map |
| 182 | + gr-pc.map |
| 183 | + gr.map |
| 184 | + hu101.map |
| 185 | + il-heb.map |
| 186 | + il-phonetic.map |
| 187 | + il.map |
| 188 | + is-latin1-us.map |
| 189 | + is-latin1.map |
| 190 | + it-ibm.map |
| 191 | + it.map |
| 192 | + it2.map |
| 193 | + jp106.map |
| 194 | + la-latin1.map |
| 195 | + lt.baltic.map |
| 196 | + lt.l4.map |
| 197 | + lt.map |
| 198 | + mk-cp1251.map |
| 199 | + mk-utf.map |
| 200 | + mk.map |
| 201 | + mk0.map |
| 202 | + nl.map |
| 203 | + nl2.map |
| 204 | + no-latin1.map |
| 205 | + no.map |
| 206 | + pc110.map |
| 207 | + pl.map |
| 208 | + pl2.map |
| 209 | + pt-latin1.map |
| 210 | + pt-latin9.map |
| 211 | + ro_win.map |
| 212 | + ru-cp1251.map |
| 213 | + ru-ms.map |
| 214 | + ru-yawerty.map |
| 215 | + ru.map |
| 216 | + ru1.map |
| 217 | + ru2.map |
| 218 | + ru3.map |
| 219 | + ru4.map |
| 220 | + ru_win.map |
| 221 | + se-fi-ir209.map |
| 222 | + se-fi-lat6.map |
| 223 | + se-ir209.map |
| 224 | + se-lat6.map |
| 225 | + sk-prog-qwerty.map |
| 226 | + sk-qwerty.map |
| 227 | + sr-cy.map |
| 228 | + sv-latin1.map |
| 229 | + tr_q-latin5.map |
| 230 | + tralt.map |
| 231 | + trq.map |
| 232 | + ua-utf-ws.map |
| 233 | + ua-utf.map |
| 234 | + ua-ws.map |
| 235 | + ua.map |
| 236 | + uk.map |
| 237 | + us-acentos.map |
| 238 | + us.map |
| 239 | + croat.map |
| 240 | + cz-us-qwertz.map |
| 241 | + de-latin1-nodeadkeys.map |
| 242 | + de-latin1.map |
| 243 | + de.map |
| 244 | + de_CH-latin1.map |
| 245 | + fr_CH-latin1.map |
| 246 | + fr_CH.map |
| 247 | + hu.map |
| 248 | + sg-latin1-lk450.map |
| 249 | + sg-latin1.map |
| 250 | + sg.map |
| 251 | + sk-prog-qwertz.map |
| 252 | + sk-qwertz.map |
| 253 | + slovene.map |
| 254 | + ''' |
| 255 | + |
| 256 | + rules = XKB() |
| 257 | + rules.parseRules() |
| 258 | + |
| 259 | + # create translation rules |
| 260 | + mappings = {} |
| 261 | + keymaps = [x.strip().split(".")[0] for x in loadkeys_keymaps.strip().split("\n")] |
| 262 | + for keymap in keymaps: |
| 263 | + x11_layout = rules.x11Layout(keymap) |
| 264 | + x11_variant = rules.x11Variant(keymap, x11_layout) |
| 265 | + mappings[keymap] = KeyboardSettings(keymap, x11_layout, x11_variant) |
| 266 | + mappings[keymap].test() |
| 267 | + |
| 268 | +if __name__ == "__main__": |
| 269 | + main() |
0 commit comments