Disabling Shortcut Keys in Full Screen mode

昨天和两个同学一起玩魔兽3C的时候,由于很长时间我都是躲在练功房里砍木头人升级,而这种体力活不需要我监视英雄的举动,所以我就不断地切出游戏去上网,这种行为弄得两个哥们十分郁闷。呵呵,谁让我是主机呢,于是就不断地出现掉线的情况。

过后我就在想,那么如何在游戏中限制用户这种动作呢,使得他无法利用 WIN功能键不断地切进切出。

      下面就是我给出的一个解决方案,原理是:利用一个底层的键盘钩子函数对待处理的键盘消息进行过滤。这个钩子即使在用户对窗口最小化或切换到另一个应用程序也是有效的。

// demo0.cpp : Defines the entry point for the application.
//******************************
//Author:phinecos
//Date:2008-4-17
//*******************************

#include 
"stdafx.h"
#include 
"demo0.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
HWND hWnd = NULL; //窗口句柄
HHOOK g_hKeyboardHook;


TCHAR szTitle[MAX_LOADSTRING];                    
// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
BOOL isFullScreen = TRUE;//是否全屏
BOOL isActive=TRUE;        // Window Active Flag Set To TRUE By Default

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, 
int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);


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 
= (isFullScreen && isActive && ((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)));
            
break;
        }

    }


    
if( bEatKeystroke )
        
return 1;
    
else
        
return CallNextHookEx( g_hKeyboardHook, nCode, wParam, lParam );
}




int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     
int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

     
// TODO: Place code here.
    MSG msg;
    g_hKeyboardHook 
= SetWindowsHookEx( WH_KEYBOARD_LL,  LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); //设置钩子

    
if (MessageBox(NULL,L"是否以全屏模式运行?", L"信息?",MB_YESNO|MB_ICONQUESTION)==IDNO)
    
{
        isFullScreen 
= FALSE;                            // Windowed Mode
    }

    
// Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_DEMO0, szWindowClass, MAX_LOADSTRING);

    
// Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    
{
        
return FALSE;
    }


    
// Main message loop:
    while (GetMessage(&msg, NULL, 00))
    
{

        TranslateMessage(
&msg);
        DispatchMessage(
&msg);
    }

    UnhookWindowsHookEx( g_hKeyboardHook ); 
//卸载钩子
    return (int) msg.wParam;
}




//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
//    This function and its usage are only necessary if you want this code
//    to be compatible with Win32 systems prior to the 'RegisterClassEx'
//    function that was added to Windows 95. It is important to call this function
//    so that the application will get 'well formed' small icons associated
//    with it.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize 
= sizeof(WNDCLASSEX);

    wcex.style            
= CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    
= WndProc;
    wcex.cbClsExtra        
= 0;
    wcex.cbWndExtra        
= 0;
    wcex.hInstance        
= hInstance;
    wcex.hIcon            
= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DEMO0));
    wcex.hCursor        
= LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground    
= (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName    
= 0;
    wcex.lpszClassName    
= szWindowClass;
    wcex.hIconSm        
= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    
return RegisterClassEx(&wcex);
}


