Files
2026-08-03 18:42:47 +08:00

227 lines
8.1 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright © 2013 Ran Benita
* SPDX-License-Identifier: MIT
*/
#ifndef _XKBCOMMON_X11_H
#define _XKBCOMMON_X11_H
#include <xcb/xcb.h>
#include <xkbcommon/xkbcommon.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file
* libxkbcommon-x11 API - Additional X11 support for xkbcommon.
*/
/**
* @defgroup x11 X11 support
* Additional X11 support for xkbcommon.
* @since 0.4.0
*
* @{
*/
/**
* @page x11-overview Overview
* @parblock
*
* The xkbcommon-x11 module provides a means for creating an xkb_keymap
* corresponding to the currently active keymap on the X server. To do
* so, it queries the XKB X11 extension using the xcb-xkb library. It
* can be used as a replacement for Xlib’s keyboard handling.
*
* Following is an example workflow using xkbcommon-x11. A complete
* example may be found in the `tools/interactive-x11.c` file in the
* xkbcommon source repository. On startup:
*
* 1. Connect to the X server using `xcb_connect()`.
* 2. Setup the XKB X11 extension. You can do this either by using the
* `xcb_xkb_use_extension()` request directly, or by using the
* `xkb_x11_setup_xkb_extension()` helper function.
*
* The XKB extension supports using separate keymaps and states for
* different keyboard devices. The devices are identified by an integer
* device ID and are managed by another X11 extension, XInput. The
* original X11 protocol only had one keyboard device, called the *core
* keyboard*, which is still supported as a *virtual device*.
*
* 3. We will use the core keyboard as an example. To get its device ID,
* use either the `xcb_xkb_get_device_info()` request directly, or the
* `xkb_x11_get_core_keyboard_device_id()` helper function.
* 4. Create an initial xkb_keymap for this device, using the
* `xkb_x11_keymap_new_from_device()` function.
* 5. Create an initial xkb_state for this device, using the
* `xkb_x11_state_new_from_device()` function.
*
* @note At this point, you may consider setting various XKB controls and
* XKB per-client flags. For example, enabling detectable autorepeat: \n
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Detectable_Autorepeat
*
* Next, you need to react to state changes (e.g. a modifier was pressed,
* the layout was changed) and to keymap changes (e.g. a tool like xkbcomp,
* setxkbmap or xmodmap was used):
*
* 6. Select to listen to at least the following XKB events:
* `NewKeyboardNotify`, `MapNotify`, `StateNotify`; using the
* `xcb_xkb_select_events_aux()` request.
* 7. When `NewKeyboardNotify` or `MapNotify` are received, recreate the
* `xkb_keymap` and `xkb_state` as described above.
* 8. When `StateNotify` is received, update the `xkb_state` accordingly
* using the `xkb_state::xkb_state_update_mask()` function.
*
* @note It is also possible to use the `KeyPress`/`KeyRelease` @p state
* field to find the effective modifier and layout state, instead of
* using `XkbStateNotify`: \n
* https://www.x.org/releases/current/doc/kbproto/xkbproto.html#Computing_A_State_Field_from_an_XKB_State
* \n However, `XkbStateNotify` is more accurate.
*
* @note There is no need to call `xkb_state_update_key()`; the state is
* already synchronized.
*
* Finally, when a key event is received, you can use ordinary xkbcommon
* functions, like `xkb_state::xkb_state_key_get_one_sym()` and
* `xkb_state::xkb_state_key_get_utf8()`, as you normally would.
*
* @endparblock
*/
/**
* The minimal compatible major version of the XKB X11 extension which
* this library can use.
*/
#define XKB_X11_MIN_MAJOR_XKB_VERSION 1
/**
* The minimal compatible minor version of the XKB X11 extension which
* this library can use (for the minimal major version).
*/
#define XKB_X11_MIN_MINOR_XKB_VERSION 0
/** Flags for the `xkb_x11_setup_xkb_extension()` function. */
enum xkb_x11_setup_xkb_extension_flags {
/** Do not apply any flags. */
XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS = 0
};
/**
* Setup the XKB X11 extension for this X client.
*
* The xkbcommon-x11 library uses various XKB requests. Before doing so,
* an X client must notify the server that it will be using the extension.
* This function (or an XCB equivalent) must be called before any other
* function in this library is used.
*
* Some X servers may not support or disable the XKB extension. If you
* want to support such servers, you need to use a different fallback.
*
* You may call this function several times; it is idempotent.
*
* @param connection
* An XCB connection to the X server.
* @param major_xkb_version
* See @p minor_xkb_version.
* @param minor_xkb_version
* The XKB extension version to request. To operate correctly, you
* must have (@p major_xkb_version, @p minor_xkb_version) >=
* (`XKB_X11_MIN_MAJOR_XKB_VERSION`, `XKB_X11_MIN_MINOR_XKB_VERSION`),
* though this is not enforced.
* @param flags
* Optional flags, or 0.
* @param[out] major_xkb_version_out
* See @p minor_xkb_version_out.
* @param[out] minor_xkb_version_out
* Backfilled with the compatible XKB extension version numbers picked
* by the server. Can be `NULL`.
* @param[out] base_event_out
* Backfilled with the XKB base (also known as first) event code, needed
* to distinguish XKB events. Can be `NULL`.
* @param[out] base_error_out
* Backfilled with the XKB base (also known as first) error code, needed
* to distinguish XKB errors. Can be `NULL`.
*
* @returns 1 on success, or 0 on failure.
*/
XKB_EXPORT int
xkb_x11_setup_xkb_extension(xcb_connection_t *connection,
uint16_t major_xkb_version,
uint16_t minor_xkb_version,
enum xkb_x11_setup_xkb_extension_flags flags,
uint16_t *major_xkb_version_out,
uint16_t *minor_xkb_version_out,
uint8_t *base_event_out,
uint8_t *base_error_out);
/**
* Get the keyboard device ID of the core X11 keyboard.
*
* @param connection An XCB connection to the X server.
*
* @returns A device ID which may be used with other `xkb_x11_*` functions,
* or -1 on failure.
*/
XKB_EXPORT int32_t
xkb_x11_get_core_keyboard_device_id(xcb_connection_t *connection);
/**
* Create a keymap from an X11 keyboard device.
*
* This function queries the X server with various requests, fetches the
* details of the active keymap on a keyboard device, and creates an
* xkb_keymap from these details.
*
* @param context
* The context in which to create the keymap.
* @param connection
* An XCB connection to the X server.
* @param device_id
* An XInput device ID (in the range 0-127) with input class KEY.
* Passing values outside of this range is an error (the XKB protocol
* predates the XInput2 protocol, which first allowed IDs > 127).
* @param flags
* Optional flags for the keymap, or 0.
*
* @returns A keymap retrieved from the X server, or `NULL` on failure.
*
* @memberof xkb_keymap
*/
XKB_EXPORT struct xkb_keymap *
xkb_x11_keymap_new_from_device(struct xkb_context *context,
xcb_connection_t *connection,
int32_t device_id,
enum xkb_keymap_compile_flags flags);
/**
* Create a new keyboard state object from an X11 keyboard device.
*
* This function is the same as `xkb_state_new()`, only pre-initialized
* with the state of the device at the time this function is called.
*
* @param keymap
* The keymap for which to create the state.
* @param connection
* An XCB connection to the X server.
* @param device_id
* An XInput 1 device ID (in the range 0-255) with input class KEY.
* Passing values outside of this range is an error.
*
* @returns A new keyboard state object, or `NULL` on failure.
*
* @memberof xkb_state
*/
XKB_EXPORT struct xkb_state *
xkb_x11_state_new_from_device(struct xkb_keymap *keymap,
xcb_connection_t *connection,
int32_t device_id);
/** @} */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* _XKBCOMMON_X11_H */