aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/config.h1
-rw-r--r--include/input_state.h3
-rw-r--r--sway/commands.c16
-rw-r--r--sway/handlers.c85
-rw-r--r--sway/input_state.c14
5 files changed, 92 insertions, 27 deletions
diff --git a/include/config.h b/include/config.h
index 5e1c39f3..8220f804 100644
--- a/include/config.h
+++ b/include/config.h
@@ -22,6 +22,7 @@ struct sway_variable {
*/
struct sway_binding {
int order;
+ bool release;
list_t *keys;
uint32_t modifiers;
char *command;
diff --git a/include/input_state.h b/include/input_state.h
index 79e27d91..903301fb 100644
--- a/include/input_state.h
+++ b/include/input_state.h
@@ -9,6 +9,9 @@
// returns true if key has been pressed, otherwise false
bool check_key(uint32_t key_sym, uint32_t key_code);
+// returns true if key_sym matches latest released key.
+bool check_released_key(uint32_t key_sym);
+
// sets a key as pressed
void press_key(uint32_t key_sym, uint32_t key_code);
diff --git a/sway/commands.c b/sway/commands.c
index 4e5bc712..6a316596 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -163,9 +163,25 @@ static struct cmd_results *cmd_bindsym(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "bindsym", "Can only be used in config file.");
}
+
struct sway_binding *binding = malloc(sizeof(struct sway_binding));
binding->keys = create_list();
binding->modifiers = 0;
+ binding->release = false;
+
+ // Handle --release
+ if (strcmp("--release", argv[0]) == 0) {
+ if (argc >= 3) {
+ binding->release = true;
+ argv++;
+ argc--;
+ } else {
+ return cmd_results_new(CMD_FAILURE, "bindsym",
+ "Invalid bindsym command"
+ "(expected more than 2 arguments, got %d)", argc);
+ }
+ }
+
binding->command = join_args(argv + 1, argc - 1);
list_t *split = split_string(argv[0], "+");
diff --git a/sway/handlers.c b/sway/handlers.c
index 470f3c95..e0acebea 100644
--- a/sway/handlers.c
+++ b/sway/handlers.c
@@ -336,6 +336,43 @@ static void handle_view_state_request(wlc_handle view, enum wlc_view_state_bit s
return;
}
+static bool handle_bindsym(struct sway_binding *binding) {
+ bool match = false;
+ int i;
+ for (i = 0; i < binding->keys->length; ++i) {
+ xkb_keysym_t *key = binding->keys->items[i];
+ if ((match = check_key(*key, 0)) == false) {
+ break;
+ }
+ }
+
+ if (match) {
+ struct cmd_results *res = handle_command(binding->command);
+ if (res->status != CMD_SUCCESS) {
+ sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error);
+ }
+ free_cmd_results(res);
+ return true;
+ }
+
+ return false;
+}
+
+static bool handle_bindsym_release(struct sway_binding *binding) {
+ if (binding->keys->length == 1) {
+ xkb_keysym_t *key = binding->keys->items[0];
+ if (check_released_key(*key)) {
+ struct cmd_results *res = handle_command(binding->command);
+ if (res->status != CMD_SUCCESS) {
+ sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error);
+ }
+ free_cmd_results(res);
+ return true;
+ }
+ }
+
+ return false;
+}
static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifiers *modifiers,
uint32_t key, enum wlc_key_state state) {
@@ -366,33 +403,6 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
release_key(sym, key);
}
- for (i = 0; i < mode->bindings->length; ++i) {
- struct sway_binding *binding = mode->bindings->items[i];
-
- if ((modifiers->mods ^ binding->modifiers) == 0) {
- bool match = false;
- int j;
- for (j = 0; j < binding->keys->length; ++j) {
- xkb_keysym_t *key = binding->keys->items[j];
- if ((match = check_key(*key, 0)) == false) {
- break;
- }
- }
- if (match) {
- if (state == WLC_KEY_STATE_PRESSED) {
- struct cmd_results *res = handle_command(binding->command);
- if (res->status != CMD_SUCCESS) {
- sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error);
- }
- free_cmd_results(res);
- return EVENT_HANDLED;
- } else if (state == WLC_KEY_STATE_RELEASED) {
- // TODO: --released
- }
- }
- }
- }
-
// handle bar modifiers pressed/released
uint32_t modifier;
for (i = 0; i < config->active_bar_modifiers->length; ++i) {
@@ -409,6 +419,27 @@ static bool handle_key(wlc_handle view, uint32_t time, const struct wlc_modifier
}
// update modifiers state
modifiers_state_update(modifiers->mods);
+
+ // handle bindings
+ for (i = 0; i < mode->bindings->length; ++i) {
+ struct sway_binding *binding = mode->bindings->items[i];
+ if ((modifiers->mods ^ binding->modifiers) == 0) {
+ switch (state) {
+ case WLC_KEY_STATE_PRESSED: {
+ if (!binding->release && handle_bindsym(binding)) {
+ return EVENT_HANDLED;
+ }
+ break;
+ }
+ case WLC_KEY_STATE_RELEASED:
+ if (binding->release && handle_bindsym_release(binding)) {
+ return EVENT_HANDLED;
+ }
+ break;
+ }
+ }
+ }
+
return EVENT_PASSTHROUGH;
}
diff --git a/sway/input_state.c b/sway/input_state.c
index 2f40b6c2..86868083 100644
--- a/sway/input_state.c
+++ b/sway/input_state.c
@@ -22,6 +22,8 @@ struct key_state {
static struct key_state key_state_array[KEY_STATE_MAX_LENGTH];
+static struct key_state last_released;
+
static uint32_t modifiers_state;
void input_init(void) {
@@ -31,6 +33,9 @@ void input_init(void) {
key_state_array[i] = none;
}
+ struct key_state none = { 0, 0, 0 };
+ last_released = none;
+
modifiers_state = 0;
}
@@ -76,6 +81,12 @@ bool check_key(uint32_t key_sym, uint32_t key_code) {
return find_key(key_sym, key_code, false) < KEY_STATE_MAX_LENGTH;
}
+bool check_released_key(uint32_t key_sym) {
+ return (key_sym != 0
+ && (last_released.key_sym == key_sym
+ || last_released.alt_sym == key_sym));
+}
+
void press_key(uint32_t key_sym, uint32_t key_code) {
if (key_code == 0) {
return;
@@ -94,6 +105,9 @@ void press_key(uint32_t key_sym, uint32_t key_code) {
void release_key(uint32_t key_sym, uint32_t key_code) {
uint8_t index = find_key(key_sym, key_code, true);
if (index < KEY_STATE_MAX_LENGTH) {
+ last_released.key_sym = key_state_array[index].key_sym;
+ last_released.alt_sym = key_state_array[index].alt_sym;
+ last_released.key_code = key_state_array[index].key_code;
struct key_state none = { 0, 0, 0 };
key_state_array[index] = none;
}