日本語VDI環境向けにascii配列の日本語キーボードを作る

# VDI環境でも英語キーボードを使いたい

## 日本語キーボードしか許されないVDI環境って辛くないですか？

在宅勤務の場合VDI環境で作業しなくてはいけない企業にお勤めで、VDI環境に英語キーボードドライバをインストールできないために泣く泣く日本語キーボードで作業している人を幸せにしたい。

## VDIには日本語キーボードに見えて、配列は英語のキーボードを作ればいい！！
配列は英語配列だけれども、USB側からは日本語キーボードに見えるキーボードを作ればうまくいくはず。
あわせてxkeymacsでやっているようなemacsキーバインドの一部も実装する。

qmkの使い方は、わかりやすい記事がたくさんあると思うので今回はキーマップ作成時の工夫の部分を中心に記載する。

最後にtada68で使っているキーマップのソースを載せるので適宜修正して幸せになってほしい。


## キーボードの選択

aliexpressでtada68というキーボードを選んだ。

選択理由は以下のとおり。

* qmk対応
* 配列が英語配列（当然）
* その他の配列も良さそう

半田づけが面倒なので完成品を選んだ。キースイッチはいろいろ好みがあると思うけれど、音が静かといわれるピンク軸を選んだ。

ただ、ピンクといえ決して無音ではないし、どうせ自宅で作業するならばもっとメカニカルなやつを買えばよかったと、ちょっと後悔している。本当はHHKのタッチが好きなので、HHKがQMKに対応してくれれば一番なのだけれども、まあそこはやむなし。


## キーマップ作成時の工夫

キーマップを作るときの一番のポイントは、シフトを押したときにレイヤーを切り替えるようにすること。

qmkの普通の使い方ではaのキーを定義するだけで、シフトを押せば大文字のAになるようにしてくれる。

しかしそれでは;のシフトが+になってしまうのでascii配列の日本語キーボードは作れない。

そこでシフトを押した時にレイヤーを切り替えて、シフト専用レイヤーを定義する。Shift+aがAになるところから全部のキーを再定義する必要があるが完全に自由なキーレイアウトが作れる（ここが一番のポイント）

### レイヤーの設計

ベースレイヤー(_BL)とコントロールレイヤー(_CTRL)、ファンクションレイヤー(_FL)に加え、シフトをレイヤー(_SHIFT)として追加する。

```c
#define _BL 0
#define _SHIFT 1
#define _CTRL 2
#define _FL 3
```

### ベースレイヤ
通常の英語配列をベースに、左側のシフトをシフトレイヤー、コントロールをコントロールレイヤーへのトリガーへ変更している。

右側のシフトとコントロールは、ディフォルトのままにしておくと定義しわすれたキーがあったときに便利（ちゃんと全部定義すればいいのだけれどもね）

```c
  /* Keymap _BL: (Base Layer) Default Layer
   * ,-----------------------------------------------------------------.
   * |Esc |  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|Backsp |~ ` |
   * |-----------------------------------------------------------------|
   * |Tab  |   q|  w|  e|  r|  t|  y|  u|  i|  o|  p|  [|  ]|  \  |Del |
   * |-----------------------------------------------------------------|
   * |MO(_CTRL)| a|  s|  d|  f|  g|  h|  j|  k|  l|  ;|  '|Return |PgUp|
   * |-----------------------------------------------------------------|
   * |MO(_SHIFT)| z|  x|  c|  v|  b|  n|  m|  ,|  .|  /|Shift | Up|PgDn|
   * |-----------------------------------------------------------------|
   * |Ctrl|Win |Alt |         Space          |Alt| FN|Ctrl|Lef|Dow|Rig |
   * `-----------------------------------------------------------------'
   */
```

### シフトレイヤー
qmkでは通常はシフトレイヤーは定義しなくていいのだが、英語配列での出力がでるようにキーマップを変更する。
シフトを押したときの大文字も全部定義するところがポイント。

```c
  /* Keymap _SHIFT: (Shift Layer)
   * ,----------------------------------------------------------------.
   * |Esc | !|  @|  #|  $|  %|  ^|  &|  *|  (|  )|  _|  +|Backsp |~ ` |
   * |----------------------------------------------------------------|
   * |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  {|  }|  |  |Del |
   * |----------------------------------------------------------------|
   * |____   |  A|  S|  D|  F|  G|  H|  J|  K|  L|  :|  "|Return |PgUp|
   * |----------------------------------------------------------------|
   * |_____   |  Z|  X|  C|  V|  B|  N|  M|  <|  >|  ?|Shift | Up|PgDn|
   * |----------------------------------------------------------------|
   * |Ctrl|Win |Alt |        Space          |Alt| FN|Ctrl|Lef|Dow|Rig |
   * `----------------------------------------------------------------'
   */
```

