27 февраля 2015 в 01:43

Создание Ultimate Hacking Keyboard перевод

Перевод истории задумки и создания Ultimate Hacking Keyboard – необычной клавиатуры, проект которой вскоре планируют запустить на Kickstarter.

Как я решил построить идеальную клавиатуру для разработчика с нуля


В августе 2007 на работе я заметил, насколько далека от идеала стандартная клавиатура для PC. Мне приходится сотни раз в день перемещать руки в разные её места, а ладони нужно держать близко друг к другу, что не очень удобно. Я подумал, что должен быть способ лучше.

Я начал думать, как можно улучшить клавиатуру и пришёл к этому:

image

Имея за плечами лишь опыт разработки софта и не зная ничего об электронике, мы сумели разработать и создать мощное и привлекательное устройство. Это был очень интересный опыт. В статье я хочу описать то, как это было сделано и как работает.

Как сделать клавиатуру?


Попробуем начать с чего-нибудь простого, например с Arduino, и постепенно повышать градус сложность, чтобы в конце прийти к Ultimate Hacking Keyboard.

Шаг 1: Клавиатура без клавиш


Сделаем USB-клавиатуру, которая выдаёт символ х раз в секунду. Для этого идеально подойдёт Arduino Micro. На ней стоит ATmega32U4 – это такой же AVR-микроконтроллер, который служит мозгом UHK.

image

С USB AVR микроконтроллером проще всего работать через библиотеку Lightweight USB Framework for AVRs (LUFA). При подключении к USB устройство должно передать особые структуры данных – USB-дескрипторы. Они сообщают компьютеры тип и свойства подключённого устройства и представлены в виде дерева. При этом устройство может реализовывать несколько функций.

Вот структура дескриптора для UHK:

Device descriptor
    Configuration descriptor
        Interface descriptor 0: GenericHID
            Endpoint descriptor
        Interface descriptor 1: Keyboard
            Endpoint descriptor
        Interface descriptor 2: Mouse
            Endpoint descriptor


Стандартные клавиатуры выдают только один дескриптор. Но на нашей клавиатуре можно запрограммировать произвольные клавиши так, чтобы они выполняли роль мыши. А интерфейс GenericHID работает как канал для коммуникаций и передачи настроек. Полную реализацию для устройства на основе LUFA можно взять здесь.

Теперь можно ежесекундно отправлять символ х:

uint8_t isSecondElapsed = 0;
 
int main(void)
{
    while (1) {
        _delay_us(1000);
        isSecondElapsed = 1;
    }
}
 
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
                                         uint8_t* const ReportID,
                                         const uint8_t ReportType,
                                         void* ReportData,
                                         uint16_t* const ReportSize)
{
    USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
    if (isSecondElapsed) {
        KeyboardReport->KeyCode[0] = HID_KEYBOARD_SC_X;
        isSecondElapsed = 0;
    }
    *ReportSize = sizeof(USB_KeyboardReport_Data_t);
    return false;
}


USB протокол работает по принципу поллинга, то есть компьютер опрашивает устройство через определённые промежутки времени (обычно 125 раз в секунду). Функция обратного вызова CALLBACK_HID_Device_CreateHIDReport() отправляет сканкод символа на компьютер, если в переменной isSecondElapsed содержится 1. Переменной присваивается 1 в цикле каждую секунду, и 0 в функции обратного вызова.

Шаг 2: Клавиатура с четырьмя клавишами


Пока наша клавиатура не особенно полезна. Чтобы иметь возможность что-либо печатать, нужны клавиши. Их надо расположить по какой-то схеме (матрице). У 104-клавишной клавиатуры 6 рядов и 18 столбцов, но мы пока ограничимся матрицей 2х2. Схемка:

image

Как это выглядит на доске для прототипирования:

image

Если ROW1 соединён с PINA0, ROW2 с PINA1, COL1 с PORTB0 и COL2 с PORTB1, то код для опроса нажатий выглядит так:

