Fix T103722: Stuck modifiers for wheel events over unfocused windows

Regression in [0] caused mouse wheel events over windows without focus
to use the modifier state at the point the window was de-activated.

Now un-focused windows have all events release, when focused again
modifier press events are set again.

[0]: 8bc76bf4b9
This commit is contained in:
Campbell Barton 2023-01-22 20:48:17 +11:00
parent 4fcbfcfc96
commit 00ac2ddca2
Notes: blender-bot 2023-02-14 06:00:49 +01:00
Referenced by issue #103722, Regression: Alt key remains locked in inactive blender window
1 changed files with 49 additions and 0 deletions

View File

@ -89,6 +89,20 @@
*/
#define USE_WIN_ACTIVATE
/**
* When the window is de-activated, release all held modifiers.
*
* Needed so events generated over unfocused (non-active) windows don't have modifiers held.
* Since modifier press/release events aren't send to unfocused windows it's best to assume
* modifiers are not pressed. This means when modifiers *are* held, events will incorrectly
* reported as not being held. Since this is standard behavior for Linux/MS-Window,
* opt to use this.
*
* NOTE(@campbellbarton): Events generated for non-active windows are rare,
* this happens when using the mouse-wheel over an unfocused window, see: T103722.
*/
#define USE_WIN_DEACTIVATE
/* the global to talk to ghost */
static GHOST_SystemHandle g_system = NULL;
#if !(defined(WIN32) || defined(__APPLE__))
@ -1130,6 +1144,41 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
switch (type) {
case GHOST_kEventWindowDeactivate:
#ifdef USE_WIN_DEACTIVATE
/* Release all held modifiers before de-activating the window. */
if (win->eventstate->modifier != 0) {
const uint8_t keymodifier_eventstate = win->eventstate->modifier;
const uint8_t keymodifier_l = wm_ghost_modifier_query(MOD_SIDE_LEFT);
const uint8_t keymodifier_r = wm_ghost_modifier_query(MOD_SIDE_RIGHT);
/* NOTE(@campbellbarton): when non-zero, there are modifiers held in
* `win->eventstate` which are not considered held by the GHOST internal state.
* While this should not happen, it's important all modifier held in event-state
* receive release events. Without this, so any events generated while the window
* is *not* active will have modifiers held. */
const uint8_t keymodifier_unhandled = keymodifier_eventstate &
~(keymodifier_l | keymodifier_r);
const uint8_t keymodifier_sided[2] = {
keymodifier_l | keymodifier_unhandled,
keymodifier_r,
};
GHOST_TEventKeyData kdata = {
.key = GHOST_kKeyUnknown,
.utf8_buf = {'\0'},
.is_repeat = false,
};
for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
if (keymodifier_eventstate & g_modifier_table[i].flag) {
for (int side = 0; side < 2; side++) {
if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
kdata.key = g_modifier_table[i].ghost_key_pair[side];
wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata);
}
}
}
}
}
#endif /* USE_WIN_DEACTIVATE */
wm_event_add_ghostevent(wm, win, type, data);
win->active = 0; /* XXX */
break;