How to call an extensions command from ruby script

I am working on automating a large amount of SketchUp files that require running a few commands from installed extensions.

Is there a way to find out the commands that are available in an extension and run them?

An example of one of the steps would be the last step of exporting the file into GLB using the SketchUp glTF Exporter by Evan Prananta. The command that I am looking to run is under Extensions > SKP glTF Exporter > Export Binary glTF 2.0

I am assuming this is a registered command somewhere withing the SketchUp environment, just need help finding out how to access it.

SketchUp has no direct way of invoking a specific command using the API. It might be possible to directly call whatever the command would call, but this requires knowledge of the internal workings of the extension. Even for an open source extension it’s fragile as method names can change, and for a proprietary extension the developer may not want you to poke around in there. You could however try reaching out to the author and see what they say. Maybe they are okay with exposing a set of simple commands publicly.

There is a clunky workaround to run a menu item.

  1. Assign a keychord shortcut via the Shortcuts panel of the Preferences dialog.

  2. Via the Ruby WIN32OLE library class, use the SendKeys method of the Windows Scripting Host’s Shell object to send the keychord to the SketchUp application. (The main window needs to have the focus in order for the keychords to be accepted.)

Example, say that you have assigned the keychord CTRL+F8 to the above menu item command:

module ShawnFrueh # <---<< top level namespace module
  module SomeNiftyTasks  # <---<< extension submodule

    extend self

    def export_gltf_binary
      require 'win32ole' unless defined?(WIN32OLE)
      shell = WIN32OLE.new('WScript.Shell')
      Sketchup.focus
      shell.SendKeys("{^F8}")
    end

    def do_task
      # ... preliminary stuff here ...
      export_gltf_binary()
    end

  end
end

The above is MS Windows platform only.

You can use utilities such as “cliclick” on Mac OS platform to send keychords to an application.


The Obvious: Since users subjectively assign shortcut keychords as they will, this paradigm is not well suited for public use in a distributed extension.

1 Like

:bulb: …if we’re talking about a clunky workaround:

The array of shortcut strings form Sketchup.get_shortcuts can be examined and find out what shortcut is assigned to the specific plugin…
(But still, this is not well suited.)

Edit add:
Perhaps:

glft = Sketchup.get_shortcuts.find{|s| s.include?("Export Binary glTF 2.0")}
glft_shortcut =glft.split(" ").first if glft

This will return a string in a format e.g. “Ctrl+F8” so the “Ctrl+” have to be replaced to ^…

1 Like

Thanks for the info, I’ve reached out to the devs to see if they have some insight on how I can call their commands via ruby.

With this particular plugin you can invoke as follows for gltf export:

temp_inst = EVP::GltfExporter::GltfExport.new
temp_inst.export(false, false, '')

for glb:

temp_inst.export(true, false, '')

I believe the export is something like: export(asGlb, ???, filename) where if filename is an empty string, the user will get a dialog prompt.

FYI: This has changed with the release of SketchUp 2022.0.

The API added the UI::Command#proc instance method to get the Proc object attached to a command.

If the extension created a UI::Command object then it’s proc can be called.

commands = ObjectSpace.each_object(UI::Command).map(&:itself)
glb_export = commands.find { |cmd| cmd.menu_text == 'Export Binary glTF 2.0' }
if glb_export && glb_export.respond_to?(:proc) # nil if not found
  glb_export.proc.call
end

But if the extension author only used Sketchup::Menu#add_item then this will not work as the menu interface does not automatically create command objects (as of the 23.0 release.)

1 Like

@DanRathbun this was helpful to understand, thanks! I wonder if there’s a way to see in which module/class the proc derives from. Alternatively I used the path within the small_icon to provide a more robust filter. The icon is likely to be located in same plugin directory.

commands = ObjectSpace.each_object(UI::Command).map(&:itself)
commands.each do |cmd|
  if (cmd.small_icon.include?("SomePluginDirectoryName") && cmd.menu_text == 'Export')
	cmd.proc.call
    break
  end
end

Unfortunately for the plugin mentioned above, it looks like the dev used Sketchup::Menu#add_item. It worked for my case as I’m working with a different plugin/scenario.

Only method objects have an #owner method to tell this.

The closest you’ll get is the Proc#source_location method which will return the path to the ruby file as the first member of the array returned. From that you can get the directory name …

location = cmd.proc.source_location
dir_name = File.basename(File.dirname(location.first))
1 Like