2014年10月6日月曜日

[windows][emacs] Windows 8.1上で(特定ユーザーログイン時に)任意のアプリの操作をemacsキーバインドにする方法

windows 8.1上のすべての操作をemacsキーバインドにできないか、と思ってネット上の情報を探したところ、keyhacというぴったりのツールが見つかりました。カスタマイズが自由&簡単、かつクリップボード履歴機能つき!

自分としては以下の設定ができれば目的達成です。
  • CapsLockをCtrlキーに
  • IMEのon/offを変換キーで
  • カーソル移動・クリップボード関連操作などをemacsキーバインドに
  • 可能であれば特定ユーザー(自分のアカウント)ログイン時のみ限定したい・・・
こちらのブログで紹介されているpythonスクリプトを、keyhac.exeと同じディレクトリにconfig.pyという名前で保存するだけでemacsキーバインドが実現できました。感謝。

config.pyのカスタマイズ方法:

せっかくなのでkeyhacのconfig.pyによるカスタマイズ方法を簡単に紹介しておきます。
config.pyでは任意のアプリ上のオリジナルのキー操作をpythonスクリプトで記述することができ、それをkeyhac上のキー操作に割り当てることで、キーバインドを実現しています。
たとえば「ペースト」はyank()という関数で以下のように定義されています。
    
            def yank():
                keymap.command_InputKey("C-v")()
                keymap_emacs.is_mark = False
    
    
それをkeymap_emacsでCtrl-yにバインドしています。
    
            keymap_emacs["C-y"]             = reset(yank)
    
    
上記のような感じで、簡単に設定が可能です。以下、自分の環境にあわせて追加した設定を紹介しておきます。
  • IMEのon/offを変換キーに割り当てる
  • 
        keymap.replaceKey( 28, 243 )
    
    
  • config.pyの編集には秀丸を利用(※"\"はエスケープが必要)
  • 
        keymap.editor = u"C:\\Program Files\\Hidemaru\\Hidemaru.exe"
    
    
  • キーバインドを変更しないアプリにexplorerとemacs-X11を追加
  • 
        def is_emacs_target(window):
            if window.getProcessName() in (# skip...
                                           "explorer.exe",       # explorer
                                           "emacs-X11.exe",      # Emacs-X11
    
    
    
  • ついでにforward/backward wordとdelete wordの定義を追加
  • 
        def forward_word():
            keymap.command_InputKey("C-Right")()
        def backward_word():
            keymap.command_InputKey("C-Left")()
        def delete_word():
            keymap.command_InputKey("C-S-Right")()
            kill_region()
            keymap_emacs.is_mark = False
        def delete_backward_word():
            keymap.command_InputKey("C-S-Left")()
            kill_region()
            keymap_emacs.is_mark = False
    
        keymap_emacs["A-b"]             = repeat(mark(backward_word))
        keymap_emacs["A-f"]             = repeat(mark(forward_word))
        keymap_emacs["A-d"]             = reset(delete_word)
        keymap_emacs["C-Back"]          = reset(delete_backward_word)
    
    

keyhacで実現できないキーバインド:

残念ながら、[Ctrl]と[Caps Lock]の入れ替えのみ、keyhacでは実現できませんでした。これは、ドライバのレイヤで、[Caps Lock]のUPイベントを抑制しているのが原因のようです。keymap.replaceKey( "LCtrl", 240 )という設定をしても意図した動作になりません。
仕方がないのでここの情報に従いレジストリをいじって、[Caps Lock]をつぶして[Ctrl]にすることで対応しています。入れ替えではなく上書きなので、本来の[Ctrl]と[Caps Lock]の両方が[Ctrl]の役割を持っている状態です。このため[Caps Lock]に[Ctrl]に割り当てる設定だけは、特定ユーザー限定という設定ができませんでした。

(2014/10/06追記)
C-k, A-d, C-BSなど範囲選択後、切り取りをするスクリプトはタイミング依存の問題(?)があるようで、keyhacの「内部デバッグ」をOFFにしていると、期待通り動作しないようです。手元の環境ではONにしていると動作しています(が、動作がのろくなるのでOFFにしたい・・・)。

(2016/01/11追記)
Caps LockにCtrlキーを割り当てる手順

  • regeditで以下のキーにScancode Mapという名前でバイナリ値を設定
    • HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout
  • 格納するバイナリ値のデータは以下の通り
    • 00 00 00 00 00 00 00 00
    • 03 00 00 00 1D 00 3A 00
    • 3A 00 3A 00 00 00 00 00

keyhac.iniを修正しコンソールウィンドウを非表示に:

デフォルトではkeyhac起動時、コンソールウィンドウが表示されます。このウィンドウを非表示にするには、keyhac.exeが存在しているディレクトリに生成されているkeyhac.iniの[console]セクションに記述されているvisible=1をvisible=0に設定すればOKです。ただし、この設定は公式ドキュメントには記載されていないようなので、自己責任でお願いします。

参考:

ちなみにmacではKarabiner(旧KeyRemap4MacBook)をインストールすれば、簡単にemacsキーバインドが実現できます。