Hash :
a380ba52
        
        Author :
  
        
        Date :
2025-01-25T07:00:43
        
      
Move XKB_EXPORT to headers The Windows dllexport annotation wants to be on the declarations, not the definitions. Signed-off-by: Ran Benita <ran@unusedvar.com>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
/*
 * Copyright © 2013 Ran Benita <ran234@gmail.com>
 * SPDX-License-Identifier: MIT
 */
#include "config.h"
#include "table.h"
#include "utils.h"
#include "keysym.h"
struct xkb_compose_state {
    int refcnt;
    enum xkb_compose_state_flags flags;
    struct xkb_compose_table *table;
    /*
     * Offsets into xkb_compose_table::nodes.
     *
     * They maintain the current and previous position in the trie; see
     * xkb_compose_state_feed().
     *
     * This is also sufficient for inferring the current status; see
     * xkb_compose_state_get_status().
     */
    uint32_t prev_context;
    uint32_t context;
};
struct xkb_compose_state *
xkb_compose_state_new(struct xkb_compose_table *table,
                      enum xkb_compose_state_flags flags)
{
    struct xkb_compose_state *state;
    state = calloc(1, sizeof(*state));
    if (!state)
        return NULL;
    state->refcnt = 1;
    state->table = xkb_compose_table_ref(table);
    state->flags = flags;
    state->prev_context = 0;
    state->context = 0;
    return state;
}
struct xkb_compose_state *
xkb_compose_state_ref(struct xkb_compose_state *state)
{
    state->refcnt++;
    return state;
}
void
xkb_compose_state_unref(struct xkb_compose_state *state)
{
    if (!state || --state->refcnt > 0)
        return;
    xkb_compose_table_unref(state->table);
    free(state);
}
struct xkb_compose_table *
xkb_compose_state_get_compose_table(struct xkb_compose_state *state)
{
    return state->table;
}
enum xkb_compose_feed_result
xkb_compose_state_feed(struct xkb_compose_state *state, xkb_keysym_t keysym)
{
    uint32_t context;
    const struct compose_node *node;
    /*
     * Modifiers do not affect the sequence directly.  In particular,
     * they do not cancel a sequence; otherwise it'd be impossible to
     * have a sequence like <dead_acute><A> (needs Shift in the middle).
     *
     * The following test is not really accurate - in order to test if
     * a key is "modifier key", we really need the keymap, but we don't
     * have it here.  However, this is (approximately) what libX11 does
     * as well.
     */
    if (xkb_keysym_is_modifier(keysym))
        return XKB_COMPOSE_FEED_IGNORED;
    node = &darray_item(state->table->nodes, state->context);
    context = (node->is_leaf ? 1 : node->internal.eqkid);
    if (context == 1 && darray_size(state->table->nodes) == 1)
        context = 0;
    while (context != 0) {
        node = &darray_item(state->table->nodes, context);
        if (keysym < node->keysym)
            context = node->lokid;
        else if (keysym > node->keysym)
            context = node->hikid;
        else
            break;
    }
    state->prev_context = state->context;
    state->context = context;
    return XKB_COMPOSE_FEED_ACCEPTED;
}
void
xkb_compose_state_reset(struct xkb_compose_state *state)
{
    state->prev_context = 0;
    state->context = 0;
}
enum xkb_compose_status
xkb_compose_state_get_status(struct xkb_compose_state *state)
{
    const struct compose_node *prev_node, *node;
    prev_node = &darray_item(state->table->nodes, state->prev_context);
    node = &darray_item(state->table->nodes, state->context);
    if (state->context == 0 && !prev_node->is_leaf)
        return XKB_COMPOSE_CANCELLED;
    if (state->context == 0)
        return XKB_COMPOSE_NOTHING;
    if (!node->is_leaf)
        return XKB_COMPOSE_COMPOSING;
    return XKB_COMPOSE_COMPOSED;
}
int
xkb_compose_state_get_utf8(struct xkb_compose_state *state,
                           char *buffer, size_t size)
{
    const struct compose_node *node =
        &darray_item(state->table->nodes, state->context);
    if (!node->is_leaf)
        goto fail;
    /* If there's no string specified, but only a keysym, try to do the
     * most helpful thing. */
    if (node->leaf.utf8 == 0 && node->leaf.keysym != XKB_KEY_NoSymbol) {
        char utf8[XKB_KEYSYM_UTF8_MAX_SIZE];
        int ret;
        ret = xkb_keysym_to_utf8(node->leaf.keysym, utf8, sizeof(utf8));
        if (ret < 0 || ret == 0) {
            /* ret < 0 is impossible.
             * ret == 0 means the keysym has no string representation. */
            goto fail;
        }
        return snprintf(buffer, size, "%s", utf8);
    }
    return snprintf(buffer, size, "%s",
                    &darray_item(state->table->utf8, node->leaf.utf8));
fail:
    if (size > 0)
        buffer[0] = '\0';
    return 0;
}
xkb_keysym_t
xkb_compose_state_get_one_sym(struct xkb_compose_state *state)
{
    const struct compose_node *node =
        &darray_item(state->table->nodes, state->context);
    if (!node->is_leaf)
        return XKB_KEY_NoSymbol;
    return node->leaf.keysym;
}