Skip to content

Repository files navigation

Morse Trainer

A Morse code trainer written in Dart / Flutter, with support for a USB iambic Morse key (USB id 413d:2107).

Downloads

Pre-built desktop applications are published on the Releases page. The links below always point at the latest release:

Platform Download
Windows (x64) Morsey-windows-x64.zip
macOS Morsey-macos.dmg
Linux (x64) .AppImage · .deb · .tar.gz
Linux (arm64) .AppImage · .deb · .tar.gz

On Linux, audio uses pacat from pulseaudio-utils; install it if it is not already present. USB-key access needs read permission on the key's /dev/hidraw* node (see Permissions).

The program

The main window has a left column listing the parts of the program; click one to open it:

  • About — a description of the program and how it works.
  • Settings — choose the keyer mode (iambic paddles, or a straight key where the press length makes the dits and dahs), the paddle orientation, the keying speed (WPM), the side-tone volume and frequency, the training character set, the appearance (follow system, light, or dark), and the language. There is no input-device selection: the USB key and the keyboard paddles are both always active, and the key can be plugged in (or unplugged) at any time.
  • Input Train — a character is shown; you key it in Morse and the trainer decodes what you send and tells you whether it was correct.
  • Listen Train — the trainer plays a character as Morse audio; you type the character you heard.
  • Listen Tutorial — a guided, 26-level listening course. Each level introduces one new letter (Koch-method order, easiest-to-distinguish sounds first): the letter is shown and its Morse is played, you type it to begin, then a random drill of every letter unlocked so far runs until each has been answered correctly three times. Completing a level unlocks the next; progress is remembered, and a dropdown lets you revisit any unlocked level.
  • Input Tutorial — the same 26-level course with the roles reversed, to teach sending. Each level shows the new letter's dots and dashes with the letter beside them; key the pattern to begin. In practice the pattern is taken away — only the letter is shown — and you key its Morse from memory (USB paddle or keyboard, exactly as in Input Train) with a live display of what you are keying. A Hear it button plays the target's rhythm (it is disabled while you are keying, since the keyer owns the side-tone), and a per-letter hint reveals the pattern if you get stuck. Its progress is tracked separately from the Listen Tutorial — hearing a letter and keying it are different skills.
  • Free Type — type any text in the top box and watch it rendered as Morse in the box below. The dots and dashes appear element by element at the keying speed set in Settings, and a toggle at the top plays the Morse audio in sync with the display.
  • Free Key — the reverse: key Morse with the paddle or keyboard and watch it decoded into text. The dots and dashes appear in the Morse box as you key; each completed character is decoded into the text box, and pausing seven dits inserts a word space. The same toggle mutes the keying side-tone.
  • Timing — shows a line from a public-domain book (1000 bundled lines from Dickens, Austen, Melville, Franklin, Adam Smith and others) with its Morse; key it and every pulse and gap is timed against the expected sequence. Alignment is per character using the keyer's decode: a miskeyed letter shows what you sent, discards that attempt's timings, and waits for a re-key (or resyncs if you skipped a letter) — one slip never poisons the rest of the line. On completion you get a histogram and consistency score (100 − coefficient of variation) per category — dits, dahs, letter gaps and word gaps with a straight key, or the gaps alone in iambic mode — plus your actual sending speed in WPM (nominal PARIS units ÷ elapsed time). Restart picks a new line.

The Hardware

The iambic keyer that I have used is the Putikeeg MCT II.

It is listed on Amazon as the "CW Key Morse Code Key Morse Telegraph Key Morse Code Key Aluminum Alloy CW Square-Shaped Base Red (Grey)"

Putikeeg Keyer Image

Keyer Amazon Link

This provides a 3.5mm jack interface. To connect to a computer you need a USB interface. The one I use is listed on Amazon as the "Morse Code Training Adapter USB Key Trainer for/Key Mobile Computer Support 3.5mmPlug Key Trainer Connectors"

Keyer USB Interface Image

USB Interface Amazon Link

The USB Morse key

The key enumerates as a standard USB HID keyboard with the identifier 413d:2107. On Linux it is read directly from its /dev/hidrawN node — no drivers needed. Each paddle is reported in the HID modifier byte:

  • Left-Ctrl bit (0x01) → one paddle
  • Right-Ctrl bit (0x10) → the other paddle

The device sends raw paddle up/down state; a software iambic keyer turns those presses into correctly-timed dits and dahs (squeeze both paddles for alternating elements) and decodes them into characters. Which paddle is dit vs dah is set in Settings ("Paddle orientation").

Permissions

On MacOs:

When first run, you should be prompted to open the input monitoring section in the settings. Grant input monitoring to Morsey then close and reopen Morsey.

On linux:

You need read access to the key's /dev/hidraw* node. On this machine the node is owned by group plugdev with an ACL, and the user is in plugdev, so it works out of the box. If not, add a udev rule such as:

# /etc/udev/rules.d/99-morse-key.rules
SUBSYSTEM=="hidraw", ATTRS{idVendor}=="413d", ATTRS{idProduct}=="2107", MODE="0660", GROUP="plugdev"

then sudo udevadm control --reload && sudo udevadm trigger.

Audio

The side-tone is a synthesised sine wave with a per-platform backend, all speaking the same morsey/tone_engine contract: an AVAudioSourceNode on macOS and iOS, WASAPI on Windows, an AudioTrack render thread on Android, and — on Linux — PCM synthesised in Dart and streamed to PulseAudio/PipeWire via pacat (from pulseaudio-utils). No gstreamer or extra Flutter audio plugin is required. If no audio backend is found the app still runs (Input Train works silently; Listen Train needs sound).

Practising without the USB key

Nothing to configure — the keyboard paddles are always active alongside the USB key. The Left-Arrow key is the dit paddle and the Right-Arrow key is the dah paddle (./- and Left/Right-Ctrl also work). Click the Input Train area first so it has keyboard focus. If you plug the USB key in mid-session it connects automatically.

Languages

The UI is internationalized with Flutter's gen-l10n. Translations live in lib/l10n/app_<locale>.arb; currently English (en), Welsh (cy), German (de), Spanish (es), French (fr), Hindi (hi), Japanese (ja), Chinese (zh), and Klingon (tlh). The language can be set in Settings ("Follow system" uses the platform locale, falling back to English). To add a language, copy app_en.arb, translate the values, add the locale to supportedLocales and AppLanguage, and rebuild.

Running

flutter run -d linux

Building

flutter build linux

Tests

flutter test

Covers the Morse table, settings/timing, the app shell, and the iambic keyer/decoder (driven by a simulated paddle).

Layout

lib/
  main.dart                     app entry + main window / left nav column
  app_scope.dart                shared Settings + AudioEngine (InheritedWidget)
  models/settings.dart          settings model (input, speed, tone, char set)
  morsey/morse_code.dart        Morse alphabet + character sets
  morsey/iambic_keyer.dart      software iambic keyer + live decoder
  audio/audio_engine.dart       Dart tone synth streamed via pacat
  input/paddle_source.dart      paddle source abstraction
  input/hid_paddle_source.dart  reads the USB key (hidraw / IOKit), hotplugs
  input/keyboard_paddle_source.dart  keyboard keys as dit/dah paddles
  input/combined_paddle_source.dart  keyboard + USB key active together
  screens/                      About / Settings / Input Train / Listen Train /
                                Listen Tutorial / Input Tutorial

About

A Morse code training program supporting a hardware input key.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages