views:

1444

answers:

3

I'm running into a very peculiar issue. I noticed that occasionally while typing into my TextBox, I'll lose some keystrokes. I added a bunch of trace statements in events hooked by this TextBox, and I found that when I lost keystrokes, the KeyUp, KeyDown, and KeyPress events all correctly fired, but the TextChanged event never fired.

Does anybody have any idea why this would happen? I could write this off as a ".NET bug", but I'd rather figure out if there is a solution here.

In case there is a suggestion that I use the KeyUp/KeyDown events to determine if the text has changed, there is an issue there as well. KeyUp/KeyDown are called multiple times for each key press, so it would be very difficult to determine if someone was typing the same letter multiple times.

+1  A: 

I don't actually know, but I have a random guess: You running in a VM?

One hack you could use is make a timer that reads the text and compares to the previously entered value. Call the event handler code when it isn't equal to the previously checked value. When you need to use the final entered value, do one additional check, in case the timer hasn't fired yet.

Merlyn Morgan-Graham
Nope, not running in a VM. I'll think about that timer idea -- good suggestion.
dreadpirateryan
A: 

Do you mean the keypress is actually lost and never shows up in the box? Or do you mean you don't get a TextChanged event for every keypress?

I believe the TextChanged event is driven by the operating system's EN_CHANGE notification which is sent via a WM_COMMAND message. I know that certain kinds of messages in Windows are "coalesced" to avoid redundant notifications. For example this can happen with WM_MOUSEMOVE messages and is why you don't receive a mouse move event for every pixel that the mouse moves across the screen.

I can't say for sure but I suspect that the TextChanged event behaves this way as well. I can say though that alternate input methods have this side effect too. When using a Tablet PC input panel, the textbox will not get a TextChanged notification for every character.

Josh Einstein
The key is actually lost and never shows up in the box -- and when that happens, I noticed that the TextChanged event doesn't fire as well.Thanks for the info on the Windows messages. Maybe I can manually fire that event during the KeyUp/KeyDown events?
dreadpirateryan
It seems like something is eating the message. Maybe there is a system-wide message hook installed somewhere that is acting up? Or dare I say, maybe some kind of keylogger? You should try running Spy++ if you have it installed and see if the message gets to the window.
Josh Einstein
There is indeed a keyboard hook in the program -- an important piece of info I should have included. The hook is created using the following code:SetWindowsHookEx(WH_KEYBOARD, KeyFunction, dllInstance, AppDomain.GetCurrentThreadId());The KeyFunction method checks for certain keystrokes, calls other functions depending on what those keystrokes are, and then calls the CallNextHookEx function.My trace statements tell me that in the cases where I'm losing keystrokes, the hook does indeed see the key, and CallNextHookEx function is getting called properly.
dreadpirateryan
Can you confirm that without the hook the keystrokes are not lost? Perhaps you could post a snippet of the code around the hook proc.
Josh Einstein
+2  A: 

Hmmm....

This is going to be a shot, but, you did say you have the KeyUp, KeyDown and KeyPress event handlers right? Have you set the flag e.Handled to true in the event handlers, have a look here:

        private void textBox1_KeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void textBox1_KeyUp(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            e.Handled = true;
        }

Have a look here in the MSDN about this Handled property. (If you have MSDN 2008 SP 1 installed locally, the link is ms-help://MS.MSDNQTR.v90.en/fxref_system.windows.forms/html/dfc80b44-1d79-6315-cbea-1388a048c018.htm)

To quote:

Handled is implemented differently by different controls within Windows Forms. 
For controls like TextBox which subclass native Win32 controls, it is 
interpreted to mean that the key message should not be passed to the underlying 
native control. 

If you set Handled to true on a TextBox, that control will not pass the key 
press events to the underlying Win32 text box control, but it will still 
display the characters that the user typed. 

Maybe it is not set i.e. e.Handled = false; thereby preventing the TextChanged Event from firing?

Can you check and confirm this?

Edit: After dreadprivateryan's response, I can suspect (due to lack of code posted), based on his response, e.Handled is true for when Enter key is pressed and false for everything else which in my mind, thinks that is the reason why no further keystrokes are being accepted as a result of this.

  • Are you trying to set focus to another control upon the Enter key being pressed? It could be that both KeyUp and KeyDown are conflicting...
  • Remove the keyboard hook and disable it...
  • My suggestion is to change the code completely in this manner as shown, take out either KeyDown or KeyUp Event Handler as they, simplistically put it, are the same, ok, technically, it is designated respectively for when a key is pressed down, and likewise when a key is released. Have a look at this link here. There was a similar question posted here on SO.

In the example below, I used the keyUp event handler to switch focus to the next available control upon enter key being pressed. In the KeyPress event handler, this simply filters the input and only allows numbers 0-9 respectively, anything else gets discarded. Included in that event handler, is the allowance for the backspace key to provide editing.

        private void textBox1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter) SendKeys.Send("{TAB}");
        }
        private const string VALID_KEYS = "0123456789";
        private void textBox1_KeyPress(object sender, KeyPressEventArgs e) 
        {                  
            if (VALID_KEYS.IndexOf(char.ToUpper(e.KeyChar)) != -1 || e.KeyChar == (char)8) 
                 e.Handled = false;                                                               
            else                                                                                 
                 e.Handled = true;                                                                
}                                                                                        

Hope this helps, Best regards, Tom.

tommieb75
Thanks for the suggestion. I am only setting e.Handled=true in the case that the keystroke is an enter key, and otherwise I'm not setting handled at all. Unfortunately I don't think this is related to my issue -- I'm losing keystrokes whether or not I press Enter.
dreadpirateryan