castanaut 1.0.0 → 1.1.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.
@@ -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