英語配列キーボードで日本語入力と英語入力を切り替えやすくしたい (1) 検討編

# はじめに 英語配列キーボードについて

Windows 10 でプログラミングをしています。最近は英語配列のキーボードを主に使っています。

* 日本語配列:<br>
  ![layout-jis.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/7241c7b8-1c16-d7c3-6c6e-a32fc98c8584.png)
* 英語配列: <br>
  ![layout-us.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/52c83e27-2078-664c-1fef-3e1a32e00452.png)


## 嬉しいこと: 1. キーボードの形

英語配列の方が、キーの数が少ないです。その分、右手のキーが長くなっています。

とくに嬉しいのは、`[Enter]` `[BackSpace]` 右手の小指が届きやすくなることです。タッチタイプするときにホームポジションがずれると変な入力になりがちですので。

## 嬉しいこと: 2. キーボードの形

違いその2、記号配列。記号を入力するだけなら、日本語・英語配列どちらが良いかはある程度好みの問題かもしれません。けれども、アプリケーションのショートカットはわりと英語配列向けに調整されていると思います。たとえば、

* Excel: 日付入力の `[Ctrl]+[;]` [^1] を `[Shift]` を一緒に押すと  `[Ctrl]+[Shift]+[;]` = `[Ctrl]+[:]` で時刻入力になり、関連していそうに見えます。日本語配列では `[:]` は別のキーです。  
* Slack: 箇条書きの `[Ctrl]+[Shift]+[8]` が、英語配列だと  `[Ctrl]+[*]` で箇条書きっぽい直感的な記号に対応しています。日本語配列では `[Ctrl]+[(]` 相当です。

[^1]: Excel では `[Ctrl]+[;]` を `[;]` キーとの組み合わせと考えます。アプリによっては  `[Shift]+[:]` がどの記号に割り当てられているかによらず、`[Ctrl]+[Shift]+[:]` 相当とします。Slack の `[Ctrl]+[Shift]+[8]` はは後者系。この両方の派閥があり、記号のショートカット割り当ては、アプリ開発者・利用者双方にとって鬼門です。日本語配列キーボードの記号配置はマイナーですから、この影響を受けやすいです。

