procon_bypass_man 0.1.8 → 0.1.12

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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -2
  3. data/.github/workflows/ruby.yml +5 -4
  4. data/.gitignore +5 -0
  5. data/.rubocop.yml +2 -0
  6. data/.ruby-version +1 -1
  7. data/CHANGELOG.md +18 -1
  8. data/Gemfile +4 -0
  9. data/Gemfile.lock +53 -2
  10. data/README.md +14 -8
  11. data/Steepfile +39 -0
  12. data/bin/console +4 -0
  13. data/bin/dev_api_server.rb +18 -0
  14. data/docs/setup_raspi.mitamae.rb +12 -0
  15. data/lib/procon_bypass_man/background/has_server_pool.rb +54 -0
  16. data/lib/procon_bypass_man/background/http_client.rb +70 -0
  17. data/lib/procon_bypass_man/background/job_performer.rb +16 -0
  18. data/lib/procon_bypass_man/background/job_runnable.rb +16 -0
  19. data/lib/procon_bypass_man/background/job_runner.rb +44 -0
  20. data/lib/procon_bypass_man/background/jobs/base_job.rb +12 -0
  21. data/lib/procon_bypass_man/background/jobs/report_boot_job.rb +10 -0
  22. data/lib/procon_bypass_man/background/jobs/report_error_job.rb +10 -0
  23. data/lib/procon_bypass_man/background/jobs/report_heartbeat_job.rb +10 -0
  24. data/lib/procon_bypass_man/background/jobs/report_pressed_buttons_job.rb +18 -0
  25. data/lib/procon_bypass_man/background/jobs/report_reload_config_job.rb +10 -0
  26. data/lib/procon_bypass_man/background.rb +10 -0
  27. data/lib/procon_bypass_man/boot_message.rb +42 -0
  28. data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/layer.rb +50 -4
  29. data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/loader.rb +12 -11
  30. data/lib/procon_bypass_man/{configuration → buttons_setting_configuration}/validator.rb +1 -1
  31. data/lib/procon_bypass_man/buttons_setting_configuration.rb +101 -0
  32. data/lib/procon_bypass_man/bypass/usb_hid_logger.rb +36 -0
  33. data/lib/procon_bypass_man/bypass.rb +61 -29
  34. data/lib/procon_bypass_man/callbacks.rb +70 -0
  35. data/lib/procon_bypass_man/commands/connect_device_command.rb +11 -0
  36. data/lib/procon_bypass_man/commands/print_boot_message_command.rb +9 -0
  37. data/lib/procon_bypass_man/commands/send_error_command.rb +18 -0
  38. data/lib/procon_bypass_man/commands/send_reload_config_event_command.rb +10 -0
  39. data/lib/procon_bypass_man/commands/write_device_id_command.rb +11 -0
  40. data/lib/procon_bypass_man/commands/write_session_id_command.rb +13 -0
  41. data/lib/procon_bypass_man/commands.rb +6 -0
  42. data/lib/procon_bypass_man/configuration.rb +92 -67
  43. data/lib/procon_bypass_man/device_connector.rb +11 -29
  44. data/lib/procon_bypass_man/io_monitor.rb +16 -8
  45. data/lib/procon_bypass_man/on_memory_cache.rb +34 -0
  46. data/lib/procon_bypass_man/procon/analog_stick.rb +31 -0
  47. data/lib/procon_bypass_man/procon/analog_stick_cap.rb +65 -0
  48. data/lib/procon_bypass_man/procon/button_collection.rb +15 -6
  49. data/lib/procon_bypass_man/procon/{data.rb → consts.rb} +1 -1
  50. data/lib/procon_bypass_man/procon/layer_changer.rb +40 -0
  51. data/lib/procon_bypass_man/procon/macro_registry.rb +2 -2
  52. data/lib/procon_bypass_man/procon/mode_registry.rb +4 -4
  53. data/lib/procon_bypass_man/procon/press_button_aware.rb +13 -0
  54. data/lib/procon_bypass_man/procon/user_operation.rb +21 -16
  55. data/lib/procon_bypass_man/procon.rb +23 -9
  56. data/lib/procon_bypass_man/procon_reader.rb +31 -0
  57. data/lib/procon_bypass_man/runner.rb +43 -64
  58. data/lib/procon_bypass_man/uptime.rb +14 -2
  59. data/lib/procon_bypass_man/version.rb +1 -1
  60. data/lib/procon_bypass_man.rb +38 -43
  61. data/project_template/README.md +1 -1
  62. data/project_template/app.rb +7 -5
  63. data/project_template/systemd_units/pbm_web.service +11 -0
  64. data/project_template/web.rb +16 -0
  65. data/sig/README.rb +4 -0
  66. data/sig/main.rbs +505 -0
  67. metadata +42 -11
  68. data/examples/practical/app.rb +0 -21
  69. data/examples/practical/setting.yml +0 -24
  70. data/lib/procon_bypass_man/procon/layer_changeable.rb +0 -28
  71. data/lib/procon_bypass_man/procon/pressed_button_helper.rb +0 -25
