keyboard bindings are functional
This commit is contained in:
parent
eeba457231
commit
739c958ac5
9 changed files with 596 additions and 5 deletions
|
@ -2,14 +2,14 @@ plugindir=$(libdir)/openbox/plugins
|
||||||
|
|
||||||
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
|
CPPFLAGS=$(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
|
||||||
-DPLUGINDIR=\"$(plugindir)\" \
|
-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
|
keyboard_la_LDFLAGS=-module -avoid-version
|
||||||
focus_la_SOURCES=focus.c
|
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
|
MAINTAINERCLEANFILES= Makefile.in
|
||||||
|
|
||||||
|
|
159
plugins/keyboard/keyaction.c
Normal file
159
plugins/keyboard/keyaction.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
36
plugins/keyboard/keyaction.h
Normal file
36
plugins/keyboard/keyaction.h
Normal file
|
@ -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
|
|
@ -1,7 +1,185 @@
|
||||||
|
#include "../../kernel/focus.h"
|
||||||
#include "../../kernel/dispatch.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)
|
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()
|
void plugin_startup()
|
||||||
|
@ -9,10 +187,12 @@ void plugin_startup()
|
||||||
dispatch_register(Event_X_KeyPress, (EventHandler)press, NULL);
|
dispatch_register(Event_X_KeyPress, (EventHandler)press, NULL);
|
||||||
|
|
||||||
/* XXX parse config file! */
|
/* XXX parse config file! */
|
||||||
|
binddef();
|
||||||
}
|
}
|
||||||
|
|
||||||
void plugin_shutdown()
|
void plugin_shutdown()
|
||||||
{
|
{
|
||||||
dispatch_register(0, (EventHandler)press, NULL);
|
dispatch_register(0, (EventHandler)press, NULL);
|
||||||
|
clearall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
plugins/keyboard/keyboard.h
Normal file
23
plugins/keyboard/keyboard.h
Normal file
|
@ -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
|
61
plugins/keyboard/translate.c
Normal file
61
plugins/keyboard/translate.c
Normal file
|
@ -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;
|
||||||
|
}
|
9
plugins/keyboard/translate.h
Normal file
9
plugins/keyboard/translate.h
Normal file
|
@ -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
|
111
plugins/keyboard/tree.c
Normal file
111
plugins/keyboard/tree.c
Normal file
|
@ -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 */
|
||||||
|
}
|
12
plugins/keyboard/tree.h
Normal file
12
plugins/keyboard/tree.h
Normal file
|
@ -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
|
Loading…
Reference in a new issue