[PATCH libxkbcommon 1/4] compose: add xkbcommon-compose - API

Ran Benita ran234 at gmail.com
Sun Sep 14 14:05:40 PDT 2014


xkbcommon-compose is a Compose implementation for xkbcommon. It mostly
behaves like libX11's Compose, but the support is somewhat low-level and
is not transparent like in libX11. The user must add some supporting code
in order to utilize it.

The intended audience are users who use xkbcommon but not a full-blown
input method. With this they can add Compose support in a straightforward
manner, so they have a fairly complete keyboard input for Latin-like
languages at least.

See the header documentation for details.

Signed-off-by: Ran Benita <ran234 at gmail.com>
---
 xkbcommon/xkbcommon-compose.h | 457 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 457 insertions(+)
 create mode 100644 xkbcommon/xkbcommon-compose.h

diff --git a/xkbcommon/xkbcommon-compose.h b/xkbcommon/xkbcommon-compose.h
new file mode 100644
index 0000000..ed35250
--- /dev/null
+++ b/xkbcommon/xkbcommon-compose.h
@@ -0,0 +1,457 @@
+/*
+ * Copyright © 2013 Ran Benita
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _XKBCOMMON_COMPOSE_H
+#define _XKBCOMMON_COMPOSE_H
+
+#include <xkbcommon/xkbcommon.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * libxkbcommon Compose API - support for Compose and dead-keys.
+ */
+
+/**
+ * @defgroup compose Compose and dead-keys support
+ * Support for Compose and dead-keys.
+ * @since TBD
+ *
+ * @{
+ */
+
+/**
+ * @page compose-overview Overview
+ * @parblock
+ *
+ * Compose and dead-keys are a common feature of many keyboard input
+ * systems.  They extend the range of the keysysm that can be produced
+ * directly from a keyboard by using a sequence of key strokes, instead
+ * of just one.
+ *
+ * Here are some example sequences, in the libX11 Compose file format:
+ *
+ *     <dead_acute> <a>         : "á"   aacute # LATIN SMALL LETTER A WITH ACUTE
+ *     <Multi_key> <A> <T>      : "@"   at # COMMERCIAL AT
+ *
+ * When the user presses a key which produces the \<dead_acute> keysym,
+ * nothing initially happens (thus the key is dubbed a "dead-key").  But
+ * when the user enters <a>, "á" is "composed", in place of "a".  If
+ * instead the user had entered a keysym which does not follow
+ * \<dead_acute\> in any compose sequence, the sequence is said to be
+ * "cancelled".
+ *
+ * Compose files define many such sequences.  For a description of the
+ * common file format for Compose files, see the Compose(5) man page.
+ *
+ * A successfuly-composed sequence has two results: a keysym and a UTF-8
+ * string.  At least one of the two is defined for each sequence.  If only
+ * a keysym is given, the keysym's string representation is used for the
+ * result string (using xkb_keysym_to_utf8()).
+ *
+ * This library provides low-level support for Compose file parsing and
+ * processing.  Higher-level APIs (such as libX11's Xutf8LookupString(3))
+ * may be built upon it, or it can be used directly.
+ *
+ * @endparblock
+ */
+
+/**
+ * @page compose-conflicting Conflicting Sequences
+ * @parblock
+ *
+ * To avoid ambiguity, a sequence is not allowed to be a prefix of another.
+ * In such a case, the conflict is resolved thus:
+ *
+ * 1. A longer sequence overrides a shorter one.
+ * 2. An equal sequence overrides an existing one.
+ * 3. A shorter sequence does not override a longer one.
+ *
+ * Sequences of length 1 are allowed, although they are not common.
+ *
+ * @endparblock
+ */
+
+/**
+ * @page compose-cancellation Cancellation Behavior
+ * @parblock
+ *
+ * What should happen when a sequence is cancelled?  For example, consider
+ * there are only the above sequences, and the input kesysms are
+ * \<dead_acute\> \<b\>.  There are a few approaches:
+ *
+ * 1. Swallow the cancelling keysym; that is, no keysym is produced.
+ *    This is the approach taken by libX11.
+ * 2. Let the cancelling keysym through; that is, \<b\> is produced.
+ * 3. Replay the entire sequence; that is, \<dead_acute\> \<b\> is produced.
+ *    This is the approach taken by Microsoft Windows (approximately;
+ *    instead of \<dead_acute\>, the underlying key is used.  This is
+ *    difficult to simulate with XKB keymaps).
+ *
+ * You can program whichever approach best fits users' expectations.
+ *
+ * @endparblock
+ */
+
+/**
+ * @struct xkb_compose_table
+ * Opaque Compose table object.
+ *
+ * The compose table holds the definitions of the Compose sequences, as
+ * gathered from Compose files.  It is immutable.
+ */
+struct xkb_compose_table;
+
+/**
+ * @struct xkb_compose_state
+ * Opaque Compose state object.
+ *
+ * The compose state maintains state for compose sequence matching, such
+ * as which possible sequences are being matched, and the position within
+ * these sequences.  It acts as a simple state machine wherein keysyms are
+ * the input, and composed keysyms and strings are the output.
+ *
+ * The compose state is usually associated with a keyboard device.
+ */
+struct xkb_compose_state;
+
+/** Flags affecting Compose file compilation. */
+enum xkb_compose_compile_flags {
+    /** Do not apply any flags. */
+    XKB_COMPOSE_COMPILE_NO_FLAGS = 0
+};
+
+/** The recognized Compose file formats. */
+enum xkb_compose_format {
+    /** The classic libX11 Compose text format, described in Compose(5). */
+    XKB_COMPOSE_FORMAT_TEXT_V1 = 1
+};
+
+/**
+ * @page compose-locale Compose Locale
+ * @parblock
+ *
+ * Compose files are locale dependent:
+ * - Compose files are written for a locale, and the locale is used when
+ *   searching for the appropriate file to use.
+ * - Compose files may reference the locale internally, with directives
+ *   such as %L.
+ * As such, functions like xkb_compose_table_new_from_locale() require
+ * a @p locale parameter.  This will usually be the current locale (see
+ * locale(7) for more details).  You may also want to allow the user to
+ * explicitly configure it, so he can use the Compose file of a given
+ * locale, but not use that locale for other things.
+ *
+ * You may query the current locale as follows:
+ * @code
+ *     const char *locale;
+ *     locale = setlocale(LC_CTYPE, NULL);
+ * @endcode
+ *
+ * This will only give useful results if the program had previously set
+ * the current locale using setlocale(3), with LC_CTYPE or LC_ALL and a
+ * non-NULL argument.
+ *
+ * If you prefer not to use the locale system of the C runtime library,
+ * you may nevertheless obtain the user's locale directly using
+ * environment variables, as described in locale(7).  For example,
+ * @code
+ *     locale = getenv("LC_ALL");
+ *     if (!locale)
+ *         locale = getenv("LC_CTYPE");
+ *     if (!locale)
+ *         locale = getenv("LANG");
+ *     if (!locale)
+ *         locale = "C";
+ * @endcode
+ *
+ * Note that some locales supported by the C standard library may not
+ * have a Compose file assigned.
+ *
+ * @endparblock
+ */
+
+/**
+ * Create a compose table for a given locale.
+ *
+ * The locale is used for searching the file-system for an appropriate
+ * Compose file.  The search order is described in Compose(5).  It is
+ * affected by the following environment variables:
+ * XCOMPOSEFILE, HOME, XLOCALEDIR.
+ *
+ * @param context
+ *     The library context in which to create the compose table.
+ * @param locale
+ *     The current locale.  See @ref compose-locale.
+ * @param flags
+ *     Optional flags for the compose table, or 0.
+ *
+ * @returns A compose table for the given locale, or NULL if the
+ * compilation failed or a Compose file was not found.
+ *
+ * @memberof xkb_compose_table
+ */
+struct xkb_compose_table *
+xkb_compose_table_new_from_locale(struct xkb_context *context,
+                                  const char *locale,
+                                  enum xkb_compose_compile_flags flags);
+
+/**
+ * Create a new compose table from a Compose file.
+ *
+ * @param context
+ *     The library context in which to create the compose table.
+ * @param file
+ *     The Compose file to compile.
+ * @param locale
+ *     The current locale.  See @ref compose-locale.
+ * @param format
+ *     The text format of the Compose file to compile.
+ * @param flags
+ *     Optional flags for the compose table, or 0.
+ *
+ * @returns A compose table compiled from the given file, or NULL if
+ * the compilation failed.
+ *
+ * @memberof xkb_compose_table
+ */
+struct xkb_compose_table *
+xkb_compose_table_new_from_file(struct xkb_context *context,
+                                FILE *file,
+                                const char *locale,
+                                enum xkb_compose_format format,
+                                enum xkb_compose_compile_flags flags);
+
+/**
+ * Create a new compose table from a memory buffer.
+ *
+ * This is just like xkb_compose_table_new_from_file(), but instead of
+ * a file, gets the table as one enormous string.
+ *
+ * @see xkb_compose_table_new_from_file()
+ * @memberof xkb_compose_table
+ */
+struct xkb_compose_table *
+xkb_compose_table_new_from_buffer(struct xkb_context *context,
+                                  const char *buffer, size_t length,
+                                  const char *locale,
+                                  enum xkb_compose_format format,
+                                  enum xkb_compose_compile_flags flags);
+
+/**
+ * Take a new reference on a compose table.
+ *
+ * @returns The passed in object.
+ *
+ * @memberof xkb_compose_table
+ */
+struct xkb_compose_table *
+xkb_compose_table_ref(struct xkb_compose_table *table);
+
+/**
+ * Release a reference on a compose table, and possibly free it.
+ *
+ * @param table The object.  If it is NULL, this function does nothing.
+ *
+ * @memberof xkb_compose_table
+ */
+void
+xkb_compose_table_unref(struct xkb_compose_table *table);
+
+/** Flags for compose state creation. */
+enum xkb_compose_state_flags {
+    /** Do not apply any flags. */
+    XKB_COMPOSE_STATE_NO_FLAGS = 0
+};
+
+/**
+ * Create a new compose state object.
+ *
+ * @param table
+ *     The compose table the state will use.
+ * @param flags
+ *     Optional flags for the compose state, or 0.
+ *
+ * @returns A new compose state, or NULL on failure.
+ *
+ * @memberof xkb_compose_state
+ */
+struct xkb_compose_state *
+xkb_compose_state_new(struct xkb_compose_table *table,
+                      enum xkb_compose_state_flags flags);
+
+/**
+ * Take a new reference on a compose state object.
+ *
+ * @returns The passed in object.
+ *
+ * @memberof xkb_compose_state
+ */
+struct xkb_compose_state *
+xkb_compose_state_ref(struct xkb_compose_state *state);
+
+/**
+ * Release a reference on a compose state object, and possibly free it.
+ *
+ * @param state The object.  If NULL, do nothing.
+ *
+ * @memberof xkb_compose_state
+ */
+void
+xkb_compose_state_unref(struct xkb_compose_state *state);
+
+/**
+ * Get the compose table which a compose state object is using.
+ *
+ * @returns The compose table which was passed to xkb_compose_state_new()
+ * when creating this state object.
+ *
+ * This function does not take a new reference on the compose table; you
+ * must explicitly reference it yourself if you plan to use it beyond the
+ * lifetime of the state.
+ *
+ * @memberof xkb_compose_state
+ */
+struct xkb_compose_table *
+xkb_compose_state_get_compose_table(struct xkb_compose_state *state);
+
+/** Status of the Compose sequence state machine. */
+enum xkb_compose_status {
+    /** The initial state; no sequence has started yet. */
+    XKB_COMPOSE_NOTHING,
+    /** In the middle of a sequence. */
+    XKB_COMPOSE_COMPOSING,
+    /** A complete sequence has been matched. */
+    XKB_COMPOSE_COMPOSED,
+    /** The last sequence was cancelled due to an invalid keysym. */
+    XKB_COMPOSE_CANCELLED
+};
+
+/** The effect of a keysym fed to xkb_compose_state_feed(). */
+enum xkb_compose_feed_result {
+    /** The keysym had no effect. */
+    XKB_COMPOSE_FEED_IGNORED,
+    /** The keysym started, advanced or cancelled a sequence. */
+    XKB_COMPOSE_FEED_ACCEPTED
+};
+
+/**
+ * Feed one keysym to the Compose sequence state machine.
+ *
+ * This function advances into a compose sequence, cancels it, or has no
+ * effect (e.g. for modifier keysyms).  The resulting status may be
+ * observed with xkb_compose_state_get_status().
+ *
+ * @param state
+ *     The compose state object.
+ * @param keysym
+ *     A keysym, usually obtained after a key-press event, with a
+ *     function such as xkb_state_key_get_one_sym().
+ *
+ * @returns Whether the keysym had any effect on the compose state.  This
+ * is useful, for example, if you want to keep a record of the current
+ * sequence, but not for much else.
+ *
+ * @memberof xkb_compose_state
+ */
+enum xkb_compose_feed_result
+xkb_compose_state_feed(struct xkb_compose_state *state,
+                       xkb_keysym_t keysym);
+
+/**
+ * Reset the Compose sequence state machine.
+ *
+ * The status is set to XKB_COMPOSE_NOTHING, and the current sequence
+ * is discarded.
+ *
+ * @memberof xkb_compose_state
+ */
+void
+xkb_compose_state_reset(struct xkb_compose_state *state);
+
+/**
+ * Get the current status of the compose state machine.
+ *
+ * @see xkb_compose_status
+ * @memberof xkb_compose_state
+ **/
+enum xkb_compose_status
+xkb_compose_state_get_status(struct xkb_compose_state *state);
+
+/**
+ * Get the result Unicode/UTF-8 string for a composed sequence.
+ *
+ * See @ref compose-overview for more details.  This function is only
+ * useful when the status is XKB_COMPOSE_COMPOSED.
+ *
+ * @param[in] state
+ *     The compose state.
+ * @param[out] buffer
+ *     A buffer to write the string into.
+ * @param[in] size
+ *     Size of the buffer.
+ *
+ * @warning If the buffer passed is too small, the string is truncated
+ * (though still NUL-terminated).
+ *
+ * @returns
+ *   The number of bytes required for the string, excluding the NUL byte.
+ *   If the sequence is not complete, or does not have a viable result
+ *   string, returns 0, and sets @p buffer to the empty string (if
+ *   possible).
+ * @returns
+ *   You may check if truncation has occurred by comparing the return value
+ *   with the size of @p buffer, similarly to the snprintf(3) function.
+ *   You may safely pass NULL and 0 to @p buffer and @p size to find the
+ *   required size (without the NUL-byte).
+ *
+ * @memberof xkb_compose_state
+ **/
+int
+xkb_compose_state_get_utf8(struct xkb_compose_state *state,
+                           char *buffer, size_t size);
+
+/**
+ * Get the result keysym for a composed sequence.
+ *
+ * See @ref compose-overview for more details.  This function is only
+ * useful when the status is XKB_COMPOSE_COMPOSED.
+ *
+ * @returns The result keysym.  If the sequence is not complete, or does
+ * not specify a result keysym, returns XKB_KEY_NoSymbol.
+ *
+ * @memberof xkb_compose_state
+ **/
+xkb_keysym_t
+xkb_compose_state_get_one_sym(struct xkb_compose_state *state);
+
+/** @} */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _XKBCOMMON_COMPOSE_H */
-- 
2.1.0



More information about the wayland-devel mailing list