Controlling clipboard from SketchUp (via Ruby or other method)

Hi forumers,

Is there a way to control clipboard from Sketchup ?
The idea is to exchange samll informations (strings mostly) from sketchup to other external software using copy and past.

For example, is there a way to call in ruby to export :
my_string.to_clipboard
OR to import :
my_string = From_clipboard()

Any idea are welcome !
Thanks

There’s nothing in the SketchUp API to do this.

If you are developing for Windows only you could try to use the Win32 API (Clipboard - Win32 apps | Microsoft Learn) directly using Fiddle (Module: Fiddle (Ruby 2.5.3)).

read/write a temp file on either platform…

john

@john_drivenupthewall good idea, but it must be by clipboard

@thomthom thanks too ! do you a start of code for example ?
it’s way more difficult than basic ruby sketchup…
thanks in advance

You could use a HtmlDialog and both let the user manually copy the text from a field pr press a button to add it to the clipboard. This may also be better UX than silently writing to the clipboard in the background somehow.

2 Likes

adrigon,
This is a link to a multi-OS clipboard interface. I’ve looked through the code and it seems to be worth trying.

@eneroth3 : You mean by using javascript ? I’m not good in this langage. But if you have any example, I can check this.

@sWilliams : It’s really interresting, I tried this library but it depends on ffi gem. What is the best process to “install” a gem in Sketchup’s Ruby ?

Open Ruby Console inside SketchUp and use command …

Gem::install "ffi"

… and wait until after the message about the gem specification. Then you (or the clipboard gem) can use …

require "ffi"

Drawback with that is that it’s not a great solution for an extension that’s distributed to other users. The Gem.install call blocks SU while installing with no feedback for noticeable time. And if other extensions tried the same they might rely on different versions which might not be compatible. I’d instead make use of what ships with the StdLib.

1 Like

Looking closer at the Win32 API this might not be as easy as I originally thought…

If SetClipboardData succeeds, the system owns the object identified by the hMem parameter. The application may not write to or free the data once ownership has been transferred to the system, but it can lock and read from the data until the CloseClipboard function is called. (The memory must be unlocked before the Clipboard is closed.) If the hMem parameter identifies a memory object, the object must have been allocated using the function with the GMEM_MOVEABLE flag.

I’m not sure how to create a memory buffer using Fiddle (or FFI) for which I can then hand over ownership. Might have to do a Ruby C Extension…

First off, heed TT’s comment’s on ffi above. At some point you’ll want to recode this solution using fiddle; but that can come later. For a simple test of concept we can load the Clipboard gem into Sketchup and patch together a little application.

In the Sketchup Ruby Console enter

Gem.install 'ffi'
Gem.install 'clipboard', '= 1.0.6' # this older version will encode the strings correctly

For a test program, how about this:

require 'clipboard'

module Test
	x = 'ABCDEFG'
	Clipboard.copy(x)

	y = Clipboard.paste
	puts "The string was #{y}"
	nil
end

Uninstalling these gems from Sketchup takes a slightly different route. Download the su_gem.rb from this forum post and paste the Ruby code in to the Ruby Console.
https://forums.sketchup.com/t/rubygems-anyone-interested-in-using/61154/6

Then to display the info about the installed Gems enter:
SUGem.query “-d”

To uninstall the ffi and clipboard gems enter:
SUGem.uninstall “clipboard”
SUGem.uninstall “ffi”

Restart Sketchup and you’r good to go.

I got a working prototype to copy+paste plain text to/from the clipboard using StdLib Fiddle.

I’ll need to clean it up first before I share it - will post back tomorrow.

3 Likes

On my mac with SU2017 Make

Gem.install 'ffi'

is not working.

Error: #<Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

I understand that gems are not the solution for portable code.
So thanks in advance @tt_su for your sample of code :slight_smile:

I was thinking that for a portable solution @eneroth3 html way would be me suitable.

SketchUp isn’t set up to install gems that need to be locally compiled. If you match the Ruby version in SketchUp you may be able to compile outside and then copy into the gems folder inside sketchup.

1 Like

How about:

def clipboard(text)
	cmd = Sketchup.platform == :platform_win ? "echo #{text} | clip" : "echo \"#{text}\" | pbcopy"
	system(cmd)
end #def

might need some escaping though for special characters.

Just remember… if it is something common, but there is no ruby api method for it, there probably is a system command for it.

@DanRathbun as a sidenote. In this case, I honestly do not like having to rely on Sketchup to tell me what platform I’m on… This is such a generic thing that it might also be added to a codebase that has nothing to do with SketchUp.

thanks, that does the job !
so what command exist for reading the clipboard ?

Reading from system commands is more difficult. In normal ipc (Inter-process communication - Wikipedia) that should not be to difficult, but there is something going wrong in SketchUp while trying to read from system commands.

There are ways to copy something to a temporary text file and then reading in that textfile.

On Mac it’s pbpaste I think. But it’s more complicated on Windows. I don’t think there is a universal distributed utility (out of the box from Microsoft) to read the clipboard.

This cross-platform Ruby API statement will mimic the user pressing CTRL+V …

Sketchup.send_action('paste:')

yes, or follow the guidance on this post: cmd - How can you get the clipboard contents with a Windows command? - Stack Overflow
Use powershell to save the contents to a temporary file and then read that file in ruby

EDIT: something like this:

def read_clipboard()
	if Sketchup.platform == :platform_win
		require "tempfile"
		tempfile = Tempfile.new()
		tempfile.close()
		cmd = "powershell -command \"Get-Clipboard\" > \"#{tempfile.path}\""
		system(cmd)
		result = File.read(tempfile.path)
		tempfile.unlink
		return result
	else
	  # can a maccy provide this?
	end
	
end #def

But the problem when using system commands or backtick execute strings is they “flash open” a command window on embedded Ruby.

How about …

module ClipText

  extend self

  CLIPDIR ||= File.join(ENV['HOME'],'.clipboard')
  Dir.mkdir(CLIPDIR) if !File.exist?(CLIPDIR)

  def clear
    copy ''
  end

  if Sketchup.platform == :platform_win

    def copy(text)
      `echo #{text} | clip.exe`
      Dir.chdir(CLIPDIR) do
        `echo #{text} > "clip.txt"`
      end
    end

    def paste()
      Dir.chdir(CLIPDIR) do
        `powershell -command "Get-Clipboard" > "clip.txt"`
        txt = File.read('clip.txt').chomp.rstrip
        # Check if ClipBoard was cleared:
        txt == 'ECHO is on.' ? '' : txt
      end
    end

  else # Mac

    def copy(text)
      `echo "#{text}" | pbcopy`
      Dir.chdir(CLIPDIR) do
        `echo "#{text}" > "clip.txt"`
      end
    end

    def paste()
      `pbpaste`.chomp
    end

  end

end # module
1 Like