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
);