castanaut 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+ # modifications for iShowU HD
2
+ # 2009-04-23
3
+ #
4
+ module Castanaut; module Plugin
5
+
6
+ # This module provides primitive support for iShowU, a screencast capturing
7
+ # tool for Mac OS X from Shiny White Box.
8
+ #
9
+ # iShowU is widely considered a good, simple application for its purpose,
10
+ # but you're by no means required to use it for Castanaut. Simply write
11
+ # your own module for Snapz Pro, or ScreenFlow, or whatever you like.
12
+ #
13
+ # Shiny White Box is promising much better Applescript support in an
14
+ # imminent version, which could tidy up this module quite a bit.
15
+ #
16
+ # More info: http://www.shinywhitebox.com/home/home.html
17
+ module Ishowuhd
18
+
19
+ # Set the screencast to capture a particular region of the screen.
20
+ # Generate appropriately-formatted co-ordinates using Castanaut::Movie#to.
21
+ def ishowu_set_region(*options)
22
+ ishowu_applescriptify
23
+
24
+ options = combine_options(*options)
25
+
26
+ ishowu_menu_item("Edit", "Edit Capture Area", false)
27
+ sleep(0.2)
28
+ automatically "mousewarp 0 0"
29
+ drag to(0, 0)
30
+
31
+ automatically "mousewarp #{options[:to][:left]} #{options[:to][:top]}"
32
+
33
+ drag to(
34
+ options[:to][:left] + options[:to][:width],
35
+ options[:to][:top] + options[:to][:height]
36
+ )
37
+
38
+
39
+ sleep(0.2)
40
+ hit Enter
41
+ ishowu_hide
42
+ end
43
+
44
+ # Tell iShowU to start recording. Will automatically stop recording when
45
+ # the movie is ended, unless you set :auto_stop => false in options.
46
+ def ishowu_start_recording(options = {})
47
+ # ishowu_hide # iShowU preference
48
+ ishowu_menu_item("Edit", "Record")
49
+ sleep(3)
50
+ unless options[:auto_stop] == false
51
+ at_end_of_movie { ishowu_stop_recording }
52
+ end
53
+ end
54
+
55
+ # Tell iShowU to stop recording.
56
+ def ishowu_stop_recording
57
+ ishowu_menu_item("Edit", "Stop")
58
+ end
59
+
60
+ # Execute an iShowU menu option.
61
+ def ishowu_menu_item(menu, item, quiet = true)
62
+ ascript = %Q`
63
+ tell application "iShowU HD"
64
+ activate
65
+ tell application "System Events"
66
+ click menu item "#{item}" of menu "#{menu}" of menu bar item "#{menu}" of menu bar 1 of process "iShowU HD"
67
+ #{'set visible of process "iShowU HD" to false' if quiet}
68
+ end tell
69
+ end
70
+ `
71
+ execute_applescript(ascript)
72
+ end
73
+
74
+ # Hide the iShowU window. This is a bit random, and suggestions are
75
+ # welcomed.
76
+ def ishowu_hide
77
+ ishowu_menu_item("iShowU HD", "Hide iShowU HD")
78
+ end
79
+
80
+ private
81
+ # iShowU is not Applescript-enabled out of the box. This fix, arguably
82
+ # a hack, lets us do some limited work with it in Applescript.
83
+ def ishowu_applescriptify
84
+ execute_applescript(%Q`
85
+ try
86
+ tell application "Finder"
87
+ set the a_app to (application file id "com.tcdc.Digitizer") as alias
88
+ end tell
89
+ set the plist_filepath to the quoted form of ¬
90
+ ((POSIX path of the a_app) & "Contents/Info")
91
+ do shell script "defaults write " & the plist_filepath & space ¬
92
+ & "NSAppleScriptEnabled -bool YES"
93
+ end try
94
+ `)
95
+ end
96
+ end
97
+ end; end
98
+
@@ -0,0 +1,111 @@
1
+ module Castanaut; module Plugin
2
+
3
+ # keystack castanaut plugin
4
+ # by trevor wennblom <trevor@corevx.com>
5
+ # 2009-04-23
6
+ #
7
+ # used in gnu screen demo
8
+ # http://ninecoldwinters.com/ferro/gnuscreenscreencast
9
+ #
10
+ # castanaut can be found here:
11
+ # http://gadgets.inventivelabs.com.au/castanaut
12
+ #
13
+ # support multiple modifier keys to achieve the likes of Command-Tab
14
+ #
15
+ # modifiers allowed are :control, :command, :option, and :shift
16
+ # these can be passed as an array
17
+ #
18
+ # this does not account for input customization, so if you use dvorak your
19
+ # results will be interesting.
20
+ #
21
+ # license compatible with castanaut
22
+ # released under the terms of the WTFPL
23
+ # http://sam.zoy.org/wtfpl
24
+ #
25
+ module Keystack
26
+
27
+ # keycode press
28
+ # keycode is a number mapped to a specific key on your keyboard, '0' and greater
29
+ def keycode(k)
30
+ k = k.to_i # if a number as type String was passed
31
+ ascript = %Q`tell application "System Events" to key code #{k}`
32
+ execute_applescript(ascript)
33
+ end
34
+
35
+ # keystroke such as 'a' or 'my sentence'
36
+ def keystroke(k)
37
+ ascript = %Q`tell application "System Events" to keystroke "#{k}"`
38
+ execute_applescript(ascript)
39
+ end
40
+
41
+ # keystroke literal such as 'return' or 'tab'
42
+ # example
43
+ # keystroke_literal('tab')
44
+ def keystroke_literal(k, *modifiers)
45
+ ascript = %Q`tell application "System Events" to keystroke #{k}`
46
+ execute_applescript(ascript)
47
+ end
48
+
49
+ # keycode press with one or more modifier keys
50
+ # keycode is a number mapped to a specific key on your keyboard, '0' and greater
51
+ def keycode_using(k, *modifiers)
52
+ k = k.to_i # if a number as type String was passed
53
+ m = modifiers_to_array(modifiers)
54
+ ascript = %Q`tell application "System Events" to key code #{k} using #{m}`
55
+ execute_applescript(ascript)
56
+ end
57
+
58
+ # keystroke with one or more modifier keys
59
+ # example
60
+ # keystroke('z', :command)
61
+ # keystroke('z', :command, :shift)
62
+ # keystroke('z', [:command, :shift])
63
+ def keystroke_using(k, *modifiers)
64
+ m = modifiers_to_array(modifiers)
65
+ ascript = %Q`tell application "System Events" to keystroke "#{k}" using #{m}`
66
+ execute_applescript(ascript)
67
+ end
68
+
69
+ # keystroke literal such as 'return' or 'tab' with one or more modifier keys
70
+ # example
71
+ # keystroke_literal_using('tab', :command) # Command-Tab switch windows
72
+ def keystroke_literal_using(k, *modifiers)
73
+ m = modifiers_to_array(modifiers)
74
+ ascript = %Q`tell application "System Events" to keystroke #{k} using #{m}`
75
+ execute_applescript(ascript)
76
+ end
77
+
78
+ protected
79
+
80
+ def modifiers_to_array(modifiers)
81
+ ary = []
82
+ raise "must be passed Array - received #{modifiers.inspect}'" unless modifiers.kind_of? Array
83
+ modifiers.flatten! # accept keystroke('z', [:command, :shift])
84
+ raise "must be passed Array with at least one element - received #{modifiers.inspect}'" if modifiers.empty?
85
+ modifiers.map! do |m|
86
+ # these are listed in the System Events dictionary
87
+ # Applications/AppleScript/Script Editor -> File -> Open Dictionary -> System Events
88
+ case m
89
+ when :control
90
+ 'control down'
91
+ when :command
92
+ 'command down'
93
+ when :option
94
+ 'option down'
95
+ when :shift
96
+ 'shift down'
97
+ else
98
+ raise "unrecognized '#{m.inspect}'"
99
+ end
100
+ end
101
+
102
+ if modifiers.size > 1
103
+ '{' + modifiers.join(', ') + '}'
104
+ else
105
+ modifiers.to_s
106
+ end
107
+ end
108
+
109
+ end # module Keystack
110
+
111
+ end; end
@@ -7,7 +7,7 @@ module Castanaut; module Plugin
7
7
  # It doesn't do any configuration of Mousepose on the fly. Configure
