pit-rayの備忘録

知識のあうとぷっと

WindowsでVimライクにウィンドウを操作

以前公開したソフトをアップデートをしました。その更新内容と補足内容です。

前の記事 www.pit-ray.com

GitHub github.com

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

目次

バージョン3.2

今回のアップデートではウィンドウの操作に関連した機能を強化しました。ここでは網羅的に書きます。

変更点

 まず、GUIオブジェクトをVimiumのようにヒンティングするEasyClickという機能の無駄な処理を省いたため、スキャン時間が3分の1程度まで短縮され、実用的なものになりました。さらに、今現在のmasterブランチのビルドでは、EasyClickのマルチスレッド稼働に対応しており、より高速で安定しています。
 また、恥ずかしながら、以前のバージョンまで文字コードを雑に扱っていた節があり、GUIからパス名を設定すると例外が発生し、強制終了するというバグがありました。17035インサイダービルド以降のWindows10からは、ASCII版の関数においても、UTF-8でエンコーディングされたファイル名を処理してくれるようですが、現在のwin-vindでは外部のやり取りにUTF-16を利用し、内部でUTF-8を利用することにしました。ネイティブエンコーディングがUTF-8にならない限り、この実装で行きたいと思います。どちらにせよ、今回のバージョンにより日本語環境でも安定した動作が期待できます。

追加点

ウィンドウの整列

 この機能は、現在開いている(最小化されていない)ウィンドウを全て検出し、メモリの使用率順でタイル状に自動で並べます。Vimの<C-w>=に相当する機能で、複数のディスプレイがある環境でも全て整列させます。現在は、メモリの使用率で順に並べていますが、使用頻度にするか検討中です。

3.2の更新内容をredditのVimコミュニティにポストしたところ、「お前はWindows用のi3wmを作った!」など絶賛されていましたが、ウィンドウマネージャという観点からはMicrosoftとそのコミュニティがオープンソースで開発しているPowerToysのFancyZonesなどのほうが美しく優れていると思います。他にもフリーウェアのPlumbLGUG2Z / yattatzbob / python-winodws-tilerなどがあり、それぞれ非常に豊富な機能を持っています。このように類似したツールが多くあるうえで、再実装するのは馬鹿らしいように思えますが、Vimのシーケンシャルなコマンド入力やコマンドラインを利用したバイディングに乗っ取っていることに多くの意味があります。

ちなみに、win-vindはワンショットの呼び出しに対応しており、win-vindのバインディング機能を利用せず、AHKのバインディングの下でユーティリティだけを使うことができます。

#a::Run, win-vind -f arrange_windows

--func/-fオプションに渡す文字列は、Cheat SheetのIDです。

ウィンドウの回転

 この機能は、選択しているウィンドウが表示されているモニタ内で、整列済みのウィンドウの回転を行います。Vimの<C-w>r<C-w>Rに相当する機能です。ただ、release版では<C-w>=で整列し、ウィンドウの順番を生成してからでないと利用できませんが、masterビルドではこの限りではありません。因みに、rが反時計周り、Rが時計回りとしています。

ウィドウの交換

 この機能は、選択しているウィンドウから最も近いウィンドウと位置とサイズを交換します。Vimの<C-w>xに相当する機能です。距離の指標には、ウィンドウの中心からのL2ノルムで計算しています。

f:id:pit-ray:20210227053639j:plain
Exchange overview

ウィンドウのリサイズ

 ウィンドウのリサイズをVimライクに行う機能です。私は、simeji / winresizerを愛用しているため、標準の機能はあまり利用しないのですが、一連の実装として追加しました。Vimのコマンドでは、Verticalが列に対する用語であるため、動作とあべこべなコマンドとなってしまいました。

高さ
:resize <num>で高さをピクセル単位で指定することができます。<num>はwin-vind独自のキーワードで、数字が入力され数字以外が入力されるまでの文字列を表しています。例えば、:resize 500で高さが500ピクセルとなります。:resize 512abcd123のような入力の場合、512ピクセルと解釈されます。また、<C-w>+または:resize +<num>で高さを増やし、<C-w>-または:resize -<num>で高さを減らすことができます。ちなみに、resizeresと短縮できます。


