この投稿は ErgoDox Advent Calendar 2016 の 16日目の記事です。
しました
ErgoDoxにモールスコード入力ボタンを実装しました pic.twitter.com/8nbV07FLi4
— みやおか (@miyaoka) 2016年12月27日
aからz、数字とスペースが出せます。
CapsLockかけとけば大文字に、日本語IMEオンにしておけばローマ字入力もできます。
できますと言っても実用性が無いことは分かりますよね。
なぜ
ErgoDoxはファームウェアいじれるんだから、もうちょいファームウェア的なネタを書きたいなと思ったので
どうだったか
- モールスコードの入力が難しくて何度も撮り直した…。もっとトンツートンツーかっこよくキメたい
- C言語よく分からなくてバッファーオーバーランした…。軽量言語ばっかり使っててごめんなさい…
実装
Merge branch 'morse' · miyaoka/qmk_firmware@9f2dcde
#define MORSE_TERM_SHORT 120
#define MORSE_TERM_CHARA MORSE_TERM_SHORT * 3
#define MORSE_TERM_WORD MORSE_TERM_SHORT * 7
短点の長さを120ms、文字間をその3倍、単語間を7倍で設定してます。
この間隔をもっと短くすればもっとかっこよくトンツーできるんじゃないかと思います。
case MORSE:
if (record->event.pressed) {
last_morse_timer = 0;
return false;
break;
}
if (!hold_timers[record->event.key.row][record->event.key.col]) {
return false;
break;
}
morse_el = timer_elapsed (hold_timers[record->event.key.row][record->event.key.col]) < MORSE_TERM_SHORT
? morse_short
: morse_long;
strcat(morse_buffer, morse_el);
last_morse_timer = timer_read();
dprintf("%s", morse_el);
return false;
break;
モールス入力用のカスタムキーの処理をここでやってます。
hold_timersってとこには富豪的に全キーの押下タイマーを格納してるんで、そこでリリース時にホールド時間から短点か長点かの判定して入力バッファに追加してます。
で、最後にリリースしたタイミングをここで記録しておきます。
void process_morse(void) {
if (last_morse_timer == 0){
return;
}
uint16_t t = timer_elapsed (last_morse_timer);
// type space
if (MORSE_TERM_WORD < t){
type_code(KC_SPC);
dprint("\n");
last_morse_timer = 0;
return;
}
if (t < MORSE_TERM_CHARA || morse_buffer[0] == '\0'){
return;
}
// type chara
int i;
for(i = 0; i < 36; i++) {
if (strcmp(morse_codes[i], morse_buffer) == 0) {
dprint(" ");
type_code(KC_A + i);
break;
}
}
dprint("\n");
morse_buffer[0] = '\0';
}
で、毎フレーム呼んでる処理がここ。(って言ってもちゃんと調べてないのでキーボードはどんな更新頻度で動いているのか知らない…。)
最終リリースタイミングからの経過時間を見て、単語間の長さを過ぎたらスペース出力して終了。
文字間の長さを過ぎたらバッファしておいたコードから文字を出力します。
どうなのか
短点に対して長点の長さは3倍というのがモールス信号の仕様みたいなんですが、
- 短点の判定は短点時間以下
- 長点の判定はそれ以上
という処理にしてるので、3倍とか関係無くなってるんだけどどうすれば良かったのか…。
あとコードの判定は文字配列でやってるのが鈍くさい。トンツーだからバイナリでいいじゃんと思ったけど、実際はトン・ツー・無だから2進じゃいけなそうなんですがどうするのがいいんでしょうか。