2012-01-26 23 views
0

これは私の元の質問 Why is D3D10SDKLayers.dll loaded during my DX11 game?私はDX11ゲームを作成していますので、私は自分のメソッドを使用しての代わりに、Windowsが自動的にそれを行う持つフルスクリーン切り替えができることをAltキー+ Enterキーをキャプチャするために、低レベルのウィンドウキーフックを使用していますの続きです必然的に問題を引き起こす。このプロセスと詳細の説明は、リンクされた質問に記載されています。私の問題は、何らかの理由で6回目のAlt + Enterの後にキーフックが一貫して機能しなくなることです。私は自分自身を登録解除していません。ここで低レベルのWindowsキーフックが機能しなくなるのはなぜですか?

はキーフックコードです:あなたはより多くの情報が必要な場合


LRESULT _stdcall MyClass::WindowsKeyHook(s32 nCode, WPARAM wParam, LPARAM lParam) { 
    printf("Key hook called, nCode: %d. ", nCode); 
    if(nCode < 0 || nCode != HC_ACTION) { // do not process message 
     return CallNextHookEx(MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam); 
    } 
    printf(" Key hook status ok.\n"); 

    BOOL bEatKeystroke = FALSE; 
    KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam; 
    switch(wParam) { 
     //NOTE: Alt seems to be a system key when it is PRESSED, but a regular key when it is released... 
     case WM_SYSKEYDOWN: 
      if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) { 
       MyClassVar.SetAltPressed(TRUE); 
      } 
      if(MyClassVar.IsAltPressed() && p->vkCode == VK_RETURN) { 
       bEatKeystroke = TRUE; 
       MyClassVar.SetAltEnterUsed(TRUE); 
       printf("Alt+Enter used.\n"); 
      } 
      break; 
     case WM_SYSKEYUP: 
      //NOTE: releasing alt+enter causes a SYSKEYUP message with code 0x13: PAUSE key... 
      break; 
     case WM_KEYDOWN: 
      break; 
     case WM_KEYUP: { 
      if(p->vkCode == VK_MENU || p->vkCode == VK_LMENU || p->vkCode == VK_RMENU) { 
       MyClassVar.SetAltPressed(FALSE); 
      } 
      bEatKeystroke = (!MyClassVar.IsShortcutKeysAllowed() && 
           (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN)); 
      break; 
     } 
    } 

    if(bEatKeystroke) { 
     return 1; 
    } 
    else { 
     return CallNextHookEx(MyClassVar.GetWindowsKeyHook(), nCode, wParam, lParam); 
    } 
} 

、ちょうど必要なものを教えてください。なぜこのようなことが起こっているのかわからないので、私はどのような情報を提供する必要があるのか​​よく分かりません。それを明示的に登録解除するだけでなく、キーフックを取り除く唯一の方法は、Windowsがそれをタイムアウトした場合、私が知る限りです。すべてのMyClassVarメソッドはできるだけ高速にインライン化されており、Alt + Enterは別のスレッドから処理されます。

+0

私はここで混乱している「Windowsは、必然的に問題を引き起こす、自動的にそれを行います」。だからあなたは自分のキーボードフックを書くことで何を避けたのですか? –

+0

@ todda.speot DX11ゲームでAlt + Enterを押すと、ウィンドウは自動的にフルスクリーンモードをトグルします。フロントバッファの解像度をデスクトップ解像度に設定します。これは、ゲームを640x480で実行したい場合は間違っています。これを避けるために、私はAlt + Enterキーをキャッチし、完全に動作する独自のToggleFullscreen()メソッドを実行するためのキーフックを設定しました。 – Darkhydro

+0

私は私の答えですこぶることをしました。 –

答えて

2

Windowsは回それを場合は明示的に登録解除以外のキーフックを取り除くための唯一の方法は、私の知る限り、です。

これは間違いなく、by increasing the LowLevelHooksTimeout registry keyが一時的にタイムアウトしていることを確認することができます。

フックが呼び出される前に、別のキーボードフックが最初に取得され、すべての入力を飲み込んでいる可能性はあまりありません(フックが特定のキーの組み合わせで行うことがまさにそのことです)。

あなたのコメントから、DXGIが全画面表示に切り替わるときにフルスクリーン解像度を選択するように思えます。

