Ruby でクリップボードを使用する方法について。
2014/1/19 追記
2014/1/12 に win32-clipboard が更新(0.5.2->0.6.0)されて、
日本語も使えるようになっています。
ですので、この記事はもはや*無意味*です。
むむむ、なんというタイミングなんだろう……。(win32-clipboard の更新は約 4 年半ぶり)
バージョンアップした win32-clipboard の使用方法の記事も書きました。
Windows 上の Ruby でクリップボードを活用する方法 その2をご覧ください。
追記ここまで
# 今回、問題を応急処置的に対応します。
# なので、文字コードは Shift_JIS のみの対応とします。
対象:
- Windows 上で Ruby 1.9 系以降
- マルチバイト文字(とりあえず今回は Shift_JIS 限定)を使用している方向け
- win32-clipboard version.0.5.2 <-2014/1/19 追記
win32-clipboard という gem を利用します。
gem install win32-clipboard
こいつ使えると便利(画像も扱えるし、クリップボード監視とかもできる)そうなんですが、
いろいろ問題があります。
問題:
- 画像情報を扱うとエラーが発生する場合がある
- 日本語を扱うと、エラーが発生する
- 上記エラー解決しても、日本語を扱う場合、文字が途中で途切れる
1. 3. はともかく、2. の日本語対応のためには、かなーり面倒な修正が必要になるので、
こちらの方が別の方法 (AutoITX を使う方法) を紹介しています。
Rubyからクリップボードを操作する方法
ただし AutoITX では、文字列しか扱えないっぽいので、お好きな方をお選びください。
以降では、以下のファイルを編集していきます。
{ ruby のインストール先 }\lib\ruby\gems\2.0.0\gems\win32-clipboard-0.5.2\lib\win32\clipboard.rb
1. 画像情報を扱うとエラーが発生する場合がある
実際動かしてみると、エンコードの異なる 2 つの変数を結合しようとしてエラーが発生します。
C:/ruby/lib/ruby/gems/2.0.0/gems/win32-clipboard-0.5.2/lib/win32/clipboard.rb:388:in `get_image_data': incompatible character encodings: ASCII-8BIT and US-ASCII
(Encoding::CompatibilityError)
from C:/ruby/lib/ruby/gems/2.0.0/gems/win32-clipboard-0.5.2/lib/win32/clipboard.rb:129:in `data'
from C:/Applications/ruby/screenshot/printscreen.rb:23:in `write'
from clipimagetest.rb:4:in `'
1. 修正方法
極めて単純。
US-ASCII として Ruby に認識されちゃっている変数を、
ASCII-8BIT(BINARY) として認識させるだけです。
buf = "\x42\x4D" + [size_image].pack('L') + 0.chr * 4 + [offset].pack('L') + buf
buf = "\x42\x4D" + [size_image].pack('L') + 0.chr * 4 + [offset].pack('L') + buf.b
※ 1.9 系の場合、String#b が無いはずなので、以下のようにしてください。
buf = "\x42\x4D" + [size_image].pack('L') + 0.chr * 4 + [offset].pack('L') + buf.force_encoding('ASCII-8BIT')
やってることは、画像情報なので、buf の中身はバイナリとして扱ってねと教えてあげてるだけです。
以上で、クリップボード上の画像情報を Ruby で扱えるようになります。
require 'win32/clipboard'
if Win32::Clipboard.format_available?(Win32::Clipboard::DIB)
File.open('image.png', 'wb'){ |f|
f.write Win32::Clipboard.data(Win32::Clipboard::DIB)
}
end
2. 日本語を扱おうとすると、エラー発生して使用できない
クリップボード上にある文字列を取得した際、その文字列が US-ASCII として認識されているのが原因。
C:/ruby/lib/ruby/gems/2.0.0/gems/win32-clipboard-0.5.2/lib/win32/clipboard.rb:123:in `[]': invalid byte sequence in US-ASCII (ArgumentError)
from C:/ruby/lib/ruby/gems/2.0.0/gems/win32-clipboard-0.5.2/lib/win32/clipboard.rb:123:in `data'
from cliptest.rb:8:in `'
2. 修正方法(暫定)
注意:この対応は応急処置的な対応で、とりあえず Shift_JIS だけ使えるようにします。
clip_data = clip_data[ /^[^\0]*/ ]
while clip_data[clip_data.bytesize - 1] == "\0"
clip_data.chop!
end
ただし Ruby(win32-clipboard) でコピーした文字列を
メモ帳などのエディタにペーストすると文字化けすると思います。
その場合は、以下のように String#tosjis を使ってあげると大丈夫です。
require 'win32/clipboard'
require 'kconv'
# shift_jis でクリップボードにセット
Win32::Clipboard.set_data("クリップボードにデータを設定".tosjis)
# クリップボードのデータを取得
puts Win32::Clipboard.data.tosjis
# UTF-8 でやった方が……というツッコミもあると思います。
# おっしゃるとおりだと思います。
# ただ、現状の win32-clipboard を結構改造しないと UTF-8 は扱えないのです……。
# なので、今回は見送ります。
3. 上記エラー解決しても、日本語を扱うと場合、文字が途中で途切れる
原因は、バイト数が必要になる箇所で、String#length および String#size を使用しているため。
参考:
length, size (String) - Rubyリファレンス
一部を抜粋すると、
1.8 系では、文字の数はバイト数と同じになります。
1.9 系ではlengthメソッドは文字の数を返します。
バイト数を得たいときはbytesizeメソッドを使います。
3. 修正方法
String#size と String#length を String#bytesize に片っ端から修正します。
たとえば 77行目あたりを例にすると以下のように修正します。
hmem = GlobalAlloc(GHND, clip_data.length + 4)
mem = GlobalLock(hmem)
memcpy(mem, clip_data, clip_data.length)
hmem = GlobalAlloc(GHND, clip_data.bytesize + 4)
mem = GlobalLock(hmem)
memcpy(mem, clip_data, clip_data.bytesize)
以上で、Shift_JIS 限定ではありますが、Ruby でクリップボードが使えるようにはなります。
実は、他にも win32-clipboard にはマルチバイト文字を扱う上で妙な箇所があったりしますが、
エンコード周りは深入りしたくないので、スルー。
# たとえば bytesize + 4 の + 4 って何者!?とか。UTF-32 を考慮して + 4 してあるのかなぁ。
でも、UTF-8くらいは使えるようにしたいので、いつか、ある程度は対応したいです。
2014/01/13
|
カテゴリ:Ruby
|
トラックバック(0)
|
コメント(0)