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,48 +1,103 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './detector.rb'
3
+ require_relative './detector'
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
7
7
  module Detectors
8
8
  class SwipeDetector < Detector
9
+ SOURCES = ['gesture'].freeze
9
10
  BUFFER_TYPE = 'gesture'
10
11
  GESTURE_RECORD_TYPE = 'swipe'
11
12
 
12
13
  FINGERS = [3, 4].freeze
13
- BASE_THERESHOLD = 10
14
- BASE_INTERVAL = 0.5
14
+ BASE_THERESHOLD = 25
15
15
 
16
16
  # @param buffers [Array<Buffers::Buffer>]
17
- # @return [Event] if event is detected
17
+ # @return [Events::Event] if event is detected
18
18
  # @return [NilClass] if event is NOT detected
19
19
  def detect(buffers)
20
- buffer = buffers.find { |b| b.type == BUFFER_TYPE }
21
- .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
22
-
23
- return if buffer.empty?
24
-
25
- move_x = buffer.avg_attrs(:move_x)
26
- move_y = buffer.avg_attrs(:move_y)
27
-
28
- finger = buffer.finger
29
- direction = Direction.new(move_x: move_x.to_f, move_y: move_y.to_f).to_s
30
- quantity = Quantity.new(move_x: move_x.to_f, move_y: move_y.to_f).to_f
31
-
32
- index = create_index(gesture: type,
33
- finger: finger,
34
- direction: direction)
35
-
36
- return unless enough?(index: index, quantity: quantity)
20
+ gesture_buffer = buffers.find { |b| b.type == BUFFER_TYPE }
21
+ .select_from_last_begin
22
+ .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
23
+
24
+ updating_events = gesture_buffer.updating_events
25
+ return if updating_events.empty?
26
+
27
+ updating_time = 100 * (updating_events.last.time - updating_events.first.time)
28
+ oneshot_move_x = gesture_buffer.sum_attrs(:move_x) / updating_time
29
+ oneshot_move_y = gesture_buffer.sum_attrs(:move_y) / updating_time
30
+
31
+ finger = gesture_buffer.finger
32
+ status = case gesture_buffer.events.last.record.status
33
+ when 'end'
34
+ 'end'
35
+ when 'update'
36
+ if updating_events.length == 1
37
+ 'begin'
38
+ else
39
+ 'update'
40
+ end
41
+ else
42
+ gesture_buffer.events.last.record.status
43
+ end
44
+
45
+ delta = if status == 'end'
46
+ gesture_buffer.events[-2].record.delta
47
+ else
48
+ gesture_buffer.events.last.record.delta
49
+ end
50
+
51
+ repeat_direction = Direction.new(move_x: delta.move_x, move_y: delta.move_y).to_s
52
+ repeat_quantity = Quantity.new(move_x: delta.move_x, move_y: delta.move_y).to_f
53
+
54
+ repeat_index = create_repeat_index(gesture: type, finger: finger,
55
+ direction: repeat_direction, status: status)
56
+
57
+ if status == 'update'
58
+ return unless moved?(repeat_quantity)
59
+
60
+ oneshot_direction = Direction.new(move_x: oneshot_move_x, move_y: oneshot_move_y).to_s
61
+ oneshot_quantity = Quantity.new(move_x: oneshot_move_x, move_y: oneshot_move_y).to_f
62
+ oneshot_index = create_oneshot_index(gesture: type, finger: finger,
63
+ direction: oneshot_direction)
64
+ if enough_oneshot_threshold?(index: oneshot_index, quantity: oneshot_quantity)
65
+ return [
66
+ create_event(record: Events::Records::IndexRecord.new(
67
+ index: oneshot_index, trigger: :oneshot, args: delta.to_h
68
+ )),
69
+ create_event(record: Events::Records::IndexRecord.new(
70
+ index: repeat_index, trigger: :repeat, args: delta.to_h
71
+ ))
72
+ ]
73
+ end
74
+ end
75
+ create_event(record: Events::Records::IndexRecord.new(
76
+ index: repeat_index, trigger: :repeat, args: delta.to_h
77
+ ))
78
+ end
37
79
 
38
- create_event(record: Events::Records::IndexRecord.new(index: index))
80
+ # @param [String] gesture
81
+ # @param [Integer] finger
82
+ # @param [String] direction
83
+ # @param [String] status
84
+ # @return [Config::Index]
85
+ def create_repeat_index(gesture:, finger:, direction:, status:)
86
+ Config::Index.new(
87
+ [
88
+ Config::Index::Key.new(gesture),
89
+ Config::Index::Key.new(finger.to_i),
90
+ Config::Index::Key.new(direction, skippable: true),
91
+ Config::Index::Key.new(status)
92
+ ]
93
+ )
39
94
  end
40
95
 
41
96
  # @param [String] gesture
42
97
  # @param [Integer] finger
43
98
  # @param [String] direction
44
99
  # @return [Config::Index]
