Class: Castanaut::OS::MacOSX::Movie

Inherits:
Movie
  • Object
show all
Defined in:
lib/castanaut/os/mac_os_x.rb

Overview

This class is intended to work on machines running Mac OS X 10.5.x or greater.

KNOWN LIMITATIONS

Partially working:
* type - does not support the :speed option
* hit - only works with special keys (those in keys.rb) not
  other characters (like 'a'), and does not support modifier keys
  (you can use keystroke instead, perhaps)

Direct Known Subclasses

TigerMovie

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Movie

#_play, #_play_and_monitor, #at_end_of_movie, #by, #initialize, #offset, #pause, #perform, #plugin, register, #run, #script, #skip, spawn, #to, #while_saying

Constructor Details

This class inherits a constructor from Castanaut::Movie

Class Method Details

.platform_supported?Boolean

Returns true if the current platform is Mac OS X 10.5 or greater.

Returns:

  • (Boolean)


21
22
23
24
25
26
# File 'lib/castanaut/os/mac_os_x.rb', line 21

def self.platform_supported?
  vers = `/usr/bin/sw_vers -productVersion`.match(/10\.(\d)/)
  vers[1].to_i >= 5
rescue
  false
end

Instance Method Details

#click(btn = "left") ⇒ Object



129
130
131
# File 'lib/castanaut/os/mac_os_x.rb', line 129

def click(btn = "left")
  automatically "mouseclick #{mouse_button_translate(btn)}"
end

#click_menu_item(*items) ⇒ Object

Click a menu item in any application. The name of the application should be the first argument.

Three dots will be automatically replaced by the appropriate ellipsis.

click_menu_item("TextMate", "Navigation", "Go to Symbol...")

Based on menu_click, by Jacob Rus, September 2006:

http://www.macosxhints.com/article.php?story=20060921045743404


238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/castanaut/os/mac_os_x.rb', line 238

def click_menu_item(*items)
  items_as_applescript_array = items.map { |i|
    %("#{i.gsub('...', "\342\200\246")}")
  }.join(", ")

  ascript = %Q`
    on menu_click(mList)
      local appName, topMenu, r
      if mList's length < 3 then error "Menu list is not long enough"

      set {appName, topMenu} to (items 1 through 2 of mList)
      set r to (items 3 through (mList's length) of mList)

      tell application "System Events" to my menu_click_recurse(r, ((process appName)'s (menu bar 1)'s (menu bar item topMenu)'s (menu topMenu)))
    end menu_click

    on menu_click_recurse(mList, parentObject)
    local f, r

    set f to item 1 of mList
    if mList's length > 1 then set r to (items 2 through (mList's length) of mList)

    tell application "System Events"
      if mList's length is 1 then
        click parentObject's menu item f
      else
        my menu_click_recurse(r, (parentObject's (menu item f)'s (menu f)))
      end if
    end tell
    end menu_click_recurse

    menu_click({#{items_as_applescript_array}})
  `
  execute_applescript(ascript)
end

#cursor(*options) ⇒ Object Also known as: move


MOUSE INPUT DIRECTIONS +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++



109
110
111
112
113
114
115
116
117
118
# File 'lib/castanaut/os/mac_os_x.rb', line 109

def cursor(*options)
  options = combine_options(*options)

  apply_offset(options)
  @cursor_loc ||= {}
  @cursor_loc[:x] = options[:to][:left]
  @cursor_loc[:y] = options[:to][:top]

  automatically "mousemove #{@cursor_loc[:x]} #{@cursor_loc[:y]}"
end

#cursor_locationObject



123
124
125
126
# File 'lib/castanaut/os/mac_os_x.rb', line 123

def cursor_location
  loc = automatically("mouselocation").strip.split(' ')
  {:x => loc[0].to_i, :y => loc[1].to_i}
end

#doubleclick(btn = "left") ⇒ Object



134
135
136
# File 'lib/castanaut/os/mac_os_x.rb', line 134

def doubleclick(btn = "left")
  automatically "mousedoubleclick #{mouse_button_translate(btn)}"
end

#drag(*options) ⇒ Object



154
155
156
157
158
# File 'lib/castanaut/os/mac_os_x.rb', line 154

def drag(*options)
  options = combine_options(*options)
  apply_offset(options)
  automatically "mousedrag #{options[:to][:left]} #{options[:to][:top]}"
end

#execute_applescript(scpt) ⇒ Object

Runs an applescript from a string. Returns the result.



282
283
284
285
286
287
# File 'lib/castanaut/os/mac_os_x.rb', line 282

def execute_applescript(scpt)
  File.open(FILE_APPLESCRIPT, 'w') {|f| f.write(scpt)}
  result = run("osascript #{FILE_APPLESCRIPT}")
  File.unlink(FILE_APPLESCRIPT)
  result
end

#hit(key, *modifiers) ⇒ Object

Does not support modifiers (shift, ctrl, etc)



34
35
36
37
# File 'lib/castanaut/os/mac_os_x.rb', line 34

def hit(key, *modifiers)
  not_supported "modifier keys for 'hit'"  unless modifiers.empty?
  automatically "hit #{key}"
