trying to use keyboard stuff better to get stuff in the menu for the current effectiv...
authorDana Jansens <danakj@orodu.net>
Tue, 9 Feb 2010 22:29:13 +0000 (17:29 -0500)
committerDana Jansens <danakj@orodu.net>
Wed, 10 Feb 2010 15:04:29 +0000 (10:04 -0500)
obt/display.h
obt/keyboard.c
obt/keyboard.h
openbox/event.c
openbox/menuframe.c

index ff20f9c92b8c5f8dabcfc7edf2c444167f5790e4..7a0329ad498f03e626520721331cc29af43f0396 100644 (file)
@@ -56,6 +56,8 @@ extern gint     obt_display_extension_sync_basep;
 
 extern Display* obt_display;
 
+/*! Open the X display.  You should call g_set_prgname() before calling this
+  function for X Input Methods to work correctly */
 gboolean obt_display_open(const char *display_name);
 void     obt_display_close(void);
 
index a1d182834c0c57289dc30a3ae21890df25435c00..738888ef10d7d68da2d34df0134cb1c2097b934b 100644 (file)
@@ -49,13 +49,70 @@ static gboolean hyper_l = FALSE;
 
 static gboolean started = FALSE;
 
+static XIM xim = NULL;
+static XIMStyle xim_style = 0;
+static XIC xic = NULL;
+static Window xic_window = None;
+
 void obt_keyboard_reload(void)
 {
     gint i, j, k;
+    gchar *aname, *aclass;
+    gchar firstc[7];
 
     if (started) obt_keyboard_shutdown(); /* free stuff */
     started = TRUE;
 
+    /* initialize the Input Method */
+
+    aname = g_strdup(g_get_prgname());
+    if (!aname) aname = g_strdup("obt");
+
+    /* capitalize first letter of the class */
+    i = g_unichar_to_utf8(g_unichar_toupper(g_utf8_get_char(aname)),
+                          firstc);
+    firstc[i] = '\0';
+    aclass = g_strdup_printf("%s%s", firstc, g_utf8_next_char(aname));
+
+    g_print("Opening Input Method for %s %s\n", aname, aclass);
+    xim = XOpenIM(obt_display, NULL, aname, aclass);
+
+    g_free(aclass);
+    g_free(aname);
+
+    if (!xim)
+        g_message("Failed to open an Input Method");
+    else {
+        XIMStyles *xim_styles = NULL;
+        char *r;
+
+        /* get the input method styles */
+        r = XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL);
+        if (r || !xim_styles)
+            g_message("Input Method does not support any styles");
+        if (xim_styles) {
+            /* pick a style that doesnt need preedit or status */
+            for (i = 0; i < xim_styles->count_styles; ++i) {
+                if (xim_styles->supported_styles[i] == 
+                    (XIMPreeditNothing | XIMStatusNothing))
+                {
+                    xim_style = xim_styles->supported_styles[i];
+                    break;
+                }
+            }
+            XFree(xim_styles);
+        }
+
+        if (!xim_style)
+            g_message("Input Method does not support a usable style");
+        else if (xic_window)
+            xic = XCreateIC(xim,
+                            XNInputStyle, xim_style,
+                            XNClientWindow, xic_window,
+                            XNFocusWindow, xic_window,
+                            NULL);
+    }
+
     /* reset the keys to not be bound to any masks */
     for (i = 0; i < OBT_KEYBOARD_NUM_MODKEYS; ++i)
         modkeys_keys[i] = 0;
@@ -64,7 +121,6 @@ void obt_keyboard_reload(void)
     /* note: modmap->max_keypermod can be 0 when there is no valid key layout
        available */
 
-
     XDisplayKeycodes(obt_display, &min_keycode, &max_keycode);
     keymap = XGetKeyboardMapping(obt_display, min_keycode,
                                  max_keycode - min_keycode + 1,
@@ -105,6 +161,11 @@ void obt_keyboard_shutdown(void)
     modmap = NULL;
     XFree(keymap);
     keymap = NULL;
+    if (xic) XDestroyIC(xic);
+    xic = NULL;
+    if (xim) XCloseIM(xim);
+    xim = NULL;
+    xim_style = 0;
     started = FALSE;
 }
 
@@ -207,21 +268,79 @@ KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym)
     return ret;
 }
 
-gchar *obt_keyboard_keycode_to_string(guint keycode)
+void obt_keyboard_set_input_context(Window window)
 {
-    KeySym sym;
+    if (xic) {
+        XDestroyIC(xic);
+        xic = NULL;
+    }
+    xic_window = window;
+    if (xic_window)
+        xic = XCreateIC(xim,
+                        XNInputStyle, xim_style,
+                        XNClientWindow, xic_window,
+                        XNFocusWindow, xic_window,
+                        NULL);
+    g_message("Created Input Context (0x%x) for window 0x%x\n",
+              xic, xic_window);
+}
 
