win32-clipboard 0.6.2 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES +6 -0
- data/README +1 -1
- data/Rakefile +6 -0
- data/lib/win32/clipboard.rb +34 -14
- data/lib/win32/windows/constants.rb +2 -0
- data/lib/win32/windows/functions.rb +3 -0
- data/test/lock.rb +18 -0
- data/test/notify.rb +27 -0
- data/test/test_clipboard.rb +22 -1
- data/test/test_clipboard_chain.rb +137 -0
- data/win32-clipboard.gemspec +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 359fdeba42a4dab1eb7e042e4bcf4a53f816238b
|
4
|
+
data.tar.gz: 03fef4f1ab539e544e6dcb1b8079d38d722cf636
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55d0dbe9871da1c7af56d9d0a5f2ce9f5daa1154983e47cb9d1f15c0059e68339b281733e9ea33ca3335fbb86a8e985bde343f56d2c4555fe9a45f5eace40bb1
|
7
|
+
data.tar.gz: 3ac574c4d51126ecf250d2e6ce867c1d9447a0e56940be4610d357d361ce03b320e9f3f25e2d311720dc28d11926f97eba4916400befd0ef50410acc558c91ff
|
data/CHANGES
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
== 0.6.3 - 7-Feb-2014
|
2
|
+
* Fixed a potential duplication notification issue in the notify_change method.
|
3
|
+
Thanks go to u338steven for the spot and patch.
|
4
|
+
* Fixed a clipboard chaining issue in the notify_change method when there are
|
5
|
+
multiple clipboard instances. Thanks again go to u338steven.
|
6
|
+
|
1
7
|
== 0.6.2 - 27-Jan-2014
|
2
8
|
* Fix and more tests for the internal get_image_data. Thanks go to u338steven
|
3
9
|
for the spot and patches.
|
data/README
CHANGED
data/Rakefile
CHANGED
@@ -51,6 +51,12 @@ namespace :test do
|
|
51
51
|
t.verbose = true
|
52
52
|
t.test_files = FileList['test/test_image_clipboard.rb']
|
53
53
|
end
|
54
|
+
|
55
|
+
Rake::TestTask.new(:chain) do |t|
|
56
|
+
t.warning = true
|
57
|
+
t.verbose = true
|
58
|
+
t.test_files = FileList['test/test_clipboard_chain.rb']
|
59
|
+
end
|
54
60
|
end
|
55
61
|
|
56
62
|
task :default => 'test:all'
|
data/lib/win32/clipboard.rb
CHANGED
@@ -16,7 +16,7 @@ module Win32
|
|
16
16
|
extend Windows::Structs
|
17
17
|
|
18
18
|
# The version of this library
|
19
|
-
VERSION = '0.6.
|
19
|
+
VERSION = '0.6.3'
|
20
20
|
|
21
21
|
# Clipboard formats
|
22
22
|
|
@@ -44,9 +44,7 @@ module Win32
|
|
44
44
|
def self.empty
|
45
45
|
begin
|
46
46
|
open
|
47
|
-
|
48
|
-
raise SystemCallError.new('EmptyClipboard', FFI.errno)
|
49
|
-
end
|
47
|
+
clear_if_already_opened
|
50
48
|
ensure
|
51
49
|
close
|
52
50
|
end
|
@@ -147,8 +145,8 @@ module Win32
|
|
147
145
|
#
|
148
146
|
def self.set_data(clip_data, format = TEXT)
|
149
147
|
begin
|
150
|
-
clear
|
151
148
|
open
|
149
|
+
clear_if_already_opened
|
152
150
|
|
153
151
|
# NULL terminate text or strip header of bitmap file
|
154
152
|
case format
|
@@ -268,10 +266,25 @@ module Win32
|
|
268
266
|
name = 'ruby-clipboard-' + Time.now.to_s
|
269
267
|
handle = CreateWindowEx(0, 'static', name, 0, 0, 0, 0, 0, 0, 0, 0, nil)
|
270
268
|
|
269
|
+
next_viewer = SetClipboardViewer(handle)
|
270
|
+
|
271
|
+
if next_viewer.nil?
|
272
|
+
raise SystemCallError.new('SetClipboardViewer', FFI.errno)
|
273
|
+
end
|
274
|
+
|
275
|
+
SetWindowLongPtr(handle, GWL_USERDATA, next_viewer)
|
276
|
+
|
277
|
+
ObjectSpace.define_finalizer(self, proc{self.close_window(handle)})
|
278
|
+
|
271
279
|
@first_notify = true
|
272
280
|
|
273
281
|
wnd_proc = FFI::Function.new(:uintptr_t, [:uintptr_t, :uint, :uintptr_t, :uintptr_t]) do |hwnd, umsg, wparam, lparam|
|
274
282
|
case umsg
|
283
|
+
when WM_DESTROY
|
284
|
+
next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
|
285
|
+
ChangeClipboardChain(hwnd, next_viewer)
|
286
|
+
PostQuitMessage(0)
|
287
|
+
rv = 0
|
275
288
|
when WM_DRAWCLIPBOARD
|
276
289
|
yield unless @first_notify
|
277
290
|
next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
|
@@ -280,8 +293,9 @@ module Win32
|
|
280
293
|
end
|
281
294
|
rv = 0
|
282
295
|
when WM_CHANGECBCHAIN
|
283
|
-
|
296
|
+
next_viewer = GetWindowLongPtr(hwnd, GWL_USERDATA)
|
284
297
|
next_viewer = lparam if next_viewer == wparam
|
298
|
+
SetWindowLongPtr(hwnd, GWL_USERDATA, next_viewer)
|
285
299
|
if next_viewer != 0
|
286
300
|
PostMessage(next_viewer, umsg, wparam, lparam)
|
287
301
|
end
|
@@ -299,14 +313,6 @@ module Win32
|
|
299
313
|
raise SystemCallError.new('SetWindowLongPtr', FFI.errno)
|
300
314
|
end
|
301
315
|
|
302
|
-
next_viewer = SetClipboardViewer(handle)
|
303
|
-
|
304
|
-
if next_viewer.nil?
|
305
|
-
raise SystemCallError.new('SetClipboardViewer', FFI.errno)
|
306
|
-
end
|
307
|
-
|
308
|
-
SetWindowLongPtr(handle, GWL_USERDATA, next_viewer)
|
309
|
-
|
310
316
|
msg = FFI::MemoryPointer.new(:char, 100)
|
311
317
|
|
312
318
|
while true
|
@@ -345,6 +351,14 @@ module Win32
|
|
345
351
|
end
|
346
352
|
end
|
347
353
|
|
354
|
+
# Clear the clipboard that is already opened
|
355
|
+
#
|
356
|
+
def self.clear_if_already_opened
|
357
|
+
unless EmptyClipboard()
|
358
|
+
raise SystemCallError.new('EmptyClipboard', FFI.errno)
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
348
362
|
# Get data for enhanced metadata files
|
349
363
|
#
|
350
364
|
def self.get_metafile_data(handle)
|
@@ -421,6 +435,12 @@ module Win32
|
|
421
435
|
|
422
436
|
array
|
423
437
|
end
|
438
|
+
|
439
|
+
# Close a window.(for self.notify_change)
|
440
|
+
#
|
441
|
+
def self.close_window(handle)
|
442
|
+
SendMessage(handle, WM_CLOSE, 0, 0)
|
443
|
+
end
|
424
444
|
end
|
425
445
|
end
|
426
446
|
|
@@ -24,6 +24,7 @@ module Windows
|
|
24
24
|
|
25
25
|
ffi_lib :user32
|
26
26
|
|
27
|
+
attach_function :ChangeClipboardChain, [:hwnd, :hwnd], :bool
|
27
28
|
attach_function :CloseClipboard, [], :bool
|
28
29
|
attach_function :CountClipboardFormats, [], :int
|
29
30
|
attach_function :CreateWindowEx, :CreateWindowExA, [:dword, :string, :string, :dword, :int, :int, :int, :int, :hwnd, :hmenu, :hinstance, :pointer], :hwnd
|
@@ -37,9 +38,11 @@ module Windows
|
|
37
38
|
attach_function :OpenClipboard, [:hwnd], :bool
|
38
39
|
attach_function :PeekMessage, :PeekMessageA, [:pointer, :hwnd, :uint, :uint, :uint], :bool
|
39
40
|
attach_function :PostMessage, :PostMessageA, [:hwnd, :uint, :uintptr_t, :uintptr_t], :bool
|
41
|
+
attach_function :PostQuitMessage, :PostQuitMessage, [:uint], :void
|
40
42
|
attach_function :RegisterClipboardFormat, :RegisterClipboardFormatA, [:string], :uint
|
41
43
|
attach_function :SetClipboardData, [:uint, :handle], :handle
|
42
44
|
attach_function :SetClipboardViewer, [:hwnd], :hwnd
|
45
|
+
attach_function :SendMessage, :SendMessageA, [:hwnd, :uint, :uintptr_t, :uintptr_t], :bool
|
43
46
|
attach_function :TranslateMessage, [:pointer], :bool
|
44
47
|
|
45
48
|
# Use Long on 32-bit Ruby, LongPtr on 64-bit Ruby
|
data/test/lock.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
def lock(&block)
|
5
|
+
Timeout::timeout(5) do
|
6
|
+
open(File.join(Dir.tmpdir, 'ruby-win32-clipboard.lock'), 'w') do |f|
|
7
|
+
begin
|
8
|
+
f.flock(File::LOCK_EX)
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
f.flock(File::LOCK_UN)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
rescue Timeout::Error
|
16
|
+
raise 'Lock(timeout)'
|
17
|
+
end
|
18
|
+
|
data/test/notify.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'win32/clipboard'
|
2
|
+
require File.join(File.dirname(__FILE__), 'lock')
|
3
|
+
|
4
|
+
include Win32
|
5
|
+
|
6
|
+
timeout = ARGV[1].to_i
|
7
|
+
|
8
|
+
def write
|
9
|
+
data = ''
|
10
|
+
lock do
|
11
|
+
data = Clipboard.data
|
12
|
+
end
|
13
|
+
|
14
|
+
begin
|
15
|
+
STDOUT.puts data
|
16
|
+
STDOUT.flush
|
17
|
+
rescue => e
|
18
|
+
puts $!
|
19
|
+
end
|
20
|
+
if data == ARGV[0]
|
21
|
+
exit
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Timeout::timeout(timeout) do
|
26
|
+
Clipboard.notify_change {write}
|
27
|
+
end
|
data/test/test_clipboard.rb
CHANGED
@@ -10,11 +10,12 @@
|
|
10
10
|
###########################################################################
|
11
11
|
require 'test-unit'
|
12
12
|
require 'win32/clipboard'
|
13
|
+
require 'timeout'
|
13
14
|
include Win32
|
14
15
|
|
15
16
|
class TC_Win32_ClipBoard < Test::Unit::TestCase
|
16
17
|
test "version is set to expected value" do
|
17
|
-
assert_equal('0.6.
|
18
|
+
assert_equal('0.6.3', Clipboard::VERSION)
|
18
19
|
end
|
19
20
|
|
20
21
|
test "data method basic functionality" do
|
@@ -141,6 +142,26 @@ class TC_Win32_ClipBoard < Test::Unit::TestCase
|
|
141
142
|
|
142
143
|
test "notify_change basic functionality" do
|
143
144
|
assert_respond_to(Clipboard, :notify_change)
|
145
|
+
def wait(&block)
|
146
|
+
Timeout::timeout(5) do
|
147
|
+
while @count == 0
|
148
|
+
yield if block
|
149
|
+
sleep(0.1)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
@count = 0
|
155
|
+
t = Thread.start do
|
156
|
+
Clipboard.notify_change {@count += 1}
|
157
|
+
end
|
158
|
+
wait {Clipboard.set_data('ready')}
|
159
|
+
@count = 0
|
160
|
+
|
161
|
+
Clipboard.set_data('foo')
|
162
|
+
wait
|
163
|
+
assert_equal(@count, 1)
|
164
|
+
t.kill
|
144
165
|
end
|
145
166
|
|
146
167
|
test "expected constants are defined" do
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
###########################################################################
|
3
|
+
# test_clipboard_chain.rb
|
4
|
+
#
|
5
|
+
# Test suite for the win32-clipboard library(only clipboard chain).
|
6
|
+
###########################################################################
|
7
|
+
require 'test-unit'
|
8
|
+
require 'win32/clipboard'
|
9
|
+
require 'timeout'
|
10
|
+
require File.join(File.dirname(__FILE__), 'lock')
|
11
|
+
|
12
|
+
include Win32
|
13
|
+
|
14
|
+
class TC_Clipboard_Chain < Test::Unit::TestCase
|
15
|
+
test "clipboard viewer chain" do
|
16
|
+
begin
|
17
|
+
# Add clipboard viewer 1-3
|
18
|
+
# clipboard viewer chain: cv3 -> cv2 -> cv1
|
19
|
+
cv1 = ClipboardViewer.new('1')
|
20
|
+
puts 'Added clipboard viewer 1'
|
21
|
+
|
22
|
+
cv2 = ClipboardViewer.new('2')
|
23
|
+
puts 'Added clipboard viewer 2'
|
24
|
+
|
25
|
+
cv3 = ClipboardViewer.new('3')
|
26
|
+
puts 'Added clipboard viewer 3'
|
27
|
+
|
28
|
+
lock do
|
29
|
+
Clipboard.set_data('foo')
|
30
|
+
end
|
31
|
+
|
32
|
+
result = Clipboard.data
|
33
|
+
assert_equal(result, cv1.result)
|
34
|
+
assert_equal(result, cv2.result)
|
35
|
+
assert_equal(result, cv3.result)
|
36
|
+
|
37
|
+
# Remove clipboard viewer 2
|
38
|
+
# clipboard viewer chain: cv3 -> cv1
|
39
|
+
assert_not_nil(cv2.remove)
|
40
|
+
|
41
|
+
cv1.clear
|
42
|
+
cv3.clear
|
43
|
+
Clipboard.set_data('bar')
|
44
|
+
|
45
|
+
result = Clipboard.data
|
46
|
+
assert_equal(result, cv1.result)
|
47
|
+
assert_equal(result, cv3.result)
|
48
|
+
|
49
|
+
# Remove clipboard viewer 3
|
50
|
+
assert_not_nil(cv3.remove)
|
51
|
+
|
52
|
+
cv1.clear
|
53
|
+
Clipboard.set_data('foobar')
|
54
|
+
|
55
|
+
result = Clipboard.data
|
56
|
+
assert_equal(result, cv1.result)
|
57
|
+
assert_not_nil(cv1.remove)
|
58
|
+
ensure
|
59
|
+
cv1.exit
|
60
|
+
cv2.exit
|
61
|
+
cv3.exit
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class ClipboardViewer
|
66
|
+
NOTIFY_TIMEOUT = 20
|
67
|
+
def initialize(key)
|
68
|
+
@key = key
|
69
|
+
load_path = File.join(File.join(File.dirname(__FILE__), '..'), 'lib')
|
70
|
+
@pipe = IO.popen("#{RbConfig.ruby} -I #{load_path} #{File.join(File.dirname(__FILE__), "notify.rb")} #{key} #{NOTIFY_TIMEOUT}")
|
71
|
+
@result = nil
|
72
|
+
is_ready = false
|
73
|
+
|
74
|
+
@t = Thread.start do
|
75
|
+
begin
|
76
|
+
while true
|
77
|
+
result = @pipe.gets.chomp
|
78
|
+
|
79
|
+
if result == 'ready'
|
80
|
+
is_ready = true
|
81
|
+
else
|
82
|
+
@result = result
|
83
|
+
end
|
84
|
+
|
85
|
+
if @result == @key.chop
|
86
|
+
break
|
87
|
+
end
|
88
|
+
end
|
89
|
+
rescue => e
|
90
|
+
puts $!
|
91
|
+
puts e.backtrace
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
Timeout::timeout(5) do
|
96
|
+
until is_ready
|
97
|
+
lock do
|
98
|
+
Clipboard.set_data('ready')
|
99
|
+
end
|
100
|
+
sleep(0.1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def clear
|
106
|
+
@result = nil
|
107
|
+
end
|
108
|
+
|
109
|
+
def result
|
110
|
+
Timeout::timeout(5) do
|
111
|
+
until @result
|
112
|
+
sleep(0.1)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
@result
|
116
|
+
rescue Timeout::Error
|
117
|
+
raise 'Cannot get result.(Timeout)'
|
118
|
+
end
|
119
|
+
|
120
|
+
def remove
|
121
|
+
return unless @t.alive?
|
122
|
+
lock do
|
123
|
+
Clipboard.set_data(@key)
|
124
|
+
end
|
125
|
+
ret = @t.join(3)
|
126
|
+
if ret
|
127
|
+
@pipe.close
|
128
|
+
end
|
129
|
+
ret
|
130
|
+
end
|
131
|
+
|
132
|
+
def exit
|
133
|
+
return unless @t.alive?
|
134
|
+
Process.kill('KILL', @pipe.pid)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/win32-clipboard.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: win32-clipboard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel J. Berger
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-02-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
@@ -87,7 +87,10 @@ files:
|
|
87
87
|
- test/img/32bit_bitfields2.bmp
|
88
88
|
- test/img/4bit.bmp
|
89
89
|
- test/img/8bit.bmp
|
90
|
+
- test/lock.rb
|
91
|
+
- test/notify.rb
|
90
92
|
- test/test_clipboard.rb
|
93
|
+
- test/test_clipboard_chain.rb
|
91
94
|
- test/test_html_clipboard.rb
|
92
95
|
- test/test_image_clipboard.rb
|
93
96
|
- win32-clipboard.gemspec
|
@@ -111,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
111
114
|
version: '0'
|
112
115
|
requirements: []
|
113
116
|
rubyforge_project: win32utils
|
114
|
-
rubygems_version: 2.2.
|
117
|
+
rubygems_version: 2.2.2
|
115
118
|
signing_key:
|
116
119
|
specification_version: 4
|
117
120
|
summary: A library for interacting with the Windows clipboard
|