fusuma 0.11.1 → 1.0

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