使用者の予測できない小賢しいことはしなくてよい。
ところでこれってデスクトップにオーバーラップ表示された複数のウィンドウに対するインターフェイスと同じだろう。
ウィンドウとタブは違う。タブコントロールは既に存在している。まねをしろ。見た目をまねしたなら反応まで。ドキュメントの上に常に表示されているタブリストは飾りじゃないんだよ。オーバーラップ表示されたウィンドウの切り替えには Z-Orderという手がかりがあるが、それに対する操作だけをまねしたタブウィンドウには何がある? ユーザーの目の前のタブリストでなく、プログラムが覚えてるだけの、過去にアクティブになった順番だ。それでは先読みができないだろう。毎回選択肢から探さなければならないのなら、いっそ名前順でソートされてる方がましってもんだ。
ところでところで、Operaの Ctrl+Tabも VC++2008EEと同じだったんだな。小さいウィンドウで選択肢を表示してワンクッション挟むところまで Windowsの Alt+Tab、VC++2008EEの Ctrl+Tabと同じ。まことにまどろっこしい。
Operaは Ctrl(+Shift)+F6、1(2)という、隣のタブに移動する代替手段を用意しているが、VC++2008EEには見つけられなかった。Safariは Firefoxと同じ操作感で良いけど、やっぱり Firefox + Tabs Open Relativeが理想的。
つまりは VC++2008EEのタブ*だけがイレギュラーで、使えない子。ほんとうんざり。
* 本当は、VC++2008EEにとってタブと呼ばれるものは別にあり、ここでタブといっている一個一個のものはドキュメントウィンドウと呼ばれている。これも紛らわしくて迷惑な話。本物のタブって見たことないんだけどー。
最終更新: 2010-07-05T02:44+0900
既存のコード(主に検索ボックス)の切り貼りで、とりあえず機能するものに。
ソース面の難はニンともしがたいが機能面の問題くらいは何とかしたいところ。以下、わかっている問題点。
switch-caseで break忘れというまぬけぶりが原因だった。
フォント(HFONT)の削除漏れも修正した。
ツールチップはリストの上下数ピクセルで出ていた。(役に立たない!でもマウスオーバーでツールチップが出てもうるさいだけなのでそのまま)
他に、WM_PAINTで行っていた処理を、本来あるべき位置である WM_COMMAND(CBN_SELCHANGE)で行うように変更した。
キーボードアクセラレータを有効にするのは難しい。矢印や PageUp/PageDownキーまでが登録されているから、単純に有効にするとアクセラレータにそれらの入力を奪われてリストの操作が行えなくなる。
ドロップダウンリストにフォーカスがあるときでもエディタのキーボードショートカットを有効にした。優先順位は
なぜ一部のキーボードショートカットを無効にするかというと、リストの先頭のアイテムが選択されているときに Homeを押してもリストはこの入力を処理しない(すでに先頭が選択されているから)のだが、リストの選択位置に依存してキーの意味が変わってしまう(リストの先頭を選択↔キャレットを行頭に移動)のは不自然だと思うから。同様のキーをわかっている分だけ無効にした結果が上記リストの 2。モディファイアキーの状態やリストの選択位置を考慮して、もっと多くのキー入力をキーボードショートカットとして渡す余地はある(が、こんなアドホックな対処にこれ以上の手間をかけるのもどうかと)。
追従しないことにむしろ驚いた。ブラウザにできてテキストエディタにできないはずがない。
ファイル名も与えられていた場合は、それを上書き保存先にしてくれると尚良し。長めの出力をコマンドプロントからエディタに流して読んだりできる。
svn diff hoge.rb | sakura --stdin "hoge.rb.diff"
Set/GetWindowLongPtr(hwnd, GWLP_USERDATA, ) の代わりに Set/Get/RemoveProp(hwnd, TEXT("MyData"), ) を使うようにした。
参考> http://hilbert.elcom.nitech.ac.jp/~taki/program.html
以下のものを見つけた。
答え。GWLP_USERDATAはウィンドウに属し、その領域は WNDCLASSEX.cbWndExtraの値に従って確保される。
いったいどこを読み書きしていたんだろう? クラッシュしなかったのは Windowsが俺みたいなうっかりもののために余白を空けていたから?
言い訳。msdnのこの記述は非常に誤解を招きやすいと思う。予め 32ビットだけメモリが確保されてると勘違いしても仕方ないじゃない?
GWLP_USERDATA | ウィンドウに関連付けられた 32 ビット値を取得します。この 32 ビット値は、ウィンドウを作成したアプリケーションで使用する目的で各ウィンドウが持っているものです。この値の初期値は 0 です。
現状の理解で、この「32 ビット値」の出所は、読み書き(Get/Set)の単位が 4バイトだというところから。LONG=32ビットだから。
ここで、LONG_PTRが 64ビットのとき、GetWindowLongPtr(,GWLP_USERDATA)は 64ビット値を取得するのでは?ドキュメントあってる?という新たな疑問。
GWLP_USERDATAのように汎用的な場所から取得した値を恐る恐る CMainToolbar* にキャストするより、特別な名前をつけた場所に保存した値をキャストする方がまだ安心できる、という理由で改訂した。
ありふれた課題のようで GWLP_USERDATA を検索するだけで似たような話が見つかる。最初にリンクを張ったページは理解しやすかったが ATLのは難しい。これから読む > WTL/ATLのメッセージマップ実現のしくみ
GWLP_USERDATAと WNDCLASSEX.cbWndExtraが別物の可能性。
別物。GWLP_USERDATAは負のオフセット(-21)。cbWndExtraで確保した領域には 0から始まるオフセット(バイト単位)でアクセスする。
GWLP_USERDATAの有効な領域はポインタのサイズに関係なく、ドキュメント通りの 32ビットなのかについては winuser.hを見てもよくわからない。GWLP?_USERDATA(-21)から GWL_EXSTYLE(-20)まで差が 1しかないし……。GWLP?_* というのはオフセットでなく特別扱いされる値で、Windowsのソースを見ないと何もわからない、ということ? GWLP_USERDATAにポインタを格納できるのとできないのの差は大きいからハッキリ 64ビットサイズだと知りたい。
/* * Window field offsets for GetWindowLong() */ #define GWL_WNDPROC (-4) #define GWL_HINSTANCE (-6) #define GWL_HWNDPARENT (-8) #define GWL_STYLE (-16) #define GWL_EXSTYLE (-20) #define GWL_USERDATA (-21) #define GWL_ID (-12) #ifdef _WIN64 #undef GWL_WNDPROC #undef GWL_HINSTANCE #undef GWL_HWNDPARENT #undef GWL_USERDATA #endif /* _WIN64 */ #define GWLP_WNDPROC (-4) #define GWLP_HINSTANCE (-6) #define GWLP_HWNDPARENT (-8) #define GWLP_USERDATA (-21) #define GWLP_ID (-12)
// まだファイルタイプは取得できないっぽい。常に基本(0)になる。 //::SendMessageAny( m_hwndFileTypeBox, CB_SETCURSEL, m_pOwner->GetDocument().m_cDocType.GetDocumentType().GetIndex()+1, 0 ); ::SendMessageAny( m_hwndFileTypeBox, CB_SETCURSEL, 0, 0 );
とコメントアウトしていた部分を復活させて
::SendMessageAny( m_hwndFileTypeBox, CB_SETCURSEL, m_pOwner->GetDocument().m_cDocType.GetDocumentType().GetIndex(), 0 );
ちょっと修正した(謎の+1を取り除いた)だけ。
アプリケーションの起動と同時にツールバーが作成されるときであれば、コメントの内容は正しい。アプリケーションが起動してファイルが読み込まれた後でツールバーが表示する設定に変更されたとき(このときもツールバーが作成される)は、そうではなかった。
どの言い分もわかる。結局問題なのは、
なのだが。自転車や自動車を一括りにしたって何も始まらない。なくそうと思えば両方を取り締まればいい。
取り締まればいいんだけど……
また、ドライバーに関しては取り締まる理由がないから*自転車が圧倒的に不利。無法な自転車乗りを取り締まると同時に自転車の車道での立場を固めてもらわないと困る。原付に乗ってても 250ccに乗ってても勘違いしたドライバーにでくわす確率はそうとう高かったのに、自転車の立場なんて確保できるとは思わないが。
タレコミに「危険だと判断した場合は自転車も歩道を走ることができる。」というような文言が見あたらなかったので上のような文章を書いた。現状の追認には特に反対しない。自転車乗りとドライバーの積極的な教育を大いに望む。
交通の方法に関する教則( http://www.npa.go.jp/koutsuu/kikaku90/shinkyuu.pdf )から省略・抜粋。
道路を横断しようとするとき、近くに自転車横断帯があれば、その自転車横断帯を通行しなければなりません。
左折レーンのあるような交差点なので自転車横断帯はあるし(多分)、規定されてなくても実際そうせざるをえないんだけど、自転車横断帯を横断した後が問題。歩道と車道をうろうろするのは危険でしょ。自転車横断帯への誘導は歩道への誘導と同じこと。
「歩行者・自転車専用」と表示されている歩行者用信号機がある場合は、歩行者用信号機の信号に従わなければなりません。
見ない。歩行者用の信号の横に付いてるプレートなんて見ない。歩行者用の信号って先読みのためにあるんでしょ?<違
確かめてみたら自転車横断帯も歩行者・自転車専用のプレートもなかった。これでふりだしへ戻った。
どちらも選べなくて困っている。
* ケータイ片手のドライバーなんて見つけるのに苦労しないが、理由のあるドライバーに対してこんな状態で何をかいわんや。二車線あるのに追い越しをしようともせずクラクションを鳴らされまくったのがつい先日。後ろの様子なんてわからないから轢かれるんじゃないかと戦々恐々で、けっきょく排水溝のふた(段差)や砂利があってすぐパンクするようなところを走らされた。こういうの、どうにもできないでしょ。
この場合はshortcutは完全にsymbolic linkとして機能しているように見える。なぜすべての場所ではなくスタートメニューの中だけでこうなってるんだ? Windows shortcutは一体どういう仕様になってるんだ?さっぱりわからん。
そこでlsしてたらもう少しだけ謎が解けていたと思います。
以前にも読んでいたのだがいいタイミングでページを再発見したので引用してみた。
どうして「わからん」になるのかを横から説明すれば
書かれている通り、<DIR>であり「ファイル」であるディレクトリに入って ls(dir)してみた結果がこう。嘘つきが誰なのかわかれば何の不思議もない。
2008/05/30 00:09 <DIR> . 2008/05/30 00:09 <DIR> .. 2008/05/30 00:09 757 target.lnk
隠し属性つきで desktop.iniも存在している。内容は
[.ShellClassInfo] CLSID2={0AFACED1-E828-11D1-9187-B532F1E9575D} Flags=2
気付くためのポイントはスタートメニューの中でだけ有効だということ。dirとエクスプローラのどちらを信用するのかをちょっと考えれば、ディレクトリの他に(仮想)フォルダ(ごみ箱やマイコンピュータやデスクトップなど)を表示するエクスプローラ (もうひとつリンク)が時に嘘つきなのは以前から知っていたはず。
$ で GREPしてみたらこういうものが無数に見つかった。だいたいが一行コメントの中に対応した state。終了条件は行末で、URLを含んでいれば sh_urlとしてマークする。
{ 'exit': true, 'regex': /$/g }, { 'regex': /(?:<?)[A-Za-z0-9_\.\/\-_]+@[A-Za-z0-9_\.\/\-_]+(?:>?)/g, 'style': 'sh_url' },
URLが改行の直前まで続いていれば、終了条件としての行末の検出がスキップされて一行コメントが次の行まで継続する。まさしく 20080513p01の問題の繰り返し。
結局、sh_main.jsに非互換な変更を加えるのは問題大ありだと判明したので sh_javascript.jsで対応することにしましたよ、と。
[ // state 2: in "string" { regex: /\\[\\"]/g }, { next: 6, regex: /\\$/gm }, { exit: true, regex: /"|$/gm } ],
[ // state 6: eat an end-of-line ※空行は食べられないよ { exit: true, regex: /^/gm } ]
動作確認は昨日の日記で。
例えば、JavaScriptのリテラル文字列では \ と改行のシークェンスは空文字を意味している。つまりこういうこと
var str = "空白を含まない\ ひとつながりの文字列です";
このシークェンスを認めるように、ダブルクォーテーション文字列の終了条件として次のようなものを shjs/lang/sh_javascript.js に含めてみたがうまくいかなかった。
[ // "string" { // \\ と \" と \(改行) を 1つのシークェンスとして // 食べてしまう。終了位置を見誤らないためであって、 // 特に何をするということもない。/\\(.|$)/gm でも構わない。 regex: /\\(?:[\\"]|$)/gm }, { // エスケープされていない " に出会ったら "~" の中に // いるという状態(state)から exitする。 // " がないまま行末に達したら、終端されていない不正な // 文字列だと判断して、やはり exitする。 exit: true, regex: /"|$/gm } ],
少し前に「行末に達した時点でマッチングを打ち切っていたのが間違い。$は空文字列にもマッチする。全てのマッチに失敗するまで続ける必要があった(20080513p01)」と自分のミスを書いて、これを修正したのだが、shjs-0.4.2はもちろん正しく、全てのマッチが失敗するまで続けている。
そうすると何が起こるか。/\\$/gm にマッチした後でも /"|$/gm のマッチに成功してしまい、結果、行末に \ があろうがなかろうが exitしてしまう。
もちろん行末に達したからといってすぐにマッチングを打ち切っては 20080513p01と同じ間違いを犯すことになるので、同一 state内で*二回以上*行末にマッチすることがないように sh_main.jsを変更した。
内の方のループの、頻繁に実行される部分に if が増えたのが気に入らないものの、悪影響のある非互換でもないし、首尾は上々だし(冒頭の文字列のハイライト結果が見本)、悪くない。
var str = "終端されていない 不正な文字列です";
var str = "終端されていない\" 不正な文字列です";
*たまたま*行末にある \" にマッチしたことで、終了条件である行末の検出がスキップされて、次の行までが文字列だと判断されている*。\" とのマッチは \$ と違い行末を要求していないから、この場合は一行目で exitしてほしい。
* 20080530p01で修正したので文章とハイライト結果が食い違っているかもしれない。