fix for error in last commit - don't overwrite options in the new operator which...
[blender.git] / source / blender / windowmanager / intern / wm_event_system.c
index 8861f128c4b2a8e21690dc13fe6e2abbdc73bb0d..079833f693ff3362a61fac85f13126ca4658fed9 100644 (file)
@@ -1,6 +1,4 @@
 /*
 /*
- * $Id$
- *
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
  * ***** BEGIN GPL LICENSE BLOCK *****
  *
  * This program is free software; you can redistribute it and/or
@@ -33,7 +31,6 @@
 
 #include <stdlib.h>
 #include <string.h>
 
 #include <stdlib.h>
 #include <string.h>
-#include <math.h>
 
 #include "DNA_listBase.h"
 #include "DNA_screen_types.h"
 
 #include "DNA_listBase.h"
 #include "DNA_screen_types.h"
@@ -47,6 +44,7 @@
 
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_utildefines.h"
+#include "BLI_math.h"
 
 #include "BKE_blender.h"
 #include "BKE_context.h"
 
 #include "BKE_blender.h"
 #include "BKE_context.h"
@@ -61,6 +59,7 @@
 
 #include "ED_fileselect.h"
 #include "ED_info.h"
 
 #include "ED_fileselect.h"
 #include "ED_info.h"
+#include "ED_render.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
 #include "ED_util.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
 #include "ED_util.h"
 #include "wm_event_types.h"
 #include "wm_draw.h"
 
 #include "wm_event_types.h"
 #include "wm_draw.h"
 
+#ifndef NDEBUG
+#  include "RNA_enum_types.h"
+#endif
+
 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only);
 
 /* ************ event management ************** */
 
 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
 {
 static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, short context, short poll_only);
 
 /* ************ event management ************** */
 
 void wm_event_add(wmWindow *win, wmEvent *event_to_add)
 {
-       wmEvent *event= MEM_callocN(sizeof(wmEvent), "event");
+       wmEvent *event= MEM_callocN(sizeof(wmEvent), "wmEvent");
        
        *event= *event_to_add;
        BLI_addtail(&win->queue, event);
        
        *event= *event_to_add;
        BLI_addtail(&win->queue, event);
@@ -183,7 +186,7 @@ void wm_event_do_notifiers(bContext *C)
        wmWindowManager *wm= CTX_wm_manager(C);
        wmNotifier *note, *next;
        wmWindow *win;
        wmWindowManager *wm= CTX_wm_manager(C);
        wmNotifier *note, *next;
        wmWindow *win;
-       unsigned int win_combine_v3d_datamask= 0;
+       uint64_t win_combine_v3d_datamask= 0;
        
        if(wm==NULL)
                return;
        
        if(wm==NULL)
                return;
@@ -222,20 +225,8 @@ void wm_event_do_notifiers(bContext *C)
 
                        if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
                                if(note->category==NC_SCENE) {
 
                        if(note->window==win || (note->window == NULL && (note->reference == NULL || note->reference == CTX_data_scene(C)))) {
                                if(note->category==NC_SCENE) {
-                                       if(note->data==ND_SCENEBROWSE) {
-                                               ED_screen_set_scene(C, note->reference);        // XXX hrms, think this over!
-                                               if(G.f & G_DEBUG)
-                                                       printf("scene set %p\n", note->reference);
-                                       }
-                                       else if(note->data==ND_FRAME)
+                                       if(note->data==ND_FRAME)
                                                do_anim= 1;
                                                do_anim= 1;
-                                       
-                                       if(note->action == NA_REMOVED) {
-                                               ED_screen_delete_scene(C, note->reference);     // XXX hrms, think this over!
-                                               if(G.f & G_DEBUG)
-                                                       printf("scene delete %p\n", note->reference);
-                                       }
-                                               
                                }
                        }
                        if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
                                }
                        }
                        if(ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
@@ -291,7 +282,7 @@ void wm_event_do_notifiers(bContext *C)
        
        /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
        for(win= wm->windows.first; win; win= win->next) {
        
        /* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
        for(win= wm->windows.first; win; win= win->next) {
-               win_combine_v3d_datamask |= ED_viewedit_datamask(win->screen);
+               win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
        }
 
        /* cached: editor refresh callbacks now, they get context */
        }
 
        /* cached: editor refresh callbacks now, they get context */
@@ -309,6 +300,7 @@ void wm_event_do_notifiers(bContext *C)
                /* XXX make lock in future, or separated derivedmesh users in scene */
                if(!G.rendering) {
                        /* depsgraph & animation: update tagged datablocks */
                /* XXX make lock in future, or separated derivedmesh users in scene */
                if(!G.rendering) {
                        /* depsgraph & animation: update tagged datablocks */
+                       Main *bmain = CTX_data_main(C);
 
                        /* copied to set's in scene_update_tagged_recursive() */
                        win->screen->scene->customdata_mask= win_combine_v3d_datamask;
 
                        /* copied to set's in scene_update_tagged_recursive() */
                        win->screen->scene->customdata_mask= win_combine_v3d_datamask;
@@ -316,7 +308,7 @@ void wm_event_do_notifiers(bContext *C)
                        /* XXX, hack so operators can enforce datamasks [#26482], gl render */
                        win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
 
                        /* XXX, hack so operators can enforce datamasks [#26482], gl render */
                        win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
 
-                       scene_update_tagged(CTX_data_main(C), win->screen->scene);
+                       scene_update_tagged(bmain, win->screen->scene);
                }
        }
 
                }
        }
 