### コントロールレイヤー

ここまででVDI環境で英語キーボードを使うということの当初の目的は達成するが、さらにemacsライクキーバインドを追加する。wordとかexcelでもemacs風にカーソルが移動できてとても楽しい。

実装したのは以下のキー。ごく一部しか実装していないけれど、これだけでもとても便利。さらにいろいろ追加してもよいと思う。



|キー  |動き  |ソース中コメント記述|
|---|---|---|
|Ctrl+b  |backward char  |<-|
|Ctrl+f  |forward char |->|
|Ctrl+p  |previous line  |Up|
|Ctrl+n  |next line  |Down|
|Ctrl+a  |move beginning of line  |Home|
|Ctrl+d  | delete char  |Del|


その他のキーはC(キーコード)と記述し、Ctrl＋キーのキーマップになるようにしてある。


```
[_CTRL] = LAYOUT_ansi(
  /* Keymap _BL: (Base Layer) Ctrl Layer
   * ,----------------------------------------------------------------------------------------.
   * |Esc  |   1|    2|    3|    4|    5|    6|    7|    8|    9|    0|    -|  =|Backsp |~ ` |
   * |---------------------------------------------------------------------------------------|
   * |Tab  |    Q|    W|    E|    R|    T|    Y|    U|    I|   O|   Up|    [|    ]|   \ |Del |
   * |---------------------------------------------------------------------------------------|
   * |___   |  Home|  S|   Del|  -> |  BS |    H|    J|     K|    L|    ;|    '|Return |PgUp|
   * |---------------------------------------------------------------------------------------|
   * |---   |    Z|   X|    C|  PgDn|  <-  |  Down|    M|     ,|    .|   /| Shift | Up|PgDn|
   * |---------------------------------------------------------------------------------------|
   * |Ctrl| Win| Alt |                        Space          | Alt|  FN| Ctrl| Lef| Dow| Rig |
   * `---------------------------------------------------------------------------------------'
   */
```


## 課題

すごく快適で幸せなのだが、どんどん廃人になっていくような気がしてならない。



## ソース全体

tada68用のqmk keymap.c全体は以下のとおり。

```c:keymap.c
#include QMK_KEYBOARD_H


#define JP_ZHTG KC_GRV   // hankaku/zenkaku|kanzi
#define JP_YEN KC_INT3   // yen, |
#define JP_CIRC KC_EQL   // ^, ~
#define JP_AT KC_LBRC    // @, `
#define JP_LBRC KC_RBRC  // [, {
#define JP_COLN KC_QUOT  // :, *
#define JP_RBRC KC_NUHS  // ], }
#define JP_BSLS KC_INT1  // \, _
#define JP_MHEN KC_INT5  // muhenkan
#define JP_HENK KC_INT4  // henkan
#define JP_KANA KC_INT2  // katakana/hiragana|ro-mazi

#define JP_MKANA KC_LANG1  // kana on MacOSX
#define JP_MEISU KC_LANG2  // eisu on MacOSX

// Aliases for shifted symbols
#define JP_DQT LSFT(KC_2)      // "
#define JP_AMPR LSFT(KC_6)     // &
#define JP_QUOT LSFT(KC_7)     // '
#define JP_LPRN LSFT(KC_8)     // (
#define JP_RPRN LSFT(KC_9)     // )
#define JP_EQL LSFT(KC_MINS)   // =
#define JP_TILD LSFT(JP_CIRC)  // ~
#define JP_PIPE LSFT(JP_YEN)   // |
#define JP_GRV LSFT(JP_AT)     // `
#define JP_LCBR LSFT(JP_LBRC)  // {
#define JP_PLUS LSFT(KC_SCLN)  // +
#define JP_ASTR LSFT(JP_COLN)  // *
#define JP_RCBR LSFT(JP_RBRC)  // }
#define JP_UNDS LSFT(JP_BSLS)  // _

// These symbols are correspond to US101-layout.
#define JP_MINS KC_MINS  // -
#define JP_SCLN KC_SCLN  // ;
#define JP_COMM KC_COMM  // ,
#define JP_DOT KC_DOT    // .
#define JP_SLSH KC_SLSH  // /
// shifted
#define JP_EXLM KC_EXLM  // !
#define JP_HASH KC_HASH  // #
#define JP_DLR KC_DLR    // $
#define JP_PERC KC_PERC  // %
#define JP_LT KC_LT      // <
#define JP_GT KC_GT      // >
#define JP_QUES KC_QUES  // ?



