fusuma 0.11.1 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/fusuma/gesture_event.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
module Fusuma
|
2
|
-
# pinch or swipe or rotate event
|
3
|
-
class GestureEvent
|
4
|
-
def initialize(time, event, finger, directions)
|
5
|
-
@time = time.to_f
|
6
|
-
@event = event
|
7
|
-
@finger = finger
|
8
|
-
@move_x = directions[:move][:x].to_f
|
9
|
-
@move_y = directions[:move][:y].to_f
|
10
|
-
@zoom = directions[:zoom].to_f
|
11
|
-
end
|
12
|
-
attr_reader :time, :event, :finger,
|
13
|
-
:move_x, :move_y, :zoom
|
14
|
-
|
15
|
-
class << self
|
16
|
-
def initialize_by(line, device_names)
|
17
|
-
return if device_names.none? do |device_name|
|
18
|
-
line =~ /^\s?#{device_name}/
|
19
|
-
end
|
20
|
-
return if line =~ /_BEGIN/
|
21
|
-
return unless line =~ /GESTURE_SWIPE|GESTURE_PINCH/
|
22
|
-
time, event, finger, directions = gesture_event_arguments(line)
|
23
|
-
MultiLogger.debug(time: time, event: event,
|
24
|
-
finger: finger, directions: directions)
|
25
|
-
new(time, event, finger, directions)
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def gesture_event_arguments(libinput_line)
|
31
|
-
event, time, finger, other = parse_libinput(libinput_line)
|
32
|
-
move_x, move_y, zoom = parse_finger_directions(other)
|
33
|
-
directions = { move: { x: move_x, y: move_y }, zoom: zoom }
|
34
|
-
[time, event, finger, directions]
|
35
|
-
end
|
36
|
-
|
37
|
-
def parse_libinput(line)
|
38
|
-
_device, event, time, other = line.strip.split(nil, 4)
|
39
|
-
finger, other = other.split(nil, 2)
|
40
|
-
[event, time, finger, other]
|
41
|
-
end
|
42
|
-
|
43
|
-
def parse_finger_directions(line)
|
44
|
-
return [] unless line
|
45
|
-
move_x, move_y, _, _, _, zoom = line.tr('/|(|)', ' ').split
|
46
|
-
[move_x, move_y, zoom]
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
module Fusuma
|
2
|
-
# libinput commands wrapper
|
3
|
-
class LibinputCommands
|
4
|
-
def initialize(*options)
|
5
|
-
@options = options
|
6
|
-
end
|
7
|
-
|
8
|
-
# `libinput-list-devices` and `libinput-debug-events` are deprecated,
|
9
|
-
# use `libinput list-devices` and `libinput debug-events` from 1.8.
|
10
|
-
NEW_CLI_OPTION_VERSION = 1.8
|
11
|
-
|
12
|
-
# @return [Boolean]
|
13
|
-
def new_cli_option_available?
|
14
|
-
Gem::Version.new(version) >= Gem::Version.new(NEW_CLI_OPTION_VERSION)
|
15
|
-
end
|
16
|
-
|
17
|
-
# @return [String]
|
18
|
-
def version
|
19
|
-
# versiom_command prints "1.6.3\n"
|
20
|
-
@version ||= `#{version_command}`.strip
|
21
|
-
end
|
22
|
-
|
23
|
-
# @yield [line] gives a line in libinput list-devices output to the block
|
24
|
-
def list_devices
|
25
|
-
cmd = list_devices_command
|
26
|
-
MultiLogger.debug(debug_events: cmd)
|
27
|
-
Open3.popen3(cmd) do |_i, o, _e, _w|
|
28
|
-
o.each { |line| yield(line) }
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# @yield [line] gives a line in libinput debug-events output to the block
|
33
|
-
def debug_events
|
34
|
-
prefix = 'stdbuf -oL --'
|
35
|
-
options = [*@options, device_option]
|
36
|
-
cmd = "#{prefix} #{debug_events_command} #{options.join(' ')}".strip
|
37
|
-
MultiLogger.debug(debug_events: cmd)
|
38
|
-
Open3.popen3(cmd) do |_i, o, _e, _w|
|
39
|
-
o.each { |line| yield(line) }
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# @return [String] command
|
44
|
-
# @raise [SystemExit]
|
45
|
-
def version_command
|
46
|
-
if which('libinput')
|
47
|
-
'libinput --version'
|
48
|
-
elsif which('libinput-list-devices')
|
49
|
-
'libinput-list-devices --version'
|
50
|
-
else
|
51
|
-
MultiLogger.error 'install libinput-tools'
|
52
|
-
exit 1
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def list_devices_command
|
57
|
-
if new_cli_option_available?
|
58
|
-
'libinput list-devices'
|
59
|
-
else
|
60
|
-
'libinput-list-devices'
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def debug_events_command
|
65
|
-
if new_cli_option_available?
|
66
|
-
'libinput debug-events'
|
67
|
-
else
|
68
|
-
'libinput-debug-events'
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
# use device option only if libinput detect only 1 device
|
75
|
-
# @return [String]
|
76
|
-
def device_option
|
77
|
-
return unless Device.available.size == 1
|
78
|
-
"--device /dev/input/#{Device.available.first.id}"
|
79
|
-
end
|
80
|
-
|
81
|
-
# which in ruby: Checking if program exists in $PATH from ruby
|
82
|
-
# (https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby)
|
83
|
-
# Cross-platform way of finding an executable in the $PATH.
|
84
|
-
#
|
85
|
-
# which('ruby') #=> /usr/bin/ruby
|
86
|
-
# @return [String, nil]
|
87
|
-
def which(command)
|
88
|
-
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
89
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
90
|
-
exts.each do |ext|
|
91
|
-
exe = File.join(path, "#{command}#{ext}")
|
92
|
-
return exe if File.executable?(exe) && !File.directory?(exe)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
nil
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
data/lib/fusuma/pinch.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
module Fusuma
|
2
|
-
# vector data
|
3
|
-
class Pinch
|
4
|
-
TYPE = 'pinch'.freeze
|
5
|
-
|
6
|
-
BASE_THERESHOLD = 0.3
|
7
|
-
BASE_INTERVAL = 0.05
|
8
|
-
|
9
|
-
def initialize(diameter)
|
10
|
-
@diameter = diameter.to_f
|
11
|
-
end
|
12
|
-
|
13
|
-
attr_reader :diameter
|
14
|
-
|
15
|
-
def direction
|
16
|
-
return 'in' if diameter > 0
|
17
|
-
'out'
|
18
|
-
end
|
19
|
-
|
20
|
-
def enough?(trigger)
|
21
|
-
MultiLogger.debug(diameter: diameter)
|
22
|
-
enough_diameter?(trigger) && enough_interval?(trigger) &&
|
23
|
-
self.class.touch_last_time
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def enough_diameter?(trigger)
|
29
|
-
diameter.abs > threshold(trigger)
|
30
|
-
end
|
31
|
-
|
32
|
-
def enough_interval?(trigger)
|
33
|
-
return true if first_time?
|
34
|
-
return true if (Time.now - self.class.last_time) > interval_time(trigger)
|
35
|
-
false
|
36
|
-
end
|
37
|
-
|
38
|
-
def first_time?
|
39
|
-
!self.class.last_time
|
40
|
-
end
|
41
|
-
|
42
|
-
def threshold(trigger)
|
43
|
-
@threshold ||= BASE_THERESHOLD * Config.threshold(trigger)
|
44
|
-
end
|
45
|
-
|
46
|
-
def interval_time(trigger)
|
47
|
-
@interval_time ||= BASE_INTERVAL * Config.interval(trigger)
|
48
|
-
end
|
49
|
-
|
50
|
-
class << self
|
51
|
-
attr_reader :last_time
|
52
|
-
|
53
|
-
def touch_last_time
|
54
|
-
@last_time = Time.now
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
data/lib/fusuma/swipe.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
module Fusuma
|
2
|
-
# vector data
|
3
|
-
class Swipe
|
4
|
-
TYPE = 'swipe'.freeze
|
5
|
-
|
6
|
-
BASE_THERESHOLD = 20
|
7
|
-
BASE_INTERVAL = 0.5
|
8
|
-
|
9
|
-
def initialize(move_x, move_y)
|
10
|
-
@x = move_x
|
11
|
-
@y = move_y
|
12
|
-
end
|
13
|
-
attr_reader :x, :y
|
14
|
-
|
15
|
-
def direction
|
16
|
-
return x > 0 ? 'right' : 'left' if x.abs > y.abs
|
17
|
-
y > 0 ? 'down' : 'up'
|
18
|
-
end
|
19
|
-
|
20
|
-
def enough?(trigger)
|
21
|
-
MultiLogger.debug(x: x, y: y)
|
22
|
-
enough_distance?(trigger) && enough_interval?(trigger) &&
|
23
|
-
self.class.touch_last_time
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def enough_distance?(trigger)
|
29
|
-
threshold = threshold(trigger)
|
30
|
-
(x.abs > threshold) || (y.abs > threshold)
|
31
|
-
end
|
32
|
-
|
33
|
-
def enough_interval?(trigger)
|
34
|
-
return true if first_time?
|
35
|
-
return true if (Time.now - self.class.last_time) > interval_time(trigger)
|
36
|
-
false
|
37
|
-
end
|
38
|
-
|
39
|
-
def first_time?
|
40
|
-
!self.class.last_time
|
41
|
-
end
|
42
|
-
|
43
|
-
def threshold(trigger)
|
44
|
-
@threshold ||= BASE_THERESHOLD * Config.threshold(trigger)
|
45
|
-
end
|
46
|
-
|
47
|
-
def interval_time(trigger)
|
48
|
-
@interval_time ||= BASE_INTERVAL * Config.interval(trigger)
|
49
|
-
end
|
50
|
-
|
51
|
-
class << self
|
52
|
-
attr_reader :last_time
|
53
|
-
|
54
|
-
def touch_last_time
|
55
|
-
@last_time = Time.now
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|