diff options
| author | Sébastien Dailly <sebastien@dailly.me> | 2025-07-20 15:26:58 +0200 | 
|---|---|---|
| committer | Sébastien Dailly <sebastien@dailly.me> | 2025-07-20 15:26:58 +0200 | 
| commit | c31148f482adf44ded7cec1d683e01d995294850 (patch) | |
| tree | 42dc4032085fc1466bbdeb5bf71076436a3844ef | |
| parent | cc2c9c0bd9d646a33f0324eae024618bd2a68983 (diff) | |
Added some tests, and a handle commands in the json (only 'layer' for now)
| -rw-r--r-- | boot.py | 7 | ||||
| -rw-r--r-- | code.py | 33 | ||||
| -rw-r--r-- | ff.json | 8 | ||||
| -rw-r--r-- | json_layer.py | 62 | ||||
| -rw-r--r-- | serial_conn.py | 90 | 
5 files changed, 124 insertions, 76 deletions
@@ -2,9 +2,12 @@ import usb_cdc  usb_cdc.enable(data=True)  import layout +import storage  if layout.check_key():      print("Key pressed") +    storage.remount("/", readonly=False) +    storage.enable_usb_drive()  else: -    import storage +    # Remount in read only +    storage.remount("/", readonly=True)      storage.disable_usb_drive() -    storage.remount("/", False) @@ -1,12 +1,15 @@  import board +from supervisor import runtime +import json +from serial_conn import Client +import oled  from supervisor import runtime  # Do not reload the application when the files are changed  runtime.autoreload = False  # Initialize the BEPO layout  import kmk.handlers.stock as handlers -#from kmk.key_validators import key_seq_sleep_validator  from kmk import keys  keys.KC.clear()  keys.KEY_GENERATORS=( @@ -18,6 +21,7 @@ keys.KEY_GENERATORS=(      keys.maybe_make_no_key,      )  KC=keys.KC +  import kmk_frnb  from kmk.kmk_keyboard import KMKKeyboard @@ -26,29 +30,34 @@ keyboard = KMKKeyboard()  import layout  layout.set_keyboard(keyboard) -import oled  oled.main(keyboard)  import json_layer  def load_json(file): -    with open("ff.json", "r") as ff_conf: -        s = ff_conf.read() -        layer = json_layer.Layer(s) -        return layer +    with open(file, "r") as conf: +        file_data = conf.read() +        key_layer = json_layer.Layer() +        json_data = json.loads(file_data.strip()) +        key_layer.load(json_data) +        return key_layer  from kmk.modules.macros import Macros  from kmk.modules.mouse_keys import MouseKeys + +# Create the first layer in the keyboard. The object will be reused later when +# receiving commands from the serial connection. +layer = load_json("ff.json") + +keyboard.keymap = [ +    layer +] +  keyboard.modules = [          Macros(), -        json_layer.JsonLayer(), +        Client(),          MouseKeys(),      ] -firefox = load_json("ff.json") - -keyboard.keymap = [ -    firefox -]  if __name__ == '__main__':      keyboard.go() @@ -1,6 +1,6 @@ -{ "Firefox": [ -    {"seq": ["A", "B", "C"]}, ["^", "R"], ["^", "T"], ["^", "W"],  -    null, null, ["^", "PAGE_UP"], ["^", "PAGE_DOWN"],  -    null, null, ["^", "WINDOWS", "LEFT_ARROW"], ["^", "WINDOWS", "RIGHT_ARROW"],  +{ "Initialized": [ +    null, null, null, null +    null, null, null, null +    null, null, null, null      null, null, null, null  ]} diff --git a/json_layer.py b/json_layer.py index 91699b5..8d12681 100644 --- a/json_layer.py +++ b/json_layer.py @@ -7,12 +7,8 @@  # {"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. @@ -48,7 +44,7 @@ def key_of_json(element, inside=False):      if isinstance(element, dict):          for key, value in element.items():              return operators[key](value) -    pass +    return  def encode_macro(element):      """ Encode the result of the function key_of_json in order to build a macro @@ -89,9 +85,9 @@ class Layer(object):          This class gives the property name in addition of the keymap list      """ -    def __init__(self, jdata): -        json_data = json.loads(jdata.strip()) -        self.load(json_data) +    def __init__(self): +        self.name = "" +        self.keys = []      def load(self, json_data):          """ Load the json dictionnary into the layer. The dictionnary shall be @@ -118,53 +114,3 @@ class Layer(object):          """ 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 - -        if not data.connected: -            keyboard.keymap[0].name = "Disconnected" -            return - -        # Nothing to parse. -        if data.in_waiting <= 0: -            return -        line = data.readline() -        if not line: -            return - -        try: -            jdata = json.loads(line.decode().strip()) -            keyboard.keymap[0].load(jdata) -        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 diff --git a/serial_conn.py b/serial_conn.py new file mode 100644 index 0000000..4e885b2 --- /dev/null +++ b/serial_conn.py @@ -0,0 +1,90 @@ +from kmk.modules import Module +from usb_cdc import data +import json + +import json_layer + +class Client(Module): +    """ Listen the connections from host, and apply the actions depending of +        the json command. +    """ + +    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 process_key(self, keyboard, key, is_pressed, int_coord): +        return key + +    def before_hid_send(self, keyboard): + +        # Serial.data isn't initialized yet. +        if not data: +            return + +        if not data.connected: +            keyboard.keymap[0].name = "Disconnected" +            return + +        # Nothing to parse. +        if data.in_waiting <= 0: +            return +        line = data.readline() +        if not line: +            return + +        try: +            content = line.decode().strip() +            if not content: +                # If strip produced an empty string, stop here. +                return +            jdata = json.loads(content) +        except ValueError as err: +            # In circuitPython, json error are reported as ValueError. +            # seet https://docs.circuitpython.org/en/latest/docs/library/json.html#json.load +            print(err, line) +            return + +        # Json is valid, try to read the command, and consider the input is a +        # direct raw layer instruction if this does not work. + +        actions = { +            "layer" : lambda x : keyboard.keymap[0].load(x), +        } + +        try: +            for action, args in jdata.items(): +                actions[action](args) +            return +        except Exception as err: +            pass + +        try: +            keyboard.keymap[0].load(jdata) +        except Exception as err: +            print("rawdata:", err) +            return + +    def before_matrix_scan(self, keyboard): +        """ Default implementation, do nothing. +        """ + +    def after_matrix_scan(self, keyboard): +        """ Default implementation, do nothing. +        """ + +    def after_hid_send(self, keyboard): +        """ Default implementation, do nothing. +        """ + +    def on_powersave_enable(self, keyboard): +        """ Default implementation, do nothing. +        """ + +    def on_powersave_disable(self, keyboard): +        """ Default implementation, do nothing. +        """  | 
