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
|
#
# 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 supervisor import ticks_ms
from kmk.keys import Key, KC
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)
return
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
This layer keep a track of the last time the layer was updated. This is
used as timer in order to put the device in sleep mode or not.
"""
def __init__(self):
self.keys = []
self._name = ""
self.timer_start = ticks_ms()
def load(self, json_data):
""" Load the json dictionnary into the layer. The dictionnary shall be
either
- a string: The key named will be sent: "A"
- a list: All the keys will be chained in a single stroke:
["^", "A"]
- a dictionnary: Used to create custom sequences:
{"seq": ["/", "W", "C", "ENTER"]}
- null: The key will do nothing.
The dictionnary must be one of the operators declared above.
"""
self.timer_start = ticks_ms()
for name, keys in json_data.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
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self.timer_start = ticks_ms()
self._name = value
|