procon_bypass_man 0.1.3 → 0.1.7

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.
@@ -24,7 +24,7 @@ class ProconBypassMan::Procon::ButtonCollection
24
24
  3 => [:zr, :r, :sr, :sl, :a, :b, :x, :y],
25
25
  4 => [:grip, :_undefined_key, :cap, :home, :thumbl, :thumbr, :plus, :minus],
26
26
  5 => [:zl, :l, :sl, :sr, :left, :right, :up, :down],
27
- }
27
+ }.freeze
28
28
 
29
29
  BUTTONS_MAP = BYTES_MAP.reduce({}) { |acc, value|
30
30
  next acc if value[1].nil?
@@ -32,7 +32,8 @@ class ProconBypassMan::Procon::ButtonCollection
32
32
  acc[button] = { byte_position: value[0], bit_position: index }
33
33
  end
34
34
  acc
35
- }
35
+ }.freeze
36
+ BUTTONS = ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.keys.freeze
36
37
 
37
38
  def self.load(button_key)
38
39
  Button.new(button_key)
@@ -0,0 +1,22 @@
1
+ class ProconBypassMan::Procon
2
+ class FlipCache
3
+ def self.fetch(key: , expires_in: , &block)
4
+ if expires_in.nil?
5
+ block.call
6
+ else
7
+ @@previous_flips_at_table[key] ||= Time.now
8
+ if @@previous_flips_at_table[key] < Time.now
9
+ @@previous_flips_at_table[key] = Time.now + expires_in
10
+ block.call
11
+ end
12
+ end
13
+ end
14
+
15
+ # for testing
16
+ def self.reset!
17
+ @@previous_flips_at_table = {}
18
+ end
19
+
20
+ reset!
21
+ end
22
+ end
@@ -13,7 +13,7 @@ module ProconBypassMan::Procon::PushedButtonHelper
13
13
  @@compiled = false
14
14
  def compile_if_not_compile_yet!
15
15
  unless @@compiled
16
- ::ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.each do |button, value|
16
+ ::ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP.each do |button, _value|
17
17
  define_method "pressed_#{button}?" do
18
18
  pressed_button?(button)
19
19
  end
@@ -1,14 +1,16 @@
1
1
  class ProconBypassMan::Procon
2
+ require "procon_bypass_man/procon/data"
2
3
  require "procon_bypass_man/procon/mode_registry"
3
4
  require "procon_bypass_man/procon/macro_registry"
4
5
  require "procon_bypass_man/procon/layer_changeable"
5
6
  require "procon_bypass_man/procon/button_collection"
6
7
  require "procon_bypass_man/procon/pressed_button_helper"
7
8
  require "procon_bypass_man/procon/user_operation"
9
+ require "procon_bypass_man/procon/flip_cache"
8
10
 
9
11
  attr_accessor :user_operation
10
12
 
11
- def self.reset_cvar!
13
+ def self.reset!
12
14
  @@status = {
13
15
  buttons: {},
14
16
  current_layer_key: :up,
@@ -16,7 +18,6 @@ class ProconBypassMan::Procon
16
18
  ongoing_mode: ModeRegistry.load(:manual),
17
19
  }
18
20
  end
19
- def self.reset!; reset_cvar!; end
20
21
  reset!
21
22
 
22
23
  def initialize(binary)
@@ -51,15 +52,21 @@ class ProconBypassMan::Procon
51
52
  when :manual
52
53
  @@status[:ongoing_mode] = ModeRegistry.load(:manual)
53
54
  current_layer.flip_buttons.each do |button, options|
54
- unless options[:if_pressed]
55
- status[button] = !status[button]
55
+ if !options[:if_pressed]
56
+ FlipCache.fetch(key: button, expires_in: options[:flip_interval]) do
57
+ status[button] = !status[button]
58
+ end
56
59
  next
57
60
  end
58
61
 
59
62
  if options[:if_pressed] && options[:if_pressed].all? { |b| user_operation.pressed_button?(b) }
60
- status[button] = !status[button]
63
+ FlipCache.fetch(key: button, expires_in: options[:flip_interval]) do
64
+ status[button] = !status[button]
65
+ end
61
66
  else
62
- status[button] = false
67
+ FlipCache.fetch(key: button, expires_in: options[:flip_interval]) do
68
+ status[button] = false
69
+ end
63
70
  end
64
71
  end
65
72
  else
@@ -99,18 +106,20 @@ class ProconBypassMan::Procon
99
106
  if !status[button]
100
107
  user_operation.unpress_button(button)
101
108
  end
