mirror of
				https://github.com/swaywm/sway.git
				synced 2025-11-03 09:01:43 -05:00 
			
		
		
		
	input/keyboard: send released only if pressed sent
This keeps track of whether surfaces received a key press event and will only send a key release event if the pressed event was sent. This also requires changing the keycodes that are sent via wl_keyboard_enter to only include those that were previously sent. This makes it so surfaces do not receive key release events for keys that they never received a key press for and makes it so switching focus doesn't leak keycodes that were consumed by bindings.
This commit is contained in:
		
							parent
							
								
									7488d33d42
								
							
						
					
					
						commit
						384afc5cb5
					
				
					 3 changed files with 54 additions and 27 deletions
				
			
		| 
						 | 
					@ -60,6 +60,7 @@ struct sway_keyboard {
 | 
				
			||||||
	struct sway_shortcut_state state_keysyms_translated;
 | 
						struct sway_shortcut_state state_keysyms_translated;
 | 
				
			||||||
	struct sway_shortcut_state state_keysyms_raw;
 | 
						struct sway_shortcut_state state_keysyms_raw;
 | 
				
			||||||
	struct sway_shortcut_state state_keycodes;
 | 
						struct sway_shortcut_state state_keycodes;
 | 
				
			||||||
 | 
						struct sway_shortcut_state state_pressed_sent;
 | 
				
			||||||
	struct sway_binding *held_binding;
 | 
						struct sway_binding *held_binding;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wl_event_source *key_repeat_source;
 | 
						struct wl_event_source *key_repeat_source;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -69,8 +69,9 @@ int get_modifier_names(const char **names, uint32_t modifier_masks) {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Remove all key ids associated to a keycode from the list of pressed keys
 | 
					 * Remove all key ids associated to a keycode from the list of pressed keys
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void state_erase_key(struct sway_shortcut_state *state,
 | 
					static bool state_erase_key(struct sway_shortcut_state *state,
 | 
				
			||||||
		uint32_t keycode) {
 | 
							uint32_t keycode) {
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
	size_t j = 0;
 | 
						size_t j = 0;
 | 
				
			||||||
	for (size_t i = 0; i < state->npressed; ++i) {
 | 
						for (size_t i = 0; i < state->npressed; ++i) {
 | 
				
			||||||
		if (i > j) {
 | 
							if (i > j) {
 | 
				
			||||||
| 
						 | 
					@ -79,6 +80,8 @@ static void state_erase_key(struct sway_shortcut_state *state,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if (state->pressed_keycodes[i] != keycode) {
 | 
							if (state->pressed_keycodes[i] != keycode) {
 | 
				
			||||||
			++j;
 | 
								++j;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	while(state->npressed > j) {
 | 
						while(state->npressed > j) {
 | 
				
			||||||
| 
						 | 
					@ -87,6 +90,7 @@ static void state_erase_key(struct sway_shortcut_state *state,
 | 
				
			||||||
		state->pressed_keycodes[state->npressed] = 0;
 | 
							state->pressed_keycodes[state->npressed] = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	state->current_key = 0;
 | 
						state->current_key = 0;
 | 
				
			||||||
 | 
						return found;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -117,7 +121,7 @@ static void state_add_key(struct sway_shortcut_state *state,
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Update the shortcut model state in response to new input
 | 
					 * Update the shortcut model state in response to new input
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void update_shortcut_state(struct sway_shortcut_state *state,
 | 
					static bool update_shortcut_state(struct sway_shortcut_state *state,
 | 
				
			||||||
		struct wlr_event_keyboard_key *event, uint32_t new_key,
 | 
							struct wlr_event_keyboard_key *event, uint32_t new_key,
 | 
				
			||||||
		uint32_t raw_modifiers) {
 | 
							uint32_t raw_modifiers) {
 | 
				
			||||||
	bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
 | 
						bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
 | 
				
			||||||
| 
						 | 
					@ -133,8 +137,10 @@ static void update_shortcut_state(struct sway_shortcut_state *state,
 | 
				
			||||||
		state_add_key(state, event->keycode, new_key);
 | 
							state_add_key(state, event->keycode, new_key);
 | 
				
			||||||
		state->last_keycode = event->keycode;
 | 
							state->last_keycode = event->keycode;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		state_erase_key(state, event->keycode);
 | 
							return state_erase_key(state, event->keycode);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -430,10 +436,14 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!handled || event->state == WLR_KEY_RELEASED) {
 | 
						if (!handled || event->state == WLR_KEY_RELEASED) {
 | 
				
			||||||
 | 
							bool pressed_sent = update_shortcut_state(
 | 
				
			||||||
 | 
									&keyboard->state_pressed_sent, event, (uint32_t)keycode, 0);
 | 
				
			||||||
 | 
							if (pressed_sent || event->state == WLR_KEY_PRESSED) {
 | 
				
			||||||
			wlr_seat_set_keyboard(wlr_seat, wlr_device);
 | 
								wlr_seat_set_keyboard(wlr_seat, wlr_device);
 | 
				
			||||||
			wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
 | 
								wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
 | 
				
			||||||
					event->keycode, event->state);
 | 
										event->keycode, event->state);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	transaction_commit_dirty();
 | 
						transaction_commit_dirty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,5 @@
 | 
				
			||||||
#define _POSIX_C_SOURCE 200809L
 | 
					#define _POSIX_C_SOURCE 200809L
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
#include <linux/input-event-codes.h>
 | 
					#include <linux/input-event-codes.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <strings.h>
 | 
					#include <strings.h>
 | 
				
			||||||
| 
						 | 
					@ -85,6 +86,38 @@ static void seat_send_activate(struct sway_node *node, struct sway_seat *seat) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct sway_keyboard *sway_keyboard_for_wlr_keyboard(
 | 
				
			||||||
 | 
							struct sway_seat *seat, struct wlr_keyboard *wlr_keyboard) {
 | 
				
			||||||
 | 
						struct sway_seat_device *seat_device;
 | 
				
			||||||
 | 
						wl_list_for_each(seat_device, &seat->devices, link) {
 | 
				
			||||||
 | 
							struct sway_input_device *input_device = seat_device->input_device;
 | 
				
			||||||
 | 
							if (input_device->wlr_device->type != WLR_INPUT_DEVICE_KEYBOARD) {
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (input_device->wlr_device->keyboard == wlr_keyboard) {
 | 
				
			||||||
 | 
								return seat_device->keyboard;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void seat_keyboard_notify_enter(struct sway_seat *seat,
 | 
				
			||||||
 | 
							struct wlr_surface *surface) {
 | 
				
			||||||
 | 
						struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
 | 
				
			||||||
 | 
						if (!keyboard) {
 | 
				
			||||||
 | 
							wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, NULL, 0, NULL);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_keyboard *sway_keyboard =
 | 
				
			||||||
 | 
							sway_keyboard_for_wlr_keyboard(seat, keyboard);
 | 
				
			||||||
 | 
						assert(sway_keyboard && "Cannot find sway_keyboard for seat keyboard");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sway_shortcut_state *state = &sway_keyboard->state_pressed_sent;
 | 
				
			||||||
 | 
						wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface,
 | 
				
			||||||
 | 
								state->pressed_keycodes, state->npressed, &keyboard->modifiers);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * If con is a view, set it as active and enable keyboard input.
 | 
					 * If con is a view, set it as active and enable keyboard input.
 | 
				
			||||||
 * If con is a container, set all child views as active and don't enable
 | 
					 * If con is a container, set all child views as active and don't enable
 | 
				
			||||||
| 
						 | 
					@ -103,15 +136,8 @@ static void seat_send_focus(struct sway_node *node, struct sway_seat *seat) {
 | 
				
			||||||
			wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 | 
								wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
 | 
					
 | 
				
			||||||
		if (keyboard) {
 | 
							seat_keyboard_notify_enter(seat, view->surface);
 | 
				
			||||||
			wlr_seat_keyboard_notify_enter(seat->wlr_seat,
 | 
					 | 
				
			||||||
					view->surface, keyboard->keycodes,
 | 
					 | 
				
			||||||
					keyboard->num_keycodes, &keyboard->modifiers);
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			wlr_seat_keyboard_notify_enter(
 | 
					 | 
				
			||||||
					seat->wlr_seat, view->surface, NULL, 0, NULL);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wlr_pointer_constraint_v1 *constraint =
 | 
							struct wlr_pointer_constraint_v1 *constraint =
 | 
				
			||||||
			wlr_pointer_constraints_v1_constraint_for_surface(
 | 
								wlr_pointer_constraints_v1_constraint_for_surface(
 | 
				
			||||||
| 
						 | 
					@ -578,8 +604,6 @@ static void seat_configure_keyboard(struct sway_seat *seat,
 | 
				
			||||||
	if (!seat_device->keyboard) {
 | 
						if (!seat_device->keyboard) {
 | 
				
			||||||
		sway_keyboard_create(seat, seat_device);
 | 
							sway_keyboard_create(seat, seat_device);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct wlr_keyboard *wlr_keyboard =
 | 
					 | 
				
			||||||
		seat_device->input_device->wlr_device->keyboard;
 | 
					 | 
				
			||||||
	sway_keyboard_configure(seat_device->keyboard);
 | 
						sway_keyboard_configure(seat_device->keyboard);
 | 
				
			||||||
	wlr_seat_set_keyboard(seat->wlr_seat,
 | 
						wlr_seat_set_keyboard(seat->wlr_seat,
 | 
				
			||||||
			seat_device->input_device->wlr_device);
 | 
								seat_device->input_device->wlr_device);
 | 
				
			||||||
| 
						 | 
					@ -587,9 +611,7 @@ static void seat_configure_keyboard(struct sway_seat *seat,
 | 
				
			||||||
	if (focus && node_is_view(focus)) {
 | 
						if (focus && node_is_view(focus)) {
 | 
				
			||||||
		// force notify reenter to pick up the new configuration
 | 
							// force notify reenter to pick up the new configuration
 | 
				
			||||||
		wlr_seat_keyboard_clear_focus(seat->wlr_seat);
 | 
							wlr_seat_keyboard_clear_focus(seat->wlr_seat);
 | 
				
			||||||
		wlr_seat_keyboard_notify_enter(seat->wlr_seat,
 | 
							seat_keyboard_notify_enter(seat, focus->sway_container->view->surface);
 | 
				
			||||||
				focus->sway_container->view->surface, wlr_keyboard->keycodes,
 | 
					 | 
				
			||||||
				wlr_keyboard->num_keycodes, &wlr_keyboard->modifiers);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1049,13 +1071,7 @@ void seat_set_focus_surface(struct sway_seat *seat,
 | 
				
			||||||
		seat_send_unfocus(focus, seat);
 | 
							seat_send_unfocus(focus, seat);
 | 
				
			||||||
		seat->has_focus = false;
 | 
							seat->has_focus = false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
 | 
						seat_keyboard_notify_enter(seat, surface);
 | 
				
			||||||
	if (keyboard) {
 | 
					 | 
				
			||||||
		wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface,
 | 
					 | 
				
			||||||
			keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface, NULL, 0, NULL);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void seat_set_focus_layer(struct sway_seat *seat,
 | 
					void seat_set_focus_layer(struct sway_seat *seat,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue