aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands/bind.c
diff options
context:
space:
mode:
authorLibravatar frsfnrrg <frsfnrrg@users.noreply.github.com>2018-07-17 22:01:06 -0400
committerLibravatar frsfnrrg <frsfnrrg@users.noreply.github.com>2018-07-23 21:14:22 -0400
commit754372c3de1f5b357850cb58cc8ddc1aee596bd6 (patch)
treeeccf5a8acb15efe794fabe09e64bab228006f52b /sway/commands/bind.c
parentMerge pull request #2342 from RyanDwyer/update-cursor (diff)
downloadsway-754372c3de1f5b357850cb58cc8ddc1aee596bd6.tar.gz
sway-754372c3de1f5b357850cb58cc8ddc1aee596bd6.tar.zst
sway-754372c3de1f5b357850cb58cc8ddc1aee596bd6.zip
Parse mouse binding options
First, the existing sway_binding structure is given an enumerated type code. As all flags to bindsym/bindcode are boolean, a single uint32 is used to hold all flags. The _BORDER, _CONTENTS, _TITLEBAR flags, when active, indicate in which part of a container the binding can trigger; to localize complexity, they do not overlap with the command line arguments, which center around _TITLEBAR being set by default. The keyboard handling code is adjusted for this change, as is binding_key_compare; note that BINDING_LOCKED is *not* part of the key portion of the binding. Next, list of mouse bindings is introduced and cleaned up. Finally, the binding command parsing code is extended to handle the case where bindsym is used to describe a mouse binding rather than a keysym binding; the difference between the two may be detected as late as when the first key/button is parsed, or as early as the first flag. As bindings can have multiple keycodes/keysyms/buttons, mixed keysym/button sequences are prohibited.
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