procon_bypass_man 0.1.5 → 0.1.9
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/.circleci/config.yml +41 -13
 - data/.github/workflows/ruby.yml +34 -0
 - data/.rubocop.yml +24 -0
 - data/.ruby-version +1 -1
 - data/CHANGELOG.md +15 -0
 - data/Gemfile +5 -0
 - data/Gemfile.lock +75 -3
 - data/README.md +22 -8
 - data/Rakefile +10 -1
 - data/Steepfile +39 -0
 - data/bin/report_receive_server.rb +11 -0
 - data/docs/setup_raspi.md +12 -7
 - data/docs/setup_raspi.mitamae.rb +60 -0
 - data/docs/setup_raspi_by_mitamae.md +14 -0
 - data/examples/practical/app.rb +2 -2
 - data/lib/procon_bypass_man/analog_stick_position.rb +14 -0
 - data/lib/procon_bypass_man/boot_message.rb +40 -0
 - data/lib/procon_bypass_man/bypass.rb +20 -7
 - data/lib/procon_bypass_man/configuration/layer.rb +33 -3
 - data/lib/procon_bypass_man/configuration/loader.rb +17 -16
 - data/lib/procon_bypass_man/configuration/validator.rb +20 -19
 - data/lib/procon_bypass_man/configuration.rb +24 -12
 - data/lib/procon_bypass_man/device_connector.rb +14 -31
 - data/lib/procon_bypass_man/error_reporter.rb +44 -0
 - data/lib/procon_bypass_man/io_monitor.rb +7 -4
 - data/lib/procon_bypass_man/on_memory_cache.rb +34 -0
 - data/lib/procon_bypass_man/procon/analog_stick_cap.rb +88 -0
 - data/lib/procon_bypass_man/procon/button_collection.rb +14 -6
 - data/lib/procon_bypass_man/procon/debug_dumper.rb +17 -0
 - data/lib/procon_bypass_man/procon/mode_registry.rb +2 -2
 - data/lib/procon_bypass_man/procon/press_button_aware.rb +13 -0
 - data/lib/procon_bypass_man/procon/pressed_button_helper.rb +1 -11
 - data/lib/procon_bypass_man/procon/user_operation.rb +10 -3
 - data/lib/procon_bypass_man/procon.rb +15 -1
 - data/lib/procon_bypass_man/reporter.rb +42 -0
 - data/lib/procon_bypass_man/runner.rb +39 -50
 - data/lib/procon_bypass_man/uptime.rb +13 -0
 - data/lib/procon_bypass_man/version.rb +1 -1
 - data/lib/procon_bypass_man.rb +53 -2
 - data/procon_bypass_man.gemspec +1 -1
 - data/project_template/README.md +17 -0
 - data/project_template/app.rb +20 -0
 - data/project_template/setting.yml +35 -0
 - data/project_template/systemd_units/pbm.service +13 -0
 - data/sig/README.rb +4 -0
 - data/sig/main.rbs +467 -0
 - metadata +27 -8
 - data/examples/pbm.service +0 -27
 - data/examples/simple.rb +0 -13
 
| 
         @@ -1,13 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module ProconBypassMan
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Configuration
         
     | 
| 
       3 
3 
     | 
    
         
             
                class Layer
         
     | 
