在游戏中禁用快捷键

本文介绍如何在 Microsoft Windows 中暂时禁用键盘快捷方式,以防止中断全屏游戏的游戏玩法。 SHIFT 键和 Ctrl 键通常用作游戏中的触发或运行按钮。 如果用户不小心按下位于这些键) 附近的 Windows 键 (,他们可能会导致自己突然跳出应用程序,从而破坏游戏体验。 只需将 SHIFT 键用作游戏按钮,就会无意中执行 StickyKeys 快捷方式,该快捷方式可能会显示警告对话框。 若要避免这些问题,应在全屏模式下运行时禁用这些键,并在以窗口模式运行时启用这些键回到其默认处理程序,或者退出应用程序。

本文介绍如何执行以下操作:

使用键盘挂钩禁用 Windows 键

使用低级键盘挂钩来筛选出 正在处理的 Windows 键。 即使用户最小化窗口或切换到另一个应用程序,示例 1 中显示的低级别键盘挂钩仍有效。 这意味着,你必须小心,确保在停用应用程序时不会禁用 Windows 密钥。 示例 1 中的代码通过处理WM_ACTIVATEAPP消息来执行此操作。

注意

此方法适用于 Windows 2000 及更高版本的 Windows。 此方法也适用于最低特权用户帐户 (也称为标准用户帐户) 。

 

此方法由 DXUT 使用,并在以下代码示例中进行了说明。

示例 1。 使用低级键盘挂钩禁用 Windows 键

HHOOK g_hKeyboardHook = nullptr;
bool g_bWindowActive = false;
bool g_bFullscreen;
 
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    // Initialization
    g_hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(nullptr), 0 );
 
    // 
    // main application code here
    // 
 
    // Cleanup before shutdown
    UnhookWindowsHookEx( g_hKeyboardHook );
    g_hKeyboardHook = nullptr;
    
    return 0;
}
 
 
LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam )
{
    if (nCode < 0 || nCode != HC_ACTION )  // do not process message 
        return CallNextHookEx( g_hKeyboardHook, nCode, wParam, lParam); 
 
    bool bEatKeystroke = false;
    auto p = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
    switch (wParam) 
    {
        case WM_KEYDOWN:  
        case WM_KEYUP:    
        {
            bEatKeystroke = (g_bFullscreen && g_bWindowActive && ((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)));
            // Note that this will not block the Xbox Game Bar hotkeys (Win+G, Win+Alt+R, etc.)
            break;
        }
    }
 
    if( bEatKeystroke )
        return 1;
    else
        return CallNextHookEx( g_hKeyboardHook, nCode, wParam, lParam );
}
 
 
LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
    switch( uMsg )
    {
       case WM_ACTIVATEAPP:
            // g_bWindowActive is used to control if the Windows key is filtered by the keyboard hook or not.
            if( wParam )
                g_bWindowActive = true;           
            else 
                g_bWindowActive = false;           
            break;
            
        case WM_SYSKEYDOWN:
            if (wParam == VK_RETURN && (lParam & 0x60000000) == 0x20000000)
            {
                // Implement the classic ALT+ENTER fullscreen toggle
             ...
                // g_bFullscreen is used to control if the Windows key is filtered by the keyboard hook or not.
                g_bFullscreen = !g_bFullscreen;                
                
                // Remember to use DXGI_MWA_NO_ALT_ENTER when you call the DXGI method MakeWindowAssociation
                // so you control the fullscreen toggling in your application.
            }
            break;
    }
}

禁用辅助功能快捷键

Windows 包括诸如 StickyKeys、FilterKeys 和 ToggleKeys 等辅助功能, (请参阅 Windows 辅助功能) 。 其中每个都有不同的用途:例如,StickyKeys 专为难以同时按住两个或多个键的用户而设计。 其中每个辅助功能还具有一个键盘快捷方式,允许打开或关闭该功能。 例如,通过按 SHIFT 键五次触发 StickyKeys 快捷方式。 如果游戏中还使用了 SHIFT 键,则用户在玩游戏期间可能会意外触发此快捷方式。 触发快捷方式时,Windows (默认情况下) 对话框中显示警告,这将导致 Windows 最小化在全屏模式下运行的游戏。 当然,这会对游戏发挥产生巨大影响。