8
8
  # Mousepose settings before running your screenplay.
9
9
  #
10
- # Tested against Mousepose 2. More info: http://www.boinx.com/mousepose
10
+ # Tested against Mousepose 3. More info: http://www.boinx.com/mousepose
11
11
  module Mousepose
12
12
 
13
13
  # Put a halo around the mouse. If a block is given to this method,
@@ -5,27 +5,73 @@ module Castanaut
5
5
  # Safari 3 on Mac OS X 10.5.2.
6
6
  module Safari
7
7
 
8
+ # An applescript fragment by the Movie launch method to determine
9
+ # whether a Safari browser window is open or not.
10
+ def ensure_window_for_safari
11
+ "if (count(windows)) < 1 then make new document"
12
+ end
13
+
14
+ # An applescript fragment by the Movie launch method to position
15
+ # the window.
16
+ def positioning_for_safari
17
+ nil
18
+ end
19
+
8
20
  # Open a URL in the front Safari tab.
9
21
  def url(str)
10
22
  execute_applescript(%Q`
11
- tell application "safari"
12
- do JavaScript "location.href = '#{str}'" in front document
13
- end tell
23
+ tell application "safari"
24
+ do JavaScript "location.href = '#{str}'" in front document
25
+ end tell
14
26
  `)
15
27
  end
