fusuma 2.0.3 → 2.2.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.
- checksums.yaml +4 -4
- data/README.md +77 -51
- data/exe/fusuma +5 -0
- data/fusuma.gemspec +4 -1
- data/lib/fusuma/config/searcher.rb +1 -2
- data/lib/fusuma/config.rb +1 -1
- data/lib/fusuma/environment.rb +1 -1
- data/lib/fusuma/libinput_command.rb +7 -9
- data/lib/fusuma/multi_logger.rb +12 -1
- data/lib/fusuma/plugin/buffers/gesture_buffer.rb +6 -1
- data/lib/fusuma/plugin/buffers/timer_buffer.rb +1 -3
- data/lib/fusuma/plugin/detectors/hold_detector.rb +129 -0
- data/lib/fusuma/plugin/detectors/pinch_detector.rb +9 -2
- data/lib/fusuma/plugin/detectors/rotate_detector.rb +8 -2
- data/lib/fusuma/plugin/detectors/swipe_detector.rb +11 -3
- data/lib/fusuma/plugin/executors/command_executor.rb +10 -10
- data/lib/fusuma/plugin/executors/executor.rb +1 -1
- data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +9 -4
- data/lib/fusuma/version.rb +1 -1
- data/lib/fusuma.rb +12 -4
- data/spec/lib/config/searcher_spec.rb +142 -60
- data/spec/lib/config_spec.rb +0 -8
- data/spec/lib/libinput_command_spec.rb +9 -5
- data/spec/lib/plugin/buffers/gesture_buffer_spec.rb +34 -14
- data/spec/lib/plugin/detectors/detector_spec.rb +1 -1
- data/spec/lib/plugin/detectors/hold_detector_spec.rb +145 -0
- data/spec/lib/plugin/executors/executor_spec.rb +10 -6
- data/spec/lib/plugin/parsers/libinput_gesture_parser_spec.rb +76 -0
- metadata +38 -33
- data/lib/fusuma/plugin/filters/libinput_timeout_filter.rb +0 -21
@@ -24,9 +24,17 @@ module Fusuma
|
|
24
24
|
updating_events = gesture_buffer.updating_events
|
25
25
|
return if updating_events.empty?
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
oneshot_move_x, oneshot_move_y = if updating_events.size >= 10
|
28
|
+
updating_time = 100 * (updating_events[-1].time - updating_events[-10].time)
|
29
|
+
last_10 = gesture_buffer.class.new(updating_events[-10..-1])
|
30
|
+
[last_10.sum_attrs(:move_x) / updating_time,
|
31
|
+
last_10.sum_attrs(:move_y) / updating_time]
|
32
|
+
else
|
33
|
+
updating_time = 100 * (updating_events.last.time - updating_events.first.time)
|
34
|
+
[gesture_buffer.sum_attrs(:move_x) / updating_time,
|
35
|
+
gesture_buffer.sum_attrs(:move_y) / updating_time]
|
36
|
+
end
|
37
|
+
gesture_buffer.sum_attrs(:move_x) / updating_time
|
30
38
|
|
31
39
|
finger = gesture_buffer.finger
|
32
40
|
status = case gesture_buffer.events.last.record.status
|
@@ -14,19 +14,19 @@ module Fusuma
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def execute(event)
|
17
|
-
search_command(event)
|
18
|
-
break unless command
|
17
|
+
command = search_command(event)
|
19
18
|
|
20
|
-
|
19
|
+
MultiLogger.info(command: command, args: event.record.args)
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
accel = args_accel(event)
|
22
|
+
additional_env = event.record.args
|
23
|
+
.deep_transform_keys(&:to_s)
|
24
|
+
.deep_transform_values { |v| (v * accel).to_s }
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
pid = Process.spawn(additional_env, command.to_s)
|
27
|
+
Process.detach(pid)
|
28
|
+
rescue SystemCallError => e
|
29
|
+
MultiLogger.error("#{event.record.index.keys}": e.message.to_s)
|
30
30
|
end
|
31
31
|
|
32
32
|
def executable?(event)
|
@@ -15,7 +15,7 @@ module Fusuma
|
|
15
15
|
# @return [Array<Symbol>]
|
16
16
|
def execute_keys
|
17
17
|
# [name.split('Executors::').last.underscore.gsub('_executor', '').to_sym]
|
18
|
-
raise NotImplementedError, "override #{name}##{__method__}"
|
18
|
+
raise NotImplementedError, "override #{self.class.name}##{__method__}"
|
19
19
|
end
|
20
20
|
|
21
21
|
# check executable
|
@@ -14,7 +14,7 @@ module Fusuma
|
|
14
14
|
# @return [Records::GestureRecord, nil]
|
15
15
|
def parse_record(record)
|
16
16
|
case line = record.to_s
|
17
|
-
when /GESTURE_SWIPE|GESTURE_PINCH/
|
17
|
+
when /GESTURE_SWIPE|GESTURE_PINCH|GESTURE_HOLD/
|
18
18
|
gesture, status, finger, delta = parse_libinput(line)
|
19
19
|
else
|
20
20
|
return
|
@@ -32,13 +32,18 @@ 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
|
+
gesture, status = *detect_gesture(event_name)
|
36
|
+
|
37
|
+
status = 'cancelled' if gesture == 'hold' && status == 'end' && other == 'cancelled'
|
35
38
|
delta = parse_delta(other)
|
36
|
-
[
|
39
|
+
[gesture, status, finger, delta]
|
37
40
|
end
|
38
41
|
|
39
42
|
def detect_gesture(event_name)
|
40
|
-
event_name =~ /GESTURE_(SWIPE|PINCH)_(BEGIN|UPDATE|END)/
|
41
|
-
|
43
|
+
event_name =~ /GESTURE_(SWIPE|PINCH|HOLD)_(BEGIN|UPDATE|END)/
|
44
|
+
gesture = Regexp.last_match(1).downcase
|
45
|
+
status = Regexp.last_match(2).downcase
|
46
|
+
[gesture, status]
|
42
47
|
end
|
43
48
|
|
44
49
|
def parse_delta(line)
|
data/lib/fusuma/version.rb
CHANGED
data/lib/fusuma.rb
CHANGED
@@ -29,6 +29,7 @@ module Fusuma
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def read_options(option)
|
32
|
+
MultiLogger.filepath = option[:log_filepath]
|
32
33
|
MultiLogger.instance.debug_mode = option[:verbose]
|
33
34
|
|
34
35
|
load_custom_config(option[:config_path])
|
@@ -142,19 +143,26 @@ module Fusuma
|
|
142
143
|
end
|
143
144
|
main_events.sort_by! { |e| e.record.trigger_priority }
|
144
145
|
|
145
|
-
|
146
|
+
matched_condition = nil
|
146
147
|
matched_context = nil
|
147
148
|
event = main_events.find do |main_event|
|
148
149
|
matched_context = Config::Searcher.find_context(request_context) do
|
149
|
-
|
150
|
+
matched_condition, modified_record = Config::Searcher.find_condition do
|
150
151
|
main_event.record.merge(records: modifiers.map(&:record))
|
151
152
|
end
|
152
|
-
|
153
|
+
if matched_condition && modified_record
|
154
|
+
main_event.record = modified_record
|
155
|
+
else
|
156
|
+
matched_condition, = Config::Searcher.find_condition do
|
157
|
+
Config.search(main_event.record.index) &&
|
158
|
+
Config.find_execute_key(main_event.record.index)
|
159
|
+
end
|
160
|
+
end
|
153
161
|
end
|
154
162
|
end
|
155
163
|
return if event.nil?
|
156
164
|
|
157
|
-
[
|
165
|
+
[matched_condition, matched_context, event]
|
158
166
|
end
|
159
167
|
|
160
168
|
# @param event [Plugin::Events::Event]
|
@@ -7,80 +7,162 @@ require './lib/fusuma/config/searcher'
|
|
7
7
|
# spec for Config
|
8
8
|
module Fusuma
|
9
9
|
RSpec.describe Config::Searcher do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
3
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
10
|
+
around do |example|
|
11
|
+
ConfigHelper.load_config_yml = <<~CONFIG
|
12
|
+
swipe:
|
13
|
+
3:
|
14
|
+
left:
|
15
|
+
command: 'alt+Left'
|
16
|
+
right:
|
17
|
+
command: 'alt+Right'
|
18
|
+
4:
|
19
|
+
left:
|
20
|
+
command: 'super+Left'
|
21
|
+
right:
|
22
|
+
command: 'super+Right'
|
23
|
+
pinch:
|
24
|
+
in:
|
25
|
+
command: 'ctrl+plus'
|
26
|
+
out:
|
27
|
+
command: 'ctrl+minus'
|
28
|
+
CONFIG
|
28
29
|
|
29
|
-
|
30
|
-
{
|
31
|
-
'swipe' => {
|
32
|
-
'left' => { 'command' => 'alt+Left' }
|
33
|
-
}
|
34
|
-
}
|
35
|
-
end
|
30
|
+
example.run
|
36
31
|
|
37
|
-
|
38
|
-
before { Singleton.__init__(Config) }
|
39
|
-
it 'should reload keymap file' do
|
40
|
-
keymap = Config.instance.keymap
|
41
|
-
Config.custom_path = './spec/lib/dummy_config.yml'
|
42
|
-
custom_keymap = Config.instance.keymap
|
43
|
-
expect(keymap).not_to eq custom_keymap
|
44
|
-
end
|
32
|
+
ConfigHelper.clear_config_yml
|
45
33
|
end
|
46
34
|
|
47
35
|
describe '.search' do
|
48
36
|
let(:index) { nil }
|
49
|
-
|
37
|
+
let(:location) { Config.instance.keymap[0] }
|
38
|
+
let(:search) { Config::Searcher.new.search(index, location: location) }
|
50
39
|
context 'index correct order' do
|
51
40
|
let(:index) { Config::Index.new %w[pinch in command] }
|
52
|
-
it {
|
41
|
+
it { expect(Config::Searcher.new.search(index, location: location)).to eq 'ctrl+plus' }
|
53
42
|
end
|
54
43
|
|
55
|
-
context 'index
|
56
|
-
let(:index)
|
57
|
-
|
58
|
-
Config::Index::Key.new('pinch'),
|
59
|
-
Config::Index::Key.new(2, skippable: true),
|
60
|
-
Config::Index::Key.new('out'),
|
61
|
-
Config::Index::Key.new('command')
|
62
|
-
]
|
63
|
-
end
|
64
|
-
it { expect(Config::Searcher.skip { subject }).to eq 'ctrl+minus' }
|
44
|
+
context 'index incorrect order' do
|
45
|
+
let(:index) { Config::Index.new %w[in pinch 2 command] }
|
46
|
+
it { expect(Config::Searcher.new.search(index, location: location)).not_to eq 'ctrl+plus' }
|
65
47
|
end
|
66
48
|
|
67
|
-
context '
|
68
|
-
|
69
|
-
|
70
|
-
Config::Index
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
49
|
+
context 'with Skip condtions' do
|
50
|
+
context 'when index includes skippable key' do
|
51
|
+
let(:index) do
|
52
|
+
Config::Index.new [
|
53
|
+
Config::Index::Key.new('pinch'),
|
54
|
+
Config::Index::Key.new(2, skippable: true),
|
55
|
+
Config::Index::Key.new('out'),
|
56
|
+
Config::Index::Key.new('command')
|
57
|
+
]
|
58
|
+
end
|
59
|
+
it 'detects ctrl+minus with skip' do
|
60
|
+
condition, value = Config::Searcher.find_condition do
|
61
|
+
Config::Searcher.new.search(index, location: location)
|
62
|
+
end
|
63
|
+
expect([condition, value]).to eq([:skip, 'ctrl+minus'])
|
64
|
+
end
|
77
65
|
end
|
78
|
-
it { expect(Config::Searcher.skip { subject }).to eq 'ctrl+plus' }
|
79
|
-
end
|
80
66
|
|
81
|
-
|
82
|
-
|
83
|
-
|
67
|
+
context 'when index includes skippable key at first' do
|
68
|
+
let(:index) do
|
69
|
+
Config::Index.new [
|
70
|
+
Config::Index::Key.new(:hoge, skippable: true),
|
71
|
+
Config::Index::Key.new(:fuga, skippable: true),
|
72
|
+
Config::Index::Key.new('pinch'),
|
73
|
+
Config::Index::Key.new('in'),
|
74
|
+
Config::Index::Key.new(:piyo, skippable: true),
|
75
|
+
Config::Index::Key.new('command')
|
76
|
+
]
|
77
|
+
end
|
78
|
+
it 'detects ctrl+plus with skip' do
|
79
|
+
condition, value = Config::Searcher.find_condition do
|
80
|
+
Config::Searcher.new.search(index, location: location)
|
81
|
+
end
|
82
|
+
expect([condition, value]).to eq([:skip, 'ctrl+plus'])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'with begin/update/end' do
|
87
|
+
around do |example|
|
88
|
+
ConfigHelper.load_config_yml = <<~CONFIG
|
89
|
+
swipe:
|
90
|
+
3:
|
91
|
+
begin:
|
92
|
+
command: 'echo begin'
|
93
|
+
update:
|
94
|
+
command: 'echo update'
|
95
|
+
end:
|
96
|
+
command: 'echo end'
|
97
|
+
keypress:
|
98
|
+
LEFTCTRL:
|
99
|
+
command: 'echo end+ctrl'
|
100
|
+
CONFIG
|
101
|
+
|
102
|
+
example.run
|
103
|
+
|
104
|
+
ConfigHelper.clear_config_yml
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'without keypress' do
|
108
|
+
let(:index) do
|
109
|
+
Config::Index.new [
|
110
|
+
Config::Index::Key.new(:swipe),
|
111
|
+
Config::Index::Key.new(3),
|
112
|
+
Config::Index::Key.new('left', skippable: true),
|
113
|
+
Config::Index::Key.new('end'),
|
114
|
+
Config::Index::Key.new('command')
|
115
|
+
]
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'detects with skip' do
|
119
|
+
condition, value = Config::Searcher.find_condition do
|
120
|
+
Config::Searcher.new.search(index, location: location)
|
121
|
+
end
|
122
|
+
expect([condition, value]).to eq([:skip, 'echo end'])
|
123
|
+
end
|
124
|
+
end
|
125
|
+
context 'with keypress' do
|
126
|
+
context 'with valid key existing in config.yml' do
|
127
|
+
let(:index) do
|
128
|
+
Config::Index.new [
|
129
|
+
Config::Index::Key.new(:swipe),
|
130
|
+
Config::Index::Key.new(3),
|
131
|
+
Config::Index::Key.new('left', skippable: true),
|
132
|
+
Config::Index::Key.new('end'),
|
133
|
+
Config::Index::Key.new('keypress', skippable: true),
|
134
|
+
Config::Index::Key.new('LEFTCTRL', skippable: true),
|
135
|
+
Config::Index::Key.new('command')
|
136
|
+
]
|
137
|
+
end
|
138
|
+
it 'detects end+ctrl with skip' do
|
139
|
+
condition, value = Config::Searcher.find_condition do
|
140
|
+
Config::Searcher.new.search(index, location: location)
|
141
|
+
end
|
142
|
+
expect([condition, value]).to eq([:skip, 'echo end+ctrl'])
|
143
|
+
end
|
144
|
+
end
|
145
|
+
context 'with non-existing key not existing in config.yml' do
|
146
|
+
let(:index) do
|
147
|
+
Config::Index.new [
|
148
|
+
Config::Index::Key.new(:swipe),
|
149
|
+
Config::Index::Key.new(3),
|
150
|
+
Config::Index::Key.new('up', skippable: true),
|
151
|
+
Config::Index::Key.new('end'),
|
152
|
+
Config::Index::Key.new('keypress', skippable: true),
|
153
|
+
Config::Index::Key.new('LEFTSHIFT', skippable: true), # Invalid key
|
154
|
+
Config::Index::Key.new('command')
|
155
|
+
]
|
156
|
+
end
|
157
|
+
it 'detects end with skip (fallback to no keypress)' do
|
158
|
+
condition, value = Config::Searcher.find_condition do
|
159
|
+
Config::Searcher.new.search(index, location: location)
|
160
|
+
end
|
161
|
+
expect([condition, value]).to eq([:skip, 'echo end'])
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
84
166
|
end
|
85
167
|
end
|
86
168
|
|
data/spec/lib/config_spec.rb
CHANGED
@@ -25,14 +25,6 @@ module Fusuma
|
|
25
25
|
}
|
26
26
|
end
|
27
27
|
|
28
|
-
let(:keymap_without_finger) do
|
29
|
-
{
|
30
|
-
'swipe' => {
|
31
|
-
'left' => { 'command' => 'alt+Left' }
|
32
|
-
}
|
33
|
-
}
|
34
|
-
end
|
35
|
-
|
36
28
|
describe '.custom_path=' do
|
37
29
|
before { Singleton.__init__(Config) }
|
38
30
|
it 'should reload keymap file' do
|
@@ -5,7 +5,9 @@ require './lib/fusuma/libinput_command'
|
|
5
5
|
|
6
6
|
module Fusuma
|
7
7
|
RSpec.describe LibinputCommand do
|
8
|
-
let(:libinput_command)
|
8
|
+
let(:libinput_command) do
|
9
|
+
described_class.new(libinput_options: libinput_options, commands: commands)
|
10
|
+
end
|
9
11
|
let(:libinput_options) { [] }
|
10
12
|
let(:commands) { {} }
|
11
13
|
describe '#version' do
|
@@ -66,7 +68,7 @@ module Fusuma
|
|
66
68
|
context 'without NEW_CLI_OPTION_VERSION' do
|
67
69
|
before do
|
68
70
|
allow(libinput_command).to receive(:version)
|
69
|
-
.and_return(
|
71
|
+
.and_return('1.7')
|
70
72
|
end
|
71
73
|
it { is_expected.to eq false }
|
72
74
|
end
|
@@ -79,7 +81,8 @@ module Fusuma
|
|
79
81
|
before do
|
80
82
|
dummy_io = StringIO.new('dummy')
|
81
83
|
io = StringIO.new('dummy output')
|
82
|
-
allow(Open3).to receive(:popen3).with(anything).and_return([dummy_io, io, dummy_io,
|
84
|
+
allow(Open3).to receive(:popen3).with(anything).and_return([dummy_io, io, dummy_io,
|
85
|
+
dummy_io, nil])
|
83
86
|
end
|
84
87
|
|
85
88
|
context 'with the alternative command' do
|
@@ -119,7 +122,7 @@ module Fusuma
|
|
119
122
|
describe 'debug_events' do
|
120
123
|
before do
|
121
124
|
@dummy_io = StringIO.new('dummy')
|
122
|
-
allow(Process).to receive(:
|
125
|
+
allow(Process).to receive(:detach).with(anything).and_return(nil)
|
123
126
|
end
|
124
127
|
subject { libinput_command.debug_events(@dummy_io) }
|
125
128
|
|
@@ -129,7 +132,8 @@ module Fusuma
|
|
129
132
|
end
|
130
133
|
|
131
134
|
it 'should call dummy events' do
|
132
|
-
expect(Process).to receive(:spawn).with('dummy_debug_events',
|
135
|
+
expect(Process).to receive(:spawn).with('dummy_debug_events',
|
136
|
+
{ out: @dummy_io, in: '/dev/null' }).once
|
133
137
|
subject
|
134
138
|
end
|
135
139
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
|
+
require 'rspec-parameterized'
|
4
5
|
|
5
6
|
require './lib/fusuma/plugin/events/event'
|
6
7
|
require './lib/fusuma/plugin/events/records/gesture_record'
|
@@ -13,7 +14,7 @@ module Fusuma
|
|
13
14
|
before do
|
14
15
|
@buffer = GestureBuffer.new
|
15
16
|
delta = Events::Records::GestureRecord::Delta.new(-1, 0, 0, 0, 0, 0)
|
16
|
-
@event_generator = lambda { |time = nil, status = '
|
17
|
+
@event_generator = lambda { |time = nil, status = 'update'|
|
17
18
|
Events::Event.new(time: time,
|
18
19
|
tag: 'libinput_gesture_parser',
|
19
20
|
record: Events::Records::GestureRecord.new(
|
@@ -53,20 +54,39 @@ module Fusuma
|
|
53
54
|
end
|
54
55
|
|
55
56
|
describe '#clear_expired' do
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
57
|
+
context 'default' do
|
58
|
+
before do
|
59
|
+
@time = Time.now
|
60
|
+
event1 = @event_generator.call(@time)
|
61
|
+
@buffer.buffer(event1)
|
62
|
+
@event2 = @event_generator.call(@time + 100)
|
63
|
+
@event3 = @event_generator.call(@time + 100)
|
64
|
+
@buffer.buffer(@event2)
|
65
|
+
@buffer.buffer(@event3)
|
66
|
+
end
|
67
|
+
it 'should keep only events generated within 30 seconds' do
|
68
|
+
@buffer.clear_expired(current_time: @time + 100.1)
|
69
|
+
expect(@buffer.events).to eq [@event2, @event3]
|
70
|
+
end
|
71
|
+
context 'with cancelled or ended' do
|
72
|
+
where(:last_state, :want) do
|
73
|
+
[
|
74
|
+
['end', []],
|
75
|
+
['cancelled', []]
|
76
|
+
]
|
77
|
+
end
|
78
|
+
|
79
|
+
with_them do
|
80
|
+
it 'should clear events' do
|
81
|
+
event4 = @event_generator.call(@time + 100, last_state)
|
82
|
+
@buffer.buffer(event4)
|
83
|
+
|
84
|
+
@buffer.clear_expired(current_time: @time + 100.1)
|
85
|
+
expect(@buffer.events).to eq want
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
68
89
|
end
|
69
|
-
|
70
90
|
context 'change seconds to keep' do
|
71
91
|
around do |example|
|
72
92
|
ConfigHelper.load_config_yml = <<~CONFIG
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
require './lib/fusuma/plugin/detectors/hold_detector'
|
6
|
+
require './lib/fusuma/plugin/buffers/gesture_buffer'
|
7
|
+
require './lib/fusuma/plugin/events/records/gesture_record'
|
8
|
+
require './lib/fusuma/config'
|
9
|
+
|
10
|
+
module Fusuma
|
11
|
+
module Plugin
|
12
|
+
module Detectors
|
13
|
+
RSpec.describe HoldDetector do
|
14
|
+
before do
|
15
|
+
@detector = HoldDetector.new
|
16
|
+
@buffer = Buffers::GestureBuffer.new
|
17
|
+
@timer_buffer = Buffers::TimerBuffer.new
|
18
|
+
end
|
19
|
+
|
20
|
+
around do |example|
|
21
|
+
ConfigHelper.load_config_yml = <<~CONFIG
|
22
|
+
threshold:
|
23
|
+
hold: 1
|
24
|
+
CONFIG
|
25
|
+
|
26
|
+
example.run
|
27
|
+
|
28
|
+
Config.custom_path = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#detect' do
|
32
|
+
context 'with no hold event in buffer' do
|
33
|
+
before do
|
34
|
+
@buffer.clear
|
35
|
+
end
|
36
|
+
it { expect(@detector.detect([@buffer, @timer_buffer])).to eq nil }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'with only hold begin event' do
|
40
|
+
before do
|
41
|
+
events = create_hold_events(statuses: ['begin'])
|
42
|
+
events.each { |event| @buffer.buffer(event) }
|
43
|
+
end
|
44
|
+
it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
|
45
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
|
46
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
|
47
|
+
it 'should detect 3 fingers hold' do
|
48
|
+
event = @detector.detect([@buffer, @timer_buffer])
|
49
|
+
expect(event.record.index.keys.map(&:symbol)).to eq([:hold, 3, :begin])
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with hold events(begin,cancelled)' do
|
54
|
+
before do
|
55
|
+
events = create_hold_events(statuses: %w[begin cancelled])
|
56
|
+
events.each { |event| @buffer.buffer(event) }
|
57
|
+
end
|
58
|
+
it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
|
59
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
|
60
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
|
61
|
+
it 'should detect 3 fingers hold canclled' do
|
62
|
+
event = @detector.detect([@buffer, @timer_buffer])
|
63
|
+
expect(event.record.index.keys.map(&:symbol)).to eq([:hold, 3, :cancelled])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with hold events(begin,end)' do
|
68
|
+
before do
|
69
|
+
events = create_hold_events(statuses: %w[begin end])
|
70
|
+
events.each { |event| @buffer.buffer(event) }
|
71
|
+
end
|
72
|
+
it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
|
73
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
|
74
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
|
75
|
+
it 'should detect 3 fingers hold' do
|
76
|
+
events = @detector.detect([@buffer, @timer_buffer])
|
77
|
+
expect(events.record.index.keys.map(&:symbol)).to eq([:hold, 3, :end])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'with hold events and timer events' do
|
82
|
+
context 'with begin event and timer events' do
|
83
|
+
before do
|
84
|
+
events = create_hold_events(statuses: %w[begin])
|
85
|
+
events.each { |event| @buffer.buffer(event) }
|
86
|
+
@time = events.last.time
|
87
|
+
@timer_buffer.buffer(create_timer_event(time: @time + HoldDetector::BASE_THERESHOLD))
|
88
|
+
end
|
89
|
+
it { expect(@detector.detect([@buffer, @timer_buffer])).to eq nil }
|
90
|
+
|
91
|
+
context 'with enough holding time' do
|
92
|
+
before do
|
93
|
+
@timer_buffer.clear
|
94
|
+
@timer_buffer.buffer(create_timer_event(time: @time + HoldDetector::BASE_THERESHOLD + 0.01))
|
95
|
+
end
|
96
|
+
it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
|
97
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
|
98
|
+
it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
|
99
|
+
it 'should detect 3 fingers hold' do
|
100
|
+
events = @detector.detect([@buffer, @timer_buffer])
|
101
|
+
expect(events.record.index.keys.map(&:symbol)).to eq([:hold, 3])
|
102
|
+
end
|
103
|
+
end
|
104
|
+
context 'with changing threshold' do
|
105
|
+
around do |example|
|
106
|
+
ConfigHelper.load_config_yml = <<~CONFIG
|
107
|
+
threshold:
|
108
|
+
hold: 0.9
|
109
|
+
CONFIG
|
110
|
+
|
111
|
+
example.run
|
112
|
+
|
113
|
+
Config.custom_path = nil
|
114
|
+
end
|
115
|
+
|
116
|
+
it { expect(@detector.detect([@buffer, @timer_buffer])).not_to eq nil }
|
117
|
+
it 'should detect 3 fingers hold' do
|
118
|
+
events = @detector.detect([@buffer, @timer_buffer])
|
119
|
+
expect(events.record.index.keys.map(&:symbol)).to eq([:hold, 3])
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def create_hold_events(statuses:)
|
129
|
+
record_type = HoldDetector::GESTURE_RECORD_TYPE
|
130
|
+
statuses.map do |status|
|
131
|
+
gesture_record = Events::Records::GestureRecord.new(status: status,
|
132
|
+
gesture: record_type,
|
133
|
+
finger: 3,
|
134
|
+
delta: nil)
|
135
|
+
Events::Event.new(tag: 'libinput_gesture_parser', record: gesture_record)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def create_timer_event(time: Time.now)
|
140
|
+
Events::Event.new(time: time, tag: 'timer_input', record: Events::Records::TextRecord.new('timer'))
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|