You forward each key press, key release, and typed character to the View with `View::FireKeyEvent()`. The page receives them as standard `keydown`, `keypress`, `input`, and `keyup` events.

Windows created through AppCore forward keyboard input automatically. See [Mouse and Scroll Input](/docs/2.0/mouse-and-scroll-input).

To decide which key presses go to the page and which stay with the game, see [Keyboard Focus and Editable State](/docs/2.0/keyboard-focus-and-editable-state).

## Choosing an Event Type

Set the `type` field on [`KeyEvent`](/api/cpp/2_0_0/classultralight_1_1_key_event.html) to tell the View which kind of keyboard event occurred.

| Type | When to Send |
| :--- | :--- |
| `KeyEvent::kType_RawKeyDown` | When a key is pressed, and on each auto-repeat while held. |
| `KeyEvent::kType_Char` | When a key press produces text. Send this immediately after the key-down event. |
| `KeyEvent::kType_KeyUp` | When a key is released. Use the same key codes as the key-down event, but set `modifiers` to include only the keys still held (releasing Shift clears the Shift flag). |

## Sending Key Presses

To dispatch a key press, initialize a `KeyEvent` and pass it to `View::FireKeyEvent()` (the C version sits in the tab).

<!-- tabs:start -->
```cpp
///
/// Synthesize a key-down event for the 'Right Arrow' key.
///
KeyEvent evt;
evt.type = KeyEvent::kType_RawKeyDown;
evt.virtual_key_code = KeyCodes::GK_RIGHT;
evt.native_key_code = 0;
evt.modifiers = 0;

///
/// Generate a key identifier string from the virtual key code
/// (needed when synthesizing your own events).
///
GetKeyIdentifierFromVirtualKeyCode(evt.virtual_key_code, evt.key_identifier);

view->FireKeyEvent(evt);
```
```c
///
/// Synthesize a key-down event for the 'Right Arrow' key. The KeyCodes
/// header is C++ only, so pass the key-code value itself (0x27 is GK_RIGHT).
///
ULString no_text = ulCreateString("");
ULKeyEvent evt = ulCreateKeyEvent(kKeyEventType_RawKeyDown, 0, 0x27, 0,
                                  no_text, no_text, false, false, false);

///
/// Fire it (the key identifier is generated from the virtual key code
/// for you), then destroy it.
///
ulViewFireKeyEvent(view, evt);
ulDestroyKeyEvent(evt);
ulDestroyString(no_text);
```
<!-- tabs:end -->

### Virtual Key Codes

Set `virtual_key_code` to a [`KeyCodes`](/api/cpp/2_0_0/namespaceultralight_1_1_key_codes.html) constant matching the pressed key. These values match Windows virtual-key codes— on other platforms or in game engines, map native key codes to these values with a lookup table.

### Key Identifiers

Call `GetKeyIdentifierFromVirtualKeyCode()` to generate `key_identifier` from the virtual key code on every key-down and key-up event.

> 🚧 Required for Form Controls
>
> Form controls depend on the key identifier to navigate and select options. Without it, arrow keys cannot change `<select>` elements or radio groups, and Space cannot toggle checkboxes.

### Modifier Keys

Set `modifiers` by combining the bit flags for all modifier keys currently held. The available flags are `KeyEvent::kMod_ShiftKey`, `kMod_CtrlKey`, `kMod_AltKey`, and `kMod_MetaKey` (Command on macOS, or the Windows key on Windows).

Physical modifier keys also require their own key-down and key-up events when pressed and released.

> 🚧 Key Events Update Mouse and Scroll Modifiers
>
> Mouse and scroll events have no `modifiers` field— they take their modifier state from the last `KeyEvent` fired on the View. Set `modifiers` on every `KeyEvent` you create (character events included), or a Shift-click reaches the page as a plain click. Calling `View::Unfocus()` clears this stored state (a modifier released while another window has focus sends the View no key-up event).

## Sending Typed Text

To insert text into a focused input field, send a `KeyEvent` with type `KeyEvent::kType_Char`.

```cpp
///
/// Synthesize the text generated by pressing Shift+A.
///
KeyEvent evt;
evt.type = KeyEvent::kType_Char;
evt.text = "A";
evt.unmodified_text = "A"; // If not available, set to same as evt.text.
evt.modifiers = KeyEvent::kMod_ShiftKey; // Shift is still held.

view->FireKeyEvent(evt);
```

Set `text` to the generated character. Set `unmodified_text` to the text generated before modifiers other than Shift were applied, or assign the same value as `text` if that value is unavailable.

Raw key-down and key-up events do not insert text into input fields.

For complex script input such as Chinese, Japanese, or Korean, use composition calls instead of character events. See [Input Method Editors](/docs/2.0/input-method-editors).

### Enter and Tab

For the Enter key, send a raw key-down event with `KeyCodes::GK_RETURN`, followed by a character event with `text` set to `"\r"`. A character event containing `"\n"` does not insert a line break or submit a form.

For the Tab key, send key-down and key-up events with `KeyCodes::GK_TAB` to move focus to the next field. A character event containing `"\t"` does nothing.

## Built-in Editing Shortcuts

The View runs standard editing shortcuts automatically when it receives a key-down event with the matching modifier keys.
| Keys | Action |
| :--- | :--- |
| `Ctrl+C`, `Ctrl+X`, `Ctrl+V` | Copy, cut, and paste selected text. |
| `Ctrl+A` | Select all text in the focused element. |
| `Ctrl+Z`, `Ctrl+Shift+Z` | Undo and redo recent edits. |
| Arrow keys, `Home`, `End`, `Page Up`, `Page Down` | Move the caret. Hold Shift to extend the selection. Hold Ctrl with Left or Right to move by word, or with Home or End to jump to the start or end of the document. |
| `Backspace`, `Delete` | Delete the character before or after the caret. Hold Ctrl to delete an entire word. |

On macOS, Command (`KeyEvent::kMod_MetaKey`) takes the place of Ctrl for these shortcuts— Ctrl+C on macOS does not copy.

To trigger these editing commands from application menus or buttons, see [Text Editing and the Clipboard](/docs/2.0/text-editing-and-clipboard).
