IWebBrowser2 Ctrl + C and other shortcuts support

2.3k views Asked by At

It seems I've got not a trivial problem.

I hook my own window into IE main window. My window is derived from WTL's CWindowImpl and hosts IWebBrowers2 control, which shows some content.

IWebBrowser2 shows html with <input type='text'/> editbox where I need a support of all keys, necessary for editing and manipulating with text (Ctrl + C, Ctrl + V, Ctrl + X, etc... + Esc, Delete, arrows up and down).

Also I need to forbid some shortcuts, such as Ctrl + P, Ctrl + S, because they call dialogs specific to webpage that I don't need.


Seems to be common problem and I need to call TranslateAccelerator for my IWebBrowser2 object.

There are some similar questions on the web – Tab key doesn't work in IWebbrowser2

Solution – hot key not work!!

Tab key support in an IWebBrowser2 control

Here is very interesting thread, all I need – Handling Control-C in a hosted web browser control


So, first of all I need to call TranslateAccelerator for my IWebBrowser2 object. But I have to get message from keyboard first.

So, lets see how it looks.

enter image description here

My hooked window doesn't recieve any keyboard input messages. A window with a class "Internet Explorer_Server" recieve all of them (actually, it's a hwnd of IE inside IWebBrowser2).

So I need to hook window proc of this hwnd.

m_ieOldProc = (PROC)::SetWindowLongPtr ( hIEWnd, GWLP_WNDPROC, (LONG_PTR)_IEWndProc );

Inside hooked wnd proc I do the following:

// ...
switch ( uMsg )
{
    case WM_KEYUP: 
    case WM_KEYDOWN: 
    {
        // ...
        IOleInPlaceActiveObject* pAccelerator;
        CComPtr< IWebBrowser2 > pWebBrowser =  CWebWindow::GetWebBrowser( hwnd );
        if( pWebBrowser )
        {               
            hr = pWebBrowser->QueryInterface( IID_IOleInPlaceActiveObject,(void**)&pAccelerator );
            if ( SUCCEEDED(hr) )
            {
                pAccelerator->TranslateAccelerator(&msg);
                pAccelerator->Release();
            }           
        }
        // ...
    }
}
// ...

Yes! Some things got work! Esc, Delete, Up and Down arrows keys work now.

But not all. There are the problem with shortcuts.

  1. Ctrl + C, Ctrl + A don't work.

Ctrl + X, Ctrl + V - do work.

Here is a log of messages in Spy++ for hwnd with a class "Internet Explorer_Server".

On Ctrl + C I don't recieve WM_COMMAND.

enter image description here

On Ctrl + X:

enter image description here

And I don't know why.

2 . "Bad" shortcuts do work. Print dialog is calling on Ctrl + P, webpage save dialog on Ctrl + S, etc. And I can't do anything in this case. Whatever I return in hooked window proc, they are still showing. So I need to handle them before sending to the window.


Solution?

You can mention that in all solutions on this problem there are:

  1. PreTranslateMessage
  2. Actually TranslateAccelerator

Until this moment I have only TranslateAccelerator in hooked message proc.

Pretranslate have to do something like that:

BOOL PreTranslateMessage(MSG* pMsg)
{
    if((pMsg->message < WM_KEYFIRST || pMsg->message > WM_KEYLAST) &&
        (pMsg->message < WM_MOUSEFIRST || pMsg->message > WM_MOUSELAST))
        return FALSE;

    // give HTML page a chance to translate this message
    return (BOOL)SendMessage(WM_FORWARDMSG, 0, (LPARAM)pMsg);
}

Also, in PreTranslateMessage I can filter "bad" shortcuts and don't send them to the window.

Another man suggests to use PretranslateMessage too (dialog from thread above):

– Derive your window from CMessageFilter, install it with CMessageLoop::AddMessageFilter, implement PreTranslateMessage as shown in the example.

– I think I've done now what the sample suggests. But the problem is that my 'parent' window doesn't get the keystrokes - they all go to the IE AX control.

– That's why you need CMessageFilter. It gets hooked into the message pump, before message are dispatched to their destination windows.

Ok, but my Root window, which hosts IWebBrowser2 doesn't receive any keyboard messages. Also I don't have PreTranslateMessage in my window, only window proc call (by parent, CWindowImpl).

As suggested above, I can derive from CMessageFilter, implement PreTranslateMessage, but I can't subscribe on events with CMessageLoop::AddMessageFilter because I don't create main window and don't have access to it's CMessageLoop.


So what I should to do now to make all this work? Should I go with PreTranslateMessage and how?

2

There are 2 answers

3
Eric Brown On

It sounds like you've implemented a toolbar. In this case, you should be implementing IInputObject, and the browser frame will forward calls to you at the appropriate time so that you can translate accelerators (and veto accelerators) appropriately.

0
Czarek Tomczak On

Recently I've been also having a problem with Copy/Cut commands not working. It turned out it wasn't a keyboard problem in TranslateAccelerator or similar. The problem was that the COM library was initialized using CoInitialize/CoInitializeEx. But it is OleInitialize that needs to be called instead for the clipboard to work. An explanation is on the MSDN "WebBrowser Customization" page:

Your application should use OleInitialize rather than CoInitialize to start COM. OleInitialize enables support for the Clipboard, drag-and-drop operations, OLE, and in-place activation. Use OleUninitialize to close the COM library when your application shuts down.

http://msdn.microsoft.com/en-us/library/aa770041(v=vs.85).aspx

If it's still not working, take a look at my implementation (C API) of the IWebBrowser2 control in the PHP Desktop project:

https://code.google.com/p/phpdesktop/source/browse/phpdesktop-msie/msie/