102
- if options[:force_neutral] && user_operation.pressed_button?(options[:force_neutral])
103
- button = options[:force_neutral]
104
- user_operation.unpress_button(button)
109
+
110
+ options[:force_neutral]&.each do |force_neutral_button|
111
+ user_operation.pressed_button?(force_neutral_button) && user_operation.unpress_button(force_neutral_button)
105
112
  end
106
113
  end
107
114
  end
108
115
 
109
- current_layer.remaps.each do |from_button, to_button|
116
+ current_layer.remaps.each do |from_button, to_buttons|
110
117
  if user_operation.pressed_button?(from_button)
111
118
  user_operation.unpress_button(from_button)
112
119
  # TODO 2重でpressしないようにしたい
113
- user_operation.press_button(to_button) unless user_operation.pressed_button?(to_button)
120
+ to_buttons[:to].each do |to_button|
121
+ user_operation.press_button(to_button) unless user_operation.pressed_button?(to_button)
122
+ end
114
123
  end
115
124
  end
116
125
 
@@ -3,10 +3,7 @@ require_relative "io_monitor"
3
3
  class ProconBypassMan::Runner
4
4
  class InterruptForRestart < StandardError; end
5
5
 
6
- def initialize(gadget: , procon: )
7
- @gadget = gadget
8
- @procon = procon
9
-
6
+ def initialize
10
7
  $will_interval_0_0_0_5 = 0
11
8
  $will_interval_1_6 = 0
12
9
  end
@@ -22,7 +19,7 @@ class ProconBypassMan::Runner
22
19
  self_write.puts(sig)
23
20
  end
24
21
  rescue ArgumentError
25
- ProconBypassMan.logger.info("Signal #{sig} not supported")
22
+ ProconBypassMan.logger.error("Signal #{sig} not supported")
26
23
  end
27
24
  end
28
25
 
@@ -31,7 +28,7 @@ class ProconBypassMan::Runner
31
28
  main_loop_pid = fork { main_loop }
32
29
 
33
30
  begin
34
- while readable_io = IO.select([self_read])
31
+ while(readable_io = IO.select([self_read]))
35
32
  signal = readable_io.first[0].gets.strip
36
33
  handle_signal(signal)
37
34
  end
@@ -53,6 +50,8 @@ class ProconBypassMan::Runner
53
50
  Process.wait
54
51
  @gadget&.close
55
52
  @procon&.close
53
+ FileUtils.rm_rf(ProconBypassMan.pid_path)
54
+ FileUtils.rm_rf(ProconBypassMan.digest_path)
56
55
  exit 1
57
56
  end
58
57
  end
@@ -97,8 +96,11 @@ class ProconBypassMan::Runner
97
96
  loop do
98
97
  break if $will_terminate_token
99
98
  bypass.send_procon_to_gadget!
99
+ rescue EOFError => e
100
+ ProconBypassMan.logger.error "Proconと通信ができませんでした.終了処理を開始します"
101
+ Process.kill "TERM", Process.ppid
100
102
  rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
101
- ProconBypassMan.logger.error "Proconが切断されました.終了処理を開始します"
103
+ ProconBypassMan.logger.error "Proconが切断されました。終了処理を開始します"
102
104
  Process.kill "TERM", Process.ppid
103
105
  end
104
106
  ProconBypassMan.logger.info "Thread2を終了します"
@@ -118,7 +120,7 @@ class ProconBypassMan::Runner
118
120
 
119
121
  ProconBypassMan.logger.info "子プロセスでgraceful shutdownの準備ができました"
120
122
  begin
121
- while readable_io = IO.select([self_read])
123
+ while(readable_io = IO.select([self_read]))
122
124
  signal = readable_io.first[0].gets.strip
123
125
  handle_signal(signal)
124
126
  end
@@ -132,38 +134,14 @@ class ProconBypassMan::Runner
132
134
  end
133
135
 
134
136
  def first_negotiation
135
- loop do
136
- begin
137
- input = @gadget.read_nonblock(128)
138
- ProconBypassMan.logger.debug { ">>> #{input.unpack("H*")}" }
139
- @procon.write_nonblock(input)
140
- if input[0] == "\x80".b && input[1] == "\x01".b
141
- ProconBypassMan.logger.info("first negotiation is over")
142
- break
143
- end
144
- break if $will_terminate_token
145
- rescue IO::EAGAINWaitReadable
146
- end
147
- end
148
-
149
- # ...
150
- # switch) 8001
151
- # procon) 8101
152
- # switch) 8002
153
- # が返ってくるプロトコルがあって、これができていないならやり直す
154
- loop do
155
- begin
156
- data = @procon.read_nonblock(128)
157
- if data[0] == "\x81".b && data[1] == "\x01".b
158
- ProconBypassMan.logger.debug { "接続を確認しました" }
159
- @gadget.write_nonblock(data)
160
- break
161
- else
162
- raise ::ProconBypassMan::FirstConnectionError
163
- end
164
- rescue IO::EAGAINWaitReadable
165
- end
166
- end
137
+ return if $will_terminate_token
138
+
139
+ @gadget, @procon = ProconBypassMan::DeviceConnector.connect
140
+ rescue ProconBypassMan::Timer::Timeout
141
+ ::ProconBypassMan.logger.error "デバイスとの通信でタイムアウトが起きて接続ができませんでした。"
142
+ @gadget&.close
143
+ @procon&.close
144
+ raise ::ProconBypassMan::EternalConnectionError
167
145
  end
