В начале февраля в Steam был фестиваль печатания. Среди множества игр, проверяющих умение работы с клавиатурой, нашлась одна, которая предлагает уникальный опыт морского боя по телеграфу: индексы клеток вводятся азбукой Морзе.
Игра совместима с мышкой, клавиатурой и джойстиком. Я посчитал, что это не достаточно аутентично, и собрал свой контроллер с телеграфным ключом и дверным звонком. Получившееся устройство подходит не только для одной игры, но и для обучения азбуке Морзе и для набора сообщений в любые поля ввода в ОС.
MORSE

MORSE — это стратегия, которая предлагает морские сражения в реальном времени с использованием азбуки Морзе. Игровое поле разделено на клетки, а переход к строке и столбцу происходит телеграфированием соответствующей цифры или буквы. Выстрел по клетке производится отдельной кнопкой, а с недавнего обновления — еще и последовательностью -…-, что позволяет играть полностью на телеграфном ключе.
Игра не требует особых навыков или оборудования. Шпаргалка с алфавитом по умолчанию включена, в настройках можно назначить любую клавишу в качестве телеграфного ключа.
У игры есть бесплатная демо-версия, в которой можно ознакомиться с первыми уровнями и составить собственные впечатления.
Эта игра — один из нескольких тестов, которые придется пройти контроллеру. Но сначала его нужно собрать.
Телеграфный ключ

Классический телеграфный ключ — это переключатель в виде подпружиненного коромысла с двумя контактами. Дальний контакт (6’) в нормальном состоянии замкнут, что эквивалентно режиму приема на аппаратуре. При нажатии на рукоятку ближайший контакт (6) замыкается и в эфир отправляется сигнал, продолжительность которого регулируется продолжительностью нажатия на ключ. При отпускании ключ возвращается в нормальное состояние.
Классический механический вертикальный ключ — это не единственное устройство для передачи «морзянки». Существуют горизонтальные полуавтоматические и автоматические ключи.
В полуавтоматических смещение коромысла влево отправляет тире, а при смещении вправо запускается маятниковый механизм, который генерирует последовательность точек, пока контакт замкнут. Автоматические ключи используют аналогичный механизм не только для точек, но и для тире.
Классический телеграфный ключ можно получить несколькими способами.
- Купить. На маркетплейсах есть современные и самодельные ключи. На «барахолке» можно найти более классические варианты.
- Напечатать на 3D-принтере. Есть несколько моделей от ключа до телеграфной системы. Есть вариант на основе столовой ложки.
- Сделать из подручных материалов. У пользователя с ником OH6DC есть подборка телеграфных ключей: на бананах, плойке и даже на телепузике.

Я выбрал самый простой вариант: купил на барахолке за 1 200 рублей ключ Пг2.175.000. Похоже, что этот ключ не вынимали из коробки со времен производства — в 1991 году. На нижней стороне устройства видны три контакта, к которым можно подключиться. Ключ требует небольшого, но ощутимого усилия для нажатия, а при замыкании слышится приятный металлический стук.
Берем эту прекрасную коробочку и добавляем обвязку для работы с компьютером.
Arduino, дверной звонок и разделочная доска

У ключа есть очевидное требование: он должен быть прикручен к какой-нибудь устойчивой поверхности. Для этого в корпусе есть четыре отверстия. Нажатие на рукоятку незакрепленного ключа приводит к отрыву ключа от стола.
Так как я планирую портативный контроллер для компьютера, то расширяю свои ресурсы подручными средствами.
- Деревянная разделочная доска 22×16 см. Материал: бамбук. В моем случае она бесплатна, потому что она служила на кухне, но уже была существенно повреждена (но не сломлена) перепадами температуры в посудомойке. Примерная текущая стоимость — 500 рублей за одну новую доску.
- Простой дверной звонок. 200 рублей.
- Arduino Leonardo. Из моих старых запасов. Текущая цена — от 500 до 4 000 рублей в зависимости от магазина и оригинальности платы. В целом подходит любая плата на базе ATmega32u4.
- Несколько перемычек вида «папа-папа». Перемычки разрезаются, зачищаются и прикручиваются к контактам звонка и ключа.

