A replica from my tweet from a while ago.

because i can.

Video 1: A morse key connected to an Adafruit Feather RP2040, running home-brewn CircuitPython code whcih interprets morse input and emulates a USB HID keyboard, sending characters to the Twitter app on Android.

Original source: because i can.

The code is a simple Gist on Github, but below you can see the full code for reference. It needs some serious improvements, but it’s good enough for me.

To be really useful as a keyboard, the set of morse codepoints was extended; instead of doing it myself, I borrowed the existing set from Google’s GBoard morse implementation, as described by Nathan Vander Wilt.

import time
import board
import digitalio
import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS
from adafruit_hid.keycode import Keycode

lookup = { ".-":"a", "-...":"b", "-.-.":"c", "-..":"d", ".":"e", "..-.":"f",
    "--.":"g", "....":"h", "..":"i", ".---":"j", "-.-":"k", ".-..":"l",
    "--":"m", "-.":"n", "---":"o", ".--.":"p", "--.-":"q", ".-.":"r",
    "...":"s", "-":"t", "..-":"u", "...-":"v", ".--":"w", "-..-":"x",
    "-.--":"y", "--..":"z", "-----":"0", ".----":"1", "..---":"2",
    "...--":"3", "....-":"4", ".....":"5", "-....":"6", "--...":"7",
    "---..":"8", "----.":"9", ".-.-.-":".", "--..--":",", "..--..":"?",
    ".----.":"\'", "-.-.--":"!", "-..-.":"/", "-.--.":"(", "-.--.-":")",
    ".-...":"&", "---...":":", "-.-.-.":";", "-...-":"=", ".-.-.":"+",
    "-....-":"-", "..--.-":"_", ".--.-.":"@", ".-..-.":"\"", "...-.":"*",
    "-.-.-":"\\", "---.-":"%", "--.-.":"#", "--.-.-":"|", "......":"^",
    ".---..":"~", "-..-.-":"`", "...-..":"$", ".--..":"[", ".--..-":"]",
    ".--.-":"{", ".--.--":"}", "-.---":"<", "-.----":">", "..--":" ",
    ".-.-":Keycode.ENTER, "----":Keycode.BACKSPACE, "....-.":Keycode.SHIFT,
    ".-----":Keycode.CONTROL, "..----":Keycode.ALT, "...---":Keycode.ESCAPE }

key = digitalio.DigitalInOut(board.D4)
key.direction = digitalio.Direction.INPUT
key.switch_to_input(pull=digitalio.Pull.UP)
keyboard = Keyboard(usb_hid.devices)
keyboard_layout = KeyboardLayoutUS(keyboard)

while True:
    dit = 0.16
    daw = 3 * dit
    pauselength = 6 * dit
    pauseduration = 0.0

    keypressed = False
    pause = False
    stack = ""
    while True:
        if not key.value and not keypressed:
            # key press detected
            starttime = time.monotonic_ns()
            keypressed = True
        elif key.value and keypressed:
            # key depressed, measure time
            duration = (time.monotonic_ns() - starttime)/1e9
            if duration <= dit:
                stack += "."
            elif duration <= daw:
                stack += "-"
            keypressed = False
            sleepstart = time.monotonic_ns()
            pause = True
        if key.value and not keypressed and pause:
            pauseduration = (time.monotonic_ns() - sleepstart)/1e9
            if pauseduration > daw and pauseduration < pauselength:
                if stack in lookup:            # Buchstaben gefunden
                    k = lookup[stack]
                    if isinstance(k, str):     # printable?
                        keyboard_layout.write(k)
                        keyboard.release_all() # automatically unlatches
                    elif k in (Keycode.SHIFT, Keycode.CONTROL, Keycode.ALT):
                        # Let's latch! Control code...
                        keyboard.press(k)
                    else:
                        # Keycode.ESCAPE, RETURN oder BACKSPACE
                        keyboard.press(k)
                        keyboard.release_all()
                    stack = ""
                else:
                    # Hab vergessen, was das macht...
                    stack = ""
            elif pauseduration >= pauselength:
                # Wortende, Leerzeichen schreiben. Lassen wir nun weg.
                stack = ""
                #keyboard_layout.write(" ")
                pause = False
        time.sleep(0.025)

Listing 1: Morse parser and USB HID keyboard implementation