ほかにも、プログラミングとしてはよく使う記号 `'` `` ` `` を `[Shift]` 無しで打てるのが嬉しいです。歴史的経緯とはいえ [^2] 揃っていれば良いのにと思います。

[^2]: [タイプライターからコンピュータへ：QWERTY配列の変遷100年間\(1\) \| \#custom\_field\-コラムタイトル（\#custom\_field\-筆者） \| 三省堂 ことばのコラム](https://dictionary.sanseido-publ.co.jp/column/qwerty01) がキー配列の歴史的経緯について詳しいです

## 困ること: [無変換] [変換] キーがない

英語配列には `[無変換]` `[変換]` キーがありません。

英語入力では使わないならないのは当然です。でも日本語入力しようと思うと、この一点でほかのすべての嬉しさを帳消しにするくらい困ります。

`[無変換]` `[変換]` キーを IME オン/オフ に割り当てたいです。Windows 10 Ver.2004 以降の新しい IME では設定から簡単に切り替えられます [^3]。Google 日本語入力でもキーカスタマイズで行えます。いま IME オン/オフかをタスクバー右下を見て確認しなくても、英語なら `[無変換]` を、日本語なら `[変換]` を先に押せばいです。便利。

[^3]: [Windows 10 Insider Preview ビルド 18277 でお試しいただける日本語入力に関する改善点 \- Windows Blog for Japan](https://blogs.windows.com/japan/2018/11/08/windows-10-insider-preview-build-18277-japanese-input/) 2018年に [変換]/[無変換] キーを IME のオン/オフに割り当てられる予定と発表がありました

しかしキーがないとどうしようもなく……。 `[Shift]+[CapsLock]` = `[英数]` キーで IME オン/オフをトグルで切り替えしつつ [^4]、うっかり間違えると `[Ctrl]+[T]` で英語に変換して確定となっていました。不便です。

[^4]: `[Shift]+[CapsLock]` = `[英数]` は `[Alt]+[~]` = `[半角/全角]` より押しやすいです。効果が少し違うようですが、IME オン/オフを切り替えられるという意味では同じです。`[Ctrl]+[Space]` 割り当ても使いやすいです。 


# TL;DR

英語配列のまま、`[無変換]` `[変換]` 相当のこともできるように、と試行錯誤するエントリです。

* よほど英語配列にしたい場合以外は、日本語配列キーボードがまずおすすめ。`[無変換]` `[変換]` キーはとても便利。これを捨てるのは大きな犠牲。
* 英語配列キーボードを使うなら、定番の [karakaram/alt\-ime\-ahk](https://github.com/karakaram/alt-ime-ahk) がおすすめ。
* それ以外を目指すなら、ようこそ茨の道へ。


# 案1: IME 状態を分かりやすく表示したい

「今 IME オン/オフ どちらかを意識しなくても」 `[無変換]` `[変換]` キーを押すと IME の状態を指定できることが嬉しいです。

これは逆にいうと、「今 IME オン/オフ どちらかが簡単に分かれば」打ち間違いしません。モードが逆の時に `[Shift]+[CapsLock]` などで切り替えれば OK。

案1で、目立つように表示する方法を考えます。


## 1-1. タスクバーの IME 表示を見る

![taskbar.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/1de17f4b-be49-8330-530b-c7c9003a1139.png)

タスクバー右下の時刻に「あ」「A」と状態が表示されています。これをいつも見れば大丈夫。

……目立ちませんよねこれ。小さいですし、色がついていませんし、ディスプレイ2つでも片方にだけ表示されますし。

しかも、IME の状態はキーボード操作なしにに変わることがあります。Excel でこのセルは IME 無効、隣のセルは有効、みたいな。WEB でも数字入力フォームでは IME 無効というのはよくあります。

入力する場所を切り替えるたびにタスクバーを見るなんて、なかなか厳しいです。


## 1-2. IME 切り替え時の表示を見る

![ime-baloon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/9e80b70b-99b6-3145-51f5-7a260c7e5249.png)

Windows 10 Ver.1909 以前の MS-IME では、IME オン/オフ を切り替えた時に全画面で大きく表示が出ていました。あまりにも目立って、「消す方法」が検索候補に上がるくらいに; 一応オプションで出さないようにできます。不評だったのか、Ver.2004 以降の新しい IME では表示されなくなりました。

Google 日本語入力でも、IME オン/オフを切り替えると、カーソル近くに IME の状態が表示されます。こちらもオプションで出さないようにできます。

これを使うと、「IME オン/オフ を変えようとしたとき」には気づけます。

しかし、IME オン/オフを変えようとせずに、確認もせずにそのまま書き込んでしまうことが良くあります。この場合の対策にはなりません。Slack を眺めていて書き込みたくなったとき、とか。


## 1-3. IME 状態をウィンドウやカーソル付近に表示するアプリを使う

カーソルやマウスカーソルなどの場所に IME オン/オフを表示するアプリはいくつかあります。いくつか試してみました。

けれど難しいです。これらに引っ掛かります。

* カーソルの位置を正しく取るのは難しい。これができるならブラウザ内のテキストフィールド内で漢字変換したときに、明後日の場所に変換候補が出てくることはないでしょうし。
* 高解像度に対応していないことがある。
* ストアアプリに対応していないことがある。


## 1-4. ディスプレイ画面内に目立つように IME 状態を表示する

1-3. で探してみて見つかりませんでしたから、DIY 気分で書こうとしてみました。

参考:
* [C\#でIMEの変換モードを監視・変更する \- Qiita](https://qiita.com/kob58im/items/a1644b36366f4d094a2c)
* [IME制御 \- eamat @Cabinet \- atwiki（アットウィキ）](https://w.atwiki.jp/eamat/pages/17.html) IME.ahk


### 1-4-a. タスクバーのアイコン

![taskbar-app.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/87830d8e-847f-1aa6-8844-4e4489eb3af7.png)

タスクバーの通知領域に単色表示だと目立ちません。それなら、タスクバーの表示をもっと派手に表示すればわかるかと、起動中のアプリアイコンを IME の状態によって変えるものを作ってみました。これなら気づきやすいはず。

……私の場合ダメでした。そんなに目立ちませんし、このアプリがタスクバーのどこに表示されるかも実行順で変わりますからどこを見ていいかも分かりません。


### 1-4-b. 壁紙

![ime-wallpaper.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/b9b7f2b3-ce5e-a6db-9a82-0a740a1af49f.png)

タスクバーのアイコン1つくらいの狭さだと目立たないなら、壁紙ならば、と試してみたものがこちら。

0.5秒間隔で IME の状態を調べて、前回と変化があれば壁紙を差し替えます。IME オンのときにタスクバーの下に色を付けたような壁紙を用意しておくと、ほかのアプリを最大化していても IME オン/オフ の色が透けて見えます。

コードは Visual Studio 2019 (C++17) でこんな感じで。

```
#pragma comment (lib, "Imm32.lib")
#include <filesystem>
#include <Windows.h>
namespace fs = std::filesystem;
constexpr int IMC_GETOPENSTATUS = 5;
int main()
{
    wchar_t lpFilename[MAX_PATH];
    GetModuleFileName(nullptr, lpFilename, MAX_PATH);
    const std::wstring imeOn = fs::path(lpFilename).parent_path().append("ime-on.png").wstring();
    const std::wstring imeOff = fs::path(lpFilename).parent_path().append("ime-off.png").wstring();
    if (!fs::exists(imeOn) || !fs::exists(imeOff)) {
        return 1;
    }
    bool imeState = false;
    MSG msg;
    SetTimer(nullptr, 1, 500, nullptr);
    while (GetMessage(&msg, nullptr, 0, 0)) {
        if (msg.message == WM_TIMER) {
            GUITHREADINFO gti;
            gti.cbSize = sizeof(gti);
            GetGUIThreadInfo(0, &gti);
            HWND hwnd = ImmGetDefaultIMEWnd(gti.hwndFocus);
            bool state = static_cast<bool>(SendMessage(hwnd, WM_IME_CONTROL, IMC_GETOPENSTATUS, 0));
            if (imeState != state) {
                imeState = state;
                const wchar_t* pvParam = imeState ? imeOn.c_str() : imeOff.c_str();
                SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, const_cast<wchar_t*>(pvParam), 
                    SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE);
            }
        }
    }
    return 0;
}
```

視線の移動としては、いつでもだいたいタスクバーのどこかを見れば良いということで満足です。

課題もいくつかあります。

* IME オン/オフ のたびに Windows の壁紙を変えますから、設定を見ると壁紙の変更履歴が荒れます。これはどうしようもないです……。
* 画面サイズによって良い感じの壁紙を用意する必要があります。マルチディスプレイで解像度が違うときにどうするのか。
* タスクバーの再描画が遅れて色が変わらず、一部のアプリの下だけ変わったりすることがあります。タスクバー以外の場所ならたぶん大丈夫ですけれど、あまり広い範囲が変わるとチカチカします。


## 1-5. 小さな外付けディスプレイを追加する

壁紙を変えるのではなくて、640*480 とかの小さなディスプレイを横において、そこを IME オン/オフ表示専用にするというのも。

困ることは、1つディスプレイ端子と広い場所を使用すること、他のアプリがはみ出してくることがありそう、でしょうか。試していません。


## 1-6. ディスプレイの外に目立つように IME モードを表示する

なんでも表示できるディスプレイではなく、IME の状態だけ表示するハードウェアを付けると良さそうです。

### 1-6-a. LED

ディスプレイの下など目立つところに LED を置くとか。

[WindowsのIMEの状態をLEDで表示するガジェット](https://blog.shapoco.net/2018/02/ime-status-to-led.html?m=1) という記事が見つかりました。こんなことをしたいです。

USB などで電源のオン/オフを制御できるハードウェアがあれば十分、なのですが、小さなものは売っていなそうです。自作すれば、でしょうか。


### 1-6-b. パトランプ

継続的インテグレーションのやり方で、テストが通らなかったなどの問題があるとパトランプがぐるぐる回って派手に知らせることがあります。同じように、日本語モードの時は赤くぐるぐる光って、今は危ないということを示せば、と。

しかし、USBで制御できるものはけっこうお値段が。そして、IME オンは警報レベルに知らせることなのかというとちょっと。


## 1-7. よく使うアプリだけでも対策する

一般的に対応するのは難しくても、よく使うアプリだけでも対策するというのはアリです。

![ime-hidemaru.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/92c40e99-9f36-b1b9-824f-49b9a08b6644.png)

たとえば秀丸エディタは、IME オフだと選択行が茶色、IME オンだと赤で表示するオプションがあります。秀丸なら IME オン/オフ の失敗を減らせます。

けれど、日本語入力を理由に他のアプリを縛るのは不便です。プログラミングだと Visual Studio Code がとても便利、とか。使うものだけでも対策を考えます。


### 1-7-a. Chrome, 新しい Edge

ブラウザ上で日本語を書くことが多いです。メール・バグ管理システムなど。ブラウザに拡張機能を入れて、IME オン/オフ を分かりやすく表示してくれれば解決。。

でも残念ながら、WEB 標準技術では IME オン/オフが分からないようです。日本語の、しかも Windows の事情となると [^5] 標準に入るのはおかしな感じです。

[^5]: たとえば iOS で入力切替をすると、日本語キーボードと英語キーボードの切り替えになります。この英語キーボードは海外でも使う、普通の英語入力モード。日本語 Windows では日本語入力方式の中に、IME オン/オフ という「サブモード」を持つ、というところが大きく違います。歴史的事情なのだと思いますけれども。

ブラウザから直接は IME オン/オフ の状態を知ることはできません。でも、IME オン/オフ の状態を返すサーバーをローカルに立てていれば、それを見て動作を切り替えられます。

これを、NativeMessagingHosts を使って実現しているものが見つかりました。

[IME State Visible \- Chrome ウェブストア](https://chrome.google.com/webstore/detail/ime-state-visible/mnbmnhpnniahlicddcllehggdjglfkeh?hl=jafor)

これは便利! ありがとうございます。


### 1-7-b. Visual Studio Code

開発環境 Visual Studio Code。Electron で Windows アプリになっていて、内部では Chrome と同じ Chromium が動いています。

同じ事情で、標準の方法だと IME オン/オフ を取れません。標準の方法では難しいというフォーラムを見ました。どなたか対応されないでしょうか (他力本願)。


## 1-8. IME 状態を分かりやすく表示したい まとめ

分かりやすく表示するは諦めて、1分くらいキーボードを触らなければ IME オフ に戻しても良いんじゃないか、という感じもしてきました。

表示で解決できない場合が多そうですので、次に進みます。


# 案2. キーボードを買い換えて解決

物理 (マネー) で殴る案。キーボードを買い換えれば解決するかも。


## 2-1. 光るキーボード

IME の状態を視覚的に分かりやすくする、の

ゲーミング用途の光るキーボードが売っています。そして、会社によっては光を制御する API を公開しています。

上に書いた壁紙変更プログラムの、 `SPI_SETDESKWALLPAPER` を指定している一行を、キーボードを光らせる API に入れ替えれば良さそうです。英語入力中は暗くて、日本語入力中はスペースバーとか目立つところが赤く光る、ような。

キーボードメーカーによっては情報を公開しているようです。たとえばこちら:

* [ロジクールGデベロッパーラボ](https://gaming.logicool.co.jp/ja-jp/innovation/developer-lab.html)
* [Razer Chroma Workshop](https://www.razer.com/chroma-workshop)
* [CUE SDK](https://corsairofficial.github.io/cue-sdk/)
* [The evolution of Aura RGB lighting leads to an official SDK \| ROG \- Republic of Gamers Global](https://rog.asus.com/articles/technologies/the-evolution-of-aura-rgb-lighting-leads-to-an-official-sdk/)

しかし、各社によって違うということは、一度書いてしまうとほかの会社のキーボードが使えなくなりそうです。そして手元の Realforce で使えなさそうなことも躊躇。

お金の関係もあり試していません。これができれば理想に近いかなと思います。


## 2-2. [無変換] [変換] 相当のカスタマイズできるキーがあるキーボードを使う

セパレートタイプのキーボードや、コンパクトキーボードの中には、親指部分に使えそうなキーが置いていることがあります。たとえばこのあたり。

* [Amazon \| Koolertronプログラム可能分離式メカニカルキーボード 全89キープログラマブルエルゴノミックキーパッド 8マクロキー Cherry MX茶軸 \| Koolertron \| ゲーミングキーボード 通販](https://www.amazon.co.jp/dp/B07QB6L6W5/)
* [Amazon \| Epomaker SK66 60％キー有線（Bluetoothなし）Gateron軸が搭載されたゲーミングメカニカルキーボード RGBバックライトシステム PBT熱昇華プロセスを経ったのキーキャップ NKRO可能メカニカルキーボード\(Gateron赤軸, グレー（ブラック）\) \| GK \| ゲーミングキーボード 通販](https://www.amazon.co.jp/dp/B08BJ3VS73/)
* [SIKAKEYB GS66 AB Red Hat – epomaker](https://epomaker.com/collections/keyboards/products/sikakeyb-gs66-ab-red-hat?variant=31888796647497)

そのキーに `[無変換]` `[変換]` キーを割り当てれば良いかも。試していません。


## 2-4. 親指が使えるエルゴノミクスキーボード

人間工学に基づいたエルゴノミクスキーボード。タッチタイプしやすく作られています。またカスタマイズ性も高いです。親指担当のどこかに `[無変換]` `[変換]` を割り当てればハッピー。

* [Advantage2 Wired Ergonomic Keyboard for Mac & PC \| Kinesis Keyboards](https://kinesis-ergo.com/shop/advantage2/) エルゴノミクスキーボードの代名詞 5万円くらい
* [ErgoDox EZ: An Incredible Mechanical Ergonomic Keyboard](https://ergodox-ez.com/) 4万円くらい

ちょっと気軽に試せる金額では; 親指はそんなに器用に動く指ではなく、親指のキーが多すぎると難しいんじゃないかという思い込みもあります。

見なかったことにしようとしつつも、[高機能エルゴノミクスキーボード「Kinesis Advantage2」の進化がすごかった（1/3 ページ） \- ITmedia NEWS](https://www.itmedia.co.jp/news/articles/2103/29/news108.html) を読むとまた欲しくなります。いやほんと、高嶺の花……。


## 2-5. 自作キーボード

ErgoDox は仕様が公開されていて、自作もできるようになっています。オープンソースのファームウェア [QMK Firmware](https://docs.qmk.fm/#/) を編集すれば、キー配置変更はわりと自由に行えるのも良い感じ。

配置が自由というだけでなく、`[Fn]` キーのように他のキー入力と組み合わせることで、キーの数を減らしたコンパクトキーボードも作れます。Planck キーボードは 47キー。なんだか `[無変換]` `[変換]` の2個の割り当てができなくて困っているのはそもそも方向性が間違っている気分になります。

* [Planck EZ: A Powerful, Backlit, Open\-Source, 40% Mechanical Keyboard \| Planck EZ](https://ergodox-ez.com/pages/planck)

自作キーボードの世界が気になり始めて、こちらを読んでみました。

* [ハロー、自作キーボードワールド \- ITmedia NEWS](https://www.itmedia.co.jp/news/series/16284/) 
* [自作キーボード温泉街の歩き方](https://salicylic-acid3.hatenablog.com/)

あ、これうっかりすると沼りますね; とても気になるものの、いったん離れます。


## 2-6. 英語配列キーボードに物理的に [無変換] [変換] キー相当を付ける

逆方向に振って。普通のキーボードでも、`[無変換]` `[変換]` キーを足せば解決です。

テンキーを外付けするみたいに、スペースキーの下にボタン数4つくらいのマクロキーボードを置けば良いかな、と。

キーボードの下にピッタリ固定するのが大変そうです;


## 2-7. 1つのキーに複数の機能を割り当てられるキーボードを使う

2021年3月に [アナログオプティカルゲーミングキーボード、Razer Huntsman V2 Analog](https://www2.razer.com/jp-jp/gaming-keyboards-keypads/razer-huntsman-v2-analog) が発売されました。

キー入力を押した/押していないの2値ではなく、どれくらいの強さで押したかが分かるようです。キーを弱く押すと `[無変換]` に、強く押すと `[Alt]` になる、というように複数の機能を割り当てられます。

使い勝手はどうなのでしょう。`[Alt]` を押すときに毎回 `[無変換]` `[変換]` どちらかが挟まるとすると不便そうです。iOS の 3D タッチも難しくて無くなったのに、もっと指の力の制御が難しそうなキーボードで2つの機能が使いこなせるのかな…… と。<del>新しいもの好きの方に伺いたいです。</del>

文字入力としてではなくゲーミング用途としてはかなり良いと思います。2キーのコンボ入力が便利そうですし、キーボードでアナログスティック入力みたいなことができるのは魅力的です。


## 2-8. 日本語配列キーボードを英語配列として認識させる

`[無変換]` `[変換]` が普通についているのはやっぱり日本語配列キーボード。`[Enter]` `[BS]` の形は諦めて、記号配列だけでも英語配列にする、というのが落としどころかと思います。

ただし、そのまま使うとキーに書いている記号と入力する文字が違って混乱します。記号も含めて完全に覚えているから大丈夫、という方以外は、どちらかになると思います。

* 日本語配列の無刻印キーボードを買う
  * 間違った配列が書いているくらいなら、何も書いていない方が良いです
* 日本語配列キーボードのキーを取り外して、英語配列のキートップに取り換える

メカニカルキーボードならキートップだけでたくさん売っています。たとえば FILCO ですとお手頃価格で購入できます。

* [キーキャップの一覧 FILCO取り扱いキーキャップ \| ダイヤテック株式会社](https://www.diatec.co.jp/products/keycap/)

こちらでも Realforce に問題が。キーキャップだけで売っていることが少なく、売っていても 1万円以上します。実質、日本語配列キーボードと英語配列キーボードの2つを購入して混ぜることに。6万円コースですよ; 

![keyboard-layout.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/575077fa-16de-ff8c-70e9-d88771faffe8.png)

ちなみに Windows で日本語配列キーボードを英語配列とするのは、設定から簡単に行えます。しかし英語配列キーボードにないキーは、そのままでは押してもキー未割り当て扱いになり、反応しません。`[無変換]` `[変換]` はその反応しないキーです。

こちらを `[無変換]` `[変換]` として認識させるには次のような回り道を取ります。

* ScanCode Map で、 `[無変換 0x83]` `[変換 0x84]` を `[F13 0x64]` `[F14 0x65]` 相当に変換する。これらのキーは英語配列で扱える。
* [Microsoft PowerToys \| Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/powertoys/) などのキーフック系ツールで `[F13]` `[F14]` を `[無変換]` `[変換]` 相当に割り当てる

ほかにも日本語配列と英語配列の中間のような AX配列を使う方法もあるようです。これはそのまま `[無変換]` `[変換]` キーを扱えます。でもこのドライバーを設定するより、上の手順の方が楽だと思います。

日本語配列キーボードとして認識したまま、キーフックアプリ ULE4JISで文字を入れ替えるという方法もあります。日本語配列のままですから  `[無変換]` `[変換]` が使えます。レイアウト変更後の再起動がなくアプリを起動するだけで簡単です。記号を伴うショートカット動作に違和感を得ることがあるかもしれません [^1] 。

* [ULE4JISの詳細情報 : Vector ソフトを探す！](https://www.vector.co.jp/soft/winnt/util/se476294.html)
* [dezz/ULE4JIS](https://github.com/dezz/ULE4JIS) 


## 2-9. キーボードを買い換えて解決 まとめ

選択肢はいろいろありますけれど、どの方針でも1万円以上の出費です。そこで中途半端な対応になるくらいなら、ガチなエルゴノミクスキーボードを用意したくなります。もっとお金がかかります。
 
というわけで日和って、次に進みます。


# 案3. 普通の英語配列キーボードに、 [無変換] [変換] キー相当を割り当てる

2-2. のコンパクトキーボードのことを考えると、普通の英語配列キーボードに、 `[無変換]` `[変換]` キー相当を割り当てるのは難しくないはず。101 キーがあります。

考えることが2点あります。

* 仕様: キー配置をどこにするか
* 実装方法: キーボードからOSに渡る仕組みのどこで差し替えるか

## 3-1. 仕様: キー配置をどこにするか

`[無変換]` `[変換]` は良く押しますから、1キーで切り替えられると便利です。

`[Ctrl]` `[Alt]` `[Shift]` といった修飾キーの空打ちを考えます。まずは方法は考えず

### 3-1-a. [左Alt] [右Alt] それぞれ空打ち

* Pros.
  * `[無変換]` `[変換]` と場所が近い
  * 左右対称で分かりやすい
  * alt-ime-ahk と同じ
* Cons.
  * `[Alt]` 単独押しが使えなくなる
    * たまにメニューバーやリボンにフォーカスを当てたくなることがあります
  * うっかり `[Alt]` と次のキー入力を同時押しすると意図しないメニューが実行されてしまう

### 3-1-b. [左Shift] [右Shift] それぞれ空打ち

* Pros.
  * 左右対称で分かりやすい
  * `[Shift]` 単独押しは効果がないはずなので、安心して使える
* Cons.
  * `[右Shift]` は押しづらすぎます
  * `[Shift]` を押しながらマウスクリックしても、キーボード的には空打ちとみなされ、`[無変換]` `[変換]` 扱いになりそう
    * 複数行選択などで良く行います

### 3-1-c. [左Ctrl] [右Ctrl] それぞれ空打ち

同上です。

### 3-1-d. [左Shift] [左Ctrl] それぞれ空打ち

* Pros.
  * `[Shift]` `[Ctrl]` どちらも単独押しは効果がないはずなので、安心して使える
* Cons.
  * 左右対称でなく混乱
  * `[Shift]` `[Ctrl]` を押しながらマウスクリックしても、キーボード的には空打ちとみなされ、`[無変換]` `[変換]` 扱いになりそう
  * ただでさえ忙しい左手小指がさらに忙しくなります

### 3-1-e. 結論: [左Alt] [右Alt] それぞれ空打ち

Cons. は次に考えます。

## 3-2. 実装方法: キーボードからOSに渡る仕組みのどこで差し替えるか

キーボードを押したあと、アプリでその文字が入力されるまでに、だいたい次の流れを通ります。

```
[キーボード]
  キー入力
    ↓
    ↓ (CapsLock を押した・離した)
    ↓
  キーボード ファームウェア [※4]
    ↓
    ↓ スキャンコード (0x3A を押した・離した)
