次の方法で共有


ゲームでのショートカット キーの無効化

XNA デベロッパー コネクション (XDC)、ソフトウェア開発主任

Jason Sandlin 著

2004 年 12 月

ここでは、全画面表示ゲームのプレイが中断されないように、Microsoft® Windows® のキーボード ショートカットを一時的に無効にする方法について説明します。Shift キーと Ctrl キーは、ゲームで発射ボタンや実行ボタンとして頻繁に使用されます。この 2 つのキーのすぐそばにある Windows キーをユーザーが誤って押すと、アプリケーションを突然離れてしまってゲームが台無しになることがあります。Shift キーをゲーム ボタンとして使用するだけでも、意図せずに StickyKeys ショートカットが実行されて警告ダイアログが表示されるおそれがあります。このような問題を回避するために、全画面表示モードで実行するときはこれらのキーを無効にし、ウィンドウ表示モードで実行するときやアプリケーションを終了するときは有効にして既定のハンドラーに戻すようにする必要があります。

ここでは、以下の操作を行う方法について説明します。

  • キーボード フックを使用した Windows キーの無効化
  • アクセシビリティ ショートカット キーの無効化

キーボード フックを使用した Windows キーの無効化

低レベルのキーボード フックを使用して、Windows キーを処理の対象から除外します。例 1 に示す低レベルのキーボード フックは、ユーザーがウィンドウを最小化したり、別のアプリケーションに切り替えたりしても効力を維持します。つまり、アプリケーションがアクティブでなくなったときに Windows キーが確実に有効になるように注意を払う必要があります。例 1 のコードは、WM_ACTIVATEAPP メッセージを処理することでこれを実現しています。

    この方法は、Windows 2000 以降のバージョンの Windows で有効です。また、最小特権のユーザー アカウント (制限付きのユーザー アカウントとも呼ばれます) で機能します。

この方法は DXUT で使用されます。次のコード例は、この方法を具体的に示したものです。

例 1: 低レベルのキーボード フックを使用した Windows キーの無効化

HHOOK g_hKeyboardHook;
BOOL g_bFullscreen;
 
INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{
    // Initialization
    g_hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL,  LowLevelKeyboardProc, GetModuleHandle(NULL), 0 );
 
    // 
    // main application code here
    // 
 
    // Cleanup before shutdown
    UnhookWindowsHookEx( g_hKeyboardHook );
}
 
 
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;
    KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam;
    switch (wParam) 
    {
        case WM_KEYDOWN:  
        case WM_KEYUP:    
        {
            bEatKeystroke = (g_bFullscreen && g_bWindowActive && ((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)));
            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 == TRUE )
                g_bWindowActive  = true;           
            else 
                g_bWindowActive  = false;           
            break;
    }
}

アクセシビリティ ショートカット キーの無効化

Windows には、StickyKeys、FilterKeys、ToggleKeys などのアクセシビリティ機能が搭載されています (「Windows Accessability (Windows のアクセシビリティ)」を参照)。各機能の目的はそれぞれに異なります。たとえば、StickyKeys は複数のキーを同時に押すことが困難なユーザー向けに作られています。また、それぞれのアクセシビリティ機能には機能のオンとオフを切り替えるためのキーボード ショートカットもあります。たとえば、StickyKeys ショートカットは Shift キーを 5 回押すことで作動します。Shift キーがゲームでも使用されると、ユーザーがゲーム プレイ中に誤ってこのショートカットを作動させる可能性があります。ショートカットが作動すると、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( true );
 
    // Restore back when going to windowed or shutting down
    AllowAccessibilityShortcutKeys( false );
}
 
 
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);
        }
    }
}