2019年06月19日

【QMK】ファームウェアでのキーマップ変更入門

「QMKファームでいくらでもキーマップ変えられるよ」
って言っても、なかなか難しい。
僕が理解する範囲でしかないけど、まとめておきました。


簡単な順:
1 今あるキーを入れ替える
2 レイヤーを加える
3 マクロを加える
4 あるキーを押しながらあるキーを押すと何か
5 同時押し


そもそも、QMKの仕様が僕は気に行っていない。
あるキーを、
「単打で押したときと、長押ししたとき」で使い分ける仕様だからだ。
そのようにふるまうキーはデフォルトではないので、
直感に反するというのがその理由。

内部にTAPPING_TERMという定数をもっていて(デフォは200。単位はミリ秒)、
キーを押したとき、
TAPPING_TERM以内に離したら単打(TAP)、
キーを押しっ放しにしたままTAPPING_TERMが過ぎたら押しっ放し(HOLD)、
というアルゴリズムで動いている。

これは直感的操作に反する。
僕らが使うキー操作は、
キーを押したとき、
(キーリピートが発生しない限り)どんなに押してから離しても単打、
押しながら何かを押せば、TAPPING_TERM以内に成立しても、
シフトキーと何かのように扱いたい
のはずだ。

実はそのように書き換えることが出来る。
config.hに、
#define PERMISSIVE_HOLD
#define RETRO_TAPPING
の二行を加えるとよい。

前者は、TAPPING_TERM以内にHOLDに設定されたキーを押しても、
TAPとみなさずHOLD扱いする
(つまりデフォルトではTAP二打扱いになる)設定。
後者は、TAPPING_TERMを過ぎて(他に何も押さず)キーを離してもTAPのキーを出力する
(デフォルトでは一度HOLD判定するとTAPにもどらない)設定。

まずこれをやってから、次の設定に挑むのがおすすめだ。

ちなみに、TAPPING_TERMは、
同様にconfig.hに、
#define TAPPING_TERM 100
などのような一行を加えることで変更できる。
動的変更ができるかどうかはわからない。



1 今あるキーを入れ替える

これは多くの人がやることで、
これをもってキーマップいじりという人もいるだろう。
だから「QMKをいじればキーマップやり放題」というデマが流れていると思う。
(正確にはマスターすれば何でもできるのだろうが、
全部をマスターするのは、初心者には難しいと思う。
実質なんでもできるわけではない)

僕はこれは狭義のキーマップ入れ替えと考えている。
メジャーな日本語配列をこれで実装出来るわけではないし、
マクロやレイヤー切り替えなどを含まないからだ。

さて。
keymap.cをみよう。

いじる前の、きちんと動いていたものは別フォルダに保存しておくこと。
動かないマップを作ってしまったとき、少なくとも元に戻ることが出来る。
(同様に、作ったキーマップは都度ナンバリングして、
別フォルダにコピーしておくことを勧める。
少なくとも一回前に動いていたやつに戻れる)

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
...
};

の...の部分がキーマップ本体。

...の部分はレイヤーごとに定義されていて、

[〇〇〇〇] = LAYOUT( \
..., ..., ... ...,\
...
..., ... ...\
),

の形で定義されている。,\のありなしに注意。
〇〇〇〇がレイヤー名、...に当るところにキーを直接書けば、
(キーコードが定義されているキーならば)そのキーがそこに置かれることになる。
ちなみに、分り易くなるように、KC_が頭につくように名前がついている。

キーコード一覧は
https://github.com/qmk/qmk_firmware/blob/master/docs/keycodes_basic.md
で。

なおAliasは略称で、どっちを使ってもよい。
文字数が少ないので、キーマップ定義内ではAliasを使うのが一般的。
(しかしあとで使うマクロ内ではAliasが使えないことに注意)

少なくとも今動いているキーマップから、
動かすだけならうまく行くはず。
ないキーをこの一覧から足したりすることも出来るはずだ。

Modifierの定義は、
「単打では機能せず、これを押しながら何かを押すと機能するキー」の事。
(ただしGuiとAltは例外)
GuiはWinではWinキー、Macではcommandキー。
AltはWinではAltキー、MacではOptionキーのこと。
LRは左右を示すが、
基本Lだけ使っていればよい。キーボード右にあるシフトキーでも、LSFTでよい。
(RALTなどはヨーロッパ系でAltGキーに使われたりする。
その為にRは避けておいたほうが混乱がない)


