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
|
#
# 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 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
"""
def __init__(self):
self.name = ""
self.keys = []
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.
"""
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
|