ATL问题集-#24 如何在控件中控制键盘?

类别:VC语言 点击:0 评论:0 推荐:

/*此文是我将网上的一些文章,自已遇到的问题进行整理,有些是翻译,所有只供学习讨论,如有版权还属于原作者——作者:黄森堂*/

#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;
}

本文地址:http://com.8s8s.com/it/it3496.htm