@@ -435,18 +427,53 @@ static void wm_operator_print(bContext *C, wmOperator *op)
        MEM_freeN(buf);
 }
 
        MEM_freeN(buf);
 }
 
+/* for debugging only, getting inspecting events manually is tedious */
+#ifndef NDEBUG
+
+void WM_event_print(wmEvent *event)
+{
+       if(event) {
+               const char *unknown= "UNKNOWN";
+               const char *type_id= unknown;
+               const char *val_id= unknown;
+
+               RNA_enum_identifier(event_type_items, event->type, &type_id);
+               RNA_enum_identifier(event_value_items, event->val, &val_id);
+
+               printf("wmEvent - type:%d/%s, val:%d/%s, "
+                      "shift:%d, ctrl:%d, alt:%d, oskey:%d, keymodifier:%d, "
+                      "mouse:(%d,%d), ascii:'%c', utf8:'%.*s', "
+                      "keymap_idname:%s, pointer:%p\n",
+                      event->type, type_id, event->val, val_id,
+                      event->shift, event->ctrl, event->alt, event->oskey, event->keymodifier,
+                      event->x, event->y, event->ascii,
+                      BLI_str_utf8_size(event->utf8_buf), event->utf8_buf,
+                      event->keymap_idname, (void *)event);
+       }
+       else {
+               printf("wmEvent - NULL\n");
+       }
+}
+
+#endif /* NDEBUG */
+
 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, int popup)
 {
        if(popup) {
                if(op->reports->list.first) {
                        /* FIXME, temp setting window, see other call to uiPupMenuReports for why */
                        wmWindow *win_prev= CTX_wm_window(C);
 static void wm_operator_reports(bContext *C, wmOperator *op, int retval, int popup)
 {
        if(popup) {
                if(op->reports->list.first) {
                        /* FIXME, temp setting window, see other call to uiPupMenuReports for why */
                        wmWindow *win_prev= CTX_wm_window(C);
+                       ScrArea *area_prev= CTX_wm_area(C);
+                       ARegion *ar_prev= CTX_wm_region(C);
+
                        if(win_prev==NULL)
                                CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
 
                        uiPupMenuReports(C, op->reports);
 
                        CTX_wm_window_set(C, win_prev);
                        if(win_prev==NULL)
                                CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
 
                        uiPupMenuReports(C, op->reports);
 
                        CTX_wm_window_set(C, win_prev);
+                       CTX_wm_area_set(C, area_prev);
+                       CTX_wm_region_set(C, ar_prev);
                }
        }
        
                }
        }
        
@@ -558,12 +585,36 @@ static int wm_operator_exec(bContext *C, wmOperator *op, int repeat)
        
 }
 
        
 }
 
-/* for running operators with frozen context (modal handlers, menus) */
+/* simply calls exec with basic checks */
+static int wm_operator_exec_notest(bContext *C, wmOperator *op)
+{
+       int retval= OPERATOR_CANCELLED;
+
+       if(op==NULL || op->type==NULL || op->type->exec==NULL)
+               return retval;
+
+       retval= op->type->exec(C, op);
+       OPERATOR_RETVAL_CHECK(retval);
+
+       return retval;
+}
+
+/* for running operators with frozen context (modal handlers, menus)
+ *
+ * warning: do not use this within an operator to call its self! [#29537] */
 int WM_operator_call(bContext *C, wmOperator *op)
 {
        return wm_operator_exec(C, op, 0);
 }
 
 int WM_operator_call(bContext *C, wmOperator *op)
 {
        return wm_operator_exec(C, op, 0);
 }
 