end

#keystroke(character, *special_keys) ⇒ Object

Hit a command key combo toward the currently active application.

Use any combination of “command”, “option”, “control”, “shift”. (“command” is the default).

Case matters! It’s easiest to use lowercase, then “shift” if needed.

keystroke "t"                     # COMMAND-t
keystroke "k", "control", "shift" # A combo


50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/castanaut/os/mac_os_x.rb', line 50

def keystroke(character, *special_keys)
  special_keys = ["command"] if special_keys.length == 0
  special_keys_as_applescript_array = special_keys.map { |k|
    "#{k} down"
  }.join(", ")
  execute_applescript(%Q'
    tell application "System Events"
      set frontApp to name of first item of (processes whose frontmost is true)
      tell application frontApp
        keystroke "#{character}" using {#{special_keys_as_applescript_array}}
      end
    end tell
  ')
end

#launch(app_name, *options) ⇒ Object Also known as: activate

The method will also look for application-specific commands for ensuring that a window is open & positioning that window. These methods should be named ensure_window_for_app_name and positioning_for_app_name respectively. So, if you launch the “Address Book” application, the ensure_window_for_address_book and positioning_for_address_book methods will be used.

See Plugin::Safari#ensure_window_for_safari for an example.



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/castanaut/os/mac_os_x.rb', line 174

def launch(app_name, *options)
  options = combine_options(*options)

  ensure_window = nil
  begin
    ensure_window = send("ensure_window_for_#{ app_name.downcase }")
  rescue
  end
  ensure_window ||= ""

  positioning = nil
  begin
    positioning = send("positioning_for_#{ app_name.downcase }")
  rescue
  end
  unless positioning
    if options[:to]
      pos = "#{options[:to][:left]}, #{options[:to][:top]}"
      dims = "#{options[:to][:left] + options[:to][:width]}, " +
        "#{options[:to][:top] + options[:to][:height]}"
      if options[:to][:width]
        positioning = "set bounds of front window to {#{pos}, #{dims}}"
      else
        positioning = "set position of front window to {#{pos}}"
      end
    end
  end

  execute_applescript(%Q`
    tell application "#{app_name}"
      activate
      #{ensure_window}
      #{positioning}
    end tell
  `)
end

#mousedown(btn = "left") ⇒ Object



144
145
146
# File 'lib/castanaut/os/mac_os_x.rb', line 144

def mousedown(btn = "left")
  automatically "mousedown #{mouse_button_translate(btn)}"
end

#mouseup(btn = "left") ⇒ Object



149
150
151
# File 'lib/castanaut/os/mac_os_x.rb', line 149

def mouseup(btn = "left")
  automatically "mouseup #{mouse_button_translate(btn)}"
end

#say(narrative) ⇒ Object

Use MacOS’s native text-to-speech functionality to emulate a human voice saying the narrative text.



293
294
295
# File 'lib/castanaut/os/mac_os_x.rb', line 293

def say(narrative)
  run(%Q`say "#{escape_dq(narrative)}"`)  unless ENV['SHHH']
end

#screen_sizeObject

Returns a region hash describing the entire screen area. (May be wonky for multi-monitor set-ups.)



217
218
219
220
221
222
223
224
225
# File 'lib/castanaut/os/mac_os_x.rb', line 217

def screen_size
  coords = execute_applescript(%Q`
    tell application "Finder"
      get bounds of window of desktop
    end tell
  `)
  coords = coords.split(", ").collect {|c| c.to_i}
  to(*coords)
end

#tripleclick(btn = "left") ⇒ Object



139
140
141
# File 'lib/castanaut/os/mac_os_x.rb', line 139

def tripleclick(btn = "left")
  automatically "mousetripleclick #{mouse_button_translate(btn)}"
end

#type(str, opts = {}) ⇒ Object

If you pass :applescript => true, the AppleScript technique for typing will be used. In this way you can use the :speed option —it’s not supported by the main (osxautomation) technique.



70
71
72
73
74
75
76
# File 'lib/castanaut/os/mac_os_x.rb', line 70

def type(str, opts = {})
  if opts.delete(:applescript)
    type_via_applescript(str, opts)
  else
    automatically "type #{str}"
  end
end

#type_via_applescript(str, opts = {}) ⇒ Object

The alternative typing method for Mac OS X - lets you set the typomatic rate with the :speed option.



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/castanaut/os/mac_os_x.rb', line 82

def type_via_applescript(str, opts = {})
  opts[:speed] = 50 unless !opts[:speed].nil?
  opts[:speed] = opts[:speed] / 1000.0

  full_str = ""
  str.split("").each do |a|
    a.gsub!(/"/, '\"')
    full_str += "delay #{opts[:speed]}\n" if !full_str.empty?
    full_str += "keystroke \"#{a}\"\n"
  end
  cmd = %Q'
      tell application "System Events"
        set frontApp to name of first item of (processes whose frontmost is true)
        tell application frontApp
          #{full_str}
        end
      end tell
  '
  execute_applescript cmd
  str
end