mirror of
https://github.com/Julow/Unexpected-Keyboard.git
synced 2024-11-24 16:23:14 +01:00
6b1551d103
The attribute 'c' specifies the symbol in the center of a key, just like 'key0'. This adds consistency with the cardinal direction attributes and is intended to make layouts more readable.
116 lines
3.9 KiB
Python
116 lines
3.9 KiB
Python
import xml.etree.ElementTree as ET
|
|
import sys, os
|
|
|
|
warning_count = 0
|
|
|
|
KNOWN_NOT_LAYOUT = set([
|
|
"number_row", "numpad", "pin",
|
|
"bottom_row", "settings", "method",
|
|
"greekmath", "numeric", "emoji_bottom_row",
|
|
"clipboard_bottom_row" ])
|
|
|
|
KEY_ATTRIBUTES = set([
|
|
"key0", "key1", "key2", "key3", "key4", "key5", "key6", "key7", "key8",
|
|
"c", "nw", "ne", "sw", "se", "w", "e", "n", "s"
|
|
])
|
|
|
|
def warn(msg):
|
|
global warning_count
|
|
print(msg)
|
|
warning_count += 1
|
|
|
|
def key_list_str(keys):
|
|
return ", ".join(sorted(list(keys)))
|
|
|
|
def missing_some_of(keys, symbols, class_name=None):
|
|
if class_name is None:
|
|
class_name = "of [" + ", ".join(symbols) + "]"
|
|
missing = set(symbols).difference(keys)
|
|
if len(missing) > 0 and len(missing) != len(symbols):
|
|
warn("Layout includes some %s but not all, missing: %s" % (
|
|
class_name, key_list_str(missing)))
|
|
|
|
def missing_required(keys, symbols, msg):
|
|
missing = set(symbols).difference(keys)
|
|
if len(missing) > 0:
|
|
warn("%s, missing: %s" % (msg, key_list_str(missing)))
|
|
|
|
def unexpected_keys(keys, symbols, msg):
|
|
unexpected = set(symbols).intersection(keys)
|
|
if len(unexpected) > 0:
|
|
warn("%s, unexpected: %s" % (msg, key_list_str(unexpected)))
|
|
|
|
# Write to [keys] and [dup].
|
|
def parse_row_from_et(row, keys, dup):
|
|
for key in row:
|
|
for attr in key.keys():
|
|
if attr in KEY_ATTRIBUTES:
|
|
k = key.get(attr).removeprefix("\\")
|
|
if k in keys: dup.add(k)
|
|
keys.add(k)
|
|
|
|
def parse_layout(fname):
|
|
keys = set()
|
|
dup = set()
|
|
root = ET.parse(fname).getroot()
|
|
if root.tag != "keyboard":
|
|
return None
|
|
for row in root:
|
|
parse_row_from_et(row, keys, dup)
|
|
return root, keys, dup
|
|
|
|
def parse_row(fname):
|
|
keys = set()
|
|
dup = set()
|
|
root = ET.parse(fname).getroot()
|
|
if root.tag != "row":
|
|
return None
|
|
parse_row_from_et(root, keys, dup)
|
|
return root, keys, dup
|
|
|
|
def check_layout(layout):
|
|
root, keys, dup = layout
|
|
if len(dup) > 0: warn("Duplicate keys: " + key_list_str(dup))
|
|
missing_some_of(keys, "~!@#$%^&*(){}`[]=\\-_;:/.,?<>'\"+|", "ASCII punctuation")
|
|
missing_some_of(keys, "0123456789", "digits")
|
|
missing_required(keys,
|
|
["loc esc", "loc tab", "backspace", "delete"],
|
|
"Layout doesn't define some important keys")
|
|
unexpected_keys(keys,
|
|
["copy", "paste", "cut", "selectAll", "shareText",
|
|
"pasteAsPlainText", "undo", "redo" ],
|
|
"Layout contains editing keys")
|
|
unexpected_keys(keys,
|
|
[ "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9",
|
|
"f10", "f11", "f12" ],
|
|
"Layout contains function keys")
|
|
unexpected_keys(keys, [""], "Layout contains empty strings")
|
|
unexpected_keys(keys, ["loc"], "Special keyword cannot be a symbol")
|
|
unexpected_keys(keys, filter(lambda k: k.strip()!=k, keys), "Some keys contain whitespaces")
|
|
unexpected_keys(keys, ["f11_placeholder", "f12_placeholder"], "These keys are now added automatically")
|
|
|
|
_, bottom_row_keys, _ = parse_row("res/xml/bottom_row.xml")
|
|
|
|
if root.get("bottom_row") == "false":
|
|
missing_required(keys, bottom_row_keys,
|
|
"Layout redefines the bottom row but some important keys are missing")
|
|
else:
|
|
unexpected_keys(keys, bottom_row_keys,
|
|
"Layout contains keys present in the bottom row")
|
|
|
|
if root.get("script") == None:
|
|
warn("Layout doesn't specify a script.")
|
|
|
|
for fname in sorted(sys.argv[1:]):
|
|
layout_id, _ = os.path.splitext(os.path.basename(fname))
|
|
if layout_id in KNOWN_NOT_LAYOUT:
|
|
continue
|
|
layout = parse_layout(fname)
|
|
if layout == None:
|
|
print("Not a layout file: %s" % layout_id)
|
|
else:
|
|
print("# %s" % layout_id)
|
|
warning_count = 0
|
|
check_layout(layout)
|
|
print("%d warnings" % warning_count)
|