pit-rayの備忘録

知識のあうとぷっと

WindowsのためのVimキーバインディングツール ー win-vind 4.0

先日、win-vindの4.0.0をリリースしたので、その更新内容を書きます。

win-vindとは

 WindowsをVimライクに操作するための常駐ツールです。機能は次の通りです。

  • 独自の高速なバインディング機構
  • Vimライクなモード管理
  • マウスレスでGUIを操作
  • WebのフォームやOffice WordなどでVimライクなテキスト編集
  • ターミナルを開かずに、ターミナルを操作 (常駐ターミナル)
  • .vimrcライクな設定
  • ユーザ権限内でのキーリマッピング
  • VimやAutoHotKeyからのワンショット呼び出し

言い換えれば、バインディングと様々なユーティリティが備わったツールです。とりわけ、Vimユーザにとっては学習コストが小さいことが特徴です。

GitHub github.com

ホームページ pit-ray.github.io

導入方法

まず、ホームページからダウンロードします。インストーラ版は、一般的なソフトウェアと同様にシステムにインストールされ、スタートメニューに追加されます。この時、設定ファイルはユーザディレクトリの~/.win-vind内に生成されます。一方、zip版は、解凍したルートディレクトリ以外に一切のファイルを生成しません。ただし、Windowsの起動時に起動するようにすると、例外的にスタートアップにショートカットファイルが生成されます。

Downloads - win-vind

win-vindを起動すると--Insert Mode--と表示され、タスクトレイにアイコンが表示されるはずです。

https://github.com/pit-ray/win-vind/blob/gh-pages/imgs/taskbar.jpg?raw=true

この状態でのキーバインディングは、次のようになっています。

Insert Mode - win-vind

使い方

 Vimとは異なり、NormalモードとVisualモードが2つあるのが少し曲者ですが、基本的な概念はVimに基づいています。

https://github.com/pit-ray/win-vind/blob/gh-pages/imgs/mode_overview.png?raw=true

左のGUIモードはUIを操作するためのモードで、右のEditorモードはWebページの入力フォームやOffice WordなどでVimのエミュレーションを行うためのモードです。

https://github.com/pit-ray/pit-ray.github.io/blob/master/win-vind/imgs/GUIandEditor.jpg?raw=true

 初めに示したモードの概念図には、Residentモード(常駐モード)があります。これは、言い換えればwin-vindをオフにするためのモードで、基本的にはこのモードにバインディングを登録しないことを前提としています。例えば、Insertモードからそれぞれのモードへの移行は、<Esc-*>という形式のコマンドですが、忠実なVimエミュレーションを行うためにEdi Normalを<Esc>にマップすると、他のアプリケーションへの<Esc>でwin-vindが反応してしまいます。この問題は、Residentモードに退避することで回避できます。ちなみに、Vimを触ったらResidentモードに自動で移行するsuppress_for_vimというオプションもあります。ただ、デフォルトではResidentモードを使う必要はありません。

 InsertモードとResidentモードは、全てのキー入力を他のアプリケーションにも渡しますが、GUI Normalモード、GUI Visualモード、Edi Normalモード、Edi Visualモード、Commandモードは入力をブロックし、吸収します。

https://github.com/pit-ray/win-vind/blob/gh-pages/imgs/mode_overview_3D.png?raw=true

次のページに短いチュートリアルがあります。

Usage - win-vind

v4の更新内容

.vimrcスタイルの設定

 v4から以前のjsonファイルを利用した網羅的な設定や複雑なGUIを廃止し、Run Commands形式の設定を採用します。利用できるコマンドや記述法を次に示しますが、英語のホームページの内容が最新かつ詳細です。

{モード}モードの接頭辞に相当します。

コマンド 構文 ({}自体は含まれません) 効果
set set {オプション名} オプションの値をtrueに設定します。
set no{オプション名} オプションの値をfalseに設定します。
set {オプション名} = {値} オプションの値を設定します。値には文字列か小数点を含む数字が利用できます。文字列にクオーテーションは必要なく、=以降の空白以外の文字以降が値として扱われます。また、=の両端のスペースは全て無視されます。
map {モード}map {入力キー} {出力キー} 現在、一つのキーから一つのキーのマッピングのみサポートされています。このコマンドは、低レベルなマッピングを行うため、Windows全体としてキーがマッピングされます。ユーザー権限内でも利用できます。
noremap {モード}noremap {コマンド} {機能ID} IDで指定した機能のコマンドを定義します。IDはチートシートを参照してください。
{モード}noremap {入力キーセット} {出力キーセット} 現在、キーセットからキーセットのマッピングのみサポートされています。ただし、機能IDをによるコマンド定義の方が優先度が高いため、一回のリマップが生じる可能性があります。例えば、
inoremap k move_cursor_left
inoremap f k
と.vindrcに記述したとします。すると、fは、move_cursor_upではなく、move_cursor_leftにマップされます。
unmap {モード}unmap {コマンド} コマンドに対応するマップを削除します。
mapclear {モード}mapclear そのモードのマップを全て削除します。
command command {コマンド} {機能ID} IDで指定した機能のコマンドを定義します。ここで指定したコマンドは:{コマンド}で呼び出せるようになります。IDはチートシートを参照してください。
delcommand delcommand {コマンド} 指定されたコマンドのマップを削除します。
comclear comclear 全てのコマンドのマップを削除します。

 以上のコマンドを.vindrcを記述するか、仮想コマンドラインで:set initmode=rのように実行することで、設定できます。ちなみに、インストーラ版では~/.win-vind/.vindrc、zip版ではwin-vind/config/.vindrcにあります。

