fusuma 2.0.2 → 2.1.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: 3d8572f753f134496b8ffc0f36c3aafbf142357aad913edd9fd5f5d494d32259
4
- data.tar.gz: 6adf4afa35ca59305efa6bde88b2ccf808c3025b5a577cc917d0b32d6b794058
3
+ metadata.gz: c964784d9707a4ca667c19b4c866bd5e0abc8e61e2f0752903c2cac3fd064448
4
+ data.tar.gz: fc9c42d27ee80535d6da10f3cdd0ee707a128ad42f147366dd40f4c2053a273a
5
5
  SHA512:
6
- metadata.gz: 68dbe15577eb01891537a573c96ab0a2c532e919588c4fdb62899b236382630d8f575f913c9de282bf9a66b5ae8f91cc820067eedc7ecaa42e839f25d090afd8
7
- data.tar.gz: cd74e943167bff03bf2eb1d3eaa9d170f28fd921c3736bcc1a981e49f0c7b755de10ecd8b9b6f314bce76377568441e04cd5228222cfe3c3afd32448569a754c
6
+ metadata.gz: 99e47419a912ae9e77215fef51bae8bc6a657ac679dbb9a55873087753f354bc9b077657f2fa7699372931ac7a0d0f3faef7d732da4197e1fcef2623b02b8b9c
7
+ data.tar.gz: 7d8ac348be34c4756e549ac0856fa01119680d5d9ebc7346ca3dc29070023b3a6c8d6a4f2218a3fde6951936d51d8ea0335723dcf2a76285f5ab7a477746ca4e
data/README.md CHANGED
@@ -1,9 +1,9 @@
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) [![Inline docs](http://inch-ci.org/github/iberianpig/fusuma.svg?branch=master)](http://inch-ci.org/github/iberianpig/fusuma)
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)
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.
5
5
 
6
- ![fusuma_image](https://i.gyazo.com/757fef526310b9d68f68e80eb1e4540f.png)
6
+ ![fusuma_image](https://repository-images.githubusercontent.com/69813387/60879a00-166c-11ea-9875-3bf0818c62ec)
7
7
 
8
8
  襖(Fusuma) means sliding door used to partition off rooms in a Japanese house.
9
9
 
@@ -83,7 +83,7 @@ $ sudo pacman -S ruby
83
83
 
84
84
  #### 3. Install Fusuma
85
85
 
86
- **Note:** By default in Arch Linux, when running ```gem```, gems are installed per-user (into ```~/.gem/ruby/```), instead of system-wide (into ```/usr/lib/ruby/gems/```). This is considered the best way to manage gems on Arch, because otherwise they might interfere with gems installed by Pacman. (From Arch Wiki)
86
+ **Note:** By default in Arch Linux, when running `gem`, gems are installed per-user (into `~/.gem/ruby/`), instead of system-wide (into `/usr/lib/ruby/gems/`). This is considered the best way to manage gems on Arch, because otherwise they might interfere with gems installed by Pacman. (From Arch Wiki)
87
87
 
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
 
@@ -121,7 +121,7 @@ $ sudo gem update fusuma
121
121
 
122
122
  ## Customize Gesture Mapping
123
123
 
124
- You can customize the settings for gestures to put and edit `~/.config/fusuma/config.yml`.
124
+ You can customize the settings for gestures to put and edit `~/.config/fusuma/config.yml`.
125
125
  **NOTE: You will need to create the `~/.config/fusuma` directory if it doesn't exist yet.**
126
126
 
127
127
  ```bash
@@ -135,12 +135,15 @@ $ nano ~/.config/fusuma/config.yml # edit config file.
135
135
  * `swipe:`
136
136
  * support `3:`, `4:` fingers
137
137
  * support `left:`, `right:`, `up:`, `down:` directions
138
+ * support `begin:`, `update:`, `end:` events
138
139
  * `pinch:`
139
140
  * support `2:`, `3:`, `4:` fingers
140
141
  * support `in:`, `out:` directions
142
+ * support `begin:`, `update:`, `end:` events
141
143
  * `rotate:`
142
144
  * support `2:`, `3:`, `4:` fingers
143
145
  * support `clockwise:`,`counterclockwise:` directions
146
+ * support `begin:`, `update:`, `end:` events
144
147
 
145
148
  ### About YAML Basic Syntax
146
149
 
@@ -157,7 +160,7 @@ https://github.com/iberianpig/fusuma/wiki/Ubuntu
157
160
  swipe:
158
161
  3:
159
162
  left:
160
- command: "xdotool key alt+Right" # History forward
163
+ command: "xdotool key alt+Right" # History forward
161
164
  right:
162
165
  command: "xdotool key alt+Left" # History back
163
166
  up:
@@ -191,6 +194,8 @@ The following wiki pages can be edited by everyone.
191
194
  - [POP OS with Cinnamon](https://github.com/iberianpig/fusuma/wiki/POP-OS-with-Cinnamon)
192
195
  - [PopOS Default Gnome](https://github.com/iberianpig/fusuma/wiki/PopOS-Default-Gnome)
193
196
  - [Ubuntu OS to mimic Mac a little](https://github.com/iberianpig/fusuma/wiki/Ubuntu-OS-to-mimic-Mac-a-little)
197
+ - [3 fingers Drag (OS X Style)](https://github.com/iberianpig/fusuma/wiki/3-fingers-Drag-(OS-X-Style))
198
+ - [3 fingers Alt Tab Switcher(Windows Style)](https://github.com/iberianpig/fusuma/wiki/3-fingers-Alt-Tab-Switcher(Windows-Style))
194
199
 
195
200
  If you have a nice configuration, please share `~/.config/fusuma/config.yml` with everyone.
196
201
 
@@ -208,19 +213,19 @@ If the swipe's interval is `0.5`, shorten swipe-interval by half to recognize a
208
213
 
209
214
  ```yaml
210
215
  swipe:
211
- 3:
212
- left:
216
+ 3:
217
+ left:
213
218
  command: 'xdotool key alt+Right' # threshold: 0.5, interval: 0.75
214
219
  threshold: 0.5
215
- right:
220
+ right:
216
221
  command: 'xdotool key alt+Left' # threshold: 0.5, interval: 0.75
217
222
  threshold: 0.5
218
- up:
223
+ up:
219
224
  command: 'xdotool key super' # threshold: 1, interval: 0.75
220
- down:
225
+ down:
221
226
  command: 'xdotool key super' # threshold: 1, interval: 0.75
222
227
  pinch:
223
- 2:
228
+ 2:
224
229
  in:
225
230
  command: "xdotool keydown ctrl click 4 keyup ctrl" # threshold: 0.5, interval: 0.5
226
231
  out:
@@ -234,7 +239,7 @@ interval:
234
239
  pinch: 0.5
235
240
  ```
236
241
 
237
- There are three priorities of `threshold:` and `interval:`.
242
+ There are three priorities of `threshold:` and `interval:`.
238
243
  The individual `threshold:` and `interval:` settings (under "direction") have a higher priority than the global one (under "root")
239
244
 
240
245
  1. child elements in the direction (left/right/down/up → threshold/interval)
@@ -280,7 +285,7 @@ swipe:
280
285
  - `xte`
281
286
  - [xte(1) - Linux man page](https://linux.die.net/man/1/xte)
282
287
  - install with `sudo apt xautomation`
283
-
288
+
284
289
  - [ydotool](https://github.com/ReimuNotMoe/ydotool)
285
290
  - Wayland compatible
286
291
  - Needs more maintainers.
@@ -292,8 +297,8 @@ swipe:
292
297
  - `-d`, `--daemon` : Daemonize process
293
298
  - `-l`, `--list-devices` : List available devices
294
299
  - `-v`, `--verbose` : Show details about the results of running fusuma
295
- - `--device="Device name"` : Open the given device only (DEPRECATED)
296
300
  - `--version` : Show fusuma version
301
+ - `--log-file=path/to/file` : Set path of log file
297
302
 
298
303
  ### Specify touchpads by device name
299
304
  Set the following options to recognize multi-touch gestures only for the specified touchpad device.
@@ -322,7 +327,7 @@ Following features are provided as plugins.
322
327
  - Features for specific Linux distributions
323
328
  - Setting different gestures per applications
324
329
 
325
- ### Installation of fusuma plugins
330
+ ### Installation of Fusuma plugins
326
331
 
327
332
  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).
328
333
 
@@ -330,16 +335,17 @@ Fusuma plugins are provided with the `fusuma-plugin-XXXXX` naming convention and
330
335
 
331
336
  ### Available plugins
332
337
 
333
- | Name | About |
334
- | ------------------------------------------------------------------------------ | --------------------------------------------- |
335
- | [fusuma-plugin-sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey) | Emulates keyboard events |
336
- | [fusuma-plugin-wmctrl](https://github.com/iberianpig/fusuma-plugin-wmctrl) | Manages Window and Workspace |
337
- | [fusuma-plugin-keypress](https://github.com/iberianpig/fusuma-plugin-keypress) | Detects gestures while pressing multiple keys |
338
- | [fusuma-plugin-tap](https://github.com/iberianpig/fusuma-plugin-tap) | Detects Tap and Hold gestures |
338
+ | Name | Version | About |
339
+ | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | --------------------------------------------- |
340
+ | [fusuma-plugin-sendkey](https://github.com/iberianpig/fusuma-plugin-sendkey) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-sendkey.svg) | Emulates keyboard events |
341
+ | [fusuma-plugin-wmctrl](https://github.com/iberianpig/fusuma-plugin-wmctrl) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-wmctrl.svg) | Manages Window and Workspace |
342
+ | [fusuma-plugin-keypress](https://github.com/iberianpig/fusuma-plugin-keypress) | ![Gem Version](https://badge.fury.io/rb/fusuma-plugin-keypress.svg) | Detects gestures while pressing multiple keys |
343
+ | [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
+ | [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 |
339
345
 
340
346
  ## Tutorial Video
341
347
 
342
- [![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")
348
+ [![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")
343
349
  [Multitouch Touchpad Gestures in Linux with Fusuma](http://www.youtube.com/watch?v=bn11Iwvf29I) by [Eric Adams](https://www.youtube.com/user/igster75)
344
350
 
345
351
  ## Support
@@ -348,7 +354,7 @@ I'm a Freelance Engineer in Japan and working on these products after finishing
348
354
  Currently, my open-source contribution times is not enough.
349
355
  If you like my work and want to contribute and become a sponsor, I will be able to focus on my projects.
350
356
 
351
- - [GitHub Sponsors](https://github.com/sponsors/iberianpig) (Zero fee!)
357
+ - [GitHub Sponsors](https://github.com/sponsors/iberianpig)
352
358
  - [Patreon](https://www.patreon.com/iberianpig)
353
359
 
354
360
  ## Contributing
data/exe/fusuma CHANGED
@@ -22,6 +22,11 @@ opt.on('-l', '--list-devices',
22
22
  option[:list] = v
23
23
  end
24
24
 
25
+ opt.on('--log=path/to/file',
26
+ 'Print logs to file') do |v|
27
+ option[:log_filepath] = v
28
+ end
29
+
25
30
  opt.on('--device="Device name"',
26
31
  'Open the given device only (DEPRECATED)') do |v|
27
32
  option[:device] = v
data/fusuma.gemspec CHANGED
@@ -15,8 +15,8 @@ Gem::Specification.new do |spec|
15
15
  spec.homepage = 'https://github.com/iberianpig/fusuma'
16
16
  spec.license = 'MIT'
17
17
 
18
- spec.files = Dir.glob('{bin,lib,exe}/**/*') + %w[LICENSE README.md fusuma.gemspec]
19
- spec.test_files = Dir.glob("{test,spec,features}/**/*")
18
+ spec.files = Dir['{bin,lib,exe}/**/*', 'LICENSE*', 'README*', '*.gemspec']
19
+ spec.test_files = Dir['{test,spec,features}/**/*']
20
20
  spec.bindir = 'exe'
21
21
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
22
  spec.require_paths = ['lib']
@@ -24,5 +24,4 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.required_ruby_version = '>= 2.5.1' # https://packages.ubuntu.com/search?keywords=ruby&searchon=names&exact=1&suite=all&section=main
26
26
  # support bionic (18.04LTS) 2.5.1
27
- spec.add_dependency 'posix-spawn'
28
27
  end
@@ -67,8 +67,7 @@ module Fusuma
67
67
 
68
68
  # next locations' candidates sorted by priority
69
69
  # 1. look up location with key
70
- # 2. fallback to other key
71
- # 3. skip the key and go to child location
70
+ # 2. skip the key and go to child location
72
71
  def next_location_cadidates(location, key)
73
72
  [
74
73
  location[key.symbol],
data/lib/fusuma/config.rb CHANGED
@@ -84,7 +84,7 @@ module Fusuma
84
84
  end.flatten
85
85
 
86
86
  execute_params = search(index)
87
- return if execute_params.nil?
87
+ return if execute_params.nil? || !execute_params.is_a?(Hash)
88
88
 
89
89
  @execute_keys.find { |k| execute_params.keys.include?(k) }
90
90
  end
@@ -20,7 +20,7 @@ module Fusuma
20
20
  libinput_command = Plugin::Inputs::LibinputCommandInput.new.command
21
21
  MultiLogger.info "Fusuma: #{VERSION}"
22
22
  MultiLogger.info "libinput: #{libinput_command.version}"
23
- MultiLogger.info "ruby #{ RUBY_VERSION }p#{ RUBY_PATCHLEVEL }"
23
+ MultiLogger.info "ruby #{RUBY_VERSION}p#{RUBY_PATCHLEVEL}"
24
24
  MultiLogger.info "OS: #{`uname -rsv`}".strip
25
25
  MultiLogger.info "Distribution: #{`cat /etc/issue`}".strip
26
26
  MultiLogger.info "Desktop session: #{`echo $DESKTOP_SESSION $XDG_SESSION_TYPE`}".strip
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'posix/spawn'
3
+ require 'open3'
4
4
 
5
5
  module Fusuma
6
6
  # Execute libinput command
@@ -33,20 +33,20 @@ module Fusuma
33
33
  def list_devices(&block)
34
34
  cmd = list_devices_command
35
35
  MultiLogger.debug(list_devices: cmd)
36
- p, i, o, e = POSIX::Spawn.popen4(cmd)
36
+ i, o, e, _w = Open3.popen3(cmd)
37
+ MultiLogger.error(e.read) if o.eof?
37
38
  i.close
39
+ e.close
38
40
  o.each(&block)
39
- ensure
40
- [i, o, e].each { |io| io.close unless io.closed? }
41
- Process.waitpid(p)
42
41
  end
43
42
 
44
- # @return [Integer, IO] return a latest line libinput debug-events
45
- def debug_events
46
- @debug_events = begin
47
- p, i, o, _e = POSIX::Spawn.popen4(debug_events_with_options)
48
- i.close
49
- [p, o]
43
+ # @return [Integer] return a latest line libinput debug-events
44
+ def debug_events(writer)
45
+ @debug_events ||= begin
46
+ pid = Process.spawn(debug_events_with_options, out: writer,
47
+ in: '/dev/null')
48
+ Process.detach(pid)
49
+ pid
50
50
  end
51
51
  end
52
52
 
@@ -11,9 +11,21 @@ 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
17
+ end
18
+
14
19
  def initialize
15
- super($stdout)
16
- @err_logger = Logger.new($stderr)
20
+ if @@filepath
21
+ logfile = File.new(@@filepath, 'a')
22
+ super(logfile)
23
+ $stderr = logfile
24
+ @err_logger = Logger.new($stderr)
25
+ else
26
+ super($stdout)
27
+ @err_logger = Logger.new($stderr)
28
+ end
17
29
  @debug_mode = false
18
30
  end
19
31
 
@@ -8,7 +8,7 @@ module Fusuma
8
8
  # manage events and generate command
9
9
  class TimerBuffer < Buffer
10
10
  DEFAULT_SOURCE = 'timer_input'
11
- DEFAULT_SECONDS_TO_KEEP = 60
11
+ DEFAULT_SECONDS_TO_KEEP = 3
12
12
 
13
13
  def config_param_types
14
14
  {
@@ -31,8 +31,6 @@ module Fusuma
31
31
  @events.each do |e|
32
32
  break if current_time - e.time < @seconds_to_keep
33
33
 
34
- MultiLogger.debug("#{self.class.name}##{__method__}")
35
-
36
34
  @events.delete(e)
37
35
  end
38
36
  end
@@ -62,8 +62,15 @@ module Fusuma
62
62
  if status == 'update'
63
63
  return unless moved?(prev_event, event)
64
64
 
65
- avg_zoom = gesture_buffer.avg_attrs(:zoom)
66
- first_zoom = updating_events.first.record.delta.zoom
65
+ first_zoom, avg_zoom = if updating_events.size >= 10
66
+ [updating_events[-10].record.delta.zoom,
67
+ gesture_buffer.class.new(
68
+ updating_events[-10..-1]
69
+ ).avg_attrs(:zoom)]
70
+ else
71
+ [updating_events.first.record.delta.zoom,
72
+ gesture_buffer.avg_attrs(:zoom)]
73
+ end
67
74
 
68
75
  oneshot_quantity = Quantity.new(target: avg_zoom, base: first_zoom).to_f
69
76
  oneshot_direction = Direction.new(target: avg_zoom, base: first_zoom).to_s
@@ -24,8 +24,14 @@ module Fusuma
24
24
  updating_events = gesture_buffer.updating_events
25
25
  return if updating_events.empty?
26
26
 
27
- updating_time = 100 * (updating_events.last.time - updating_events.first.time)
28
- oneshot_angle = gesture_buffer.sum_attrs(:rotate) / updating_time
27
+ oneshot_angle = if updating_events.size >= 10
28
+ updating_time = 100 * (updating_events[-1].time - updating_events[-10].time)
29
+ last_10 = gesture_buffer.class.new(updating_events[-10..-1])
30
+ last_10.sum_attrs(:rotate) / updating_time
31
+ else
32
+ updating_time = 100 * (updating_events.last.time - updating_events.first.time)
33
+ gesture_buffer.sum_attrs(:rotate) / updating_time
34
+ end
29
35
 
30
36
  return if updating_events.empty?
31
37
 
@@ -24,9 +24,17 @@ module Fusuma
24
24
  updating_events = gesture_buffer.updating_events
25
25
  return if updating_events.empty?
26
26
 
27
- updating_time = 100 * (updating_events.last.time - updating_events.first.time)
28
- oneshot_move_x = gesture_buffer.sum_attrs(:move_x) / updating_time
29
- oneshot_move_y = gesture_buffer.sum_attrs(:move_y) / updating_time
27
+ oneshot_move_x, oneshot_move_y = if updating_events.size >= 10
28
+ updating_time = 100 * (updating_events[-1].time - updating_events[-10].time)
29
+ last_10 = gesture_buffer.class.new(updating_events[-10..-1])
30
+ [last_10.sum_attrs(:move_x) / updating_time,
31
+ last_10.sum_attrs(:move_y) / updating_time]
32
+ else
33
+ updating_time = 100 * (updating_events.last.time - updating_events.first.time)
34
+ [gesture_buffer.sum_attrs(:move_x) / updating_time,
35
+ gesture_buffer.sum_attrs(:move_y) / updating_time]
36
+ end
37
+ gesture_buffer.sum_attrs(:move_x) / updating_time
30
38
 
31
39
  finger = gesture_buffer.finger
32
40
  status = case gesture_buffer.events.last.record.status
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'posix/spawn'
4
3
  require_relative './executor'
5
4
 
6
5
  module Fusuma
@@ -15,18 +14,19 @@ module Fusuma
15
14
  end
16
15
 
17
16
  def execute(event)
18
- search_command(event).tap do |command|
19
- break unless command
17
+ command = search_command(event)
20
18
 
21
- MultiLogger.info(command: command, args: event.record.args)
19
+ MultiLogger.info(command: command, args: event.record.args)
22
20
 
23
- additional_env = event.record.args
24
- .deep_transform_keys(&:to_s)
25
- .deep_transform_values { |v| (v * args_accel(event)).to_s }
21
+ accel = args_accel(event)
22
+ additional_env = event.record.args
23
+ .deep_transform_keys(&:to_s)
24
+ .deep_transform_values { |v| (v * accel).to_s }
26
25
 
27
- pid = POSIX::Spawn.spawn(additional_env, command.to_s)
28
- Process.detach(pid)
29
- end
26
+ pid = Process.spawn(additional_env, command.to_s)
27
+ Process.detach(pid)
28
+ rescue SystemCallError => e
29
+ MultiLogger.error("#{event.record.index.keys}": e.message.to_s)
30
30
  end
31
31
 
32
32
  def executable?(event)
@@ -15,7 +15,7 @@ module Fusuma
15
15
  # @return [Array<Symbol>]
16
16
  def execute_keys
17
17
  # [name.split('Executors::').last.underscore.gsub('_executor', '').to_sym]
18
- raise NotImplementedError, "override #{name}##{__method__}"
18
+ raise NotImplementedError, "override #{self.class.name}##{__method__}"
19
19
  end
20
20
 
21
21
  # check executable
@@ -25,8 +25,9 @@ module Fusuma
25
25
  # @return [IO]
26
26
  def io
27
27
  @io ||= begin
28
- @pid, io = command.debug_events
29
- io
28
+ reader, writer = create_io
29
+ @pid = command.debug_events(writer)
30
+ reader
30
31
  end
31
32
  end
32
33
 
@@ -64,6 +65,12 @@ module Fusuma
64
65
  def list_devices_command
65
66
  config_params(:'libinput-list-devices')
66
67
  end
68
+
69
+ private
70
+
71
+ def create_io
72
+ IO.pipe
73
+ end
67
74
  end
68
75
  end
69
76
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fusuma
4
- VERSION = '2.0.2'
4
+ VERSION = '2.1.0'
5
5
  end
data/lib/fusuma.rb CHANGED
@@ -29,6 +29,7 @@ module Fusuma
29
29
  end
30
30
 
31
31
  def read_options(option)
32
+ MultiLogger.filepath = option[:log_filepath]
32
33
  MultiLogger.instance.debug_mode = option[:verbose]
33
34
 
34
35
  load_custom_config(option[:config_path])
@@ -142,19 +143,26 @@ module Fusuma
142
143
  end
143
144
  main_events.sort_by! { |e| e.record.trigger_priority }
144
145
 
145
- condition = nil
146
+ matched_condition = nil
146
147
  matched_context = nil
147
148
  event = main_events.find do |main_event|
148
149
  matched_context = Config::Searcher.find_context(request_context) do
149
- condition, index_record = Config::Searcher.find_condition do
150
+ matched_condition, modified_record = Config::Searcher.find_condition do
150
151
  main_event.record.merge(records: modifiers.map(&:record))
151
152
  end
152
- main_event if index_record
153
+ if matched_condition && modified_record
154
+ main_event.record = modified_record
155
+ else
156
+ matched_condition, = Config::Searcher.find_condition do
157
+ Config.search(main_event.record.index) &&
158
+ Config.find_execute_key(main_event.record.index)
159
+ end
160
+ end
153
161
  end
154
162
  end
155
163
  return if event.nil?
156
164
 
157
- [condition, matched_context, event]
165
+ [matched_condition, matched_context, event]
158
166
  end
159
167
 
160
168
  # @param event [Plugin::Events::Event]
@@ -7,80 +7,162 @@ require './lib/fusuma/config/searcher'
7
7
  # spec for Config
8
8
  module Fusuma
9
9
  RSpec.describe Config::Searcher do
10
- let(:keymap) do
11
- {
12
- 'swipe' => {
13
- 3 => {
14
- 'left' => { 'command' => 'alt+Left' },
15
- 'right' => { 'command' => 'alt+Right' }
16
- },
17
- 4 => {
18
- 'left' => { 'command' => 'super+Left' },
19
- 'right' => { 'command' => 'super+Right' }
20
- }
21
- },
22
- 'pinch' => {
23
- 'in' => { 'command' => 'ctrl+plus' },
24
- 'out' => { 'command' => 'ctrl+minus' }
25
- }
26
- }
27
- end
10
+ around do |example|
11
+ ConfigHelper.load_config_yml = <<~CONFIG
12
+ swipe:
13
+ 3:
14
+ left:
15
+ command: 'alt+Left'
16
+ right:
17
+ command: 'alt+Right'
18
+ 4:
19
+ left:
20
+ command: 'super+Left'
21
+ right:
22
+ command: 'super+Right'
23
+ pinch:
24
+ in:
25
+ command: 'ctrl+plus'
26
+ out:
27
+ command: 'ctrl+minus'
28
+ CONFIG
28
29
 
29
- let(:keymap_without_finger) do
30
- {
31
- 'swipe' => {
32
- 'left' => { 'command' => 'alt+Left' }
33
- }
34
- }
35
- end
30
+ example.run
36
31
 
37
- describe '.custom_path=' do
38
- before { Singleton.__init__(Config) }
39
- it 'should reload keymap file' do
40
- keymap = Config.instance.keymap
41
- Config.custom_path = './spec/lib/dummy_config.yml'
42
- custom_keymap = Config.instance.keymap
43
- expect(keymap).not_to eq custom_keymap
44
- end
32
+ ConfigHelper.clear_config_yml
45
33
  end
46
34
 
47
35
  describe '.search' do
48
36
  let(:index) { nil }
49
- subject { Config::Searcher.new.search(index, location: keymap.deep_symbolize_keys) }
37
+ let(:location) { Config.instance.keymap[0] }
38
+ let(:search) { Config::Searcher.new.search(index, location: location) }
50
39
  context 'index correct order' do
51
40
  let(:index) { Config::Index.new %w[pinch in command] }
52
- it { is_expected.to eq 'ctrl+plus' }
41
+ it { expect(Config::Searcher.new.search(index, location: location)).to eq 'ctrl+plus' }
53
42
  end
54
43
 
55
- context 'index include skippable key' do
56
- let(:index) do
57
- Config::Index.new [
58
- Config::Index::Key.new('pinch'),
59
- Config::Index::Key.new(2, skippable: true),
60
- Config::Index::Key.new('out'),
61
- Config::Index::Key.new('command')
62
- ]
63
- end
64
- it { expect(Config::Searcher.skip { subject }).to eq 'ctrl+minus' }
44
+ context 'index incorrect order' do
45
+ let(:index) { Config::Index.new %w[in pinch 2 command] }
46
+ it { expect(Config::Searcher.new.search(index, location: location)).not_to eq 'ctrl+plus' }
65
47
  end
66
48
 
67
- context 'index include skippable key at first' do
68
- let(:index) do
69
- Config::Index.new [
70
- Config::Index::Key.new(:hoge, skippable: true),
71
- Config::Index::Key.new(:fuga, skippable: true),
72
- Config::Index::Key.new('pinch'),
73
- Config::Index::Key.new('in'),
74
- Config::Index::Key.new(:piyo, skippable: true),
75
- Config::Index::Key.new('command')
76
- ]
49
+ context 'with Skip condtions' do
50
+ context 'when index includes skippable key' do
51
+ let(:index) do
52
+ Config::Index.new [
53
+ Config::Index::Key.new('pinch'),
54
+ Config::Index::Key.new(2, skippable: true),
55
+ Config::Index::Key.new('out'),
56
+ Config::Index::Key.new('command')
57
+ ]
58
+ end
59
+ it 'detects ctrl+minus with skip' do
60
+ condition, value = Config::Searcher.find_condition do
61
+ Config::Searcher.new.search(index, location: location)
62
+ end
63
+ expect([condition, value]).to eq([:skip, 'ctrl+minus'])
64
+ end
77
65
  end
78
- it { expect(Config::Searcher.skip { subject }).to eq 'ctrl+plus' }
79
- end
80
66
 
81
- context 'index incorrect order' do
82
- let(:index) { Config::Index.new %w[in pinch 2 command] }
83
- it { is_expected.not_to eq 'ctrl+plus' }
67
+ context 'when index includes skippable key at first' do
68
+ let(:index) do
69
+ Config::Index.new [
70
+ Config::Index::Key.new(:hoge, skippable: true),
71
+ Config::Index::Key.new(:fuga, skippable: true),
72
+ Config::Index::Key.new('pinch'),
73
+ Config::Index::Key.new('in'),
74
+ Config::Index::Key.new(:piyo, skippable: true),
75
+ Config::Index::Key.new('command')
76
+ ]
77
+ end
78
+ it 'detects ctrl+plus with skip' do
79
+ condition, value = Config::Searcher.find_condition do
80
+ Config::Searcher.new.search(index, location: location)
81
+ end
82
+ expect([condition, value]).to eq([:skip, 'ctrl+plus'])
83
+ end
84
+ end
85
+
86
+ context 'with begin/update/end' do
87
+ around do |example|
88
+ ConfigHelper.load_config_yml = <<~CONFIG
89
+ swipe:
90
+ 3:
91
+ begin:
92
+ command: 'echo begin'
93
+ update:
94
+ command: 'echo update'
95
+ end:
96
+ command: 'echo end'
97
+ keypress:
98
+ LEFTCTRL:
99
+ command: 'echo end+ctrl'
100
+ CONFIG
101
+
102
+ example.run
103
+
104
+ ConfigHelper.clear_config_yml
105
+ end
106
+
107
+ context 'without keypress' do
108
+ let(:index) do
109
+ Config::Index.new [
110
+ Config::Index::Key.new(:swipe),
111
+ Config::Index::Key.new(3),
112
+ Config::Index::Key.new('left', skippable: true),
113
+ Config::Index::Key.new('end'),
114
+ Config::Index::Key.new('command')
115
+ ]
116
+ end
117
+
118
+ it 'detects with skip' do
119
+ condition, value = Config::Searcher.find_condition do
120
+ Config::Searcher.new.search(index, location: location)
121
+ end
122
+ expect([condition, value]).to eq([:skip, 'echo end'])
123
+ end
124
+ end
125
+ context 'with keypress' do
126
+ context 'with valid key existing in config.yml' do
127
+ let(:index) do
128
+ Config::Index.new [
129
+ Config::Index::Key.new(:swipe),
130
+ Config::Index::Key.new(3),
131
+ Config::Index::Key.new('left', skippable: true),
132
+ Config::Index::Key.new('end'),
133
+ Config::Index::Key.new('keypress', skippable: true),
134
+ Config::Index::Key.new('LEFTCTRL', skippable: true),
135
+ Config::Index::Key.new('command')
136
+ ]
137
+ end
138
+ it 'detects end+ctrl with skip' do
139
+ condition, value = Config::Searcher.find_condition do
140
+ Config::Searcher.new.search(index, location: location)
141
+ end
142
+ expect([condition, value]).to eq([:skip, 'echo end+ctrl'])
143
+ end
144
+ end
145
+ context 'with non-existing key not existing in config.yml' do
146
+ let(:index) do
147
+ Config::Index.new [
148
+ Config::Index::Key.new(:swipe),
149
+ Config::Index::Key.new(3),
150
+ Config::Index::Key.new('up', skippable: true),
151
+ Config::Index::Key.new('end'),
152
+ Config::Index::Key.new('keypress', skippable: true),
153
+ Config::Index::Key.new('LEFTSHIFT', skippable: true), # Invalid key
154
+ Config::Index::Key.new('command')
155
+ ]
156
+ end
157
+ it 'detects end with skip (fallback to no keypress)' do
158
+ condition, value = Config::Searcher.find_condition do
159
+ Config::Searcher.new.search(index, location: location)
160
+ end
161
+ expect([condition, value]).to eq([:skip, 'echo end'])
162
+ end
163
+ end
164
+ end
165
+ end
84
166
  end
85
167
  end
86
168
 
@@ -25,14 +25,6 @@ module Fusuma
25
25
  }
26
26
  end
27
27
 
28
- let(:keymap_without_finger) do
29
- {
30
- 'swipe' => {
31
- 'left' => { 'command' => 'alt+Left' }
32
- }
33
- }
34
- end
35
-
36
28
  describe '.custom_path=' do
37
29
  before { Singleton.__init__(Config) }
38
30
  it 'should reload keymap file' do
@@ -24,11 +24,9 @@ module Fusuma
24
24
  .and_return(libinput_device_command)
25
25
 
26
26
  @dummy_io = StringIO.new('dummy')
27
- allow(Process).to receive(:waitpid).and_return(nil)
28
-
29
- allow(POSIX::Spawn).to receive(:popen4)
27
+ allow(Open3).to receive(:popen3)
30
28
  .with(libinput_device_command)
31
- .and_return([nil, @dummy_io, list_devices_output, @dummy_io])
29
+ .and_return([@dummy_io, list_devices_output, @dummy_io, nil])
32
30
  end
33
31
 
34
32
  context 'with XPS-9360 (have a correct device)' do
@@ -5,7 +5,9 @@ require './lib/fusuma/libinput_command'
5
5
 
6
6
  module Fusuma
7
7
  RSpec.describe LibinputCommand do
8
- let(:libinput_command) { described_class.new(libinput_options: libinput_options, commands: commands) }
8
+ let(:libinput_command) do
9
+ described_class.new(libinput_options: libinput_options, commands: commands)
10
+ end
9
11
  let(:libinput_options) { [] }
10
12
  let(:commands) { {} }
11
13
  describe '#version' do
@@ -79,15 +81,15 @@ module Fusuma
79
81
  before do
80
82
  dummy_io = StringIO.new('dummy')
81
83
  io = StringIO.new('dummy output')
82
- allow(POSIX::Spawn).to receive(:popen4).with(anything).and_return([nil, dummy_io, io, dummy_io])
83
- allow(Process).to receive(:waitpid).and_return(nil)
84
+ allow(Open3).to receive(:popen3).with(anything).and_return([dummy_io, io, dummy_io,
85
+ dummy_io, nil])
84
86
  end
85
87
 
86
88
  context 'with the alternative command' do
87
89
  let(:commands) { { list_devices_command: 'dummy_list_devices' } }
88
90
 
89
91
  it 'should call dummy events' do
90
- expect(POSIX::Spawn).to receive(:popen4).with(/dummy_list_devices/)
92
+ expect(Open3).to receive(:popen3).with(/dummy_list_devices/)
91
93
  end
92
94
  end
93
95
 
@@ -99,7 +101,7 @@ module Fusuma
99
101
 
100
102
  it 'call `libinput list-devices`' do
101
103
  command = 'libinput list-devices'
102
- expect(POSIX::Spawn).to receive(:popen4)
104
+ expect(Open3).to receive(:popen3)
103
105
  .with(command)
104
106
  end
105
107
  end
@@ -111,27 +113,34 @@ module Fusuma
111
113
 
112
114
  it 'call `libinput-list-devices`' do
113
115
  command = 'libinput-list-devices'
114
- expect(POSIX::Spawn).to receive(:popen4)
116
+ expect(Open3).to receive(:popen3)
115
117
  .with(command)
116
118
  end
117
119
  end
118
120
  end
119
121
 
120
122
  describe 'debug_events' do
121
- subject { libinput_command.debug_events }
122
123
  before do
123
- dummy_io = StringIO.new('dummy')
124
- allow(POSIX::Spawn).to receive(:popen4).with(anything).and_return([nil, dummy_io, dummy_io, dummy_io])
124
+ @dummy_io = StringIO.new('dummy')
125
+ allow(Process).to receive(:detach).with(anything).and_return(nil)
125
126
  end
127
+ subject { libinput_command.debug_events(@dummy_io) }
126
128
 
127
129
  context 'with the alternative command' do
128
- let(:commands) { { debug_events_command: 'dummy_debug_events' } }
130
+ before do
131
+ allow(libinput_command).to receive(:debug_events_with_options).and_return 'dummy_debug_events'
132
+ end
129
133
 
130
134
  it 'should call dummy events' do
131
- expect(POSIX::Spawn).to receive(:popen4).with(/dummy_debug_events/).once
135
+ expect(Process).to receive(:spawn).with('dummy_debug_events',
136
+ { out: @dummy_io, in: '/dev/null' }).once
132
137
  subject
133
138
  end
134
139
  end
140
+ end
141
+
142
+ describe '#debug_events_with_options' do
143
+ subject { libinput_command.debug_events_with_options }
135
144
 
136
145
  context 'with new cli version' do
137
146
  before do
@@ -139,13 +148,7 @@ module Fusuma
139
148
  .to receive(:new_cli_option_available?)
140
149
  .and_return(true)
141
150
  end
142
-
143
- it 'should call `libinput debug-events`' do
144
- command = 'libinput debug-events'
145
- expect(POSIX::Spawn).to receive(:popen4)
146
- .with("stdbuf -oL -- #{command}")
147
- subject
148
- end
151
+ it { is_expected.to eq 'stdbuf -oL -- libinput debug-events' }
149
152
  end
150
153
 
151
154
  context 'with old cli version' do
@@ -154,13 +157,7 @@ module Fusuma
154
157
  .to receive(:new_cli_option_available?)
155
158
  .and_return(false)
156
159
  end
157
-
158
- it 'should call `libinput-debug-events`' do
159
- command = 'libinput-debug-events'
160
- expect(POSIX::Spawn).to receive(:popen4)
161
- .with("stdbuf -oL -- #{command}")
162
- subject
163
- end
160
+ it { is_expected.to eq 'stdbuf -oL -- libinput-debug-events' }
164
161
  end
165
162
  end
166
163
  end
@@ -27,7 +27,7 @@ module Fusuma
27
27
 
28
28
  example.run
29
29
 
30
- Config.custom_path = nil
30
+ ConfigHelper.clear_config_yml
31
31
  end
32
32
 
33
33
  describe '#detect' do
@@ -33,7 +33,7 @@ module Fusuma
33
33
  it 'spawn' do
34
34
  command = 'echo dummy'
35
35
  env = {}
36
- expect(POSIX::Spawn).to receive(:spawn).with(env, command)
36
+ expect(Process).to receive(:spawn).with(env, command)
37
37
  expect(Process).to receive(:detach).with(anything)
38
38
  @executor.execute(@event)
39
39
  end
@@ -13,20 +13,24 @@ module Fusuma
13
13
  RSpec.describe Executor do
14
14
  before { @executor = Executor.new }
15
15
 
16
+ describe '#execute_key' do
17
+ it { expect { @executor.execute_keys }.to raise_error(NotImplementedError) }
18
+ end
19
+
16
20
  describe '#execute' do
17
- it do
18
- expect { @executor.execute('dummy') }.to raise_error(NotImplementedError)
19
- end
21
+ it { expect { @executor.execute('dummy') }.to raise_error(NotImplementedError) }
20
22
  end
21
23
 
22
24
  describe '#executable?' do
23
- it do
24
- expect { @executor.executable?('dummy') }.to raise_error(NotImplementedError)
25
- end
25
+ it { expect { @executor.executable?('dummy') }.to raise_error(NotImplementedError) }
26
26
  end
27
27
  end
28
28
 
29
29
  class DummyExecutor < Executor
30
+ def execute_keys
31
+ [:dummy]
32
+ end
33
+
30
34
  def execute(event)
31
35
  index = Config::Index.new([*event.record.index.keys, :dummy])
32
36
  content = Config.search(index)
@@ -15,7 +15,8 @@ module Fusuma
15
15
  dummy_pid = 999_999_999
16
16
  libinput_command = instance_double(LibinputCommand)
17
17
  allow(LibinputCommand).to receive(:new).and_return(libinput_command)
18
- allow(libinput_command).to receive(:debug_events).and_return([dummy_pid, @dummy_io])
18
+ allow(libinput_command).to receive(:debug_events).with(@dummy_io).and_return(dummy_pid)
19
+ allow(input).to receive(:create_io).and_return [@dummy_io, @dummy_io]
19
20
  end
20
21
 
21
22
  it { expect(input.io).to eq @dummy_io }
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fusuma
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-12 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: posix-spawn
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: '0'
11
+ date: 2021-10-01 00:00:00.000000000 Z
12
+ dependencies: []
27
13
  description: Fusuma is multitouch gesture recognizer. This gem makes your touchpad
28
14
  on Linux able to recognize swipes or pinchs and assign command to them. Read installation
29
15
  on Github(https://github.com/iberianpig/fusuma#installation).
@@ -120,7 +106,7 @@ licenses:
120
106
  - MIT
121
107
  metadata:
122
108
  yard.run: yri
123
- post_install_message:
109
+ post_install_message:
124
110
  rdoc_options: []
125
111
  require_paths:
126
112
  - lib
@@ -135,44 +121,44 @@ required_rubygems_version: !ruby/object:Gem::Requirement
135
121
  - !ruby/object:Gem::Version
136
122
  version: '0'
137
123
  requirements: []
138
- rubygems_version: 3.1.4
139
- signing_key:
124
+ rubygems_version: 3.2.22
125
+ signing_key:
140
126
  specification_version: 4
141
127
  summary: Multitouch gestures with libinput driver, Linux
142
128
  test_files:
143
- - spec/lib/device_spec.rb
129
+ - spec/helpers/config_helper.rb
144
130
  - spec/lib/config/searcher_spec.rb
145
- - spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt
131
+ - spec/lib/config_spec.rb
132
+ - spec/lib/custom_process_spec.rb
133
+ - spec/lib/device_spec.rb
146
134
  - spec/lib/dummy_config.yml
135
+ - spec/lib/fusuma_spec.rb
136
+ - spec/lib/libinput-list-devices_iberianpig-XPS-9360.txt
147
137
  - spec/lib/libinput-list-devices_magic_trackpad.txt
148
- - spec/lib/custom_process_spec.rb
138
+ - spec/lib/libinput-list-devices_razer_razer_blade.txt
139
+ - spec/lib/libinput-list-devices_thejinx0r.txt
140
+ - spec/lib/libinput-list-devices_unavailable.txt
141
+ - spec/lib/libinput_command_spec.rb
149
142
  - spec/lib/plugin/base_spec.rb
150
- - spec/lib/plugin/inputs/libinput_command_input_spec.rb
151
- - spec/lib/plugin/inputs/input_spec.rb
152
- - spec/lib/plugin/inputs/timer_input_spec.rb
153
- - spec/lib/plugin/events/records/record_spec.rb
143
+ - spec/lib/plugin/buffers/buffer_spec.rb
144
+ - spec/lib/plugin/buffers/dummy_buffer.rb
145
+ - spec/lib/plugin/buffers/gesture_buffer_spec.rb
146
+ - spec/lib/plugin/detectors/detector_spec.rb
147
+ - spec/lib/plugin/detectors/dummy_detector.rb
148
+ - spec/lib/plugin/detectors/pinch_detector_spec.rb
149
+ - spec/lib/plugin/detectors/rotate_detector_spec.rb
150
+ - spec/lib/plugin/detectors/swipe_detector_spec.rb
151
+ - spec/lib/plugin/events/event_spec.rb
154
152
  - spec/lib/plugin/events/records/gesture_record_spec.rb
153
+ - spec/lib/plugin/events/records/record_spec.rb
155
154
  - spec/lib/plugin/events/records/text_record_spec.rb
156
- - spec/lib/plugin/events/event_spec.rb
157
- - spec/lib/plugin/filters/libinput_filter_spec.rb
155
+ - spec/lib/plugin/executors/command_executor_spec.rb
156
+ - spec/lib/plugin/executors/executor_spec.rb
158
157
  - spec/lib/plugin/filters/filter_spec.rb
159
- - spec/lib/plugin/detectors/detector_spec.rb
160
- - spec/lib/plugin/detectors/swipe_detector_spec.rb
161
- - spec/lib/plugin/detectors/rotate_detector_spec.rb
162
- - spec/lib/plugin/detectors/pinch_detector_spec.rb
163
- - spec/lib/plugin/detectors/dummy_detector.rb
158
+ - spec/lib/plugin/filters/libinput_filter_spec.rb
159
+ - spec/lib/plugin/inputs/input_spec.rb
160
+ - spec/lib/plugin/inputs/libinput_command_input_spec.rb
161
+ - spec/lib/plugin/inputs/timer_input_spec.rb
164
162
  - spec/lib/plugin/manager_spec.rb
165
- - spec/lib/plugin/buffers/dummy_buffer.rb
166
- - spec/lib/plugin/buffers/buffer_spec.rb
167
- - spec/lib/plugin/buffers/gesture_buffer_spec.rb
168
163
  - spec/lib/plugin/parsers/parser_spec.rb
169
- - spec/lib/plugin/executors/executor_spec.rb
170
- - spec/lib/plugin/executors/command_executor_spec.rb
171
- - spec/lib/libinput-list-devices_unavailable.txt
172
- - spec/lib/libinput_command_spec.rb
173
- - spec/lib/fusuma_spec.rb
174
- - spec/lib/libinput-list-devices_razer_razer_blade.txt
175
- - spec/lib/libinput-list-devices_thejinx0r.txt
176
- - spec/lib/config_spec.rb
177
- - spec/helpers/config_helper.rb
178
164
  - spec/spec_helper.rb