aboutsummaryrefslogtreecommitdiff
path: root/json_layer.py
blob: 8d126810b67a5300bc9832f12fd74f03bbe2f6b4 (plain)
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