sensible-cinema 0.28.1 → 0.34.0
Sign up to get free protection for your applications and to get access to all the features.
- data/{README → README.TXT} +35 -14
- data/Rakefile +49 -41
- data/TODO +337 -250
- data/VERSION +1 -1
- data/bin/sensible-cinema +15 -14
- data/bin/sensible-cinema-cli +1 -1
- data/business_ideas.txt +8 -0
- data/change_log_with_feature_list.txt +198 -1
- data/documentation/is_it_legal_to_copy_dvds.txt +44 -30
- data/goc.bat +1 -1
- data/gpl-2.0.txt +339 -0
- data/history_and_related_works_list.txt +37 -33
- data/{cone.png → inventionzy_files/cone.png} +0 -0
- data/legal_draft +23 -0
- data/lib/add_any_bundled_gems_to_load_path.rb +4 -3
- data/lib/check_installed_mac.rb +10 -10
- data/lib/count_down_timer_jruby_swing.rb +4 -4
- data/lib/edl_parser.rb +155 -142
- data/lib/extract/dumpstream.bat +1 -0
- data/lib/extract/get_init.bat +3 -0
- data/lib/extract/pause_early.rb +13 -0
- data/lib/gui/base.rb +707 -0
- data/lib/gui/create-file.rb +244 -0
- data/lib/gui/create.rb +565 -0
- data/lib/gui/dependencies.rb +177 -0
- data/lib/gui/normal.rb +190 -0
- data/lib/gui/{sensible-cinema-upconvert.rb → upconvert.rb} +33 -14
- data/lib/keyboard_input.rb +0 -2
- data/lib/mencoder_wrapper.rb +8 -3
- data/lib/movie_hasher.rb +27 -0
- data/lib/mplayer_edl.rb +1 -0
- data/lib/subtitle_profanity_finder.rb +141 -103
- data/lib/vlc_programmer.rb +1 -1
- data/lib/zoom_player_max_edl.rb +50 -0
- data/{developer_how_to_contribute_to_the_project.txt → notes_for_potential_developers.txt} +18 -11
- data/roadmap_possibilities +12 -0
- data/spec/arse.srt +6 -1
- data/spec/dragon.srt +3 -0
- data/spec/edl_parser.spec.rb +57 -52
- data/spec/mencoder_wrapper.spec.rb +26 -19
- data/spec/mplayer_edl.spec.rb +40 -10
- data/spec/notes +3043 -9
- data/spec/sensible_cinema_gui.spec.rb +8 -3
- data/spec/subtitle_profanity_finder.spec.rb +91 -36
- data/spec/zoom_player_max_edl.spec.rb +29 -0
- data/template_bats/README_DISTRO.TXT +3 -1
- data/template_bats/RUN SENSIBLE CINEMA CLICK HERE WINDOWS.bat +25 -0
- data/template_bats/mac/RUN SENSIBLE CINEMA CLICK HERE.command +2 -1
- data/template_bats/mac/advanced--create or edit sensible cinema edit list files.command +2 -1
- data/template_bats/mac/advanced--run-upconverting-video-player.command +2 -1
- data/template_bats/pc/advanced--create or edit sensible cinema edit list files.bat +2 -0
- data/template_bats/pc/advanced--run-upconverting-video-player.bat +2 -0
- data/todo.inventionzy.txt +69 -2
- data/todo.propaganda +34 -10
- data/todo.upconvert +8 -1
- data/{upconvert_netflix/latest2 → upconvert_from_screen}/go_upscaling.bat +0 -0
- data/{also_see_rogerdpack_youtube_account_and_sourceforge_files_movies_account → upconvert_from_screen/go_upscaling_works} +0 -0
- data/{upconvert_netflix → upconvert_from_screen/old}/latest2/combine_video.avs +0 -0
- data/{upconvert_netflix → upconvert_from_screen/old}/latest2/go_no_upscaling.bat +0 -0
- data/upconvert_from_screen/old/latest2/go_upscaling.bat +12 -0
- data/{upconvert_netflix → upconvert_from_screen/old}/latest2/push2.GRF +0 -0
- data/upconvert_from_screen/old/latest2/push3.grf +0 -0
- data/{upconvert_netflix → upconvert_from_screen/old}/latest2/setup_capture_coords.rb +0 -0
- data/{upconvert_netflix → upconvert_from_screen/old}/latest2/setup_directshow_filter_params.rb +0 -0
- data/{upconvert_netflix → upconvert_from_screen/old}/latest2/upconvert_from_screen_me2.avs +1 -1
- data/{upconvert_netflix → upconvert_from_screen}/old/latest_now_possibly_oudated/push2.GRF +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/latest_now_possibly_oudated/upconvert_from_screen_me2.avs +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/position_window.png +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/push_source_desktop.GRF +0 -0
- data/{upconvert_netflix → upconvert_from_screen/old}/record_screen/record.bat +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/upconvert_from_screen.avs +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/upconvert_from_screen_me.avs +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/upconvert_from_screen_me2.avs +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/upconvert_from_screen_me_push_source.avs +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/uscreen.GRF +0 -0
- data/{upconvert_netflix → upconvert_from_screen}/old/uscreen_me.GRF +0 -0
- data/upconvert_from_screen/push3.grf +0 -0
- data/upconvert_from_screen/upconvert_from_screen_me2.avs +19 -0
- data/vendor/mplayer_patches/apply.bat +12 -0
- data/vendor/{rdp-win32screenshot-0.0.9/RDP_BRANCH_HAS_MASTER_WITH_CORRECT_VERSION_NUMBER → mplayer_patches/configure_from_betterlogic} +0 -0
- data/vendor/mplayer_patches/libdvdnav/2905259c3b45529b3d8dedba572b6e4f67a2d8f4.diff +19 -0
- data/vendor/mplayer_patches/libdvdnav/83f1c9256f500285e46f1e44bcc74ffce90159db.diff +16 -0
- data/vendor/mplayer_patches/libdvdnav/eb91fb74680d30322461a1b9e425918ad4e2b2df.diff +21 -0
- data/vendor/mplayer_patches/libdvdnav/jump_to_time.diff +654 -0
- data/vendor/mplayer_patches/libdvdnav/non_strict.diff +13 -0
- data/vendor/mplayer_patches/mplayer_edl.diff +354 -0
- data/vendor/mplayer_patches/port_dir/PortIndex.quick +2 -0
- data/vendor/mplayer_patches/port_dir/how_to +13 -0
- data/vendor/mplayer_patches/port_dir/multimedia/mplayer-edl/Portfile +300 -0
- data/vendor/mplayer_patches/port_dir/multimedia/mplayer-edl/files/configure.x11.patch +20 -0
- data/vendor/mplayer_patches/port_dir/multimedia/mplayer-edl/files/llvm-gcc-workaround.patch +11 -0
- data/vendor/mplayer_patches/port_dir/multimedia/rdp-projects/Portfile +43 -0
- data/vendor/{rdp-win32screenshot-0.0.9/RDP_VERSION_IS_IN_RDP_BRANCH → mplayer_patches/updated_lib_too} +0 -0
- data/vendor/{readme.txt → readme.txt.setpriority} +0 -0
- data/www/content_editor.html +28 -28
- data/www/index.html +6 -1
- data/www/upconverting_movie_player.html +13 -3
- data/www/youtube_edl/.htaccess +44 -0
- data/{inventionzy_files/control_youtube.html → www/youtube_edl/control_youtube.rhtml} +39 -33
- data/www/youtube_edl/dispatch.fcgi +25 -0
- data/www/youtube_edl/render_edited.rb +25 -0
- data/{inventionzy_files/serve.rb → www/youtube_edl/server_this_dir.rb} +0 -0
- data/www/youtube_edl/todo +23 -0
- data/www/zoomplayer_max.png +0 -0
- data/zamples/edit_decision_lists/dvds/Harry Potter 2 chamber of secrets.txt +10 -5
- data/zamples/edit_decision_lists/dvds/aladdin.txt +30 -0
- data/zamples/edit_decision_lists/dvds/bambi.txt +1 -1
- data/zamples/edit_decision_lists/dvds/big_buck_bunny_dvd.txt +2 -0
- data/zamples/edit_decision_lists/dvds/bobs_big_plan.txt +2 -2
- data/zamples/edit_decision_lists/dvds/cars_2.txt +26 -0
- data/zamples/edit_decision_lists/dvds/cars_disney.txt +1 -1
- data/zamples/edit_decision_lists/dvds/condor_man_widescreen.txt +22 -0
- data/zamples/edit_decision_lists/dvds/court_jester.txt +10 -13
- data/zamples/edit_decision_lists/dvds/edls_being_edited/making_marriage_work.txt +15 -0
- data/zamples/edit_decision_lists/dvds/edls_being_edited/national_treasure.txt +23 -0
- data/zamples/edit_decision_lists/dvds/edls_being_edited/ratatouille.txt +35 -0
- data/zamples/edit_decision_lists/dvds/edls_being_edited/the_explorers.txt +49 -0
- data/zamples/edit_decision_lists/dvds/finding_neverland.txt +32 -0
- data/zamples/edit_decision_lists/dvds/flight_of_the_navigator.txt +22 -16
- data/zamples/edit_decision_lists/dvds/harry_potter_3_prisoner_of_azkaban.txt +21 -4
- data/zamples/edit_decision_lists/dvds/hitchhiker's_guide_to_the_galaxy.txt +1 -1
- data/zamples/edit_decision_lists/dvds/{edls_being_edited/king_of_kings.txt → king_of_kings.txt} +5 -5
- data/zamples/edit_decision_lists/dvds/nanny_mcphee.txt +31 -0
- data/zamples/edit_decision_lists/dvds/pack_jackson_wedding_2007-03-03.txt +9 -2
- data/zamples/edit_decision_lists/dvds/remember_the_titans.txt +35 -0
- data/zamples/edit_decision_lists/dvds/sintel_open_source_blender_ntsc_dvd.txt +8 -4
- data/zamples/edit_decision_lists/dvds/speed_racer.txt +1 -1
- data/zamples/edit_decision_lists/dvds/tangled.txt +21 -0
- data/zamples/edit_decision_lists/dvds/tron_legacy.txt +4 -1
- data/zamples/edit_decision_lists/files/conference_music_video.txt +10 -0
- data/zamples/edit_decision_lists/notes_on_movies_without_edls_yet/tron.txt +10 -0
- data/zamples/edit_decision_lists/old_not_yet_updated/example_edit_decision_list.txt +1 -1
- metadata +139 -117
- data/conclusions +0 -6
- data/documentation/how_to_create_your_own_delete_lists.txt +0 -69
- data/lib/gui/sensible-cinema-base.rb +0 -620
- data/lib/gui/sensible-cinema-create.rb +0 -331
- data/lib/gui/sensible-cinema-dependencies.rb +0 -28
- data/lib/gui/sensible-cinema-normal.rb +0 -351
- data/lib/gui/sensible-cinema-side-by-side.rb +0 -27
- data/lib/shutdown_kill.rb +0 -32
- data/lib/storage.rb +0 -105
- data/ocr.todo_if_need_speed +0 -6
- data/upconvert_netflix/record_screen/recording/1.png +0 -0
- data/upconvert_netflix/record_screen/recording/10.png +0 -0
- data/upconvert_netflix/record_screen/recording/2.png +0 -0
- data/upconvert_netflix/record_screen/recording/3.png +0 -0
- data/upconvert_netflix/record_screen/recording/4.png +0 -0
- data/upconvert_netflix/record_screen/recording/5.png +0 -0
- data/upconvert_netflix/record_screen/recording/6.png +0 -0
- data/upconvert_netflix/record_screen/recording/7.png +0 -0
- data/upconvert_netflix/record_screen/recording/8.png +0 -0
- data/upconvert_netflix/record_screen/recording/9.png +0 -0
- data/upconvert_netflix/record_screen/recording/d.png +0 -0
- data/vendor/monkey.png +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/.document +0 -5
- data/vendor/rdp-win32screenshot-0.0.9/History.rdoc +0 -53
- data/vendor/rdp-win32screenshot-0.0.9/LICENSE +0 -20
- data/vendor/rdp-win32screenshot-0.0.9/README.rdoc +0 -95
- data/vendor/rdp-win32screenshot-0.0.9/Rakefile +0 -63
- data/vendor/rdp-win32screenshot-0.0.9/VERSION +0 -1
- data/vendor/rdp-win32screenshot-0.0.9/enumerated +0 -55576
- data/vendor/rdp-win32screenshot-0.0.9/lib/aero_offscreen_srccopy_captureblt_doesnt_have_everything.bmp.gz +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/enumerate.rb +0 -6
- data/vendor/rdp-win32screenshot-0.0.9/lib/firefox.bmp +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/normal.bmp +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/normal2.bmp +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/notes +0 -5
- data/vendor/rdp-win32screenshot-0.0.9/lib/snapshot.rb +0 -10
- data/vendor/rdp-win32screenshot-0.0.9/lib/srccopy.bmp +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/srccopyplus.bmp +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/srccopyplusdirectx.bmp +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/vc.bmp +0 -0
- data/vendor/rdp-win32screenshot-0.0.9/lib/win32/screenshot.rb +0 -95
- data/vendor/rdp-win32screenshot-0.0.9/lib/win32/screenshot/bitmap_maker.rb +0 -200
- data/vendor/rdp-win32screenshot-0.0.9/lib/win32/util.rb +0 -93
- data/vendor/rdp-win32screenshot-0.0.9/spec/spec.opts +0 -1
- data/vendor/rdp-win32screenshot-0.0.9/spec/spec_helper.rb +0 -85
- data/vendor/rdp-win32screenshot-0.0.9/spec/win32_screenshot_spec.rb +0 -194
- data/vendor/rdp-win32screenshot-0.0.9/spec/win32_screenshot_util_spec.rb +0 -75
- data/vendor/rdp-win32screenshot-0.0.9/win32screenshot.gemspec +0 -69
- data/vendor/tsmuxer_1.10.6/licence.txt +0 -42
- data/zamples/edit_decision_lists/dvds/making_marriage_work.txt +0 -15
- data/zamples/edit_decision_lists/notes/tron.txt +0 -4
- data/zamples/edit_decision_lists/old_not_yet_updated/dvds/making marriage work.txt +0 -9
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -1,5 +0,0 @@
|
|
1
|
-
without aero
|
2
|
-
Win32::Screenshot.window( /virtual/i, 0) {|h,w,bits| File.binwrite('1' +name, bits)}
|
3
|
-
was "cropped" and probably had to come to the front, but was full.
|
4
|
-
|
5
|
-
with aero, it didn't show everything [!] so I guess it's really just grabbing that window via hwnd.
|
@@ -1,10 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require './win32/screenshot'
|
3
|
-
require 'sane'
|
4
|
-
#sleep 2
|
5
|
-
p 'taking it'
|
6
|
-
#p Win32::Screenshot::BitmapMaker.hwnd(/virtual/i).to_s(16)
|
7
|
-
name = ARGV[0] || 'out.bmp'
|
8
|
-
Win32::Screenshot::BitmapMaker.capture_area( Win32::Screenshot::BitmapMaker.hwnd(/virtual/i), 0,0,1000,1000) {|h,w,bits| File.binwrite(name, bits)}
|
9
|
-
Win32::Screenshot.window( /virtual/i, 0) {|h,w,bits| File.binwrite('1' +name, bits)}
|
10
|
-
p name
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -1,95 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/screenshot/bitmap_maker'
|
2
|
-
require File.dirname(__FILE__) + '/util'
|
3
|
-
|
4
|
-
module Win32
|
5
|
-
# Captures screenshots with Ruby on Windows
|
6
|
-
class Screenshot
|
7
|
-
class << self
|
8
|
-
|
9
|
-
# captures foreground
|
10
|
-
def foreground(&proc)
|
11
|
-
hwnd = BitmapMaker.foreground_window
|
12
|
-
BitmapMaker.capture_all(hwnd, &proc)
|
13
|
-
end
|
14
|
-
|
15
|
-
# captures area of the foreground
|
16
|
-
# where *x1* and *y1* are 0 in the upper left corner and
|
17
|
-
# *x2* specifies the width and *y2* the height of the area to be captured
|
18
|
-
def foreground_area(x1, y1, x2, y2, &proc)
|
19
|
-
hwnd = BitmapMaker.foreground_window
|
20
|
-
validate_coordinates(hwnd, x1, y1, x2, y2)
|
21
|
-
BitmapMaker.capture_area(hwnd, x1, y1, x2, y2, &proc)
|
22
|
-
end
|
23
|
-
|
24
|
-
# captures visible view of the screen
|
25
|
-
#
|
26
|
-
# to make screenshot of the real desktop, all
|
27
|
-
# windows must be minimized before
|
28
|
-
def desktop(&proc)
|
29
|
-
hwnd = BitmapMaker.desktop_window
|
30
|
-
BitmapMaker.capture_all(hwnd, &proc)
|
31
|
-
end
|
32
|
-
|
33
|
-
# captures area of the visible view of the screen
|
34
|
-
# where *x1* and *y1* are 0 in the upper left corner and
|
35
|
-
# *x2* specifies the width and *y2* the height of the area to be captured
|
36
|
-
#
|
37
|
-
# to make screenshot of the real desktop, all
|
38
|
-
# windows must be minimized before
|
39
|
-
def desktop_area(x1, y1, x2, y2, &proc)
|
40
|
-
hwnd = BitmapMaker.desktop_window
|
41
|
-
validate_coordinates(hwnd, x1, y1, x2, y2)
|
42
|
-
BitmapMaker.capture_area(hwnd, x1, y1, x2, y2, &proc)
|
43
|
-
end
|
44
|
-
|
45
|
-
# captures window with a *title_query* and waits *pause* (by default is 0.5)
|
46
|
-
# seconds after trying to set window to the foreground
|
47
|
-
def window(title_query, pause=0.5, &proc)
|
48
|
-
hwnd = Util.window_hwnd(title_query)
|
49
|
-
hwnd(hwnd, pause, &proc)
|
50
|
-
end
|
51
|
-
|
52
|
-
# captures area of the window with a *title_query*
|
53
|
-
# where *x1* and *y1* are 0 in the upper left corner and
|
54
|
-
# *x2* specifies the width and *y2* the height of the area to be captured
|
55
|
-
def window_area(title_query, x1, y1, x2, y2, pause=0.5, &proc)
|
56
|
-
hwnd = Util.window_hwnd(title_query)
|
57
|
-
hwnd_area(hwnd, x1, y1, x2, y2, pause, &proc)
|
58
|
-
end
|
59
|
-
|
60
|
-
# captures by window handle
|
61
|
-
def hwnd(hwnd, pause=0.5, &proc)
|
62
|
-
BitmapMaker.prepare_window(hwnd, pause)
|
63
|
-
BitmapMaker.capture_all(hwnd, &proc)
|
64
|
-
end
|
65
|
-
|
66
|
-
# captures area of the window with a handle of *hwnd*
|
67
|
-
# where *x1* and *y1* are 0 in the upper left corner and
|
68
|
-
# *x2* specifies the width and *y2* the height of the area to be captured
|
69
|
-
def hwnd_area(hwnd, x1, y1, x2, y2, pause=0.5, &proc)
|
70
|
-
validate_coordinates(hwnd, x1, y1, x2, y2)
|
71
|
-
BitmapMaker.prepare_window(hwnd, pause)
|
72
|
-
BitmapMaker.capture_area(hwnd, x1, y1, x2, y2, &proc)
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
|
77
|
-
def validate_coordinates(hwnd, *coords)
|
78
|
-
specified_coordinates = coords.join(', ')
|
79
|
-
if coords.any? {|c| c < 0}
|
80
|
-
raise "specified coordinates (#{specified_coordinates}) are invalid - cannot be negative!"
|
81
|
-
end
|
82
|
-
x1, y1, x2, y2 = *coords
|
83
|
-
if x1 >= x2 || y1 >= y2
|
84
|
-
raise "specified coordinates (#{specified_coordinates}) are invalid - cannot have x1 > x2 or y1 > y2!"
|
85
|
-
end
|
86
|
-
|
87
|
-
max_width, max_height = Util.dimensions_for(hwnd)
|
88
|
-
if x2 > max_width || y2 > max_height
|
89
|
-
raise "specified coordinates (#{specified_coordinates}) are invalid - maximum are x2=#{max_width} and y2=#{max_height}!"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
end
|
95
|
-
end
|
@@ -1,200 +0,0 @@
|
|
1
|
-
require 'ffi'
|
2
|
-
|
3
|
-
module Win32
|
4
|
-
class Screenshot
|
5
|
-
# internal methods
|
6
|
-
class BitmapMaker #:nodoc:all
|
7
|
-
class << self
|
8
|
-
extend FFI::Library
|
9
|
-
|
10
|
-
ffi_lib 'user32', 'gdi32'
|
11
|
-
ffi_convention :stdcall
|
12
|
-
callback :enum_callback, [:long, :pointer], :bool
|
13
|
-
|
14
|
-
# user32.dll
|
15
|
-
attach_function :enum_windows, :EnumWindows,
|
16
|
-
[:enum_callback, :pointer], :int
|
17
|
-
attach_function :enum_child_windows, :EnumChildWindows,
|
18
|
-
[:long, :enum_callback, :pointer], :int
|
19
|
-
attach_function :window_text, :GetWindowTextA,
|
20
|
-
[:long, :pointer, :int], :int
|
21
|
-
attach_function :window_text_length, :GetWindowTextLengthA,
|
22
|
-
[:long], :int
|
23
|
-
attach_function :class_name, :GetClassNameA,
|
24
|
-
[:long, :pointer, :int], :int
|
25
|
-
attach_function :window_visible, :IsWindowVisible,
|
26
|
-
[:long], :bool
|
27
|
-
attach_function :dc, :GetDC,
|
28
|
-
[:long], :long
|
29
|
-
attach_function :client_rect, :GetClientRect,
|
30
|
-
[:long, :pointer], :bool
|
31
|
-
attach_function :window_rect, :GetWindowRect,
|
32
|
-
[:long, :pointer], :bool
|
33
|
-
attach_function :minimized, :IsIconic,
|
34
|
-
[:long], :bool
|
35
|
-
attach_function :show_window, :ShowWindow,
|
36
|
-
[:long, :int], :bool
|
37
|
-
attach_function :foreground_window, :GetForegroundWindow,
|
38
|
-
[], :long
|
39
|
-
attach_function :desktop_window, :GetDesktopWindow,
|
40
|
-
[], :long
|
41
|
-
attach_function :window_thread_process_id, :GetWindowThreadProcessId,
|
42
|
-
[:long, :pointer], :long
|
43
|
-
attach_function :attach_thread_input, :AttachThreadInput,
|
44
|
-
[:long, :long, :bool], :bool
|
45
|
-
attach_function :set_foreground_window, :SetForegroundWindow,
|
46
|
-
[:long], :bool
|
47
|
-
attach_function :bring_window_to_top, :BringWindowToTop,
|
48
|
-
[:long], :bool
|
49
|
-
attach_function :set_active_window, :SetActiveWindow,
|
50
|
-
[:long], :long
|
51
|
-
attach_function :GetWindowThreadProcessId, [:ulong, :pointer],
|
52
|
-
:uint
|
53
|
-
|
54
|
-
# gdi32.dll
|
55
|
-
attach_function :create_compatible_dc, :CreateCompatibleDC,
|
56
|
-
[:long], :long
|
57
|
-
attach_function :create_compatible_bitmap, :CreateCompatibleBitmap,
|
58
|
-
[:long, :int, :int], :long
|
59
|
-
attach_function :select_object, :SelectObject,
|
60
|
-
[:long, :long], :long
|
61
|
-
attach_function :bit_blt, :BitBlt,
|
62
|
-
[:long, :int, :int, :int, :int, :long, :int, :int, :long], :bool
|
63
|
-
attach_function :di_bits, :GetDIBits,
|
64
|
-
[:long, :long, :int, :int, :pointer, :pointer, :int], :int
|
65
|
-
attach_function :delete_object, :DeleteObject,
|
66
|
-
[:long], :bool
|
67
|
-
attach_function :delete_dc, :DeleteDC,
|
68
|
-
[:long], :bool
|
69
|
-
attach_function :release_dc, :ReleaseDC,
|
70
|
-
[:long, :long], :int
|
71
|
-
|
72
|
-
|
73
|
-
EnumWindowCallback = FFI::Function.new(:bool, [ :long, :pointer ], { :convention => :stdcall }) do |hwnd, param|
|
74
|
-
searched_window = WindowStruct.new param
|
75
|
-
if(searched_window[:search_class] != 0)
|
76
|
-
title = Util.window_class(hwnd)
|
77
|
-
else
|
78
|
-
title = Util.window_title(hwnd)
|
79
|
-
end
|
80
|
-
if title =~ Regexp.new(searched_window[:title].read_string) && window_visible(hwnd)
|
81
|
-
searched_window[:hwnd] = hwnd
|
82
|
-
false
|
83
|
-
else
|
84
|
-
if(searched_window[:search_class] != 0)
|
85
|
-
# if they're searching for a classname, enumerate children, too
|
86
|
-
enum_child_windows(hwnd, EnumWindowCallback, param)
|
87
|
-
if searched_window[:hwnd] != 0
|
88
|
-
# return early if already discovered
|
89
|
-
false
|
90
|
-
else
|
91
|
-
true
|
92
|
-
end
|
93
|
-
else
|
94
|
-
true
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
class WindowStruct < FFI::Struct
|
100
|
-
layout :title, :pointer,
|
101
|
-
:hwnd, :long,
|
102
|
-
:search_class, :char # boolean
|
103
|
-
end
|
104
|
-
|
105
|
-
def hwnd(window_title, search_class = false)
|
106
|
-
window = WindowStruct.new
|
107
|
-
unless window_title.is_a?(Regexp)
|
108
|
-
window_title = Regexp.escape(window_title.to_s)
|
109
|
-
else
|
110
|
-
window_title = window_title.to_s
|
111
|
-
end
|
112
|
-
window_title = FFI::MemoryPointer.from_string(window_title)
|
113
|
-
window[:title] = window_title
|
114
|
-
window[:search_class] = search_class ? 1 : 0
|
115
|
-
enum_windows(EnumWindowCallback, window.to_ptr)
|
116
|
-
window[:hwnd] == 0 ? nil : window[:hwnd]
|
117
|
-
end
|
118
|
-
|
119
|
-
def prepare_window(hwnd, pause)
|
120
|
-
restore(hwnd) if minimized(hwnd)
|
121
|
-
set_foreground(hwnd)
|
122
|
-
sleep pause
|
123
|
-
end
|
124
|
-
|
125
|
-
SW_RESTORE = 9
|
126
|
-
|
127
|
-
def restore(hwnd)
|
128
|
-
show_window(hwnd, SW_RESTORE)
|
129
|
-
end
|
130
|
-
|
131
|
-
def set_foreground(hwnd)
|
132
|
-
if foreground_window != hwnd
|
133
|
-
set_foreground_window(hwnd)
|
134
|
-
set_active_window(hwnd)
|
135
|
-
bring_window_to_top(hwnd)
|
136
|
-
# and just in case...
|
137
|
-
foreground_thread = window_thread_process_id(foreground_window, nil)
|
138
|
-
other_thread = window_thread_process_id(hwnd, nil)
|
139
|
-
attach_thread_input(foreground_thread, other_thread, true) unless other_thread == foreground_thread
|
140
|
-
set_foreground_window(hwnd)
|
141
|
-
set_active_window(hwnd)
|
142
|
-
bring_window_to_top(hwnd)
|
143
|
-
attach_thread_input(foreground_thread, other_thread, false) unless other_thread == foreground_thread
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def get_process_id_from_hwnd hwnd
|
148
|
-
out = FFI::MemoryPointer.new(:uint)
|
149
|
-
GetWindowThreadProcessId(hwnd, out)
|
150
|
-
out.get_uint32(0) # read_uint
|
151
|
-
end
|
152
|
-
|
153
|
-
def capture_all(hwnd, &proc)
|
154
|
-
width, height = Util.dimensions_for(hwnd)
|
155
|
-
capture_area(hwnd, 0, 0, width, height, &proc)
|
156
|
-
end
|
157
|
-
|
158
|
-
SRCCOPY = 0x00CC0020
|
159
|
-
CAPTUREBLT = 0x40000000 #0x40000000
|
160
|
-
DIB_RGB_COLORS = 0
|
161
|
-
|
162
|
-
def capture_area(hwnd, x1, y1, x2, y2) # block
|
163
|
-
hScreenDC = dc(hwnd)
|
164
|
-
w = x2-x1
|
165
|
-
h = y2-y1
|
166
|
-
|
167
|
-
hmemDC = create_compatible_dc(hScreenDC)
|
168
|
-
hmemBM = create_compatible_bitmap(hScreenDC, w, h)
|
169
|
-
select_object(hmemDC, hmemBM)
|
170
|
-
# p (SRCCOPY|CAPTUREBLT).to_s(16), 'hello'
|
171
|
-
bit_blt(hmemDC, 0, 0, w, h, hScreenDC, x1, y1, SRCCOPY)
|
172
|
-
bitmap_size = w * h * 3 + w % 4 * h # assumes 24 bit, funky math LOL
|
173
|
-
lpvpxldata = FFI::MemoryPointer.new(bitmap_size)
|
174
|
-
|
175
|
-
# Bitmap header
|
176
|
-
# http://www.fortunecity.com/skyscraper/windows/364/bmpffrmt.html
|
177
|
-
bmInfo = [40, w, h, 1, 24, 0, 0, 0, 0, 0, 0, 0].pack('L3S2L6')
|
178
|
-
di_bits(hmemDC, hmemBM, 0, h, lpvpxldata, bmInfo, DIB_RGB_COLORS) # converts to 24 bit here...
|
179
|
-
|
180
|
-
bmFileHeader = [
|
181
|
-
19778,
|
182
|
-
bitmap_size + 40 + 14,
|
183
|
-
0,
|
184
|
-
0,
|
185
|
-
54
|
186
|
-
].pack('SLSSL')
|
187
|
-
p 'header length', bmFileHeader.size, 'info length', bmInfo.size, 'data length', lpvpxldata.read_string(bitmap_size).length
|
188
|
-
bmp_data = bmFileHeader + bmInfo + lpvpxldata.read_string(bitmap_size)
|
189
|
-
p 'total', bmp_data.size
|
190
|
-
yield(w, h, bmp_data)
|
191
|
-
ensure
|
192
|
-
lpvpxldata.free
|
193
|
-
delete_object(hmemBM)
|
194
|
-
delete_dc(hmemDC)
|
195
|
-
release_dc(0, hScreenDC)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
@@ -1,93 +0,0 @@
|
|
1
|
-
module Win32
|
2
|
-
class Screenshot
|
3
|
-
class Util
|
4
|
-
class << self
|
5
|
-
|
6
|
-
def all_desktop_windows
|
7
|
-
titles = []
|
8
|
-
window_callback = FFI::Function.new(:bool, [ :long, :pointer ], { :convention => :stdcall }) do |hwnd, param|
|
9
|
-
titles << [window_title(hwnd), hwnd]
|
10
|
-
true
|
11
|
-
end
|
12
|
-
|
13
|
-
BitmapMaker.enum_windows(window_callback, nil)
|
14
|
-
titles
|
15
|
-
end
|
16
|
-
|
17
|
-
# just returns a long list of hwnd's...
|
18
|
-
# unless with_info is true
|
19
|
-
# then it will return all hwnds with full info about each window
|
20
|
-
def windows_hierarchy with_info = false
|
21
|
-
all = {}
|
22
|
-
desktop_hwnd = BitmapMaker.desktop_window
|
23
|
-
root = {:hwnd => desktop_hwnd, :children => []}
|
24
|
-
root.merge!(get_info(desktop_hwnd)) if with_info
|
25
|
-
parents = []
|
26
|
-
parents << root
|
27
|
-
window_callback = FFI::Function.new(:bool, [ :long, :pointer ], { :convention => :stdcall }) do |hwnd, param|
|
28
|
-
# this is a child of the most recent parent
|
29
|
-
myself = {:hwnd => hwnd, :children => []}
|
30
|
-
myself.merge!(get_info(hwnd)) if with_info
|
31
|
-
parents[-1][:children] << myself
|
32
|
-
parents << myself
|
33
|
-
if !all[hwnd]
|
34
|
-
all[hwnd] = true
|
35
|
-
BitmapMaker.enum_child_windows(hwnd, window_callback, nil)
|
36
|
-
end
|
37
|
-
|
38
|
-
parents.pop
|
39
|
-
true
|
40
|
-
end
|
41
|
-
BitmapMaker.enum_child_windows(desktop_hwnd, window_callback, nil)
|
42
|
-
root
|
43
|
-
end
|
44
|
-
|
45
|
-
def get_info hwnd
|
46
|
-
{:title => window_title(hwnd),
|
47
|
-
:class => window_class(hwnd),
|
48
|
-
:dimensions => dimensions_for(hwnd),
|
49
|
-
:starting_coordinates => location_of(hwnd)
|
50
|
-
}
|
51
|
-
end
|
52
|
-
|
53
|
-
def window_title hwnd
|
54
|
-
title_length = BitmapMaker.window_text_length(hwnd) + 1
|
55
|
-
title = FFI::MemoryPointer.new :char, title_length
|
56
|
-
BitmapMaker.window_text(hwnd, title, title_length)
|
57
|
-
title.read_string
|
58
|
-
end
|
59
|
-
|
60
|
-
def window_class hwnd
|
61
|
-
title = FFI::MemoryPointer.new :char, 100
|
62
|
-
BitmapMaker.class_name(hwnd, title, 99)
|
63
|
-
title.read_string
|
64
|
-
end
|
65
|
-
|
66
|
-
def window_hwnd(title_query)
|
67
|
-
hwnd = BitmapMaker.hwnd(title_query)
|
68
|
-
raise "window with title '#{title_query}' was not found!" unless hwnd
|
69
|
-
hwnd
|
70
|
-
end
|
71
|
-
|
72
|
-
def location_of(hwnd)
|
73
|
-
rect = [0, 0, 0, 0].pack('L4')
|
74
|
-
BitmapMaker.window_rect(hwnd, rect)
|
75
|
-
x, y, width, height = rect.unpack('L4')
|
76
|
-
return x, y
|
77
|
-
end
|
78
|
-
|
79
|
-
def dimensions_for(hwnd)
|
80
|
-
rect = [0, 0, 0, 0].pack('L4')
|
81
|
-
BitmapMaker.client_rect(hwnd, rect)
|
82
|
-
_, _, width, height = rect.unpack('L4')
|
83
|
-
return width, height
|
84
|
-
end
|
85
|
-
|
86
|
-
def window_process_id(hwnd)
|
87
|
-
BitmapMaker.get_process_id_from_hwnd(hwnd)
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
@@ -1 +0,0 @@
|
|
1
|
-
--color
|
@@ -1,85 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
-
require 'win32/screenshot'
|
4
|
-
require 'rubygems'
|
5
|
-
require 'spec'
|
6
|
-
require 'spec/autorun'
|
7
|
-
require 'RMagick'
|
8
|
-
require 'fileutils'
|
9
|
-
|
10
|
-
module SpecHelper
|
11
|
-
SW_MAXIMIZE = 3
|
12
|
-
SW_MINIMIZE = 6
|
13
|
-
HWND_TOPMOST = -1
|
14
|
-
HWND_NOTOPMOST = -2
|
15
|
-
SWP_NOSIZE = 1
|
16
|
-
SWP_NOMOVE = 2
|
17
|
-
SWP_SHOWWINDOW = 40
|
18
|
-
|
19
|
-
extend FFI::Library
|
20
|
-
ffi_lib 'user32'
|
21
|
-
ffi_convention :stdcall
|
22
|
-
|
23
|
-
# user32.dll
|
24
|
-
attach_function :set_window_pos, :SetWindowPos,
|
25
|
-
[:long, :long, :int, :int, :int, :int, :int], :bool
|
26
|
-
|
27
|
-
def cleanup
|
28
|
-
FileUtils.rm Dir.glob(File.join(File.dirname(__FILE__), "tmp/*"))
|
29
|
-
end
|
30
|
-
|
31
|
-
def check_image(bmp, file=nil)
|
32
|
-
temp_dir = File.join(File.dirname(__FILE__), 'tmp')
|
33
|
-
FileUtils.mkdir temp_dir unless File.exists?(temp_dir)
|
34
|
-
File.open(File.join(temp_dir, "#{file}.bmp"), "wb") {|io| io.write(bmp)} unless file.nil?
|
35
|
-
bmp[0..1].should == 'BM'
|
36
|
-
img = Magick::Image.from_blob(bmp)
|
37
|
-
png = img[0].to_blob {self.format = 'PNG'}
|
38
|
-
png[0..3].should == "\211PNG"
|
39
|
-
File.open(File.join(temp_dir, "#{file}.png"), "wb") {|io| io.puts(png)} unless file.nil?
|
40
|
-
end
|
41
|
-
|
42
|
-
def wait_for_programs_to_open
|
43
|
-
until Win32::Screenshot::BitmapMaker.hwnd(/Internet Explorer/) &&
|
44
|
-
Win32::Screenshot::BitmapMaker.hwnd(/Notepad/)
|
45
|
-
sleep 0.1
|
46
|
-
end
|
47
|
-
wait_for_calculator_to_open
|
48
|
-
|
49
|
-
# just in case of slow PC
|
50
|
-
sleep 8
|
51
|
-
end
|
52
|
-
|
53
|
-
def wait_for_calculator_to_open
|
54
|
-
until Win32::Screenshot::BitmapMaker.hwnd(/Calculator/)
|
55
|
-
sleep 0.1
|
56
|
-
end
|
57
|
-
# just in case of slow PC
|
58
|
-
sleep 2
|
59
|
-
end
|
60
|
-
|
61
|
-
def maximize title
|
62
|
-
Win32::Screenshot::BitmapMaker.show_window(Win32::Screenshot::BitmapMaker.hwnd(title),
|
63
|
-
SW_MAXIMIZE)
|
64
|
-
sleep 1
|
65
|
-
end
|
66
|
-
|
67
|
-
def minimize title
|
68
|
-
Win32::Screenshot::BitmapMaker.show_window(Win32::Screenshot::BitmapMaker.hwnd(title),
|
69
|
-
SW_MINIMIZE)
|
70
|
-
sleep 1
|
71
|
-
end
|
72
|
-
|
73
|
-
def resize title
|
74
|
-
hwnd = Win32::Screenshot::BitmapMaker.hwnd(title)
|
75
|
-
set_window_pos(hwnd,
|
76
|
-
HWND_TOPMOST,
|
77
|
-
0, 0, 150, 238,
|
78
|
-
SWP_NOMOVE)
|
79
|
-
set_window_pos(hwnd,
|
80
|
-
HWND_NOTOPMOST,
|
81
|
-
0, 0, 0, 0,
|
82
|
-
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE)
|
83
|
-
sleep 1
|
84
|
-
end
|
85
|
-
end
|