エスリル NISSE ファームウェア改造ガイド (4)

エスリル ニューキーボード − NISSEファームウェアを自分用に改造するメモ。

6. Fn キーをワンショットモディファイヤ化する

ワンショットモディファイヤとは、単独で押して放すと放したタイミングで自身のキーコードを送出するが、他のキーと同時に押すとモディファイヤとして振る舞う(自身のキーコードを送出しない)もの。普通のキーとモディファイヤキーを重ね合わせることで、少ない物理キーに多くの機能を割り当てる常套手段である。いわゆる SandS もワンショットモディファイヤの一種だ。
NISSE は親指領域にキーが10個もあるように見えるが、いちばん外側は遠すぎてホームポジションからは常用できず、いちばん内側も親指の移動にかなり時間がかかるので頻繁には使えない。常用できるのは残る6個(デフォルトの配列だと [Fn], [LShift], [Backspace], [Space], [RShift], [Fn])だが、そのうち2個が [Fn] に占有されるので、ドライバ側で検出できる(のどかでカスタマイズできる)のはわずか4個。えっ、4個? そんなん普通の OADG 109 キーボードと変わらんやないか!! 常用可能な親指キーには1個1万円の価値があるのだから*1、6万円の NISSE を買ったら親指キーが6個は常用できないと割に合わんのだよ!!!
というわけで、NISSE の Fn キーをワンショットモディファイヤ化して、単独で押して放したときは別のキーとして働くようにしたい。具体的には、[左Fn] の単打を [F14] に、[右Fn] の単打を [F13] にしたい。これを実現する作戦は2つ考えられる。

  1. 外部モディファイ作戦。キーボード側からはモディファイヤキーも普通のキーと同様に送出する。つまり、[右Fn] が押されている間、他の同時に押されているキーコードに加えて [F13] を送出しつづける。ワンショットモディファイヤ化はドライバ側で(のどかを使って)行う。
  2. 内部モディファイ作戦。キーボード側でワンショットモディファイヤ化を行う。つまり、[右Fn] が単独で押して放されたときに限り、放されたタイミングで [F13] を一度だけ送出する。

簡単なのはどちらかと言えば外部モディファイ作戦だろう。Fn 面のマッピングをキーボード側ではなくドライバ側で定義するので、NISSE を使っていない他のマシンとの配列共通化も容易にできる。内部モディファイ作戦は、もし NISSE が携帯性に優れた製品で、ドライバをいじれない出先のマシンに接続して使うようなものだったら意味があると思う。というわけで、手始めに外部モディファイ作戦を採用しよう。

外部モディファイ作戦

[左Fn] と [右Fn] に異なる機能を持たせるために、まずは両者を区別できるようにする。Keyboard.h の

#define KEY_FN          0xF0

#define KEY_LEFTFN      0xF0
#define KEY_RIGHTFN     0xF1

とし、KeyboardCommon.c の onPressed 関数にある

    if (KEY_FN == key) {

    if (KEY_LEFTFN == key || KEY_RIGHTFN == key) {

とすればよい。あとは KeybaordUS.c にある配列 matrixQwerty, matrixDvorak, matrixColemak, matrixJIS, matrixNicolaF に含まれる KEY_FN を KEY_LEFTFN または KEY_RIGHTFN に置き換えれば OK。
次に、Fn キーがキーコードを発生するようにする。今いじった KeyboardCommon.c の onPressed 関数にある

    if (KEY_LEFTFN == key || KEY_RIGHTFN == key) {
        current[1] |= MOD_FN;
        return; // ←これを削除
    }

この return; を削除する。それから、KeyboarCommon.c にある配列 matrixFn の [左Fn] と [右Fn] にあたる位置に、それぞれ押下時に送出したいキーを書く。たとえば [F14] と [F13] を送出したければ、matrixFn の最下行をこうする*2

{{0}, {0}, {KEY_F14}, {0}, {KEY_LEFTCONTROL, KEY_BACKSPACE}, {0}, {0}, {KEY_LEFTCONTROL, KEY_SPACEBAR}, {0}, {KEY_F13}, {0}, {0}}

これで [左Fn] を押している間は [F14] が、[右Fn] を押している間は [F13] が送出され、ドライバで検出できるようになった。
ここまで来れば Fn 面のマッピングはドライバ側で(のどかを使って)自由に定義できる。だから、もはやキーボード側で苦労して Fn 面をリマップする必要はないのだ。いっそ matrixFn の中身を matrixJIS と同じ並びにしちゃってもいい。こんなふうに。

static uint8_t const matrixFn[8][12][3] =
{
    {{KEY_RIGHT_BRACKET}, {KEY_F2}, {KEY_F3}, {KEY_F4}, {KEY_F5}, {KEY_F6}, {KEY_F7}, {KEY_F8}, {KEY_F9}, {KEY_F10}, {KEY_F11}, {KEY_EQUAL}},
    {{KEY_INTERNATIONAL3}, {KEY_F1}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {KEY_F12}, {KEY_LEFT_BRACKET}},
    {{KEY_NON_US_HASH}, {KEY_1}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {0}, {KEY_0}, {KEY_MINUS}},
    {{KEY_CAPS_LOCK}, {KEY_2}, {KEY_3}, {KEY_4}, {KEY_5}, {0}, {0}, {KEY_6}, {KEY_7}, {KEY_8}, {KEY_9}, {KEY_QUOTE}},
    {{KEY_Q}, {KEY_W}, {KEY_E}, {KEY_R}, {KEY_T}, {0}, {0}, {KEY_Y}, {KEY_U}, {KEY_I}, {KEY_O}, {KEY_P}},
    {{KEY_A}, {KEY_S}, {KEY_D}, {KEY_F}, {KEY_G}, {KEY_ESCAPE}, {KEY_APPLICATION}, {KEY_H}, {KEY_J}, {KEY_K}, {KEY_L}, {KEY_SEMICOLON}},
    {{KEY_Z}, {KEY_X}, {KEY_C}, {KEY_V}, {KEY_B}, {KEY_TAB}, {KEY_ENTER}, {KEY_N}, {KEY_M}, {KEY_COMMA}, {KEY_PERIOD}, {KEY_SLASH}},
    {{0}, {0}, {KEY_F14}, {0}, {KEY_BACKSPACE}, {0}, {0}, {KEY_SPACEBAR}, {0}, {KEY_F13}, {0}, {0}}
};

こうすれば、のどかの設定を他のマシンとほとんど共通化できるはずだ。
次回は(気が向いたら)内部モディファイ作戦を試してみるよ。

ダウンロード

筆者がカスタマイズしたファームウェアソースコードはここからダウンロードできる。

Hex ファイルが欲しい人はコメントください。

*1:5万円の μTRON キーボードは6個、2.5万円の Truly Ergonomic Keyboard は2個の親指キーが常用できることから逆算。

*2:[Fn] が標準の位置にある場合。筆者のカスタマイズ例では [Fn] と [Shift] を入れ替えたので {{0}, {0}, {0}, {KEY_F14}, {KEY_BACKSPACE}, {0}, {0}, {KEY_SPACEBAR}, {KEY_F13}, {0}, {0}, {0}} となる。