/* Пин микроконтроллера, к которому подсоединён ряд или столбец */
typedef struct {
    volatile uint8_t *Direction;
    volatile uint8_t *Name;
    uint8_t Number;
} Pin_t;
 
/* Эта часть матрицы хранится в Flash для экономии места в SRAM. */
typedef struct {
    const uint8_t ColNum;
    const uint8_t RowNum;
    const Pin_t *ColPorts;
    const Pin_t *RowPins;
} KeyMatrixInfo_t;
 
/* Эта часть матрицы хранится в SRAM */
typedef struct {
    const __flash KeyMatrixInfo_t *Info;
    uint8_t *Matrix;
} KeyMatrix_t;
 
const __flash KeyMatrixInfo_t KeyMatrix = {
    .ColNum = 2,
    .RowNum = 2,
    .RowPins = (Pin_t[]) {
        { .Direction=&DDRA, .Name=&PINA, .Number=PINA0 },
        { .Direction=&DDRA, .Name=&PINA, .Number=PINA1 }
    },
    .ColPorts = (Pin_t[]) {
        { .Direction=&DDRB, .Name=&PORTB, .Number=PORTB0 },
        { .Direction=&DDRB, .Name=&PORTB, .Number=PORTB1 },
    }
};
 
void KeyMatrix_Scan(KeyMatrix_t *KeyMatrix)
{
    for (uint8_t Col=0; Col<KeyMatrix->Info->ColNum; Col++) {
        const Pin_t *ColPort = KeyMatrix->Info->ColPorts + Col;
        for (uint8_t Row=0; Row<KeyMatrix->Info->RowNum; Row++) {
            const Pin_t *RowPin = KeyMatrix->Info->RowPins + Row;
            uint8_t IsKeyPressed = *RowPin->Name & 1<<RowPin->Number;
            KeyMatrix_SetElement(KeyMatrix, Row, Col, IsKeyPressed);
        }
    }
}


Код сканирует клавиатуру по одному столбцу за раз, и в столбце читает состояние отдельных переключателей. Затем состояние кнопок сохраняется в массиве. Внутри CALLBACK_HID_Device_CreateHIDReport() на основании этого массива будут назначены соответствующие сканкоды.

Шаг 3: клавиатура из двух половинок


Продолжая путь к UHK, необходимо добавить вторую половину клавиатуры. Она будет содержать ещё одну матрицу клавиш, которая будет работать тем же методом. Интересным моментом будет общение двух половинок между собой. Три самых популярных протокола для соединения устройств — SPI, I2C и UART. В статье будет использован UART.

image

Двустороннее общение идёт через RX вправо и через TX влево. VCC и GND нужны для передачи питания. Для UART нужно, чтобы у всех устройств была одинаковая скорость передачи, количество бит данных и стоповых битов.

Пока что левая часть отправляет однобайтовые сообщения в правую через UART, представляющие собой нажатия и отпускания клавиш. Правая половина обрабатывает их и создаёт матрицу для полной клавиатуры.

Отправка сообщений с левой части:

USART_SendByte(IsKeyPressed<<7 | Row*COLS_NUM + Col);

Правая часть принимает сообщения:

void KeyboardRxCallback(void)
{
    uint8_t Event = USART_ReceiveByte();
    if (!MessageBuffer_IsFull(&KeyStateBuffer)) {
        MessageBuffer_Insert(&KeyStateBuffer, Event);
    }
}


Хэндлер прерывания KeyboardRxCallback() срабатывает при получении байта. Для скорейшего срабатывания хэндлеров полученные сообщения складываются в кольцевой буфер. Он обрабатывается из основного цикла, и матрица клавиатуры обновляется на основании этого сообщения.

Это упрощённое описание, результирующий протокол получится несколько посложнее. Надо будет обрабатывать многобайтовые сообщения, и проверять сообщения на правильность по контрольным суммам.

