]> Dogcows Code - chaz/openbox/commitdiff
keyboard bindings are functional
authorDana Jansens <danakj@orodu.net>
Tue, 18 Mar 2003 08:38:33 +0000 (08:38 +0000)
committerDana Jansens <danakj@orodu.net>
Tue, 18 Mar 2003 08:38:33 +0000 (08:38 +0000)
plugins/keyboard/Makefile.am
plugins/keyboard/keyaction.c [new file with mode: 0644]
plugins/keyboard/keyaction.h [new file with mode: 0644]
plugins/keyboard/keyboard.c
plugins/keyboard/keyboard.h [new file with mode: 0644]
plugins/keyboard/translate.c [new file with mode: 0644]
plugins/keyboard/translate.h [new file with mode: 0644]
plugins/keyboard/tree.c [new file with mode: 0644]
plugins/keyboard/tree.h [new file with mode: 0644]

index 78ff2ccf11986b65002dc34b5cbada256a769e3d..983fd39aba0313b07e575f1cd80979d2dc4f1684 100644 (file)
@@ -2,14 +2,14 @@ plugindir=$(libdir)/openbox/plugins
 
 CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
 -DPLUGINDIR=\"$(plugindir)\" \
--DG_LOG_DOMAIN=\"Openbox-Plugin\"
+-DG_LOG_DOMAIN=\"Plugin-Keyboard\"
 
-plugin_LTLIBRARIES=focus.la
+plugin_LTLIBRARIES=keyboard.la
 
-focus_la_LDFLAGS=-module -avoid-version
-focus_la_SOURCES=focus.c
+keyboard_la_LDFLAGS=-module -avoid-version
+keyboard_la_SOURCES=keyboard.c tree.c translate.c keyaction.c
 
-noinst_HEADERS=
+noinst_HEADERS=keyboard.h tree.h translate.h keyaction.h
 
 MAINTAINERCLEANFILES= Makefile.in
 