低レベルなキーマッピング

 imap <capslock> <ctrl>のような構文で、低レベルなキーマッピングを行います。このキーマッピングの大きな特徴は、ユーザ権限内で利用できることと、トグルキーを通常のキーのように動作させることができる点です。例えば、AHKやPowerToysなどのキーマッピングでは、トグルキーにマッピングしたキーが押下状態のままになってしまうことが多々あります。対して、このマッピングではトグルキーの押下状態をモニタリングし、疑似的な押下状態の開放を行います。

 テスト段階では、非常に低負荷で動作しており、実用上の問題はありません。ただ、実装で述べているように、トグルキーの開放には数ミリ秒の遅延があります。この点、プルリクエストをお待ちしております。

ウィンドウを対話的に操作

f:id:pit-ray:20210624214823g:plain
Window Resizer Demo
 Vimのプラグインwinresizerに強く影響された機能です。

github.com

 デフォルトのバインディングはGUIノーマルモードで<C-w>eです。呼び出すと、リサイズ、移動、選択の3つのサブモードからなるウィンドウリサイザを利用できます。eキーでそれぞれのモードを切り替えることができ、どれもhjklによるスムーズな操作を行えます。ちなみに、ウィンドウリサイザの初期モードは、winresizer_initmodeオプションで変更できます。

set winresizer_initmode = 0 " リサイズモード
set winresizer_initmode = 1 " 移動モード
set winresizer_initmode = 2 " 選択モード
プロセス実行系の強化

ShellExecuteのラッパ
 まず、Windowsの有名なAPIであるShellExecuteのラッパを追加しました。デフォルトでは、:execute, :e, :editにマッピングされています。ShellExecuteは、エクスプローラでアイコンをダブルクリックしたのと同様の処理を行うAPIで、指定したファイルに関連付けられたアプリケーションでファイルを開きます。

 例えば、:e ~/.vimrcという風に実行すると、Vimで.vimrcファイルを開きます。URLも同様で、:e https://www.google.comのように実行すると、ブラウザでGoogleのトップページが開かれます。

:!コマンドの拡張
 :!コマンドの動作が、Vimとほぼ同じような動作になりました。従来のwin-vindは、事前に登録したエイリアスに従ってプロセスを起動する陳腐なものでしたが、v4からは指定したターミナルを介してプロセスを起動します。

 加えて、:!:shell:terminalなどのターミナルを起動するコマンドは、エクスプローラのウィンドウを選択しながら実行することで、そのディレクトリをカレントディレクトリとして起動します。

新たなオプションは、次の通りです。

set shell = powershell
set shellcmdflag = -c
set shell_startupdir = C:/Users  "このオプションを利用すると、カレントディレクトリが固定されます
インスタントモード

 一時的にGUIノーマルモードに移行し、コマンドを処理したら元のモードに戻る特殊なモードです。デフォルトのバインディングは、インサートモードで<F8>で、マップリーダのように利用します。例えば、インサートモードにいるとき<F8>FFと入力すると、このモードを介してGUIノーマルモードの機能であるEasyClickを呼び出すことができます。

 この機能が必要になった経緯は、インサートモードがキー入力を吸収しないという特性によるものです。インサートモードでのバインディングは、コマンドが他のアプリケーションのショートカットキーになっていないか、テキストとして入力されないかを意識しなければならず、その組み合わせに限りがあります。その点、このインスタントモードを活用すれば、GUIノーマルモードだけを管理すれば良くなります。

その他
  • --helpオプションを追加しました。
  • キーボードの配列を自動検出するようになりました。
  • タスクトレイに「起動時に起動するかどうか」ボタンを追加しました。
  • タスクトレイに更新確認ボタンを追加しました。
  • 従来のGUIを廃止することで、win-vindが高速に起動するようになりました。
  • 高速でキー入力をすると、キーが押下状態だと誤解する問題を修正しました。
  • ある状況において、1回のバックスペース入力で、仮想コマンドラインの文字が複数消える問題を修正しました。

最後に

 今回のバージョンアップのテーマは、導入コストを減らす普段使いに溶け込むです。特に、rcスタイルの設定は、懸念していたカスタマイズ性や学習コストの問題を大幅に解消できたと思います。今後の課題は、mapやnoremapのコマンドからコマンドへのマッピングや、トグルキーの遅延の問題などがありますが、のんびり改善していけたらと思います。