私はプロジェクタを天井に投影してベッドに寝転がってPCを使用する際にXbox360の有線コントローラを使用しています。
ゲームコントローラでPCの操作をするのに、最初は定番のJoyToKeyを試したのですが、何故かスタートメニューが開けない等の問題が発生しました。JoyToKeyのバグかと思い、同じようなソフトを自作してみましたが、そちらでも同様の現象が発生しました。
具体的に何が起こるかというと
- スタートメニューを開くと一瞬で閉じてしまう
- MediaCenterをフルスクリーンで使用しているとタスクバーが出てくる
- 一度本物のキーボードに触れるとしばらく収まるが、少しするとまた発生する
キーボードを触ると収まることから、スクリーンセーバーか省電力機能を疑ったのですが、どちらの設定もこんなに早く現象が発生するほど短い時間設定ではありませんでした。
実際に何がおこっているのかSpy++を使って調べてみると、キーボードやマウスを1分間触らずにいると、WM_SYSCOMMANDのSC_SCREENSAVEが1秒間隔で繰り返し送られていました。この時間は他の設定によらす、決まっているようです。
SC_SCREENSAVEは、フォアグラウンドウインドウに対してスクリーンセーバが起動することを通知するメッセージです。スタートメニューが閉じたりMediaCenterが微妙にフルスクリーンモードを解除するのは、スクリーンセーバの起動を察知して反応しているようです。しかし、SC_SCREENSAVEが届くにも関わらずスクリーンセーバが起動しないので、今回のような問題が発生したようです。
また、このメッセージをアプリケーション側で適切に処理することにより、スクリーンセーバの起動を抑制できます。ゲームや動画プレイヤーなど、ユーザがキーボードやマウスをしばらく操作していないがスクリーンセーバは起動して欲しくない場合に、このメッセージを処理してスクリーンセーバの起動を抑制します。
SC_SCREENSAVEは、自前のアプリケーションからPostしても、拒否されなければスクリーンセーバを即座に起動できる(起動してしまう)という性質のメッセージでもあります。しかし、拒否していないにも関わらずスクリーンセーバが起動しないことから、このメッセージを送ってくる犯人はサードパーティ製のアプリケーション等ではなく、Windowsのコアかそれに近いMicrosoft製のコンポーネントであることが予想されます。
結論として私のVista Ultimateに入っているDreamScene(Ultimateの特典の動画壁紙機能)が犯人であることが分かりました。
調べた結果、スクリーンセーバを「(なし)」に設定していても、指定した時間になるとSC_SCREENSAVEが送られてくるようです。今回はスクリーンセーバの待ち時間が1分になっていたので、1分で送られて送られてきました。0分に設定しようとすると1分になってしまうので、999分のように十分に長い時間に設定することで回避することにしました。
ちなみに、ユーザがキーボードやマウスを最後に動かした時間というのは、GetLastInputInfoというAPIで取得することができます。JoyToKeyのようなアプリケーションでは、SendInputというAPIを使ってマウスやキーボードの操作をエミュレーションするのですが、このSendInputでGetLastInputInfoの時間もリセットされます。しかし、今回問題になった無操作時間の判定には、GetLastInputInfoとは別の時間が使われているようで、その時間はSendInputではリセットされないようです。