0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2025-05-24

はじめに

こんにちは、Ctrlです。

worm_eaten_000.png

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

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

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

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

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

主な変更点

CTRL配列:2.0以降の主な変更点

### ● 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

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

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

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

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

使用している物理キーボードは@takashicompanyさんのWorm Eatenです。

全体のサンプルコード

keymap.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),
};

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

※この 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つあるため、全てが同時に壊れることは考えにくいことから、現在現在の環境が失われることはないでしょう。

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

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

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

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?