tags:

views:

381

answers:

5

I have a MSHTML-based control embedded in an application and the ContentEditable mode is used to edit documents inside it. The body of the HTML document initially contains the following lines:

<div></div>
<div id="signature"></div>

The caret is placed at the beginning of the document, that is inside the first DIV element. Now when user clicks with mouse inside the control in a place below the last line, the caret is moved into the second DIV element, as it's the closest one to the point where the user clicked.

I want to move the pointer to the end of the first DIV on the mouse click. Now I have the code to calculate the intended position of the caret as IMarkupPointer and IDisplayPointer. What I need to know is where to intercept the MSHTML event pipeline to do the actual caret move.

I've written code that implements IHTMLEditDesigner and moves the caret using IHTMLCaret.MoveCaretToPointer to the intended position. The problem is that no matter where I intercept the event (PreHandleEvent, PostHandleEvent or PostEditorEventNotify) the caret position is eventually reverted to the default one on single click (but it is not reverted if I hold the left mouse button pressed for a while or if I click with right mouse button).

+1  A: 

Maybe there are separate events for mouseDown mouseUp and mouseClick.

You intercept mouseClick but default behavior gets executed on mouseUp.

Kamil Szot
You are right that there are three events (down, up, click), but I tried intercepting each/all of them and it didn't help.
Filip Navara
+2  A: 

Use jscript inside of the HTML that you load into the IE control. If you do not know HTML and jscript very well you will find this task very painful.

See these questions for my experience when I tried do so something like this.

I also had lots of other problem, including have to write resize logic in jscript to get the HTML editor to size along with the WinForm form and having to pass the default form/coontrol colours into the HTML editor so that it looked write then users changed colour schemes on Windows.

Even better just find a HTML editor and load it into the IE control, you will still have to code with standard window colours etc yourself.

There are also 3rd party winforms HTML editors you can use. If possible I think you should buy in a solution as ContentEditable is a lot harder in real life then it look.

A quick google found.

Ian Ringrose
Thanks for many useful hints, but none of them really answer my specific question. I can't use JScript, but I can hook all the DOM events from C#, so I can do practically the same things too, if I only knew what events to hook to. I've worked with the first two editors you mentioned (Writer and NetRix) and both are buggy and don't have the specific functionality I am looking for (moving a cursor out of the signature DIV when clicking into the control).
Filip Navara
You can add jscript callbacks using some of the APIs on the MSHTML control by editing the DOM after the control has been created. Be careful as the control creates the DOM on a background thread and you have to wait until it has fired the "loaded" event.
Ian Ringrose
I am marking this as accepted answer, since your responses really helped me. I have isolated the problem now and I will post more about the solution later. You deserve the bounty points.
Filip Navara
+1  A: 

Have you tried using a winforms timer with a timeout of 0?

  • When you get the mouse down event start the timer.
  • Then the MSHTML control will process the event
  • You will then go back to the windows message loop
  • All other messages in the message queue will then be process before the timer
  • Hopefully by now MSHTML has set the default caret position on single click
  • You can then move the caret position yourself when the timer fires

Have a look with Spy++ to see what events are being sent between the diffent windows in the MSHTML control to get other ideals. The MSHTML control is like no other winforms control and you have to go back to all the trick you used in the days of C and Win32 programming.

Ian Ringrose
This may work, I will try it tonight.
Filip Navara
+1 for the ideas, but it didn't work. Even with the timer the caret position is restored in next few milliseconds (about at the time the caret is supposed to blink). The only window message appearing between the move of caret from my explicitly set position to the wrong one is WM_NCHITTEST.
Filip Navara
+1  A: 

Have you tied setting the "focus" to the first div by finding the dom item for it, and calling the setFocus (or whatever it is called) dom method? The caret should move to where the fosus is.

(There are interfaces that MSHTML expose to find dom items and call methods on them. Sorry I don't recall the details of how to do this)

Ian Ringrose
Will try. I have all the interfaces defined and this looks like a very sane suggestion.
Filip Navara
A: 

I believe you need to change the SelectStart property and leave the SelectionLength = 0. That will move the caret to a new position.

uosɐſ