Stop a function while running with "ESC" key

Is it possible to code something to stop a function while it is running by pressing the “esc” key?

Can I assume this is for an extension you have written yourself? If so, you need to implement the Tool method #onCancel.

1 Like

Yes, my extension shows and hide items in an order but it could take more time than expected or you could want to stop the process becasuse you don’t need to cotinue.
Thanks @slbaumgartner

Yes, as Steve said, currently only an active Tool can receive keystrokes if the main application has focus.

However, if it’s an UI::HtmlDialog that has the focus, then it can receive the ESC keystroke in JavaScript and fire off a Ruby callback to set some Ruby-side state variable that a timer could check periodically to decide whether to continue some operation.

2 Likes

The process is: I press an icon in an UI::HtmlDialog which run a Ruby callback that run a Ruby function. The last function is the one I need to stop while running, it doesn’t send any data to the UI::HtmlDialog while running.

Well, after the HTML icon is clicked, but just before calling the Ruby callback, you can attach a JavaScript event handler to the button waiting for an ESC keypress. If it happens it can call a “bailout” dialog callback.

Periodically, your processing can check a Ruby-side state variable to continue. The “bailout” callback can set this Ruby state variable to false.

At some point the Ruby-side should call a JS-side reset() function.

Here is some example code …not tested (Take it for what it’s worth. Ie, an idea.)
I think that the button must remain having the focus for the keyboard “keyup” event to fire.

module Rtches
	module SomeExtensionName
    extend self

    # Returns the HTML for the dialog.
    def html()
      js = %[
        var clicked = false;

        function setup() {
          var button = document.getElementById('clickme');
          button.addEventListener("click", (event) => {
            if (clicked) {
              return;
            } else {
              clicked = true;
              watchForEscape(this);
              sketchup.clicked;
            }
          });
          document.removeEventListener("DOMContentLoaded", setup);
          sketchup.load_complete;
        }

        function handleEscape(event) {
          if (event.code === 'Escape') {
            sketchup.bailout;
            // The Ruby side will need to call reset on the JS side!
          };
        }

        function watchForEscape(button) {
          button.addEventListener("keyup", handleEscape);
        }

        function stopWatchingForEscape() {
          var button = document.getElementById('clickme');
          button.removeEventListener("keyup", handleEscape);
        }

        // Needs to be called from the Ruby-side after porcessing is
        // complete or a baliout condition has been set via ESC.
        function reset() {
          stopWatchingForEscape();
          clicked = false;
        }

        document.addEventListener("DOMContentLoaded", setup);
      ]

      html = %[
        <!DOCTYPE html>
        <html>
          <head>
            <script>
              #{js}
            </script>
          </head>
          <body>
            <button id="clickme" tabindex="0" autofocus>Click Me</button>
          </body>
        </html>
      ]
    end # html()

  end # extension submodule
end # top level namespace

I’ll try to test something like that. Thanks @DanRathbun

Whoops, the clicked JS variable needs to be global. (Moved it outside the setup() function.)