Подключение Arduino к дверному звонку и ключу элементарно. Подключаем цифровые выходы, в моем случае 2 и 4, и землю к кнопкам. Механизм внутренней подтяжки (INPUT_PULLUP) позволяет не использовать внешние резисторы, чем максимально упрощает схему. А простую схему можно собрать навесным монтажом.
Суммарная стоимость всех компонентов будущего контроллера — около трех тысяч рублей. Хотя цена максимально зависит от телеграфного ключа и микроконтроллера.
Надежно прикручиваем элементы на бывшую разделочную доску и можем переходить к программированию.
Программирование
Наивный алгоритм
Ранее я отмечал, что нужен микроконтроллер на базе ATmega32u4. Дело в том, что эти микроконтроллеры умеют в эмуляцию USB HID, то есть могут «прикидываться» настоящей клавиатурой.
Реализуем наивный алгоритм, который при замыкании ключа нажимает клавишу, а при размыкании — отпускает.
#include <Keyboard.h>
const int keyPin = 2;
const char keyButton = ' ';
bool lastState = HIGH;
void setup() {
pinMode(keyPin , INPUT_PULLUP);
Keyboard.begin();
}
void loop() {
bool now = digitalRead(keyPin);
if (keyPin == HIGH && now == LOW) { // нажали
Keyboard.press(keyButton);
}
if (keyPin == LOW && now == HIGH) { // отпустили
Keyboard.release(keyButton);
}
lastState = now;
}
В общем случае программа работает и может быть легко расширена для поддержки второй кнопки — дверного звонка. Однако программа не идеальна: при телеграфировании иногда возникает дребезг контактов, из-за чего игра распознает «лишнюю» точку. А кнопки «Backspace», как известно, в телеграфных системах нет.
Улучшенный алгоритм
После модификации программа стала более объемной, но и вместе с тем более функциональной.
- Поддерживается как телеграфный ключ, так и кнопка.
- Предусмотрен антидребезг: сигнал считается стабильным, если сохраняется как минимум 10 мс. Это значение вынесено в константы и может быть изменено перед прошивкой.
- Добавлен «сырой» режим, в котором микроконтроллер отправляет изменение состояния переключателей по COM-порту. Это опциональный режим.
Исходный код прошивки слишком большой, чтобы выносить его в статью, поэтому его можно посмотреть на GitHub.
Я, конечно, новичок и «печатаю» медленно, но играть на телеграфном ключе интереснее, чем на клавиатуре. А опыт — дело наживное.
Телеграфирование в операционную систему
А если вы хотите с помощью азбуки Морзе не только играть в игры, но и вводить текст в программы, будь то Telegram, Google Docs и прочее, то давайте продолжим.

Алфавит в коде Морзе и правила кодирования помещаются на лист А5. Должно быть просто декодировать сигнал, поступающий с контроллера, и программно нажимать кнопки клавиатуры, соответствующие коду, верно?
Для декодирования Морзе нужно следовать пяти правилам.
- Длина точки берется за единицу времени.
- Тире занимает три точки.
- Длина тишины между сигналами одной буквы — одна точка.
- Длина тишины между буквами — три точки.
- Длина тишины между словами — семь точек.
Длина точки не регламентирована, новички могут передавать сообщение медленно, профессионалы — быстро. До тех пор, пока выполняются перечисленные пять правил — сообщение будет декодировано. Более того, в передачах есть специальные сокращения, Q-коды, обозначающие «Передавайте медленнее» (QRS) и «Передавайте быстрее» (QRQ).
Так как я хочу написать декодер, который будет понимать меня только на заданной скорости, а не в «любом случае», то необходимо, собственно, определить скорость телеграфирования — Words Per Minute (WPM).
Стандартными словами для измерения скорости считаются слова PARIS (длина передачи — 50 точек) и CODEX (60 точек). Несложно подсчитать, что при скорости 1 слово в минуту на передачу одной точки уходит от 1 000 до 1 200 миллисекунд. Эти константы позволяют высчитывать длину точки при разных скоростях передачи. Например, при WPM 20 длина точки 60 мс, а при WPM 35 — 35 мс.

За пару вечеров я набросал программу на .NET, которая распознает коды, показывает распознанные точки и тире в окне, а также позволяет видеть длительность сигнала и паузы между сигналами.
Программа считывает команды из COM-порта, которые отправляет контроллер. Формат сообщения текстовый, сообщения разделяются переносом строки, данные в сообщении — пробелом.
- EVT — «заголовок» сообщения нажатия кнопки.
- BTN или KEY — указывает к кнопке или к ключу относится сообщение.
- 0 или 1 — обозначает новое состояние переключателя. 0 — разомкнутно.
- Временная метка в миллисекундах. Внутреннее время контроллера позволяет более точно вычислить длительность передаваемого сигнала.
Превращение данных в точки и тире происходит с небольшой погрешностью. Длина точки может колебаться от 0.5 до 2.0 точек, а длина тире — от 2.1 и больше. Аналогично производится расчет для принадлежности символа к текущей букве или к следующей.
Для эмуляции нажатия клавиш используется .NET класс SendKeys и метод SendWait в частности. Особенность этого подхода в том, что это именно «нажатие» клавиш. Если набрать код латинского символа «Q», а в операционной системе будет выбрана русская раскладка, то в поле ввода появится символ «Й». Более того, пользователи QWERTZ-раскладок тоже увидят нестыковку: символ «Y» будет напечатан как «Z».
Приложение на уровне ОС может корректно обрабатывать эти ситуации, переключать раскладки и, при необходимости, отправлять текст в приложения без перехвата фокуса.
Полезные источники
Если вы впечатлились и хотите изучить код Морзе, то для этого есть несколько разных решений.
Игра MORSE, с которой началась эта статья. Возможно, игра — не лучшее решение именно для изучения, но определенно хорошее место для закрепления полученных навыков в стрессовой среде. Поддерживает мышь, клавиатуру, джойстик. Только английский алфавит. В сообществе Steam есть тема, посвященная DIY-контроллерам для игры.
Сервис MorseMaster. Онлайн-сервис, предлагающий уроки с прогрессирующей сложностью. Поддерживает мышь и клавиатуру. Только английский алфавит.
Если вам кажется, что я уделил мало текста истории и устройству телеграфных линий, то можете обратиться к статье моего коллеги по блогу.
Полный исходный код проекта из статьи доступен на GitHub.