/*此文是我将网上的一些文章,自已遇到的问题进行整理,有些是翻译,所有只供学习讨论,如有版权还属于原作者——作者:黄森堂*/
#24 如何在控件中控制键盘?
用ATL开发控件经常需要在一个活动的Form(VB的表单)中处理键盘,如果ActiveX控件容器中包含了其它子窗口或窗口控制需要对键盘进行控制的话,那么你需要在控件中实现几个方法,具有UI界面的控件总是会调用IOleInPlaceActiveObject::TranslateAccelerator() 与IOleControl::GetControlInfo(),你可能需要覆盖IOleControl::OnMnemonics()与正确处理Windows的键盘消息,而不管是个容器还是在用户模式。
下面演示在ATL开发Active X控件中在子窗口中处理键盘消息。
1.UI激活:当控件初激活时才能收到键盘消息,以下代码演示如何在ATL控件中处理WM_MOUSEACTIVEATE消息来激活UI,它使用了IsUserMode()方法中使用CComControlBase::InPlaceActivate(OLEIVERB_UIACTIVATE)来完成UI激活,这后控件就可以接收键盘消息了。
LRESULT OnMouseActivate(UINT uMsg,
WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if(IsUserMode())
{
InPlaceActivate(OLEIVERB_UIACTIVATE);
}
return 0;
}
2.设置子窗口焦点:
LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&
bHandled)
{
CComControl<CJazzControl>::OnSetFocus (uMsg,
wParam, lParam, bHandled);
if (IsUserMode())
{
InPlaceActivate (OLEIVERB_UIACTIVATE);
m_ChildControl.SetFocus();
}
return 0;
}
3.实现IOleInPlaceActiveObject::TranslateAccelerator().ATL提供了IOleInPlaceActiveObject接口的包装类IOleInPlaceActiveObjectImpl,ATL 2.1默认实现IOleInPlaceActiveObjectImpl::TranslateAccelerator()返回E_NOTIMPL,你需要覆盖它:
STDMETHOD(TranslateAccelerator)(MSG *pMsg)
{
if (
((pMsg->message >= WM_KEYFIRST) &&
(pMsg->message <= WM_KEYLAST))
&&
((pMsg->wParam == VK_TAB) ||
(pMsg->wParam == VK_RETURN))
)
{
CComQIPtr<IOleControlSite,&IID_IOleControlSite>
spCtrlSite(m_spClientSite);
if(spCtrlSite)
{
return spCtrlSite->TranslateAccelerator(pMsg, 0);
}
}
return S_FALSE;
}
上述的代码是在子窗口的编辑框中处理TAB与ENTER键,如果你需要处理UP ARROW, DOWN ARROW, PAGE UP, and PAGE DOWN,可如下示例:
if((pMsg->wParam == VK_UP) ||
(pMsg->wParam == VK_DOWN)||
(pMsg->wParam == VK_LEFT) ||
(pMsg->wParam == VK_RIGHT))
{
::IsDialogMessage(m_hWnd, pMsg);
return S_OK;
}
如果Active X控件有滚动条,你需要处理VK_UP与VK_DOWN,如下示例:
if (pMsg->wParam == VK_UP)
{
::SendMessage(m_hWnd,WM_VSCROLL,
SB_LINEUP,MAKELONG(0,m_hWnd));
return S_FALSE;
}
默认按钮的处理:当用户按下ENTER,你应该允许焦点转移到默认的按钮上(如果一个按钮设置为“默认”),那么你需要实现IOleControl::GetControlInfo()来接受ENTER与ESC键,ATL默认实现IOleControlImpl::GetControlInfo() 返回E_NOTIMPL,你需要覆盖它:
HRESULT STDMETHODCALLTYPE GetControlInfo(CONTROLINFO *pCI)
{
if(!pCI)
{
return E_POINTER;
}
pCI->hAccel = NULL; //load your accelerators here, if any
pCI->cAccel = 0;
pCI->dwFlags = 0;
return S_OK;
}