1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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
|