#636 – Keyboard Events that Fire When A Key Is Held Down

When you hold a key down in Windows, the key begins to repeat after a short delay, as if you you were repeatedly pressing it.

While a key is held down, the PreviewKeyDown, KeyDown and PreviewTextInput events will fire repeatedly.

You can detect whether a keypress is the original/first keypress, or one of the repeats, by checking the KeyEventArgs.IsRepeat property.

Let’s say we press the ‘a’ key while a TextBox has focus and hold it down long enough for three ‘a’ characters to be inserted.  We’ll get the following events:

  • PreviewKeyDown, Key = A, IsRepeat = False
  • KeyDown, Key = A, IsRepeat = False
  • PreviewTextInput, Text = a
  • (TextBox contains “a”)
  • PreviewKeyDown, Key = A, IsRepeat = True
  • KeyDown, Key = A, IsRepeat = True
  • PreviewTextInput, Text = a
  • (TextBox contains “aa”)
  • PreviewKeyDown, Key = A, IsRepeat = True
  • KeyDown, Key = A, IsRepeat = True
  • PreviewTextInput, Text = a
  • (TextBox  contains “aaa”)
  • PreviewKeyUp, Key = A, IsRepeat = False
  • KeyUp, Key = A, IsRepeat = False
Advertisement

#631 – Event Sequence for KeyPressUp, KeyPressDown and TextInput

The full event sequence for keyboard related events is shown below, as they propagate down (tunneling) or up (bubbling) the logical tree.

If we have a Window that contains a StackPanel, which in turn contains a TextBox, the sequence of events would be:

  • Window_PreviewKeyDown
  • StackPanel_PreviewKeyDown
  • TextBox_PreviewKeyDown
  • TextBox_KeyDown
  • StackPanel_KeyDown
  • Window_KeyDown
  • Window_PreviewTextInput
  • StackPanel_PreviewTextInput
  • TextBox_PreviewTextInput
  • TextBox_TextInput – suppressed/handled
  • StackPanel_TextInput – suppressed/handled
  • Window_TextInput – suppressed/handled
  • Window_PreviewKeyUp
  • StackPanel_PreviewKeyUp
  • TextBox_PreviewKeyUp
  • TextBox_KeyUp
  • StackPanel_KeyUp
  • Window_KeyUp

Note that the TextInput event is listed, since TextInput events would normally fire for the originating control and then propagate up the logical tree.  But in the case of TextBox, the TextInput event is marked as handled and therefore does not fire.

#629 – Some Controls May Swallow Keypress Events

If you are handling KeyUp and/or KeyDown events for a control, you’ll notice that certain keys may be “swallowed” by a particular control.  In other words, you might not get all of the keypress events.

A control may intercept a particular event and mark it as handled if it interprets the keypress and uses it within the control.

For example, a TextBox control will “swallow” the KeyDown event for the Backspace key, since this key is used to delete characters in the control.

In the example below, I press the ‘a’ key and see all four (PreviewKeyDown, KeyDown, PreviewKeyUp, KeyUp) keypress events.  However, when I press Backspace, I see only three events–the TextBox intercepts the KeyDown event, erases a character, and marks the event as handled.

 

#628 – Key Up/Down Sequence When Using ALT Key

When you use the Alt-key in combination with another key, the control that has focus will receive KeyUp and KeyDown events for both the Alt key and the combination key.

When using the Alt key, the Key property of the KeyEventArgs object will be Key.System and the actual key being pressed will be available in the SystemKey property.  This is true for both the Alt key and the combination key.

For example, pressing Alt-Q while a TextBox control has focus will result in the following events for the TextBox, in the sequence listed.

  • PreviewKeyDown, Key = System, SystemKey = LeftAlt
  • KeyDown, Key = System, SystemKey = LeftAlt
  • PreviewKeyDown, Key = System, SystemKey = Q
  • KeyDown, Key = System, SystemKey = Q
  • PreviewKeyUp, Key = System, SystemKey = Q
  • KeyUp, Key = System, SystemKey = Q
  • PreviewKeyUp, Key = System, SystemKey = LeftAlt
  • KeyUp, Key = System, SystemKey = LeftAlt

#627 – Detecting Whether The Ctrl Key Is Pressed In a KeyDown Event Handler

When you press a Ctrl-key combination (e.g. Ctrl+G) and you are monitoring KeyDown (or KeyUp) events, you’ll see two separate KeyDown events–one for the Ctrl key and one for the key pressed with it.

If you want to respond to a Ctrl-key combination within a KeyDown event handler, you can do the following :

  • Use the KeyEventArgs.Key property to see whether the event is being fired because the combination key (e.g. ‘G’) is being pressed
  • Use the Keyboard.IsKeyDown method to check whether the Ctrl key is also currently down
        private void TextBox_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.Key == Key.G) &&
                (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
                MessageBox.Show("You pressed Ctrl+G !");
        }

