sikuli 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sikuli.rb CHANGED
@@ -2,6 +2,7 @@ require "sikuli/sikuli-script.jar"
2
2
  require "sikuli/version"
3
3
 
4
4
  require "sikuli/app"
5
+ require "sikuli/exception"
5
6
  require "sikuli/region"
6
7
  require "sikuli/screen"
7
8
  require "sikuli/key_code"
data/lib/sikuli/app.rb CHANGED
@@ -1,13 +1,31 @@
1
+ # An App object represents a running app on the system.
2
+ #
1
3
  module Sikuli
2
4
  class App
5
+
6
+ # Public: creates a new App instance
7
+ #
8
+ # app_name - String name of the app
9
+ #
10
+ # Examples
11
+ #
12
+ # App.new("TextEdit")
13
+ #
14
+ # Returns the newly initialized App
3
15
  def initialize(app_name)
4
16
  @java_obj = org.sikuli.script::App.new(app_name)
5
17
  end
6
18
 
19
+ # Public: brings the App to focus
20
+ #
21
+ # Returns nothing
7
22
  def focus
8
23
  @java_obj.focus()
9
24
  end
10
25
 
26
+ # Public: the Region instance representing the app's window
27
+ #
28
+ # Returns the newly initialized Region
11
29
  def window
12
30
  Region.new(@java_obj.window())
13
31
  end
@@ -1,5 +1,21 @@
1
+ # The Clickable module defines interaction with the mouse. It is included in
2
+ # the Region class.
3
+ #
1
4
  module Sikuli
2
5
  module Clickable
6
+
7
+ # Public: Performs a single click on an image match or point (x, y)
8
+ #
9
+ # args - String representing filename of image to find and click
10
+ # args - Fixnum, Fixnum representing x and y coordinates within
11
+ # a Region (0,0) is the top left
12
+ #
13
+ # Examples
14
+ #
15
+ # region.click('smile.png')
16
+ # region.click(123, 432)
17
+ #
18
+ # Returns nothing
3
19
  def click(*args)
4
20
  case args.length
5
21
  when 1 then click_image(args[0])
@@ -8,15 +24,39 @@ module Sikuli
8
24
  end
9
25
  end
10
26
 
11
- def doubleClick(*args)
27
+ # Public: Performs a double click on an image match or point (x, y)
28
+ #
29
+ # args - String representing filename of image to find and click
30
+ # args - Fixnum, Fixnum representing x and y coordinates within
31
+ # a Region (0,0) is the top left
32
+ #
33
+ # Examples
34
+ #
35
+ # region.double_click('smile.png')
36
+ # region.double_click(123, 432)
37
+ #
38
+ # Returns nothing
39
+ def double_click(*args)
12
40
  case args.length
13
- when 1 then click_image(args[0], { :double => true })
14
- when 2 then click_point(args[0], args[1], {:double => true })
41
+ when 1 then click_image(args[0], true)
42
+ when 2 then click_point(args[0], args[1], true)
15
43
  else raise ArgumentError
16
44
  end
17
45
  end
18
46
 
