fusuma 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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