13#include <xkbcommon/xkbcommon-x11.h>
14#include <xkbcommon/xkbcommon.h>
60 const char *release,
const char *border,
const char *whole_window,
61 const char *exclude_titlebar,
const char *command,
const char *modename,
64 DLOG(
"Binding %p bindtype %s, modifiers %s, input code %s, release %s\n", new_binding, bindtype, modifiers, input_code, release);
65 new_binding->
release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS);
66 new_binding->
border = (border != NULL);
69 if (strcmp(bindtype,
"bindsym") == 0) {
70 new_binding->
input_type = (strncasecmp(input_code,
"button", (
sizeof(
"button") - 1)) == 0
78 ELOG(
"Could not parse \"%s\" as an input code, ignoring this binding.\n", input_code);
88 int group_bits_set = 0;
101 if (group_bits_set > 1) {
102 ELOG(
"Keybinding has more than one Group specified, but your X server is always in precisely one group. The keybinding can never trigger.\n");
119 case XCB_XKB_GROUP_1:
121 case XCB_XKB_GROUP_2:
123 case XCB_XKB_GROUP_3:
125 case XCB_XKB_GROUP_4:
128 ELOG(
"BUG: xkb_current_group (= %d) outside of [XCB_XKB_GROUP_1..XCB_XKB_GROUP_4]\n",
xkb_current_group);
135#define GRAB_KEY(modifier) \
137 xcb_grab_key(conn, 0, root, modifier, keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); \
140 DLOG(
"Binding %p Grabbing keycode %d with event state mask 0x%x (mods 0x%x)\n",
173 TAILQ_FOREACH (binding_keycode, &(bind->keycodes_head), keycodes) {
175 const int mods = (binding_keycode->
modifiers & 0xFFFF);
176 DLOG(
"Binding %p Grabbing keycode %d with mods %d\n", bind,
keycode, mods);
177 xcb_grab_key(
conn, 0,
root, mods,
keycode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
189 xcb_grab_server(
conn);
193 if (con->
window == NULL) {
197 xcb_ungrab_button(
conn, XCB_BUTTON_INDEX_ANY, con->
window->
id, XCB_BUTTON_MASK_ANY);
202 xcb_ungrab_server(
conn);
221 if (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS) {
222 bind->
release = B_UPON_KEYRELEASE;
227 const uint32_t xkb_group_state = (state_filtered & 0xFFFF0000);
228 const uint32_t modifiers_state = (state_filtered & 0x0000FFFF);
235 const bool groups_match = ((xkb_group_state & xkb_group_mask) == xkb_group_mask);
237 DLOG(
"skipping binding %p because XKB groups do not match\n", bind);
244 bool found_keycode =
false;
246 xcb_keycode_t input_keycode = (xcb_keycode_t)input_code;
248 TAILQ_FOREACH (binding_keycode, &(bind->keycodes_head), keycodes) {
249 const uint32_t modifiers_mask = (binding_keycode->
modifiers & 0x0000FFFF);
250 const bool mods_match = (modifiers_mask == modifiers_state);
251 DLOG(
"binding_keycode->modifiers = %d, modifiers_mask = %d, modifiers_state = %d, mods_match = %s\n",
252 binding_keycode->
modifiers, modifiers_mask, modifiers_state, (mods_match ?
"yes" :
"no"));
253 if (binding_keycode->
keycode == input_keycode &&
254 (mods_match || (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS && is_release))) {
255 found_keycode =
true;
261 if (bind->
keycode != input_code) {
266 TAILQ_FOREACH (binding_keycode, &(bind->keycodes_head), keycodes) {
267 const uint32_t modifiers_mask = (binding_keycode->
modifiers & 0x0000FFFF);
268 const bool mods_match = (modifiers_mask == modifiers_state);
269 DLOG(
"binding_keycode->modifiers = %d, modifiers_mask = %d, modifiers_state = %d, mods_match = %s\n",
270 binding_keycode->
modifiers, modifiers_mask, modifiers_state, (mods_match ?
"yes" :
"no"));
271 if (mods_match || (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS && is_release)) {
272 found_keycode =
true;
277 if (!found_keycode) {
285 if (bind->
release == B_UPON_KEYRELEASE && !is_release) {
286 bind->
release = B_UPON_KEYRELEASE_IGNORE_MODS;
287 DLOG(
"marked bind %p as B_UPON_KEYRELEASE_IGNORE_MODS\n", bind);
295 if ((bind->
release == B_UPON_KEYPRESS && is_release)) {
301 }
else if (!result) {
316 const bool is_release = (
event->response_type == XCB_KEY_RELEASE ||
317 event->response_type == XCB_BUTTON_RELEASE);
319 const input_type_t input_type = ((
event->response_type == XCB_BUTTON_RELEASE ||
320 event->response_type == XCB_BUTTON_PRESS)
324 const uint16_t event_state = ((xcb_key_press_event_t *)event)->state;
325 const uint16_t event_detail = ((xcb_key_press_event_t *)event)->detail;
329 DLOG(
"(removed capslock, state = 0x%x)\n", state_filtered);
339 switch ((event_state & 0x6000) >> 13) {
340 case XCB_XKB_GROUP_1:
343 case XCB_XKB_GROUP_2:
346 case XCB_XKB_GROUP_3:
349 case XCB_XKB_GROUP_4:
353 state_filtered &= ~0x6000;
354 DLOG(
"(transformed keyboard group, state = 0x%x)\n", state_filtered);
355 return get_binding(state_filtered, is_release, event_detail, input_type);
378#define ADD_TRANSLATED_KEY(code, mods) \
380 struct Binding_Keycode *binding_keycode = smalloc(sizeof(struct Binding_Keycode)); \
381 binding_keycode->modifiers = (mods); \
382 binding_keycode->keycode = (code); \
383 TAILQ_INSERT_TAIL(&(bind->keycodes_head), binding_keycode, keycodes); \
393 const struct resolve *resolving = data;
395 xkb_keysym_t sym = xkb_state_key_get_one_sym(resolving->
xkb_state, key);
396 if (sym != resolving->
keysym) {
399 const xkb_layout_index_t layout = xkb_state_key_get_layout(resolving->
xkb_state, key);
400 if (layout == XKB_LAYOUT_INVALID) {
403 if (xkb_state_key_get_level(resolving->
xkb_state, key, layout) > 1) {
408 if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_Equal) {
413 if (sym != resolving->
keysym) {
431 xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(numlock_state, key);
432 if (sym_numlock == resolving->
keysym) {
439 DLOG(
"Skipping automatic numlock fallback, key %d resolves to 0x%x with numlock\n",
450 struct xkb_state *dummy_state = NULL;
451 struct xkb_state *dummy_state_no_shift = NULL;
452 struct xkb_state *dummy_state_numlock = NULL;
453 struct xkb_state *dummy_state_numlock_no_shift = NULL;
454 bool has_errors =
false;
456 if ((dummy_state = xkb_state_new(
xkb_keymap)) == NULL ||
457 (dummy_state_no_shift = xkb_state_new(
xkb_keymap)) == NULL ||
458 (dummy_state_numlock = xkb_state_new(
xkb_keymap)) == NULL ||
459 (dummy_state_numlock_no_shift = xkb_state_new(
xkb_keymap)) == NULL) {
460 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
469 ELOG(
"Could not translate string to button: \"%s\"\n", bind->
symbol);
472 xcb_keycode_t key = button;
474 DLOG(
"Binding Mouse button, Keycode = %d\n", key);
477 xkb_layout_index_t group = XCB_XKB_GROUP_1;
479 group = XCB_XKB_GROUP_2;
481 group = XCB_XKB_GROUP_3;
483 group = XCB_XKB_GROUP_4;
486 DLOG(
"Binding %p group = %d, event_state_mask = %d, &2 = %s, &3 = %s, &4 = %s\n",
493 (void)xkb_state_update_mask(
502 (void)xkb_state_update_mask(
503 dummy_state_no_shift,
511 (void)xkb_state_update_mask(
520 (void)xkb_state_update_mask(
521 dummy_state_numlock_no_shift,
550 xkb_keysym_t sym = xkb_state_key_get_one_sym(dummy_state, bind->
keycode);
551 xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(dummy_state_numlock, bind->
keycode);
552 if (sym == sym_numlock) {
559 DLOG(
"Skipping automatic numlock fallback, key %d resolves to 0x%x with numlock\n",
568 const xkb_keysym_t keysym = xkb_keysym_from_name(bind->
symbol, XKB_KEYSYM_NO_FLAGS);
569 if (keysym == XKB_KEY_NoSymbol) {
570 ELOG(
"Could not translate string to key symbol: \"%s\"\n",
578 .xkb_state = dummy_state,
579 .xkb_state_no_shift = dummy_state_no_shift,
580 .xkb_state_numlock = dummy_state_numlock,
581 .xkb_state_numlock_no_shift = dummy_state_numlock_no_shift,
590 int num_keycodes = 0;
592 TAILQ_FOREACH (binding_keycode, &(bind->keycodes_head), keycodes) {
605 if (check->
symbol != NULL) {
617 DLOG(
"state=0x%x, cfg=\"%s\", sym=0x%x → keycodes%s (%d)\n",
623 xkb_state_unref(dummy_state);
624 xkb_state_unref(dummy_state_no_shift);
625 xkb_state_unref(dummy_state_numlock);
626 xkb_state_unref(dummy_state_numlock_no_shift);
633#undef ADD_TRANSLATED_KEY
642 DLOG(
"Switching to mode %s\n", new_mode);
645 if (strcmp(mode->
name, new_mode) != 0) {
660 if (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS) {
661 bind->
release = B_UPON_KEYRELEASE;
666 sasprintf(&event_msg,
"{\"change\":\"%s\", \"pango_markup\":%s}",
675 ELOG(
"Mode not found\n");
705 struct bindings_head *reordered =
scalloc(1,
sizeof(
struct bindings_head));
707 for (
int i = 0; i < n; i++) {
790 if (bind == current) {
800 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keycode %d, command \"%s\"\n",
803 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keysym %s, command \"%s\"\n",
816 if (bind->
symbol != NULL) {
824 TAILQ_FOREACH (binding_keycode, &(bind->keycodes_head), keycodes) {
826 *ret_binding_keycode = *binding_keycode;
893 "The configured command for this shortcut could not be run successfully.",
910 xcb_intern_atom_reply_t *atom_reply;
911 size_t content_max_words = 256;
913 atom_reply = xcb_intern_atom_reply(
914 conn, xcb_intern_atom(
conn, 0, strlen(
"_XKB_RULES_NAMES"),
"_XKB_RULES_NAMES"), NULL);
915 if (atom_reply == NULL) {
919 xcb_get_property_cookie_t prop_cookie;
920 xcb_get_property_reply_t *prop_reply;
921 prop_cookie = xcb_get_property_unchecked(
conn,
false,
root, atom_reply->atom,
922 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
923 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
924 if (prop_reply == NULL) {
928 if (xcb_get_property_value_length(prop_reply) > 0 && prop_reply->bytes_after > 0) {
931 content_max_words += ceil(prop_reply->bytes_after / 4.0);
934 prop_cookie = xcb_get_property_unchecked(
conn,
false,
root, atom_reply->atom,
935 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
936 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
937 if (prop_reply == NULL) {
942 if (xcb_get_property_value_length(prop_reply) == 0) {
948 const char *walk = (
const char *)xcb_get_property_value(prop_reply);
949 int remaining = xcb_get_property_value_length(prop_reply);
950 for (
int i = 0; i < 5 && remaining > 0; i++) {
951 const int len = strnlen(walk, remaining);
954 sasprintf((
char **)&(xkb_names->rules),
"%.*s", len, walk);
957 sasprintf((
char **)&(xkb_names->model),
"%.*s", len, walk);
960 sasprintf((
char **)&(xkb_names->layout),
"%.*s", len, walk);
963 sasprintf((
char **)&(xkb_names->variant),
"%.*s", len, walk);
966 sasprintf((
char **)&(xkb_names->options),
"%.*s", len, walk);
969 DLOG(
"component %d of _XKB_RULES_NAMES is \"%.*s\"\n", i, len, walk);
971 remaining -= (len + 1);
986 ELOG(
"Could not create xkbcommon context\n");
993 if (
xkb_supported && (device_id = xkb_x11_get_core_keyboard_device_id(
conn)) > -1) {
994 if ((new_keymap = xkb_x11_keymap_new_from_device(
xkb_context,
conn, device_id, 0)) == NULL) {
995 ELOG(
"xkb_x11_keymap_new_from_device failed\n");
1001 LOG(
"No XKB / core keyboard device? Assembling keymap from local RMLVO.\n");
1002 struct xkb_rule_names names = {
1009 ELOG(
"Could not get _XKB_RULES_NAMES atom from root window, falling back to defaults.\n");
1012 new_keymap = xkb_keymap_new_from_names(
xkb_context, &names, 0);
1013 free((
char *)names.rules);
1014 free((
char *)names.model);
1015 free((
char *)names.layout);
1016 free((
char *)names.variant);
1017 free((
char *)names.options);
1018 if (new_keymap == NULL) {
1019 ELOG(
"xkb_keymap_new_from_names failed\n");
1039 const int num_max = 25;
1041 int buffer[num_max];
1051 if (num + 1 == num_max) {
1062 ELOG(
"Could not parse button number, skipping this binding. Please report this bug in i3.\n");
1067 bool exists =
false;
1068 for (
int i = 0; i < num; i++) {
1069 if (buffer[i] == button) {
1076 buffer[num++] = button;
1081 int *buttons =
scalloc(num,
sizeof(
int));
1082 memcpy(buttons, buffer, num *
sizeof(
int));
void binding_free(Binding *bind)
Frees the binding.
static struct xkb_context * xkb_context
void check_for_duplicate_bindings(struct context *context)
Checks for duplicate key bindings (the same keycode or keysym is configured more than once).
static bool binding_same_key(Binding *a, Binding *b)
static Binding * binding_copy(Binding *bind)
bool load_keymap(void)
Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
static int reorder_binding_cmp(const void *a, const void *b)
void grab_all_keys(xcb_connection_t *conn)
Grab the bound keys (tell X to send us keypress events for those keycodes)
static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
const char * DEFAULT_BINDING_MODE
The name of the default mode.
static struct xkb_keymap * xkb_keymap
static Binding * get_binding(i3_event_state_mask_t state_filtered, bool is_release, uint16_t input_code, input_type_t input_type)
Binding * get_binding_from_xcb_event(xcb_generic_event_t *event)
Returns a pointer to the Binding that matches the given xcb event or NULL if no such binding exists.
void regrab_all_buttons(xcb_connection_t *conn)
Release the button grabs on all managed windows and regrab them, reevaluating which buttons need to b...
int * bindings_get_buttons_to_grab(void)
Returns a list of buttons that should be grabbed on a window.
void switch_mode(const char *new_mode)
Switches the key bindings to the given mode, if the mode exists.
static int fill_rmlvo_from_root(struct xkb_rule_names *xkb_names)
Binding * configure_binding(const char *bindtype, const char *modifiers, const char *input_code, const char *release, const char *border, const char *whole_window, const char *exclude_titlebar, const char *command, const char *modename, bool pango_markup)
Adds a binding from config parameters given as strings and returns a pointer to the binding structure...
#define GRAB_KEY(modifier)
static struct Mode * mode_from_name(const char *name, bool pango_markup)
static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint32_t keycode)
pid_t command_error_nagbar_pid
CommandResult * run_binding(Binding *bind, Con *con)
Runs the given binding and handles parse errors.
#define ADD_TRANSLATED_KEY(code, mods)
static void reorder_bindings_of_mode(struct Mode *mode)
void reorder_bindings(void)
Reorders bindings by event_state_mask descendingly so that get_binding() correctly matches more speci...
static bool binding_in_current_group(const Binding *bind)
void translate_keysyms(void)
Translates keysymbols to keycodes for all bindings which use keysyms.
CommandResult * parse_command(const char *input, yajl_gen gen, ipc_client *client)
Parses and executes the given command.
char * current_configpath
void ungrab_all_keys(xcb_connection_t *conn)
Ungrabs all keys, to be called before re-grabbing the keys because of a mapping_notify event or a con...
static char * current_mode
i3_event_state_mask_t event_state_from_str(const char *str)
A utility function to convert a string containing the group and modifiers to the corresponding bit ma...
void start_config_error_nagbar(const char *configpath, bool has_errors)
Launch nagbar to indicate errors in the configuration file.
struct all_cons_head all_cons
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
void start_nagbar(pid_t *nagbar_pid, char *argv[])
Starts an i3-nagbar instance with the given parameters.
bool parse_long(const char *str, long *out, int base)
Converts a string into a long using strtol().
unsigned int xcb_numlock_mask
void xcb_grab_buttons(xcb_connection_t *conn, xcb_window_t window, int *buttons)
Grab the specified buttons on a window when managing it.
void ipc_send_binding_event(const char *event_type, Binding *bind, const char *modename)
For the binding events, we send the serialized binding struct.
void ipc_send_event(const char *event, uint32_t message_type, const char *payload)
Sends the specified event to all IPC clients which are currently connected and subscribed to this kin...
xcb_connection_t * conn
XCB connection and root screen.
const char * current_binding_mode
struct bindings_head * bindings
uint32_t i3_event_state_mask_t
The lower 16 bits contain a xcb_key_but_mask_t, the higher 16 bits contain an i3_xkb_group_mask_t.
input_type_t
Binding input types.
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
void * scalloc(size_t num, size_t size)
Safe-wrapper around calloc which exits if malloc returns NULL (meaning that there is no more memory a...
int sasprintf(char **strp, const char *fmt,...)
Safe-wrapper around asprintf which exits if it returns -1 (meaning that there is no more memory avail...
void * smalloc(size_t size)
Safe-wrapper around malloc which exits if malloc returns NULL (meaning that there is no more memory a...
#define SLIST_FOREACH(var, head, field)
#define TAILQ_FOREACH(var, head, field)
#define SLIST_INSERT_HEAD(head, elm, field)
#define TAILQ_INSERT_TAIL(head, elm, field)
#define TAILQ_FIRST(head)
#define TAILQ_REMOVE(head, elm, field)
#define TAILQ_EMPTY(head)
struct xkb_state * xkb_state_numlock_no_shift
struct xkb_state * xkb_state
struct xkb_state * xkb_state_numlock
struct xkb_state * xkb_state_no_shift
A struct that contains useful information about the result of a command as a whole (e....
Used during the config file lexing/parsing to keep the state of the lexer in order to provide useful ...
The configuration file can contain multiple sets of bindings.
struct bindings_head * bindings
Stores a resolved keycode (from a keysym), including the modifier mask.
i3_event_state_mask_t modifiers
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
bool whole_window
If this is true for a mouse binding, the binding should be executed when the button is pressed over a...
char * command
Command, like in command mode.
bool border
If this is true for a mouse binding, the binding should be executed when the button is pressed over t...
uint32_t keycode
Keycode to bind.
char * symbol
Symbol the user specified in configfile, if any.
enum Binding::@10 release
If true, the binding should be executed upon a KeyRelease event, not a KeyPress (the default).
bool exclude_titlebar
If this is true for a mouse binding, the binding should only be executed if the button press was not ...
i3_event_state_mask_t event_state_mask
Bitmask which is applied against event->state for KeyPress and KeyRelease events to determine whether...
A 'Con' represents everything from the X11 root window down to a single X11 window.
char * pattern
The pattern/name used to load the font.