11 typedef struct KeyBindingTree {
16 /* the next binding in the tree at the same level */
17 struct KeyBindingTree *next_sibling;
18 /* the first child of this binding (next binding in a chained sequence).*/
19 struct KeyBindingTree *first_child;
23 static KeyBindingTree *firstnode, *curpos;
24 static guint reset_key, reset_state;
25 static gboolean grabbed, user_grabbed;
27 guint kbind_translate_modifier(char *str)
29 if (!strcmp("Mod1", str)) return Mod1Mask;
30 else if (!strcmp("Mod2", str)) return Mod2Mask;
31 else if (!strcmp("Mod3", str)) return Mod3Mask;
32 else if (!strcmp("Mod4", str)) return Mod4Mask;
33 else if (!strcmp("Mod5", str)) return Mod5Mask;
34 else if (!strcmp("C", str)) return ControlMask;
35 else if (!strcmp("S", str)) return ShiftMask;
36 g_warning("Invalid modifier '%s' in binding.", str);
40 static gboolean translate(char *str, guint *state, guint *keycode)
48 parsed = g_strsplit(str, "-", -1);
50 /* first, find the key (last token) */
52 for (i = 0; parsed[i] != NULL; ++i)
55 goto translation_fail;
57 /* figure out the mod mask */
59 for (i = 0; parsed[i] != l; ++i) {
60 guint m = kbind_translate_modifier(parsed[i]);
61 if (!m) goto translation_fail;
65 /* figure out the keycode */
66 sym = XStringToKeysym(l);
67 if (sym == NoSymbol) {
68 g_warning("Invalid key name '%s' in key binding.", l);
69 goto translation_fail;
71 *keycode = XKeysymToKeycode(ob_display, sym);
73 g_warning("Key '%s' does not exist on the display.", l);
74 goto translation_fail;
84 static void destroytree(KeyBindingTree *tree)
89 destroytree(tree->next_sibling);
90 c = tree->first_child;
93 for (it = tree->keylist; it != NULL; it = it->next)
95 g_list_free(tree->keylist);
102 static KeyBindingTree *buildtree(GList *keylist)
105 KeyBindingTree *ret = NULL, *p;
107 if (g_list_length(keylist) <= 0)
108 return NULL; /* nothing in the list.. */
110 for (it = g_list_last(keylist); it != NULL; it = it->prev) {
112 ret = g_new(KeyBindingTree, 1);
113 ret->next_sibling = NULL;
117 /* this is the first built node, the bottom node of the tree */
118 ret->keylist = g_list_copy(keylist); /* shallow copy */
119 for (it = ret->keylist; it != NULL; it = it->next) /* deep copy */
120 it->data = g_strdup(it->data);
122 ret->first_child = p;
123 if (!translate(it->data, &ret->state, &ret->key)) {
131 static void assimilate(KeyBindingTree *node)
133 KeyBindingTree *a, *b, *tmp, *last;
135 if (firstnode == NULL) {
136 /* there are no nodes at this level yet */
144 if (!(a->state == b->state && a->key == b->key)) {
153 if (!(last->state == b->state && last->key == a->key))
154 last->next_sibling = b;
156 last->first_child = b->first_child;
162 KeyBindingTree *find(KeyBindingTree *search, gboolean *conflict)
164 KeyBindingTree *a, *b;
171 if (!(a->state == b->state && a->key == b->key)) {
174 if ((a->first_child == NULL) == (b->first_child == NULL)) {
175 if (a->first_child == NULL) {
176 /* found it! (return the actual node, not the search's) */
181 return NULL; /* the chain status' don't match (conflict!) */
187 return NULL; // it just isn't in here
190 static void grab_keys(gboolean grab)
193 XUngrabKey(ob_display, AnyKey, AnyModifier, ob_root);
195 KeyBindingTree *p = firstnode;
197 XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
198 GrabModeAsync, GrabModeSync);
210 g_message("reset chains. user: %d", user_grabbed);
212 XUngrabKeyboard(ob_display, CurrentTime);
216 void kbind_fire(guint state, guint key, gboolean press)
219 struct Client *c = focus_client;
220 GQuark context = c != NULL ? g_quark_try_string("client")
221 : g_quark_try_string("root");
224 data = eventdata_new_key(press ? Key_Press : Key_Release,
225 context, c, state, key, NULL);
226 g_assert(data != NULL);
227 hooks_fire_keyboard(data);
228 eventdata_free(data);
231 if (key == reset_key && state == reset_state) {
233 XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
239 p = curpos->first_child;
241 if (p->key == key && p->state == state) {
242 if (p->first_child != NULL) { /* part of a chain */
244 if (!grabbed && !user_grabbed) {
245 /*grab should never fail because we should have a sync
246 grab at this point */
247 XGrabKeyboard(ob_display, ob_root, 0, GrabModeAsync,
248 GrabModeSync, CurrentTime);
252 XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
254 data = eventdata_new_key(press ? Key_Press : Key_Release,
255 context, c, state, key,
257 g_assert(data != NULL);
259 eventdata_free(data);
261 XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
271 gboolean kbind_add(GList *keylist)
273 KeyBindingTree *tree, *t;
276 if (!(tree = buildtree(keylist)))
277 return FALSE; /* invalid binding requested */
279 t = find(tree, &conflict);
281 /* conflicts with another binding */
287 /* already bound to something */
290 /* grab the server here to make sure no key pressed go missed */
291 XGrabServer(ob_display);
292 XSync(ob_display, FALSE);
296 /* assimilate this built tree into the main tree */
297 assimilate(tree); // assimilation destroys/uses the tree
301 XUngrabServer(ob_display);
308 void kbind_clearall()
311 destroytree(firstnode);
320 curpos = firstnode = NULL;
321 grabbed = user_grabbed = FALSE;
323 b = translate("C-G", &reset_state, &reset_key);
327 void kbind_shutdown()
329 if (grabbed || user_grabbed) {
331 kbind_grab_keyboard(FALSE);
334 destroytree(firstnode);
338 gboolean kbind_grab_keyboard(gboolean grab)
343 g_message("grab_keyboard(false). grabbed: %d", grabbed);
348 ret = XGrabKeyboard(ob_display, ob_root, 0, GrabModeAsync,
349 GrabModeAsync, CurrentTime) == GrabSuccess;
351 XUngrabKeyboard(ob_display, CurrentTime);