:vertical resize <num>で幅をピクセル単位で指定できます。同様に、<C-w><gt>または:vertical resize +<num>で幅を増やし、<C-w><lt>または:vertical resize -<num>で幅を減らすことができます。この点、横方向のリサイズにも関わらず、verticalとなっています。ちなみに、vertical resizevert resと短縮できます。

ウィンドウのスナップ

 この機能は、選択しているウィンドウをある方向の画面半分にします。Vimの<C-w>H, <C-w>J, <C-w>K, <C-w>Lに相当する機能です。Windows標準のショートカットである<win-left><win-right>とは違い、ウィンドウ自体のリサイズと移動を伴います。

ウィンドウの選択

 この機能は、Vimの<C-w>h, <C-w>j, <C-w>k, <C-w>lに対応する機能です。選択したい方向の端の中心から最も近いウィンドウを選択します。距離には、L2ノルムを用いています。この機能は、複数のモニタ間でも動作します。

f:id:pit-ray:20210227064354j:plain
Select a left window Overview

ウィンドウの複製

 現在選択しているウィンドウを半分にし、空いた部分に同じプログラムを起動します。Vimの:split:vsplitに相当する機能です。エクスプローラやウェブサイトを分割して開きたいときに便利です。多重起動を許さないなどの理由によって新しいウィンドウを作れなかった場合には、ウィンドウのリサイズだけ行います。

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

このソフトウェアについて

 このツールは、gVimを利用しているときに他のソフトを触りたいときや、Wordの使用を余儀なくされているときにVimと同じように操作したいという気持ちから作りました(Vimのエミュレート機能についてはオモチャみたいなものですが...)。しかし、READMEにVimのエミュレート機能を強くアピールしていたせいか、メモ帳をVimに変える面白ソフトにとして紹介されたことがありました。

 概念的に言えば、Vimというアプリケーションよりも一つ上のレイヤから、Vimバインディングを行うような機能に相当します。Vimプラグインのskywind3000 / asyncrun.vimを利用すれば、VimにGUI操作用のモードを追加するツールとしても使えます。

Plug 'skywind3000/asyncrun.vim'

command! GUINormal :AsyncRun win-vind -f change_to_normal

これにより、:GUINormalでGUI操作用モードに移行できます。

 ただ、WindowsはLinuxのようにウィンドウマネージャを切り替える手段を提供していないため、Windows APIを呼び出すだけの疑似的なものでしかありません。また、Vimのようなシーケンシャルなコマンド入力は、rcmdnk / vim_ahkのようにAutoHotKeyでも再現することができます。したがって、AHKスクリプトのRunなどを利用すれば、単体の機能を有するツールを呼び出し、同様にVimバインディングのユーティリティツールを再現できます。(例えば、EasyClickの機能にはzsims / hunt-and-peckなどが利用できます)

 AHKは高度なカスタマイズを行えるソフトウェアである一方、win-vindは事前定義された関数を呼ぶため、処理の内容まで変更できません。しかし、プログラミングを主として、バインディングをその支援とするユーザにとっては、行き過ぎた自由度は導入のコストを増やします。特に、上記のようなヒンティング機能であったり、Vimバインディング導入のためには、さまざまなリソースに依存することになります。対して win-vindは、Vimライクなバインディング機能とユーティリティを一括で導入でき、カスタマイズの自由度も必要最低限です。

今後

 現在のwin-vindは、初期値をカスタマイズするようにして利用しますが、これでは導入コストが高いように思います。それに、網羅的な設定が一つのファイルに収まっているため、カスタマイズが難解であることは否めません。そこで、ゲーミングデバイスようなプリセット機能であったり、.vimrcライクな記法を導入しようかと検討中です。とはいっても自由度を高めすぎると、学習コストが高まったり、最終的にAHKに収束してしまうような気もします。また、UWP系のモダンなUIに憧れがあるので、GUIを印新するかもしれません。WinUI3の動向や今流行りのFlutter2を触ってみて決めたいと思います。