16
28
 
29
+ # Sleep until the specified element appears on-screen. Use this if you
30
+ # want to wait until the a page or AJAX request has finished loading
31
+ # before proceding to the next command.
32
+ #
33
+ # Options include:
34
+ # * :timeout - maximum number of seconds to wait for the element to
35
+ # appear. Defaults to 10.
36
+ # * :index - an integer (*n*) that gets the *n*th element matching the
37
+ # selector. Defaults to the first element.
38
+ # appear. Defaults to 10.
39
+ # * :index - an integer (*n*) that gets the *n*th element matching the
40
+ # selector. Defaults to the first element.
41
+ #
42
+ def wait_for_element(selector, options = {})
43
+ timeout = Time.now.to_i + (options[:timeout] || 10).to_i
44
+ while true
45
+ begin
46
+ coords = element_coordinates(selector, options)
47
+ return coords unless coords.nil?
48
+ rescue Castanaut::Exceptions::ElementNotFound > e
49
+ raise e if Time.now.to_i > timeout
50
+ end
51
+ sleep 0.3
52
+ end
53
+ end
54
+
17
55
  # Get the co-ordinates of an element in the front Safari tab. Use this
18
56
  # with Castanaut::Movie#cursor to send the mouse cursor to the element.
19
57
  #
20
58
  # Options include:
21
- # * :index - an integer (*n*) that gets the *n*th element matching the
59
+ # * :index - an integer (*n*) that gets the *n*th element matching the
22
60
  # selector. Defaults to the first element.
23
- # * :area - whereabouts in the element do you want the coordinates.
24
- # Valid values are: left, center, right, and top, middle, bottom.
61
+ # * :area - whereabouts in the element do you want the coordinates.
62
+ # Valid values are: left, center, right, and top, middle, bottom.
25
63
  # Defaults to ["center", "middle"].
26
64
  # If single axis is given (eg "left"), the other axis uses its default.
65
+ # * :timeout - maximum seconds to wait for the element to appear.
66
+ # Useful if you're waiting for a page load or AJAX call to complete
67
+ # Defaults to 0.
68
+ #
27
69
  def to_element(selector, options = {})
28
70
  pos = options.delete(:area)
71
+ if options[:timeout]
72
+ wait_for_element(selector, options)
73
+ options.delete(:timeout)
74
+ end
29
75
  coords = element_coordinates(selector, options)
30
76
 
31
77
  x_axis, y_axis = [:center, :middle]
@@ -34,30 +80,31 @@ module Castanaut
34
80
  x_axis = p.to_sym if %w[left center right].include?(p)
35
81
  y_axis = p.to_sym if %w[top middle bottom].include?(p)
36
82
  end
37
-
83
+
38
84
  edge_offset = options[:edge_offset] || 3
39
85
  case x_axis
40
- when :left
41
- x = coords[0] + edge_offset
42
- when :center
43
- x = (coords[0] + coords[2] * 0.5).to_i
44
- when :right
45
- x = (coords[0] + coords[2]) - edge_offset
86
+ when :left
87
+ x = coords[0] + edge_offset
88
+ when :center
89
+ x = (coords[0] + coords[2] * 0.5).to_i
90
+ when :right
91
+ x = (coords[0] + coords[2]) - edge_offset
46
92
  end
47
93
 
48
94
  case y_axis
49
- when :top
50
- y = coords[1] + edge_offset
51
- when :middle
52
- y = (coords[1] + coords[3] * 0.5).to_i
53
- when :bottom
54
- y = (coords[1] + coords[3]) - edge_offset
95
+ when :top
96
+ y = coords[1] + edge_offset
97
+ when :middle
98
+ y = (coords[1] + coords[3] * 0.5).to_i
99
+ when :bottom
100
+ y = (coords[1] + coords[3]) - edge_offset
55
101
  end
