From 944a6e78f54fb4b0cb976f900bfbd6a39fe1c8da Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 2 Mar 2023 16:13:15 +1100 Subject: [PATCH] Fix #105277: Alt key suck after Alt-Tab on Windows 11 Windows 11 has strange behavior with Alt-Tab. In some cases an Alt-Press event is sent to the window immediately after it is de-activated (both Left & Right Alt keys for some reason even when only one is held). This meant that: - Modifiers could be enabled for de-activated windows (so we can't assume de-activated windows have modifiers released). - Releasing the modifier key would not be sent to the inactive window causing the modifier key to be stuck. - Button events over an inactive window are generated before activation, so even though activation reads the correct modifier state, the button event uses the "stuck" modifier state. Now button & drop events on inactive windows always read the modifier state first instead of relying on the modifier state to be cleared. This has some advantages: - If modifiers are held, they will be used as part of the click action. - While modifier keys on inactive windows should be rare, in the case this does happen - stuck keys are avoided. So it makes sense to apply these changes for all platforms. --- source/blender/windowmanager/intern/wm_window.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 53021ecb4ef..94f2aaddb8d 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -522,6 +522,12 @@ void WM_window_set_dpi(const wmWindow *win) /** * When windows are activated, simulate modifier press/release to match the current state of * held modifier keys, see #40317. + * + * NOTE(@ideasman42): There is a bug in Windows11 where Alt-Tab sends an Alt-press event + * to the window after it's deactivated, this means window de-activation is not a fool-proof + * way of ensuring modifier keys are cleared for inactive windows. So any event added to an + * inactive window must run #wm_window_update_eventstate_modifiers first to ensure no modifier + * keys are held. See: #105277. */ static void wm_window_update_eventstate_modifiers(wmWindowManager *wm, wmWindow *win) { @@ -1395,6 +1401,8 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt case GHOST_kEventDraggingDropDone: { GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt); + /* Ensure the event state matches modifiers (window was inactive). */ + wm_window_update_eventstate_modifiers(wm, win); /* Entering window, update mouse position (without sending an event). */ wm_window_update_eventstate(win); @@ -1492,6 +1500,7 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt if (win->active == 0) { /* Entering window, update cursor/tablet state & modifiers. * (ghost sends win-activate *after* the mouse-click in window!) */ + wm_window_update_eventstate_modifiers(wm, win); wm_window_update_eventstate(win); }