lib/fusuma/plugin/detectors/swipe_detector.rb in fusuma-2.0.0.pre vs lib/fusuma/plugin/detectors/swipe_detector.rb in fusuma-2.0.0.pre2

- old
+ new

@@ -1,129 +1,166 @@ # frozen_string_literal: true -require_relative './detector.rb' +require_relative './detector' module Fusuma module Plugin module Detectors class SwipeDetector < Detector + SOURCES = ['gesture'].freeze BUFFER_TYPE = 'gesture' GESTURE_RECORD_TYPE = 'swipe' FINGERS = [3, 4].freeze - BASE_THERESHOLD = 10 - BASE_INTERVAL = 0.5 + BASE_THERESHOLD = 25 # @param buffers [Array<Buffers::Buffer>] - # @return [Event] if event is detected + # @return [Events::Event] if event is detected # @return [NilClass] if event is NOT detected def detect(buffers) - buffer = buffers.find { |b| b.type == BUFFER_TYPE } - .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE } + gesture_buffer = buffers.find { |b| b.type == BUFFER_TYPE } + .select_from_last_begin + .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE } - return if buffer.empty? + updating_events = gesture_buffer.updating_events + return if updating_events.empty? - move_x = buffer.avg_attrs(:move_x) - move_y = buffer.avg_attrs(:move_y) + updating_time = 100 * (updating_events.last.time - updating_events.first.time) + oneshot_move_x = gesture_buffer.sum_attrs(:move_x) / updating_time + oneshot_move_y = gesture_buffer.sum_attrs(:move_y) / updating_time - finger = buffer.finger - direction = Direction.new(move_x: move_x.to_f, move_y: move_y.to_f).to_s - quantity = Quantity.new(move_x: move_x.to_f, move_y: move_y.to_f).to_f + finger = gesture_buffer.finger + status = case gesture_buffer.events.last.record.status + when 'end' + 'end' + when 'update' + if updating_events.length == 1 + 'begin' + else + 'update' + end + else + gesture_buffer.events.last.record.status + end - index = create_index(gesture: type, - finger: finger, - direction: direction) + delta = if status == 'end' + gesture_buffer.events[-2].record.delta + else + gesture_buffer.events.last.record.delta + end - return unless enough?(index: index, quantity: quantity) + repeat_direction = Direction.new(move_x: delta.move_x, move_y: delta.move_y).to_s + repeat_quantity = Quantity.new(move_x: delta.move_x, move_y: delta.move_y).to_f - create_event(record: Events::Records::IndexRecord.new(index: index)) + repeat_index = create_repeat_index(gesture: type, finger: finger, + direction: repeat_direction, status: status) + + if status == 'update' + return unless moved?(repeat_quantity) + + oneshot_direction = Direction.new(move_x: oneshot_move_x, move_y: oneshot_move_y).to_s + oneshot_quantity = Quantity.new(move_x: oneshot_move_x, move_y: oneshot_move_y).to_f + oneshot_index = create_oneshot_index(gesture: type, finger: finger, + direction: oneshot_direction) + if enough_oneshot_threshold?(index: oneshot_index, quantity: oneshot_quantity) + return [ + create_event(record: Events::Records::IndexRecord.new( + index: oneshot_index, trigger: :oneshot, args: delta.to_h + )), + create_event(record: Events::Records::IndexRecord.new( + index: repeat_index, trigger: :repeat, args: delta.to_h + )) + ] + end + end + create_event(record: Events::Records::IndexRecord.new( + index: repeat_index, trigger: :repeat, args: delta.to_h + )) end # @param [String] gesture # @param [Integer] finger # @param [String] direction + # @param [String] status # @return [Config::Index] - def create_index(gesture:, finger:, direction:) + def create_repeat_index(gesture:, finger:, direction:, status:) Config::Index.new( [ Config::Index::Key.new(gesture), + Config::Index::Key.new(finger.to_i), + Config::Index::Key.new(direction, skippable: true), + Config::Index::Key.new(status) + ] + ) + end + + # @param [String] gesture + # @param [Integer] finger + # @param [String] direction + # @return [Config::Index] + def create_oneshot_index(gesture:, finger:, direction:) + Config::Index.new( + [ + Config::Index::Key.new(gesture), Config::Index::Key.new(finger.to_i, skippable: true), Config::Index::Key.new(direction) ] ) end private - def enough?(index:, quantity:) - enough_interval?(index: index) && enough_distance?(index: index, quantity: quantity) + def moved?(repeat_quantity) + repeat_quantity > 0.3 end - def enough_distance?(index:, quantity:) + def enough_oneshot_threshold?(index:, quantity:) quantity > threshold(index: index) end - def enough_interval?(index:) - return true if first_time? - return true if (Time.now - last_time) > interval_time(index: index) - - false - end - def threshold(index:) @threshold ||= {} @threshold[index.cache_key] ||= begin - keys_specific = Config::Index.new [*index.keys, 'threshold'] - keys_global = Config::Index.new ['threshold', type] - config_value = Config.search(keys_specific) || - Config.search(keys_global) || 1 - BASE_THERESHOLD * config_value - end + keys_specific = Config::Index.new [*index.keys, 'threshold'] + keys_global = Config::Index.new ['threshold', type] + config_value = Config.search(keys_specific) || + Config.search(keys_global) || 1 + BASE_THERESHOLD * config_value + end end - def interval_time(index:) - @interval_time ||= {} - @interval_time[index.cache_key] ||= begin - keys_specific = Config::Index.new [*index.keys, 'interval'] - keys_global = Config::Index.new ['interval', type] - config_value = Config.search(keys_specific) || - Config.search(keys_global) || 1 - BASE_INTERVAL * config_value - end - end - # direction of gesture class Direction RIGHT = 'right' LEFT = 'left' DOWN = 'down' UP = 'up' def initialize(move_x:, move_y:) - @move_x = move_x - @move_y = move_y + @move_x = move_x.to_f + @move_y = move_y.to_f end def to_s calc end def calc if @move_x.abs > @move_y.abs - @move_x > 0 ? RIGHT : LEFT - elsif @move_y > 0 + @move_x.positive? ? RIGHT : LEFT + elsif @move_y.positive? DOWN else UP end end end # quantity of gesture class Quantity def initialize(move_x:, move_y:) - @x = move_x.abs - @y = move_y.abs + @x = move_x.to_f.abs + @y = move_y.to_f.abs end def to_f calc.to_f end