diff options
Diffstat (limited to 'source/blender/windowmanager/intern/wm_event_system.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_event_system.c | 407 |
1 files changed, 237 insertions, 170 deletions
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 0e262f8c388..62aeb8a2928 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -97,9 +97,10 @@ static int wm_operator_call_internal(bContext *C, ReportList *reports, const wmOperatorCallContext context, const bool poll_only, - wmEvent *event); + const wmEvent *event); static bool wm_operator_check_locked_interface(bContext *C, wmOperatorType *ot); +static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win); /* -------------------------------------------------------------------- */ /** \name Event Management @@ -145,7 +146,7 @@ wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add) copy_v2_v2_int(win->eventstate->prev_xy, win->eventstate->xy); copy_v2_v2_int(event->prev_xy, win->eventstate->xy); } - else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) { + else if (ISKEYBOARD_OR_BUTTON(event->type)) { win->eventstate->prev_val = event->prev_val = win->eventstate->val; win->eventstate->prev_type = event->prev_type = win->eventstate->type; @@ -154,13 +155,36 @@ wmEvent *WM_event_add_simulate(wmWindow *win, const wmEvent *event_to_add) if (event->val == KM_PRESS) { if ((event->flag & WM_EVENT_IS_REPEAT) == 0) { - copy_v2_v2_int(win->eventstate->prev_click_xy, event->xy); + copy_v2_v2_int(win->eventstate->prev_press_xy, event->xy); } } } return event; } +static void wm_event_custom_free(wmEvent *event) +{ + if ((event->customdata && event->customdata_free) == 0) { + return; + } + + /* NOTE: pointer to #ListBase struct elsewhere. */ + if (event->custom == EVT_DATA_DRAGDROP) { + ListBase *lb = event->customdata; + WM_drag_free_list(lb); + } + else { + MEM_freeN(event->customdata); + } +} + +static void wm_event_custom_clear(wmEvent *event) +{ + event->custom = 0; + event->customdata = NULL; + event->customdata_free = false; +} + void wm_event_free(wmEvent *event) { #ifndef NDEBUG @@ -172,22 +196,35 @@ void wm_event_free(wmEvent *event) } #endif - if (event->customdata) { - if (event->customdata_free) { - /* NOTE: pointer to #ListBase struct elsewhere. */ - if (event->custom == EVT_DATA_DRAGDROP) { - ListBase *lb = event->customdata; - WM_drag_free_list(lb); - } - else { - MEM_freeN(event->customdata); - } - } - } + wm_event_custom_free(event); MEM_freeN(event); } +/** A version of #wm_event_free that holds the last handled event. */ +static void wm_event_free_last_handled(wmWindow *win, wmEvent *event) +{ + /* Don't rely on this pointer being valid, + * callers should behave as if the memory has been freed. + * As this function should be interchangeable with #wm_event_free. */ +#ifndef NDEBUG + { + wmEvent *event_copy = MEM_dupallocN(event); + MEM_freeN(event); + event = event_copy; + } +#endif + + if (win->event_last_handled) { + wm_event_free(win->event_last_handled); + } + /* Don't store custom data in the last handled event as we don't have control how long this event + * will be stored and the referenced data may become invalid (also it's not needed currently). */ + wm_event_custom_free(event); + wm_event_custom_clear(event); + win->event_last_handled = event; +} + static void wm_event_free_last(wmWindow *win) { wmEvent *event = BLI_poptail(&win->event_queue); @@ -1276,7 +1313,7 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event) */ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, - wmEvent *event, + const wmEvent *event, PointerRNA *properties, ReportList *reports, const bool poll_only, @@ -1317,7 +1354,9 @@ static int wm_operator_invoke(bContext *C, } if (op->type->invoke && event) { - wm_region_mouse_co(C, event); + /* Temporarily write into `mval` (not technically `const` correct) but this is restored. */ + int mval_prev[2] = {UNPACK2(event->mval)}; + wm_region_mouse_co(C, (wmEvent *)event); if (op->type->flag & OPTYPE_UNDO) { wm->op_undo_depth++; @@ -1329,6 +1368,8 @@ static int wm_operator_invoke(bContext *C, if (op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm) { wm->op_undo_depth--; } + + copy_v2_v2_int(((wmEvent *)event)->mval, mval_prev); } else if (op->type->exec) { if (op->type->flag & OPTYPE_UNDO) { @@ -1440,7 +1481,7 @@ static int wm_operator_call_internal(bContext *C, ReportList *reports, const wmOperatorCallContext context, const bool poll_only, - wmEvent *event) + const wmEvent *event) { int retval; @@ -1572,19 +1613,21 @@ static int wm_operator_call_internal(bContext *C, int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, - PointerRNA *properties) + PointerRNA *properties, + const wmEvent *event) { BLI_assert(ot == WM_operatortype_find(ot->idname, true)); - return wm_operator_call_internal(C, ot, properties, NULL, context, false, NULL); + return wm_operator_call_internal(C, ot, properties, NULL, context, false, event); } int WM_operator_name_call(bContext *C, const char *opstring, wmOperatorCallContext context, - PointerRNA *properties) + PointerRNA *properties, + const wmEvent *event) { wmOperatorType *ot = WM_operatortype_find(opstring, 0); if (ot) { - return WM_operator_name_call_ptr(C, ot, context, properties); + return WM_operator_name_call_ptr(C, ot, context, properties, event); } return 0; @@ -1603,12 +1646,13 @@ bool WM_operator_name_poll(bContext *C, const char *opstring) int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, wmOperatorCallContext context, - struct IDProperty *properties) + struct IDProperty *properties, + const wmEvent *event) { PointerRNA props_ptr; wmOperatorType *ot = WM_operatortype_find(opstring, false); RNA_pointer_create(G_MAIN->wm.first, ot->srna, properties, &props_ptr); - return WM_operator_name_call_ptr(C, ot, context, &props_ptr); + return WM_operator_name_call_ptr(C, ot, context, &props_ptr, event); } void WM_menu_name_call(bContext *C, const char *menu_name, short context) @@ -1617,7 +1661,7 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context) PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); RNA_string_set(&ptr, "name", menu_name); - WM_operator_name_call_ptr(C, ot, context, &ptr); + WM_operator_name_call_ptr(C, ot, context, &ptr, NULL); WM_operator_properties_free(&ptr); } @@ -1729,7 +1773,8 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us WM_operator_name_call_ptr(C, opwait->optype_params.optype, opwait->optype_params.opcontext, - opwait->optype_params.opptr); + opwait->optype_params.opptr, + event); CTX_store_set(C, NULL); } @@ -1751,6 +1796,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, wmOperatorType *ot, wmOperatorCallContext opcontext, PointerRNA *properties, + const wmEvent *event, const char *drawstr) { int flag = ot->flag; @@ -1763,7 +1809,7 @@ void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, } if ((flag & OPTYPE_DEPENDS_ON_CURSOR) == 0) { - WM_operator_name_call_ptr(C, ot, opcontext, properties); + WM_operator_name_call_ptr(C, ot, opcontext, properties, event); return; } @@ -3062,8 +3108,7 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis WM_drag_free_list(lb); WM_drag_free_list(&single_lb); - event->customdata = NULL; - event->custom = 0; + wm_event_custom_clear(event); wm_drop_end(C, drag, drop); @@ -3165,21 +3210,22 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) * in `action` setting #WM_HANDLER_HANDLED, but not #WM_HANDLER_BREAK. */ if ((action & WM_HANDLER_BREAK) == 0 || wm_action_not_handled(action)) { if (win->event_queue_check_drag) { - if (WM_event_drag_test(event, event->prev_click_xy)) { + if ((event->flag & WM_EVENT_FORCE_DRAG_THRESHOLD) || + WM_event_drag_test(event, event->prev_press_xy)) { win->event_queue_check_drag_handled = true; const int direction = WM_event_drag_direction(event); - const int prev_xy[2] = {UNPACK2(event->xy)}; + /* Intentionally leave `event->xy` as-is, event users are expected to use + * `event->prev_press_xy` if they need to access the drag start location. */ const short prev_val = event->val; const short prev_type = event->type; const uint8_t prev_modifier = event->modifier; const short prev_keymodifier = event->keymodifier; - copy_v2_v2_int(event->xy, event->prev_click_xy); event->val = KM_CLICK_DRAG; - event->type = event->prev_click_type; - event->modifier = event->prev_click_modifier; - event->keymodifier = event->prev_click_keymodifier; + event->type = event->prev_press_type; + event->modifier = event->prev_press_modifier; + event->keymodifier = event->prev_press_keymodifier; event->direction = direction; CLOG_INFO(WM_LOG_HANDLERS, 1, "handling PRESS_DRAG"); @@ -3191,7 +3237,6 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) event->modifier = prev_modifier; event->val = prev_val; event->type = prev_type; - copy_v2_v2_int(event->xy, prev_xy); win->event_queue_check_click = false; if (!((action & WM_HANDLER_BREAK) == 0 || wm_action_not_handled(action))) { @@ -3205,7 +3250,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) win->event_queue_check_drag = false; } } - else if (ISMOUSE_BUTTON(event->type) || ISKEYBOARD(event->type)) { + else if (ISKEYBOARD_OR_BUTTON(event->type)) { /* All events that don't set #wmEvent.prev_type must be ignored. */ /* Test for CLICK events. */ @@ -3222,8 +3267,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } else if (event->val == KM_RELEASE) { if (win->event_queue_check_drag) { - if ((event->prev_click_type != event->type) && - (ISKEYMODIFIER(event->type) || (event->type == event->prev_click_keymodifier))) { + if ((event->prev_press_type != event->type) && + (ISKEYMODIFIER(event->type) || (event->type == event->prev_press_keymodifier))) { /* Support releasing modifier keys without canceling the drag event, see T89989. */ } else { @@ -3232,12 +3277,12 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } - if (event->prev_click_type == event->type) { + if (event->prev_press_type == event->type) { if (event->val == KM_RELEASE) { if (event->prev_val == KM_PRESS) { if (win->event_queue_check_click == true) { - if (WM_event_drag_test(event, event->prev_click_xy)) { + if (WM_event_drag_test(event, event->prev_press_xy)) { win->event_queue_check_click = false; win->event_queue_check_drag = false; } @@ -3246,7 +3291,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) * accurate selecting in case the mouse drifts a little. */ int xy[2] = {UNPACK2(event->xy)}; - copy_v2_v2_int(event->xy, event->prev_click_xy); + copy_v2_v2_int(event->xy, event->prev_press_xy); event->val = KM_CLICK; CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK"); @@ -3406,11 +3451,8 @@ static void wm_event_drag_and_drop_test(wmWindowManager *wm, wmWindow *win, wmEv event->type = EVT_DROP; /* Create custom-data, first free existing. */ - if (event->customdata) { - if (event->customdata_free) { - MEM_freeN(event->customdata); - } - } + wm_event_custom_free(event); + wm_event_custom_clear(event); event->custom = EVT_DATA_DRAGDROP; event->customdata = &wm->drags; @@ -3653,6 +3695,19 @@ void wm_event_do_handlers(bContext *C) while ((event = win->event_queue.first)) { int action = WM_HANDLER_CONTINUE; + /* Force handling drag if a key is pressed even if the drag threshold has not been met. + * Needed so tablet actions (which typically use a larger threshold) can click-drag + * then press keys - activating the drag action early. + * Limit to mouse-buttons drag actions interrupted by pressing any non-mouse button. + * Otherwise pressing two keys on the keyboard will interpret this as a drag action. */ + if (win->event_queue_check_drag) { + if ((event->val == KM_PRESS) && ((event->flag & WM_EVENT_IS_REPEAT) == 0) && + ISKEYBOARD_OR_BUTTON(event->type) && ISMOUSE_BUTTON(event->prev_press_type)) { + event = wm_event_add_mousemove_to_head(win); + event->flag |= WM_EVENT_FORCE_DRAG_THRESHOLD; + } + } + /* Active screen might change during handlers, update pointer. */ screen = WM_window_get_active_screen(win); @@ -3668,7 +3723,7 @@ void wm_event_do_handlers(bContext *C) CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed"); } BLI_remlink(&win->event_queue, event); - wm_event_free(event); + wm_event_free_last_handled(win, event); continue; } @@ -3678,7 +3733,7 @@ void wm_event_do_handlers(bContext *C) if (event->type == EVT_XR_ACTION) { wm_event_handle_xrevent(C, wm, win, event); BLI_remlink(&win->event_queue, event); - wm_event_free(event); + wm_event_free_last_handled(win, event); /* Skip mouse event handling below, which is unnecessary for XR events. */ continue; } @@ -3816,7 +3871,7 @@ void wm_event_do_handlers(bContext *C) /* Un-link and free here, Blender-quit then frees all. */ BLI_remlink(&win->event_queue, event); - wm_event_free(event); + wm_event_free_last_handled(win, event); } /* Only add mouse-move when the event queue was read entirely. */ @@ -4692,11 +4747,11 @@ static bool wm_event_is_double_click(const wmEvent *event) { if ((event->type == event->prev_type) && (event->prev_val == KM_RELEASE) && (event->val == KM_PRESS)) { - if (ISMOUSE(event->type) && WM_event_drag_test(event, event->prev_click_xy)) { + if (ISMOUSE(event->type) && WM_event_drag_test(event, event->prev_press_xy)) { /* Pass. */ } else { - if ((PIL_check_seconds_timer() - event->prev_click_time) * 1000 < U.dbl_click_time) { + if ((PIL_check_seconds_timer() - event->prev_press_time) * 1000 < U.dbl_click_time) { return true; } } @@ -4714,14 +4769,14 @@ static void wm_event_prev_values_set(wmEvent *event, wmEvent *event_state) event->prev_type = event_state->prev_type = event_state->type; } -static void wm_event_prev_click_set(wmEvent *event, wmEvent *event_state) +static void wm_event_prev_click_set(wmEvent *event_state) { - event->prev_click_time = event_state->prev_click_time = PIL_check_seconds_timer(); - event->prev_click_type = event_state->prev_click_type = event_state->type; - event->prev_click_modifier = event_state->prev_click_modifier = event_state->modifier; - event->prev_click_keymodifier = event_state->prev_click_keymodifier = event_state->keymodifier; - event->prev_click_xy[0] = event_state->prev_click_xy[0] = event_state->xy[0]; - event->prev_click_xy[1] = event_state->prev_click_xy[1] = event_state->xy[1]; + event_state->prev_press_time = PIL_check_seconds_timer(); + event_state->prev_press_type = event_state->type; + event_state->prev_press_modifier = event_state->modifier; + event_state->prev_press_keymodifier = event_state->keymodifier; + event_state->prev_press_xy[0] = event_state->xy[0]; + event_state->prev_press_xy[1] = event_state->xy[1]; } static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event) @@ -4745,6 +4800,38 @@ static wmEvent *wm_event_add_mousemove(wmWindow *win, const wmEvent *event) return event_new; } +static wmEvent *wm_event_add_mousemove_to_head(wmWindow *win) +{ + /* Use the last handled event instead of `win->eventstate` because the state of the modifiers + * and previous values should be set based on the last state, not using values from the future. + * So this gives an accurate simulation of mouse motion before the next event is handled. */ + const wmEvent *event_last = win->event_last_handled; + + wmEvent tevent; + if (event_last) { + tevent = *event_last; + + tevent.flag = 0; + tevent.ascii = '\0'; + tevent.utf8_buf[0] = '\0'; + + wm_event_custom_clear(&tevent); + } + else { + memset(&tevent, 0x0, sizeof(tevent)); + } + + tevent.type = MOUSEMOVE; + copy_v2_v2_int(tevent.prev_xy, tevent.xy); + + wmEvent *event_new = wm_event_add(win, &tevent); + BLI_remlink(&win->event_queue, event_new); + BLI_addhead(&win->event_queue, event_new); + + copy_v2_v2_int(event_new->prev_xy, event_last->xy); + return event_new; +} + static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int deltax, int deltay) { /* Ignore in between track-pad events for performance, we only need high accuracy @@ -4765,6 +4852,46 @@ static wmEvent *wm_event_add_trackpad(wmWindow *win, const wmEvent *event, int d return event_new; } +/** + * Update the event-state for any kind of event that supports #KM_PRESS / #KM_RELEASE. + */ +static void wm_event_state_update_and_click_set(const GHOST_TEventType type, + wmEvent *event, + wmEvent *event_state) +{ + BLI_assert(ISKEYBOARD_OR_BUTTON(event->type)); + BLI_assert(ELEM(event->val, KM_PRESS, KM_RELEASE)); + + /* Only copy these flags into the `event_state`. */ + const eWM_EventFlag event_state_flag_mask = WM_EVENT_IS_REPEAT; + + wm_event_prev_values_set(event, event_state); + + /* Copy to event state. */ + event_state->val = event->val; + event_state->type = event->type; + /* It's important only to write into the `event_state` modifier for keyboard + * events because emulate MMB clears one of the modifiers in `event->modifier`, + * making the second press not behave as if the modifier is pressed, see T96279. */ + if (ELEM(type, GHOST_kEventKeyDown, GHOST_kEventKeyUp)) { + event_state->modifier = event->modifier; + } + event_state->flag = (event->flag & event_state_flag_mask); + /* NOTE: It's important that `keymodifier` is handled in the keyboard event handling logic + * since the `event_state` and the `event` are not kept in sync. */ + + /* Double click test. */ + if (wm_event_is_double_click(event)) { + CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); + event->val = KM_DBL_CLICK; + } + else if (event->val == KM_PRESS) { + if ((event->flag & WM_EVENT_IS_REPEAT) == 0) { + wm_event_prev_click_set(event_state); + } + } +} + void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void *customdata) { if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) { @@ -4806,15 +4933,13 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void * while not common, avoid a false alarm. */ #ifndef NDEBUG if ((event_state->type || event_state->val) && /* Ignore cleared event state. */ - !(ISMOUSE_BUTTON(event_state->type) || ISKEYBOARD(event_state->type) || - (event_state->type == EVENT_NONE))) { + !(ISKEYBOARD_OR_BUTTON(event_state->type) || (event_state->type == EVENT_NONE))) { CLOG_WARN(WM_LOG_HANDLERS, "Non-keyboard/mouse button found in 'win->eventstate->type = %d'", event_state->type); } if ((event_state->prev_type || event_state->prev_val) && /* Ignore cleared event state. */ - !(ISMOUSE_BUTTON(event_state->prev_type) || ISKEYBOARD(event_state->prev_type) || - (event_state->type == EVENT_NONE))) { + !(ISKEYBOARD_OR_BUTTON(event_state->prev_type) || (event_state->type == EVENT_NONE))) { CLOG_WARN(WM_LOG_HANDLERS, "Non-keyboard/mouse button found in 'win->eventstate->prev_type = %d'", event_state->prev_type); @@ -4924,20 +5049,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void wm_tablet_data_from_ghost(&bd->tablet, &event.tablet); wm_eventemulation(&event, false); - wm_event_prev_values_set(&event, event_state); - - /* Copy to event state. */ - event_state->val = event.val; - event_state->type = event.type; - - /* Double click test. */ - if (wm_event_is_double_click(&event)) { - CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); - event.val = KM_DBL_CLICK; - } - if (event.val == KM_PRESS) { - wm_event_prev_click_set(&event, event_state); - } + wm_event_state_update_and_click_set(type, &event, event_state); /* Add to other window if event is there (not to both!). */ wmWindow *win_other = wm_event_cursor_other_windows(wm, win, &event); @@ -4966,9 +5078,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case GHOST_kEventKeyDown: case GHOST_kEventKeyUp: { GHOST_TEventKeyData *kd = customdata; - /* Only copy these flags into the `event_state`. */ - const eWM_EventFlag event_state_flag_mask = WM_EVENT_IS_REPEAT; - bool keymodifier = 0; event.type = convert_key(kd->key); event.ascii = kd->ascii; /* Might be not NULL terminated. */ @@ -4979,12 +5088,6 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void event.val = (type == GHOST_kEventKeyDown) ? KM_PRESS : KM_RELEASE; wm_eventemulation(&event, false); - wm_event_prev_values_set(&event, event_state); - - /* Copy to event state. */ - event_state->val = event.val; - event_state->type = event.type; - event_state->flag = (event.flag & event_state_flag_mask); /* Exclude arrow keys, escape, etc from text input. */ if (type == GHOST_kEventKeyUp) { @@ -5017,108 +5120,68 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void switch (event.type) { case EVT_LEFTSHIFTKEY: - case EVT_RIGHTSHIFTKEY: - if (event.val == KM_PRESS) { - keymodifier = true; - } - if (keymodifier) { - event.modifier |= KM_SHIFT; - event_state->modifier |= KM_SHIFT; - } - else { - event.modifier &= ~KM_SHIFT; - event_state->modifier &= ~KM_SHIFT; - } + case EVT_RIGHTSHIFTKEY: { + SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_SHIFT); break; + } case EVT_LEFTCTRLKEY: - case EVT_RIGHTCTRLKEY: - if (event.val == KM_PRESS) { - keymodifier = true; - } - if (keymodifier) { - event.modifier |= KM_CTRL; - event_state->modifier |= KM_CTRL; - } - else { - event.modifier &= ~KM_CTRL; - event_state->modifier &= ~KM_CTRL; - } + case EVT_RIGHTCTRLKEY: { + SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_CTRL); break; + } case EVT_LEFTALTKEY: - case EVT_RIGHTALTKEY: - if (event.val == KM_PRESS) { - keymodifier = true; - } - if (keymodifier) { - event.modifier |= KM_ALT; - event_state->modifier |= KM_ALT; - } - else { - event.modifier &= ~KM_ALT; - event_state->modifier &= ~KM_ALT; - } + case EVT_RIGHTALTKEY: { + SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_ALT); + break; + } + case EVT_OSKEY: { + SET_FLAG_FROM_TEST(event.modifier, (event.val == KM_PRESS), KM_OSKEY); break; - case EVT_OSKEY: + } + default: { if (event.val == KM_PRESS) { - keymodifier = true; - } - if (keymodifier) { - event.modifier |= KM_OSKEY; - event_state->modifier |= KM_OSKEY; + if (event.keymodifier == 0) { + /* Only set in `eventstate`, for next event. */ + event_state->keymodifier = event.type; + } } else { - event.modifier &= ~KM_OSKEY; - event_state->modifier &= ~KM_OSKEY; + BLI_assert(event.val == KM_RELEASE); + if (event.keymodifier == event.type) { + event.keymodifier = event_state->keymodifier = 0; + } } - break; - default: - if (event.val == KM_PRESS && event.keymodifier == 0) { - /* Only set in `eventstate`, for next event. */ - event_state->keymodifier = event.type; + + /* This case happens on holding a key pressed, + * it should not generate press events with the same key as modifier. */ + if (event.keymodifier == event.type) { + event.keymodifier = 0; } - else if (event.val == KM_RELEASE && event.keymodifier == event.type) { - event.keymodifier = event_state->keymodifier = 0; + else if (event.keymodifier == EVT_UNKNOWNKEY) { + /* This case happens with an external number-pad, and also when using 'dead keys' + * (to compose complex latin characters e.g.), it's not really clear why. + * Since it's impossible to map a key modifier to an unknown key, + * it shouldn't harm to clear it. */ + event_state->keymodifier = event.keymodifier = 0; } break; + } } - /* Double click test. */ - /* If previous event was same type, and previous was release, and now it presses... */ - if (wm_event_is_double_click(&event)) { - CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click"); - event.val = KM_DBL_CLICK; - } - - /* This case happens on holding a key pressed, - * it should not generate press events with the same key as modifier. */ - if (event.keymodifier == event.type) { - event.keymodifier = 0; - } - - /* This case happens with an external number-pad, and also when using 'dead keys' - * (to compose complex latin characters e.g.), it's not really clear why. - * Since it's impossible to map a key modifier to an unknown key, - * it shouldn't harm to clear it. */ - if (event.keymodifier == EVT_UNKNOWNKEY) { - event_state->keymodifier = event.keymodifier = 0; - } + /* It's important `event.modifier` has been initialized first. */ + wm_event_state_update_and_click_set(type, &event, event_state); /* If test_break set, it catches this. Do not set with modifier presses. - * XXX Keep global for now? */ - if ((event.type == EVT_ESCKEY && event.val == KM_PRESS) && - /* Check other modifiers because ms-windows uses these to bring up the task manager. */ - ((event.modifier & (KM_SHIFT | KM_CTRL | KM_ALT)) == 0)) { + * Exclude modifiers because MS-Windows uses these to bring up the task manager. + * + * NOTE: in general handling events here isn't great design as + * event handling should be managed by the event handling loop. + * Make an exception for `G.is_break` as it ensures we can always cancel operations + * such as rendering or baking no matter which operation is currently handling events. */ + if ((event.type == EVT_ESCKEY) && (event.val == KM_PRESS) && (event.modifier == 0)) { G.is_break = true; } - /* Double click test - only for press. */ - if (event.val == KM_PRESS) { - /* Don't reset timer & location when holding the key generates repeat events. */ - if ((event.flag & WM_EVENT_IS_REPEAT) == 0) { - wm_event_prev_click_set(&event, event_state); - } - } - wm_event_add(win, &event); break; @@ -5173,11 +5236,15 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void case GHOST_kRelease: event.val = KM_RELEASE; break; + default: + BLI_assert_unreachable(); } event.custom = 0; event.customdata = NULL; + wm_event_state_update_and_click_set(type, &event, event_state); + wm_event_add(win, &event); break; @@ -5230,7 +5297,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void #ifdef WITH_XR_OPENXR void wm_event_add_xrevent(wmWindow *win, wmXrActionData *actiondata, short val) { - BLI_assert(val == KM_PRESS || val == KM_RELEASE); + BLI_assert(ELEM(val, KM_PRESS, KM_RELEASE)); wmEvent event = { .type = EVT_XR_ACTION, |