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.
- checksums.yaml +4 -4
- data/README.md +50 -11
- data/fusuma.gemspec +5 -6
- data/lib/fusuma.rb +87 -33
- data/lib/fusuma/config.rb +33 -40
- data/lib/fusuma/config/index.rb +34 -8
- data/lib/fusuma/config/searcher.rb +80 -4
- data/lib/fusuma/custom_process.rb +13 -0
- data/lib/fusuma/device.rb +19 -6
- data/lib/fusuma/environment.rb +4 -3
- data/lib/fusuma/hash_support.rb +40 -0
- data/lib/fusuma/libinput_command.rb +10 -15
- data/lib/fusuma/multi_logger.rb +2 -6
- data/lib/fusuma/plugin/base.rb +18 -15
- data/lib/fusuma/plugin/buffers/buffer.rb +3 -2
- data/lib/fusuma/plugin/buffers/gesture_buffer.rb +34 -25
- data/lib/fusuma/plugin/buffers/timer_buffer.rb +3 -3
- data/lib/fusuma/plugin/detectors/detector.rb +26 -5
- data/lib/fusuma/plugin/detectors/pinch_detector.rb +109 -58
- data/lib/fusuma/plugin/detectors/rotate_detector.rb +91 -50
- data/lib/fusuma/plugin/detectors/swipe_detector.rb +93 -56
- data/lib/fusuma/plugin/events/event.rb +5 -4
- data/lib/fusuma/plugin/events/records/context_record.rb +27 -0
- data/lib/fusuma/plugin/events/records/gesture_record.rb +9 -6
- data/lib/fusuma/plugin/events/records/index_record.rb +46 -14
- data/lib/fusuma/plugin/events/records/record.rb +1 -1
- data/lib/fusuma/plugin/events/records/text_record.rb +2 -1
- data/lib/fusuma/plugin/executors/command_executor.rb +21 -4
- data/lib/fusuma/plugin/executors/executor.rb +45 -3
- data/lib/fusuma/plugin/filters/filter.rb +1 -1
- data/lib/fusuma/plugin/filters/libinput_device_filter.rb +6 -7
- data/lib/fusuma/plugin/filters/libinput_timeout_filter.rb +2 -2
- data/lib/fusuma/plugin/inputs/input.rb +20 -7
- data/lib/fusuma/plugin/inputs/libinput_command_input.rb +17 -5
- data/lib/fusuma/plugin/inputs/timer_input.rb +7 -7
- data/lib/fusuma/plugin/manager.rb +22 -29
- data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +10 -8
- data/lib/fusuma/plugin/parsers/parser.rb +8 -9
- data/lib/fusuma/string_support.rb +16 -0
- data/lib/fusuma/version.rb +1 -1
- data/spec/helpers/config_helper.rb +20 -0
- data/spec/lib/config/searcher_spec.rb +97 -0
- data/spec/lib/config_spec.rb +112 -0
- data/spec/lib/custom_process_spec.rb +28 -0
- data/spec/lib/device_spec.rb +96 -0
- data/spec/lib/dummy_config.yml +31 -0
- data/spec/lib/fusuma_spec.rb +103 -0
- data/spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt +181 -0
- data/spec/lib/libinput-list-devices_magic_trackpad.txt +51 -0
- data/spec/lib/libinput-list-devices_razer_razer_blade.txt +252 -0
- data/spec/lib/libinput-list-devices_thejinx0r.txt +361 -0
- data/spec/lib/libinput-list-devices_unavailable.txt +36 -0
- data/spec/lib/libinput_command_spec.rb +160 -0
- data/spec/lib/plugin/base_spec.rb +74 -0
- data/spec/lib/plugin/buffers/buffer_spec.rb +80 -0
- data/spec/lib/plugin/buffers/dummy_buffer.rb +20 -0
- data/spec/lib/plugin/buffers/gesture_buffer_spec.rb +172 -0
- data/spec/lib/plugin/detectors/detector_spec.rb +43 -0
- data/spec/lib/plugin/detectors/dummy_detector.rb +24 -0
- data/spec/lib/plugin/detectors/pinch_detector_spec.rb +119 -0
- data/spec/lib/plugin/detectors/rotate_detector_spec.rb +125 -0
- data/spec/lib/plugin/detectors/swipe_detector_spec.rb +118 -0
- data/spec/lib/plugin/events/event_spec.rb +30 -0
- data/spec/lib/plugin/events/records/gesture_record_spec.rb +22 -0
- data/spec/lib/plugin/events/records/record_spec.rb +31 -0
- data/spec/lib/plugin/events/records/text_record_spec.rb +26 -0
- data/spec/lib/plugin/executors/command_executor_spec.rb +57 -0
- data/spec/lib/plugin/executors/executor_spec.rb +160 -0
- data/spec/lib/plugin/filters/filter_spec.rb +92 -0
- data/spec/lib/plugin/filters/libinput_filter_spec.rb +120 -0
- data/spec/lib/plugin/inputs/input_spec.rb +70 -0
- data/spec/lib/plugin/inputs/libinput_command_input_spec.rb +121 -0
- data/spec/lib/plugin/inputs/timer_input_spec.rb +40 -0
- data/spec/lib/plugin/manager_spec.rb +27 -0
- data/spec/lib/plugin/parsers/parser_spec.rb +45 -0
- data/spec/spec_helper.rb +20 -0
- metadata +84 -38
- data/.github/FUNDING.yml +0 -8
- data/.github/ISSUE_TEMPLATE/bug_report.md +0 -32
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -17
- data/.github/pull_request_template.md +0 -9
- data/.github/stale.yml +0 -18
- data/.gitignore +0 -17
- data/.reek.yml +0 -96
- data/.rspec +0 -2
- data/.rubocop.yml +0 -40
- data/.rubocop_todo.yml +0 -40
- data/.travis.yml +0 -11
- data/CHANGELOG.md +0 -456
- data/CODE_OF_CONDUCT.md +0 -74
- data/CONTRIBUTING.md +0 -72
- data/Gemfile +0 -18
- data/Rakefile +0 -15
@@ -1,48 +1,103 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './detector
|
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 =
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
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
|
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
|
58
|
-
|
112
|
+
def moved?(repeat_quantity)
|
113
|
+
repeat_quantity > 0.3
|
59
114
|
end
|
60
115
|
|
61
|
-
def
|
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
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
|
113
|
-
elsif @move_y
|
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
|
4
|
-
require_relative './records/record
|
5
|
-
require_relative './records/text_record
|
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
|
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
|
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, :
|
12
|
+
attr_reader :status, :gesture, :finger, :delta
|
13
13
|
|
14
|
-
Delta = Struct.new(:move_x, :move_y,
|
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
|
20
|
-
def initialize(status:, gesture:, finger:,
|
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
|
-
@
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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 './record
|
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
|
-
|
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 =
|
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
|