+/* this is intended to be used when an invoke operator wants to call exec on its self
+ * and is basically like running op->type->exec() directly, no poll checks no freeing,
+ * since we assume whoever called invokle will take care of that */
+int WM_operator_call_notest(bContext *C, wmOperator *op)
+{
+       return wm_operator_exec_notest(C, op);
+}
+
 /* do this operator again, put here so it can share above code */
 int WM_operator_repeat(bContext *C, wmOperator *op)
 {
 /* do this operator again, put here so it can share above code */
 int WM_operator_repeat(bContext *C, wmOperator *op)
 {
@@ -593,7 +644,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot, P
        }
        else {
                IDPropertyTemplate val = {0};
        }
        else {
                IDPropertyTemplate val = {0};
-               op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
+               op->properties= IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
        }
        RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
 
        }
        RNA_pointer_create(&wm->id, ot->srna, op->properties, op->ptr);
 
@@ -678,6 +729,47 @@ static void wm_region_mouse_co(bContext *C, wmEvent *event)
        }
 }
 
        }
 }
 
+static int wm_operator_init_from_last(wmWindowManager *wm, wmOperator *op)
+{
+       int change= FALSE;
+       wmOperator *lastop;
+
+       for(lastop= wm->operators.last; lastop; lastop= lastop->prev) {
+               /* equality check is a bit paranoid but just incase */
+               if((op != lastop) && (op->type == (lastop->type))) {
+                       break;
+               }
+       }
+
+       if (lastop && op != lastop) {
+               PropertyRNA *iterprop;
+               iterprop= RNA_struct_iterator_property(op->type->srna);
+
+               RNA_PROP_BEGIN(op->ptr, itemptr, iterprop) {
+                       PropertyRNA *prop= itemptr.data;
+                       if((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
+                               if (!RNA_property_is_set(op->ptr, prop)) { /* don't override a setting already set */
+                                       const char *identifier= RNA_property_identifier(prop);
+                                       IDProperty *idp_src= IDP_GetPropertyFromGroup(lastop->properties, identifier);
+                                       if(idp_src) {
+                                               IDProperty *idp_dst = IDP_CopyProperty(idp_src);
+
+                                               /* note - in the future this may need to be done recursively,
+                                                * but for now RNA doesn't access nested operators */
+                                               idp_dst->flag |= IDP_FLAG_GHOST;
+
+                                               IDP_ReplaceInGroup(op->properties, idp_dst);
+                                               change= TRUE;
+                                       }
+                               }
+                       }
+               }
+               RNA_PROP_END;
+       }
+
+       return change;
+}
+
 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
 static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, PointerRNA *properties, ReportList *reports, short poll_only)
 {
        wmWindowManager *wm= CTX_wm_manager(C);
@@ -690,6 +782,11 @@ static int wm_operator_invoke(bContext *C, wmOperatorType *ot, wmEvent *event, P
        if(WM_operator_poll(C, ot)) {
                wmOperator *op= wm_operator_create(wm, ot, properties, reports); /* if reports==NULL, theyll be initialized */
                
        if(WM_operator_poll(C, ot)) {
                wmOperator *op= wm_operator_create(wm, ot, 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 */
+                       wm_operator_init_from_last(wm, op);
+               }
+
                if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
                        printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
                
                if((G.f & G_DEBUG) && event && event->type!=MOUSEMOVE)
                        printf("handle evt %d win %d op %s\n", event?event->type:0, CTX_wm_screen(C)->subwinactive, ot->idname); 
                
@@ -1141,7 +1238,7 @@ static int wm_eventmatch(wmEvent *winevent, wmKeyMapItem *kmi)
 
        /* the matching rules */
        if(kmitype==KM_TEXTINPUT)
 
        /* the matching rules */
        if(kmitype==KM_TEXTINPUT)
-               if(ISTEXTINPUT(winevent->type) && winevent->ascii) return 1;
+               if(ISTEXTINPUT(winevent->type) && (winevent->ascii || winevent->utf8_buf[0])) return 1;
        if(kmitype!=KM_ANY)
                if(winevent->type!=kmitype) return 0;
        
        if(kmitype!=KM_ANY)
                if(winevent->type!=kmitype) return 0;
        
@@ -1218,41 +1315,47 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                        retval= ot->modal(C, op, event);
                        OPERATOR_RETVAL_CHECK(retval);
 
                        retval= ot->modal(C, op, event);
                        OPERATOR_RETVAL_CHECK(retval);
 
-                       if(ot->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
-                               wm->op_undo_depth--;
+                       /* when this is _not_ the case the modal modifier may have loaded
+                        * a new blend file (demo mode does this), so we have to assume
+                        * the event, operator etc have all been freed. - campbell */
+                       if(CTX_wm_manager(C) == wm) {
 
 
-                       /* putting back screen context, reval can pass trough after modal failures! */
-                       if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
-                               CTX_wm_area_set(C, area);
-                               CTX_wm_region_set(C, region);
-                       }
-                       else {
-                               /* this special cases is for areas and regions that get removed */
-                               CTX_wm_area_set(C, NULL);
-                               CTX_wm_region_set(C, NULL);
-                       }               
+                               if(ot->flag & OPTYPE_UNDO)
+                                       wm->op_undo_depth--;
 
 
-                       if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED))
-                               wm_operator_reports(C, op, retval, 0);
-                       
-                       if(retval & OPERATOR_FINISHED) {
-                               wm_operator_finished(C, op, 0);
-                               handler->op= NULL;
-                       }
-                       else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
-                               WM_operator_free(op);
-                               handler->op= NULL;
-                       }
-                       
-                       /* remove modal handler, operator itself should have been cancelled and freed */
-                       if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
-                               WM_cursor_ungrab(CTX_wm_window(C));
+                               /* putting back screen context, reval can pass trough after modal failures! */
+                               if((retval & OPERATOR_PASS_THROUGH) || wm_event_always_pass(event)) {
+                                       CTX_wm_area_set(C, area);
+                                       CTX_wm_region_set(C, region);
+                               }
+                               else {
+                                       /* this special cases is for areas and regions that get removed */
+                                       CTX_wm_area_set(C, NULL);
+                                       CTX_wm_region_set(C, NULL);
+                               }
 
 
-                               BLI_remlink(handlers, handler);
-                               wm_event_free_handler(handler);
-                               
-                               /* prevent silly errors from operator users */
-                               //retval &= ~OPERATOR_PASS_THROUGH;
+                               if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED))
+                                       wm_operator_reports(C, op, retval, 0);
+
+                               if(retval & OPERATOR_FINISHED) {
+                                       wm_operator_finished(C, op, 0);
+                                       handler->op= NULL;
+                               }
+                               else if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
+                                       WM_operator_free(op);
+                                       handler->op= NULL;
+                               }
+
+                               /* remove modal handler, operator itself should have been cancelled and freed */
+                               if(retval & (OPERATOR_CANCELLED|OPERATOR_FINISHED)) {
+                                       WM_cursor_ungrab(CTX_wm_window(C));
+
+                                       BLI_remlink(handlers, handler);
+                                       wm_event_free_handler(handler);
+
+                                       /* prevent silly errors from operator users */
+                                       //retval &= ~OPERATOR_PASS_THROUGH;
+                               }
                        }
                        
                }
                        }
                        
                }
