win32-clipboard 0.6.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,232 +1,232 @@
1
- # The Win32 module serves as a namespace only.
2
- #
3
- module Win32
4
-
5
- # The HtmlClipboard class is a subclass of Clipboard that explicitly
6
- # handles text in HTML format.
7
- #
8
- class HtmlClipboard < Clipboard
9
-
10
- private
11
-
12
- # Marker block output
13
- #--
14
- # Version: Version of the clipboard.
15
- #
16
- # StartHTML: bytecount from the beginning of the clipboard to the
17
- # start of the context, or -1 if no context.
18
- #
19
- # EndHTML: bytecount from the beginning of the clipboard to the end
20
- # of the context, or -1 if no context.
21
- #
22
- # StartFragment: bytecount from the beginning of the clipboard to
23
- # the start of the fragment.
24
- #
25
- # EndFragment: bytecount from the beginning of the clipboard to the
26
- # end of the fragment.
27
- #
28
- # StartSelection: bytecount from the beginning of the clipboard to
29
- # the start of the selection.
30
- #
31
- # EndSelection: bytecount from the beginning of the clipboard to the
32
- # end of the selection.
33
- #
34
- MARKER_BLOCK_OUTPUT =
35
- "Version:1.0\r\n" \
36
- "StartHTML:%09d\r\n" \
37
- "EndHTML:%09d\r\n" \
38
- "StartFragment:%09d\r\n" \
39
- "EndFragment:%09d\r\n" \
40
- "StartSelection:%09d\r\n" \
41
- "EndSelection:%09d\r\n" \
42
- "SourceURL:%s\r\n"
43
-
44
- # Extended marker block
45
- MARKER_BLOCK_EX =
46
- 'Version:(\S+)\s+' \
47
- 'StartHTML:(\d+)\s+' \
48
- 'EndHTML:(\d+)\s+' \
49
- 'StartFragment:(\d+)\s+' \
50
- 'EndFragment:(\d+)\s+' \
51
- 'StartSelection:(\d+)\s+' \
52
- 'EndSelection:(\d+)\s+' \
53
- 'SourceURL:(\S+)'
54
-
55
- # Regular expression for extended marker block
56
- MARKER_BLOCK_EX_RE = Regexp.new(MARKER_BLOCK_EX, Regexp::MULTILINE) # :nodoc:
57
-
58
- # Standard marker block
59
- MARKER_BLOCK =
60
- 'Version:(\S+)\s+' \
61
- 'StartHTML:(\d+)\s+' \
62
- 'EndHTML:(\d+)\s+' \
63
- 'StartFragment:(\d+)\s+' \
64
- 'EndFragment:(\d+)\s+' \
65
- 'SourceURL:(\S+)'
66
-
67
- # Regular expression for the standard marker block
68
- MARKER_BLOCK_RE = Regexp.new(MARKER_BLOCK, Regexp::MULTILINE)
69
-
70
- # Default HTML body
71
- DEFAULT_HTML_BODY =
72
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \
73
- "<HTML><BODY><!--StartFragment-->%s<!--EndFragment--></BODY></HTML>"
74
-
75
- public
76
-
77
- # Clipboard format value
78
- CF_HTML = RegisterClipboardFormat("HTML Format")
79
-
80
- def initialize # :nodoc:
81
- @html = nil
82
- @fragment = nil
83
- @selection = nil
84
- @source = nil
85
- @version = nil
86
- end
87
-
88
- # Returns a boolean indicating whether or not the clipboard contains
89
- # data in HTML format.
90
- #
91
- def self.html_format?
92
- format_available?(CF_HTML)
93
- end
94
-
95
- # This method is nearly identical to the Clipboard.data method, but
96
- # it decodes the data to preserve the HTML formatting.
97
- #
98
- def self.data
99
- begin
100
- self.open
101
- if IsClipboardFormatAvailable(CF_HTML)
102
- handle = GetClipboardData(CF_HTML)
103
- size = GlobalSize(handle)
104
- ptr = FFI::Pointer.new(:char, handle)
105
-
106
- clip_data = decode_data(ptr.read_bytes(size))
107
- else
108
- clip_data = ''
109
- end
110
- ensure
111
- self.close
112
- end
113
- clip_data
114
- end
115
-
116
- # Returns the block marker information for the HTML, or an empty
117
- # string if there is no clipboard data.
118
- #
119
- def self.data_details
120
- clip_data = data
121
- string = ""
122
- unless clip_data.empty?
123
- string << "prefix=>>>#{@prefix}<<<END"
124
- string << "version=>>>#{@version}<<<END"
125
- string << "selection=>>>#{@selection}<<<END"
126
- string << "fragment=>>>#{@fragment}<<<END"
127
- string << "html=>>>#{@html}<<<END"
128
- string << "source=>>>#{@source}<<<END"
129
- end
130
- string
131
- end
132
-
133
- # Put a well-formed fragment of HTML on the clipboard.
134
- #
135
- # The +selection+, if provided, must be a literal string within a
136
- # fragment.
137
- #
138
- # The +html+ value, if provided, must be a well formed HTML document
139
- # that textually contains a fragment and its required markers.
140
- #
141
- # The +source+, if provided, should include a scheme (file, http, or
142
- # https) plus a file name. The default is file:// + __FILE__.
143
- #
144
- def self.set_data(fragment, selection=nil, html=nil, source=nil)
145
- selection ||= fragment
146
- html ||= DEFAULT_HTML_BODY % fragment
147
- source ||= 'file://' + __FILE__
148
-
149
- fragment_start = html.index(fragment)
150
- fragment_end = fragment_start + fragment.length
151
- selection_start = html.index(selection)
152
- selection_end = selection_start + selection.length
153
-
154
- clip_data = encode_data(
155
- html,
156
- fragment_start,
157
- fragment_end,
158
- selection_start,
159
- selection_end,
160
- source
161
- )
162
-
163
- self.open
164
- EmptyClipboard()
165
-
166
- # Global Allocate a movable piece of memory.
167
- hmem = GlobalAlloc(GHND, clip_data.length + 4)
168
- mem = GlobalLock(hmem)
169
- mem.write_bytes(clip_data, 0, clip_data.size)
170
-
171
- clip_data2 = fragment.gsub(/<[^>]+?>/,'')
172
- hmem2 = GlobalAlloc(GHND, clip_data2.length + 4)
173
- mem2 = GlobalLock(hmem2)
174
- mem2.write_bytes(clip_data2, 0, clip_data2.size)
175
-
176
- # Set the new data
177
- begin
178
- if SetClipboardData(CF_HTML, hmem) == 0
179
- raise SystemCallError.new('SetClipboardData', FFI.errno)
180
- end
181
-
182
- if SetClipboardData(CF_TEXT, hmem2) == 0
183
- raise SystemCallError.new('SetClipboardData', FFI.errno)
184
- end
185
- ensure
186
- GlobalFree(hmem)
187
- GlobalFree(hmem2)
188
- self.close
189
- end
190
- self
191
- end
192
-
193
- private
194
-
195
- # Encode the data markers into the HTML data
196
- def self.encode_data(html,frag_start,frag_end,select_start,select_end,src)
197
- dummy_prefix = MARKER_BLOCK_OUTPUT % [0,0,0,0,0,0,src]
198
- len_prefix = dummy_prefix.length
199
- prefix = MARKER_BLOCK_OUTPUT % [len_prefix, html.length + len_prefix,
200
- frag_start + len_prefix, frag_end + len_prefix,
201
- select_start + len_prefix, select_end + len_prefix, src]
202
- prefix + html
203
- end
204
-
205
- # Decode the given string to figure out the details of the HTML
206
- # that's on the string.
207
- #--
208
- # Try the extended format first, which has an explicit selection.
209
- # If that fails, try the version without a selection.
210
- #
211
- def self.decode_data(src)
212
- if (matches = MARKER_BLOCK_EX_RE.match(src))
213
- @prefix = matches[0]
214
- @version = matches[1]
215
- @html = src[matches[2].to_i ... matches[3].to_i]
216
- @fragment = src[matches[4].to_i ... matches[5].to_i]
217
- @selection = src[matches[6].to_i ... matches[7].to_i]
218
- @source = matches[8]
219
- elsif (matches = MARKER_BLOCK_RE.match(src))
220
- @prefix = matches[0]
221
- @version = matches[1]
222
- @html = src[matches[2].to_i ... matches[3].to_i]
223
- @fragment = src[matches[4].to_i ... matches[5].to_i]
224
- @source = matches[6]
225
- @selection = @fragment
226
- else
227
- raise 'failed to match block markers'
228
- end
229
- @fragment
230
- end
231
- end
232
- end
1
+ # The Win32 module serves as a namespace only.
2
+ #
3
+ module Win32
4
+
5
+ # The HtmlClipboard class is a subclass of Clipboard that explicitly
6
+ # handles text in HTML format.
7
+ #
8
+ class HtmlClipboard < Clipboard
9
+
10
+ private
11
+
12
+ # Marker block output
13
+ #--
14
+ # Version: Version of the clipboard.
15
+ #
16
+ # StartHTML: bytecount from the beginning of the clipboard to the
17
+ # start of the context, or -1 if no context.
18
+ #
19
+ # EndHTML: bytecount from the beginning of the clipboard to the end
20
+ # of the context, or -1 if no context.
21
+ #
22
+ # StartFragment: bytecount from the beginning of the clipboard to
23
+ # the start of the fragment.
24
+ #
25
+ # EndFragment: bytecount from the beginning of the clipboard to the
26
+ # end of the fragment.
27
+ #
28
+ # StartSelection: bytecount from the beginning of the clipboard to
29
+ # the start of the selection.
30
+ #
31
+ # EndSelection: bytecount from the beginning of the clipboard to the
32
+ # end of the selection.
33
+ #
34
+ MARKER_BLOCK_OUTPUT =
35
+ "Version:1.0\r\n" \
36
+ "StartHTML:%09d\r\n" \
37
+ "EndHTML:%09d\r\n" \
38
+ "StartFragment:%09d\r\n" \
39
+ "EndFragment:%09d\r\n" \
40
+ "StartSelection:%09d\r\n" \
41
+ "EndSelection:%09d\r\n" \
42
+ "SourceURL:%s\r\n"
43
+
44
+ # Extended marker block
45
+ MARKER_BLOCK_EX =
46
+ 'Version:(\S+)\s+' \
47
+ 'StartHTML:(\d+)\s+' \
48
+ 'EndHTML:(\d+)\s+' \
49
+ 'StartFragment:(\d+)\s+' \
50
+ 'EndFragment:(\d+)\s+' \
51
+ 'StartSelection:(\d+)\s+' \
52
+ 'EndSelection:(\d+)\s+' \
53
+ 'SourceURL:(\S+)'
54
+
55
+ # Regular expression for extended marker block
56
+ MARKER_BLOCK_EX_RE = Regexp.new(MARKER_BLOCK_EX, Regexp::MULTILINE) # :nodoc:
57
+
58
+ # Standard marker block
59
+ MARKER_BLOCK =
60
+ 'Version:(\S+)\s+' \
61
+ 'StartHTML:(\d+)\s+' \
62
+ 'EndHTML:(\d+)\s+' \
63
+ 'StartFragment:(\d+)\s+' \
64
+ 'EndFragment:(\d+)\s+' \
65
+ 'SourceURL:(\S+)'
66
+
67
+ # Regular expression for the standard marker block
68
+ MARKER_BLOCK_RE = Regexp.new(MARKER_BLOCK, Regexp::MULTILINE)
69
+
70
+ # Default HTML body
71
+ DEFAULT_HTML_BODY =
72
+ "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\r\n" \
73
+ "<HTML><BODY><!--StartFragment-->%s<!--EndFragment--></BODY></HTML>"
74
+
75
+ public
76
+
77
+ # Clipboard format value
78
+ CF_HTML = RegisterClipboardFormat("HTML Format")
79
+
80
+ def initialize # :nodoc:
81
+ @html = nil
82
+ @fragment = nil
83
+ @selection = nil
84
+ @source = nil
85
+ @version = nil
86
+ end
87
+
88
+ # Returns a boolean indicating whether or not the clipboard contains
89
+ # data in HTML format.
90
+ #
91
+ def self.html_format?
92
+ format_available?(CF_HTML)
93
+ end
94
+
95
+ # This method is nearly identical to the Clipboard.data method, but
96
+ # it decodes the data to preserve the HTML formatting.
97
+ #
98
+ def self.data
99
+ begin
100
+ self.open
101
+ if IsClipboardFormatAvailable(CF_HTML)
102
+ handle = GetClipboardData(CF_HTML)
103
+ size = GlobalSize(handle)
104
+ ptr = FFI::Pointer.new(:char, handle)
105
+
106
+ clip_data = decode_data(ptr.read_bytes(size))
107
+ else
108
+ clip_data = ''
109
+ end
110
+ ensure
111
+ self.close
112
+ end
113
+ clip_data
114
+ end
115
+
116
+ # Returns the block marker information for the HTML, or an empty
117
+ # string if there is no clipboard data.
118
+ #
119
+ def self.data_details
120
+ clip_data = data
121
+ string = ""
122
+ unless clip_data.empty?
123
+ string << "prefix=>>>#{@prefix}<<<END"
124
+ string << "version=>>>#{@version}<<<END"
125
+ string << "selection=>>>#{@selection}<<<END"
126
+ string << "fragment=>>>#{@fragment}<<<END"
127
+ string << "html=>>>#{@html}<<<END"
128
+ string << "source=>>>#{@source}<<<END"
129
+ end
130
+ string
131
+ end
132
+
133
+ # Put a well-formed fragment of HTML on the clipboard.
134
+ #
135
+ # The +selection+, if provided, must be a literal string within a
136
+ # fragment.
137
+ #
138
+ # The +html+ value, if provided, must be a well formed HTML document
139
+ # that textually contains a fragment and its required markers.
140
+ #
141
+ # The +source+, if provided, should include a scheme (file, http, or
142
+ # https) plus a file name. The default is file:// + __FILE__.
143
+ #
144
+ def self.set_data(fragment, selection=nil, html=nil, source=nil)
145
+ selection ||= fragment
146
+ html ||= DEFAULT_HTML_BODY % fragment
147
+ source ||= 'file://' + __FILE__
148
+
149
+ fragment_start = html.index(fragment)
150
+ fragment_end = fragment_start + fragment.length
151
+ selection_start = html.index(selection)
152
+ selection_end = selection_start + selection.length
153
+
154
+ clip_data = encode_data(
155
+ html,
156
+ fragment_start,
157
+ fragment_end,
158
+ selection_start,
159
+ selection_end,
160
+ source
161
+ )
162
+
163
+ self.open
164
+ EmptyClipboard()
165
+
166
+ # Global Allocate a movable piece of memory.
167
+ hmem = GlobalAlloc(GHND, clip_data.length + 4)
168
+ mem = GlobalLock(hmem)
169
+ mem.write_bytes(clip_data, 0, clip_data.size)
170
+
171
+ clip_data2 = fragment.gsub(/<[^>]+?>/,'')
172
+ hmem2 = GlobalAlloc(GHND, clip_data2.length + 4)
173
+ mem2 = GlobalLock(hmem2)
174
+ mem2.write_bytes(clip_data2, 0, clip_data2.size)
175
+
176
+ # Set the new data
177
+ begin
178
+ if SetClipboardData(CF_HTML, hmem) == 0
179
+ raise SystemCallError.new('SetClipboardData', FFI.errno)
180
+ end
181
+
182
+ if SetClipboardData(CF_TEXT, hmem2) == 0
183
+ raise SystemCallError.new('SetClipboardData', FFI.errno)
184
+ end
185
+ ensure
186
+ GlobalFree(hmem)
187
+ GlobalFree(hmem2)
188
+ self.close
189
+ end
190
+ self
191
+ end
192
+
193
+ private
194
+
195
+ # Encode the data markers into the HTML data
196
+ def self.encode_data(html,frag_start,frag_end,select_start,select_end,src)
197
+ dummy_prefix = MARKER_BLOCK_OUTPUT % [0,0,0,0,0,0,src]
198
+ len_prefix = dummy_prefix.length
199
+ prefix = MARKER_BLOCK_OUTPUT % [len_prefix, html.length + len_prefix,
200
+ frag_start + len_prefix, frag_end + len_prefix,
201
+ select_start + len_prefix, select_end + len_prefix, src]
202
+ prefix + html
203
+ end
204
+
205
+ # Decode the given string to figure out the details of the HTML
206
+ # that's on the string.
207
+ #--
208
+ # Try the extended format first, which has an explicit selection.
209
+ # If that fails, try the version without a selection.
210
+ #
211
+ def self.decode_data(src)
212
+ if (matches = MARKER_BLOCK_EX_RE.match(src))
213
+ @prefix = matches[0]
214
+ @version = matches[1]
215
+ @html = src[matches[2].to_i ... matches[3].to_i]
216
+ @fragment = src[matches[4].to_i ... matches[5].to_i]
217
+ @selection = src[matches[6].to_i ... matches[7].to_i]
218
+ @source = matches[8]
219
+ elsif (matches = MARKER_BLOCK_RE.match(src))
220
+ @prefix = matches[0]
221
+ @version = matches[1]
222
+ @html = src[matches[2].to_i ... matches[3].to_i]
223
+ @fragment = src[matches[4].to_i ... matches[5].to_i]
224
+ @source = matches[6]
225
+ @selection = @fragment
226
+ else
227
+ raise 'failed to match block markers'
228
+ end
229
+ @fragment
230
+ end
231
+ end
232
+ end