| 
       4 
     | 
    
         
            -
                  attr_accessor :mode, :flips, :macros, :remaps
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :mode, :flips, :macros, :remaps, :left_analog_stick_caps
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
                  def initialize(mode: :manual 
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(mode: :manual)
         
     | 
| 
       7 
7 
     | 
    
         
             
                    self.mode = mode
         
     | 
| 
       8 
8 
     | 
    
         
             
                    self.flips = {}
         
     | 
| 
       9 
9 
     | 
    
         
             
                    self.macros = {}
         
     | 
| 
       10 
10 
     | 
    
         
             
                    self.remaps = {}
         
     | 
| 
      
 11 
     | 
    
         
            +
                    self.left_analog_stick_caps = {}
         
     | 
| 
       11 
12 
     | 
    
         
             
                    instance_eval(&block) if block_given?
         
     | 
| 
       12 
13 
     | 
    
         
             
                  end
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
         @@ -50,7 +51,6 @@ module ProconBypassMan 
     | 
|
| 
       50 
51 
     | 
    
         
             
                    end
         
     | 
| 
       51 
52 
     | 
    
         
             
                  end
         
     | 
| 
       52 
53 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                  PRESET_MACROS = [:fast_return]
         
     | 
| 
       54 
54 
     | 
    
         
             
                  def macro(name, if_pressed: )
         
     | 
| 
       55 
55 
     | 
    
         
             
                    if name.respond_to?(:name)
         
     | 
| 
       56 
56 
     | 
    
         
             
                      macro_name = name.name.to_sym
         
     | 
| 
         @@ -72,6 +72,36 @@ module ProconBypassMan 
     | 
|
| 
       72 
72 
     | 
    
         
             
                    end
         
     | 
| 
       73 
73 
     | 
    
         
             
                  end
         
     | 
| 
       74 
74 
     | 
    
         | 
| 
      
 75 
     | 
    
         
            +
                  def left_analog_stick_cap(cap: , if_pressed: nil, force_neutral: nil)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    hash = { cap: cap }
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    case if_pressed
         
     | 
| 
      
 79 
     | 
    
         
            +
                    when TrueClass
         
     | 
| 
      
 80 
     | 
    
         
            +
                      raise "not support class"
         
     | 
| 
      
 81 
     | 
    
         
            +
                    when Symbol, String
         
     | 
| 
      
 82 
     | 
    
         
            +
                      if_pressed = [if_pressed]
         
     | 
| 
      
 83 
     | 
    
         
            +
                    when Array, FalseClass
         
     | 
| 
      
 84 
     | 
    
         
            +
                      # sono mama
         
     | 
| 
      
 85 
     | 
    
         
            +
                    when NilClass
         
     | 
| 
      
 86 
     | 
    
         
            +
                      if_pressed = nil
         
     | 
| 
      
 87 
     | 
    
         
            +
                    else
         
     | 
| 
      
 88 
     | 
    
         
            +
                      raise "not support if_pressed"
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    if force_neutral
         
     | 
| 
      
 92 
     | 
    
         
            +
                      case force_neutral
         
     | 
| 
      
 93 
     | 
    
         
            +
                      when TrueClass, FalseClass
         
     | 
| 
      
 94 
     | 
    
         
            +
                        raise "ボタンを渡してください"
         
     | 
| 
      
 95 
     | 
    
         
            +
                      when Symbol, String
         
     | 
| 
      
 96 
     | 
    
         
            +
                        hash[:force_neutral] = [force_neutral]
         
     | 
| 
      
 97 
     | 
    
         
            +
                      when Array
         
     | 
| 
      
 98 
     | 
    
         
            +
                        hash[:force_neutral] = force_neutral
         
     | 
| 
      
 99 
     | 
    
         
            +
                      end
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    left_analog_stick_caps[if_pressed] = hash
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
       75 
105 
     | 
    
         
             
                  # @return [Array]
         
     | 
| 
       76 
106 
     | 
    
         
             
                  def flip_buttons
         
     | 
| 
       77 
107 
     | 
    
         
             
                    flips
         
     | 
| 
         @@ -1,24 +1,22 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module ProconBypassMan
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Configuration
         
     | 
| 
       3 
3 
     | 
    
         
             
                module Loader
         
     | 
| 
      
 4 
     | 
    
         
            +
                  require 'digest/md5'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
       4 
6 
     | 
    
         
             
                  def self.load(setting_path: )
         
     | 
| 
       5 
     | 
    
         
            -
                     
     | 
| 
       6 
     | 
    
         
            -
                       
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
                       
     | 
| 
       10 
     | 
    
         
            -
                         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
             
     | 
| 
       13 
     | 
    
         
            -
                        instance.errors[:base] << "yamlのシンタックスエラーです"
         
     | 
| 
       14 
     | 
    
         
            -
                        next(instance)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    ProconBypassMan::Configuration.switch_new_context(:validation) do |validation_instance|
         
     | 
| 
      
 8 
     | 
    
         
            +
                      yaml = YAML.load_file(setting_path) or raise "読み込みに失敗しました"
         
     | 
| 
      
 9 
     | 
    
         
            +
                      validation_instance.instance_eval(yaml["setting"])
         
     | 
| 
      
 10 
     | 
    
         
            +
                      validator = Validator.new(validation_instance)
         
     | 
| 
      
 11 
     | 
    
         
            +
                      if validator.valid?
         
     | 
| 
      
 12 
     | 
    
         
            +
                        next
         
     | 
| 
      
 13 
     | 
    
         
            +
                      else
         
     | 
| 
      
 14 
     | 
    
         
            +
                        raise ProconBypassMan::CouldNotLoadConfigError, validator.errors
         
     | 
| 
       15 
15 
     | 
    
         
             
                      end
         
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
                       
     | 
| 
       18 
     | 
    
         
            -
                     
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                    if !validation_instance.errors.empty?
         
     | 
| 
       21 
     | 
    
         
            -
                      raise ProconBypassMan::CouldNotLoadConfigError, validation_instance.errors
         
     | 
| 
      
 16 
     | 
    
         
            +
                    rescue SyntaxError
         
     | 
| 
      
 17 
     | 
    
         
            +
                      raise ProconBypassMan::CouldNotLoadConfigError, "Rubyのシンタックスエラーです"
         
     | 
| 
      
 18 
     | 
    
         
            +
                    rescue Psych::SyntaxError
         
     | 
| 
      
 19 
     | 
    
         
            +
                      raise ProconBypassMan::CouldNotLoadConfigError, "yamlのシンタックスエラーです"
         
     | 
| 
       22 
20 
     | 
    
         
             
                    end
         
     | 
| 
       23 
21 
     | 
    
         | 
| 
       24 
22 
     | 
    
         
             
                    yaml = YAML.load_file(setting_path)
         
     | 
| 
         @@ -33,6 +31,9 @@ module ProconBypassMan 
     | 
|
| 
       33 
31 
     | 
    
         
             
                      ProconBypassMan.logger.warn "不明なバージョンです。failoverします"
         
     | 
| 
       34 
32 
     | 
    
         
             
                      ProconBypassMan::Configuration.instance.instance_eval(yaml["setting"])
         
     | 
| 
       35 
33 
     | 
    
         
             
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    File.write(ProconBypassMan.digest_path, Digest::MD5.hexdigest(yaml["setting"]))
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
       36 
37 
     | 
    
         
             
                    ProconBypassMan::Configuration.instance
         
     | 
| 
       37 
38 
     | 
    
         
             
                  end
         
     | 
| 
       38 
39 
     | 
    
         | 
| 
         @@ -1,6 +1,11 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module ProconBypassMan
         
     | 
| 
       2 
2 
     | 
    
         
             
              class Configuration
         
     | 
| 
       3 
     | 
    
         
            -
                 
     | 
| 
      
 3 
     | 
    
         
            +
                class Validator
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize(config)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    @layers = config.layers
         
     | 
| 
      
 6 
     | 
    
         
            +
                    @prefix_keys = config.prefix_keys
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
       4 
9 
     | 
    
         
             
                  # @return [Boolean]
         
     | 
| 
       5 
10 
     | 
    
         
             
                  def valid?
         
     | 
| 
       6 
11 
     | 
    
         
             
                    @errors = Hash.new {|h,k| h[k] = [] }
         
     | 
| 
         @@ -38,7 +43,7 @@ module ProconBypassMan 
     | 
|
| 
       38 
43 
     | 
    
         
             
                  end
         
     | 
| 
       39 
44 
     | 
    
         | 
| 
       40 
45 
     | 
    
         
             
                  def validate_require_prefix_keys
         
     | 
| 
       41 
     | 
    
         
            -
                    if prefix_keys.empty?
         
     | 
| 
      
 46 
     | 
    
         
            +
                    if @prefix_keys.empty?
         
     | 
| 
       42 
47 
     | 
    
         
             
                      @errors[:prefix_keys] ||= []
         
     | 
| 
       43 
48 
     | 
    
         
             
                      @errors[:prefix_keys] << "prefix_keys_for_changing_layerに値が入っていません。"
         
     | 
| 
       44 
49 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -48,24 +53,20 @@ module ProconBypassMan 
     | 
|
| 
       48 
53 
     | 
    
         
             
                    @layers.each do |layer_key, value|
         
     | 
| 
       49 
54 
     | 
    
         
             
                      unverified_buttons = []
         
     | 
| 
       50 
55 
     | 
    
         
             
                      # teplevel target button
         
     | 
| 
       51 
     | 
    
         
            -
                      value. 
     | 
| 
       52 
     | 
    
         
            -
                      value. 
     | 
| 
      
 56 
     | 
    
         
            +
                      value.flips.keys.map(&:to_sym).each { |b| unverified_buttons << b }
         
     | 
| 
      
 57 
     | 
    
         
            +
                      value.remaps.keys.map(&:to_sym).each { |b| unverified_buttons << b }
         
     | 
| 
       53 
58 
     | 
    
         
             
                      # internal target button
         
     | 
| 
       54 
     | 
    
         
            -
                      value. 
     | 
| 
       55 
     | 
    
         
            -
                         
     | 
| 
       56 
     | 
    
         
            -
                           
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
                            flip_option_target_button
         
     | 
| 
       60 
     | 
    
         
            -
                          }
         
     | 