56
102
 
57
103
  result = { :to => { :left => x, :top => y } }
58
104
  end
59
105
 
60
106
  private
107
+
61
108
  # Note: the script should set the Castanaut.result variable.
62
109
  def execute_javascript(scpt)
63
110
  execute_applescript %Q`
@@ -105,7 +152,7 @@ module Castanaut
105
152
  end
106
153
 
107
154
  end
108
- end
155
+ end
109
156
 
110
157
  module Exceptions
111
158
  # When getting an element's coordinates, this is raised if no element on
@@ -0,0 +1,55 @@
1
+ module Castanaut
2
+
3
+ module Plugin
4
+
5
+ # This module provides primitive support for Snapz Pro, a screencast capturing
6
+ # tool for Mac OS X from Abrosia Software.
7
+ #
8
+ # Unfortunately Snapz Pro has virtually no AppleScript support so for this plugin
9
+ # to work correctly you must do the following.
10
+ #
11
+ # 1. Invoke Snapz Pro.
12
+ # 2. Position the initial window so that it is flush with the left side of the screen & the top of the window is flush with the bottom of the menu-bar. The window's close button will be below & slightly to the left of the Apple menu.
13
+ # 3. Click the "Movie..." button & set everything up just the way you want it.
14
+ # 4. Close all Snapz Pro windows & run your castanaut script as usual :-)
15
+ #
16
+ # Once your script has finished you'll have to tell Snapz how & where to save
17
+ # the captured movie manually.
18
+ #
19
+ # More info: http://www.ambrosiasw.com/utilities/snapzprox
20
+ module SnapzPro
21
+
22
+ # Tell Snapz to start recording. Will automatically stop recording when
23
+ # the movie is ended, unless you set :auto_stop => false in options.
24
+ def snapz_start_recording(options = {})
25
+ snapz_invoke
26
+
27
+ # Click the "Movie..." button
28
+ move to(332, 130)
29
+ click
30
+
31
+ # Start recording
32
+ hit Castanaut::Enter
33
+
34
+ unless options[:auto_stop] == false
35
+ at_end_of_movie { snapz_stop_recording }
36
+ end
37
+ end
38
+
39
+ # Tell Snapz to stop recording (by invoking it again).
40
+ def snapz_stop_recording
41
+ snapz_invoke
42
+ end
43
+
44
+ private
45
+ # Invoke Snapz Pro. Bascially the same thing as hitting the keyboard shortcut.
46
+ def snapz_invoke
47
+ execute_applescript(%Q`
48
+ tell application "Snapz Pro X"
49
+ invoke
50
+ end tell
51
+ `)
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,55 @@
1
+ module Castanaut
2
+
3
+ module Plugin
4
+ # This module provides actions for controlling Terminal.app
5
+ # Terminal 2.0.1 on Mac OS X 10.5.6
6
+ module Terminal
7
+
8
+ # Applescript fragment for new windows.
9
+ def ensure_window_for_terminal
10
+ do_script
11
+ end
12
+
13
+ def do_script(args = '')
14
+ "do script \"#{args}\""
15
+ end
16
+
17
+ def launch_terminal
18
+ launch "Terminal"
19
+ execute_applescript ensure_window_for_terminal
20
+ end
21
+
22
+ def run_in_terminal(cmd)
23
+ execute_applescript "
24
+ tell application \"Terminal\"
25
+ #{do_script(cmd)} in window 1
26
+ end tell"
27
+ end
28
+
29
+ def focus_on_terminal
30
+ execute_applescript "
31
+ tell application \"Terminal\"
32
+ activate
33
+ end tell"
34
+ end
35
+
36
+ def cli(cmd, opts = {})
37
+ type(cmd, opts)
38
+ hit Enter
39
+ end
40
+
41
+ def type_pre(string)
42
+ type string.gsub(/\n/, '
43
+ end
44
+
45
+ def vim_insert(string)
46
+ type_pre 'i' + string + ''
47
+ end
48
+
49
+ end
50
+ end
51
+
52
+ module Exceptions
53
+ end
54
+
55
+ end
@@ -0,0 +1,65 @@
1
+ module Castanaut; module Plugin
2
+
3
+ ##
4
+ # Contributed by Geoffrey Grosenbach
5
+ # http://peepcode.com
6
+
7
+ # Modified by Brian Hogan
8
+ # http://www.napcs.com/
9
+
10
+ module Textmate
11
+
12
+ ##
13
+ # Types text into TextMate all at once.
14
+ #
15
+ # The as_snippet option is documented but doesn't seem to do anything.
16
+
17
+ def tm_insert_text(text, as_snippet=false)
18
+ escaped_text = text.gsub(/"/, '\"')
19
+ snippet_directive = (as_snippet ? "with as snippet" : "")
20
+
21
+ execute_applescript(%Q`
22
+ tell application "TextMate"
23
+ insert "#{escaped_text}" #{snippet_directive}
24
+ end
25
+ `)
26
+ end
27
+
28
+ ##
29
+ # Open a file, optionally at a specific line and column.
30
+ def tm_open_file(file_path, line=0, column=0)
31
+ full_url = "txmt://open?url=file://#{file_path}&line=#{line}&column=#{column}"
32
+ execute_applescript(%Q`
33
+ tell application "TextMate"
34
+ get url "#{full_url}"
35
+ end
36
+ `)
37
+ end
38
+
39
+ # Position the cursor at the given coordinates.
40
+ def tm_move_to(line=0, column=0)
41
+ full_url = "txmt://open?line=#{line}&column=#{column}"
42
+
43
+ execute_applescript(%Q`
44
+ tell application "TextMate"
45
+ get url "#{full_url}"
46
+ end
47
+ `)
48
+ end
49
+
50
+ # Create a new file on the filesystem and open it in textmate.
51
+ def tm_new_file(file)
52
+ execute_applescript(%Q`
53
+ do shell script "touch #{file}"
54
+ tell application "TextMate"
55
+ activate
56
+ end
57
+ `)
58
+
59
+ tm_open_file(file)
60
+ end
61
+
62
+
63
+ end
64
+
65
+ end; end
data/test/helper.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'test/unit'
2
+ require 'lib/castanaut'
3
+
4
+
5
+ def fixture_path(path)
6
+ File.join(File.dirname(__FILE__), 'fixtures', path)
7
+ end
8
+
9
+
10
+ def fixture(path)
11
+ IO.read(fixture_path(path))
12
+ end
data/test/main_test.rb ADDED
@@ -0,0 +1,13 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class MainTest < Test::Unit::TestCase
4
+
5
+ def test_instantiate_movie_with_screenplay
6
+ assert(
7
+ Castanaut::Main.run(
8
+ [fixture_path('1.screenplay')]
9
+ ).kind_of?(Castanaut::Movie)
10
+ )
11
+ end
12
+
13
+ end
@@ -0,0 +1,67 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class MovieTest < Test::Unit::TestCase
4
+
5
+ def test_truth
6
+ assert(true)
7
+ end
8
+
9
+
10
+ def test_instantiate_movie
11
+ assert(Castanaut::Movie.spawn.kind_of?(Castanaut::Movie))
12
+ end
13
+
14
+
15
+ def test_absolute_mouse_movement
16
+ mov = Castanaut::Movie.spawn
17
+
18
+ mov.move(mov.to(100, 100))
19
+ mloc = mov.cursor_location
20
+ assert((99..101).to_a.include?(mloc[:x]))
21
+ assert((99..101).to_a.include?(mloc[:y]))
22
+ end
23
+
24
+
25
+ def test_relative_mouse_movement
26
+ mov = Castanaut::Movie.spawn
27
+
28
+ mloc = mov.cursor_location
29
+ mov.move(mov.by(100, 100))
30
+
31
+ new_mloc = mov.cursor_location
32
+ assert_equal(new_mloc[:x], mloc[:x] + 100)
33
+ assert_equal(new_mloc[:y], mloc[:y] + 100)
34
+ end
35
+
36
+
37
+ def test_plugin_extensibility
38
+ mov = Castanaut::Movie.spawn
39
+ assert(!mov.respond_to?(:to_element))
40
+ mov.plugin('safari')
41
+ assert(mov.respond_to?(:to_element))
42
+ end
43
+
44
+
45
+ def test_perform_and_skip
46
+ mov = Castanaut::Movie.spawn
47
+
48
+ x = 1
49
+ mov.perform("Something") {
50
+ x = 3
51
+ mov.skip
52
+ x = 4
53
+ }
54
+ assert_equal(3, x)
55
+ end
56
+
57
+
58
+ def test_credits
59
+ mov = Castanaut::Movie.spawn
60
+ x = 1
61
+ mov.at_end_of_movie { x = 3 }
62
+ assert_equal(1, x)
63
+ mov.send(:roll_credits)
64
+ assert_equal(3, x)
65
+ end
66
+
67
+ end