fusuma 2.0.0.pre → 2.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -6,7 +6,7 @@ module Fusuma
|
|
6
6
|
# Search config.yml
|
7
7
|
class Searcher
|
8
8
|
def initialize
|
9
|
-
@cache
|
9
|
+
@cache = nil
|
10
10
|
end
|
11
11
|
|
12
12
|
# @param index [Index]
|
@@ -31,9 +31,25 @@ module Fusuma
|
|
31
31
|
value
|
32
32
|
end
|
33
33
|
|
34
|
+
def search_with_context(index, location:, context:)
|
35
|
+
return nil if location.nil?
|
36
|
+
|
37
|
+
return search(index, location: location[0]) if context == {}
|
38
|
+
|
39
|
+
new_location = location.find do |conf|
|
40
|
+
search(index, location: conf) if conf[:context] == context
|
41
|
+
end
|
42
|
+
search(index, location: new_location)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @param index [Index]
|
46
|
+
# @param location [Hash]
|
47
|
+
# @return [NilClass]
|
48
|
+
# @return [Hash]
|
49
|
+
# @return [Object]
|
34
50
|
def search_with_cache(index, location:)
|
35
|
-
cache([index.cache_key, Searcher.skip?, Searcher.fallback?]) do
|
36
|
-
|
51
|
+
cache([index.cache_key, Searcher.context, Searcher.skip?, Searcher.fallback?]) do
|
52
|
+
search_with_context(index, location: location, context: Searcher.context)
|
37
53
|
end
|
38
54
|
end
|
39
55
|
|
@@ -56,12 +72,72 @@ module Fusuma
|
|
56
72
|
def next_location_cadidates(location, key)
|
57
73
|
[
|
58
74
|
location[key.symbol],
|
59
|
-
Searcher.fallback? && key.fallback && location[key.fallback],
|
60
75
|
Searcher.skip? && key.skippable && location
|
61
76
|
].compact
|
62
77
|
end
|
63
78
|
|
64
79
|
class << self
|
80
|
+
# @return [Hash]
|
81
|
+
def conditions(&block)
|
82
|
+
{
|
83
|
+
nothing: -> { block.call },
|
84
|
+
skip: -> { Config::Searcher.skip { block.call } }
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
# Execute block with specified conditions
|
89
|
+
# @param conidtion [Symbol]
|
90
|
+
# @return [Object]
|
91
|
+
def with_condition(condition, &block)
|
92
|
+
conditions(&block)[condition].call
|
93
|
+
end
|
94
|
+
|
95
|
+
# Execute block with all conditions
|
96
|
+
# @return [Array<Symbol, Object>]
|
97
|
+
def find_condition(&block)
|
98
|
+
conditions(&block).find do |c, l|
|
99
|
+
result = l.call
|
100
|
+
return [c, result] if result
|
101
|
+
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Search with context from load_streamed Config
|
107
|
+
# @param context [Hash]
|
108
|
+
# @return [Object]
|
109
|
+
def with_context(context, &block)
|
110
|
+
@context = context || {}
|
111
|
+
result = block.call
|
112
|
+
@context = {}
|
113
|
+
result
|
114
|
+
end
|
115
|
+
|
116
|
+
# Return a matching context from config
|
117
|
+
# @params request_context [Hash]
|
118
|
+
# @return [Hash]
|
119
|
+
def find_context(request_context, &block)
|
120
|
+
# Search in blocks in the following order.
|
121
|
+
# 1. complete match config[:context] == request_context
|
122
|
+
# 2. partial match config[:context] =~ request_context
|
123
|
+
# 3. no context
|
124
|
+
Config.instance.keymap.each do |config|
|
125
|
+
next unless config[:context] == request_context
|
126
|
+
return config[:context] if with_context(config[:context]) { block.call }
|
127
|
+
end
|
128
|
+
if request_context.keys.size > 1
|
129
|
+
Config.instance.keymap.each do |config|
|
130
|
+
next if config[:context].nil?
|
131
|
+
|
132
|
+
next unless config[:context].all? { |k, v| request_context[k] == v }
|
133
|
+
return config[:context] if with_context(config[:context]) { block.call }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
return {} if with_context({}) { block.call }
|
137
|
+
end
|
138
|
+
|
139
|
+
attr_reader :context
|
140
|
+
|
65
141
|
def fallback?
|
66
142
|
@fallback
|
67
143
|
end
|
data/lib/fusuma/device.rb
CHANGED
@@ -1,18 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative './multi_logger'
|
4
|
-
require_relative './libinput_command
|
4
|
+
require_relative './libinput_command'
|
5
5
|
|
6
6
|
module Fusuma
|
7
7
|
# detect input device
|
8
8
|
class Device
|
9
|
-
attr_reader :available
|
10
|
-
attr_reader :name
|
11
|
-
attr_reader :id
|
9
|
+
attr_reader :id, :name, :capabilities, :available
|
12
10
|
|
13
|
-
def initialize(id: nil, name: nil, available: nil)
|
11
|
+
def initialize(id: nil, name: nil, capabilities: nil, available: nil)
|
14
12
|
@id = id
|
15
13
|
@name = name
|
14
|
+
@capabilities = capabilities
|
16
15
|
@available = available
|
17
16
|
end
|
18
17
|
|
@@ -24,6 +23,8 @@ module Fusuma
|
|
24
23
|
@id = v
|
25
24
|
when :name
|
26
25
|
@name = v
|
26
|
+
when :capabilities
|
27
|
+
@capabilities = v
|
27
28
|
when :available
|
28
29
|
@available = v
|
29
30
|
end
|
@@ -31,9 +32,13 @@ module Fusuma
|
|
31
32
|
end
|
32
33
|
|
33
34
|
class << self
|
35
|
+
# Return devices
|
36
|
+
# sort devices by capabilities of gesture
|
34
37
|
# @return [Array]
|
35
38
|
def all
|
36
|
-
@all ||= fetch_devices
|
39
|
+
@all ||= fetch_devices.partition do |d|
|
40
|
+
d.capabilities.match?(/gesture/)
|
41
|
+
end.flatten
|
37
42
|
end
|
38
43
|
|
39
44
|
# @raise [SystemExit]
|
@@ -104,6 +109,8 @@ module Fusuma
|
|
104
109
|
{ id: id }
|
105
110
|
elsif (name = name_from(line))
|
106
111
|
{ name: name }
|
112
|
+
elsif (capabilities = capabilities_from(line))
|
113
|
+
{ capabilities: capabilities }
|
107
114
|
elsif (available = available_from(line))
|
108
115
|
{ available: available }
|
109
116
|
else
|
@@ -123,6 +130,12 @@ module Fusuma
|
|
123
130
|
end
|
124
131
|
end
|
125
132
|
|
133
|
+
def capabilities_from(line)
|
134
|
+
line.match('^Capabilities:[[:space:]]*') do |m|
|
135
|
+
m.post_match.strip
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
126
139
|
def available_from(line)
|
127
140
|
# NOTE: is natural scroll available?
|
128
141
|
if line =~ /^Nat.scrolling: /
|
data/lib/fusuma/environment.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './version
|
4
|
-
require_relative './libinput_command
|
5
|
-
require_relative './multi_logger
|
3
|
+
require_relative './version'
|
4
|
+
require_relative './libinput_command'
|
5
|
+
require_relative './multi_logger'
|
6
6
|
|
7
7
|
module Fusuma
|
8
8
|
# Output Environment information
|
@@ -20,6 +20,7 @@ module Fusuma
|
|
20
20
|
libinput_command = Plugin::Inputs::LibinputCommandInput.new.command
|
21
21
|
MultiLogger.info "Fusuma: #{VERSION}"
|
22
22
|
MultiLogger.info "libinput: #{libinput_command.version}"
|
23
|
+
MultiLogger.info "ruby #{ RUBY_VERSION }p#{ RUBY_PATCHLEVEL }"
|
23
24
|
MultiLogger.info "OS: #{`uname -rsv`}".strip
|
24
25
|
MultiLogger.info "Distribution: #{`cat /etc/issue`}".strip
|
25
26
|
MultiLogger.info "Desktop session: #{`echo $DESKTOP_SESSION $XDG_SESSION_TYPE`}".strip
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Patch to hash
|
4
|
+
class Hash
|
5
|
+
# activesupport-4.1.1/lib/active_support/core_ext/hash/keys.rb
|
6
|
+
def deep_symbolize_keys
|
7
|
+
deep_transform_keys do |key|
|
8
|
+
key.to_sym
|
9
|
+
rescue StandardError
|
10
|
+
key
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def deep_transform_keys(&block)
|
15
|
+
result = {}
|
16
|
+
each do |key, value|
|
17
|
+
result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
|
18
|
+
end
|
19
|
+
result
|
20
|
+
end
|
21
|
+
|
22
|
+
# activesupport/lib/active_support/core_ext/hash/deep_transform_values.rb
|
23
|
+
def deep_transform_values(&block)
|
24
|
+
_deep_transform_values_in_object(self, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Support methods for deep transforming nested hashes and arrays.
|
30
|
+
def _deep_transform_values_in_object(object, &block)
|
31
|
+
case object
|
32
|
+
when Hash
|
33
|
+
object.transform_values { |value| _deep_transform_values_in_object(value, &block) }
|
34
|
+
when Array
|
35
|
+
object.map { |e| _deep_transform_values_in_object(e, &block) }
|
36
|
+
else
|
37
|
+
yield(object)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'open3'
|
4
4
|
|
5
5
|
module Fusuma
|
6
6
|
# Execute libinput command
|
@@ -30,24 +30,19 @@ module Fusuma
|
|
30
30
|
end
|
31
31
|
|
32
32
|
# @yieldparam [String] gives a line in libinput list-devices output to the block
|
33
|
-
def list_devices
|
33
|
+
def list_devices(&block)
|
34
34
|
cmd = list_devices_command
|
35
35
|
MultiLogger.debug(list_devices: cmd)
|
36
|
-
|
36
|
+
i, o, e, _w = Open3.popen3(cmd)
|
37
|
+
MultiLogger.error(e.read) if o.eof?
|
37
38
|
i.close
|
38
|
-
|
39
|
-
|
40
|
-
[i, o, e].each { |io| io.close unless io.closed? }
|
41
|
-
Process.waitpid(p)
|
39
|
+
e.close
|
40
|
+
o.each(&block)
|
42
41
|
end
|
43
42
|
|
44
|
-
# @return [
|
45
|
-
def debug_events
|
46
|
-
@debug_events ||=
|
47
|
-
_p, i, o, _e = POSIX::Spawn.popen4(debug_events_with_options)
|
48
|
-
i.close
|
49
|
-
o
|
50
|
-
end
|
43
|
+
# @return [Integer] return a latest line libinput debug-events
|
44
|
+
def debug_events(writer)
|
45
|
+
@debug_events ||= Process.spawn(debug_events_with_options, out: writer, in: '/dev/null')
|
51
46
|
end
|
52
47
|
|
53
48
|
# @return [String] command
|
@@ -60,7 +55,7 @@ module Fusuma
|
|
60
55
|
elsif which('libinput-list-devices')
|
61
56
|
'libinput-list-devices --version'
|
62
57
|
else
|
63
|
-
MultiLogger.error 'install libinput-tools'
|
58
|
+
MultiLogger.error 'Please install libinput-tools'
|
64
59
|
exit 1
|
65
60
|
end
|
66
61
|
end
|
data/lib/fusuma/multi_logger.rb
CHANGED
@@ -12,15 +12,11 @@ module Fusuma
|
|
12
12
|
attr_accessor :debug_mode
|
13
13
|
|
14
14
|
def initialize
|
15
|
-
super(
|
16
|
-
@err_logger = Logger.new(
|
15
|
+
super($stdout)
|
16
|
+
@err_logger = Logger.new($stderr)
|
17
17
|
@debug_mode = false
|
18
18
|
end
|
19
19
|
|
20
|
-
def info(msg)
|
21
|
-
super(msg)
|
22
|
-
end
|
23
|
-
|
24
20
|
def debug(msg)
|
25
21
|
return unless debug_mode?
|
26
22
|
|
data/lib/fusuma/plugin/base.rb
CHANGED
@@ -1,22 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './manager
|
4
|
-
require_relative '../config
|
3
|
+
require_relative './manager'
|
4
|
+
require_relative '../config'
|
5
|
+
require_relative '../custom_process'
|
5
6
|
|
6
7
|
module Fusuma
|
7
8
|
module Plugin
|
8
9
|
# Create a Plugin Class with extending this class
|
9
10
|
class Base
|
11
|
+
include CustomProcess
|
10
12
|
# when inherited from subclass
|
11
13
|
def self.inherited(subclass)
|
14
|
+
super
|
12
15
|
subclass_path = caller_locations(1..1).first.path
|
13
16
|
Manager.add(plugin_class: subclass, plugin_path: subclass_path)
|
14
17
|
end
|
15
18
|
|
16
|
-
# get
|
17
|
-
# @
|
18
|
-
# [Vectors::Vector]
|
19
|
-
# @return [Array]
|
19
|
+
# get subclasses
|
20
|
+
# @return [Array<Class>]
|
20
21
|
def self.plugins
|
21
22
|
Manager.plugins[name]
|
22
23
|
end
|
@@ -33,19 +34,21 @@ module Fusuma
|
|
33
34
|
|
34
35
|
return params unless key
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
@config_params ||= {}
|
38
|
+
@config_params["#{base.cache_key},#{key}"] ||=
|
39
|
+
params.fetch(key, nil).tap do |val|
|
40
|
+
next if val.nil?
|
38
41
|
|
39
|
-
|
40
|
-
|
42
|
+
# NOTE: Type checking for config.yml
|
43
|
+
param_types = Array(config_param_types.fetch(key))
|
41
44
|
|
42
|
-
|
45
|
+
next if param_types.any? { |klass| val.is_a?(klass) }
|
43
46
|
|
44
|
-
|
45
|
-
|
47
|
+
MultiLogger.error('Please fix config.yml.')
|
48
|
+
MultiLogger.error(":#{base.keys.map(&:symbol)
|
46
49
|
.join(' => :')} => :#{key} should be #{param_types.join(' OR ')}.")
|
47
|
-
|
48
|
-
|
50
|
+
exit 1
|
51
|
+
end
|
49
52
|
end
|
50
53
|
|
51
54
|
def config_index
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '../base
|
3
|
+
require_relative '../base'
|
4
4
|
|
5
5
|
module Fusuma
|
6
6
|
module Plugin
|
@@ -8,6 +8,7 @@ module Fusuma
|
|
8
8
|
# buffer events and output
|
9
9
|
class Buffer < Base
|
10
10
|
def initialize(*args)
|
11
|
+
super()
|
11
12
|
@events = Array.new(*args)
|
12
13
|
end
|
13
14
|
|
@@ -15,7 +16,7 @@ module Fusuma
|
|
15
16
|
|
16
17
|
# @return [String]
|
17
18
|
def type
|
18
|
-
self.class.name.underscore.split('/').last.gsub('_buffer', '')
|
19
|
+
@type ||= self.class.name.underscore.split('/').last.gsub('_buffer', '')
|
19
20
|
end
|
20
21
|
|
21
22
|
# @param event [Event]
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative './buffer
|
3
|
+
require_relative './buffer'
|
4
4
|
|
5
5
|
module Fusuma
|
6
6
|
module Plugin
|
@@ -8,17 +8,17 @@ module Fusuma
|
|
8
8
|
# manage events and generate command
|
9
9
|
class GestureBuffer < Buffer
|
10
10
|
DEFAULT_SOURCE = 'libinput_gesture_parser'
|
11
|
-
DEFAULT_SECONDS_TO_KEEP =
|
11
|
+
DEFAULT_SECONDS_TO_KEEP = 100
|
12
12
|
|
13
13
|
def config_param_types
|
14
14
|
{
|
15
|
-
|
16
|
-
|
15
|
+
source: [String],
|
16
|
+
seconds_to_keep: [Float, Integer]
|
17
17
|
}
|
18
18
|
end
|
19
19
|
|
20
20
|
# @param event [Event]
|
21
|
-
# @return [Buffer,
|
21
|
+
# @return [Buffer, FalseClass]
|
22
22
|
def buffer(event)
|
23
23
|
# TODO: buffering events into buffer plugins
|
24
24
|
# - gesture event buffer
|
@@ -26,16 +26,13 @@ module Fusuma
|
|
26
26
|
# - other event buffer
|
27
27
|
return if event&.tag != source
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
self
|
32
|
-
else
|
33
|
-
clear
|
34
|
-
false
|
35
|
-
end
|
29
|
+
@events.push(event)
|
30
|
+
self
|
36
31
|
end
|
37
32
|
|
38
33
|
def clear_expired(current_time: Time.now)
|
34
|
+
clear if ended?
|
35
|
+
|
39
36
|
@seconds_to_keep ||= (config_params(:seconds_to_keep) || DEFAULT_SECONDS_TO_KEEP)
|
40
37
|
@events.each do |e|
|
41
38
|
break if current_time - e.time < @seconds_to_keep
|
@@ -46,17 +43,28 @@ module Fusuma
|
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|
46
|
+
def ended?
|
47
|
+
return false if empty?
|
48
|
+
|
49
|
+
@events.last.record.status == 'end'
|
50
|
+
end
|
51
|
+
|
49
52
|
# @param attr [Symbol]
|
50
53
|
# @return [Float]
|
51
54
|
def sum_attrs(attr)
|
52
|
-
|
53
|
-
|
55
|
+
updating_events.map do |gesture_event|
|
56
|
+
gesture_event.record.delta[attr].to_f
|
57
|
+
end.inject(:+)
|
58
|
+
end
|
59
|
+
|
60
|
+
def updating_events
|
61
|
+
@events.select { |e| e.record.status == 'update' }
|
54
62
|
end
|
55
63
|
|
56
64
|
# @param attr [Symbol]
|
57
65
|
# @return [Float]
|
58
66
|
def avg_attrs(attr)
|
59
|
-
sum_attrs(attr).to_f /
|
67
|
+
sum_attrs(attr).to_f / updating_events.length
|
60
68
|
end
|
61
69
|
|
62
70
|
# return [Integer]
|
@@ -76,20 +84,21 @@ module Fusuma
|
|
76
84
|
@events.empty?
|
77
85
|
end
|
78
86
|
|
79
|
-
def select_by_events
|
80
|
-
return enum_for(:
|
87
|
+
def select_by_events(&block)
|
88
|
+
return enum_for(:select_by_events) unless block_given?
|
81
89
|
|
82
|
-
events = @events.select
|
90
|
+
events = @events.select(&block)
|
83
91
|
self.class.new events
|
84
92
|
end
|
85
93
|
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
94
|
+
def select_from_last_begin
|
95
|
+
return self if empty?
|
96
|
+
|
97
|
+
index_from_last = @events.reverse.find_index { |e| e.record.status == 'begin' }
|
98
|
+
return GestureBuffer.new([]) if index_from_last.nil?
|
99
|
+
|
100
|
+
index_last_begin = events.length - index_from_last - 1
|
101
|
+
GestureBuffer.new(@events[index_last_begin..-1])
|
93
102
|
end
|
94
103
|
end
|
95
104
|
end
|