Help with the WPF TextCompositionManager events

2019-01-24 10:16发布

问题:

The docs on this are pretty shoddy. There are a number of events you can hook into to monitor and take control of text input that are accessed via the TextCompositionManager. If you're wanting to do something like snag card swipe data, this is where you'd do it.

There are three events that concern text input: TextInput, TextStart, and TextUpdate. There are two versions of each event, one where the event is tunneling (traveling down from the Window to the control which has focus) and when it is bubbling (traveling up from the focused UI element to the window):

Tunneling:

  • PreviewTextInputEvent
  • PreviewTextInputStartEvent
  • PreviewTextInputUpdateEvent

Bubbling:

  • TextInputEvent
  • TextInputStartEvent
  • TextInputUpdateEvent

So, depending where in the logical tree you hook into the TextCompositionManager, you can modify these text events before they get to the focus of the event, or just view them afterwards. All this is pretty simple and clear in the docs and in use.


TL;DR

I can't find a decent definition of the three events. An acceptable answer will not only define the three events (TextInput, TextInputStart, and TextInputUpdate), but also will compare and contrast them. No sharing of answers, please reference your sources and Wikipedia is off limits. 25% of your grade depends on this.

回答1:

The differences between them depend on what type of character you're typing.

  • Standard key: printable characters like 'a', 'A', '5', '%', Backspace, and so on.
  • Control key: Ctrl+C, Ctrl+H, Ctrl+M, etc.
  • Decimal key code: things like Alt+numpad 2 5 5 (for IBM extended-ASCII code 255, which is Unicode nonbreaking space U+00A0) and Alt+numpad 0 2 5 5 (for Windows ANSI code 255, which is Unicode U+00FF). Would probably also apply to Alt+numpad plus 2 6 3 B (for U+263B) if you have the Registry setting to enable it; I haven't confirmed this. (I set the Registry setting but it had no immediate effect; probably requires a reboot.)
  • Dead keys: I understand that multilingual keyboards have extra things called "dead keys" that modify the following keystroke. E.g., you might press the "umlaut" dead key, followed by 'o', which would "type" an ö (o with an umlaut). (I may have the details wrong. I've always used an en-US keyboard and I don't know how what it takes to use dead keys.) I suspect these would behave similarly to decimal key codes; see below.
  • IMEs: Ideographic languages use something called an "Input Method Editor". I know even less about these than I do about dead keys, and I have no idea whether they fire these events or not.

Note that modifier keys like Shift and Ctrl do not fire these events directly (unlike KeyDown where you see the Shift being pressed, then the 5 being pressed, etc). For example, Shift+5, to get "%", only generates one sequence of events (i.e., one TextInputStart and one TextInput), with both receiving the string "%".


TextInputStart is fired whenever you begin typing a character or character code. It's fired when you press a standard key, a control key, or the first digit of a decimal key code. When this is fired, the system sometimes, but not always, already knows what key you're pressing (as in the case of standard keys and control keys). If it knows, it will tell you in the TextCompositionEventArgs; if it doesn't know, the TextCompositionEventArgs is empty and tells you nothing at all.

TextInputUpdate is fired when you enter the second and subsequent digits of a decimal key code. I have yet to see anything but an empty TextCompositionEventArgs for this event (though it's possible that that changes with dead keys or IMEs).

TextInput is fired when you're done entering the key, and the system knows for sure what key you entered, so it always has useful information in the TextCompositionEventArgs. This event means the character is actually being "typed" now (i.e. it corresponds to when the character would show up if you were typing into a TextBox).


So here's how the sequences of events work for different types of characters:

Standard key: As soon as you press the key, you get a TextInputStart immediately followed by a TextInput. Both have the same content in their TextCompositionEventArgs: e.Text and e.TextComposition.Text are both set to the key you pressed. (Note that this is not always a printable character. If you press Backspace, it's in e.Text.) If the key is held down, you get the pair of events (TextInputStart/TextInput) for each key-repeat.

Control key: As soon as you press the letter key, you get a TextInputStart immediately followed by a TextInput. Both have the same content in their TextCompositionEventArgs: e.ControlText and e.TextComposition.ControlText are both set to the control key you pressed. If the letter key is held down, you get the pair of events (TextInputStart/TextInput) for each key-repeat.

Decimal key code: Let's say you're typing Alt+numpad 0 2 5 5. As soon as you press numpad 0, you get a TextInputStart event, which tells you absolutely nothing useful. For each of the keystrokes numpad 2, numpad 5, and numpad 5, you get a TextInputUpdate event, again with no useful information (you can't tell what digits have been pressed so far). When you release the Alt key (which actually "types" the key whose code you entered), then you get the TextInput event, with the key you entered in the e.Text and e.TextComposition.Text properties. (This may be a nonprintable character, e.g. if you entered Alt+numpad 0 8.) Key-repeat isn't possible for decimal key codes.

Dead key: As I mentioned above, I don't know how to test this. If anyone has the answer, let me know, and I'll include it here.

IME: Again, I don't know how to test this.


My impression is that, for most uses, TextInput is the only one of these events that it makes sense to use (since the other two don't always tell you anything). That's probably why it's the only one of the three that's re-exposed as a standard routed (non-attached) event on UIElement, UIElement3D, and ContentElement.