Allowing users to escape from long operations in AutoCAD .NET

The bulk of this code was donated by Virupaksha Aithal, a member of our DevTech team in India.

It's fairly common for developers to want to check for user input from time to time during long operations, especially to see whether the user wants to cancel the current activity. In VB you'd use DoEvents() to enable messages to be processed by the application's message loop and in ObjectARX you'd use acedUsrBrk().

So how to do this in .NET?

The answer is to use a message filter. This allows us to check on user-input events... we still call DoEvents, as with previous versions of VB, which allows user input events (such as keystrokes) to flow into our message filter function. We can then detect the events we care about, and filter them out, if necessary.

This C# code filters all keystrokes during a loop operation, and allows the application to respond in its own way to the user hitting the Escape key:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using System;

using System.Windows.Forms;

namespace LoopTest

{

  public class LoopCommands

  {

    [CommandMethod("loop")]

    static public void Loop()

    {

      DocumentCollection dm =

        Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager;

      Editor ed =

        dm.MdiActiveDocument.Editor;

      // Create and add our message filter

      MyMessageFilter filter = new MyMessageFilter();

      System.Windows.Forms.Application.AddMessageFilter(filter);

      // Start the loop

      while (true)

      {

        // Check for user input events

        System.Windows.Forms.Application.DoEvents();

        // Check whether the filter has set the flag

        if (filter.bCanceled == true)

        {

          ed.WriteMessage("\nLoop cancelled.");

          break;

        }

        ed.WriteMessage("\nInside while loop...");

      }

      // We're done - remove the message filter

      System.Windows.Forms.Application.RemoveMessageFilter(filter);

    }

    // Our message filter class

    public class MyMessageFilter : IMessageFilter

    {

      public const int WM_KEYDOWN = 0x0100;

      public bool bCanceled = false;

      public bool PreFilterMessage(ref Message m)

      {

        if (m.Msg == WM_KEYDOWN)

        {

          // Check for the Escape keypress

          Keys kc = (Keys)(int)m.WParam & Keys.KeyCode;

          if (m.Msg == WM_KEYDOWN && kc == Keys.Escape)

          {

            bCanceled = true;

          }

          // Return true to filter all keypresses

          return true;

        }

        // Return false to let other messages through

        return false;

      }

    }

  }

}

  1. Tony Tanzillo Avatar

    One or two releases ago, acedUserBrk() was changed to not call AfxPumpMessage() on the main thread, because it caused many problems.

    So the developers renamed acedUsrBrk() to acedUsrBrkWithMessagePump(), and implemented a new acedUsrBrk() that does not call AfxPumpMessge() to process pending input messages.

    I've found that for checking the input queue, and also getting AutoCAD to periodically update its window, the simplest and easiest way to do this from managed code, is to just P/Invoke acedUsrBrkWithMessagePump(), and be done with it.

    🙂

  2. thank you for the code.it was very helpful.

  3. doug@barense.com Avatar
    doug@barense.com

    I truly appreciate the example above. However I'm trying to apply a similar use for the Tab key. Can you give me any suggestions on how to check whether the Tab key has been pressed?

  4. doug@barense.com Avatar
    doug@barense.com

    never mind. 🙂

  5. This code pauses the operation to check for a key operation.

    Is there any way to pause the operation and maybe do something else? Like open a browser window. (I'm trying to show a spec page during a block insertion)

  6. I suppose you could fire off another process to view a web-page. I'd warn against locking up the AutoCAD-based code while waiting for something elsewhere to happen (that's likely to end badly), but a separate process should be safe enough.

    Kean

Leave a Reply to Tony Tanzillo Cancel reply

Your email address will not be published. Required fields are marked *