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.
This commit is contained in:
Campbell Barton
2023-03-02 16:13:15 +11:00
parent b61807ebcf
commit 944a6e78f5

View File

@@ -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);
}