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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +50 -11
  3. data/fusuma.gemspec +5 -6
  4. data/lib/fusuma.rb +87 -33
  5. data/lib/fusuma/config.rb +33 -40
  6. data/lib/fusuma/config/index.rb +34 -8
  7. data/lib/fusuma/config/searcher.rb +80 -4
  8. data/lib/fusuma/custom_process.rb +13 -0
  9. data/lib/fusuma/device.rb +19 -6
  10. data/lib/fusuma/environment.rb +4 -3
  11. data/lib/fusuma/hash_support.rb +40 -0
  12. data/lib/fusuma/libinput_command.rb +10 -15
  13. data/lib/fusuma/multi_logger.rb +2 -6
  14. data/lib/fusuma/plugin/base.rb +18 -15
  15. data/lib/fusuma/plugin/buffers/buffer.rb +3 -2
  16. data/lib/fusuma/plugin/buffers/gesture_buffer.rb +34 -25
  17. data/lib/fusuma/plugin/buffers/timer_buffer.rb +3 -3
  18. data/lib/fusuma/plugin/detectors/detector.rb +26 -5
  19. data/lib/fusuma/plugin/detectors/pinch_detector.rb +109 -58
  20. data/lib/fusuma/plugin/detectors/rotate_detector.rb +91 -50
  21. data/lib/fusuma/plugin/detectors/swipe_detector.rb +93 -56
  22. data/lib/fusuma/plugin/events/event.rb +5 -4
  23. data/lib/fusuma/plugin/events/records/context_record.rb +27 -0
  24. data/lib/fusuma/plugin/events/records/gesture_record.rb +9 -6
  25. data/lib/fusuma/plugin/events/records/index_record.rb +46 -14
  26. data/lib/fusuma/plugin/events/records/record.rb +1 -1
  27. data/lib/fusuma/plugin/events/records/text_record.rb +2 -1
  28. data/lib/fusuma/plugin/executors/command_executor.rb +21 -4
  29. data/lib/fusuma/plugin/executors/executor.rb +45 -3
  30. data/lib/fusuma/plugin/filters/filter.rb +1 -1
  31. data/lib/fusuma/plugin/filters/libinput_device_filter.rb +6 -7
  32. data/lib/fusuma/plugin/filters/libinput_timeout_filter.rb +2 -2
  33. data/lib/fusuma/plugin/inputs/input.rb +20 -7
  34. data/lib/fusuma/plugin/inputs/libinput_command_input.rb +17 -5
  35. data/lib/fusuma/plugin/inputs/timer_input.rb +7 -7
  36. data/lib/fusuma/plugin/manager.rb +22 -29
  37. data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +10 -8
  38. data/lib/fusuma/plugin/parsers/parser.rb +8 -9
  39. data/lib/fusuma/string_support.rb +16 -0
  40. data/lib/fusuma/version.rb +1 -1
  41. data/spec/helpers/config_helper.rb +20 -0
  42. data/spec/lib/config/searcher_spec.rb +97 -0
  43. data/spec/lib/config_spec.rb +112 -0
  44. data/spec/lib/custom_process_spec.rb +28 -0
  45. data/spec/lib/device_spec.rb +96 -0
  46. data/spec/lib/dummy_config.yml +31 -0
  47. data/spec/lib/fusuma_spec.rb +103 -0
  48. data/spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt +181 -0
  49. data/spec/lib/libinput-list-devices_magic_trackpad.txt +51 -0
  50. data/spec/lib/libinput-list-devices_razer_razer_blade.txt +252 -0
  51. data/spec/lib/libinput-list-devices_thejinx0r.txt +361 -0
  52. data/spec/lib/libinput-list-devices_unavailable.txt +36 -0
  53. data/spec/lib/libinput_command_spec.rb +160 -0
  54. data/spec/lib/plugin/base_spec.rb +74 -0
  55. data/spec/lib/plugin/buffers/buffer_spec.rb +80 -0
  56. data/spec/lib/plugin/buffers/dummy_buffer.rb +20 -0
  57. data/spec/lib/plugin/buffers/gesture_buffer_spec.rb +172 -0
  58. data/spec/lib/plugin/detectors/detector_spec.rb +43 -0
  59. data/spec/lib/plugin/detectors/dummy_detector.rb +24 -0
  60. data/spec/lib/plugin/detectors/pinch_detector_spec.rb +119 -0
  61. data/spec/lib/plugin/detectors/rotate_detector_spec.rb +125 -0
  62. data/spec/lib/plugin/detectors/swipe_detector_spec.rb +118 -0
  63. data/spec/lib/plugin/events/event_spec.rb +30 -0
  64. data/spec/lib/plugin/events/records/gesture_record_spec.rb +22 -0
  65. data/spec/lib/plugin/events/records/record_spec.rb +31 -0
  66. data/spec/lib/plugin/events/records/text_record_spec.rb +26 -0
  67. data/spec/lib/plugin/executors/command_executor_spec.rb +57 -0
  68. data/spec/lib/plugin/executors/executor_spec.rb +160 -0
  69. data/spec/lib/plugin/filters/filter_spec.rb +92 -0
  70. data/spec/lib/plugin/filters/libinput_filter_spec.rb +120 -0
  71. data/spec/lib/plugin/inputs/input_spec.rb +70 -0
  72. data/spec/lib/plugin/inputs/libinput_command_input_spec.rb +121 -0
  73. data/spec/lib/plugin/inputs/timer_input_spec.rb +40 -0
  74. data/spec/lib/plugin/manager_spec.rb +27 -0
  75. data/spec/lib/plugin/parsers/parser_spec.rb +45 -0
  76. data/spec/spec_helper.rb +20 -0
  77. metadata +84 -38
  78. data/.github/FUNDING.yml +0 -8
  79. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
  80. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
  81. data/.github/pull_request_template.md +0 -9
  82. data/.github/stale.yml +0 -18
  83. data/.gitignore +0 -17
  84. data/.reek.yml +0 -96
  85. data/.rspec +0 -2
  86. data/.rubocop.yml +0 -40
  87. data/.rubocop_todo.yml +0 -40
  88. data/.travis.yml +0 -11
  89. data/CHANGELOG.md +0 -456
  90. data/CODE_OF_CONDUCT.md +0 -74
  91. data/CONTRIBUTING.md +0 -72
  92. data/Gemfile +0 -18
  93. data/Rakefile +0 -15
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base.rb'
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
- # execute somthing
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,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base.rb'
3
+ require_relative '../base'
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './filter.rb'
4
- require_relative '../../device.rb'
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
- from_config = Array(config_params(:keep_device_names))
35
- KeepDevice.new(name_patterns: from_config)
36
- end
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 './filter.rb'
4
- require_relative '../../libinput_command.rb'
3
+ require_relative './filter'
4
+ require_relative '../../libinput_command'
5
5
 
