11import time
2- import keyfactory
32from adafruit_macropad import MacroPad
43from app import App
5- from display import Display
6- from pixels import Pixels
7- from sleep import Sleep
4+ from keys import Keys
5+ from screen import ScreenListener
6+ from pixels import PixelListener
7+ from hid import InputDeviceListener
8+ from commands import Sleep
9+
10+ ## DEPRECATED
11+ # Ensure backwards compatibility for the 2.x series
12+ # So we don't have to change import statements in old macros
13+ import sys
14+ import commands
15+ sys .modules ['keyboard' ] = commands
16+ sys .modules ['mouse' ] = commands
17+ sys .modules ['pause' ] = commands
18+ sys .modules ['sleep' ] = commands
19+ sys .modules ['midi' ] = commands
20+ sys .modules ['consumer' ] = commands
821
9- KEY_LAUNCH = - 1
10- KEY_ENC_BUTTON = 12
11- KEY_ENC_LEFT = 13
12- KEY_ENC_RIGHT = 14
13- MAX_KEYS = 14
14- MAX_LEDS = 12
1522MACRO_FOLDER = '/macros'
1623
24+ # Core objects
1725macropad = MacroPad ()
18- last_position = macropad .encoder
26+ screen = ScreenListener (macropad )
27+ pixels = PixelListener (macropad )
28+ hid = InputDeviceListener (macropad )
29+
30+ # State variables
1931last_time_seconds = time .monotonic ()
32+ last_position = macropad .encoder
2033sleep_remaining = None
34+ keys = None
2135macro_changed = False
2236app_index = 0
23- app_current = None
24-
25- # The application state that is shared with the key events
26- state = {
27- "macropad" : macropad ,
28- "screen" : Display (macropad ),
29- "pixels" : Pixels (macropad ),
30- "sleeping" : False ,
31- }
3237
3338# Fractions of a second that have elapsed since this method's last run
3439def elapsed_seconds ():
@@ -40,116 +45,69 @@ def elapsed_seconds():
4045
4146# Set the macro page (app) at the given index
4247def set_app (index ):
43- global app_current , app_index , sleep_remaining
48+ global app_index , keys , screen , sleep_remaining
4449 app_index = index
45- app_current = apps [app_index ]
46- sleep_remaining = app_current .timeout
47- state ["macropad" ].keyboard .release_all ()
48- state ["screen" ].setApp (app_current )
49- state ["pixels" ].setApp (app_current )
5050
51- # Get the macro sequence to execute for a given key
52- def get_sequence (key ):
53- global app_current
54- if key == KEY_LAUNCH :
55- return app_current .launch [2 ] if app_current .launch else None
56- try : # No such sequence for this key
57- return app_current .macros [key ][2 ] if key <= MAX_KEYS else []
58- except (IndexError ) as err :
59- print ("Couldn't find sequence for key number " , key )
60- return None
51+ sleep_remaining = apps [app_index ].timeout
52+ screen .setTitle (apps [app_index ].name )
53+ macropad .keyboard .release_all ()
54+
55+ keys = Keys (apps [app_index ])
56+ keys .addListener (hid )
57+ keys .addListener (screen )
58+ keys .addListener (pixels )
6159
6260# Load available macros
63- state [ " screen" ] .initialize ()
61+ screen .initialize ()
6462apps = App .load_all (MACRO_FOLDER )
6563if not apps :
66- state [ " screen" ]. setTitle ('NO MACRO FILES FOUND' )
64+ screen . setError ('NO MACRO FILES FOUND' )
6765 while True :
68- pass
66+ time .sleep (60.0 )
67+ set_app (app_index )
6968
7069try : # Test the USB HID connection
71- state [ " macropad" ] .keyboard .release_all ()
70+ macropad .keyboard .release_all ()
7271except OSError as err :
7372 print (err )
74- state [ " screen" ]. setTitle ('NO USB CONNECTION' )
73+ screen . setError ('NO USB CONNECTION' )
7574 while True :
76- pass
75+ time . sleep ( 60.0 )
7776
7877# Prep before the run loop
79- set_app (0 )
8078
81- while True : # Event loop
82- state ["macropad" ].encoder_switch_debounced .update ()
83- position = state ["macropad" ].encoder
84- pressed = False
85- rotated = False
8679
87- # Do we need to press the "sleep" button?
80+ while True : # Input event loop
81+ macropad .encoder_switch_debounced .update ()
8882 sleep_remaining -= elapsed_seconds ()
89- if not state ["sleeping" ] and sleep_remaining <= 0 :
90- Sleep ().press (state )
91- continue
92-
93- if position != last_position : # Did we rotate the encoder?
94- key_number = KEY_ENC_LEFT if position < last_position else KEY_ENC_RIGHT
95- last_position = position
96- rotated = True
97-
98- # Do we need to change macro pages?
99- if rotated and state ["macropad" ].encoder_switch :
100- macro_changed = True
101- app_next = app_index - 1 if key_number is KEY_ENC_LEFT else app_index + 1
102- set_app (app_next % len (apps ))
103- continue # Changing macros, not a keypress event
104- # We are now switching to a new macro page
105- elif macro_changed and state ["macropad" ].encoder_switch_debounced .released :
106- macro_changed = False
107- key_number = KEY_LAUNCH
108- rotated = True
109- # We only clicked the encoder button (not switching to a new page)
110- elif state ["macropad" ].encoder_switch_debounced .released :
111- key_number = KEY_ENC_BUTTON
112- pressed = state ["macropad" ].encoder_switch_debounced .released
113- else : # Was there a keypress event on the keypad?
114- event = state ["macropad" ].keys .events .get ()
115- if not event or event .key_number >= len (app_current .macros ):
116- if state ["sleeping" ]: time .sleep (1.0 ) # Low power mode
117- continue # No key events, or no corresponding macro, resume loop
118- key_number = event .key_number
119- pressed = event .pressed
120-
121- # Wake up if there is a key event while sleeping
122- sleep_remaining = app_current .timeout
123- if state ["sleeping" ] and (pressed or rotated ):
124- Sleep ().press (state )
125- continue
126-
127- sequence = get_sequence (key_number )
128- if sequence and (rotated or pressed ): # Key Down Event
129- if not state ["sleeping" ] and (0 <= key_number < MAX_LEDS ):
130- state ["pixels" ].highlight (key_number , 0xFFFFFF )
131- state ["screen" ].highlight (key_number )
132-
133- if type (sequence ) is list :
134- for item in sequence :
135- if type (item ) is list : # We have a macro to execute
136- for subitem in item : # Press the key combination
137- keyfactory .get (subitem ).press (state )
138- for subitem in item : # Immediately release the key combo
139- keyfactory .get (subitem ).release (state )
140- else : # We have a key combination to press
141- keyfactory .get (item ).press (state )
142- else : # We just have a single command to execute
143- keyfactory .get (sequence ).press (state )
144-
145- if sequence and (rotated or not pressed ): # Key Up Event
146- if type (sequence ) is list :
147- for item in sequence :
148- if type (item ) is not list : # Release any still-pressed key combinations
149- keyfactory .get (item ).release (state )
150- # Macro key cobinations should already have been released
151- else : # Release any still-pressed single commands
152- keyfactory .get (sequence ).release (state )
153- if not state ["sleeping" ] and (0 <= key_number < MAX_LEDS ): # No pixel for encoder button
154- state ["pixels" ].reset (key_number )
155- state ["screen" ].reset (key_number )
83+ event = macropad .keys .events .get ()
84+
85+ if event or last_position != macropad .encoder or macropad .encoder_switch_debounced .released :
86+ keys .release (Keys .KEY_SLEEP ) # Don't go to sleep!
87+ sleep_remaining = apps [app_index ].timeout
88+ if sleep_remaining <= 0 : # Go to sleep and slow down
89+ keys .press (Keys .KEY_SLEEP )
90+ time .sleep (1.0 )
91+ elif event and event .pressed : # Key was pressed
92+ keys .press (event .key_number )
93+ elif event and event .released : # Key was released
94+ keys .release (event .key_number )
95+ elif macropad .encoder_switch and macropad .encoder < last_position :
96+ last_position = macropad .encoder # Push down and turn (left)
97+ set_app ((app_index - 1 ) % len (apps ))
98+ macro_changed = True
99+ elif macropad .encoder_switch and macropad .encoder > last_position :
100+ last_position = macropad .encoder # Push down and turn (right)
101+ set_app ((app_index + 1 ) % len (apps ))
102+ macro_changed = True
103+ elif macropad .encoder < last_position : # Rotary counter-clockwise
104+ last_position = macropad .encoder
105+ keys .press (Keys .KEY_ENC_LEFT )
106+ keys .release (Keys .KEY_ENC_LEFT )
107+ elif macropad .encoder > last_position : # Rotary clockwise
108+ last_position = macropad .encoder
109+ keys .press (Keys .KEY_ENC_RIGHT )
110+ keys .release (Keys .KEY_ENC_RIGHT )
111+ elif macropad .encoder_switch_debounced .released :
112+ if macro_changed : macro_changed = False # Land on the selected macro page
113+ else : keys .press (Keys .KEY_ENC_BUTTON ) # Encoder button "pressed"
0 commit comments