Skip to content

Commit

Permalink
Merge pull request #137 from iberianpig/feature/reload_device_when_ne…
Browse files Browse the repository at this point in the history
…w_device_added

Reload Filter when new device is added
  • Loading branch information
iberianpig authored Oct 19, 2019
2 parents ba92198 + 00fbdba commit 38b4032
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 74 deletions.
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Metrics/LineLength:
Max: 100
Exclude:
- "fusuma.gemspec"
- "**/*_spec.rb"
3 changes: 2 additions & 1 deletion lib/fusuma.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def read_options(option)
print_enabled_plugins

print_device_list if option[:list]
Device.given_devices = option[:device]
# TODO: remove keep_device_from_option from command line options
Plugin::Filters::LibinputDeviceFilter::KeepDevice.from_option = option[:device]
Process.daemon if option[:daemon]
end

Expand Down
26 changes: 0 additions & 26 deletions lib/fusuma/device.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ def assign_attributes(attributes)
end

class << self
attr_reader :given_devices

# @return [Array]
def all
@all ||= fetch_devices
Expand All @@ -53,19 +51,6 @@ def reset
@available = nil
end

# Narrow down available device list
# @param names [String, Array]
def given_devices=(names)
# NOTE: convert to Array
device_names = Array(names)
return if device_names.empty?

@given_devices = narrow_available_devices(device_names: device_names)
return unless @given_devices.empty?

exit 1
end

private

# @return [Array]
Expand All @@ -77,17 +62,6 @@ def fetch_devices
line_parser.generate_devices
end

def narrow_available_devices(device_names:)
device_names.select do |name|
if available.map(&:name).include? name
MultiLogger.info("Touchpad is found: #{name}")
true
else
MultiLogger.warn("Touchpad is not found: #{name}")
end
end
end

# parse line and generate devices
class LineParser
attr_reader :lines
Expand Down
5 changes: 3 additions & 2 deletions lib/fusuma/plugin/filters/filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module Fusuma
module Plugin
# filter class
module Filters
# Inherite this base
# Filter record to keep
class Filter < Base
# Filter input event
# @param event [Event]
Expand All @@ -24,7 +24,8 @@ def filter(event)

# @abstract override `#keep?` to implement
# @param record [String]
# @return [True, False]
# @return [True] when keeping record
# @return [False] when discarding record
def keep?(record)
true if record
end
Expand Down
60 changes: 48 additions & 12 deletions lib/fusuma/plugin/filters/libinput_device_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,59 @@ def config_param_types
}
end

