views:

332

answers:

2

I find this situation comes up from time to time, and I never seem to have a really robust generic solution to it.

I have a control - in this example an EDIT control on a dialog. I want to take certain actions in response to the user - and only the user - modifying the contents of the edit control.

The edit control can be set programmatically - e.g. when the dialog is being setup, there may be an initial value placed into the edit field. Or when the user selects an item from a listview, that selection's text may well be what's placed into the edit field.

But when the user modifies the contents of the edit field, I need to know that, and respond (in this scenario, I want to clear the selection from the corresponding listview).

I am currently looking at what control has focus, and only considering EN_CHANGE's to be "from the user" if the edit control has focus.

This works beautifully under Windows 7. This fails under XP (I haven't tested Vista yet).

In XP, if the edit field has the focus, but the user clicks on the list view, and the list view tells the edit control to set its contents, then I get a notification from the edit control which claims to still have focus (::GetFocus() == HWND of edit control). But this incorrect state doesn't occur in Win7.

This is a layered interface, so I cannot modify the list-view notification handler. It gets a selection change, and updates the edit field without my involvement or ability to really intervene other than to get notifications from both of them.

Any thoughts on how to generically, permanently solve the "Is this control notification really from the user" conundrum?

+1  A: 

You can always track LVM_ITEMCHANGING, LVM_ITEMCHANGED, and EN_MSGFILTER messages. If the edit box is modified between LVM_ITEMCHANGING and LVM_ITEMCHANGED without an EN_MSGFILTER in between then you can probably assume the user did not modify the item. Or just check to see if there are any items selected when EN_CHANGE fires and if not or the text doesn't match the selected item, assume it is a user edit.

Or use ES_MULTILINE (from EN_CHANGE documentation):

The EN_CHANGE notification is not sent when the ES_MULTILINE style is used and the text is sent through WM_SETTEXT.

MSN
+1  A: 

I'd suggest using the right message. EN_CHANGE is too generic, you want to know if the user typed or pasted text. So why not subclass the control and watch for WM_KEYPRESS messages?

Alternatively, you can set a flag in your other code that sets the edit control content. You might be able to assume that anything that makes your wndproc re-entrant represents a programmatic change.

You aren't looking for something actually secure, are you? If you just want to exclude set content calls that's fairly straightforward. If you want to differentiate between user action and programmatic simulation of user keypresses, that's a much harder problem.

Ben Voigt
Nothing especial secure or foolproof. I just need to detect whether the ListView is sending the text, or the user has typed (or pasted) something into the edit control. The reality is that this is in the File Dialog, and the control is really a COMBOBOX32EX which contains a COMBOBOX which contains an EDIT control, which I have tried forwarding the messages out from the inside using wndproc hooking (subclassing), but due to the out of order issue (ComboBox is given a WM_SETTEXT while it still believes it has focus), I don't know how to adequately filter for this.
Mordachai
What's the call stack look like when the ListView is changing the text? This should be pretty easy to solve if calls to your WndProc are being nested (e.g. you handle ListView notifications by calling SendMessage), if the changes are using the message queue (e.g. you handle ListView notifications by calling PostMessage) then things will be tougher.
Ben Voigt