ctrl+c, ctrl+v不起作用的时候, 如果使用的是CHtmlView, 那么是它的一个BUG, 在资源文件中加入以下内容可以解决:/
//
// Accelerator
//
IDC_XTPRO2 ACCELERATORS
BEGIN
“C”, ID_EDIT_COPY, VIRTKEY, CONTROL, NOINVERT
“X”, ID_EDIT_CUT, VIRTKEY, CONTROL, NOINVERT
“V”, ID_EDIT_PASTE, VIRTKEY, CONTROL, NOINVERT
END
加入有C, X, V 开头的三行, 这个比较容易. 今天讨论的主题不是CHtmlView的问题, 而是在标准Winodws API SDK编程下, 如何处理IWebBrowser2中的快捷键问题.
一. TranslateAccelerator为什么得不到调用?
IDocHostUIHandler::TranslateAccelerator Method is Called by MSHTML when IOleInPlaceActiveObject::TranslateAccelerator or IOleControlSite::TranslateAccelerator is called
IOleInPlaceActiveObject::TranslateAccelerator - Processes menu accelerator-key messages from the container’s message queue. This method should only be used for objects created by a DLL object application.
An object created by an EXE object application gets keystrokes from its own message pump, so the container does not get those messages.If you need to implement this method, you can do so by simply wrapping the call to the Window’s TranslateAccelerator function.
IOleControlSite::TranslateAccelerator – Instructs the control site to process the keystroke.This method is called by a control that can be UI-active. In such cases, a control can process all keystrokes first through IOleInPlaceActiveObject::TranslateAccelerator, according to normal OLE Compound Document rules. Inside that method, the control can give the container certain messages to process first by calling IOleControlSite::TranslateAccelerator and using the return value to determine if any processing took place. Otherwise, the control always processes the message first. If the control does not use the keystroke as an accelerator, it passes the keystroke to the container through this method.
以上Y文给我们讲得很明白, 必须要IOleInPlaceActiveObject 或者 IOleControlSite 的 TranslateAccelerator 方法得到调用, IDocHostUIHandler::TranslateAccelerator才会响应, 可见IDocHostUIHandler::TranslateAccelerator并不是主动响应的, 而是你的应用程序框架调用的, 调用的地方在你的消息泵处理时.
二. 如何使TranslateAccelerator得到调用?
在CHtmlView中, 是如下调用TranslateAccelerator的:
BOOL CHtmlView::PreTranslateMessage(MSG* pMsg)
{
// 省略若干处理
//…..
// check if the browser control wants to handle the message
BOOL bRet = FALSE;
if(m_pBrowserApp != NULL)
{
CComQIPtr spInPlace = m_pBrowserApp;
if (spInPlace)
bRet = (spInPlace->TranslateAccelerator(pMsg) == S_OK) ? TRUE : FALSE;
}
return bRet;
}
我的程序中没有这样的函数, 就难以派发消息, IWebBrowser2就不能够响应ctrl+c, ctrl+v, ctrl+x等一切键盘快捷键. 所以, 解决的关键是要实现一个消息派发机制, 参见下面的入口函数:
//MFC的消息入口代码, 仅作参考
BOOL AFXAPI AfxInternalPumpMessage()
{
_AFX_THREAD_STATE *pState = AfxGetThreadState();
if (!::GetMessage(&(pState->m_msgCur), NULL, NULL, NULL))
{
// Note: prevents calling message loop things in ‘ExitInstance’
// will never be decremented
return FALSE;
}
// process this message
if (pState->m_msgCur.message != WM_KICKIDLE && !AfxPreTranslateMessage(&(pState->m_msgCur)))
{
::TranslateMessage(&(pState->m_msgCur));
::DispatchMessage(&(pState->m_msgCur));
}
return TRUE;
}
三. 总结及其它方面
IWebBrowser2中复制的关键:
1. 菜单复制, 需要在构造函数中添加: OleInitialize(NULL);
2. 快捷键复制, 需要处理IOleInPlaceActiveObject接口, 一般在CHtmlView::PreTranslateMessage(MSG* pMsg) 处处理, 如果你用的不是CHtmlView类, 没用MFC/ATL之类的,
那么就需要在消息入口处处理这个事情, 否则WebBrowser按键可能不响应
3. 要合理处理PreTranslateMessage的返回值, FALSE的时候才把消息传递下去.