diff --git a/plugins/keyboard/keyaction.c b/plugins/keyboard/keyaction.c
new file mode 100644 (file)
index 0000000..e3b9aca
--- /dev/null
@@ -0,0 +1,159 @@
+#include "keyaction.h"
+#include <glib.h>
+
+void keyaction_set_none(KeyAction *a, guint index)
+{
+    a->type[index] = DataType_Bool;
+}
+
+void keyaction_set_bool(KeyAction *a, guint index, gboolean b)
+{
+    a->type[index] = DataType_Bool;
+    a->data[index].b = b;
+}
+
+void keyaction_set_int(KeyAction *a, guint index, int i)
+{
+    a->type[index] = DataType_Int;
+    a->data[index].i = i;
+}
+
+void keyaction_set_uint(KeyAction *a, guint index, guint u)
+{
+    a->type[index] = DataType_Uint;
+    a->data[index].u = u;
+}
+
+void keyaction_set_string(KeyAction *a, guint index, char *s)
+{
+    a->type[index] = DataType_String;
+    a->data[index].s = g_strdup(s);
+}
+
+void keyaction_free(KeyAction *a)
+{
+    guint i;
+
+    for (i = 0; i < 2; ++i)
+        if (a->type[i] == DataType_String)
+            g_free(a->data[i].s);
+}
+
+void keyaction_do(KeyAction *a, Client *c)
+{
+    switch (a->action) {
+    case Action_Execute:
+        g_assert(a->type[0] == DataType_String);
+        action_execute(a->data[0].s);
+        break;
+    case Action_Iconify:
+        if (c != NULL) action_iconify(c);
+        break;
+    case Action_Raise:
+        if (c != NULL) action_raise(c);
+        break;
+    case Action_Lower:
+        if (c != NULL) action_lower(c);
+        break;
+    case Action_Close:
+        if (c != NULL) action_close(c);
+        break;
+    case Action_Shade:
+        if (c != NULL) action_shade(c);
+        break;
+    case Action_Unshade:
+        if (c != NULL) action_unshade(c);
+        break;
+    case Action_ToggleShade:
+        if (c != NULL) action_toggle_shade(c);
+        break;
+    case Action_ToggleOmnipresent:
+        if (c != NULL) action_toggle_omnipresent(c);
+        break;
+    case Action_MoveRelative:
+        g_assert(a->type[0] == DataType_Int);
+        g_assert(a->type[1] == DataType_Int);
+        if (c != NULL) action_move_relative(c, a->data[0].i, a->data[1].i);
+        break;
+    case Action_ResizeRelative:
+        g_assert(a->type[0] == DataType_Int);
+        g_assert(a->type[1] == DataType_Int);
+        if (c != NULL) action_resize_relative(c, a->data[0].i, a->data[1].i);
+        break;
+    case Action_MaximizeFull:
+        if (c != NULL) action_maximize_full(c);
+        break;
+    case Action_UnmaximizeFull:
+        if (c != NULL) action_unmaximize_full(c);
+        break;
+    case Action_ToggleMaximizeFull:
+        if (c != NULL) action_toggle_maximize_full(c);
+        break;
+    case Action_MaximizeHorz:
+        if (c != NULL) action_maximize_horz(c);
+        break;
+    case Action_UnmaximizeHorz:
+        if (c != NULL) action_unmaximize_horz(c);
+        break;
+    case Action_ToggleMaximizeHorz:
+        if (c != NULL) action_toggle_maximize_horz(c);
+        break;
+    case Action_MaximizeVert:
+        if (c != NULL) action_maximize_vert(c);
+        break;
+    case Action_UnmaximizeVert:
+        if (c != NULL) action_unmaximize_vert(c);
+        break;
+    case Action_ToggleMaximizeVert:
+        if (c != NULL) action_toggle_maximize_vert(c);
+        break;
+    case Action_SendToDesktop:
+        g_assert(a->type[0] == DataType_Uint);
+        if (c != NULL) action_send_to_desktop(c, a->data[0].u);
+        break;
+    case Action_SendToNextDesktop:
+        g_assert(a->type[0] == DataType_Bool);
+        g_assert(a->type[1] == DataType_Bool);
+        if (c != NULL) action_send_to_next_desktop(c, a->data[0].b,
+                                                   a->data[1].b);
+        break;
+    case Action_SendToPreviousDesktop:
+        g_assert(a->type[0] == DataType_Bool);
+        g_assert(a->type[1] == DataType_Bool);
+        if (c != NULL) action_send_to_previous_desktop(c, a->data[0].b,
+                                                       a->data[1].b);
+        break;
+    case Action_Desktop:
+        g_assert(a->type[0] == DataType_Uint);
+        action_desktop(a->data[0].u);
+        break;
+    case Action_NextDesktop:
+        g_assert(a->type[0] == DataType_Bool);
+        action_next_desktop(a->data[0].b);
+        break;
+    case Action_PreviousDesktop:
+        g_assert(a->type[0] == DataType_Bool);
+        action_previous_desktop(a->data[0].b);
+        break;
+    case Action_NextDesktopColumn:
+        g_assert(a->type[0] == DataType_Bool);
+        action_next_desktop_column(a->data[0].b);
+        break;
+    case Action_PreviousDesktopColumn:
+        g_assert(a->type[0] == DataType_Bool);
+        action_previous_desktop_column(a->data[0].b);
+        break; 
+    case Action_NextDesktopRow:
+        g_assert(a->type[0] == DataType_Bool);
+        action_next_desktop_row(a->data[0].b);
+        break;
+    case Action_PreviousDesktopRow:
+        g_assert(a->type[0] == DataType_Bool);
+        action_previous_desktop_row(a->data[0].b);
+        break; 
+    case Action_ToggleDecorations:
+        if (c != NULL) action_toggle_decorations(c);
+        break; 
+   }
+}
+
diff --git a/plugins/keyboard/keyaction.h b/plugins/keyboard/keyaction.h
new file mode 100644 (file)
index 0000000..e4ae977
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef __plugin_keyboard_action_h
+#define __plugin_keyboard_action_h
+
+#include "../../kernel/action.h"
+
+typedef enum {
+    DataType_Bool,
+    DataType_Int,
+    DataType_Uint,
+    DataType_String
+} KeyActionDataType;
+
+typedef union {
+    gboolean b;
+    int i;
+    guint u;
+    char *s;
+} KeyActionData;
+
+typedef struct {
+    Action action;
+    KeyActionDataType type[2];
+    KeyActionData data[2];
+} KeyAction;
+
+void keyaction_set_none(KeyAction *a, guint index);
+void keyaction_set_bool(KeyAction *a, guint index, gboolean bool);
+void keyaction_set_int(KeyAction *a, guint index, int i);
+void keyaction_set_uint(KeyAction *a, guint index, guint uint);
+void keyaction_set_string(KeyAction *a, guint index, char *string);
+
+void keyaction_free(KeyAction *a);
+
+void keyaction_do(KeyAction *a, Client *c);
+
+#endif
index 3e621849921784562cb57c14c2b98ef104a44684..4a090dc3d3742c66a889c5c073ad0cdce0715d2a 100644 (file)
@@ -1,7 +1,185 @@
+#include "../../kernel/focus.h"
 #include "../../kernel/dispatch.h"
