fusuma 3.9.0 → 3.10.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 +4 -4
 - data/README.md +27 -1
 - data/lib/fusuma/config/index.rb +12 -7
 - data/lib/fusuma/config/searcher.rb +17 -6
 - data/lib/fusuma/config/yaml_duplication_checker.rb +6 -0
 - data/lib/fusuma/config.rb +17 -3
 - data/lib/fusuma/custom_process.rb +3 -0
 - data/lib/fusuma/device.rb +15 -0
 - data/lib/fusuma/environment.rb +4 -0
 - data/lib/fusuma/hash_support.rb +6 -1
 - data/lib/fusuma/libinput_command.rb +11 -3
 - data/lib/fusuma/multi_logger.rb +15 -4
 - data/lib/fusuma/plugin/base.rb +11 -1
 - data/lib/fusuma/plugin/buffers/buffer.rb +6 -0
 - data/lib/fusuma/plugin/buffers/gesture_buffer.rb +15 -9
 - data/lib/fusuma/plugin/buffers/timer_buffer.rb +2 -1
 - data/lib/fusuma/plugin/detectors/detector.rb +15 -15
 - data/lib/fusuma/plugin/detectors/hold_detector.rb +10 -2
 - data/lib/fusuma/plugin/detectors/pinch_detector.rb +13 -1
 - data/lib/fusuma/plugin/detectors/rotate_detector.rb +11 -0
 - data/lib/fusuma/plugin/detectors/swipe_detector.rb +12 -0
 - data/lib/fusuma/plugin/events/event.rb +5 -2
 - data/lib/fusuma/plugin/events/records/gesture_record.rb +2 -0
 - data/lib/fusuma/plugin/events/records/index_record.rb +2 -0
 - data/lib/fusuma/plugin/events/records/record.rb +1 -0
 - data/lib/fusuma/plugin/events/records/text_record.rb +3 -0
 - data/lib/fusuma/plugin/executors/command_executor.rb +5 -1
 - data/lib/fusuma/plugin/executors/executor.rb +6 -0
 - data/lib/fusuma/plugin/filters/filter.rb +2 -0
 - data/lib/fusuma/plugin/filters/libinput_device_filter.rb +10 -0
 - data/lib/fusuma/plugin/inputs/input.rb +5 -0
 - data/lib/fusuma/plugin/inputs/libinput_command_input.rb +10 -3
 - data/lib/fusuma/plugin/inputs/timer_input.rb +4 -0
 - data/lib/fusuma/plugin/manager.rb +11 -1
 - data/lib/fusuma/plugin/parsers/libinput_gesture_parser.rb +9 -0
 - data/lib/fusuma/plugin/parsers/parser.rb +4 -0
 - data/lib/fusuma/string_support.rb +1 -0
 - data/lib/fusuma/version.rb +1 -1
 - data/lib/fusuma.rb +10 -1
 - metadata +2 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 7161de044b786ed9f12f64be26a497307ba1ea87159760e68b5ac90d87ea1d73
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: aa9359be7d9c0bcc6ca283ba5c2aa17b55f07424a26d3f22b056c47b924488bc
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 1187109a3b4b3ba67b35feaa274ab73a58dc3411ae8b3de6f62e5ef153c7ca8647383ae0cebeeb8e5632bd69ec0218477826e5e5aa4d32002233a87b521eba43
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: eec0e66de8f07b7e64ffec123b16a1b51103701346819b0b048850d83e8bf8a78c020f3d51e889f7ff5474218d534a7e7e6bf834bac36c6ff739f279a06da4c8
         
     | 
    
        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  
     | 
| 
      
 12 
     | 
    
         
            +
            - **Easy Installation**: Quick generate 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.
         
     | 
| 
         @@ -449,6 +449,32 @@ I'm a Freelance Engineer in Japan and working on these products after finishing 
     | 
|
| 
       449 
449 
     | 
    
         
             
            Currently, my open-source contribution times is not enough.
         
     | 
| 
       450 
450 
     | 
    
         
             
            If you like my work and want to contribute and become a sponsor, I will be able to focus on my projects.
         
     | 
| 
       451 
451 
     | 
    
         | 
| 
      
 452 
     | 
    
         
            +
            ## Development
         
     | 
| 
      
 453 
     | 
    
         
            +
             
     | 
| 
      
 454 
     | 
    
         
            +
            ### Type Checking
         
     | 
| 
      
 455 
     | 
    
         
            +
             
     | 
