diff options
-rw-r--r-- | include/sway/config.h | 3 | ||||
-rw-r--r-- | include/sway/input/cursor.h | 8 | ||||
-rw-r--r-- | sway/commands/bind.c | 126 | ||||
-rw-r--r-- | sway/input/cursor.c | 65 | ||||
-rw-r--r-- | sway/ipc-server.c | 8 | ||||
-rw-r--r-- | sway/sway.5.scd | 2 |
6 files changed, 157 insertions, 55 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index ebf16e6a..29c21afe 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -27,7 +27,8 @@ struct sway_variable { | |||
27 | enum binding_input_type { | 27 | enum binding_input_type { |
28 | BINDING_KEYCODE, | 28 | BINDING_KEYCODE, |
29 | BINDING_KEYSYM, | 29 | BINDING_KEYSYM, |
30 | BINDING_MOUSE, | 30 | BINDING_MOUSECODE, |
31 | BINDING_MOUSESYM, | ||
31 | }; | 32 | }; |
32 | 33 | ||
33 | enum binding_flags { | 34 | enum binding_flags { |
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 22e278b0..4636bf6b 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h | |||
@@ -86,4 +86,12 @@ void cursor_warp_to_container(struct sway_cursor *cursor, | |||
86 | 86 | ||
87 | void cursor_warp_to_workspace(struct sway_cursor *cursor, | 87 | void cursor_warp_to_workspace(struct sway_cursor *cursor, |
88 | struct sway_workspace *workspace); | 88 | struct sway_workspace *workspace); |
89 | |||
90 | uint32_t get_mouse_bindsym(const char *name, char **error); | ||
91 | |||
92 | uint32_t get_mouse_bindcode(const char *name, char **error); | ||
93 | |||
94 | // Considers both bindsym and bindcode | ||
95 | uint32_t get_mouse_button(const char *name, char **error); | ||
96 | |||
89 | #endif | 97 | #endif |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index 4fceaf8c..be47d412 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -85,69 +85,91 @@ static int key_qsort_cmp(const void *keyp_a, const void *keyp_b) { | |||
85 | */ | 85 | */ |
86 | static struct cmd_results *identify_key(const char* name, bool first_key, | 86 | static struct cmd_results *identify_key(const char* name, bool first_key, |
87 | uint32_t* key_val, enum binding_input_type* type) { | 87 | uint32_t* key_val, enum binding_input_type* type) { |
88 | if (*type == BINDING_KEYCODE) { | 88 | if (*type == BINDING_MOUSECODE) { |
89 | // check for keycode | 89 | // check for mouse bindcodes |
90 | xkb_keycode_t keycode = strtol(name, NULL, 10); | 90 | char *message = NULL; |
91 | if (!xkb_keycode_is_legal_ext(keycode)) { | 91 | uint32_t button = get_mouse_bindcode(name, &message); |
92 | return cmd_results_new(CMD_INVALID, "bindcode", | 92 | if (!button) { |
93 | "Invalid keycode '%s'", name); | 93 | if (message) { |
94 | struct cmd_results *error = | ||
95 | cmd_results_new(CMD_INVALID, "bindcode", message); | ||
96 | free(message); | ||
97 | return error; | ||
98 | } else { | ||
99 | return cmd_results_new(CMD_INVALID, "bindcode", | ||
100 | "Unknown button code %s", name); | ||
101 | } | ||
94 | } | 102 | } |
95 | *key_val = keycode; | 103 | *key_val = button; |
96 | } else { | 104 | } else if (*type == BINDING_MOUSESYM) { |
97 | // check for keysym | 105 | // check for mouse bindsyms (x11 buttons or event names) |
98 | xkb_keysym_t keysym = xkb_keysym_from_name(name, | 106 | char *message = NULL; |
99 | XKB_KEYSYM_CASE_INSENSITIVE); | 107 | uint32_t button = get_mouse_bindsym(name, &message); |
100 | 108 | if (!button) { | |
101 | // Check for mouse binding | 109 | if (message) { |
102 | uint32_t button = 0; | 110 | struct cmd_results *error = |
103 | if (strncasecmp(name, "button", strlen("button")) == 0) { | 111 | cmd_results_new(CMD_INVALID, "bindsym", message); |
104 | // Map to x11 mouse buttons | 112 | free(message); |
105 | button = name[strlen("button")] - '0'; | 113 | return error; |
106 | if (button < 1 || button > 9 || strlen(name) > strlen("button0")) { | 114 | } else if (!button) { |
107 | return cmd_results_new(CMD_INVALID, "bindsym", | 115 | return cmd_results_new(CMD_INVALID, "bindsym", |
108 | "Only buttons 1-9 are supported. For other mouse " | 116 | "Unknown button %s", name); |
109 | "buttons, use the name of the event code."); | ||
110 | } | 117 | } |
111 | uint32_t buttons[] = {BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, | 118 | } |
112 | SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT, | 119 | *key_val = button; |
113 | SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA}; | 120 | } else if (*type == BINDING_KEYCODE) { |
114 | button = buttons[button - 1]; | 121 | // check for keycode. If it is the first key, allow mouse bindcodes |
115 | } else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) { | 122 | if (first_key) { |
116 | // Get event code | 123 | char *message = NULL; |
117 | int code = libevdev_event_code_from_name(EV_KEY, name); | 124 | uint32_t button = get_mouse_bindcode(name, &message); |
118 | if (code == -1) { | 125 | free(message); |
119 | return cmd_results_new(CMD_INVALID, "bindsym", | 126 | if (button) { |
120 | "Invalid event code name %s", name); | 127 | *type = BINDING_MOUSECODE; |
128 | *key_val = button; | ||
129 | return NULL; | ||
121 | } | 130 | } |
122 | button = code; | ||
123 | } | 131 | } |
124 | 132 | ||
125 | if (*type == BINDING_KEYSYM) { | 133 | xkb_keycode_t keycode = strtol(name, NULL, 10); |
126 | if (button) { | 134 | if (!xkb_keycode_is_legal_ext(keycode)) { |
127 | if (first_key) { | 135 | if (first_key) { |
128 | *type = BINDING_MOUSE; | 136 | return cmd_results_new(CMD_INVALID, "bindcode", |
129 | *key_val = button; | 137 | "Invalid keycode or button code '%s'", name); |
130 | } else { | ||
131 | return cmd_results_new(CMD_INVALID, "bindsym", | ||
132 | "Mixed button '%s' into key sequence", name); | ||
133 | } | ||
134 | } else if (keysym) { | ||
135 | *key_val = keysym; | ||
136 | } else { | 138 | } else { |
137 | return cmd_results_new(CMD_INVALID, "bindsym", | 139 | return cmd_results_new(CMD_INVALID, "bindcode", |
138 | "Unknown key '%s'", name); | 140 | "Invalid keycode '%s'", name); |
139 | } | 141 | } |
140 | } else { | 142 | } |
141 | if (button) { | 143 | *key_val = keycode; |
144 | } else { | ||
145 | // check for keysym. If it is the first key, allow mouse bindsyms | ||
146 | if (first_key) { | ||
147 | char *message = NULL; | ||
148 | uint32_t button = get_mouse_bindsym(name, &message); | ||
149 | if (message) { | ||
150 | struct cmd_results *error = | ||
151 | cmd_results_new(CMD_INVALID, "bindsym", message); | ||
152 | free(message); | ||
153 | return error; | ||
154 | } else if (button) { | ||
155 | *type = BINDING_MOUSESYM; | ||
142 | *key_val = button; | 156 | *key_val = button; |
143 | } else if (keysym) { | 157 | return NULL; |
158 | } | ||
159 | } | ||
160 | |||
161 | xkb_keysym_t keysym = xkb_keysym_from_name(name, | ||
162 | XKB_KEYSYM_CASE_INSENSITIVE); | ||
163 | if (!keysym) { | ||
164 | if (first_key) { | ||
144 | return cmd_results_new(CMD_INVALID, "bindsym", | 165 | return cmd_results_new(CMD_INVALID, "bindsym", |
145 | "Mixed keysym '%s' into button sequence", name); | 166 | "Unknown key or button '%s'", name); |
146 | } else { | 167 | } else { |
147 | return cmd_results_new(CMD_INVALID, "bindsym", | 168 | return cmd_results_new(CMD_INVALID, "bindsym", |
148 | "Unknown button '%s'", name); | 169 | "Unknown key '%s'", name); |
149 | } | 170 | } |
150 | } | 171 | } |
172 | *key_val = keysym; | ||
151 | } | 173 | } |
152 | return NULL; | 174 | return NULL; |
153 | } | 175 | } |
@@ -201,7 +223,8 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | |||
201 | } | 223 | } |
202 | if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR) | 224 | if (binding->flags & (BINDING_BORDER | BINDING_CONTENTS | BINDING_TITLEBAR) |
203 | || exclude_titlebar) { | 225 | || exclude_titlebar) { |
204 | binding->type = BINDING_MOUSE; | 226 | binding->type = binding->type == BINDING_KEYCODE ? |
227 | BINDING_MOUSECODE : BINDING_MOUSESYM; | ||
205 | } | 228 | } |
206 | 229 | ||
207 | if (argc < 2) { | 230 | if (argc < 2) { |
@@ -249,7 +272,8 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, | |||
249 | // that this is one | 272 | // that this is one |
250 | if (exclude_titlebar) { | 273 | if (exclude_titlebar) { |
251 | binding->flags &= ~BINDING_TITLEBAR; | 274 | binding->flags &= ~BINDING_TITLEBAR; |
252 | } else if (binding->type == BINDING_MOUSE) { | 275 | } else if (binding->type == BINDING_MOUSECODE |
276 | || binding->type == BINDING_MOUSESYM) { | ||
253 | binding->flags |= BINDING_TITLEBAR; | 277 | binding->flags |= BINDING_TITLEBAR; |
254 | } | 278 | } |
255 | 279 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 409e7b12..9af7ef57 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -2,8 +2,10 @@ | |||
2 | #include <math.h> | 2 | #include <math.h> |
3 | #include <libevdev/libevdev.h> | 3 | #include <libevdev/libevdev.h> |
4 | #include <linux/input-event-codes.h> | 4 | #include <linux/input-event-codes.h> |
5 | #include <errno.h> | ||
5 | #include <float.h> | 6 | #include <float.h> |
6 | #include <limits.h> | 7 | #include <limits.h> |
8 | #include <strings.h> | ||
7 | #include <wlr/types/wlr_cursor.h> | 9 | #include <wlr/types/wlr_cursor.h> |
8 | #include <wlr/types/wlr_xcursor_manager.h> | 10 | #include <wlr/types/wlr_xcursor_manager.h> |
9 | #include <wlr/types/wlr_idle.h> | 11 | #include <wlr/types/wlr_idle.h> |
@@ -1533,3 +1535,66 @@ void cursor_warp_to_workspace(struct sway_cursor *cursor, | |||
1533 | 1535 | ||
1534 | wlr_cursor_warp(cursor->cursor, NULL, x, y); | 1536 | wlr_cursor_warp(cursor->cursor, NULL, x, y); |
1535 | } | 1537 | } |
1538 | |||
1539 | uint32_t get_mouse_bindsym(const char *name, char **error) { | ||
1540 | if (strncasecmp(name, "button", strlen("button")) == 0) { | ||
1541 | // Map to x11 mouse buttons | ||
1542 | int number = name[strlen("button")] - '0'; | ||
1543 | if (number < 1 || number > 9 || strlen(name) > strlen("button0")) { | ||
1544 | *error = strdup("Only buttons 1-9 are supported. For other mouse " | ||
1545 | "buttons, use the name of the event code."); | ||
1546 | return 0; | ||
1547 | } | ||
1548 | static const uint32_t buttons[] = {BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, | ||
1549 | SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT, | ||
1550 | SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA}; | ||
1551 | return buttons[number - 1]; | ||
1552 | } else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) { | ||
1553 | // Get event code from name | ||
1554 | int code = libevdev_event_code_from_name(EV_KEY, name); | ||
1555 | if (code == -1) { | ||
1556 | size_t len = snprintf(NULL, 0, "Unknown event %s", name) + 1; | ||
1557 | *error = malloc(len); | ||
1558 | if (*error) { | ||
1559 | snprintf(*error, len, "Unknown event %s", name); | ||
1560 | } | ||
1561 | return 0; | ||
1562 | } | ||
1563 | return code; | ||
1564 | } | ||
1565 | return 0; | ||
1566 | } | ||
1567 | |||
1568 | uint32_t get_mouse_bindcode(const char *name, char **error) { | ||
1569 | // Validate event code | ||
1570 | errno = 0; | ||
1571 | char *endptr; | ||
1572 | int code = strtol(name, &endptr, 10); | ||
1573 | if (endptr == name && code <= 0) { | ||
1574 | *error = strdup("Button event code must be a positive integer."); | ||
1575 | return 0; | ||
1576 | } else if (errno == ERANGE) { | ||
1577 | *error = strdup("Button event code out of range."); | ||
1578 | return 0; | ||
1579 | } | ||
1580 | const char *event = libevdev_event_code_get_name(EV_KEY, code); | ||
1581 | if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) { | ||
1582 | size_t len = snprintf(NULL, 0, "Event code %d (%s) is not a button", | ||
1583 | code, event) + 1; | ||
1584 | *error = malloc(len); | ||
1585 | if (*error) { | ||
1586 | snprintf(*error, len, "Event code %d (%s) is not a button", | ||
1587 | code, event); | ||
1588 | } | ||
1589 | return 0; | ||
1590 | } | ||
1591 | return code; | ||
1592 | } | ||
1593 | |||
1594 | uint32_t get_mouse_button(const char *name, char **error) { | ||
1595 | uint32_t button = get_mouse_bindsym(name, error); | ||
1596 | if (!button && !error) { | ||
1597 | button = get_mouse_bindcode(name, error); | ||
1598 | } | ||
1599 | return button; | ||
1600 | } | ||
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 456db866..ff1bc89f 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -445,8 +445,12 @@ void ipc_event_binding(struct sway_binding *binding) { | |||
445 | json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); | 445 | json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); |
446 | json_object_object_add(json_binding, "symbols", symbols); | 446 | json_object_object_add(json_binding, "symbols", symbols); |
447 | json_object_object_add(json_binding, "symbol", symbol); | 447 | json_object_object_add(json_binding, "symbol", symbol); |
448 | json_object_object_add(json_binding, "input_type", binding->type == BINDING_MOUSE ? | 448 | |
449 | json_object_new_string("mouse") : json_object_new_string("keyboard")); | 449 | bool mouse = binding->type == BINDING_MOUSECODE || |
450 | binding->type == BINDING_MOUSESYM; | ||
451 | json_object_object_add(json_binding, "input_type", mouse | ||
452 | ? json_object_new_string("mouse") | ||
453 | : json_object_new_string("keyboard")); | ||
450 | 454 | ||
451 | json_object *json = json_object_new_object(); | 455 | json_object *json = json_object_new_object(); |
452 | json_object_object_add(json, "change", json_object_new_string("run")); | 456 | json_object_object_add(json, "change", json_object_new_string("run")); |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 3757a097..3398ad58 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -302,7 +302,7 @@ runtime. | |||
302 | ``` | 302 | ``` |
303 | 303 | ||
304 | *bindcode* [--release|--locked] [--input-device=<device>] [--no-warn] <code> <command> | 304 | *bindcode* [--release|--locked] [--input-device=<device>] [--no-warn] <code> <command> |
305 | is also available for binding with key codes instead of key names. | 305 | is also available for binding with key/button codes instead of key/button names. |
306 | 306 | ||
307 | *client.<class>* <border> <background> <text> <indicator> <child\_border> | 307 | *client.<class>* <border> <background> <text> <indicator> <child\_border> |
308 | Configures the color of window borders and title bars. All 5 colors are | 308 | Configures the color of window borders and title bars. All 5 colors are |