+#include "../../kernel/openbox.h"
+#include "../../kernel/action.h"
+#include "tree.h"
+#include "keyboard.h"
+#include "keyaction.h"
+#include <glib.h>
+
+KeyBindingTree *firstnode;
+
+static KeyBindingTree *curpos;
+static guint reset_key, reset_state;
+static gboolean grabbed;
+
+static void grab_keys(gboolean grab)
+{
+    if (!grab) {
+       XUngrabKey(ob_display, AnyKey, AnyModifier, ob_root);
+    } else {
+       KeyBindingTree *p = firstnode;
+       while (p) {
+           XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
+                    GrabModeAsync, GrabModeSync);
+           p = p->next_sibling;
+       }
+    }
+}
+
+static void reset_chains()
+{
+    /* XXX kill timer */
+    curpos = NULL;
+    if (grabbed) {
+       grabbed = FALSE;
+        XUngrabKeyboard(ob_display, CurrentTime);
+    }
+}
+
+static void clearall()
+{
+    grab_keys(FALSE);
+    tree_destroy(firstnode);
+    firstnode = NULL;
+    grab_keys(TRUE);
+}
+
+static gboolean bind(GList *keylist, KeyAction *action)
+{
+    KeyBindingTree *tree, *t;
+    gboolean conflict;
+
+    if (!(tree = tree_build(keylist))) {
+        g_warning("invalid binding");
+        return FALSE;
+    }
+
+    t = tree_find(tree, &conflict);
+    if (conflict) {
+        g_warning("conflict with binding");
+        tree_destroy(tree);
+        return FALSE;
+    }
+    if (t != NULL) {
+       /* already bound to something */
+       g_warning("keychain is already bound");
+        tree_destroy(tree);
+        return FALSE;
+    }
+
+    /* grab the server here to make sure no key pressed go missed */
+    XGrabServer(ob_display);
+    XSync(ob_display, FALSE);
+
+    grab_keys(FALSE);
+
+    /* set the function */
+    t = tree;
+    while (t->first_child) t = t->first_child;
+    t->action.action = action->action;
+    t->action.type[0] = action->type[0];
+    t->action.type[1] = action->type[1];
+    t->action.data[0] = action->data[0];
+    t->action.data[1] = action->data[1];
+
+    /* assimilate this built tree into the main tree */
+    tree_assimilate(tree); /* assimilation destroys/uses the tree */
+
+    grab_keys(TRUE); 
+
+    XUngrabServer(ob_display);
+    XFlush(ob_display);
+
+    return TRUE;
+}
 
 static void press(ObEvent *e, void *foo)
 {
+    if (e->data.x.e->xkey.keycode == reset_key &&
+        e->data.x.e->xkey.state == reset_state) {
+        reset_chains();
+        XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
+    } else {
+        KeyBindingTree *p;
+        if (curpos == NULL)
+            p = firstnode;
+        else
+            p = curpos->first_child;
+        while (p) {
+            if (p->key == e->data.x.e->xkey.keycode &&
+                p->state == e->data.x.e->xkey.state) {
+                if (p->first_child != NULL) { /* part of a chain */
+                    /* XXX TIMER */
+                    if (!grabbed) {
+                        /*grab should never fail because we should have a
+                          sync grab at this point */
+                        XGrabKeyboard(ob_display, ob_root, 0,
+                                      GrabModeAsync, GrabModeSync,
+                                      CurrentTime);
+                    }
+                    grabbed = TRUE;
+                    curpos = p;
+                    XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
+                } else {
+                    keyaction_do(&p->action, focus_client);
+
+                    XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
+                    reset_chains();
+                }
+                break;
+            }
+            p = p->next_sibling;
+        }
+    }
+}
+
+static void binddef()
+{
+    GList *list = g_list_append(NULL, NULL);
+    KeyAction a;
+
+    list->data = "C-Right";
+    a.action = Action_NextDesktop;
+    keyaction_set_bool(&a, 0, TRUE);
+    keyaction_set_none(&a, 1);
+    bind(list, &a);
+
+    list->data = "C-Left";
+    a.action = Action_PreviousDesktop;
+    keyaction_set_bool(&a, 0, TRUE);
+    keyaction_set_none(&a, 1);
+    bind(list, &a);
+
+    list->data = "C-1";
+    a.action = Action_Desktop;
+    keyaction_set_uint(&a, 0, 0);
+    keyaction_set_none(&a, 1);
+    bind(list, &a);
+
+    list->data = "C-2";
+    a.action = Action_Desktop;
+    keyaction_set_uint(&a, 0, 1);
+    keyaction_set_none(&a, 1);
+    bind(list, &a);
+
+    list->data = "C-3";
+    a.action = Action_Desktop;
+    keyaction_set_uint(&a, 0, 2);
+    keyaction_set_none(&a, 1);
+    bind(list, &a);
+
+    list->data = "C-4";
+    a.action = Action_Desktop;
+    keyaction_set_uint(&a, 0, 3);
+    keyaction_set_none(&a, 1);
+    bind(list, &a);
+
+    list->data = "C-space";
+    a.action = Action_Execute;
+    keyaction_set_string(&a, 0, "xterm");
+    keyaction_set_none(&a, 1);
+    bind(list, &a);
 }
 
 void plugin_startup()
