diff --git a/CircuitPython_MacroPad_NKRO/boot.py b/CircuitPython_MacroPad_NKRO/boot.py new file mode 100644 index 000000000..0e9e8006d --- /dev/null +++ b/CircuitPython_MacroPad_NKRO/boot.py @@ -0,0 +1,57 @@ +import usb_hid + +BITMAP_KEYBOARD_DESCRIPTOR_REPORT_ID = 7 +REPORT_BYTES = 16 +bitmap_keyboard_descriptor = bytes(( + 0x05, 0x01, # Usage Page (Generic Desktop), + 0x09, 0x06, # Usage (Keyboard), + 0xA1, 0x01, # Collection (Application), + 0x85, 0xFF, # 6,7 Report ID [SET AT RUNTIME] + # bitmap of modifiers + 0x75, 0x01, # Report Size (1), + 0x95, 0x08, # Report Count (8), + 0x05, 0x07, # Usage Page (Key Codes), + 0x19, 0xE0, # Usage Minimum (224), + 0x29, 0xE7, # Usage Maximum (231), + 0x15, 0x00, # Logical Minimum (0), + 0x25, 0x01, # Logical Maximum (1), + 0x81, 0x02, # Input (Data, Variable, Absolute), ;Modifier byte + # LED output report + 0x95, 0x05, # Report Count (5), + 0x75, 0x01, # Report Size (1), + 0x05, 0x08, # Usage Page (LEDs), + 0x19, 0x01, # Usage Minimum (1), + 0x29, 0x05, # Usage Maximum (5), + 0x91, 0x02, # Output (Data, Variable, Absolute), + 0x95, 0x01, # Report Count (1), + 0x75, 0x03, # Report Size (3), + 0x91, 0x03, # Output (Constant), + # bitmap of keys + 0x95, (REPORT_BYTES-1)*8, # Report Count (), + 0x75, 0x01, # Report Size (1), + 0x15, 0x00, # Logical Minimum (0), + 0x25, 0x01, # Logical Maximum(1), + 0x05, 0x07, # Usage Page (Key Codes), + 0x19, 0x00, # Usage Minimum (0), + 0x29, (REPORT_BYTES-1)*8-1, # Usage Maximum (), + 0x81, 0x02, # Input (Data, Variable, Absolute), + 0xc0 # End Collection +)) + +bitmap_keyboard = usb_hid.Device( + report_descriptor = bitmap_keyboard_descriptor, + usage_page = 0x1, + usage = 0x6, + in_report_length = 16, + out_report_length = 1, + report_id_index = BITMAP_KEYBOARD_DESCRIPTOR_REPORT_ID, +) + +print(bitmap_keyboard) +devices = [ + bitmap_keyboard, + usb_hid.Device.CONSUMER_CONTROL, + usb_hid.Device.MOUSE, +] +usb_hid.enable(devices) +print("enabled HID with custom keyboard device") diff --git a/CircuitPython_MacroPad_NKRO/code.py b/CircuitPython_MacroPad_NKRO/code.py new file mode 100644 index 000000000..8439c3c29 --- /dev/null +++ b/CircuitPython_MacroPad_NKRO/code.py @@ -0,0 +1,78 @@ +import keypad +import board +import usb_hid +from adafruit_hid.keyboard import Keyboard, find_device +from adafruit_hid.keycode import Keycode + +key_pins = ( + board.KEY1, + board.KEY2, + board.KEY3, + board.KEY4, + board.KEY5, + board.KEY6, + board.KEY7, + board.KEY8, + board.KEY9, + board.KEY10, + board.KEY11, + board.KEY12, +) + +keys = keypad.Keys(key_pins, value_when_pressed=False, pull=True) + +class BitmapKeyboard(Keyboard): + def __init__(self, devices): + device = find_device(devices, usage_page=0x1, usage=0x6) + + try: + device.send_report(b'\0' * 16) + except ValueError: + print("found keyboard, but it did not accept a 16-byte report. check that boot.py is installed properly") + + self._keyboard_device = device + + # report[0] modifiers + # report[1:16] regular key presses bitmask + self.report = bytearray(16) + + self.report_modifier = memoryview(self.report)[0:1] + self.report_bitmap = memoryview(self.report)[1:] + + def _add_keycode_to_report(self, keycode): + modifier = Keycode.modifier_bit(keycode) + if modifier: + # Set bit for this modifier. + self.report_modifier[0] |= modifier + else: + self.report_bitmap[keycode >> 3] |= 1 << (keycode & 0x7) + + def _remove_keycode_from_report(self, keycode): + modifier = Keycode.modifier_bit(keycode) + if modifier: + # Set bit for this modifier. + self.report_modifier[0] &= ~modifier + else: + self.report_bitmap[keycode >> 3] &= ~(1 << (keycode & 0x7)) + + def release_all(self): + for i in range(len(self.report)): + self.report[i] = 0 + self._keyboard_device.send_report(self.report) + +kbd = BitmapKeyboard(usb_hid.devices) + +keymap = [ + Keycode.ONE, Keycode.TWO, Keycode.THREE, + Keycode.Q, Keycode.W, Keycode.E, + Keycode.A, Keycode.S, Keycode.D, + Keycode.Z, Keycode.X, Keycode.C] + +while True: + ev = keys.events.get() + if ev is not None: + key = keymap[ev.key_number] + if ev.pressed: + kbd.press(key) + else: + kbd.release(key)