昨天和两个同学一起玩魔兽<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" /><chmetcnv unitname="C" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0" w:st="on"><span lang="EN-US" style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana">3C</span></chmetcnv>的时候,由于很长时间我都是躲在练功房里砍木头人升级,而这种体力活不需要我监视英雄的举动,所以我就不断地切出游戏去上网,这种行为弄得两个哥们十分郁闷。呵呵,谁让我是主机呢,于是就不断地出现掉线的情况。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
过后我就在想,那么如何在游戏中限制用户这种动作呢,使得他无法利用’ WIN功能键”不断地切进切出。
下面就是我给出的一个解决方案,原理是:利用一个底层的键盘钩子函数对待处理的键盘消息进行过滤。这个钩子即使在用户对窗口最小化或切换到另一个应用程序也是有效的。
//
demo0.cpp:Definestheentrypointfortheapplication.
//
******************************
//
Author:phinecos
//
Date:2008-4-17
//
*******************************
#include
"
stdafx.h
"
#include
"
demo0.h
"

#define
MAX_LOADSTRING100

//
GlobalVariables:
HINSTANCEhInst;
//
currentinstance
HWNDhWnd
=
NULL;
//
窗口句柄
HHOOKg_hKeyboardHook;


TCHARszTitle[MAX_LOADSTRING];
//
Thetitlebartext
TCHARszWindowClass[MAX_LOADSTRING];
//
themainwindowclassname
BOOLisFullScreen
=
TRUE;
//
是否全屏
BOOLisActive
=
TRUE;
//
WindowActiveFlagSetToTRUEByDefault

//
Forwarddeclarationsoffunctionsincludedinthiscodemodule:
ATOMMyRegisterClass(HINSTANCEhInstance);
BOOLInitInstance(HINSTANCE,
int
);
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);


LRESULTCALLBACKLowLevelKeyboardProc(
int
nCode,WPARAMwParam,LPARAMlParam)

{
if(nCode<0||nCode!=HC_ACTION)//donotprocessmessage
returnCallNextHookEx(g_hKeyboardHook,nCode,wParam,lParam);

boolbEatKeystroke=false;
KBDLLHOOKSTRUCT*p=(KBDLLHOOKSTRUCT*)lParam;
switch(wParam)


{
caseWM_KEYDOWN:
caseWM_KEYUP:


{
bEatKeystroke=(isFullScreen&&isActive&&((p->vkCode==VK_LWIN)||(p->vkCode==VK_RWIN)));
break;
}
}

if(bEatKeystroke)
return1;
else
returnCallNextHookEx(g_hKeyboardHook,nCode,wParam,lParam);
}



int
APIENTRY_tWinMain(HINSTANCEhInstance,
HINSTANCEhPrevInstance,
LPTSTRlpCmdLine,
int
nCmdShow)

{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);

//TODO:Placecodehere.
MSGmsg;
g_hKeyboardHook=SetWindowsHookEx(WH_KEYBOARD_LL,LowLevelKeyboardProc,GetModuleHandle(NULL),0);//设置钩子

if(MessageBox(NULL,L"是否以全屏模式运行?",L"信息?",MB_YESNO|MB_ICONQUESTION)==IDNO)


{
isFullScreen=FALSE;//WindowedMode
}
//Initializeglobalstrings
LoadString(hInstance,IDS_APP_TITLE,szTitle,MAX_LOADSTRING);
LoadString(hInstance,IDC_DEMO0,szWindowClass,MAX_LOADSTRING);

//Performapplicationinitialization:
if(!InitInstance(hInstance,nCmdShow))


{
returnFALSE;
}

//Mainmessageloop:
while(GetMessage(&msg,NULL,0,0))


{

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



//
//
FUNCTION:MyRegisterClass()
//
//
PURPOSE:Registersthewindowclass.
//
//
COMMENTS:
//
//
Thisfunctionanditsusageareonlynecessaryifyouwantthiscode
//
tobecompatiblewithWin32systemspriortothe'RegisterClassEx'
//
functionthatwasaddedtoWindows95.Itisimportanttocallthisfunction
//
sothattheapplicationwillget'wellformed'smalliconsassociated
//
withit.
//
ATOMMyRegisterClass(HINSTANCEhInstance)

{
WNDCLASSEXwcex;

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));

returnRegisterClassEx(&wcex);
}

VOIDKillWindow(VOID)
//
ProperlyKillTheWindow

{
if(isFullScreen)//AreWeInFullscreenMode?


{
ChangeDisplaySettings(NULL,0);//IfSoSwitchBackToTheDesktop
ShowCursor(TRUE);//ShowMousePointer
}
if(hWnd&&!DestroyWindow(hWnd))//AreWeAbleToDestroyTheWindow?


{
MessageBox(NULL,L"CouldNotReleasehWnd.",L"SHUTDOWNERROR",MB_OK|MB_ICONINFORMATION);
hWnd=NULL;//SethWndToNULL
}
if(!UnregisterClass(szWindowClass,hInst))//AreWeAbleToUnregisterClass


{
MessageBox(NULL,L"CouldNotUnregisterClass.",L"SHUTDOWNERROR",MB_OK|MB_ICONINFORMATION);
hInst=NULL;//SethInstanceToNULL
}
}


BOOLMyCreateWindow(TCHAR
*
title,
int
width,
int
height,
int
bits,BOOLfullscreenflag)

