88
99# pylint: disable=import-error, unused-import, too-few-public-methods, eval-used
1010
11- import json
1211import os
1312import time
1413import board
1817import rotaryio
1918import terminalio
2019import usb_hid
20+ from adafruit_display_shapes .rect import Rect
2121from adafruit_display_text import label
2222from adafruit_hid .keyboard import Keyboard
2323from adafruit_hid .keycode import Keycode
24+ from adafruit_hid .keyboard_layout_us import KeyboardLayoutUS
2425
2526
2627# CONFIGURABLES ------------------------
@@ -55,71 +56,48 @@ def debounce(self):
5556 return value
5657 return None
5758
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-
7159class App :
7260 """ Class representing a host-side application, for which we have a set
7361 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' ]
8565
8666 def switch (self ):
8767 """ Activate application settings; update OLED labels and LED
8868 colors. """
89- GROUP [12 ].text = self .name # Application name
69+ GROUP [13 ].text = self .name # Application name
9070 for i in range (12 ):
9171 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 ]
9474 else : # Key not in use, no label or LED
9575 PIXELS [i ] = 0
9676 GROUP [i ].text = ''
9777 PIXELS .show ()
9878
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-
10479
10580# INITIALIZATION -----------------------
10681
10782DISPLAY = board .DISPLAY
10883ENCODER = rotaryio .IncrementalEncoder (board .ENCODER_B , board .ENCODER_A )
10984PIXELS = neopixel .NeoPixel (board .NEOPIXEL , 12 , auto_write = False )
11085KEYBOARD = Keyboard (usb_hid .devices )
86+ LAYOUT = KeyboardLayoutUS (KEYBOARD )
87+
11188
112- GROUP = displayio .Group (max_size = 13 )
89+ GROUP = displayio .Group (max_size = 14 )
11390for KEY_INDEX in range (12 ):
11491 x = KEY_INDEX % 3
11592 y = KEY_INDEX // 3
11693 GROUP .append (label .Label (terminalio .FONT , text = '' , color = 0xFFFFFF ,
11794 anchored_position = ((DISPLAY .width - 1 ) * x / 2 ,
11895 DISPLAY .height - 1 -
119- (3 - y ) * 11 ),
96+ (3 - y ) * 12 ),
12097 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 ),
123101 anchor_point = (0.5 , 0.0 ), max_glyphs = 30 ))
124102DISPLAY .show (GROUP )
125103
@@ -129,12 +107,14 @@ def code(name):
129107 board .KEY11 , board .KEY12 , board .ENCODER_SWITCH ):
130108 KEYS .append (Key (pin ))
131109
110+ # Load all the macro key setups from .py files in MACRO_FOLDER
132111APPS = []
133112FILES = os .listdir (MACRO_FOLDER )
134113FILES .sort ()
135114for 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 ))
138118
139119if not APPS :
140120 print ('No valid macro files found' )
@@ -158,28 +138,24 @@ def code(name):
158138 for KEY_INDEX , KEY in enumerate (KEYS [0 : len (APPS [APP_INDEX ].macros )]):
159139 action = KEY .debounce ()
160140 if action is not None :
161- keys = APPS [APP_INDEX ].macros [KEY_INDEX ]. sequence
141+ sequence = APPS [APP_INDEX ].macros [KEY_INDEX ][ 2 ]
162142 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 )
182152 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