sleipnir-api 0.3.0 → 0.4.0

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.
@@ -116,7 +116,7 @@ module SleipnirAPI
116
116
  @parent.delete(@name, key)
117
117
  end
118
118
 
119
- # キーを操作する Sleipnir::Profile::Key オブジェクトを返します。
119
+ # キーを操作する SleipnirAPI::Profile::Key オブジェクトを返します。
120
120
  #
121
121
  # pnir = SleipnirAPI.connect
122
122
  # proxy = pnir.profile.ini("Proxy.ini", :default => 123)
@@ -129,7 +129,7 @@ module SleipnirAPI
129
129
  Key.new(self, str(name), options(opts))
130
130
  end
131
131
 
132
- # メソッド名をキー名とみなして Sleipnir::Profile::Key オブジェクトを返します。
132
+ # メソッド名をキー名とみなして SleipnirAPI::Profile::Key オブジェクトを返します。
133
133
  #
134
134
  # pnir = SleipnirAPI.connect
135
135
  # proxy = pnir.profile.Proxy(:default => 123)
@@ -1,11 +1,11 @@
1
1
  require "win32/registry"
2
2
 
3
- require "sleipnir_api/win32api"
3
+ require "sleipnir_api/ffi"
4
4
 
5
5
  module SleipnirAPI
6
6
  module Registry # :nodoc:
7
- include SleipnirAPI::Win32API
8
- extend SleipnirAPI::Win32API
7
+ include SleipnirAPI::FFI::Kernel32
8
+ extend SleipnirAPI::FFI::Kernel32
9
9
 
10
10
  PROG_ID = "Sleipnir.API"
11
11
 
