WindowsのキーボードにMacのようなfnキーを導入する


## 何がやりたい？

以下の図のようなキーバインドを Windows でも実現したい。 [^1]

![2019_03_03 17_35 Office Lens.jpg](https://qiita-image-store.s3.amazonaws.com/0/47014/2031d23a-485b-5929-1696-2c19ef437a33.jpeg)

## どうやって？

このような用途に使える有名なツールとしては [のどか](http://www.appletkan.com/) や [AutoHotkey](https://www.autohotkey.com/) などがあるが、今回はドッグフーディングも兼ねて自作ツールの [Crevice](https://github.com/creviceapp/creviceapp) で設定を行った。

## Crevice の設定

```csharp
// マウスジェスチャーとは別のプロファイルを作る。
DeclareProfile("Keyboard");

{
    var fn = false;

    // 常に有効なジェスチャを設定する
    var Whenever = When(ctx =>
    {
        return true;
    });

    // ここでは右シフトキーをfnキーとして設定する
    Whenever.
    OnDecomposed(Keys.RShiftKey).
    Press(ctx => fn = true).
    Release(ctx => fn = false);

    // fnキーが有効なとき、あるキーを別のキーに変更する
    void swapIfFn(
        Crevice.Core.DSL.WhenElement<Crevice.GestureMachine.EvaluationContext, Crevice.GestureMachine.ExecutionContext> when,
        Crevice.UserScript.Keys.LogicalSystemKey from,
        Crevice.UserScript.Keys.LogicalSystemKey to
    ) {
        when.
        OnDecomposed(from).
        Press(ctx => {
            if (fn) {
                SendInput.KeyDown(to);
                return;
            }
            SendInput.KeyDown(from);
        }).
        Release(ctx => {
            if (fn) {
                SendInput.KeyUp(to);
                return;
            }
            SendInput.KeyUp(from);
        });
    }   

    // fnキーが有効なとき、あるキーを無効にする
    void disableIfFn(
        Crevice.Core.DSL.WhenElement<Crevice.GestureMachine.EvaluationContext, Crevice.GestureMachine.ExecutionContext> when,
        Crevice.UserScript.Keys.LogicalSystemKey from
    ) {
        when.
        OnDecomposed(from).
        Press(ctx => {
            if (fn) {
                return;
            }
            SendInput.KeyDown(from);
        }).
        Release(ctx => {
            if (fn) {
                return;
            }
            SendInput.KeyUp(from);
        });
    }   

    // fn + 1234567890-^ -> F1-12
    swapIfFn(Whenever, Keys.D1, Keys.F1);
    swapIfFn(Whenever, Keys.D2, Keys.F2);
    swapIfFn(Whenever, Keys.D3, Keys.F3);
    swapIfFn(Whenever, Keys.D4, Keys.F4);
    swapIfFn(Whenever, Keys.D5, Keys.F5);
    swapIfFn(Whenever, Keys.D6, Keys.F6);
    swapIfFn(Whenever, Keys.D7, Keys.F7);
    swapIfFn(Whenever, Keys.D8, Keys.F8);
    swapIfFn(Whenever, Keys.D9, Keys.F9);
    swapIfFn(Whenever, Keys.D0, Keys.F10);
    swapIfFn(Whenever, Keys.OemMinus, Keys.F11);
    swapIfFn(Whenever, Keys.Oem7, Keys.F12);

    // fn + JIKL -> ←↑↓→
    swapIfFn(Whenever, Keys.J, Keys.Left);
    swapIfFn(Whenever, Keys.I, Keys.Up);
    swapIfFn(Whenever, Keys.K, Keys.Down);
    swapIfFn(Whenever, Keys.L, Keys.Right);

    // fn + UOP; -> N/A
    disableIfFn(Whenever, Keys.U);
    disableIfFn(Whenever, Keys.O);
    disableIfFn(Whenever, Keys.P);
    disableIfFn(Whenever, Keys.Oemplus);

    // fn + @ -> Home
    swapIfFn(Whenever, Keys.Oem3, Keys.Home);
    // fn + : -> End
    swapIfFn(Whenever, Keys.Oem1, Keys.End);

    // fn + [ -> PageUp
    swapIfFn(Whenever, Keys.Oem4, Keys.PageUp);
    // fn + ] -> PageDown
    swapIfFn(Whenever, Keys.Oem6, Keys.PageDown);
}
```


## Mac のような「英数」「かな」での IME 切り替えを実現する

Google IME のキー設定で「無変換」「変換」にそれぞれ「IME を無効化」「IME を有効化」を割り当てる。
<img width="264" alt="SnapCrab_Google 日本語入力 プロパティ_2019-3-3_18-15-5_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/47014/02402b00-056c-1dfe-5f4f-da09c4a76cd0.png">
<img width="377" alt="SnapCrab_NoName_2019-3-3_18-14-41_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/47014/ded1cc89-98b2-e665-5fe0-f6d6cbe63344.png">

## OS レベルであるキーを別のキーに割り当てる

[Change Key](https://forest.watch.impress.co.jp/library/software/changekey/) が使いやすい。

<img width="530" alt="SnapCrab_ChangeKey チェンジキー v150    管理者 _2019-3-2_15-57-35_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/47014/1260272a-fc51-2b10-a4bb-36bbdd7f302c.png">
<img width="530" alt="SnapCrab_ChangeKey チェンジキー v150    管理者 _2019-3-3_16-36-5_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/47014/aec3c750-bf67-50c0-4931-8c3c08c0647e.png">
<img width="530" alt="SnapCrab_ChangeKey チェンジキー v150    管理者 _2019-3-3_16-36-22_No-00.png" src="https://qiita-image-store.s3.amazonaws.com/0/47014/3c2a5197-9d8f-c0dd-6b98-8ca7550d2873.png">




[^1]: MacではKarabiner-Elementsで実現できる。参考: https://gist.github.com/rubyu/9f6b0b823df13214fb33ef507f051aab