Manipulating the caret (text cursor) using the Win32 API
published 19 jun 2011
I recently dealt with a case where I wanted to automatically format user’s text as they type it. For example, if the user is typing a phone number, they might type “9595551234”, and as they type, their text would be formatted as such (system-inserted characters emphasized):
This kind of user interface, when done very carefully 1, can make data entry faster and ensure better-formatted results.
Unfortunately using the
WM_SETTEXT message to set the text of the control
causes the text caret (aka cursor, aka text insertion point) to revert to the beginning of the text. We want to
make sure that the user’s cursor ends up where it belongs, so that they can continue to type.
Initial research led me to believe that
setcursorpos and its counterpart
getcursorpos would do what I wanted,
but after some frustrating trials, I found that while
getcursorpos would return something vaguely plausible,
setcursorpos did nothing at all. I suspect that in fact these functions only work if you are manually managing
cursors you create yourself using
createcursor, but I’m not sure.
If there is no selection, the starting and ending values are both the position of the caret.
I made a trimmed down sample app for this post. Let’s say I’ve got users who love typing “hahahaha” ad infinitum; By inserting the “a” for them, they could type that string simply by holding down the “h” key, which cuts their keystrokes by 50%! The code is as follows:
Inside your handler for the text change notification (see full solution for more context):
The key logic here (and this is probably not really sophisticated enough, to be honest—consider a user trying to delete a trailing “a”)
is that we check if they initially had nothing selected (
firstChar == lastChar), and if their cursor was at the end of the string
firstChar == len.) In this case, we want to move the cursor forward by one character to account for the character we just added.
It took me a while to figure this out, and for whatever reason, the documentation is poor, and there’s a lot of misleading information around the web, so I hope this helps someone!
do a great deal of testing before you consider this feature ready for prime time. Some questions to ask:
- What happens if the user enters their own punctuation instead of accepting mine? Are users allowed to override default formatting rules?
- Am I assuming a certain length of string? What happens if the user enters a different length?
- What happens if the user goes back and edits their text somewhere in the middle?
- What happens if the user deletes their text, or a range of text?
Manipulating the user’s text as they enter it is fraught with peril. Be prepared to ↩