CTRL配列：左右・反転・兼用 15キーレイアウト - v.1.0

## はじめに

こんにちは、Ctrlです。

![worm_eaten_000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/608727/fe976502-484d-c938-0076-67d551f32e46.png)

今回はCTRL配列を左手から右手に移行した後も、左手専用のキーボードが多数あったため、時々でも使えるよう調整したキーボードレイアウトです。

左手の場合はWorm EatenのPro Microに接続し、右手の場合はte96から切り離したPro Micro付き基盤を経由して、TRRSケーブルで接続することで、左右の切り替えを行うようにしました。

現在はKensingtonのスリムブレード、Worm Eaten、ディスプレイの下に無指向性マイクを設置して作業しています。

## 片手キーボードの設計思想

* **15キー構成の限界への挑戦**  
  * 物理的なキー数を絞り、部品の費用を削減しながら、基本操作を網羅できる構成が目標
* **ホームポジションから動かない**  
  * 指を移動させずに済む配置により、作業時のストレスや疲労を軽減
* **左右対称／反転運用の両立**  
  * 左手・右手どちらでも同じ操作感を実現し、状況に応じて使い分けが可能
* **用途別のレイヤー設計**  
  * 入力・編集・マウス操作を押しやすさ重視でレイヤーに分離し、必要時に素早く切り替え
* **誤操作の抑制**  
  * 不要なキーを排除し、無意識の誤爆を防ぐためのコンパクトな配置を採用
* **マウスとの一体化**  
  * トラックボール操作やマウスクリックを含めて、片手での完結を前提
* **ショートカットの集中化**  
  * 操作に必要なコマンドはすべてキーボードに割り当て、ドラッグをマウスに頼らない作業が可能
* **姿勢と環境への適応**  
  * 座椅子や布団など、柔軟な作業環境でも使えるよう設計されており、机が不要
* **切り替えの簡易性**  
  * TRRSケーブルやPro Microの差し替えにより、物理的に素早く左右を切り替え可能
* **記憶より感覚**  
  * キー配置を覚えるのではなく、感覚で自然に手が動くことを重視した配列
 
## 主な変更点

<details><summary>CTRL配列：2.0以降の主な変更点</summary>

``` 

### ● 2.0（タイピング便振化とQMK改良）

* タップダンスによる大文字入力を導入（TD_LTR）
* Vimiumとの使用を意識したキー割り当てへと変更
* ショートカット操作（コピー・ペースト・検索など）をキーボードに集積
* QMKファームウェア側で独自キーコード（VOICE, PRNなど）を設定

https://qiita.com/hiyoctrl/items/11ea9d917f2716408944

---

### ● 3.0（トラックボール使用とマウス操作拡張）

* Kensington SlimBlade に合わせたカーソル操作レイヤーを追加
* マウスホイール操作（MS_WHLU / MS_WHLD）をレイヤーで実装
* マウスボタン（BTN1 / BTN2 / BTN3）を片手で操作可能に
* ESC, DEL, TABなどの「戻る系」操作の最適配置を強化

https://qiita.com/hiyoctrl/items/f19cc1c8f90177073fe2

---

### ● 片手1.0（左右反転・兼用対応レイアウト）

* 左手配列をベースに右手用レイアウトへ完全反転
* TRRSケーブルで左右の切り替えに対応した構成へ変更
* レイヤー構造は左右共通、QMKファームウェア内で反転実装
* Vimiumとのショートカット広和を抑えつつ、マウス／ブラウザ操作を統合
* キーボードを右手でも安定して操作できるよう、体動の自由度を向上

https://qiita.com/hiyoctrl/items/788995d2333bbd2f8406

``` 
</details>

- 右手と左手のレイアウトを反転して使いやすく調整
- Vimiumによる操作のずれの解消と最適化
- Vimiumによるブラウザ操作の一部をキーボードショートカットに統一
- 左手の場合はWorm EatenのPro Microに接続
- 右手の場合はPro Micro付き基盤とTRRSケーブルで接続
- ブラウザの起動などのエイリアスを調整

以上が主な変更点です。スワップハンドの導入も検討しましたが、やはり両手での入力の必要性を感じられなかったため、3年ほどで使い慣れた左手、今のところ1ヶ月程度で使いやすいと感じている右手を、それぞれ片手で使えるという方向性で進めてみました。

現在1週間程度経過しましたが、TRRSケーブルで接続している右手モードの方が、物理的に端子部分が壊れる不安も少ないため、右手モードの状態の方が多いです。


## 使用しているPCB：物理キーボード

