diff --git a/README.md b/README.md index b541840..178d0ca 100644 --- a/README.md +++ b/README.md @@ -572,6 +572,13 @@ The `kbplacer` is used by additional tools available in [tools](tools/README.md) + + + kle2kle.py - edit KLE layout, supports:
+ labels and colors reset and automatic VIA style row,column matrix label annotation. + + + diff --git a/pyproject.toml b/pyproject.toml index 691ee96..13aa4d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -153,3 +153,4 @@ layout2image = "python tools/layout2image.py {args}" layout2schematic = "python tools/layout2schematic.py {args}" layout2url = "python tools/layout2url.py {args}" layout2openscad = "python tools/layout2openscad.py {args}" +kle2kle = "python tools/kle2kle.py {args}" diff --git a/resources/example-kle2kle.png b/resources/example-kle2kle.png new file mode 100644 index 0000000..efd2ff0 Binary files /dev/null and b/resources/example-kle2kle.png differ diff --git a/tools/kle2kle.py b/tools/kle2kle.py new file mode 100644 index 0000000..b7066c9 --- /dev/null +++ b/tools/kle2kle.py @@ -0,0 +1,115 @@ +import argparse +import json +import math +import sys +from typing import List, Tuple + +from kbplacer import kle_serial +from kbplacer.kle_serial import ( + Key, + Keyboard, + KeyDefault, + MatrixAnnotatedKeyboard, + parse_kle, +) + + +def get_key_center(key: Key) -> Tuple[float, float]: + x = key.x + (key.width / 2) + y = key.y + (key.height / 2) + + rot_origin_x = key.rotation_x + rot_origin_y = key.rotation_y + angle = 1 * key.rotation_angle + angle_rad = angle * math.pi / 180 + + x = x - rot_origin_x + y = y - rot_origin_y + + x1 = (x * math.cos(angle_rad)) - (y * math.sin(angle_rad)) + y1 = (x * math.sin(angle_rad)) + (y * math.cos(angle_rad)) + + x = x1 + rot_origin_x + y = y1 + rot_origin_y + + return x, y + + +def annotate_keys(keys: List[Key]) -> None: + for key in keys: + x, y = get_key_center(key) + x, y = int(x), int(y) + key.set_label(MatrixAnnotatedKeyboard.MATRIX_COORDINATES_LABEL, f"{y},{x}") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="KLE edit") + parser.add_argument("-in", required=True, help="Layout file") + parser.add_argument("-out", required=False, help="Result file") + parser.add_argument( + "-text", required=False, action="store_true", help="Print KLE raw data" + ) + + parser.add_argument( + "-remove-labels", action="store_true", help="Remove all key labels" + ) + parser.add_argument( + "-reset-colors", action="store_true", help="Reset colors to defaults" + ) + parser.add_argument( + "-annotate", + action="store_true", + help=( + "Automatically annotate keys with row,column labels. " + "All labels must be empty. Can be combined with -remove-labels action." + ), + ) + + args = parser.parse_args() + input_path = getattr(args, "in") + output_path = getattr(args, "out") + print_result = args.text + remove_labels = args.remove_labels + reset_colors = args.reset_colors + annotate = args.annotate + + with open(input_path, "r", encoding="utf-8") as input_file: + layout = json.load(input_file) + + keyboard = None + try: + keyboard = parse_kle(layout) + output_format = "KLE_RAW" + except Exception: + keyboard = Keyboard.from_json(layout) + output_format = "KLE_INTERNAL" + + if keyboard == None: + print(f"Unable to get keyboard layout from file '{input_file}'") + sys.exit(1) + + if remove_labels: + for k in keyboard.keys: + k.labels = [] + + if reset_colors: + for k in keyboard.keys: + k.color = kle_serial.DEFAULT_KEY_COLOR + k.textColor = [] + k.default = KeyDefault() + + if annotate: + annotate_keys(keyboard.keys) + + if print_result: + raw_kle = keyboard.to_kle() + print(raw_kle) + + if output_format == "KLE_INTERNAL": + result = json.loads(keyboard.to_json()) + else: # KLE_RAW + result = json.loads("[" + keyboard.to_kle() + "]") + + if output_path: + with open(output_path, "w", encoding="utf-8") as output_file: + json.dump(result, output_file, indent=2)