Hatena::ブログ(Diary)

NyaRuRuの日記 RSSフィード

archive

2008-09-25

ゲームプレイ中のスクリーンセーバやディスプレイ休止を回避する方法

主にゲームパッドのみでプレイできる PC ゲームでは,ゲームプレイ中にスクリーンセーバが起動したりディスプレイの電源が切れたりして「むがー!」ということがあります.

これはプログラム側の対応である程度防止できますので,その辺のメモでも.

もっとも保守的で無難な方法は,ウィンドウメッセージのトラップです.WM_SYSCOMMAND メッセージのうち SC_MONITORPOWER と SC_SCREENSAVE を DefWindowProc に渡さないようにします.

Once a screen saver is chosen, Windows monitors keystrokes and mouse movements and then starts the screen saver after a period of inactivity. However, Windows does not start the screen saver if any of the following conditions exist:

  • The active application is not a Windows-based application.
  • A computer-based training (CBT) window is present.
  • The active application receives the WM_SYSCOMMAND message with the wParam parameter set to the SC_SCREENSAVE value, but it does not pass the message to the DefWindowProc function.

Windows Vista and later: If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification.

Handling Screen Savers - MSDN Library
case WM_SYSCOMMAND:
    switch( ( wParam & 0xFFF0 ) )
    {
        case SC_MONITORPOWER:
        case SC_SCREENSAVE:
            return 0; // DefWindowProc は呼ばない
            break;
        
        ...以下略

これだけでかなりのケースは対応できます.以下各論.

ゲームパッドの操作でディスプレイ休止は阻止できることもある

これは手元の Windows Vista SP1 (x86) + Xbox 360 パッド (純正ドライバ) で確認したケースですが,Xbox 360 パッドの操作中はディスプレイの休止は発生せず,またディスプレイ休止状態に Xbox 360 パッドを操作するとディスプレイ休止状態から回復することを確認しています.

ただややこしいことに,スクリーンセーバには効果がないようでした.

SetThreadExecutionState API ではスクリーンセーバを阻止中断できない

This function does not stop the screen saver from executing either.

SetThreadExecutionState Function - MSDN Library

(2009年10月12日追記)

  • 一度実行してしまったスクリーンセーバを SetThreadExecutionState で中断することはできない.
  • スクリーンセーバ起動防止に使うためには,SetThreadExecutionState(ES_DISPLAY_REQUIRED) のように ES_DISPLAY_REQUIRED 単独で指定する必要がある.ES_DISPLAY_REQUIRED | ES_CONTINUOUS 等は効果がない.

参考:

WM_SYSCOMMAND の wParam の扱い

本来 0xfff0 と & を取るのが正しい……はず.

In WM_SYSCOMMAND messages, the four low-order bits of the wParam parameter are used internally by the system. To obtain the correct result when testing the value of wParam, an application must combine the value 0xFFF0 with the wParam value by using the bitwise AND operator.

WM_SYSCOMMAND Notification - MSDN Library

でも KB とか見ると結構適当.

2. あるアプリケーションが起動中にスクリーンセーバを起動させない方法

スクリーンセーバの機動を止めるには WM_SYSCOMMAND の wParam == SC_SCREENSAVE の時 return 1 を返してください。

case WM_SYSCOMMAND:
    if ( wParam == SC_SCREENSAVE )
    {
        return 1;
    }
    return (DefWindowProc(hWnd, message, wParam, lParam));
スクリーンセーバを抑制する方法 - Microsoft サポート オンライン

何も考えずに wParam == SC_SCREENSAVE とかやってますけどいいんすかねこれ.みんなコピペ大好きですよ?

WM_SYSCOMMAND トラップ時の返値は 0 にすべきか 1 にすべきか

2. あるアプリケーションが起動中にスクリーンセーバを起動させない方法

スクリーンセーバの機動を止めるには WM_SYSCOMMAND の wParam == SC_SCREENSAVE の時 return 1 を返してください。

case WM_SYSCOMMAND:
    if ( wParam == SC_SCREENSAVE )
    {
        return 1;
    }
    return (DefWindowProc(hWnd, message, wParam, lParam));
スクリーンセーバを抑制する方法 - Microsoft サポート オンライン

ここだけ読むと 1 を返すことが重要なように読めますが……

Return Value

An application should return zero if it processes this message.

WM_SYSCOMMAND Notification - MSDN Library

Once a screen saver is chosen, Windows monitors keystrokes and mouse movements and then starts the screen saver after a period of inactivity. However, Windows does not start the screen saver if any of the following conditions exist:

  • The active application is not a Windows-based application.
  • A computer-based training (CBT) window is present.
  • The active application receives the WM_SYSCOMMAND message with the wParam parameter set to the SC_SCREENSAVE value, but it does not pass the message to the DefWindowProc function.
Handling Screen Savers - MSDN Library

戻り値としては 0 の方が適切だし,スクリーンセーバ避けには DefWindowProc を呼ばないことの方が重要にも読めます.一方で,昔の Windows だと違った系の可能性も.

Windows Vista 以降,スクリーンセーバのパスワードロックが有効だと,メッセージトラップでスクリーンセーバを阻止できない

Windows Vista and later: If password protection is enabled by policy, the screen saver is started regardless of what an application does with the SC_SCREENSAVE notification.

Handling Screen Savers - MSDN Library

Windows Vista 以降,ここにチェックが入っていると,SC_SCREENSAVE トラップを行ってもスクリーンセーバは起動します.

これを気にするのであれば,ダミーのキーイベントかマウスイベントを発生させることを検討した方が良いのかもしれず.

渋木宏明(ひどり)渋木宏明(ひどり) 2008/09/25 16:11 サポート情報は結構「やっつけ」的なこと書いてあることもあるので…

WndProc の戻り値は「見てないだろ?」的なメッセージも結構あると思います。

使わないまま更新するくらいならインシデント使ってみるとかw

NyaRuRuNyaRuRu 2008/09/25 16:26 >使わないまま更新するくらいならインシデント使ってみるとかw

そろそろそういう時期ですのぅ.
優先順位考えてみますかね.何かインシデントで突っ込みたいネタが2〜3あったような記憶が.

quietsixquietsix 2008/09/25 21:45 非常に参考になりやした。
うちのゲームでもばっちりスクリーンセーバを防げるようになった模様です。

NyaRuRuNyaRuRu 2008/09/26 12:49 ういー
リリースがんばってくださいませー

ねこねこ 2010/10/22 23:24 Vista 以降で非アクティブな状態で抑制するにはどうしたらいいでしょう?

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証