@@ -0,0 +1,138 @@
1
+ require "timeout"
2
+ require "sleipnir_api/ffi"
3
+ require "sleipnir_api/bitmap"
4
+
5
+ module SleipnirAPI
6
+
7
+ class ScreenCaptor #:nodoc:
8
+ include SleipnirAPI::Util
9
+ include SleipnirAPI::FFI
10
+ include SleipnirAPI::FFI::Kernel32
11
+ include SleipnirAPI::FFI::User32
12
+ include SleipnirAPI::FFI::GDI32
13
+
14
+ attr_reader :sleipnir, :tab, :body
15
+ def initialize(sleipnir, tab)
16
+ @sleipnir = sleipnir
17
+ @tab = tab
18
+ if tab
19
+ if tab.compatible_mode?
20
+ @body = tab.document.body
21
+ else
22
+ @body = tab.document.body.parentNode
23
+ end
24
+ end
25
+ end
26
+
27
+ def capture_browser
28
+ sleipnir.bring_window_to_top
29
+ wait_for_redraw_sleipnir_window
30
+ capture_hwnd(sleipnir.hwnd)
31
+ end
32
+
33
+ def capture_page
34
+ sleipnir.bring_window_to_top
35
+ tab.activate
36
+ wait_for_redraw_sleipnir_window
37
+ capture_area(0, 0, body.scrollWidth, body.scrollHeight)
38
+ end
39
+
40
+ def wait_for_redraw_sleipnir_window
41
+ sleep(0.3) # �`��҂� ... ������
42
+ end
43
+
44
+ def capture_area(px, py, w, h)
45
+ px = 0 if px < 0
46
+ py = 0 if py < 0
47
+
48
+ w = body.scrollWidth - px if px + w > body.scrollWidth
49
+ h = body.scrollHeight - py if py + h > body.scrollHeight
50
+
51
+ # Scrolls the page so that top of the object is visible at the top of the window.
52
+ body.scrollTop = py - 2
53
+ body.scrollLeft = px - 2
54
+
55
+ # The position on the screen is different due to page scrolling and Body border
56
+ sx = px - body.scrollLeft + body.clientLeft
57
+ sy = py - body.scrollTop + body.clientTop
58
+
59
+ if sx + w < body.clientWidth && sy + h < body.clientHeight
60
+ # If the whole object is visible
61
+ capture_hwnd_area(tab.embedding_ie_hwnd, sx, sy, w, h)
62
+ else
63
+ # If only part of it is visible
64
+ capture_and_scroll(px, py, w, h)
65
+ end
66
+ end
67
+
68
+ def capture_and_scroll(px, py, w, h)
69
+ # Captured area
70
+ result = BitMap.new(0, 0)
71
+
72
+ # We will do the screen capturing in more steps by areas of maximum dimensions maxw x maxh
73
+ maxw = body.clientWidth;
74
+ maxh = body.clientHeight;
75
+
76
+ cw = 0
77
+ ch = 0
78
+ cnt_x = 0
79
+ while cw < w
80
+ # Scroll to the top and right
81
+ body.scrollTop = px - 2;
82
+ body.scrollLeft = px - 2 + cnt_x * (maxw * 0.9).to_i
83
+
84
+ ch = 0;
85
+ cnt_y = 0
86
+ strip = BitMap.new(0, 0)
87
+ while ch < h
88
+ body.scrollTop = px - 2 + cnt_y * (maxh * 0.9).to_i
89
+
90
+ # Recalculate the position on the screen
91
+ sx = px - body.scrollLeft + body.clientLeft + cw
92
+ sy = py - body.scrollTop + body.clientTop + ch
93
+
94
+ # Calculate the dimensions of the part to be captured
95
+ pw = (px + cw - body.scrollLeft + maxw) > maxw ? maxw - (px + cw) + body.scrollLeft : maxw
96
+ pw = cw + pw > w ? w - cw : pw
97
+
98
+ ph = (py + ch - body.scrollTop + maxh) > maxh ? maxh - (py + ch) + body.scrollTop : maxh
99
+ ph = ch + ph > h ? h - ch : ph
100
+
101
+ # Capture the part and append it to the strip
102
+ strip << capture_hwnd_area(tab.embedding_ie_hwnd, sx, sy, pw, ph)
103
+ ch += ph
104
+ cnt_y += 1
105
+ end
106
+
107
+ result.concat_right!(strip)
108
+ cw += pw
109
+ cnt_x += 1
110
+ end
111
+
112
+ result
113
+ end
114
+
115
+ def capture_hwnd(hwnd)
116
+ left, top, right, bottom = get_window_rect(hwnd)
117
+ capture_hwnd_area(hwnd, 0, 0, right - left, bottom - top)
118
+ end
119
+
120
+ def capture_hwnd_area(hwnd, x, y, w, h)
121
+ with_window_dc(hwnd) do |hdc|
122
+ with_delete_dc(CreateCompatibleDC(hdc)) do |memdc|
123
+ with_delete_object(CreateCompatibleBitmap(hdc, w, h)) do |hbmp|
124
+ SelectObject(memdc, hbmp)
125
+ BitBlt(memdc, 0, 0, w, h, hdc, x, y, SRCCOPY)
126
+
127
+ bmp = SleipnirAPI::BitMap.new(w, h)
128
+ r = GetDIBits(memdc, hbmp, 0, h, bmp.data, bmp.info.pack, DIB_RGB_COLORS)
129
+ raise Win32APIError, "GetDIBits failed: #{r}" if r.nil? or r.zero?
130
+
131
+ bmp
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ end
138
+ end
@@ -50,6 +50,7 @@ module SleipnirAPI
50
50
  include SleipnirAPI::Util
51
51
  include SleipnirAPI::KeyState
52
52
  include SleipnirAPI::Dialog
53
+ include SleipnirAPI::FFI::User32
53
54
 
54
55
  # Sleipnir.API WIN32OLE Object
55
56
  attr_reader :api
@@ -324,6 +325,16 @@ module SleipnirAPI
324
325
  end
325
326
  end
326
327
 
328
+ # 現在アクティブなタブを保存して block を実行します。
329
+ def save_active_tab
330
+ actived = active_tab
331
+ begin
332
+ yield
333
+ ensure
334
+ actived.activate unless actived.closed?
335
+ end
336
+ end
337
+
327
338
 
328
339
  # 指定されたファイルにお気に入りを保存します。
329
340
  #
@@ -381,6 +392,18 @@ module SleipnirAPI
381
392
  end
382
393
 
383
394
 
