OS のキーボード配列が JIS キーボードの時の QMK Firmware の設定について
前置き
QMK Firmware は US 配列を前提にしたファームウェアなので、OS のキーボード配列を US キーボードにして US キーキャップを使う場合は、言語関係の問題は生じません。
しかし、OS のキーボード配列を JIS キーボードに設定すると、途端に言語関係の問題が生じます。対応方法は、US キーキャップを使う場合と JIS キーキャップを使う場合でそれぞれ違いますので、それぞれのパターンについて紹介したいと思います。
tl,dl
- JIS キーキャップを使う場合
- qmk_firmware/keymap_japanese.h at master · qmk/qmk_firmware を
keymap.c
の先頭で#include"keymap_jp.h"
して読み込んだ上で、KC_*
の代わりにJP_*
キーを使います。 - US キーキャップを使う場合
- この場合の方法は、次の2つです。
方法1
koktoh/jtu_custom_keycodes: Keycodes to use jis keycode in us keymap を使い、個別に対応が必要なキーを JU_*
キーに置き換えます。
ただし、!
や (
のように Shift キーを押しながら入力する記号類を直接入力する場合(例えば、Raise レイヤーで Q
を押したら !
が入力されるといったものです。)、qmk_firmware/keymap_japanese.h at master · qmk/qmk_firmware を使って JP_EXLM
等の形で指定する必要があります。1
方法2
Version 0.14.0 で導入された Key Overrides 機能と JP_*
キー を組み合わせてキーの挙動を変更するという方法です。
QMK Breaking Changes - 2021 August 28 Changelog
一見すると回りくどい方法ですが、JU_*
キーはキーリピートが効かないのに対し、この方法で設定したキーはキーリピートが効きますので、普通のキーの挙動に可能な限り近づけることができます。
解説
追加ライブラリまたは設定が必要な理由
keymap.c
で KC_A
と指定したキーをタイプした時、キーボードから PC に送信されるデータは A
という文字に応じたキーコードです。そして、OS は受け取ったキーコードに応じた文字をアプリケーションに渡します。2
問題は、このキーコードと文字の対応関係が言語によって異なっており、例えば、[
に当たる KC_LBRC
のキーコードを送信しても、OS のキーボード配列が JIS になっていると OSは =
を返してしまいます。
このような取り違えが生じるキーがいくつかありますので、OS のキーボード配列を JIS にした状態でキーキャップの印字通りに入力したい場合、何らかの変換処理が必要となります。
上記で紹介した qmk_firmware/keymap_japanese.h at master · qmk/qmk_firmware と koktoh/jtu_custom_keycodes: Keycodes to use jis keycode in us keymap を使う方法は、ライブラリに変換処理を任せる方法で、Key Overrides を使う方法は自力で変換処理を行うという方法です。
実装
ここからは具体的な実装を紹介していきます。なお、OS のキーボード配列が JIS 配列になっていることが前提です。
JIS キーキャップを使う場合
qmk_firmware/keymap_japanese.h at master · qmk/qmk_firmware を keymap.c
の先頭で #include"keymap_jp.h"
して読み込んで、KC_*
の代わりに JP_*
キーを使います。
以下のキーマップは、OS のキーボード配列とキーキャップを JIS にする前提で設計された 自作キーボードキット『JISplit89』ビルドガイド - 自作キーボード温泉街の歩き方 のデフォルトキーマップですが、JIS キーキャップ独自のキー(下の図の赤枠のキー)のキーコードに JP_*
キーコードを指定しています。
1[_QWERTY] = LAYOUT(
2 //,-----------------------------------------------------| |--------------------------------------------------------------------------------.
3 KC_ESC, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_INS, KC_PSCR,
4 //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------|
5 LT(_ADJUST,KC_ZKHK),KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, JP_MINS, JP_CIRC, JP_YEN, KC_BSPC, KC_DEL,
6 //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------|
7 KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, JP_AT, JP_LBRC, KC_ENT, KC_HOME,
8 //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------|
9 KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, JP_SCLN, JP_COLN, JP_RBRC, KC_END,
10 //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------|
11 KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, JP_BSLS, KC_PGDN, KC_UP, KC_PGUP,
12 //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------|
13 KC_LCTRL, KC_LGUI, KC_LALT, KC_MHEN, KC_SPC, KC_SPC, KC_SPC, KC_SPC, KC_HENK, KC_KANA, KC_APP, KC_LEFT, KC_DOWN,KC_RIGHT
14 //`-----------------------------------------------------| |--------------------------------------------------------------------------------'
15),
このように、JIS キーキャップと US キーキャップで印字が異なるキーについて、JP_*
キーコードを使用して違いを吸収しています。
US キーキャップを使う場合
JU_*
を使う場合
koktoh/jtu_custom_keycodes: Keycodes to use jis keycode in us keymap を使い、;
や '
のように Shift キーを使わなくてもキーキャップの印字通りに入力されないキーや、Shift キーを使った場合に印字通りに入力されない 2
や 6
について、JU_*
キーを使って違いを吸収しています。
1[_QWERTY] = LAYOUT(
2 KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, JU_GRV, \
3 KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, JU_SCLN, JU_QUOT, \
4),
5[_LOWER] = LAYOUT( \
6 KC_1, JU_2, KC_3, KC_4, KC_5, JU_6, JU_7, JU_8, JU_9, JU_0, JU_BSLS, \
7 KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, JU_MINS, JU_EQL, JU_LBRC, JU_RBRC, _______, \
8),
なお、JU_*
キーを使う場合、ライブラリとして読み込む方法とコードをコピペして使う方法の2つがあります。jtu_custom_keycodes/default/README.md に手順が記載されていますので、そちらを確認して実装します。
Key Overrides を使う方法
Key Overrides の詳細は、QMK Firmware の公式ドキュメントの暫定日本語訳 で確認できますが、この機能を簡単に説明すると、修飾キーとキーの組み合わせを上書きして別のキーを送信できるようにするというものです。PC に送信するキーコード自体を変更できますので、US と JIS の違いを吸収するのにうってつけの機能となります。
例えば、OS のキーボード配列が JIS だと Shift + 2
は "
と解釈されますが、Key Overrides を使うと Shift + 2
を JP_AT
に変換して PC に送信できますので、Shift + 2
を押して @
を表示させるということができるようになります。このように修飾キーとキーの組み合わせを上書きすることで、US キーキャップの印字通りの入力を実現できるようになります。
ここから具体的なコードを示しますが、まず、Key Overrides を使うには rules.mk
に KEY_OVERRIDE_ENABLE = yes
を追加する必要があります。
1KEY_OVERRIDE_ENABLE = yes
次に、keymap.c
に Key Overrides の対象となるキーの組み合わせなどを定義した key_override_t
構造体を初期化します。
1// `shift + '` を上書きして `"` を送信する
2const key_override_t JP_QUOT_key_override =
3 ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, JP_QUOT, S(KC_2), ~0, MOD_MASK_CAG);
4
5// `shift + 2` を上書きして `@` を送信する
6const key_override_t KC_2_key_override =
7 ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_2, KC_LBRC, ~0, MOD_MASK_CAG);
初期化で使っている ko_make_with_layers_and_negmods
初期化子は、最もオプションが多い初期化子で、Key Overrides を使うレイヤーや押してはいけない修飾キーを指定できます。1つ目の設定に指定している引数の内容は次のとおりです。
MOD_MASK_SHIFT
- Key Overrides を使うために押す必要がある修飾キーに Shift キーを指定しています。キーの指定は、
MOD_BIT(KC_RSFT)
のようにMOD_BIT()
を使うか、モッドマスク(MOD_MASK_CTRL
等)を使って行います。 JP_QUOT
- Key Overrides を使うために押す必要があるキーに
'
を指定しています。なお、KC_QUOT
ではなくJP_QUOT
としているのは、キーマップでKC_QUOT
の代わりにJP_QUOT
を指定しているためです。 S(KC_2)
"
を送信するためのキーコードを指定しています。OS のキーボード配列が JIS の場合に"
を送信するにはS(KC_2)
と指定する必要がありますが、JP_DQUO
と指定しても OK です。ここは好みで決めます。~0
- 全てのレイヤーで Key Overrides を使うという指定です。レイヤー i でこのオーバーライドを使うには、i 番目のビット
(1 << i)
を設定します。 MOD_MASK_CAG
- Key Overrides を使うときに押していてはいけない修飾キーに
control
、windows
、alt
キーを指定しています。なお、押していてはいけない修飾キーを指定する場合、shift
、control
、windows
、alt
の4種類の修飾キーを「押す必要がある」と「押していてはいけない」のどちらかに指定する必要があります。指定漏れや重複指定があると Key Overrides が無効化されます。
それから、key_overrides
配列の要素に key_override_t
構造体を指定します。key_overrides
配列は NULL で終了し、key_override_t
値へのポインタ (const key_override_t **) を含みます。
1const key_override_t **key_overrides = (const key_override_t *[]){
2 &JP_QUOT_key_override,
3 &KC_2_key_override,
4 NULL // Null terminate the array of overrides!
5};
あとは、これを必要なキーの数だけ繰り返していきます。私が行った設定をキーマップと合わせて以下に示します。
1// 全レイヤーで Key Overrides を有効化
2// Ctrl, Win, Altキーを押していたら Key Overrides を発動しない
3const key_override_t JP_GRV_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, JP_GRV, S(KC_EQL), ~0, MOD_MASK_CAG);
4const key_override_t KC_SCLN_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_SCLN, KC_QUOT, ~0, MOD_MASK_CAG);
5const key_override_t JP_QUOT_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, JP_QUOT, S(KC_2), ~0, MOD_MASK_CAG);
6const key_override_t KC_2_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_2, KC_LBRC, ~0, MOD_MASK_CAG);
7const key_override_t KC_6_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_6, KC_EQL, ~0, MOD_MASK_CAG);
8const key_override_t KC_7_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_7, S(KC_6), ~0, MOD_MASK_CAG);
9const key_override_t KC_8_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_8, S(KC_QUOT), ~0, MOD_MASK_CAG);
10const key_override_t KC_9_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_9, S(KC_8), ~0, MOD_MASK_CAG);
11const key_override_t KC_0_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_0, S(KC_9), ~0, MOD_MASK_CAG);
12const key_override_t JP_BSLS_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, JP_BSLS, S(KC_INT3), ~0, MOD_MASK_CAG);
13const key_override_t KC_MINS_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, KC_MINS, S(KC_INT1), ~0, MOD_MASK_CAG);
14const key_override_t JP_EQL_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, JP_EQL, S(KC_SCLN), ~0, MOD_MASK_CAG);
15const key_override_t JP_LBRC_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, JP_LBRC, S(KC_RBRC), ~0, MOD_MASK_CAG);
16const key_override_t JP_RBRC_key_override = ko_make_with_layers_and_negmods(MOD_MASK_SHIFT, JP_RBRC, S(KC_NUHS), ~0, MOD_MASK_CAG);
17
18const key_override_t **key_overrides = (const key_override_t *[]){
19 &JP_GRV_key_override,
20 &KC_SCLN_key_override,
21 &JP_QUOT_key_override,
22 &KC_2_key_override,
23 &KC_6_key_override,
24 &KC_7_key_override,
25 &KC_8_key_override,
26 &KC_9_key_override,
27 &KC_0_key_override,
28 &JP_BSLS_key_override,
29 &KC_MINS_key_override,
30 &JP_EQL_key_override,
31 &JP_LBRC_key_override,
32 &JP_RBRC_key_override,
33 NULL // Null terminate the array of overrides!
34};
35// key override setting end
36
37/* keymap */
38const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { \
39 [_QWERTY] = LAYOUT(
40 KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, JP_GRV, \
41 KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, JP_QUOT, \
42 KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT, \
43 KC_LANG2, KC_ESC, KC_LALT, KC_LGUI, LOWER, KC_SPC, KC_BSPC, RAISE, KC_RGUI, KC_RALT, KC_RCTL, KC_LANG1 \
44 ),
45
46 [_LOWER] = LAYOUT( \
47 JP_ZKHK, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, JP_BSLS, \
48 _______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_MINS, JP_EQL, JP_LBRC, JP_RBRC, _______, \
49 _______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_APP, JP_LPRN, JP_RPRN, _______, _______, \
50 _______, _______, _______, _______, _______, _______, KC_DEL, _______, _______, _______, _______, _______ \
51 ),
52
53 [_RAISE] = LAYOUT( \
54 KC_AGRV, KC_NO, KC_PGUP, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_INS, KC_NO, KC_PSCR, KC_NO, \
55 _______, KC_HOME, KC_PGDN, KC_END, KC_NO, KC_NO, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, KC_NO, KC_NO, \
56 _______, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, _______, _______, _______, _______, \
57 _______, _______, _______, _______, _______, KC_ENT, _______, _______, _______, _______, _______, _______ \
58 ),
59
60 [_ADJUST] = LAYOUT( \
61 RESET, JP_EXLM, JP_AT, JP_HASH, JP_DLR, JP_PERC, JP_CIRC, JP_AMPR, JP_ASTR, JP_LPRN, JP_RPRN, KC_NO, \
62 DEBUG, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_CAD, KC_APSCR, KC_NO,\
63 _______, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, _______, _______, _______, _______, \
64 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
65 )
66};
S(JU_2) の形で指定したキーを押しても何も送信されませんので、
JP_EXLM
等のキーコードを使う必要があります。 ↩︎PC に送信されるキーコードは qmk_firmware/keycode.h at master · qmk/qmk_firmware で定義されています。このキーコードは USB 規格 の HID Usage Table で定められているコードを基にして、現在の OS では使われないコード (0xA5-0xDF) にメディアキー等が割り当てられています。 ↩︎