Python の拡張モジュールの話。Thread State and the Global Interpreter Lock の辺り。
Python はバイトコードの命令を sys.getcheckinterval() 回実行するたびにスレッドが切り替わる。もし拡張モジュール内の C で書かれた関数を呼び出し、それが GetMessage 〜 DispatchMessage のループのようにある条件の間ループし続けるものだった場合、Python インタプリタ側から見るとその関数の呼び出しは「1 命令」分なので、その関数の実行中はスレッドの切り替えが起らず、マルチスレッドでは期待通りに動作しない。
上記のループや、何らかの重い処理を行う場合は、該当コードの前後に Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS を書く。こうすることでスレッドの切り替えが起るようになる。
と思ったら GetMessage 〜 DispatchMessage のループ中に恋するセグメンテーションフォールトが起きるんですが。特定のメッセージが発生すると起きるので、どうにもそれが怪しいのですが、今一。
Python for Windows extionsion のソースコードを参照してみたのですが、ループ自体はほぼ同一です。どうしたものか。
Python のモジュールのビルドやインストールは distutils を使えばいいのですが、インストールはともかく、アンインストールはどうすればいいんでしょう。
ドキュメントには全く記述がありませんから、そんなものはないようです。検索するとメーリングリストでそれっぽい話題があったということは解ったのですが、まだ標準で用意されている訳ではありません。
今まで拡張モジュールを書いたことはないので、単純なものを作って試しにインストールしようとして困りました。まあ、別にいいか。
大抵の場合、自己組織化探索は探索で一致したデータを探索対象のデータ列の先頭に移動させる、つまりは各データは最終アクセス時刻をキーにソートされているのだけど、それ以外にもキーにできそうな情報はある。例えばデータの被探索回数や、前回探索されたから今回探索されるまでの時間差など。
元々はパフォーマンス向上のためのアルゴリズムであるから、余計な手間をかけるよりも単純なままの方が速いし、その方がいい。しかし、「次に探索されるであろうデータを予測する」ために用いることもできなくはない。この場合は多少計算量が増えても構わない。
ということを思いついたのだけど、これはよく考えたらかな漢字変換のそれだな。かな漢字変換に限らず、対話的な入力の補完に応用できないかと思ったけど、下手に並び替えられるよりは名前順や最終アクセス時刻でソートされている方がいいか。
色々あって遅れましたが、以前云っていたファイラーを数日前から作り始めました。基本的な構造はできたので、後は細かいところを詰めていくだけ。いくつかの機能についてはどの方法を取るべきかで少々悩んでいます。
例えばファイル名を受け取り、その種類に応じて異なった処理を行う……つまりは FILE がテキストなら less FILE、.tar.bz2 なアーカイブなら tar jtvf FILE | less のように処理をしたい場合、受け取ったファイルの種類はどうやって判定しましょう。
ベタな方法では拡張子での判定。WD はこの方法を取っています。MS-DOS の世界でファイル名は 8.3 形式と決まっているので何の問題もありませんが、現代では色々と問題が:
次に思いつくのは、拡張子ではなく、ファイル名そのものを対象にパターンマッチを行って判定する方法。パターン数が多くなるとアレな気がしますが、登録するようなパターン数はたかが知れているし、そもそも気になるほど重い処理ではないでしょう。仮に重かったとしても、頻繁に使われるものは大抵決まっているので、簡単な自己組織化探索でどうとでもなります。
これとは別の方法で、file(1) の出力を対象にパターンマッチを行うという方法もあるのだけど、これの出力が万国共通だとは思えないし。
まー、自分用だからどうでもいいか。
~/.vimrc に以下のようなものを書く。
au BufRead,BufNewFile *.xml set expandtab softtabstop=2 shiftwidth=2
これだけ。もっとちゃんとした方法があるようだけど、私にはこの程度で十分。
ああ、set だと問題ありです。オプションのグローバルな値が変更されてしまうので、例えば this.xml を開いた後に that.non_xml を開いた場合、変更された後の値が適用されてしまいます。
この場合は setlocal を使えばいいはずです。
しかしまあ、まさかデバッグのために PC-98 を起動するとは思わなかった。(マシンスペックに見合った) それなりの速度で bbLean が動作しているのだけど、何かシュールだ。
スタートメニューを見たらずっと大貧民とかあるし!
数箇所変更すれば Windows Me でも BBTaskSwitch が動作すると grischka さんから助言をいただきました。
そりゃそうだよなー。無理に A-Tab に拘らずとも A-F1 とかに変えればいい。何で気付かないかな。
後、EnumDesktopWindows は NT 系専用だった。Windows 95 で使おうとするとこのファンクションは Win32 モードでのみ有効です。と怒られた。
しかし、キーバインドを変えるのは気に食わない。やろうと思えば窓使いの憂鬱で誤魔化せないことはないけど。
Windows XP で BBTaskSwitch がロードできないという報告までありましたが、さすがにこれは原因が解らんぞ。0.0.1 と 0.0.2 の diff 取っても直接問題となるような修正はないと思う。とはいえ、何かを変更して問題が起きるのであれば、何をどうこじつけようとその変更が原因だからなぁ。
こちらの環境で再現できないことには何ともいえない。
ぎがう。違う。私の環境だとちゃんと動いていた。ただ、別のウィンドウでオーナーを HWND_MESSASGE にしてて、それが原因で beginPlugin に失敗していただけだ。HWND_MESSASGE は 2000/XP 限定。エラーメッセージを見誤ったせいで凄まじい勘違いになってた。
ということは、報告された例も CreateWindowEx のパラメータがおかしかったことが原因か。問題の起きる OS がどれか解らないのでまだ正確な理由は解らないけど。
後、Windows 95 では BBTaskSwitch が動作しませんでした。問題の起きる箇所を修正して確認してみたのだけど、標準のものを置き換えることができません。XP だと RegisterHotKey で Alt-Tab を登録すれば簡単に標準のものを置き換えることができるのですが、95 だとそうはいかない模様。RegisterHotKey 以外の方法だとフックくらいしか思い浮かびませんが、95 だと WH_KEYBOARD_LL が使えないので、標準のものを置き換えることは不可能です。
BBTaskSwitch doesn't work on Windows 95.
……は?
beginPlugin から呼び出した TS_New は成功している。その戻り値 (Alt-Tab 置き換え作業を行うウィンドウへのハンドル) は当然非 NULL のはず。(1) で確認したところ、やはり非 NULL。
なのにその次の段階、(2) のところで戻り値が NULL か否かの確認で NULL と判断されている。何故だ?
/* (1) */
notice(TEXT("G_TSWnd == %p"), G_TSWnd = (*pTS_New)(option, G_TSModule));
(*pTSOption_Del)(opt);
/* (2) */
if (G_TSWnd == NULL) {
show_last_error(TEXT("beginPlugin/TS_New"));
goto E_TS_NEW;
}(2) の手前の部分で確認しても非 NULL。もしやと思って IsWindow(G_TSWnd) を調べてみたけど、戻り値は真。でも G_TSWnd == NULL が真なのは何故だ!
まさか far とか near とか huge とかその辺のことが絡んでたりしないだろうな。……でも MS-DOS ならともかく Windows 上だしなぁ。多分 (2) の条件を (!IsWindow(G_TSWnd)) && (G_TSWnd == NULL) にすれば大丈夫だろうけど、すっごく納得いかない。
報告してくれた方の場合は、TS_New 内の CreateWindowEx の戻り値の確認で同様の現象が起きていると思われます。……待て、じゃあ何で私の環境じゃその確認は期待通りに動いているんだ?
ゆるねじフォーラムにて BBTaskSwitch がロードできないとの報告があったのですが、どうにも理由が解らない。
再現しようがないのでどうしようかと思ってたけど、よく考えたら隣に埃被ってる 98 (Windows 98 ではない) があった。気合を入れれば Windows 95 が動くので、試しにそこで起動してみたら確かにエラーが出た。
エラーが起きるのは WM_CREATE を受信し、それを DefWindowProc が処理する直前以降のどこかで起きている。XP Pro では起きなかったので、9x 系固有の問題か。
しかし、9x 系にない API 使ってるなら beginPlugin が呼び出される前にエラーとなるしなぁ。何故だ。
何度か提案されたので、試しに BBTaskSwitch にアイコンを追加してみたのだけど、すごくダサいのでやっぱ絶対に追加しない。
やっぱ forums.loose-screws.com に BBTaskSwitch のトピックを立てた方がいいですか。メールが。メールが。でも、あそこに自分でトピック立てるのは何か気が引ける。
まあ、まだ Windows 標準のものと完全に同一のものが表示できている訳ではないし、それができるまでは立てないことにしておきましょう。
しっかし選別条件は何なんだ。タスクバーに表示されるものなら簡単だけど、それとは微妙に違うし。
そういえば半年くらい前に Windows のソースコードが流出したというニュースがありましたよね。……いい加減、問題を考えるのが面倒になってきたので、それを探して直接答えをm
まあ、今更手に入るかねぇ。それに、手に入れたところで該当するコードが必ず含まれている訳ではないし、第一直接答えを見るのはプライドが許可しません。
I was just woundering if you had planed to implement icon support for the bbtaskswitch.
I think so, but I'll never support icons or other things for BBTaskSwitch.
しかし、(巣作りドラゴンのような) この手のゲームをやってると、その内部構造がどんな風になっているか気になって気になってしょうがない。
一番楽しいのが、侵入者との戦闘。迎撃用モンスターが待機する部屋に侵入者が入ると戦闘になるのですが、その様子の表示が特に気になってしょうがない。どちらかが撃退されたり、必殺等のスキルが発生した場合は通常と比べて優先的に表示されている (と思う) のですが、あれは各地の情報 (モンスターが待機しているとか、侵入者が罠にかかったとか) を重要度に関して整理して表示してるんだろうか、とか。でもそこまでしているとすれば、カメラワークもそれに連携させて上手い具合に自動でスクロールすることができないはずはないよな、とか (何も操作しない限り、侵入者がこれまでに侵入した最奥地点へ自動でスクロールします。が、これじゃ詰まらないし、場合によっては余計なお世話だったりする)。
云い出したらきりがないので以下省略 (買った理由の一つは戦闘パートの動きだ)。
色々悩んで悶えて、結局巣作りドラゴン買いました。たのしー。
楽しいし、作りもきちんとしてるのだけど、そのせいで細かい欠点が目立って残念。でも地味に面白いですよ。こういうのは大好きだ。
個人的に、一番重大な欠点は、
左利きマウスに対応していますか?
これに「はい」と答えるなら、マウスカーソルを左右反転させたものを用意して下さい。
[2004-08-12T08:30] の続き。
キー入力の処理部分を再度見直し。U-Alt の再チェックについては TSM_STARTSEL (タスク選択のための前準備) の終りに行うことにしました。そもそも WM_SETFOCUS が来ない── SetForegroundWindow に失敗する場合だってありますからね。適当に CPU に負荷かけて実験してましたけど、多分大丈夫なはず (この手の確認作業を定型化できないのが気持ち悪い。何か上手い方法はないかな)。
簡単に云うと、BBTaskSwitch が 9x 系でも快適に動作するようになったということです。use_alt_method を true にしてる場合には関係のない話。
後は (ジョークで) いくつかオプションを追加したら 0.0.2 リリース。
[2004-08-10T21:31] の続き。A-Tab を高速で入力し、かつ何らかの原因で BBTaskSwitch の処理がもたついた場合に U-Alt を見失います。その対策の話。
WM_SETFOCUS が来る)WM_KEYUP 等) で受け取ることができなかった」と判断し、選択されたタスクに切り替える考えとしてはこれで間違っていないと思うのですが、これで U-Alt を見失っているか否かの判断ができない場合があります。A-Tab は、実際には D-A-Alt D-A-Tab U-A-Tab U-Alt、もしくは D-A-Alt D-A-Tab U-A-Alt U-Tab という入力になります (D- はキーを押すこと。U- はキーを離すこと)。どちらの場合も後ろの U-xxx 二つが WM_SETFOCUS の受信前に入力されれば U-Alt を上手く判断できるのですが、最初の U-xxx だけだと上手く判断できません。U-Alt か否かの判断は GetAsyncKeyState(VK_MENU) で行っているのですが、何が悪いのでしょう。
問題とは直接関係ないけれど、Alt と Tab を離す順番によって Alt を離したときに送られるメッセージが変わります。Alt を先に離すと WM_SYSKEYUP、後に離すと WM_KEYUP になります。これはこれで何故だ。
後、上の対策方法だと、D-A-Alt D-A-Tab D-A-X U-A-X U-A-Tab U-Alt を高速で入力し、U-xxx を全て見失った場合を考慮していません (これは選択の途中でA-Tab 以外のキーを押しているので、選択をキャンセルしたと判断すべき。だけど上の対策方法ではこのような場合でも A-Tab を入力したものと見なし、タスクの切り替えが行われてしまう)。でも、こんなキーストロークを高速で入力することは多分ないから構わないか。
メソッドのデフォルト引数はちゃんと初期化されていないことがある
関数のデフォルト引数は定義時に評価されるためです。
list のように mutable なオブジェクトをデフォルト引数に使おうとするとはまります。
TaskSwitchXP のソースをざっと見てみたのだけど、これのリストアップするウィンドウは、
WS_VISIBLE なものを残し、WS_EX_TOOLWINDOW でない、または WS_EX_APPWINDOW であるものを残し、のようです。
…… WS_EX_TOOLWINDOW で蹴ってるということは、Windows 標準のものと同じものが表示されないと思うのですが。特にコントロールパネル周りのもの。でも、BBTaskSwitch みたいにごちゃごちゃしてない分、スマートでいいか。キー入力周りも簡潔だし。
一つ気になったのは、不要になると即座にフックや Alt-Tab のウィンドウを消しているのですが、あれは何でだろう。そりゃ MSDN に「フックは要らなくなったらとっとと解除しろ」と書かれてますけど、そう神経質にならなくてもいいと思うのですが。Alt-Tab は頻繁に使われるものだし、逆にオーバーヘッドにならないかな (まあ、大した量じゃないか。それに TaskSwitchXP はスクリーンショットからしてアレだし)。
BBTaskSwitch のキー入力部分、特に U-Alt と A-NonTab の辺りを見直し。よく考えたら無駄なものがいっぱいあった。
後、use_alt_method を使ってない場合、たまにキー入力を見失う問題だけど、あれは多分 BBTaskSwitch にフォーカスが移る前に入力されたからだ。フォーカスが移らないと WM_KEYUP 等のメッセージは受け取れないので「見失う」。
とはいえ、あの明らかに無駄の多そうな方法以外に対策はあるかな。
変更点は [2004-08-09T12:26] の方法でタスクの一覧を作成するようにしただけです。
コードで示します。ある問題を除けば Windows 標準のものと 100% 互換のはず。
BOOL
IS_VISIBLE_AND_HAS_SYSMENU_AND_ENABLED(DWORD style)
{
return !(style & WS_DISABLED)
&& (style & WS_SYSMENU)
&& (style & WS_VISIBLE);
}
BOOL CALLBACK
EnumWindowsProc(HWND hwnd, LPARAM lp)
{
HWND parent;
parent = GetParent(hwnd);
if (parent == arg->desktop || parent == NULL) {
DWORD hwnd_style;
HWND lapopup;
DWORD lapopup_style;
hwnd_style = GetWindowLongPtr(hwnd, GWL_STYLE);
lapopup = GetLastActivePopup(hwnd);
lapopup_style = GetWindowLongPtr(lapopup, GWL_STYLE);
if ( !IS_VISIBLE_AND_HAS_SYSMENU_AND_ENABLED(lapopup_style)
&& !IS_VISIBLE_AND_HAS_SYSMENU_AND_ENABLED(hwnd_style) )
{
return TRUE; /* skip */
}
if (IS_EXISTENT_IN_LIST(lapopup))
return TRUE; /* skip */
ADD_INTO_LIST(lapopup);
}
return TRUE;
}ある問題というのは、
と、上記の選別では SHOUTcast の設定ウィンドウが抜け落ちます。Windows 標準のものには表示されるのですが。
まあ、ワークスペースなんて Windows には標準で存在しないものだし、その辺りが絡んだ際の挙動に多少違いが出ても別にいいのですが、それな何となく嫌だ。
ZiVE DNSサービスでは、Internet接続時に常に同じIPアドレスを利用できないホストでも、Internetに接続されている間は、あるいは、接続されている任意の時間内だけは、常に登録されたホスト名でInternetからのアクセスが可能なようにDNSの名前解決を提供するサービスです。
RFC2136などで定義されている、いわゆるDynamic Update DNSのことを直接意味しているわけではありません。
似たようなサービスに ieServer.Net がありますが、試しに使ってみた感じでは ZiVE の方が良さそうでした。予め設定した時間が経過すると自動で「オフラインモード」になり、Web ブラウザからアクセスされると不在応答してくれます。よく設定の解除を忘れてしまいますから。
プリンタ欲しい。長い文書をオンラインで読むの疲れる。
タスクトレイにアイコンを表示するには Shell_NotifyIcon 使う。
Modified to send the bro@ms at loading or unloading BBMediator.
BBMediator のロード時とアンロード時に bro@m を送るようにしました。言い換えれば、これを利用してシェルの起動時と終了時に何かできるようになったということです。取り敢えず、高級 BBSoundFX 以外の用途としては、起動時にランダムでスタイルを変えるというのを思いついたけど、設定面倒な上に素直に BBStyle 使えという話。
これで Windows のデフォルトのものとほぼ 100% 同じものが一覧に表示される、はず。また、後から気付きましたが、PSPad だけでなく Winamp も一覧に複数表示されていましたね。
後、プラグインと Alt-Tab 置き換え部分は完全に分離させたので、別のアプリケーションで再利用することができます。再利用するかどうかは別の話。
bbLean 1.13b1 がリリースされています。実際には確認していませんが、修正事項は以下の二つのようです。
ちなみに、後者の例として「Miranda を shade すると Firefox が shade される」という報告があったのを見て思い出したのですが、昨日か一昨日に Miranda を試していたとき、Miranda を shade した直後にシステムがリブートしました。それも何か関係があったりするのでしょうか。
必要なもの:
準備:
これで Winamp から line://dev=wms や line://dev=wyamaha を開いて再生すれば Wave 出力が Winamp に回ってきます。
なお、NULL Output を選んでいないと愉快なことになるので気をつけましょう。
例: SHOUTcast 等を利用してWave 出力をそのままストリーミング配信を行うとします。きちんと配信できているかどうか、サーバーと同じマシンから確認しようとすると; (1) Winamp が LineIn plugin で Wave 出力を読み込む; (2) SHOUTcast がそれを配信する; (3) 配信したものがクライアントに届く; (4) クライアントが受信したものを再生する; (5) クライアントが再生したものが再び Winamp に! ……という訳で、line in を読み込んでいる Winamp が、読み込んだものをそのまま再生するとアレなのです。
これにマイクなどを付ければゲームの実況中継なんてできますね。
ああ、別にプラグインなんて入れなくてもよかった。SHOUTcast の Input Device を Soundcard Input にして、ボリュームコントロールで録音元に Stereo Out を選ぶだけで構いません。
あはは。bbLean 1.13b0 のメニューの表示の挙動が以前のバージョンと違うとぼやいてましたが、blackbox.rc の session.menu.position.use を true にすればいいようです。メニューからであれば Configuration -> Menus -> Fixed Kbd Position。また、1.13b0 に同梱の BBKeys を使わなければ動作しません。
しかし何故同梱のものが必要なのでしょう。この程度のことは本体だけで処理できるし、そうのように作るべきだと思うのですが。何かの予定があってああしてるのかな。