{
DWORDdwExStyle;//WindowExtendedStyle
DWORDdwStyle;//WindowStyle
RECTWindowRect;//GrabsRectangleUpperLeft/LowerRightValues
WindowRect.left=(long)0;//SetLeftValueTo0
WindowRect.right=(long)width;//SetRightValueToRequestedWidth
WindowRect.top=(long)0;//SetTopValueTo0
WindowRect.bottom=(long)height;//SetBottomValueToRequestedHeight

isFullScreen=fullscreenflag;//SetTheGlobalFullscreenFlag
if(isFullScreen)//AttemptFullscreenMode?


{
DEVMODEdmScreenSettings;//DeviceMode
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));//MakesSureMemory'sCleared
dmScreenSettings.dmSize=sizeof(dmScreenSettings);//SizeOfTheDevmodeStructure
dmScreenSettings.dmPelsWidth=width;//SelectedScreenWidth
dmScreenSettings.dmPelsHeight=height;//SelectedScreenHeight
dmScreenSettings.dmBitsPerPel=bits;//SelectedBitsPerPixel
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

//TryToSetSelectedModeAndGetResults.NOTE:CDS_FULLSCREENGetsRidOfStartBar.
if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)


{
//IfTheModeFails,OfferTwoOptions.QuitOrUseWindowedMode.
if(MessageBox(NULL,L"TheRequestedFullscreenModeIsNotSupportedBy/nYourVideoCard.UseWindowedModeInstead?",L"Infomation",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)


{
isFullScreen=FALSE;//WindowedModeSelected.Fullscreen=FALSE
}
else


{
//PopUpAMessageBoxLettingUserKnowTheProgramIsClosing.
MessageBox(NULL,L"ProgramWillNowClose.",L"ERROR",MB_OK|MB_ICONSTOP);
returnFALSE;//ReturnFALSE
}
}
}

if(isFullScreen)//AreWeStillInFullscreenMode?


{
dwExStyle=WS_EX_APPWINDOW;//WindowExtendedStyle
dwStyle=WS_POPUP;//WindowsStyle
ShowCursor(FALSE);//HideMousePointer
}
else


{
dwExStyle=WS_EX_APPWINDOW|WS_EX_WINDOWEDGE;//WindowExtendedStyle
dwStyle=WS_OVERLAPPEDWINDOW;//WindowsStyle
}

AdjustWindowRectEx(&WindowRect,dwStyle,FALSE,dwExStyle);//AdjustWindowToTrueRequestedSize

//CreateTheWindow
if(!(hWnd=CreateWindowEx(dwExStyle,//ExtendedStyleForTheWindow
szWindowClass,//ClassName
title,//WindowTitle
dwStyle|//DefinedWindowStyle
WS_CLIPSIBLINGS|//RequiredWindowStyle
WS_CLIPCHILDREN,//RequiredWindowStyle
0,0,//WindowPosition
WindowRect.right-WindowRect.left,//CalculateWindowWidth
WindowRect.bottom-WindowRect.top,//CalculateWindowHeight
NULL,//NoParentWindow
NULL,//NoMenu
hInst,//Instance
NULL)))//DontPassAnythingToWM_CREATE


{
KillWindow();//ResetTheDisplay
MessageBox(NULL,L"WindowCreationError.",L"ERROR",MB_OK|MB_ICONEXCLAMATION);
returnFALSE;//ReturnFALSE
}
ShowWindow(hWnd,SW_SHOW);//ShowTheWindow
SetForegroundWindow(hWnd);//SlightlyHigherPriority
SetFocus(hWnd);//SetsKeyboardFocusToTheWindow

returnTRUE;//Success
}
//
//
FUNCTION:InitInstance(HINSTANCE,int)
//
//
PURPOSE:Savesinstancehandleandcreatesmainwindow
//
//
COMMENTS:
//
//
Inthisfunction,wesavetheinstancehandleinaglobalvariableand
//
createanddisplaythemainprogramwindow.
//
BOOLInitInstance(HINSTANCEhInstance,
int
nCmdShow)

{
MyRegisterClass(hInstance);
hInst=hInstance;//Storeinstancehandleinourglobalvariable
MyCreateWindow(szTitle,640,480,16,isFullScreen);

if(!hWnd)


{
returnFALSE;
}

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

returnTRUE;
}

//
//
FUNCTION:WndProc(HWND,UINT,WPARAM,LPARAM)
//
//
PURPOSE:Processesmessagesforthemainwindow.
//
//
WM_COMMAND-processtheapplicationmenu
//
WM_PAINT-Paintthemainwindow
//
WM_DESTROY-postaquitmessageandreturn
//
//
LRESULTCALLBACKWndProc(HWNDhWnd,UINTmessage,WPARAMwParam,LPARAMlParam)

{
PAINTSTRUCTps;
HDChdc;

switch(message)


{
caseWM_PAINT:
hdc=BeginPaint(hWnd,&ps);
//TODO:Addanydrawingcodehere
EndPaint(hWnd,&ps);
break;
caseWM_DESTROY:
PostQuitMessage(0);
break;
caseWM_ACTIVATEAPP:
//g_bWindowActiveisusedtocontroliftheWindowskeyisfilteredbythekeyboardhookornot.
if(wParam==TRUE)
isActive=TRUE;
else
isActive=FALSE;
break;

caseWM_KEYDOWN:


{
if(wParam==VK_ESCAPE)


{//退出
KillWindow();//KillOurCurrentWindow
}
}
break;
default:
returnDefWindowProc(hWnd,message,wParam,lParam);
}
return0;
}
参考资料:
1, Disabling Shortcut Keys in Games
2, Nehe OpenGL tutorial