|
| 1 | +""" |
| 2 | +`M5StackCardputerKbd` |
| 3 | +==================================================== |
| 4 | +
|
| 5 | +CircuitPython M5Stack Cardputer Matrix Keyboard driver. |
| 6 | +
|
| 7 | +* Author(s): foamyguy during YouTube livestream |
| 8 | + https://www.youtube.com/watch?v=la7g24fP7IQ&t=4s |
| 9 | +
|
| 10 | + retiredwizard added modifier keys (shift, alt, ...) and minor performance changes |
| 11 | +
|
| 12 | +""" |
| 13 | + |
| 14 | + |
| 15 | +import board |
| 16 | +import digitalio |
| 17 | +import keypad |
| 18 | +from adafruit_debouncer import Debouncer |
| 19 | +#import time |
| 20 | + |
| 21 | +class MultiplexerKeys(): |
| 22 | + |
| 23 | + def __init__(self,multiplexed_row_pins, column_pins, value_when_pressed=False): |
| 24 | + self.row_pins = multiplexed_row_pins |
| 25 | + self.column_pins = column_pins |
| 26 | + self.row_dio_objs = [] |
| 27 | + self.col_dio_objs = [] |
| 28 | + |
| 29 | + # Initialize the row pins as outputs |
| 30 | + for row_pin in self.row_pins: |
| 31 | + _cur_dio = digitalio.DigitalInOut(row_pin) |
| 32 | + _cur_dio.direction = digitalio.Direction.OUTPUT |
| 33 | + self.row_dio_objs.append(_cur_dio) |
| 34 | + |
| 35 | + # Initialize the colun pins as inputs with pull-ups |
| 36 | + for column_pin in self.column_pins: |
| 37 | + _cur_dio = digitalio.DigitalInOut(column_pin) |
| 38 | + _cur_dio.direction = digitalio.Direction.INPUT |
| 39 | + _cur_dio.pull = digitalio.Pull.UP |
| 40 | + self.col_dio_objs.append(Debouncer(_cur_dio,.1)) |
| 41 | +# self.col_dio_objs.append(_cur_dio) |
| 42 | + |
| 43 | + self.value_when_pressed = value_when_pressed |
| 44 | + |
| 45 | + self._events = [] |
| 46 | + self._last_key = None |
| 47 | + |
| 48 | + @property |
| 49 | + def events(self): |
| 50 | + self._scan() |
| 51 | + return self._events |
| 52 | + |
| 53 | +# Function to scan the key matrix |
| 54 | + def _scan(self): |
| 55 | + self._events = [] |
| 56 | + key_num = -1 # Set so held button can be differentiated from no key pressed |
| 57 | + for i in range(8): |
| 58 | + self.set_multiplexer_state(i) |
| 59 | + for col, column_pin in enumerate(self.col_dio_objs): |
| 60 | + column_pin.update() |
| 61 | + column_pin.update() |
| 62 | + while column_pin.state not in [0,3]: |
| 63 | + column_pin.update() |
| 64 | + if column_pin.value == self.value_when_pressed: # If a key is pressed |
| 65 | + key_num = (i * len(self.col_dio_objs)) + col |
| 66 | + #print("Key ({}, {:03b}, {}) pressed".format(key_num, i, col)) |
| 67 | + self._events.append(keypad.Event(key_number=key_num, pressed=True)) |
| 68 | + self._last_key = key_num |
| 69 | +# time.sleep(.1) |
| 70 | + if key_num == -1: # No keys pressed |
| 71 | + if self._last_key is not None: |
| 72 | + self._events.append(keypad.Event(key_number=self._last_key, pressed=False)) |
| 73 | + self._last_key = None |
| 74 | +# time.sleep(.1) |
| 75 | + |
| 76 | + def set_multiplexer_state(self, state_binary): |
| 77 | + for idx, compare in enumerate((0b100,0b010,0b001)): |
| 78 | + self.row_dio_objs[idx].value = True if state_binary & compare else False |
| 79 | + |
| 80 | +class Cardputer(): |
| 81 | + def __init__(self): |
| 82 | + row_pins = (board.KB_A_0, board.KB_A_1, board.KB_A_2) |
| 83 | + column_pins = ( |
| 84 | + board.KB_COL_0, board.KB_COL_1, board.KB_COL_2, board.KB_COL_3, board.KB_COL_4, board.KB_COL_5, board.KB_COL_6) |
| 85 | + |
| 86 | + self._KEY_MATRIX_LUT = [ |
| 87 | + # row 4 |
| 88 | + ("OPT","",""), ("z","Z",""), ("c","C",""), ("b","B",""), |
| 89 | + ("m","M",""), (".",">","DOWN"), (" ","",""), ("CTRL","",""), |
| 90 | + ("ALT","",""), ("x","X",""), ("v","V",""), ("n","N",""), |
| 91 | + (",","<","LEFT"), ("/","?","RIGHT"), |
| 92 | + |
| 93 | + # row 2 |
| 94 | + ("q","Q",""), ("e","E",""), ("t","T",""), ("u","U",""), |
| 95 | + ("o","O",""), ("[","{",""), ("\\","|",""), ("\t","",""), |
| 96 | + ("w","W",""), ("r","R",""), ("y","Y",""), ("i","I",""), |
| 97 | + ("p","P",""), ("]","}",""), |
| 98 | + |
| 99 | + # row 3 |
| 100 | + ("SHIFT","",""), ("s","S",""), ("f","F",""), ("h","H",""), |
| 101 | + ("k","K",""), (";",":","UP"), ("\n","",""), ("FN","",""), |
| 102 | + ("a","A",""), ("d","D",""), ("g","G",""), ("j","J",""), |
| 103 | + ("l","L",""), ("'",'"',""), |
| 104 | + |
| 105 | + # row 1 |
| 106 | + ("1","!",""), ("3","#",""), ("5","%",""), ("7","&",""), |
| 107 | + ("9","(",""), ("_","-",""), ("\x08","",""), ("`","~","\x1b"), |
| 108 | + ("2","@",""), ("4","$",""), ("6","^",""), ("8","*",""), |
| 109 | + ("0",")",""), ("=","+","") |
| 110 | + ] |
| 111 | + |
| 112 | + self.keyboard = MultiplexerKeys(row_pins, column_pins) |
| 113 | + |
| 114 | + self.shift = False |
| 115 | + self.funct = False |
| 116 | + self.ctrl = False |
| 117 | + self.opt = False |
| 118 | + self.alt = False |
| 119 | + |
| 120 | + def check_keyboard(self): |
| 121 | + events = self.keyboard.events |
| 122 | + new_char_buffer = "" |
| 123 | + if events: |
| 124 | + for event in events: |
| 125 | + if event.pressed: |
| 126 | + new_char = self._KEY_MATRIX_LUT[event.key_number][0] |
| 127 | + if new_char in ['SHIFT','FN','CTRL','OPT','ALT']: |
| 128 | + new_char = "" |
| 129 | + else: |
| 130 | + if self.shift: |
| 131 | + new_char = self._KEY_MATRIX_LUT[event.key_number][1] |
| 132 | + self.shift = False |
| 133 | + elif self.funct: |
| 134 | + new_char = self._KEY_MATRIX_LUT[event.key_number][2] |
| 135 | + self.funct = False |
| 136 | + #new_char_buffer += new_char # Replaced so only last char if multiple events |
| 137 | + new_char_buffer = new_char # (multiple keys simultaneously pressed) |
| 138 | + |
| 139 | + else: |
| 140 | + # For modifer keys disable auto-repeat by only responding to "RELEASE" events |
| 141 | + new_char = self._KEY_MATRIX_LUT[event.key_number][0] |
| 142 | + if new_char == "SHIFT": |
| 143 | + self.shift = not self.shift |
| 144 | + elif new_char == "FN": |
| 145 | + self.funct = not self.funct |
| 146 | + elif new_char == "CTRL": |
| 147 | + self.ctrl = not self.ctrl |
| 148 | + elif new_char == "OPT": |
| 149 | + self.opt = not self.opt |
| 150 | + elif new_char == "ALT": |
| 151 | + self.alt = not self.alt |
| 152 | + |
| 153 | + |
| 154 | + return new_char_buffer |
| 155 | + |
| 156 | +# Exmple Usage: |
| 157 | +# |
| 158 | +#cardputer = Cardputer() |
| 159 | + |
| 160 | +#while True: |
| 161 | +# print(cardputer.check_keyboard(),end="") |
| 162 | + |
0 commit comments