Revit API Forum
Welcome to Autodesk’s Revit API Forums. Share your knowledge, ask questions, and explore popular Revit API topics.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Intercepting commands executed by keyboard shortcuts

6 REPLIES 6
Reply
Message 1 of 7
tamas.deri
448 Views, 6 Replies

Intercepting commands executed by keyboard shortcuts

I understand that I can create eventhandlers on Autodesk.Windows.ComponentManager.PreviewExecute and Autodesk.Windows.ComponentManager.ItemExecuted to be notified when a command is just about to start from a ribbon button, and when the exectuion of that command just finished. However I realized that these events are not being fired when those commands are executed via keyboard shortcuts. Both commands executions are logged into the journal file as Jrn.Command, and there is also a differentiation wether it was a ribbon button click, or a keyboard shortcut (Jrn.Command "KeyboardShortcut" , "Create a wall , ID_OBJECTS_WALL"  and Jrn.Command "Ribbon" , "Create a wall , ID_OBJECTS_WALL" )

I would like to know if there is any direct way to catch these events of using keyboard shortcuts, or my only real option would be to track the journal file continously, and act if a newly created line includes "KeyboardShortcut"? I wouldn't really like that option because it is ugly and seems to be resource heavy.

6 REPLIES 6
Message 2 of 7
Kennan.Chen
in reply to: tamas.deri

By utilizing AdWindows.dll, you have the ability to iterate through all ribbon items and obtain the ICommand instance associated with each item. Subsequently, you can encapsulate the ICommand instance with a new ICommand instance and link the new one to the ribbon item. Within the new ICommand instance, you can then execute any desired actions before the real command is executed.

 

This approach bears resemblance to Aspect-Oriented Programming (AOP).

Message 3 of 7
tamas.deri
in reply to: Kennan.Chen

Since the AdWindows.dll is not documented at all I couldn't really find a way to do that. Can you tell me a bit more about it?

Message 4 of 7
jeremy_tammik
in reply to: tamas.deri

Yes, use of AdWindows is not officially supported in the Revit API context. I think it is supported, however, in AutoCAD.NET programming, and the DLL is probably similar or even identical, so you might have better luck there. Also, some uses of it are documented by The Building Coder:

  

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 5 of 7
jeremy_tammik
in reply to: tamas.deri

... also note that .NET assemblies are self-documenting, to a certain extent...

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
Message 6 of 7
Kennan.Chen
in reply to: tamas.deri

A piece of code without any test.

Hope it helps!

 

public class RibbonCommandInterceptor
{
  public static event EventHandler<RibbonItem> BeforeExecuting;
  public static event EventHandler<RibbonItem> Executed;

  private static void RegisterCommand(InterceptorCommand command)
  {
    command.BeforeExecuting += (sender, e) =>
    {
      RibbonCommandInterceptor.BeforeExecuting?.Invoke(sender, e);
    };
    command.Executed += (sender, e) =>
    {
      RibbonCommandInterceptor.Executed?.Invoke(sender, e);
    };
  }

  // core method to intercept the ribbon commands.
  // call this method once at startup and call it whenever the ribbon items get updated.
  public static void Intercept()
  {
    // go through all the ribbon command items and intercept them with our own commands
    ComponentManager.Ribbon.Tabs.ForEach((tab) =>
    {
      tab.Panels.ForEach((panel) =>
      {
        panel.Source.Items.Where(item => item is RibbonCommandItem).Cast<RibbonCommandItem>().ForEach((item) =>
        {
          var command = item.CommandHandler;
          if (command is InterceptorCommand)
          {
            return;
          }
          // wrap the command with our own
          var interceptedCommand = new InterceptorCommand(command, item);
          // replace the command with our own
          item.CommandHandler = interceptedCommand;
        });
      });
    });
  }

  // wrapper command that intercepts the execution of the command
  private class InterceptorCommand : ICommand
  {
    private ICommand _wrappedCommand;
    private RibbonCommandItem _item;
    public InterceptorCommand(ICommand command, RibbonCommandItem item)
    {
      this._wrappedCommand = command;
      this._item = item;
      this._wrappedCommand.CanExecuteChanged += (sender, e) =>
      {
        this.CanExecuteChanged?.Invoke(this._item, e);
      };
      RibbonCommandInterceptor.RegisterCommand(this);
    }
    public event EventHandler<RibbonCommandItem> BeforeExecuting;
    public event EventHandler<RibbonCommandItem> Executed;
    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
      return _wrappedCommand.CanExecute(parameter);
    }

    public void Execute(object parameter)
    {
      try
      {
        this.BeforeExecuting?.Invoke(this._item);
      }
      catch (System.Exception)
      {
        Console.WriteLine("Error in BeforeExecuting");
      }

      this._wrappedCommand.Execute(parameter);

      try
      {
        this.Executed?.Invoke(this._item);
      }
      catch (System.Exception)
      {
        Console.WriteLine("Error in Executed");
      }
    }
  }
}

 

 

Message 7 of 7
tamas.deri
in reply to: Kennan.Chen

That is really nice, thanks for the effort!

 However, I've found that only Buttons created by addins have .CommandHandler. For built-in buttons it is null. Sot it seems to be a dead-and again 😞

I also couldn't figure out what to put as sender when I Invoke BeforeExecuting and Executed event. (in the example there is only one argument, this._item, which seems to be EventArg)

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Forma Design Contest


Rail Community