Skip to content

Commit 96cc3f8

Browse files
committed
BSNESv115: implement an extended gamepad controller with 4 extra buttons
this is a breaking change for existing movies, but only when a non-gamepad controller was used, which is rare
1 parent 339994c commit 96cc3f8

File tree

9 files changed

+92
-29
lines changed

9 files changed

+92
-29
lines changed

Assets/dll/bsnes.wbx.zst

-3.22 KB
Binary file not shown.

src/BizHawk.Client.Common/movie/import/LsmvImport.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ protected override void RunImport()
5454
ss.LeftPort = port1 switch
5555
{
5656
"none" => BsnesApi.BSNES_PORT1_INPUT_DEVICE.None,
57-
// "gamepad16" => BsnesApi.BSNES_PORT1_INPUT_DEVICE.ExtendedGamepad, // coming soon (hopefully)
57+
"gamepad16" => BsnesApi.BSNES_PORT1_INPUT_DEVICE.ExtendedGamepad,
5858
"multitap" => BsnesApi.BSNES_PORT1_INPUT_DEVICE.SuperMultitap,
5959
"multitap16" => BsnesApi.BSNES_PORT1_INPUT_DEVICE.Payload,
6060
_ => BsnesApi.BSNES_PORT1_INPUT_DEVICE.Gamepad
@@ -68,7 +68,7 @@ protected override void RunImport()
6868
ss.RightPort = port2 switch
6969
{
7070
"none" => BsnesApi.BSNES_INPUT_DEVICE.None,
71-
// "gamepad16" => BsnesApi.BSNES_INPUT_DEVICE.ExtendedGamepad, // coming soon (hopefully)
71+
"gamepad16" => BsnesApi.BSNES_INPUT_DEVICE.ExtendedGamepad,
7272
"multitap" => BsnesApi.BSNES_INPUT_DEVICE.SuperMultitap,
7373
"multitap16" => BsnesApi.BSNES_INPUT_DEVICE.Payload,
7474
// will these even work lol

src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesApi_Enums.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,22 +126,24 @@ public enum BSNES_INPUT_DEVICE
126126
{
127127
None = 0,
128128
Gamepad = 1,
129-
Mouse = 2,
130-
SuperMultitap = 3,
131-
Payload = 4,
132-
SuperScope = 5,
133-
Justifier = 6,
134-
Justifiers = 7
129+
ExtendedGamepad = 2,
130+
Mouse = 3,
131+
SuperMultitap = 4,
132+
Payload = 5,
133+
SuperScope = 6,
134+
Justifier = 7,
135+
Justifiers = 8
135136
}
136137

137138
/// this a subset of the <see cref="BSNES_INPUT_DEVICE"/> enum with all lightgun controllers removed
138139
public enum BSNES_PORT1_INPUT_DEVICE
139140
{
140141
None = 0,
141142
Gamepad = 1,
142-
Mouse = 2,
143-
SuperMultitap = 3,
144-
Payload = 4
143+
ExtendedGamepad = 2,
144+
Mouse = 3,
145+
SuperMultitap = 4,
146+
Payload = 5
145147
}
146148

147149
public enum ENTROPY

src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesControllers.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ private static IBsnesController GetController(BSNES_INPUT_DEVICE t, BsnesCore.Sn
1717
{
1818
BSNES_INPUT_DEVICE.None => new BsnesUnpluggedController(),
1919
BSNES_INPUT_DEVICE.Gamepad => new BsnesController(),
20+
BSNES_INPUT_DEVICE.ExtendedGamepad => new BsnesExtendedController(),
2021
BSNES_INPUT_DEVICE.Mouse => new BsnesMouseController
2122
{
2223
LimitAnalogChangeSensitivity = ss.LimitAnalogChangeSensitivity
@@ -128,6 +129,48 @@ public short GetState(IController controller, int index, int id)
128129
return (short) (controller.IsPressed(Buttons[id]) ? 1 : 0);
129130
}
130131
}
132+
internal class BsnesExtendedController : IBsnesController
133+
{
134+
private static readonly string[] Buttons =
135+
{
136+
"0Up", "0Down", "0Left", "0Right", "0B", "0A", "0Y", "0X", "0L", "0R", "0Select", "0Start", "0Extra1", "0Extra2", "0Extra3", "0Extra4"
137+
};
138+
139+
private static readonly Dictionary<string, int> DisplayButtonOrder = new()
140+
{
141+
["0B"] = 0,
142+
["0Y"] = 1,
143+
["0Select"] = 2,
144+
["0Start"] = 3,
145+
["0Up"] = 4,
146+
["0Down"] = 5,
147+
["0Left"] = 6,
148+
["0Right"] = 7,
149+
["0A"] = 8,
150+
["0X"] = 9,
151+
["0L"] = 10,
152+
["0R"] = 11,
153+
["0Extra1"] = 12,
154+
["0Extra2"] = 13,
155+
["0Extra3"] = 14,
156+
["0Extra4"] = 15
157+
};
158+
159+
private static readonly ControllerDefinition _definition = new("(SNES Controller fragment)")
160+
{
161+
BoolButtons = Buttons.OrderBy(b => DisplayButtonOrder[b]).ToList()
162+
};
163+
164+
public ControllerDefinition Definition => _definition;
165+
166+
public short GetState(IController controller, int index, int id)
167+
{
168+
if (id >= 16)
169+
return 0;
170+
171+
return (short) (controller.IsPressed(Buttons[id]) ? 1 : 0);
172+
}
173+
}
131174

132175
internal class BsnesMouseController : IBsnesController
133176
{

src/BizHawk.Emulation.Cores/vpads_schemata/SnesSchema.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,9 @@ private IEnumerable<PadSchema> GetBsnesPadSchemas(ISettable<BsnesCore.SnesSettin
134134
case BsnesApi.BSNES_INPUT_DEVICE.Gamepad:
135135
yield return StandardController(playerNum);
136136
break;
137+
case BsnesApi.BSNES_INPUT_DEVICE.ExtendedGamepad:
138+
yield return ExtendedStandardController(playerNum);
139+
break;
137140
case BsnesApi.BSNES_INPUT_DEVICE.Mouse:
138141
yield return Mouse(playerNum);
139142
break;

waterbox/bsnescore/bsnes/sfc/controller/controller.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ auto ControllerPort::connect(uint deviceID) -> void {
4747
switch(deviceID) { default:
4848
case ID::Device::None: device = new Controller(port); break;
4949
case ID::Device::Gamepad: device = new Gamepad(port); break;
50+
case ID::Device::ExtendedGamepad: device = new Gamepad(port, true); break;
5051
case ID::Device::Mouse: device = new Mouse(port); break;
5152
case ID::Device::SuperMultitap: device = new SuperMultitap(port, false); break;
5253
case ID::Device::Payload: device = new SuperMultitap(port, true); break;
Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
Gamepad::Gamepad(uint port) : Controller(port) {
1+
Gamepad::Gamepad(uint port, bool isPayloadController) : Controller(port), isPayload(isPayloadController) {
2+
device = isPayloadController ? ID::Device::ExtendedGamepad : ID::Device::Gamepad;
23
latched = 0;
34
counter = 0;
45
}
56

67
auto Gamepad::data() -> uint2 {
78
if(counter >= 16) return 1;
8-
if(latched == 1) return platform->inputPoll(port, ID::Device::Gamepad, B);
9+
if(latched == 1) return platform->inputPoll(port, device, B);
10+
if (counter >= 12 && !isPayload) return 0; //12-15: signature
911

1012
//note: D-pad physically prevents up+down and left+right from being pressed at the same time
1113
// patched this "fix" out because it is handled in bizhawk frontend and fixing it here does not seem right anyway
@@ -22,9 +24,12 @@ auto Gamepad::data() -> uint2 {
2224
case 9: return x;
2325
case 10: return l;
2426
case 11: return r;
27+
case 12: return extra1;
28+
case 13: return extra2;
29+
case 14: return extra3;
30+
case 15: return extra4;
2531
}
26-
27-
return 0; //12-15: signature
32+
unreachable;
2833
}
2934

3035
auto Gamepad::latch(bool data) -> void {
@@ -34,17 +39,22 @@ auto Gamepad::latch(bool data) -> void {
3439

3540
if(latched == 0) {
3641
if (port == ID::Port::Controller1) platform->notify("LATCH");
37-
b = platform->inputPoll(port, ID::Device::Gamepad, B);
38-
y = platform->inputPoll(port, ID::Device::Gamepad, Y);
39-
select = platform->inputPoll(port, ID::Device::Gamepad, Select);
40-
start = platform->inputPoll(port, ID::Device::Gamepad, Start);
41-
up = platform->inputPoll(port, ID::Device::Gamepad, Up);
42-
down = platform->inputPoll(port, ID::Device::Gamepad, Down);
43-
left = platform->inputPoll(port, ID::Device::Gamepad, Left);
44-
right = platform->inputPoll(port, ID::Device::Gamepad, Right);
45-
a = platform->inputPoll(port, ID::Device::Gamepad, A);
46-
x = platform->inputPoll(port, ID::Device::Gamepad, X);
47-
l = platform->inputPoll(port, ID::Device::Gamepad, L);
48-
r = platform->inputPoll(port, ID::Device::Gamepad, R);
42+
b = platform->inputPoll(port, device, B);
43+
y = platform->inputPoll(port, device, Y);
44+
select = platform->inputPoll(port, device, Select);
45+
start = platform->inputPoll(port, device, Start);
46+
up = platform->inputPoll(port, device, Up);
47+
down = platform->inputPoll(port, device, Down);
48+
left = platform->inputPoll(port, device, Left);
49+
right = platform->inputPoll(port, device, Right);
50+
a = platform->inputPoll(port, device, A);
51+
x = platform->inputPoll(port, device, X);
52+
l = platform->inputPoll(port, device, L);
53+
r = platform->inputPoll(port, device, R);
54+
if (!isPayload) return;
55+
extra1 = platform->inputPoll(port, device, Extra1);
56+
extra2 = platform->inputPoll(port, device, Extra2);
57+
extra3 = platform->inputPoll(port, device, Extra3);
58+
extra4 = platform->inputPoll(port, device, Extra4);
4959
}
5060
}
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
11
struct Gamepad : Controller {
22
enum : uint {
3-
Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start,
3+
Up, Down, Left, Right, B, A, Y, X, L, R, Select, Start, Extra1, Extra2, Extra3, Extra4
44
};
55

6-
Gamepad(uint port);
6+
Gamepad(uint port, bool isPayloadController = false);
77

88
auto data() -> uint2;
99
auto latch(bool data) -> void;
1010

1111
private:
12+
bool isPayload;
13+
uint device;
1214
uint counter;
1315

1416
boolean b, y, select, start;
1517
boolean up, down, left, right;
1618
boolean a, x, l, r;
19+
boolean extra1, extra2, extra3, extra4;
1720
};

waterbox/bsnescore/bsnes/sfc/interface/interface.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ struct ID {
1919
struct Device { enum : uint {
2020
None,
2121
Gamepad,
22+
ExtendedGamepad,
2223
Mouse,
2324
SuperMultitap,
2425
Payload,

0 commit comments

Comments
 (0)