11 #include <xkbcommon/xkbcommon.h> 12 #include <xkbcommon/xkbcommon-x11.h> 35 if (strcmp(mode->
name, name) == 0) {
58 const char *release,
const char *border,
const char *whole_window,
59 const char *exclude_titlebar,
const char *command,
const char *modename,
62 DLOG(
"Binding %p bindtype %s, modifiers %s, input code %s, release %s\n", new_binding, bindtype, modifiers, input_code, release);
63 new_binding->
release = (release != NULL ? B_UPON_KEYRELEASE : B_UPON_KEYPRESS);
64 new_binding->
border = (border != NULL);
67 if (strcmp(bindtype,
"bindsym") == 0) {
68 new_binding->
input_type = (strncasecmp(input_code,
"button", (
sizeof(
"button") - 1)) == 0
76 ELOG(
"Could not parse \"%s\" as an input code, ignoring this binding.\n", input_code);
86 int group_bits_set = 0;
95 if (group_bits_set > 1)
96 ELOG(
"Keybinding has more than one Group specified, but your X server is always in precisely one group. The keybinding can never trigger.\n");
111 case XCB_XKB_GROUP_1:
113 case XCB_XKB_GROUP_2:
115 case XCB_XKB_GROUP_3:
117 case XCB_XKB_GROUP_4:
120 ELOG(
"BUG: xkb_current_group (= %d) outside of [XCB_XKB_GROUP_1..XCB_XKB_GROUP_4]\n",
xkb_current_group);
127 #define GRAB_KEY(modifier) \ 129 xcb_grab_key(conn, 0, root, modifier, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); \ 132 DLOG(
"Binding %p Grabbing keycode %d with event state mask 0x%x (mods 0x%x)\n",
165 const int mods = (binding_keycode->
modifiers & 0xFFFF);
166 DLOG(
"Binding %p Grabbing keycode %d with mods %d\n", bind, keycode, mods);
167 xcb_grab_key(conn, 0,
root, mods, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC);
179 xcb_grab_server(conn);
186 xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, con->
window->
id, XCB_BUTTON_MASK_ANY);
191 xcb_ungrab_server(conn);
208 if (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS)
209 bind->
release = B_UPON_KEYRELEASE;
213 const uint32_t xkb_group_state = (state_filtered & 0xFFFF0000);
214 const uint32_t modifiers_state = (state_filtered & 0x0000FFFF);
221 const bool groups_match = ((xkb_group_state & xkb_group_mask) == xkb_group_mask);
223 DLOG(
"skipping binding %p because XKB groups do not match\n", bind);
231 xcb_keycode_t input_keycode = (xcb_keycode_t)input_code;
232 bool found_keycode =
false;
235 const uint32_t modifiers_mask = (binding_keycode->
modifiers & 0x0000FFFF);
236 const bool mods_match = (modifiers_mask == modifiers_state);
237 DLOG(
"binding_keycode->modifiers = %d, modifiers_mask = %d, modifiers_state = %d, mods_match = %s\n",
238 binding_keycode->
modifiers, modifiers_mask, modifiers_state, (mods_match ?
"yes" :
"no"));
239 if (binding_keycode->
keycode == input_keycode && mods_match) {
240 found_keycode =
true;
244 if (!found_keycode) {
249 if (bind->
keycode != input_code) {
253 bool found_keycode =
false;
256 const uint32_t modifiers_mask = (binding_keycode->
modifiers & 0x0000FFFF);
257 const bool mods_match = (modifiers_mask == modifiers_state);
258 DLOG(
"binding_keycode->modifiers = %d, modifiers_mask = %d, modifiers_state = %d, mods_match = %s\n",
259 binding_keycode->
modifiers, modifiers_mask, modifiers_state, (mods_match ?
"yes" :
"no"));
260 if (mods_match || (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS && is_release)) {
261 found_keycode =
true;
265 if (!found_keycode) {
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)) {
302 const bool is_release = (
event->response_type == XCB_KEY_RELEASE ||
303 event->response_type == XCB_BUTTON_RELEASE);
305 const input_type_t input_type = ((
event->response_type == XCB_BUTTON_RELEASE ||
306 event->response_type == XCB_BUTTON_PRESS)
310 const uint16_t event_state = ((xcb_key_press_event_t *)event)->state;
311 const uint16_t event_detail = ((xcb_key_press_event_t *)event)->detail;
315 DLOG(
"(removed capslock, state = 0x%x)\n", state_filtered);
325 switch ((event_state & 0x6000) >> 13) {
326 case XCB_XKB_GROUP_1:
329 case XCB_XKB_GROUP_2:
332 case XCB_XKB_GROUP_3:
335 case XCB_XKB_GROUP_4:
339 state_filtered &= ~0x6000;
340 DLOG(
"(transformed keyboard group, state = 0x%x)\n", state_filtered);
341 return get_binding(state_filtered, is_release, event_detail, input_type);
371 const struct resolve *resolving = data;
373 xkb_keysym_t sym = xkb_state_key_get_one_sym(resolving->
xkb_state, key);
374 if (sym != resolving->
keysym) {
377 const xkb_layout_index_t layout = xkb_state_key_get_layout(resolving->
xkb_state, key);
378 if (layout == XKB_LAYOUT_INVALID)
380 if (xkb_state_key_get_level(resolving->
xkb_state, key, layout) > 1)
384 if (sym >= XKB_KEY_KP_Space && sym <= XKB_KEY_KP_Equal)
388 if (sym != resolving->
keysym)
393 #define ADD_TRANSLATED_KEY(mods) \ 395 struct Binding_Keycode *binding_keycode = smalloc(sizeof(struct Binding_Keycode)); \ 396 binding_keycode->modifiers = (mods); \ 397 binding_keycode->keycode = key; \ 398 TAILQ_INSERT_TAIL(&(bind->keycodes_head), binding_keycode, keycodes); \ 413 xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(numlock_state, key);
414 if (sym_numlock == resolving->
keysym) {
421 DLOG(
"Skipping automatic numlock fallback, key %d resolves to 0x%x with numlock\n",
426 #undef ADD_TRANSLATED_KEY 435 if (dummy_state == NULL) {
436 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
441 if (dummy_state_no_shift == NULL) {
442 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
447 if (dummy_state_numlock == NULL) {
448 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
453 if (dummy_state_numlock_no_shift == NULL) {
454 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
458 bool has_errors =
false;
461 #define ADD_TRANSLATED_KEY(code, mods) \ 463 struct Binding_Keycode *binding_keycode = smalloc(sizeof(struct Binding_Keycode)); \ 464 binding_keycode->modifiers = (mods); \ 465 binding_keycode->keycode = (code); \ 466 TAILQ_INSERT_TAIL(&(bind->keycodes_head), binding_keycode, keycodes); \ 472 ELOG(
"Could not translate string to button: \"%s\"\n", bind->
symbol);
475 xcb_keycode_t key = button;
477 DLOG(
"Binding Mouse button, Keycode = %d\n", key);
480 xkb_layout_index_t group = XCB_XKB_GROUP_1;
482 group = XCB_XKB_GROUP_2;
484 group = XCB_XKB_GROUP_3;
486 group = XCB_XKB_GROUP_4;
488 DLOG(
"Binding %p group = %d, event_state_mask = %d, &2 = %s, &3 = %s, &4 = %s\n",
495 (void)xkb_state_update_mask(
504 (void)xkb_state_update_mask(
505 dummy_state_no_shift,
513 (void)xkb_state_update_mask(
522 (void)xkb_state_update_mask(
523 dummy_state_numlock_no_shift,
552 xkb_keysym_t sym = xkb_state_key_get_one_sym(dummy_state, bind->
keycode);
553 xkb_keysym_t sym_numlock = xkb_state_key_get_one_sym(dummy_state_numlock, bind->
keycode);
554 if (sym == sym_numlock) {
561 DLOG(
"Skipping automatic numlock fallback, key %d resolves to 0x%x with numlock\n",
570 const xkb_keysym_t
keysym = xkb_keysym_from_name(bind->
symbol, XKB_KEYSYM_NO_FLAGS);
571 if (keysym == XKB_KEY_NoSymbol) {
572 ELOG(
"Could not translate string to key symbol: \"%s\"\n",
580 .xkb_state = dummy_state,
581 .xkb_state_no_shift = dummy_state_no_shift,
582 .xkb_state_numlock = dummy_state_numlock,
583 .xkb_state_numlock_no_shift = dummy_state_numlock_no_shift,
592 int num_keycodes = 0;
606 if (check->
symbol != NULL)
616 DLOG(
"state=0x%x, cfg=\"%s\", sym=0x%x → keycodes%s (%d)\n",
620 #undef ADD_TRANSLATED_KEY 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);
640 DLOG(
"Switching to mode %s\n", new_mode);
643 if (strcasecmp(mode->
name, new_mode) != 0)
652 sasprintf(&event_msg,
"{\"change\":\"%s\", \"pango_markup\":%s}",
661 ELOG(
"ERROR: Mode not found\n");
691 struct bindings_head *reordered =
scalloc(1,
sizeof(
struct bindings_head));
693 for (
int i = 0; i < n; i++) {
750 if ((bind->
symbol == NULL && current->
symbol != NULL) ||
756 if (bind->
symbol != NULL &&
769 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keycode %d, command \"%s\"\n",
772 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keysym %s, command \"%s\"\n",
793 *ret_binding_keycode = *binding_keycode;
854 "The configured command for this shortcut could not be run successfully.",
870 xcb_intern_atom_reply_t *atom_reply;
871 size_t content_max_words = 256;
875 atom_reply = xcb_intern_atom_reply(
876 conn, xcb_intern_atom(
conn, 0, strlen(
"_XKB_RULES_NAMES"),
"_XKB_RULES_NAMES"), NULL);
877 if (atom_reply == NULL)
880 xcb_get_property_cookie_t prop_cookie;
881 xcb_get_property_reply_t *prop_reply;
882 prop_cookie = xcb_get_property_unchecked(
conn,
false, root, atom_reply->atom,
883 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
884 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
885 if (prop_reply == NULL) {
889 if (xcb_get_property_value_length(prop_reply) > 0 && prop_reply->bytes_after > 0) {
892 content_max_words += ceil(prop_reply->bytes_after / 4.0);
895 prop_cookie = xcb_get_property_unchecked(
conn,
false, root, atom_reply->atom,
896 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
897 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
898 if (prop_reply == NULL) {
903 if (xcb_get_property_value_length(prop_reply) == 0) {
909 const char *walk = (
const char *)xcb_get_property_value(prop_reply);
910 int remaining = xcb_get_property_value_length(prop_reply);
911 for (
int i = 0; i < 5 && remaining > 0; i++) {
912 const int len = strnlen(walk, remaining);
916 sasprintf((
char **)&(xkb_names->rules),
"%.*s", len, walk);
919 sasprintf((
char **)&(xkb_names->model),
"%.*s", len, walk);
922 sasprintf((
char **)&(xkb_names->layout),
"%.*s", len, walk);
925 sasprintf((
char **)&(xkb_names->variant),
"%.*s", len, walk);
928 sasprintf((
char **)&(xkb_names->options),
"%.*s", len, walk);
931 DLOG(
"component %d of _XKB_RULES_NAMES is \"%.*s\"\n", i, len, walk);
947 ELOG(
"Could not create xkbcommon context\n");
954 if (
xkb_supported && (device_id = xkb_x11_get_core_keyboard_device_id(
conn)) > -1) {
955 if ((new_keymap = xkb_x11_keymap_new_from_device(
xkb_context,
conn, device_id, 0)) == NULL) {
956 ELOG(
"xkb_x11_keymap_new_from_device failed\n");
962 LOG(
"No XKB / core keyboard device? Assembling keymap from local RMLVO.\n");
963 struct xkb_rule_names names = {
970 ELOG(
"Could not get _XKB_RULES_NAMES atom from root window, falling back to defaults.\n");
971 if ((new_keymap = xkb_keymap_new_from_names(
xkb_context, &names, 0)) == NULL) {
972 ELOG(
"xkb_keymap_new_from_names(NULL) failed\n");
976 new_keymap = xkb_keymap_new_from_names(
xkb_context, &names, 0);
977 free((
char *)names.rules);
978 free((
char *)names.model);
979 free((
char *)names.layout);
980 free((
char *)names.variant);
981 free((
char *)names.options);
982 if (new_keymap == NULL) {
983 ELOG(
"xkb_keymap_new_from_names(RMLVO) failed\n");
1005 int buffer[num_max];
1015 if (num + 1 == num_max)
1024 ELOG(
"Could not parse button number, skipping this binding. Please report this bug in i3.\n");
1029 for (
int i = 0; i < num; i++) {
1030 if (buffer[i] == button)
1034 buffer[num++] = button;
1038 int *buttons =
scalloc(num,
sizeof(
int));
1039 memcpy(buttons, buffer, num *
sizeof(
int));
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...
input_type_t
Binding input types.
enum Binding::@12 release
If true, the binding should be executed upon a KeyRelease event, not a KeyPress (the default)...
struct bindings_head * bindings
static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint32_t keycode)
char * sstrdup(const char *str)
Safe-wrapper around strdup which exits if malloc returns NULL (meaning that there is no more memory a...
#define TAILQ_EMPTY(head)
static struct xkb_keymap * xkb_keymap
A 'Con' represents everything from the X11 root window down to a single X11 window.
struct xkb_state * xkb_state_no_shift
char * command
Command, like in command mode.
xcb_connection_t * conn
XCB connection and root screen.
static Binding * get_binding(i3_event_state_mask_t state_filtered, bool is_release, uint16_t input_code, input_type_t input_type)
void switch_mode(const char *new_mode)
Switches the key bindings to the given mode, if the mode exists.
void ipc_send_binding_event(const char *event_type, Binding *bind)
For the binding events, we send the serialized binding struct.
#define TAILQ_INSERT_TAIL(head, elm, field)
const char * DEFAULT_BINDING_MODE
The name of the default mode.
static struct Mode * mode_from_name(const char *name, bool pango_markup)
struct bindings_head * bindings
xcb_screen_t * root_screen
struct xkb_state * xkb_state
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
uint32_t keycode
Keycode to bind.
CommandResult * run_binding(Binding *bind, Con *con)
Runs the given binding and handles parse errors.
pid_t command_error_nagbar_pid
void grab_all_keys(xcb_connection_t *conn)
Grab the bound keys (tell X to send us keypress events for those keycodes)
i3_event_state_mask_t modifiers
bool parse_long(const char *str, long *out, int base)
Converts a string into a long using strtol().
#define TAILQ_FOREACH(var, head, field)
bool exclude_titlebar
If this is true for a mouse binding, the binding should only be executed if the button press was not ...
#define TAILQ_FIRST(head)
void reorder_bindings(void)
Reorders bindings by event_state_mask descendingly so that get_binding() correctly matches more speci...
void check_for_duplicate_bindings(struct context *context)
Checks for duplicate key bindings (the same keycode or keysym is configured more than once)...
void start_config_error_nagbar(const char *configpath, bool has_errors)
Launch nagbar to indicate errors in the configuration file.
#define TAILQ_REMOVE(head, elm, field)
char * pattern
The pattern/name used to load the font.
char * current_configpath
static int reorder_binding_cmp(const void *a, const void *b)
static bool binding_in_current_group(const Binding *bind)
static char * current_mode
keycodes_head
Only in use if symbol != NULL.
struct all_cons_head all_cons
void binding_free(Binding *bind)
Frees the binding.
void * smalloc(size_t size)
Safe-wrapper around malloc 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...
static Binding * binding_copy(Binding *bind)
#define ADD_TRANSLATED_KEY(mods)
bool whole_window
If this is true for a mouse binding, the binding should be executed when the button is pressed over a...
#define SLIST_INSERT_HEAD(head, elm, field)
bool load_keymap(void)
Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
A struct that contains useful information about the result of a command as a whole (e...
static int fill_rmlvo_from_root(struct xkb_rule_names *xkb_names)
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...
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.
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...
i3_event_state_mask_t event_state_mask
Bitmask which is applied against event->state for KeyPress and KeyRelease events to determine whether...
unsigned int xcb_numlock_mask
void translate_keysyms(void)
Translates keysymbols to keycodes for all bindings which use keysyms.
#define SLIST_FOREACH(var, head, field)
The configuration file can contain multiple sets of bindings.
Used during the config file lexing/parsing to keep the state of the lexer in order to provide useful ...
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...
void xcb_grab_buttons(xcb_connection_t *conn, xcb_window_t window, int *buttons)
Grab the specified buttons on a window when managing it.
char * symbol
Symbol the user specified in configfile, if any.
int * bindings_get_buttons_to_grab(void)
Returns a list of buttons that should be grabbed on a window.
struct xkb_state * xkb_state_numlock_no_shift
struct xkb_state * xkb_state_numlock
void tree_render(void)
Renders the tree, that is rendering all outputs using render_con() and pushing the changes to X11 usi...
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...
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...
void start_nagbar(pid_t *nagbar_pid, char *argv[])
Starts an i3-nagbar instance with the given parameters.
static void add_keycode_if_matches(struct xkb_keymap *keymap, xkb_keycode_t key, void *data)
#define GRAB_KEY(modifier)
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.
bool border
If this is true for a mouse binding, the binding should be executed when the button is pressed over t...
Stores a resolved keycode (from a keysym), including the modifier mask.