code.py
  1  # SPDX-FileCopyrightText: 2020 John Park for Adafruit Industries
  2  #
  3  # SPDX-License-Identifier: MIT
  4  
  5  # ItsyBitsy Keypad
  6  # Uses ItsyBitsy M4/M0 plus Pimoroni Keybow
  7  # To build a customizable USB keypad
  8  
  9  import time
 10  import board
 11  from digitalio import DigitalInOut, Direction, Pull
 12  import usb_hid
 13  from adafruit_hid.keyboard import Keyboard
 14  from adafruit_hid.keycode import Keycode
 15  from adafruit_hid.consumer_control import ConsumerControl
 16  from adafruit_hid.consumer_control_code import ConsumerControlCode
 17  import adafruit_dotstar as dotstar
 18  
 19  dots = dotstar.DotStar(board.SCK, board.MOSI, 12, brightness=0.4)
 20  
 21  RED = 0xFF0000
 22  AMBER = 0xAA9900
 23  BLUE = 0x0066FF
 24  MAGENTA = 0xFF00FF
 25  PURPLE = 0x3B0F85
 26  BLACK = 0x000000
 27  
 28  kbd = Keyboard(usb_hid.devices)
 29  cc = ConsumerControl(usb_hid.devices)
 30  
 31  orientation = 1  # 0 = portrait/vertical, 1 = landscape/horizontal
 32  if orientation == 0:
 33      key_dots = [0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11]
 34      # 0  #4  #8
 35      # 1  #5  #9
 36      # 2  #6  #10
 37      # 3  #7  #11
 38  if orientation == 1:
 39      key_dots = [3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8]
 40      # 3  #2  #1  #0
 41      # 7  #6  #5  #4
 42      # 11 #10 #9  #8
 43  
 44  
 45  def dot_on(dot, color):
 46      dots[dot] = color
 47  
 48  
 49  def dot_off(dot):
 50      dots[dot] = BLACK
 51  
 52  
 53  # Pin definitions
 54  if orientation == 0:  # 0 = portrait/vertical
 55      pins = [
 56          board.D11,
 57          board.D12,
 58          board.D2,
 59          board.D10,
 60          board.D9,
 61          board.D7,
 62          board.A5,
 63          board.A4,
 64          board.A3,
 65          board.A2,
 66          board.A1,
 67          board.A0,
 68      ]
 69  if orientation == 1:  # 1 = landscape/horizontal
 70      pins = [
 71          board.A2,
 72          board.A5,
 73          board.D10,
 74          board.D11,
 75          board.A1,
 76          board.A4,
 77          board.D9,
 78          board.D12,
 79          board.A0,
 80          board.A3,
 81          board.D7,
 82          board.D2,
 83      ]
 84  # the two command types -- MEDIA for ConsumerControlCodes, KEY for Keycodes
 85  # this allows button press to send the correct HID command for the type specified
 86  MEDIA = 1
 87  KEY = 2
 88  keymap = {
 89      (0): (AMBER, MEDIA, ConsumerControlCode.PLAY_PAUSE),
 90      (1): (AMBER, MEDIA, ConsumerControlCode.MUTE),
 91      (2): (AMBER, MEDIA, ConsumerControlCode.VOLUME_DECREMENT),
 92      (3): (AMBER, MEDIA, ConsumerControlCode.VOLUME_INCREMENT),
 93      (4): (BLUE, KEY, (Keycode.GUI, Keycode.C)),
 94      (5): (BLUE, KEY, (Keycode.GUI, Keycode.V)),
 95      (6): (MAGENTA, KEY, [Keycode.UP_ARROW]),
 96      (7): (PURPLE, KEY, [Keycode.BACKSPACE]),
 97      (8): (BLUE, KEY, [Keycode.SPACE]),
 98      (9): (MAGENTA, KEY, [Keycode.LEFT_ARROW]),
 99      (10): (MAGENTA, KEY, [Keycode.DOWN_ARROW]),
100      (11): (MAGENTA, KEY, [Keycode.RIGHT_ARROW]),
101  }
102  
103  switches = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
104  for i in range(12):
105      switches[i] = DigitalInOut(pins[i])
106      switches[i].direction = Direction.INPUT
107      switches[i].pull = Pull.UP
108  
109  switch_state = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
110  
111  print("ItsyBitsy Keybow")
112  
113  # Starup lights
114  for k in range(12):
115      dot_on(key_dots[k], RED)
116      time.sleep(0.05)
117      dot_on(key_dots[k], keymap[k][0])  # use individual key colors from set
118      time.sleep(0.05)
119  
120  while True:
121      for button in range(12):
122          if switch_state[button] == 0:
123              if not switches[button].value:
124                  try:
125                      if keymap[button][1] == KEY:
126                          kbd.press(*keymap[button][2])
127                      else:
128                          cc.send(keymap[button][2])
129                      dot_on(key_dots[button], RED)
130                  except ValueError:  # deals w six key limit
131                      pass
132                  print("pressed key{}".format(button))
133                  switch_state[button] = 1
134  
135          if switch_state[button] == 1:
136              if switches[button].value:
137                  try:
138                      if keymap[button][1] == KEY:
139                          kbd.release(*keymap[button][2])
140                      dot_on(key_dots[button], keymap[button][0])
141                  except ValueError:
142                      pass
143                  print("released key{}".format(button))
144                  switch_state[button] = 0
145  
146      time.sleep(0.01)  # debounce