| 
      
 59 
     | 
    
         
            +
                      value.flips.flat_map { |_flip_button, flip_option|
         
     | 
| 
      
 60 
     | 
    
         
            +
                        flip_option.flat_map { |flip_option_key, flip_option_target_button|
         
     | 
| 
      
 61 
     | 
    
         
            +
                          next if flip_option_key == :flip_interval
         
     | 
| 
      
 62 
     | 
    
         
            +
                          next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
         
     | 
| 
      
 63 
     | 
    
         
            +
                          flip_option_target_button
         
     | 
| 
       61 
64 
     | 
    
         
             
                        }
         
     | 
| 
       62 
65 
     | 
    
         
             
                      }.compact.each { |b| unverified_buttons << b }
         
     | 
| 
       63 
     | 
    
         
            -
                      value. 
     | 
| 
       64 
     | 
    
         
            -
                         
     | 
| 
       65 
     | 
    
         
            -
                           
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
                            flip_option_target_button
         
     | 
| 
       68 
     | 
    
         
            -
                          }
         
     | 
| 
      
 66 
     | 
    
         
            +
                      value.remaps.flat_map { |_button, option|
         
     | 
| 
      
 67 
     | 
    
         
            +
                        option.flat_map { |_flip_option_key, flip_option_target_button|
         
     | 
| 
      
 68 
     | 
    
         
            +
                          next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
         
     | 
| 
      
 69 
     | 
    
         
            +
                          flip_option_target_button
         
     | 
| 
       69 
70 
     | 
    
         
             
                        }
         
     | 
| 
       70 
71 
     | 
    
         
             
                      }.compact.each { |b| unverified_buttons << b }
         
     | 
| 
       71 
72 
     | 
    
         
             
                      unless(nunsupport_buttons = (unverified_buttons - ProconBypassMan::Procon::ButtonCollection::BUTTONS)).length.zero?
         
     | 
| 
         @@ -78,8 +79,8 @@ module ProconBypassMan 
     | 
|
| 
       78 
79 
     | 
    
         
             
                    @layers.each do |layer_key, value|
         
     | 
| 
       79 
80 
     | 
    
         
             
                      flip_buttons = []
         
     | 
| 
       80 
81 
     | 
    
         
             
                      remap_buttons = []
         
     | 
| 
       81 
     | 
    
         
            -
                      value. 
     | 
| 
       82 
     | 
    
         
            -
                      value. 
     | 
| 
      
 82 
     | 
    
         
            +
                      value.flips.keys.map(&:to_sym).each { |b| flip_buttons << b }
         
     | 
| 
      
 83 
     | 
    
         
            +
                      value.remaps.keys.map(&:to_sym).each { |b| remap_buttons << b }
         
     | 
| 
       83 
84 
     | 
    
         
             
                      if(duplicated_buttons = flip_buttons & remap_buttons).length > 0
         
     | 
| 
       84 
85 
     | 
    
         
             
                        @errors[:layers] << "レイヤー#{layer_key}で、連打とリマップの定義が重複しているボタン#{duplicated_buttons.join(", ")}があります"
         
     | 
| 
       85 
86 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -4,14 +4,13 @@ require "procon_bypass_man/configuration/layer" 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ProconBypassMan
         
     | 
| 
       6 
6 
     | 
    
         
             
              class Configuration
         
     | 
| 
       7 
     | 
    
         
            -
                include Validator
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
7 
     | 
    
         
             
                attr_accessor :layers,
         
     | 
| 
       10 
8 
     | 
    
         
             
                  :setting_path,
         
     | 
| 
       11 
9 
     | 
    
         
             
                  :mode_plugins,
         
     | 
| 
       12 
10 
     | 
    
         
             
                  :macro_plugins,
         
     | 
| 
       13 
11 
     | 
    
         
             
                  :context,
         
     | 
| 
       14 
     | 
    
         
            -
                  :current_context_key
         
     | 
| 
      
 12 
     | 
    
         
            +
                  :current_context_key,
         
     | 
| 
      
 13 
     | 
    
         
            +
                  :neutral_position
         
     | 
| 
       15 
14 
     | 
    
         | 
| 
       16 
15 
     | 
    
         
             
                def self.instance
         
     | 
| 
       17 
16 
     | 
    
         
             
                  @@current_context_key ||= :main
         
     | 
| 
         @@ -19,13 +18,12 @@ module ProconBypassMan 
     | 
|
| 
       19 
18 
     | 
    
         
             
                  @@context[@@current_context_key] ||= new
         
     | 
| 
       20 
19 
     | 
    
         
             
                end
         
     | 
| 
       21 
20 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
                def self. 
     | 
| 
       23 
     | 
    
         
            -
                  @@context[key]  
     | 
| 
      
 21 
     | 
    
         
            +
                def self.switch_new_context(key)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @@context[key] = new
         
     | 
| 
       24 
23 
     | 
    
         
             
                  previous_key = @@current_context_key
         
     | 
| 
       25 
24 
     | 
    
         
             
                  if block_given?
         
     | 
| 
       26 
25 
     | 
    
         
             
                    @@current_context_key = key
         
     | 
| 
       27 
26 
     | 
    
         
             
                    value = yield(@@context[key])
         
     | 
| 
       28 
     | 
    
         
            -
                    @@context[key].reset!
         
     | 
| 
       29 
27 
     | 
    
         
             
                    @@current_context_key = previous_key
         
     | 
| 
       30 
28 
     | 
    
         
             
                    return value
         
     | 
| 
       31 
29 
     | 
    
         
             
                  else
         
     | 
| 
         @@ -37,13 +35,21 @@ module ProconBypassMan 
     | 
|
| 
       37 
35 
     | 
    
         
             
                  reset!
         
     | 
| 
       38 
36 
     | 
    
         
             
                end
         
     | 
| 
       39 
37 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                 
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                    mode_name = mode.name.to_sym
         
     | 
| 
       44 
     | 
    
         
            -
                  else
         
     | 
| 
       45 
     | 
    
         
            -
                    mode_name = mode
         
     | 
| 
      
 38 
     | 
    
         
            +
                module ManualMode
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def self.name
         
     | 
| 
      
 40 
     | 
    
         
            +
                    'manual'
         
     | 
| 
       46 
41 
     | 
    
         
             
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
                MODES = [:manual]
         
     | 