@@ -1265,6 +1368,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
                if(ot)
                        retval= wm_operator_invoke(C, ot, event, properties, NULL, FALSE);
        }
                if(ot)
                        retval= wm_operator_invoke(C, ot, event, properties, NULL, FALSE);
        }
+       /* Finished and pass through flag as handled */
 
        /* Finished and pass through flag as handled */
        if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
 
        /* Finished and pass through flag as handled */
        if(retval == (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH))
@@ -1394,6 +1498,9 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                                         * only have because lib linking errors need to be seen by users :(
                                                         * it can be removed without breaking anything but then no linking errors - campbell */
                                                        wmWindow *win_prev= CTX_wm_window(C);
                                                         * only have because lib linking errors need to be seen by users :(
                                                         * it can be removed without breaking anything but then no linking errors - campbell */
                                                        wmWindow *win_prev= CTX_wm_window(C);
+                                                       ScrArea *area_prev= CTX_wm_area(C);
+                                                       ARegion *ar_prev= CTX_wm_region(C);
+
                                                        if(win_prev==NULL)
                                                                CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
 
                                                        if(win_prev==NULL)
                                                                CTX_wm_window_set(C, CTX_wm_manager(C)->windows.first);
 
@@ -1405,6 +1512,8 @@ static int wm_handler_fileselect_call(bContext *C, ListBase *handlers, wmEventHa
                                                        BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
 
                                                        CTX_wm_window_set(C, win_prev);
                                                        BLI_movelisttolist(&CTX_wm_reports(C)->list, &handler->op->reports->list);
 
                                                        CTX_wm_window_set(C, win_prev);
+                                                       CTX_wm_area_set(C, area_prev);
+                                                       CTX_wm_region_set(C, ar_prev);
                                                }
 
                                                WM_operator_free(handler->op);
                                                }
 
                                                WM_operator_free(handler->op);
@@ -1773,11 +1882,14 @@ void wm_event_do_handlers(bContext *C)
                                        }
                                        
                                        if(playing == 0) {
                                        }
                                        
                                        if(playing == 0) {
-                                               int ncfra = sound_sync_scene(scene) * (float)FPS + 0.5f;
-                                               if(ncfra != scene->r.cfra)      {
-                                                       scene->r.cfra = ncfra;
-                                                       ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
-                                                       WM_event_add_notifier(C, NC_WINDOW, NULL);
+                                               float time = sound_sync_scene(scene);
+                                               if(finite(time)) {
+                                                       int ncfra = sound_sync_scene(scene) * (float)FPS + 0.5f;
+                                                       if(ncfra != scene->r.cfra)      {
+                                                               scene->r.cfra = ncfra;
+                                                               ED_update_for_newframe(CTX_data_main(C), scene, win->screen, 1);
+                                                               WM_event_add_notifier(C, NC_WINDOW, NULL);
+                                                       }
                                                }
                                        }
                                        
                                                }
                                        }
                                        