また、日本語JISで特有のキーがあり、
それ用に定義されているキーもあるよ。
変換無変換、¥など。
ちなみに全角半角キーは、グレイヴアクセントKC_GRAVE
で、OSレベルで代用することになっている。
(AliasでKC_GRV, KC_ZKHKのふたつの表記があるのはそのため)

これらのルールを守れば、
US基準のQMKといえど、日本語入力用のキーマップも作れるので、
一個一個置いていけばいいだけのことだ。

たとえばJIS記号配置のキーマップを作ることだって、
面倒だけどやれば出来るよ。
(ちなみに自分のPCが、現在USレイアウトなのかJIS配列なのかは確認しよう。
シフト+2を押してみて、@が出たらUS、"が出たらJIS。
そしてこれはマシンのローカルな設定でどちらでも出来る。
USとJISは主に記号配置が異なる。
詳しくは調べてください)


また、KC_にはブラウザコマンドやボリュームコマンドなどの、
特殊コマンドがあるので、
これらをキーボードから打てるようにすることも可能だ。

また、特殊なものがふたつ。
KC_NO(XXXXXXX)何もしない(あえて殺すとき。テストに使ったりする)
KC_TRANSPARENT(KC_TRNSまたは_______) 無視
上のレイヤーにいるとき、
下のレイヤーの同じ位置のキーを有効にするTRNSはよく使うので、
空いてればTRANSにしておくとよいだろう。


これらのものは、すべて単打で定義される。
単打キーだけのキーボードであれば、
これで全部実装出来るはずだ。
これをもってキーマップを自由にいじる、
と考えてもよいが、以下のものは覚えて損はない。

「単打は単打キー、押しながらだとモデファイア」
MT()を使う。モデファイアはKC_の代りにMOD_に。
MT(MOD_LSFT, KC_SPC) 単打でスペース、押しながらでシフト(SandS)
MT(MOD_LCTL, KC_ENT) 単打でエンター、押しながらでコントロール
などのように設定できる。

また、単打で何かのキーKC_、
押しながらだと別レイヤーという設定も可能で(LT())、
それに関しては後述する。



2 レイヤーを加える

大体の自作キーボードのキーマップは、
4レイヤーで構成されている。
default, lower, raise, ajdustだ。
Ergo42ではBASE, META, SYMB, GAMEの4レイヤーだが、
名前が違うだけで機能はおなじだ。

ひとつめがデフォで、
ふたつめ、みっつめが、レイヤーキー1,レイヤーキー2を押しながらのレイヤー、
よっつめが、レイヤーキーを両方押しながらのレイヤー、
という風に定義されている。
これはほぼ習慣のようなもの。

QMKは、全部で32レイヤーを持つことが出来る。
(逆に32しかない!)

レイヤー名は、

#define _QWERTY 0
#define _LOWER 1
#define _RAISE 2
#define _ADJUST 16

のような部分で、レイヤー番号とともに定義する。
(これはminiAxeの定義部で、
_が頭にくるものはレイヤー名という決まりで書かれている)
0番のレイヤーが電源がオンになったときに読み込まれるレイヤーだ。

レイヤーのオンオフは、
layer_on(〇〇〇〇);
layer_off(〇〇〇〇);
の関数で行えるが、これはそのままキーマップ内に記述できないので、
マクロ内に書くことになる。

たとえば、
英語配列をデフォルトに、
IMEONマクロキーを押したら日本語レイヤーに
(IMEOFFマクロキーを押したら英語に)、
さらに日本語レイヤーでは、
たとえば月配列のように、
DKを押した後一回だけシフトレイヤーをONにする、
などのようにつくることが出来る。
アドバンスキーコード、
https://github.com/qmk/qmk_firmware/blob/master/docs/feature_advanced_keycodes.md
の、OSL()を使えばいいはず。
マクロに関しての説明は次に。



3 マクロを加える

色々なマクロを定義できる。
一個のキーを押したときに、
複数の文字(モデファイアを含む)をだしたり、
レイヤーを切り替えたりすることが可能だ。

マクロ名は、

enum custom_keycodes {
QWERTY = SAFE_RANGE,
LOWER,
RAISE,
ADJUST,
};

