procon_bypass_man 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/lib/procon_bypass_man.rb +9 -4
- data/lib/procon_bypass_man/configuration.rb +8 -3
- data/lib/procon_bypass_man/configuration/layer.rb +30 -6
- data/lib/procon_bypass_man/configuration/validator.rb +68 -4
- data/lib/procon_bypass_man/device_connector.rb +336 -0
- data/lib/procon_bypass_man/procon.rb +9 -7
- data/lib/procon_bypass_man/procon/button_collection.rb +3 -2
- data/lib/procon_bypass_man/runner.rb +13 -37
- data/lib/procon_bypass_man/timer.rb +14 -0
- data/lib/procon_bypass_man/version.rb +1 -1
- metadata +4 -3
- data/lib/procon_bypass_man/device_registry.rb +0 -42
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5780c7567981a37aef9f32801868f1e59db9d70e47f5cb65dc302cc16a22252e
|
4
|
+
data.tar.gz: e1f6d212b9076c0e081e720f3f3c75217183d3bdb4cbab660ab14abc61a35671
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4ea7163f5d33b68c1cfe9e65c15bbe40414435ecf6c5c3fdadc9c70e29eb77f8fa4bbd8897cc8306f2d9cb8b42d231cce240973828f30e8e24771a66235c7304
|
7
|
+
data.tar.gz: d829cdf3cd7d3428247a55eb2e5140344d79d6c0b48321a4a7bdcbc3f3e122c66066fa31839bc260016643375b104847f9c8435dfe151f9afa027990b98df630
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,13 @@
|
|
1
|
-
## [0.1.
|
1
|
+
## [0.1.5] - 2021-07-29
|
2
|
+
- siwtch, proコンが電源OFF時にCPU使いまくるのを修正した
|
3
|
+
- 連打中に無視するボタンを複数登録できるようにした
|
4
|
+
- キーのリマップ先に複数ボタンを登録できるようにした
|
5
|
+
- 1つのボタンへ連打とリマップをできないようにしました
|
6
|
+
- NG ex)
|
7
|
+
- flip :zr, if_pressed: [:y]
|
8
|
+
- remap :zr, to: [:x]
|
9
|
+
|
10
|
+
## [0.1.4] - 2021-07-11
|
2
11
|
- ProconBypassMan.rootの定義を、gem rootからproject rootへ変更した
|
3
12
|
- 連打の頻度を変更できるようにした
|
4
13
|
- シグナルで設定ファイルを読み直すとpid_pathが消滅する不具合を修正した
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -60,9 +60,9 @@ Switch <-- (PBM): ZR連打
|
|
60
60
|
## 開発系
|
61
61
|
```ruby
|
62
62
|
ProconBypassMan.tap do |pbm|
|
63
|
+
pbm.root = File.expand_path(__dir__)
|
63
64
|
pbm.logger = Logger.new("#{ProconBypassMan.root}/app.log", 5, 1024 * 1024 * 10)
|
64
65
|
pbm.logger.level = :debug
|
65
|
-
pbm.root = File.expand_path(__dir__)
|
66
66
|
end
|
67
67
|
```
|
68
68
|
|
data/lib/procon_bypass_man.rb
CHANGED
@@ -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/
|
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
|
@@ -34,13 +35,17 @@ module ProconBypassMan
|
|
34
35
|
def self.run(setting_path: nil, &block)
|
35
36
|
configure(setting_path: setting_path, &block)
|
36
37
|
File.write(pid_path, $$)
|
37
|
-
|
38
|
-
Runner.new(gadget: registry.gadget, procon: registry.procon).run
|
38
|
+
Runner.new.run
|
39
39
|
rescue CouldNotLoadConfigError
|
40
40
|
ProconBypassMan.logger.error "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
|
41
41
|
puts "設定ファイルが不正です。設定ファイルの読み込みに失敗しました"
|
42
42
|
FileUtils.rm_rf(ProconBypassMan.pid_path)
|
43
43
|
exit 1
|
44
|
+
rescue EternalConnectionError
|
45
|
+
ProconBypassMan.logger.error "接続の見込みがないのでsleepしまくります"
|
46
|
+
puts "接続の見込みがないのでsleepしまくります"
|
47
|
+
FileUtils.rm_rf(ProconBypassMan.pid_path)
|
48
|
+
sleep(999999999999999999)
|
44
49
|
rescue FirstConnectionError
|
45
50
|
puts "接続を確立できませんでした。やりなおします。"
|
46
51
|
retry
|
@@ -39,11 +39,16 @@ module ProconBypassMan
|
|
39
39
|
|
40
40
|
MODES = [:manual]
|
41
41
|
def layer(direction, mode: :manual, &block)
|
42
|
-
|
43
|
-
|
42
|
+
if mode.respond_to?(:name)
|
43
|
+
mode_name = mode.name.to_sym
|
44
|
+
else
|
45
|
+
mode_name = mode
|
46
|
+
end
|
47
|
+
unless (MODES + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode_name)
|
48
|
+
raise("#{mode_name} mode is unknown")
|
44
49
|
end
|
45
50
|
|
46
|
-
layer = Layer.new(mode:
|
51
|
+
layer = Layer.new(mode: mode_name)
|
47
52
|
layer.instance_eval(&block) if block_given?
|
48
53
|
self.layers[direction] = layer
|
49
54
|
self
|
@@ -16,7 +16,7 @@ module ProconBypassMan
|
|
16
16
|
case if_pressed
|
17
17
|
when TrueClass
|
18
18
|
if_pressed = [button]
|
19
|
-
when Symbol
|
19
|
+
when Symbol, String
|
20
20
|
if_pressed = [if_pressed]
|
21
21
|
when Array, FalseClass
|
22
22
|
# sono mama
|
@@ -25,8 +25,16 @@ module ProconBypassMan
|
|
25
25
|
end
|
26
26
|
hash = { if_pressed: if_pressed }
|
27
27
|
if force_neutral
|
28
|
-
|
28
|
+
case force_neutral
|
29
|
+
when TrueClass, FalseClass
|
30
|
+
raise "ボタンを渡してください"
|
31
|
+
when Symbol, String
|
32
|
+
hash[:force_neutral] = [force_neutral]
|
33
|
+
when Array
|
34
|
+
hash[:force_neutral] = force_neutral
|
35
|
+
end
|
29
36
|
end
|
37
|
+
|
30
38
|
if flip_interval
|
31
39
|
if /\A(\d+)F\z/i =~ flip_interval
|
32
40
|
interval = ((frame = $1.to_i) / 60.0).floor(2)
|
@@ -35,17 +43,33 @@ module ProconBypassMan
|
|
35
43
|
end
|
36
44
|
hash[:flip_interval] = interval
|
37
45
|
end
|
38
|
-
self.flips[button]
|
46
|
+
if self.flips[button]
|
47
|
+
raise "#{button}への設定をすでに割り当て済みです"
|
48
|
+
else
|
49
|
+
self.flips[button] = hash
|
50
|
+
end
|
39
51
|
end
|
40
52
|
|
41
53
|
PRESET_MACROS = [:fast_return]
|
42
54
|
def macro(name, if_pressed: )
|
43
|
-
|
55
|
+
if name.respond_to?(:name)
|
56
|
+
macro_name = name.name.to_sym
|
57
|
+
else
|
58
|
+
macro_name = name
|
59
|
+
end
|
60
|
+
self.macros[macro_name] = { if_pressed: if_pressed }
|
44
61
|
end
|
45
62
|
|
46
63
|
def remap(button, to: )
|
47
|
-
|
48
|
-
|
64
|
+
case to
|
65
|
+
when TrueClass, FalseClass
|
66
|
+
raise "ボタンを渡してください"
|
67
|
+
when Symbol, String
|
68
|
+
self.remaps[button] = { to: [to] }
|
69
|
+
when Array
|
70
|
+
raise "ボタンを渡してください" if to.size.zero?
|
71
|
+
self.remaps[button] = { to: to }
|
72
|
+
end
|
49
73
|
end
|
50
74
|
|
51
75
|
# @return [Array]
|
@@ -4,10 +4,11 @@ module ProconBypassMan
|
|
4
4
|
# @return [Boolean]
|
5
5
|
def valid?
|
6
6
|
@errors = Hash.new {|h,k| h[k] = [] }
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
|
8
|
+
validate_require_prefix_keys
|
9
|
+
validate_config_of_button_lonely
|
10
|
+
validate_verify_button_existence
|
11
|
+
validate_flip_and_remap_are_hate_each_other
|
11
12
|
|
12
13
|
@errors.empty?
|
13
14
|
end
|
@@ -21,6 +22,69 @@ module ProconBypassMan
|
|
21
22
|
def errors
|
22
23
|
@errors ||= Hash.new {|h,k| h[k] = [] }
|
23
24
|
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def validate_config_of_button_lonely
|
29
|
+
@layers.each do |layer_key, value|
|
30
|
+
if ProconBypassMan::Procon::ModeRegistry::PRESETS.key?(value.mode)
|
31
|
+
next
|
32
|
+
else
|
33
|
+
if !value.flips.empty? || !value.macros.empty?
|
34
|
+
@errors[:layers] << "#{layer_key}でmodeを設定しているのでボタンの設定はできません。"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate_require_prefix_keys
|
41
|
+
if prefix_keys.empty?
|
42
|
+
@errors[:prefix_keys] ||= []
|
43
|
+
@errors[:prefix_keys] << "prefix_keys_for_changing_layerに値が入っていません。"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def validate_verify_button_existence
|
48
|
+
@layers.each do |layer_key, value|
|
49
|
+
unverified_buttons = []
|
50
|
+
# teplevel target button
|
51
|
+
value.instance_eval { @flips.keys }.map(&:to_sym).each { |b| unverified_buttons << b }
|
52
|
+
value.instance_eval { @remaps.keys }.map(&:to_sym).each { |b| unverified_buttons << b }
|
53
|
+
# internal target button
|
54
|
+
value.instance_eval {
|
55
|
+
@flips.flat_map { |flip_button, flip_option|
|
56
|
+
flip_option.flat_map { |flip_option_key, flip_option_target_button|
|
57
|
+
next if flip_option_key == :flip_interval
|
58
|
+
next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
|
59
|
+
flip_option_target_button
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}.compact.each { |b| unverified_buttons << b }
|
63
|
+
value.instance_eval {
|
64
|
+
@remaps.flat_map { |button, option|
|
65
|
+
option.flat_map { |flip_option_key, flip_option_target_button|
|
66
|
+
next if flip_option_target_button.is_a?(FalseClass) || flip_option_target_button.is_a?(TrueClass)
|
67
|
+
flip_option_target_button
|
68
|
+
}
|
69
|
+
}
|
70
|
+
}.compact.each { |b| unverified_buttons << b }
|
71
|
+
unless(nunsupport_buttons = (unverified_buttons - ProconBypassMan::Procon::ButtonCollection::BUTTONS)).length.zero?
|
72
|
+
@errors[:layers] << "#{layer_key}で存在しないボタン#{nunsupport_buttons.join(", ")}があります"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate_flip_and_remap_are_hate_each_other
|
78
|
+
@layers.each do |layer_key, value|
|
79
|
+
flip_buttons = []
|
80
|
+
remap_buttons = []
|
81
|
+
value.instance_eval { @flips.keys }.map(&:to_sym).each { |b| flip_buttons << b }
|
82
|
+
value.instance_eval { @remaps.keys }.map(&:to_sym).each { |b| remap_buttons << b }
|
83
|
+
if(duplicated_buttons = flip_buttons & remap_buttons).length > 0
|
84
|
+
@errors[:layers] << "レイヤー#{layer_key}で、連打とリマップの定義が重複しているボタン#{duplicated_buttons.join(", ")}があります"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
24
88
|
end
|
25
89
|
end
|
26
90
|
end
|
@@ -0,0 +1,336 @@
|
|
1
|
+
class ProconBypassMan::DeviceConnector
|
2
|
+
class BytesMismatchError < StandardError; end
|
3
|
+
|
4
|
+
class Value
|
5
|
+
attr_accessor :read_from, :values
|
6
|
+
def initialize(values: , read_from: )
|
7
|
+
@values = values
|
8
|
+
@read_from = read_from
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
PROCON_PATH = "/dev/hidraw0"
|
13
|
+
PROCON2_PATH = "/dev/hidraw1"
|
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)
|
33
|
+
s = new(throw_error_if_timeout: true, enable_at_exit: false)
|
34
|
+
s.add([
|
35
|
+
["0000"],
|
36
|
+
["0000"],
|
37
|
+
["8005"],
|
38
|
+
["0010"],
|
39
|
+
], read_from: :switch)
|
40
|
+
# 1
|
41
|
+
s.add([["8001"]], read_from: :switch)
|
42
|
+
s.add([/^8101/], read_from: :procon) # <<< 81010003176d96e7a5480000000, macaddressとコントローラー番号を返す
|
43
|
+
# 2
|
44
|
+
s.add([["8002"]], read_from: :switch)
|
45
|
+
s.add([/^8102/], read_from: :procon)
|
46
|
+
# 3
|
47
|
+
s.add([/^0100/], read_from: :switch)
|
48
|
+
s.add([/^21/], read_from: :procon)
|
49
|
+
# 4
|
50
|
+
s.add([["8004"]], read_from: :switch)
|
51
|
+
s.drain_all
|
52
|
+
return [s.switch, s.procon]
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(throw_error_if_timeout: false, throw_error_if_mismatch: false , enable_at_exit: true)
|
56
|
+
@stack = []
|
57
|
+
@initialized_devices = false
|
58
|
+
@throw_error_if_timeout = throw_error_if_timeout
|
59
|
+
@throw_error_if_mismatch = throw_error_if_mismatch
|
60
|
+
@enable_at_exit = enable_at_exit
|
61
|
+
end
|
62
|
+
|
63
|
+
def add(values, read_from: )
|
64
|
+
@stack << Value.new(values: values, read_from: read_from)
|
65
|
+
end
|
66
|
+
|
67
|
+
def drain_all
|
68
|
+
unless @initialized_devices
|
69
|
+
init_devices
|
70
|
+
end
|
71
|
+
|
72
|
+
while(item = @stack.shift)
|
73
|
+
item.values.each do |value|
|
74
|
+
data = nil
|
75
|
+
timer = ProconBypassMan::Timer.new
|
76
|
+
begin
|
77
|
+
timer.throw_if_timeout!
|
78
|
+
data = from_device(item).read_nonblock(128)
|
79
|
+
rescue IO::EAGAINWaitReadable
|
80
|
+
retry
|
81
|
+
end
|
82
|
+
|
83
|
+
result =
|
84
|
+
case value
|
85
|
+
when String, Array
|
86
|
+
value == data.unpack("H*")
|
87
|
+
when Regexp
|
88
|
+
value =~ data.unpack("H*").first
|
89
|
+
else
|
90
|
+
raise "#{value}は知りません"
|
91
|
+
end
|
92
|
+
if result
|
93
|
+
ProconBypassMan.logger.info "OK(expected: #{value}, got: #{data.unpack("H*")})"
|
94
|
+
else
|
95
|
+
ProconBypassMan.logger.info "NG(expected: #{value}, got: #{data.unpack("H*")})"
|
96
|
+
raise BytesMismatchError if @throw_error_if_mismatch
|
97
|
+
end
|
98
|
+
to_device(item).write_nonblock(data)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
rescue ProconBypassMan::Timer::Timeout
|
102
|
+
ProconBypassMan.logger.error "timeoutになりました"
|
103
|
+
raise if @throw_error_if_timeout
|
104
|
+
end
|
105
|
+
|
106
|
+
# switchに任意の命令を入力して、switchから読み取る
|
107
|
+
def write_switch(data, only_write: false)
|
108
|
+
if data.encoding.name == "UTF-8"
|
109
|
+
data = [data].pack("H*")
|
110
|
+
end
|
111
|
+
unless @initialized_devices
|
112
|
+
init_devices
|
113
|
+
end
|
114
|
+
|
115
|
+
timer = ProconBypassMan::Timer.new
|
116
|
+
data = nil
|
117
|
+
begin
|
118
|
+
timer.throw_if_timeout!
|
119
|
+
switch.write_nonblock(data)
|
120
|
+
rescue IO::EAGAINWaitReadable
|
121
|
+
retry
|
122
|
+
rescue ProconBypassMan::Timer::Timeout
|
123
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
124
|
+
raise
|
125
|
+
end
|
126
|
+
return(data.unpack("H*")) if only_write
|
127
|
+
|
128
|
+
timer = ProconBypassMan::Timer.new
|
129
|
+
begin
|
130
|
+
timer.throw_if_timeout!
|
131
|
+
data = switch.read_nonblock(128)
|
132
|
+
ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
|
133
|
+
rescue IO::EAGAINWaitReadable
|
134
|
+
retry
|
135
|
+
rescue ProconBypassMan::Timer::Timeout
|
136
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
137
|
+
raise
|
138
|
+
end
|
139
|
+
rescue ProconBypassMan::Timer::Timeout
|
140
|
+
raise if @throw_error_if_timeout
|
141
|
+
end
|
142
|
+
|
143
|
+
def write_procon(data, only_write: false)
|
144
|
+
if data.encoding.name == "UTF-8"
|
145
|
+
data = [data].pack("H*")
|
146
|
+
end
|
147
|
+
unless @initialized_devices
|
148
|
+
init_devices
|
149
|
+
end
|
150
|
+
|
151
|
+
timer = ProconBypassMan::Timer.new
|
152
|
+
begin
|
153
|
+
timer.throw_if_timeout!
|
154
|
+
procon.write_nonblock(data)
|
155
|
+
rescue IO::EAGAINWaitReadable
|
156
|
+
retry
|
157
|
+
rescue ProconBypassMan::Timer::Timeout
|
158
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
159
|
+
raise
|
160
|
+
end
|
161
|
+
return(data.unpack("H*")) if only_write
|
162
|
+
|
163
|
+
timer = ProconBypassMan::Timer.new
|
164
|
+
begin
|
165
|
+
timer.throw_if_timeout!
|
166
|
+
data = procon.read_nonblock(128)
|
167
|
+
ProconBypassMan.logger.error " <<< #{data.unpack("H*")})"
|
168
|
+
rescue IO::EAGAINWaitReadable
|
169
|
+
retry
|
170
|
+
rescue ProconBypassMan::Timer::Timeout
|
171
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
172
|
+
raise
|
173
|
+
end
|
174
|
+
rescue ProconBypassMan::Timer::Timeout
|
175
|
+
raise if @throw_error_if_timeout
|
176
|
+
end
|
177
|
+
|
178
|
+
def read_procon(only_read: false)
|
179
|
+
unless @initialized_devices
|
180
|
+
init_devices
|
181
|
+
end
|
182
|
+
|
183
|
+
data = nil
|
184
|
+
timer = ProconBypassMan::Timer.new
|
185
|
+
begin
|
186
|
+
timer.throw_if_timeout!
|
187
|
+
data = procon.read_nonblock(128)
|
188
|
+
ProconBypassMan.logger.debug { " <<< #{data.unpack("H*")})" }
|
189
|
+
rescue IO::EAGAINWaitReadable
|
190
|
+
retry
|
191
|
+
rescue ProconBypassMan::Timer::Timeout
|
192
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
193
|
+
raise
|
194
|
+
end
|
195
|
+
return(data.unpack("H*")) if only_read
|
196
|
+
|
197
|
+
timer = ProconBypassMan::Timer.new
|
198
|
+
begin
|
199
|
+
timer.throw_if_timeout!
|
200
|
+
switch.write_nonblock(data)
|
201
|
+
rescue IO::EAGAINWaitReadable
|
202
|
+
retry
|
203
|
+
rescue ProconBypassMan::Timer::Timeout
|
204
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
205
|
+
raise
|
206
|
+
end
|
207
|
+
rescue ProconBypassMan::Timer::Timeout
|
208
|
+
raise if @throw_error_if_timeout
|
209
|
+
end
|
210
|
+
|
211
|
+
def read_switch(only_read: false)
|
212
|
+
unless @initialized_devices
|
213
|
+
init_devices
|
214
|
+
end
|
215
|
+
|
216
|
+
data = nil
|
217
|
+
timer = ProconBypassMan::Timer.new
|
218
|
+
begin
|
219
|
+
timer.throw_if_timeout!
|
220
|
+
data = switch.read_nonblock(128)
|
221
|
+
ProconBypassMan.logger.debug { " >>> #{data.unpack("H*")})" }
|
222
|
+
rescue IO::EAGAINWaitReadable
|
223
|
+
retry
|
224
|
+
rescue ProconBypassMan::Timer::Timeout
|
225
|
+
ProconBypassMan.logger.error "readでtimeoutになりました"
|
226
|
+
raise
|
227
|
+
end
|
228
|
+
return(data.unpack("H*")) if only_read
|
229
|
+
|
230
|
+
timer = ProconBypassMan::Timer.new
|
231
|
+
begin
|
232
|
+
timer.throw_if_timeout!
|
233
|
+
procon.write_nonblock(data)
|
234
|
+
rescue IO::EAGAINWaitReadable
|
235
|
+
retry
|
236
|
+
rescue ProconBypassMan::Timer::Timeout
|
237
|
+
ProconBypassMan.logger.error "writeでtimeoutになりました"
|
238
|
+
raise
|
239
|
+
end
|
240
|
+
rescue ProconBypassMan::Timer::Timeout
|
241
|
+
raise if @throw_error_if_timeout
|
242
|
+
end
|
243
|
+
|
244
|
+
def from_device(item)
|
245
|
+
case item.read_from
|
246
|
+
when :switch
|
247
|
+
switch
|
248
|
+
when :procon
|
249
|
+
procon
|
250
|
+
else
|
251
|
+
raise
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# fromの対になる
|
256
|
+
def to_device(item)
|
257
|
+
case item.read_from
|
258
|
+
when :switch
|
259
|
+
procon
|
260
|
+
when :procon
|
261
|
+
switch
|
262
|
+
else
|
263
|
+
raise
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def switch
|
268
|
+
@gadget
|
269
|
+
end
|
270
|
+
|
271
|
+
def procon
|
272
|
+
@procon
|
273
|
+
end
|
274
|
+
|
275
|
+
def is_available_device?(path)
|
276
|
+
return false if !File.exist?(path)
|
277
|
+
|
278
|
+
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
279
|
+
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
280
|
+
sleep 0.5
|
281
|
+
|
282
|
+
file = File.open(path, "w+")
|
283
|
+
begin
|
284
|
+
file.read_nonblock(128)
|
285
|
+
rescue EOFError
|
286
|
+
file.close
|
287
|
+
return false
|
288
|
+
rescue IO::EAGAINWaitReadable
|
289
|
+
file.close
|
290
|
+
return true
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
def to_bin(string)
|
295
|
+
string.unpack "H*"
|
296
|
+
end
|
297
|
+
|
298
|
+
def init_devices
|
299
|
+
if @initialized_devices
|
300
|
+
return
|
301
|
+
end
|
302
|
+
|
303
|
+
case
|
304
|
+
when is_available_device?(PROCON_PATH)
|
305
|
+
ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON_PATH}を使います"
|
306
|
+
@procon = File.open(PROCON_PATH, "w+")
|
307
|
+
@gadget = File.open('/dev/hidg0', "w+")
|
308
|
+
when is_available_device?(PROCON2_PATH)
|
309
|
+
ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON2_PATH}を使います"
|
310
|
+
@procon = File.open(PROCON2_PATH, "w+")
|
311
|
+
@gadget = File.open('/dev/hidg0', "w+")
|
312
|
+
else
|
313
|
+
raise "/dev/hidraw0, /dev/hidraw1の両方見つかりませんでした"
|
314
|
+
end
|
315
|
+
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
316
|
+
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
317
|
+
sleep 0.5
|
318
|
+
|
319
|
+
@initialized_devices = true
|
320
|
+
|
321
|
+
if @enable_at_exit
|
322
|
+
at_exit do
|
323
|
+
@procon&.close
|
324
|
+
@gadget&.close
|
325
|
+
end
|
326
|
+
end
|
327
|
+
rescue Errno::ENXIO => e
|
328
|
+
# /dev/hidg0 をopenできないときがある
|
329
|
+
ProconBypassMan.logger.error "Errno::ENXIO (No such device or address @ rb_sysopen - /dev/hidg0)が起きました。resetします"
|
330
|
+
ProconBypassMan.logger.error e
|
331
|
+
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
332
|
+
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
333
|
+
sleep 2
|
334
|
+
retry
|
335
|
+
end
|
336
|
+
end
|
@@ -1,4 +1,5 @@
|
|
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"
|
@@ -9,7 +10,7 @@ class ProconBypassMan::Procon
|
|
9
10
|
|
10
11
|
attr_accessor :user_operation
|
11
12
|
|
12
|
-
def self.
|
13
|
+
def self.reset!
|
13
14
|
@@status = {
|
14
15
|
buttons: {},
|
15
16
|
current_layer_key: :up,
|
@@ -17,7 +18,6 @@ class ProconBypassMan::Procon
|
|
17
18
|
ongoing_mode: ModeRegistry.load(:manual),
|
18
19
|
}
|
19
20
|
end
|
20
|
-
def self.reset!; reset_cvar!; end
|
21
21
|
reset!
|
22
22
|
|
23
23
|
def initialize(binary)
|
@@ -106,18 +106,20 @@ class ProconBypassMan::Procon
|
|
106
106
|
if !status[button]
|
107
107
|
user_operation.unpress_button(button)
|
108
108
|
end
|
109
|
-
|
110
|
-
|
111
|
-
user_operation.unpress_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)
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
current_layer.remaps.each do |from_button,
|
116
|
+
current_layer.remaps.each do |from_button, to_buttons|
|
117
117
|
if user_operation.pressed_button?(from_button)
|
118
118
|
user_operation.unpress_button(from_button)
|
119
119
|
# TODO 2重でpressしないようにしたい
|
120
|
-
|
120
|
+
to_buttons[:to].each do |to_button|
|
121
|
+
user_operation.press_button(to_button) unless user_operation.pressed_button?(to_button)
|
122
|
+
end
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
@@ -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)
|
@@ -3,10 +3,7 @@ require_relative "io_monitor"
|
|
3
3
|
class ProconBypassMan::Runner
|
4
4
|
class InterruptForRestart < StandardError; end
|
5
5
|
|
6
|
-
def initialize
|
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
|
@@ -98,8 +95,11 @@ class ProconBypassMan::Runner
|
|
98
95
|
loop do
|
99
96
|
break if $will_terminate_token
|
100
97
|
bypass.send_procon_to_gadget!
|
98
|
+
rescue EOFError => e
|
99
|
+
ProconBypassMan.logger.error "Proconと通信ができませんでした.終了処理を開始します"
|
100
|
+
Process.kill "TERM", Process.ppid
|
101
101
|
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
102
|
-
ProconBypassMan.logger.error "Procon
|
102
|
+
ProconBypassMan.logger.error "Proconが切断されました。終了処理を開始します"
|
103
103
|
Process.kill "TERM", Process.ppid
|
104
104
|
end
|
105
105
|
ProconBypassMan.logger.info "Thread2を終了します"
|
@@ -133,38 +133,14 @@ class ProconBypassMan::Runner
|
|
133
133
|
end
|
134
134
|
|
135
135
|
def first_negotiation
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
145
|
-
break if $will_terminate_token
|
146
|
-
rescue IO::EAGAINWaitReadable
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# ...
|
151
|
-
# switch) 8001
|
152
|
-
# procon) 8101
|
153
|
-
# switch) 8002
|
154
|
-
# が返ってくるプロトコルがあって、これができていないならやり直す
|
155
|
-
loop do
|
156
|
-
begin
|
157
|
-
data = @procon.read_nonblock(128)
|
158
|
-
if data[0] == "\x81".b && data[1] == "\x01".b
|
159
|
-
ProconBypassMan.logger.debug { "接続を確認しました" }
|
160
|
-
@gadget.write_nonblock(data)
|
161
|
-
break
|
162
|
-
else
|
163
|
-
raise ::ProconBypassMan::FirstConnectionError
|
164
|
-
end
|
165
|
-
rescue IO::EAGAINWaitReadable
|
166
|
-
end
|
167
|
-
end
|
136
|
+
return if $will_terminate_token
|
137
|
+
|
138
|
+
@gadget, @procon = ProconBypassMan::DeviceConnector.connect(throw_error_if_timeout: true, enable_at_exit: false)
|
139
|
+
rescue ProconBypassMan::Timer::Timeout
|
140
|
+
::ProconBypassMan.logger.error "デバイスとの通信でタイムアウトが起きて接続ができませんでした。"
|
141
|
+
@gadget&.close
|
142
|
+
@procon&.close
|
143
|
+
raise ::ProconBypassMan::EternalConnectionError
|
168
144
|
end
|
169
145
|
|
170
146
|
def handle_signal(sig)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: procon_bypass_man
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jiikko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-07-
|
11
|
+
date: 2021-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: extension for Nintendo Switch Pro Controller
|
14
14
|
email:
|
@@ -41,7 +41,7 @@ files:
|
|
41
41
|
- lib/procon_bypass_man/configuration/layer.rb
|
42
42
|
- lib/procon_bypass_man/configuration/loader.rb
|
43
43
|
- lib/procon_bypass_man/configuration/validator.rb
|
44
|
-
- lib/procon_bypass_man/
|
44
|
+
- lib/procon_bypass_man/device_connector.rb
|
45
45
|
- lib/procon_bypass_man/io_monitor.rb
|
46
46
|
- lib/procon_bypass_man/processor.rb
|
47
47
|
- lib/procon_bypass_man/procon.rb
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/procon_bypass_man/procon/pressed_button_helper.rb
|
55
55
|
- lib/procon_bypass_man/procon/user_operation.rb
|
56
56
|
- lib/procon_bypass_man/runner.rb
|
57
|
+
- lib/procon_bypass_man/timer.rb
|
57
58
|
- lib/procon_bypass_man/version.rb
|
58
59
|
- procon_bypass_man.gemspec
|
59
60
|
homepage: https://github.com/splaspla-hacker/procon_bypass_man
|
@@ -1,42 +0,0 @@
|
|
1
|
-
class ProconBypassMan::DeviceRegistry
|
2
|
-
PROCON_PATH = "/dev/hidraw0"
|
3
|
-
PROCON2_PATH = "/dev/hidraw1"
|
4
|
-
|
5
|
-
def gadget
|
6
|
-
@gadget
|
7
|
-
end
|
8
|
-
|
9
|
-
def procon
|
10
|
-
@procon
|
11
|
-
end
|
12
|
-
|
13
|
-
def initialize
|
14
|
-
init_devices
|
15
|
-
end
|
16
|
-
|
17
|
-
# @return [void]
|
18
|
-
def init_devices
|
19
|
-
loop do
|
20
|
-
case
|
21
|
-
when File.exist?(PROCON_PATH)
|
22
|
-
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
23
|
-
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
24
|
-
sleep 0.5
|
25
|
-
@gadget = File.open('/dev/hidg0', "w+")
|
26
|
-
@procon = File.open(PROCON_PATH, "w+")
|
27
|
-
break
|
28
|
-
when File.exist?(PROCON2_PATH)
|
29
|
-
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
30
|
-
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
31
|
-
sleep 0.5
|
32
|
-
@gadget = File.open('/dev/hidg0', "w+")
|
33
|
-
@procon = File.open(PROCON2_PATH, "w+")
|
34
|
-
break
|
35
|
-
else
|
36
|
-
puts "プロコンをラズベイに挿してください"
|
37
|
-
ProconBypassMan.logger.info("プロコンをラズベイに挿してください")
|
38
|
-
sleep(1)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|