-------- 物理の壁 --------
[OS カーネルモード]
    ↓
  デバイスドライバー  [※3]
  キーボードドライバー ← レイアウト(日本語, 英語, ...)
    ↓              ← ScanCode Map [※2]
    ↓ 仮想キー (VK_CAPITAL を押した・離した)
 -------- カーネル/ユーザーモードの壁 --------
[OS ユーザーモード]
    ↓
  (フック系アプリ) [※1]
    ↓
    ↓ 仮想キー (VK_CAPITAL を押した・離した)
    ↓
  各アプリで使用
```

差し替えられる場所は※の4か所です。

|階層|例|
|:--|:--|
|※1 フック系アプリ|Microsoft PowerToys, AutoHotKey|
|※2 ScanCode Map (レジストリ)|レジストリ エディター, ...|
|※3 デバイスドライバー|のどか|
|※4 ファームウェア|QMK|

それぞれの場所でキーの情報を加工して次に渡しています。この中で特記したいことは、キーボードドライバーがキーを別のキーとみなすことです。

```
[キーボード]
  キー入力
    ↓
    ↓ (Shift を押した) (CapsLock を押した)
    ↓
  キーボード ファームウェア [※4]
    ↓
    ↓ スキャンコード (0x2C を押した) (0x3A を押した)