# @return [TrueClass] when keeping it
# @return [FalseClass] when discarding it
def keep?(record)
keep_device_ids.any? { |device_id| record.to_s =~ /^\s?#{device_id}/ }
end
# NOTE: purge cache when found new device
if record.to_s =~ /\sDEVICE_ADDED\s/ && keep_device.match_pattern?(record.to_s)
keep_device.reset
return false
end

private
keep_device.all.map(&:id).any? { |device_id| record.to_s =~ /^\s?#{device_id}\s/ }
end

# @return [Array]
def keep_device_ids
@keep_device_ids ||= Device.all.select do |device|
keep_device_names.any? { |name| device.name.match(name) }
end.map(&:id)
def keep_device
@keep_device ||= begin
from_config = Array(config_params(:keep_device_names))
KeepDevice.new(name_patterns: from_config)
end
end

# @return [Array]
def keep_device_names
Array(config_params(:keep_device_names)).tap do |names|
break Device.all.map(&:name) if names.empty?
# Select Device to keep
class KeepDevice
def initialize(name_patterns:)
@name_patterns = name_patterns | Array(self.class.from_option)
end

# remove cache for reloading new devices
def reset
@all = nil
Device.reset
end

# @return [Array]
def all
@all ||= if @name_patterns.empty?
Device.available
else
Device.all.select do |device|
match_pattern?(device.name)
end
end
end

# @return [TrueClass]
# @return [FalseClass]
def match_pattern?(string)
return true if @name_patterns.empty?

@name_patterns.any? { |name_pattern| string.match(name_pattern) }
end

class << self
# TODO: remove from_option and command line options
attr_accessor :from_option
end
end
end
Expand Down
10 changes: 1 addition & 9 deletions lib/fusuma/plugin/inputs/libinput_command_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def list_devices
# @yield [line] gives a line in libinput debug-events output to the block
def debug_events
prefix = 'stdbuf -oL --'
options = [*libinput_options, device_option]
options = [*libinput_options]
cmd = "#{prefix} #{debug_events_command} #{options.join(' ')}".strip
MultiLogger.debug(debug_events: cmd)
Open3.popen3(cmd) do |_i, o, _e, _w|
Expand Down Expand Up @@ -90,14 +90,6 @@ def debug_events_command

private

# use device option only if libinput detect only 1 device
# @return [String]
def device_option
return unless Device.available.size == 1

"--device=/dev/input/#{Device.available.first.id}"
end

# TODO: add specs
def libinput_options
enable_tap = '--enable-tap' if config_params(:'enable-tap')
Expand Down
5 changes: 4 additions & 1 deletion spec/fusuma_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
require 'spec_helper'
require './lib/fusuma.rb'
require './lib/fusuma/plugin/inputs/libinput_command_input.rb'
require './lib/fusuma/plugin/filters/libinput_device_filter.rb'

module Fusuma
RSpec.describe Runner do
Expand Down Expand Up @@ -56,10 +57,12 @@ module Fusuma
end
end

# TODO: remove from_option and command line options
context 'when run with argument "--device="test_device2"' do
it 'should set device' do
allow(Device).to receive(:names) { %w[test_device1 test_device2] }
expect(Device).to receive(:given_devices=).with('test_device2')
expect(Plugin::Filters::LibinputDeviceFilter::KeepDevice)
.to receive(:from_option=).with('test_device2')
Runner.run(device: 'test_device2')
end
end
Expand Down
6 changes: 3 additions & 3 deletions spec/lib/plugin/filters/filter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ def config_param_types

context 'with config' do
around do |example|
CUSTOME_SOURCE = 'custom_input'
@custom_source = 'custom_input'

ConfigHelper.load_config_yml = <<~CONFIG
plugin:
filters:
dummy_filter:
source: #{CUSTOME_SOURCE}
source: #{@custom_source}
CONFIG

example.run

Config.custom_path = nil
end

it { is_expected.to eq CUSTOME_SOURCE }
it { is_expected.to eq @custom_source }
end
end

Expand Down
67 changes: 56 additions & 11 deletions spec/lib/plugin/filters/libinput_filter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,53 +11,98 @@ module Fusuma
module Plugin
module Filters
RSpec.describe LibinputDeviceFilter do
let(:filter) { LibinputDeviceFilter.new }
before do
@filter = LibinputDeviceFilter.new
end

describe '#source' do
it { expect(filter.source).to eq LibinputDeviceFilter::DEFAULT_SOURCE }
it { expect(@filter.source).to eq LibinputDeviceFilter::DEFAULT_SOURCE }

context 'with config' do
around do |example|
CUSTOME_SOURCE = 'custom_input'
@custom_source = 'custom_input'

ConfigHelper.load_config_yml = <<~CONFIG
plugin:
filters:
libinput_device_filter:
source: #{CUSTOME_SOURCE}
source: #{@custom_source}
CONFIG

example.run

Config.custom_path = nil
end

it { expect(filter.source).to eq CUSTOME_SOURCE }
it { expect(@filter.source).to eq @custom_source }
end
end

describe '#filter' do
let(:event) { Events::Event.new(tag: 'libinput_command_input', record: 'dummy') }
before do
@event = Events::Event.new(tag: 'libinput_command_input', record: 'dummy')
end

context 'when filter#keep? return false' do
before do
allow(filter).to receive(:keep?).and_return(false)
allow(@filter).to receive(:keep?).and_return(false)
end

it { expect(filter.filter(event)).to be nil }
it { expect(@filter.filter(@event)).to be nil }
end

context 'when filter#keep? return true' do
before do
allow(filter).to receive(:keep?).and_return(true)
allow(@filter).to receive(:keep?).and_return(true)
end

it { expect(filter.filter(event)).to be event }
it { expect(@filter.filter(@event)).to be @event }
end
end

describe '#keep?' do
pending 'Not implemented'
before do
device = Device.new(id: 'event18', name: 'Awesome Touchpad', available: true)
allow(Device).to receive(:all).and_return([device])
@keep_device = LibinputDeviceFilter::KeepDevice.new(name_patterns: [])
allow(@filter).to receive(:keep_device).and_return(@keep_device)
end

context 'when including record generated from touchpad' do
before do
text = ' event18 GESTURE_SWIPE_UPDATE +1.44s 4 11.23/ 1.00 (36.91/ 3.28 unaccelerated) '
@event = Events::Event.new(tag: 'libinput_command_input', record: text)
end
it 'should keep record' do
expect(@filter.keep?(@event.record)).to be true
end
end
context 'when new device is added' do
before do
text = '-event18 DEVICE_ADDED Apple Wireless Trackpad seat0 default group13 cap:pg size 132x112mm tap(dl off) left scroll-nat scroll-2fg-edge click-buttonareas-clickfing '
@event = Events::Event.new(tag: 'libinput_command_input', record: text)
end
it 'should reset KeepDevice' do
expect(@keep_device).to receive(:reset)
@filter.keep?(@event.record)
end

it 'discard DEVICE_ADDED record' do
expect(@filter.keep?(@event.record)).to be false
end

context 'when keep device is NOT matched' do
before do
@keep_device = LibinputDeviceFilter::KeepDevice.new(name_patterns: ['Microsoft Arc Mouse'])
allow(@filter).to receive(:keep_device).and_return(@keep_device)
end
it 'should NOT reset KeepDevice' do
expect(@keep_device).not_to receive(:reset)
# NOTE: @event.record is 'Apple Wireless Touchpad'
@filter.keep?(@event.record)
end
end
end
end
end
end
Expand Down
15 changes: 6 additions & 9 deletions spec/lib/plugin/inputs/libinput_command_input_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,37 +105,34 @@ module Inputs
describe 'debug_events' do
subject { libinput_command.debug_events }

before do
allow(libinput_command).to receive(:device_option)
.and_return('--device stub_device')
end

after { subject }

context 'with new cli version' do
before do
allow(libinput_command).to receive(:new_cli_option_available?)
allow(libinput_command)
.to receive(:new_cli_option_available?)
.and_return(true)
end

it 'call `libinput debug-events`' do
command = 'libinput debug-events'
expect(Open3).to receive(:popen3)
.with("stdbuf -oL -- #{command} --device stub_device")
.with("stdbuf -oL -- #{command}")
.and_return 'stub message'
end
end

context 'with old cli version' do
before do
allow(libinput_command).to receive(:new_cli_option_available?)
allow(libinput_command)
.to receive(:new_cli_option_available?)
.and_return(false)
end

it 'call `libinput-debug-events`' do
command = 'libinput-debug-events'
expect(Open3).to receive(:popen3)
.with("stdbuf -oL -- #{command} --device stub_device")
.with("stdbuf -oL -- #{command}")
.and_return 'stub message'
end
end
Expand Down

0 comments on commit 38b4032

Please sign in to comment.