fusuma 3.11.1 → 3.12.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: '064986ef807ceb1aa5ce1d021cdaf8931e44a1099fe8b72cd6aee283bc7ccf3a'
4
- data.tar.gz: 31d80cdd2c54c1f12a4e55005c4393ae4c3683ed0a0c3a4e506090cc2c0f4f73
3
+ metadata.gz: d715f3ca82e4571ad3c23547a0e6d1d833327c225b40db7337b14b38fd10d024
4
+ data.tar.gz: 414ed1c453e221a0e01524212627c945564643af054d81c8022436929ce0964a
5
5
  SHA512:
6
- metadata.gz: f27789347f194611db15b63f8cd8f04c47e3737ad2349950ab2a9210612f76a96f166c50a136bd2e4e22cce8dd9e640f89a7f8be19f2c282b4a071650cc26af1
7
- data.tar.gz: 86d0e0bac6c527e7453f4495bde1e58b4b74942b3670ee313d1a7f0323c7a4f9e5ed44c33f64614357ff8b38bbf9e265e074abbd6ce5915925233e3c7f3adc01
6
+ metadata.gz: 01f4fcec30760030cadc3d746d8c5c2423940493f610505d7ab6ceadb79751f845181f559b5c3924c80c8c272d773ba9ca56a9c9be5230e18e7b393b829b681d
7
+ data.tar.gz: 21db3821c594aca2aa3b8e881ea5288bec8e5447ed0b0e75a1a060a17fb4b0ab5cab8aa7489cc9d295fd212ec84f5dd4a489f4f45ad8439dc334459fa95b2574
data/README.md CHANGED
@@ -9,7 +9,7 @@ Fusuma is a powerful tool designed to enable multitouch gesture recognition on L
9
9
 
10
10
  ## Features
11
11
 
12
- - **Easy Installation**: Quick generate via RubyGems.
12
+ - **Easy Installation**: Easy to install via RubyGems.
13
13
  - **Flexible Configuration**: Customize gestures and actions freely in YAML file format.
14
14
  - **Sensitivity Settings**: Fine-tune gesture recognition with adjustable thresholds and intervals to suit your preferences and enhance precision.