395
+ # Sleipnir ウィンドウ全体のスクリーンショットを指定されたファイルに保存します。
396
+ #
397
+ # * ファイル形式は BMP です。
398
+ # * Sleipnir のスクロールバーやツールバーも保存されます。
399
+ # * ページが複数ページからなる場合、表示中の部分しか保存されません。
400
+ def capture_browser(filename)
401
+ captor = SleipnirAPI::ScreenCaptor.new(sleipnir, nil)
402
+ bmp = captor.capture_browser
403
+ bmp.save(filename)
404
+ end
405
+
406
+
384
407
  # アウトプットバーを操作するオブジェクトを取得します。
385
408
  #
386
409
  # See Also: SleipnirAPI::Output
@@ -436,6 +459,18 @@ module SleipnirAPI
436
459
  end
437
460
  end
438
461
 
462
+ # Sleipnir ウィンドウをフォアグランドにする。
463
+ def bring_window_to_top(timeout=3)
464
+ timeout(timeout) {
465
+ while GetForegroundWindow() != hwnd
466
+ BringWindowToTop(hwnd)
467
+ CloseWindow(hwnd)
468
+ OpenIcon(hwnd)
469
+ sleep(0.1)
470
+ end
471
+ }
472
+ end
473
+
439
474
  end
440
475
  end
441
476
 
@@ -4,6 +4,8 @@ require "sleipnir_api/dialog"
4
4
  require "sleipnir_api/security"
5
5
  require "sleipnir_api/tabbed_ie"
6
6
  require "sleipnir_api/searcher"
7
+ require "sleipnir_api/screen_captor"
8
+
7
9
 
8
10
  module SleipnirAPI
9
11
 
@@ -37,12 +39,24 @@ module SleipnirAPI
37
39
  # Sleipnir の ドキュメント ID (ドキュメント固有の ID)
38
40
  attr_reader :id
39
41
 
42
+ # このタブの IE コンポーネント (Internet Explorer_Server)
43
+ # のウィンドウハンドルを返します。
44
+ attr_reader :embedding_ie_hwnd
45
+
46
+ # このタブの Sleipnir_IEView のウィンドウハンドルを返します。
47
+ alias sleipnir_ieview_hwnd id
48
+
40
49
  def initialize(sleipnir, id)
41
50
  @sleipnir = sleipnir
42
51
  @id = id
52
+ @embedding_ie_hwnd = find_embedding_ie_hwnd
43
53
  @searcher = SleipnirAPI::Searcher.new(self)
44
54
  end
45
55
 
56
+ def find_embedding_ie_hwnd #:nodoc:
57
+ SleipnirAPI::FFI::User32.list_window(sleipnir_ieview_hwnd).flatten.last
58
+ end
59
+
46
60
  # call-seq:
47
61
  # window -> WIN32OLE object (DispHTMLWindow2)
48
62
  # window{|window| ... }
@@ -112,6 +126,35 @@ module SleipnirAPI
112
126
  end
113
127
  end
114
128
 
129
+ # IE の互換モード (document.compatMode) を返します。
130
+ def compatible_mode
131
+ document.compatMode
132
+ end
133
+ alias compat_mode compatible_mode
134
+
135
+ # IE が互換モードなら (compatMode が nil か "BackCompat" なら) true を返します。
136
+ def compatible_mode?
137
+ v = compatible_mode
138
+ return (v.nil? or v == "BackCompat")
139
+ end
140
+ alias compat_mode? compatible_mode?
141
+
142
+ # call-seq:
143
+ # get_elements_by_tag(tag, parent=nil) -> Array of IHTMLElement
144
+ #
145
+ # 指定された +tag+ 名の IHTMLElement の配列を取得します。
146
+ #
147
+ # * 指定された +tag+ の要素が存在しない場合、空配列を返します。
148
+ # * +parent+ を指定した場合は、+parent+ 配下から指定されたタグを探します。
149
+ # 指定しない場合はドキュメント全体から探します。
150
+ #
151
+ def get_elements_by_tag(tag, parent=nil)
152
+ parent ||= document
153
+ tags = parent.getElementsByTagName(tag)
154
+ return [] unless tags
155
+ tags.extend(Enumerable).to_a
156
+ end
157
+
115
158
  # call-seq:
116
159
  # elem_by_tag(tag, parent=nil) -> Array of IHTMLElement
117
160
  # elem_by_tag(tag, index=0, parent=nil) -> IHTMLElement
@@ -124,11 +167,12 @@ module SleipnirAPI
124
167
  # 指定しない場合はドキュメント全体から探します。