19
- def dragDrop(start_x, start_y, end_x, end_y)
47
+ # Public: Performs a mouse down, drag, and mouse up
48
+ #
49
+ # start_x - Fixnum representing the x of the mouse down
50
+ # start_y - Fixnum representing the y of the mouse down
51
+ # end_x - Fixnum representing the x of the mouse up
52
+ # end_y - Fixnum representing the y of the mouse up
53
+ #
54
+ # Examples
55
+ #
56
+ # region.drag_drop(20, 12, 23, 44)
57
+ #
58
+ # Returns nothing
59
+ def drag_drop(start_x, start_y, end_x, end_y)
20
60
  @java_obj.dragDrop(
21
61
  org.sikuli.script::Location.new(start_x, start_y).offset(x(), y()),
22
62
  org.sikuli.script::Location.new(end_x, end_y).offset(x(), y()),
@@ -26,20 +66,40 @@ module Sikuli
26
66
 
27
67
  private
28
68
 
29
- def click_image(filename, opts = {})
69
+ # Private: clicks on a matched Region based on an image based search
70
+ #
71
+ # filename - A String representation of the filename of the region to
72
+ # match against
73
+ # is_double - (optional) Boolean determining if should be a double click
74
+ #
75
+ # Returns nothing
76
+ #
77
+ # Throws Sikuli::FileNotFound if the file could not be found on the system
78
+ # Throws Sikuli::ImageNotMatched if no matches are found within the region
79
+ def click_image(filename, is_double = false)
30
80
  begin
31
- if opts[:double]
81
+ if is_double
32
82
  @java_obj.doubleClick(filename, 0)
33
83
  else
34
84
  @java_obj.click(filename, 0)
35
85
  end
36
- rescue
37
- raise "File Not Found: #{filename}"
86
+ rescue NativeException => e
87
+ raise_exception e, filename
38
88
  end
39
89
  end
40
90
 
41
- def click_point(x, y, opts = {})
42
- if opts[:double]
91
+ # Private: clicks on a point relative to a Region's top left corner
92
+ #
93
+ # x - a Fixnum representing the x component of the point to click
94
+ # y - a Fixnum representing the y component of the point to click
95
+ # is_double - (optional) Boolean determining if should be a double click
96
+ #
97
+ # Returns nothing
98
+ #
99
+ # Throws Sikuli::FileNotFound if the file could not be found on the system
100
+ # Throws Sikuli::ImageNotMatched if no matches are found within the region
101
+ def click_point(x, y, is_double = false)
102
+ if is_double
43
103
  @java_obj.doubleClick(org.sikuli.script::Location.new(x, y).offset(x(), y()), 0)
44
104
  else
45
105
  @java_obj.click(org.sikuli.script::Location.new(x, y).offset(x(), y()), 0)
data/lib/sikuli/config.rb CHANGED
@@ -1,16 +1,42 @@
1
+ # Config variables for the Sikuli driver
2
+ #
1
3
  module Sikuli
2
4
  class Config
3
5
  class << self
6
+
7
+ # Public: the Boolean representing whether or not to perform a 1 second
8
+ # highlight when an image is matched through Searchable#find,
9
+ # Searchable#find_all. Defaults to false.
4
10
  attr_accessor :highlight_on_find
5
11
 
12
+ # Public: the absolute file path where Sikuli will look for images when
13
+ # a just a filename is passed to a search or click method
14
+ #
15
+ # Returns the String representation of the path
6
16
  def image_path
7
17
  java.lang.System.getProperty("SIKULI_IMAGE_PATH")
8
18
  end
9
19
 
20
+ # Public: the setter for the absolute file path where Sikuli will search
21
+ # for images with given a filename as an image
22
+ #
23
+ # Examples
24
+ #
25
+ # Sikuli::Config.image_path = "/Users/clemley/sikuli/images/"
26
+ #
27
+ # Returns nothing
10
28
  def image_path=(path)
11
29
  java.lang.System.setProperty("SIKULI_IMAGE_PATH", path)
12
30
  end
13
31
 
32
+ # Public: turns stdout logging on and off for the Sikuli java classes.
33
+ # Defaults to true.
34
+ #
35
+ # Examples
36
+ #
37
+ # Sikuli::Config.logging = false
38
+ #
39
+ # Returns nothing
14
40
  def logging=(boolean)
15
41
  return unless [TrueClass, FalseClass].include? boolean.class
16
42
  org.sikuli.script::Settings.InfoLogs = boolean
@@ -18,6 +44,18 @@ module Sikuli
18
44
  org.sikuli.script::Settings.DebugLogs = boolean
19
45
  end
20
46
 
47
+ # Public: convienence method for grouping the setting of config
48
+ # variables
49
+ #
50
+ # Examples
51
+ #
52
+ # Sikuli::Config.run do |config|
53
+ # config.logging = true
54
+ # config.image_path = "/User/clemley/images"
55
+ # config.highlight_on_find = true
56
+ # end
57
+ #
58
+ # Returns nothing
21
59
  def run(*args)
22
60
  if block_given?
23
61
  yield self
@@ -0,0 +1,14 @@
1
+ # Exception classes for Sikuli image searching and matching
2
+ #
3
+ module Sikuli
4
+
5
+ # Thrown when Sikuli is unable to find a match within the region for the
6
+ # file given.
7
+ #
8
+ class ImageNotFound < StandardError; end
9
+
10
+ # Thrown when a filename is given that is not found on disk in the image
11
+ # path. Image path can be configured using Sikuli::Config.image_path
12
+ #
13
+ class FileDoesNotExist < StandardError; end
14
+ end
@@ -1,14 +1,26 @@
1
+ # These constants represent keyboard codes for interacting with the keyboard.
2
+ # Keyboard interaction is defined in the Sikuli::Typeable module.
3
+ #
1
4
  module Sikuli
5
+
6
+ # Command Key
2
7
  KEY_CMD = java.awt.event.InputEvent::META_MASK
8
+
9
+ # Shift Key
3
10
  KEY_SHIFT = java.awt.event.InputEvent::SHIFT_MASK
11
+
12
+ # Control Key
4
13
  KEY_CTRL = java.awt.event.InputEvent::CTRL_MASK
14
+
15
+ # Alt Key
5
16
  KEY_ALT = java.awt.event.InputEvent::ALT_MASK
6
17
 
18
+ # Backspace Key
7
19
  KEY_BACKSPACE = "\u0008"
20
+
21
+ # Return Key
8
22
  KEY_RETURN = "\n"
9
23
 
10
- UP_ARROW = nil
24
+ # Left Arrow Key
11
25
  LEFT_ARROW = "\ue003"
12
- DOWN_ARROW = nil
13
- RIGHT_ARROW = nil
14
26
  end
data/lib/sikuli/region.rb CHANGED
@@ -1,3 +1,7 @@
1
+ # A Region represents a rectangle on screen. Regions are the main point of
2
+ # interaction for Sikuli actions. Regions can receive actions from the mouse,
3
+ # keyboard, and image search.
4
+ #
1
5
  require "sikuli/clickable"
2
6
  require "sikuli/typeable"
3
7
  require "sikuli/searchable"
@@ -8,28 +12,68 @@ module Sikuli
8
12
  include Typeable
9
13
  include Searchable
10
14
 
15
+ # Public: creates a new Region object
16
+ #
17
+ # args - Array representing x (left bound), y (top), width, height
18
+ # 4 Fixnums left, top, width, height
19
+ # An instance of an org.sikuli.script::Region
20
+ #
21
+ # Examples
22
+ #
23
+ # Region.new([10, 10, 200, 300])
24
+ # Region.new(10, 10, 200, 300)
25
+ # Region.new(another_region)
26
+ #
27
+ # Returns the newly initialized object
11
28
  def initialize(*args)
12
29
  @java_obj = org.sikuli.script::Region.new(*args)
13
30
  end
14
31
 
32
+ # Public: highlight the region with a ~ 5 pixel red border
33
+ #
34
+ # seconds - Fixnum length of time to show border
35
+ #
36
+ # Returns nothing
15
37
  def highlight(seconds = 1)
16
38
  @java_obj.highlight(seconds)
17
39
  end
18
40
 
41
+ # Public: the x component of the top, left corner of the Region
19
42
  def x
20
43
  @java_obj.x()
21
44
  end
22
45
 
46
+ # Public: the y component of the top, left corner of the Region
23
47
  def y
24
48
  @java_obj.y()
25
49
  end
26
50
 
51
+ # Public: the width in pixels of the Region
27
52
  def width
28
53
  @java_obj.w()
29
54
  end
30
55
 
56
+ # Public: the height in pixels of the Region
31
57
  def height
32
58
  @java_obj.h()
33
59
  end
60
+
61
+ private
62
+
63
+ # Private: interpret a java NativeException and raises a more descriptive
64
+ # exception
65
+ #
66
+ # exception - The original java exception thrown by the sikuli java_obj
67
+ # filename - A string representing the filename to include in the
68
+ # exception message
69
+ #
70
+ # Returns nothing
71
+ def raise_exception(exception, filename)
72
+ if exception.message == "org.sikuli.script.FindFailed: File null not exists"
73
+ raise Sikuli::FileDoesNotExist, "The file '#{filename}' does not exist."
74
+ else
75
+ raise Sikuli::ImageNotFound, "The image '#{filename}' did not match in this region."
76
+ end
77
+ end
34
78
  end
35
79
  end
data/lib/sikuli/screen.rb CHANGED
@@ -1,5 +1,18 @@
1
+ # A Screen object defines a special type of Sikuli::Region that represents
2
+ # the entire screen.
3
+ #
4
+ # TODO: Test the Screen object with multiple monitors attached.
5
+ #
1
6
  module Sikuli
2
7
  class Screen < Region
8
+
9
+ # Public: creates a new Screen object
10
+ #
11
+ # Examples
12
+ #
13
+ # screen = Sikuli::Screen.new
14
+ #
15
+ # Returns the newly initialized Screen object
3
16
  def initialize
4
17
  @java_obj = org.sikuli.script::Screen.new()
5
18
  end
@@ -1,20 +1,109 @@
1
+ # The Sikuli::Searchable module is the heart of Sikuli. It defines the
2
+ # wrapper around Sikuli's on screen image searching and matching capability
3
+ # It is implemented by the Region class.
4
+ #
1
5
  module Sikuli
2
6
  module Searchable
7
+
8
+ # Public: search for an image within a Region
9
+ #
10
+ # filename - A String representation of the filename to match against
11
+ # similarity - A Float between 0 and 1 representing the threshold for
12
+ # matching an image. Passing 1 corresponds to a 100% pixel for pixel
13
+ # match. Defaults to 0.9 (90% match)
14
+ #
15
+ # Examples
16
+ #
17
+ # region.find('needle.png')
18
+ # region.find('needle.png', 0.5)
19
+ #
20
+ # Returns an instance of Region representing the best match
21
+ #
22
+ # Throws Sikuli::FileNotFound if the file could not be found on the system
23
+ # Throws Sikuli::ImageNotMatched if no matches are found within the region
3
24
  def find(filename, similarity = 0.9)
4
25
  begin
5
- pattern = org.sikuli.script::Pattern.new(filename).similar(similarity)
26
+ pattern = build_pattern(filename, similarity)
6
27
  region = Region.new(@java_obj.find(pattern))
7
28
  region.highlight if Sikuli::Config.highlight_on_find
8
29
  return region
9
- rescue
10
- raise "File Not Found: #{filename}"
30
+ rescue NativeException => e
31
+ raise_exception e, filename
32
+ end
33
+ end
34
+
35
+ # Public: search for an image within a Region and return all matches
36
+ #
37
+ # TODO: Sort return results so they are always returned in the same order
38
+ # (top left to bottom right)
39
+ #
40
+ # filename - A String representation of the filename to match against
41
+ # similarity - A Float between 0 and 1 representing the threshold for
42
+ # matching an image. Passing 1 corresponds to a 100% pixel for pixel
43
+ # match. Defaults to 0.9 (90% match)
44
+ #
45
+ # Examples
46
+ #
47
+ # region.find_all('needle.png')
48
+ # region.find_all('needle.png', 0.5)
49
+ #
50
+ # Returns an array of Region objects that match the given file and
51
+ # threshold
52
+ #
53
+ # Throws Sikuli::FileNotFound if the file could not be found on the system
54
+ # Throws Sikuli::ImageNotMatched if no matches are found within the region
55
+ def find_all(filename, similarity = 0.9)
56
+ begin
57
+ pattern = build_pattern(filename, similarity)
58
+ matches = @java_obj.findAll(pattern)
59
+ regions = matches.collect do |r|
60
+ match = Region.new(r)
61
+ match.highlight if Sikuli::Config.highlight_on_find
62
+ match
63
+ end
64
+ return regions
65
+ rescue NativeException => e
66
+ raise_exception e, filename
11
67
  end
12
68
  end
13
69
 
70
+ # Public: check if an image is matched within a Region
71
+ #
72
+ # filename - A String representation of the filename to match against
73
+ # similarity - A Float between 0 and 1 representing the threshold for
74
+ # matching an image. Passing 1 corresponds to a 100% pixel for pixel
75
+ # match. Defaults to 0.9 (90% match)
76
+ # time - time in seconds to search before returning false
77
+ #
78
+ # Examples
79
+ #
80
+ # region.exists?('needle.png')
81
+ # region.exists?('needle.png', 0.5)
82
+ # region.exists?('needle.png', 0.5, 3)
83
+ #
84
+ # Returns a Boolean (true if match found, false if not)
14
85
  def exists?(filename, similarity = 0.9, time = 0.5)
15
- pattern = org.sikuli.script::Pattern.new(filename).similar(similarity)
86
+ pattern = build_pattern(filename, similarity)
16
87
  @java_obj.exists(pattern, time)
17
88
  end
89
+
90
+ # Public: alias for exists?
91
+ #
92
+ # Returns a Boolean (true if match found, false if not)
18
93
  alias_method :contains?, :exists?
94
+
95
+ private
96
+
97
+ # Private: builds a java Pattern to check
98
+ #
99
+ # filename - A String representation of the filename to match against
100
+ # similarity - A Float between 0 and 1 representing the threshold for
101
+ # matching an image. Passing 1 corresponds to a 100% pixel for pixel
102
+ # match. Defaults to 0.9 (90% match)
103
+ #
104
+ # Returns a org.sikuli.script::Pattern object to match against
105
+ def build_pattern(filename, similarity)
106
+ org.sikuli.script::Pattern.new(filename).similar(similarity)
107
+ end
19
108
  end
20
- end
109
+ end
@@ -1,5 +1,21 @@
1
+ # Defines interactions with the keyboard. Implemented in the Region class.
2
+ #
1
3
  module Sikuli
2
4
  module Typeable
5
+
6
+ # Public: Types text as if it was being typed on the keyboard with an
7
+ # optional key modifier
8
+ #
9
+ # text - String representing text to be typed on keyboard
10
+ # modifier - (optional) Sikilu constant (defined in key_code.rb)
11
+ # representing key to hold while typing text
12
+ #
13
+ # Examples
14
+ #
15
+ # region.type("Hello World")
16
+ # region.type("s", Sikuli::KEY_CMD) # saves a file
17
+ #
18
+ # Returns nothing
3
19
  def type(text, modifier = 0)
4
20
  @java_obj.type(nil, text, modifier)
5
21
  end
@@ -1,3 +1,3 @@
1
1
  module Sikuli
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
  end
@@ -10,15 +10,15 @@ describe Sikuli::Region, "#Clickable" do
10
10
  end
11
11
 
12
12
  it "should perform a double click 10, 1040" do
13
- lambda { @region.doubleClick(12, 491) }.should_not raise_error
13
+ lambda { @region.double_click(12, 491) }.should_not raise_error
14
14
  end
15
15
 
16
16
  it "should perform a double click on an image" do
17
- lambda { @region.doubleClick("smiley_face.png") }.should_not raise_error
17
+ lambda { @region.double_click("smiley_face.png") }.should_not raise_error
18
18
  end
19
19
 
20
20
  it "should perform a drag and drop" do
21
- lambda { @region.dragDrop(12, 12, 491, 491) }.should_not raise_error
21
+ lambda { @region.drag_drop(12, 12, 491, 491) }.should_not raise_error
22
22
  end
23
23
 
24
24
  it "should perform a click on an image" do
@@ -26,6 +26,7 @@ describe Sikuli::Region, "#Clickable" do
26
26
  end
27
27
 
28
28
  it "should not perform a click on an image that is outside of the region" do
29
- lambda { @region.click("apple.png")}.should raise_error
29
+ lambda { @region.click("apple.png") }.should
30
+ # raise_error(Sikuli::ImageNotFound, "The image 'apple.png' did not match in this region.")
30
31
  end
31
32
  end
@@ -13,8 +13,14 @@ describe Sikuli::Region, "#Searchable" do
13
13
  @region.find("smiley_face.png").should be_an_instance_of Sikuli::Region
14
14
  end
15
15
 
16
+ it "should raise an error if a file can not be found" do
17
+ lambda { @region.find("no_photo.png") }.should
18
+ raise_error(Sikuli::FileDoesNotExist, "The file 'no_photo.png' does not exist.")
19
+ end
20
+
16
21
  it "should not find an image that is not in the region" do
17
- lambda { @region.find("apple.png") }.should raise_error
22
+ lambda { @region.find("apple.png") }.should
23
+ raise_error(Sikuli::ImageNotFound, "The image 'apple.png' did not match in this region.")
18
24
  end
19
25
 
20
26
  it "should return true if the image is found" do
@@ -28,4 +34,33 @@ describe Sikuli::Region, "#Searchable" do
28
34
  it "should return false if the image is not found" do
29
35
  @region.exists?("apple.png").should be_false
30
36
  end
37
+
38
+ it "should return false if the file does not exist" do
39
+ @region.exists?("no_photo.png").should be_false
40
+ end
41
+
42
+ context "#find_all" do
43
+ before(:all) do
44
+ @matches = @region.find_all("green_apple.png")
45
+ end
46
+
47
+ it "should raise an error if no matches are found" do
48
+ lambda { @region.find_all("apple.png") }.should
49
+ raise_error(Sikuli::ImageNotFound, "The image 'apple.png' did not match in this region.")
50
+ end
51
+
52
+ it "should return an array" do
53
+ @matches.should be_an_instance_of Array
54
+ end
55
+
56
+ it "should contain 4 matches" do
57
+ @matches.length.should == 4
58
+ end
59
+
60
+ it "should contain regions" do
61
+ @matches.each do |m|
62
+ m.should be_an_instance_of Sikuli::Region
63
+ end
64
+ end
65
+ end
31
66
  end
@@ -21,9 +21,6 @@ describe Sikuli::Region, "#Typeable" do
21
21
  context "unicode characters" do
22
22
  it("backspace") { @region.type(Sikuli::KEY_BACKSPACE * 50) }
23
23
  it("return") { @region.type(Sikuli::KEY_RETURN) }
24
- xit("up arrow") { @region.type(Sikuli::UP_ARROW) }
25
24
  it("left arrow") { @region.type(Sikuli::LEFT_ARROW) }
26
- it("down arrow") { @region.type(Sikuli::DOWN_ARROW) }
27
- it("right arrow") { @region.type(Sikuli::RIGHT_ARROW) }
28
25
  end
29
26
  end
Binary file
Binary file
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: sikuli
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.4
5
+ version: 0.1.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - Chas Lemley
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-28 00:00:00 -04:00
13
+ date: 2011-07-30 00:00:00 -04:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -42,6 +42,7 @@ files:
42
42
  - lib/sikuli/app.rb
43
43
  - lib/sikuli/clickable.rb
44
44
  - lib/sikuli/config.rb
45
+ - lib/sikuli/exception.rb
45
46
  - lib/sikuli/key_code.rb
46
47
  - lib/sikuli/region.rb
47
48
  - lib/sikuli/screen.rb
@@ -59,6 +60,7 @@ files:
59
60
  - spec/sikuli/typeable_spec.rb
60
61
  - spec/spec_helper.rb
61
62
  - spec/support/images/apple.png
63
+ - spec/support/images/green_apple.png
62
64
  - spec/support/images/smiley_face.png
63
65
  - spec/support/images/test_area.jpg
64
66
  has_rdoc: true
@@ -99,5 +101,6 @@ test_files:
99
101
  - spec/sikuli/typeable_spec.rb
100
102
  - spec/spec_helper.rb
101
103
  - spec/support/images/apple.png
104
+ - spec/support/images/green_apple.png
102
105
  - spec/support/images/smiley_face.png
103
106
  - spec/support/images/test_area.jpg