15
15
  - **Extension through Plugins**: A [plugin system](https://github.com/iberianpig/fusuma/#fusuma-plugins) allows for additional functionality as needed.
@@ -32,7 +32,7 @@ Then, You apply the change with no logout or reboot.
32
32
  newgrp input
33
33
  ```
34
34
 
35
- **IMPORTANT**: This makes `/dev/input/` readable, so if that's an issue for you for some reason (like for privacy- or securityconcerns etc. or if it causes other parts of your OS to misbehave), **consider this your heads-up.**
35
+ **IMPORTANT**: This makes `/dev/input/` readable, so if that's an issue for you for some reason (like for privacy- or security concerns etc. or if it causes other parts of your OS to misbehave), **consider this your heads-up.**
36
36
 
37
37
  <details>
38
38
  <summary>For Debian Based Distros (Ubuntu, Debian, Mint, Pop!_OS)</summary>
@@ -109,7 +109,7 @@ For sending shortcuts:
109
109
  ```sh
110
110
  sudo pacman -Syu xdotool
111
111
  ```
112
- **For the truly lazy people:** As with pretty much anything else available as Open-Source-Software, you can install Fusuma via a package from the AUR. As off time of writing (March 2023), the package you would want is called `ruby-fusuma`.
112
+ **For the truly lazy people:** As with pretty much anything else available as Open-Source-Software, you can install Fusuma via a package from the AUR. The package you would want is called `ruby-fusuma`.
113
113
 
114
114
  Please keep in mind that this community-built package is NOT officially supported here and while it might do the job, it is not the intended way to install.
115
115
  Installing Fusuma this way means that if things do not work as intended during or after the installation, you are on your own.
@@ -428,8 +428,8 @@ Fusuma plugins are provided with the `fusuma-plugin-XXXXX` naming convention and
428
428
  ### Installation of Fusuma plugins
429
429
 
430
430
  ```sh
431
- # install fusuma-plugin-XXXX
432
- sudo gem install fusuma-plugin-XXXXX`
431
+ # install fusuma-plugin-XXXXX
432
+ sudo gem install fusuma-plugin-XXXXX
433
433
  ```
434
434
  ```sh
435
435
  # update
data/bin/console CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'bundler/setup'
5
- require 'fusuma'
4
+ require "bundler/setup"
5
+ require "fusuma"
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
@@ -10,9 +10,9 @@ require 'fusuma'
10
10
  # (If you use this, don't forget to add pry to your Gemfile!)
11
11
 
12
12
  def reload!(print = true)
13
- puts 'Reloading ...' if print
13
+ puts "Reloading ..." if print
14
14
  # Main project directory.
15
- root_dir = File.expand_path('..', __dir__)
15
+ root_dir = File.expand_path("..", __dir__)
16
16
  # Directories within the project that should be reloaded.
17
17
  reload_dirs = %w[lib]
18
18
  # Loop through and reload every file in all relevant project directories.
data/exe/fusuma CHANGED
@@ -1,47 +1,47 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'optparse'
5
- require_relative '../lib/fusuma'
4
+ require "optparse"
5
+ require_relative "../lib/fusuma"
6
6
 
7
7
  option = {}
8
8
  opt = OptionParser.new
9
9
 
10
- opt.on('-c', '--config=path/to/file',
11
- 'Use an alternative config file') do |v|
10
+ opt.on("-c", "--config=path/to/file",
11
+ "Use an alternative config file") do |v|
12
12
  option[:config_path] = v
13
13
  end
14
14
 
15
- opt.on('-d', '--daemon',
16
- 'Daemonize process') do |v|
15
+ opt.on("-d", "--daemon",
16
+ "Daemonize process") do |v|
17
17
  option[:daemon] = v
18
18
  end
19
19
 
20
- opt.on('-l', '--list-devices',
21
- 'List available devices') do |v|
20
+ opt.on("-l", "--list-devices",
21
+ "List available devices") do |v|
22
22
  option[:list] = v
23
23
  end
24
24
 
25
- opt.on('--log=path/to/file',
26
- 'Print logs to file') do |v|
25
+ opt.on("--log=path/to/file",
26
+ "Print logs to file") do |v|
27
27
  option[:log_filepath] = v
28
28
  end
29
29
 
30
- opt.on('--show-config', 'Show config as YAML format which is loaded internally') do |v|
30
+ opt.on("--show-config", "Show config as YAML format which is loaded internally") do |v|
31
31
  option[:show_config] = v
32
32
  end
33
33
 
34
34
  opt.on('--device="Device name"',
35
- 'Open the given device only (DEPRECATED)') do |v|
35
+ "Open the given device only (DEPRECATED)") do |v|
36
36
  option[:device] = v
37
37
  end
38
38
 
39
- opt.on('-v', '--verbose',
40
- 'Show details about the results of running fusuma') do |v|
39
+ opt.on("-v", "--verbose",
40
+ "Show details about the results of running fusuma") do |v|
41
41
  option[:verbose] = v
42
42
  end
43
43
 
44
- opt.on('--version', 'Show fusuma version') do |v|
44
+ opt.on("--version", "Show fusuma version") do |v|
45
45
  option[:version] = v
46
46
  end
47
47
 
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Fusuma
4
+ class Config
5
+ # Matches context conditions for configuration lookup.
6
+ # Supports AND (multiple keys) and OR (array values) conditions.
7
+ class ContextMatcher
8
+ class << self
9
+ # Check if config context matches request context.
10
+ # @param config_context [Hash, nil] context defined in YAML config
11
+ # @param request_context [Hash, nil] context from runtime
12
+ # @return [Boolean] true if matched
13
+ #: (Hash[untyped, untyped]?, Hash[untyped, untyped]?) -> bool
14
+ def match?(config_context, request_context)
15
+ return true if config_context.nil? || config_context.empty?
16
+ return false if request_context.nil? || request_context.empty?
17
+
18
+ config_context.all? do |key, expected_value|
19
+ match_value?(expected_value, request_context[key])
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # @param expected [Object] expected value (single or array for OR)
26
+ # @param actual [Object] actual value from request context
27
+ # @return [Boolean] true if matched
28
+ #: (untyped, untyped) -> bool
29
+ def match_value?(expected, actual)
30
+ case expected
31
+ when Array
32
+ if actual.is_a?(Array)
33
+ expected == actual # exact match when both are arrays
34
+ else
35
+ expected.include?(actual) # OR condition
36
+ end
37
+ else
38
+ expected == actual
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -45,6 +45,8 @@ module Fusuma
45
45
  @symbol = case symbol_word
46
46
  when Integer, Symbol
47
47
  symbol_word
48
+ when /\A[1-9]\d*\z/
49
+ symbol_word.to_i
48
50
  else
49
51
  symbol_word.to_sym
50
52
  end
@@ -19,29 +19,37 @@ module Fusuma
19
19
  def search(index, location:)
20
20
  key = index.keys.first
21
21
  return location if key.nil?
22
-
23
22
  return nil if location.nil?
24
-
25
23
  return nil unless location.is_a?(Hash)
26
24
 
27
- next_index = Index.new(Array(index.keys[1..-1]))
25
+ next_index = Index.new(index.keys.drop(1))
28
26
 
29
- value = nil
30
- next_location_cadidates(location, key).find do |next_location|
31
- value = search(next_index, location: next_location)
27
+ next_location_cadidates(location, key).each do |next_location|
28
+ result = search(next_index, location: next_location)
29
+ return result if result
32
30
  end
33
- value
31
+ nil
34
32
  end
35
33
 
36
34
  #: (Fusuma::Config::Index, location: Array[untyped], context: Hash[untyped, untyped] | nil) -> untyped
37
35
  def search_with_context(index, location:, context:)
38
36
  return nil if location.nil?
39
37
 
40
- return search(index, location: location[0]) if context == {}
38
+ # When context is nil or empty, search in no-context config blocks
39
+ if context.nil? || context == {}
40
+ no_context_conf = location.find { |conf| conf[:context].nil? }
41
+ return no_context_conf ? search(index, location: no_context_conf) : nil
42
+ end
41
43
 
44
+ # When context is specified, search only in context-having config blocks
42
45
  value = nil
43
- location.find do |conf|
44
- value = search(index, location: conf) if conf[:context] == context
46
+ location.each do |conf|
47
+ next if conf[:context].nil? # skip no-context blocks
48
+
49
+ if ContextMatcher.match?(conf[:context], context)
50
+ value = search(index, location: conf)
51
+ break if value
52
+ end
45
53
  end
46
54
  value
47
55
  end
@@ -77,7 +85,7 @@ module Fusuma
77
85
  def next_location_cadidates(location, key)
78
86
  [
79
87
  location[key.symbol],
80
- key.skippable && location
88
+ key.skippable ? location : nil
81
89
  ].compact
82
90
  end
83
91
 
@@ -103,12 +111,11 @@ module Fusuma
103
111
  #: (Hash[untyped, untyped], ?Array[untyped]) { () -> untyped } -> Hash[untyped, untyped]?
104
112
  def find_context(request_context, fallbacks = CONTEXT_SEARCH_ORDER, &block)
105
113
  # Search in blocks in the following order.
106
- # 1. primary context(no context)
107
- # 2. complete match config[:context] == request_context
108
- # 3. partial match config[:context] =~ request_context
109
- # no_context?(&block) ||
110
- # complete_match_context(request_context, &block) ||
111
- # partial_match_context(request_context, &block)
114
+ # 1. no_context: primary context (no context specified)
115
+ # 2. complete_match_context: config[:context] matches request_context
116
+ # - Supports OR condition (array values)
117
+ # - Supports AND condition (multiple keys)
118
+ # 3. partial_match_context: config[:context] partially matches request_context
112
119
  fallbacks.find do |method|
113
120
  result = send(method, request_context, &block)
114
121
  return result if result
@@ -125,14 +132,15 @@ module Fusuma
125
132
  {} if with_context({}, &block)
126
133
  end
127
134
 
128
- # Complete match request context
135
+ # Match config context with request context using ContextMatcher.
136
+ # Supports OR condition (array values) and AND condition (multiple keys).
129
137
  # @param request_context [Hash]
130
138
  # @return [Hash] matched context
131
139
  # @return [NilClass] if not matched
132
140
  #: (Hash[untyped, untyped]) { () -> untyped } -> Hash[untyped, untyped]?
133
141
  def complete_match_context(request_context, &block)
134
142
  Config.instance.keymap.each do |config|
135
- next unless config[:context] == request_context
143
+ next unless ContextMatcher.match?(config[:context], request_context)
136
144
  return config[:context] if with_context(config[:context], &block)
137
145
  end
138
146
  nil
data/lib/fusuma/config.rb CHANGED
@@ -3,6 +3,7 @@
3
3
  require_relative "multi_logger"
4
4
  require_relative "config/index"
5
5
  require_relative "config/searcher"
6
+ require_relative "config/context_matcher"
6
7
  require_relative "config/yaml_duplication_checker"
7
8
  require_relative "plugin/manager"
8
9
  require_relative "hash_support"
@@ -8,6 +8,7 @@ module Fusuma
8
8
  module Detectors
9
9
  # Inherite this base
10
10
  class Detector < Base
11
+ #: (String) -> String
11
12
  def self.type(tag_name)
12
13
  tag_name.gsub("_detector", "")
13
14
  end
@@ -9,6 +9,7 @@ module Fusuma
9
9
  # libinput commands wrapper
10
10
  class TimerInput < Input
11
11
  include Singleton
12
+
12
13
  DEFAULT_INTERVAL = 5
13
14
  EPSILON_TIME = 0.02
14
15
  def config_param_types
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fusuma
4
- VERSION = "3.11.1"
4
+ VERSION = "3.12.0"
5
5
  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: 3.11.1
4
+ version: 3.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - iberianpig
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-01-10 00:00:00.000000000 Z
11
+ date: 2026-01-26 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
@@ -29,6 +29,7 @@ files:
29
29
  - lib/fusuma.rb
30
30
  - lib/fusuma/config.rb
31
31
  - lib/fusuma/config.yml
32
+ - lib/fusuma/config/context_matcher.rb
32
33
  - lib/fusuma/config/index.rb
33
34
  - lib/fusuma/config/searcher.rb
34
35
  - lib/fusuma/config/yaml_duplication_checker.rb