aboutsummaryrefslogtreecommitdiff
path: root/json_layer.py
diff options
context:
space:
mode:
Diffstat (limited to 'json_layer.py')
-rw-r--r--json_layer.py153
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