11 #include <xkbcommon/xkbcommon.h> 12 #include <xkbcommon/xkbcommon-x11.h> 35 if (strcmp(mode->
name, name) == 0)
57 const char *release,
const char *border,
const char *whole_window,
58 const char *command,
const char *modename,
bool pango_markup) {
60 DLOG(
"Binding %p bindtype %s, modifiers %s, input code %s, release %s\n", new_binding, bindtype, modifiers, input_code, release);
61 new_binding->
release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS);
62 new_binding->
border = (border != NULL);
64 if (strcmp(bindtype,
"bindsym") == 0) {
65 new_binding->
input_type = (strncasecmp(input_code,
"button", (
sizeof(
"button") - 1)) == 0
72 long keycode = strtol(input_code, &endptr, 10);
75 if (keycode == LONG_MAX || keycode == LONG_MIN || keycode < 0 || *endptr !=
'\0' || endptr == input_code) {
76 ELOG(
"Could not parse \"%s\" as an input code, ignoring this binding.\n", input_code);
83 int group_bits_set = 0;
92 if (group_bits_set > 1)
93 ELOG(
"Keybinding has more than one Group specified, but your X server is always in precisely one group. The keybinding can never trigger.\n");
108 case XCB_XKB_GROUP_1:
110 case XCB_XKB_GROUP_2:
112 case XCB_XKB_GROUP_3:
114 case XCB_XKB_GROUP_4:
117 ELOG(
"BUG: xkb_current_group (= %d) outside of [XCB_XKB_GROUP_1..XCB_XKB_GROUP_4]\n",
xkb_current_group);
124 #define GRAB_KEY(modifier) \ 126 xcb_grab_key(conn, 0, root, modifier, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); \ 129 DLOG(
"Binding %p Grabbing keycode %d with event state mask 0x%x (mods 0x%x)\n",
160 TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
162 const int mods = (binding_keycode->
modifiers & 0xFFFF);
163 DLOG(
"Binding %p Grabbing keycode %d with mods %d\n", bind, keycode, mods);
164 xcb_grab_key(conn, 0,
root, mods, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
176 xcb_grab_server(conn);
183 xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, con->
window->
id, XCB_BUTTON_MASK_ANY);
188 xcb_ungrab_server(conn);
191 static bool modifiers_match(
const uint32_t modifiers_mask,
const uint32_t modifiers_state) {
194 if (modifiers_mask == 0) {
197 return (modifiers_state == 0);
199 return ((modifiers_state & modifiers_mask) == modifiers_mask);
216 if (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS)
217 bind->
release = B_UPON_KEYRELEASE;
221 const uint32_t xkb_group_state = (state_filtered & 0xFFFF0000);
222 const uint32_t modifiers_state = (state_filtered & 0x0000FFFF);
228 const bool groups_match = ((xkb_group_state & xkb_group_mask) == xkb_group_mask);
230 DLOG(
"skipping binding %p because XKB groups do not match\n", bind);
238 xcb_keycode_t input_keycode = (xcb_keycode_t)input_code;
239 bool found_keycode =
false;
241 TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
242 const uint32_t modifiers_mask = (binding_keycode->
modifiers & 0x0000FFFF);
243 const bool mods_match =
modifiers_match(modifiers_mask, modifiers_state);
244 DLOG(
"binding_keycode->modifiers = %d, modifiers_mask = %d, modifiers_state = %d, mods_match = %s\n",
245 binding_keycode->
modifiers, modifiers_mask, modifiers_state, (mods_match ?
"yes" :
"no"));
246 if (binding_keycode->
keycode == input_keycode && mods_match) {
247 found_keycode =
true;
255 const bool mods_match =
modifiers_match(modifiers_mask, modifiers_state);
256 DLOG(
"binding mods_match = %s\n", (mods_match ?
"yes" :
"no"));
261 (bind->
release != B_UPON_KEYRELEASE_IGNORE_MODS ||
266 if (bind->
keycode != input_code)
274 if (bind->
release == B_UPON_KEYRELEASE && !is_release) {
275 bind->
release = B_UPON_KEYRELEASE_IGNORE_MODS;
276 DLOG(
"marked bind %p as B_UPON_KEYRELEASE_IGNORE_MODS\n", bind);
285 if ((bind->
release == B_UPON_KEYPRESS && is_release) ||
286 (bind->
release >= B_UPON_KEYRELEASE && !is_release))
301 const bool is_release = (
event->response_type == XCB_KEY_RELEASE ||
302 event->response_type == XCB_BUTTON_RELEASE);
304 const input_type_t input_type = ((
event->response_type == XCB_BUTTON_RELEASE ||
305 event->response_type == XCB_BUTTON_PRESS)
309 const uint16_t event_state = ((xcb_key_press_event_t *)event)->state;
310 const uint16_t event_detail = ((xcb_key_press_event_t *)event)->detail;
314 DLOG(
"(removed capslock, state = 0x%x)\n", state_filtered);
324 switch ((event_state & 0x6000) >> 13) {
325 case XCB_XKB_GROUP_1:
328 case XCB_XKB_GROUP_2:
331 case XCB_XKB_GROUP_3:
334 case XCB_XKB_GROUP_4:
338 state_filtered &= ~0x6000;
339 DLOG(
"(transformed keyboard group, state = 0x%x)\n", state_filtered);
340 return get_binding(state_filtered, is_release, event_detail, input_type);
370 const struct resolve *resolving = data;
372 xkb_keysym_t sym = xkb_state_key_get_one_sym(resolving->
xkb_state, key);
373 if (sym != resolving->
keysym) {
376 const xkb_layout_index_t layout = xkb_state_key_get_layout(resolving->
xkb_state, key);
377 if (layout == XKB_LAYOUT_INVALID)
379 if (xkb_state_key_get_level(resolving->
xkb_state, key, layout) > 1)
383 if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_Equal)
387 if (sym != resolving->
keysym)
392 #define ADD_TRANSLATED_KEY(mods) \ 394 struct Binding_Keycode *binding_keycode = smalloc(sizeof(struct Binding_Keycode)); \ 395 binding_keycode->modifiers = (mods); \ 396 binding_keycode->keycode = key; \ 397 TAILQ_INSERT_TAIL(&(bind->keycodes_head), binding_keycode, keycodes); \ 412 xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(numlock_state, key);
413 if (sym_numlock == resolving->
keysym) {
420 DLOG(
"Skipping automatic numlock fallback, key %d resolves to 0x%x with numlock\n",
425 #undef ADD_TRANSLATED_KEY 434 if (dummy_state == NULL) {
435 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
440 if (dummy_state_no_shift == NULL) {
441 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
446 if (dummy_state_numlock == NULL) {
447 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
452 if (dummy_state_numlock_no_shift == NULL) {
453 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
457 bool has_errors =
false;
462 long button = strtol(bind->
symbol + (
sizeof(
"button") - 1), &endptr, 10);
465 if (button == LONG_MAX || button == LONG_MIN || button < 0 || *endptr != '\0' || endptr == bind->symbol)
466 ELOG(
"Could not translate string to button: \"%s\"\n", bind->
symbol);
475 const xkb_keysym_t
keysym = xkb_keysym_from_name(bind->
symbol, XKB_KEYSYM_NO_FLAGS);
476 if (keysym == XKB_KEY_NoSymbol) {
477 ELOG(
"Could not translate string to key symbol: \"%s\"\n",
482 xkb_layout_index_t group = XCB_XKB_GROUP_1;
484 group = XCB_XKB_GROUP_2;
486 group = XCB_XKB_GROUP_3;
488 group = XCB_XKB_GROUP_4;
490 DLOG(
"Binding %p group = %d, event_state_mask = %d, &2 = %s, &3 = %s, &4 = %s\n",
497 (void)xkb_state_update_mask(
506 (void)xkb_state_update_mask(
507 dummy_state_no_shift,
515 (void)xkb_state_update_mask(
524 (void)xkb_state_update_mask(
525 dummy_state_numlock_no_shift,
536 .xkb_state = dummy_state,
537 .xkb_state_no_shift = dummy_state_no_shift,
538 .xkb_state_numlock = dummy_state_numlock,
539 .xkb_state_numlock_no_shift = dummy_state_numlock_no_shift,
548 int num_keycodes = 0;
550 TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
562 if (check->
symbol != NULL)
572 DLOG(
"state=0x%x, cfg=\"%s\", sym=0x%x → keycodes%s (%d)\n",
577 xkb_state_unref(dummy_state);
578 xkb_state_unref(dummy_state_no_shift);
579 xkb_state_unref(dummy_state_numlock);
580 xkb_state_unref(dummy_state_numlock_no_shift);
594 DLOG(
"Switching to mode %s\n", new_mode);
597 if (strcasecmp(mode->
name, new_mode) != 0)
606 sasprintf(&event_msg,
"{\"change\":\"%s\", \"pango_markup\":%s}",
615 ELOG(
"ERROR: Mode not found\n");
645 struct bindings_head *reordered =
scalloc(1,
sizeof(
struct bindings_head));
647 for (
int i = 0; i < n; i++) {
704 if ((bind->
symbol == NULL && current->
symbol != NULL) ||
710 if (bind->
symbol != NULL &&
723 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keycode %d, command \"%s\"\n",
726 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keysym %s, command \"%s\"\n",
745 TAILQ_FOREACH(binding_keycode, &(bind->keycodes_head), keycodes) {
747 *ret_binding_keycode = *binding_keycode;
808 "The configured command for this shortcut could not be run successfully.",
824 xcb_intern_atom_reply_t *atom_reply;
825 size_t content_max_words = 256;
829 atom_reply = xcb_intern_atom_reply(
830 conn, xcb_intern_atom(
conn, 0, strlen(
"_XKB_RULES_NAMES"),
"_XKB_RULES_NAMES"), NULL);
831 if (atom_reply == NULL)
834 xcb_get_property_cookie_t prop_cookie;
835 xcb_get_property_reply_t *prop_reply;
836 prop_cookie = xcb_get_property_unchecked(
conn,
false, root, atom_reply->atom,
837 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
838 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
839 if (prop_reply == NULL) {
843 if (xcb_get_property_value_length(prop_reply) > 0 && prop_reply->bytes_after > 0) {
846 content_max_words += ceil(prop_reply->bytes_after / 4.0);
849 prop_cookie = xcb_get_property_unchecked(
conn,
false, root, atom_reply->atom,
850 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
851 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
852 if (prop_reply == NULL) {
857 if (xcb_get_property_value_length(prop_reply) == 0) {
863 const char *walk = (
const char *)xcb_get_property_value(prop_reply);
864 int remaining = xcb_get_property_value_length(prop_reply);
865 for (
int i = 0; i < 5 && remaining > 0; i++) {
866 const int len = strnlen(walk, remaining);
870 sasprintf((
char **)&(xkb_names->rules),
"%.*s", len, walk);
873 sasprintf((
char **)&(xkb_names->model),
"%.*s", len, walk);
876 sasprintf((
char **)&(xkb_names->layout),
"%.*s", len, walk);
879 sasprintf((
char **)&(xkb_names->variant),
"%.*s", len, walk);
882 sasprintf((
char **)&(xkb_names->options),
"%.*s", len, walk);
885 DLOG(
"component %d of _XKB_RULES_NAMES is \"%.*s\"\n", i, len, walk);
901 ELOG(
"Could not create xkbcommon context\n");
908 if (
xkb_supported && (device_id = xkb_x11_get_core_keyboard_device_id(
conn)) > -1) {
909 if ((new_keymap = xkb_x11_keymap_new_from_device(
xkb_context,
conn, device_id, 0)) == NULL) {
910 ELOG(
"xkb_x11_keymap_new_from_device failed\n");
916 LOG(
"No XKB / core keyboard device? Assembling keymap from local RMLVO.\n");
917 struct xkb_rule_names names = {
924 ELOG(
"Could not get _XKB_RULES_NAMES atom from root window, falling back to defaults.\n");
925 if ((new_keymap = xkb_keymap_new_from_names(
xkb_context, &names, 0)) == NULL) {
926 ELOG(
"xkb_keymap_new_from_names(NULL) failed\n");
930 new_keymap = xkb_keymap_new_from_names(
xkb_context, &names, 0);
931 free((
char *)names.rules);
932 free((
char *)names.model);
933 free((
char *)names.layout);
934 free((
char *)names.variant);
935 free((
char *)names.options);
936 if (new_keymap == NULL) {
937 ELOG(
"xkb_keymap_new_from_names(RMLVO) failed\n");
969 if (num + 1 == num_max)
977 long button = strtol(bind->
symbol + (
sizeof(
"button") - 1), &endptr, 10);
978 if (button == LONG_MAX || button == LONG_MIN || button < 0 || *endptr != '\0' || endptr == bind->symbol) {
979 ELOG(
"Could not parse button number, skipping this binding. Please report this bug in i3.\n");
984 for (
int i = 0; i < num_max; i++) {
985 if (buffer[i] == button)
989 buffer[num++] = button;
993 int *buttons =
scalloc(num,
sizeof(
int));
994 memcpy(buttons, buffer, num *
sizeof(
int));
struct bindings_head * bindings
xcb_screen_t * root_screen
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint32_t keycode)
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...
static struct xkb_keymap * xkb_keymap
bool whole_window
If this is true for a mouse binding, the binding should be executed when the button is pressed over a...
static Binding * get_binding(i3_event_state_mask_t state_filtered, bool is_release, uint16_t input_code, input_type_t input_type)
Used during the config file lexing/parsing to keep the state of the lexer in order to provide useful ...
void switch_mode(const char *new_mode)
Switches the key bindings to the given mode, if the mode exists.
struct bindings_head * bindings
const char * DEFAULT_BINDING_MODE
The name of the default mode.
static struct Mode * mode_from_name(const char *name, bool pango_markup)
static void reorder_bindings_of_mode(struct Mode *mode)
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...
static struct xkb_context * xkb_context
CommandResult * run_binding(Binding *bind, Con *con)
Runs the given binding and handles parse errors.
pid_t command_error_nagbar_pid
#define TAILQ_INSERT_TAIL(head, elm, field)
char * command
Command, like in command mode.
struct xkb_state * xkb_state_numlock
void grab_all_keys(xcb_connection_t *conn)
Grab the bound keys (tell X to send us keypress events for those keycodes)
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
Stores a resolved keycode (from a keysym), including the modifier mask.
xcb_connection_t * conn
XCB connection and root screen.
#define TAILQ_FOREACH(var, head, field)
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 reorder_bindings(void)
Reorders bindings by event_state_mask descendingly so that get_binding() correctly matches more speci...
#define TAILQ_FIRST(head)
void check_for_duplicate_bindings(struct context *context)
Checks for duplicate key bindings (the same keycode or keysym is configured more than once)...
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
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...
void ipc_send_binding_event(const char *event_type, Binding *bind)
For the binding events, we send the serialized binding struct.
bool border
If this is true for a mouse binding, the binding should be executed when the button is pressed over t...
#define TAILQ_REMOVE(head, elm, field)
void start_config_error_nagbar(const char *configpath, bool has_errors)
Launch nagbar to indicate errors in the configuration file.
char * current_configpath
static int reorder_binding_cmp(const void *a, const void *b)
enum Binding::@12 release
If true, the binding should be executed upon a KeyRelease event, not a KeyPress (the default)...
static bool binding_in_current_group(const Binding *bind)
static char * current_mode
struct xkb_state * xkb_state
void binding_free(Binding *bind)
Frees the binding.
i3_event_state_mask_t modifiers
unsigned int xcb_numlock_mask
static Binding * binding_copy(Binding *bind)
char * symbol
Symbol the user specified in configfile, if any.
#define ADD_TRANSLATED_KEY(mods)
A struct that contains useful information about the result of a command as a whole (e...
bool load_keymap(void)
Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
struct all_cons_head all_cons
static int fill_rmlvo_from_root(struct xkb_rule_names *xkb_names)
void * smalloc(size_t size)
Safe-wrapper around malloc which exits if malloc returns NULL (meaning that there is no more memory a...
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...
CommandResult * parse_command(const char *input, yajl_gen gen)
Parses and executes the given command.
struct xkb_state * xkb_state_no_shift
struct xkb_state * xkb_state_numlock_no_shift
A 'Con' represents everything from the X11 root window down to a single X11 window.
The configuration file can contain multiple sets of bindings.
#define SLIST_FOREACH(var, head, field)
void translate_keysyms(void)
Translates keysymbols to keycodes for all bindings which use keysyms.
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...
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.
int * bindings_get_buttons_to_grab(void)
Returns a list of buttons that should be grabbed on a window.
void xcb_grab_buttons(xcb_connection_t *conn, xcb_window_t window, int *buttons)
Grab the specified buttons on a window when managing it.
#define TAILQ_EMPTY(head)
static bool modifiers_match(const uint32_t modifiers_mask, const uint32_t modifiers_state)
uint32_t keycode
Keycode to bind.
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 *command, const char *modename, bool pango_markup)
Adds a binding from config parameters given as strings and returns a pointer to the binding structure...
i3_event_state_mask_t event_state_mask
Bitmask which is applied against event->state for KeyPress and KeyRelease events to determine whether...
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 void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
#define GRAB_KEY(modifier)
#define SLIST_INSERT_HEAD(head, elm, field)
input_type_t
Binding input types.
char * pattern
The pattern/name used to load the font.
void start_nagbar(pid_t *nagbar_pid, char *argv[])
Starts an i3-nagbar instance with the given parameters.