| 
      
 44 
     | 
    
         
            +
                def layer(direction, mode: ManualMode, &block)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  mode_name = case mode
         
     | 
| 
      
 46 
     | 
    
         
            +
                              when String
         
     | 
| 
      
 47 
     | 
    
         
            +
                                mode.to_sym
         
     | 
| 
      
 48 
     | 
    
         
            +
                              when Symbol
         
     | 
| 
      
 49 
     | 
    
         
            +
                                mode
         
     | 
| 
      
 50 
     | 
    
         
            +
                              else
         
     | 
| 
      
 51 
     | 
    
         
            +
                                mode.name.to_sym
         
     | 
| 
      
 52 
     | 
    
         
            +
                              end
         
     | 
| 
       47 
53 
     | 
    
         
             
                  unless (MODES + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode_name)
         
     | 
| 
       48 
54 
     | 
    
         
             
                    raise("#{mode_name} mode is unknown")
         
     | 
| 
       49 
55 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -69,6 +75,11 @@ module ProconBypassMan 
     | 
|
| 
       69 
75 
     | 
    
         
             
                  self
         
     | 
| 
       70 
76 
     | 
    
         
             
                end
         
     | 
| 
       71 
77 
     | 
    
         | 
| 
      
 78 
     | 
    
         
            +
                def set_neutral_position(x, y)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  self.neutral_position = AnalogStickPosition.new(x: x, y: y)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  self
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
       72 
83 
     | 
    
         
             
                def prefix_keys
         
     | 
| 
       73 
84 
     | 
    
         
             
                  @prefix_keys_for_changing_layer
         
     | 
| 
       74 
85 
     | 
    
         
             
                end
         
     | 
| 
         @@ -83,6 +94,7 @@ module ProconBypassMan 
     | 
|
| 
       83 
94 
     | 
    
         
             
                    left: Layer.new,
         
     | 
| 
       84 
95 
     | 
    
         
             
                    right: Layer.new,
         
     | 
| 
       85 
96 
     | 
    
         
             
                  }
         
     | 
| 
      
 97 
     | 
    
         
            +
                  @neutral_position = AnalogStickPosition.new(x: 2124, y: 1808)
         
     | 
| 
       86 
98 
     | 
    
         
             
                end
         
     | 
| 
       87 
99 
     | 
    
         
             
              end
         
     | 
| 
       88 
100 
     | 
    
         
             
            end
         
     | 
| 
         @@ -12,24 +12,7 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       12 
12 
     | 
    
         
             
              PROCON_PATH = "/dev/hidraw0"
         
     | 
| 
       13 
13 
     | 
    
         
             
              PROCON2_PATH = "/dev/hidraw1"
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
               
     | 
| 
       16 
     | 
    
         
            -
              def self.reset_connection!
         
     | 
| 
       17 
     | 
    
         
            -
                s = new
         
     | 
| 
       18 
     | 
    
         
            -
                s.add([
         
     | 
| 
       19 
     | 
    
         
            -
                  ["0000"],
         
     | 
| 
       20 
     | 
    
         
            -
                  ["0000"],
         
     | 
| 
       21 
     | 
    
         
            -
                  ["8005"],
         
     | 
| 
       22 
     | 
    
         
            -
                  ["0000"],
         
     | 
| 
       23 
     | 
    
         
            -
                  ["8001"],
         
     | 
| 
       24 
     | 
    
         
            -
                ], read_from: :switch)
         
     | 
| 
       25 
     | 
    
         
            -
                s.drain_all
         
     | 
| 
       26 
     | 
    
         
            -
                s.read_procon
         
     | 