VOID KillWindow(VOID)                                
// Properly Kill The Window
{
    
if (isFullScreen)                                        // Are We In Fullscreen Mode?
    {
        ChangeDisplaySettings(NULL,
0);                    // If So Switch Back To The Desktop
        ShowCursor(TRUE);                                // Show Mouse Pointer
    }

    
if (hWnd && !DestroyWindow(hWnd))                    // Are We Able To Destroy The Window?
    {
        MessageBox(NULL,L
"Could Not Release hWnd.",L"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        hWnd
=NULL;                                        // Set hWnd To NULL
    }

    
if (!UnregisterClass(szWindowClass,hInst))            // Are We Able To Unregister Class
    {
        MessageBox(NULL,L
"Could Not Unregister Class.",L"SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
        hInst
=NULL;                                    // Set hInstance To NULL
    }

}



BOOL MyCreateWindow(TCHAR
* title, int width, int height, int bits, BOOL fullscreenflag)
{
    DWORD        dwExStyle;                
// Window Extended Style
    DWORD        dwStyle;                // Window Style
    RECT        WindowRect;                // Grabs Rectangle Upper Left / Lower Right Values
    WindowRect.left=(long)0;            // Set Left Value To 0
    WindowRect.right=(long)width;        // Set Right Value To Requested Width
    WindowRect.top=(long)0;                // Set Top Value To 0
    WindowRect.bottom=(long)height;        // Set Bottom Value To Requested Height

    isFullScreen 
= fullscreenflag;            // Set The Global Fullscreen Flag
    if (isFullScreen)                                                // Attempt Fullscreen Mode?
    {
        DEVMODE dmScreenSettings;                                
// Device Mode
        memset(&dmScreenSettings,0,sizeof(dmScreenSettings));    // Makes Sure Memory's Cleared
        dmScreenSettings.dmSize=sizeof(dmScreenSettings);        // Size Of The Devmode Structure
        dmScreenSettings.dmPelsWidth    = width;                // Selected Screen Width
        dmScreenSettings.dmPelsHeight    = height;                // Selected Screen Height
        dmScreenSettings.dmBitsPerPel    = bits;                    // Selected Bits Per Pixel
        dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

        
// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.
        if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
        
{
            
// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.
            if (MessageBox(NULL,L"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?",L"Infomation",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
            
{
                isFullScreen 
= FALSE;        // Windowed Mode Selected.  Fullscreen = FALSE
            }

            
else
            
{
                
// Pop Up A Message Box Letting User Know The Program Is Closing.
                MessageBox(NULL,L"Program Will Now Close.",L"ERROR",MB_OK|MB_ICONSTOP);
                
return FALSE;                                    // Return FALSE
            }

        }

    }


    
if (isFullScreen)                                                // Are We Still In Fullscreen Mode?
    {
        dwExStyle
=WS_EX_APPWINDOW;                                // Window Extended Style
        dwStyle=WS_POPUP;                                        // Windows Style
        ShowCursor(FALSE);                                        // Hide Mouse Pointer
    }

    
else
    
{
        dwExStyle
=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;            // Window Extended Style
        dwStyle=WS_OVERLAPPEDWINDOW;                            // Windows Style
    }


    AdjustWindowRectEx(
&WindowRect, dwStyle, FALSE, dwExStyle);        // Adjust Window To True Requested Size

    
// Create The Window
    if (!(hWnd=CreateWindowEx(    dwExStyle,                            // Extended Style For The Window
        szWindowClass,                            // Class Name
        title,                                // Window Title
        dwStyle |                            // Defined Window Style
        WS_CLIPSIBLINGS |                    // Required Window Style
        WS_CLIPCHILDREN,                    // Required Window Style
        00,                                // Window Position
        WindowRect.right-WindowRect.left,    // Calculate Window Width
        WindowRect.bottom-WindowRect.top,    // Calculate Window Height
        NULL,                                // No Parent Window
        NULL,                                // No Menu
        hInst,                            // Instance
        NULL)))                                // Dont Pass Anything To WM_CREATE
    {
        KillWindow();                                
// Reset The Display
        MessageBox(NULL,L"Window Creation Error.",L"ERROR",MB_OK|MB_ICONEXCLAMATION);
        
return FALSE;                                // Return FALSE
    }

    ShowWindow(hWnd,SW_SHOW);                        
// Show The Window
    SetForegroundWindow(hWnd);                        // Slightly Higher Priority
    SetFocus(hWnd);                                    // Sets Keyboard Focus To The Window

    
return TRUE;                                    // Success
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    MyRegisterClass(hInstance);
   hInst 
= hInstance; // Store instance handle in our global variable
    MyCreateWindow(szTitle,640,480,16,isFullScreen);

   
if (!hWnd)
   
{
      
return FALSE;
   }


   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   
return TRUE;
}


//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND    - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY    - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    
switch (message)
    
{
    
case WM_PAINT:
        hdc 
= BeginPaint(hWnd, &ps);
        
// TODO: Add any drawing code here
        EndPaint(hWnd, &ps);
        
break;
    
case WM_DESTROY:
        PostQuitMessage(
0);
        
break;
    
case WM_ACTIVATEAPP:
        
// g_bWindowActive is used to control if the Windows key is filtered by the keyboard hook or not.
        if( wParam == TRUE )
            isActive  
= TRUE;           
        
else 
            isActive  
= FALSE;           
        
break;

    
case WM_KEYDOWN:
        
{
            
if (wParam==VK_ESCAPE)
            
{//退出
                KillWindow();                        // Kill Our Current Window
            }

        }

        
break;
    
default:
        
return DefWindowProc(hWnd, message, wParam, lParam);
    }

    
return 0;
}


参考资料:

1,  Disabling Shortcut Keys in Games

2,  Nehe OpenGL tutorial

posted on 2008-04-17 11:43  Phinecos(洞庭散人)  阅读(2199)  评论(5编辑  收藏  举报

导航