X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fkeymap.c;h=c1d5a10b8b5d5801f4dc40cc49d33cd1a9c5ebe7;hb=61deac5607691686c89507dcb57c8fd8214d5fe9;hp=a36a404733efd0d9ccd2f6e8b3814124f56efe56;hpb=d941bc0c03580804169de3d07e6b6e4224b3d254;p=platform%2Fupstream%2Flibxkbcommon.git diff --git a/src/keymap.c b/src/keymap.c index a36a404..c1d5a10 100644 --- a/src/keymap.c +++ b/src/keymap.c @@ -50,29 +50,11 @@ * * ********************************************************/ +#include "config.h" + #include "keymap.h" #include "text.h" -struct xkb_keymap * -xkb_keymap_new(struct xkb_context *ctx, - enum xkb_keymap_format format, - enum xkb_keymap_compile_flags flags) -{ - struct xkb_keymap *keymap; - - keymap = calloc(1, sizeof(*keymap)); - if (!keymap) - return NULL; - - keymap->refcnt = 1; - keymap->ctx = xkb_context_ref(ctx); - - keymap->format = format; - keymap->flags = flags; - - return keymap; -} - XKB_EXPORT struct xkb_keymap * xkb_keymap_ref(struct xkb_keymap *keymap) { @@ -83,28 +65,36 @@ xkb_keymap_ref(struct xkb_keymap *keymap) XKB_EXPORT void xkb_keymap_unref(struct xkb_keymap *keymap) { - unsigned int i; - struct xkb_key *key; - if (!keymap || --keymap->refcnt > 0) return; - for (i = 0; i < keymap->num_types; i++) { - free(keymap->types[i].map); - free(keymap->types[i].level_names); + if (keymap->keys) { + struct xkb_key *key; + xkb_keys_foreach(key, keymap) { + if (key->groups) { + for (unsigned i = 0; i < key->num_groups; i++) { + if (key->groups[i].levels) { + for (unsigned j = 0; j < XkbKeyNumLevels(key, i); j++) + if (key->groups[i].levels[j].num_syms > 1) + free(key->groups[i].levels[j].u.syms); + free(key->groups[i].levels); + } + } + free(key->groups); + } + } + free(keymap->keys); } - free(keymap->types); - darray_foreach(key, keymap->keys) { - free(key->sym_index); - free(key->num_syms); - free(key->syms); - free(key->actions); - free(key->kt_index); + if (keymap->types) { + for (unsigned i = 0; i < keymap->num_types; i++) { + free(keymap->types[i].entries); + free(keymap->types[i].level_names); + } + free(keymap->types); } - darray_free(keymap->keys); - darray_free(keymap->sym_interpret); - darray_free(keymap->key_aliases); - darray_free(keymap->group_names); + free(keymap->sym_interprets); + free(keymap->key_aliases); + free(keymap->group_names); free(keymap->keycodes_section_name); free(keymap->symbols_section_name); free(keymap->types_section_name); @@ -113,21 +103,171 @@ xkb_keymap_unref(struct xkb_keymap *keymap) free(keymap); } +static const struct xkb_keymap_format_ops * +get_keymap_format_ops(enum xkb_keymap_format format) +{ + static const struct xkb_keymap_format_ops *keymap_format_ops[] = { + [XKB_KEYMAP_FORMAT_TEXT_V1] = &text_v1_keymap_format_ops, + }; + + if ((int) format < 0 || (int) format >= (int) ARRAY_SIZE(keymap_format_ops)) + return NULL; + + return keymap_format_ops[(int) format]; +} + +XKB_EXPORT struct xkb_keymap * +xkb_keymap_new_from_names(struct xkb_context *ctx, + const struct xkb_rule_names *rmlvo_in, + enum xkb_keymap_compile_flags flags) +{ + struct xkb_keymap *keymap; + struct xkb_rule_names rmlvo; + const enum xkb_keymap_format format = XKB_KEYMAP_FORMAT_TEXT_V1; + const struct xkb_keymap_format_ops *ops; + + ops = get_keymap_format_ops(format); + if (!ops || !ops->keymap_new_from_names) { + log_err_func(ctx, "unsupported keymap format: %d\n", format); + return NULL; + } + + if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) { + log_err_func(ctx, "unrecognized flags: %#x\n", flags); + return NULL; + } + + keymap = xkb_keymap_new(ctx, format, flags); + if (!keymap) + return NULL; + + if (rmlvo_in) + rmlvo = *rmlvo_in; + else + memset(&rmlvo, 0, sizeof(rmlvo)); + xkb_context_sanitize_rule_names(ctx, &rmlvo); + + if (!ops->keymap_new_from_names(keymap, &rmlvo)) { + xkb_keymap_unref(keymap); + return NULL; + } + + return keymap; +} + +XKB_EXPORT struct xkb_keymap * +xkb_keymap_new_from_string(struct xkb_context *ctx, + const char *string, + enum xkb_keymap_format format, + enum xkb_keymap_compile_flags flags) +{ + return xkb_keymap_new_from_buffer(ctx, string, strlen(string), + format, flags); +} + +XKB_EXPORT struct xkb_keymap * +xkb_keymap_new_from_buffer(struct xkb_context *ctx, + const char *buffer, size_t length, + enum xkb_keymap_format format, + enum xkb_keymap_compile_flags flags) +{ + struct xkb_keymap *keymap; + const struct xkb_keymap_format_ops *ops; + + ops = get_keymap_format_ops(format); + if (!ops || !ops->keymap_new_from_string) { + log_err_func(ctx, "unsupported keymap format: %d\n", format); + return NULL; + } + + if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) { + log_err_func(ctx, "unrecognized flags: %#x\n", flags); + return NULL; + } + + if (!buffer) { + log_err_func1(ctx, "no buffer specified\n"); + return NULL; + } + + keymap = xkb_keymap_new(ctx, format, flags); + if (!keymap) + return NULL; + + /* Allow a zero-terminated string as a buffer */ + if (length > 0 && buffer[length - 1] == '\0') + length--; + + if (!ops->keymap_new_from_string(keymap, buffer, length)) { + xkb_keymap_unref(keymap); + return NULL; + } + + return keymap; +} + +XKB_EXPORT struct xkb_keymap * +xkb_keymap_new_from_file(struct xkb_context *ctx, + FILE *file, + enum xkb_keymap_format format, + enum xkb_keymap_compile_flags flags) +{ + struct xkb_keymap *keymap; + const struct xkb_keymap_format_ops *ops; + + ops = get_keymap_format_ops(format); + if (!ops || !ops->keymap_new_from_file) { + log_err_func(ctx, "unsupported keymap format: %d\n", format); + return NULL; + } + + if (flags & ~(XKB_KEYMAP_COMPILE_NO_FLAGS)) { + log_err_func(ctx, "unrecognized flags: %#x\n", flags); + return NULL; + } + + if (!file) { + log_err_func1(ctx, "no file specified\n"); + return NULL; + } + + keymap = xkb_keymap_new(ctx, format, flags); + if (!keymap) + return NULL; + + if (!ops->keymap_new_from_file(keymap, file)) { + xkb_keymap_unref(keymap); + return NULL; + } + + return keymap; +} + +XKB_EXPORT char * +xkb_keymap_get_as_string(struct xkb_keymap *keymap, + enum xkb_keymap_format format) +{ + const struct xkb_keymap_format_ops *ops; + + if (format == XKB_KEYMAP_USE_ORIGINAL_FORMAT) + format = keymap->format; + + ops = get_keymap_format_ops(format); + if (!ops || !ops->keymap_get_as_string) { + log_err_func(keymap->ctx, "unsupported keymap format: %d\n", format); + return NULL; + } + + return ops->keymap_get_as_string(keymap); +} + /** * Returns the total number of modifiers active in the keymap. */ XKB_EXPORT xkb_mod_index_t xkb_keymap_num_mods(struct xkb_keymap *keymap) { - xkb_mod_index_t i; - - for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) - if (!keymap->vmod_names[i]) - break; - - /* We always have all the core modifiers (for now), plus any virtual - * modifiers we may have defined. */ - return i + XKB_NUM_CORE_MODS; + return keymap->mods.num_mods; } /** @@ -136,19 +276,10 @@ xkb_keymap_num_mods(struct xkb_keymap *keymap) XKB_EXPORT const char * xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx) { - const char *name; - - if (idx >= xkb_keymap_num_mods(keymap)) + if (idx >= keymap->mods.num_mods) return NULL; - /* First try to find a legacy modifier name. If that fails, try to - * find a virtual mod name. */ - name = ModIndexToName(idx); - if (!name) - name = xkb_atom_text(keymap->ctx, - keymap->vmod_names[idx - XKB_NUM_CORE_MODS]); - - return name; + return xkb_atom_text(keymap->ctx, keymap->mods.mods[idx].name); } /** @@ -157,25 +288,13 @@ xkb_keymap_mod_get_name(struct xkb_keymap *keymap, xkb_mod_index_t idx) XKB_EXPORT xkb_mod_index_t xkb_keymap_mod_get_index(struct xkb_keymap *keymap, const char *name) { - xkb_mod_index_t i; xkb_atom_t atom; - i = ModNameToIndex(name); - if (i != XKB_MOD_INVALID) - return i; - atom = xkb_atom_lookup(keymap->ctx, name); if (atom == XKB_ATOM_NONE) return XKB_MOD_INVALID; - for (i = 0; i < XKB_NUM_VIRTUAL_MODS; i++) { - if (keymap->vmod_names[i] == XKB_ATOM_NONE) - break; - if (keymap->vmod_names[i] == atom) - return i + XKB_NUM_CORE_MODS; - } - - return XKB_MOD_INVALID; + return XkbModNameToIndex(&keymap->mods, atom, MOD_BOTH); } /** @@ -193,11 +312,10 @@ xkb_keymap_num_layouts(struct xkb_keymap *keymap) XKB_EXPORT const char * xkb_keymap_layout_get_name(struct xkb_keymap *keymap, xkb_layout_index_t idx) { - if (idx >= xkb_keymap_num_layouts(keymap) || - idx >= darray_size(keymap->group_names)) + if (idx >= keymap->num_group_names) return NULL; - return xkb_atom_text(keymap->ctx, darray_item(keymap->group_names, idx)); + return xkb_atom_text(keymap->ctx, keymap->group_names[idx]); } /** @@ -207,14 +325,13 @@ XKB_EXPORT xkb_layout_index_t xkb_keymap_layout_get_index(struct xkb_keymap *keymap, const char *name) { xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name); - xkb_atom_t *group_name; xkb_layout_index_t i; if (atom == XKB_ATOM_NONE) return XKB_LAYOUT_INVALID; - darray_enumerate(i, group_name, keymap->group_names) - if (*group_name == atom) + for (i = 0; i < keymap->num_group_names; i++) + if (keymap->group_names[i] == atom) return i; return XKB_LAYOUT_INVALID; @@ -246,59 +363,116 @@ xkb_keymap_num_levels_for_key(struct xkb_keymap *keymap, xkb_keycode_t kc, if (!key) return 0; - return XkbKeyGroupWidth(keymap, key, layout); + layout = XkbWrapGroupIntoRange(layout, key->num_groups, + key->out_of_range_group_action, + key->out_of_range_group_number); + if (layout == XKB_LAYOUT_INVALID) + return 0; + + return XkbKeyNumLevels(key, layout); } /** - * Return the total number of active LEDs in the keymap. + * Return the total number of LEDs in the keymap. */ XKB_EXPORT xkb_led_index_t xkb_keymap_num_leds(struct xkb_keymap *keymap) { - xkb_led_index_t ret = 0; - xkb_led_index_t i; - - for (i = 0; i < XKB_NUM_INDICATORS; i++) - if (keymap->indicators[i].which_groups || - keymap->indicators[i].which_mods || - keymap->indicators[i].ctrls) - ret++; - - return ret; + return keymap->num_leds; } /** - * Returns the name for a given group. + * Returns the name for a given LED. */ XKB_EXPORT const char * xkb_keymap_led_get_name(struct xkb_keymap *keymap, xkb_led_index_t idx) { - if (idx >= xkb_keymap_num_leds(keymap)) + if (idx >= keymap->num_leds) return NULL; - return xkb_atom_text(keymap->ctx, keymap->indicators[idx].name); + return xkb_atom_text(keymap->ctx, keymap->leds[idx].name); } /** - * Returns the index for a named group. + * Returns the index for a named LED. */ -XKB_EXPORT xkb_layout_index_t +XKB_EXPORT xkb_led_index_t xkb_keymap_led_get_index(struct xkb_keymap *keymap, const char *name) { - xkb_led_index_t num_leds = xkb_keymap_num_leds(keymap); xkb_atom_t atom = xkb_atom_lookup(keymap->ctx, name); xkb_led_index_t i; + const struct xkb_led *led; if (atom == XKB_ATOM_NONE) return XKB_LED_INVALID; - for (i = 0; i < num_leds; i++) - if (keymap->indicators[i].name == atom) + xkb_leds_enumerate(i, led, keymap) + if (led->name == atom) return i; return XKB_LED_INVALID; } +XKB_EXPORT size_t +xkb_keymap_key_get_mods_for_level(struct xkb_keymap *keymap, + xkb_keycode_t kc, + xkb_layout_index_t layout, + xkb_level_index_t level, + xkb_mod_mask_t *masks_out, + size_t masks_size) +{ + const struct xkb_key *key = XkbKey(keymap, kc); + if (!key) + return 0; + + layout = XkbWrapGroupIntoRange(layout, key->num_groups, + key->out_of_range_group_action, + key->out_of_range_group_number); + if (layout == XKB_LAYOUT_INVALID) + return 0; + + if (level >= XkbKeyNumLevels(key, layout)) + return 0; + + const struct xkb_key_type *type = key->groups[layout].type; + + size_t count = 0; + + /* + * If the active set of modifiers doesn't match any explicit entry of + * the key type, the resulting level is 0 (i.e. Level 1). + * So, if we are asked to find the modifiers for level==0, we can offer + * an ~infinite supply, which is not very workable. + * What we do instead, is special case the empty set of modifiers for + * this purpose. If the empty set isn't explicit mapped to a level, we + * take it to map to Level 1. + * This is almost always what we want. If applicable, given it priority + * over other ways to generate the level. + */ + if (level == 0) { + bool empty_mapped = false; + for (unsigned i = 0; i < type->num_entries && count < masks_size; i++) + if (entry_is_active(&type->entries[i]) && + type->entries[i].mods.mask == 0) { + empty_mapped = true; + break; + } + if (!empty_mapped && count < masks_size) { + masks_out[count++] = 0; + } + } + + /* Now search explicit mappings. */ + for (unsigned i = 0; i < type->num_entries && count < masks_size; i++) { + if (entry_is_active(&type->entries[i]) && + type->entries[i].level == level) { + masks_out[count++] = type->entries[i].mods.mask; + } + } + + return count; +} + /** * As below, but takes an explicit layout/level rather than state. */ @@ -314,16 +488,25 @@ xkb_keymap_key_get_syms_by_level(struct xkb_keymap *keymap, if (!key) goto err; - if (layout >= key->num_groups) + + layout = XkbWrapGroupIntoRange(layout, key->num_groups, + key->out_of_range_group_action, + key->out_of_range_group_number); + if (layout == XKB_LAYOUT_INVALID) goto err; - if (level >= XkbKeyGroupWidth(keymap, key, layout)) + + if (level >= XkbKeyNumLevels(key, layout)) goto err; - num_syms = XkbKeyNumSyms(key, layout, level); + num_syms = key->groups[layout].levels[level].num_syms; if (num_syms == 0) goto err; - *syms_out = XkbKeySymEntry(key, layout, level); + if (num_syms == 1) + *syms_out = &key->groups[layout].levels[level].u.sym; + else + *syms_out = key->groups[layout].levels[level].u.syms; + return num_syms; err: @@ -331,6 +514,62 @@ err: return 0; } +XKB_EXPORT xkb_keycode_t +xkb_keymap_min_keycode(struct xkb_keymap *keymap) +{ + return keymap->min_key_code; +} + +XKB_EXPORT xkb_keycode_t +xkb_keymap_max_keycode(struct xkb_keymap *keymap) +{ + return keymap->max_key_code; +} + +XKB_EXPORT void +xkb_keymap_key_for_each(struct xkb_keymap *keymap, xkb_keymap_key_iter_t iter, + void *data) +{ + struct xkb_key *key; + + xkb_keys_foreach(key, keymap) + iter(keymap, key->keycode, data); +} + +XKB_EXPORT const char * +xkb_keymap_key_get_name(struct xkb_keymap *keymap, xkb_keycode_t kc) +{ + const struct xkb_key *key = XkbKey(keymap, kc); + + if (!key) + return NULL; + + return xkb_atom_text(keymap->ctx, key->name); +} + +XKB_EXPORT xkb_keycode_t +xkb_keymap_key_by_name(struct xkb_keymap *keymap, const char *name) +{ + struct xkb_key *key; + xkb_atom_t atom; + + atom = xkb_atom_lookup(keymap->ctx, name); + if (atom) { + xkb_atom_t ratom = XkbResolveKeyAlias(keymap, atom); + if (ratom) + atom = ratom; + } + if (!atom) + return XKB_KEYCODE_INVALID; + + xkb_keys_foreach(key, keymap) { + if (key->name == atom) + return key->keycode; + } + + return XKB_KEYCODE_INVALID; +} + /** * Simple boolean specifying whether or not the key should repeat. */ @@ -344,3 +583,17 @@ xkb_keymap_key_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc) return key->repeats; } + +XKB_EXPORT int +xkb_keymap_key_set_repeats(struct xkb_keymap *keymap, xkb_keycode_t kc, int enable) +{ + struct xkb_key *key = (struct xkb_key *)XkbKey(keymap, kc); + + if (!key) + return 0; + + key->repeats = !!enable; + key->explicit |= EXPLICIT_REPEAT; + + return 1; +}