| 
      
 456 
     | 
    
         
            +
            Fusuma uses [RBS](https://github.com/ruby/rbs) for type signatures and [Steep](https://github.com/soutaro/steep) for type checking.
         
     | 
| 
      
 457 
     | 
    
         
            +
             
     | 
| 
      
 458 
     | 
    
         
            +
            #### Running Type Checks
         
     | 
| 
      
 459 
     | 
    
         
            +
             
     | 
| 
      
 460 
     | 
    
         
            +
            ```sh
         
     | 
| 
      
 461 
     | 
    
         
            +
            # Generate RBS signatures and run type checking
         
     | 
| 
      
 462 
     | 
    
         
            +
            bundle exec rake rbs:generate && bundle exec steep check
         
     | 
| 
      
 463 
     | 
    
         
            +
             
     | 
| 
      
 464 
     | 
    
         
            +
            # Validate RBS files
         
     | 
| 
      
 465 
     | 
    
         
            +
            bundle exec rake rbs:validate
         
     | 
| 
      
 466 
     | 
    
         
            +
             
     | 
| 
      
 467 
     | 
    
         
            +
            # Generate inline RBS from code comments
         
     | 
| 
      
 468 
     | 
    
         
            +
            bundle exec rbs-inline --opt-out lib --output --base .
         
     | 
| 
      
 469 
     | 
    
         
            +
            ```
         
     | 
| 
      
 470 
     | 
    
         
            +
             
     | 
| 
      
 471 
     | 
    
         
            +
            #### RBS Development
         
     | 
| 
      
 472 
     | 
    
         
            +
             
     | 
| 
      
 473 
     | 
    
         
            +
            The project uses both traditional RBS files and inline RBS comments:
         
     | 
| 
      
 474 
     | 
    
         
            +
            - Inline RBS comments in source code (processed by `rbs-inline`)
         
     | 
| 
      
 475 
     | 
    
         
            +
            - Generated RBS files in `sig/generated/`
         
     | 
| 
      
 476 
     | 
    
         
            +
            - Type checking via Steep with configuration in `Steepfile`
         
     | 
| 
      
 477 
     | 
    
         
            +
             
     | 
| 
       452 
478 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       453 
479 
     | 
    
         | 
| 
       454 
480 
     | 
    
         
             
            Bug reports and pull requests are welcome on GitHub at https://github.com/iberianpig/fusuma. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
         
     | 
    
        data/lib/fusuma/config/index.rb
    CHANGED
    
    | 
         @@ -5,6 +5,7 @@ module Fusuma 
     | 
|
| 
       5 
5 
     | 
    
         
             
              class Config
         
     | 
| 
       6 
6 
     | 
    
         
             
                # index for config.yml
         
     | 
| 
       7 
7 
     | 
    
         
             
                class Index
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #: (Array[untyped] | String | Symbol | Integer) -> void
         
     | 
| 
       8 
9 
     | 
    
         
             
                  def initialize(keys)
         
     | 
| 
       9 
10 
     | 
    
         
             
                    case keys
         
     | 
| 
       10 
11 
     | 
    
         
             
                    when Array
         
     | 
| 
         @@ -21,6 +22,9 @@ module Fusuma 
     | 
|
| 
       21 
22 
     | 
    
         
             
                    end
         
     | 
| 
       22 
23 
     | 
    
         
             
                  end
         
     | 
| 
       23 
24 
     | 
    
         | 
| 
      
 25 
     | 
    
         
            +
                  attr_reader :keys #: Array[Key]
         
     | 
| 
      
 26 
     | 
    
         
            +
                  attr_reader :cache_key #: Symbol | Integer
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
       24 
28 
     | 
    
         
             
                  def to_s
         
     | 
| 
       25 
29 
     | 
    
         
             
                    @keys.map(&:inspect)
         
     | 
| 
       26 
30 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -31,15 +35,18 @@ module Fusuma 
     | 
|
| 
       31 
35 
     | 
    
         
             
                    cache_key == other.cache_key
         
     | 
| 
       32 
36 
     | 
    
         
             
                  end
         
     | 
| 
       33 
37 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                  attr_reader :keys, :cache_key
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
38 
     | 
    
         
             
                  # Keys in Index
         
     | 
| 
       37 
39 
     | 
    
         
             
                  class Key
         
     | 
| 
      
 40 
     | 
    
         
            +
                    attr_reader :symbol #: Symbol | Integer
         
     | 
| 
      
 41 
     | 
    
         
            +
                    attr_reader :skippable #: bool
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    #: (String | Integer | Symbol, ?skippable: bool) -> void
         
     | 
| 
       38 
44 
     | 
    
         
             
                    def initialize(symbol_word, skippable: false)
         
     | 
| 
       39 
     | 
    
         
            -
                      @symbol =  
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
                      rescue
         
     | 
| 
      
 45 
     | 
    
         
            +
                      @symbol = case symbol_word
         
     | 
| 
      
 46 
     | 
    
         
            +
                      when Integer, Symbol
         
     | 
| 
       42 
47 
     | 
    
         
             
                        symbol_word
         
     | 
| 
      
 48 
     | 
    
         
            +
                      else
         
     | 
| 
      
 49 
     | 
    
         
            +
                        symbol_word.to_sym
         
     | 
| 
       43 
50 
     | 
    
         
             
                      end
         
     | 
| 
       44 
51 
     | 
    
         | 
| 
       45 
52 
     | 
    
         
             
                      @skippable = skippable
         
     | 
| 
         @@ -52,8 +59,6 @@ module Fusuma 
     | 
|
| 
       52 
59 
     | 
    
         
             
                        @symbol.to_s
         
     | 
| 
       53 
60 
     | 
    
         
             
                      end
         
     | 
| 
       54 
61 
     | 
    
         
             
                    end
         
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                    attr_reader :symbol, :skippable
         
     | 
| 
       57 
62 
     | 
    
         
             
                  end
         
     | 
| 
       58 
63 
     | 
    
         
             
                end
         
     | 
| 
       59 
64 
     | 
    
         
             
              end
         
     | 
| 
         @@ -5,6 +5,7 @@ module Fusuma 
     | 
|
| 
       5 
5 
     | 
    
         
             
              class Config
         
     | 
| 
       6 
6 
     | 
    
         
             
                # Search config.yml
         
     | 
| 
       7 
7 
     | 
    
         
             
                class Searcher
         
     | 
| 
      
 8 
     | 
    
         
            +
                  #: () -> void
         
     | 
| 
       8 
9 
     | 
    
         
             
                  def initialize
         
     | 
| 
       9 
10 
     | 
    
         
             
                    @cache = {}
         
     | 
| 
       10 
11 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -14,6 +15,7 @@ module Fusuma 
     | 
|
| 
       14 
15 
     | 
    
         
             
                  # @return [NilClass]
         
     | 
| 
       15 
16 
     | 
    
         
             
                  # @return [Hash]
         
     | 
| 
       16 
17 
     | 
    
         
             
                  # @return [Object]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #: (Fusuma::Config::Index, location: untyped) -> untyped
         
     | 
| 
       17 
19 
     | 
    
         
             
                  def search(index, location:)
         
     | 
| 
       18 
20 
     | 
    
         
             
                    key = index.keys.first
         
     | 
| 
       19 
21 
     | 
    
         
             
                    return location if key.nil?
         
     | 
| 
         @@ -22,7 +24,7 @@ module Fusuma 
     | 
|
| 
       22 
24 
     | 
    
         | 
| 
       23 
25 
     | 
    
         
             
                    return nil unless location.is_a?(Hash)
         
     | 
| 
       24 
26 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                    next_index = Index.new(index.keys[1..-1])
         
     | 
| 
      
 27 
     | 
    
         
            +
                    next_index = Index.new(Array(index.keys[1..-1]))
         
     | 
| 
       26 
28 
     | 
    
         | 
| 
       27 
29 
     | 
    
         
             
                    value = nil
         
     | 
| 
       28 
30 
     | 
    
         
             
                    next_location_cadidates(location, key).find do |next_location|
         
     | 
| 
         @@ -31,6 +33,7 @@ module Fusuma 
     | 
|
| 
       31 
33 
     | 
    
         
             
                    value
         
     | 
| 
       32 
34 
     | 
    
         
             
                  end
         
     | 
| 
       33 
35 
     | 
    
         | 
| 
      
 36 
     | 
    
         
            +
                  #: (Fusuma::Config::Index, location: Array[untyped], context: Hash[untyped, untyped] | nil) -> untyped
         
     | 
| 
       34 
37 
     | 
    
         
             
                  def search_with_context(index, location:, context:)
         
     | 
| 
       35 
38 
     | 
    
         
             
                    return nil if location.nil?
         
     | 
| 
       36 
39 
     | 
    
         | 
| 
         @@ -48,12 +51,14 @@ module Fusuma 
     | 
|
| 
       48 
51 
     | 
    
         
             
                  # @return [NilClass]
         
     | 
| 
       49 
52 
     | 
    
         
             
                  # @return [Hash]
         
     | 
| 
       50 
53 
     | 
    
         
             
                  # @return [Object]
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #: (Fusuma::Config::Index, location: Array[untyped])
         
     | 
| 
       51 
55 
     | 
    
         
             
                  def search_with_cache(index, location:)
         
     | 
| 
       52 
56 
     | 
    
         
             
                    cache([index.cache_key, Searcher.context]) do
         
     | 
| 
       53 
57 
     | 
    
         
             
                      search_with_context(index, location: location, context: Searcher.context)
         
     | 
| 
       54 
58 
     | 
    
         
             
                    end
         
     | 
| 
       55 
59 
     | 
    
         
             
                  end
         
     | 
| 
       56 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
                  #: (Array[untyped] | String) { () -> untyped } -> untyped
         
     | 
| 
       57 
62 
     | 
    
         
             
                  def cache(key)
         
     | 
| 
       58 
63 
     | 
    
         
             
                    key = key.join(",") if key.is_a? Array
         
     | 
| 
       59 
64 
     | 
    
         
             
                    if @cache.key?(key)
         
     | 
| 
         @@ -68,6 +73,7 @@ module Fusuma 
     | 
|
| 
       68 
73 
     | 
    
         
             
                  # next locations' candidates sorted by priority
         
     | 
| 
       69 
74 
     | 
    
         
             
                  #  1. look up location with key
         
     | 
| 
       70 
75 
     | 
    
         
             
                  #  2. skip the key and go to child location
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #: (Hash[untyped, untyped], Fusuma::Config::Index::Key) -> Array[untyped]
         
     | 
| 
       71 
77 
     | 
    
         
             
                  def next_location_cadidates(location, key)
         
     | 
| 
       72 
78 
     | 
    
         
             
                    [
         
     | 
| 
       73 
79 
     | 
    
         
             
                      location[key.symbol],
         
     | 
| 
         @@ -81,19 +87,20 @@ module Fusuma 
     | 
|
| 
       81 
87 
     | 
    
         
             
                    # Search with context from load_streamed Config
         
     | 
| 
       82 
88 
     | 
    
         
             
                    # @param context [Hash]
         
     | 
| 
       83 
89 
     | 
    
         
             
                    # @return [Object]
         
     | 
| 
      
 90 
     | 
    
         
            +
                    #: (?Hash[untyped, untyped]) { () -> untyped } -> untyped
         
     | 
| 
       84 
91 
     | 
    
         
             
                    def with_context(context = {}, &block)
         
     | 
| 
       85 
92 
     | 
    
         
             
                      before = @context
         
     | 
| 
       86 
93 
     | 
    
         
             
                      @context = context
         
     | 
| 
       87 
     | 
    
         
            -
                       
     | 
| 
      
 94 
     | 
    
         
            +
                      block.call
         
     | 
| 
       88 
95 
     | 
    
         
             
                    ensure # NOTE: ensure is called even if return in block
         
     | 
| 
       89 
96 
     | 
    
         
             
                      @context = before
         
     | 
| 
       90 
     | 
    
         
            -
                      result
         
     | 
| 
       91 
97 
     | 
    
         
             
                    end
         
     | 
| 
       92 
98 
     | 
    
         | 
| 
       93 
99 
     | 
    
         
             
                    CONTEXT_SEARCH_ORDER = [:no_context, :complete_match_context, :partial_match_context]
         
     | 
| 
       94 
100 
     | 
    
         
             
                    # Return a matching context from config
         
     | 
| 
       95 
101 
     | 
    
         
             
                    # @params request_context [Hash]
         
     | 
| 
       96 
102 
     | 
    
         
             
                    # @return [Hash]
         
     | 
| 
      
 103 
     | 
    
         
            +
                    #: (Hash[untyped, untyped], ?Array[untyped]) { () -> untyped } -> Hash[untyped, untyped]?
         
     | 
| 
       97 
104 
     | 
    
         
             
                    def find_context(request_context, fallbacks = CONTEXT_SEARCH_ORDER, &block)
         
     | 
| 
       98 
105 
     | 
    
         
             
                      # Search in blocks in the following order.
         
     | 
| 
       99 
106 
     | 
    
         
             
                      # 1. primary context(no context)
         
     | 
| 
         @@ -113,6 +120,7 @@ module Fusuma 
     | 
|
| 
       113 
120 
     | 
    
         
             
                    # No context(primary context)
         
     | 
| 
       114 
121 
     | 
    
         
             
                    # @return [Hash]
         
     | 
| 
       115 
122 
     | 
    
         
             
                    # @return [NilClass]
         
     | 
| 
      
 123 
     | 
    
         
            +
                    #: (Hash[untyped, untyped]) { () -> untyped } -> Hash[untyped, untyped]?
         
     | 
| 
       116 
124 
     | 
    
         
             
                    def no_context(_request_context, &block)
         
     | 
| 
       117 
125 
     | 
    
         
             
                      {} if with_context({}, &block)
         
     | 
| 
       118 
126 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -121,6 +129,7 @@ module Fusuma 
     | 
|
| 
       121 
129 
     | 
    
         
             
                    # @param request_context [Hash]
         
     | 
| 
       122 
130 
     | 
    
         
             
                    # @return [Hash] matched context
         
     | 
| 
       123 
131 
     | 
    
         
             
                    # @return [NilClass] if not matched
         
     | 
| 
      
 132 
     | 
    
         
            +
                    #: (Hash[untyped, untyped]) { () -> untyped } -> Hash[untyped, untyped]?
         
     | 
| 
       124 
133 
     | 
    
         
             
                    def complete_match_context(request_context, &block)
         
     | 
| 
       125 
134 
     | 
    
         
             
                      Config.instance.keymap.each do |config|
         
     | 
| 
       126 
135 
     | 
    
         
             
                        next unless config[:context] == request_context
         
     | 
| 
         @@ -133,6 +142,7 @@ module Fusuma 
     | 
|
| 
       133 
142 
     | 
    
         
             
                    # @param request_context [Hash]
         
     | 
| 
       134 
143 
     | 
    
         
             
                    # @return [Hash] matched context
         
     | 
| 
       135 
144 
     | 
    
         
             
                    # @return [NilClass] if not matched
         
     | 
| 
      
 145 
     | 
    
         
            +
                    #: (Hash[untyped, untyped]) { () -> untyped } -> Hash[untyped, untyped]?
         
     | 
| 
       136 
146 
     | 
    
         
             
                    def partial_match_context(request_context, &block)
         
     | 
| 
       137 
147 
     | 
    
         
             
                      if request_context.keys.size > 1
         
     | 
| 
       138 
148 
     | 
    
         
             
                        Config.instance.keymap.each do |config|
         
     | 
| 
         @@ -155,6 +165,7 @@ module Fusuma 
     | 
|
| 
       155 
165 
     | 
    
         
             
                    # @param request_context [Hash]
         
     | 
| 
       156 
166 
     | 
    
         
             
                    # @return [Hash] matched context
         
     | 
| 
       157 
167 
     | 
    
         
             
                    # @return [NilClass] if not matched
         
     | 
| 
      
 168 
     | 
    
         
            +
                    #: (Hash[untyped, untyped]) { () -> untyped } -> Hash[untyped, untyped]?
         
     | 
| 
       158 
169 
     | 
    
         
             
                    def plugin_default_context(request_context, &block)
         
     | 
| 
       159 
170 
     | 
    
         
             
                      complete_match_context = nil
         
     | 
| 
       160 
171 
     | 
    
         
             
                      Config.instance.keymap.each do |config|
         
     | 
| 
         @@ -167,9 +178,9 @@ module Fusuma 
     | 
|
| 
       167 
178 
     | 
    
         | 
| 
       168 
179 
     | 
    
         
             
                        return config[:context] if with_context(config[:context], &block)
         
     | 
| 
       169 
180 
     | 
    
         
             
                      end
         
     | 
| 
       170 
     | 
    
         
            -
             
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
                         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                      complete_match_context&.tap do |context|
         
     | 
| 
      
 183 
     | 
    
         
            +
                        with_context(context, &block)
         
     | 
| 
       173 
184 
     | 
    
         
             
                      end
         
     | 
| 
       174 
185 
     | 
    
         
             
                    end
         
     | 
| 
       175 
186 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -1,10 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require "yaml"
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
       3 
5 
     | 
    
         
             
            module Fusuma
         
     | 
| 
       4 
6 
     | 
    
         
             
              class Config
         
     | 
| 
       5 
7 
     | 
    
         
             
                # ref: https://github.com/rubocop-hq/rubocop/blob/97e4ffc8a71e9e5239a927c6a534dfc1e0da917f/lib/rubocop/yaml_duplication_checker.rb
         
     | 
| 
       6 
8 
     | 
    
         
             
                # Find duplicated keys from YAML.
         
     | 
| 
      
 9 
     | 
    
         
            +
                # steep:ignore:start
         
     | 
| 
       7 
10 
     | 
    
         
             
                module YAMLDuplicationChecker
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #: (String, String) { (string) -> void }  -> void
         
     | 
| 
       8 
12 
     | 
    
         
             
                  def self.check(yaml_string, filename, &on_duplicated)
         
     | 
| 
       9 
13 
     | 
    
         
             
                    tree = YAML.parse(yaml_string, filename: filename)
         
     | 
| 
       10 
14 
     | 
    
         
             
                    return unless tree
         
     | 
| 
         @@ -12,6 +16,7 @@ module Fusuma 
     | 
|
| 
       12 
16 
     | 
    
         
             
                    traverse(tree, &on_duplicated)
         
     | 
| 
       13 
17 
     | 
    
         
             
                  end
         
     | 
| 
       14 
18 
     | 
    
         | 
| 
      
 19 
     | 
    
         
            +
                  #: (untyped) { () -> void } -> Array[untyped]?
         
     | 
| 
       15 
20 
     | 
    
         
             
                  def self.traverse(tree, &on_duplicated)
         
     | 
| 
       16 
21 
     | 
    
         
             
                    case tree
         
     | 
| 
       17 
22 
     | 
    
         
             
                    when Psych::Nodes::Mapping
         
     | 
| 
         @@ -31,5 +36,6 @@ module Fusuma 
     | 
|
| 
       31 
36 
     | 
    
         | 
| 
       32 
37 
     | 
    
         
             
                  private_class_method :traverse
         
     | 
| 
       33 
38 
     | 
    
         
             
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
                # steep:ignore:end
         
     | 
| 
       34 
40 
     | 
    
         
             
              end
         
     | 
| 
       35 
41 
     | 
    
         
             
            end
         
     | 
    
        data/lib/fusuma/config.rb
    CHANGED
    
    | 
         @@ -20,6 +20,7 @@ module Fusuma 
     | 
|
| 
       20 
20 
     | 
    
         
             
                include Singleton
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
                class << self
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #: (Fusuma::Config::Index) -> (String | Hash[untyped, untyped] | Integer | Float)?
         
     | 
| 
       23 
24 
     | 
    
         
             
                  def search(index)
         
     | 
| 
       24 
25 
     | 
    
         
             
                    instance.search(index)
         
     | 
| 
       25 
26 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -28,6 +29,7 @@ module Fusuma 
     | 
|
| 
       28 
29 
     | 
    
         
             
                    instance.find_execute_key(index)
         
     | 
| 
       29 
30 
     | 
    
         
             
                  end
         
     | 
| 
       30 
31 
     | 
    
         | 
| 
      
 32 
     | 
    
         
            +
                  #: (String?) -> Fusuma::Config
         
     | 
| 
       31 
33 
     | 
    
         
             
                  def custom_path=(new_path)
         
     | 
| 
       32 
34 
     | 
    
         
             
                    instance.custom_path = new_path
         
     | 
| 
       33 
35 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -35,22 +37,26 @@ module Fusuma 
     | 
|
| 
       35 
37 
     | 
    
         | 
| 
       36 
38 
     | 
    
         
             
                attr_reader :custom_path, :searcher
         
     | 
| 
       37 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
                #: () -> void
         
     | 
| 
       38 
41 
     | 
    
         
             
                def initialize
         
     | 
| 
       39 
42 
     | 
    
         
             
                  @searcher = Searcher.new
         
     | 
| 
       40 
43 
     | 
    
         
             
                  @custom_path = nil
         
     | 
| 
       41 
44 
     | 
    
         
             
                  @keymap = nil
         
     | 
| 
       42 
45 
     | 
    
         
             
                end
         
     | 
| 
       43 
46 
     | 
    
         | 
| 
      
 47 
     | 
    
         
            +
                #: (String?) -> Fusuma::Config
         
     | 
| 
       44 
48 
     | 
    
         
             
                def custom_path=(new_path)
         
     | 
| 
       45 
49 
     | 
    
         
             
                  @custom_path = new_path
         
     | 
| 
       46 
50 
     | 
    
         
             
                  reload
         
     | 
| 
       47 
51 
     | 
    
         
             
                end
         
     | 
| 
       48 
52 
     | 
    
         | 
| 
      
 53 
     | 
    
         
            +
                #: () -> Array[untyped]?
         
     | 
| 
       49 
54 
     | 
    
         
             
                def keymap
         
     | 
| 
       50 
55 
     | 
    
         
             
                  # FIXME: @keymap is not initialized when called from outside Fusuma::Runner like fusuma-senkey
         
     | 
| 
       51 
56 
     | 
    
         
             
                  @keymap || reload.keymap
         
     | 
| 
       52 
57 
     | 
    
         
             
                end
         
     | 
| 
       53 
58 
     | 
    
         | 
| 
      
 59 
     | 
    
         
            +
                #: () -> Fusuma::Config
         
     | 
| 
       54 
60 
     | 
    
         
             
                def reload
         
     | 
| 
       55 
61 
     | 
    
         
             
                  plugin_defaults = plugin_defaults_paths.map do |default_yml|
         
     | 
| 
       56 
62 
     | 
    
         
             
                    {
         
     | 
| 
         @@ -76,6 +82,7 @@ module Fusuma 
     | 
|
| 
       76 
82 
     | 
    
         
             
                # @param key [Symbol]
         
     | 
| 
       77 
83 
     | 
    
         
             
                # @param base [Config::Index]
         
     | 
| 
       78 
84 
     | 
    
         
             
                # @return [Hash]
         
     | 
| 
      
 85 
     | 
    
         
            +
                #: (Symbol?, Fusuma::Config::Index) -> (String | Hash[untyped, untyped] | Float | Integer | bool)?
         
     | 
| 
       79 
86 
     | 
    
         
             
                def fetch_config_params(key, base)
         
     | 
| 
       80 
87 
     | 
    
         
             
                  request_context = {plugin_defaults: base.keys.last.symbol.to_s}
         
     | 
| 
       81 
88 
     | 
    
         
             
                  fallbacks = [:no_context, :plugin_default_context]
         
     | 
| 
         @@ -90,15 +97,16 @@ module Fusuma 
     | 
|
| 
       90 
97 
     | 
    
         | 
| 
       91 
98 
     | 
    
         
             
                # @return [Hash] If check passes
         
     | 
| 
       92 
99 
     | 
    
         
             
                # @raise [InvalidFileError] If check does not pass
         
     | 
| 
      
 100 
     | 
    
         
            +
                #: (String) -> Array[Hash[Symbol, untyped]]
         
     | 
| 
       93 
101 
     | 
    
         
             
                def validate(path)
         
     | 
| 
       94 
102 
     | 
    
         
             
                  duplicates = []
         
     | 
| 
       95 
     | 
    
         
            -
                  YAMLDuplicationChecker.check(File.read(path), path) do |ignored, duplicate|
         
     | 
| 
      
 103 
     | 
    
         
            +
                  YAMLDuplicationChecker.check(File.read(path), path) do |ignored, duplicate| # steep:ignore UnexpectedBlockGiven
         
     | 
| 
       96 
104 
     | 
    
         
             
                    MultiLogger.error "#{path}: #{ignored.value} is duplicated"
         
     | 
| 
       97 
105 
     | 
    
         
             
                    duplicates << duplicate.value
         
     | 
| 
       98 
106 
     | 
    
         
             
                  end
         
     | 
| 
       99 
107 
     | 
    
         
             
                  raise InvalidFileError, "Detect duplicate keys #{duplicates}" unless duplicates.empty?
         
     | 
| 
       100 
108 
     | 
    
         | 
| 
       101 
     | 
    
         
            -
                  yamls = YAML.load_stream(File.read(path)).compact
         
     | 
| 
      
 109 
     | 
    
         
            +
                  yamls = YAML.load_stream(File.read(path)).compact # steep:ignore NoMethod
         
     | 
| 
       102 
110 
     | 
    
         
             
                  yamls.map do |yaml|
         
     | 
| 
       103 
111 
     | 
    
         
             
                    raise InvalidFileError, "Invalid config.yml: #{path}" unless yaml.is_a? Hash
         
     | 
| 
       104 
112 
     | 
    
         | 
| 
         @@ -109,7 +117,9 @@ module Fusuma 
     | 
|
| 
       109 
117 
     | 
    
         
             
                end
         
     | 
| 
       110 
118 
     | 
    
         | 
| 
       111 
119 
     | 
    
         
             
                # @param index [Index]
         
     | 
| 
      
 120 
     | 
    
         
            +
                #: (Fusuma::Config::Index) -> (String | Hash[untyped, untyped] | Integer | Float)?
         
     | 
| 
       112 
121 
     | 
    
         
             
                def search(index)
         
     | 
| 
      
 122 
     | 
    
         
            +
                  return nil if index.nil? || index.keys.empty?
         
     | 
| 
       113 
123 
     | 
    
         
             
                  @searcher.search_with_cache(index, location: keymap)
         
     | 
| 
       114 
124 
     | 
    
         
             
                end
         
     | 
| 
       115 
125 
     | 
    
         | 
| 
         @@ -120,7 +130,7 @@ module Fusuma 
     | 
|
| 
       120 
130 
     | 
    
         
             
                    executor.new.execute_keys
         
     | 
| 
       121 
131 
     | 
    
         
             
                  end.flatten
         
     | 
| 
       122 
132 
     | 
    
         | 
| 
       123 
     | 
    
         
            -
                  @cache_execute_keys ||= {}
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @cache_execute_keys ||= {} #: Hash[String, untyped]
         
     | 
| 
       124 
134 
     | 
    
         | 
| 
       125 
135 
     | 
    
         
             
                  cache_key = [index.cache_key, Searcher.context].join
         
     | 
| 
       126 
136 
     | 
    
         | 
| 
         @@ -135,6 +145,7 @@ module Fusuma 
     | 
|
| 
       135 
145 
     | 
    
         | 
| 
       136 
146 
     | 
    
         
             
                private
         
     | 
| 
       137 
147 
     | 
    
         | 
| 
      
 148 
     | 
    
         
            +
                #: () -> String
         
     | 
| 
       138 
149 
     | 
    
         
             
                def find_config_filepath
         
     | 
| 
       139 
150 
     | 
    
         
             
                  filename = "fusuma/config.yml"
         
     | 
| 
       140 
151 
     | 
    
         
             
                  if custom_path
         
     | 
| 
         @@ -149,10 +160,12 @@ module Fusuma 
     | 
|
| 
       149 
160 
     | 
    
         
             
                  end
         
     | 
| 
       150 
161 
     | 
    
         
             
                end
         
     | 
| 
       151 
162 
     | 
    
         | 
| 
      
 163 
     | 
    
         
            +
                #: () -> String
         
     | 
| 
       152 
164 
     | 
    
         
             
                def expand_custom_path
         
     | 
| 
       153 
165 
     | 
    
         
             
                  File.expand_path(custom_path)
         
     | 
| 
       154 
166 
     | 
    
         
             
                end
         
     | 
| 
       155 
167 
     | 
    
         | 
| 
      
 168 
     | 
    
         
            +
                #: (String) -> String
         
     | 
| 
       156 
169 
     | 
    
         
             
                def expand_config_path(filename)
         
     | 
| 
       157 
170 
     | 
    
         
             
                  File.expand_path "~/.config/#{filename}"
         
     | 
| 
       158 
171 
     | 
    
         
             
                end
         
     | 
| 
         @@ -161,6 +174,7 @@ module Fusuma 
     | 
|
| 
       161 
174 
     | 
    
         
             
                  File.expand_path "../../#{filename}", __FILE__
         
     | 
| 
       162 
175 
     | 
    
         
             
                end
         
     | 
| 
       163 
176 
     | 
    
         | 
| 
      
 177 
     | 
    
         
            +
                #: () -> Array[untyped]
         
     | 
| 
       164 
178 
     | 
    
         
             
                def plugin_defaults_paths
         
     | 
| 
       165 
179 
     | 
    
         
             
                  Plugin::Manager.load_paths.map do |plugin_path|
         
     | 
| 
       166 
180 
     | 
    
         
             
                    yml = plugin_path.gsub(/\.rb$/, ".yml")
         
     | 
| 
         @@ -7,10 +7,12 @@ module Fusuma 
     | 
|
| 
       7 
7 
     | 
    
         
             
              module CustomProcess
         
     | 
| 
       8 
8 
     | 
    
         
             
                attr_writer :proctitle
         
     | 
| 
       9 
9 
     | 
    
         | 
| 
      
 10 
     | 
    
         
            +
                #: () -> Array[untyped]
         
     | 
| 
       10 
11 
     | 
    
         
             
                def child_pids
         
     | 
| 
       11 
12 
     | 
    
         
             
                  @child_pids ||= []
         
     | 
| 
       12 
13 
     | 
    
         
             
                end
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
                #: () { () -> void } -> nil
         
     | 
| 
       14 
16 
     | 
    
         
             
                def fork
         
     | 
| 
       15 
17 
     | 
    
         
             
                  pid = Process.fork do
         
     | 
| 
       16 
18 
     | 
    
         
             
                    Process.setproctitle(proctitle)
         
     | 
| 
         @@ -35,6 +37,7 @@ module Fusuma 
     | 
|
| 
       35 
37 
     | 
    
         
             
                  end
         
     | 
| 
       36 
38 
     | 
    
         
             
                end
         
     | 
| 
       37 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
                #: () -> String
         
     | 
| 
       38 
41 
     | 
    
         
             
                def proctitle
         
     | 
| 
       39 
42 
     | 
    
         
             
                  @proctitle ||= self.class.name.underscore
         
     | 
| 
       40 
43 
     | 
    
         
             
                end
         
     | 
    
        data/lib/fusuma/device.rb
    CHANGED
    
    | 
         @@ -8,6 +8,7 @@ module Fusuma 
     | 
|
| 
       8 
8 
     | 
    
         
             
              class Device
         
     | 
| 
       9 
9 
     | 
    
         
             
                attr_reader :id, :name, :capabilities, :available
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
                #: (?id: nil | String, ?name: nil | String, ?capabilities: nil, ?available: nil | bool) -> void
         
     | 
| 
       11 
12 
     | 
    
         
             
                def initialize(id: nil, name: nil, capabilities: nil, available: nil)
         
     | 
| 
       12 
13 
     | 
    
         
             
                  @id = id
         
     | 
| 
       13 
14 
     | 
    
         
             
                  @name = name
         
     | 
| 
         @@ -16,6 +17,7 @@ module Fusuma 
     | 
|
| 
       16 
17 
     | 
    
         
             
                end
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
19 
     | 
    
         
             
                # @param attributes [Hash]
         
     | 
| 
      
 20 
     | 
    
         
            +
                #: (Hash[untyped, untyped]) -> Hash[untyped, untyped]
         
     | 
| 
       19 
21 
     | 
    
         
             
                def assign_attributes(attributes)
         
     | 
| 
       20 
22 
     | 
    
         
             
                  attributes.each do |k, v|
         
     | 
| 
       21 
23 
     | 
    
         
             
                    case k
         
     | 
| 
         @@ -35,6 +37,7 @@ module Fusuma 
     | 
|
| 
       35 
37 
     | 
    
         
             
                  # Return devices
         
     | 
| 
       36 
38 
     | 
    
         
             
                  # sort devices by capabilities of gesture
         
     | 
| 
       37 
39 
     | 
    
         
             
                  # @return [Array]
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #: () -> Array[Device]
         
     | 
| 
       38 
41 
     | 
    
         
             
                  def all
         
     | 
| 
       39 
42 
     | 
    
         
             
                    @all ||= fetch_devices.partition do |d|
         
     | 
| 
       40 
43 
     | 
    
         
             
                      d.capabilities.match?(/gesture/)
         
     | 
| 
         @@ -43,6 +46,7 @@ module Fusuma 
     | 
|
| 
       43 
46 
     | 
    
         | 
| 
       44 
47 
     | 
    
         
             
                  # @raise [SystemExit]
         
     | 
| 
       45 
48 
     | 
    
         
             
                  # @return [Array]
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #: () -> Array[Device]
         
     | 
| 
       46 
50 
     | 
    
         
             
                  def available
         
     | 
| 
       47 
51 
     | 
    
         
             
                    @available ||= all.select(&:available).tap do |d|
         
     | 
| 
       48 
52 
     | 
    
         
             
                      MultiLogger.debug(available_devices: d)
         
     | 
| 
         @@ -54,6 +58,7 @@ module Fusuma 
     | 
|
| 
       54 
58 
     | 
    
         
             
                    exit 1
         
     | 
| 
       55 
59 
     | 
    
         
             
                  end
         
     | 
| 
       56 
60 
     | 
    
         | 
| 
      
 61 
     | 
    
         
            +
                  #: () -> nil
         
     | 
| 
       57 
62 
     | 
    
         
             
                  def reset
         
     | 
| 
       58 
63 
     | 
    
         
             
                    @all = nil
         
     | 
| 
       59 
64 
     | 
    
         
             
                    @available = nil
         
     | 
| 
         @@ -62,6 +67,7 @@ module Fusuma 
     | 
|
| 
       62 
67 
     | 
    
         
             
                  private
         
     | 
| 
       63 
68 
     | 
    
         | 
| 
       64 
69 
     | 
    
         
             
                  # @return [Array]
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #: () -> Array[Device]
         
     | 
| 
       65 
71 
     | 
    
         
             
                  def fetch_devices
         
     | 
| 
       66 
72 
     | 
    
         
             
                    line_parser = LineParser.new
         
     | 
| 
       67 
73 
     | 
    
         | 
| 
         @@ -72,6 +78,7 @@ module Fusuma 
     | 
|
| 
       72 
78 
     | 
    
         
             
                    line_parser.generate_devices
         
     | 
| 
       73 
79 
     | 
    
         
             
                  end
         
     | 
| 
       74 
80 
     | 
    
         | 
| 
      
 81 
     | 
    
         
            +
                  #: () -> Fusuma::LibinputCommand
         
     | 
| 
       75 
82 
     | 
    
         
             
                  def libinput_command
         
     | 
| 
       76 
83 
     | 
    
         
             
                    @libinput_command ||= Plugin::Inputs::LibinputCommandInput.new.command
         
     | 
| 
       77 
84 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -81,16 +88,19 @@ module Fusuma 
     | 
|
| 
       81 
88 
     | 
    
         
             
                class LineParser
         
     | 
| 
       82 
89 
     | 
    
         
             
                  attr_reader :lines
         
     | 
| 
       83 
90 
     | 
    
         | 
| 
      
 91 
     | 
    
         
            +
                  #: () -> void
         
     | 
| 
       84 
92 
     | 
    
         
             
                  def initialize
         
     | 
| 
       85 
93 
     | 
    
         
             
                    @lines = []
         
     | 
| 
       86 
94 
     | 
    
         
             
                  end
         
     | 
| 
       87 
95 
     | 
    
         | 
| 
       88 
96 
     | 
    
         
             
                  # @param line [String]
         
     | 
| 
      
 97 
     | 
    
         
            +
                  #: (String) -> Array[untyped]
         
     | 
| 
       89 
98 
     | 
    
         
             
                  def push(line)
         
     | 
| 
       90 
99 
     | 
    
         
             
                    lines.push(line)
         
     | 
| 
       91 
100 
     | 
    
         
             
                  end
         
     | 
| 
       92 
101 
     | 
    
         | 
| 
       93 
102 
     | 
    
         
             
                  # @return [Array]
         
     | 
| 
      
 103 
     | 
    
         
            +
                  #: () -> Array[Device]
         
     | 
| 
       94 
104 
     | 
    
         
             
                  def generate_devices
         
     | 
| 
       95 
105 
     | 
    
         
             
                    lines.each_with_object([]) do |line, devices|
         
     | 
| 
       96 
106 
     | 
    
         
             
                      attributes = extract_attribute(line: line)
         
     | 
| 
         @@ -108,6 +118,7 @@ module Fusuma 
     | 
|
| 
       108 
118 
     | 
    
         | 
| 
       109 
119 
     | 
    
         
             
                  # @param line [String]
         
     | 
| 
       110 
120 
     | 
    
         
             
                  # @return [Hash]
         
     | 
| 
      
 121 
     | 
    
         
            +
                  #: (line: String) -> Hash[untyped, untyped]
         
     | 
| 
       111 
122 
     | 
    
         
             
                  def extract_attribute(line:)
         
     | 
| 
       112 
123 
     | 
    
         
             
                    if (id = id_from(line))
         
     | 
| 
       113 
124 
     | 
    
         
             
                      {id: id}
         
     | 
| 
         @@ -122,24 +133,28 @@ module Fusuma 
     | 
|
| 
       122 
133 
     | 
    
         
             
                    end
         
     | 
| 
       123 
134 
     | 
    
         
             
                  end
         
     | 
| 
       124 
135 
     | 
    
         | 
| 
      
 136 
     | 
    
         
            +
                  #: (String) -> String?
         
     | 
| 
       125 
137 
     | 
    
         
             
                  def id_from(line)
         
     | 
| 
       126 
138 
     | 
    
         
             
                    line.match("^Kernel:[[:space:]]*") do |m|
         
     | 
| 
       127 
139 
     | 
    
         
             
                      m.post_match.match(/event[0-9]+/).to_s
         
     | 
| 
       128 
140 
     | 
    
         
             
                    end
         
     | 
| 
       129 
141 
     | 
    
         
             
                  end
         
     | 
| 
       130 
142 
     | 
    
         | 
| 
      
 143 
     | 
    
         
            +
                  #: (String) -> String?
         
     | 
| 
       131 
144 
     | 
    
         
             
                  def name_from(line)
         
     | 
| 
       132 
145 
     | 
    
         
             
                    line.match("^Device:[[:space:]]*") do |m|
         
     | 
| 
       133 
146 
     | 
    
         
             
                      m.post_match.strip
         
     | 
| 
       134 
147 
     | 
    
         
             
                    end
         
     | 
| 
       135 
148 
     | 
    
         
             
                  end
         
     | 
| 
       136 
149 
     | 
    
         | 
| 
      
 150 
     | 
    
         
            +
                  #: (String) -> String?
         
     | 
| 
       137 
151 
     | 
    
         
             
                  def capabilities_from(line)
         
     | 
| 
       138 
152 
     | 
    
         
             
                    line.match("^Capabilities:[[:space:]]*") do |m|
         
     | 
| 
       139 
153 
     | 
    
         
             
                      m.post_match.strip
         
     | 
| 
       140 
154 
     | 
    
         
             
                    end
         
     | 
| 
       141 
155 
     | 
    
         
             
                  end
         
     | 
| 
       142 
156 
     | 
    
         | 
| 
      
 157 
     | 
    
         
            +
                  #: (String) -> bool?
         
     | 
| 
       143 
158 
     | 
    
         
             
                  def available_from(line)
         
     | 
| 
       144 
159 
     | 
    
         
             
                    # NOTE: is natural scroll available?
         
     | 
| 
       145 
160 
     | 
    
         
             
                    if /^Nat.scrolling: /.match?(line)
         
     | 
    
        data/lib/fusuma/environment.rb
    CHANGED
    
    | 
         @@ -8,6 +8,7 @@ module Fusuma 
     | 
|
| 
       8 
8 
     | 
    
         
             
              # Output Environment information
         
     | 
| 
       9 
9 
     | 
    
         
             
              class Environment
         
     | 
| 
       10 
10 
     | 
    
         
             
                class << self
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #: () -> void
         
     | 
| 
       11 
12 
     | 
    
         
             
                  def dump_information
         
     | 
| 
       12 
13 
     | 
    
         
             
                    MultiLogger.info "---------------------------------------------"
         
     | 
| 
       13 
14 
     | 
    
         
             
                    print_version
         
     | 
| 
         @@ -16,6 +17,7 @@ module Fusuma 
     | 
|
| 
       16 
17 
     | 
    
         
             
                    MultiLogger.info "---------------------------------------------"
         
     | 
| 
       17 
18 
     | 
    
         
             
                  end
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
      
 20 
     | 
    
         
            +
                  #: () -> void
         
     | 
| 
       19 
21 
     | 
    
         
             
                  def print_version
         
     | 
| 
       20 
22 
     | 
    
         
             
                    libinput_command = Plugin::Inputs::LibinputCommandInput.new.command
         
     | 
| 
       21 
23 
     | 
    
         
             
                    MultiLogger.info "Fusuma: #{VERSION}"
         
     | 
| 
         @@ -26,6 +28,7 @@ module Fusuma 
     | 
|
| 
       26 
28 
     | 
    
         
             
                    MultiLogger.info "Desktop session: #{`echo $DESKTOP_SESSION $XDG_SESSION_TYPE`}".strip
         
     | 
| 
       27 
29 
     | 
    
         
             
                  end
         
     | 
| 
       28 
30 
     | 
    
         | 
| 
      
 31 
     | 
    
         
            +
                  #: () -> void
         
     | 
| 
       29 
32 
     | 
    
         
             
                  def print_enabled_plugins
         
     | 
| 
       30 
33 
     | 
    
         
             
                    MultiLogger.info "Enabled Plugins: "
         
     | 
| 
       31 
34 
     | 
    
         
             
                    Plugin::Manager.plugins
         
     | 
| 
         @@ -34,6 +37,7 @@ module Fusuma 
     | 
|
| 
       34 
37 
     | 
    
         
             
                      .flatten.sort.each { |name| MultiLogger.info(name) }
         
     | 
| 
       35 
38 
     | 
    
         
             
                  end
         
     | 
| 
       36 
39 
     | 
    
         | 
| 
      
 40 
     | 
    
         
            +
                  #: () -> void
         
     | 
| 
       37 
41 
     | 
    
         
             
                  def print_device_list
         
     | 
| 
       38 
42 
     | 
    
         
             
                    Plugin::Filters::LibinputDeviceFilter.new.keep_device.all.map do |device|
         
     | 
| 
       39 
43 
     | 
    
         
             
                      puts device.name
         
     | 
    
        data/lib/fusuma/hash_support.rb
    CHANGED
    
    | 
         @@ -1,6 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            #  
     | 
| 
      
 3 
     | 
    
         
            +
            # @rbs generic unchecked out K
         
     | 
| 
      
 4 
     | 
    
         
            +
            # @rbs generic unchecked out V
         
     | 
| 
       4 
5 
     | 
    
         
             
            class Hash
         
     | 
| 
       5 
6 
     | 
    
         
             
              # activesupport-5.2.0/lib/active_support/core_ext/hash/deep_merge.rb
         
     | 
| 
       6 
7 
     | 
    
         
             
              def deep_merge(other_hash, &block)
         
     | 
| 
         @@ -25,6 +26,7 @@ class Hash 
     | 
|
| 
       25 
26 
     | 
    
         
             
              end
         
     | 
| 
       26 
27 
     | 
    
         | 
| 
       27 
28 
     | 
    
         
             
              # activesupport-4.1.1/lib/active_support/core_ext/hash/keys.rb
         
     | 
| 
      
 29 
     | 
    
         
            +
              #: () -> Hash[Symbol, untyped]
         
     | 
| 
       28 
30 
     | 
    
         
             
              def deep_symbolize_keys
         
     | 
| 
       29 
31 
     | 
    
         
             
                deep_transform_keys do |key|
         
     | 
| 
       30 
32 
     | 
    
         
             
                  key.to_sym
         
     | 
| 
         @@ -33,6 +35,7 @@ class Hash 
     | 
|
| 
       33 
35 
     | 
    
         
             
                end
         
     | 
| 
       34 
36 
     | 
    
         
             
              end
         
     | 
| 
       35 
37 
     | 
    
         | 
| 
      
 38 
     | 
    
         
            +
              #: [T] () { (untyped) -> T } -> Hash[T, untyped]
         
     | 
| 
       36 
39 
     | 
    
         
             
              def deep_transform_keys(&block)
         
     | 
| 
       37 
40 
     | 
    
         
             
                result = {}
         
     | 
| 
       38 
41 
     | 
    
         
             
                each do |key, value|
         
     | 
| 
         @@ -42,6 +45,7 @@ class Hash 
     | 
|
| 
       42 
45 
     | 
    
         
             
              end
         
     | 
| 
       43 
46 
     | 
    
         | 
| 
       44 
47 
     | 
    
         
             
              # activesupport/lib/active_support/core_ext/hash/deep_transform_values.rb
         
     | 
| 
      
 48 
     | 
    
         
            +
              #: () { (untyped) -> untyped } -> Hash[untyped, untyped]
         
     | 
| 
       45 
49 
     | 
    
         
             
              def deep_transform_values(&block)
         
     | 
| 
       46 
50 
     | 
    
         
             
                _deep_transform_values_in_object(self, &block)
         
     | 
| 
       47 
51 
     | 
    
         
             
              end
         
     | 
| 
         @@ -49,6 +53,7 @@ class Hash 
     | 
|
| 
       49 
53 
     | 
    
         
             
              private
         
     | 
| 
       50 
54 
     | 
    
         | 
| 
       51 
55 
     | 
    
         
             
              # Support methods for deep transforming nested hashes and arrays.
         
     | 
| 
      
 56 
     | 
    
         
            +
              #: (Hash[untyped, untyped]) { (untyped) -> untyped } -> Hash[untyped, untyped]
         
     | 
| 
       52 
57 
     | 
    
         
             
              def _deep_transform_values_in_object(object, &block)
         
     | 
| 
       53 
58 
     | 
    
         
             
                case object
         
     | 
| 
       54 
59 
     | 
    
         
             
                when Hash
         
     | 
| 
         @@ -5,6 +5,7 @@ require "open3" 
     | 
|
| 
       5 
5 
     | 
    
         
             
            module Fusuma
         
     | 
| 
       6 
6 
     | 
    
         
             
              # Execute libinput command
         
     | 
| 
       7 
7 
     | 
    
         
             
              class LibinputCommand
         
     | 
| 
      
 8 
     | 
    
         
            +
                #: (?libinput_options: Array[String], ?commands: Hash[untyped, untyped]) -> void
         
     | 
| 
       8 
9 
     | 
    
         
             
                def initialize(libinput_options: [], commands: {})
         
     | 
| 
       9 
10 
     | 
    
         
             
                  @libinput_command = commands[:libinput_command]
         
     | 
| 
       10 
11 
     | 
    
         
             
                  @debug_events_command = commands[:debug_events_command]
         
     | 
| 
         @@ -17,6 +18,7 @@ module Fusuma 
     | 
|
| 
       17 
18 
     | 
    
         
             
                NEW_CLI_OPTION_VERSION = "1.8"
         
     | 
| 
       18 
19 
     | 
    
         | 
| 
       19 
20 
     | 
    
         
             
                # @return [Boolean]
         
     | 
| 
      
 21 
     | 
    
         
            +
                #: () -> bool
         
     | 
| 
       20 
22 
     | 
    
         
             
                def new_cli_option_available?
         
     | 
| 
       21 
23 
     | 
    
         
             
                  Gem::Version.new(version) >= Gem::Version.new(NEW_CLI_OPTION_VERSION)
         
     | 
| 
       22 
24 
     | 
    
         
             
                end
         
     | 
| 
         @@ -27,32 +29,35 @@ module Fusuma 
     | 
|
| 
       27 
29 
     | 
    
         
             
                end
         
     | 
| 
       28 
30 
     | 
    
         | 
| 
       29 
31 
     | 
    
         
             
                # @return [String]
         
     | 
| 
      
 32 
     | 
    
         
            +
                #: () -> String?
         
     | 
| 
       30 
33 
     | 
    
         
             
                def version
         
     | 
| 
       31 
34 
     | 
    
         
             
                  # version_command prints "1.6.3\n"
         
     | 
| 
       32 
35 
     | 
    
         
             
                  @version ||= `#{version_command}`.strip
         
     | 
| 
       33 
36 
     | 
    
         
             
                end
         
     | 
| 
       34 
37 
     | 
    
         | 
| 
       35 
38 
     | 
    
         
             
                # @yieldparam [String] gives a line in libinput list-devices output to the block
         
     | 
| 
      
 39 
     | 
    
         
            +
                #: () { (String) -> void } -> void
         
     | 
| 
       36 
40 
     | 
    
         
             
                def list_devices(&block)
         
     | 
| 
       37 
41 
     | 
    
         
             
                  cmd = list_devices_command
         
     | 
| 
       38 
42 
     | 
    
         
             
                  MultiLogger.debug(list_devices: cmd)
         
     | 
| 
       39 
     | 
    
         
            -
                  o,  
     | 
| 
      
 43 
     | 
    
         
            +
                  o, _, s = Open3.capture3(cmd)
         
     | 
| 
       40 
44 
     | 
    
         | 
| 
       41 
45 
     | 
    
         
             
                  unless s.success?
         
     | 
| 
       42 
     | 
    
         
            -
                     
     | 
| 
       43 
     | 
    
         
            -
                    return
         
     | 
| 
      
 46 
     | 
    
         
            +
                    raise "libinput list-devices failed with output: #{o}"
         
     | 
| 
       44 
47 
     | 
    
         
             
                  end
         
     | 
| 
       45 
48 
     | 
    
         | 
| 
       46 
49 
     | 
    
         
             
                  o.each_line(&block)
         
     | 
| 
       47 
50 
     | 
    
         
             
                end
         
     | 
| 
       48 
51 
     | 
    
         | 
| 
       49 
52 
     | 
    
         
             
                # @return [Integer] return a latest line libinput debug-events
         
     | 
| 
      
 53 
     | 
    
         
            +
                #: (StringIO) -> Array[untyped]
         
     | 
| 
       50 
54 
     | 
    
         
             
                def debug_events(writer)
         
     | 
| 
       51 
55 
     | 
    
         
             
                  Open3.pipeline_start([debug_events_with_options], ["grep -v POINTER_ --line-buffered"], out: writer, in: "/dev/null")
         
     | 
| 
       52 
56 
     | 
    
         
             
                end
         
     | 
| 
       53 
57 
     | 
    
         | 
| 
       54 
58 
     | 
    
         
             
                # @return [String] command
         
     | 
| 
       55 
59 
     | 
    
         
             
                # @raise [SystemExit]
         
     | 
| 
      
 60 
     | 
    
         
            +
                #: () -> String?
         
     | 
| 
       56 
61 
     | 
    
         
             
                def version_command
         
     | 
| 
       57 
62 
     | 
    
         
             
                  if @libinput_command
         
     | 
| 
       58 
63 
     | 
    
         
             
                    "#{@libinput_command} --version"
         
     | 
| 
         @@ -68,6 +73,7 @@ module Fusuma 
     | 
|
| 
       68 
73 
     | 
    
         
             
                  end
         
     | 
| 
       69 
74 
     | 
    
         
             
                end
         
     | 
| 
       70 
75 
     | 
    
         | 
| 
      
 76 
     | 
    
         
            +
                #: () -> String
         
     | 
| 
       71 
77 
     | 
    
         
             
                def list_devices_command
         
     | 
| 
       72 
78 
     | 
    
         
             
                  if @libinput_command
         
     | 
| 
       73 
79 
     | 
    
         
             
                    @libinput_command + " list-devices"
         
     | 
| 
         @@ -80,6 +86,7 @@ module Fusuma 
     | 
|
| 
       80 
86 
     | 
    
         
             
                  end
         
     | 
| 
       81 
87 
     | 
    
         
             
                end
         
     | 
| 
       82 
88 
     | 
    
         | 
| 
      
 89 
     | 
    
         
            +
                #: () -> String
         
     | 
| 
       83 
90 
     | 
    
         
             
                def debug_events_command
         
     | 
| 
       84 
91 
     | 
    
         
             
                  if @libinput_command
         
     | 
| 
       85 
92 
     | 
    
         
             
                    @libinput_command + " debug-events"
         
     | 
| 
         @@ -92,6 +99,7 @@ module Fusuma 
     | 
|
| 
       92 
99 
     | 
    
         
             
                  end
         
     | 
| 
       93 
100 
     | 
    
         
             
                end
         
     | 
| 
       94 
101 
     | 
    
         | 
| 
      
 102 
     | 
    
         
            +
                #: () -> String
         
     | 
| 
       95 
103 
     | 
    
         
             
                def debug_events_with_options
         
     | 
| 
       96 
104 
     | 
    
         
             
                  prefix = "stdbuf -oL --"
         
     | 
| 
       97 
105 
     | 
    
         
             
                  "#{prefix} #{debug_events_command} #{@libinput_options.join(" ")}".strip
         
     |