おれのIT日記
2006/04/16 (日)
テキストエディタQX
F11でウィンドウ最大化→解除のトグルをしたい
永年、QXを使ってきたが、おれはあまりカスタマイズに凝る方ではない。また、特に人に勧めることもしていないが、仕事にも使っているので、人からは、QXの愛用者と思われているようである。キーアサインはもちろん、Vz風だ。自分ではもうこれしかない。
TeraPadはかっこいいが、キーアサインが変えられないので、やめてしまった。EmEditorは会社では広く使われているが、同じ理由で、使いこなしていない。もっと言うと、指が乱れるといやなので、覚えるのを避けているのだ。指は無意識に動かないとイヤだ。この年になって、違う方式は覚えたくない。
昔、Vzエディタ一筋だったから、秀丸にはなじめず、Wzにもなじめなかっただけだと自分では思っているが、考えてみると10年以上使っている。3000円じゃ安い。
安定性は確かに凄い。おれが言わなくてもみんな言っているので今更だが、この場で、しつこく、断言する。
この10年で、落ちたことはたぶん数度だけだ。それも、Windows98の頃である。QXではなくOSが落ちたのだと、おれは今でも思っている。
とは言え、インストールディレクトリのQXWERROR.LOGを覗いてみたら、2002年頃にもなにやら記録されていたが、大事なテキストをパーにされた記憶は一度もない。
先日、仕事で、1.6GのCSVを作ったが、QXは、落ちずに、根気良くファイルを開いた。さすがに最後までは読めなかったが、異常終了もせず、たいしたものだ。
マクロも拾ってきてそれなりに整備し、QXの最大の欠点である「ださい外観」も、メタリックアイコンのお世話になってちょっとだけクールにし、配色も凝りに凝り、キーワードファイルも整備して……やっぱり、それなりに「愛用」している方になるだろうか?
先日は、有志の方が作成したUnicode対応DLLを仕入れ、これでもう言うことはない!という状態であったが、ちょっとした不満というか、自分がわかってないだけだと思うが、望みがあった。それは、とてもとても些細なことで、タイトルの通りである。
F11を押すウィンドウの最大化は、Vzのダイヤモンドカーソル最高!なおれには似合わないことだが、結構好きなのである。FireFoxをF11で最大化して使うのが好きになってから、ますますひどくなった。いや、顕著になった。右手をホームポジションから離して、F11に持っていくのが、それほど苦痛ではなくなってきた。
QXのF11に、@WindowAppMaximizeをアサインすれば、最大化はできる。
しかしそれだけでは、「もう一回押すと元に戻る」ということができない。
さらに欲を出すと、おれは、QXを最大化した時、タイトルとメニューを消すのが好きだ。だが、メニューを見たいときもある。見えなくてもALTを押しながら呼び出せるが、だいたい間違える。10年使っていても間違える。メニューは一つ残らず自分でカスタマイズしているにもかかわらず、いや、カスタマイズしたからか、メニューを見ないと、正しく呼び出せない。正しく呼び出せないから、キーにアサインせずメニューに入れてあるというか、ええーいややこしい、とにかく、メニューを消すのが好きだが、見たい時にぱっと出ないと、それはそれで困る。
つまり、
メニューとタイトルを消して最大化する
↓
メニューとタイトルを出して最大化する
↓
元に戻す
↓
メニューとタイトルを消して…(以下繰り返し)
というトグル動作が欲しい。ところが、今、QXが最大化しているかどうか、どうマクロで判断すればいいか、実は、10年使ってるおれも、ぱっと考えて、わからないのである。いかに、使いこなしてなかったか、判る。
さて、最初に考えたのは、Win32APIで、ウィンドウの状態を把握すればいいだろう、という安易な解決法である。
CDeclare int GetWindowPlacement(HWND,WINDOWPLACEMENT *);
ところが、WINDOWPLACEMENT構造体をどう記述していいかわからない。こいつは、内部に、UINTとPOINTとRECTを持っている。QXマクロヘルプによれば、type宣言で作るユーザー宣言型の内部に、またユーザー宣言型を宣言することはできないので、この型は受け渡しできないように思える。(自信がないが誰も教えてくれない)
そこで次に考えたのは、じゃ、必要な情報だけ判断して返すDLLを自分で作ろう、という場当たり的な解決法である。これは一見うまく行った。
まずDLLのソース。
#include <stdio.h>
#include <windows.h>
BOOL __declspec(dllexport) __stdcall isWindowShowCmd( HWND );
BOOL WINAPI DllMain( HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved ) {
return TRUE;
}
BOOL __declspec(dllexport) __stdcall isWindowShowCmd( HWND hWnd ) {
WINDOWPLACEMENT wp;
int rc = -1;
if ( GetWindowPlacement ( hWnd, &wp ) ) {
if ( wp.showCmd == SW_SHOWMAXIMIZED ) {
rc = TRUE;
}
}
return rc;
}
bcc32でコンパイルする。
bcc32 -WD xxx.c
で、QXマクロ側では、こんな風に定義して、呼び出す。
dllname "xxx.DLL"
cdeclare int isWindowShowCmd(HWND);
(中略)
dim rc
rc = isWindowShowCmd(@@hwnd)
' rc = -1なら最大化していない。それ以外なら最大化している。
以上、作成したマクロをマクロディレクトリに放り込み、出来上がったxxx.dllはQX実行ファイルディレクトリに放り込み、見事動作。完成!
……なのだが、何が「一見」かというと、実はこのテストは、XPと2000だけで行った。そのあとWin98やMeで動かないことに気づいてしまったのである。どうもGetWindowPlacementのshowCmdの値が、ぜんぜん違うようなのだ。
自宅にある「Windows95APIバイブル1」(古っ!)をいくら見ても何も書いちょらん。
そこでNT系じゃない場合と処理を分けて、Win32APIのGetWindowRectで、デスクトップとQXのそれぞれの大きさを調べ、比べて、QXが小さかったら最大化してない、という風に組んでみた。どうやって分けた?というと、QXマクロの基本機能で、
#32_NT [2000やXP用の処理記述]
#32_95 [98やMe用の処理記述]
だけで良いから楽である。
Win98ではうまく行ったかに見えたのだが、Meでは思いっきり失敗していることがわかった。それは、メニューとタイトルを復活した場合に、どうやら、デスクトップより小さい値が返ってくるようなのだ。いろいろ動きを試して、2000、XP、98、Meで動かし比べてみると、タスクバーの幅を計算に入れるのと、入れないのとの違いのようである。98とMeで動きが違うわけではなく、うまく行ったように見えたのは、タスクバーの普段の設定と、位置のせいだった。
つまり、NT系と9x系でそれぞれ違いがあり、どうも同じやり方ではダメらしい?のである。Win32APIは詳しくないので、これも自信がないが、取り立てて掘り下げたいネタとも思わないのである。
考えてみると、サイズを比べる方法では、手動で、思いっきり大きくウィンドウを広げた場合にも、判断を誤る可能性もあると気づいた。
だから、厳密にやるなら、タスクバーを除いた、デスクトップの有効面積を調べる必要がある。APIは、System何とかかんとかなんだが……だんだん正攻法で作るのは面倒になってきた。
そこで考えたのだが、「一回、最大化してしまって、前後でQXウィンドウの大きさが変わったら、最大化してなかった、と判断する」ことにした。
もし偶然、最大化と同じサイズだったら?その時は、最大化しているのと同じだから、次のトグルに行ってもいいではないか。それに、ピクセル単位でドンピシャリ一致することはそんなに無いから、実用上はこれでいいだろう。
というわけで、最初に作ったDLLはNT系のときだけ呼ぶことにして、次のようなマクロにまとめた。
'--------------------------------------------------------------------
' 画面の最大化(メニュー・タイトル無し)→最大化(メニュー・タイトル有り)→元の大きさ
' でトグルするマクロ
'--------------------------------------------------------------------
Proc YWindowAppMaximize()
Dim rc
#32_NT rc = isWindowShowCmd(@@hwnd)
#32_95 rc = val(isWindowShowCmd_9x$(@@MaxFrameHideTitle))
' 最大化していない
If rc = -1 Then
' -- タイトルとメニューを消して最大化
@@MaxFrameHideTitle = 1
@WindowAppMaximize
' 最大化している
Else
' タイトルとメニューが消えているなら、復活して最大化
If @@MaxFrameHideTitle = -1 Then
@@MaxFrameHideTitle = 0
@WindowAppMaximize
' タイトルとメニューが消えていなければ、元の大きさへ
Else
@WindowAppRestore
End If
End If
End Proc
Function isWindowShowCmd_9x$( maxFrameHideTitle )
Dim rectOrigin as RECT
Dim rectModify as RECT
' 現在のウィンドウサイズを記録
GetWindowRect(@@hwnd,rectOrigin)
' 最大化してみる
@WindowAppMaximize
' 最大化したあとのウィンドウサイズを記録
GetWindowRect(@@hwnd,rectModify)
' 最大化によって、少しでもサイズが違っていれば、最大化していなかったと判断する。
if ( rectOrigin.Top <> rectModify.Top ) or \
( rectOrigin.Bottom <> rectModify.Bottom ) or \
( rectOrigin.Right <> rectModify.Right ) or \
( rectOrigin.Left <> rectModify.Left ) Then
@WindowAppRestore
isWindowShowCmd_9x$ = "-1"
Else
isWindowShowCmd_9x$ = "1"
End If
End Function
普段使うのは、2000系なので、問題ないが、同じマクロを9x系で使うと、「一回最大化して、あらためてまた最大化する」という動きをするので、ちょっと画面がうるさい。が、自分で使う分にはこれでいいやって感じである。
で、最後に……本当はもっと簡単に、QXマクロの基本機能を使えばできたんじゃないか?という気がするので、QXのえらい方に教わりたいです。
(最後だけ謙虚)