sikuli 0.1.4 → 0.1.5

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.
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