deskbot 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/CHANGELOG.md +5 -0
- data/Cargo.lock +966 -0
- data/Cargo.toml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +236 -0
- data/Rakefile +18 -0
- data/ext/deskbot/Cargo.toml +16 -0
- data/ext/deskbot/extconf.rb +6 -0
- data/ext/deskbot/src/alert.rs +5 -0
- data/ext/deskbot/src/bitmap.rs +268 -0
- data/ext/deskbot/src/keys.rs +38 -0
- data/ext/deskbot/src/lib.rs +49 -0
- data/ext/deskbot/src/mouse.rs +55 -0
- data/ext/deskbot/src/screen.rs +34 -0
- data/lib/deskbot/area.rb +12 -0
- data/lib/deskbot/bitmap.rb +89 -0
- data/lib/deskbot/color.rb +36 -0
- data/lib/deskbot/point.rb +10 -0
- data/lib/deskbot/providers/autopilot/bitmap.rb +21 -0
- data/lib/deskbot/providers/autopilot.rb +28 -0
- data/lib/deskbot/screen.rb +131 -0
- data/lib/deskbot/size.rb +10 -0
- data/lib/deskbot/types.rb +30 -0
- data/lib/deskbot/version.rb +5 -0
- data/lib/deskbot.rb +28 -0
- data/sig/deskbot.rbs +4 -0
- metadata +132 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
extern crate autopilot;
|
2
|
+
use std::collections::HashMap;
|
3
|
+
|
4
|
+
fn button(symbol: String) -> autopilot::mouse::Button {
|
5
|
+
match symbol.as_str() {
|
6
|
+
"left" => autopilot::mouse::Button::Left,
|
7
|
+
"middle" => autopilot::mouse::Button::Middle,
|
8
|
+
"right" => autopilot::mouse::Button::Right,
|
9
|
+
_ => panic!("Invalid button"),
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
fn scroll_direction(symbol: String) -> autopilot::mouse::ScrollDirection {
|
14
|
+
match symbol.as_str() {
|
15
|
+
"up" => autopilot::mouse::ScrollDirection::Up,
|
16
|
+
"down" => autopilot::mouse::ScrollDirection::Down,
|
17
|
+
_ => panic!("Invalid scroll direction"),
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
pub fn location() -> HashMap<String, f64> {
|
22
|
+
let point = autopilot::mouse::location();
|
23
|
+
return HashMap::from([("x".to_string(), point.x), ("y".to_string(), point.y)]);
|
24
|
+
}
|
25
|
+
|
26
|
+
pub fn move_to(x: f64, y: f64) -> bool {
|
27
|
+
let command = autopilot::mouse::move_to(autopilot::geometry::Point::new(x, y));
|
28
|
+
match command {
|
29
|
+
Ok(_) => true,
|
30
|
+
Err(_) => false,
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
pub fn smooth_move(x: f64, y: f64, duration: Option<f64>) -> bool {
|
35
|
+
let command = autopilot::mouse::smooth_move(autopilot::geometry::Point::new(x, y), duration);
|
36
|
+
|
37
|
+
match command {
|
38
|
+
Ok(_) => true,
|
39
|
+
Err(_) => false,
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
pub fn toggle(_button: String, down: bool) -> () {
|
44
|
+
let button = button(_button);
|
45
|
+
autopilot::mouse::toggle(button, down);
|
46
|
+
}
|
47
|
+
|
48
|
+
pub fn click(_button: String, delay_ms: Option<u64>) -> () {
|
49
|
+
let button = button(_button);
|
50
|
+
autopilot::mouse::click(button, delay_ms);
|
51
|
+
}
|
52
|
+
|
53
|
+
pub fn scroll(direction: String, clicks: u32) -> () {
|
54
|
+
autopilot::mouse::scroll(scroll_direction(direction), clicks);
|
55
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
extern crate autopilot;
|
2
|
+
use std::collections::HashMap;
|
3
|
+
|
4
|
+
pub fn get_color(x: f64, y: f64) -> Option<Vec<u8>> {
|
5
|
+
let color = autopilot::screen::get_color(autopilot::geometry::Point::new(x, y));
|
6
|
+
match color {
|
7
|
+
Ok(color) => Some(color.0.to_vec()),
|
8
|
+
Err(_) => None
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
pub fn size() -> HashMap<String, f64> {
|
13
|
+
let size = autopilot::screen::size();
|
14
|
+
|
15
|
+
HashMap::from([
|
16
|
+
("width".to_string(), size.width),
|
17
|
+
("height".to_string(), size.height)
|
18
|
+
])
|
19
|
+
}
|
20
|
+
|
21
|
+
pub fn scale() -> f64 {
|
22
|
+
autopilot::screen::scale()
|
23
|
+
}
|
24
|
+
|
25
|
+
pub fn is_point_visible(x: f64, y: f64) -> bool {
|
26
|
+
let point = autopilot::geometry::Point::new(x, y);
|
27
|
+
autopilot::screen::is_point_visible(point)
|
28
|
+
}
|
29
|
+
|
30
|
+
pub fn is_rect_visible(x: f64, y: f64, width: f64, height: f64) -> bool {
|
31
|
+
let point = autopilot::geometry::Point::new(x, y);
|
32
|
+
let size = autopilot::geometry::Size::new(width, height);
|
33
|
+
autopilot::screen::is_rect_visible(autopilot::geometry::Rect::new(point, size))
|
34
|
+
}
|
data/lib/deskbot/area.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deskbot
|
4
|
+
class Bitmap
|
5
|
+
include Dry::Monads[:result]
|
6
|
+
include Dry::Matcher.for(
|
7
|
+
:find_color,
|
8
|
+
:find,
|
9
|
+
with: Dry::Matcher::ResultMatcher
|
10
|
+
)
|
11
|
+
|
12
|
+
Rgba = Types::Array
|
13
|
+
.of(Types::Integer.constrained(gteq: 0, lteq: 255))
|
14
|
+
.constrained(size: 4)
|
15
|
+
|
16
|
+
def initialize(provider)
|
17
|
+
@provider = provider
|
18
|
+
end
|
19
|
+
|
20
|
+
def save(image_path)
|
21
|
+
@provider.save(Types::String[image_path])
|
22
|
+
end
|
23
|
+
|
24
|
+
def bounds
|
25
|
+
Area.new(@provider.bounds)
|
26
|
+
end
|
27
|
+
|
28
|
+
def color_at(x, y) # rubocop:disable Naming/MethodParameterName
|
29
|
+
red, green, blue, alpha = @provider.color_at(x, y)
|
30
|
+
Color.new(red:, green:, blue:, alpha:)
|
31
|
+
end
|
32
|
+
|
33
|
+
def eql?(image_path, tolerance: nil)
|
34
|
+
@provider.bitmap_eq(
|
35
|
+
Types::String[image_path],
|
36
|
+
Types::Float.optional[tolerance]
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def find(image_path, tolerance: nil)
|
41
|
+
result = @provider.find(
|
42
|
+
Types::String[image_path],
|
43
|
+
Types::Float.optional[tolerance]
|
44
|
+
)
|
45
|
+
|
46
|
+
if result
|
47
|
+
Success(Point.new(result))
|
48
|
+
else
|
49
|
+
Failure(:not_found)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_color(color, tolerance: nil)
|
54
|
+
found = @provider.find_color(
|
55
|
+
Rgba[color],
|
56
|
+
Types::Float.optional[tolerance]
|
57
|
+
)
|
58
|
+
|
59
|
+
if found
|
60
|
+
Success(Point.new(found))
|
61
|
+
else
|
62
|
+
Failure(:not_found)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def all(image_path, tolerance: nil)
|
67
|
+
@provider.all(
|
68
|
+
Types::String[image_path],
|
69
|
+
Types::Float.optional[tolerance]
|
70
|
+
)
|
71
|
+
.map { |point| Point.new(point) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def all_color(color, tolerance: nil)
|
75
|
+
@provider.all_color(
|
76
|
+
Rgba[color],
|
77
|
+
Types::Float.optional[tolerance]
|
78
|
+
)
|
79
|
+
.map { |point| Point.new(point) }
|
80
|
+
end
|
81
|
+
|
82
|
+
def count(image_path, tolerance: nil)
|
83
|
+
@provider.count(
|
84
|
+
Types::String[image_path],
|
85
|
+
Types::Float.optional[tolerance]
|
86
|
+
)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deskbot
|
4
|
+
class Color < Dry::Struct
|
5
|
+
attribute :red, Types::Integer
|
6
|
+
attribute :green, Types::Integer
|
7
|
+
attribute :blue, Types::Integer
|
8
|
+
attribute :alpha, Types::Integer
|
9
|
+
|
10
|
+
transform_keys do |key|
|
11
|
+
{
|
12
|
+
"r" => :red,
|
13
|
+
"g" => :green,
|
14
|
+
"b" => :blue,
|
15
|
+
"a" => :alpha
|
16
|
+
# rubocop:enable Style/StringHashKeys
|
17
|
+
}.fetch(key, key)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_hex(hex)
|
21
|
+
red, green, blue, alpha = hex
|
22
|
+
.match(/^#(..)(..)(..)(..)?$/)
|
23
|
+
.captures
|
24
|
+
.map do |hex_pair|
|
25
|
+
hex_pair&.hex
|
26
|
+
end
|
27
|
+
|
28
|
+
new(
|
29
|
+
red:,
|
30
|
+
green:,
|
31
|
+
blue:,
|
32
|
+
alpha: alpha || 255
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deskbot
|
4
|
+
module Providers
|
5
|
+
module Autopilot
|
6
|
+
class Bitmap # rubocop:disable Lint/EmptyClass
|
7
|
+
# Holds rust autopilot bitmap bindings
|
8
|
+
# See ext/deskbot/src/bitmap.rs for more details
|
9
|
+
#
|
10
|
+
# def bounds
|
11
|
+
# def color_at
|
12
|
+
# def bitmap_eq
|
13
|
+
# def find
|
14
|
+
# def find_color
|
15
|
+
# def all
|
16
|
+
# def all_color
|
17
|
+
# def count
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deskbot
|
4
|
+
module Providers
|
5
|
+
module Autopilot
|
6
|
+
# Holds rust autopilot bindings
|
7
|
+
# See ext/deskbot/src/lib.rs for more details
|
8
|
+
#
|
9
|
+
# def type
|
10
|
+
# def alert
|
11
|
+
# def toggle_key
|
12
|
+
# def tap_key
|
13
|
+
# def mouse_location
|
14
|
+
# def move_mouse
|
15
|
+
# def smooth_move_mouse
|
16
|
+
# def toggle_mouse
|
17
|
+
# def scroll
|
18
|
+
# def click
|
19
|
+
# def color_at
|
20
|
+
# def screen_size
|
21
|
+
# def screen_scale
|
22
|
+
# def is_point_visible
|
23
|
+
# def is_area_visible
|
24
|
+
# def capture_screen
|
25
|
+
# def capture_screen_portion
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deskbot
|
4
|
+
class Screen
|
5
|
+
# This is the API for any provider
|
6
|
+
|
7
|
+
def initialize(provider)
|
8
|
+
@provider = provider
|
9
|
+
end
|
10
|
+
|
11
|
+
def alert(message)
|
12
|
+
@provider.alert(Types::String[message])
|
13
|
+
end
|
14
|
+
|
15
|
+
def type(text, flags: [], wpm: 60.0, noise: 0.0)
|
16
|
+
@provider.type(
|
17
|
+
Types::String[text],
|
18
|
+
Types::Flags[flags],
|
19
|
+
Types::Float[wpm],
|
20
|
+
Types::Float[noise]
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def toggle_key(key, down: true, flags: [], modifier_delay_ms: 0.0)
|
25
|
+
@provider.toggle_key(
|
26
|
+
Types::Character[key],
|
27
|
+
Types::Bool[down],
|
28
|
+
Types::Flags[flags],
|
29
|
+
Types::Float[modifier_delay_ms]
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def tap_key(key, flags: [], delay_ms: 0.0, modifier_delay_ms: 0.0)
|
34
|
+
@provider.tap_key(
|
35
|
+
Types::Character[key],
|
36
|
+
Types::Flags[flags],
|
37
|
+
Types::Float[delay_ms],
|
38
|
+
Types::Float[modifier_delay_ms]
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def mouse_location
|
43
|
+
Point.new(@provider.mouse_location)
|
44
|
+
end
|
45
|
+
|
46
|
+
def move_mouse(x, y) # rubocop:disable Naming/MethodParameterName
|
47
|
+
@provider.move_mouse(
|
48
|
+
Types::Coercible::Float[x],
|
49
|
+
Types::Coercible::Float[y]
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def smooth_move_mouse(x, y, duration: 1) # rubocop:disable Naming/MethodParameterName
|
54
|
+
@provider.smooth_move_mouse(
|
55
|
+
Types::Coercible::Float[x],
|
56
|
+
Types::Coercible::Float[y],
|
57
|
+
Types::Coercible::Float[duration]
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def toggle_mouse(button = "left", down: true)
|
62
|
+
@provider.toggle_mouse(
|
63
|
+
Types::Button[button],
|
64
|
+
Types::Bool[down]
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def click(button = "left", delay_ms: nil)
|
69
|
+
@provider.click(
|
70
|
+
Types::Button[button],
|
71
|
+
Types::Float.optional[delay_ms]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def scroll(direction = "up", clicks: 1)
|
76
|
+
@provider.scroll(
|
77
|
+
Types::ScrollDirection[direction],
|
78
|
+
Types::Integer[clicks]
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def color_at(x, y) # rubocop:disable Naming/MethodParameterName
|
83
|
+
red, green, blue, alpha = @provider.color_at(
|
84
|
+
Types::Coercible::Float[x],
|
85
|
+
Types::Coercible::Float[y]
|
86
|
+
)
|
87
|
+
|
88
|
+
Color.new(red:, green:, blue:, alpha:)
|
89
|
+
end
|
90
|
+
|
91
|
+
def size
|
92
|
+
Size.new(@provider.screen_size)
|
93
|
+
end
|
94
|
+
|
95
|
+
def scale
|
96
|
+
@provider.screen_scale
|
97
|
+
end
|
98
|
+
|
99
|
+
def point_visible?(x, y) # rubocop:disable Naming/MethodParameterName
|
100
|
+
@provider.is_point_visible(
|
101
|
+
Types::Coercible::Float[x],
|
102
|
+
Types::Coercible::Float[y]
|
103
|
+
)
|
104
|
+
end
|
105
|
+
|
106
|
+
def area_visible?(x:, y:, width:, height:) # rubocop:disable Naming/MethodParameterName
|
107
|
+
@provider.is_area_visible(
|
108
|
+
Types::Coercible::Float[x],
|
109
|
+
Types::Coercible::Float[y],
|
110
|
+
Types::Coercible::Float[width],
|
111
|
+
Types::Coercible::Float[height]
|
112
|
+
)
|
113
|
+
end
|
114
|
+
|
115
|
+
def capture
|
116
|
+
bitmap = @provider.capture_screen
|
117
|
+
Deskbot::Bitmap.new(bitmap)
|
118
|
+
end
|
119
|
+
|
120
|
+
def capture_area(x:, y:, width:, height:) # rubocop:disable Naming/MethodParameterName
|
121
|
+
bitmap = @provider.capture_screen_area(
|
122
|
+
Types::Coercible::Float[x],
|
123
|
+
Types::Coercible::Float[y],
|
124
|
+
Types::Coercible::Float[width],
|
125
|
+
Types::Coercible::Float[height]
|
126
|
+
)
|
127
|
+
|
128
|
+
Deskbot::Bitmap.new(bitmap)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/lib/deskbot/size.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Deskbot
|
4
|
+
module Types
|
5
|
+
include Dry.Types(default: :strict)
|
6
|
+
|
7
|
+
Flag = Types::Coercible::String.enum(
|
8
|
+
"shift",
|
9
|
+
"control",
|
10
|
+
"alt",
|
11
|
+
"meta",
|
12
|
+
"help"
|
13
|
+
)
|
14
|
+
|
15
|
+
Button = Types::Coercible::String.enum(
|
16
|
+
"left",
|
17
|
+
"middle",
|
18
|
+
"right"
|
19
|
+
)
|
20
|
+
|
21
|
+
Flags = Types::Array.of(Flag)
|
22
|
+
|
23
|
+
Character = Types::Coercible::String.constrained(size: 1)
|
24
|
+
|
25
|
+
ScrollDirection = Types::Coercible::String.enum(
|
26
|
+
"up",
|
27
|
+
"down"
|
28
|
+
)
|
29
|
+
end
|
30
|
+
end
|
data/lib/deskbot.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/types"
|
4
|
+
require "dry/struct"
|
5
|
+
require "dry/monads"
|
6
|
+
require "dry/matcher/result_matcher"
|
7
|
+
|
8
|
+
require_relative "deskbot/version"
|
9
|
+
require_relative "deskbot/deskbot"
|
10
|
+
require_relative "deskbot/types"
|
11
|
+
require_relative "deskbot/point"
|
12
|
+
require_relative "deskbot/color"
|
13
|
+
require_relative "deskbot/size"
|
14
|
+
require_relative "deskbot/area"
|
15
|
+
require_relative "deskbot/bitmap"
|
16
|
+
|
17
|
+
require "deskbot/providers/autopilot/bitmap"
|
18
|
+
require "deskbot/providers/autopilot"
|
19
|
+
|
20
|
+
require "deskbot/screen"
|
21
|
+
|
22
|
+
module Deskbot
|
23
|
+
class Error < StandardError; end
|
24
|
+
|
25
|
+
def self.screen(provider: Providers::Autopilot)
|
26
|
+
@screen ||= Screen.new(provider)
|
27
|
+
end
|
28
|
+
end
|
data/sig/deskbot.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: deskbot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nolan J Tait
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-05-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dry-matcher
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-monads
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-struct
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dry-types
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
description: Ruby desktop automation
|
70
|
+
email:
|
71
|
+
- nolanjtait@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions:
|
74
|
+
- ext/deskbot/Cargo.toml
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".rspec"
|
78
|
+
- ".rubocop.yml"
|
79
|
+
- CHANGELOG.md
|
80
|
+
- Cargo.lock
|
81
|
+
- Cargo.toml
|
82
|
+
- LICENSE.txt
|
83
|
+
- README.md
|
84
|
+
- Rakefile
|
85
|
+
- ext/deskbot/Cargo.toml
|
86
|
+
- ext/deskbot/extconf.rb
|
87
|
+
- ext/deskbot/src/alert.rs
|
88
|
+
- ext/deskbot/src/bitmap.rs
|
89
|
+
- ext/deskbot/src/keys.rs
|
90
|
+
- ext/deskbot/src/lib.rs
|
91
|
+
- ext/deskbot/src/mouse.rs
|
92
|
+
- ext/deskbot/src/screen.rs
|
93
|
+
- lib/deskbot.rb
|
94
|
+
- lib/deskbot/area.rb
|
95
|
+
- lib/deskbot/bitmap.rb
|
96
|
+
- lib/deskbot/color.rb
|
97
|
+
- lib/deskbot/point.rb
|
98
|
+
- lib/deskbot/providers/autopilot.rb
|
99
|
+
- lib/deskbot/providers/autopilot/bitmap.rb
|
100
|
+
- lib/deskbot/screen.rb
|
101
|
+
- lib/deskbot/size.rb
|
102
|
+
- lib/deskbot/types.rb
|
103
|
+
- lib/deskbot/version.rb
|
104
|
+
- sig/deskbot.rbs
|
105
|
+
homepage: https://github.com/nolantait/desktbot
|
106
|
+
licenses:
|
107
|
+
- MIT
|
108
|
+
metadata:
|
109
|
+
homepage_uri: https://github.com/nolantait/desktbot
|
110
|
+
source_code_uri: https://github.com/nolantait/desktbot
|
111
|
+
changelog_uri: https://github.com/nolantait/desktbot
|
112
|
+
rubygems_mfa_required: 'true'
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '3.3'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 3.3.11
|
127
|
+
requirements: []
|
128
|
+
rubygems_version: 3.5.9
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: Ruby dekstop automation
|
132
|
+
test_files: []
|