45
- def create_index(gesture:, finger:, direction:)
100
+ def create_oneshot_index(gesture:, finger:, direction:)
46
101
  Config::Index.new(
47
102
  [
48
103
  Config::Index::Key.new(gesture),
@@ -54,41 +109,23 @@ module Fusuma
54
109
 
55
110
  private
56
111
 
57
- def enough?(index:, quantity:)
58
- enough_interval?(index: index) && enough_distance?(index: index, quantity: quantity)
112
+ def moved?(repeat_quantity)
113
+ repeat_quantity > 0.3
59
114
  end
60
115
 
61
- def enough_distance?(index:, quantity:)
116
+ def enough_oneshot_threshold?(index:, quantity:)
62
117
  quantity > threshold(index: index)
63
118
  end
64
119
 
65
- def enough_interval?(index:)
66
- return true if first_time?
67
- return true if (Time.now - last_time) > interval_time(index: index)
68
-
69
- false
70
- end
71
-
72
120
  def threshold(index:)
73
121
  @threshold ||= {}
74
122
  @threshold[index.cache_key] ||= begin
75
- keys_specific = Config::Index.new [*index.keys, 'threshold']
76
- keys_global = Config::Index.new ['threshold', type]
77
- config_value = Config.search(keys_specific) ||
78
- Config.search(keys_global) || 1
79
- BASE_THERESHOLD * config_value
80
- end
81
- end
82
-
83
- def interval_time(index:)
84
- @interval_time ||= {}
85
- @interval_time[index.cache_key] ||= begin
86
- keys_specific = Config::Index.new [*index.keys, 'interval']
87
- keys_global = Config::Index.new ['interval', type]
88
- config_value = Config.search(keys_specific) ||
89
- Config.search(keys_global) || 1
90
- BASE_INTERVAL * config_value
91
- end
123
+ keys_specific = Config::Index.new [*index.keys, 'threshold']
124
+ keys_global = Config::Index.new ['threshold', type]
125
+ config_value = Config.search(keys_specific) ||
126
+ Config.search(keys_global) || 1
127
+ BASE_THERESHOLD * config_value
128
+ end
92
129
  end
93
130
 
94
131
  # direction of gesture
@@ -99,8 +136,8 @@ module Fusuma
99
136
  UP = 'up'
100
137
 
101
138
  def initialize(move_x:, move_y:)
102
- @move_x = move_x
103
- @move_y = move_y
139
+ @move_x = move_x.to_f
140
+ @move_y = move_y.to_f
104
141
  end
105
142
 
106
143
  def to_s
@@ -109,8 +146,8 @@ module Fusuma
109
146
 
110
147
  def calc
111
148
  if @move_x.abs > @move_y.abs
112
- @move_x > 0 ? RIGHT : LEFT
113
- elsif @move_y > 0
149
+ @move_x.positive? ? RIGHT : LEFT
150
+ elsif @move_y.positive?
114
151
  DOWN
115
152
  else
116
153
  UP
@@ -121,8 +158,8 @@ module Fusuma
121
158
  # quantity of gesture
122
159
  class Quantity
123
160
  def initialize(move_x:, move_y:)
124
- @x = move_x.abs
125
- @y = move_y.abs
161
+ @x = move_x.to_f.abs
162
+ @y = move_y.to_f.abs
126
163
  end
127
164
 
128
165
  def to_f
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../base.rb'
4
- require_relative './records/record.rb'
5
- require_relative './records/text_record.rb'
3
+ require_relative '../base'
4
+ require_relative './records/record'
5
+ require_relative './records/text_record'
6
6
 
7
7
  module Fusuma
8
8
  module Plugin
@@ -15,7 +15,8 @@ module Fusuma
15
15
  # @param time [Time]
16
16
  # @param tag [Tag]
17
17
  # @param record [String, Record]
18
- def initialize(time: Time.now, tag:, record:)
18
+ def initialize(tag:, record:, time: Time.now)
19
+ super()
19
20
  @time = time
20
21
  @tag = tag
21
22
  @record = case record
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fusuma
4
+ module Plugin
5
+ module Events
6
+ module Records
7
+ # Context Record
8
+ class ContextRecord < Record
9
+ # define gesture format
10
+ attr_reader :name, :value
11
+
12
+ # @param name [#to_sym]
13
+ # @param value [String]
14
+ def initialize(name:, value:)
15
+ super()
16
+ @name = name.to_sym
17
+ @value = value
18
+ end
19
+
20
+ def type
21
+ :context
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './text_record.rb'
3
+ require_relative './text_record'
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
@@ -9,19 +9,22 @@ module Fusuma
9
9
  # Gesture Record
10
10
  class GestureRecord < Record
11
11
  # define gesture format
12
- attr_reader :status, :gesture, :finger, :direction
12
+ attr_reader :status, :gesture, :finger, :delta
13
13
 
14
- Delta = Struct.new(:move_x, :move_y, :zoom, :rotate)
14
+ Delta = Struct.new(:move_x, :move_y,
15
+ :unaccelerated_x, :unaccelerated_y,
16
+ :zoom, :rotate)
15
17
 
16
18
  # @param status [String]
17
19
  # @param gesture [String]
18
20
  # @param finger [String, Integer]
19
- # @param direction [Delta, NilClass]
20
- def initialize(status:, gesture:, finger:, direction:)
21
+ # @param delta [Delta, NilClass]
22
+ def initialize(status:, gesture:, finger:, delta:)
23
+ super()
21
24
  @status = status
22
25
  @gesture = gesture
23
26
  @finger = finger.to_i
24
- @direction = direction
27
+ @delta = delta
25
28
  end
26
29
  end
27
30
  end
@@ -8,36 +8,68 @@ module Fusuma
8
8
  # have index
9
9
  class IndexRecord < Record
10
10
  # define gesture format
11
- attr_reader :index
12
- attr_reader :position
11
+ attr_accessor :index
12
+ attr_reader :position, :trigger, :args
13
13
 
14
14
  # @param [Config::Index] index
15
15
  # @param [Symbol] position [:prefix, :body, :surfix]
16
- def initialize(index:, position: :body)
16
+ # @param [Symbol] trigger [:oneshot, :repeat]
17
+ def initialize(index:, position: :body, trigger: :oneshot, args: {})
18
+ super()
17
19
  @index = index
18
20
  @position = position
21
+ @trigger = trigger
22
+ @args = args
19
23
  end
20
24
 
21
25
  def type
22
26
  :index
23
27
  end
24
28
 
29
+ # FIXME: move to Config::Index
25
30
  # @param records [Array<IndexRecord>]
26
- # @return [IndexRecord]
27
- def merge(records:)
31
+ # @return [IndexRecord] when merge is succeeded
32
+ # @return [NilClass] when merge is not succeeded
33
+ def merge(records:, index: @index)
34
+ # FIXME: cache
28
35
  raise "position is NOT body: #{self}" unless mergable?
29
36
 
30
- @index = records.reduce(@index) do |merged_index, record|
31
- case record.position
32
- when :prefix
33
- Config::Index.new([*record.index.keys, *merged_index.keys])
34
- when :surfix
35
- Config::Index.new([*merged_index.keys, *record.index.keys])
36
- else
37
- raise "invalid index position: #{record}"
37
+ if records.empty?
38
+ if Config.find_execute_key(index)
39
+ @index = index
40
+ return self
38
41
  end
42
+ return nil
43
+ end
44
+
45
+ record = records.shift
46
+ new_index = case record.position
47
+ when :surfix
48
+ Config::Index.new([*index.keys, *record.index.keys])
49
+ else
50
+ raise "invalid index position: #{record}"
51
+ end
52
+
53
+ return unless exist_on_conf?(new_index)
54
+
55
+ merge(records: records, index: new_index)
56
+ end
57
+
58
+ # @param [Config::Searcher] searcher
59
+ def exist_on_conf?(index = @index)
60
+ Config.search(index)
61
+ end
62
+
63
+ # @return [Integer]
64
+ def trigger_priority
65
+ case @trigger
66
+ when :oneshot
67
+ 10
68
+ when :repeat
69
+ 100
70
+ else
71
+ 1000
39
72
  end
40
- self
41
73
  end
42
74
 
43
75
  def mergable?
@@ -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,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './record.rb'
3
+ require_relative './record'
4
4
 
5
5
  module Fusuma
6
6
  module Plugin
@@ -10,6 +10,7 @@ module Fusuma
10
10
  class TextRecord < Record
11
11
  # @param text [String]
12
12
  def initialize(text)
13
+ super()
13
14
  @text = text
14
15
  end
15
16
 
@@ -1,20 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'posix/spawn'
4
- require_relative './executor.rb'
3
+ require_relative './executor'
5
4
 
6
5
  module Fusuma
7
6
  module Plugin
8
7
  module Executors
9
8
  # Exector plugin
10
9
  class CommandExecutor < Executor
10
+ # Executor parameter on config.yml
11
+ # @return [Array<Symbol>]
12
+ def execute_keys
13
+ [:command]
14
+ end
15
+
11
16
  def execute(event)
12
17
  search_command(event).tap do |command|
13
18
  break unless command
14
19
 
15
- MultiLogger.info(command: command)
20
+ MultiLogger.info(command: command, args: event.record.args)
21
+
22
+ accel = args_accel(event)
23
+ additional_env = event.record.args
24
+ .deep_transform_keys(&:to_s)
25
+ .deep_transform_values { |v| (v * accel).to_s }
16
26
 
17
- pid = POSIX::Spawn.spawn(command.to_s)
27
+ pid = Process.spawn(additional_env, command.to_s)
18
28
  Process.detach(pid)
19
29
  end
20
30
  end
@@ -31,6 +41,13 @@ module Fusuma
31
41
  command_index = Config::Index.new([*event.record.index.keys, :command])
32
42
  Config.search(command_index)
33
43
  end
44
+
45
+ # @param event [Event]
46
+ # @return [Float]
47
+ def args_accel(event)
48
+ accel_index = Config::Index.new([*event.record.index.keys, :accel])
49
+ (Config.search(accel_index) || 1).to_f
50
+ end
34
51
  end
35
52
  end
36
53
  end