6
6
  module Fusuma
7
7
  module Plugin
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base.rb'
4
- require_relative '../events/event.rb'
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).tap do |e|
40
- MultiLogger.debug(input_event: e)
41
- end
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.rb'
4
- require_relative './input.rb'
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
- 'device': [String],
15
+ device: [String],
14
16
  'enable-dwt': [TrueClass, FalseClass],
15
17
  'enable-tap': [TrueClass, FalseClass],
16
18
  'show-keycodes': [TrueClass, FalseClass],
17
- 'verbose': [TrueClass, FalseClass],
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 ||= command.debug_events
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.rb'
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
- 'interval': [Float]
13
+ interval: [Float]
14
14
  }
15
15
  end
16
16
 
17
- attr_reader :writer
17
+ attr_reader :pid
18
18
 
19
19
  def io
20
20
  @io ||= begin
21
- reader, writer = create_io
22
- @pid = start(reader, writer)
21
+ reader, writer = create_io
22
+ @pid = start(reader, writer)
23
23
 
24
- reader
25
- end
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
- require 'pathname'
4
- require_relative '../multi_logger.rb'
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
- if siblings_plugin =~ %r{fusuma-plugin-(.+).*/lib/#{plugin_dir_name}/\1_.+.rb}
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.rb'
62
- require_relative './events/event.rb'
63
- require_relative './inputs/input.rb'
64
- require_relative './filters/filter.rb'
65
- require_relative './parsers/parser.rb'
66
- require_relative './buffers/buffer.rb'
67
- require_relative './detectors/detector.rb'
68
- require_relative './executors/executor.rb'
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.rb'
4
- require_relative '../events/records/gesture_record.rb'
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, direction = parse_libinput(line)
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
- direction: direction)
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
- direction = parse_direction(other)
36
- [*detect_gesture(event_name), finger, direction]
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 parse_direction(line)
44
+ def parse_delta(line)
45
45
  return if line.nil?
46
46
 
47
- move_x, move_y, _, _, _, zoom, _, rotate = line.tr('/|(|)', ' ').split
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.rb'
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.tap do |e|
17
- next if e.tag != source
16
+ return event if event.tag != source
18
17
 
19
- new_record = parse_record(e.record)
20
- next unless new_record
18
+ new_record = parse_record(event.record)
19
+ return event if new_record.nil?
21
20
 
22
- e.record = new_record
23
- e.tag = tag
24
- end
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