@@ -1,86 +1,111 @@
1
- require "procon_bypass_man/configuration/validator"
2
- require "procon_bypass_man/configuration/loader"
3
- require "procon_bypass_man/configuration/layer"
4
-
5
- module ProconBypassMan
6
- class Configuration
7
-
8
- attr_accessor :layers,
9
- :setting_path,
10
- :mode_plugins,
11
- :macro_plugins,
12
- :context,
13
- :current_context_key
14
-
15
- def self.instance
16
- @@current_context_key ||= :main
17
- @@context ||= {}
18
- @@context[@@current_context_key] ||= new
1
+ class ProconBypassMan::Configuration
2
+ module ClassMethods
3
+ def root
4
+ config.root
19
5
  end
20
6
 
21
- def self.switch_new_context(key)
22
- @@context[key] = new
23
- previous_key = @@current_context_key
24
- if block_given?
25
- @@current_context_key = key
26
- value = yield(@@context[key])
27
- @@current_context_key = previous_key
28
- return value
29
- else
30
- @@current_context_key = key
31
- end
7
+ def logger
8
+ config.logger
32
9
  end
33
10
 
34
- def initialize
35
- reset!
11
+ def error_logger
12
+ config.error_logger
36
13
  end
37
14
 
38
- MODES = [:manual]
39
- def layer(direction, mode: :manual, &block)
40
- if mode.respond_to?(:name)
41
- mode_name = mode.name.to_sym
42
- else
43
- mode_name = mode
44
- end
45
- unless (MODES + ProconBypassMan::Procon::ModeRegistry.plugins.keys).include?(mode_name)
46
- raise("#{mode_name} mode is unknown")
47
- end
48
-
49
- layer = Layer.new(mode: mode_name)
50
- layer.instance_eval(&block) if block_given?
51
- self.layers[direction] = layer
52
- self
15
+ def pid_path
16
+ @@pid_path ||= File.expand_path("#{root}/pbm_pid", __dir__).freeze
53
17
  end
54
18
 
55
- def install_mode_plugin(klass)
56
- ProconBypassMan::Procon::ModeRegistry.install_plugin(klass)
57
- self
19
+ def digest_path
20
+ config.digest_path
58
21
  end
59
22
 
60
- def install_macro_plugin(klass)
61
- ProconBypassMan::Procon::MacroRegistry.install_plugin(klass)
62
- self
23
+ def cache
24
+ @@cache_table ||= ProconBypassMan::OnMemoryCache.new
63
25
  end
64
26
 
65
- def prefix_keys_for_changing_layer(buttons)
66
- @prefix_keys_for_changing_layer = buttons
67
- self
27
+ # @return [String]
28
+ def session_id
29
+ ProconBypassMan::WriteSessionIdCommand.execute
68
30
  end
69
31
 
