8
8
9
9
# pylint: disable=import-error, unused-import, too-few-public-methods, eval-used
10
10
11
- import json
12
11
import os
13
12
import time
14
13
import board
18
17
import rotaryio
19
18
import terminalio
20
19
import usb_hid
20
+ from adafruit_display_shapes .rect import Rect
21
21
from adafruit_display_text import label
22
22
from adafruit_hid .keyboard import Keyboard
23
23
from adafruit_hid .keycode import Keycode
24
+ from adafruit_hid .keyboard_layout_us import KeyboardLayoutUS
24
25
25
26
26
27
# CONFIGURABLES ------------------------
@@ -55,71 +56,48 @@ def debounce(self):
55
56
return value
56
57
return None
57
58
58
- class Macro :
59
- """ Class representing a single macro sequence - a text label, LED color
60
- for the keypad, and a keycode sequence to issue when activated. """
61
- def __init__ (self , desc , color , sequence ):
62
- self .desc = desc
63
- self .color = eval (color )
64
- self .sequence = sequence
65
- self .in_order = False
66
- for key in sequence :
67
- if key .startswith ('+' ) or key .startswith ('-' ):
68
- self .in_order = True
69
- break
70
-
71
59
class App :
72
60
""" Class representing a host-side application, for which we have a set
73
61
of macro sequences. """
74
- def __init__ (self , filename ):
75
- with open (MACRO_FOLDER + '/' + filename ) as jsonfile :
76
- json_data = json .load (jsonfile )
77
- self .name = json_data ['name' ]
78
- default_color = json_data ['color' ] if 'color' in json_data else '0'
79
- self .macros = []
80
- for mac in json_data ['macros' ]:
81
- self .macros .append (Macro (
82
- mac ['desc' ] if 'desc' in mac else None ,
83
- mac ['color' ] if 'color' in mac else default_color ,
84
- mac ['sequence' ] if 'sequence' in mac else None ))
62
+ def __init__ (self , appdata ):
63
+ self .name = appdata ['name' ]
64
+ self .macros = appdata ['macros' ]
85
65
86
66
def switch (self ):
87
67
""" Activate application settings; update OLED labels and LED
88
68
colors. """
89
- GROUP [12 ].text = self .name # Application name
69
+ GROUP [13 ].text = self .name # Application name
90
70
for i in range (12 ):
91
71
if i < len (self .macros ): # Key in use, set label + LED color
92
- PIXELS [i ] = self .macros [i ]. color
93
- GROUP [i ].text = self .macros [i ]. desc
72
+ PIXELS [i ] = self .macros [i ][ 0 ]
73
+ GROUP [i ].text = self .macros [i ][ 1 ]
94
74
else : # Key not in use, no label or LED
95
75
PIXELS [i ] = 0
96
76
GROUP [i ].text = ''
97
77
PIXELS .show ()
98
78
99
- def code (name ):
100
- """ Convert a key code name (e.g. 'COMMAND') to a numeric value for
101
- press/release events. """
102
- return eval ('Keycode.' + name .upper ())
103
-
104
79
105
80
# INITIALIZATION -----------------------
106
81
107
82
DISPLAY = board .DISPLAY
108
83
ENCODER = rotaryio .IncrementalEncoder (board .ENCODER_B , board .ENCODER_A )
109
84
PIXELS = neopixel .NeoPixel (board .NEOPIXEL , 12 , auto_write = False )
110
85
KEYBOARD = Keyboard (usb_hid .devices )
86
+ LAYOUT = KeyboardLayoutUS (KEYBOARD )
87
+
111
88
112
- GROUP = displayio .Group (max_size = 13 )
89
+ GROUP = displayio .Group (max_size = 14 )
113
90
for KEY_INDEX in range (12 ):
114
91
x = KEY_INDEX % 3
115
92
y = KEY_INDEX // 3
116
93
GROUP .append (label .Label (terminalio .FONT , text = '' , color = 0xFFFFFF ,
117
94
anchored_position = ((DISPLAY .width - 1 ) * x / 2 ,
118
95
DISPLAY .height - 1 -
119
- (3 - y ) * 11 ),
96
+ (3 - y ) * 12 ),
120
97
anchor_point = (x / 2 , 1.0 ), max_glyphs = 15 ))
121
- GROUP .append (label .Label (terminalio .FONT , text = '' , color = 0xFFFFFF ,
122
- anchored_position = (DISPLAY .width // 2 , 0 ),
98
+ GROUP .append (Rect (0 , 0 , DISPLAY .width , 12 , fill = 0xFFFFFF ))
99
+ GROUP .append (label .Label (terminalio .FONT , text = '' , color = 0x000000 ,
100
+ anchored_position = (DISPLAY .width // 2 , - 2 ),
123
101
anchor_point = (0.5 , 0.0 ), max_glyphs = 30 ))
124
102
DISPLAY .show (GROUP )
125
103
@@ -129,12 +107,14 @@ def code(name):
129
107
board .KEY11 , board .KEY12 , board .ENCODER_SWITCH ):
130
108
KEYS .append (Key (pin ))
131
109
110
+ # Load all the macro key setups from .py files in MACRO_FOLDER
132
111
APPS = []
133
112
FILES = os .listdir (MACRO_FOLDER )
134
113
FILES .sort ()
135
114
for FILENAME in FILES :
136
- if FILENAME .endswith ('.json' ):
137
- APPS .append (App (FILENAME ))
115
+ if FILENAME .endswith ('.py' ):
116
+ module = __import__ (MACRO_FOLDER + '/' + FILENAME [:- 3 ])
117
+ APPS .append (App (module .app ))
138
118
139
119
if not APPS :
140
120
print ('No valid macro files found' )
@@ -158,28 +138,24 @@ def code(name):
158
138
for KEY_INDEX , KEY in enumerate (KEYS [0 : len (APPS [APP_INDEX ].macros )]):
159
139
action = KEY .debounce ()
160
140
if action is not None :
161
- keys = APPS [APP_INDEX ].macros [KEY_INDEX ]. sequence
141
+ sequence = APPS [APP_INDEX ].macros [KEY_INDEX ][ 2 ]
162
142
if action is False : # Macro key pressed
163
- PIXELS [KEY_INDEX ] = 0xFFFFFF
164
- PIXELS .show ()
165
- if APPS [APP_INDEX ].macros [KEY_INDEX ].in_order :
166
- for x in APPS [APP_INDEX ].macros [KEY_INDEX ].sequence :
167
- if x .startswith ('+' ): # Press and hold key
168
- KEYBOARD .press (code (x [1 :]))
169
- elif x .startswith ('-' ): # Release key
170
- KEYBOARD .release (code (x [1 :]))
171
- else : # Press and release key
172
- KEYBOARD .press (code (x ))
173
- KEYBOARD .release (code (x ))
174
- else : # Send press events now, release later
175
- for x in APPS [APP_INDEX ].macros [KEY_INDEX ].sequence :
176
- KEYBOARD .press (code (x ))
177
- elif action is True : # Macro key released
178
- # Release all keys in reverse order
179
- for x in reversed (APPS [APP_INDEX ].macros [KEY_INDEX ].sequence ):
180
- if x .startswith ('+' ) or x .startswith ('-' ):
181
- KEYBOARD .release (code (x [1 :]))
143
+ if KEY_INDEX < 12 :
144
+ PIXELS [KEY_INDEX ] = 0xFFFFFF
145
+ PIXELS .show ()
146
+ for item in sequence :
147
+ if isinstance (item , int ):
148
+ if item >= 0 :
149
+ KEYBOARD .press (item )
150
+ else :
151
+ KEYBOARD .release (item )
182
152
else :
183
- KEYBOARD .release (code (x ))
184
- PIXELS [KEY_INDEX ] = APPS [APP_INDEX ].macros [KEY_INDEX ].color
185
- PIXELS .show ()
153
+ LAYOUT .write (item )
154
+ elif action is True : # Macro key released
155
+ # Release any still-pressed modifier keys
156
+ for item in sequence :
157
+ if isinstance (item , int ) and item >= 0 :
158
+ KEYBOARD .release (item )
159
+ if KEY_INDEX < 12 :
160
+ PIXELS [KEY_INDEX ] = APPS [APP_INDEX ].macros [KEY_INDEX ][0 ]
161
+ PIXELS .show ()
0 commit comments