-------- 物理の壁 --------
[OS カーネルモード]
    ↓ 
  デバイスドライバー  [※3]
  キーボードドライバー ← レイアウト(日本語, 英語, ...)
    ↓              ← ScanCode Map [※2]
    ↓ 仮想キー (VK_LSHIFT を押した) (VK_OEM_ATTN を押した)
-------- カーネル/ユーザーモードの壁 --------
[OS ユーザーモード]
    ↓
  (フック系アプリ) [※1]
    ↓
    ↓ 仮想キー (VK_LSHIFT を押した) (VK_OEM_ATTN を押した)
    ↓
  各アプリで使用
```

`[Shift]+[CapsLock]` という組み合わせで入力したはずが、`VK_OEM_ATTN` = `[英数]` という別のキーを押したことにされます。そして押したときだけこう変換され、離したときは処理されません。そうすると下流にとっては、いつ英数キーを離したかが取れません。

良い場所にあってあまり使わない `[CapsLock]` を別のキーに差し替えようと思っても、この理由により、下流では差し替えるとおかしなことになってしまいます。

なら上流で行えばよいかというと、上流ほど生のデータが流れていて、処理が面倒です。また、取れる情報が少ないです。キーボード内では IME オン/オフ は知らないです、とか。

このような前提をもとに、下流から順に、どこで差し込むのが良いか考えます。


### 3-2-a. フック系アプリ

`[Alt]` に割り当てるなら、定番の alt-ime-ahk でだいたい完璧です。ダウンロードして exe を実行するだけ。簡単すぎます。

しかしそのまま使うには困るところがあります。

「素早く入力すると Alt が入ってしまいがち」

alt-ime-ahk は 1つのキーに「IME on」と「Alt」の機能を持たせるために、「Alt を空打ちしたとき = Alt を離した時」にモードが確定します。

そうすると、急いで打っているときに順番が `[Alt ↓]` `[F↓]` `[Alt ↑]` `[F ↑]` `[A ↓]` `[A ↑]` のようになってしまうと、`[Alt]+[F]` `[A]` というメニューが誤爆します。

日本語配列キーボードの  `[無変換]` `[変換]` は押した瞬間に発動します。 `[変換 ↓]` `[F↓]` `[変換 ↑]` `[F ↑]` `[A ↓]` `[A ↑]` は IME on 後に `ふぁ` と入ります。これは普通です。

誤爆によっては無害で済みます。けれど、ファイルを保存したりウィンドウを閉じたりされるととてもきつい……。
 `[Alt ↓]` `[Alt ↑]` でワンテンポ待てると良いですが。だいたい忘れたころにこのミスをやってしまいますと。

alt-ime-ahk に限らず、1つのキーに複数の機能を割り当てようとすると、どうしても付きまとう問題だと思います。この一点だけでも、日本語配列キーボードを諦めるのは勿体ないと思います。

お手軽さは下がりますが、alt-ime-ahk を動かしている土台の [AutoHotkey](https://www.autohotkey.com/) を手に入れて、自作することもできます。キーボードカスタマイズアプリの定番で、マクロなど複雑なこともできます。alt-ime-ahk のソースコードを参考にできます。


### 3-2-b. ScanCode Map

ScanCode Map というレジストリーの場所に設定を書くことで、Windows 標準の仕組みでキー配置を入れ替えできます。

レジストリーの書き換えに失敗すると、最悪 Windows が動かなくなります。設定には要注意です。または Change Key などのアプリを使うと安全です。

ScanCode Map はただ入れ替えるだけで、それ以上のことはできません。OS が扱えない・おせっかいな対応をするキーを `[F13]` などの素直なキーに割り当てる、などに使います。

`[Ctrl]` と `[CapsLock]` をここで入れ替える方も多いと思います。 `[CapsLock]` の方が押しやすい場所、ということで。

ScanCode は AutoHotKey でも調べられます。日本語配列キーボードを英語配列設定にして、`[LAlt]` `[RAlt]` `[無変換]` `[変換]` の順番に押した結果がこちら。

![scancode-success.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/64f08c83-19cd-8cc6-c8c3-bd2c4eb8794f.png)

|仮想キー|ScanCode|Up/Down|物理的な入力キー|
|---|---|---|---|
|0xF4 (VK_LMENU)|0x038|d, u|`[LAlt]`|
|0xA5 (VK_RMENU)|0x138|d, u|`[RAlt]`|
|0xEB|0x07B|d, u|`[無変換]`|
|0xFF|0x079|d, u|`[変換]`|

`[無変換]` `[変換]` は知らない仮想キーに割り当てられます。 `[BS]` 隣の `[\]` も 0xFF で、仮想キーの世界ではもう区別できません。でも ScanCode は別ですから、ScanCode Map を設定すれば使えるようになります。

もう1つ、3-2. 最初でも挙げた、日本語配列キーボードで `[CapsLock]` `[Shift]+[CapsLock]` `[Shift]+[CapsLock]` の順に入力した例を。

![scancode-failed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118172/cfe6f747-259b-b1ec-8f63-27f289871e75.png)

|仮想キー|ScanCode|Up/Down|物理的な入力キー|
|---|---|---|---|
|0x14 (VK_CAPITAL)|0x03A|d, u|`[CapsLock]`|
|0xA0 (VK_LSHIFT)|0x02A|d|`[左Shift ↓]`|
|0xF0|0x03A|d のみ|`[英数]` (IME オフにする)|
|0xA0 (VK_LSHIFT)|0x02A|u|`[左Shift ↑]`|
|0xA0 (VK_LSHIFT)|0x02A|d|`[左Shift ↓]`|
|0xF2|0x03A|u のみ|`[英数]` (IME オンにする)|
|0xF0|^|d のみ|^|
|0xA0 (VK_LSHIFT)|0x02A|u|`[左Shift ↑]`|

たしかに `[英数]` 扱いが特殊だと分かります。困ったものです。

* 参考
  * [Keyboard and mouse class drivers \- Windows drivers \| Microsoft Docs](https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/keyboard-and-mouse-class-drivers#scan-code-mapper-for-keyboards)
  * [HKEY\_LOCAL\_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout](https://answers.microsoft.com/en-us/windows/forum/windows_7-desktop/remap-keyboard-with-scancode-map-for-current-user/34abda0d-721a-4e27-b9a4-044f34dc113a)
    * ユーザー設定 HKCU は Windows 10 ではできません。システム設定 HKLM だけです。
  * [Virtual\-Key Codes \(Winuser\.h\) \- Win32 apps \| Microsoft Docs](https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes)
  * [https://forest.watch.impress.co.jp/library/software/changekey/](「Change Key」非常駐型でフリーのキー配置変更ソフト - 窓の杜)


### 3-2-c. デバイスドライバー

デバイスドライバーでキーレイアウトを変更するというと、[Applet LLC](https://appletllc.com/) で頒布されている、のどか。フック系アプリと違い、`[CapsLock]` が違うキーになっていた、ということで悩むことがなくなります。

しかしこの場所では扱いにくいです。ドライバーが適切に動くか、Windows が厳しく確認しています。なにせカーネルモードで動くということは、OSをクラッシュさせる、OS のセキュリティーホールになりかねない、というもの。安心して使えることが分かるように、ドライバーには署名が必要。気軽には入れられません。

Windows 10Xでさらに厳しくなりそうですし。

* 参考
    * [Windows ドライバーの概要 - Windows drivers | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows-hardware/drivers/develop/getting-started-with-windows-drivers)


### 3-2-d. ファームウェア

自作キーボードで定番の QMK firmware なら、タップと長押しで挙動を切り替えるというようなカスタマイズは簡単。たぶん `ALT_T(KC_F13)` です。コンパクトキーボードで望まれる機能が揃っています。

QMK firmware の場合はある程度のプログラミングが必要そうです。単純なキー割り当てだけではない場合。まあでもプログラミングをお仕事や趣味にしている人なら大丈夫でしょう。

当然ながら、普通に購入できるキーボードの多くには、カスタマイズ可能なファームウェアは組み込まれていない、ということです。そりゃそうです。そんな内臓を触らせてキーボードが文鎮と化したらどうにもなりません。

そうすると、この方針なら自作キーボードとセットでしょうか。

いえ、このように中継器を挟めば、手元のキーボードでもできるはず。

```
[キーボード]
  キー入力
    ↓
    ↓ (CapsLock を押した・離した)
    ↓
  キーボード ファームウェア [触れない]
    ↓
    ↓ スキャンコード (0x3A を押した・離した)