70
- def prefix_keys
71
- @prefix_keys_for_changing_layer
32
+ # @return [String]
33
+ def device_id
34
+ ProconBypassMan::WriteDeviceIdCommand.execute
35
+ end
36
+ end
37
+
38
+ attr_accessor :enable_critical_error_logging, :raw_setting
39
+ attr_writer :verbose_bypass_log
40
+
41
+ def root=(path)
42
+ @root = path
43
+ return self
44
+ end
45
+
46
+ def root
47
+ if defined?(@root)
48
+ @root
49
+ else
50
+ File.expand_path('..', __dir__ || ".").freeze
51
+ end
52
+ end
53
+
54
+ def api_servers=(api_servers)
55
+ @api_servers = api_servers
56
+ return self
57
+ end
58
+
59
+ def logger=(logger)
60
+ @logger = logger
61
+ return self
62
+ end
63
+
64
+ def logger
65
+ if ENV["PBM_ENV"] == 'test'
66
+ return Logger.new($stdout)
72
67
  end
73
68
 
74
- def reset!
75
- @prefix_keys_for_changing_layer = []
76
- self.mode_plugins = {}
77
- self.macro_plugins = {}
78
- self.layers = {
79
- up: Layer.new,
80
- down: Layer.new,
81
- left: Layer.new,
82
- right: Layer.new,
83
- }
69
+ if defined?(@logger) && @logger.is_a?(Logger)
70
+ @logger
71
+ else
72
+ Logger.new(File.open("/dev/null"))
84
73
  end
85
74
  end
75
+
76
+ def error_logger
77
+ if enable_critical_error_logging
78
+ @@error_logger ||= Logger.new("#{ProconBypassMan.root}/error.log", 5, 1024 * 1024 * 10)
79
+ else
80
+ Logger.new(File.open("/dev/null"))
81
+ end
82
+ self
83
+ end
84
+
85
+ def digest_path
86
+ "#{root}/.setting_yaml_digest"
87
+ end
88
+
89
+ # @return [String] pbm-webの接続先
90
+ def internal_api_servers
91
+ if !!ENV["INTERNAL_API_SERVER"]
92
+ [ENV["INTERNAL_API_SERVER"]]
93
+ else
94
+ [ 'http://localhost:9090',
95
+ 'http://localhost:8080',
96
+ ].compact
97
+ end
98
+ end
99
+
100
+ def api_servers
101
+ if !!ENV["API_SERVER"]
102
+ [ENV["API_SERVER"]].reject(&:nil?)
103
+ else
104
+ [@api_servers].flatten.reject(&:nil?)
105
+ end
106
+ end
107
+
108
+ def verbose_bypass_log
109
+ @verbose_bypass_log || !!ENV["VERBOSE_BYPASS_LOG"]
110
+ end
86
111
  end
@@ -12,23 +12,6 @@ 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
15
  def self.connect
33
16
  s = new(throw_error_if_timeout: true, enable_at_exit: false)