@@ -1901,13 +2013,14 @@ void wm_event_do_handlers(bContext *C)
                                        win->eventstate->prevy= event->y;
                                        //printf("win->eventstate->prev = %d %d\n", event->x, event->y);
                                }
                                        win->eventstate->prevy= event->y;
                                        //printf("win->eventstate->prev = %d %d\n", event->x, event->y);
                                }
-                               else
-                                       ;//printf("not setting prev to %d %d\n", event->x, event->y);
+                               else {
+                                       //printf("not setting prev to %d %d\n", event->x, event->y);
+                               }
                        }
                        
                        /* store last event for this window */
                        /* mousemove and timer events don't overwrite last type */
                        }
                        
                        /* store last event for this window */
                        /* mousemove and timer events don't overwrite last type */
-                       if (event->type != MOUSEMOVE && !ISTIMER(event->type)) {
+                       if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE) && !ISTIMER(event->type)) {
                                if (wm_action_not_handled(action)) {
                                        if (win->eventstate->prevtype == event->type) {
                                                /* set click time on first click (press -> release) */
                                if (wm_action_not_handled(action)) {
                                        if (win->eventstate->prevtype == event->type) {
                                                /* set click time on first click (press -> release) */
@@ -2558,38 +2671,52 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                        GHOST_TEventKeyData *kd= customdata;
                        event.type= convert_key(kd->key);
                        event.ascii= kd->ascii;
                        GHOST_TEventKeyData *kd= customdata;
                        event.type= convert_key(kd->key);
                        event.ascii= kd->ascii;
+                       memcpy(event.utf8_buf, kd->utf8_buf,sizeof(event.utf8_buf));/* might be not null terminated*/
                        event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
                        
                        /* exclude arrow keys, esc, etc from text input */
                        event.val= (type==GHOST_kEventKeyDown)?KM_PRESS:KM_RELEASE;
                        
                        /* exclude arrow keys, esc, etc from text input */
-                       if(type==GHOST_kEventKeyUp || (event.ascii<32 && event.ascii>0))
+                       if(type==GHOST_kEventKeyUp) {
                                event.ascii= '\0';
                                event.ascii= '\0';
-                       
-                       /* modifiers */
-                       if (event.type==LEFTSHIFTKEY || event.type==RIGHTSHIFTKEY) {
-                               event.shift= evt->shift= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->oskey))
-                                  event.shift= evt->shift = 3;         // define?
-                       } 
-                       else if (event.type==LEFTCTRLKEY || event.type==RIGHTCTRLKEY) {
-                               event.ctrl= evt->ctrl= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->shift || evt->alt || evt->oskey))
-                                  event.ctrl= evt->ctrl = 3;           // define?
-                       } 
-                       else if (event.type==LEFTALTKEY || event.type==RIGHTALTKEY) {
-                               event.alt= evt->alt= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->shift || evt->oskey))
-                                  event.alt= evt->alt = 3;             // define?
-                       } 
-                       else if (event.type==OSKEY) {
-                               event.oskey= evt->oskey= (event.val==KM_PRESS);
-                               if(event.val==KM_PRESS && (evt->ctrl || evt->alt || evt->shift))
-                                  event.oskey= evt->oskey = 3;         // define?
+
+                               /* ghost should do this already for key up */
+                               if (event.utf8_buf[0]) {
+                                       printf("%s: ghost on your platform is misbehaving, utf8 events on key up!\n", __func__);
+                               }
+                               event.utf8_buf[0]= '\0';
                        }
                        }
