227 lines
8.1 KiB
C
227 lines
8.1 KiB
C
/*
|
||
* 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 */
|