画餅展覧会

2009 年 3 月 16 日

WM_ACTIVATEでキー状態テーブルが更新されない

カテゴリー: C++, KanaInput, Programming, Windows Mobile — jk78 @ 7:22 PM

おお、KanaInputにバグだ。設定ダイアログだけど。

設定ダイアログを、バックグラウンドに持っていき、隠れている間にCaps LockやらカナLockの状態を変更して、設定ダイアログを再表示させると、変更したロック状態が反映されない。何かのキーを押すか、ボタンのフォーカスを変えると直ります。

正確な再現手順は以下の通り:

  1. KanaInput設定ダイアログを立ち上げる。Caps LockはOFFにしておく。
  2. 別の画面に移る。Today 画面でOK。
  3. Caps LockをONにする。
  4. KanaInput設定ダイアログを再表示するのだが、このとき、キーボードを使用してはいけない。[スタート]→[プログラム]から jk78 KanaInput のアイコンをスタイラスで、一瞬だけタッチしてすぐ離す(笑)。
  5. KanaInput設定ダイアログが表示されるが、Caps Lock表示がOFFのままである。

よくもこんなバグらしいバグが残ってたねえ。でも確かにこのテストケースを考えた覚えが無い。

KanaInput設定ダイアログの状態ページは、システムが管理するCaps LockとカナLockの状態を表示する。KanaInput常駐部も独自にLock状態を管理しているが、そちらの値は使わない。システムのキーLock状態はGetKeyState()で取得する。このAPIで得られる値こそが、アプリケーションに直接影響するからである。もし万が一、システムの状態とKanaInputの状態が食い違った場合、画面を見て明らかになるからである。問題があることが判れば、KanaInputを再立ち上げするなどして、解決することができる。(実際にはKanaInput設定ダイアログ開始時に常駐部の状態とシステム状態を強制的に一致させます)

まあいいや。WM_ACTIVATEで更新すりゃ良いんでしょ。簡単だ。と思ったが甘かった。デスクトップWindowsではWM_ACTIVATEで更新すれば良いのだが、Pocket PCではWM_ACTIVATEを受け取っても、システムのキー状態テーブルが更新されていないらしく、GetKeyState()が古い値を返してしまう。バグじゃん(笑)。バグは仕様の始まり、ってことか。う~む。散々悩んだ結果、入力イベント(マウス・キーボードイベント)を受け取った時点でテーブルがアップデートされると判断。WM_ACTIVATE処理でkeybd_event()かmouse_event()を使って副作用のなさそうなイベントを投げておけば、次のWM_PAINT迄には入力イベントを処理していることでしょう。こんなんで良いのか。(追記:WM_MOUSEWHEELを送ってみたところ、PPC2003SEエミュレーターでは動きましたが、Window Mobile 5/6ではキー状態テーブルが更新されませんでした。涙)

アップデートする理由ができましたな。

2009 年 3 月 9 日

CScrollImplでのDialog作成はあきらめ

カテゴリー: C++, KanaInput, Programming, W-ZERO3, Windows Mobile, 未分類 — jk78 @ 11:04 PM

いろいろ工夫したCScrollImpl継承のCScrollDialogImplだったが、Pocket PC 2003 SEエミュレーター上で回避できない問題にぶち当たり、使用を断念しました。

下の画面が問題発生時で、画面を縦から横へ回転させた直後です。

cscrolldialoggarbage

画面下にちょうどスクロールバー相当の幅でゴミが残っています。このときのダイアログ・ウィンドウの状態を調べてみると、クライアントエリアはちょうどスクロールバー相当分だけ高さが足りないのに、ウィンドウ・スタイルにはWS_HSCROLLがたっていません。どうもWM_SIZEの最中にScrollWindowExを使うとこの症状が起きるというOSのバグみたいです。W-ZERO3[es](WinMo5)では起きないんですけどね。

あきらめて、自作のスクロール・ダイアログを使うことにしました。ScrollWindowExは使っていないので安心です。ScrollWindowEx制限として、ダイアログの内容は全てコントロールとして配置しなければなりませんが(つまりWM_PAINTで描画するような内容は不可)。

さあ、いやなことは忘れて、先に進もう(笑)。

2009 年 2 月 14 日

CScrollDialogImplにスクロール問題

カテゴリー: C++, Programming, Windows Mobile — jk78 @ 10:29 PM

まだやってるんですよ。CScrollDialogImplってつまりはCScrollImplの問題なんですが。

さて、簡単に行くかと思ったが、そうは問屋が卸さない。水平スクロールバーが表示されたダイアログを、めいっぱい右側にスクロールした状態から、ウィンドウを広げてみる。ダイアログ内の表示が乱れます。

scrolldialogdisorder

通常、この問題の対処は、ダイアログにWS_CLIPCHILDRENを指定するんですが、そうすると今度は、Group Boxの描画と、SetScrollOffset()時の再描画に問題が出ます。結論:WindowsはタコOS。まっとうな人間の使うもんじゃない。(追記:も少し詳しく説明すると、一つにはScrollWindowEx()とSetWindowPos()をこの順で呼び出すと干渉する-これはGDIがタコでしょう。逆に呼び出せばかなりましなのですが-のと、二つにはGROUPBOXコントロールが背景描画をしない-なんで?-ことによります。GROUPBOXはsubclassして逃げるにしても、ScrollWindowEx()とSetWindowPos()の干渉は、複雑な条件判断で醜い行為をしないと逃げられん)

対処としては、WM_SIZEの処理で、親クラスの OnSize() を呼び出す前と後で GetScrollOffset() の戻り値をチェックし、変更があったらダイアログ全体をInvalidate()すると。ああ、きたねえ(笑)。

さあ、いやなことは忘れて、自分の問題に集中しましょう(笑)。

古い投稿 »

Powered by WordPress