hokusai-zero 0.1.1
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.
- checksums.yaml +7 -0
- data/Dockerfile +26 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +91 -0
- data/LICENSE +21 -0
- data/README.md +28 -0
- data/ast/genheader +3 -0
- data/ast/include/hashmap.c +1151 -0
- data/ast/include/hashmap.c.license +20 -0
- data/ast/include/hashmap.h +54 -0
- data/ast/src/core/ast.c +448 -0
- data/ast/src/core/ast.h +259 -0
- data/ast/src/core/common.h +24 -0
- data/ast/src/core/component.c +85 -0
- data/ast/src/core/component.h +35 -0
- data/ast/src/core/hml.c +665 -0
- data/ast/src/core/hml.h +11 -0
- data/ast/src/core/input.c +458 -0
- data/ast/src/core/input.h +118 -0
- data/ast/src/core/style.c +101 -0
- data/ast/src/core/style.h +41 -0
- data/ast/src/core/text.c +784 -0
- data/ast/src/core/text.h +93 -0
- data/ast/src/core/util.c +140 -0
- data/ast/src/core/util.h +48 -0
- data/ast/src/hokusai.c +6 -0
- data/ast/src/hokusai.h +6 -0
- data/ast/test/fixtures/test.ui +13 -0
- data/ast/test/greatest.h +1266 -0
- data/ast/test/hokusai.c +14 -0
- data/ast/test/parser.c +234 -0
- data/ast/test/text.c +116 -0
- data/ext/extconf.rb +27 -0
- data/grammar/Cargo.lock +80 -0
- data/grammar/Cargo.toml +26 -0
- data/grammar/binding.gyp +20 -0
- data/grammar/bindings/node/binding.cc +28 -0
- data/grammar/bindings/node/index.js +19 -0
- data/grammar/bindings/rust/build.rs +40 -0
- data/grammar/bindings/rust/lib.rs +52 -0
- data/grammar/corpus/1_document.txt +131 -0
- data/grammar/corpus/2_selectors.txt +58 -0
- data/grammar/corpus/3_spaces.txt +69 -0
- data/grammar/corpus/4_errors.txt +10 -0
- data/grammar/corpus/5_macros.txt +175 -0
- data/grammar/corpus/6_styles.txt +81 -0
- data/grammar/grammar.js +275 -0
- data/grammar/package-lock.json +34 -0
- data/grammar/package.json +33 -0
- data/grammar/src/grammar.json +1269 -0
- data/grammar/src/node-types.json +474 -0
- data/grammar/src/parser.c +5772 -0
- data/grammar/src/scanner.c +258 -0
- data/grammar/src/tree_sitter/parser.h +230 -0
- data/grammar/src/tree_sitter/scanner.h +12 -0
- data/grammar/test.nml +10 -0
- data/hokusai.gemspec +19 -0
- data/ui/examples/assets/DigitalDisplay.ttf +0 -0
- data/ui/examples/assets/OpenSans-Regular.ttf +0 -0
- data/ui/examples/assets/addy.png +0 -0
- data/ui/examples/assets/baby_sean.png +0 -0
- data/ui/examples/assets/football-troll.png +0 -0
- data/ui/examples/assets/gear.png +0 -0
- data/ui/examples/assets/icecold.ttf +0 -0
- data/ui/examples/assets/science-troll.png +0 -0
- data/ui/examples/buddy.rb +31 -0
- data/ui/examples/clock.rb +58 -0
- data/ui/examples/counter.rb +123 -0
- data/ui/examples/dynamic.rb +147 -0
- data/ui/examples/foobar.rb +236 -0
- data/ui/examples/stock.rb +115 -0
- data/ui/examples/stock_decider/option.rb +74 -0
- data/ui/examples/tic_tac_toe.rb +246 -0
- data/ui/lib/lib_hokusai.rb +425 -0
- data/ui/spec/hokusai/ast_spec.rb +88 -0
- data/ui/spec/hokusai/automation/keys_transcoder_spec.rb +50 -0
- data/ui/spec/hokusai/automation/selector_spec.rb +68 -0
- data/ui/spec/hokusai/block_spec.rb +126 -0
- data/ui/spec/hokusai/directives_spec.rb +327 -0
- data/ui/spec/hokusai/e2e/client_spec.rb +58 -0
- data/ui/spec/hokusai/e2e/meta_spec.rb +42 -0
- data/ui/spec/hokusai/publisher_spec.rb +38 -0
- data/ui/spec/hokusai/slots_spec.rb +150 -0
- data/ui/spec/hokusai/util/piece_table_spec.rb +90 -0
- data/ui/spec/hokusai_spec.rb +0 -0
- data/ui/spec/spec_helper.rb +30 -0
- data/ui/src/hokusai/ast.rb +446 -0
- data/ui/src/hokusai/automation/client.rb +167 -0
- data/ui/src/hokusai/automation/constants.rb +98 -0
- data/ui/src/hokusai/automation/converters/selector_converter.rb +61 -0
- data/ui/src/hokusai/automation/driver.rb +54 -0
- data/ui/src/hokusai/automation/driver_command_queue.rb +50 -0
- data/ui/src/hokusai/automation/driver_commands/base.rb +79 -0
- data/ui/src/hokusai/automation/driver_commands/get_attribute.rb +41 -0
- data/ui/src/hokusai/automation/driver_commands/invoke.rb +33 -0
- data/ui/src/hokusai/automation/driver_commands/locate.rb +48 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_keyboard.rb +94 -0
- data/ui/src/hokusai/automation/driver_commands/trigger_mouse.rb +213 -0
- data/ui/src/hokusai/automation/keys_transcoder.rb +128 -0
- data/ui/src/hokusai/automation/selector.rb +39 -0
- data/ui/src/hokusai/automation/server.rb +114 -0
- data/ui/src/hokusai/automation.rb +3 -0
- data/ui/src/hokusai/backends/raylib/config.rb +47 -0
- data/ui/src/hokusai/backends/raylib/font.rb +113 -0
- data/ui/src/hokusai/backends/raylib/keys.rb +124 -0
- data/ui/src/hokusai/backends/raylib.rb +449 -0
- data/ui/src/hokusai/backends/sdl2/Monaco.ttf +0 -0
- data/ui/src/hokusai/backends/sdl2/color.rb +12 -0
- data/ui/src/hokusai/backends/sdl2/config.rb +31 -0
- data/ui/src/hokusai/backends/sdl2/font.rb +127 -0
- data/ui/src/hokusai/backends/sdl2/keys.rb +119 -0
- data/ui/src/hokusai/backends/sdl2.rb +529 -0
- data/ui/src/hokusai/block.rb +237 -0
- data/ui/src/hokusai/blocks/button.rb +100 -0
- data/ui/src/hokusai/blocks/checkbox.rb +51 -0
- data/ui/src/hokusai/blocks/circle.rb +28 -0
- data/ui/src/hokusai/blocks/clipped.rb +23 -0
- data/ui/src/hokusai/blocks/cursor.rb +49 -0
- data/ui/src/hokusai/blocks/dynamic.rb +37 -0
- data/ui/src/hokusai/blocks/empty.rb +10 -0
- data/ui/src/hokusai/blocks/hblock.rb +35 -0
- data/ui/src/hokusai/blocks/image.rb +18 -0
- data/ui/src/hokusai/blocks/input.rb +200 -0
- data/ui/src/hokusai/blocks/label.rb +39 -0
- data/ui/src/hokusai/blocks/panel.rb +126 -0
- data/ui/src/hokusai/blocks/rect.rb +24 -0
- data/ui/src/hokusai/blocks/scissor_begin.rb +18 -0
- data/ui/src/hokusai/blocks/scissor_end.rb +12 -0
- data/ui/src/hokusai/blocks/scrollbar.rb +103 -0
- data/ui/src/hokusai/blocks/selectable.rb +77 -0
- data/ui/src/hokusai/blocks/svg.rb +20 -0
- data/ui/src/hokusai/blocks/text.rb +214 -0
- data/ui/src/hokusai/blocks/titlebar/osx.rb +145 -0
- data/ui/src/hokusai/blocks/toggle.rb +55 -0
- data/ui/src/hokusai/blocks/vblock.rb +35 -0
- data/ui/src/hokusai/commands/base.rb +22 -0
- data/ui/src/hokusai/commands/circle.rb +47 -0
- data/ui/src/hokusai/commands/image.rb +45 -0
- data/ui/src/hokusai/commands/rect.rb +158 -0
- data/ui/src/hokusai/commands/scissor.rb +22 -0
- data/ui/src/hokusai/commands/text.rb +92 -0
- data/ui/src/hokusai/commands.rb +87 -0
- data/ui/src/hokusai/diff.rb +124 -0
- data/ui/src/hokusai/error.rb +3 -0
- data/ui/src/hokusai/event.rb +54 -0
- data/ui/src/hokusai/events/keyboard.rb +84 -0
- data/ui/src/hokusai/events/mouse.rb +172 -0
- data/ui/src/hokusai/font.rb +280 -0
- data/ui/src/hokusai/meta.rb +152 -0
- data/ui/src/hokusai/mounting/loop_entry.rb +230 -0
- data/ui/src/hokusai/mounting/mount_entry.rb +74 -0
- data/ui/src/hokusai/mounting/update_entry.rb +101 -0
- data/ui/src/hokusai/node.rb +98 -0
- data/ui/src/hokusai/node_mounter.rb +102 -0
- data/ui/src/hokusai/painter.rb +214 -0
- data/ui/src/hokusai/publisher.rb +32 -0
- data/ui/src/hokusai/style.rb +72 -0
- data/ui/src/hokusai/types.rb +266 -0
- data/ui/src/hokusai/util/clamping_iterator.rb +202 -0
- data/ui/src/hokusai/util/piece_table.rb +111 -0
- data/ui/src/hokusai/util/selection.rb +145 -0
- data/ui/src/hokusai.rb +120 -0
- data/ui/vendor/.gitkeep +0 -0
- data/vendor/.gitkeep +0 -0
- data/xmake.lua +192 -0
- metadata +222 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative "../selector"
|
2
|
+
|
3
|
+
module Hokusai::Automation
|
4
|
+
module Converters
|
5
|
+
module SelectorConverter
|
6
|
+
def self.parse_selectors(selector)
|
7
|
+
final = []
|
8
|
+
scanner = StringScanner.new(selector)
|
9
|
+
|
10
|
+
while !scanner.eos?
|
11
|
+
if node = scan_node(scanner)
|
12
|
+
id = scan_id(scanner)
|
13
|
+
classes = scan_classes(scanner)
|
14
|
+
final << Selector.new(node, id, classes)
|
15
|
+
|
16
|
+
scan_space(scanner)
|
17
|
+
elsif id = scan_id(scanner)
|
18
|
+
classes = scan_classes(scanner)
|
19
|
+
final << Selector.new(nil, id, classes)
|
20
|
+
|
21
|
+
scan_space(scanner)
|
22
|
+
elsif classes = scan_classes(scanner)
|
23
|
+
final << Selector.new(nil, nil, classes)
|
24
|
+
|
25
|
+
scan_space(scanner)
|
26
|
+
else
|
27
|
+
scanner.terminate
|
28
|
+
|
29
|
+
if scanner.rest.empty?
|
30
|
+
scanner.terminate
|
31
|
+
else
|
32
|
+
raise Automation::Error.new("Error Scanning: Improperly formatted selector: #{scanner.rest}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
final
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def self.scan_id(scanner)
|
43
|
+
scanner.scan(/\#([A-Za-z0-9-_]+)/)
|
44
|
+
scanner[1]
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.scan_classes(scanner)
|
48
|
+
scanner.scan(/((\.[A-Za-z0-9-_]+)+)/)
|
49
|
+
scanner[1]&.[](1..-1)&.split(".")
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.scan_node(scanner)
|
53
|
+
scanner.scan(/[A-Za-z0-9-_]+/)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.scan_space(scanner)
|
57
|
+
scanner.scan(/\s*/)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require_relative "./driver_commands/base"
|
2
|
+
require_relative "./driver_commands/get_attribute"
|
3
|
+
require_relative "./driver_commands/invoke"
|
4
|
+
require_relative "./driver_commands/locate"
|
5
|
+
require_relative "./driver_commands/trigger_keyboard"
|
6
|
+
require_relative "./driver_commands/trigger_mouse"
|
7
|
+
require_relative "./driver_command_queue"
|
8
|
+
|
9
|
+
module Hokusai
|
10
|
+
module Automation
|
11
|
+
class Driver
|
12
|
+
attr_reader :server, :queue, :results
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@queue = DriverCommandQueue.new
|
16
|
+
@results = {}
|
17
|
+
@server = Hokusai::Automation::Server
|
18
|
+
end
|
19
|
+
|
20
|
+
def serve(*args)
|
21
|
+
@server.start(*args, driver: self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def stop
|
25
|
+
@server.stop
|
26
|
+
end
|
27
|
+
|
28
|
+
def complete
|
29
|
+
queue.completed(results)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Adds a driver command to the queue to be executed
|
33
|
+
#
|
34
|
+
# Commands process one-by-one on each iteration of the
|
35
|
+
# UI loop.
|
36
|
+
#
|
37
|
+
# When a command is finished, its result will be populated in `#results`
|
38
|
+
def execute(command)
|
39
|
+
queue.commands << command
|
40
|
+
end
|
41
|
+
|
42
|
+
# Process a command with the given UI state
|
43
|
+
#
|
44
|
+
# Results will added to the results hash and picked up by the current server request
|
45
|
+
#
|
46
|
+
# * `blocks` is a tuple containing a block and its parent
|
47
|
+
# * `canvas` is the current canvas being painted
|
48
|
+
# * `input` is the application input state for this loop iteration
|
49
|
+
def process(blocks, canvas, input)
|
50
|
+
queue.process(blocks, canvas, input)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
# A queue of `DriverCommand`
|
3
|
+
#
|
4
|
+
# The queue is processed async on each iteration of the event loop
|
5
|
+
class DriverCommandQueue
|
6
|
+
attr_accessor :commands
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@commands = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def completed(results)
|
13
|
+
if command = commands[0]
|
14
|
+
# command was added in the middle of a render cycle, don't complete it.
|
15
|
+
return if command.waiting?
|
16
|
+
|
17
|
+
if value = command.on_complete
|
18
|
+
case value
|
19
|
+
when ::Hokusai::Automation::Error
|
20
|
+
results[command.request_id] = [command, value]
|
21
|
+
else
|
22
|
+
results[command.request_id] = [command, value]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if command.done?
|
27
|
+
|
28
|
+
commands.shift
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Processes any availabe commands in the queue
|
34
|
+
#
|
35
|
+
# Returns a Tuple containing the command and it's wrapped return value
|
36
|
+
def process(blocks, canvas, input)
|
37
|
+
return nil if commands.empty?
|
38
|
+
|
39
|
+
command = commands[0]
|
40
|
+
|
41
|
+
# wait for the start of the render loop
|
42
|
+
#
|
43
|
+
# if there is no parent, execute the command
|
44
|
+
return if !blocks[1].nil? && command.waiting?
|
45
|
+
|
46
|
+
command.pending! if command.waiting?
|
47
|
+
command.execute(blocks, canvas, input)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
module DriverCommands
|
3
|
+
class Base
|
4
|
+
attr_accessor :request_id, :status, :last_parent
|
5
|
+
attr_reader :state
|
6
|
+
|
7
|
+
[:waiting, :pending, :done].each do |key|
|
8
|
+
define_method("#{key}?") do
|
9
|
+
status == key
|
10
|
+
end
|
11
|
+
|
12
|
+
define_method("#{key}!") do
|
13
|
+
self.status = key
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(hash)
|
18
|
+
@state = hash
|
19
|
+
@last_parent = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def status
|
23
|
+
@status ||= :wait
|
24
|
+
end
|
25
|
+
|
26
|
+
def request_id
|
27
|
+
@request_id ||= SecureRandom.uuid
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_complete(&block)
|
31
|
+
raise NotImplementedError.new("Must implement #{self.class}#on_complete")
|
32
|
+
end
|
33
|
+
|
34
|
+
def execute(blocks, canvas, input)
|
35
|
+
raise NotImplementedError.new("Must implement #{self.class}#execute")
|
36
|
+
end
|
37
|
+
|
38
|
+
def matches_block(block)
|
39
|
+
return false unless block.node.portal
|
40
|
+
|
41
|
+
if location == block.node.portal.uuid.to_s
|
42
|
+
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def matches_blocks(blocks)
|
50
|
+
if matches_block(blocks[0]) || (last_parent == blocks[1] && !last_parent.nil?)
|
51
|
+
self.last_parent = blocks[0]
|
52
|
+
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
|
56
|
+
false
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def mouse_center(canvas, input)
|
61
|
+
x = canvas.x + (canvas.width / 2)
|
62
|
+
y = canvas.y + (canvas.height / 2)
|
63
|
+
|
64
|
+
mouse_move(x, y, input)
|
65
|
+
end
|
66
|
+
|
67
|
+
def mouse_move(x, y, input)
|
68
|
+
LibHokusai.hoku_input_set_mouse_position(input, vec2(x, y))
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
# Returns an HmlVec2 from {x,y}
|
74
|
+
def vec2(x, y)
|
75
|
+
LibHokusai::HmlVec2.create(x, y)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
module DriverCommands
|
3
|
+
class GetAttribute < Base
|
4
|
+
attr_accessor :value
|
5
|
+
|
6
|
+
def initialize(state)
|
7
|
+
@value = nil
|
8
|
+
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def location
|
13
|
+
state[:uuid]
|
14
|
+
end
|
15
|
+
|
16
|
+
def attribute_name
|
17
|
+
state[:attribute_name]
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_complete
|
21
|
+
done!
|
22
|
+
|
23
|
+
if value.nil?
|
24
|
+
return ::Hokusai::Automation::Error.new("Attribute #{attribute_name} not found")
|
25
|
+
end
|
26
|
+
|
27
|
+
return value
|
28
|
+
end
|
29
|
+
|
30
|
+
def execute(blocks, canvas, input)
|
31
|
+
return unless matches_block(blocks[0])
|
32
|
+
|
33
|
+
Log.debug { "Props: #{blocks[0].node.meta.props}".colorize(:yellow) }
|
34
|
+
|
35
|
+
attribute = blocks[0].node.meta.props[attribute_name.to_sym]
|
36
|
+
|
37
|
+
self.value = attribute
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
module DriverCommands
|
3
|
+
class Invoke < Base
|
4
|
+
attr_accessor :value
|
5
|
+
|
6
|
+
def location
|
7
|
+
state[:uuid]
|
8
|
+
end
|
9
|
+
|
10
|
+
def method
|
11
|
+
state[:method]
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(hash)
|
15
|
+
@value = nil
|
16
|
+
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_complete
|
21
|
+
return value if done?
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute(block, canvas, input)
|
25
|
+
return unless matches_block(blocks[0])
|
26
|
+
|
27
|
+
self.value = blocks[0].public_send(method)
|
28
|
+
|
29
|
+
done!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative "../converters/selector_converter"
|
2
|
+
|
3
|
+
module Hokusai::Automation
|
4
|
+
module DriverCommands
|
5
|
+
class Locate < Base
|
6
|
+
attr_reader :matches
|
7
|
+
|
8
|
+
def initialize(hash)
|
9
|
+
@matches = []
|
10
|
+
@selectors = nil
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_complete
|
16
|
+
return if waiting?
|
17
|
+
|
18
|
+
done!
|
19
|
+
|
20
|
+
return ::Hokusai::Automation::Error.new("No matches found") if matches.empty?
|
21
|
+
|
22
|
+
matches.last
|
23
|
+
end
|
24
|
+
|
25
|
+
def selectors
|
26
|
+
@selectors ||= Converters::SelectorConverter.parse_selectors(state[:selector])
|
27
|
+
end
|
28
|
+
|
29
|
+
def execute(blocks, canvas, input)
|
30
|
+
if selector = selectors.shift
|
31
|
+
if selector.matches(blocks[0])
|
32
|
+
Log.debug {"Location match! #{selector}".colorize(:light_magenta)}
|
33
|
+
|
34
|
+
portal = blocks[0].node.portal
|
35
|
+
|
36
|
+
Log.debug { "uuid: #{portal.uuid.to_s}".colorize(:light_magenta) }
|
37
|
+
|
38
|
+
matches << portal.uuid.to_s
|
39
|
+
|
40
|
+
selectors.unshift(selector) if selectors.empty?
|
41
|
+
else
|
42
|
+
selectors.unshift(selector)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
module DriverCommands
|
3
|
+
class TriggerKeyboard < Base
|
4
|
+
attr_reader :exception
|
5
|
+
|
6
|
+
def initialize(state)
|
7
|
+
@exception = nil
|
8
|
+
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def location
|
13
|
+
state[:uuid]
|
14
|
+
end
|
15
|
+
|
16
|
+
def keys
|
17
|
+
@keys ||= KeysTranscoder.decode(state[:keys])
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_complete
|
21
|
+
if keys.empty?
|
22
|
+
done!
|
23
|
+
end
|
24
|
+
|
25
|
+
return exception || true
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute(blocks, canvas, input)
|
29
|
+
return unless matches_block(blocks[0])
|
30
|
+
|
31
|
+
Log.info { "Trigger keypress on #{blocks[0].class}".colorize(:cyan) }
|
32
|
+
|
33
|
+
decode_key = keys.shift
|
34
|
+
|
35
|
+
mouse_center(canvas, input)
|
36
|
+
state = LibHokusai::HmlInputMouseButton.create(clicked: true)
|
37
|
+
LibHokusai.hoku_input_mouse_set_button(input, state, 0)
|
38
|
+
|
39
|
+
begin
|
40
|
+
key_results = to_hml_keygroup(decode_key)
|
41
|
+
|
42
|
+
LibHokusai.hoku_input_keyboard_start(input)
|
43
|
+
|
44
|
+
key_results.each do |key|
|
45
|
+
Log.info { "populating #{key}"}
|
46
|
+
|
47
|
+
LibHokusai.hoku_input_keyboard_set_key(input, key, true)
|
48
|
+
end
|
49
|
+
|
50
|
+
LibHokusai.hoku_input_keyboard_stop(input)
|
51
|
+
rescue Automation::Error => ex
|
52
|
+
keys.clear
|
53
|
+
self.exeception = ex
|
54
|
+
|
55
|
+
done!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Transforms a DecodedKey to an array of `LibHokusai::HmlInputKey`
|
60
|
+
def to_hml_keygroup(decode_key)
|
61
|
+
key_group = []
|
62
|
+
|
63
|
+
case decode_key
|
64
|
+
when Array
|
65
|
+
decode_key.each do |key|
|
66
|
+
if hml_key = CODE_TO_HML_KEY[key]
|
67
|
+
key_group << hml_key
|
68
|
+
else
|
69
|
+
raise Automation::Exception.new("Error translating key to HmlInput: #{key} not found")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
else
|
73
|
+
if hml_key CODE_TO_HML_KEY[decode_key]
|
74
|
+
key_group << hml_key
|
75
|
+
else
|
76
|
+
raise Automation::Exception.new("Error translating key to HmlInput: #{key} not found")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
key_group
|
81
|
+
end
|
82
|
+
|
83
|
+
def to_hml_keys
|
84
|
+
hml_keys = []
|
85
|
+
|
86
|
+
keys.each do |decode_key|
|
87
|
+
hml_keys << to_hml_keygroup(decode_key)
|
88
|
+
end
|
89
|
+
|
90
|
+
hml_keys
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
module Hokusai::Automation
|
2
|
+
module DriverCommands
|
3
|
+
module MouseMethods
|
4
|
+
def trigger_mouse(input, **args)
|
5
|
+
state = LibHokusai::HmlInputMouseButton.create(**args)
|
6
|
+
|
7
|
+
LibHokusai.hoku_input_mouse_set_button(input, state, button)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class TriggerMouseBase < Base
|
12
|
+
include MouseMethods
|
13
|
+
|
14
|
+
attr_accessor :value
|
15
|
+
|
16
|
+
def initialize(hash)
|
17
|
+
@value = false
|
18
|
+
|
19
|
+
super
|
20
|
+
end
|
21
|
+
|
22
|
+
def location
|
23
|
+
state[:uuid]
|
24
|
+
end
|
25
|
+
|
26
|
+
def button
|
27
|
+
state[:button]
|
28
|
+
end
|
29
|
+
|
30
|
+
def on_complete
|
31
|
+
return value if done?
|
32
|
+
|
33
|
+
return Automation::Error.new("Could not locate block")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class TriggerMouseDown < TriggerMouseBase
|
38
|
+
def execute(blocks, canvas, input)
|
39
|
+
if matches_blocks(blocks)
|
40
|
+
|
41
|
+
mouse_center(canvas, input)
|
42
|
+
trigger_mouse(input, down: true)
|
43
|
+
|
44
|
+
self.value = true
|
45
|
+
|
46
|
+
done!
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class TriggerMouseUp < TriggerMouseBase
|
52
|
+
def execute(blocks, canvas, input)
|
53
|
+
if matches_blocks(blocks)
|
54
|
+
|
55
|
+
mouse_center(canvas, input)
|
56
|
+
trigger_mouse(input, up: true)
|
57
|
+
|
58
|
+
self.value = true
|
59
|
+
|
60
|
+
done!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class TriggerMouseClick < TriggerMouseBase
|
66
|
+
def execute(blocks, canvas, input)
|
67
|
+
if matches_blocks(blocks)
|
68
|
+
|
69
|
+
mouse_center(canvas, input)
|
70
|
+
trigger_mouse(input, clicked: true)
|
71
|
+
|
72
|
+
self.value = true
|
73
|
+
|
74
|
+
done!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class TriggerMouseRelease < TriggerMouseBase
|
80
|
+
def execute(blocks, canvas, input)
|
81
|
+
if matches_blocks(blocks)
|
82
|
+
|
83
|
+
mouse_center(canvas, input)
|
84
|
+
trigger_mouse(input, released: true)
|
85
|
+
|
86
|
+
self.value = true
|
87
|
+
|
88
|
+
done!
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
class TriggerMouseHover < Base
|
94
|
+
def location
|
95
|
+
state[:uuid]
|
96
|
+
end
|
97
|
+
|
98
|
+
def on_complete
|
99
|
+
return true if done?
|
100
|
+
|
101
|
+
return Automation::Error.new("Could not locate block")
|
102
|
+
end
|
103
|
+
|
104
|
+
def execute(blocks, canvas, input)
|
105
|
+
if matches_block(blocks[0])
|
106
|
+
mouse_center(canvas, input)
|
107
|
+
|
108
|
+
done!
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class TriggerMouseMove < Base
|
114
|
+
def x
|
115
|
+
state[:x]
|
116
|
+
end
|
117
|
+
|
118
|
+
def y
|
119
|
+
state[:y]
|
120
|
+
end
|
121
|
+
|
122
|
+
def on_complete
|
123
|
+
return true
|
124
|
+
end
|
125
|
+
|
126
|
+
def execute(blocks, canvas, input)
|
127
|
+
mouse_move(x, y, input) unless done?
|
128
|
+
|
129
|
+
done!
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
class TriggerMouseDrag < Base
|
134
|
+
include MouseMethods
|
135
|
+
|
136
|
+
attr_accessor :dragging, :cursory_y, :button
|
137
|
+
|
138
|
+
def initialize(hash)
|
139
|
+
@dragging = false
|
140
|
+
@cursory_y = 0.0
|
141
|
+
@button = 0
|
142
|
+
|
143
|
+
super
|
144
|
+
end
|
145
|
+
|
146
|
+
def location
|
147
|
+
state[:uuid]
|
148
|
+
end
|
149
|
+
|
150
|
+
def x
|
151
|
+
state[:x]
|
152
|
+
end
|
153
|
+
|
154
|
+
def y
|
155
|
+
state[:y]
|
156
|
+
end
|
157
|
+
|
158
|
+
def on_complete
|
159
|
+
return false if dragging
|
160
|
+
|
161
|
+
true
|
162
|
+
end
|
163
|
+
|
164
|
+
def execute(blocks, canvas, input)
|
165
|
+
if matches_block(blocks[0])
|
166
|
+
local_x = x || canvas.x + (canvas.width / 2.0)
|
167
|
+
local_y = y || canvas.y + (canvas.height / 2.0)
|
168
|
+
|
169
|
+
if cursor_y < local_y && dragging
|
170
|
+
trigger_mouse(input, down: true)
|
171
|
+
mouse_move(local_x, cursor_y, input)
|
172
|
+
|
173
|
+
self.cursor_y += 2.0
|
174
|
+
elsif !dragging
|
175
|
+
trigger_mouse(input, clicked: true)
|
176
|
+
|
177
|
+
self.dragging = true
|
178
|
+
else
|
179
|
+
self.dragging = false
|
180
|
+
|
181
|
+
done!
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
class TriggerMouseWheel < Base
|
188
|
+
def location
|
189
|
+
state[:uuid]
|
190
|
+
end
|
191
|
+
|
192
|
+
def scroll_amount
|
193
|
+
state[:scroll_amount]
|
194
|
+
end
|
195
|
+
|
196
|
+
def on_complete
|
197
|
+
return true if done?
|
198
|
+
|
199
|
+
return Automation::Error.new("Could not locate block")
|
200
|
+
end
|
201
|
+
|
202
|
+
def execute(blocks, canvas, input)
|
203
|
+
if matches_block(blocks[0])
|
204
|
+
mouse_center(canvas, input)
|
205
|
+
LibHokusai.hoku_input_mouse_set_scroll(input, scroll_amount)
|
206
|
+
|
207
|
+
|
208
|
+
done!
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|