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.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +8 -0
- data/.gitignore +6 -0
- data/.reek.yml +93 -45
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +16 -75
- data/Gemfile +2 -0
- data/README.md +12 -5
- data/Rakefile +2 -1
- data/bin/console +1 -1
- data/exe/fusuma +1 -0
- data/fusuma.gemspec +9 -2
- data/lib/fusuma.rb +88 -31
- data/lib/fusuma/config.rb +65 -66
- data/lib/fusuma/config/index.rb +49 -0
- data/lib/fusuma/device.rb +58 -37
- data/lib/fusuma/multi_logger.rb +3 -0
- data/lib/fusuma/plugin/base.rb +56 -0
- data/lib/fusuma/plugin/buffers/buffer.rb +41 -0
- data/lib/fusuma/plugin/buffers/gesture_buffer.rb +70 -0
- data/lib/fusuma/plugin/detectors/detector.rb +41 -0
- data/lib/fusuma/plugin/detectors/pinch_detector.rb +141 -0
- data/lib/fusuma/plugin/detectors/rotate_detector.rb +135 -0
- data/lib/fusuma/plugin/detectors/swipe_detector.rb +145 -0
- data/lib/fusuma/plugin/events/event.rb +38 -0
- data/lib/fusuma/plugin/events/records/gesture_record.rb +31 -0
- data/lib/fusuma/plugin/events/records/index_record.rb +53 -0
- data/lib/fusuma/plugin/events/records/record.rb +20 -0
- data/lib/fusuma/plugin/events/records/text_record.rb +28 -0
- data/lib/fusuma/plugin/executors/command_executor.rb +39 -0
- data/lib/fusuma/plugin/executors/executor.rb +27 -0
- data/lib/fusuma/plugin/filters/filter.rb +40 -0
- data/lib/fusuma/plugin/filters/libinput_device_filter.rb +42 -0
- data/lib/fusuma/plugin/inputs/input.rb +28 -0
- data/lib/fusuma/plugin/inputs/libinput_command_input.rb +133 -0
- data/lib/fusuma/plugin/manager.rb +118 -0
- data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +54 -0
- data/lib/fusuma/plugin/parsers/parser.rb +46 -0
- data/lib/fusuma/version.rb +3 -1
- metadata +74 -14
- data/lib/fusuma/command_executor.rb +0 -43
- data/lib/fusuma/event_stack.rb +0 -87
- data/lib/fusuma/gesture_event.rb +0 -50
- data/lib/fusuma/libinput_commands.rb +0 -98
- data/lib/fusuma/pinch.rb +0 -58
- 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
|
data/lib/fusuma/version.rb
CHANGED
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
|
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-
|
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: '
|
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: '
|
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
|
-
|
112
|
-
|
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/
|
150
|
-
- lib/fusuma/
|
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: '
|
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
|
data/lib/fusuma/event_stack.rb
DELETED
@@ -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
|