168
146
 
169
147
  def handle_signal(sig)
@@ -179,10 +157,14 @@ class ProconBypassMan::Runner
179
157
  # @return [void]
180
158
  def print_booted_message
181
159
  booted_message = <<~EOF
160
+ ----
161
+ RUBY_VERSION: #{RUBY_VERSION}
182
162
  ProconBypassMan: #{ProconBypassMan::VERSION}
183
- pid_path: #{ProconBypassMan.pid_path}
184
163
  pid: #{$$}
185
- project_path: #{ProconBypassMan.root}
164
+ root: #{ProconBypassMan.root}
165
+ pid_path: #{ProconBypassMan.pid_path}
166
+ setting_path: #{ProconBypassMan::Configuration.instance.setting_path}
167
+ ----
186
168
  EOF
187
169
  ProconBypassMan.logger.info(booted_message)
188
170
  puts booted_message
@@ -0,0 +1,14 @@
1
+ module ProconBypassMan
2
+ class Timer
3
+ class Timeout < StandardError; end
4
+
5
+ # 5秒後がタイムアウト
6
+ def initialize(timeout: Time.now + 5)
7
+ @timeout = timeout
8
+ end
9
+
10
+ def throw_if_timeout!
11
+ raise Timeout if @timeout < Time.now
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProconBypassMan
4
- VERSION = "0.1.3"
4
+ VERSION = "0.1.7"
5
5
  end
@@ -3,11 +3,11 @@ require 'yaml'
3
3
  require "fileutils"
4
4
 
5
5
  require_relative "procon_bypass_man/version"
6
- require_relative "procon_bypass_man/device_registry"
6
+ require_relative "procon_bypass_man/timer"
7
7
  require_relative "procon_bypass_man/bypass"
8
+ require_relative "procon_bypass_man/device_connector"
8
9
  require_relative "procon_bypass_man/runner"
9
10
  require_relative "procon_bypass_man/processor"
10
- require_relative "procon_bypass_man/procon/data"
11
11
  require_relative "procon_bypass_man/configuration"
12
12
  require_relative "procon_bypass_man/procon"
13
13
 
@@ -18,6 +18,7 @@ module ProconBypassMan
18
18
  class ProConRejected < StandardError; end
19
19
  class CouldNotLoadConfigError < StandardError; end
20
20
  class FirstConnectionError < StandardError; end
21
+ class EternalConnectionError < StandardError; end
21
22
 
22
23
  def self.configure(setting_path: nil, &block)
23
24
  unless setting_path
@@ -33,14 +34,19 @@ module ProconBypassMan
33
34
 
34
35
  def self.run(setting_path: nil, &block)
35
36
  configure(setting_path: setting_path, &block)
36
- at_exit { FileUtils.rm_rf(pid_path) }
37
37
  File.write(pid_path, $$)
38
- registry = ProconBypassMan::DeviceRegistry.new
39
- Runner.new(gadget: registry.gadget, procon: registry.procon).run
38
+ Runner.new.run
40
39
  rescue CouldNotLoadConfigError
41
40
  ProconBypassMan.logger.error "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
42
41
  puts "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
42
+ FileUtils.rm_rf(ProconBypassMan.pid_path)
43
+ FileUtils.rm_rf(ProconBypassMan.digest_path)
43
44
  exit 1
45
+ rescue EternalConnectionError
46
+ ProconBypassMan.logger.error "接続の見込みがないのでsleepしまくります"
47
+ puts "接続の見込みがないのでsleepしまくります"
48
+ FileUtils.rm_rf(ProconBypassMan.pid_path)
49
+ sleep(999999999)
44
50
  rescue FirstConnectionError
45
51
  puts "接続を確立できませんでした。やりなおします。"
46
52
  retry
@@ -58,9 +64,8 @@ module ProconBypassMan
58
64
  end
59
65
  end
60
66
 
61
- DEFAULT_PID_PATH = File.expand_path('../pbm_pid', __dir__).freeze
62
67
  def self.pid_path
63
- @@pid_path ||= DEFAULT_PID_PATH
68
+ @@pid_path ||= File.expand_path("#{root}/pbm_pid", __dir__).freeze
64
69
  end
