procon_bypass_man 0.1.8 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
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