From 8e841734dc722a89f4c146db2f3c6641a11eb05a Mon Sep 17 00:00:00 2001 From: Jorge Rodriguez Date: Sat, 21 Jan 2012 09:50:12 -0800 Subject: [PATCH] Commit:8c0dfcc06fa4fe134a8595495548239dda552596 * This patch is against svn r43583 Changes: * A new option for the transform tool allows the user to press the grab/rotate/resize button while the tool is already active to confirm the current transformation. If the option is on then in the case of switching rotation modes, this functionality has been moved to Shift-R instead. When using a transform tool bound to right click, right clicking will confirm instead of cancel; otherwise it will cancel like before. * A new option for holding the transform button/key to drag the object. If the user holds for longer than 250ms or farther than 10 pixels then the action is treated like a drag and when the key is released the transformation is automatically confirmed. Notes: * This patch removes some duplicate code in the modal handler for transform events. * In order to support this patch some slight changes have been made in the way handler operators are called. Duplicate button/key presses are now filtered by the handler and not sent to the operator, and information about the handler/keymapitem which invoked the operator (if any) have been added to the wmOperator structure. * The previous event state also now includes the "prevkeytime" - the time that the previous keyboard key was pressed. Justification: This patch attempts to improve the usability of the transformation tools by implementing behavior which most users will expect. If a button is pressed once to activate a tool, than users can expect to be able to press that same button again to deactivate the tool. If the user presses and holds the button then the functionality should remain active for as long an the button is held down and then deactivate when it is released. Since the new behavior is optional and defaults to off, it should have no impact on existing Blender users. --- source/blender/editors/transform/transform.c | 194 ++++++++++++-------- source/blender/editors/transform/transform.h | 4 +- source/blender/editors/transform/transform_ops.c | 10 +- source/blender/makesdna/DNA_windowmanager_types.h | 4 +- source/blender/windowmanager/WM_types.h | 1 + .../blender/windowmanager/intern/wm_event_system.c | 53 ++++-- 6 files changed, 167 insertions(+), 99 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 41e7356..6f0ee65 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -74,9 +74,12 @@ #include "ED_mesh.h" #include "ED_clip.h" +#include "PIL_time.h" + #include "UI_view2d.h" #include "WM_types.h" #include "WM_api.h" +#include "wm_event_system.h" #include "BLI_math.h" #include "BLI_blenlib.h" @@ -532,10 +535,6 @@ wmKeyMap* transform_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, TFM_MODAL_CONFIRM); - WM_modalkeymap_add_item(keymap, GKEY, KM_PRESS, 0, 0, TFM_MODAL_TRANSLATE); - WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, TFM_MODAL_ROTATE); - WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, TFM_MODAL_RESIZE); - WM_modalkeymap_add_item(keymap, TABKEY, KM_PRESS, KM_SHIFT, 0, TFM_MODAL_SNAP_TOGGLE); WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, TFM_MODAL_SNAP_INV_ON); @@ -560,8 +559,43 @@ wmKeyMap* transform_modal_keymap(wmKeyConfig *keyconf) return keymap; } +int is_same_type(int type1, int type2) +{ + if(type1 == type2) + return 1; + + switch(type1) { + case SELECTMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type2 == LEFTMOUSE; + else + return type2 == RIGHTMOUSE; + + case ACTIONMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type2 == RIGHTMOUSE; + else + return type2 == LEFTMOUSE; + } + + switch(type2) { + case SELECTMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type1 == LEFTMOUSE; + else + return type1 == RIGHTMOUSE; + + case ACTIONMOUSE: + if(U.flag & USER_LMOUSESELECT) + return type1 == RIGHTMOUSE; + else + return type1 == LEFTMOUSE; + } -int transformEvent(TransInfo *t, wmEvent *event) + return 0; +} + +int transformEvent(TransInfo *t, wmOperator *op, wmEvent *event) { float mati[3][3]= MAT3_UNITY; char cmode = constraintModeToChar(t); @@ -590,8 +624,12 @@ int transformEvent(TransInfo *t, wmEvent *event) t->redraw |= handleSnapping(t, event); } - /* handle modal keymap first */ - if (event->type == EVT_MODAL_MAP) { + if (RNA_boolean_get(op->ptr, "tap_confirm") && op->kmi && strcmp(op->idname, op->kmi->idname) == 0 && is_same_type(op->kmi->type, event->type) && op->kmi->val == event->val && + op->kmi->alt == event->alt && op->kmi->ctrl == event->ctrl && op->kmi->shift == event->shift && op->kmi->oskey == event->oskey) { + // If this button was the button that created this operator being pressed again then it is a confirm. + t->state = TRANS_CONFIRM; + } + else if (event->type == EVT_MODAL_MAP) { switch (event->val) { case TFM_MODAL_CANCEL: t->state = TRANS_CANCEL; @@ -599,55 +637,6 @@ int transformEvent(TransInfo *t, wmEvent *event) case TFM_MODAL_CONFIRM: t->state = TRANS_CONFIRM; break; - case TFM_MODAL_TRANSLATE: - /* only switch when... */ - if( ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) { - resetTransRestrictions(t); - restoreTransObjects(t); - initTranslation(t); - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - } - else if(t->mode == TFM_TRANSLATION) { - if(t->options&CTX_MOVIECLIP) { - restoreTransObjects(t); - - t->flag^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - } - } - break; - case TFM_MODAL_ROTATE: - /* only switch when... */ - if(!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) { - if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { - - resetTransRestrictions(t); - - if (t->mode == TFM_ROTATION) { - restoreTransObjects(t); - initTrackball(t); - } - else { - restoreTransObjects(t); - initRotation(t); - } - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - } - } - break; - case TFM_MODAL_RESIZE: - /* only switch when... */ - if( ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) { - resetTransRestrictions(t); - restoreTransObjects(t); - initResize(t); - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - } - break; - case TFM_MODAL_SNAP_INV_ON: t->modifiers |= MOD_SNAP_INVERT; t->redraw |= TREDRAW_HARD; @@ -861,6 +850,16 @@ int transformEvent(TransInfo *t, wmEvent *event) initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; } + else if(t->mode == TFM_TRANSLATION) { + if(t->options&CTX_MOVIECLIP) { + restoreTransObjects(t); + + t->flag^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + } + else if (RNA_boolean_get(op->ptr, "tap_confirm")) + t->state = TRANS_CONFIRM; + } break; case SKEY: /* only switch when... */ @@ -871,14 +870,16 @@ int transformEvent(TransInfo *t, wmEvent *event) initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; } + else if(t->mode == TFM_RESIZE && RNA_boolean_get(op->ptr, "tap_confirm")) + t->state = TRANS_CONFIRM; break; case RKEY: /* only switch when... */ if(!(t->options & CTX_TEXTURE) && !(t->options & CTX_MOVIECLIP)) { - if( ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) { - + if( ELEM(t->mode, TFM_RESIZE, TFM_TRANSLATION) || (!RNA_boolean_get(op->ptr, "tap_confirm") && ELEM(t->mode, TFM_ROTATION, TFM_TRACKBALL)) ) { + resetTransRestrictions(t); - + if (t->mode == TFM_ROTATION) { restoreTransObjects(t); initTrackball(t); @@ -890,6 +891,25 @@ int transformEvent(TransInfo *t, wmEvent *event) initSnapping(t, NULL); // need to reinit after mode change t->redraw |= TREDRAW_HARD; } + else if( RNA_boolean_get(op->ptr, "tap_confirm") && ELEM(t->mode, TFM_ROTATION, TFM_TRACKBALL) ) { + if( event->shift ) { + resetTransRestrictions(t); + + if (t->mode == TFM_ROTATION) { + restoreTransObjects(t); + initTrackball(t); + } + else { + restoreTransObjects(t); + initRotation(t); + } + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + } + else { + t->state = TRANS_CONFIRM; + } + } } break; case CKEY: @@ -1035,30 +1055,42 @@ int transformEvent(TransInfo *t, wmEvent *event) } else if (event->val==KM_RELEASE) { - switch (event->type){ - case LEFTSHIFTKEY: - case RIGHTSHIFTKEY: - t->modifiers &= ~MOD_CONSTRAINT_PLANE; - t->redraw |= TREDRAW_HARD; - break; - - case MIDDLEMOUSE: - if ((t->flag & T_NO_CONSTRAINT)==0) { - t->modifiers &= ~MOD_CONSTRAINT_SELECT; - postSelectConstraint(t); + if ((t->flag&T_DRAGGING) && op->kmi && strcmp(op->idname, op->kmi->idname) == 0 && is_same_type(op->kmi->type, event->type) && is_same_type(event->prevtype, event->type) && + op->kmi->alt == event->alt && op->kmi->ctrl == event->ctrl && op->kmi->shift == event->shift && op->kmi->oskey == event->oskey) { + // If this is the same key that was originally pressed to begin this operator, and it is now being released, + // then this may be a drag. If the mouse has moved far or long enough, we are at the end of the drag. + if (RNA_boolean_get(op->ptr, "drag_drop") && (PIL_check_seconds_timer() - event->prevkeytime > 0.250 || ABS(event->mval[0] - t->imval[0]) > 10 || ABS(event->mval[1] - t->imval[1]) > 10)) + t->state = TRANS_CONFIRM; + else + // Once the key is released we can never drag again! At least until the next operator invoke. + t->flag &= ~T_DRAGGING; + } + else { + switch (event->type){ + case LEFTSHIFTKEY: + case RIGHTSHIFTKEY: + t->modifiers &= ~MOD_CONSTRAINT_PLANE; t->redraw |= TREDRAW_HARD; + break; + + case MIDDLEMOUSE: + if ((t->flag & T_NO_CONSTRAINT)==0) { + t->modifiers &= ~MOD_CONSTRAINT_SELECT; + postSelectConstraint(t); + t->redraw |= TREDRAW_HARD; + } + break; + // case LEFTMOUSE: + // case RIGHTMOUSE: + // if(WM_modal_tweak_exit(event, t->event_type)) + //// if (t->options & CTX_TWEAK) + // t->state = TRANS_CONFIRM; + // break; + default: + handled = 0; + break; + } } - break; -// case LEFTMOUSE: -// case RIGHTMOUSE: -// if(WM_modal_tweak_exit(event, t->event_type)) -//// if (t->options & CTX_TWEAK) -// t->state = TRANS_CONFIRM; -// break; - default: - handled = 0; - break; - } /* confirm transform if launch key is released after mouse move */ if (t->flag & T_RELEASE_CONFIRM) diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index aab7dda..b70d1f2 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -377,6 +377,8 @@ typedef struct TransInfo { /* alternative transformation. used to add offset to tracking markers */ #define T_ALT_TRANSFORM (1 << 24) +#define T_DRAGGING (1 << 25) + /* TransInfo->modifiers */ #define MOD_CONSTRAINT_SELECT 0x01 #define MOD_PRECISION 0x02 @@ -435,7 +437,7 @@ void TRANSFORM_OT_transform(struct wmOperatorType *ot); int initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, struct wmEvent *event, int mode); void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op); -int transformEvent(TransInfo *t, struct wmEvent *event); +int transformEvent(TransInfo *t, struct wmOperator *op, struct wmEvent *event); void transformApply(struct bContext *C, TransInfo *t); int transformEnd(struct bContext *C, TransInfo *t); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 1843768..3308ce1 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -369,7 +369,7 @@ static int transform_modal(bContext *C, wmOperator *op, wmEvent *event) /* XXX insert keys are called here, and require context */ t->context= C; - exit_code = transformEvent(t, event); + exit_code = transformEvent(t, op, event); t->context= NULL; transformApply(C, t); @@ -423,12 +423,17 @@ static int transform_exec(bContext *C, wmOperator *op) static int transform_invoke(bContext *C, wmOperator *op, wmEvent *event) { + TransInfo *t; + if (!transformops_data(C, op, event)) { G.moving = 0; return OPERATOR_CANCELLED; } + t = op->customdata; + t->flag |= T_DRAGGING; + if(RNA_struct_property_is_set(op->ptr, "value")) { return transform_exec(C, op); } @@ -511,6 +516,9 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) // Add confirm method all the time. At the end because it's not really that important and should be hidden only in log, not in keymap edit /*prop =*/ RNA_def_boolean(ot->srna, "release_confirm", 0, "Confirm on Release", "Always confirm operation when releasing button"); //RNA_def_property_flag(prop, PROP_HIDDEN); + + RNA_def_boolean(ot->srna, "tap_confirm", 0, "Tap To Confirm", "Tap the operator's key or button again to confirm the transformation"); + RNA_def_boolean(ot->srna, "drag_drop", 0, "Drag And Drop", "Hold the operator's key or button to drag, release to confirm the transformation"); } void TRANSFORM_OT_translate(struct wmOperatorType *ot) diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 156d2eb..15b1683 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -306,6 +306,8 @@ typedef struct wmOperator { IDProperty *properties; /* saved, user-settable properties */ /* runtime */ + struct wmEventHandler *handler;/* The event handler that created this operator, if any */ + struct wmKeyMapItem *kmi; /* The key that was pressed to create this operator, if any */ struct wmOperatorType *type;/* operator type definition from idname */ void *customdata; /* custom storage, only while operator runs */ void *py_instance; /* python stores the class instance here */ @@ -316,7 +318,7 @@ typedef struct wmOperator { ListBase macro; /* list of operators, can be a tree */ struct wmOperator *opm; /* current running macro, not saved */ struct uiLayout *layout; /* runtime for drawing */ - short flag, pad[3]; + short flag, keydown, pad[2]; } wmOperator; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 357eaf2..a9dcb20 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -357,6 +357,7 @@ typedef struct wmEvent { short prevval; int prevx, prevy; double prevclicktime; + double prevkeytime; int prevclickx, prevclicky; /* modifier states */ diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 079833f..e82010f 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -629,14 +629,21 @@ int WM_operator_repeat_check(const bContext *UNUSED(C), wmOperator *op) return op->type->exec != NULL; } -static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, PointerRNA *properties, ReportList *reports) +static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, wmEventHandler *handler, wmKeyMapItem *kmi, PointerRNA *properties, ReportList *reports) { wmOperator *op= MEM_callocN(sizeof(wmOperator), ot->idname); /* XXX operatortype names are static still. for debug */ /* XXX adding new operator could be function, only happens here now */ op->type= ot; BLI_strncpy(op->idname, ot->idname, OP_MAX_TYPENAME); - + + op->handler= handler; + op->kmi= kmi; + + // If it was a button that created this operator then the key must be down. + // Otherwise it's a python script or something and the key doesn't exist. + op->keydown= !!kmi; + /* initialize properties, either copy or create */ op->ptr= MEM_callocN(sizeof(PointerRNA), "wmOperatorPtrRNA"); if(properties && properties->data) { @@ -684,7 +691,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P { wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0); PointerRNA someptr = RNA_property_pointer_get(properties, prop); - wmOperator *opm= wm_operator_create(wm, otm, &someptr, NULL); + wmOperator *opm= wm_operator_create(wm, otm, handler, kmi, &someptr, NULL); IDP_ReplaceGroupInGroup(opm->properties, otmacro->properties); @@ -698,7 +705,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P } else { for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) { wmOperatorType *otm= WM_operatortype_find(otmacro->idname, 0); - wmOperator *opm= wm_operator_create(wm, otm, otmacro->ptr, NULL); + wmOperator *opm= wm_operator_create(wm, otm, handler, kmi, otmacro->ptr, NULL); BLI_addtail(&motherop->macro, opm); opm->opm= motherop; /* pointer to mom, for modal() */ @@ -780,7 +787,7 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P return WM_operator_poll(C, ot); if(WM_operator_poll(C, ot)) { - wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */ + wmOperator *op= wm_operator_create(wm, ot, handler, kmi, properties, reports); /* if reports==NULL, theyll be initialized */ /* initialize setting from previous run */ if(wm->op_undo_depth == 0 && (ot->flag & OPTYPE_REGISTER)) { /* not called by py script */ @@ -954,7 +961,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA CTX_wm_region_set(C, ar1); } - retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); + retval= wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); /* set region back */ CTX_wm_region_set(C, ar); @@ -968,7 +975,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA ARegion *ar= CTX_wm_region(C); CTX_wm_region_set(C, NULL); - retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); + retval= wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); CTX_wm_region_set(C, ar); return retval; @@ -982,7 +989,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA CTX_wm_region_set(C, NULL); CTX_wm_area_set(C, NULL); - retval= wm_operator_invoke(C, ot, event, properties, reports, poll_only); + retval= wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); CTX_wm_area_set(C, area); CTX_wm_region_set(C, ar); @@ -990,7 +997,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA } case WM_OP_EXEC_DEFAULT: case WM_OP_INVOKE_DEFAULT: - return wm_operator_invoke(C, ot, event, properties, reports, poll_only); + return wm_operator_invoke(C, ot, NULL, NULL, event, properties, reports, poll_only); } } @@ -1019,7 +1026,7 @@ int WM_operator_call_py(bContext *C, wmOperatorType *ot, int context, PointerRNA #if 0 wmOperator *op; - op= wm_operator_create(wm, ot, properties, reports); + op= wm_operator_create(wm, ot, NULL, NULL, properties, reports); if (op->type->exec) { if(op->type->flag & OPTYPE_UNDO) @@ -1290,7 +1297,7 @@ static void wm_event_modalkeymap(const bContext *C, wmOperator *op, wmEvent *eve } /* Warning: this function removes a modal handler, when finished */ -static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmEvent *event, PointerRNA *properties) +static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHandler *handler, wmKeyMapItem *kmi, wmEvent *event, PointerRNA *properties) { int retval= OPERATOR_PASS_THROUGH; @@ -1299,6 +1306,20 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wmOperator *op= handler->op; wmOperatorType *ot= op->type; + if(op->kmi) { + if (op->kmi->type==event->type && op->kmi->alt==event->alt && op->kmi->ctrl==event->ctrl && op->kmi->shift==event->shift && op->kmi->oskey==event->oskey) { + // If this is the same button as that created the operator and it's a duplicate message, don't pass it along. + if (event->val==KM_PRESS && op->keydown) + return (WM_HANDLER_BREAK|WM_HANDLER_MODAL); + + if (event->val==KM_PRESS && !op->keydown) + op->keydown = 1; + + if (event->val==KM_RELEASE && op->keydown) + op->keydown = 0; + } + } + if(ot->modal) { /* we set context to where modal handler came from */ wmWindowManager *wm= CTX_wm_manager(C); @@ -1366,7 +1387,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand wmOperatorType *ot= WM_operatortype_find(event->keymap_idname, 0); if(ot) - retval= wm_operator_invoke(C, ot, event, properties, NULL, FALSE); + retval= wm_operator_invoke(C, ot, handler, kmi, event, properties, NULL, FALSE); } /* Finished and pass through flag as handled */ @@ -1611,7 +1632,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) event->keymap_idname= kmi->idname; /* weak, but allows interactive callback to not use rawkey */ - action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr); + action |= wm_handler_operator_call(C, handlers, handler, kmi, event, kmi->ptr); if(action & WM_HANDLER_BREAK) /* not always_pass here, it denotes removed handler */ break; } @@ -1661,7 +1682,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } else { /* modal, swallows all */ - action |= wm_handler_operator_call(C, handlers, handler, event, NULL); + action |= wm_handler_operator_call(C, handlers, handler, NULL, event, NULL); } if(action & WM_HANDLER_BREAK) { @@ -2043,10 +2064,12 @@ void wm_event_do_handlers(bContext *C) win->eventstate->prevclickx = event->x; win->eventstate->prevclicky = event->y; } else { /* reset if not */ - win->eventstate->prevtype = -1; + win->eventstate->prevtype = event->type; win->eventstate->prevval = 0; win->eventstate->prevclicktime = 0; } + + win->eventstate->prevkeytime = (event->val == KM_PRESS || event->val == KM_RELEASE)?PIL_check_seconds_timer():0; } /* unlink and free here, blender-quit then frees all */ -- 1.7.3.1.msysgit.0