fusuma 2.0.0.pre → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
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