fusuma 2.5.0 → 3.0.0
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 +4 -4
- data/README.md +55 -34
- data/bin/console +2 -2
- data/lib/fusuma/config/index.rb +19 -46
- data/lib/fusuma/config/searcher.rb +14 -61
- data/lib/fusuma/custom_process.rb +33 -1
- data/lib/fusuma/device.rb +1 -0
- data/lib/fusuma/multi_logger.rb +16 -0
- data/lib/fusuma/plugin/base.rb +4 -1
- data/lib/fusuma/plugin/buffers/gesture_buffer.rb +63 -6
- data/lib/fusuma/plugin/detectors/detector.rb +10 -9
- data/lib/fusuma/plugin/detectors/hold_detector.rb +24 -14
- data/lib/fusuma/plugin/detectors/pinch_detector.rb +10 -10
- data/lib/fusuma/plugin/detectors/rotate_detector.rb +4 -11
- data/lib/fusuma/plugin/detectors/swipe_detector.rb +7 -15
- data/lib/fusuma/plugin/events/records/gesture_record.rb +5 -2
- data/lib/fusuma/plugin/events/records/index_record.rb +1 -1
- data/lib/fusuma/plugin/executors/command_executor.rb +2 -2
- data/lib/fusuma/plugin/executors/executor.rb +1 -4
- data/lib/fusuma/plugin/filters/libinput_device_filter.rb +2 -1
- data/lib/fusuma/plugin/inputs/input.rb +14 -36
- data/lib/fusuma/plugin/inputs/timer_input.rb +36 -21
- data/lib/fusuma/plugin/manager.rb +48 -22
- data/lib/fusuma/version.rb +1 -1
- data/lib/fusuma.rb +44 -34
- metadata +3 -3
@@ -15,37 +15,56 @@ module Fusuma
|
|
15
15
|
fusuma_default_plugin_paths.each { |siblings_plugin| require(siblings_plugin) }
|
16
16
|
end
|
17
17
|
|
18
|
-
def fusuma_default_plugin_paths
|
19
|
-
search_key = File.join("../../", plugin_dir_name, "*.rb")
|
20
|
-
Dir.glob(File.expand_path("#{__dir__}/#{search_key}")).sort
|
21
|
-
end
|
22
|
-
|
23
18
|
def require_siblings_from_gems
|
24
19
|
fusuma_external_plugin_paths.each { |siblings_plugin| require(siblings_plugin) }
|
25
20
|
end
|
26
21
|
|
22
|
+
def exclude_path_pattern
|
23
|
+
%r{fusuma/plugin/[^/]*.rb}
|
24
|
+
end
|
25
|
+
|
26
|
+
def fusuma_default_plugin_paths
|
27
|
+
@_fusuma_default_plugin_paths ||= Dir.glob(File.expand_path("#{__dir__}/../../#{search_key}")).grep_v(exclude_path_pattern).sort
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Array<String>] paths of external plugins (installed by gem)
|
27
31
|
def fusuma_external_plugin_paths
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
32
|
+
@_fusuma_external_plugin_paths ||=
|
33
|
+
Gem.find_latest_files(search_key).map do |siblings_plugin|
|
34
|
+
next unless %r{fusuma-plugin-(.+).*/lib/#{plugin_dir_name}/.+\.rb}.match?(siblings_plugin)
|
35
|
+
|
36
|
+
match_data = siblings_plugin.match(%r{(.*)/(.*)/lib/(.*)})
|
37
|
+
plugin_gemspec_path = Dir.glob("#{match_data[1]}/#{match_data[2]}/*.gemspec").first
|
38
|
+
raise "Not Found: #{match_data[1]}/#{match_data[2]}/*.gemspec" unless plugin_gemspec_path
|
39
|
+
|
40
|
+
plugin_gemspec = Gem::Specification.load(plugin_gemspec_path)
|
41
|
+
fusuma_gemspec_path = File.expand_path("../../../fusuma.gemspec", __dir__)
|
42
|
+
fusuma_gemspec = Gem::Specification.load(fusuma_gemspec_path)
|
43
|
+
|
44
|
+
if plugin_gemspec.dependencies.find { |d| d.name == "fusuma" }&.match?(fusuma_gemspec)
|
45
|
+
siblings_plugin
|
46
|
+
else
|
47
|
+
MultiLogger.warn "#{plugin_gemspec.name} #{plugin_gemspec.version} is incompatible with running #{fusuma_gemspec.name} #{fusuma_gemspec.version}"
|
48
|
+
MultiLogger.warn "gemspec: #{plugin_gemspec_path}"
|
49
|
+
next
|
50
|
+
end
|
51
|
+
end.compact.grep_v(exclude_path_pattern).sort
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [String] search key for plugin
|
55
|
+
# @example
|
56
|
+
# search_key
|
57
|
+
# => "fusuma/plugin/detectors/*rb"
|
58
|
+
def search_key
|
59
|
+
File.join(plugin_dir_name, "*rb")
|
45
60
|
end
|
46
61
|
|
47
62
|
private
|
48
63
|
|
64
|
+
# @example
|
65
|
+
# plugin_dir_name
|
66
|
+
# => "fusuma/plugin/detectors"
|
67
|
+
# @return [String]
|
49
68
|
def plugin_dir_name
|
50
69
|
@plugin_class.name.match(/(Fusuma::.*)::/)[1].to_s.underscore
|
51
70
|
end
|
@@ -70,6 +89,13 @@ module Fusuma
|
|
70
89
|
load_paths << plugin_path
|
71
90
|
|
72
91
|
manager = Manager.new(plugin_class)
|
92
|
+
|
93
|
+
@already_required ||= {}
|
94
|
+
|
95
|
+
key = manager.search_key
|
96
|
+
return if @already_required[key]
|
97
|
+
|
98
|
+
@already_required[key] = true
|
73
99
|
manager.require_siblings_from_plugin_dir
|
74
100
|
manager.require_siblings_from_gems
|
75
101
|
end
|
data/lib/fusuma/version.rb
CHANGED
data/lib/fusuma.rb
CHANGED
@@ -13,9 +13,9 @@ module Fusuma
|
|
13
13
|
class Runner
|
14
14
|
class << self
|
15
15
|
def run(option = {})
|
16
|
-
set_trap
|
17
16
|
read_options(option)
|
18
17
|
instance = new
|
18
|
+
instance.set_trap
|
19
19
|
## NOTE: Uncomment following line to measure performance
|
20
20
|
# instance.run_with_lineprof
|
21
21
|
instance.run
|
@@ -23,11 +23,6 @@ module Fusuma
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
def set_trap
|
27
|
-
Signal.trap("INT") { puts exit } # Trap ^C
|
28
|
-
Signal.trap("TERM") { puts exit } # Trap `Kill `
|
29
|
-
end
|
30
|
-
|
31
26
|
def read_options(option)
|
32
27
|
MultiLogger.filepath = option[:log_filepath]
|
33
28
|
MultiLogger.instance.debug_mode = option[:verbose]
|
@@ -56,7 +51,9 @@ module Fusuma
|
|
56
51
|
end
|
57
52
|
|
58
53
|
def initialize
|
59
|
-
@inputs = Plugin::Inputs::Input.plugins.map
|
54
|
+
@inputs = Plugin::Inputs::Input.plugins.map do |cls|
|
55
|
+
cls.ancestors.include?(Singleton) ? cls.instance : cls.new
|
56
|
+
end
|
60
57
|
@filters = Plugin::Filters::Filter.plugins.map(&:new)
|
61
58
|
@parsers = Plugin::Parsers::Parser.plugins.map(&:new)
|
62
59
|
@buffers = Plugin::Buffers::Buffer.plugins.map(&:new)
|
@@ -75,8 +72,8 @@ module Fusuma
|
|
75
72
|
parsed = parse(filtered) || return
|
76
73
|
buffered = buffer(parsed) || return
|
77
74
|
detected = detect(buffered) || return
|
78
|
-
|
79
|
-
execute(
|
75
|
+
context, event = merge(detected) || return
|
76
|
+
execute(context, event)
|
80
77
|
end
|
81
78
|
|
82
79
|
# For performance monitoring
|
@@ -98,12 +95,14 @@ module Fusuma
|
|
98
95
|
|
99
96
|
# @param [Plugin::Events::Event]
|
100
97
|
# @return [Plugin::Events::Event]
|
98
|
+
# @return [NilClass]
|
101
99
|
def filter(event)
|
102
100
|
event if @filters.any? { |f| f.filter(event) }
|
103
101
|
end
|
104
102
|
|
105
103
|
# @param [Plugin::Events::Event]
|
106
104
|
# @return [Plugin::Events::Event]
|
105
|
+
# @return [NilClass]
|
107
106
|
def parse(event)
|
108
107
|
@parsers.reduce(event) { |e, p| p.parse(e) if e }
|
109
108
|
end
|
@@ -117,6 +116,7 @@ module Fusuma
|
|
117
116
|
|
118
117
|
# @param buffers [Array<Buffer>]
|
119
118
|
# @return [Array<Event>]
|
119
|
+
# @return [NilClass]
|
120
120
|
def detect(buffers)
|
121
121
|
matched_detectors = @detectors.select do |detector|
|
122
122
|
detector.watch? ||
|
@@ -124,7 +124,8 @@ module Fusuma
|
|
124
124
|
end
|
125
125
|
|
126
126
|
events = matched_detectors.each_with_object([]) do |detector, detected|
|
127
|
-
Array(detector.detect(@buffers)).each { |e| detected << e }
|
127
|
+
# Array(detector.detect(@buffers)).each { |e| detected << e }
|
128
|
+
detected.concat(Array(detector.detect(@buffers)))
|
128
129
|
end
|
129
130
|
|
130
131
|
return if events.empty?
|
@@ -133,7 +134,7 @@ module Fusuma
|
|
133
134
|
end
|
134
135
|
|
135
136
|
# @param events [Array<Plugin::Events::Event>]
|
136
|
-
# @return [Plugin::Events::Event] Event merged all
|
137
|
+
# @return [Array<Hash, Plugin::Events::Event>] Event merged all events from arguments and used context
|
137
138
|
# @return [NilClass] when event is NOT given
|
138
139
|
def merge(events)
|
139
140
|
index_events, context_events = events.partition { |event| event.record.type == :index }
|
@@ -143,44 +144,34 @@ module Fusuma
|
|
143
144
|
end
|
144
145
|
main_events.sort_by! { |e| e.record.trigger_priority }
|
145
146
|
|
146
|
-
matched_condition = nil
|
147
147
|
matched_context = nil
|
148
148
|
event = main_events.find do |main_event|
|
149
149
|
matched_context = Config::Searcher.find_context(request_context) do
|
150
|
-
|
151
|
-
main_event.record.merge(records: modifiers.map(&:record))
|
152
|
-
end
|
153
|
-
if matched_condition && modified_record
|
150
|
+
if modified_record = main_event.record.merge(records: modifiers.map(&:record))
|
154
151
|
main_event.record = modified_record
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
152
|
+
elsif !modifiers.empty?
|
153
|
+
# try basically the same, but without any modifiers
|
154
|
+
# if modifiers is empty then we end up here only if there is no execute key for this
|
155
|
+
Config.instance.search(main_event.record.index) &&
|
156
|
+
Config.instance.find_execute_key(main_event.record.index)
|
160
157
|
end
|
161
158
|
end
|
162
159
|
end
|
163
160
|
return if event.nil?
|
164
161
|
|
165
|
-
[
|
162
|
+
[matched_context, event]
|
166
163
|
end
|
167
164
|
|
165
|
+
# @return [NilClass] when event is NOT given or executable context is NOT found
|
168
166
|
# @param event [Plugin::Events::Event]
|
169
|
-
def execute(
|
167
|
+
def execute(context, event)
|
170
168
|
return unless event
|
171
169
|
|
172
|
-
# Find executable
|
173
|
-
executor = Config::Searcher.with_context(context) do
|
174
|
-
Config::Searcher.with_condition(condition) do
|
175
|
-
@executors.find { |e| e.executable?(event) }
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
return if executor.nil?
|
180
|
-
|
181
|
-
# Check interval and execute
|
170
|
+
# Find executable context
|
182
171
|
Config::Searcher.with_context(context) do
|
183
|
-
|
172
|
+
executor = @executors.find { |e| e.executable?(event) }
|
173
|
+
if executor
|
174
|
+
# Check interval and execute
|
184
175
|
executor.enough_interval?(event) &&
|
185
176
|
executor.update_interval(event) &&
|
186
177
|
executor.execute(event)
|
@@ -191,5 +182,24 @@ module Fusuma
|
|
191
182
|
def clear_expired_events
|
192
183
|
@buffers.each(&:clear_expired)
|
193
184
|
end
|
185
|
+
|
186
|
+
def set_trap
|
187
|
+
Signal.trap("INT") {
|
188
|
+
shutdown
|
189
|
+
puts exit
|
190
|
+
} # Trap ^C
|
191
|
+
Signal.trap("TERM") {
|
192
|
+
shutdown
|
193
|
+
puts exit
|
194
|
+
} # Trap `Kill `
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def shutdown
|
200
|
+
[@inputs, @filters, @parsers, @buffers, @detectors, @executors].flatten.each do |plugin|
|
201
|
+
plugin.shutdown
|
202
|
+
end
|
203
|
+
end
|
194
204
|
end
|
195
205
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fusuma
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iberianpig
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Fusuma is multitouch gesture recognizer. This gem makes your touchpad
|
14
14
|
on Linux able to recognize swipes or pinchs and assign command to them. Read installation
|
@@ -86,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
86
86
|
- !ruby/object:Gem::Version
|
87
87
|
version: '0'
|
88
88
|
requirements: []
|
89
|
-
rubygems_version: 3.
|
89
|
+
rubygems_version: 3.3.26
|
90
90
|
signing_key:
|
91
91
|
specification_version: 4
|
92
92
|
summary: Multitouch gestures with libinput driver, Linux
|