#626 – Key Up/Down Sequence When Using CTRL Key

When you use the Ctrl-key in combination with another key, e.g. pressing Ctrl-G, the control that has focus will receive KeyUp and KeyDown events for both the Ctrl key and the main key that you are pressing.

For example, if a TextBox control has focus and I press Ctrl-G (which doesn’t normally do anything in a TextBox) and I use the Ctrl key on the left side of the keyboard, I’ll see the following events for the TextBox, in the sequence listed.

  • PreviewKeyDown, key = LeftCtrl
  • KeyDown, key = LeftCtrl
  • PreviewKeyDown, key = G
  • KeyDown, key = G
  • PreviewKeyUp, key = G
  • KeyUp, key = G
  • PreviewKeyUp, key = LeftCtrl
  • KeyUp, key = LeftCtrl

In this case, you can see that my sequence in pressing/releasing the keys was:

  • Press and hold left Ctrl key
  • Press G key
  • Release G key
  • Release Ctrl key

#624 – Information Available to Key Up/Down Events

All four of the keypress-related events (PreviewKeyDown, KeyDown, PreviewKeyUp, and KeyUp) send an instance of the KeyEventArgs object to the associated event handler.

private void TextBox_KeyDown(object sender, KeyEventArgs e)
{
}

Here are some of the more important properties available in the KeyEventArgs object:

  • Key property – The System.Windows.Input.Key being pressed.  E.g. Key.Q
  • Timestamp – Time of key press, in # ticks (milliseconds) since last reboot
  • IsDown / IsUp – Is the key currently down or up?
  • IsRepeat – Is this keystroke a repeat due to holding a key down?
  • IsToggled – For keys that toggle, like Caps Lock, indicates current toggled state
  • Source – The control that had focus when the key was pressed
  • OriginalSource – Either the control where the key was pressed, or a lower-level child element
  • Handled – Can set to true to indicate that you’ve handled the event, short-circuiting the event routing (generally)

#620 – Why Are There So Many KeyPress Events?

When you press a single key within a WPF application, there are potentially a number of different keypress events that can fire.  But why are there so many different events that can possibly fire?

There are several reasons why there isn’t just a single keypress event.

  • Your application will only see the events for which you define a handler.  There is a large set of possible events so that you can choose which ones make sense for your application to handle.
  • Preview events exist so that a parent control can intercept keypress events for its children or descendants.  The tunneling allows you to decide at what level you want to preview the event.
  • The actual keypress event bubbles up the logical tree so that you can decide at what level to actually respond to the event.  In this way, you can handle multiple events in a single place.

#619 – Event Sequence for the Key Up/Down Events

There are four basic events related to a key being pressed or released that a GUI element can fire in WPF.  An event fires when you press a key down (KeyDown) and a different event fires when you release the key (KeyUp).  When these events fire for an element, they fire first for the element and then work back up the logical tree, firing for each ancestor element.  These are bubbling events.

There are also the PreviewKeyDown and PreviewKeyUp events, which fire before the KeyDown and KeyUp events, but fire from the top of the logical tree down to the control where the event originated.  (Tunneling events).

For a Window containing a StackPanel that contains a TextBox, the event sequence when a user presses a key while the TextBox has focus is:

  • Window_PreviewKeyDown
  • StackPanel_PreviewKeyDown
  • TextBox_PreviewKeyDown
  • TextBox_KeyDown
  • StackPanel_KeyDown
  • Window_KeyDown
  • Window_PreviewKeyUp
  • StackPanel_PreviewKeyUp
  • TextBox_PreviewKeyUp
  • TextBox_KeyUp
  • StackPanel_KeyUp
  • Window_KeyUp

 

#588 – If You Handle PreviewKeyDown Event, KeyDown Won’t Fire

The PreviewKeyDown and KeyDown events in WPF are paired routed events.  When a user presses a key in a control, the PreviewKeyDown event fires first, as a tunneling event.  When the event has propagated down the logical tree to the control where the key press originated, the KeyDown event fires.  KeyDown propagates up the logical tree, since it is defined as a bubbling event.

If you handle the PreviewKeyDown event as it is propagating down the tree and you mark the event as handled (setting KeyEventArgs.Handled to true), the PreviewKeyDown event will not continue propagating down the tree.

But if you mark PreviewKeyDown as handled, the corresponding KeyDown event will not fire at all.  This works because the two events share the same instance of a KeyEventArgs object, so when PreviewKeyDown marks the event as handled, KeyDown also treats the event as handled.