Edit

kc3-lang/libxkbcommon/src/keymap.h

Branch :

  • Show log

    Commit

  • Author : Pierre Le Marre
    Date : 2025-06-16 15:48:25
    Hash : ef6a550f
    Message : Add xkb_keymap_new_from_rmlvo() Use the new RMLVO builder API to compile keymaps.

  • src/keymap.h
  • /*
     * For MIT-open-group:
     * Copyright 1985, 1987, 1990, 1998  The Open Group
     *
     * For HPND
     * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc.
     *
     * For MIT:
     * Copyright © 2009 Dan Nicholson
     * Copyright © 2012 Intel Corporation
     * Copyright © 2012 Ran Benita
     *
     * SPDX-License-Identifier: MIT-open-group AND HPND AND MIT
     *
     * Author: Daniel Stone <daniel@fooishbar.org>
     * Author: Dan Nicholson <dbn.lists@gmail.com>
     */
    #pragma once
    
     /* Don't use compat names in internal code. */
    #define _XKBCOMMON_COMPAT_H
    
    #include <stdint.h>
    #include <stdbool.h>
    
    #include "xkbcommon/xkbcommon.h"
    
    #include "rmlvo.h"
    #include "utils.h"
    #include "context.h"
    
    /* Note: imposed by the size of the xkb_layout_mask_t type (32).
     * This is more than enough though. */
    #define XKB_MAX_GROUPS 32
    #define XKB_ALL_GROUPS ((UINT64_C(1) << XKB_MAX_GROUPS) - UINT64_C(1))
    /* Limit imposed by X11 */
    #define XKB_MAX_GROUPS_X11 4
    
    static inline xkb_layout_index_t
    format_max_groups(enum xkb_keymap_format format)
    {
        return (format == XKB_KEYMAP_FORMAT_TEXT_V1)
            ? XKB_MAX_GROUPS_X11
            : XKB_MAX_GROUPS;
    }
    
    /* Don't allow more modifiers than we can hold in xkb_mod_mask_t. */
    #define XKB_MAX_MODS ((xkb_mod_index_t) (sizeof(xkb_mod_mask_t) * CHAR_BIT))
    
    /* Don't allow more leds than we can hold in xkb_led_mask_t. */
    #define XKB_MAX_LEDS ((xkb_led_index_t) (sizeof(xkb_led_mask_t) * CHAR_BIT))
    
    /* Special value to handle modMap None {…} */
    #define XKB_MOD_NONE 0xffffffffU
    
    enum mod_type {
        /** X11 core modifier */
        MOD_REAL = (1 << 0),
        /** A non-X11 core modifier */
        MOD_VIRT = (1 << 1),
        /** Any modifier */
        MOD_BOTH = (MOD_REAL | MOD_VIRT)
    };
    #define MOD_REAL_MASK_ALL ((xkb_mod_mask_t) 0x000000ff)
    
    /** Predefined (AKA real, core, X11) modifiers. The order is important! */
    enum real_mod_index {
        XKB_MOD_INDEX_SHIFT = 0,
        XKB_MOD_INDEX_CAPS,
        XKB_MOD_INDEX_CTRL,
        XKB_MOD_INDEX_MOD1,
        XKB_MOD_INDEX_MOD2,
        XKB_MOD_INDEX_MOD3,
        XKB_MOD_INDEX_MOD4,
        XKB_MOD_INDEX_MOD5,
        _XKB_MOD_INDEX_NUM_ENTRIES
    };
    static_assert(_XKB_MOD_INDEX_NUM_ENTRIES == 8, "Invalid X11 core modifiers");
    
    enum xkb_action_type {
        ACTION_TYPE_NONE = 0,
        ACTION_TYPE_VOID, /* libxkbcommon extension */
        ACTION_TYPE_MOD_SET,
        ACTION_TYPE_MOD_LATCH,
        ACTION_TYPE_MOD_LOCK,
        ACTION_TYPE_GROUP_SET,
        ACTION_TYPE_GROUP_LATCH,
        ACTION_TYPE_GROUP_LOCK,
        ACTION_TYPE_PTR_MOVE,
        ACTION_TYPE_PTR_BUTTON,
        ACTION_TYPE_PTR_LOCK,
        ACTION_TYPE_PTR_DEFAULT,
        ACTION_TYPE_TERMINATE,
        ACTION_TYPE_SWITCH_VT,
        ACTION_TYPE_CTRL_SET,
        ACTION_TYPE_CTRL_LOCK,
        ACTION_TYPE_UNSUPPORTED_LEGACY,
        ACTION_TYPE_PRIVATE,
        ACTION_TYPE_INTERNAL, /* Action specific and internal to xkbcommon */
        _ACTION_TYPE_NUM_ENTRIES
    };
    
    enum xkb_action_flags {
        ACTION_LOCK_CLEAR = (1 << 0),
        ACTION_LATCH_TO_LOCK = (1 << 1),
        ACTION_LOCK_NO_LOCK = (1 << 2),
        ACTION_LOCK_NO_UNLOCK = (1 << 3),
        ACTION_MODS_LOOKUP_MODMAP = (1 << 4),
        ACTION_ABSOLUTE_SWITCH = (1 << 5),
        ACTION_ABSOLUTE_X = (1 << 6),
        ACTION_ABSOLUTE_Y = (1 << 7),
        ACTION_ACCEL = (1 << 8),
        ACTION_SAME_SCREEN = (1 << 9),
    };
    
    enum xkb_action_controls {
        CONTROL_REPEAT = (1 << 0),
        CONTROL_SLOW = (1 << 1),
        CONTROL_DEBOUNCE = (1 << 2),
        CONTROL_STICKY = (1 << 3),
        CONTROL_MOUSEKEYS = (1 << 4),
        CONTROL_MOUSEKEYS_ACCEL = (1 << 5),
        CONTROL_AX = (1 << 6),
        CONTROL_AX_TIMEOUT = (1 << 7),
        CONTROL_AX_FEEDBACK = (1 << 8),
        CONTROL_BELL = (1 << 9),
        CONTROL_IGNORE_GROUP_LOCK = (1 << 10),
        CONTROL_ALL = \
            (CONTROL_REPEAT | CONTROL_SLOW | CONTROL_DEBOUNCE | CONTROL_STICKY | \
             CONTROL_MOUSEKEYS | CONTROL_MOUSEKEYS_ACCEL | CONTROL_AX | \
             CONTROL_AX_TIMEOUT | CONTROL_AX_FEEDBACK | CONTROL_BELL | \
             CONTROL_IGNORE_GROUP_LOCK)
    };
    
    enum xkb_match_operation {
        MATCH_NONE,
        MATCH_ANY_OR_NONE,
        MATCH_ANY,
        MATCH_ALL,
        MATCH_EXACTLY,
    };
    
    struct xkb_mods {
        xkb_mod_mask_t mods;       /* original real+virtual mods in definition */
        xkb_mod_mask_t mask;       /* computed effective mask */
    };
    
    struct xkb_mod_action {
        enum xkb_action_type type;
        enum xkb_action_flags flags;
        struct xkb_mods mods;
    };
    
    struct xkb_group_action {
        enum xkb_action_type type;
        enum xkb_action_flags flags;
        int32_t group;
    };
    
    struct xkb_controls_action {
        enum xkb_action_type type;
        enum xkb_action_flags flags;
        enum xkb_action_controls ctrls;
    };
    
    struct xkb_pointer_default_action {
        enum xkb_action_type type;
        enum xkb_action_flags flags;
        int8_t value;
    };
    
    struct xkb_switch_screen_action {
        enum xkb_action_type type;
        enum xkb_action_flags flags;
        int8_t screen;
    };
    
    struct xkb_pointer_action {
        enum xkb_action_type type;
        enum xkb_action_flags flags;
        int16_t x;
        int16_t y;
    };
    
    struct xkb_pointer_button_action {
        enum xkb_action_type type;
        enum xkb_action_flags flags;
        uint8_t count;
        uint8_t button;
    };
    
    struct xkb_private_action {
        enum xkb_action_type type;
        uint8_t data[7];
    };
    
    enum xkb_internal_action_flags {
        INTERNAL_BREAKS_GROUP_LATCH = (1 << 0),
        INTERNAL_BREAKS_MOD_LATCH = (1 << 1),
    };
    
    /* Action specific and internal to xkbcommon */
    struct xkb_internal_action {
        enum xkb_action_type type;
        enum xkb_internal_action_flags flags;
        union {
            /* flag == INTERNAL_BREAKS_MOD_LATCH */
            xkb_mod_mask_t clear_latched_mods;
        };
    };
    
    union xkb_action {
        enum xkb_action_type type;
        struct xkb_mod_action mods;
        struct xkb_group_action group;
        struct xkb_controls_action ctrls;
        struct xkb_pointer_default_action dflt;
        struct xkb_switch_screen_action screen;
        struct xkb_pointer_action ptr;
        struct xkb_pointer_button_action btn;
        struct xkb_private_action priv;
        struct xkb_internal_action internal;
    };
    
    struct xkb_key_type_entry {
        xkb_level_index_t level;
        struct xkb_mods mods;
        struct xkb_mods preserve;
    };
    
    struct xkb_key_type {
        xkb_atom_t name;
        struct xkb_mods mods;
        xkb_level_index_t num_levels;
        xkb_level_index_t num_level_names;
        xkb_atom_t *level_names;
        darray_size_t num_entries;
        struct xkb_key_type_entry *entries;
    };
    
    typedef uint16_t xkb_action_count_t;
    #define MAX_ACTIONS_PER_LEVEL UINT16_MAX
    
    struct xkb_sym_interpret {
        xkb_keysym_t sym;
        enum xkb_match_operation match;
        xkb_mod_mask_t mods;
        xkb_mod_index_t virtual_mod;
        bool level_one_only;
        bool repeat;
        xkb_action_count_t num_actions;
        union {
            /* num_actions <= 1 */
            union xkb_action action;
            /* num_actions >  1 */
            union xkb_action *actions;
        } a;
    };
    
    struct xkb_led {
        xkb_atom_t name;
        enum xkb_state_component which_groups;
        xkb_layout_mask_t groups;
        enum xkb_state_component which_mods;
        struct xkb_mods mods;
        enum xkb_action_controls ctrls;
    };
    
    struct xkb_key_alias {
        xkb_atom_t real;
        xkb_atom_t alias;
    };
    
    struct xkb_controls {
        unsigned char groups_wrap;
        struct xkb_mods internal;
        struct xkb_mods ignore_lock;
        unsigned short repeat_delay;
        unsigned short repeat_interval;
        unsigned short slow_keys_delay;
        unsigned short debounce_delay;
        unsigned short ax_options;
        unsigned short ax_timeout;
        unsigned short axt_opts_mask;
        unsigned short axt_opts_values;
        unsigned int axt_ctrls_mask;
        unsigned int axt_ctrls_values;
    };
    
    /* Such an awkward name.  Oh well. */
    enum xkb_range_exceed_type {
        RANGE_WRAP = 0,
        RANGE_SATURATE,
        RANGE_REDIRECT,
    };
    
    enum xkb_explicit_components {
        EXPLICIT_SYMBOLS = (1 << 0),
        EXPLICIT_INTERP = (1 << 1),
        EXPLICIT_TYPES = (1 << 2),
        EXPLICIT_VMODMAP = (1 << 3),
        EXPLICIT_REPEAT = (1 << 4),
    };
    
    typedef uint16_t xkb_keysym_count_t;
    #define MAX_KEYSYMS_PER_LEVEL UINT16_MAX
    
    /** A key level */
    struct xkb_level {
        /** Count of keysyms */
        xkb_keysym_count_t num_syms;
        /** Count of actions */
        xkb_action_count_t num_actions;
        /** Upper keysym */
        union {
            /** num_syms == 1: Upper keysym */
            xkb_keysym_t upper;
            /** num_syms >  1: Indicate if `syms` contains the upper case keysyms
             *                 after the lower ones. */
            bool has_upper;
        };
        /** Keysyms */
        union {
            xkb_keysym_t sym;          /* num_syms == 1 */
            xkb_keysym_t *syms;        /* num_syms > 1  */
        } s;
        /** Actions */
        union {
            union xkb_action action;   /* num_actions == 1 */
            union xkb_action *actions; /* num_actions >  1 */
        } a;
    };
    
    /**
     * Group in a key
     */
    struct xkb_group {
        /**
         * Flag that indicates whether a group has explicit actions. In case it has,
         * compatibility interpretations will not be used on it.
         * See also EXPLICIT_INTERP flag at key level.
         */
        bool explicit_actions:1;
        /**
         * Flag that indicates whether a group has an explicit key type. In case it
         * has, type detection will not be used on it.
         */
        bool explicit_type:1;
        /**
         * Key type of the group. Points to an entry in keymap->types.
         */
        const struct xkb_key_type *type;
        /**
         * Array of group levels. Use `XkbKeyNumLevels` for the number of levels.
         */
        struct xkb_level *levels;
    };
    
    struct xkb_key {
        xkb_keycode_t keycode;
        xkb_atom_t name;
    
        enum xkb_explicit_components explicit;
    
        xkb_mod_mask_t modmap;
        xkb_mod_mask_t vmodmap;
    
        bool repeats;
    
        enum xkb_range_exceed_type out_of_range_group_action;
        xkb_layout_index_t out_of_range_group_number;
    
        xkb_layout_index_t num_groups;
        struct xkb_group *groups;
    };
    
    struct xkb_mod {
        xkb_atom_t name;
        enum mod_type type;
        xkb_mod_mask_t mapping; /* vmod -> real mod mapping */
    };
    
    struct xkb_mod_set {
        struct xkb_mod mods[XKB_MAX_MODS];
        xkb_mod_index_t num_mods;
        xkb_mod_mask_t explicit_vmods;
    };
    
    /*
     * Our current implementation with continuous arrays does not allow efficient
     * mapping of keycodes. Allowing the API max valid keycode XKB_KEYCODE_MAX could
     * result in memory exhaustion or memory waste (sparse arrays) with huge enough
     * valid values. Let’s be more conservative for now, based on the existing Linux
     * keycodes.
     */
    #define XKB_KEYCODE_MAX_IMPL 0xfff
    static_assert(XKB_KEYCODE_MAX_IMPL < XKB_KEYCODE_MAX,
                  "Valid keycodes");
    static_assert(XKB_KEYCODE_MAX_IMPL < darray_max_alloc(sizeof(xkb_atom_t)),
                  "Max keycodes names");
    static_assert(XKB_KEYCODE_MAX_IMPL < darray_max_alloc(sizeof(struct xkb_key)),
                  "Max keymap keys");
    
    /*
     * Our current implementation with continuous arrays does not allow efficient
     * mapping of levels. Allowing the max valid level UINT32_MAX could result in
     * memory exhaustion or memory waste (sparse arrays) with huge enough valid
     * values. Let’s be more conservative for now. This value should be big enough
     * to satisfy automatically generated keymaps.
     */
    #define XKB_LEVEL_MAX_IMPL 2048
    static_assert(XKB_LEVEL_MAX_IMPL < XKB_LEVEL_INVALID,
                  "Valid levels");
    static_assert(XKB_LEVEL_MAX_IMPL < darray_max_alloc(sizeof(xkb_atom_t)),
                  "Max key types level names");
    static_assert(XKB_LEVEL_MAX_IMPL < darray_max_alloc(sizeof(struct xkb_level)),
                  "Max keys levels");
    
    /* Common keyboard description structure */
    struct xkb_keymap {
        struct xkb_context *ctx;
    
        int refcnt;
        enum xkb_keymap_compile_flags flags;
        enum xkb_keymap_format format;
    
        enum xkb_action_controls enabled_ctrls;
    
        xkb_keycode_t min_key_code;
        xkb_keycode_t max_key_code;
        struct xkb_key *keys;
    
        /* aliases in no particular order */
        darray_size_t num_key_aliases;
        struct xkb_key_alias *key_aliases;
    
        struct xkb_key_type *types;
        darray_size_t num_types;
    
        darray_size_t num_sym_interprets;
        struct xkb_sym_interpret *sym_interprets;
    
        /**
         * Modifiers configuration.
         * This is *internal* to the keymap; other implementations may use different
         * virtual modifiers indexes. Ours depends on:
         *   1. the order of the parsing of the keymap components;
         *   2. the order of the virtual modifiers declarations;
         */
        struct xkb_mod_set mods;
        /**
         * Modifier mask of the *canonical* state, i.e. the mask with the *smallest*
         * population count that denotes all bits used to encode the modifiers in
         * the keyboard state. It is equal to the bitwise OR of *real* modifiers and
         * all *virtual* modifiers mappings.
         *
         * [WARNING] The bits that do not correspond to *real* modifiers should
         * *not* be interpreted as corresponding to indexes of virtual modifiers of
         * the keymap. Indeed, one may use explicit vmod mapping with an arbitrary
         * value.
         *
         * E.g. if M1 is the only vmod and it is defined by:
         *
         *     virtual_modifiers M1=0x80000000; // 1 << (32 - 1)
         *
         * then the 32th bit of a modifier mask input does *not* denote the 32th
         * virtual modifier of the keymap, but merely the encoding of the mapping of
         * M1.
         *
         * In the API, any input mask should be preprocessed to resolve the bits
         * that do not match the canonical mask.
         */
        xkb_mod_mask_t canonical_state_mask;
    
        /* This field has 2 uses:
         * • During parsing: Expected layouts count after RMLVO resolution, if any;
         * • After parsing: Number of groups in the key with the most groups. */
        xkb_layout_index_t num_groups;
        /* Not all groups must have names. */
        xkb_layout_index_t num_group_names;
        xkb_atom_t *group_names;
    
        struct xkb_led leds[XKB_MAX_LEDS];
        xkb_led_index_t num_leds;
    
        char *keycodes_section_name;
        char *symbols_section_name;
        char *types_section_name;
        char *compat_section_name;
    };
    
    #define xkb_keys_foreach(iter, keymap) \
        for ((iter) = (keymap)->keys + (keymap)->min_key_code; \
             (iter) <= (keymap)->keys + (keymap)->max_key_code; \
             (iter)++)
    
    #define xkb_mods_foreach(iter, mods_) \
        for ((iter) = (mods_)->mods; \
             (iter) < (mods_)->mods + (mods_)->num_mods; \
             (iter)++)
    
    #define xkb_mods_mask_foreach(mask, iter, mods_) \
        for ((iter) = (mods_)->mods; \
             (mask) && (iter) < (mods_)->mods + (mods_)->num_mods; \
             (iter)++, (mask) >>= 1) \
            if ((mask) & 0x1)
    
    /** Enumerate all modifiers */
    #define xkb_mods_enumerate(idx, iter, mods_) \
        for ((idx) = 0, (iter) = (mods_)->mods; \
             (idx) < (mods_)->num_mods; \
             (idx)++, (iter)++)
    
    /** Enumerate only real modifiers */
    #define xkb_rmods_enumerate(idx, iter, mods_) \
        for ((idx) = 0, (iter) = (mods_)->mods; \
             (idx) < _XKB_MOD_INDEX_NUM_ENTRIES; \
             (idx)++, (iter)++)
    
    /** Enumerate only virtual modifiers */
    #define xkb_vmods_enumerate(idx, iter, mods_) \
        for ((idx) = _XKB_MOD_INDEX_NUM_ENTRIES, \
             (iter) = &(mods_)->mods[_XKB_MOD_INDEX_NUM_ENTRIES]; \
             (idx) < (mods_)->num_mods; \
             (idx)++, (iter)++)
    
    #define xkb_leds_foreach(iter, keymap) \
        for ((iter) = (keymap)->leds; \
             (iter) < (keymap)->leds + (keymap)->num_leds; \
             (iter)++)
    
    #define xkb_leds_enumerate(idx, iter, keymap) \
        for ((idx) = 0, (iter) = (keymap)->leds; \
             (idx) < (keymap)->num_leds; \
             (idx)++, (iter)++)
    
    void
    clear_level(struct xkb_level *leveli);
    
    static inline const struct xkb_key *
    XkbKey(struct xkb_keymap *keymap, xkb_keycode_t kc)
    {
        if (kc < keymap->min_key_code || kc > keymap->max_key_code)
            return NULL;
        return &keymap->keys[kc];
    }
    
    static inline xkb_level_index_t
    XkbKeyNumLevels(const struct xkb_key *key, xkb_layout_index_t layout)
    {
        return key->groups[layout].type->num_levels;
    }
    
    /*
     * Map entries which specify unbound virtual modifiers are not considered.
     * See: the XKB protocol, section “Determining the KeySym Associated with a Key
     * Event”
     *
     * xserver does this with cached entry->active field.
     */
    static inline bool
    entry_is_active(const struct xkb_key_type_entry *entry)
    {
        return entry->mods.mods == 0 || entry->mods.mask != 0;
    }
    
    struct xkb_keymap *
    xkb_keymap_new(struct xkb_context *ctx,
                   enum xkb_keymap_format format,
                   enum xkb_keymap_compile_flags flags);
    
    struct xkb_key *
    XkbKeyByName(struct xkb_keymap *keymap, xkb_atom_t name, bool use_aliases);
    
    xkb_atom_t
    XkbResolveKeyAlias(const struct xkb_keymap *keymap, xkb_atom_t name);
    
    void
    XkbEscapeMapName(char *name);
    
    xkb_mod_index_t
    XkbModNameToIndex(const struct xkb_mod_set *mods, xkb_atom_t name,
                      enum mod_type type);
    
    bool
    XkbLevelsSameSyms(const struct xkb_level *a, const struct xkb_level *b);
    
    bool
    action_equal(const union xkb_action *a, const union xkb_action *b);
    
    bool
    XkbLevelsSameActions(const struct xkb_level *a, const struct xkb_level *b);
    
    xkb_layout_index_t
    XkbWrapGroupIntoRange(int32_t group,
                          xkb_layout_index_t num_groups,
                          enum xkb_range_exceed_type out_of_range_group_action,
                          xkb_layout_index_t out_of_range_group_number);
    
    XKB_EXPORT_PRIVATE xkb_mod_mask_t
    mod_mask_get_effective(struct xkb_keymap *keymap, xkb_mod_mask_t mods);
    
    struct xkb_level *
    xkb_keymap_key_get_level(struct xkb_keymap *keymap, const struct xkb_key *key,
                             xkb_layout_index_t layout, xkb_level_index_t level);
    
    xkb_action_count_t
    xkb_keymap_key_get_actions_by_level(struct xkb_keymap *keymap,
                                        const struct xkb_key *key,
                                        xkb_layout_index_t layout,
                                        xkb_level_index_t level,
                                        const union xkb_action **actions);
    
    struct xkb_keymap_format_ops {
        bool (*keymap_new_from_rmlvo)(struct xkb_keymap *keymap,
                                      const struct xkb_rmlvo_builder *rmlvo);
        bool (*keymap_new_from_names)(struct xkb_keymap *keymap,
                                      const struct xkb_rule_names *names);
        bool (*keymap_new_from_string)(struct xkb_keymap *keymap,
                                       const char *string, size_t length);
        bool (*keymap_new_from_file)(struct xkb_keymap *keymap, FILE *file);
        char *(*keymap_get_as_string)(struct xkb_keymap *keymap,
                                      enum xkb_keymap_format format);
    };
    
    extern const struct xkb_keymap_format_ops text_v1_keymap_format_ops;