aboutsummaryrefslogtreecommitdiff
path: root/json_layer.py
blob: 9e98fc3bae9e0538245598ff1f25d8b1b998fca6 (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
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