fusuma-plugin-touchscreen 0.0.1.alpha → 0.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.
- checksums.yaml +4 -4
- data/LICENSE +0 -0
- data/README.md +71 -2
- data/fusuma-plugin-touchscreen.gemspec +3 -2
- data/lib/fusuma/plugin/buffers/touch_buffer.rb +17 -81
- data/lib/fusuma/plugin/detectors/touch_detector.rb +31 -14
- data/lib/fusuma/plugin/detectors/touch_detectors/base.rb +7 -0
- data/lib/fusuma/plugin/detectors/touch_detectors/edge_detector.rb +0 -0
- data/lib/fusuma/plugin/detectors/touch_detectors/hold_detector.rb +11 -3
- data/lib/fusuma/plugin/detectors/touch_detectors/pinch_detector.rb +59 -1
- data/lib/fusuma/plugin/detectors/touch_detectors/rotate_detector.rb +65 -1
- data/lib/fusuma/plugin/detectors/touch_detectors/swipe_detector.rb +11 -9
- data/lib/fusuma/plugin/detectors/touch_detectors/tap_detector.rb +2 -2
- data/lib/fusuma/plugin/detectors/touch_detectors/tap_hold_base.rb +21 -0
- data/lib/fusuma/plugin/devices/touchscreen_device.rb +0 -0
- data/lib/fusuma/plugin/events/records/touch_record.rb +14 -1
- data/lib/fusuma/plugin/events/records/touch_records/base.rb +2 -0
- data/lib/fusuma/plugin/events/records/touch_records/features/direction.rb +36 -0
- data/lib/fusuma/plugin/events/records/touch_records/hold_record.rb +0 -0
- data/lib/fusuma/plugin/events/records/touch_records/pinch_record.rb +23 -0
- data/lib/fusuma/plugin/events/records/touch_records/rotate_record.rb +23 -0
- data/lib/fusuma/plugin/events/records/touch_records/swipe_record.rb +2 -12
- data/lib/fusuma/plugin/events/records/touch_records/tap_record.rb +0 -0
- data/lib/fusuma/plugin/parsers/touch_parser.rb +2 -47
- data/lib/fusuma/plugin/touchscreen/math.rb +68 -0
- data/lib/fusuma/plugin/touchscreen/version.rb +1 -1
- data/lib/fusuma/plugin/touchscreen.rb +0 -0
- data/spec/fusuma/plugin/buffers/touch_buffer_spec.rb +216 -0
- data/spec/fusuma/plugin/detectors/hold_detector_spec.rb +71 -0
- data/spec/fusuma/plugin/detectors/pinch_detector_spec.rb +96 -0
- data/spec/fusuma/plugin/detectors/rotate_detector_spec.rb +123 -0
- data/spec/fusuma/plugin/detectors/swipe_detector_spec.rb +141 -0
- data/spec/fusuma/plugin/detectors/tap_detector_spec.rb +84 -0
- data/spec/fusuma/plugin/detectors/touch_detector_spec.rb +266 -0
- data/spec/fusuma/plugin/devices/touchscreen_device_spec.rb +6 -3
- data/spec/fusuma/plugin/parsers/touch_parser_spec.rb +30 -5
- data/spec/samples/1-finger-hold.txt +0 -0
- data/spec/samples/2-fingers-rotate-clockwise.txt +426 -0
- data/spec/samples/2-fingers-rotate-counterclockwise.txt +459 -0
- data/spec/samples/2-fingers-swipe-right.txt +0 -0
- data/spec/samples/3-fingers-pinch-in.txt +140 -0
- data/spec/samples/3-fingers-pinch-out.txt +171 -0
- data/spec/samples/3-fingers-tap.txt +0 -0
- data/spec/{fixtures/libinput-list-devices_ms-surface-3-pro.txt → samples/libinput-list-devices.txt} +0 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/helpers/events_and_records.rb +43 -0
- data/spec/support/shared_contexts/with_touch_buffer.rb +10 -0
- data/spec/support/shared_examples/real_sample.rb +29 -0
- metadata +40 -10
- data/lib/fusuma/utils/angle.rb +0 -12
- data/spec/samples/libinput-devices.txt +0 -182
@@ -0,0 +1,36 @@
|
|
1
|
+
module Fusuma
|
2
|
+
module Plugin
|
3
|
+
module Events
|
4
|
+
module Records
|
5
|
+
module TouchRecords
|
6
|
+
module Features
|
7
|
+
module Direction
|
8
|
+
|
9
|
+
def self.prepended(base)
|
10
|
+
base.class_eval do
|
11
|
+
attr_reader :direction
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(direction:, **args)
|
16
|
+
super(**args)
|
17
|
+
@direction = direction.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
super(other) && direction == other.direction
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def config_index_keys
|
27
|
+
super << Config::Index::Key.new(@direction)
|
28
|
+
end
|
29
|
+
|
30
|
+
end # module WithDirection
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
File without changes
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
require_relative './features/direction'
|
3
|
+
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
module Fusuma
|
7
|
+
module Plugin
|
8
|
+
module Events
|
9
|
+
module Records
|
10
|
+
module TouchRecords
|
11
|
+
class PinchRecord < Base
|
12
|
+
prepend Features::Direction
|
13
|
+
|
14
|
+
def repeatable?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
end # class PinchRecord
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
require_relative './features/direction'
|
3
|
+
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
module Fusuma
|
7
|
+
module Plugin
|
8
|
+
module Events
|
9
|
+
module Records
|
10
|
+
module TouchRecords
|
11
|
+
class RotateRecord < Base
|
12
|
+
prepend Features::Direction
|
13
|
+
|
14
|
+
def repeatable?
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
end # class RotateRecord
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative './base'
|
2
|
+
require_relative './features/direction'
|
2
3
|
|
3
4
|
# frozen_string_literal: true
|
4
5
|
|
@@ -8,23 +9,12 @@ module Fusuma
|
|
8
9
|
module Records
|
9
10
|
module TouchRecords
|
10
11
|
class SwipeRecord < Base
|
11
|
-
|
12
|
-
def initialize(direction:, **args)
|
13
|
-
super(**args)
|
14
|
-
@direction = direction.to_s
|
15
|
-
end
|
12
|
+
prepend Features::Direction
|
16
13
|
|
17
14
|
def repeatable?
|
18
15
|
true
|
19
16
|
end
|
20
17
|
|
21
|
-
protected
|
22
|
-
|
23
|
-
def config_index_keys
|
24
|
-
super << Config::Index::Key.new(@direction)
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
18
|
end # class SwipeRecord
|
29
19
|
end
|
30
20
|
end
|
File without changes
|
@@ -1,58 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'fusuma/plugin/parsers/parser'
|
4
|
+
|
3
5
|
module Fusuma
|
4
6
|
module Plugin
|
5
7
|
module Parsers
|
6
8
|
class TouchParser < Parser
|
7
9
|
DEFAULT_SOURCE = 'libinput_command_input'
|
8
10
|
|
9
|
-
=begin
|
10
|
-
3-finger touch:
|
11
|
-
|
12
|
-
event4 TOUCH_DOWN +0.000s 0 (0) 58.64/44.04 (148.16/73.74mm)
|
13
|
-
event4 TOUCH_DOWN +0.000s 1 (1) 49.33/47.67 (124.63/79.84mm)
|
14
|
-
event4 TOUCH_DOWN +0.000s 2 (2) 43.54/64.23 (110.00/107.56mm)
|
15
|
-
event4 TOUCH_UP +0.079s 2 (2)
|
16
|
-
event4 TOUCH_UP +0.099s 1 (1)
|
17
|
-
event4 TOUCH_UP +0.108s 0 (0)
|
18
|
-
=end
|
19
|
-
|
20
|
-
=begin
|
21
|
-
2-finger swipe:
|
22
|
-
|
23
|
-
event4 TOUCH_DOWN +0.000s 0 (0) 27.07/42.62 (68.39/71.37mm)
|
24
|
-
event4 TOUCH_DOWN +0.000s 1 (1) 26.45/53.27 (66.82/89.21mm)
|
25
|
-
event4 TOUCH_MOTION +0.051s 1 (1) 26.84/53.27 (67.82/89.21mm)
|
26
|
-
event4 TOUCH_MOTION +0.061s 0 (0) 27.40/42.91 (69.24/71.86mm)
|
27
|
-
event4 TOUCH_MOTION +0.061s 1 (1) 27.21/53.28 (68.74/89.23mm)
|
28
|
-
event4 TOUCH_MOTION +0.071s 0 (0) 28.03/43.27 (70.82/72.47mm)
|
29
|
-
event4 TOUCH_MOTION +0.071s 1 (1) 27.67/53.33 (69.92/89.30mm)
|
30
|
-
event4 TOUCH_MOTION +0.082s 0 (0) 28.59/43.49 (72.24/72.84mm)
|
31
|
-
event4 TOUCH_MOTION +0.082s 1 (1) 28.43/53.37 (71.84/89.37mm)
|
32
|
-
event4 TOUCH_MOTION +0.091s 0 (0) 29.32/43.66 (74.08/73.12mm)
|
33
|
-
event4 TOUCH_MOTION +0.091s 1 (1) 28.90/53.41 (73.03/89.44mm)
|
34
|
-
event4 TOUCH_MOTION +0.101s 0 (0) 30.17/43.99 (76.24/73.67mm)
|
35
|
-
event4 TOUCH_MOTION +0.101s 1 (1) 29.84/53.21 (75.39/89.12mm)
|
36
|
-
event4 TOUCH_MOTION +0.111s 0 (0) 30.51/44.08 (77.08/73.81mm)
|
37
|
-
event4 TOUCH_MOTION +0.111s 1 (1) 30.47/53.35 (76.97/89.35mm)
|
38
|
-
event4 TOUCH_MOTION +0.121s 0 (0) 31.84/44.59 (80.45/74.67mm)
|
39
|
-
event4 TOUCH_MOTION +0.121s 1 (1) 31.65/53.73 (79.97/89.98mm)
|
40
|
-
event4 TOUCH_MOTION +0.131s 0 (0) 32.56/44.76 (82.26/74.95mm)
|
41
|
-
event4 TOUCH_MOTION +0.131s 1 (1) 32.62/54.21 (82.42/90.79mm)
|
42
|
-
event4 TOUCH_MOTION +0.141s 0 (0) 33.51/44.94 (84.66/75.26mm)
|
43
|
-
event4 TOUCH_MOTION +0.141s 1 (1) 33.49/54.46 (84.61/91.21mm)
|
44
|
-
event4 TOUCH_MOTION +0.151s 0 (0) 34.88/45.38 (88.13/76.00mm)
|
45
|
-
event4 TOUCH_MOTION +0.151s 1 (1) 35.05/54.74 (88.55/91.67mm)
|
46
|
-
event4 TOUCH_MOTION +0.162s 0 (0) 36.14/45.72 (91.32/76.56mm)
|
47
|
-
event4 TOUCH_MOTION +0.162s 1 (1) 36.62/55.28 (92.53/92.58mm)
|
48
|
-
event4 TOUCH_MOTION +0.171s 0 (0) 37.53/46.12 (94.82/77.23mm)
|
49
|
-
event4 TOUCH_MOTION +0.171s 1 (1) 38.21/55.84 (96.55/93.51mm)
|
50
|
-
event4 TOUCH_MOTION +0.181s 0 (0) 39.94/47.08 (100.92/78.84mm)
|
51
|
-
event4 TOUCH_MOTION +0.181s 1 (1) 39.91/56.03 (100.84/93.84mm)
|
52
|
-
event4 TOUCH_UP +0.220s 0 (0)
|
53
|
-
event4 TOUCH_UP +0.220s 1 (1)
|
54
|
-
=end
|
55
|
-
|
56
11
|
def parse_record(record)
|
57
12
|
MultiLogger.debug("#{self.class.name}##{__method__}")
|
58
13
|
MultiLogger.debug(" record = #{record.inspect}")
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Fusuma
|
2
|
+
module Plugin
|
3
|
+
module Touchscreen
|
4
|
+
module Math
|
5
|
+
|
6
|
+
def self.angles_difference(angle1, angle2)
|
7
|
+
normalized_angle1 = normalize_angle(angle1)
|
8
|
+
normalized_angle2 = normalize_angle(angle2)
|
9
|
+
|
10
|
+
raw_difference = normalized_angle2 - normalized_angle1
|
11
|
+
|
12
|
+
if raw_difference < -180
|
13
|
+
raw_difference += 360
|
14
|
+
elsif raw_difference > 180
|
15
|
+
raw_difference -= 360
|
16
|
+
end
|
17
|
+
|
18
|
+
raw_difference
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.normalize_angle(angle)
|
22
|
+
angle %= 360
|
23
|
+
angle < 0 ? angle + 360 : angle
|
24
|
+
end
|
25
|
+
private_class_method :normalize_angle
|
26
|
+
|
27
|
+
def self.angles_average(angles)
|
28
|
+
sum_x = 0.0
|
29
|
+
sum_y = 0.0
|
30
|
+
|
31
|
+
angles.each do |angle|
|
32
|
+
radians = angle * ::Math::PI / 180.0
|
33
|
+
sum_x += ::Math.cos(radians)
|
34
|
+
sum_y += ::Math.sin(radians)
|
35
|
+
end
|
36
|
+
|
37
|
+
average_radians = ::Math.atan2(sum_y, sum_x)
|
38
|
+
average_degrees = average_radians * 180.0 / ::Math::PI
|
39
|
+
average_degrees += 360.0 if average_degrees < 0
|
40
|
+
|
41
|
+
average_degrees
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.distance(point1, point2)
|
45
|
+
::Math.sqrt((point1[:x] - point2[:x])**2 + (point1[:y] - point2[:y])**2)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.distance_from_line(x, y, k, b)
|
49
|
+
(k * x + b - y).abs / ::Math.sqrt(k**2 + 1)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.center(points)
|
53
|
+
x = points.map { |p| p[:x] }.reduce(:+) / points.size
|
54
|
+
y = points.map { |p| p[:y] }.reduce(:+) / points.size
|
55
|
+
{ x: x, y: y }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.angle_between(base_point, other_point)
|
59
|
+
radians = ::Math.atan2(other_point[:y] - base_point[:y], other_point[:x] - base_point[:x])
|
60
|
+
degrees = radians * 180.0 / ::Math::PI
|
61
|
+
degrees += 360.0 if degrees < 0
|
62
|
+
degrees
|
63
|
+
end
|
64
|
+
|
65
|
+
end # module Math
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
File without changes
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
require 'fusuma/plugin/events/event'
|
4
|
+
require 'fusuma/plugin/buffers/touch_buffer'
|
5
|
+
require 'fusuma/plugin/events/records/touch_record'
|
6
|
+
|
7
|
+
module Fusuma
|
8
|
+
RSpec.describe Plugin::Buffers::TouchBuffer do
|
9
|
+
subject { described_class.new }
|
10
|
+
|
11
|
+
it 'builds finger_events_map' do
|
12
|
+
event = generate_touch_event
|
13
|
+
subject.buffer(event)
|
14
|
+
expect(subject.finger_events_map[event.record.finger]).not_to be_empty
|
15
|
+
expect(subject.finger_events_map[event.record.finger].first).to eq event
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
it 'clears finger_events_map' do
|
20
|
+
event = generate_touch_event
|
21
|
+
subject.buffer(event)
|
22
|
+
subject.clear
|
23
|
+
expect(subject.finger_events_map).to be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#clear_expired' do
|
27
|
+
it 'outdated' do
|
28
|
+
allow(subject).to receive(:config_params).and_call_original
|
29
|
+
allow(subject).to receive(:config_params).with(:seconds_to_keep).and_return(50)
|
30
|
+
expired_event = generate_touch_event(time: Time.now - 100)
|
31
|
+
actual_event = generate_touch_event
|
32
|
+
subject.buffer(expired_event)
|
33
|
+
subject.buffer(actual_event)
|
34
|
+
subject.clear_expired
|
35
|
+
expect(subject.finger_events_map[actual_event.record.finger]).not_to include(expired_event)
|
36
|
+
expect(subject.finger_events_map[actual_event.record.finger]).to include(actual_event)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'ended' do
|
40
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'begin')))
|
41
|
+
subject.clear_expired
|
42
|
+
expect(subject.finger_events_map).not_to be_empty
|
43
|
+
|
44
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'end')))
|
45
|
+
subject.clear_expired
|
46
|
+
expect(subject.finger_events_map).to be_empty
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#empty?' do
|
51
|
+
it 'is empty' do
|
52
|
+
expect(subject.empty?).to be_truthy
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'is not empty' do
|
56
|
+
event = generate_touch_event
|
57
|
+
subject.buffer(event)
|
58
|
+
expect(subject.empty?).to be_falsey
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#finger' do
|
63
|
+
it 'returns 0 if finger_events_map is empty' do
|
64
|
+
expect(subject.finger).to eq 0
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'returns count of fingers' do
|
68
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(finger: 1)))
|
69
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(finger: 2)))
|
70
|
+
expect(subject.finger).to eq 2
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'is based on count of fingers, not finger number' do
|
74
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(finger: 2)))
|
75
|
+
expect(subject.finger).to eq 1
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#began?' do
|
80
|
+
it 'not began yet' do
|
81
|
+
expect(subject.began?).to be_falsey
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'began' do
|
85
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'begin')))
|
86
|
+
expect(subject.began?).to be_truthy
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'doesn\'t contain begin events (being updated or so, but began before that)' do
|
90
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'update')))
|
91
|
+
expect(subject.began?).to be_falsey
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'one finger began, other continued to update' do
|
95
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'begin', finger: 1)))
|
96
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'update', finger: 2)))
|
97
|
+
expect(subject.began?).to be_falsey
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#ended?' do
|
102
|
+
it 'not ended yet' do
|
103
|
+
expect(subject.ended?).to be_falsey
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'ended' do
|
107
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'end')))
|
108
|
+
expect(subject.ended?).to be_truthy
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'doesn\'t contain end events (being updated or so, but ended before that)' do
|
112
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'update')))
|
113
|
+
expect(subject.ended?).to be_falsey
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'one finger ended, other continued to update' do
|
117
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'end', finger: 1)))
|
118
|
+
subject.buffer(generate_touch_event(record: generate_touch_record(status: 'update', finger: 2)))
|
119
|
+
expect(subject.ended?).to be_falsey
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe '#finger_movements / #moved' do
|
124
|
+
before do
|
125
|
+
allow(subject).to receive(:movement_threshold).and_return(0.5)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'returns empty array if finger_events_map is empty' do
|
129
|
+
expect(subject.finger_movements).to be_empty
|
130
|
+
expect(subject.moved?).to be_falsey
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'no movement if only one event' do
|
134
|
+
event = generate_touch_event
|
135
|
+
subject.buffer(event)
|
136
|
+
expect(subject.finger_movements).to be_empty
|
137
|
+
expect(subject.moved?).to be_falsey
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'does not detect movement lesser than movement threshold' do
|
141
|
+
event1 = generate_touch_event(record: generate_touch_record(status: 'begin', x_mm: 0, y_mm: 0))
|
142
|
+
event2 = generate_touch_event(record: generate_touch_record(status: 'update', x_mm: 0.4, y_mm: 0))
|
143
|
+
subject.buffer(event1)
|
144
|
+
subject.buffer(event2)
|
145
|
+
expect(subject.finger_movements).to be_empty
|
146
|
+
expect(subject.moved?).to be_falsey
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'detects movement outside jitter threshold' do
|
150
|
+
event1 = generate_touch_event(record: generate_touch_record(status: 'begin', x_mm: 0, y_mm: 0))
|
151
|
+
event2 = generate_touch_event(record: generate_touch_record(status: 'update', x_mm: 1, y_mm: 2))
|
152
|
+
subject.buffer(event1)
|
153
|
+
subject.buffer(event2)
|
154
|
+
expect(subject.finger_movements).to eq({ 0 => { first_position: { x: 0.0, y: 0.0 }, last_position: { x: 1.0, y: 2.0 } } })
|
155
|
+
expect(subject.moved?).to be_truthy
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#begin_time' do
|
160
|
+
it 'returns nil if no begin event' do
|
161
|
+
expect(subject.begin_time).to be_nil
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'returns begin event time' do
|
165
|
+
begin_event = generate_touch_event(time: Time.now - 60, record: generate_touch_record(status: 'begin'))
|
166
|
+
subject.buffer(begin_event)
|
167
|
+
update_event = generate_touch_event(time: Time.now, record: generate_touch_record(status: 'end'))
|
168
|
+
subject.buffer(update_event)
|
169
|
+
expect(subject.begin_time).to eq(begin_event.time)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe '#end_time' do
|
174
|
+
it 'returns nil if no end event' do
|
175
|
+
expect(subject.end_time).to be_nil
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'returns end event time' do
|
179
|
+
begin_event = generate_touch_event(time: Time.now - 60, record: generate_touch_record(status: 'begin'))
|
180
|
+
subject.buffer(begin_event)
|
181
|
+
end_event = generate_touch_event(time: Time.now, record: generate_touch_record(status: 'end'))
|
182
|
+
subject.buffer(end_event)
|
183
|
+
expect(subject.end_time).to eq(end_event.time)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '#duration' do
|
188
|
+
it 'zero if nothing happened' do
|
189
|
+
expect(subject.duration).to eq(0)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'gesture ended' do
|
193
|
+
t = Time.now
|
194
|
+
begin_event = generate_touch_event(time: t - 60, record: generate_touch_record(status: 'begin'))
|
195
|
+
subject.buffer(begin_event)
|
196
|
+
update_event = generate_touch_event(time: t - 40, record: generate_touch_record(status: 'update'))
|
197
|
+
subject.buffer(update_event)
|
198
|
+
end_event = generate_touch_event(time: t - 20, record: generate_touch_record(status: 'end'))
|
199
|
+
subject.buffer(end_event)
|
200
|
+
expect(subject.duration).to eq(40)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'gesture not ended' do
|
204
|
+
t = Time.now
|
205
|
+
Timecop.freeze(t) do
|
206
|
+
begin_event = generate_touch_event(time: t - 60, record: generate_touch_record(status: 'begin'))
|
207
|
+
subject.buffer(begin_event)
|
208
|
+
update_event = generate_touch_event(time: t - 40, record: generate_touch_record(status: 'update'))
|
209
|
+
subject.buffer(update_event)
|
210
|
+
expect(subject.duration.round).to eq(60)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end # duration
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'timecop'
|
3
|
+
require 'fusuma/plugin/events/event'
|
4
|
+
require 'fusuma/plugin/parsers/touch_parser'
|
5
|
+
require 'fusuma/plugin/buffers/touch_buffer'
|
6
|
+
require 'fusuma/plugin/detectors/touch_detectors/hold_detector'
|
7
|
+
require 'fusuma/plugin/events/records/touch_records/hold_record'
|
8
|
+
|
9
|
+
module Fusuma
|
10
|
+
RSpec.describe Plugin::Detectors::TouchDetectors::HoldDetector do
|
11
|
+
subject { described_class.new }
|
12
|
+
let(:touch_buffer) { Plugin::Buffers::TouchBuffer.new }
|
13
|
+
let(:t) { Time.now }
|
14
|
+
|
15
|
+
before do
|
16
|
+
allow(touch_buffer).to receive(:movement_threshold).and_return(0.5)
|
17
|
+
allow(subject).to receive(:tap_hold_threshold).and_return(0.5)
|
18
|
+
allow(subject).to receive(:jitter_threshold).and_return(5.0)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'no events' do
|
22
|
+
expect(subject.detect(touch_buffer)).to be nil
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'under tap_hold_threshold' do
|
26
|
+
touch_buffer.buffer(generate_touch_event(time: t - 0.1, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 10, y_mm: 10)))
|
27
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 10, y_mm: 10)))
|
28
|
+
|
29
|
+
expect(subject.detect(touch_buffer)).to be nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'not moved' do
|
33
|
+
touch_buffer.buffer(generate_touch_event(time: t - 1, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 10, y_mm: 10)))
|
34
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 10, y_mm: 10)))
|
35
|
+
|
36
|
+
expect(subject.detect(touch_buffer)).to be_a(Plugin::Events::Records::TouchRecords::HoldRecord)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'moved under jitter_threshold' do
|
40
|
+
touch_buffer.buffer(generate_touch_event(time: t - 1, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 10, y_mm: 10)))
|
41
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 10, y_mm: 15)))
|
42
|
+
|
43
|
+
expect(subject.detect(touch_buffer)).to be_a(Plugin::Events::Records::TouchRecords::HoldRecord)
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'moved more than jitter_threshold' do
|
47
|
+
touch_buffer.buffer(generate_touch_event(time: t - 1, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 10, y_mm: 10)))
|
48
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 10, y_mm: 20)))
|
49
|
+
|
50
|
+
expect(subject.detect(touch_buffer)).to be nil
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'works on real data' do
|
54
|
+
parser = Plugin::Parsers::TouchParser.new
|
55
|
+
buffer = Plugin::Buffers::TouchBuffer.new
|
56
|
+
lines = File.readlines("spec/samples/1-finger-hold.txt").map(&:strip).reject(&:empty?)
|
57
|
+
t = Time.now - 30
|
58
|
+
lines.each do |line|
|
59
|
+
record = parser.parse_record(line)
|
60
|
+
next unless record
|
61
|
+
|
62
|
+
event = Plugin::Events::Event.new(tag: 'libinput_touch_parser', record: record, time: t += 1)
|
63
|
+
buffer.buffer(event)
|
64
|
+
end
|
65
|
+
gesture = subject.detect(buffer)
|
66
|
+
expect(gesture).to be_a(Plugin::Events::Records::TouchRecords::HoldRecord)
|
67
|
+
expect(gesture.finger).to eq(1)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'fusuma/plugin/detectors/touch_detectors/pinch_detector'
|
2
|
+
|
3
|
+
module Fusuma
|
4
|
+
RSpec.describe Plugin::Detectors::TouchDetectors::PinchDetector do
|
5
|
+
include_context 'with touch buffer'
|
6
|
+
subject { described_class.new }
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(subject).to receive(:jitter_threshold).and_return(5.0)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'no events' do
|
13
|
+
expect(subject.detect(touch_buffer)).to be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'not moved' do
|
17
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 10, y_mm: 10)))
|
18
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 10, y_mm: 10)))
|
19
|
+
|
20
|
+
expect(subject.detect(touch_buffer)).to be_nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'moved, only one finger' do
|
24
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 10, y_mm: 10)))
|
25
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 20, y_mm: 20)))
|
26
|
+
|
27
|
+
expect(subject.detect(touch_buffer)).to be_nil
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'moved, not enough distance change between first 2 fingers' do
|
31
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 10, y_mm: 10)))
|
32
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 8, y_mm: 10)))
|
33
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 2, x_mm: 10, y_mm: 10)))
|
34
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 2, x_mm: 12, y_mm: 10)))
|
35
|
+
|
36
|
+
expect(subject.detect(touch_buffer)).to be_nil
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'just two fingers' do
|
40
|
+
# inside down left
|
41
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 0, y_mm: 0)))
|
42
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 10, y_mm: 10)))
|
43
|
+
# inside up right
|
44
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 2, x_mm: 20, y_mm: 20)))
|
45
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 2, x_mm: 10, y_mm: 10)))
|
46
|
+
|
47
|
+
gesture = subject.detect(touch_buffer)
|
48
|
+
expect(gesture).to be_a(Plugin::Events::Records::TouchRecords::PinchRecord)
|
49
|
+
expect(gesture.finger).to eq(2)
|
50
|
+
expect(gesture.direction).to eq('in')
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'three fingers, the third finger moved in wrong direction' do
|
54
|
+
# outside up right
|
55
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 20, y_mm: 10)))
|
56
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 30, y_mm: 0)))
|
57
|
+
# outside down left
|
58
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 2, x_mm: 10, y_mm: 20)))
|
59
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 2, x_mm: 0, y_mm: 30)))
|
60
|
+
# inside up left
|
61
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 3, x_mm: 30, y_mm: 30)))
|
62
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 3, x_mm: 20, y_mm: 20)))
|
63
|
+
|
64
|
+
expect(subject.detect(touch_buffer)).to be_nil
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'three fingers' do
|
68
|
+
# outside up right
|
69
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 1, x_mm: 20, y_mm: 10)))
|
70
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 1, x_mm: 30, y_mm: 0)))
|
71
|
+
# outside down left
|
72
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 2, x_mm: 10, y_mm: 20)))
|
73
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 2, x_mm: 0, y_mm: 30)))
|
74
|
+
# outside down right
|
75
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'begin', finger: 3, x_mm: 20, y_mm: 20)))
|
76
|
+
touch_buffer.buffer(generate_touch_event(time: t, record: generate_touch_record(status: 'update', finger: 3, x_mm: 30, y_mm: 30)))
|
77
|
+
|
78
|
+
gesture = subject.detect(touch_buffer)
|
79
|
+
expect(gesture).to be_a(Plugin::Events::Records::TouchRecords::PinchRecord)
|
80
|
+
expect(gesture.direction).to eq('out')
|
81
|
+
expect(gesture.finger).to eq(3)
|
82
|
+
end
|
83
|
+
|
84
|
+
it_behaves_like 'real sample',
|
85
|
+
detector_class: Plugin::Detectors::TouchDetectors::PinchDetector,
|
86
|
+
sample_path: 'spec/samples/3-fingers-pinch-in.txt',
|
87
|
+
expected_gesture_class: Plugin::Events::Records::TouchRecords::PinchRecord,
|
88
|
+
expected_gesture_attributes: { finger: 3, direction: 'in' }
|
89
|
+
it_behaves_like 'real sample',
|
90
|
+
detector_class: Plugin::Detectors::TouchDetectors::PinchDetector,
|
91
|
+
sample_path: 'spec/samples/3-fingers-pinch-out.txt',
|
92
|
+
expected_gesture_class: Plugin::Events::Records::TouchRecords::PinchRecord,
|
93
|
+
expected_gesture_attributes: { finger: 3, direction: 'out' }
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|