以下は、DirectX Graphics Infrastructure (DXGI): Best Practicesの抜粋です。この情報は、WM_SIZEについて話しているこの抜粋の前に私が逃した内容と同様に、役に立たないかもしれません。

上記の説明の方法論は、非常に特定の経路に従います。 DXGIはデフォルトでフルスクリーン解像度をデスクトップ解像度に設定します。ただし、多くのアプリケーションでは、フルスクリーン解像度を推奨しています。そのような場合、DXGIはIDXGISwapChain::ResizeTargetを提供します。これは、SetFullscreenStateを呼び出す前に呼び出す必要があります。これらのメソッドは、反対の順序(SetFullscreenStateが最初に続き、その後にResizeTargetが続きます)でも呼び出すことができますが、これにより余分なWM_SIZEメッセージがアプリケーションに送信されます。 DXGIは2つのモード変更を行わなければならないので、ちらつきが発生する可能性があります。SetFullscreenStateを呼び出した後、RefreshRateメンバを0にしてResizeTargetに再度呼び出すことをお勧めします。これはDXGIの操作なし命令になりますが、リフレッシュレートの問題を回避することができます。これについては次に説明します。

DXGI Overview一つは、それは次のようになり望んでいるだろうとResizeTargetはとして有用ではないかもしれないことを、問題のいくつかのより多くの情報を持っている:デフォルトでは

、DXGIは、クライアントのほとんどが含まれている出力を選択しますウィンドウの領域。これは、alt-enterに応答してフルスクリーンになったときにDXGIが利用できる唯一のオプションです。

ただし、サイズはウィンドウのクライアント領域によって決まります。おそらく、キーボードフックをインストールする代わりに、limit the client areaにしたいですか?

+1

私はDXGIのベストプラクティスを実際に読んでおり、それを手紙に従っています。繰り返しますが、キーフックなしでこれが完全に機能していることを強調したいと思います。私のメソッドを使用してフルスクリーンを切り替えるためにキーTを使用する場合、私は無限にそれを行うことができ、それは素晴らしい(キーフックが機能していても)効果があります。問題は、Alt + Enterキーを使用すると、キーフックが6時間後に機能しなくなることです。 – Darkhydro

+0

私はあなたの答えを編集しました。追加情報をありがとう、私は実際にDXGIの概要のものについて知りませんでした。これは、キーフックを使用する回避策を提供する可能性があります。 – Darkhydro

+0

@Darkhydro運が良かったです。私はこれを行うには合理的な距離があるべきだと思う、低レベルのキーボードのフックは、過度の叫び声。 –

1

DXGIのフックを無効にしましたか?

IDXGISwapChain::MakeWindowAssociation(DXGI_MWA_NO_WINDOW_CHANGES) 

また、DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCHでswapchainを作成するDXGIが最も密接にあなたのウィンドウサイズが一致して表示モードを見つけることになります。すでにResizeTarget()が640x480になっていて、少なくとも640x480モードがある場合は、それを入手する必要があります。次に、ResizeBuffersを呼び出す機会であるWM_SIZEを640x480に設定します。 ResizeBuffersがこのように呼び出された場合、モード切り替え後、ページフリッピングが有効になります(新しいバックバッファがモニタに関連付けられているか、システムが直接ページフリップできません)。このようにページフリッピングが有効になっていないと、現在のすべてのコールで、不要な帯域幅を吸い取るblt操作が呼び出されます。

640x480が表示される場合と表示されない場合があります。たとえば、ディスプレイが回転している場合は、おそらく768x1024になる640x480を含む次の最大のモードになります。回転したディスプレイでうまく動作するようにするには、これとレターボックスを4x3のアスペクト比に注意してください。

しかし、DXGIに表示モードを選択させることが一般的にはベストプラクティスです。なぜなら、デスクトップモードが最良のものになる理由はたくさんあります。ユーザは、その1つのモードのみを行うことができるプロジェクタにそのコンピュータを接続している可能性がある。一部のLCDは、ネイティブ解像度で640x480を表示します。つまり、モニタの中央に小さな郵便切手が表示されます。理想的には、基本的にどの解像度でも、少なくとも4x3,3x4,6x9、および9x6のアスペクト比で見えるようにアプリケーションをコーディングする必要があります。 * Windowsは*自動的にWindows全画面表示をしないと、あなたのソリューションが問題を抱えている:

ハッピーコーディング -Jeff

関連する問題