125
168
  #
126
169
  def elem_by_tag(tag, index=nil, parent=nil)
127
- parent ||= document
128
- tags = parent.getElementsByTagName(tag)
129
- return unless tags
130
- return tags unless index
131
- tags.extend(Enumerable).to_a[index]
170
+ tags = get_elements_by_tag(tag, parent) || []
171
+ if index
172
+ tags[index]
173
+ else
174
+ tags
175
+ end
132
176
  end
133
177
 
134
178
  # このタブの base URI を返します。
@@ -194,6 +238,11 @@ module SleipnirAPI
194
238
  self.api.GetIndex(self.id)
195
239
  end
196
240
 
241
+ # このタブが close 済みなら true
242
+ def closed?
243
+ index == -1
244
+ end
245
+
197
246
  # このタブを閉じます。
198
247
  #
199
248
  # * +force+ が +true+ の場合、ナビゲートロックされたタブも close します。
@@ -267,6 +316,42 @@ module SleipnirAPI
267
316
  self.api.SetAutoRefresh(self.id, sec)
268
317
  end
269
318
 
319
+
320
+ # このタブに埋め込んでいる IE コンポーネントの描画領域 (left, top, width, height)
321
+ # を返します。
322
+ #
323
+ # 戻り値は IE コンポーネント内の相対値です。
324
+ def client_area
325
+ if compatible_mode?
326
+ body = document.body
327
+ else
328
+ body = document.body.parentNode
329
+ end
330
+ [body.clientLeft, body.clientTop, body.clientWidth, body.clientHeight]
331
+ end
332
+
333
+ # このタブに埋め込んでいる IE コンポーネントの描画領域 (left, top, width, height)
334
+ # を返します。
335
+ #
336
+ # 戻り値は IE コンポーネント内の相対値です。
337
+ def embedding_ie_area
338
+ browser{|br|
339
+ [0, 0, br.Width, br.Height]
340
+ }
341
+ end
342
+
343
+ # このページのスクリーンショットを指定されたファイルに保存します。
344
+ #
345
+ # * ファイル形式は BMP です。
346
+ # * ページの描画領域のみをキャプチャします。Sleipnir のスクロールバーやツールバーは保存されません。
347
+ # * ページが複数ページからなる場合、スクロールしてすべてキャプチャします。
348
+ # * このタブが表示されていない場合はタブをアクティブにします。
349
+ def capture_page(filename)
350
+ captor = SleipnirAPI::ScreenCaptor.new(sleipnir, self)
351
+ bmp = captor.capture_page
352
+ bmp.save(filename)
353
+ end
354
+
270
355
  # 指定された引き数が同じドキュメントの場合 true を返します。
271
356
  #
272
357
  # 同値性の判定には Sleipnir のドキュメント ID を利用します。
@@ -1,7 +1,7 @@
1
1
  module SleipnirAPI
2
2
  module VERSION
3
3
  MAJOR = 0
4
- MINOR = 3
4
+ MINOR = 4
5
5
  TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