| 
       27 
     | 
    
         
            -
                s.write_switch("213c910080005db7723d48720a800300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
         
     | 
| 
       28 
     | 
    
         
            -
                sleep(10) # いらないかも
         
     | 
| 
       29 
     | 
    
         
            -
                s
         
     | 
| 
       30 
     | 
    
         
            -
              end
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
              def self.connect(throw_error_if_timeout: true, enable_at_exit: false)
         
     | 
| 
      
 15 
     | 
    
         
            +
              def self.connect
         
     | 
| 
       33 
16 
     | 
    
         
             
                s = new(throw_error_if_timeout: true, enable_at_exit: false)
         
     | 
| 
       34 
17 
     | 
    
         
             
                s.add([
         
     | 
| 
       35 
18 
     | 
    
         
             
                  ["0000"],
         
     | 
| 
         @@ -37,16 +20,16 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       37 
20 
     | 
    
         
             
                  ["8005"],
         
     | 
| 
       38 
21 
     | 
    
         
             
                  ["0010"],
         
     | 
| 
       39 
22 
     | 
    
         
             
                ], read_from: :switch)
         
     | 
| 
       40 
     | 
    
         
            -
                # 1
         
     | 
| 
      
 23 
     | 
    
         
            +
                # 1. Sends current connection status, and if the Joy-Con are connected,
         
     | 
| 
       41 
24 
     | 
    
         
             
                s.add([["8001"]], read_from: :switch)
         
     | 
| 
       42 
25 
     | 
    
         
             
                s.add([/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
         
     | 
| 
       43 
     | 
    
         
            -
                # 2
         
     | 
| 
      
 26 
     | 
    
         
            +
                # 2. Sends handshaking packets over UART to the Joy-Con or Pro Controller Broadcom chip. This command can only be called once per session.
         
     | 
| 
       44 
27 
     | 
    
         
             
                s.add([["8002"]], read_from: :switch)
         
     | 
| 
       45 
28 
     | 
    
         
             
                s.add([/^8102/], read_from: :procon)
         
     | 
| 
       46 
29 
     | 
    
         
             
                # 3
         
     | 
| 
       47 
30 
     | 
    
         
             
                s.add([/^0100/], read_from: :switch)
         
     | 
| 
       48 
31 
     | 
    
         
             
                s.add([/^21/], read_from: :procon)
         
     | 
| 
       49 
     | 
    
         
            -
                # 4
         
     | 
| 
      
 32 
     | 
    
         
            +
                # 4. Forces the Joy-Con or Pro Controller to only talk over USB HID without any timeouts. This is required for the Pro Controller to not time out and revert to Bluetooth.
         
     | 
| 
       50 
33 
     | 
    
         
             
                s.add([["8004"]], read_from: :switch)
         
     | 
| 
       51 
34 
     | 
    
         
             
                s.drain_all
         
     | 
| 
       52 
35 
     | 
    
         
             
                return [s.switch, s.procon]
         
     | 
| 
         @@ -75,7 +58,7 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       75 
58 
     | 
    
         
             
                    timer = ProconBypassMan::Timer.new
         
     | 
| 
       76 
59 
     | 
    
         
             
                    begin
         
     | 
| 
       77 
60 
     | 
    
         
             
                      timer.throw_if_timeout!
         
     | 
| 
       78 
     | 
    
         
            -
                      data = from_device(item).read_nonblock( 
     | 
| 
      
 61 
     | 
    
         
            +
                      data = from_device(item).read_nonblock(64)
         
     | 
| 
       79 
62 
     | 
    
         
             
                    rescue IO::EAGAINWaitReadable
         
     | 
| 
       80 
63 
     | 
    
         
             
                      retry
         
     | 
| 
       81 
64 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -128,7 +111,7 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       128 
111 
     | 
    
         
             
                timer = ProconBypassMan::Timer.new
         
     | 
| 
       129 
112 
     | 
    
         
             
                begin
         
     | 
| 
       130 
113 
     | 
    
         
             
                  timer.throw_if_timeout!
         
     | 
| 
       131 
     | 
    
         
            -
                  data = switch.read_nonblock( 
     | 
| 
      
 114 
     | 
    
         
            +
                  data = switch.read_nonblock(64)
         
     | 
| 
       132 
115 
     | 
    
         
             
                  ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
         
     | 
| 
       133 
116 
     | 
    
         
             
                rescue IO::EAGAINWaitReadable
         
     | 
| 
       134 
117 
     | 
    
         
             
                  retry
         
     | 
| 
         @@ -163,7 +146,7 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       163 
146 
     | 
    
         
             
                timer = ProconBypassMan::Timer.new
         
     | 
| 
       164 
147 
     | 
    
         
             
                begin
         
     | 
| 
       165 
148 
     | 
    
         
             
                  timer.throw_if_timeout!
         
     | 
| 
       166 
     | 
    
         
            -
                  data = procon.read_nonblock( 
     | 
| 
      
 149 
     | 
    
         
            +
                  data = procon.read_nonblock(64)
         
     | 
| 
       167 
150 
     | 
    
         
             
                  ProconBypassMan.logger.error " <<< #{data.unpack("H*")})"
         
     | 
| 
       168 
151 
     | 
    
         
             
                rescue IO::EAGAINWaitReadable
         
     | 
| 
       169 
152 
     | 
    
         
             
                  retry
         
     | 
| 
         @@ -184,7 +167,7 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       184 
167 
     | 
    
         
             
                timer = ProconBypassMan::Timer.new
         
     | 
| 
       185 
168 
     | 
    
         
             
                begin
         
     | 
| 
       186 
169 
     | 
    
         
             
                  timer.throw_if_timeout!
         
     | 
| 
       187 
     | 
    
         
            -
                  data = procon.read_nonblock( 
     | 
| 
      
 170 
     | 
    
         
            +
                  data = procon.read_nonblock(64)
         
     | 
| 
       188 
171 
     | 
    
         
             
                  ProconBypassMan.logger.debug { " <<< #{data.unpack("H*")})" }
         
     | 
| 
       189 
172 
     | 
    
         
             
                rescue IO::EAGAINWaitReadable
         
     | 
| 
       190 
173 
     | 
    
         
             
                  retry
         
     | 
| 
         @@ -217,7 +200,7 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       217 
200 
     | 
    
         
             
                timer = ProconBypassMan::Timer.new
         
     | 
| 
       218 
201 
     | 
    
         
             
                begin
         
     | 
| 
       219 
202 
     | 
    
         
             
                  timer.throw_if_timeout!
         
     | 
| 
       220 
     | 
    
         
            -
                  data = switch.read_nonblock( 
     | 
| 
      
 203 
     | 
    
         
            +
                  data = switch.read_nonblock(64)
         
     | 
| 
       221 
204 
     | 
    
         
             
                  ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
         
     | 
| 
       222 
205 
     | 
    
         
             
                rescue IO::EAGAINWaitReadable
         
     | 
| 
       223 
206 
     | 
    
         
             
                  retry
         
     | 
| 
         @@ -281,7 +264,7 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       281 
264 
     | 
    
         | 
| 
       282 
265 
     | 
    
         
             
                file = File.open(path, "w+")
         
     | 
| 
       283 
266 
     | 
    
         
             
                begin
         
     | 
| 
       284 
     | 
    
         
            -
                  file.read_nonblock( 
     | 
| 
      
 267 
     | 
    
         
            +
                  file.read_nonblock(64)
         
     | 
| 
       285 
268 
     | 
    
         
             
                rescue EOFError
         
     | 
| 
       286 
269 
     | 
    
         
             
                  file.close
         
     | 
| 
       287 
270 
     | 
    
         
             
                  return false
         
     | 
| 
         @@ -303,12 +286,12 @@ class ProconBypassMan::DeviceConnector 
     | 
|
| 
       303 
286 
     | 
    
         
             
                case
         
     | 
| 
       304 
287 
     | 
    
         
             
                when is_available_device?(PROCON_PATH)
         
     | 
| 
       305 
288 
     | 
    
         
             
                  ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON_PATH}を使います"
         
     | 
| 
       306 
     | 
    
         
            -
                  @procon = File.open(PROCON_PATH, "w+")
         
     | 
| 
       307 
     | 
    
         
            -
                  @gadget = File.open('/dev/hidg0', "w+")
         
     | 
| 
      
 289 
     | 
    
         
            +
                  @procon = File.open(PROCON_PATH, "w+b")
         
     | 
| 
      
 290 
     | 
    
         
            +
                  @gadget = File.open('/dev/hidg0', "w+b")
         
     | 
| 
       308 
291 
     | 
    
         
             
                when is_available_device?(PROCON2_PATH)
         
     | 
| 
       309 
292 
     | 
    
         
             
                  ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON2_PATH}を使います"
         
     | 
| 
       310 
     | 
    
         
            -
                  @procon = File.open(PROCON2_PATH, "w+")
         
     | 
| 
       311 
     | 
    
         
            -
                  @gadget = File.open('/dev/hidg0', "w+")
         
     | 
| 
      
 293 
     | 
    
         
            +
                  @procon = File.open(PROCON2_PATH, "w+b")
         
     | 
| 
      
 294 
     | 
    
         
            +
                  @gadget = File.open('/dev/hidg0', "w+b")
         
     | 
| 
       312 
295 
     | 
    
         
             
                else
         
     | 
| 
       313 
296 
     | 
    
         
             
                  raise "/dev/hidraw0, /dev/hidraw1の両方見つかりませんでした"
         
     | 
| 
       314 
297 
     | 
    
         
             
                end
         
     | 
| 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "net/http"
         
     | 
| 
      
 2 
     | 
    
         
            +
            require "json"
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            class ProconBypassMan::ErrorReporter
         
     | 
| 
      
 5 
     | 
    
         
            +
              PATH = "/api/error_reports" # POST
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              class Client
         
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @server = ProconBypassMan.api_server
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @hostname = `hostname`.chomp
         
     | 
| 
      
 11 
     | 
    
         
            +
                end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                def post(body: )
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # TODO ここでvalidationする
         
     | 
| 
      
 15 
     | 
    
         
            +
                  if @server.nil?
         
     | 
| 
      
 16 
     | 
    
         
            +
                    ProconBypassMan.logger.info('送信先が未設定なのでスキップしました')
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  uri = URI.parse("#{@server}#{PATH}")
         
     | 
| 
      
 21 
     | 
    
         
            +
                  http = Net::HTTP.new(uri.host, uri.port)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  http.use_ssl = uri.scheme === "https"
         
     | 
| 
      
 23 
     | 
    
         
            +
                  response = http.post(
         
     | 
| 
      
 24 
     | 
    
         
            +
                    uri.path,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    { report: body.full_message.to_json, hostname: @hostname }.to_json,
         
     | 
| 
      
 26 
     | 
    
         
            +
                    { "Content-Type" => "application/json" },
         
     | 
| 
      
 27 
     | 
    
         
            +
                  )
         
     | 
| 
      
 28 
     | 
    
         
            +
                  unless response.code == /^20/
         
     | 
| 
      
 29 
     | 
    
         
            +
                    ProconBypassMan.logger.error(response.body)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                rescue => e
         
     | 
| 
      
 32 
     | 
    
         
            +
                  puts e
         
     | 
| 
      
 33 
     | 
    
         
            +
                  ProconBypassMan.logger.error(e)
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              def self.report(body: )
         
     | 
| 
      
 38 
     | 
    
         
            +
                ProconBypassMan.logger.error(body)
         
     | 
| 
      
 39 
     | 
    
         
            +
                Client.new.post(body: body)
         
     | 
| 
      
 40 
     | 
    
         
            +
              rescue => e
         
     | 
| 
      
 41 
     | 
    
         
            +
                ProconBypassMan.logger.error(e)
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
            end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
         @@ -62,10 +62,13 @@ module ProconBypassMan 
     | 
|
| 
       62 
62 
     | 
    
         
             
                      }.join(", ")
         
     | 
| 
       63 
63 
     | 
    
         
             
                      max_output_length = line.length
         
     | 
| 
       64 
64 
     | 
    
         
             
                      sleep 0.7
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
                       
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                      if ENV["PBM_FOREGROUND"]
         
     | 
| 
      
 67 
     | 
    
         
            +
                        print "\r"
         
     | 
| 
      
 68 
     | 
    
         
            +
                        print " " * max_output_length
         
     | 
| 
      
 69 
     | 
    
         
            +
                        print "\r"
         
     | 
| 
      
 70 
     | 
    
         
            +
                        print line
         
     | 
| 
      
 71 
     | 
    
         
            +
                      end
         
     | 
| 
       69 
72 
     | 
    
         
             
                      ProconBypassMan.logger.debug { line }
         
     | 
| 
       70 
73 
     | 
    
         
             
                      break if $will_terminate_token
         
     | 
| 
       71 
74 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -0,0 +1,34 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class ProconBypassMan::OnMemoryCache
         
     | 
| 
      
 2 
     | 
    
         
            +
              class CacheValue
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :expired_at, :value
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(expired_at: , value: )
         
     | 
| 
      
 6 
     | 
    
         
            +
                  self.expired_at = expired_at
         
     | 
| 
      
 7 
     | 
    
         
            +
                  self.value = value
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
              end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              def initialize
         
     | 
| 
      
 12 
     | 
    
         
            +
                @table = {}
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              # @param [Integer] expires_in 秒数
         
     | 
| 
      
 16 
     | 
    
         
            +
              # @param [String] key
         
     | 
| 
      
 17 
     | 
    
         
            +
              def fetch(key: , expires_in: , &block)
         
     | 
| 
      
 18 
     | 
    
         
            +
                now = Time.now
         
     | 
| 
      
 19 
     | 
    
         
            +
                if @table[key].nil?
         
     | 
| 
      
 20 
     | 
    
         
            +
                  value = block.call
         
     | 
| 
      
 21 
     | 
    
         
            +
                  value_object = CacheValue.new(expired_at: now + expires_in, value: value)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @table[key] = value_object
         
     | 
| 
      
 23 
     | 
    
         
            +
                  return value
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                if @table[key].expired_at < now
         
     | 
| 
      
 27 
     | 
    
         
            +
                  value = block.call
         
     | 
| 
      
 28 
     | 
    
         
            +
                  @table[key] = CacheValue.new(expired_at: now + expires_in, value: value)
         
     | 
| 
      
 29 
     | 
    
         
            +
                  return value
         
     | 
| 
      
 30 
     | 
    
         
            +
                else
         
     | 
| 
      
 31 
     | 
    
         
            +
                  return @table[key].value
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,88 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class ProconBypassMan::Procon::AnalogStickCap
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Position
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_accessor :x, :y
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(x:, y:)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @x = x.to_i
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @y = y.to_i
         
     | 
| 
      
 8 
     | 
    
         
            +
                end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                def to_binary
         
     | 
| 
      
 11 
     | 
    
         
            +
                  analog_stick_data = [
         
     | 
| 
      
 12 
     | 
    
         
            +
                    (@x & "0xff".to_i(16)),
         
     | 
| 
      
 13 
     | 
    
         
            +
                    ((@y << 4) & "0xf0".to_i(16)) | ((@x >> 8) & "0x0f".to_i(16)),
         
     | 
| 
      
 14 
     | 
    
         
            +
                    (@y >> 4) & "0xff".to_i(16),
         
     | 
| 
      
 15 
     | 
    
         
            +
                  ]
         
     | 
| 
      
 16 
     | 
    
         
            +
                  hex = analog_stick_data.map{ |x| x.to_s(16).rjust(2, "0") }.join
         
     | 
| 
      
 17 
     | 
    
         
            +
                  [hex].pack("H*")
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              attr_accessor :bin_x, :bin_y
         
     | 
| 
      
 22 
     | 
    
         
            +
              attr_accessor :neutral_position
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              def initialize(binary)
         
     | 
| 
      
 25 
     | 
    
         
            +
                @neutral_position = ProconBypassMan::Configuration.instance.neutral_position
         
     | 
| 
      
 26 
     | 
    
         
            +
                @binary = binary
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                byte6 = binary[6].unpack("H*").first.to_i(16).to_s(2).rjust(8, "0")
         
     | 
| 
      
 29 
     | 
    
         
            +
                byte7 = binary[7].unpack("H*").first.to_i(16).to_s(2).rjust(8, "0")
         
     | 
| 
      
 30 
     | 
    
         
            +
                byte8 = binary[8].unpack("H*").first.to_i(16).to_s(2).rjust(8, "0")
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                self.bin_x = "#{byte7[4..7]}#{byte6}"
         
     | 
| 
      
 33 
     | 
    
         
            +
                self.bin_y = "#{byte8}#{byte7[0..3]}"
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              # @return [ProconBypassMan::Procon::AnalogStickCap::Position]
         
     | 
| 
      
 37 
     | 
    
         
            +
              def capped_position(cap_hypotenuse: )
         
     | 
| 
      
 38 
     | 
    
         
            +
                if hypotenuse > cap_hypotenuse
         
     | 
| 
      
 39 
     | 
    
         
            +
                  relative_capped_x = cap_hypotenuse * Math.cos(rad * Math::PI / 180).abs
         
     | 
| 
      
 40 
     | 
    
         
            +
                  relative_capped_y = cap_hypotenuse * Math.sin(rad * Math::PI / 180).abs
         
     | 
| 
      
 41 
     | 
    
         
            +
                  relative_capped_x = -(relative_capped_x.abs) if relative_x.negative?
         
     | 
| 
      
 42 
     | 
    
         
            +
                  relative_capped_y = -(relative_capped_y.abs) if relative_y.negative?
         
     | 
| 
      
 43 
     | 
    
         
            +
                  return Position.new(
         
     | 
| 
      
 44 
     | 
    
         
            +
                    x: relative_capped_x + neutral_position.x,
         
     | 
| 
      
 45 
     | 
    
         
            +
                    y: relative_capped_y + neutral_position.y,
         
     | 
| 
      
 46 
     | 
    
         
            +
                  )
         
     | 
| 
      
 47 
     | 
    
         
            +
                else
         
     | 
| 
      
 48 
     | 
    
         
            +
                  return position
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              # @return [ProconBypassMan::Procon::AnalogStickCap::Position]
         
     | 
| 
      
 53 
     | 
    
         
            +
              def position
         
     | 
| 
      
 54 
     | 
    
         
            +
                Position.new(x: abs_x, y: abs_y)
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              # 0, 0からのx
         
     | 
| 
      
 58 
     | 
    
         
            +
              def abs_x
         
     | 
| 
      
 59 
     | 
    
         
            +
                bin_x.to_i(2)
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
              # 0, 0からのy
         
     | 
| 
      
 63 
     | 
    
         
            +
              def abs_y
         
     | 
| 
      
 64 
     | 
    
         
            +
                bin_y.to_i(2)
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              def relative_x
         
     | 
| 
      
 68 
     | 
    
         
            +
                bin_x.to_i(2) - neutral_position.x
         
     | 
| 
      
 69 
     | 
    
         
            +
              end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
              def relative_y
         
     | 
| 
      
 72 
     | 
    
         
            +
                bin_y.to_i(2) - neutral_position.y
         
     | 
| 
      
 73 
     | 
    
         
            +
              end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              # @deprecated
         
     | 
| 
      
 76 
     | 
    
         
            +
              def x; relative_x; end
         
     | 
| 
      
 77 
     | 
    
         
            +
              def y; relative_y; end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
              def rad
         
     | 
| 
      
 80 
     | 
    
         
            +
                (
         
     | 
| 
      
 81 
     | 
    
         
            +
                  Math.atan(y / x.to_f) * 180 / Math::PI
         
     | 
| 
      
 82 
     | 
    
         
            +
                ).floor(6)
         
     | 
| 
      
 83 
     | 
    
         
            +
              end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
              def hypotenuse
         
     | 
| 
      
 86 
     | 
    
         
            +
                Math.sqrt(x**2 + y**2).floor(6)
         
     | 
| 
      
 87 
     | 
    
         
            +
              end
         
     | 
| 
      
 88 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -8,15 +8,20 @@ class ProconBypassMan::Procon::ButtonCollection 
     | 
|
| 
       8 
8 
     | 
    
         
             
                end
         
     | 
| 
       9 
9 
     | 
    
         
             
              end
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
      
 11 
     | 
    
         
            +
              # https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/ac8093c84194b3232acb675ac1accce9bcb456a3/bluetooth_hid_notes.md
         
     | 
| 
      
 12 
     | 
    
         
            +
              #0) Input report ID
         
     | 
| 
      
 13 
     | 
    
         
            +
              #1) Timer. Increments very fast. Can be used to estimate excess Bluetooth latency.
         
     | 
| 
      
 14 
     | 
    
         
            +
              #2 high nibble) Battery level. 8=full, 6=medium, 4=low, 2=critical, 0=empty. LSB=Charging.
         
     | 
| 
      
 15 
     | 
    
         
            +
              #2 low nibble) Connection info. (con_info >> 1) & 3 - 3=JC, 0=Pro/ChrGrip. con_info & 1 - 1=Switch/USB powered.
         
     | 
| 
       11 
16 
     | 
    
         
             
              #3)  ZR	R	SR(right)	SL(right)	A	B	X	Y
         
     | 
| 
       12 
17 
     | 
    
         
             
              #4)  Grip	(none)	Cap	Home	ThumbL	ThumbR	+	-
         
     | 
| 
       13 
18 
     | 
    
         
             
              #5)  ZL	L	SL(left)	SR(left)	Left	Right	Up	Down
         
     | 
| 
       14 
     | 
    
         
            -
              #6)  analog[0]
         
     | 
| 
       15 
     | 
    
         
            -
              #7)  analog[1]
         
     | 
| 
       16 
     | 
    
         
            -
              #8)  analog[2]
         
     | 
| 
       17 
     | 
    
         
            -
              #9)  analog[3]
         
     | 
| 
       18 
     | 
    
         
            -
              #a)  analog[4]
         
     | 
| 
       19 
     | 
    
         
            -
              #b)  analog[5]
         
     | 
| 
      
 19 
     | 
    
         
            +
              #6)  analog[0] Left analog stick data
         
     | 
| 
      
 20 
     | 
    
         
            +
              #7)  analog[1] Left analog stick data
         
     | 
| 
      
 21 
     | 
    
         
            +
              #8)  analog[2] Left analog stick data
         
     | 
| 
      
 22 
     | 
    
         
            +
              #9)  analog[3] Right analog stick data
         
     | 
| 
      
 23 
     | 
    
         
            +
              #a)  analog[4] Right analog stick data
         
     | 
| 
      
 24 
     | 
    
         
            +
              #b)  analog[5] Right analog stick data
         
     | 
| 
       20 
25 
     | 
    
         
             
              BYTES_MAP = {
         
     | 
| 
       21 
26 
     | 
    
         
             
                0 => nil,
         
     | 
| 
       22 
27 
     | 
    
         
             
                1 => nil,
         
     | 
| 
         @@ -24,6 +29,9 @@ class ProconBypassMan::Procon::ButtonCollection 
     | 
|
| 
       24 
29 
     | 
    
         
             
                3 => [:zr, :r, :sr, :sl, :a, :b, :x, :y],
         
     | 
| 
       25 
30 
     | 
    
         
             
                4 => [:grip, :_undefined_key, :cap, :home, :thumbl, :thumbr, :plus, :minus],
         
     | 
| 
       26 
31 
     | 
    
         
             
                5 => [:zl, :l, :sl, :sr, :left, :right, :up, :down],
         
     | 
| 
      
 32 
     | 
    
         
            +
                6 => [],
         
     | 
| 
      
 33 
     | 
    
         
            +
                7 => [],
         
     | 
| 
      
 34 
     | 
    
         
            +
                8 => [],
         
     | 
| 
       27 
35 
     | 
    
         
             
              }.freeze
         
     | 
| 
       28 
36 
     | 
    
         | 
| 
       29 
37 
     | 
    
         
             
              BUTTONS_MAP = BYTES_MAP.reduce({}) { |acc, value|
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class ProconBypassMan::Procon::DebugDumper
         
     | 
| 
      
 2 
     | 
    
         
            +
              def initialize(binary: )
         
     | 
| 
      
 3 
     | 
    
         
            +
                @binary = binary
         
     | 
| 
      
 4 
     | 
    
         
            +
                # ProconBypassMan.logger.debug { "<<< patched #{@binary.unpack("H*")}" }
         
     | 
| 
      
 5 
     | 
    
         
            +
              end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              def dump_analog_sticks
         
     | 
| 
      
 8 
     | 
    
         
            +
                byte6 = @binary[6].unpack("H*").first.to_i(16).to_s(2).rjust(8, "0")
         
     | 
| 
      
 9 
     | 
    
         
            +
                byte7 = @binary[7].unpack("H*").first.to_i(16).to_s(2).rjust(8, "0")
         
     | 
| 
      
 10 
     | 
    
         
            +
                byte8 = @binary[8].unpack("H*").first.to_i(16).to_s(2).rjust(8, "0")
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                x = "#{byte7[4..7]}#{byte6}"
         
     | 
| 
      
 13 
     | 
    
         
            +
                y = "#{byte8}#{byte7[0..3]}"
         
     | 
| 
      
 14 
     | 
    
         
            +
                ProconBypassMan.logger.debug "x: #{x}, val: #{x.to_i(2)}"
         
     | 
| 
      
 15 
     | 
    
         
            +
                ProconBypassMan.logger.debug "y: #{y}, val: #{y.to_i(2)}"
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -23,10 +23,10 @@ class ProconBypassMan::Procon::ModeRegistry 
     | 
|
| 
       23 
23 
     | 
    
         
             
              }
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
25 
     | 
    
         
             
              def self.install_plugin(klass)
         
     | 
| 
       26 
     | 
    
         
            -
                if plugins[klass.name]
         
     | 
| 
      
 26 
     | 
    
         
            +
                if plugins[klass.name.to_sym]
         
     | 
| 
       27 
27 
     | 
    
         
             
                  raise "すでに登録済みです"
         
     | 
| 
       28 
28 
     | 
    
         
             
                end
         
     | 
| 
       29 
     | 
    
         
            -
                plugins[klass.name] = klass.binaries
         
     | 
| 
      
 29 
     | 
    
         
            +
                plugins[klass.name.to_sym] = klass.binaries
         
     | 
| 
       30 
30 
     | 
    
         
             
              end
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
       32 
32 
     | 
    
         
             
              def self.load(name)
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class ProconBypassMan::PpressButtonAware
         
     | 
| 
      
 2 
     | 
    
         
            +
              def initialize(binary)
         
     | 
| 
      
 3 
     | 
    
         
            +
                @binary = binary
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              def pressed_button?(button)
         
     | 
| 
      
 7 
     | 
    
         
            +
                @binary[
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ::ProconBypassMan::Procon::ButtonCollection.load(button).byte_position
         
     | 
| 
      
 9 
     | 
    
         
            +
                ].unpack("H*").first.to_i(16).to_s(2).reverse[
         
     | 
| 
      
 10 
     | 
    
         
            +
                  ::ProconBypassMan::Procon::ButtonCollection.load(button).bit_position
         
     | 
| 
      
 11 
     | 
    
         
            +
                ] == '1'
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,19 +1,9 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module ProconBypassMan::Procon::PushedButtonHelper
         
     | 
| 
       2 
     | 
    
         
            -
              module Static
         
     | 
| 
       3 
     | 
    
         
            -
                def pressed_button?(button)
         
     | 
| 
       4 
     | 
    
         
            -
                  binary[
         
     | 
| 
       5 
     | 
    
         
            -
                    ::ProconBypassMan::Procon::ButtonCollection.load(button).byte_position
         
     | 
| 
       6 
     | 
    
         
            -
                  ].unpack("H*").first.to_i(16).to_s(2).reverse[
         
     | 
| 
       7 
     | 
    
         
            -
                    ::ProconBypassMan::Procon::ButtonCollection.load(button).bit_position
         
     | 
| 
       8 
     | 
    
         
            -
                  ] == '1'
         
     | 
| 
       9 
     | 
    
         
            -
                end
         
     | 
| 
       10 
     | 
    
         
            -
              end
         
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
2 
     | 
    
         
             
              module Dynamic
         
     | 
| 
       13 
3 
     | 
    
         
             
                @@compiled = false
         
     | 
| 
       14 
4 
     | 
    
         
             
                def compile_if_not_compile_yet!
         
     | 
| 
       15 
5 
     | 
    
         
             
                  unless @@compiled
         
     | 
| 
       16 
     | 
    
         
            -
                    ::ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.each do |button,  
     | 
| 
      
 6 
     | 
    
         
            +
                    ::ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.each do |button, _value|
         
     | 
| 
       17 
7 
     | 
    
         
             
                      define_method "pressed_#{button}?" do
         
     | 
| 
       18 
8 
     | 
    
         
             
                        pressed_button?(button)
         
     | 
| 
       19 
9 
     | 
    
         
             
                      end
         
     |