Прототип уже выглядит внушительно:

image

Шаг 4: LED дисплей


Мы захотели, чтобы у UHK было несколько раскладок, и чтобы пользователь знал, какая из них используется в данный момент. Для этого нам понадобится LED дисплей.

image

Дисплей представляет из себя матрицу 8х6

image

Каждые два ряда красных символов – это один из 14-сегментных дисплеев. Белые символы – три дополнительных статусных индикатора.

Для того, чтобы LED загорелся, на соответствующий столбец подаётся высокое напряжение, а на ряд – низкое. Из этого следует, что работать может только один столбец. Можно решить, что из-за этого нельзя работать со всеми дисплеями одновременно – но суть в том, что они просто мигают настолько быстро, что этого не замечает глаз.

Матрица LED управляется двумя интегральными микросхемами (ИС), одна из которых управляет рядами, а другая – столбцами. Столбцами управляет PCA9634 I2C:

image

Рядами управляет TPIC6C595:

image

Код:

uint8_t LedStates[LED_MATRIX_ROWS_NUM];

void LedMatrix_UpdateNextRow(bool IsKeyboardColEnabled)
{
    TPIC6C595_Transmit(LedStates[ActiveLedMatrixRow]);
    PCA9634_Transmit(1 << ActiveLedMatrixRow);

    if (++ActiveLedMatrixRow == LED_MATRIX_ROWS_NUM) {
          ActiveLedMatrixRow = 0;
    }
}


LedMatrix_UpdateNextRow() вызывается каждую миллисекунду и обновляет ряд матрицы. Массив LedStates сохраняет состояния отдельных LED, и обновляется через UART на основании сообщений с правой стороны клавиатуры примерно так же, как обрабатываются нажатия клавиш.

Общий план


Вот мы и построили компоненты для нашей клавиатуры. Внутренности клавиатуры представляют из себя компьютерную сеть в миниатюре: множество узлов, соединённых между собою.

image

Надо упомянуть и софт, работающий с клавиатурой на стороне компьютера – UHK Agent. В отличие от железной части, Agent пока в рудиментарном состоянии. Но основные принципы его работы уже определены, о чём я и хочу упомянуть.

UHK Agent – приложение для настроек клавиатуры под нужды пользователя. Хотя это и толстый (rich) клиент, Agent использует веб-технологии и работает на платформе webkit. С клавиатурой он общается через библиотеку node-usb. Он Express.js для доступа к нему сторонних приложений через REST API. Также он Angular.js для рисования красивого интерфейса пользователя.

var enumerationModes = {
    'keyboard'         : 0,
    'bootloader-right' : 1,
    'bootloader-left'  : 2
};

function sendReenumerateCommand(enumerationMode, callback)
{
    var AGENT_COMMAND_REENUMERATE = 0;
    sendAgentCommand(AGENT_COMMAND_REENUMERATE, enumerationMode, callback);
}

function sendAgentCommand(command, arg, callback)
{
    setReport(new Buffer([command, arg]), callback);
}

function setReport(message, callback)
{
    device.controlTransfer(
        0x21,             // bmRequestType (константа этого запроса)
        0x09,             // bmRequest (константа этого запроса)
        0,                // wValue (MSB тип отчёта, LSB номер отчёта)
        interfaceNumber,  // wIndex (номер интерфейса)
        message,          // сообщение
        callback
    );
}


У каждой команды есть 8-битный идентификатор и набор аргументов, зависящих от команды. Сейчас реализована только команда re-enumerate.

Что же умеет этот софт? Agent может отображать износ кнопок и предупреждать о необходимости их замены. Он может предоставлять интерфейс для настройки различных раскладок. Задавать скорость и ускорение курсора мыши. И много всего другого.

Создание прототипа


