由于duilib是开源无专人管理的界面库,导致网上流传了各式各样的版本。今天某某修复了这个bug上传一版,明天某某修复另一个bug上传别的版本,太过杂乱。而且之所以写这篇文章,是因为公司用的duilib库,存在EDIT控件对table键支持的bug。即焦点混乱。花了近一天时间研究了PaintManager.cpp,Edit.cpp,EditWnd.cpp三个文件的源码,发现逻辑上不存在问题。试了csdn多个博主提供的方法改动皆无成效的情况下,决定采用无脑的方法实现帐号密码框table键的切换。
接下来阐述本人使用的方法,希望有小伙伴遇到类似情况看了此文章能有所帮助。在我自己的项目中,登录界面是一个子窗口它有自身的句柄,只要有句柄,我们就可以使用钩(Hook)这个窗口,拿到我们想要的信息。
我们不妨脑补下登录界面的流程。以仅有帐号框,密码框,登录按钮的登录界面为例,大致分为两种情况:
1. 鼠标点击帐号框,table键按下情况下切换到密码框,再按下切回帐号框。
2. 鼠标点击密码框,table键按下情况下切换到帐号框,再按下切回密码框。
最后点击登录按钮执行登录操作。所以我们只需要钩键盘消息即可。在duilib中,HandWindow函数功能丰富,鼠标按下的消息可以直接在里面进行捕获和实现可以。
以下贴上功能实现的代码部分。CPP实现开头加上如下键盘消息回调代码。其中WM_TAB_KEY_PRESS是自定义的table键消息
#define WM_TAB_KEY_PRESS WM_USER+100
HWND g_hHwndMain = NULL;
HHOOK g_hKeyBoardHook = NULL;
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (0 == nCode)
{
//lParam的最高位为1代表按键正在被释放操作,0代表按键正在被按下操作
//代表正在按下Tab键
if ((((lParam >> 31) & 1) == 0) && (wParam == VK_TAB))
::PostMessage(g_hHwndMain, WM_TAB_KEY_PRESS, 0, 0);
}
return CallNextHookEx(g_hKeyBoardHook, nCode, wParam, lParam);
}
在创建登录窗口的函数中,调用HookLoginWindows()函数,钩住键盘消息。回调函数为KeyboardProc。其中g_hHwndMain和g_hKeyBoardHook是全局句柄变量
void CLoginWnd::HookLoginWindows()
{
g_hHwndMain = m_hWnd;
g_hKeyBoardHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, GetCurrentThreadId());
}
接下来只要在登录窗口类中重载HandleMessage方法。处理此自定义消息即可。
LRESULT CLoginWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_TAB_KEY_PRESS:
HandleTableMessage();
break;
default:
break;
}
return __super::HandleMessage(uMsg, wParam, lParam);
}
HandleTableMessage方法中处理的形式就多种多样了。先说下我对table切换帐号密码的处理方式:
定义一个变量记录鼠标点击在了帐号框,还是密码框。如果点击在帐号框,table键切换后,给密码框发送一个鼠标点击消息。
::SendMessage(m_hWnd, WM_LBUTTONDOWN, NULL, MAKELONG(rect.left, rect.top))
rect是控件的坐标。通过GetPos方法获得。反之则给帐号框发送点击消息。这样就实现了tab键切换帐号密码框的功能了。