summaryrefslogtreecommitdiff
path: root/src/code.py
diff options
context:
space:
mode:
authorSébastien Dailly <sebastien@dailly.me>2023-05-22 08:40:47 +0200
committerSébastien Dailly <sebastien@dailly.me>2023-05-22 08:40:47 +0200
commit597b007333d8ec0d9cfd29e6941fcbe57379108a (patch)
tree0cf87e1ac487e7deb91acf7f2bec70bd4dd06703 /src/code.py
Initial commit
Diffstat (limited to 'src/code.py')
-rw-r--r--src/code.py158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/code.py b/src/code.py
new file mode 100644
index 0000000..813574a
--- /dev/null
+++ b/src/code.py
@@ -0,0 +1,158 @@
+# SPDX-FileCopyrightText: 2021 Phillip Burgess for Adafruit Industries
+#
+# SPDX-License-Identifier: MIT
+
+"""
+A macro/hotkey program for Adafruit MACROPAD. Macro setups are stored in the
+/macros folder (configurable below), load up just the ones you're likely to
+use. Plug into computer's USB port, use dial to select an application macro
+set, press MACROPAD keys to send key sequences and other USB protocols.
+"""
+
+# pylint: disable=import-error, unused-import, too-few-public-methods
+
+import os
+import time
+import displayio
+import terminalio
+
+import usb_cdc
+import json
+
+#from adafruit_display_shapes.rect import Rect
+#from adafruit_display_text import label
+from adafruit_macropad import MacroPad
+
+from supervisor import runtime
+
+from actions import Action
+import skeleton
+import menu
+
+# CONFIGURABLES ------------------------
+
+MACRO_FOLDER = '/macros'
+
+
+# INITIALIZATION -----------------------
+
+# Do not reload the application when the files are changed
+runtime.autoreload = False
+
+macropad = MacroPad()
+macropad.display.auto_refresh = False
+macropad.pixels.auto_write = False
+
+Action().set_macropad(macropad)
+
+# Load all the macro key setups from .py files in MACRO_FOLDER
+apps = []
+files = os.listdir(MACRO_FOLDER)
+files.sort()
+for filename in files:
+ if filename.startswith('._'):
+ continue
+ if filename.endswith('.py'):
+ module_name = filename[:-3]
+ elif filename.endswith('.mpy'):
+ module_name = filename[:-4]
+ else:
+ continue
+
+ try:
+ module = __import__(MACRO_FOLDER + '/' + module_name)
+ apps.append(module.configuration)
+ except (SyntaxError, ImportError, AttributeError, KeyError, NameError,
+ IndexError, TypeError) as err:
+ print("ERROR in", filename)
+ import traceback
+ traceback.print_exception(err, err, err.__traceback__)
+
+if not apps:
+ group[13].text = 'NO MACRO FILES FOUND'
+ macropad.display.refresh()
+ while True:
+ pass
+
+app_index = 0
+
+def run_application(app):
+ # Read encoder position. If it's changed, declare it as a button.
+ position = app.macropad.encoder
+ if position > app.position:
+ app.position = position
+ key_number = 12
+ pressed = True
+ elif position < app.position:
+ app.position = position
+ key_number = 13
+ pressed = True
+ else:
+ event = app.macropad.keys.events.get()
+ if not event:
+ app.tick()
+ return # No key events
+ key_number = event.key_number
+ pressed = event.pressed
+
+ return app.execute_action(key_number, pressed or False)
+
+def switch_layout(configuration):
+ global app
+ app = skeleton.Handler(macropad, configuration)
+ app.start()
+
+
+def search_and_switch(layout):
+ found_application = False
+ for local_app in apps:
+ if local_app.title == layout and app is not local_app:
+ found_application = True
+ switch_layout(local_app)
+ break
+
+def send_layout(_any):
+ if usb_cdc.data.connected:
+ usb_cdc.data.write(bytes("%s\n" % app.name, "utf-8"))
+
+actions = {
+ "layout" : search_and_switch,
+ "get_layout" : send_layout,
+ }
+
+switch_layout(apps[app_index])
+
+# MAIN LOOP ----------------------------
+
+while True:
+
+ # First read from the serial
+ # If we have an application name from the command line, switch to this app.
+ if usb_cdc.data.connected and usb_cdc.data.in_waiting != 0:
+ line = usb_cdc.data.read(usb_cdc.data.in_waiting).strip()
+ commands = json.loads(line)
+ for command in commands:
+ for key, value in command.items():
+ actions[key](value)
+ continue
+
+ # Handle encoder button. If state has changed, and if there's a
+ # corresponding macro, set up variables to act on this just like
+ # the keypad keys, as if it were a 13th key/macro.
+ app.macropad.encoder_switch_debounced.update()
+ encoder_switch = app.macropad.encoder_switch_debounced.pressed
+ # On the encoder button, switch to the next mode
+ if encoder_switch:
+
+ config = menu.build_application(apps)
+ menu_app = skeleton.Handler(macropad, config)
+ menu_app.start()
+ while True:
+ configuration = run_application(menu_app)
+ if configuration is None: continue
+ switch_layout(configuration)
+ break
+ send_layout(None)
+
+ run_application(app)
+ continue