使用している物理キーボードは[@takashicompany](https://twitter.com/takashicompany)さんのWorm Eatenです。

https://github.com/takashicompany/worm_eaten/tree/master

## 全体のサンプルコード

<details><summary>keymap.c</summary>

```c

#include QMK_KEYBOARD_H
enum layer_number {
    _BASE0 = 0,_LT1,_LT2,_LT3,_LT4,_LT5,_LT6,_LT7,_LT8,_LT9,_LT10,
};

enum custom_keycodes {
	VOICE = SAFE_RANGE,PRN,BRC,CBR,ABK,
};

#define SEND_PAIR(str) if (record->event.pressed) SEND_STRING(str);

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
        case VOICE: SEND_PAIR(SS_TAP(X_LNG1) SS_RCTL(SS_LSFT("s"))); break;
        case PRN:   SEND_PAIR("()"); break;
        case BRC:   SEND_PAIR("[]"); break;
        case CBR:   SEND_PAIR("<>"); break;
        case ABK:   SEND_PAIR("{}"); break;
    }
    return true;
}

enum {
    A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,
};

#define TD_LTR(kc) ACTION_TAP_DANCE_DOUBLE(KC_##kc, S(KC_##kc))

#define TD_ROW(a, b, c, d, e) \
    [a] = TD_LTR(A), [b] = TD_LTR(B), [c] = TD_LTR(C), [d] = TD_LTR(D), [e] = TD_LTR(E)

tap_dance_action_t tap_dance_actions[] = {
    [A] = TD_LTR(A), [B] = TD_LTR(B), [C] = TD_LTR(C), [D] = TD_LTR(D), [E] = TD_LTR(E),
    [F] = TD_LTR(F), [G] = TD_LTR(G), [H] = TD_LTR(H), [I] = TD_LTR(I), [J] = TD_LTR(J),
    [K] = TD_LTR(K), [L] = TD_LTR(L), [M] = TD_LTR(M), [N] = TD_LTR(N), [O] = TD_LTR(O),
    [P] = TD_LTR(P), [Q] = TD_LTR(Q), [R] = TD_LTR(R), [S] = TD_LTR(S), [T] = TD_LTR(T),
    [U] = TD_LTR(U), [V] = TD_LTR(V), [W] = TD_LTR(W), [X] = TD_LTR(X), [Y] = TD_LTR(Y),
    [Z] = TD_LTR(Z),
};

#define BSPC         KC_BSPC
#define ENG          KC_LNG2
#define JPN          KC_LNG1
#define DEL          KC_DEL
#define SPC          KC_SPC
#define BTN1         KC_BTN1
#define BTN2         KC_BTN2
#define BTN3         KC_BTN3
#define ESC          KC_ESC
#define TAB          KC_TAB
#define ENT          KC_ENT
#define RGHT         KC_RGHT
#define LEFT         KC_LEFT
#define HOME         KC_HOME
#define END          KC_END
#define IBUS         C(KC_F1)
#define KEYBOARD     C(KC_F2)
#define MOUSE        C(KC_F3)
#define CHROMIUM     C(KC_F4)
#define SOUND        C(KC_F6)
#define FIREFOX      C(KC_F9)
#define SETTINGS     C(KC_F10)
#define THUNAR       C(KC_F11)
#define TERMINAL     C(KC_F12)

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

[_BASE0] = LAYOUT(
    LT(8,ESC),    LT(7,KC_DOT), LT(6,KC_COMM), MS_WHLU,      VOICE,         VOICE,        MS_WHLU,      LT(6,KC_COMM), LT(7,KC_DOT), LT(8,ESC),
    LT(9,BTN3),   LEFT,         RGHT,          LT(5,BTN1),   LT(4,TAB),     LT(4,TAB),    LT(5,BTN1),   LEFT,          RGHT,         LT(9,BTN3),
    LT(10,ENT),   XXXXXXX,      XXXXXXX,       MS_WHLD,      LT(3,SPC),     LT(3,SPC),    MS_WHLD,      XXXXXXX,       XXXXXXX,      LT(10,ENT),
    XXXXXXX,      XXXXXXX,      SH_TOGG,       LT(1,DEL),    LT(2,BSPC),    LT(2,BSPC),   LT(1,DEL),    SH_TOGG,       XXXXXXX,      XXXXXXX),
[_LT1] = LAYOUT(
    TD(L),        TD(O),        TD(E),         TD(Y),        TD(W),         TD(W),        TD(Y),        TD(E),         TD(O),        TD(L),
    TD(A),        TD(J),        TD(C),         TD(I),        TD(F),         TD(F),        TD(I),        TD(C),         TD(J),        TD(A),
    TD(Q),        XXXXXXX,      XXXXXXX,       TD(U),        TD(V),         TD(V),        TD(U),        XXXXXXX,       XXXXXXX,      TD(Q),
    XXXXXXX,      XXXXXXX,      XXXXXXX,       XXXXXXX,      JPN,           JPN,          XXXXXXX,      XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT2] = LAYOUT(
    TD(X),        TD(S),        TD(T),         TD(R),        TD(P),         TD(P),        TD(R),        TD(T),         TD(S),        TD(X),
    TD(K),        TD(Z),        TD(D),         TD(N),        TD(H),         TD(H),        TD(N),        TD(D),         TD(Z),        TD(K),
    TD(G),        XXXXXXX,      XXXXXXX,       TD(M),        TD(B),         TD(B),        TD(M),        XXXXXXX,       XXXXXXX,      TD(G),
    XXXXXXX,      XXXXXXX,      XXXXXXX,       ENG,          XXXXXXX,       XXXXXXX,      ENG,          XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT3] = LAYOUT(
    XXXXXXX,      S(HOME),      S(END),        S(KC_UP),     C(KC_A),       C(KC_A),      S(KC_UP),     S(HOME),       S(END),       XXXXXXX,
    RCS(KC_V),    S(LEFT),      S(RGHT),       C(KC_C),      C(KC_X),       C(KC_X),      C(KC_C),      S(LEFT),       S(RGHT),      RCS(KC_V),
    C(KC_V),      XXXXXXX,      XXXXXXX,       S(KC_DOWN),   XXXXXXX,       XXXXXXX,      S(KC_DOWN),   XXXXXXX,       XXXXXXX,      C(KC_V),
    XXXXXXX,      XXXXXXX,      XXXXXXX,       S(DEL),       A(KC_F4),      A(KC_F4),     S(DEL),       XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT4] = LAYOUT(
    IBUS,         KEYBOARD,     MOUSE,         CHROMIUM,     C(KC_F5),      C(KC_F5),     CHROMIUM,     MOUSE,         KEYBOARD,     IBUS,
    SOUND,        C(KC_F7),     C(KC_F8),      QK_BOOT,      XXXXXXX,       XXXXXXX,      QK_BOOT,      C(KC_F8),      C(KC_F7),     SOUND,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       FIREFOX,      SETTINGS,      SETTINGS,     FIREFOX,      XXXXXXX,       XXXXXXX,      XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       THUNAR,       TERMINAL,      TERMINAL,     THUNAR,       XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT5] = LAYOUT(
    KC_HASH,      KC_COLN,      KC_SLSH,       XXXXXXX,      XXXXXXX,       XXXXXXX,      XXXXXXX,      KC_SLSH,       KC_COLN,      KC_HASH,
    C(KC_T),      KC_EXLM,      KC_QUES,       XXXXXXX,      BTN2,          BTN2,         XXXXXXX,      KC_QUES,       KC_EXLM,      C(KC_T),
    KC_UNDS,      XXXXXXX,      XXXXXXX,       C(KC_Y),      C(KC_Z),       C(KC_Z),      C(KC_Y),      XXXXXXX,       XXXXXXX,      KC_UNDS,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       RCS(KC_T),    C(KC_W),       C(KC_W),      RCS(KC_T),    XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT6] = LAYOUT(
    XXXXXXX,      RCS(KC_C),    XXXXXXX,       C(HOME),      XXXXXXX,       XXXXXXX,      C(HOME),      XXXXXXX,       RCS(KC_C),    XXXXXXX,
    A(KC_S),      XXXXXXX,      XXXXXXX,       A(TAB),       XXXXXXX,       XXXXXXX,      A(TAB),       XXXXXXX,       XXXXXXX,      A(KC_S),
    XXXXXXX,      XXXXXXX,      XXXXXXX,       C(END),       C(KC_H),       C(KC_H),      C(END),       XXXXXXX,       XXXXXXX,      XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       XXXXXXX,      C(KC_F),       C(KC_F),      XXXXXXX,      XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT7] = LAYOUT(
    XXXXXXX,      XXXXXXX,      PRN,           ABK,          XXXXXXX,       XXXXXXX,      ABK,          PRN,           XXXXXXX,      XXXXXXX,
    CBR,          XXXXXXX,      XXXXXXX,       BRC,          XXXXXXX,       XXXXXXX,      BRC,          XXXXXXX,       XXXXXXX,      CBR,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       KC_PLUS,      KC_MINS,       KC_MINS,      KC_PLUS,      XXXXXXX,       XXXXXXX,      XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       KC_ASTR,      KC_EQL,        KC_EQL,       KC_ASTR,      XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT8] = LAYOUT(
    XXXXXXX,      KC_AMPR,      KC_PERC,       KC_TILD,      XXXXXXX,       XXXXXXX,      KC_TILD,      KC_PERC,       KC_AMPR,      XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       KC_AT,        XXXXXXX,       XXXXXXX,      KC_AT,        XXXXXXX,       XXXXXXX,      XXXXXXX,
    KC_CAPS,      XXXXXXX,      XXXXXXX,       KC_CIRC,      KC_GRV,        KC_GRV,       KC_CIRC,      XXXXXXX,       XXXXXXX,      KC_CAPS,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       KC_DQUO,      KC_QUOT,       KC_QUOT,      KC_DQUO,      XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT9] = LAYOUT(
    XXXXXXX,      KC_SCLN,      KC_BSLS,       KC_F11,       KC_F5,         KC_F5,        KC_F11,       KC_BSLS,       KC_SCLN,      XXXXXXX,
    XXXXXXX,      KC_PIPE,      KC_DLR,        KC_F7,        KC_F10,        KC_F10,       KC_F7,        KC_DLR,        KC_PIPE,      XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       RCS(TAB),     C(TAB),        RCS(TAB),     C(TAB),       XXXXXXX,       XXXXXXX,      XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       RCS(KC_PGUP), RCS(KC_PGDN),  RCS(KC_PGUP), RCS(KC_PGDN), XXXXXXX,       XXXXXXX,      XXXXXXX),
[_LT10] = LAYOUT(
    XXXXXXX,      KC_4,         KC_3,          KC_2,         KC_1,          KC_1,         KC_2,         KC_3,          KC_4,         XXXXXXX,
    XXXXXXX,      KC_8,         KC_7,          KC_6,         KC_5,          KC_5,         KC_6,         KC_7,          KC_8,         XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       KC_0,         KC_9,          KC_9,         KC_0,         XXXXXXX,       XXXXXXX,      XXXXXXX,
    XXXXXXX,      XXXXXXX,      XXXXXXX,       A(LEFT),      A(RGHT),       A(LEFT),      A(RGHT),      XXXXXXX,       XXXXXXX,      XXXXXXX),
};

```

</details>

以上が今回の全体のサンプルコードになります。

※この keymap.c は、QMKファームウェアで動作する15キー仕様のカスタムレイアウトをベースにしています。左右両用にするため、各レイヤーに対してキー配置を反転・最適化しています。

## Vimiumの設定

```
unmapAll
	
# map <c-S> goBack
# map <space> goNext
# map <tab> LinkHints.activateModeToOpenInNewForegroundTab
# map <delete> restoreTab
# map <backspace> removeTab

map <c-home> scrollToTop
map <c-end> scrollToBottom

map <c-s> copyCurrentUrl

# map , previousTab
# map . nextTab

mapkey 0 0
mapkey 1 0
mapkey 2 0
mapkey 3 0
mapkey 4 0
mapkey 5 0
mapkey 6 0
mapkey 7 0
mapkey 8 0
mapkey 9 0
```

Vimiumについては、コメントアウトした項目が非常に使いやすかったものの、押しやすさが逆に誤爆の原因になったので、一時的に外しました。

Vimiumでしか実現できなかったのが、Googleドキュメント利用時のトップとボトムの移動、見ているページのURLのコピーのみだったため、この2つは残しました。

また、タブの移動が左右反転させると逆になってしまうこともあり、調整がうまくいけば再度元に戻したいとも考えています。

ただし、キーボードショートカットとマウス操作で全て移動できる状態になっているため、スリム化や重複を避けることを考えると現在の状態がベストです。

## まとめ

今回は左手を使うかどうかは分からないものの、物理的に左手でしか使えないキーボードがたくさんあることが気になったために作ったキーボードレイアウトと言えます。

基本的には右手での作業の方が快適なため、もしかしたら左手のみのレイアウトに戻すかもしれません。今回の気づきとしては、片手キーボードではあるものの、操作する右手のキーボードはマスターとしてではなく、スレーブとして扱うことで、いつでも安心・安全に使えるようになった点です。

TRRSケーブルによる接続はとても快適であり、端子の部分が壊れたとしても、取り替えるのが難しい場所でないため、交換やメンテナンスにも向いている点も安心感があります。

また、左右反転に対応したものを含めて、右手として使える物理的なキーボードも合計で5つ、te96から切り離したPro Micro付き基盤は合計で4つあるため、全てが同時に壊れることは考えにくいことから、現在現在の環境が失われることはないでしょう。

左手用のキーボードも多数あることを考えると、もしもの時？に備えるとすれば、スリムブレードの買い増しか、左右どちらでも使えるトラックボールの購入を検討するかなとは思っております。トラックボールでおすすめがあったら教えてください。

最後までお読みいただきありがとうございました。

キーボードレイアウトやキーボードショートカットなど、何か面白い取り組みがあったら教えてくれると嬉しいです。

ライティング案件や自作キーボード関連のお仕事などありましたら、お気軽にご相談ください！

https://crowdworks.jp/public/employees/1089210

https://www.lancers.jp/profile/Ctrl