のように定義する。
= SAFE_RANGE
の部分はよく分からないが、最初のマクロにつけとくと問題がない。
また、//のあとにコメントを書けるので、
どんなマクロを定義したのかわかりやすくしておくことを勧める。
この例では、

enum custom_keycodes {
QWERTY = SAFE_RANGE, //ベースのqwerty配列
LOWER, //Lowレイヤー、数字と制御系
RAISE, //Raiレイヤー、記号系
ADJUST, //Fnキーとボリューム調整
};
などのように書いておくと便利だ。

これはレイヤー切替のマクロによく使われる。
たいていの自作キーボードのキーマップには、
これらのレイヤー切り替えのコードが書いてあるので、
それを参考にしていくとよいだろう。

マクロの定義部分はこうなっている。

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case 〇〇〇〇:
if (record->event.pressed) {
......(押されたときの処理)
}
   ( else { 離したときの処理 })
return false;
break;
case XXXX:
......
}
return true;
}

のフォーマットで書かれる。
レイヤー切り替えマクロでは、
レイヤーオンオフなどを制御するコードをここに書くとよい。
(たいていすでに書かれているものをコピペすれば動くはず)


IMEのオンオフ:
windowsではIMEの設定で、
無変換にIMEOFF、変換にIMEONを割り付けておけば、
KC_MHEN、KC_HENKをキーマップ内にいれればよい。
どうしてもトグルにしたければ、グレイヴキーを使えばいいだろう。

マクロ内だと、
tap_code(KC_MHEN);
tap_code(KC_HENK);
でそれぞれのキー入力をしたことになる。

Macでは、それぞれ
tap_code(KC_LANG2);(英数)
tap_code(KC_LANG1);(かな)
だ。

ひとつのキーボードでwinとmacを共用したければ、
何かフラグの変数をつくり、
winmacを明示的にキーから入力し、
それに応じてマクロ内で処理を変える、
などをcで組めばよいことになる。


複数の文字を出力:

SEND_STRING();
関数を使う。
""で囲まれた文字列を出力、
または、SS_TAP(X_ENTER)のように、制御コードも出力できる。
このときAliasを使えないのは、糞仕様だなあ。
詳しくはSEND_STRING();を調べること。

また、これでユニコード文字も出せるはずなんだけど、
(そういう仕様であるようにマニュアルからは読める)
うまく行かなかった。
〇や……や【】≪≫などの記号を出したいが、それが出来る人募集中。



4 あるキーを押しながらあるキーを押すと何か

マクロ内の、
case 〇〇〇〇:
if (record->event.pressed) {
......(押されたときの処理)
}
の部分に、レイヤーオンなど、何かを書くとよい。
たとえば。
if (record->event.pressed) {
set_oneshot_layer(LAYER1, ONESHOT_START);
} else {
clear_oneshot_layer_state(ONESHOT_PRESSED);
}
などでカタナ式を動かしている。

DvorakJではただ出力されるものを並べておけば良かったが、
qmkはc++言語なので処理を全部関数で書かなくてはならない。
従って、どれだけ関数を知ってるかとか、
どれだけ処理をうまくc++で書けるか、
ということに依存してしまうことに注意されたい。
(出来ないならデフォルトのqwertyをqmkで設定して、
そのあとDvorakJでキー変更してもいいんだよ)



5 同時押し

同時押しにはいくつかのロジックがある。
「ABを〇ミリ秒以内に押せばよい(離しは問わない)」ならば、
comboを使えば出来るはず(僕は研究していない)。
新下駄などはこれで実装できるはず。すごい手間がかかるけど。

「Aを押しながらB、Bを押しながらA」の双方向シフトで定義することも出来て、
それはeswaiさんがNICOLAや薙刀式で実装しているので、
参考にしてほしい。
https://github.com/eswai/qmk_firmware/blob/master/keyboards/crkbd/keymaps/nicola/keymap.c
https://github.com/eswai/qmk_firmware/tree/master/keyboards/crkbd/keymaps/naginata


とりあえず僕がわかっていることを書いた。
参考までに。
多分もっとプログラミングが出来る人がいるはずで、
そういった人のソースコードをみたほうがいいかもだ。
posted by おおおかとしひこ at 17:20| Comment(0) | カタナ式 | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

※ブログオーナーが承認したコメントのみ表示されます。