aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSébastien Dailly <sebastien@dailly.me>2025-07-20 15:26:58 +0200
committerSébastien Dailly <sebastien@dailly.me>2025-07-20 15:26:58 +0200
commitc31148f482adf44ded7cec1d683e01d995294850 (patch)
tree42dc4032085fc1466bbdeb5bf71076436a3844ef
parentcc2c9c0bd9d646a33f0324eae024618bd2a68983 (diff)
Added some tests, and a handle commands in the json (only 'layer' for now)
-rw-r--r--boot.py7
-rw-r--r--code.py33
-rw-r--r--ff.json8
-rw-r--r--json_layer.py62
-rw-r--r--serial_conn.py90
5 files changed, 124 insertions, 76 deletions
diff --git a/boot.py b/boot.py
index e1c58e0..3f2dfb2 100644
--- a/boot.py
+++ b/boot.py
@@ -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)
diff --git a/code.py b/code.py
index a104d7c..a738543 100644
--- a/code.py
+++ b/code.py
@@ -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()
diff --git a/ff.json b/ff.json
index ad8f44e..b0f2f83 100644
--- a/ff.json
+++ b/ff.json
@@ -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.
+ """