fusuma 0.11.1 → 1.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +8 -0
  3. data/.gitignore +6 -0
  4. data/.reek.yml +93 -45
  5. data/.rubocop.yml +2 -0
  6. data/.rubocop_todo.yml +16 -75
  7. data/Gemfile +2 -0
  8. data/README.md +12 -5
  9. data/Rakefile +2 -1
  10. data/bin/console +1 -1
  11. data/exe/fusuma +1 -0
  12. data/fusuma.gemspec +9 -2
  13. data/lib/fusuma.rb +88 -31
  14. data/lib/fusuma/config.rb +65 -66
  15. data/lib/fusuma/config/index.rb +49 -0
  16. data/lib/fusuma/device.rb +58 -37
  17. data/lib/fusuma/multi_logger.rb +3 -0
  18. data/lib/fusuma/plugin/base.rb +56 -0
  19. data/lib/fusuma/plugin/buffers/buffer.rb +41 -0
  20. data/lib/fusuma/plugin/buffers/gesture_buffer.rb +70 -0
  21. data/lib/fusuma/plugin/detectors/detector.rb +41 -0
  22. data/lib/fusuma/plugin/detectors/pinch_detector.rb +141 -0
  23. data/lib/fusuma/plugin/detectors/rotate_detector.rb +135 -0
  24. data/lib/fusuma/plugin/detectors/swipe_detector.rb +145 -0
  25. data/lib/fusuma/plugin/events/event.rb +38 -0
  26. data/lib/fusuma/plugin/events/records/gesture_record.rb +31 -0
  27. data/lib/fusuma/plugin/events/records/index_record.rb +53 -0
  28. data/lib/fusuma/plugin/events/records/record.rb +20 -0
  29. data/lib/fusuma/plugin/events/records/text_record.rb +28 -0
  30. data/lib/fusuma/plugin/executors/command_executor.rb +39 -0
  31. data/lib/fusuma/plugin/executors/executor.rb +27 -0
  32. data/lib/fusuma/plugin/filters/filter.rb +40 -0
  33. data/lib/fusuma/plugin/filters/libinput_device_filter.rb +42 -0
  34. data/lib/fusuma/plugin/inputs/input.rb +28 -0
  35. data/lib/fusuma/plugin/inputs/libinput_command_input.rb +133 -0
  36. data/lib/fusuma/plugin/manager.rb +118 -0
  37. data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +54 -0
  38. data/lib/fusuma/plugin/parsers/parser.rb +46 -0
  39. data/lib/fusuma/version.rb +3 -1
  40. metadata +74 -14
  41. data/lib/fusuma/command_executor.rb +0 -43
  42. data/lib/fusuma/event_stack.rb +0 -87
  43. data/lib/fusuma/gesture_event.rb +0 -50
  44. data/lib/fusuma/libinput_commands.rb +0 -98
  45. data/lib/fusuma/pinch.rb +0 -58
  46. data/lib/fusuma/swipe.rb +0 -59
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../multi_logger.rb'
4
+
5
+ module Fusuma
6
+ module Plugin
7
+ # Manage Fusuma plugins
8
+ class Manager
9
+ def initialize(plugin_class)
10
+ @plugin_class = plugin_class
11
+ end
12
+
13
+ def require_siblings_from_local
14
+ search_key = File.join('./lib', plugin_dir_name, '*.rb')
15
+ Dir.glob(search_key).each do |siblings_plugin|
16
+ require './' + siblings_plugin
17
+ end
18
+ end
19
+
20
+ def require_siblings_from_gems
21
+ search_key = File.join(plugin_dir_name, '*.rb')
22
+ Gem.find_files(search_key).each do |siblings_plugin|
23
+ if siblings_plugin =~ %r{fusuma-plugin-(.+).*/lib/#{plugin_dir_name}/\1_.+.rb}
24
+ require siblings_plugin
25
+ end
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def plugin_dir_name
32
+ @plugin_class.name.match(/(Fusuma::.*)::/)[1].to_s.underscore
33
+ end
34
+
35
+ class << self
36
+ # @example
37
+ # Manager.plugins
38
+ # => {"Base"=>[Detectors::Detector],
39
+ # "Detectors::Detector"=>[Detectors::RotateDetector,
40
+ # Detectors::PinchDetector,
41
+ # Detectors::SwipeDetector]}
42
+
43
+ # @param plugin_class [Class]
44
+ # return [Hash, false]
45
+ def add(plugin_class:, plugin_path:)
46
+ return false if exist?(plugin_class: plugin_class, plugin_path: plugin_path)
47
+
48
+ base = plugin_class.superclass.name
49
+ plugins[base] ||= []
50
+ plugins[base] << plugin_class
51
+
52
+ load_paths << plugin_path
53
+
54
+ manager = Manager.new(plugin_class)
55
+ manager.require_siblings_from_local
56
+ manager.require_siblings_from_gems
57
+ end
58
+
59
+ def require_plugins_from_relative
60
+ require_relative './base.rb'
61
+ require_relative './events/event.rb'
62
+ require_relative './inputs/input.rb'
63
+ require_relative './filters/filter.rb'
64
+ require_relative './parsers/parser.rb'
65
+ require_relative './buffers/buffer.rb'
66
+ require_relative './detectors/detector.rb'
67
+ require_relative './executors/executor.rb'
68
+ end
69
+
70
+ def require_plugins_from_config
71
+ local_plugin_paths = Config.search(Config::Index.new('local_plugin_paths'))
72
+ return unless local_plugin_paths
73
+
74
+ Array.new(local_plugin_paths).each do |plugin_path|
75
+ require plugin_path
76
+ end
77
+ end
78
+
79
+ def plugins
80
+ @plugins ||= {}
81
+ end
82
+
83
+ def load_paths
84
+ @load_paths ||= []
85
+ end
86
+
87
+ # @param plugin_class [Class]
88
+ # @return [Boolean]
89
+ def exist?(plugin_class:, plugin_path:)
90
+ return false if load_paths.include?(plugin_path)
91
+
92
+ base = plugin_class.superclass.name
93
+ return false unless plugins[base]
94
+
95
+ plugins[base].include?(plugin_class)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ # support camerize and underscore
103
+ class String
104
+ def camerize
105
+ split('_').map do |w|
106
+ w[0].upcase!
107
+ w
108
+ end.join
109
+ end
110
+
111
+ def underscore
112
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
113
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
114
+ .gsub('::', '/')
115
+ .tr('-', '_')
116
+ .downcase
117
+ end
118
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../events/records/record.rb'
4
+ require_relative '../events/records/gesture_record.rb'
5
+
6
+ module Fusuma
7
+ module Plugin
8
+ module Parsers
9
+ # parse libinput and generate gesture record
10
+ class LibinputGestureParser < Parser
11
+ DEFAULT_SOURCE = 'libinput_command_input'
12
+
13
+ # @param record [String]
14
+ # @return [Records::GestureRecord, nil]
15
+ def parse_record(record)
16
+ case line = record.to_s
17
+ when /GESTURE_SWIPE|GESTURE_PINCH/
18
+ gesture, status, finger, direction = parse_libinput(line)
19
+ else
20
+ return
21
+ end
22
+
23
+ Events::Records::GestureRecord.new(status: status,
24
+ gesture: gesture,
25
+ finger: finger,
26
+ direction: direction)
27
+ end
28
+
29
+ private
30
+
31
+ def parse_libinput(line)
32
+ _device, event_name, _time, other = line.strip.split(nil, 4)
33
+ finger, other = other.split(nil, 2)
34
+
35
+ direction = parse_direction(other)
36
+ [*detect_gesture(event_name), finger, direction]
37
+ end
38
+
39
+ def detect_gesture(event_name)
40
+ event_name =~ /GESTURE_(SWIPE|PINCH)_(BEGIN|UPDATE|END)/
41
+ [Regexp.last_match(1).downcase, Regexp.last_match(2).downcase]
42
+ end
43
+
44
+ def parse_direction(line)
45
+ return if line.nil?
46
+
47
+ move_x, move_y, _, _, _, zoom, _, rotate = line.tr('/|(|)', ' ').split
48
+ Events::Records::GestureRecord::Delta.new(move_x.to_f, move_y.to_f,
49
+ zoom.to_f, rotate.to_f)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base.rb'
4
+
5
+ module Fusuma
6
+ module Plugin
7
+ module Parsers
8
+ # Parser change record and tag in event
9
+ # Inherite this base class
10
+ class Parser < Base
11
+ # Parse Event and convert Record and Tag
12
+ # if `#parse_record` return nil, this method will return original event
13
+ # @param event [Event]
14
+ # @return [Event]
15
+ def parse(event)
16
+ event.tap do |e|
17
+ next if e.tag != source
18
+
19
+ new_record = parse_record(e.record)
20
+ next unless new_record
21
+
22
+ e.record = new_record
23
+ e.tag = tag
24
+ end
25
+ end
26
+
27
+ # Set source for tag from config.yml.
28
+ # DEFAULT_SOURCE is defined in each Parser plugins.
29
+ def source
30
+ @source ||= config_params(:source) || self.class.const_get('DEFAULT_SOURCE')
31
+ end
32
+
33
+ def tag
34
+ self.class.name.split('::').last.underscore
35
+ end
36
+
37
+ # parse Record object
38
+ # @param _record [Record]
39
+ # @return [Record, nil]
40
+ def parse_record(_record)
41
+ nil
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Fusuma
2
- VERSION = '0.11.1'.freeze
4
+ VERSION = '1.0'
3
5
  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: 0.11.1
4
+ version: '1.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-27 00:00:00.000000000 Z
11
+ date: 2019-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,20 +52,48 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry-doc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-inline
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: rake
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
87
  - - "~>"
60
88
  - !ruby/object:Gem::Version
61
- version: '12.3'
89
+ version: '13.0'
62
90
  type: :development
63
91
  prerelease: false
64
92
  version_requirements: !ruby/object:Gem::Requirement
65
93
  requirements:
66
94
  - - "~>"
67
95
  - !ruby/object:Gem::Version
68
- version: '12.3'
96
+ version: '13.0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: reek
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -108,8 +136,22 @@ dependencies:
108
136
  - - ">="
109
137
  - !ruby/object:Gem::Version
110
138
  version: '0'
111
- description: Fusuma is multitouch gesture recognizer. This gem makes your linux PC
112
- able to recognize swipes or pinchs and assign command to them. Read installation
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Fusuma is multitouch gesture recognizer. This gem makes your touchpad
154
+ on Linux able to recognize swipes or pinchs and assign command to them. Read installation
113
155
  on Github(https://github.com/iberianpig/fusuma#installation).
114
156
  email:
115
157
  - yhkyky@gmail.com
@@ -118,6 +160,7 @@ executables:
118
160
  extensions: []
119
161
  extra_rdoc_files: []
120
162
  files:
163
+ - ".github/FUNDING.yml"
121
164
  - ".github/ISSUE_TEMPLATE/bug_report.md"
122
165
  - ".github/ISSUE_TEMPLATE/feature_request.md"
123
166
  - ".github/stale.yml"
@@ -138,21 +181,38 @@ files:
138
181
  - exe/fusuma
139
182
  - fusuma.gemspec
140
183
  - lib/fusuma.rb
141
- - lib/fusuma/command_executor.rb
142
184
  - lib/fusuma/config.rb
143
185
  - lib/fusuma/config.yml
186
+ - lib/fusuma/config/index.rb
144
187
  - lib/fusuma/device.rb
145
- - lib/fusuma/event_stack.rb
146
- - lib/fusuma/gesture_event.rb
147
- - lib/fusuma/libinput_commands.rb
148
188
  - lib/fusuma/multi_logger.rb
149
- - lib/fusuma/pinch.rb
150
- - lib/fusuma/swipe.rb
189
+ - lib/fusuma/plugin/base.rb
190
+ - lib/fusuma/plugin/buffers/buffer.rb
191
+ - lib/fusuma/plugin/buffers/gesture_buffer.rb
192
+ - lib/fusuma/plugin/detectors/detector.rb
193
+ - lib/fusuma/plugin/detectors/pinch_detector.rb
194
+ - lib/fusuma/plugin/detectors/rotate_detector.rb
195
+ - lib/fusuma/plugin/detectors/swipe_detector.rb
196
+ - lib/fusuma/plugin/events/event.rb
197
+ - lib/fusuma/plugin/events/records/gesture_record.rb
198
+ - lib/fusuma/plugin/events/records/index_record.rb
199
+ - lib/fusuma/plugin/events/records/record.rb
200
+ - lib/fusuma/plugin/events/records/text_record.rb
201
+ - lib/fusuma/plugin/executors/command_executor.rb
202
+ - lib/fusuma/plugin/executors/executor.rb
203
+ - lib/fusuma/plugin/filters/filter.rb
204
+ - lib/fusuma/plugin/filters/libinput_device_filter.rb
205
+ - lib/fusuma/plugin/inputs/input.rb
206
+ - lib/fusuma/plugin/inputs/libinput_command_input.rb
207
+ - lib/fusuma/plugin/manager.rb
208
+ - lib/fusuma/plugin/parsers/libinput_gesture_parser.rb
209
+ - lib/fusuma/plugin/parsers/parser.rb
151
210
  - lib/fusuma/version.rb
152
211
  homepage: https://github.com/iberianpig/fusuma
153
212
  licenses:
154
213
  - MIT
155
- metadata: {}
214
+ metadata:
215
+ yard.run: yri
156
216
  post_install_message:
157
217
  rdoc_options: []
158
218
  require_paths:
@@ -161,7 +221,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
221
  requirements:
162
222
  - - ">="
163
223
  - !ruby/object:Gem::Version
164
- version: '0'
224
+ version: '2.3'
165
225
  required_rubygems_version: !ruby/object:Gem::Requirement
166
226
  requirements:
167
227
  - - ">="
@@ -1,43 +0,0 @@
1
- module Fusuma
2
- # Execute Command
3
- class CommandExecutor
4
- def initialize(finger, vector)
5
- @finger = finger.to_i
6
- @direction = vector.direction
7
- @event_type = vector.class::TYPE
8
- end
9
- attr_reader :finger, :direction, :event_type
10
-
11
- def execute
12
- pid = fork {
13
- Process.daemon(true)
14
- exec("#{command_or_shortcut}")
15
- }
16
- Process.detach(pid)
17
- MultiLogger.info("Execute: #{command_or_shortcut}")
18
- end
19
-
20
- private
21
-
22
- def command_or_shortcut
23
- @command_or_shortcut ||= command || shortcut || no_command
24
- end
25
-
26
- def command
27
- Config.command(self)
28
- end
29
-
30
- def shortcut
31
- s = Config.shortcut(self)
32
- return unless s
33
- c = "xdotool key #{s}"
34
- MultiLogger.warn 'shortcut property is deprecated.'
35
- MultiLogger.warn "Use command: #{c} instead of shortcut: #{s}"
36
- c
37
- end
38
-
39
- def no_command
40
- 'echo "Command is not assigned"'
41
- end
42
- end
43
- end
@@ -1,87 +0,0 @@
1
- module Fusuma
2
- # manage events and generate command
3
- class EventStack < Array
4
- ELAPSED_TIME = 0.01
5
-
6
- def initialize(*args)
7
- super(*args)
8
- end
9
-
10
- # @return [CommandExecutor, nil]
11
- def generate_command_executor
12
- return unless enough_events?
13
- vector = generate_vector(detect_event_type)
14
- trigger = CommandExecutor.new(finger, vector)
15
- return unless vector.enough?(trigger)
16
- clear
17
- trigger
18
- end
19
-
20
- # @params [GestureEvent]
21
- def push(gesture_event)
22
- super(gesture_event)
23
- clear if event_end?
24
- end
25
- alias << push
26
-
27
- private
28
-
29
- def generate_vector(event_type)
30
- case event_type
31
- when 'swipe'
32
- avg_swipe
33
- when 'pinch'
34
- avg_pinch
35
- end
36
- end
37
-
38
- def finger
39
- last.finger
40
- end
41
-
42
- def avg_swipe
43
- move_x = avg_attrs(:move_x)
44
- move_y = avg_attrs(:move_y)
45
- Swipe.new(move_x, move_y)
46
- end
47
-
48
- def avg_pinch
49
- diameter = avg_attrs(:zoom)
50
- delta_diameter = diameter - first.zoom
51
- Pinch.new(delta_diameter)
52
- end
53
-
54
- def sum_attrs(attr)
55
- send('map') do |gesture_event|
56
- gesture_event.send(attr.to_sym.to_s)
57
- end.compact.inject(:+)
58
- end
59
-
60
- def avg_attrs(attr)
61
- sum_attrs(attr) / length
62
- end
63
-
64
- def event_end?
65
- last_event_name =~ /_END$/
66
- end
67
-
68
- def last_event_name
69
- return false if last.class != GestureEvent
70
- last.event
71
- end
72
-
73
- def enough_events?
74
- length > 2
75
- end
76
-
77
- def enough_elapsed_time?
78
- return false if length.zero?
79
- (last.time - first.time) > ELAPSED_TIME
80
- end
81
-
82
- def detect_event_type
83
- first.event =~ /GESTURE_(.*?)_/
84
- Regexp.last_match(1).downcase
85
- end
86
- end
87
- end