fusuma 2.0.0.pre → 2.0.3
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 +50 -11
- data/fusuma.gemspec +5 -6
- data/lib/fusuma.rb +87 -33
- data/lib/fusuma/config.rb +33 -40
- data/lib/fusuma/config/index.rb +34 -8
- data/lib/fusuma/config/searcher.rb +80 -4
- data/lib/fusuma/custom_process.rb +13 -0
- data/lib/fusuma/device.rb +19 -6
- data/lib/fusuma/environment.rb +4 -3
- data/lib/fusuma/hash_support.rb +40 -0
- data/lib/fusuma/libinput_command.rb +10 -15
- data/lib/fusuma/multi_logger.rb +2 -6
- data/lib/fusuma/plugin/base.rb +18 -15
- data/lib/fusuma/plugin/buffers/buffer.rb +3 -2
- data/lib/fusuma/plugin/buffers/gesture_buffer.rb +34 -25
- data/lib/fusuma/plugin/buffers/timer_buffer.rb +3 -3
- data/lib/fusuma/plugin/detectors/detector.rb +26 -5
- data/lib/fusuma/plugin/detectors/pinch_detector.rb +109 -58
- data/lib/fusuma/plugin/detectors/rotate_detector.rb +91 -50
- data/lib/fusuma/plugin/detectors/swipe_detector.rb +93 -56
- data/lib/fusuma/plugin/events/event.rb +5 -4
- data/lib/fusuma/plugin/events/records/context_record.rb +27 -0
- data/lib/fusuma/plugin/events/records/gesture_record.rb +9 -6
- data/lib/fusuma/plugin/events/records/index_record.rb +46 -14
- data/lib/fusuma/plugin/events/records/record.rb +1 -1
- data/lib/fusuma/plugin/events/records/text_record.rb +2 -1
- data/lib/fusuma/plugin/executors/command_executor.rb +21 -4
- data/lib/fusuma/plugin/executors/executor.rb +45 -3
- data/lib/fusuma/plugin/filters/filter.rb +1 -1
- data/lib/fusuma/plugin/filters/libinput_device_filter.rb +6 -7
- data/lib/fusuma/plugin/filters/libinput_timeout_filter.rb +2 -2
- data/lib/fusuma/plugin/inputs/input.rb +20 -7
- data/lib/fusuma/plugin/inputs/libinput_command_input.rb +17 -5
- data/lib/fusuma/plugin/inputs/timer_input.rb +7 -7
- data/lib/fusuma/plugin/manager.rb +22 -29
- data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +10 -8
- data/lib/fusuma/plugin/parsers/parser.rb +8 -9
- data/lib/fusuma/string_support.rb +16 -0
- data/lib/fusuma/version.rb +1 -1
- data/spec/helpers/config_helper.rb +20 -0
- data/spec/lib/config/searcher_spec.rb +97 -0
- data/spec/lib/config_spec.rb +112 -0
- data/spec/lib/custom_process_spec.rb +28 -0
- data/spec/lib/device_spec.rb +96 -0
- data/spec/lib/dummy_config.yml +31 -0
- data/spec/lib/fusuma_spec.rb +103 -0
- data/spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt +181 -0
- data/spec/lib/libinput-list-devices_magic_trackpad.txt +51 -0
- data/spec/lib/libinput-list-devices_razer_razer_blade.txt +252 -0
- data/spec/lib/libinput-list-devices_thejinx0r.txt +361 -0
- data/spec/lib/libinput-list-devices_unavailable.txt +36 -0
- data/spec/lib/libinput_command_spec.rb +160 -0
- data/spec/lib/plugin/base_spec.rb +74 -0
- data/spec/lib/plugin/buffers/buffer_spec.rb +80 -0
- data/spec/lib/plugin/buffers/dummy_buffer.rb +20 -0
- data/spec/lib/plugin/buffers/gesture_buffer_spec.rb +172 -0
- data/spec/lib/plugin/detectors/detector_spec.rb +43 -0
- data/spec/lib/plugin/detectors/dummy_detector.rb +24 -0
- data/spec/lib/plugin/detectors/pinch_detector_spec.rb +119 -0
- data/spec/lib/plugin/detectors/rotate_detector_spec.rb +125 -0
- data/spec/lib/plugin/detectors/swipe_detector_spec.rb +118 -0
- data/spec/lib/plugin/events/event_spec.rb +30 -0
- data/spec/lib/plugin/events/records/gesture_record_spec.rb +22 -0
- data/spec/lib/plugin/events/records/record_spec.rb +31 -0
- data/spec/lib/plugin/events/records/text_record_spec.rb +26 -0
- data/spec/lib/plugin/executors/command_executor_spec.rb +57 -0
- data/spec/lib/plugin/executors/executor_spec.rb +160 -0
- data/spec/lib/plugin/filters/filter_spec.rb +92 -0
- data/spec/lib/plugin/filters/libinput_filter_spec.rb +120 -0
- data/spec/lib/plugin/inputs/input_spec.rb +70 -0
- data/spec/lib/plugin/inputs/libinput_command_input_spec.rb +121 -0
- data/spec/lib/plugin/inputs/timer_input_spec.rb +40 -0
- data/spec/lib/plugin/manager_spec.rb +27 -0
- data/spec/lib/plugin/parsers/parser_spec.rb +45 -0
- data/spec/spec_helper.rb +20 -0
- metadata +84 -38
- data/.github/FUNDING.yml +0 -8
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
- data/.github/pull_request_template.md +0 -9
- data/.github/stale.yml +0 -18
- data/.gitignore +0 -17
- data/.reek.yml +0 -96
- data/.rspec +0 -2
- data/.rubocop.yml +0 -40
- data/.rubocop_todo.yml +0 -40
- data/.travis.yml +0 -11
- data/CHANGELOG.md +0 -456
- data/CODE_OF_CONDUCT.md +0 -74
- data/CONTRIBUTING.md +0 -72
- data/Gemfile +0 -18
- data/Rakefile +0 -15
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../base
|
3
|
+
require_relative '../base'
|
4
4
|
|
5
5
|
module Fusuma
|
6
6
|
module Plugin
|
@@ -8,14 +8,56 @@ module Fusuma
|
|
8
8
|
module Executors
|
9
9
|
# Inherite this base
|
10
10
|
class Executor < Base
|
11
|
+
BASE_ONESHOT_INTERVAL = 0.3
|
12
|
+
BASE_REPEAT_INTERVAL = 0.1
|
13
|
+
|
14
|
+
# Executor parameter on config.yml
|
15
|
+
# @return [Array<Symbol>]
|
16
|
+
def execute_keys
|
17
|
+
# [name.split('Executors::').last.underscore.gsub('_executor', '').to_sym]
|
18
|
+
raise NotImplementedError, "override #{name}##{__method__}"
|
19
|
+
end
|
20
|
+
|
11
21
|
# check executable
|
12
|
-
# @param _event [Event]
|
22
|
+
# @param _event [Events::Event]
|
13
23
|
# @return [TrueClass, FalseClass]
|
14
24
|
def executable?(_event)
|
15
25
|
raise NotImplementedError, "override #{self.class.name}##{__method__}"
|
16
26
|
end
|
17
27
|
|
18
|
-
#
|
28
|
+
# @param event [Events::Event]
|
29
|
+
# @param time [Time]
|
30
|
+
# @return [TrueClass, FalseClass]
|
31
|
+
def enough_interval?(event)
|
32
|
+
# NOTE: Cache at the index that is actually used, reflecting Fallback and Skip.
|
33
|
+
# Otherwise, a wrong index will cause invalid intervals.
|
34
|
+
return true if event.record.index.with_context.keys.any? { |key| key.symbol == :end }
|
35
|
+
|
36
|
+
return false if @wait_until && event.time < @wait_until
|
37
|
+
|
38
|
+
true
|
39
|
+
end
|
40
|
+
|
41
|
+
def update_interval(event)
|
42
|
+
@wait_until = event.time + interval(event).to_f
|
43
|
+
end
|
44
|
+
|
45
|
+
def interval(event)
|
46
|
+
@interval_time ||= {}
|
47
|
+
index = event.record.index
|
48
|
+
@interval_time[index.cache_key] ||= begin
|
49
|
+
config_value =
|
50
|
+
Config.search(Config::Index.new([*index.keys, 'interval'])) ||
|
51
|
+
Config.search(Config::Index.new(['interval', Detectors::Detector.type(event.tag)]))
|
52
|
+
if event.record.trigger == :oneshot
|
53
|
+
(config_value || 1) * BASE_ONESHOT_INTERVAL
|
54
|
+
else
|
55
|
+
(config_value || 1) * BASE_REPEAT_INTERVAL
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# execute something
|
19
61
|
# @param _event [Event]
|
20
62
|
# @return [nil]
|
21
63
|
def execute(_event)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './filter
|
4
|
-
require_relative '../../device
|
3
|
+
require_relative './filter'
|
4
|
+
require_relative '../../device'
|
5
5
|
|
6
6
|
module Fusuma
|
7
7
|
module Plugin
|
@@ -25,15 +25,14 @@ module Fusuma
|
|
25
25
|
keep_device.reset
|
26
26
|
return false
|
27
27
|
end
|
28
|
-
|
29
|
-
keep_device.all.map(&:id).any? { |device_id| record.to_s =~ /^\s?#{device_id}\s/ }
|
28
|
+
keep_device.all.map(&:id).any? { |device_id| record.to_s =~ /^[\s-]?#{device_id}\s/ }
|
30
29
|
end
|
31
30
|
|
32
31
|
def keep_device
|
33
32
|
@keep_device ||= begin
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
from_config = Array(config_params(:keep_device_names))
|
34
|
+
KeepDevice.new(name_patterns: from_config)
|
35
|
+
end
|
37
36
|
end
|
38
37
|
|
39
38
|
def config_param_sample
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../base
|
4
|
-
require_relative '../events/event
|
3
|
+
require_relative '../base'
|
4
|
+
require_relative '../events/event'
|
5
5
|
|
6
6
|
module Fusuma
|
7
7
|
module Plugin
|
@@ -12,7 +12,7 @@ module Fusuma
|
|
12
12
|
# Wait multiple inputs until it becomes readable
|
13
13
|
# and read lines with nonblock
|
14
14
|
# @param inputs [Array<Input>]
|
15
|
-
# @return Event
|
15
|
+
# @return [Event]
|
16
16
|
def self.select(inputs)
|
17
17
|
ios = IO.select(inputs.map(&:io))
|
18
18
|
io = ios&.first&.first
|
@@ -21,14 +21,27 @@ module Fusuma
|
|
21
21
|
|
22
22
|
begin
|
23
23
|
line = io.readline_nonblock("\n").chomp
|
24
|
+
rescue EOFError => e
|
25
|
+
warn "#{input.class.name}: #{e}"
|
26
|
+
warn 'Send SIGKILL to fusuma processes'
|
27
|
+
inputs.reject { |i| i == input }.each do |i|
|
28
|
+
warn "stop process: #{i.class.name.underscore}"
|
29
|
+
Process.kill(:SIGKILL, i.pid)
|
30
|
+
end
|
31
|
+
exit 1
|
24
32
|
rescue StandardError => e
|
25
|
-
warn e
|
33
|
+
warn "#{input.class.name}: #{e}"
|
26
34
|
exit 1
|
27
35
|
end
|
28
36
|
|
29
37
|
input.create_event(record: line)
|
30
38
|
end
|
31
39
|
|
40
|
+
# @return [Integer]
|
41
|
+
def pid
|
42
|
+
raise NotImplementedError, "override #{self.class.name}##{__method__}"
|
43
|
+
end
|
44
|
+
|
32
45
|
# @return [IO]
|
33
46
|
def io
|
34
47
|
raise NotImplementedError, "override #{self.class.name}##{__method__}"
|
@@ -36,9 +49,9 @@ module Fusuma
|
|
36
49
|
|
37
50
|
# @return [Event]
|
38
51
|
def create_event(record: 'dummy input')
|
39
|
-
Events::Event.new(tag: tag, record: record)
|
40
|
-
|
41
|
-
|
52
|
+
e = Events::Event.new(tag: tag, record: record)
|
53
|
+
MultiLogger.debug(input_event: e)
|
54
|
+
e
|
42
55
|
end
|
43
56
|
|
44
57
|
def tag
|
@@ -1,20 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../../libinput_command
|
4
|
-
require_relative './input
|
3
|
+
require_relative '../../libinput_command'
|
4
|
+
require_relative './input'
|
5
5
|
|
6
6
|
module Fusuma
|
7
7
|
module Plugin
|
8
8
|
module Inputs
|
9
9
|
# libinput commands wrapper
|
10
10
|
class LibinputCommandInput < Input
|
11
|
+
attr_reader :pid
|
12
|
+
|
11
13
|
def config_param_types
|
12
14
|
{
|
13
|
-
|
15
|
+
device: [String],
|
14
16
|
'enable-dwt': [TrueClass, FalseClass],
|
15
17
|
'enable-tap': [TrueClass, FalseClass],
|
16
18
|
'show-keycodes': [TrueClass, FalseClass],
|
17
|
-
|
19
|
+
verbose: [TrueClass, FalseClass],
|
18
20
|
'libinput-debug-events': [String],
|
19
21
|
'libinput-list-devices': [String]
|
20
22
|
}
|
@@ -22,7 +24,11 @@ module Fusuma
|
|
22
24
|
|
23
25
|
# @return [IO]
|
24
26
|
def io
|
25
|
-
@io ||=
|
27
|
+
@io ||= begin
|
28
|
+
reader, writer = create_io
|
29
|
+
@pid = command.debug_events(writer)
|
30
|
+
reader
|
31
|
+
end
|
26
32
|
end
|
27
33
|
|
28
34
|
# @return [LibinputCommand]
|
@@ -59,6 +65,12 @@ module Fusuma
|
|
59
65
|
def list_devices_command
|
60
66
|
config_params(:'libinput-list-devices')
|
61
67
|
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def create_io
|
72
|
+
IO.pipe
|
73
|
+
end
|
62
74
|
end
|
63
75
|
end
|
64
76
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './input
|
3
|
+
require_relative './input'
|
4
4
|
|
5
5
|
module Fusuma
|
6
6
|
module Plugin
|
@@ -10,19 +10,19 @@ module Fusuma
|
|
10
10
|
DEFAULT_INTERVAL = 0.3
|
11
11
|
def config_param_types
|
12
12
|
{
|
13
|
-
|
13
|
+
interval: [Float]
|
14
14
|
}
|
15
15
|
end
|
16
16
|
|
17
|
-
attr_reader :
|
17
|
+
attr_reader :pid
|
18
18
|
|
19
19
|
def io
|
20
20
|
@io ||= begin
|
21
|
-
|
22
|
-
|
21
|
+
reader, writer = create_io
|
22
|
+
@pid = start(reader, writer)
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
reader
|
25
|
+
end
|
26
26
|
end
|
27
27
|
|
28
28
|
def start(reader, writer)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require_relative '../
|
3
|
+
require_relative '../multi_logger'
|
4
|
+
require_relative '../string_support'
|
5
5
|
|
6
6
|
module Fusuma
|
7
7
|
module Plugin
|
@@ -21,8 +21,19 @@ module Fusuma
|
|
21
21
|
def require_siblings_from_gems
|
22
22
|
search_key = File.join(plugin_dir_name, '*.rb')
|
23
23
|
Gem.find_latest_files(search_key).each do |siblings_plugin|
|
24
|
-
|
24
|
+
next unless siblings_plugin =~ %r{fusuma-plugin-(.+).*/lib/#{plugin_dir_name}/\1_.+.rb}
|
25
|
+
|
26
|
+
match_data = siblings_plugin.match(%r{(.*)/(.*)/lib/(.*)})
|
27
|
+
gemspec_path = Dir.glob("#{match_data[1]}/#{match_data[2]}/*.gemspec").first
|
28
|
+
raise "Not Found: #{match_data[1]}/#{match_data[2]}/*.gemspec" unless gemspec_path
|
29
|
+
|
30
|
+
gemspec = Gem::Specification.load(gemspec_path)
|
31
|
+
fusuma_gemspec_path = File.expand_path('../../../fusuma.gemspec', __dir__)
|
32
|
+
fusuma_gemspec = Gem::Specification.load(fusuma_gemspec_path)
|
33
|
+
if gemspec.dependencies.find { |d| d.name == 'fusuma' }&.match?(fusuma_gemspec)
|
25
34
|
require siblings_plugin
|
35
|
+
else
|
36
|
+
MultiLogger.warn "#{gemspec.name} #{gemspec.version} is incompatible with running #{fusuma_gemspec.name} #{fusuma_gemspec.version}"
|
26
37
|
end
|
27
38
|
end
|
28
39
|
end
|
@@ -58,14 +69,14 @@ module Fusuma
|
|
58
69
|
end
|
59
70
|
|
60
71
|
def require_base_plugins
|
61
|
-
require_relative './base
|
62
|
-
require_relative './events/event
|
63
|
-
require_relative './inputs/input
|
64
|
-
require_relative './filters/filter
|
65
|
-
require_relative './parsers/parser
|
66
|
-
require_relative './buffers/buffer
|
67
|
-
require_relative './detectors/detector
|
68
|
-
require_relative './executors/executor
|
72
|
+
require_relative './base'
|
73
|
+
require_relative './events/event'
|
74
|
+
require_relative './inputs/input'
|
75
|
+
require_relative './filters/filter'
|
76
|
+
require_relative './parsers/parser'
|
77
|
+
require_relative './buffers/buffer'
|
78
|
+
require_relative './detectors/detector'
|
79
|
+
require_relative './executors/executor'
|
69
80
|
end
|
70
81
|
|
71
82
|
def plugins
|
@@ -90,21 +101,3 @@ module Fusuma
|
|
90
101
|
end
|
91
102
|
end
|
92
103
|
end
|
93
|
-
|
94
|
-
# support camerize and underscore
|
95
|
-
class String
|
96
|
-
def camerize
|
97
|
-
split('_').map do |w|
|
98
|
-
w[0].upcase!
|
99
|
-
w
|
100
|
-
end.join
|
101
|
-
end
|
102
|
-
|
103
|
-
def underscore
|
104
|
-
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
105
|
-
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
106
|
-
.gsub('::', '/')
|
107
|
-
.tr('-', '_')
|
108
|
-
.downcase
|
109
|
-
end
|
110
|
-
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../events/records/record
|
4
|
-
require_relative '../events/records/gesture_record
|
3
|
+
require_relative '../events/records/record'
|
4
|
+
require_relative '../events/records/gesture_record'
|
5
5
|
|
6
6
|
module Fusuma
|
7
7
|
module Plugin
|
@@ -15,7 +15,7 @@ module Fusuma
|
|
15
15
|
def parse_record(record)
|
16
16
|
case line = record.to_s
|
17
17
|
when /GESTURE_SWIPE|GESTURE_PINCH/
|
18
|
-
gesture, status, finger,
|
18
|
+
gesture, status, finger, delta = parse_libinput(line)
|
19
19
|
else
|
20
20
|
return
|
21
21
|
end
|
@@ -23,7 +23,7 @@ module Fusuma
|
|
23
23
|
Events::Records::GestureRecord.new(status: status,
|
24
24
|
gesture: gesture,
|
25
25
|
finger: finger,
|
26
|
-
|
26
|
+
delta: delta)
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
@@ -32,8 +32,8 @@ module Fusuma
|
|
32
32
|
_device, event_name, _time, other = line.strip.split(nil, 4)
|
33
33
|
finger, other = other.split(nil, 2)
|
34
34
|
|
35
|
-
|
36
|
-
[*detect_gesture(event_name), finger,
|
35
|
+
delta = parse_delta(other)
|
36
|
+
[*detect_gesture(event_name), finger, delta]
|
37
37
|
end
|
38
38
|
|
39
39
|
def detect_gesture(event_name)
|
@@ -41,11 +41,13 @@ module Fusuma
|
|
41
41
|
[Regexp.last_match(1).downcase, Regexp.last_match(2).downcase]
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
44
|
+
def parse_delta(line)
|
45
45
|
return if line.nil?
|
46
46
|
|
47
|
-
move_x, move_y,
|
47
|
+
move_x, move_y, unaccelerated_x, unaccelerated_y, _, zoom, _, rotate =
|
48
|
+
line.tr('/|(|)', ' ').split
|
48
49
|
Events::Records::GestureRecord::Delta.new(move_x.to_f, move_y.to_f,
|
50
|
+
unaccelerated_x.to_f, unaccelerated_y.to_f,
|
49
51
|
zoom.to_f, rotate.to_f)
|
50
52
|
end
|
51
53
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../base
|
3
|
+
require_relative '../base'
|
4
4
|
|
5
5
|
module Fusuma
|
6
6
|
module Plugin
|
@@ -13,15 +13,14 @@ module Fusuma
|
|
13
13
|
# @param event [Event]
|
14
14
|
# @return [Event]
|
15
15
|
def parse(event)
|
16
|
-
event.
|
17
|
-
next if e.tag != source
|
16
|
+
return event if event.tag != source
|
18
17
|
|
19
|
-
|
20
|
-
|
18
|
+
new_record = parse_record(event.record)
|
19
|
+
return event if new_record.nil?
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
event.record = new_record
|
22
|
+
event.tag = tag
|
23
|
+
event
|
25
24
|
end
|
26
25
|
|
27
26
|
# Set source for tag from config.yml.
|
@@ -31,7 +30,7 @@ module Fusuma
|
|
31
30
|
end
|
32
31
|
|
33
32
|
def tag
|
34
|
-
self.class.name.split('::').last.underscore
|
33
|
+
@tag ||= self.class.name.split('::').last.underscore
|
35
34
|
end
|
36
35
|
|
37
36
|
# parse Record object
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# support camerize and underscore
|
4
|
+
class String
|
5
|
+
def camelize
|
6
|
+
split('_').map(&:capitalize).join
|
7
|
+
end
|
8
|
+
|
9
|
+
def underscore
|
10
|
+
gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
11
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
12
|
+
.gsub('::', '/')
|
13
|
+
.tr('-', '_')
|
14
|
+
.downcase
|
15
|
+
end
|
16
|
+
end
|