Reputation: 231
How do you copy text to the clipboard in Ruby?
Sounds simple right? But I've been trying to do this for 5 days now, with no success.
I searched on internet, but all I got is how to do it in newer versions of Ruby (I'm using 1.8.7 and no I can't use a newer version).
So I tried making a HTML file to do it for me. After trying 4-5 different ways (from online guides), in 3 browsers, and even looking at Photobucket's source code to try figuring how it copies img codes, I gave up. Nothing worked for me.
So I made a C# .exe and made my Ruby program call it. Finally something is being sent to the clipboard. It's a step forward, but still, it's only the first word in a string. When I try copying two words
, only two
is copied.
my Ruby program looks like this:
system ("CopyClip.exe #{text}")
and in C# (in CopyClip), it does:
Clipboard.set_text(args[0])
Basically, I don't care if you help me do it in Ruby, HTML, C#, or any other language, as long as it works.
Upvotes: 23
Views: 18755
Reputation: 1175
The clipboard gem allows you to access the clipboard on Liunx, MacOS and Windows. The focus is on simple text. You can copy a string with Clipboard.copy("string") and paste it with Clipboard.paste()
.
That's it, basically.
Now let's take a closer look at the specific platforms.
Linux
For Linux support, the little utility xclip is needed. You can install it on Ubuntu with sudo apt-get install xclip
.
Furthermore, you can choose from which clipboard you want to paste (the default is PRIMARYCLIPBOARD). copy()
copies to all the clipboards in Clipboard::CLIPBOARDS
, fo example Clipboard.paste :primary
.
macOS
On the macOS, it works fine.
Upvotes: 6
Reputation: 9953
For those writing GTK+ applications (which the OP isn't), writing to the clipboard is quite straightforward:
Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD).set_text(content).store
You can also use the primary (Gdk::Selection::PRIMARY
) or secondary (Gdk::Selection::SECONDARY
) X selections.
See also the full ruby API and its underlying C API.
Upvotes: 2
Reputation: 42192
Seems like you are using windows, this works with Ruby 1.9.3 under windows 7.
For the original answer, see Ruby copy to clipboard with Fiddle
require 'open3'
module Clipboard; end
module Clipboard::Windows
extend self
CF_TEXT = 1
CF_UNICODETEXT = 13
GMEM_MOVEABLE = 2
# get ffi function handlers
begin
require 'ffi'
rescue LoadError
raise LoadError, 'Could not load the required ffi gem, install it with: gem install ffi'
end
module User32
extend FFI::Library
ffi_lib "user32"
ffi_convention :stdcall
attach_function :open, :OpenClipboard, [ :long ], :long
attach_function :close, :CloseClipboard, [ ], :long
attach_function :empty, :EmptyClipboard, [ ], :long
attach_function :get, :GetClipboardData, [ :long ], :long
attach_function :set, :SetClipboardData, [ :long, :long ], :long
end
module Kernel32
extend FFI::Library
ffi_lib 'kernel32'
ffi_convention :stdcall
attach_function :lock, :GlobalLock, [ :long ], :pointer
attach_function :unlock, :GlobalUnlock, [ :long ], :long
attach_function :size, :GlobalSize, [ :long ], :long
attach_function :alloc, :GlobalAlloc, [ :long, :long ], :long
end
# see http://www.codeproject.com/KB/clipboard/archerclipboard1.aspx
def paste(_ = nil)
ret = ""
if 0 != User32.open( 0 )
hclip = User32.get( CF_UNICODETEXT )
if hclip && 0 != hclip
pointer_to_data = Kernel32.lock( hclip )
data = ""
# Windows Unicode is ended by to null bytes, so get the whole string
size = Kernel32.size( hclip )
data << pointer_to_data.get_bytes( 0, size - 2 )
if RUBY_VERSION >= '1.9'
ret = data.force_encoding("UTF-16LE").encode(Encoding.default_external) # TODO catch bad encodings
else # 1.8: fallback to simple CP850 encoding
require 'iconv'
utf8 = Iconv.iconv( "UTF-8", "UTF-16LE", data)[0]
ret = Iconv.iconv( "CP850", "UTF-8", utf8)[0]
end
if data && 0 != data
Kernel32.unlock( hclip )
end
end
User32.close( )
end
ret || ""
end
def clear
if 0 != User32.open( 0 )
User32.empty( )
User32.close( )
end
paste
end
def copy(data_to_copy)
if ( RUBY_VERSION >= '1.9' ) && 0 != User32.open( 0 )
User32.empty( )
data = data_to_copy.encode("UTF-16LE") # TODO catch bad encodings
data << 0
handler = Kernel32.alloc( GMEM_MOVEABLE, data.bytesize )
pointer_to_data = Kernel32.lock( handler )
pointer_to_data.put_bytes( 0, data, 0, data.bytesize )
Kernel32.unlock( handler )
User32.set( CF_UNICODETEXT, handler )
User32.close( )
else # don't touch anything
Open3.popen3( 'clip' ){ |input,_,_| input << data_to_copy } # depends on clip (available by default since Vista)
end
paste
end
end
Clipboard::Windows.copy("test")
puts Clipboard::Windows.paste
In my collection I had another script that used to work in Windows 7 32 bit, if you have trouble with the first one and only use 32 bit, try this one
#!/usr/bin/env ruby -w
# win32 only
require 'singleton'
require 'thread'
require 'Win32API'
class Clipboard
include Singleton
CF_TEXT = 1
def initialize
@@mutex = Mutex.new
@@open = Win32API.new("user32","OpenClipboard",['L'],'L')
@@close = Win32API.new("user32","CloseClipboard",[],'L')
@@empty = Win32API.new("user32","EmptyClipboard",[],'L')
@@set = Win32API.new("user32","SetClipboardData",['L','P'],'L')
@@get = Win32API.new("user32", "GetClipboardData", ['L'], 'L')
@@lock = Win32API.new("kernel32", "GlobalLock", ['L'], 'P')
@@unlock = Win32API.new("kernel32", "GlobalUnlock", ['L'], 'L')
end
def copy
@@mutex.synchronize do
@@open.Call(0)
str = @@lock.Call(@@get.Call(CF_TEXT))
@@unlock.Call(@@get.Call(CF_TEXT))
@@close.Call
return str
end
end
def paste(str)
@@mutex.synchronize do
@@open.Call(0)
@@empty.Call
@@set.Call(CF_TEXT, str)
@@close.Call
@@lock = Win32API.new("kernel32", "GlobalLock", ['L'], 'P')
@@unlock = Win32API.new("kernel32", "GlobalUnlock", ['L'], 'L')
return nil
end
end
end
clip = Clipboard.instance
puts clip.copy
puts str
clip.paste("foo")
puts clip.copy
If you don't mind to install a gem, here is a much simpler solution, works on windows7 64 bit, Ruby 1.9.3.
#gem install clipboard
require 'clipboard'
Clipboard.copy("This is a sentence that has been copied to your clipboard")
puts Clipboard.paste
Upvotes: 0
Reputation: 3638
This answer works great for OSX:
def pbcopy(input)
str = input.to_s
IO.popen('pbcopy', 'w') { |f| f << str }
str
end
def pbpaste
`pbpaste`
end
Upvotes: 59
Reputation: 20125
I suspect if you wrap the argument to your C# app in quotes, you'll get all the text in args[0]
:
system("CopyClip.exe '#{text}'")
Alternatively, and probably better in case your text contains apostrophes or other special shell characters:
system("CopyClip.exe", text)
Or perhaps even better, use the clipboard gem - this works for me on 1.8.7, but I haven't been able to test it on Windows:
require 'clipboard'
Clipboard.copy text
Upvotes: 7