summaryrefslogtreecommitdiffstats
path: root/sway/commands/bind.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/commands/bind.c')
-rw-r--r--sway/commands/bind.c152
1 files changed, 105 insertions, 47 deletions
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index 83e9e432..6910237f 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -34,11 +34,14 @@ void free_sway_binding(struct sway_binding *binding) {
34 */ 34 */
35static bool binding_key_compare(struct sway_binding *binding_a, 35static bool binding_key_compare(struct sway_binding *binding_a,
36 struct sway_binding *binding_b) { 36 struct sway_binding *binding_b) {
37 if (binding_a->release != binding_b->release) { 37 if (binding_a->type != binding_b->type) {
38 return false; 38 return false;
39 } 39 }
40 40
41 if (binding_a->bindcode != binding_b->bindcode) { 41 uint32_t conflict_generating_flags = BINDING_RELEASE | BINDING_BORDER
42 | BINDING_CONTENTS | BINDING_TITLEBAR;
43 if ((binding_a->flags & conflict_generating_flags) !=
44 (binding_b->flags & conflict_generating_flags)) {
42 return false; 45 return false;
43 } 46 }
44 47
@@ -69,6 +72,66 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) {
69 return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0); 72 return (key_a < key_b) ? -1 : ((key_a > key_b) ? 1 : 0);
70} 73}
71 74
75
76/**
77 * From a keycode, bindcode, or bindsym name and the most likely binding type,
78 * identify the appropriate numeric value corresponding to the key. Return NULL
79 * and set *key_val if successful, otherwise return a specific error. Change
80 * the value of *type if the initial type guess was incorrect and if this
81 * was the first identified key.
82 */
83static struct cmd_results *identify_key(const char* name, bool first_key,
84 uint32_t* key_val, enum binding_input_type* type) {
85 if (*type == BINDING_KEYCODE) {
86 // check for keycode
87 xkb_keycode_t keycode = strtol(name, NULL, 10);
88 if (!xkb_keycode_is_legal_ext(keycode)) {
89 return cmd_results_new(CMD_INVALID, "bindcode",
90 "Invalid keycode '%s'", name);
91 }
92 *key_val = keycode;
93 } else {
94 // check for keysym
95 xkb_keysym_t keysym = xkb_keysym_from_name(name,
96 XKB_KEYSYM_CASE_INSENSITIVE);
97
98 // Check for mouse binding
99 uint32_t button = 0;
100 if (strncasecmp(name, "button", strlen("button")) == 0 &&
101 strlen(name) == strlen("button0")) {
102 button = name[strlen("button")] - '1' + BTN_LEFT;
103 }
104
105 if (*type == BINDING_KEYSYM) {
106 if (button) {
107 if (first_key) {
108 *type = BINDING_MOUSE;
109 *key_val = button;
110 } else {
111 return cmd_results_new(CMD_INVALID, "bindsym",
112 "Mixed button '%s' into key sequence", name);
113 }
114 } else if (keysym) {
115 *key_val = keysym;
116 } else {
117 return cmd_results_new(CMD_INVALID, "bindsym",
118 "Unknown key '%s'", name);
119 }
120 } else {
121 if (button) {
122 *key_val = button;
123 } else if (keysym) {
124 return cmd_results_new(CMD_INVALID, "bindsym",
125 "Mixed keysym '%s' into button sequence", name);
126 } else {
127 return cmd_results_new(CMD_INVALID, "bindsym",
128 "Unknown button '%s'", name);
129 }
130 }
131 }
132 return NULL;
133}
134
72static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, 135static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
73 bool bindcode) { 136 bool bindcode) {
74 const char *bindtype = bindcode ? "bindcode" : "bindsym"; 137 const char *bindtype = bindcode ? "bindcode" : "bindsym";
@@ -85,22 +148,34 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
85 } 148 }
86 binding->keys = create_list(); 149 binding->keys = create_list();
87 binding->modifiers = 0; 150 binding->modifiers = 0;
88 binding->release = false; 151 binding->flags = 0;
89 binding->locked = false; 152 binding->type = bindcode ? BINDING_KEYCODE : BINDING_KEYSYM;
90 binding->bindcode = bindcode; 153
154 bool exclude_titlebar = false;
91 155
92 // Handle --release and --locked 156 // Handle --release and --locked
93 while (argc > 0) { 157 while (argc > 0) {
94 if (strcmp("--release", argv[0]) == 0) { 158 if (strcmp("--release", argv[0]) == 0) {
95 binding->release = true; 159 binding->flags |= BINDING_RELEASE;
96 } else if (strcmp("--locked", argv[0]) == 0) { 160 } else if (strcmp("--locked", argv[0]) == 0) {
97 binding->locked = true; 161 binding->flags |= BINDING_LOCKED;
162 } else if (strcmp("--whole-window", argv[0]) == 0) {
163 binding->flags |= BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR;
164 } else if (strcmp("--border", argv[0]) == 0) {
165 binding->flags |= BINDING_BORDER;
166 } else if (strcmp("--exclude-titlebar", argv[0]) == 0) {
167 exclude_titlebar = true;
98 } else { 168 } else {
99 break; 169 break;
100 } 170 }
101 argv++; 171 argv++;
102 argc--; 172 argc--;
103 } 173 }
174 if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR)
175 || exclude_titlebar) {
176 binding->type = BINDING_MOUSE;
177 }
178
104 if (argc < 2) { 179 if (argc < 2) {
105 free_sway_binding(binding); 180 free_sway_binding(binding);
106 return cmd_results_new(CMD_FAILURE, bindtype, 181 return cmd_results_new(CMD_FAILURE, bindtype,
@@ -119,64 +194,47 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
119 continue; 194 continue;
120 } 195 }
121 196
122 xkb_keycode_t keycode; 197 // Identify the key and possibly change binding->type
123 xkb_keysym_t keysym; 198 uint32_t key_val = 0;
124 if (bindcode) { 199 error = identify_key(split->items[i], binding->keys->length == 0,
125 // parse keycode 200 &key_val, &binding->type);
126 keycode = (int)strtol(split->items[i], NULL, 10); 201 if (error) {
127 if (!xkb_keycode_is_legal_ext(keycode)) { 202 free_sway_binding(binding);
128 error = 203 list_free(split);
129 cmd_results_new(CMD_INVALID, "bindcode", 204 return error;
130 "Invalid keycode '%s'", (char *)split->items[i]);
131 free_sway_binding(binding);
132 list_free(split);
133 return error;
134 }
135 } else {
136 // Check for xkb key
137 keysym = xkb_keysym_from_name(split->items[i],
138 XKB_KEYSYM_CASE_INSENSITIVE);
139
140 // Check for mouse binding
141 if (strncasecmp(split->items[i], "button", strlen("button")) == 0 &&
142 strlen(split->items[i]) == strlen("button0")) {
143 keysym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT;
144 }
145 if (!keysym) {
146 struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
147 "Unknown key '%s'", (char *)split->items[i]);
148 free_sway_binding(binding);
149 free_flat_list(split);
150 return ret;
151 }
152 } 205 }
206
153 uint32_t *key = calloc(1, sizeof(uint32_t)); 207 uint32_t *key = calloc(1, sizeof(uint32_t));
154 if (!key) { 208 if (!key) {
155 free_sway_binding(binding); 209 free_sway_binding(binding);
156 free_flat_list(split); 210 free_flat_list(split);
157 return cmd_results_new(CMD_FAILURE, bindtype, 211 return cmd_results_new(CMD_FAILURE, bindtype,
158 "Unable to allocate binding"); 212 "Unable to allocate binding key");
159 } 213 }
160 214 *key = key_val;
161 if (bindcode) {
162 *key = (uint32_t)keycode;
163 } else {
164 *key = (uint32_t)keysym;
165 }
166
167 list_add(binding->keys, key); 215 list_add(binding->keys, key);
168 } 216 }
169 free_flat_list(split); 217 free_flat_list(split);
170 binding->order = binding_order++; 218 binding->order = binding_order++;
171 219
220 // refine region of interest for mouse binding once we are certain
221 // that this is one
222 if (exclude_titlebar) {
223 binding->flags &= ~BINDING_TITLEBAR;
224 } else if (binding->type == BINDING_MOUSE) {
225 binding->flags |= BINDING_TITLEBAR;
226 }
227
172 // sort ascending 228 // sort ascending
173 list_qsort(binding->keys, key_qsort_cmp); 229 list_qsort(binding->keys, key_qsort_cmp);
174 230
175 list_t *mode_bindings; 231 list_t *mode_bindings;
176 if (bindcode) { 232 if (binding->type == BINDING_KEYCODE) {
177 mode_bindings = config->current_mode->keycode_bindings; 233 mode_bindings = config->current_mode->keycode_bindings;
178 } else { 234 } else if (binding->type == BINDING_KEYSYM) {
179 mode_bindings = config->current_mode->keysym_bindings; 235 mode_bindings = config->current_mode->keysym_bindings;
236 } else {
237 mode_bindings = config->current_mode->mouse_bindings;
180 } 238 }
181 239
182 // overwrite the binding if it already exists 240 // overwrite the binding if it already exists