继续上一章对其按键消息处理抽丝剥茧。看BuildEvent()函数里面
我们先来分析其这段代码
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; }
再看外面怎么调用的
case WM_SYSKEYDOWN: if(wparam == VK_F4) { if(pHGE->procExitFunc && !pHGE->procExitFunc()) return FALSE; return DefWindowProc(hwnd, msg, wparam, lparam); } else if(wparam == VK_RETURN) { pHGE->System_SetState(HGE_WINDOWED, !pHGE->System_GetState(HGE_WINDOWED)); return FALSE; } else { pHGE->_BuildEvent(INPUT_KEYDOWN, wparam, HIWORD(lparam) & 0xFF, (lparam & 0x40000000) ? HGEINP_REPEAT:0, -1, -1); return FALSE; } case WM_KEYDOWN: pHGE->_BuildEvent(INPUT_KEYDOWN, wparam, HIWORD(lparam) & 0xFF, (lparam & 0x40000000) ? HGEINP_REPEAT:0, -1, -1); return FALSE;
所有键盘按键响应,都会响应WM_SYSKEYDOWN消息,这里的INPUT_KEYDOWN和INPUT_KEYUP已经包括了特殊系统按键,即TAB,CTRL,ALT;
除此之外,还有很重要的东西,那就是关于keyz数组的应用。
这个就是表格驱动法的典型应用(引自【代码大全】)
思想就是将按键的键值和鼠标的左,中, 右三个键值看做一个维度,将按键行为作为另一个维度。
我们可以看到代码中就是把键值作为数组的下标,数组元素初始化为0,
用和0x01,0x10的或操作来记录DOWN和UP的行为。
这样做的好处便于数据表的维护,不至于添加新的键值或者修改旧的键值的同时,需要去维护一大堆if else逻辑代替的代码。
同时在整个代码设计上来说,实现了新的分层,将行为层与逻辑处理层分隔开,符合内聚原则。
我们可以看到外面需要获取按键情况的时候,接口如下:
bool CALL HGE_Impl::Input_KeyDown(int key) { return (keyz[key] & 1) != 0; } bool CALL HGE_Impl::Input_KeyUp(int key) { return (keyz[key] & 2) != 0; }
其中传进来的key值就是一个代表是左键按下或者右键按下的值。
再想想,我们完全可以把这种处理放到我们的程序中,并作为一个单件使用。