# # Read data in the json format from the serial connexion. # The json shall hold in a single line, and the following commands are # recognized : # {"layer": layer_name} : change the keyboard to the given layer # {"stack": layer_name} : stack a new layer on top on an existing one # {"get_layer"} # from usb_cdc import data import json from kmk.modules import Module from kmk.keys import Key, KC #from kmk.handlers.sequences import simple_key_sequence from kmk.modules.macros import Delay, Macros, Tap # This dictionnary is a sort of point of function. # # It gives a way to apply a specific function in the json # # There is mutually recursive calls between # - operators # - key_of_json # - sequence # # I do not define it yet, only declare it. operators = {} def key_of_json(element, inside=False): """ Create the key from the key name. The value can be either a string or a list. If the parameter is a string, the associated key will be returned, otherwise this will be the chain of all of them. """ if isinstance(element, int): return element if isinstance(element, str): return KC[element] if isinstance(element, list): hd, *tl = element key = key_of_json(hd) if len(tl) != 0: # Chainable key / recursive function return key( key_of_json(tl) ) else: return key if isinstance(element, dict): for key, value in element.items(): return operators[key](value) pass def encode_macro(element): """ Encode the result of the function key_of_json in order to build a macro of this """ key = key_of_json(element) if isinstance(key, int): return Delay(key) elif isinstance(key, Key): return Tap(key) return key def sequence(element): """ Convert a list of keys into a sequence of them. """ # Convert each element in the list as Tap function seq = list(map(encode_macro, element)) # Send the list as arguments to the function return KC.MACRO(*seq) def no_release(element): key = key_of_json(element) return key(no_release=True) def no_press(element): key = key_of_json(element) return key(no_press=True) # Now I can define the dictionnary operators["key"] = key_of_json operators["chain"] = key_of_json operators["seq"] = sequence operators["no_release"] = no_release operators["no_press"] = no_press class Layer(object): """ Layer as an object. This class gives the property name in addition of the keymap list """ def __init__(self, jdata): self.load(jdata) def load(self, json_data): jdata = json.loads(json_data.strip()) for name, keys in jdata.items(): self.name = name self.keys = list(map(key_of_json, keys)) def __getitem__(self, idx): """ When the layer is indexed, return the keymap associated with """ return self.keys[idx] def __eq__(self, other): """ Compare two layer by the name only """ return self.name == other.name class JsonLayer(Module): def during_bootup(self, keyboard): try: # Do not set any timeout, we check before reading a string if there # is any content to read, but block to be sure to read everything. data.timeout = None except AttributeError: pass def before_matrix_scan(self, keyboard): pass def after_matrix_scan(self, keyboard): pass def process_key(self, keyboard, key, is_pressed, int_coord): return key def before_hid_send(self, keyboard): # Serial.data isn't initialized. if not data: return # Nothing to parse. if data.in_waiting <= 0: return line = data.readline() if not line: return try: keyboard.keymap[0].load(line.decode()) except Exception as err: print(err) def after_hid_send(self, keyboard): pass def on_powersave_enable(self, keyboard): pass def on_powersave_disable(self, keyboard): pass