|
| 1 | +import time |
| 2 | +import board |
| 3 | +import digitalio |
| 4 | +import rotaryio |
| 5 | +import neopixel |
| 6 | +import json |
| 7 | +import os |
| 8 | + |
| 9 | +import displayio |
| 10 | +import terminalio |
| 11 | +from adafruit_display_text import label |
| 12 | + |
| 13 | +import usb_hid |
| 14 | +from adafruit_hid.keyboard import Keyboard |
| 15 | +from adafruit_hid.keycode import Keycode |
| 16 | + |
| 17 | +#from adafruit_hid.mouse import Mouse |
| 18 | +#from adafruit_hid.consumer_control import ConsumerControl |
| 19 | +#from adafruit_hid.consumer_control_code import ConsumerControlCode |
| 20 | + |
| 21 | +MACRO_FOLDER = '/' |
| 22 | + |
| 23 | +DISPLAY = board.DISPLAY |
| 24 | +ENCODER = rotaryio.IncrementalEncoder(board.ENCODER_B, board.ENCODER_A) |
| 25 | +PIXELS = neopixel.NeoPixel(board.NEOPIXEL, 12, auto_write=False) |
| 26 | +KEYBOARD = Keyboard(usb_hid.devices) |
| 27 | + |
| 28 | +group = displayio.Group(max_size=10) |
| 29 | +text1 = "0123\n4567\n89AB\nCDEF\n1234\n5678\n9AB" |
| 30 | +text_area = label.Label(terminalio.FONT, text=text1, color=0xFFFFFF, x=8, y=8) |
| 31 | +group.append(text_area) |
| 32 | + |
| 33 | +DISPLAY.show(group) |
| 34 | + |
| 35 | +class key: |
| 36 | + DEBOUNCE_TIME = 1 / 50 |
| 37 | + |
| 38 | + def __init__(self, keyname): |
| 39 | + self.io = digitalio.DigitalInOut(keyname) |
| 40 | + self.io.direction = digitalio.Direction.INPUT |
| 41 | + self.io.pull = digitalio.Pull.UP |
| 42 | + self.last_value = self.io.value # Initial state |
| 43 | + self.last_time = time.monotonic() |
| 44 | + |
| 45 | + def debounce(self): |
| 46 | + value = self.io.value |
| 47 | + if value != self.last_value: |
| 48 | + now = time.monotonic() |
| 49 | + elapsed = now - self.last_time |
| 50 | + if elapsed >= self.DEBOUNCE_TIME: |
| 51 | + self.last_value = value |
| 52 | + self.last_time = now |
| 53 | + return value |
| 54 | + return None |
| 55 | + |
| 56 | +KEYS = [] |
| 57 | +for keyname in (board.KEY1, board.KEY2, board.KEY3, board.KEY4, board.KEY5, |
| 58 | + board.KEY6, board.KEY7, board.KEY8, board.KEY9, board.KEY10, |
| 59 | + board.KEY11, board.KEY12, board.ENCODER_SWITCH): |
| 60 | + KEYS.append(key(keyname)) |
| 61 | + |
| 62 | + |
| 63 | +class macro: |
| 64 | + def __init__(self, desc, color, sequence): |
| 65 | + self.desc = desc |
| 66 | + self.color = color |
| 67 | + self.sequence = sequence |
| 68 | + self.in_order = False |
| 69 | + for key in sequence: |
| 70 | + if key.startswith('-'): |
| 71 | + self.in_order = True |
| 72 | + break |
| 73 | + |
| 74 | +class app: |
| 75 | + def __init__(self, filename): |
| 76 | + with open(filename) as jsonfile: |
| 77 | + json_data = json.load(jsonfile) |
| 78 | + self.name = json_data['name'] |
| 79 | + default_color = json_data['color'] if 'color' in json_data else None |
| 80 | + self.macros = [] |
| 81 | + for mac in json_data['macros']: |
| 82 | + self.macros.append(macro( |
| 83 | + mac['desc'] if 'desc' in mac else None, |
| 84 | + mac['color'] if 'color' in mac else default_color, |
| 85 | + mac['sequence'] if 'sequence' in mac else None)) |
| 86 | + |
| 87 | + def activate(self): |
| 88 | + # Config screen, button colors, key sequences here |
| 89 | + pass |
| 90 | + |
| 91 | + |
| 92 | +APPS = [] |
| 93 | +files = os.listdir(MACRO_FOLDER) |
| 94 | +files.sort() |
| 95 | +for filename in files: |
| 96 | + if filename.endswith('.json'): |
| 97 | + APPS.append(app(filename)) |
| 98 | + |
| 99 | +if not len(APPS): |
| 100 | + print('No valid macro files found') |
| 101 | + while True: |
| 102 | + pass |
| 103 | + |
| 104 | +APP_INDEX = 0 |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | +FOO = ((Keycode.A, Keycode.ONE, Keycode.X), Keycode.B, Keycode.C) |
| 109 | + |
| 110 | + |
| 111 | +last_position = None |
| 112 | +while True: |
| 113 | + position = ENCODER.position |
| 114 | + if position != last_position: |
| 115 | + PIXELS.fill(0) |
| 116 | + PIXELS[position % len(APPS)] = 0xFFFFFF |
| 117 | + PIXELS.show() |
| 118 | + print(position) |
| 119 | + last_position = position |
| 120 | + for i, key in enumerate(KEYS): |
| 121 | + action = key.debounce() |
| 122 | + if action is not None: |
| 123 | + print(i, len(APPS[APP_INDEX].macros)) |
| 124 | + |
| 125 | + if i >= len(APPS[APP_INDEX].macros): |
| 126 | + continue # Ignore if key # exceeds macro list length |
| 127 | + |
| 128 | + keys = APPS[APP_INDEX].macros[i].sequence |
| 129 | + if action is False: # Key pressed |
| 130 | + print('Press', i) |
| 131 | + if APPS[APP_INDEX].macros[i].in_order: |
| 132 | + for x in APPS[APP_INDEX].macros[i].sequence: |
| 133 | + if x.startswith('-'): |
| 134 | + KEYBOARD.release(eval('Keycode.' + x[1:])) |
| 135 | + else: |
| 136 | + KEYBOARD.press(eval('Keycode.' + x)) |
| 137 | + else: |
| 138 | + for x in APPS[APP_INDEX].macros[i].sequence: |
| 139 | + KEYBOARD.press(eval('Keycode.' + x)) |
| 140 | + elif action is True: # Key released |
| 141 | + print('Release', i) |
| 142 | + for x in reversed(APPS[APP_INDEX].macros[i].sequence): |
| 143 | + if not x.startswith('-'): |
| 144 | + KEYBOARD.release(eval('Keycode.' + x)) |
| 145 | + |
| 146 | + |
| 147 | +META = ('LEFT_CONTROL', 'CONTROL', 'LEFT_SHIFT', 'SHIFT', 'LEFT_ALT', 'ALT', |
| 148 | + 'OPTION', 'LEFT_GUI', 'GUI', 'WINDOWS', 'COMMAND', 'RIGHT_CONTROL', |
| 149 | + 'RIGHT_SHIFT', 'RIGHT_ALT', 'RIGHT_GUI', 'modifier_bit') |
| 150 | + |
| 151 | +#>>> print(dir(board)) |
| 152 | +#['__class__', 'BUTTON', 'DISPLAY', 'ENCODER_A', 'ENCODER_B', 'ENCODER_SWITCH', 'I2C', 'KEY1', 'KEY10', 'KEY11', 'KEY12', 'KEY2', 'KEY3', 'KEY4', 'KEY5', 'KEY6', 'KEY7', 'KEY8', 'KEY9', 'LED', 'MISO', 'MOSI', 'NEOPIXEL', 'OLED_CS', 'OLED_DC', 'OLED_RESET', 'ROTA', 'ROTB', 'SCK', 'SCL', 'SDA', 'SPEAKER', 'SPEAKER_SHUTDOWN', 'SPI'] |
| 153 | + |
| 154 | +#>>> print(dir(Keycode)) |
| 155 | +#['__class__', '__module__', '__name__', '__qualname__', '__bases__', '__dict__', 'C', 'M', 'A', 'B', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE', 'ZERO', 'ENTER', 'RETURN', 'ESCAPE', 'BACKSPACE', 'TAB', 'SPACEBAR', 'SPACE', 'MINUS', 'EQUALS', 'LEFT_BRACKET', 'RIGHT_BRACKET', 'BACKSLASH', 'POUND', 'SEMICOLON', 'QUOTE', 'GRAVE_ACCENT', 'COMMA', 'PERIOD', 'FORWARD_SLASH', 'CAPS_LOCK', 'F1', 'F2', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12', 'PRINT_SCREEN', 'SCROLL_LOCK', 'PAUSE', 'INSERT', 'HOME', 'PAGE_UP', 'DELETE', 'END', 'PAGE_DOWN', 'RIGHT_ARROW', 'LEFT_ARROW', 'DOWN_ARROW', 'UP_ARROW', 'KEYPAD_NUMLOCK', 'KEYPAD_FORWARD_SLASH', 'KEYPAD_ASTERISK', 'KEYPAD_MINUS', 'KEYPAD_PLUS', 'KEYPAD_ENTER', 'KEYPAD_ONE', 'KEYPAD_TWO', 'KEYPAD_THREE', 'KEYPAD_FOUR', 'KEYPAD_FIVE', 'KEYPAD_SIX', 'KEYPAD_SEVEN', 'KEYPAD_EIGHT', 'KEYPAD_NINE', 'KEYPAD_ZERO', 'KEYPAD_PERIOD', 'KEYPAD_BACKSLASH', 'APPLICATION', 'POWER', 'KEYPAD_EQUALS', 'F13', 'F14', 'F15', 'F16', 'F17', 'F18', 'F19', 'LEFT_CONTROL', 'CONTROL', 'LEFT_SHIFT', 'SHIFT', 'LEFT_ALT', 'ALT', 'OPTION', 'LEFT_GUI', 'GUI', 'WINDOWS', 'COMMAND', 'RIGHT_CONTROL', 'RIGHT_SHIFT', 'RIGHT_ALT', 'RIGHT_GUI', 'modifier_bit'] |
| 156 | + |
| 157 | +#>>> print(eval('Keycode.' + 'COMMAND')) |
| 158 | + |
0 commit comments