|
| 1 | +# SPDX-FileCopyrightText: 2024 Liz Clark for Adafruit Industries |
| 2 | +# |
| 3 | +# SPDX-License-Identifier: MIT |
| 4 | + |
| 5 | +import board |
| 6 | +import keypad |
| 7 | +import rotaryio |
| 8 | +import neopixel |
| 9 | +import usb_hid |
| 10 | +from adafruit_hid.keyboard import Keyboard |
| 11 | +from adafruit_hid.keycode import Keycode |
| 12 | + |
| 13 | +# neopixel colors |
| 14 | +RED = (255, 0, 0) |
| 15 | +ORANGE = (255, 127, 0) |
| 16 | +YELLOW = (255, 255, 0) |
| 17 | +GREEN = (0, 255, 0) |
| 18 | +AQUA = (0, 255, 255) |
| 19 | +BLUE = (0, 0, 255) |
| 20 | +PURPLE = (127, 0, 255) |
| 21 | +PINK = (255, 0, 255) |
| 22 | +OFF = (0, 0, 0) |
| 23 | +# axis states selected with keys 9-11 |
| 24 | +axis_states = [0, "x", "y", "z"] |
| 25 | +state = axis_states[0] |
| 26 | +# keymap for key matrix |
| 27 | +keymap = { |
| 28 | + (0): (axis_states[0], [Keycode.HOME], RED), # HOME X/Y |
| 29 | + (1): (axis_states[0], [Keycode.END], ORANGE), # HOME Z |
| 30 | + (2): (axis_states[0], (Keycode.HOME, Keycode.END), YELLOW), # HOME ALL |
| 31 | + |
| 32 | + (3): (axis_states[0], (Keycode.SHIFT, Keycode.A), GREEN), # SHORTCUT A |
| 33 | + (4): (axis_states[0], (Keycode.SHIFT, Keycode.B), AQUA), # SHORTCUT B |
| 34 | + (5): (axis_states[0], (Keycode.SHIFT, Keycode.C), BLUE), # SHORTCUT C |
| 35 | + |
| 36 | + (6): (axis_states[0], [Keycode.TWO], AQUA), # SET STEPS 1MM |
| 37 | + (7): (axis_states[0], [Keycode.THREE], PURPLE), # SET STEPS 10MM |
| 38 | + (8): (axis_states[0], [Keycode.FOUR], PINK), # SET STEPS 100MM |
| 39 | + |
| 40 | + (9): (axis_states[1], None, RED), # SET X-AXIS STATE |
| 41 | + (10): (axis_states[2], None, GREEN), # SET Y-AXIS STATE |
| 42 | + (11): (axis_states[3], None, BLUE), # SET Z-AXIS STATE |
| 43 | +} |
| 44 | +# keymap for encoder based on state; pos = [0], neg = [1] |
| 45 | +encoder_map = { |
| 46 | + ("x"): ([Keycode.RIGHT_ARROW], [Keycode.LEFT_ARROW]), |
| 47 | + ("y"): ([Keycode.UP_ARROW], [Keycode.DOWN_ARROW]), |
| 48 | + ("z"): ([Keycode.W], [Keycode.S]), |
| 49 | +} |
| 50 | +# make a keyboard |
| 51 | +kbd = Keyboard(usb_hid.devices) |
| 52 | +# key matrix |
| 53 | +COLUMNS = 3 |
| 54 | +ROWS = 4 |
| 55 | +keys = keypad.KeyMatrix( |
| 56 | + row_pins=(board.D12, board.D11, board.D10, board.D9), |
| 57 | + column_pins=(board.A0, board.A1, board.A2), |
| 58 | + columns_to_anodes=False, |
| 59 | +) |
| 60 | +# neopixels and key num to pixel function |
| 61 | +pixels = neopixel.NeoPixel(board.D5, 12, brightness=0.3) |
| 62 | +def key_to_pixel_map(key_number): |
| 63 | + row = key_number // COLUMNS |
| 64 | + column = key_number % COLUMNS |
| 65 | + if row % 2 == 1: |
| 66 | + column = COLUMNS - column - 1 |
| 67 | + return row * COLUMNS + column |
| 68 | +pixels.fill(OFF) # Begin with pixels off. |
| 69 | + |
| 70 | +# make an encoder |
| 71 | +encoder = rotaryio.IncrementalEncoder(board.A3, board.A4) |
| 72 | +last_position = 0 |
| 73 | + |
| 74 | +while True: |
| 75 | + # poll for key event |
| 76 | + key_event = keys.events.get() |
| 77 | + # get position of encoder |
| 78 | + position = encoder.position |
| 79 | + # if position changes.. |
| 80 | + if position != last_position: |
| 81 | + # ..and it increases.. |
| 82 | + if position > last_position: |
| 83 | + # ..and state is x: |
| 84 | + if state is axis_states[1]: |
| 85 | + kbd.press(*encoder_map[state][0]) |
| 86 | + # ..and state is y: |
| 87 | + if state is axis_states[2]: |
| 88 | + kbd.press(*encoder_map[state][0]) |
| 89 | + # ..and state is z: |
| 90 | + if state is axis_states[3]: |
| 91 | + kbd.press(*encoder_map[state][0]) |
| 92 | + # ..and it decreases.. |
| 93 | + if position < last_position: |
| 94 | + # ..and state is x: |
| 95 | + if state is axis_states[1]: |
| 96 | + kbd.press(*encoder_map[state][1]) |
| 97 | + # ..and state is y: |
| 98 | + if state is axis_states[2]: |
| 99 | + kbd.press(*encoder_map[state][1]) |
| 100 | + # ..and state is z: |
| 101 | + if state is axis_states[3]: |
| 102 | + kbd.press(*encoder_map[state][1]) |
| 103 | + # print(position) |
| 104 | + # release all keys |
| 105 | + kbd.release_all() |
| 106 | + # update last_position |
| 107 | + last_position = position |
| 108 | + # if a key event.. |
| 109 | + if key_event: |
| 110 | + # print(key_event) |
| 111 | + # ..and it's pressed.. |
| 112 | + if key_event.pressed: |
| 113 | + # ..and it's keys 0-8, send key presses from keymap: |
| 114 | + if keymap[key_event.key_number][0] is axis_states[0]: |
| 115 | + state = axis_states[0] |
| 116 | + kbd.press(*keymap[key_event.key_number][1]) |
| 117 | + # ..and it's key 9, set state to x |
| 118 | + if keymap[key_event.key_number][0] is axis_states[1]: |
| 119 | + state = axis_states[1] |
| 120 | + pixels[key_to_pixel_map(10)] = OFF |
| 121 | + pixels[key_to_pixel_map(11)] = OFF |
| 122 | + # ..and it's key 10, set state to y |
| 123 | + if keymap[key_event.key_number][0] is axis_states[2]: |
| 124 | + state = axis_states[2] |
| 125 | + pixels[key_to_pixel_map(9)] = OFF |
| 126 | + pixels[key_to_pixel_map(11)] = OFF |
| 127 | + # ..and it's key 11, set state to z |
| 128 | + if keymap[key_event.key_number][0] is axis_states[3]: |
| 129 | + state = axis_states[3] |
| 130 | + pixels[key_to_pixel_map(9)] = OFF |
| 131 | + pixels[key_to_pixel_map(10)] = OFF |
| 132 | + # turn on neopixel for key with color from keymap |
| 133 | + pixels[key_to_pixel_map(key_event.key_number)] = keymap[key_event.key_number][2] |
| 134 | + # ..and it's released.. |
| 135 | + if key_event.released: |
| 136 | + # if it's key 0-8, release the key press and turn off neopixel |
| 137 | + if keymap[key_event.key_number][0] is axis_states[0]: |
| 138 | + kbd.release(*keymap[key_event.key_number][1]) |
| 139 | + pixels.fill(OFF) |
0 commit comments