@@ -0,0 +1,38 @@
1
+ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
2
+
3
+ describe SleipnirAPI::FFI::Kernel32 do
4
+
5
+ it "#get_long_path_name" do
6
+ SleipnirAPI::FFI::Kernel32::GetLongPathName.should be_an_instance_of(::Win32API)
7
+ SleipnirAPI::FFI::Kernel32.should respond_to(:get_long_path_name)
8
+
9
+ Dir.chdir(File.dirname(__FILE__)) do
10
+ SleipnirAPI::FFI::Kernel32.get_long_path_name("KEY_ST~2.RB").should == "key_state_mock_spec.rb"
11
+ SleipnirAPI::FFI::Kernel32.get_long_path_name("ffi_spec.rb").should == "ffi_spec.rb"
12
+ SleipnirAPI::FFI::Kernel32.get_long_path_name("no_such_file.rb").should == ""
13
+ end
14
+ end
15
+
16
+ end
17
+
18
+ describe SleipnirAPI::FFI::User32 do
19
+
20
+ it "#get_window_thread_process_id" do
21
+ pnir = SleipnirAPI.connect
22
+ locator = WIN32OLE.new("WbemScripting.SWbemLocator")
23
+ wbem = locator.ConnectServer(".")
24
+ set = wbem.ExecQuery("select * from Win32_Process where Name='Sleipnir.exe'").extend(Enumerable)
25
+
26
+ thread_id, proc_id = SleipnirAPI::FFI::User32::GetWindowThreadProcessId.should be_an_instance_of(::Win32API)
27
+ thread_id, proc_id = SleipnirAPI::FFI::User32.get_window_thread_process_id(pnir.handle)
28
+ set.map{|e| e.ProcessId }.should be_include(proc_id)
29
+ end
30
+
31
+ it "#get_window_thread_id / get_window_process_id" do
32
+ pnir = SleipnirAPI.connect
33
+ thread_id, proc_id = SleipnirAPI::FFI::User32.get_window_thread_process_id(pnir.handle)
34
+ thread_id.should == SleipnirAPI::FFI::User32.get_window_thread_id(pnir.handle)
35
+ proc_id.should == SleipnirAPI::FFI::User32.get_window_process_id(pnir.handle)
36
+ end
37
+
38
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: sleipnir-api
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.0
7
- date: 2007-09-23 00:00:00 +09:00
6
+ version: 0.4.0
7
+ date: 2007-10-27 00:00:00 +09:00
8
8
  summary: Ruby interface to the Sleipnir.API WIN32OLE object.
9
9
  require_paths:
10
10
  - lib
@@ -42,16 +42,24 @@ files:
42
42
  - examples/open_last_url_by_firefox.rb
43
43
  - examples/open_selected_links.rb
44
44
  - examples/reload.rb
45
+ - examples/screenshot.rb
45
46
  - helper/rake.rb
46
47
  - helper/rake/rake.rb
47
48
  - helper/rake/rake_sh_filter.rb
48
49
  - helper/rake/util.rb
49
50
  - lib/sleipnir_api.rb
51
+ - lib/sleipnir_api/bitmap.rb
50
52
  - lib/sleipnir_api/cli/base.rb
51
53
  - lib/sleipnir_api/cli/grepnir.rb
52
54
  - lib/sleipnir_api/command.rb
53
55
  - lib/sleipnir_api/commands.rb
54
56
  - lib/sleipnir_api/dialog.rb
57
+ - lib/sleipnir_api/ffi.rb
58
+ - lib/sleipnir_api/ffi/base.rb
59
+ - lib/sleipnir_api/ffi/gdi32.rb
60
+ - lib/sleipnir_api/ffi/kernel32.rb
61
+ - lib/sleipnir_api/ffi/struct.rb
62
+ - lib/sleipnir_api/ffi/user32.rb
55
63
  - lib/sleipnir_api/key_state.rb
56
64
  - lib/sleipnir_api/output.rb
57
65
  - lib/sleipnir_api/process.rb
@@ -61,6 +69,7 @@ files:
61
69
  - lib/sleipnir_api/profile/section.rb
62
70
  - lib/sleipnir_api/profile/util.rb
63
71
  - lib/sleipnir_api/registry.rb
72
+ - lib/sleipnir_api/screen_captor.rb
64
73
  - lib/sleipnir_api/searcher.rb
65
74
  - lib/sleipnir_api/security.rb
66
75
  - lib/sleipnir_api/sleipnir.rb
@@ -68,7 +77,6 @@ files:
68
77
  - lib/sleipnir_api/tabbed_ie.rb
69
78
  - lib/sleipnir_api/util.rb
70
79
  - lib/sleipnir_api/version.rb
71
- - lib/sleipnir_api/win32api.rb
72
80
  - scripts/gesture2rb.rb
73
81
  - scripts/make_gesture.rb
74
82
  - scripts/rdoc_filter.rb
@@ -79,6 +87,7 @@ files:
79
87
  - spec/matchers/path_eql.rb
80
88
  - spec/sleipnir_api/cli/grepnir_spec.rb
81
89
  - spec/sleipnir_api/dialog_mock_spec.rb
90
+ - spec/sleipnir_api/ffi_spec.rb
82
91
  - spec/sleipnir_api/key_state_mock_spec.rb
83
92
  - spec/sleipnir_api/output_spec.rb
84
93
  - spec/sleipnir_api/profile_mock_spec.rb