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(
"bindtype %s, modifiers %s, input code %s, release %s\n", 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");
106 #define GRAB_KEY(modifier) \
108 xcb_grab_key(conn, 0, root, modifier, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC); \
120 DLOG(
"Grabbing keycode %d with event state mask 0x%x (mods 0x%x)\n",
156 xcb_grab_server(conn);
163 xcb_ungrab_button(conn, XCB_BUTTON_INDEX_ANY, con->
window->
id, XCB_BUTTON_MASK_ANY);
167 xcb_ungrab_server(conn);
184 if (bind->
release == B_UPON_KEYRELEASE_IGNORE_MODS)
185 bind->
release = B_UPON_KEYRELEASE;
189 const uint32_t xkb_group_state = (state_filtered & 0xFFFF0000);
190 const uint32_t modifiers_state = (state_filtered & 0x0000FFFF);
196 const bool groups_match = ((xkb_group_state & xkb_group_mask) == xkb_group_mask);
198 if (modifiers_mask == 0) {
201 mods_match = (modifiers_state == 0);
203 mods_match = ((modifiers_state & modifiers_mask) == modifiers_mask);
205 const bool state_matches = (groups_match && mods_match);
207 DLOG(
"binding groups_match = %s, mods_match = %s, state_matches = %s\n",
208 (groups_match ?
"yes" :
"no"),
209 (mods_match ?
"yes" :
"no"),
210 (state_matches ?
"yes" :
"no"));
216 if (!state_matches &&
217 (bind->
release != B_UPON_KEYRELEASE_IGNORE_MODS ||
225 xcb_keycode_t input_keycode = (xcb_keycode_t)input_code;
228 &input_keycode,
sizeof(xcb_keycode_t)) == NULL)
232 if (bind->
keycode != input_code)
240 if (bind->
release == B_UPON_KEYRELEASE && !is_release)
241 bind->
release = B_UPON_KEYRELEASE_IGNORE_MODS;
244 if ((bind->
release == B_UPON_KEYPRESS && is_release) ||
245 (bind->
release >= B_UPON_KEYRELEASE && !is_release))
260 const bool is_release = (
event->response_type == XCB_KEY_RELEASE ||
261 event->response_type == XCB_BUTTON_RELEASE);
263 const input_type_t input_type = ((
event->response_type == XCB_BUTTON_RELEASE ||
264 event->response_type == XCB_BUTTON_PRESS)
268 const uint16_t event_state = ((xcb_key_press_event_t *)event)->state;
269 const uint16_t event_detail = ((xcb_key_press_event_t *)event)->detail;
273 DLOG(
"(removed numlock, state = 0x%x)\n", state_filtered);
283 switch ((event_state & 0x6000) >> 13) {
284 case XCB_XKB_GROUP_1:
287 case XCB_XKB_GROUP_2:
290 case XCB_XKB_GROUP_3:
293 case XCB_XKB_GROUP_4:
297 state_filtered &= ~0x6000;
298 DLOG(
"(transformed keyboard group, state = 0x%x)\n", state_filtered);
299 return get_binding(state_filtered, is_release, event_detail, input_type);
323 const struct resolve *resolving = data;
324 xkb_keysym_t sym = xkb_state_key_get_one_sym(resolving->
xkb_state, key);
325 if (sym != resolving->
keysym) {
328 const xkb_layout_index_t layout = xkb_state_key_get_layout(resolving->
xkb_state, key);
329 if (layout == XKB_LAYOUT_INVALID)
331 if (xkb_state_key_get_level(resolving->
xkb_state, key, layout) > 1)
334 if (sym != resolving->
keysym)
340 (
sizeof(xcb_keycode_t) *
350 struct xkb_state *dummy_state = xkb_state_new(
xkb_keymap);
351 if (dummy_state == NULL) {
352 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
356 struct xkb_state *dummy_state_no_shift = xkb_state_new(
xkb_keymap);
357 if (dummy_state_no_shift == NULL) {
358 ELOG(
"Could not create XKB state, cannot translate keysyms.\n");
362 bool has_errors =
false;
367 long button = strtol(bind->
symbol + (
sizeof(
"button") - 1), &endptr, 10);
370 if (button == LONG_MAX || button == LONG_MIN || button < 0 || *endptr != '\0' || endptr == bind->symbol)
371 ELOG(
"Could not translate string to button: \"%s\"\n", bind->
symbol);
380 const xkb_keysym_t keysym = xkb_keysym_from_name(bind->
symbol, XKB_KEYSYM_NO_FLAGS);
381 if (keysym == XKB_KEY_NoSymbol) {
382 ELOG(
"Could not translate string to key symbol: \"%s\"\n",
387 xkb_layout_index_t group = XCB_XKB_GROUP_1;
389 group = XCB_XKB_GROUP_2;
391 group = XCB_XKB_GROUP_3;
393 group = XCB_XKB_GROUP_4;
395 DLOG(
"group = %d, event_state_mask = %d, &2 = %s, &3 = %s, &4 = %s\n", group,
400 (void)xkb_state_update_mask(
409 (void)xkb_state_update_mask(
410 dummy_state_no_shift,
421 .xkb_state = dummy_state,
422 .xkb_state_no_shift = dummy_state_no_shift,
439 if (check->
symbol != NULL)
449 DLOG(
"state=0x%x, cfg=\"%s\", sym=0x%x → keycodes%s (%d)\n",
454 xkb_state_unref(dummy_state);
455 xkb_state_unref(dummy_state_no_shift);
469 DLOG(
"Switching to mode %s\n", new_mode);
472 if (strcasecmp(mode->
name, new_mode) != 0)
481 sasprintf(&event_msg,
"{\"change\":\"%s\", \"pango_markup\":%s}",
490 ELOG(
"ERROR: Mode not found\n");
520 struct bindings_head *reordered =
scalloc(1,
sizeof(
struct bindings_head));
522 for (
int i = 0; i < n; i++) {
579 if ((bind->
symbol == NULL && current->
symbol != NULL) ||
585 if (bind->
symbol != NULL &&
598 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keycode %d, command \"%s\"\n",
601 ELOG(
"Duplicate keybinding in config file:\n state mask 0x%x with keysym %s, command \"%s\"\n",
674 "The configured command for this shortcut could not be run successfully.",
690 xcb_intern_atom_reply_t *atom_reply;
691 size_t content_max_words = 256;
695 atom_reply = xcb_intern_atom_reply(
696 conn, xcb_intern_atom(
conn, 0, strlen(
"_XKB_RULES_NAMES"),
"_XKB_RULES_NAMES"), NULL);
697 if (atom_reply == NULL)
700 xcb_get_property_cookie_t prop_cookie;
701 xcb_get_property_reply_t *prop_reply;
702 prop_cookie = xcb_get_property_unchecked(
conn,
false, root, atom_reply->atom,
703 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
704 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
705 if (prop_reply == NULL) {
709 if (xcb_get_property_value_length(prop_reply) > 0 && prop_reply->bytes_after > 0) {
712 content_max_words += ceil(prop_reply->bytes_after / 4.0);
715 prop_cookie = xcb_get_property_unchecked(
conn,
false, root, atom_reply->atom,
716 XCB_GET_PROPERTY_TYPE_ANY, 0, content_max_words);
717 prop_reply = xcb_get_property_reply(
conn, prop_cookie, NULL);
718 if (prop_reply == NULL) {
723 if (xcb_get_property_value_length(prop_reply) == 0) {
729 const char *walk = (
const char *)xcb_get_property_value(prop_reply);
730 int remaining = xcb_get_property_value_length(prop_reply);
731 for (
int i = 0; i < 5 && remaining > 0; i++) {
732 const int len = strnlen(walk, remaining);
736 sasprintf((
char **)&(xkb_names->rules),
"%.*s", len, walk);
739 sasprintf((
char **)&(xkb_names->model),
"%.*s", len, walk);
742 sasprintf((
char **)&(xkb_names->layout),
"%.*s", len, walk);
745 sasprintf((
char **)&(xkb_names->variant),
"%.*s", len, walk);
748 sasprintf((
char **)&(xkb_names->options),
"%.*s", len, walk);
751 DLOG(
"component %d of _XKB_RULES_NAMES is \"%.*s\"\n", i, len, walk);
767 ELOG(
"Could not create xkbcommon context\n");
774 if (
xkb_supported && (device_id = xkb_x11_get_core_keyboard_device_id(
conn)) > -1) {
775 if ((new_keymap = xkb_x11_keymap_new_from_device(
xkb_context,
conn, device_id, 0)) == NULL) {
776 ELOG(
"xkb_x11_keymap_new_from_device failed\n");
782 LOG(
"No XKB / core keyboard device? Assembling keymap from local RMLVO.\n");
783 struct xkb_rule_names names = {
790 ELOG(
"Could not get _XKB_RULES_NAMES atom from root window, falling back to defaults.\n");
791 if ((new_keymap = xkb_keymap_new_from_names(
xkb_context, &names, 0)) == NULL) {
792 ELOG(
"xkb_keymap_new_from_names(NULL) failed\n");
796 new_keymap = xkb_keymap_new_from_names(
xkb_context, &names, 0);
797 free((
char *)names.rules);
798 free((
char *)names.model);
799 free((
char *)names.layout);
800 free((
char *)names.variant);
801 free((
char *)names.options);
802 if (new_keymap == NULL) {
803 ELOG(
"xkb_keymap_new_from_names(RMLVO) failed\n");
828 long button = strtol(bind->
symbol + (
sizeof(
"button") - 1), &endptr, 10);
829 if (button == LONG_MAX || button == LONG_MIN || button < 0 || *endptr != '\0' || endptr == bind->symbol) {
830 ELOG(
"Could not parse button number, skipping this binding. Please report this bug in i3.\n");
835 if (button == 4 || button == 5) {
static void grab_keycode_for_binding(xcb_connection_t *conn, Binding *bind, uint32_t keycode)
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...
static struct xkb_keymap * xkb_keymap
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...
char * symbol
Symbol the user specified in configfile, if any.
static int fill_rmlvo_from_root(struct xkb_rule_names *xkb_names)
static struct Mode * mode_from_name(const char *name, bool pango_markup)
void * smalloc(size_t size)
Safe-wrapper around malloc which exits if malloc returns NULL (meaning that there is no more memory a...
void start_config_error_nagbar(const char *configpath, bool has_errors)
Launch nagbar to indicate errors in the configuration file.
#define TAILQ_EMPTY(head)
void reorder_bindings(void)
Reorders bindings by event_state_mask descendingly so that get_binding() correctly matches more speci...
struct bindings_head * bindings
void xcb_grab_buttons(xcb_connection_t *conn, xcb_window_t window, bool bind_scrollwheel)
Grab the specified buttons on a window when managing it.
#define TAILQ_FOREACH(var, head, field)
unsigned int xcb_numlock_mask
void ipc_send_binding_event(const char *event_type, Binding *bind)
For the binding events, we send the serialized binding struct.
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...
struct xkb_state * xkb_state_no_shift
xcb_connection_t * conn
XCB connection and root screen.
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.
void check_for_duplicate_bindings(struct context *context)
Checks for duplicate key bindings (the same keycode or keysym is configured more than once)...
#define GRAB_KEY(modifier)
char * command
Command, like in command mode.
bool whole_window
If this is true for a mouse binding, the binding should be executed when the button is pressed over a...
struct xkb_state * xkb_state
bool bindings_should_grab_scrollwheel_buttons(void)
Returns true if the current config has any binding to a scroll wheel button (4 or 5) which is a whole...
CommandResult * parse_command(const char *input, yajl_gen gen)
Parses and executes the given command.
#define SLIST_FOREACH(var, head, field)
void binding_free(Binding *bind)
Frees the binding.
#define TAILQ_REMOVE(head, elm, field)
static struct xkb_context * xkb_context
uint32_t keycode
Keycode to bind.
The configuration file can contain multiple sets of bindings.
bool load_keymap(void)
Loads the XKB keymap from the X11 server and feeds it to xkbcommon.
enum Binding::@12 release
If true, the binding should be executed upon a KeyRelease event, not a KeyPress (the default)...
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.
void * srealloc(void *ptr, size_t size)
Safe-wrapper around realloc which exits if realloc returns NULL (meaning that there is no more memory...
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 void reorder_bindings_of_mode(struct Mode *mode)
struct bindings_head * bindings
static Binding * get_binding(i3_event_state_mask_t state_filtered, bool is_release, uint16_t input_code, input_type_t input_type)
CommandResult * run_binding(Binding *bind, Con *con)
Runs the given binding and handles parse errors.
pid_t command_error_nagbar_pid
i3_event_state_mask_t event_state_mask
Bitmask which is applied against event->state for KeyPress and KeyRelease events to determine whether...
void switch_mode(const char *new_mode)
Switches the key bindings to the given mode, if the mode exists.
char * pattern
The pattern/name used to load the font.
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...
A 'Con' represents everything from the X11 root window down to a single X11 window.
#define SLIST_INSERT_HEAD(head, elm, field)
A struct that contains useful information about the result of a command as a whole (e...
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...
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_INSERT_TAIL(head, elm, field)
xcb_screen_t * root_screen
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)
static char * current_mode
void grab_all_keys(xcb_connection_t *conn)
Grab the bound keys (tell X to send us keypress events for those keycodes)
const char * DEFAULT_BINDING_MODE
The name of the default mode.
char * current_configpath
static int reorder_binding_cmp(const void *a, const void *b)
struct all_cons_head all_cons
bool border
If this is true for a mouse binding, the binding should be executed when the button is pressed over t...
void translate_keysyms(void)
Translates keysymbols to keycodes for all bindings which use keysyms.
xcb_keycode_t * translated_to
Only in use if symbol != NULL.
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...
input_type_t
Binding input types.
static Binding * binding_copy(Binding *bind)
Used during the config file lexing/parsing to keep the state of the lexer in order to provide useful ...
Holds a keybinding, consisting of a keycode combined with modifiers and the command which is executed...