fusuma 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c964784d9707a4ca667c19b4c866bd5e0abc8e61e2f0752903c2cac3fd064448
4
- data.tar.gz: fc9c42d27ee80535d6da10f3cdd0ee707a128ad42f147366dd40f4c2053a273a
3
+ metadata.gz: 701d329da6fb23d22958f210648a1bf30b73f947064c94c2f30a1ab634edf5e4
4
+ data.tar.gz: 6335546af4a4624fd450107800b5fde80692f0aa60ab910758be940163006d54
5
5
  SHA512:
6
- metadata.gz: 99e47419a912ae9e77215fef51bae8bc6a657ac679dbb9a55873087753f354bc9b077657f2fa7699372931ac7a0d0f3faef7d732da4197e1fcef2623b02b8b9c
7
- data.tar.gz: 7d8ac348be34c4756e549ac0856fa01119680d5d9ebc7346ca3dc29070023b3a6c8d6a4f2218a3fde6951936d51d8ea0335723dcf2a76285f5ab7a477746ca4e
6
+ metadata.gz: 931976b9864eb6077a6ebbc34b4425848782cb1b40358ada6e1b2dae6b145bff5382ec61b17ef58835ce1b179be28fca13d76e870243d0f70c40cddb67317700
7
+ data.tar.gz: 4ccc5737a5ae4d9f979fb409374f3f02c285046f266e368a05c1f5f6e846bfb9ddd47af3bff809f9f6ed1329564aeaaa66b5723ac7e7f342b2031b0322cefbea
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Fusuma [![Gem Version](https://badge.fury.io/rb/fusuma.svg)](https://badge.fury.io/rb/fusuma) [![Build Status](https://travis-ci.com/iberianpig/fusuma.svg?branch=master)](https://travis-ci.com/iberianpig/fusuma) [![Coverage Status](https://coveralls.io/repos/github/iberianpig/fusuma/badge.svg?branch=master)](https://coveralls.io/github/iberianpig/fusuma?branch=master)
1
+ # Fusuma [![Gem Version](https://badge.fury.io/rb/fusuma.svg)](https://badge.fury.io/rb/fusuma) [![Testing on Ubuntu](https://github.com/iberianpig/fusuma/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/iberianpig/fusuma/actions/workflows/ubuntu.yml) [![Coverage Status](https://coveralls.io/repos/github/iberianpig/fusuma/badge.svg?branch=master)](https://coveralls.io/github/iberianpig/fusuma?branch=master)
2
2
 
3
3
  Fusuma is multitouch gesture recognizer.
4
4
  This gem makes your linux able to recognize swipes or pinchs and assign commands to them.
@@ -22,13 +22,13 @@ This gem makes your linux able to recognize swipes or pinchs and assign commands
22
22
  **IMPORTANT**: You **MUST** be a member of the **INPUT** group to read touchpad by Fusuma.
23
23
 
24
24
  ```bash
25
- $ sudo gpasswd -a $USER input
25
+ sudo gpasswd -a $USER input
26
26
  ```
27
27
 
28
28
  Then, You apply the change with no logout or reboot.
29
29
 
30
30
  ```bash
31
- $ newgrp input
31
+ newgrp input
32
32
  ```
33
33
 
34
34
  ### For Debian Based Distros (Ubuntu, Debian, Mint, Pop!OS)
@@ -38,7 +38,7 @@ $ newgrp input
38
38
  You need `libinput` release 1.0 or later.
39
39
 
40
40
  ```bash
41
- $ sudo apt-get install libinput-tools
41
+ sudo apt-get install libinput-tools
42
42
  ```
43
43
 
44
44
  #### 2. Install Ruby
@@ -46,13 +46,13 @@ $ sudo apt-get install libinput-tools
46
46
  Fusuma runs in Ruby, so you must install it first.
47
47
 
48
48
  ```bash
49
- $ sudo apt-get install ruby
49
+ sudo apt-get install ruby
50
50
  ```
51
51
 
52
52
  #### 3. Install Fusuma
53
53
 
54
54
  ```bash
55
- $ sudo gem install fusuma
55
+ sudo gem install fusuma
56
56
  ```
57
57
 
58
58
  #### 4. Install xdotool (optional)
@@ -60,7 +60,7 @@ $ sudo gem install fusuma
60
60
  For sending shortcuts:
61
61
 
62
62
  ```bash
63
- $ sudo apt-get install xdotool
63
+ sudo apt-get install xdotool
64
64
  ```
65
65
 
66
66
  ### For Arch Based Distros (Manjaro, Arch)
@@ -70,7 +70,7 @@ $ sudo apt-get install xdotool
70
70
  You need `libinput` release 1.0 or later. This is most probably installed by default on Manjaro
71
71
 
72
72
  ```z-h
73
- $ sudo pacman -S libinput
73
+ sudo pacman -S libinput
74
74
  ```
75
75
 
76
76
  #### 2. Install Ruby
@@ -78,7 +78,7 @@ $ sudo pacman -S libinput
78
78
  Fusuma runs in Ruby, so you must install it first.
79
79
 
80
80
  ```zsh
81
- $ sudo pacman -S ruby
81
+ sudo pacman -S ruby
82
82
  ```
83
83
 
84
84
  #### 3. Install Fusuma
@@ -88,7 +88,7 @@ $ sudo pacman -S ruby
88
88
  To install gems system-wide, see any of the methods listed on [Arch Wiki](https://wiki.archlinux.org/index.php/ruby#Installing_gems_system-wide)
89
89
 
90
90
  ```zsh
91
- $ sudo gem install fusuma
91
+ sudo gem install fusuma
92
92
  ```
93
93
 
94
94
  #### 4. Install xdotool (optional)
@@ -96,7 +96,7 @@ $ sudo gem install fusuma
96
96
  For sending shortcuts:
97
97
 
98
98
  ```zsh
99
- $ sudo pacman -S xdotool
99
+ sudo pacman -S xdotool
100
100
  ```
101
101
 
102
102
  ### Touchpad not working in GNOME
@@ -104,19 +104,19 @@ $ sudo pacman -S xdotool
104
104
  Ensure the touchpad events are being sent to the GNOME desktop by running the following command:
105
105
 
106
106
  ```bash
107
- $ gsettings set org.gnome.desktop.peripherals.touchpad send-events enabled
107
+ gsettings set org.gnome.desktop.peripherals.touchpad send-events enabled
108
108
  ```
109
109
 
110
110
  ## Usage
111
111
 
112
112
  ```bash
113
- $ fusuma
113
+ fusuma
114
114
  ```
115
115
 
116
116
  ## Update
117
117
 
118
118
  ```bash
119
- $ sudo gem update fusuma
119
+ sudo gem update fusuma
120
120
  ```
121
121
 
122
122
  ## Customize Gesture Mapping
@@ -125,25 +125,35 @@ You can customize the settings for gestures to put and edit `~/.config/fusuma/co
125
125
  **NOTE: You will need to create the `~/.config/fusuma` directory if it doesn't exist yet.**
126
126
 
127
127
  ```bash
128
- $ mkdir -p ~/.config/fusuma # create config directory
129
- $ nano ~/.config/fusuma/config.yml # edit config file.
128
+ mkdir -p ~/.config/fusuma # create config directory
129
+ nano ~/.config/fusuma/config.yml # edit config file.
130
130
  ```
131
131
 
132
132
 
133
133
  ### Available gestures
134
134
 
135
- * `swipe:`
136
- * support `3:`, `4:` fingers
137
- * support `left:`, `right:`, `up:`, `down:` directions
138
- * support `begin:`, `update:`, `end:` events
139
- * `pinch:`
140
- * support `2:`, `3:`, `4:` fingers
141
- * support `in:`, `out:` directions
142
- * support `begin:`, `update:`, `end:` events
143
- * `rotate:`
144
- * support `2:`, `3:`, `4:` fingers
145
- * support `clockwise:`,`counterclockwise:` directions
146
- * support `begin:`, `update:`, `end:` events
135
+ #### swipe:
136
+
137
+ * support `3:`, `4:` fingers
138
+ * support `left:`, `right:`, `up:`, `down:` directions
139
+ * support `begin:`, `update:`, `end:` events
140
+
141
+ #### pinch:
142
+
143
+ * support `2:`, `3:`, `4:` fingers
144
+ * support `in:`, `out:` directions
145
+ * support `begin:`, `update:`, `end:` events
146
+
147
+ #### rotate:
148
+
149
+ * support `2:`, `3:`, `4:` fingers
150
+ * support `clockwise:`,`counterclockwise:` directions
151
+ * support `begin:`, `update:`, `end:` events
152
+
153
+ #### hold:
154
+ * require libinput version 1.19.0 or later
155
+ * support `1:`, `2:`, `3:`, `4:` fingers
156
+ * support `begin:`, `end:`, `cancelled:` events
147
157
 
148
158
  ### About YAML Basic Syntax
149
159
 
@@ -181,6 +191,9 @@ pinch:
181
191
  command: "xdotool keydown ctrl click 4 keyup ctrl" # Zoom in
182
192
  out:
183
193
  command: "xdotool keydown ctrl click 5 keyup ctrl" # Zoom out
194
+ hold:
195
+ 4:
196
+ command: "xdotool key super" # Activity
184
197
  ```
185
198
 
186
199
  ### More Example of config.yml
@@ -201,12 +214,12 @@ If you have a nice configuration, please share `~/.config/fusuma/config.yml` wit
201
214
 
202
215
  ### Threshold and Interval
203
216
 
204
- if `command:` properties are blank, the swipe/pinch doesn't execute command.
217
+ if `command:` properties are blank, the swipe/pinch/hold doesn't execute command.
205
218
 
206
- `threshold:` is sensitivity to swipe/pinch. Default value is 1.
219
+ `threshold:` is sensitivity to swipe/pinch/hold. Default value is 1.
207
220
  If the swipe's threshold is `0.5`, shorten swipe-length by half.
208
221
 
209
- `interval:` is delay between swipes/pinches. Default value is 1.
222
+ `interval:` is delay between swipes/pinches/hold. Default value is 1.
210
223
  If the swipe's interval is `0.5`, shorten swipe-interval by half to recognize a next swipe.
211
224
 
212
225
  ### Example of `threshold:` / `interval:` settings
@@ -243,7 +256,7 @@ There are three priorities of `threshold:` and `interval:`.
243
256
  The individual `threshold:` and `interval:` settings (under "direction") have a higher priority than the global one (under "root")
244
257
 
245
258
  1. child elements in the direction (left/right/down/up → threshold/interval)
246
- 1. root child elements (threshold/interval → swipe/pinch)
259
+ 1. root child elements (threshold/interval → swipe/pinch/hold)
247
260
  1. default value (= 1)
248
261
 
249
262
  ### `command:` property for assigning commands
@@ -314,8 +327,8 @@ plugin:
314
327
 
315
328
  ## Autostart (gnome-session-properties)
316
329
 
317
- 1. Check the path where you installed fusuma with `$ which fusuma`
318
- 2. Open `$ gnome-session-properties`
330
+ 1. Check the path where you installed fusuma with `which fusuma`
331
+ 2. Open `gnome-session-properties`
319
332
  3. Add Fusuma and enter the location where the above path was checked in the command input field
320
333
  4. Add the `-d` option at the end of the command input field
321
334
 
@@ -327,14 +340,10 @@ Following features are provided as plugins.
327
340
  - Features for specific Linux distributions
328
341
  - Setting different gestures per applications
329
342
 
330
- ### Installation of Fusuma plugins
343
+ ### Available plugins
331
344
 
332
345
  Fusuma plugins are provided with the `fusuma-plugin-XXXXX` naming convention and hosted on [RubyGems](https://rubygems.org/search?utf8=%E2%9C%93&query=fusuma-plugins).
333
346
 
334
- `$ sudo gem install fusuma-plugin-XXXXX`
335
-
336
- ### Available plugins
337
-
338
347
  | Name | Version | About |
339
348
  | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------- |
340
349
  | [fusuma-plugin-sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-sendkey.svg) | Emulates keyboard events |
@@ -343,6 +352,18 @@ Fusuma plugins are provided with the `fusuma-plugin-XXXXX` naming convention and
343
352
  | [fusuma-plugin-tap](https://github.com/iberianpig/fusuma-plugin-tap) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-tap.svg) | Detects Tap and Hold gestures |
344
353
  | [fusuma-plugin-appmatcher](https://github.com/iberianpig/fusuma-plugin-appmatcher) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-appmatcher.svg) | Configure app-specific gestures |
345
354
 
355
+
356
+ ### Installation of Fusuma plugins
357
+
358
+ ```bash
359
+ # install fusuma-plugin-XXXX
360
+ sudo gem install fusuma-plugin-XXXXX`
361
+ ```
362
+ ```bash
363
+ # update
364
+ sudo gem list fusuma-plugin- | cut -d' ' -f1 | xargs --no-run-if-empty sudo gem update
365
+ ```
366
+
346
367
  ## Tutorial Video
347
368
 
348
369
  [![Multitouch Touchpad Gestures in Linux with Fusuma](http://img.youtube.com/vi/bn11Iwvf29I/0.jpg)](http://www.youtube.com/watch?v=bn11Iwvf29I "Multitouch Touchpad Gestures in Linux with Fusuma")
data/fusuma.gemspec CHANGED
@@ -20,7 +20,10 @@ Gem::Specification.new do |spec|
20
20
  spec.bindir = 'exe'
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ['lib']
23
- spec.metadata['yard.run'] = 'yri' # use "yard" to build full HTML docs.
23
+ spec.metadata = {
24
+ 'rubygems_mfa_required' => 'true',
25
+ 'yard.run' => 'yri' # use "yard" to build full HTML docs.
26
+ }
24
27
 
25
28
  spec.required_ruby_version = '>= 2.5.1' # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
26
29
  # support bionic (18.04LTS) 2.5.1
@@ -13,10 +13,7 @@ module Fusuma
13
13
 
14
14
  # `libinput-list-devices` and `libinput-debug-events` are deprecated,
15
15
  # use `libinput list-devices` and `libinput debug-events` from 1.8.
16
- NEW_CLI_OPTION_VERSION = 1.8
17
-
18
- DEFAULT_WAIT_TIME = 0.3
19
- TIMEOUT_MESSAGE = 'LIBINPUT TIMEOUT'
16
+ NEW_CLI_OPTION_VERSION = '1.8'
20
17
 
21
18
  # @return [Boolean]
22
19
  def new_cli_option_available?
@@ -92,10 +89,6 @@ module Fusuma
92
89
 
93
90
  private
94
91
 
95
- def wait_time
96
- DEFAULT_WAIT_TIME
97
- end
98
-
99
92
  # which in ruby: Checking if program exists in $PATH from ruby
100
93
  # (https://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby)
101
94
  # Cross-platform way of finding an executable in the $PATH.
@@ -11,21 +11,20 @@ module Fusuma
11
11
  attr_reader :err_logger
12
12
  attr_accessor :debug_mode
13
13
 
14
- @@filepath = nil
15
- def self.filepath=(filepath)
16
- @@filepath = filepath
14
+ class << self
15
+ attr_writer :filepath
17
16
  end
18
17
 
19
18
  def initialize
20
- if @@filepath
21
- logfile = File.new(@@filepath, 'a')
19
+ filepath = self.class.instance_variable_get('@filepath')
20
+ if filepath
21
+ logfile = File.new(filepath, 'a')
22
22
  super(logfile)
23
23
  $stderr = logfile
24
- @err_logger = Logger.new($stderr)
25
24
  else
26
25
  super($stdout)
27
- @err_logger = Logger.new($stderr)
28
26
  end
27
+ @err_logger = Logger.new($stderr)
29
28
  @debug_mode = false
30
29
  end
31
30
 
@@ -46,7 +46,12 @@ module Fusuma
46
46
  def ended?
47
47
  return false if empty?
48
48
 
49
- @events.last.record.status == 'end'
49
+ case @events.last.record.status
50
+ when 'end', 'cancelled'
51
+ true
52
+ else
53
+ false
54
+ end
50
55
  end
51
56
 
52
57
  # @param attr [Symbol]
@@ -0,0 +1,129 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './detector'
4
+
5
+ module Fusuma
6
+ module Plugin
7
+ module Detectors
8
+ # Detect Hold gesture
9
+ class HoldDetector < Detector
10
+ SOURCES = %w[gesture timer].freeze
11
+ BUFFER_TYPE = 'gesture'
12
+ GESTURE_RECORD_TYPE = 'hold'
13
+
14
+ BASE_THERESHOLD = 0.7
15
+
16
+ # @param buffers [Array<Buffers::Buffer>]
17
+ # @return [Events::Event] if event is detected
18
+ # @return [Array<Events::Event>] if hold end event is detected
19
+ # @return [NilClass] if event is NOT detected
20
+ def detect(buffers)
21
+ hold_buffer = find_hold_buffer(buffers)
22
+ return if hold_buffer.empty?
23
+
24
+ hold_events = hold_buffer.events
25
+
26
+ timer_buffer = buffers.find { |b| b.type == 'timer' }
27
+ timer_events = timer_buffer.events
28
+
29
+ finger = hold_buffer.finger
30
+ holding_time = calc_holding_time(hold_events: hold_events, timer_events: timer_events)
31
+
32
+ @timeout ||= nil
33
+ status = case hold_events.last.record.status
34
+ when 'begin'
35
+ if holding_time.zero?
36
+ 'begin'
37
+ else
38
+ 'timer'
39
+ end
40
+ when 'cancelled'
41
+ 'cancelled'
42
+ when 'end'
43
+ 'end'
44
+ else
45
+ last_record = hold_events.last.record.status
46
+ raise "Unexpected Status:#{last_record.status} in #{last_record}"
47
+ end
48
+
49
+ repeat_index = create_repeat_index(finger: finger, status: status)
50
+ oneshot_index = create_oneshot_index(finger: finger)
51
+
52
+ @timeout = nil if status == 'begin'
53
+
54
+ if status == 'timer'
55
+ return if @timeout
56
+
57
+ return unless enough?(index: oneshot_index, holding_time: holding_time)
58
+
59
+ @timeout = holding_time
60
+ return create_event(record: Events::Records::IndexRecord.new(
61
+ index: oneshot_index, trigger: :oneshot
62
+ ))
63
+ end
64
+
65
+ create_event(record: Events::Records::IndexRecord.new(
66
+ index: repeat_index, trigger: :repeat
67
+ ))
68
+ end
69
+
70
+ # @param [Integer] finger
71
+ # @return [Config::Index]
72
+ def create_oneshot_index(finger:)
73
+ Config::Index.new(
74
+ [
75
+ Config::Index::Key.new(type),
76
+ Config::Index::Key.new(finger.to_i)
77
+ ]
78
+ )
79
+ end
80
+
81
+ # @param [Integer] finger
82
+ # @return [Config::Index]
83
+ def create_repeat_index(finger:, status:)
84
+ Config::Index.new(
85
+ [
86
+ Config::Index::Key.new(type),
87
+ Config::Index::Key.new(finger.to_i),
88
+ Config::Index::Key.new(status)
89
+ ]
90
+ )
91
+ end
92
+
93
+ private
94
+
95
+ # @param buffers [Array<Buffers::Buffer>]
96
+ # @return [Buffers::GestureBuffer]
97
+ def find_hold_buffer(buffers)
98
+ buffers.find { |b| b.type == BUFFER_TYPE }
99
+ .select_from_last_begin
100
+ .select_by_events { |e| e.record.gesture == GESTURE_RECORD_TYPE }
101
+ end
102
+
103
+ def calc_holding_time(hold_events:, timer_events:)
104
+ last_time = if !timer_events.empty? && (hold_events.last.time < timer_events.last.time)
105
+ timer_events.last.time
106
+ else
107
+ hold_events.last.time
108
+ end
109
+ last_time - hold_events.first.time
110
+ end
111
+
112
+ def enough?(index:, holding_time:)
113
+ holding_time > threshold(index: index)
114
+ end
115
+
116
+ def threshold(index:)
117
+ @threshold ||= {}
118
+ @threshold[index.cache_key] ||= begin
119
+ keys_specific = Config::Index.new [*index.keys, 'threshold']
120
+ keys_global = Config::Index.new ['threshold', type]
121
+ config_value = Config.search(keys_specific) ||
122
+ Config.search(keys_global) || 1
123
+ BASE_THERESHOLD * config_value
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -14,7 +14,7 @@ module Fusuma
14
14
  # @return [Records::GestureRecord, nil]
15
15
  def parse_record(record)
16
16
  case line = record.to_s
17
- when /GESTURE_SWIPE|GESTURE_PINCH/
17
+ when /GESTURE_SWIPE|GESTURE_PINCH|GESTURE_HOLD/
18
18
  gesture, status, finger, delta = parse_libinput(line)
19
19
  else
20
20
  return
@@ -32,13 +32,18 @@ module Fusuma
32
32
  _device, event_name, _time, other = line.strip.split(nil, 4)
33
33
  finger, other = other.split(nil, 2)
34
34
 
35
+ gesture, status = *detect_gesture(event_name)
36
+
37
+ status = 'cancelled' if gesture == 'hold' && status == 'end' && other == 'cancelled'
35
38
  delta = parse_delta(other)
36
- [*detect_gesture(event_name), finger, delta]
39
+ [gesture, status, finger, delta]
37
40
  end
38
41
 
39
42
  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]
43
+ event_name =~ /GESTURE_(SWIPE|PINCH|HOLD)_(BEGIN|UPDATE|END)/
44
+ gesture = Regexp.last_match(1).downcase
45
+ status = Regexp.last_match(2).downcase
46
+ [gesture, status]
42
47
  end
43
48
 
44
49
  def parse_delta(line)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fusuma
4
- VERSION = '2.1.0'
4
+ VERSION = '2.2.0'
5
5
  end
@@ -68,7 +68,7 @@ module Fusuma
68
68
  context 'without NEW_CLI_OPTION_VERSION' do
69
69
  before do
70
70
  allow(libinput_command).to receive(:version)
71
- .and_return(LibinputCommand::NEW_CLI_OPTION_VERSION - 0.1)
71
+ .and_return('1.7')
72
72
  end
73
73
  it { is_expected.to eq false }
74
74
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'spec_helper'
4
+ require 'rspec-parameterized'
4
5
 
5
6
  require './lib/fusuma/plugin/events/event'
6
7
  require './lib/fusuma/plugin/events/records/gesture_record'
@@ -13,7 +14,7 @@ module Fusuma
13
14
  before do
14
15
  @buffer = GestureBuffer.new
15
16
  delta = Events::Records::GestureRecord::Delta.new(-1, 0, 0, 0, 0, 0)
16
- @event_generator = lambda { |time = nil, status = 'updating'|
17
+ @event_generator = lambda { |time = nil, status = 'update'|
17
18
  Events::Event.new(time: time,
18
19
  tag: 'libinput_gesture_parser',
19
20
  record: Events::Records::GestureRecord.new(
@@ -53,20 +54,39 @@ module Fusuma
53
54
  end
54
55
 
55
56
  describe '#clear_expired' do
56
- it 'should keep only events generated within 30 seconds' do
57
- time = Time.now
58
- event1 = @event_generator.call(time)
59
- @buffer.buffer(event1)
60
- event2 = @event_generator.call(time + 100)
61
- event3 = @event_generator.call(time + 100)
62
- @buffer.buffer(event2)
63
- @buffer.buffer(event3)
64
-
65
- @buffer.clear_expired(current_time: time + 100.1)
66
-
67
- expect(@buffer.events).to eq [event2, event3]
57
+ context 'default' do
58
+ before do
59
+ @time = Time.now
60
+ event1 = @event_generator.call(@time)
61
+ @buffer.buffer(event1)
62
+ @event2 = @event_generator.call(@time + 100)
63
+ @event3 = @event_generator.call(@time + 100)
64
+ @buffer.buffer(@event2)
65
+ @buffer.buffer(@event3)
66
+ end
67
+ it 'should keep only events generated within 30 seconds' do
68
+ @buffer.clear_expired(current_time: @time + 100.1)
69
+ expect(@buffer.events).to eq [@event2, @event3]
70
+ end
71
+ context 'with cancelled or ended' do
72
+ where(:last_state, :want) do
73
+ [
74
+ ['end', []],
75
+ ['cancelled', []]
76
+ ]
77
+ end
78
+
79
+ with_them do
80
+ it 'should clear events' do
81
+ event4 = @event_generator.call(@time + 100, last_state)
82
+ @buffer.buffer(event4)
83
+
84
+ @buffer.clear_expired(current_time: @time + 100.1)
85
+ expect(@buffer.events).to eq want
86
+ end
87
+ end
88
+ end
68
89
  end
69
-
70
90
  context 'change seconds to keep' do
71
91
  around do |example|
72
92
  ConfigHelper.load_config_yml = <<~CONFIG
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ require './lib/fusuma/plugin/detectors/hold_detector'
6
+ require './lib/fusuma/plugin/buffers/gesture_buffer'
7
+ require './lib/fusuma/plugin/events/records/gesture_record'
8
+ require './lib/fusuma/config'
9
+
10
+ module Fusuma
11
+ module Plugin
12
+ module Detectors
13
+ RSpec.describe HoldDetector do
14
+ before do
15
+ @detector = HoldDetector.new
16
+ @buffer = Buffers::GestureBuffer.new
17
+ @timer_buffer = Buffers::TimerBuffer.new
18
+ end
19
+
20
+ around do |example|
21
+ ConfigHelper.load_config_yml = <<~CONFIG
22
+ threshold:
23
+ hold: 1
24
+ CONFIG
25
+
26
+ example.run
27
+
28
+ Config.custom_path = nil
29
+ end
30
+
31
+ describe '#detect' do
32
+ context 'with no hold event in buffer' do
33
+ before do
34
+ @buffer.clear
35
+ end
36
+ it { expect(@detector.detect([@buffer, @timer_buffer])).to eq nil }
37
+ end
38
+
39
+ context 'with only hold begin event' do
40
+ before do
41
+ events = create_hold_events(statuses: ['begin'])
42
+ events.each { |event| @buffer.buffer(event) }
43
+ end
44
+ it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
45
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
46
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
47
+ it 'should detect 3 fingers hold' do
48
+ event = @detector.detect([@buffer, @timer_buffer])
49
+ expect(event.record.index.keys.map(&:symbol)).to eq([:hold, 3, :begin])
50
+ end
51
+ end
52
+
53
+ context 'with hold events(begin,cancelled)' do
54
+ before do
55
+ events = create_hold_events(statuses: %w[begin cancelled])
56
+ events.each { |event| @buffer.buffer(event) }
57
+ end
58
+ it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
59
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
60
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
61
+ it 'should detect 3 fingers hold canclled' do
62
+ event = @detector.detect([@buffer, @timer_buffer])
63
+ expect(event.record.index.keys.map(&:symbol)).to eq([:hold, 3, :cancelled])
64
+ end
65
+ end
66
+
67
+ context 'with hold events(begin,end)' do
68
+ before do
69
+ events = create_hold_events(statuses: %w[begin end])
70
+ events.each { |event| @buffer.buffer(event) }
71
+ end
72
+ it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
73
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
74
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
75
+ it 'should detect 3 fingers hold' do
76
+ events = @detector.detect([@buffer, @timer_buffer])
77
+ expect(events.record.index.keys.map(&:symbol)).to eq([:hold, 3, :end])
78
+ end
79
+ end
80
+
81
+ context 'with hold events and timer events' do
82
+ context 'with begin event and timer events' do
83
+ before do
84
+ events = create_hold_events(statuses: %w[begin])
85
+ events.each { |event| @buffer.buffer(event) }
86
+ @time = events.last.time
87
+ @timer_buffer.buffer(create_timer_event(time: @time + HoldDetector::BASE_THERESHOLD))
88
+ end
89
+ it { expect(@detector.detect([@buffer, @timer_buffer])).to eq nil }
90
+
91
+ context 'with enough holding time' do
92
+ before do
93
+ @timer_buffer.clear
94
+ @timer_buffer.buffer(create_timer_event(time: @time + HoldDetector::BASE_THERESHOLD + 0.01))
95
+ end
96
+ it { expect(@detector.detect([@buffer, @timer_buffer])).to be_a Events::Event }
97
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record).to be_a Events::Records::IndexRecord }
98
+ it { expect(@detector.detect([@buffer, @timer_buffer]).record.index).to be_a Config::Index }
99
+ it 'should detect 3 fingers hold' do
100
+ events = @detector.detect([@buffer, @timer_buffer])
101
+ expect(events.record.index.keys.map(&:symbol)).to eq([:hold, 3])
102
+ end
103
+ end
104
+ context 'with changing threshold' do
105
+ around do |example|
106
+ ConfigHelper.load_config_yml = <<~CONFIG
107
+ threshold:
108
+ hold: 0.9
109
+ CONFIG
110
+
111
+ example.run
112
+
113
+ Config.custom_path = nil
114
+ end
115
+
116
+ it { expect(@detector.detect([@buffer, @timer_buffer])).not_to eq nil }
117
+ it 'should detect 3 fingers hold' do
118
+ events = @detector.detect([@buffer, @timer_buffer])
119
+ expect(events.record.index.keys.map(&:symbol)).to eq([:hold, 3])
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ private
127
+
128
+ def create_hold_events(statuses:)
129
+ record_type = HoldDetector::GESTURE_RECORD_TYPE
130
+ statuses.map do |status|
131
+ gesture_record = Events::Records::GestureRecord.new(status: status,
132
+ gesture: record_type,
133
+ finger: 3,
134
+ delta: nil)
135
+ Events::Event.new(tag: 'libinput_gesture_parser', record: gesture_record)
136
+ end
137
+ end
138
+
139
+ def create_timer_event(time: Time.now)
140
+ Events::Event.new(time: time, tag: 'timer_input', record: Events::Records::TextRecord.new('timer'))
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require './lib/fusuma/plugin/parsers/parser'
5
+ require './lib/fusuma/plugin/events/event'
6
+
7
+ module Fusuma
8
+ module Plugin
9
+ module Parsers
10
+ RSpec.describe LibinputGestureParser do
11
+ let(:parser) { LibinputGestureParser.new }
12
+
13
+ around do |example|
14
+ ConfigHelper.load_config_yml = <<~CONFIG
15
+ plugin:
16
+ parsers:
17
+ libinput_gesture_parser:
18
+ dummy: dummy
19
+ CONFIG
20
+
21
+ example.run
22
+
23
+ Config.custom_path = nil
24
+ end
25
+
26
+ describe '#source' do
27
+ subject { parser.source }
28
+
29
+ it { is_expected.to be LibinputGestureParser::DEFAULT_SOURCE }
30
+ end
31
+
32
+ describe '#parse' do
33
+ context 'with different tag(dummy) event' do
34
+ let(:event) { Events::Event.new(tag: 'dummy_input', record: 'dummy') }
35
+ it { expect(parser.parse(event).record).not_to be_a Events::Records::GestureRecord }
36
+ it { expect(parser.parse(event)).to eq event }
37
+ end
38
+
39
+ context 'with libinput_command_input event' do
40
+ let(:event) { Events::Event.new(tag: 'libinput_command_input', record: record) }
41
+ context 'with swipe gestures' do
42
+ # event10 GESTURE_SWIPE_BEGIN +0.728s 3
43
+ # event10 GESTURE_SWIPE_UPDATE +0.948s 3 0.23/ 0.00 ( 0.29/ 0.00 unaccelerated)
44
+ # event10 GESTURE_SWIPE_END +0.989s 3
45
+ let(:record) { 'event10 GESTURE_SWIPE_BEGIN +0.728s 3' }
46
+ it { expect(parser.parse(event).record).to be_a Events::Records::GestureRecord }
47
+ it { expect(parser.parse(event).record.status).to eq 'begin' }
48
+ end
49
+
50
+ context 'with hold gestures' do
51
+ # -event10 GESTURE_HOLD_BEGIN +2.125s 3
52
+ # event10 GESTURE_HOLD_END +3.274s 3
53
+ # event10 GESTURE_HOLD_BEGIN +5.573s 4
54
+ # event10 GESTURE_HOLD_END +6.462s 4 cancelled
55
+ context 'with begin' do
56
+ let(:record) { '-event10 GESTURE_HOLD_BEGIN +2.125s 3' }
57
+ it { expect(parser.parse(event).record).to be_a Events::Records::GestureRecord }
58
+ it { expect(parser.parse(event).record.status).to eq 'begin' }
59
+ end
60
+ context 'with end' do
61
+ let(:record) { ' event10 GESTURE_HOLD_END +3.274s 3' }
62
+ it { expect(parser.parse(event).record).to be_a Events::Records::GestureRecord }
63
+ it { expect(parser.parse(event).record.status).to eq 'end' }
64
+ end
65
+ context 'with end(cancelled)' do
66
+ let(:record) { ' event10 GESTURE_HOLD_END +6.462s 4 cancelled' }
67
+ it { expect(parser.parse(event).record).to be_a Events::Records::GestureRecord }
68
+ it { expect(parser.parse(event).record.status).to eq 'cancelled' }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
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: 2.1.0
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-10-01 00:00:00.000000000 Z
11
+ date: 2021-11-21 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Fusuma is multitouch gesture recognizer. This gem makes your touchpad
14
14
  on Linux able to recognize swipes or pinchs and assign command to them. Read installation
@@ -43,6 +43,7 @@ files:
43
43
  - lib/fusuma/plugin/buffers/gesture_buffer.rb
44
44
  - lib/fusuma/plugin/buffers/timer_buffer.rb
45
45
  - lib/fusuma/plugin/detectors/detector.rb
46
+ - lib/fusuma/plugin/detectors/hold_detector.rb
46
47
  - lib/fusuma/plugin/detectors/pinch_detector.rb
47
48
  - lib/fusuma/plugin/detectors/rotate_detector.rb
48
49
  - lib/fusuma/plugin/detectors/swipe_detector.rb
@@ -56,7 +57,6 @@ files:
56
57
  - lib/fusuma/plugin/executors/executor.rb
57
58
  - lib/fusuma/plugin/filters/filter.rb
58
59
  - lib/fusuma/plugin/filters/libinput_device_filter.rb
59
- - lib/fusuma/plugin/filters/libinput_timeout_filter.rb
60
60
  - lib/fusuma/plugin/inputs/input.rb
61
61
  - lib/fusuma/plugin/inputs/libinput_command_input.rb
62
62
  - lib/fusuma/plugin/inputs/timer_input.rb
@@ -84,6 +84,7 @@ files:
84
84
  - spec/lib/plugin/buffers/gesture_buffer_spec.rb
85
85
  - spec/lib/plugin/detectors/detector_spec.rb
86
86
  - spec/lib/plugin/detectors/dummy_detector.rb
87
+ - spec/lib/plugin/detectors/hold_detector_spec.rb
87
88
  - spec/lib/plugin/detectors/pinch_detector_spec.rb
88
89
  - spec/lib/plugin/detectors/rotate_detector_spec.rb
89
90
  - spec/lib/plugin/detectors/swipe_detector_spec.rb
@@ -99,12 +100,14 @@ files:
99
100
  - spec/lib/plugin/inputs/libinput_command_input_spec.rb
100
101
  - spec/lib/plugin/inputs/timer_input_spec.rb
101
102
  - spec/lib/plugin/manager_spec.rb
103
+ - spec/lib/plugin/parsers/libinput_gesture_parser_spec.rb
102
104
  - spec/lib/plugin/parsers/parser_spec.rb
103
105
  - spec/spec_helper.rb
104
106
  homepage: https://github.com/iberianpig/fusuma
105
107
  licenses:
106
108
  - MIT
107
109
  metadata:
110
+ rubygems_mfa_required: 'true'
108
111
  yard.run: yri
109
112
  post_install_message:
110
113
  rdoc_options: []
@@ -145,6 +148,7 @@ test_files:
145
148
  - spec/lib/plugin/buffers/gesture_buffer_spec.rb
146
149
  - spec/lib/plugin/detectors/detector_spec.rb
147
150
  - spec/lib/plugin/detectors/dummy_detector.rb
151
+ - spec/lib/plugin/detectors/hold_detector_spec.rb
148
152
  - spec/lib/plugin/detectors/pinch_detector_spec.rb
149
153
  - spec/lib/plugin/detectors/rotate_detector_spec.rb
150
154
  - spec/lib/plugin/detectors/swipe_detector_spec.rb
@@ -160,5 +164,6 @@ test_files:
160
164
  - spec/lib/plugin/inputs/libinput_command_input_spec.rb
161
165
  - spec/lib/plugin/inputs/timer_input_spec.rb
162
166
  - spec/lib/plugin/manager_spec.rb
167
+ - spec/lib/plugin/parsers/libinput_gesture_parser_spec.rb
163
168
  - spec/lib/plugin/parsers/parser_spec.rb
164
169
  - spec/spec_helper.rb
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative './filter'
4
- require_relative '../../libinput_command'
5
-
6
- module Fusuma
7
- module Plugin
8
- module Filters
9
- # Filter device log
10
- class LibinputTimeoutFilter < Filter
11
- DEFAULT_SOURCE = 'libinput_command_input'
12
-
13
- # @return [TrueClass] when keeping it
14
- # @return [FalseClass] when discarding it
15
- def keep?(record)
16
- record.to_s == LibinputCommand::TIMEOUT_MESSAGE
17
- end
18
- end
19
- end
20
- end
21
- end