/** * @file encoder.h * * Key event encoding to terminal escape sequences. */ #ifndef GHOSTTY_VT_KEY_ENCODER_H#define GHOSTTY_VT_KEY_ENCODER_H #include <stddef.h>#include <stdint.h>#include <ghostty/vt/types.h>#include <ghostty/vt/allocator.h>#include <ghostty/vt/terminal.h>#include <ghostty/vt/key/event.h> /** * Opaque handle to a key encoder instance. * * This handle represents a key encoder that converts key events into terminal * escape sequences. * * @ingroup key */typedef struct GhosttyKeyEncoderImpl *GhosttyKeyEncoder; /** * Kitty keyboard protocol flags. * * Bitflags representing the various modes of the Kitty keyboard protocol. * These can be combined using bitwise OR operations. Valid values all * start with `GHOSTTY_KITTY_KEY_`. * * @ingroup key */typedef uint8_t GhosttyKittyKeyFlags; /** Kitty keyboard protocol disabled (all flags off) */#define GHOSTTY_KITTY_KEY_DISABLED 0 /** Disambiguate escape codes */#define GHOSTTY_KITTY_KEY_DISAMBIGUATE (1 << 0) /** Report key press and release events */#define GHOSTTY_KITTY_KEY_REPORT_EVENTS (1 << 1) /** Report alternate key codes */#define GHOSTTY_KITTY_KEY_REPORT_ALTERNATES (1 << 2) /** Report all key events including those normally handled by the terminal */#define GHOSTTY_KITTY_KEY_REPORT_ALL (1 << 3) /** Report associated text with key events */#define GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED (1 << 4) /** All Kitty keyboard protocol flags enabled */#define GHOSTTY_KITTY_KEY_ALL (GHOSTTY_KITTY_KEY_DISAMBIGUATE | GHOSTTY_KITTY_KEY_REPORT_EVENTS | GHOSTTY_KITTY_KEY_REPORT_ALTERNATES | GHOSTTY_KITTY_KEY_REPORT_ALL | GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED) /** * macOS option key behavior. * * Determines whether the "option" key on macOS is treated as "alt" or not. * See the Ghostty `macos-option-as-alt` configuration option for more details. * * @ingroup key */typedef enum GHOSTTY_ENUM_TYPED { /** Option key is not treated as alt */ GHOSTTY_OPTION_AS_ALT_FALSE = 0, /** Option key is treated as alt */ GHOSTTY_OPTION_AS_ALT_TRUE = 1, /** Only left option key is treated as alt */ GHOSTTY_OPTION_AS_ALT_LEFT = 2, /** Only right option key is treated as alt */ GHOSTTY_OPTION_AS_ALT_RIGHT = 3, GHOSTTY_OPTION_AS_ALT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,} GhosttyOptionAsAlt; /** * Key encoder option identifiers. * * These values are used with ghostty_key_encoder_setopt() to configure * the behavior of the key encoder. * * @ingroup key */typedef enum GHOSTTY_ENUM_TYPED { /** Terminal DEC mode 1: cursor key application mode (value: bool) */ GHOSTTY_KEY_ENCODER_OPT_CURSOR_KEY_APPLICATION = 0, /** Terminal DEC mode 66: keypad key application mode (value: bool) */ GHOSTTY_KEY_ENCODER_OPT_KEYPAD_KEY_APPLICATION = 1, /** Terminal DEC mode 1035: ignore keypad with numlock (value: bool) */ GHOSTTY_KEY_ENCODER_OPT_IGNORE_KEYPAD_WITH_NUMLOCK = 2, /** Terminal DEC mode 1036: alt sends escape prefix (value: bool) */ GHOSTTY_KEY_ENCODER_OPT_ALT_ESC_PREFIX = 3, /** xterm modifyOtherKeys mode 2 (value: bool) */ GHOSTTY_KEY_ENCODER_OPT_MODIFY_OTHER_KEYS_STATE_2 = 4, /** Kitty keyboard protocol flags (value: GhosttyKittyKeyFlags bitmask) */ GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS = 5, /** macOS option-as-alt setting (value: GhosttyOptionAsAlt) */ GHOSTTY_KEY_ENCODER_OPT_MACOS_OPTION_AS_ALT = 6, /** Backarrow key mode (value: bool) * See https://vt100.net/dec/ek-vt3xx-tp-002.pdf page 170 * If `false` (the default), `backspace` emits 0x7f * If `true`, `backspace` emits 0x08 */ GHOSTTY_KEY_ENCODER_OPT_BACKARROW_KEY_MODE = 7, GHOSTTY_KEY_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,} GhosttyKeyEncoderOption; /** * Create a new key encoder instance. * * Creates a new key encoder with default options. The encoder can be configured * using ghostty_key_encoder_setopt() and must be freed using * ghostty_key_encoder_free() when no longer needed. * * @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator * @param encoder Pointer to store the created encoder handle * @return GHOSTTY_SUCCESS on success, or an error code on failure * * @ingroup key */GHOSTTY_API GhosttyResult ghostty_key_encoder_new(const GhosttyAllocator *allocator, GhosttyKeyEncoder *encoder); /** * Free a key encoder instance. * * Releases all resources associated with the key encoder. After this call, * the encoder handle becomes invalid and must not be used. * * @param encoder The encoder handle to free (may be NULL) * * @ingroup key */GHOSTTY_API void ghostty_key_encoder_free(GhosttyKeyEncoder encoder); /** * Set an option on the key encoder. * * Configures the behavior of the key encoder. Options control various aspects * of encoding such as terminal modes (cursor key application mode, keypad mode), * protocol selection (Kitty keyboard protocol flags), and platform-specific * behaviors (macOS option-as-alt). * * If you are using a terminal instance, you can set the key encoding * options based on the active terminal state (e.g. legacy vs Kitty mode * and associated flags) with ghostty_key_encoder_setopt_from_terminal(). * * A null pointer value does nothing. It does not reset the value to the * default. The setopt call will do nothing. * * @param encoder The encoder handle, must not be NULL * @param option The option to set * @param value Pointer to the value to set (type depends on the option) * * @ingroup key */GHOSTTY_API void ghostty_key_encoder_setopt(GhosttyKeyEncoder encoder, GhosttyKeyEncoderOption option, const void *value); /** * Set encoder options from a terminal's current state. * * Reads the terminal's current modes and flags and applies them to the * encoder's options. This sets cursor key application mode, keypad mode, * alt escape prefix, modifyOtherKeys state, and Kitty keyboard protocol * flags from the terminal state. * * Note that the `macos_option_as_alt` option cannot be determined from * terminal state and is reset to `GHOSTTY_OPTION_AS_ALT_FALSE` by this * call. Use ghostty_key_encoder_setopt() to set it afterward if needed. * * @param encoder The encoder handle, must not be NULL * @param terminal The terminal handle, must not be NULL * * @ingroup key */GHOSTTY_API void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, GhosttyTerminal terminal); /** * Encode a key event into a terminal escape sequence. * * Converts a key event into the appropriate terminal escape sequence based on * the encoder's current options. The sequence is written to the provided buffer. * * Not all key events produce output. For example, unmodified modifier keys * typically don't generate escape sequences. Check the out_len parameter to * determine if any data was written. * * If the output buffer is too small, this function returns GHOSTTY_OUT_OF_SPACE * and out_len will contain the required buffer size. The caller can then * allocate a larger buffer and call the function again. * * @param encoder The encoder handle, must not be NULL * @param event The key event to encode, must not be NULL * @param out_buf Buffer to write the encoded sequence to * @param out_buf_size Size of the output buffer in bytes * @param out_len Pointer to store the number of bytes written (may be NULL) * @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if buffer too small, or other error code * * ## Example: Calculate required buffer size * * @code{.c} * // Query the required size with a NULL buffer (always returns OUT_OF_SPACE) * size_t required = 0; * GhosttyResult result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required); * assert(result == GHOSTTY_OUT_OF_SPACE); * * // Allocate buffer of required size * char *buf = malloc(required); * * // Encode with properly sized buffer * size_t written = 0; * result = ghostty_key_encoder_encode(encoder, event, buf, required, &written); * assert(result == GHOSTTY_SUCCESS); * * // Use the encoded sequence... * * free(buf); * @endcode * * ## Example: Direct encoding with static buffer * * @code{.c} * // Most escape sequences are short, so a static buffer often suffices * char buf[128]; * size_t written = 0; * GhosttyResult result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written); * * if (result == GHOSTTY_SUCCESS) { * // Write the encoded sequence to the terminal * write(pty_fd, buf, written); * } else if (result == GHOSTTY_OUT_OF_SPACE) { * // Buffer too small, written contains required size * char *dynamic_buf = malloc(written); * result = ghostty_key_encoder_encode(encoder, event, dynamic_buf, written, &written); * assert(result == GHOSTTY_SUCCESS); * write(pty_fd, dynamic_buf, written); * free(dynamic_buf); * } * @endcode * * @ingroup key */GHOSTTY_API GhosttyResult ghostty_key_encoder_encode(GhosttyKeyEncoder encoder, GhosttyKeyEvent event, char *out_buf, size_t out_buf_size, size_t *out_len); #endif /* GHOSTTY_VT_KEY_ENCODER_H */
/**
* @file encoder.h
*
* Key event encoding to terminal escape sequences.
*/
#ifndef GHOSTTY_VT_KEY_ENCODER_H
#define GHOSTTY_VT_KEY_ENCODER_H
#include <stddef.h>
#include <stdint.h>
#include <ghostty/vt/types.h>
#include <ghostty/vt/allocator.h>
#include <ghostty/vt/terminal.h>
#include <ghostty/vt/key/event.h>
/**
* Opaque handle to a key encoder instance.
*
* This handle represents a key encoder that converts key events into terminal
* escape sequences.
*
* @ingroup key
*/
typedef struct GhosttyKeyEncoderImpl *GhosttyKeyEncoder;
/**
* Kitty keyboard protocol flags.
*
* Bitflags representing the various modes of the Kitty keyboard protocol.
* These can be combined using bitwise OR operations. Valid values all
* start with `GHOSTTY_KITTY_KEY_`.
*
* @ingroup key
*/
typedef uint8_t GhosttyKittyKeyFlags;
/** Kitty keyboard protocol disabled (all flags off) */
#define GHOSTTY_KITTY_KEY_DISABLED 0
/** Disambiguate escape codes */
#define GHOSTTY_KITTY_KEY_DISAMBIGUATE (1 << 0)
/** Report key press and release events */
#define GHOSTTY_KITTY_KEY_REPORT_EVENTS (1 << 1)
/** Report alternate key codes */
#define GHOSTTY_KITTY_KEY_REPORT_ALTERNATES (1 << 2)
/** Report all key events including those normally handled by the terminal */
#define GHOSTTY_KITTY_KEY_REPORT_ALL (1 << 3)
/** Report associated text with key events */
#define GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED (1 << 4)
/** All Kitty keyboard protocol flags enabled */
#define GHOSTTY_KITTY_KEY_ALL (GHOSTTY_KITTY_KEY_DISAMBIGUATE | GHOSTTY_KITTY_KEY_REPORT_EVENTS | GHOSTTY_KITTY_KEY_REPORT_ALTERNATES | GHOSTTY_KITTY_KEY_REPORT_ALL | GHOSTTY_KITTY_KEY_REPORT_ASSOCIATED)
/**
* macOS option key behavior.
*
* Determines whether the "option" key on macOS is treated as "alt" or not.
* See the Ghostty `macos-option-as-alt` configuration option for more details.
*
* @ingroup key
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Option key is not treated as alt */
GHOSTTY_OPTION_AS_ALT_FALSE = 0,
/** Option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_TRUE = 1,
/** Only left option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_LEFT = 2,
/** Only right option key is treated as alt */
GHOSTTY_OPTION_AS_ALT_RIGHT = 3,
GHOSTTY_OPTION_AS_ALT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyOptionAsAlt;
/**
* Key encoder option identifiers.
*
* These values are used with ghostty_key_encoder_setopt() to configure
* the behavior of the key encoder.
*
* @ingroup key
*/
typedef enum GHOSTTY_ENUM_TYPED {
/** Terminal DEC mode 1: cursor key application mode (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_CURSOR_KEY_APPLICATION = 0,
/** Terminal DEC mode 66: keypad key application mode (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_KEYPAD_KEY_APPLICATION = 1,
/** Terminal DEC mode 1035: ignore keypad with numlock (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_IGNORE_KEYPAD_WITH_NUMLOCK = 2,
/** Terminal DEC mode 1036: alt sends escape prefix (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_ALT_ESC_PREFIX = 3,
/** xterm modifyOtherKeys mode 2 (value: bool) */
GHOSTTY_KEY_ENCODER_OPT_MODIFY_OTHER_KEYS_STATE_2 = 4,
/** Kitty keyboard protocol flags (value: GhosttyKittyKeyFlags bitmask) */
GHOSTTY_KEY_ENCODER_OPT_KITTY_FLAGS = 5,
/** macOS option-as-alt setting (value: GhosttyOptionAsAlt) */
GHOSTTY_KEY_ENCODER_OPT_MACOS_OPTION_AS_ALT = 6,
/** Backarrow key mode (value: bool)
* See https://vt100.net/dec/ek-vt3xx-tp-002.pdf page 170
* If `false` (the default), `backspace` emits 0x7f
* If `true`, `backspace` emits 0x08
*/
GHOSTTY_KEY_ENCODER_OPT_BACKARROW_KEY_MODE = 7,
GHOSTTY_KEY_ENCODER_OPT_MAX_VALUE = GHOSTTY_ENUM_MAX_VALUE,
} GhosttyKeyEncoderOption;
/**
* Create a new key encoder instance.
*
* Creates a new key encoder with default options. The encoder can be configured
* using ghostty_key_encoder_setopt() and must be freed using
* ghostty_key_encoder_free() when no longer needed.
*
* @param allocator Pointer to the allocator to use for memory management, or NULL to use the default allocator
* @param encoder Pointer to store the created encoder handle
* @return GHOSTTY_SUCCESS on success, or an error code on failure
*
* @ingroup key
*/
GHOSTTY_API GhosttyResult ghostty_key_encoder_new(const GhosttyAllocator *allocator, GhosttyKeyEncoder *encoder);
/**
* Free a key encoder instance.
*
* Releases all resources associated with the key encoder. After this call,
* the encoder handle becomes invalid and must not be used.
*
* @param encoder The encoder handle to free (may be NULL)
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_encoder_free(GhosttyKeyEncoder encoder);
/**
* Set an option on the key encoder.
*
* Configures the behavior of the key encoder. Options control various aspects
* of encoding such as terminal modes (cursor key application mode, keypad mode),
* protocol selection (Kitty keyboard protocol flags), and platform-specific
* behaviors (macOS option-as-alt).
*
* If you are using a terminal instance, you can set the key encoding
* options based on the active terminal state (e.g. legacy vs Kitty mode
* and associated flags) with ghostty_key_encoder_setopt_from_terminal().
*
* A null pointer value does nothing. It does not reset the value to the
* default. The setopt call will do nothing.
*
* @param encoder The encoder handle, must not be NULL
* @param option The option to set
* @param value Pointer to the value to set (type depends on the option)
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_encoder_setopt(GhosttyKeyEncoder encoder, GhosttyKeyEncoderOption option, const void *value);
/**
* Set encoder options from a terminal's current state.
*
* Reads the terminal's current modes and flags and applies them to the
* encoder's options. This sets cursor key application mode, keypad mode,
* alt escape prefix, modifyOtherKeys state, and Kitty keyboard protocol
* flags from the terminal state.
*
* Note that the `macos_option_as_alt` option cannot be determined from
* terminal state and is reset to `GHOSTTY_OPTION_AS_ALT_FALSE` by this
* call. Use ghostty_key_encoder_setopt() to set it afterward if needed.
*
* @param encoder The encoder handle, must not be NULL
* @param terminal The terminal handle, must not be NULL
*
* @ingroup key
*/
GHOSTTY_API void ghostty_key_encoder_setopt_from_terminal(GhosttyKeyEncoder encoder, GhosttyTerminal terminal);
/**
* Encode a key event into a terminal escape sequence.
*
* Converts a key event into the appropriate terminal escape sequence based on
* the encoder's current options. The sequence is written to the provided buffer.
*
* Not all key events produce output. For example, unmodified modifier keys
* typically don't generate escape sequences. Check the out_len parameter to
* determine if any data was written.
*
* If the output buffer is too small, this function returns GHOSTTY_OUT_OF_SPACE
* and out_len will contain the required buffer size. The caller can then
* allocate a larger buffer and call the function again.
*
* @param encoder The encoder handle, must not be NULL
* @param event The key event to encode, must not be NULL
* @param out_buf Buffer to write the encoded sequence to
* @param out_buf_size Size of the output buffer in bytes
* @param out_len Pointer to store the number of bytes written (may be NULL)
* @return GHOSTTY_SUCCESS on success, GHOSTTY_OUT_OF_SPACE if buffer too small, or other error code
*
* ## Example: Calculate required buffer size
*
* @code{.c}
* // Query the required size with a NULL buffer (always returns OUT_OF_SPACE)
* size_t required = 0;
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, NULL, 0, &required);
* assert(result == GHOSTTY_OUT_OF_SPACE);
*
* // Allocate buffer of required size
* char *buf = malloc(required);
*
* // Encode with properly sized buffer
* size_t written = 0;
* result = ghostty_key_encoder_encode(encoder, event, buf, required, &written);
* assert(result == GHOSTTY_SUCCESS);
*
* // Use the encoded sequence...
*
* free(buf);
* @endcode
*
* ## Example: Direct encoding with static buffer
*
* @code{.c}
* // Most escape sequences are short, so a static buffer often suffices
* char buf[128];
* size_t written = 0;
* GhosttyResult result = ghostty_key_encoder_encode(encoder, event, buf, sizeof(buf), &written);
*
* if (result == GHOSTTY_SUCCESS) {
* // Write the encoded sequence to the terminal
* write(pty_fd, buf, written);
* } else if (result == GHOSTTY_OUT_OF_SPACE) {
* // Buffer too small, written contains required size
* char *dynamic_buf = malloc(written);
* result = ghostty_key_encoder_encode(encoder, event, dynamic_buf, written, &written);
* assert(result == GHOSTTY_SUCCESS);
* write(pty_fd, dynamic_buf, written);
* free(dynamic_buf);
* }
* @endcode
*
* @ingroup key
*/
GHOSTTY_API GhosttyResult ghostty_key_encoder_encode(GhosttyKeyEncoder encoder, GhosttyKeyEvent event, char *out_buf, size_t out_buf_size, size_t *out_len);
#endif /* GHOSTTY_VT_KEY_ENCODER_H */