某些客户需要辅助功能,并且本身不会干扰全屏游戏;因此,不应更改辅助功能设置。 但是,由于辅助功能快捷方式在意外触发时可能会中断游戏玩法,因此仅当未通过调用 SystemParametersInfo 启用该功能时,才应关闭辅助功能快捷方式。

即使应用程序退出, SystemParametersInfo 关闭的辅助功能快捷方式也会保持关闭状态。 这意味着,在退出应用程序之前,必须还原设置。 由于应用程序可能无法正确退出,因此应将这些设置写入永久性存储,以便在应用程序再次运行时还原这些设置。 如果发生崩溃,还可以使用异常处理程序还原这些设置。

关闭这些快捷方式

  1. 在禁用当前辅助功能设置之前捕获它们。
  2. 如果禁用辅助功能,则当应用程序进入全屏模式时禁用辅助功能快捷方式。
  3. 在应用程序进入窗口模式或退出时还原辅助功能设置。

此方法在 DXUT 中使用,并在以下代码示例中进行了说明。

注意

此方法在标准用户帐户上运行时有效。

 

示例 2。 禁用辅助功能快捷键

STICKYKEYS g_StartupStickyKeys = {sizeof(STICKYKEYS), 0};
TOGGLEKEYS g_StartupToggleKeys = {sizeof(TOGGLEKEYS), 0};
FILTERKEYS g_StartupFilterKeys = {sizeof(FILTERKEYS), 0};    
 
 
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    // Save the current sticky/toggle/filter key settings so they can be restored them later
    SystemParametersInfo(SPI_GETSTICKYKEYS, sizeof(STICKYKEYS), &g_StartupStickyKeys, 0);
    SystemParametersInfo(SPI_GETTOGGLEKEYS, sizeof(TOGGLEKEYS), &g_StartupToggleKeys, 0);
    SystemParametersInfo(SPI_GETFILTERKEYS, sizeof(FILTERKEYS), &g_StartupFilterKeys, 0);
 
 ...
 
    // Disable when full screen
    AllowAccessibilityShortcutKeys( false );
 
 ...
 
    // Restore back when going to windowed or shutting down
    AllowAccessibilityShortcutKeys( true );
}
 
 
void AllowAccessibilityShortcutKeys( bool bAllowKeys )
{
    if( bAllowKeys )
    {
        // Restore StickyKeys/etc to original state and enable Windows key      
        STICKYKEYS sk = g_StartupStickyKeys;
        TOGGLEKEYS tk = g_StartupToggleKeys;
        FILTERKEYS fk = g_StartupFilterKeys;
        
        SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &g_StartupStickyKeys, 0);
        SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &g_StartupToggleKeys, 0);
        SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &g_StartupFilterKeys, 0);
    }
    else
    {
        // Disable StickyKeys/etc shortcuts but if the accessibility feature is on, 
        // then leave the settings alone as its probably being usefully used
 
        STICKYKEYS skOff = g_StartupStickyKeys;
        if( (skOff.dwFlags & SKF_STICKYKEYSON) == 0 )
        {
            // Disable the hotkey and the confirmation
            skOff.dwFlags &= ~SKF_HOTKEYACTIVE;
            skOff.dwFlags &= ~SKF_CONFIRMHOTKEY;
 
            SystemParametersInfo(SPI_SETSTICKYKEYS, sizeof(STICKYKEYS), &skOff, 0);
        }
 
        TOGGLEKEYS tkOff = g_StartupToggleKeys;
        if( (tkOff.dwFlags & TKF_TOGGLEKEYSON) == 0 )
        {
            // Disable the hotkey and the confirmation
            tkOff.dwFlags &= ~TKF_HOTKEYACTIVE;
            tkOff.dwFlags &= ~TKF_CONFIRMHOTKEY;
 
            SystemParametersInfo(SPI_SETTOGGLEKEYS, sizeof(TOGGLEKEYS), &tkOff, 0);
        }
 
        FILTERKEYS fkOff = g_StartupFilterKeys;
        if( (fkOff.dwFlags & FKF_FILTERKEYSON) == 0 )
        {
            // Disable the hotkey and the confirmation
            fkOff.dwFlags &= ~FKF_HOTKEYACTIVE;
            fkOff.dwFlags &= ~FKF_CONFIRMHOTKEY;
 
            SystemParametersInfo(SPI_SETFILTERKEYS, sizeof(FILTERKEYS), &fkOff, 0);
        }
    }
}