На прототипы уходит очень много сил. Для начала нужно определиться с механическим дизайном – это само по себе сложная задача, для которой нужно подготовить множество пластиковых деталей, вырезать лазером детали из листов нержавеющей стали, выточить высокоточные стальные направляющие и приспособить неодимовые магниты, которые будут скреплять две половинки. Предварительно все детали просчитываются в CAD.

image

Корпус клавиатуры, распечатанный на 3D-принтере:

image

На основании механического дизайна и схемы нужно изготовить печатную плату. Правая часть выглядит в KiCad так:

image

Делаем плату и вручную припаиваем элементы:

image

Наконец, изготовив все части, напечатав и отшлифовав пластиковые детали, и собрав всё это вместе, мы получаем работающий прототип клавиатуры:

image

Заключение


Я сравниваю клавиатуры для разработчиков с музыкальными инструментами. Клавиатура – довольно интимный объект. Мы используем их весь день для создания завтрашних программ, печатая один символ за другим.

Поэтому для меня разработка UHK – это привилегия, и несмотря на все трудности, это волнующее приключение и прекрасный опыт в обучении новому.

За подробной информацией я приглашаю вас посетить сайт ultimatehackingkeyboard.com, и там же вы сможете подписаться на уведомление о начале нашей краудфандинговой компании.
Перевод: László Monda
Вячеслав Голованов @SLY_G
карма
147,2
рейтинг 435,7
Редактор GeekTimes
Похожие публикации
Самое читаемое

