sleipnir-api 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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