Input Module |
前面提到输入事件,那么对输入事件分类,分类如下
/* ** HGE Input Event type constants */ #define INPUT_KEYDOWN 1 #define INPUT_KEYUP 2 #define INPUT_MBUTTONDOWN 3 #define INPUT_MBUTTONUP 4 #define INPUT_MOUSEMOVE 5 #define INPUT_MOUSEWHEEL 6 |
接下来看每个函数
_InputInit |
在引擎中初始化鼠标和键盘信息,在引擎 的初始化过程(构造函数)中会遇到(system.cpp:hge_impl)。
void HGE_Impl::_InputInit() { POINT pt; GetCursorPos(&pt); ScreenToClient(hwnd, &pt); Xpos = (float)pt.x; Ypos = (float)pt.y; memset(&keyz, 0, sizeof(keyz)); } |
_UpdateMouse |
这个函数会在主循环(system.cpp:system_start)中被调用,每一帧都更新鼠标的信息。
1.更新获得鼠标的位置;2.判断如果鼠标被按下(bCaptured==true)同时在游戏窗口内,则设置标志bMouseOver(鼠标是否在游戏窗口内)。
void HGE_Impl::_UpdateMouse() { POINT pt; RECT rc; GetCursorPos(&pt); GetClientRect(hwnd, &rc); MapWindowPoints(hwnd, NULL, (LPPOINT)&rc, 2); if(bCaptured || (PtInRect(&rc, pt) && WindowFromPoint(pt)==hwnd)) bMouseOver=true; else bMouseOver=false; } |
_BuildEvent(int type, int key, int scan, int flags, int x, int y) 核心!核心!核心! |
在这个函数中,根据type的不同选填不同的参数,创建不同的事件,填写事件结构,在window的消息处理函数中调用。(system.cpp:WindowProc)
- 将事件类型设置为传递过来的类型;键码设置为0;鼠标位置更新为传递进来的x,y
- GetKeyboardState(kbstate)获取当时的键盘信息
- 按键按下类型:如果重复按下则不更新,否则更新引擎所管理的按键信息(全局)
- 按键弹起类型:更新按键信息弹起信息
- 滚轮类型:是的情况下,按键设置为0,将滚轮属性定位key值;否的情况下,则将按键属性更新为key值,否则为0
- 鼠标按键按下类型:设置按键信息;设置焦点
- 鼠标按键弹起类型:设置按键信息,取消焦点;重新设置鼠标坐标,更新鼠标位置信息
- 对于功能键的属性的按键的更新
- 如果传递进来的x=-1,则为按键类型的事件,现在讲事件的鼠标信息更新;否则判断鼠标是否出界,并更新鼠标位置
- 将事件加入输入事件队列
- 更新引擎所掌握的鼠标位置、按键信息
void HGE_Impl::_BuildEvent(int type, int key, int scan, int flags, int x, int y) { CInputEventList *last, *eptr=new CInputEventList; unsigned char kbstate[256]; POINT pt; eptr->event.type=type; eptr->event.chr=0; pt.x=x; pt.y=y; GetKeyboardState(kbstate); if(type==INPUT_KEYDOWN) { if((flags & HGEINP_REPEAT) == 0) keyz[key] |= 1; ToAscii(key, scan, kbstate, (unsigned short *)&eptr->event.chr, 0); } if(type==INPUT_KEYUP) { keyz[key] |= 2; ToAscii(key, scan, kbstate, (unsigned short *)&eptr->event.chr, 0); } if(type==INPUT_MOUSEWHEEL) { eptr->event.key=0; eptr->event.wheel=key; ScreenToClient(hwnd,&pt); } else { eptr->event.key=key; eptr->event.wheel=0; } if(type==INPUT_MBUTTONDOWN) { keyz[key] |= 1; SetCapture(hwnd); bCaptured=true; } if(type==INPUT_MBUTTONUP) { keyz[key] |= 2; ReleaseCapture(); Input_SetMousePos(Xpos, Ypos); pt.x=(int)Xpos; pt.y=(int)Ypos; bCaptured=false; } if(kbstate[VK_SHIFT] & 0x80) flags|=HGEINP_SHIFT; if(kbstate[VK_CONTROL] & 0x80) flags|=HGEINP_CTRL; if(kbstate[VK_MENU] & 0x80) flags|=HGEINP_ALT; if(kbstate[VK_CAPITAL] & 0x1) flags|=HGEINP_CAPSLOCK; if(kbstate[VK_SCROLL] & 0x1) flags|=HGEINP_SCROLLLOCK; if(kbstate[VK_NUMLOCK] & 0x1) flags|=HGEINP_NUMLOCK; eptr->event.flags=flags; if(pt.x==-1) { eptr->event.x=Xpos;eptr->event.y=Ypos; } else { if(pt.x<0) pt.x=0; if(pt.y<0) pt.y=0; if(pt.x>=nScreenWidth) pt.x=nScreenWidth-1; if(pt.y>=nScreenHeight) pt.y=nScreenHeight-1; eptr->event.x=(float)pt.x; eptr->event.y=(float)pt.y; } eptr->next=0; if(!queue) queue=eptr; else { last=queue; while(last->next) last=last->next; last->next=eptr; } if(eptr->event.type==INPUT_KEYDOWN || eptr->event.type==INPUT_MBUTTONDOWN) { VKey=eptr->event.key;Char=eptr->event.chr; } else if(eptr->event.type==INPUT_MOUSEMOVE) { Xpos=eptr->event.x;Ypos=eptr->event.y; } else if(eptr->event.type==INPUT_MOUSEWHEEL) { Zpos+=eptr->event.wheel; } } |
_ClearQueue |
清理输入事件队列,清理键盘,在主循环中会被调用。
void HGE_Impl::_ClearQueue() { CInputEventList *nexteptr, *eptr=queue; memset(&keyz, 0, sizeof(keyz)); while(eptr) { nexteptr=eptr->next; delete eptr; eptr=nexteptr; } queue=0; VKey=0; Char=0; Zpos=0; } |
Input_GetEvent(hgeInputEvent *event) |
获取输入事件队列的第一个事件。
bool CALL HGE_Impl::Input_GetEvent(hgeInputEvent *event) { CInputEventList *eptr; if(queue) { eptr=queue; memcpy(event, &eptr->event, sizeof(hgeInputEvent)); queue=eptr->next; delete eptr; return true; } return false; } |
Input_GetMousePos(float *x, float *y) |
获取鼠标当前的位置信息。
void CALL HGE_Impl::Input_GetMousePos(float *x, float *y) { *x=Xpos; *y=Ypos; } |
Input_SetMousePos(float x, float y) |
设置鼠标位置:需要先ClientToScreen,再SetCursorPos。
void CALL HGE_Impl::Input_SetMousePos(float x, float y) { POINT pt; pt.x=(long)x; pt.y=(long)y; ClientToScreen(hwnd, &pt); SetCursorPos(pt.x,pt.y); } |
Input_GetMouseWheel |
获取鼠标的滚轮信息。
int CALL HGE_Impl::Input_GetMouseWheel() { return Zpos; } |
Input_IsMouseOver |
返回鼠标是否在游戏窗口上。
bool CALL HGE_Impl::Input_IsMouseOver() { return bMouseOver; } |
Input_GetKeyState(int key) |
返回键盘按键key是否被按键,在这里并没有调用引擎管理的当前键盘的状态来获取,而是直接通过GetKeyState(key)&0x8000来获取即时信息。
bool CALL HGE_Impl::Input_GetKeyState(int key) { return ((GetKeyState(key) & 0x8000) != 0); } |
Input_KeyDown |
按键是否被按下,这里按键按下是通过查看引擎管理的键盘信息来查看。
bool CALL HGE_Impl::Input_KeyDown(int key) { return (keyz[key] & 1) != 0; } |
Input_KeyUp |
按键是否弹起,这里也是通过引擎管理的键盘信息来查看。
bool CALL HGE_Impl::Input_KeyUp(int key) { return (keyz[key] & 2) != 0; } |
Input_GetKeyName |
获取某一个按键的名字。
char* CALL HGE_Impl::Input_GetKeyName(int key) { return KeyNames[key]; } |
Input_GetKey |
获取当前被触发的按键。
int CALL HGE_Impl::Input_GetKey() { return VKey; } |
Input_GetChar |
获取当前被触发按键的键码 。
int CALL HGE_Impl::Input_GetChar() { return Char; } |