-    if ((sym = XKeycodeToKeysym(obt_display, keycode, 0)) != NoSymbol)
+gchar *obt_keyboard_keypress_to_string(XKeyPressedEvent *ev)
+{
+    KeySym sym;
+    int ret;
+    Status status;
+    gchar *buf;
+
+    if (xic) {
+#ifdef X_HAVE_UTF8_STRING
+        ret = Xutf8LookupString(xic, ev, buf, 0, &sym, &status);
+#else
+        ret = XmbLookupString(xic, ev, buf, 0, &sym, &status);
+#endif
+        if (status == XBufferOverflow) {
+            g_message("bufferoverflow");
+            buf = g_malloc(ret+1);
+            buf[ret] = '\0';
+#ifdef X_HAVE_UTF8_STRING
+            ret = Xutf8LookupString(xic, ev, buf, ret+1, &sym, &status);
+            g_message("bufferoverflow read %d bytes", ret);
+#else
+            ret = XmbLookupString(xic, ev, buf, ret+1, &sym, &status);
+#endif
+            if (status == XLookupChars || status == XLookupBoth) {
+#ifndef X_HAVE_UTF8_STRING 
+                gchar *buf2 = buf;
+                buf = g_locale_to_utf8(buf2, -1, NULL, NULL, NULL);
+                g_free(buf2);
+#endif
+               return buf;
+            }
+        }
+        else if (status == XLookupKeySym)
+            return g_locale_to_utf8(XKeysymToString(sym), -1,
+                                    NULL, NULL, NULL);
+    }
+    
+    buf = g_malloc(2);
+    buf[1] = '\0';
+    ret = XLookupString(ev, buf, 1, &sym, NULL);
+    if (ret)
+        return buf;
+
+    g_free(buf);
+    if (sym != NoSymbol)
         return g_locale_to_utf8(XKeysymToString(sym), -1, NULL, NULL, NULL);
+
     return NULL;
 }
 
-gunichar obt_keyboard_keycode_to_unichar(guint keycode)
+gunichar obt_keyboard_keypress_to_unichar(XKeyPressedEvent *ev)
 {
     gunichar unikey = 0;
     char *key;
 
-    if ((key = obt_keyboard_keycode_to_string(keycode)) != NULL &&
+    if ((key = obt_keyboard_keypress_to_string(ev)) != NULL &&
         /* don't accept keys that aren't a single letter, like "space" */
         key[1] == '\0')
     {
index 4fb60186fb2491f2542ca31b8ca4916d81a04c00..ae9f997128ddd8236123a9d8d8f60dc6c15502ec 100644 (file)
@@ -57,11 +57,18 @@ guint obt_keyboard_modkey_to_modmask(ObtModkeysKey key);
 /*! Convert a KeySym to all the KeyCodes which generate it. */
 KeyCode* obt_keyboard_keysym_to_keycode(KeySym sym);
 
-/*! Give the string form of a KeyCode */
-gchar *obt_keyboard_keycode_to_string(guint keycode);
+/*! Set the input context to be the given window.  This must be called
+  before using obt_keyboard_keycode_to_unichar() and
+  obt_keyboard_keycode_to_string().
+  @window The window where input focus is (logically).  Can be None.
+*/
+void obt_keyboard_set_input_context(Window window);
+
+/*! Give the string form of a KeyPressEvent */
+gchar *obt_keyboard_keypress_to_string(XKeyPressedEvent *ev);
 
-/*! Translate a KeyCode to the unicode character it represents */
-gunichar obt_keyboard_keycode_to_unichar(guint keycode);
+/*! Translate a KeyPressEvent to the unicode character it represents */
+gunichar obt_keyboard_keypress_to_unichar(XKeyPressedEvent *ev);
 
 
 G_END_DECLS
index b2f9be4eca9d34e2863ef83a933f92e8fa7768f0..da7771e36bf4a94cd2fff536a881f204d4a0107b 100644 (file)
@@ -665,6 +665,18 @@ static void event_process(const XEvent *ec, gpointer data)
             if (((XkbStateNotifyEvent*)e)->changed & XkbGroupStateMask)
                 ob_reconfigure_keyboard();
 
+            {
+                //XkbDescPtr kbd;
+                XkbStateRec state;
+
+                //kbd = XkbAllocKeyboard();
+                XkbGetState(obt_display, XkbUseCoreKbd, &state);
+                g_print("effective group: %d\n", state.group);
+                g_print("base group: %d\n", state.base_group);
+
+                //XkbFreeKeyboard(kbd, 0, TRUE);
+            }
+
             break;
         default:
             break;
@@ -1809,14 +1821,13 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 f->child == e->frame)
                 menu_frame_select(e->frame, e, FALSE);
     }
-    else if (ev->type == KeyPress || ev->type == KeyRelease) {
+    else if (ev->type == KeyPress) {
         guint keycode, state;
-        gunichar unikey;
+        static gunichar unikey;
         ObMenuFrame *frame;
 
         keycode = ev->xkey.keycode;
         state = ev->xkey.state;
-        unikey = obt_keyboard_keycode_to_unichar(keycode);
 
         frame = find_active_or_last_menu();
         if (frame == NULL)
@@ -1873,6 +1884,12 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 menu_frame_select_last(frame);
                 ret = TRUE;
             }
+
+            /* Remember the last keypress */
+            else {
+                unikey = obt_keyboard_keypress_to_unichar(&ev->xkey);
+                ret = !!unikey;
+            }
         }
 
         /* Use KeyRelease events for running things so that the key release
index 4ee5d31e436cbc0e665838bb0add670760a908fe..5ee55b1cb893d7aa5ea5add6d3142e902c7c62c2 100644 (file)
@@ -27,6 +27,7 @@
 #include "openbox.h"
 #include "config.h"
 #include "obt/prop.h"
+#include "obt/keyboard.h"
 #include "obrender/theme.h"
 
 #define PADDING 2
@@ -960,6 +961,8 @@ static gboolean menu_frame_show(ObMenuFrame *self)
             ungrab_pointer();
             return FALSE;
         }
+
+        obt_keyboard_set_input_context(obt_root(ob_screen));
     }
 
     menu_frame_update(self);
@@ -1082,6 +1085,8 @@ static void menu_frame_hide(ObMenuFrame *self)
 
     if (menu_frame_visible == NULL) {
         /* last menu shown */
+        obt_keyboard_set_input_context(None);
+
         ungrab_pointer();
         ungrab_keyboard();
     }