Комментарии (35)

  • +18
    Все знают, что пихать кнопку FN на место CTRL — плохо. По-этому у наc там суперкнопка SUPER. Другое дело!
    • 0
      Насколько я понял, клавиатура будет полностью настраиваемой, так что их можно будет просто поменять местами.
  • +13
    Функциональных нету — идем дальше.
    • 0
      с доп кнопкой включаются. просто придется двумя руками жто делат ьвместо одной. Возможно, не сильно страшно.
  • +3
    Ну я могу представить что можно жить без «стрелочек» и F1-12, хоть и придется зажимать лишнюю клавишу, но вот для меня жизнь без удобно расположенных Del/Home/End будет просто невыносима.
    Ну и что уж там, я люблю большие Enter`ы.
    • 0
      Не представляю как жить без кнопки F5
      • +4
        Да, в mc без неё никак. ;)
        • 0
          Ну так не мышкой же клацать по обновлению страницы чтоб видеть как карма улетает в трубу :D
          • 0
            Cmd/Ctrl+R удобнее. =)
            • 0
              Дело привычки. Мне, например, F5 удобнее :)
              • 0
                Мне сначала тоже было непривычно, но теперь — только так. Тянуться меньше надо. =)
                • +1
                  Я дотергеймер со стажем, поэтому положение «по-умолчанию» моей левой руки на клаве — на ряду qwer, а не asd. Для меня нажать на F5 — чуть двинуть указательным пальцем :D
                  • 0
                    Ну тогда конечно. =)
    • 0
      Эта клавиатура — по сути эргономичный и перепрограммируемый вариант Happy Hacking Keyboard, даже название «Ultimate Hacking Keyboard» об этом говорит. Оригинальная HHK — супер-хардкорная и дорогая штука для очень узкой аудитории, и в ней намеренно нет стрелок, функциональных клавиш и Home/End. Всё только через Fn. geektimes.ru/post/144911/
      • 0
        В чем её эргономичность? В разделении на два блока?
        • 0
          Да. Если даже Microsoft называет свою монолитную клавиатуру эргономичной, то здесь эргономики и того больше: блоки можно раздвигать и изменять углы (в разумных пределах).
  • +2
    Esc, Del, CTRL, стрелки не на месте, такая клавиатура на любителя.
  • +1
    Как уже сказали, нет блока стрелок, Esc и F1—12, мелкий Enter, Super на месте Control, отсутствуют Del, PageUp/Down, Home, End.
    Из личных придирок: отсутствие цифрового блока (бывает, что надо вбить много цифирь, в верхнем ряду это делать не так удобно), Mouse на месте CapsLock, которым многие переключают раскладку. На мой взгляд, категорически неюзабельно. Единственный плюс — программируемая.
    Мне больше всего нравились низкопрофильные A4Tech с пирамидальной раскладкой. И все кнопки есть, и Enter большой, и руки в удобной позиции не устают (порой по 16 часов не отрывался от клавы), и ход приятный: небольшой, но нажатие ощущается вполне однозначно. Жаль, их делать перестали, а запасы подходят к концу, последнюю стаптываю.
    • 0
      KV-300H? Моя любимая клавиатура. Но энрер у неё всё же маленький.
      • 0
        Нет, это не «пирамидка». Типа вот такой: a4tech.ru/products/keyboard/standart/kls-23mu/
        У меня не совсем такая, но я сейчас далеко от неё, не могу посмотреть точную модель. С пирамидкой реально руки гораздо меньше устают, когда долго не отрываешься от клавиатуры.
  • 0
    Я так полагаю, что кнопки внизу слева можно легко поменять местами (они одинакового размера), включить в поставку особую прошивку. И можно добавить несколько кнопок с кастомными названиями, что-то вроде легкой кастомизации.

    И да, отсутствие кнопок f1-12 немного смущает. Одной рукой не запустить сборку проекта, нужно уже будет нажимтаь 3 разные клавиши одновременно.

    Но в целом идея хорошая. Сколько стоит? :)

    А еще — как управлять мышкой?
  • 0
    Кстати, еще важный момент: правую кнопку super лучше сделать такого же размера, как и соседние в нижнем ряду. Тогда ее тоже можно будет передвинуть в более удобное привычное положение (как command у макбуков)
  • +1
    А почему вы не выровняли столбцы кнопок?
    • –1
      Зачем? Замучаешься вслепую печатать.
      • +2
        Да вот как раз наоборот стало бы гораздо проще.
        • 0
          Это почти как перейти на Dvorak, потом не сможете пользоваться стандартными клавиатурами.
          • 0
            Сможете. У меня такая на работе (Truly Ergonomic), и обычная дома. Требуется от силы минута для адаптации.
            • 0
              Давно думаю на эту тему. Сейчас пишу на Natural Ergonomic майкрософтовской. Очень раздражает что Enter справа находится там, где слева Caps Lock, перемапленный в Control. Хочу Control и там и там, а Enter вообще где-нибудь в другом месте.

              Ссылка чего-то недоступна, она ещё в продаже? Truly Ergonomic я имею в виду. Мне кажется она бы решила мою проблему.
              • 0
                Ссылка у меня работает, в продаже есть. По сравнению с MS Ergo 4000 можно отметить ряд недостатков/особенностей:
                • Нет обратного наклона самой клавиатуры
                • Неудобное расположение стрелок/home/end/pgup/pgdn
                • Неудобное расположение альтов.
                • cherry mx без амортизационных колец. Если вы привыкли на мембранках прожимать клавиши до упора, то будет довольно неприятно поначалу
    • +1
      А почему вы задаете этот вопрос переводчику?
  • 0
    ESC для любителей Vim забыли.
  • 0
    Полную реализацию для устройства на основе LUFA можно взять здесь

    Нет ссылки.
  • +2
    Нет нампада, стрелочек, ESC, F-клавиш, блока insert-page down, но зато две кнопки Fn!

    Почему все самодельные клавиатуры всегда так сильно модифицируют раскладку и столько полезных кнопок выкидывают?
    • 0
      Потому что для этого и делают :)
  • 0
    Мда. Только хотел обрадоваться, что снова появилась нормальная разделяемая клавиатура, а тут…
    До сих пор пользуюсь BTC 8120 — прекрасная вещь. Ей бы клавиши с коротким ходом — цены бы ей не было. Аналогов до сих пор не встречал.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.