2012-01-26 41 views
0

这是我原来的问题的延续 Why is D3D10SDKLayers.dll loaded during my DX11 game?我正在创建一个DX11游戏,并使用一个低级别的Windows键来捕获Alt + Enter,这样我就可以使用我自己的方法切换全屏而不是让Windows自动执行它,这不可避免地会导致问题。这个过程和细节的描述可以在链接的问题中找到。我的问题是,由于某种原因,在第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将自动做到这一点,这不可避免地会导致问题,”我很困惑在这里:Windows不会使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可能会被迫执行两种模式更改。)在致电SetFullscreenState后,建议再次拨打ResizeTarget,并将RefreshRate成员置零。这相当于DXGI中的无操作指令,但它可以避免刷新率问题,这将在下面讨论。

DXGI Overview有关于此事的一些详细信息,这ResizeTarget可能没有帮助的人们希望这将是:

默认情况下,DXGI会选择包含大多数客户端的输出窗户的面积。这是DXGI在响应alt-enter全屏显示时唯一可用的选项。

但是,它确实提到,大小由窗口的客户区域决定。也许你想要limit the client area,而不是安装键盘钩子?

+1

事实上,我已经阅读了DXGI的最佳实践,并且正在关注这封信。再一次,我想强调,如果没有关键的钩子,我可以很好地工作。如果我使用键T例如使用我的方法切换全屏,我可以无限期地做到这一点,它可以很好地工作(即使钥匙钩继续工作)。问题是当我使用Alt + Enter时,钥匙钩在第六次后停止工作。 – 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模式可用,则应该获取它。然后,您将获得一个WM_SIZE为640x480,这是您调用ResizeBuffers的机会。如果ResizeBuffers像这样调用,在模式切换之后,它将启用翻页(新的后缓冲区必须与监视器关联,或者系统不能直接翻页)。如果页面翻转没有这样启用,那么所有的Present调用将会调用一个blt操作,这将吸引你不需要花费的带宽。

请注意,您可能会或可能不会获得640x480。例如,如果显示器被旋转,您可能会获得下一个最大模式,其中包含640x480,可能是768x1024。如果你想在旋转显示器上工作得很好,你可以留意这一点,并将自己的信箱变成你想要的4x3纵横比。

但是,让DXGI选择显示模式通常是最佳做法,因为桌面模式可能是最好的原因有很多原因。用户可能已将电脑连接到只能执行一种模式的投影机。某些液晶显示器将以原始分辨率显示640x480,即显示器中间的小型邮票。理想情况下,您应该编码您的应用程序,以便能够在基本上任何分辨率下看起来漂亮,但至少在4x3,3x4,6x9和9x6纵横比下。

快乐编码 -Jeff