65
70
 
66
71
  def self.reset!
@@ -72,6 +77,18 @@ module ProconBypassMan
72
77
  end
73
78
 
74
79
  def self.root
75
- File.expand_path('..', __dir__).freeze
80
+ if defined?(@@root)
81
+ @@root
82
+ else
83
+ File.expand_path('..', __dir__).freeze
84
+ end
85
+ end
86
+
87
+ def self.root=(path)
88
+ @@root = path
89
+ end
90
+
91
+ def self.digest_path
92
+ "#{root}/.setting_yaml_digest"
76
93
  end
77
94
  end
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
 
11
11
  spec.summary = "extension for Nintendo Switch Pro Controller"
12
12
  spec.description = spec.summary
13
- spec.homepage = "https://github.com/splaspla-hacker/procon_bypass_man"
13
+ spec.homepage = "https://github.com/splaplapla/procon_bypass_man"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
16
 
@@ -0,0 +1,16 @@
1
+ # Project Template
2
+ https://github.com/splaplapla/pbmenv で使っているファイルです
3
+
4
+ ## systemd
5
+ * sudo ln -s /usr/share/pbm/current/systemd_units/pbm.service /etc/systemd/system/pbm.service
6
+ * commnds
7
+ * systemctl daemon-reload
8
+ * systemctl enable pbm.service
9
+ * systemctl disable pbm.service
10
+ * systemctl start pbm.service
11
+ * systemctl status pbm.service
12
+ * systemctl restart pbm.service
13
+
14
+ ### ログ
15
+ * journalctl -xe -f
16
+
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
8
+ gem 'procon_bypass_man', '0.1.7'
9
+ gem 'procon_bypass_man-splatoon2', github: 'splaplapla/procon_bypass_man-splatoon2', tag: "0.1.1"
10
+ end
11
+
12
+ ProconBypassMan.tap do |pbm|
13
+ pbm.root = File.expand_path(__dir__)
14
+ pbm.logger = Logger.new("#{ProconBypassMan.root}/app.log", 5, 1024 * 1024 * 10)
15
+ pbm.logger.level = :debug
16
+ end
17
+
18
+ ProconBypassMan.run(setting_path: "./setting.yml")
@@ -0,0 +1,35 @@
1
+ version: 1.0
2
+ setting: |-
3
+ fast_return = ProconBypassMan::Splatoon2::Macro::FastReturn
4
+ guruguru = ProconBypassMan::Splatoon2::Mode::Guruguru
5
+
6
+ install_macro_plugin fast_return
7
+ install_macro_plugin ProconBypassMan::Splatoon2::Macro::JumpToUpKey
8
+ install_macro_plugin ProconBypassMan::Splatoon2::Macro::JumpToRightKey
9
+ install_macro_plugin ProconBypassMan::Splatoon2::Macro::JumpToLeftKey
10
+ install_mode_plugin guruguru
11
+
12
+ prefix_keys_for_changing_layer [:zr, :zl, :l]
13
+
14
+ layer :up, mode: :manual do
15
+ # flip :zr, if_pressed: :zr, force_neutral: :zl
16
+ flip :zr, if_pressed: :zr, force_neutral: :zl
17
+ flip :zl, if_pressed: [:y, :b, :zl]
18
+ flip :a, if_pressed: [:a]
19
+ flip :down, if_pressed: :down
20
+ macro fast_return.name, if_pressed: [:y, :b, :down]
21
+ macro ProconBypassMan::Splatoon2::Macro::JumpToUpKey, if_pressed: [:y, :b, :up]
22
+ macro ProconBypassMan::Splatoon2::Macro::JumpToRightKey, if_pressed: [:y, :b, :right]
23
+ macro ProconBypassMan::Splatoon2::Macro::JumpToLeftKey, if_pressed: [:y, :b, :left]
24
+ remap :l, to: :zr
25
+ end
26
+ layer :right, mode: guruguru.name
27
+ layer :left do
28
+ # flip :zr, if_pressed: :zr, force_neutral: :zl
29
+ remap :l, to: :zr
30
+ end
31
+ layer :down do
32
+ # flip :zl
33
+ # flip :zr, if_pressed: :zr, force_neutral: :zl, flip_interval: "1F"
34
+ remap :l, to: :zr
35
+ end
@@ -0,0 +1,13 @@
1
+ [Unit]
2
+ Description=PBM
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ WorkingDirectory=/usr/share/pbm/current
8
+ ExecStart=/bin/bash -c "ruby /usr/share/pbm/current/app.rb"
9
+ Restart=always
10
+ Nice=-19
11
+
12
+ [Install]
13
+ WantedBy=multi-user.target