-------- 物理の壁 --------
[中継器]
    ↓
  キーボード ファームウェア [※4]
    ↓
    ↓ 変換後のスキャンコード (違うキーを押した・離した)
-------- 物理の壁 --------
[OS カーネルモード]
    ↓
  デバイスドライバー  [※3]
  キーボードドライバー ← レイアウト(日本語, 英語, ...)
    ↓              ← ScanCode Map [※2]
    ↓ 仮想キー (VK_CAPITAL を押した・離した)
 -------- カーネル/ユーザーモードの壁 --------
[OS ユーザーモード]
    ↓
  (フック系アプリ) [※1]
    ↓
    ↓ 仮想キー (VK_CAPITAL を押した・離した)
    ↓
  各アプリで使用
```

そんな中継器があれば……

[Keyboard Quantizer \- のぎけす屋 \- BOOTH](https://booth.pm/ja/items/2256612)

ありました! これならお手頃で、自作キーボードの入り口にも良さそうです。

でも残念ながら品切れでした。試していません。


### 3-2-e. 方針: フック系アプリ

フック系アプリ AutoHotKey を使って、alt-ime-ahk をベースに、困っていることに対応しようとしてみます。


# TL;DR (再掲)

* よほど英語配列にしたい場合以外は、日本語配列キーボードがまずおすすめ。`[無変換]` `[変換]` キーはとても便利。これを捨てるのは大きな犠牲。
* 英語配列キーボードを使うなら、定番の [karakaram/alt\-ime\-ahk](https://github.com/karakaram/alt-ime-ahk) がおすすめ。
* それ以外を目指すなら、ようこそ茨の道へ。

という茨の道を進むエントリに続きます。