MacBookを買ったら初めにやりたいKeyRemap4MacBookの設定

MacBook

もう一週間前になるんですが、MacBook買いました。性能的にはさほど変わらないのに、価格は3万円ぐらい安くてお得な白ポリカのMacBookです。アルミよりも少し重い(公称で約200g)のが残念だけど、見た目的にもキータッチもこちらの方が好みだったので。今のところVMware Fusionも購入せず、メモリも標準2GBのままです。購入したのはATOKとディスプレイアダプタだけ。

Motorola insideなMac miniは持っていて、これが2台目のMacです。ハードウェアの非力さと、当時は自分にとって必要な環境を整えられるだけのソフト資産が無かったので挫折してしまいました。あれから2年以上経って、さて今度の挑戦はどうなるか。Windowsを捨てるのは難しいにしても併用まで行ければいいな。


僕はWindowsをやたらめったらカスタマイズしていて、それがWindowsに縛られる大きな要因になっていました。特に困っていたのがキー配列のカスタマイズでしたが、今はKeyRemap4MacBookなんて便利な物があるということなので、これを試してみました。

設定はファイルに書くのではなく、基本的には用意されているメニューから項目を選ぶ形になります。ここで、

  • 「英数」キーに「ESC」を割り当て
  • 「かな」キーでIMEのON/OFFをトグル切り替え

を選択。IMEのON/OFFを「かな」「英数」で明示的に指定、というMacのアプローチに魅力は感じながらも、ESCが親指で押せるというのはvimを使う上で自分にとって外せない要素なので、ここはWindowsと同じ設定に。あとは、キーリピートとかそれなりの値に調整しておく。

で、ここからが本番。僕はかな入力なのでキーボードは必然的に日本語キーボードになります。それ以外でも、

  • リターンキーは大きい方が安心感がある
  • スペースキーが長いことより、キーが多い方が便利

あたりの理由があって、今のところ英語キーボードを使う見込みはありません。

でも記号の配置に関しては、確かに英語配列の方が優れていると感じる部分も多いです。よろしい、ならばカスタマイズだ。

元のキー 変換後 +SHIFT
@ [ {
[ ] }
] ' "
2 2 @
^ = ^
ESC ` ~

だいたいこんな感じのキーマップにしたい。

単純にキーを入れ替えるだけだと、日本語入力の時に「゛」「゜」「む」あたりの配列が変わってしまうのでNG。日本語入力は標準のままでやりたい。UbuntuAnthyを使った時は、かな入力のマッピングを変更できたけど、Mac + ATOKではそういう設定は見当たらない。なので、キーマップを変更するソフトの側で面倒を見てやる必要がある。

Windowsだと窓使いの憂鬱の設定ファイル書けば済むけど、KeyRemap4MacBookでメニューにない設定をするにはソースを書き換えてmakeし直す必要があります。Mac版のmayuも出てるんだけど、どうやらIMEの状態を取得するモディファイアが効いていないようなので見送り。

で、ソースを眺めてると何となく書き方が分かってきました。

  • IMEの状態はJISKanaMode::getMode()で取得する
    • JISKanaMode::JISKANAMODE_ASCII, JISKanaMode::JISKANAMODE_HIRAGANA, JISKanaMode::JISKANAMODE_KATAKANAのいずれかが取れる
    • ATOKでもちゃんと動作した(全角アルファベット入力が取れるのかは不明)
  • KeyCodeは英語キーボードを基準に定義してあるので、日本語キーボードだとキー名とコードが違う
    • 公式にある方法でキーコード調べた
  • SHIFT押し下げ状態はFlagStatus::temporary_increase, FlagStatus::temporary_decreaseで制御する
    • SHIFT状態をシミュレートするにはKeyDown時にincreaseして、KeyUp時にdecreaseする
    • 「SHIFTを離す処理」を入れておかないと、ソフト的にSHIFTがロックされてしまう

そのあたりを踏まえつつ、個別の設定にするのも面倒なので、こんな関数にまとめました。もっとスマートな書き方はいくらでもあるだろうけど、ひとまず目的を達成することだけを優先。そもそもCとか15年ぐらい前にHDD無しのX68kでHelloWorldのコンパイルに2分ぐらい待たされて挫折して以来なので、全く分からん。

  void
  remap_nekoya_custom(const RemapParams &remapParams)
  {
      if (! config.remap_nekoya_custom) return;
      if (JISKanaMode::getMode() != JISKanaMode::JISKANAMODE_ASCII) return;

      // brackets
      RemapUtil::keyToKey(remapParams, KeyCode::BRACKET_LEFT, KeyCode::BRACKET_RIGHT);
      RemapUtil::keyToKey(remapParams, KeyCode::BRACKET_RIGHT, KeyCode::BACKSLASH);

      // quotes
      if (RemapUtil::isKey(remapParams, KeyCode::BACKSLASH) && !FlagStatus::isHeldDown_shift()) {
          if (RemapUtil::isKeyDown(remapParams, KeyCode::BACKSLASH)) {
              FlagStatus::temporary_increase(ModifierFlag::SHIFT_L);
          } else {
              FlagStatus::temporary_decrease(ModifierFlag::SHIFT_L);
          }
          RemapUtil::keyToKey(remapParams, KeyCode::BACKSLASH, KeyCode::KEY_7);
      } else {
          RemapUtil::keyToKey(remapParams, KeyCode::BACKSLASH, KeyCode::KEY_2);
      }

      // atmark
      if (RemapUtil::isKey(remapParams, KeyCode::KEY_2) && FlagStatus::isHeldDown_shift()) {
          if (RemapUtil::isKeyDown(remapParams, KeyCode::KEY_2)) {
              FlagStatus::temporary_decrease(ModifierFlag::SHIFT_L);
              FlagStatus::temporary_decrease(ModifierFlag::SHIFT_R);
          }
          RemapUtil::keyToKey(remapParams, KeyCode::KEY_2, KeyCode::BRACKET_LEFT);
      }

      // escape
      if (RemapUtil::isKey(remapParams, KeyCode::ESCAPE) && !FlagStatus::isHeldDown_shift()) {
          if (RemapUtil::isKeyDown(remapParams, KeyCode::ESCAPE)) {
              FlagStatus::temporary_increase(ModifierFlag::SHIFT_L);
          } else {
              FlagStatus::temporary_decrease(ModifierFlag::SHIFT_L);
          }
          RemapUtil::keyToKey(remapParams, KeyCode::ESCAPE, KeyCode::BRACKET_LEFT);
      } else {
          RemapUtil::keyToKey(remapParams, KeyCode::ESCAPE, KeyCode::EQUAL);
      }

      // ^
      if (RemapUtil::isKey(remapParams, KeyCode::EQUAL)) {
          if (! FlagStatus::isHeldDown_shift()) {
              if (RemapUtil::isKeyDown(remapParams, KeyCode::EQUAL)) {
                  FlagStatus::temporary_increase(ModifierFlag::SHIFT_L);
              } else {
                  FlagStatus::temporary_decrease(ModifierFlag::SHIFT_L);
              }
              RemapUtil::keyToKey(remapParams, KeyCode::EQUAL, KeyCode::MINUS);
          } else {
              FlagStatus::temporary_decrease(ModifierFlag::SHIFT_L);
              FlagStatus::temporary_decrease(ModifierFlag::SHIFT_R);
          }
      }
  }

これでキー配列の問題が解決して、まずは第一段階突破。次はRealForceをつないだ時のキー配列かな。