34
17
  s.add([
@@ -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(128)
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(128)
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(128)
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(128)
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(128)
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(128)
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
@@ -326,8 +309,7 @@ class ProconBypassMan::DeviceConnector
326
309
  end
327
310
  rescue Errno::ENXIO => e
328
311
  # /dev/hidg0 をopenできないときがある
329
- ProconBypassMan.logger.error "Errno::ENXIO (No such device or address @ rb_sysopen - /dev/hidg0)が起きました。resetします"
330
- ProconBypassMan.logger.error e
312
+ ProconBypassMan::SendErrorCommand.execute(error: "Errno::ENXIO (No such device or address @ rb_sysopen - /dev/hidg0)が起きました。resetします. #{e.full_message}")
331
313
  system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
332
314
  system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
333
315
  sleep 2
@@ -1,11 +1,12 @@
1
1
  module ProconBypassMan
2
2
  class Counter
3
- attr_accessor :label, :table, :previous_table
3
+ attr_accessor :label, :table, :previous_table, :active
4
4
 
5
5
  def initialize(label: )
6
6
  self.label = label
7
7
  self.table = {}
8
8
  self.previous_table = {}
9
+ self.active = true
9
10
  end
10
11
 
11
12
  # アクティブなバケットは1つだけ
@@ -24,7 +25,7 @@ module ProconBypassMan
24
25
  self
25
26
  end
26
27
 
27
- def formated_previous_table
28
+ def formatted_previous_table
28
29
  t = previous_table.dup
29
30
  start_function = t[:start_function] || 0
30
31
  end_function = t[:end_function] || 0
@@ -32,6 +33,10 @@ module ProconBypassMan
32
33
  eagain_wait_readable_on_write = t[:eagain_wait_readable_on_write] || 0
33
34
  "(#{(end_function / start_function.to_f * 100).floor(1)}%(#{end_function}/#{start_function}), loss: #{eagain_wait_readable_on_read}, #{eagain_wait_readable_on_write})"
34
35
  end
36
+
37
+ def shutdown
38
+ self.active = false
39
+ end
35
40
  end
36
41
 
37
42
  module IOMonitor
@@ -51,21 +56,24 @@ module ProconBypassMan
51
56
  Thread.start do
52
57
  max_output_length = 0
53
58
  loop do
54
- list = @@list.dup
59
+ list = @@list.select(&:active).dup
55
60
  unless list.all? { |x| x&.previous_table.is_a?(Hash) }
56
61
  sleep 0.5
57
62
  next
58
63
  end
59
64
 
60
65
  line = list.map { |counter|
61
- "#{counter.label}(#{counter.formated_previous_table})"
66
+ "#{counter.label}(#{counter.formatted_previous_table})"
62
67
  }.join(", ")
63
68
  max_output_length = line.length
64
69
  sleep 0.7
65
- print "\r"
66
- print " " * max_output_length
67
- print "\r"
68
- print line
70
+
71
+ if ENV["PBM_FOREGROUND"]
72
+ print "\r"
73
+ print " " * max_output_length
74
+ print "\r"
75
+ print line
76
+ end
69
77
  ProconBypassMan.logger.debug { line }
70
78
  break if $will_terminate_token
71
79
  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,31 @@
1
+ class ProconBypassMan::Procon::AnalogStick
2
+ attr_accessor :neutral_position
3
+ attr_accessor :bin_x, :bin_y
4
+
5
+ def initialize(binary: )
6
+ @neutral_position = ProconBypassMan::ButtonsSettingConfiguration.instance.neutral_position
7
+
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
+ self.bin_x = "#{byte7[4..7]}#{byte6}"
13
+ self.bin_y = "#{byte8}#{byte7[0..3]}"
14
+ end
15
+
16
+ def abs_x
17
+ bin_x.to_i(2)
18
+ end
19
+
20
+ def abs_y
21
+ bin_y.to_i(2)
22
+ end
23
+
24
+ def relative_x
25
+ bin_x.to_i(2) - neutral_position.x
26
+ end
27
+
28
+ def relative_y
29
+ bin_y.to_i(2) - neutral_position.y
30
+ end
31
+ end
@@ -0,0 +1,65 @@
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
+ def initialize(binary)
22
+ @binary = binary
23
+ @analog_stick = ProconBypassMan::Procon::AnalogStick.new(binary: binary)
24
+ end
25
+
26
+ # @return [ProconBypassMan::Procon::AnalogStickCap::Position]
27
+ def capped_position(cap_hypotenuse: )
28
+ if hypotenuse > cap_hypotenuse
29
+ relative_capped_x = cap_hypotenuse * Math.cos(rad * Math::PI / 180).abs
30
+ relative_capped_y = cap_hypotenuse * Math.sin(rad * Math::PI / 180).abs
31
+ relative_capped_x = -(relative_capped_x.abs) if relative_x.negative?
32
+ relative_capped_y = -(relative_capped_y.abs) if relative_y.negative?
33
+ return Position.new(
34
+ x: relative_capped_x + @analog_stick.neutral_position.x,
35
+ y: relative_capped_y + @analog_stick.neutral_position.y,
36
+ )
37
+ else
38
+ return position
39
+ end
40
+ end
41
+
42
+ # @return [ProconBypassMan::Procon::AnalogStickCap::Position]
43
+ def position
44
+ Position.new(x: abs_x, y: abs_y)
45
+ end
46
+
47
+ def abs_x; @analog_stick.abs_x; end # 0, 0からのx
48
+ def abs_y; @analog_stick.abs_y; end # 0, 0からのy
49
+ def relative_x; @analog_stick.relative_x; end
50
+ def relative_y; @analog_stick.relative_y; end
51
+
52
+ # @deprecated
53
+ def x; relative_x; end
54
+ def y; relative_y; end
55
+
56
+ def rad
57
+ (
58
+ Math.atan(relative_y / relative_x.to_f) * 180 / Math::PI
59
+ ).floor(6)
60
+ end
61
+
62
+ def hypotenuse
63
+ Math.sqrt(relative_x**2 + relative_y**2).floor(6)
64
+ end
65
+ 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,11 +29,15 @@ 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|
30
38
  next acc if value[1].nil?
31
39
  value[1].reverse.each.with_index do |button, index|
40
+ next(acc) if button == :grip || button == :_undefined_key
32
41
  acc[button] = { byte_position: value[0], bit_position: index }
33
42
  end
34
43
  acc
@@ -1,5 +1,5 @@
1
1
  class ProconBypassMan::Procon
2
- module Data
2
+ module Consts
3
3
  NO_ACTION = "30f28100800078c77448287509550274ff131029001b0022005a0271ff191028001e00210064027cff1410280020002100000000000000000000000000000000".freeze
4
4
  end
5
5
  end
@@ -0,0 +1,40 @@
1
+ class ProconBypassMan::Procon::LayerChanger
2
+ def initialize(binary: )
3
+ @procon_reader = ProconBypassMan::ProconReader.new(binary: binary)
4
+ end
5
+
6
+ # @return [Symbol]
7
+ def next_layer_key
8
+ case
9
+ when pressed?(button: :up)
10
+ :up
11
+ when pressed?(button: :right)
12
+ :right
13
+ when pressed?(button: :left)
14
+ :left
15
+ when pressed?(button: :down)
16
+ :down
17
+ else
18
+ ProconBypassMan.logger.warn("next_layer_key is unknown")
19
+ :up
20
+ end
21
+ end
22
+
23
+ # @return [Boolean]
24
+ def change_layer?
25
+ if ProconBypassMan::ButtonsSettingConfiguration.instance.prefix_keys.empty?
26
+ raise "prefix_keysが未設定です"
27
+ end
28
+ ProconBypassMan::ButtonsSettingConfiguration.instance.prefix_keys.map { |b| pressed?(button: b) }.all?
29
+ end
30
+
31
+ # @return [Boolean]
32
+ def pressed_next_layer?
33
+ change_layer? && (pressed?(button: :up) || pressed?(button: :right) || pressed?(button: :left) || pressed?(button: :down))
34
+ end
35
+
36
+ # @return [Boolean]
37
+ def pressed?(button: )
38
+ @procon_reader.pressed.include?(button)
39
+ end
40
+ end
@@ -37,11 +37,11 @@ class ProconBypassMan::Procon::MacroRegistry
37
37
  end
38
38
 
39
39
  def self.reset!
40
- ProconBypassMan::Configuration.instance.macro_plugins = {}
40
+ ProconBypassMan::ButtonsSettingConfiguration.instance.macro_plugins = {}
41
41
  end
42
42
 
43
43
  def self.plugins
44
- ProconBypassMan::Configuration.instance.macro_plugins
44
+ ProconBypassMan::ButtonsSettingConfiguration.instance.macro_plugins
45
45
  end
46
46
 
47
47
  reset!
@@ -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)
@@ -35,11 +35,11 @@ class ProconBypassMan::Procon::ModeRegistry
35
35
  end
36
36
 
37
37
  def self.reset!
38
- ProconBypassMan::Configuration.instance.mode_plugins = {}
38
+ ProconBypassMan::ButtonsSettingConfiguration.instance.mode_plugins = {}
39
39
  end
40
40
 
41
41
  def self.plugins
42
- ProconBypassMan::Configuration.instance.mode_plugins
42
+ ProconBypassMan::ButtonsSettingConfiguration.instance.mode_plugins
43
43
  end
44
44
 
45
45
  reset!
@@ -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