#define _BL 0
#define _SHIFT 1
#define _CTRL 2
#define _FL 3


const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  /* Keymap _BL: (Base Layer) Default Layer
   * ,-----------------------------------------------------------------.
   * |Esc |  1|  2|  3|  4|  5|  6|  7|  8|  9|  0|  -|  =|Backsp |~ ` |
   * |-----------------------------------------------------------------|
   * |Tab  |   q|  w|  e|  r|  t|  y|  u|  i|  o|  p|  [|  ]|  \  |Del |
   * |-----------------------------------------------------------------|
   * |MO(_CTRL)| a|  s|  d|  f|  g|  h|  j|  k|  l|  ;|  '|Return |PgUp|
   * |-----------------------------------------------------------------|
   * |MO(_SHIFT)| z|  x|  c|  v|  b|  n|  m|  ,|  .|  /|Shift | Up|PgDn|
   * |-----------------------------------------------------------------|
   * |Ctrl|Win |Alt |         Space          |Alt| FN|Ctrl|Lef|Dow|Rig |
   * `-----------------------------------------------------------------'
   */
[_BL] = LAYOUT_ansi(
  KC_ESC,    KC_1,   KC_2,   KC_3,   KC_4,   KC_5,   KC_6,   KC_7,   KC_8,   KC_9,   KC_0,   JP_MINS, JP_EQL, KC_BSPC, JP_GRV, \
  KC_TAB,  KC_Q,   KC_W,   KC_E,   KC_R,   KC_T,   KC_Y,   KC_U,   KC_I,   KC_O,   KC_P,   JP_LBRC, JP_RBRC, JP_BSLS, KC_DEL, \
  MO(_CTRL), KC_A,   KC_S,   KC_D,   KC_F,   KC_G,   KC_H,   KC_J,   KC_K,   KC_L,   JP_SCLN, JP_QUOT,           KC_ENT,KC_PGUP, \
  MO(_SHIFT), KC_Z,   KC_X,   KC_C,   KC_V,   KC_B,   KC_N,   KC_M,   JP_COMM, JP_DOT, JP_SLSH,   KC_RSFT, KC_UP,KC_PGDN, \
  KC_LCTL, KC_LGUI,KC_LALT,                KC_SPC,                        KC_RALT,MO(_FL),KC_RCTRL, KC_LEFT,KC_DOWN,KC_RGHT),

  /* Keymap _SHIFT: (Shift Layer)
   * ,----------------------------------------------------------------.
   * |Esc | !|  @|  #|  $|  %|  ^|  &|  *|  (|  )|  _|  +|Backsp |~ ` |
   * |----------------------------------------------------------------|
   * |Tab  |  Q|  W|  E|  R|  T|  Y|  U|  I|  O|  P|  {|  }|  |  |Del |
   * |----------------------------------------------------------------|
   * |____   |  A|  S|  D|  F|  G|  H|  J|  K|  L|  :|  "|Return |PgUp|
   * |----------------------------------------------------------------|
   * |_____   |  Z|  X|  C|  V|  B|  N|  M|  <|  >|  ?|Shift | Up|PgDn|
   * |----------------------------------------------------------------|
   * |Ctrl|Win |Alt |        Space          |Alt| FN|Ctrl|Lef|Dow|Rig |
   * `----------------------------------------------------------------'
   */

[_SHIFT] = LAYOUT_ansi(
  JP_ZHTG, JP_EXLM,   JP_AT,   JP_HASH,   JP_DLR,   JP_PERC,   JP_CIRC,   JP_AMPR,   JP_ASTR,   JP_LPRN,   JP_RPRN,   JP_UNDS, JP_PLUS, S(KC_BSPC),JP_TILD, \
  S(KC_TAB),  S(KC_Q),   S(KC_W),   S(KC_E),   S(KC_R),   S(KC_T),   S(KC_Y),   S(KC_U),   S(KC_I),   S(KC_O),   S(KC_P),   JP_LCBR, JP_RCBR, JP_PIPE, S(KC_DEL), \
  _______, S(KC_A),   S(KC_S),   S(KC_D),   S(KC_F),   S(KC_G),   S(KC_H),   S(KC_J),   S(KC_K),   S(KC_L),   JP_COLN, JP_DQT,   S(KC_ENT), S(KC_PGUP), \
  _______, S(KC_Z),   S(KC_X),   S(KC_C),   S(KC_V),   S(KC_B),   S(KC_N),   S(KC_M),   JP_LT, JP_GT, JP_QUES,   S(KC_RSFT), S(KC_UP), S(KC_PGDN), \
                       KC_LCTL, KC_LGUI,KC_LALT,                KC_SPC,                        KC_RALT,MO(_FL),KC_RCTRL, S(KC_LEFT), S(KC_DOWN),S(KC_RGHT)),