@@ -9,10 +187,12 @@ void plugin_startup()
     dispatch_register(Event_X_KeyPress, (EventHandler)press, NULL);
 
     /* XXX parse config file! */
+    binddef();
 }
 
 void plugin_shutdown()
 {
     dispatch_register(0, (EventHandler)press, NULL);
+    clearall();
 }
 
diff --git a/plugins/keyboard/keyboard.h b/plugins/keyboard/keyboard.h
new file mode 100644 (file)
index 0000000..b183fa3
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __plugin_keyboard_keybaord_h
+#define __plugin_keyboard_keybaord_h
+
+#include "keyaction.h"
+#include <glib.h>
+
+typedef struct KeyBindingTree {
+    guint state;
+    guint key;
+    GList *keylist;
+    KeyAction action;
+
+    /* the next binding in the tree at the same level */
+    struct KeyBindingTree *next_sibling; 
+    /* the first child of this binding (next binding in a chained sequence).*/
+    struct KeyBindingTree *first_child;
+} KeyBindingTree;
+
+extern KeyBindingTree *firstnode;
+
+guint keyboard_translate_modifier(char *str);
+
+#endif
diff --git a/plugins/keyboard/translate.c b/plugins/keyboard/translate.c
new file mode 100644 (file)
index 0000000..75c077f
--- /dev/null
@@ -0,0 +1,61 @@
+#include "../../kernel/openbox.h"
+#include "keyboard.h"
+#include <glib.h>
+#include <string.h>
+
+guint keyboard_translate_modifier(char *str)
+{
+    if (!strcmp("Mod1", str) || !strcmp("A", str)) return Mod1Mask;
+    else if (!strcmp("Mod2", str)) return Mod2Mask;
+    else if (!strcmp("Mod3", str)) return Mod3Mask;
+    else if (!strcmp("Mod4", str) || !strcmp("W", str)) return Mod4Mask;
+    else if (!strcmp("Mod5", str)) return Mod5Mask;
+    else if (!strcmp("C", str)) return ControlMask;
+    else if (!strcmp("S", str)) return ShiftMask;
+    g_warning("Invalid modifier '%s' in binding.", str);
+    return 0;
+}
+
+gboolean translate_key(char *str, guint *state, guint *keycode)
+{
+    char **parsed;
+    char *l;
+    int i;
+    gboolean ret = FALSE;
+    KeySym sym;
+
+    parsed = g_strsplit(str, "-", -1);
+    
+    /* first, find the key (last token) */
+    l = NULL;
+    for (i = 0; parsed[i] != NULL; ++i)
+       l = parsed[i];
+    if (l == NULL)
+       goto translation_fail;
+
+    /* figure out the mod mask */
+    *state = 0;
+    for (i = 0; parsed[i] != l; ++i) {
+       guint m = keyboard_translate_modifier(parsed[i]);
+       if (!m) goto translation_fail;
+       *state |= m;
+    }
+
+    /* figure out the keycode */
+    sym = XStringToKeysym(l);
+    if (sym == NoSymbol) {
+       g_warning("Invalid key name '%s' in key binding.", l);
+       goto translation_fail;
+    }
+    *keycode = XKeysymToKeycode(ob_display, sym);
+    if (!keycode) {
+       g_warning("Key '%s' does not exist on the display.", l); 
+       goto translation_fail;
+    }
+
+    ret = TRUE;
+
+translation_fail:
+    g_strfreev(parsed);
+    return ret;
+}
diff --git a/plugins/keyboard/translate.h b/plugins/keyboard/translate.h
new file mode 100644 (file)
index 0000000..e0d0bae
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef __plugin_keyboard_translate_h
+#define __plugin_keyboard_translate_h
+
+#include <glib.h>
+
+guint translate_modifier(char *str);
+gboolean translate_key(char *str, guint *state, guint *keycode);
+
+#endif
diff --git a/plugins/keyboard/tree.c b/plugins/keyboard/tree.c
new file mode 100644 (file)
index 0000000..b7f5188
--- /dev/null
@@ -0,0 +1,111 @@
+#include "keyboard.h"
+#include "translate.h"
+#include "keyaction.h"
+#include <glib.h>
+
+void tree_destroy(KeyBindingTree *tree)
+{
+    KeyBindingTree *c;
+
+    while (tree) {
+       tree_destroy(tree->next_sibling);
+       c = tree->first_child;
+       if (c == NULL) {
+           GList *it;
+           for (it = tree->keylist; it != NULL; it = it->next)
+               g_free(it->data);
+           g_list_free(tree->keylist);
+            keyaction_free(&tree->action);
+       }
+       g_free(tree);
+       tree = c;
+    }
+}
+
+KeyBindingTree *tree_build(GList *keylist)
+{
+    GList *it;
+    KeyBindingTree *ret = NULL, *p;
+
+    if (g_list_length(keylist) <= 0)
+       return NULL; /* nothing in the list.. */
+
+    for (it = g_list_last(keylist); it != NULL; it = it->prev) {
+       p = ret;
+       ret = g_new(KeyBindingTree, 1);
+       ret->next_sibling = NULL;
+       if (p == NULL) {
+           GList *it;
+
+           /* this is the first built node, the bottom node of the tree */
+           ret->keylist = g_list_copy(keylist); /* shallow copy */
+           for (it = ret->keylist; it != NULL; it = it->next) /* deep copy */
+               it->data = g_strdup(it->data);
+       }
+       ret->first_child = p;
+       if (!translate_key(it->data, &ret->state, &ret->key)) {
+           tree_destroy(ret);
+           return NULL;
+       }
+    }
+    return ret;
+}
+
+void tree_assimilate(KeyBindingTree *node)
+{
+    KeyBindingTree *a, *b, *tmp, *last;
+
+    if (firstnode == NULL) {
+       /* there are no nodes at this level yet */
+       firstnode = node;
+    } else {
+       a = firstnode;
+       last = a;
+       b = node;
+       while (a) {
+           last = a;
+           if (!(a->state == b->state && a->key == b->key)) {
+               a = a->next_sibling;
+           } else {
+               tmp = b;
+               b = b->first_child;
+               g_free(tmp);
+               a = a->first_child;
+           }
+       }
+       if (!(last->state == b->state && last->key == b->key))
+           last->next_sibling = b;
+       else {
+           last->first_child = b->first_child;
+           g_free(b);
+       }
+    }
+}
+
+KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict)
+{
+    KeyBindingTree *a, *b;
+
+    *conflict = FALSE;
+
+    a = firstnode;
+    b = search;
+    while (a && b) {
+       if (!(a->state == b->state && a->key == b->key)) {
+           a = a->next_sibling;
+       } else {
+           if ((a->first_child == NULL) == (b->first_child == NULL)) {
+               if (a->first_child == NULL) {
+                   /* found it! (return the actual node, not the search's) */
+                   return a;
+               }
+           } else {
+               *conflict = TRUE;
+               return NULL; /* the chain status' don't match (conflict!) */
+           }
+           b = b->first_child;
+           a = a->first_child;
+       }
+    }
+    return NULL; /* it just isn't in here */
+}
diff --git a/plugins/keyboard/tree.h b/plugins/keyboard/tree.h
new file mode 100644 (file)
index 0000000..ab84643
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef __plugin_keyboard_tree_h
+#define __plugin_keyboard_tree_h
+
+#include "keyboard.h"
+#include <glib.h>
+
+void tree_destroy(KeyBindingTree *tree);
+KeyBindingTree *tree_build(GList *keylist);
+void tree_assimilate(KeyBindingTree *node);
+KeyBindingTree *tree_find(KeyBindingTree *search, gboolean *conflict);
+
+#endif
This page took 0.036349 seconds and 4 git commands to generate.