#!/usr/bin/env python3 import functools import itertools import json import unicodedata from typing import NamedTuple, List, Optional import pyperclip class KeyCode(NamedTuple): scan_code: int name_lower: str name_upper: str ascii_lower: Optional[str] ascii_upper: Optional[str] # scancodes retrieved from https://wiki.osdev.org/PS/2_Keyboard # scancodes transformed with https://www.convertjson.com/html-table-to-json.htm blacklist_names = {'(zero)'} special_map = { '\\': 'forwardSlash', '/': 'backSlash', '[': 'bracketLeft', ']': 'bracketRight', ';': 'colonPressed', "'": None, '`': None, ',': 'comma', '.': 'dot', # todo keypad * '-': 'dash', '=': 'equals', } def get_unknown(i): return KeyCode(i, f"Unknown{i:02x}Lower", f"Unknown{i:02x}Upper", None, None) def not_in_blacklist(name: str) -> bool: return name not in blacklist_names def remove_braces(name: str) -> str: name = name.lstrip('(').rstrip(')') if name in special_map: return special_map[name] return name def key_name_to_name(names: List[str]) -> str: _names: List[str] = list(filter(lambda i: i is not None, map(remove_braces, filter(not_in_blacklist, names)))) _names_cap = itertools.chain([_names[0][0].lower() + _names[0][1:]], map(lambda i: i[0].upper() + i[1:], _names[1:])) return ''.join(_names_cap) def get_name(item: str): item = item.replace(' ', ' ') if len(item) == 1: item = unicodedata.name(item).title() if item.startswith('Latin'): return 'Letter' + item.split()[-1] return item.replace(' ', '_') if item else None def transform_set1(path): codes = [] with open(path) as f: data = json.load(f) for ibm_number, make_break_1, _, _, lower, upper in data: make_code, break_code = make_break_1.split('/') if make_code.startswith('E0') or make_code.startswith('E1'): # skipping multi codes for now continue make_code_i = int(make_code, base=16) break_code_i = int(break_code, base=16) if make_code_i != break_code_i ^ 0x80: raise ValueError("Make/Break not equal" + ibm_number) codes.append(KeyCode( make_code_i, get_name(lower), get_name(upper), lower, upper, )) codes_map = {} for code in codes: if code.scan_code in codes_map: raise ValueError(f"Duplicate code {code!r}") codes_map[code.scan_code] = code # max_val = functools.reduce(lambda a, b: max(a, b), map(lambda x: x.scan_code, codes), 0) return codes_map # txts = [] # for i in range(max_val): # code = codes_map.get(i) or get_unknown(i) # txts.append(f'{code.scan_code}\t{code.name_lower}\t{code.name_upper}\t{code.ascii_lower or None}\t{code.ascii_upper or None}') # pyperclip.copy('\n'.join(txts)) def get_ascii_val(val: str): if not val: return 'NULL' if len(val) > 1: return 'NULL' if val == "'": return "'\\''" return repr(val) def main(): transform_set1() if __name__ == '__main__': main()