]> git.sur5r.net Git - i3/i3lock/commitdiff
Add support for Compose and dead-keys with libxkbcommon
authorDaniel Otero <otero.o.daniel@gmail.com>
Wed, 11 Feb 2015 23:37:23 +0000 (00:37 +0100)
committerDaniel Otero <otero.o.daniel@gmail.com>
Wed, 11 Feb 2015 23:37:23 +0000 (00:37 +0100)
README.md
i3lock.c

index b587c277183234996f51c5f296617e2480cba3de..6965a38740c836b02bb25f0dbc998baf3624e3a8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -29,8 +29,8 @@ Requirements
 - libx11-dev
 - libx11-xcb-dev
 - libxkbfile-dev
-- libxkbcommon >= 0.4.0
-- libxkbcommon-x11 >= 0.4.0
+- libxkbcommon >= 0.5.0
+- libxkbcommon-x11 >= 0.5.0
 
 Running i3lock
 -------------
index 942781a82e0bd285e50da5b55303601de47c2a58..02e67940abf9ba1b7904e31aba86189535e02c99 100644 (file)
--- a/i3lock.c
+++ b/i3lock.c
@@ -25,6 +25,7 @@
 #include <ev.h>
 #include <sys/mman.h>
 #include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-compose.h>
 #include <xkbcommon/xkbcommon-x11.h>
 #include <cairo.h>
 #include <cairo/cairo-xcb.h>
@@ -72,6 +73,8 @@ bool show_failed_attempts = false;
 static struct xkb_state *xkb_state;
 static struct xkb_context *xkb_context;
 static struct xkb_keymap *xkb_keymap;
+static struct xkb_compose_table *xkb_compose_table;
+static struct xkb_compose_state *xkb_compose_state;
 static uint8_t xkb_base_event;
 static uint8_t xkb_base_error;
 
@@ -137,6 +140,37 @@ static bool load_keymap(void) {
     return true;
 }
 
+/*
+ * Loads the XKB compose table from the given locale.
+ *
+ */
+static bool load_compose_table(const char *locale) {
+    if (xkb_context == NULL) {
+        if ((xkb_context = xkb_context_new(0)) == NULL) {
+            fprintf(stderr, "[i3lock] could not create xkbcommon context\n");
+            return false;
+        }
+    }
+
+    xkb_compose_table_unref(xkb_compose_table);
+
+    if ((xkb_compose_table = xkb_compose_table_new_from_locale(xkb_context, locale, 0)) == NULL) {
+        fprintf(stderr, "[i3lock] xkb_compose_table_new_from_locale failed\n");
+        return false;
+    }
+
+    struct xkb_compose_state *new_compose_state = xkb_compose_state_new(xkb_compose_table, 0);
+    if (new_compose_state == NULL) {
+        fprintf(stderr, "[i3lock] xkb_compose_state_new failed\n");
+        return false;
+    }
+
+    xkb_compose_state_unref(xkb_compose_state);
+    xkb_compose_state = new_compose_state;
+
+    return true;
+}
+
 /*
  * Clears the memory which stored the password to be a bit safer against
  * cold-boot attacks.
@@ -289,13 +323,36 @@ static void handle_key_press(xcb_key_press_event_t *event) {
     char buffer[128];
     int n;
     bool ctrl;
+    bool composed = false;
 
     ksym = xkb_state_key_get_one_sym(xkb_state, event->detail);
     ctrl = xkb_state_mod_name_is_active(xkb_state, "Control", XKB_STATE_MODS_DEPRESSED);
 
     /* The buffer will be null-terminated, so n >= 2 for 1 actual character. */
     memset(buffer, '\0', sizeof(buffer));
-    n = xkb_keysym_to_utf8(ksym, buffer, sizeof(buffer));
+
+    if (xkb_compose_state && xkb_compose_state_feed(xkb_compose_state, ksym) == XKB_COMPOSE_FEED_ACCEPTED) {
+        switch (xkb_compose_state_get_status(xkb_compose_state)) {
+        case XKB_COMPOSE_NOTHING:
+            break;
+        case XKB_COMPOSE_COMPOSING:
+            return;
+        case XKB_COMPOSE_COMPOSED:
+            /* xkb_compose_state_get_utf8 doesn't include the terminating byte in the return value
+             * as xkb_keysym_to_utf8 does. Adding one makes the variable n consistent. */
+            n = xkb_compose_state_get_utf8(xkb_compose_state, buffer, sizeof(buffer)) + 1;
+            //ksym = xkb_compose_state_get_one_sym(xkb_compose_state); // Not sure if it's needed
+            composed = true;
+            break;
+        case XKB_COMPOSE_CANCELLED:
+            xkb_compose_state_reset(xkb_compose_state);
+            break;
+        }
+    }
+
+    if (!composed) {
+        n = xkb_keysym_to_utf8(ksym, buffer, sizeof(buffer));
+    }
 
     switch (ksym) {
     case XKB_KEY_Return:
@@ -824,6 +881,19 @@ int main(int argc, char *argv[]) {
     if (!load_keymap())
         errx(EXIT_FAILURE, "Could not load keymap");
 
+    const char *locale = getenv("LC_ALL");
+    if (!locale)
+        locale = getenv("LC_CTYPE");
+    if (!locale)
+        locale = getenv("LANG");
+    if (!locale) {
+        if (debug_mode)
+            fprintf(stderr, "Can't detect your locale, fallback to C\n");
+        locale = "C";
+    }
+
+    load_compose_table(locale);
+
     xinerama_init();
     xinerama_query_screens();