forked from extern/Unexpected-Keyboard
500f4e41d3
This merges the "Layouts" option with the "Custom layout" option. A custom layout becomes an item in the "Layouts" list among the other layouts. It's possible to add several custom layouts. Selecting the "Custom layout" item in the list opens a second dialog for entering the layout description. Layouts are serialized as JSON object and are decoded solely in the LayoutsPreference class.
72 lines
2.9 KiB
Python
72 lines
2.9 KiB
Python
#!/usr/bin/env python
|
|
|
|
# Generates the list of layouts in res/values/layouts.xml from the layout files
|
|
# in res/xml. Every layouts must have a 'name' attribute to be listed.
|
|
|
|
import itertools as it
|
|
import sys, os, glob
|
|
import xml.etree.ElementTree as XML
|
|
|
|
# Layouts first in the list (these are the programming layouts). Other layouts
|
|
# are sorted alphabetically.
|
|
FIRST_LAYOUTS = [ "latn_qwerty_us", "latn_colemak", "latn_dvorak" ]
|
|
|
|
# File names that are known not to be layouts. Avoid warning about them.
|
|
KNOWN_NOT_LAYOUT = set([
|
|
"number_row", "numpad", "pin", "bottom_row", "settings", "method",
|
|
"greekmath", "numeric" ])
|
|
|
|
# Read a layout from a file. Returns [None] if [fname] is not a layout.
|
|
def read_layout(fname):
|
|
root = XML.parse(fname).getroot()
|
|
if root.tag != "keyboard":
|
|
return None
|
|
return { "name": root.get("name") }
|
|
|
|
# Yields the id (based on the file name) and the display name for every layouts
|
|
def read_layouts(files):
|
|
for layout_file in files:
|
|
layout_id, _ = os.path.splitext(os.path.basename(layout_file))
|
|
layout = read_layout(layout_file)
|
|
if layout_id in KNOWN_NOT_LAYOUT:
|
|
continue
|
|
elif layout == None:
|
|
print("Not a layout file: %s" % layout_file)
|
|
elif layout["name"] == None:
|
|
print("Layout doesn't have a name: %s" % layout_id)
|
|
else:
|
|
yield (layout_id, layout["name"])
|
|
|
|
# Sort layouts alphabetically, except for layouts in FIRST_LAYOUTS, which are
|
|
# placed at the top.
|
|
# Returns a list. 'layouts' can be an iterator.
|
|
def sort_layouts(layouts):
|
|
layouts = dict(layouts)
|
|
head = [ (lid, layouts.pop(lid)) for lid in FIRST_LAYOUTS ]
|
|
return head + sorted(layouts.items())
|
|
|
|
# Write the XML arrays used in the preferences.
|
|
def generate_arrays(out, layouts):
|
|
def mk_array(tag, name, strings_items):
|
|
elem = XML.Element(tag, name=name)
|
|
for s in strings_items:
|
|
item = XML.Element("item")
|
|
item.text = s
|
|
elem.append(item)
|
|
return elem
|
|
system_item = [ ("system", "@string/pref_layout_e_system") ]
|
|
custom_item = [ ("custom", "@string/pref_layout_e_custom") ]
|
|
values_items, entries_items = zip(*(system_item + layouts + custom_item)) # unzip
|
|
ids_items = map(lambda s: "@xml/%s" % s if s not in ["system", "custom"] else "-1", values_items)
|
|
root = XML.Element("resources")
|
|
root.append(XML.Comment(text="DO NOT EDIT. This file is generated, see gen_layouts.py."))
|
|
root.append(mk_array("string-array", "pref_layout_values", values_items))
|
|
root.append(mk_array("string-array", "pref_layout_entries", entries_items))
|
|
root.append(mk_array("integer-array", "layout_ids", ids_items))
|
|
XML.indent(root)
|
|
XML.ElementTree(element=root).write(out, encoding="unicode", xml_declaration=True)
|
|
|
|
layouts = sort_layouts(read_layouts(glob.glob("res/xml/*.xml")))
|
|
with open("res/values/layouts.xml", "w") as out:
|
|
generate_arrays(out, layouts)
|