* or NULL if no such binding exists.
*
*/
-Binding *get_binding(uint16_t modifiers, xcb_keycode_t keycode);
+Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode);
/**
* Kills the configerror i3-nagbar process, if any.
*
*/
struct Binding {
+ /** If true, the binding should be executed upon a KeyRelease event, not a
+ * KeyPress (the default). */
+ bool release;
+
/** Symbol the user specified in configfile, if any. This needs to be
* stored with the binding to be able to re-convert it into a keycode
* if the keyboard mapping changes (using Xmodmap for example) */
%x BAR_COLOR
%x EXEC
+%x OPTRELEASE
%%
<ASSIGN_TARGET_COND>[ \t]+ { BEGIN(WANT_STRING); }
<EXEC>--no-startup-id { printf("no startup id\n"); yy_pop_state(); return TOK_NO_STARTUP_ID; }
<EXEC>. { printf("anything else: *%s*\n", yytext); yyless(0); yy_pop_state(); yy_pop_state(); }
+<OPTRELEASE>--release { printf("--release\n"); yy_pop_state(); return TOK_RELEASE; }
+<OPTRELEASE>. { printf("anything else (optrelease): *%s*\n", yytext); yyless(0); yy_pop_state(); yy_pop_state(); }
[0-9-]+ { yylval.number = atoi(yytext); return NUMBER; }
bar { yy_push_state(BAR); return TOK_BAR; }
mode { return TOKMODE; }
bind { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; }
-bindcode { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; }
-bindsym { yy_push_state(BINDSYM_COND); yy_push_state(EAT_WHITESPACE); return TOKBINDSYM; }
+bindcode { yy_push_state(WANT_STRING); yy_push_state(EAT_WHITESPACE); yy_push_state(EAT_WHITESPACE); yy_push_state(OPTRELEASE); yy_push_state(EAT_WHITESPACE); return TOKBINDCODE; }
+bindsym { yy_push_state(BINDSYM_COND); yy_push_state(EAT_WHITESPACE); yy_push_state(OPTRELEASE); yy_push_state(EAT_WHITESPACE); return TOKBINDSYM; }
floating_maximum_size { return TOKFLOATING_MAXIMUM_SIZE; }
floating_minimum_size { return TOKFLOATING_MINIMUM_SIZE; }
floating_modifier { return TOKFLOATING_MODIFIER; }
* vim:ts=4:sw=4:expandtab
*
*/
+#undef I3__FILE__
+#define I3__FILE__ "cfgparse.y"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
%token TOK_BAR_COLOR_INACTIVE_WORKSPACE "inactive_workspace"
%token TOK_BAR_COLOR_URGENT_WORKSPACE "urgent_workspace"
%token TOK_NO_STARTUP_ID "--no-startup-id"
+%token TOK_RELEASE "--release"
%token TOK_MARK "mark"
%token TOK_CLASS "class"
%type <number> bar_mode_mode
%type <number> bar_modifier_modifier
%type <number> optional_no_startup_id
+%type <number> optional_release
%type <string> command
%type <string> word_or_number
%type <string> qstring_or_number
;
bindcode:
- binding_modifiers NUMBER command
+ optional_release binding_modifiers NUMBER command
{
- printf("\tFound keycode binding mod%d with key %d and command %s\n", $1, $2, $3);
+ DLOG("bindcode: release = %d, mod = %d, key = %d, command = %s\n", $1, $2, $3, $4);
Binding *new = scalloc(sizeof(Binding));
- new->keycode = $2;
- new->mods = $1;
- new->command = $3;
+ new->release = $1;
+ new->keycode = $3;
+ new->mods = $2;
+ new->command = $4;
$$ = new;
}
;
bindsym:
- binding_modifiers word_or_number command
+ optional_release binding_modifiers word_or_number command
{
- printf("\tFound keysym binding mod%d with key %s and command %s\n", $1, $2, $3);
+ DLOG("bindsym: release = %d, mod = %d, key = %s, command = %s\n", $1, $2, $3, $4);
Binding *new = scalloc(sizeof(Binding));
- new->symbol = $2;
- new->mods = $1;
- new->command = $3;
+ new->release = $1;
+ new->symbol = $3;
+ new->mods = $2;
+ new->command = $4;
$$ = new;
}
;
+optional_release:
+ /* empty */ { $$ = false; }
+ | TOK_RELEASE { $$ = true; }
+ ;
+
for_window:
TOK_FOR_WINDOW match command
{
* or NULL if no such binding exists.
*
*/
-Binding *get_binding(uint16_t modifiers, xcb_keycode_t keycode) {
+Binding *get_binding(uint16_t modifiers, bool key_release, xcb_keycode_t keycode) {
Binding *bind;
TAILQ_FOREACH(bind, bindings, bindings) {
if (bind->mods != modifiers)
continue;
+ /* Check if the binding is for a KeyPress or a KeyRelease event */
+ if (bind->release != key_release)
+ continue;
+
/* If a symbol was specified by the user, we need to look in
* the array of translated keycodes for the event’s keycode */
if (bind->symbol != NULL) {
switch (type) {
case XCB_KEY_PRESS:
+ case XCB_KEY_RELEASE:
handle_key_press((xcb_key_press_event_t*)event);
break;
};
/*
- * There was a key press. We compare this key code with our bindings table and pass
- * the bound action to parse_command().
+ * There was a KeyPress or KeyRelease (both events have the same fields). We
+ * compare this key code with our bindings table and pass the bound action to
+ * parse_command().
*
*/
void handle_key_press(xcb_key_press_event_t *event) {
+ bool key_release = (event->response_type == XCB_KEY_RELEASE);
last_timestamp = event->time;
- DLOG("Keypress %d, state raw = %d\n", event->detail, event->state);
+ DLOG("%s %d, state raw = %d\n", (key_release ? "KeyRelease" : "KeyPress"), event->detail, event->state);
/* Remove the numlock bit, all other bits are modifiers we can bind to */
uint16_t state_filtered = event->state & ~(xcb_numlock_mask | XCB_MOD_MASK_LOCK);
DLOG("(checked mode_switch, state %d)\n", state_filtered);
/* Find the binding */
- Binding *bind = get_binding(state_filtered, event->detail);
+ Binding *bind = get_binding(state_filtered, key_release, event->detail);
/* No match? Then the user has Mode_switch enabled but does not have a
* specific keybinding. Fall back to the default keybindings (without
if (bind == NULL) {
state_filtered &= ~(BIND_MODE_SWITCH);
DLOG("no match, new state_filtered = %d\n", state_filtered);
- if ((bind = get_binding(state_filtered, event->detail)) == NULL) {
- ELOG("Could not lookup key binding (modifiers %d, keycode %d)\n",
+ if ((bind = get_binding(state_filtered, key_release, event->detail)) == NULL) {
+ /* This is not a real error since we can have release and
+ * non-release keybindings. On a KeyPress event for which there is
+ * only a !release-binding, but no release-binding, the
+ * corresponding KeyRelease event will trigger this. No problem,
+ * though. */
+ DLOG("Could not lookup key binding (modifiers %d, keycode %d)\n",
state_filtered, event->detail);
return;
}