-                       else {
+                       else if (event.ascii<32 && event.ascii > 0) {
+                               event.ascii= '\0';
+                               /* TODO. should this also zero utf8?, dont for now, campbell */
+                       }
+
+                       if (event.utf8_buf[0]) {
+                               if (BLI_str_utf8_size(event.utf8_buf) == -1) {
+                                       printf("%s: ghost detected an invalid unicode character '%d'!\n", __func__, (int)(unsigned char)event.utf8_buf[0]);
+                                       event.utf8_buf[0]= '\0';
+                               }
+                       }
+
+                       /* modifiers */
+                       /* assigning both first and second is strange - campbell */
+                       switch(event.type) {
+                       case LEFTSHIFTKEY: case RIGHTSHIFTKEY:
+                               event.shift= evt->shift= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case LEFTCTRLKEY: case RIGHTCTRLKEY:
+                               event.ctrl= evt->ctrl= (event.val==KM_PRESS) ? ((evt->shift || evt->alt || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case LEFTALTKEY: case RIGHTALTKEY:
+                               event.alt= evt->alt= (event.val==KM_PRESS) ? ((evt->ctrl || evt->shift || evt->oskey) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       case OSKEY:
+                               event.oskey= evt->oskey= (event.val==KM_PRESS) ? ((evt->ctrl || evt->alt || evt->shift) ? (KM_MOD_FIRST | KM_MOD_SECOND) : KM_MOD_FIRST) : FALSE;
+                               break;
+                       default:
                                if(event.val==KM_PRESS && event.keymodifier==0)
                                        evt->keymodifier= event.type; /* only set in eventstate, for next event */
                                else if(event.val==KM_RELEASE && event.keymodifier==event.type)
                                        event.keymodifier= evt->keymodifier= 0;
                                if(event.val==KM_PRESS && event.keymodifier==0)
                                        evt->keymodifier= event.type; /* only set in eventstate, for next event */
                                else if(event.val==KM_RELEASE && event.keymodifier==event.type)
                                        event.keymodifier= evt->keymodifier= 0;
+                               break;
                        }
 
                        /* this case happens on some systems that on holding a key pressed,
                        }
 
                        /* this case happens on some systems that on holding a key pressed,
@@ -2598,6 +2725,11 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                           key we don't want the key modifier */
                        if(event.keymodifier == event.type)
                                event.keymodifier= 0;
                           key we don't want the key modifier */
                        if(event.keymodifier == event.type)
                                event.keymodifier= 0;
+                       /* this case happened with an external numpad, it's not really clear
+                          why, but it's also impossible to map a key modifier to an unknwon
+                          key, so it shouldn't harm */
+                       if(event.keymodifier == UNKNOWNKEY)
+                               event.keymodifier= 0;
                        
                        /* if test_break set, it catches this. XXX Keep global for now? */
                        if(event.type==ESCKEY)
                        
                        /* if test_break set, it catches this. XXX Keep global for now? */
                        if(event.type==ESCKEY)
@@ -2675,4 +2807,8 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
                }
 
        }
                }
 
        }
+
+       /* Handy when debugging checking events */
+       /* WM_event_print(&event); */
+
 }
 }