Конфигурация вакидзаси
В прошлых постах (про идею, про сборку) рассказывал про вакидзаси, но так и не написал статью про то, как пользоваться клавиатурой. На момент написания статьи она собрана, запрограммирована, работает.
Главное к клавиатуре — раскладка. Я пока не определился с ней до конца. Очень важно, чтобы было легко её настраивать. В этой статье расскажу, как это делалось.
Как обрабатываются аккорды
Функция void exec_chord(chord currc)
вызывается для исполнения аккорда. С
точки зрения прошивки, аккорд (chord
) — число из 11 битов. Каждый бит
соответствует одной кнопке. Минимально доступный размер числа, 1 байт, слишком
маленький. Следующий, 2 байта, слишком большой, но ладно уж.
typedef uint16_t chord;
Идея обработки аккордов проста: берём аккорд, сравниваем с аккордами из раскладки, что есть, вот его берём и исполняем. Рассматривал другой подход: есть массив, а индексы соответствуют аккордам, но я его посчитал дурацким.
Специально для этого в си есть конструкция switch
. В целом, примерно так
должна выглядеть обработка:
void exec_chord(chord currc) {
switch (currc) {
case 0b10000000000: {
// ...
break;
}
case 0b01000000000: {
// ...
break;
}
...
}
}
Вообще, реальный код сложнее, но я опускаю подробности. Статья не про это. Если
интересна реальность, прошу пожаловать в репозиторий на
гитхабе (смотреть файл layout.h
).
Ну так вот, в итоге получается очень много case
-выражений. Мне вручную их
писать не хотелось, значит надо это дело передать кому-нибудь.
Первая итерация: m4
Эта итерация началась задолго до того, как я начал собственно делать клавиатуру. Также она началась решительно сразу после того, как я бросил свой макропроцессор Агидель.
m4
— доисторический макропроцессора, развитие макропроцессор m3
(ожидаемо,
улучшенная версия m4
называется m5
), установленный на все UNIX-системы (а
другими пользоваться мне не позволяет религия).
На сайте GNU есть хороший мануал.
Суть такая: есть файл, в котором я своими макросами описываю раскладку, а потом она магически самораскрывается в код. Я преуспел в этой итерации. Вот такой код раскрывался в то, что надо:
start_layout
mode_latin
single_(O, A, T, E,
H, S, N, I,
SPACE, DOT, COMMA)
shifted_single_(O, A, T, E,
H, S, N, I,
_, _capslock, _)
symbol_single_(GRAVE, APOSTROPHE, EQUAL, MINUS)
end_mode
end_layout
Красиво и круто. Но язык m4
мудрёный очень, код на нём превращался в кашу
решительно сразу. Вот исходный код некоторых макросов:
define(`single_count', `10')
define(`single_helper',
`if_key($1, `match(eval(BV($2), 2, 11),
`send_scancode (KEY_$1);') LF')')
define(`single_helper2',
`ifelse($#, `1', `single_helper($1, single_count)',
`single_helper($1, single_count)define(`single_count', decr(single_count))dnl
single_helper2(shift($*))')')
define(`single_', `single_helper2($*)')
Вторая итерация: графический редактор
Все любят графические редакторы! Решил сделать его в формате веб-приложения. Стек: Ruby, Sinatra, Bootstrap, Typescript. В целом, кое-что сделал:
Назвал эту программу остроумно: Wakizashi sharpener. Эту программу было интересно разрабатывать. Я узнал много нового и впервые что-то написал на тайпскрипте. Потом я на нём, кстати написал, симулятор вакидзаси и ввод цифр бинарно.
Потом мой импульс любви к графическим редакторам сошёл на нет.
Третья итерация: непонятно что
В это время приступил к собственно разработке вакидзаси. Воспользовался старыми
макросами первой итерации, и потом их продукт редактировал вручную. Понял, что
так нельзя. Делать ещё больше непонятных макросов m4
не хотел, поэтому решил
выбрать другой формат для конфига.
Четвёртая итерация: YAML
YAML Ain’t Markup Language не язык разметки, это как JSON, но круче. Отличается чистеньким синтаксисом как в питончике, на отступах, но при этом в него можно смело вставлять кусочки на JSON.
В общем, вот такая штука:
---
name: Wakizashi Default Latin+Cyrillic
layers:
latin:
single:
normal: [
o, a, p, e,
h, s, n, i,
' ', ',', '.'
]
shift: [
O, A, P, E,
H, S, N, I,
]
symbol: [
8, 4, 2, 1,
':', '"', "'", ";"
]
function: [
mod_ctrl, mod_altl, mod_shift, mod_super,
_left_arrow, _down_arrow, _up_arrow, _right_arrow
]
macro: [
_, _, _, _,
'a ', 'in ', 'that ', 'be '
]
vertical:
normal: [r, l, d, u]
shift: [R, L, D, U]
symbol: [
'-', _, '(', ')'
]
function: [
_page_down, _page_up, _tab, _esc
]
macro: []
control: []
# ...
Программка на руби её хитро превращала в код на си. Работало, юзал. Специальные символы оборачивались в кавычки, ещё были специальные соглашения:
- Если элемент начинался с
mod_
, этот аккорд включает соответствующий режим модификатора. - Если он представлял из себя нижнее подчёркивание, то этот аккорд пропускался.
- Если он с него только начинался, то отправлялось что-нибудь хитрое.
- Если это был массив, то его элементы конкатились, и это вставлялось в код на си прямо так.
Проблема: не понятно, что чему соответствует.
Пятая итерация: CSV
Раз не получалось использовать конфиг как шпаргалку, начал рисовать шпаргалку. Нарисовал пару строчек (хотя вернее сказать «написал»). Присмотрелся. Да это же CSV!
Comma separated values — самый примитивный
формат представления табличных данных. Каждая строчка файла — строчка таблицы.
Столбики отделяются чем-нибудь. Из названия понятно, что обычно это запятая. Я
взял же таб, который \t
, потому что он невидимый более-менее и при отрисовке
всё выглядит довольно таблично.
chord no t1 t2 t3 t23
// Single presses
0000 , .
0000
1000 o O 8 mod_shift
h H : _left_arrow
0100 a A 4 mod_altl
s S " _up_arrow
0010 p P 2 mod_ctrl
n N ' _down_arrow
0001 e E 1 mod_super
i I ; _right_arrow
// Vertical presses
1000 r R - _page_down
1000
0100 l L _page_up
0100
0010 d D ( _tab
0010
0001 u U ) _esc
0001
Чтобы писать ещё меньше текста, сделал так, что если в первом столбике только одна строчка аккорда, то справа описывается сразу два аккорда: верхний и нижний.
Формат настолько очевидный, что программу для обработки написал буквально в течение дня (а для прошлых итераций я корячился заметное время).
Также такой конфиг можно использовать как шпаргалку!
Каждый слой раскладки (латинский и кириллский) описывается в отдельном файле (на момент создания файла за кириллский пока не взялся), а всё вместе собирается мейкфайлом (тоже крутая технология, как выяснилось).
Как заключение
Какая итерация понравилась анонимному читателю больше всего? Мне, понятное дело, последняя. Кстати, почти весь конфиг написал с вакидзаси. Столкнулся с резкой неэргономичностью некоторых кнопок. Но это мелочь, конечно же. Я очень доволен тем, как всё получилось :)