[_CTRL] = LAYOUT_ansi(
  /* Keymap _BL: (Base Layer) Ctrl Layer
   * ,----------------------------------------------------------------------------------------.
   * |Esc  |   1|    2|    3|    4|    5|    6|    7|    8|    9|    0|    -|  =|Backsp |~ ` |
   * |---------------------------------------------------------------------------------------|
   * |Tab  |    Q|    W|    E|    R|    T|    Y|    U|    I|   O|   Up|    [|    ]|   \ |Del |
   * |---------------------------------------------------------------------------------------|
   * |CAPS   |  Home|  S|   Del|  -> |  BS |    H|    J|     K|    L|    ;|    '|Return |PgUp|
   * |---------------------------------------------------------------------------------------|
   * |Shift   |    Z|   X|    C|  PgDn|  <-  |  Down|    M|     ,|    .|   /| Shift | Up|PgDn|
   * |---------------------------------------------------------------------------------------|
   * |Ctrl| Win| Alt |                        Space          | Alt|  FN| Ctrl| Lef| Dow| Rig |
   * `---------------------------------------------------------------------------------------'
   */

C(KC_ESC), JP_EXLM,   JP_AT,   JP_HASH,   JP_DLR,   JP_PERC,   JP_CIRC,   JP_AMPR,   JP_ASTR,   JP_LPRN,   JP_RPRN,   JP_UNDS, JP_PLUS, C(KC_BSPC),JP_TILD, \
  C(KC_TAB),  C(KC_Q),   C(KC_W),   KC_END,   C(KC_R),   C(KC_T),   C(KC_Y),   C(KC_U),   C(KC_I),   C(KC_O),   KC_UP,   JP_LCBR, KC_ESC, JP_PIPE, C(KC_DEL), \
  _______, KC_HOME,   C(KC_S),   KC_DEL,   KC_RGHT,   C(KC_G),   KC_BSPC,   C(KC_J),   C(KC_K),   C(KC_L),   JP_COLN, JP_DQT,   C(KC_ENT), C(KC_PGUP), \
  _______, C(KC_Z),   C(KC_X),   C(KC_C),   KC_PGDN,   KC_LEFT,   KC_DOWN,   C(KC_M),   JP_LT, JP_GT, JP_QUES,   C(KC_RSFT), C(KC_UP), C(KC_PGDN), \
                       KC_LCTL, KC_LGUI,KC_LALT,                KC_SPC,                        KC_RALT,MO(_FL),KC_RCTRL, C(KC_LEFT), C(KC_DOWN),C(KC_RGHT)),



  /* Keymap _FL: Function Layer
   * ,----------------------------------------------------------------.
   * |   | F1|F2 |F3 |F4 |F5 |F6 |F7 |F8 |F9 |F10|F11|F12|Del    |Ins |
   * |----------------------------------------------------------------|
   * |     |   |Up |   |   |   |   |   |   |   |   |   |   |     |Hme |
   * |----------------------------------------------------------------|
   * |      |<- |Dn | ->|   |   |   |   |   |   |   |   |        |End |
   * |----------------------------------------------------------------|
   * |        |   |   |Bl-|BL |BL+|   |VU-|VU+|MUT|   |   McL|MsU|McR |
   * |----------------------------------------------------------------|
   * |    |    |    |                       |   |   |    |MsL|MsD|MsR |
   * `----------------------------------------------------------------'
   */
[_FL] = LAYOUT_ansi(
  _______, 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_DEL, KC_INS ,  \
  _______,_______, KC_UP,_______,_______, _______,_______,_______,_______,_______,_______,_______,_______, _______,KC_HOME, \
  _______,KC_LEFT,KC_DOWN,KC_RIGHT,_______,_______,_______,_______,_______,_______,_______,_______,        _______,KC_END, \
  _______,_______,_______,BL_DEC, BL_TOGG,BL_INC, _______,KC_VOLD,KC_VOLU,KC_MUTE,_______,KC_BTN1, KC_MS_U, KC_BTN2, \
  _______,_______,_______,                 _______,               _______,_______,_______,KC_MS_L,KC_MS_D, KC_MS_R),
};
```