Edit

kc3-lang/libxkbcommon/src/text.c

Branch :

  • Show log

    Commit

  • Author : Pierre Le Marre
    Date : 2025-07-01 14:52:11
    Hash : b21a58d0
    Message : Add support for all level indices to LevelN constants Note that serialization must use numbers instead of names for levels > 8, to ensure backward compatibility.

  • src/text.c
  • /*
     * Copyright (c) 1994 by Silicon Graphics Computer Systems, Inc.
     * SPDX-License-Identifier: HPND
     */
    
    #include "config.h"
    
    #include <assert.h>
    
    #include "keymap.h"
    #include "keysym.h"
    #include "text.h"
    
    bool
    LookupString(const LookupEntry tab[], const char *string,
                  unsigned int *value_rtrn)
    {
        if (!string)
            return false;
    
        for (const LookupEntry *entry = tab; entry->name; entry++) {
            if (istreq(entry->name, string)) {
                *value_rtrn = entry->value;
                return true;
            }
        }
    
        return false;
    }
    
    const char *
    LookupValue(const LookupEntry tab[], unsigned int value)
    {
        for (const LookupEntry *entry = tab; entry->name; entry++)
            if (entry->value == value)
                return entry->name;
    
        return NULL;
    }
    
    const LookupEntry ctrlMaskNames[] = {
        { "RepeatKeys", CONTROL_REPEAT },
        { "Repeat", CONTROL_REPEAT },
        { "AutoRepeat", CONTROL_REPEAT },
        { "SlowKeys", CONTROL_SLOW },
        { "BounceKeys", CONTROL_DEBOUNCE },
        { "StickyKeys", CONTROL_STICKY },
        { "MouseKeys", CONTROL_MOUSEKEYS },
        { "MouseKeysAccel", CONTROL_MOUSEKEYS_ACCEL },
        { "AccessXKeys", CONTROL_AX },
        { "AccessXTimeout", CONTROL_AX_TIMEOUT },
        { "AccessXFeedback", CONTROL_AX_FEEDBACK },
        { "AudibleBell", CONTROL_BELL },
        { "IgnoreGroupLock", CONTROL_IGNORE_GROUP_LOCK },
        { "all", CONTROL_ALL },
        { "none", 0 },
        { "Overlay1", 0 },
        { "Overlay2", 0 },
        { NULL, 0 }
    };
    
    const LookupEntry modComponentMaskNames[] = {
        { "base", XKB_STATE_MODS_DEPRESSED },
        { "latched", XKB_STATE_MODS_LATCHED },
        { "locked", XKB_STATE_MODS_LOCKED },
        { "effective", XKB_STATE_MODS_EFFECTIVE },
        { "compat", XKB_STATE_MODS_EFFECTIVE },
        { "any", XKB_STATE_MODS_EFFECTIVE },
        { "none", 0 },
        { NULL, 0 }
    };
    
    const LookupEntry groupComponentMaskNames[] = {
        { "base", XKB_STATE_LAYOUT_DEPRESSED },
        { "latched", XKB_STATE_LAYOUT_LATCHED },
        { "locked", XKB_STATE_LAYOUT_LOCKED },
        { "effective", XKB_STATE_LAYOUT_EFFECTIVE },
        { "any", XKB_STATE_LAYOUT_EFFECTIVE },
        { "none", 0 },
        { NULL, 0 }
    };
    
    const LookupEntry groupMaskNames[] = {
        { "none", 0x00 },
        { "all", XKB_ALL_GROUPS },
        { NULL, 0 }
    };
    
    const LookupEntry buttonNames[] = {
        { "Button1", 1 },
        { "Button2", 2 },
        { "Button3", 3 },
        { "Button4", 4 },
        { "Button5", 5 },
        { "default", 0 },
        { NULL, 0 }
    };
    
    const LookupEntry useModMapValueNames[] = {
        { "LevelOne", 1 },
        { "Level1", 1 },
        { "AnyLevel", 0 },
        { "any", 0 },
        { NULL, 0 }
    };
    
    const LookupEntry actionTypeNames[] = {
        { "NoAction", ACTION_TYPE_NONE },
        { "VoidAction", ACTION_TYPE_VOID },
        { "SetMods", ACTION_TYPE_MOD_SET },
        { "LatchMods", ACTION_TYPE_MOD_LATCH },
        { "LockMods", ACTION_TYPE_MOD_LOCK },
        { "SetGroup", ACTION_TYPE_GROUP_SET },
        { "LatchGroup", ACTION_TYPE_GROUP_LATCH },
        { "LockGroup", ACTION_TYPE_GROUP_LOCK },
        { "MovePtr", ACTION_TYPE_PTR_MOVE },
        { "MovePointer", ACTION_TYPE_PTR_MOVE },
        { "PtrBtn", ACTION_TYPE_PTR_BUTTON },
        { "PointerButton", ACTION_TYPE_PTR_BUTTON },
        { "LockPtrBtn", ACTION_TYPE_PTR_LOCK },
        { "LockPtrButton", ACTION_TYPE_PTR_LOCK },
        { "LockPointerButton", ACTION_TYPE_PTR_LOCK },
        { "LockPointerBtn", ACTION_TYPE_PTR_LOCK },
        { "SetPtrDflt", ACTION_TYPE_PTR_DEFAULT },
        { "SetPointerDefault", ACTION_TYPE_PTR_DEFAULT },
        { "Terminate", ACTION_TYPE_TERMINATE },
        { "TerminateServer", ACTION_TYPE_TERMINATE },
        { "SwitchScreen", ACTION_TYPE_SWITCH_VT },
        { "SetControls", ACTION_TYPE_CTRL_SET },
        { "LockControls", ACTION_TYPE_CTRL_LOCK },
        { "Private", ACTION_TYPE_PRIVATE },
        /* deprecated actions below here - unused */
        { "RedirectKey", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "Redirect", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "ISOLock", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "ActionMessage", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "MessageAction", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "Message", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DeviceBtn", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DevBtn", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DevButton", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DeviceButton", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "LockDeviceBtn", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "LockDevBtn", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "LockDevButton", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "LockDeviceButton", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DeviceValuator", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DevVal", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DeviceVal", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { "DevValuator", ACTION_TYPE_UNSUPPORTED_LEGACY },
        { NULL, 0 },
    };
    
    const LookupEntry symInterpretMatchMaskNames[] = {
        { "NoneOf", MATCH_NONE },
        { "AnyOfOrNone", MATCH_ANY_OR_NONE },
        { "AnyOf", MATCH_ANY },
        { "AllOf", MATCH_ALL },
        { "Exactly", MATCH_EXACTLY },
        { NULL, 0 },
    };
    
    const char *
    ModIndexText(struct xkb_context *ctx, const struct xkb_mod_set *mods,
                 xkb_mod_index_t ndx)
    {
        if (ndx == XKB_MOD_INVALID)
            return "none";
    
        if (ndx == XKB_MOD_NONE)
            return "None";
    
        if (ndx >= mods->num_mods)
            return NULL;
    
        return xkb_atom_text(ctx, mods->mods[ndx].name);
    }
    
    const char *
    ActionTypeText(enum xkb_action_type type)
    {
        const char *name = LookupValue(actionTypeNames, type);
        return name ? name : "Private";
    }
    
    const char *
    KeysymText(struct xkb_context *ctx, xkb_keysym_t sym)
    {
        char *buffer = xkb_context_get_buffer(ctx, XKB_KEYSYM_NAME_MAX_SIZE);
        xkb_keysym_get_name(sym, buffer, XKB_KEYSYM_NAME_MAX_SIZE);
        return buffer;
    }
    
    const char *
    KeyNameText(struct xkb_context *ctx, xkb_atom_t name)
    {
        const char *sname = xkb_atom_text(ctx, name);
        size_t len = strlen_safe(sname) + 3;
        char *buf = xkb_context_get_buffer(ctx, len);
        snprintf(buf, len, "<%s>", strempty(sname));
        return buf;
    }
    
    const char *
    SIMatchText(enum xkb_match_operation type)
    {
        return LookupValue(symInterpretMatchMaskNames, type);
    }
    
    const char *
    ModMaskText(struct xkb_context *ctx, enum mod_type type,
                const struct xkb_mod_set *mods, xkb_mod_mask_t mask)
    {
        char buf[1024] = {0};
        size_t pos = 0;
        const struct xkb_mod *mod;
    
        /* We want to avoid boolean blindness, but we expected only 2 values */
        assert(type == MOD_REAL || type == MOD_BOTH);
    
        if (mask == 0)
            return "none";
    
        if (mask == MOD_REAL_MASK_ALL)
            return "all";
    
        if ((type == MOD_REAL && (mask & ~MOD_REAL_MASK_ALL)) ||
            unlikely(mask & ~((UINT64_C(1) << mods->num_mods) - 1))) {
            /* If we get a mask that cannot be expressed with the known modifiers
             * of the given type, print it as hexadecimal */
            const int ret = snprintf(buf, sizeof(buf), "0x%"PRIx32, mask);
            static_assert(sizeof(mask) == 4 && sizeof(buf) >= sizeof("0xffffffff"),
                          "Buffer too small");
            assert(ret >= 0 && (size_t) ret < sizeof(buf));
            pos = (size_t) ret;
        } else {
            /* Print known mods */
            xkb_mods_mask_foreach(mask, mod, mods) {
                int ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
                                   pos == 0 ? "" : "+",
                                   xkb_atom_text(ctx, mod->name));
                if (ret <= 0 || pos + ret >= sizeof(buf))
                    break;
                else
                    pos += ret;
            }
        }
        pos++;
    
        return memcpy(xkb_context_get_buffer(ctx, pos), buf, pos);
    }
    
    const char *
    LedStateMaskText(struct xkb_context *ctx, const LookupEntry *lookup,
                     enum xkb_state_component mask)
    {
        char buf[1024];
        size_t pos = 0;
    
        if (mask == 0)
            return "0";
    
        for (unsigned int i = 0; mask; i++) {
            int ret;
    
            if (!(mask & (1u << i)))
                continue;
    
            mask &= ~(1u << i);
    
            const char* const maskText = LookupValue(lookup, 1u << i);
            assert(maskText != NULL);
            ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
                           pos == 0 ? "" : "+", maskText);
            if (ret <= 0 || pos + ret >= sizeof(buf))
                break;
            else
                pos += ret;
        }
        pos++;
    
        return memcpy(xkb_context_get_buffer(ctx, pos), buf, pos);
    }
    
    const char *
    ControlMaskText(struct xkb_context *ctx, enum xkb_action_controls mask)
    {
        char buf[1024];
        size_t pos = 0;
    
        if (mask == 0)
            return "none";
    
        if (mask == CONTROL_ALL)
            return "all";
    
        for (unsigned int i = 0; mask; i++) {
            int ret;
    
            if (!(mask & (1u << i)))
                continue;
    
            mask &= ~(1u << i);
    
            const char* const maskText = LookupValue(ctrlMaskNames, 1u << i);
            assert(maskText != NULL);
            ret = snprintf(buf + pos, sizeof(buf) - pos, "%s%s",
                           pos == 0 ? "" : "+", maskText);
            if (ret <= 0 || pos + ret >= sizeof(buf))
                break;
            else
                pos += ret;
        }
        pos++;
    
        return memcpy(xkb_context_get_buffer(ctx, pos), buf, pos);
    }