Detect KeyDown and MouseDown Events from ScriptComponent

Hi @Dani_Abalde,
Thank you for your help. Yes, I noticed that there were a difference between the two events I subscribed to, but I don’t really understand why my event din’t fire because it looks like I already had it hooked (the second alternative):

Oh well. Remains the problem pointed out by @TomTom.

Back in the days of Delphi, which didn’t (doesn’t) have GarbageCollection I used a dirty trick utilizing Interfaces to do the “GC” for me, by embedding variables in a interface (calling them Guard), then when the code would go out of scope (leaving a method) any local variables based on this interface would be disposed of, due to the reference counting mechanism. Running it would look like pictured below (if I had the correct hook to the GH_Component, that is)

In this case I cannot really “hook” any such variable to the GH_Component class (since @DavidRutten didn’t provide any “OnDispose” hook… but he sure will…?), so to illustrate the idea I made a separate class to host the event, but the idea is the same; When the class is being disposed of, the Dispose method would unregister (unhook) the MouseDown delegate.

The code:

  private void RunScript(object x, ref object A)
  {
    var canvas = Canvas;

    if (canvas == null)
      return;

    if (m_gcevents == null)
    {
      m_gcevents = new GuardedMouseDownEvent(); // implements IDisposable
      m_gcevents.m_owner = this;
      m_gcevents.MouseDown_Subscriber(true);
    }

    Reflect(m_gcevents); // Just some blah-blah code

    System.Threading.Thread.Sleep(500);

    // Garbage collector should take care of unsubscribing, but...
    m_gcevents.Dispose(); 
    // ...sigh. Calling Dispose is only my dirty thing here, since the GC doesn't 
    // seem to be polite enough to actually Dispose of the object.
    m_gcevents = null;
  }

The implementations :

  // Still in Script_Instance...
  private GuardedMouseDownEvent m_gcevents;

  public GH_Canvas Canvas {
    get  { return Grasshopper.Instances.ActiveCanvas;  }
  }

and on the follwing lines the class dealing with MouseDown event and, in the next section, implementing the IDisposable, the dirty trick of sorts:

  // ========================================
  // CLASS GuardedMouseDownEvent
  // ========================================
  public class GuardedMouseDownEvent: IDisposable
  {
    public Script_Instance m_owner; // back reference to the script component

    public GH_Canvas Canvas {
      get { return Grasshopper.Instances.ActiveCanvas; } // for convenience
    }

    public void MouseDown_Subscriber(bool subscribe) {
      if (subscribe)
      {
        Rhino.RhinoApp.WriteLine("Registering GC_MouseDown event");
        Canvas.MouseDown += GC_MouseDown;
      } else {
        Rhino.RhinoApp.WriteLine("Unregistering GC_MouseDown event (poor mouse is now very dead... )");
        Canvas.MouseDown -= GC_MouseDown;
      }
    }

    // Some dummy action on MouseDown
    public void GC_MouseDown(object sender, MouseEventArgs e) {
      Rhino.RhinoApp.WriteLine("GCEvents.GH_MouseDown: Alive & Kicking!");
    }

… and here the IDisposable implementation

    // ==================================
    // IMPLEMENTING INTERFACE IDISPOSABLE
    // ==================================
    bool disposed = false;
    System.Runtime.InteropServices.SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);

    public void Dispose()
    {
      Dispose(true);
      GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
      if (disposed)  return;

      if (disposing) { // only managed objects
        handle.Dispose();        
      }

      // Unmanaged stuff, for example hooked events
      Rhino.RhinoApp.WriteLine(string.Format("(Dispose({0}))", disposing));
      MouseDown_Subscriber(false);   // = "unsubscribe"

      disposed = true;
    }
  } // end class  
} // </Custom additional code> 

Me and the .NET GC have not become freinds as of yet, so the GC doesn’t really dispose of the “GuardedMouseDownEvent” instance, but you guys may know better how to force .NET do dump the object without resorting to that ugly call to Dispose();

In any case, @DavidRutten should consider adding more hooks to GH so we can have more fun. Cough, cough.

// Rolf