diff options
author | Sébastien Dailly <sebastien@dailly.me> | 2024-08-11 16:43:29 +0200 |
---|---|---|
committer | Sébastien Dailly <sebastien@dailly.me> | 2024-08-11 16:43:29 +0200 |
commit | 109c4395a86c72fb34f820c633a1679590dc8fdb (patch) | |
tree | 7f6f405b9e4d4bf6b1650f65d4b9e40fcdbe3f83 /json_layer.py |
Initial commitmain
Diffstat (limited to 'json_layer.py')
-rw-r--r-- | json_layer.py | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/json_layer.py b/json_layer.py new file mode 100644 index 0000000..4d4c69c --- /dev/null +++ b/json_layer.py @@ -0,0 +1,153 @@ +# +# 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 |