Snes Support (#205)
* SNES product ID found, logic partially filled. Icon added. * Bluetooth working, icon working. Wired still laggy. * Fixed wired connection and stick centering issues
This commit is contained in:
parent
8838f2edba
commit
ac17d06aa0
8 changed files with 223 additions and 191 deletions
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2036
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29418.71
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterJoyForCemu", "BetterJoyForCemu\BetterJoyForCemu.csproj", "{1BF709E9-C133-41DF-933A-C9FF3F664C7B}"
|
||||
EndProject
|
||||
|
@ -15,8 +15,8 @@ Global
|
|||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1BF709E9-C133-41DF-933A-C9FF3F664C7B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1BF709E9-C133-41DF-933A-C9FF3F664C7B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1BF709E9-C133-41DF-933A-C9FF3F664C7B}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{1BF709E9-C133-41DF-933A-C9FF3F664C7B}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{1BF709E9-C133-41DF-933A-C9FF3F664C7B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{1BF709E9-C133-41DF-933A-C9FF3F664C7B}.Debug|x64.Build.0 = Debug|x64
|
||||
{1BF709E9-C133-41DF-933A-C9FF3F664C7B}.Debug|x86.ActiveCfg = Debug|x86
|
||||
|
|
|
@ -174,6 +174,7 @@
|
|||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Icons\snes.png" />
|
||||
<None Include="Properties\app.manifest" />
|
||||
<Content Include="Icons\betterjoyforcemu_icon.ico" />
|
||||
<Content Include="hidapi.dll">
|
||||
|
@ -215,9 +216,9 @@
|
|||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\packages\Fody.4.2.1\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.4.2.1\build\Fody.targets'))" />
|
||||
<Error Condition="!Exists('..\packages\Costura.Fody.3.3.1\build\Costura.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Costura.Fody.3.3.1\build\Costura.Fody.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Fielder.Fody.1.2.3\build\Fielder.Fody.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fielder.Fody.1.2.3\build\Fielder.Fody.props'))" />
|
||||
<Error Condition="!Exists('..\packages\Fody.4.2.1\build\Fody.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Fody.4.2.1\build\Fody.targets'))" />
|
||||
</Target>
|
||||
<Import Project="..\packages\Fody.4.2.1\build\Fody.targets" Condition="Exists('..\packages\Fody.4.2.1\build\Fody.targets')" />
|
||||
</Project>
|
BIN
BetterJoyForCemu/Icons/snes.png
Normal file
BIN
BetterJoyForCemu/Icons/snes.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 37 KiB |
|
@ -18,6 +18,7 @@ namespace BetterJoyForCemu {
|
|||
|
||||
public string path = String.Empty;
|
||||
public bool isPro = false;
|
||||
public bool isSnes = false;
|
||||
bool isUSB = false;
|
||||
public Joycon other;
|
||||
|
||||
|
@ -234,7 +235,7 @@ namespace BetterJoyForCemu {
|
|||
|
||||
private float[] activeData;
|
||||
|
||||
public Joycon(IntPtr handle_, bool imu, bool localize, float alpha, bool left, string path, string serialNum, int id = 0, bool isPro = false) {
|
||||
public Joycon(IntPtr handle_, bool imu, bool localize, float alpha, bool left, string path, string serialNum, int id = 0, bool isPro = false, bool isSnes = false) {
|
||||
serial_number = serialNum;
|
||||
activeData = new float[6];
|
||||
handle = handle_;
|
||||
|
@ -246,7 +247,8 @@ namespace BetterJoyForCemu {
|
|||
|
||||
PadId = id;
|
||||
LED = (byte)(0x1 << PadId);
|
||||
this.isPro = isPro;
|
||||
this.isPro = isPro || isSnes;
|
||||
this.isSnes = isSnes;
|
||||
isUSB = serialNum == "000000000001";
|
||||
|
||||
this.path = path;
|
||||
|
@ -474,7 +476,7 @@ namespace BetterJoyForCemu {
|
|||
xin.SendReport(report);
|
||||
}
|
||||
|
||||
if (ts_en == raw_buf[1]) {
|
||||
if (ts_en == raw_buf[1] && !isSnes) {
|
||||
form.AppendTextBox("Duplicate timestamp enqueued.\r\n");
|
||||
DebugPrint(string.Format("Duplicate timestamp enqueued. TS: {0:X2}", ts_en), DebugType.THREADING);
|
||||
}
|
||||
|
@ -490,7 +492,7 @@ namespace BetterJoyForCemu {
|
|||
Stopwatch watch = new Stopwatch();
|
||||
watch.Start();
|
||||
while (!stop_polling & state > state_.NO_JOYCONS) {
|
||||
if (isUSB || rumble_obj.t > 0)
|
||||
if (!isSnes && (isUSB || rumble_obj.t > 0))
|
||||
SendRumble(rumble_obj.GetData());
|
||||
else if (watch.ElapsedMilliseconds >= 1000) {
|
||||
// Send a no-op operation as heartbeat to keep connection alive.
|
||||
|
@ -541,39 +543,40 @@ namespace BetterJoyForCemu {
|
|||
bool swapXY = Boolean.Parse(ConfigurationManager.AppSettings["SwapXY"]);
|
||||
private int ProcessButtonsAndStick(byte[] report_buf) {
|
||||
if (report_buf[0] == 0x00) return -1;
|
||||
if (!isSnes) {
|
||||
stick_raw[0] = report_buf[6 + (isLeft ? 0 : 3)];
|
||||
stick_raw[1] = report_buf[7 + (isLeft ? 0 : 3)];
|
||||
stick_raw[2] = report_buf[8 + (isLeft ? 0 : 3)];
|
||||
|
||||
stick_raw[0] = report_buf[6 + (isLeft ? 0 : 3)];
|
||||
stick_raw[1] = report_buf[7 + (isLeft ? 0 : 3)];
|
||||
stick_raw[2] = report_buf[8 + (isLeft ? 0 : 3)];
|
||||
if (isPro) {
|
||||
stick2_raw[0] = report_buf[6 + (!isLeft ? 0 : 3)];
|
||||
stick2_raw[1] = report_buf[7 + (!isLeft ? 0 : 3)];
|
||||
stick2_raw[2] = report_buf[8 + (!isLeft ? 0 : 3)];
|
||||
}
|
||||
|
||||
if (isPro) {
|
||||
stick2_raw[0] = report_buf[6 + (!isLeft ? 0 : 3)];
|
||||
stick2_raw[1] = report_buf[7 + (!isLeft ? 0 : 3)];
|
||||
stick2_raw[2] = report_buf[8 + (!isLeft ? 0 : 3)];
|
||||
}
|
||||
stick_precal[0] = (UInt16)(stick_raw[0] | ((stick_raw[1] & 0xf) << 8));
|
||||
stick_precal[1] = (UInt16)((stick_raw[1] >> 4) | (stick_raw[2] << 4));
|
||||
ushort[] cal = form.nonOriginal ? new ushort[6] { 2048, 2048, 2048, 2048, 2048, 2048 } : stick_cal;
|
||||
ushort dz = form.nonOriginal ? (ushort)200 : deadzone;
|
||||
stick = CenterSticks(stick_precal, cal, dz);
|
||||
|
||||
stick_precal[0] = (UInt16)(stick_raw[0] | ((stick_raw[1] & 0xf) << 8));
|
||||
stick_precal[1] = (UInt16)((stick_raw[1] >> 4) | (stick_raw[2] << 4));
|
||||
ushort[] cal = form.nonOriginal ? new ushort[6] { 2048, 2048, 2048, 2048, 2048, 2048 } : stick_cal;
|
||||
ushort dz = form.nonOriginal ? (ushort)200 : deadzone;
|
||||
stick = CenterSticks(stick_precal, cal, dz);
|
||||
if (isPro) {
|
||||
stick2_precal[0] = (UInt16)(stick2_raw[0] | ((stick2_raw[1] & 0xf) << 8));
|
||||
stick2_precal[1] = (UInt16)((stick2_raw[1] >> 4) | (stick2_raw[2] << 4));
|
||||
stick2 = CenterSticks(stick2_precal, form.nonOriginal ? cal : stick2_cal, deadzone2);
|
||||
}
|
||||
|
||||
if (isPro) {
|
||||
stick2_precal[0] = (UInt16)(stick2_raw[0] | ((stick2_raw[1] & 0xf) << 8));
|
||||
stick2_precal[1] = (UInt16)((stick2_raw[1] >> 4) | (stick2_raw[2] << 4));
|
||||
stick2 = CenterSticks(stick2_precal, form.nonOriginal ? cal : stick2_cal, deadzone2);
|
||||
}
|
||||
// Read other Joycon's sticks
|
||||
if (isLeft && other != null && other != this) {
|
||||
stick2 = otherStick;
|
||||
other.otherStick = stick;
|
||||
}
|
||||
|
||||
// Read other Joycon's sticks
|
||||
if (isLeft && other != null && other != this) {
|
||||
stick2 = otherStick;
|
||||
other.otherStick = stick;
|
||||
}
|
||||
|
||||
if (!isLeft && other != null && other != this) {
|
||||
Array.Copy(stick, stick2, 2);
|
||||
stick = otherStick;
|
||||
other.otherStick = stick2;
|
||||
if (!isLeft && other != null && other != this) {
|
||||
Array.Copy(stick, stick2, 2);
|
||||
stick = otherStick;
|
||||
other.otherStick = stick2;
|
||||
}
|
||||
}
|
||||
//
|
||||
|
||||
|
@ -688,14 +691,16 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
if (xin != null) {
|
||||
if (other != null || isPro) { // no need for && other != this
|
||||
report.SetAxis(Xbox360Axes.LeftThumbX, CastStickValue((other == this && !isLeft) ? stick2[0] : stick[0]));
|
||||
report.SetAxis(Xbox360Axes.LeftThumbY, CastStickValue((other == this && !isLeft) ? stick2[1] : stick[1]));
|
||||
report.SetAxis(Xbox360Axes.RightThumbX, CastStickValue((other == this && !isLeft) ? stick[0] : stick2[0]));
|
||||
report.SetAxis(Xbox360Axes.RightThumbY, CastStickValue((other == this && !isLeft) ? stick[1] : stick2[1]));
|
||||
} else { // single joycon mode
|
||||
report.SetAxis(Xbox360Axes.LeftThumbY, CastStickValue((isLeft ? 1 : -1) * stick[0]));
|
||||
report.SetAxis(Xbox360Axes.LeftThumbX, CastStickValue((isLeft ? -1 : 1) * stick[1]));
|
||||
if (!isSnes) {
|
||||
if (other != null || isPro) { // no need for && other != this
|
||||
report.SetAxis(Xbox360Axes.LeftThumbX, CastStickValue((other == this && !isLeft) ? stick2[0] : stick[0]));
|
||||
report.SetAxis(Xbox360Axes.LeftThumbY, CastStickValue((other == this && !isLeft) ? stick2[1] : stick[1]));
|
||||
report.SetAxis(Xbox360Axes.RightThumbX, CastStickValue((other == this && !isLeft) ? stick[0] : stick2[0]));
|
||||
report.SetAxis(Xbox360Axes.RightThumbY, CastStickValue((other == this && !isLeft) ? stick[1] : stick2[1]));
|
||||
} else { // single joycon mode
|
||||
report.SetAxis(Xbox360Axes.LeftThumbY, CastStickValue((isLeft ? 1 : -1) * stick[0]));
|
||||
report.SetAxis(Xbox360Axes.LeftThumbX, CastStickValue((isLeft ? -1 : 1) * stick[1]));
|
||||
}
|
||||
}
|
||||
report.SetAxis(Xbox360Axes.LeftTrigger, (short)(buttons[(int)(isLeft ? Button.SHOULDER_2 : Button.SHOULDER2_2)] ? Int16.MaxValue : 0));
|
||||
report.SetAxis(Xbox360Axes.RightTrigger, (short)(buttons[(int)(isLeft ? Button.SHOULDER2_2 : Button.SHOULDER_2)] ? Int16.MaxValue : 0));
|
||||
|
@ -705,82 +710,84 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
private void ExtractIMUValues(byte[] report_buf, int n = 0) {
|
||||
gyr_r[0] = (Int16)(report_buf[19 + n * 12] | ((report_buf[20 + n * 12] << 8) & 0xff00));
|
||||
gyr_r[1] = (Int16)(report_buf[21 + n * 12] | ((report_buf[22 + n * 12] << 8) & 0xff00));
|
||||
gyr_r[2] = (Int16)(report_buf[23 + n * 12] | ((report_buf[24 + n * 12] << 8) & 0xff00));
|
||||
acc_r[0] = (Int16)(report_buf[13 + n * 12] | ((report_buf[14 + n * 12] << 8) & 0xff00));
|
||||
acc_r[1] = (Int16)(report_buf[15 + n * 12] | ((report_buf[16 + n * 12] << 8) & 0xff00));
|
||||
acc_r[2] = (Int16)(report_buf[17 + n * 12] | ((report_buf[18 + n * 12] << 8) & 0xff00));
|
||||
if (!isSnes) {
|
||||
gyr_r[0] = (Int16)(report_buf[19 + n * 12] | ((report_buf[20 + n * 12] << 8) & 0xff00));
|
||||
gyr_r[1] = (Int16)(report_buf[21 + n * 12] | ((report_buf[22 + n * 12] << 8) & 0xff00));
|
||||
gyr_r[2] = (Int16)(report_buf[23 + n * 12] | ((report_buf[24 + n * 12] << 8) & 0xff00));
|
||||
acc_r[0] = (Int16)(report_buf[13 + n * 12] | ((report_buf[14 + n * 12] << 8) & 0xff00));
|
||||
acc_r[1] = (Int16)(report_buf[15 + n * 12] | ((report_buf[16 + n * 12] << 8) & 0xff00));
|
||||
acc_r[2] = (Int16)(report_buf[17 + n * 12] | ((report_buf[18 + n * 12] << 8) & 0xff00));
|
||||
|
||||
|
||||
if (form.nonOriginal) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
acc_g.X = (acc_r[i] - activeData[3]) * (1.0f / acc_sen[i]) * 4.0f;
|
||||
gyr_g.X = (gyr_r[i] - activeData[0]) * (816.0f / gyr_sen[i]);
|
||||
if (form.calibrate) {
|
||||
form.xA.Add(acc_r[i]);
|
||||
form.xG.Add(gyr_r[i]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
acc_g.Y = (!isLeft ? -1 : 1) * (acc_r[i] - activeData[4]) * (1.0f / acc_sen[i]) * 4.0f;
|
||||
gyr_g.Y = -(!isLeft ? -1 : 1) * (gyr_r[i] - activeData[1]) * (816.0f / gyr_sen[i]);
|
||||
if (form.calibrate) {
|
||||
form.yA.Add(acc_r[i]);
|
||||
form.yG.Add(gyr_r[i]);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
acc_g.Z = (!isLeft ? -1 : 1) * (acc_r[i] - activeData[5]) * (1.0f / acc_sen[i]) * 4.0f;
|
||||
gyr_g.Z = -(!isLeft ? -1 : 1) * (gyr_r[i] - activeData[2]) * (816.0f / gyr_sen[i]);
|
||||
if (form.calibrate) {
|
||||
form.zA.Add(acc_r[i]);
|
||||
form.zG.Add(gyr_r[i]);
|
||||
}
|
||||
break;
|
||||
if (form.nonOriginal) {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
acc_g.X = (acc_r[i] - activeData[3]) * (1.0f / acc_sen[i]) * 4.0f;
|
||||
gyr_g.X = (gyr_r[i] - activeData[0]) * (816.0f / gyr_sen[i]);
|
||||
if (form.calibrate) {
|
||||
form.xA.Add(acc_r[i]);
|
||||
form.xG.Add(gyr_r[i]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
acc_g.Y = (!isLeft ? -1 : 1) * (acc_r[i] - activeData[4]) * (1.0f / acc_sen[i]) * 4.0f;
|
||||
gyr_g.Y = -(!isLeft ? -1 : 1) * (gyr_r[i] - activeData[1]) * (816.0f / gyr_sen[i]);
|
||||
if (form.calibrate) {
|
||||
form.yA.Add(acc_r[i]);
|
||||
form.yG.Add(gyr_r[i]);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
acc_g.Z = (!isLeft ? -1 : 1) * (acc_r[i] - activeData[5]) * (1.0f / acc_sen[i]) * 4.0f;
|
||||
gyr_g.Z = -(!isLeft ? -1 : 1) * (gyr_r[i] - activeData[2]) * (816.0f / gyr_sen[i]);
|
||||
if (form.calibrate) {
|
||||
form.zA.Add(acc_r[i]);
|
||||
form.zG.Add(gyr_r[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Int16[] offset;
|
||||
if (isPro)
|
||||
offset = pro_hor_offset;
|
||||
else if (isLeft)
|
||||
offset = left_hor_offset;
|
||||
else
|
||||
offset = right_hor_offset;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
acc_g.X = (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
|
||||
gyr_g.X = (gyr_r[i] - gyr_neutral[i]) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
|
||||
|
||||
break;
|
||||
case 1:
|
||||
acc_g.Y = (!isLeft ? -1 : 1) * (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
|
||||
gyr_g.Y = -(!isLeft ? -1 : 1) * (gyr_r[i] - gyr_neutral[i]) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
|
||||
break;
|
||||
case 2:
|
||||
acc_g.Z = (!isLeft ? -1 : 1) * (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
|
||||
gyr_g.Z = -(!isLeft ? -1 : 1) * (gyr_r[i] - gyr_neutral[i]) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (other == null && !isPro) { // single joycon mode; Z do not swap, rest do
|
||||
if (isLeft) {
|
||||
acc_g.X = -acc_g.X;
|
||||
gyr_g.X = -gyr_g.X;
|
||||
} else {
|
||||
gyr_g.Y = -gyr_g.Y;
|
||||
Int16[] offset;
|
||||
if (isPro)
|
||||
offset = pro_hor_offset;
|
||||
else if (isLeft)
|
||||
offset = left_hor_offset;
|
||||
else
|
||||
offset = right_hor_offset;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
acc_g.X = (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
|
||||
gyr_g.X = (gyr_r[i] - gyr_neutral[i]) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
|
||||
|
||||
break;
|
||||
case 1:
|
||||
acc_g.Y = (!isLeft ? -1 : 1) * (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
|
||||
gyr_g.Y = -(!isLeft ? -1 : 1) * (gyr_r[i] - gyr_neutral[i]) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
|
||||
break;
|
||||
case 2:
|
||||
acc_g.Z = (!isLeft ? -1 : 1) * (acc_r[i] - offset[i]) * (1.0f / (acc_sensiti[i] - acc_neutral[i])) * 4.0f;
|
||||
gyr_g.Z = -(!isLeft ? -1 : 1) * (gyr_r[i] - gyr_neutral[i]) * (816.0f / (gyr_sensiti[i] - gyr_neutral[i]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float temp = acc_g.X; acc_g.X = acc_g.Y; acc_g.Y = temp;
|
||||
temp = gyr_g.X; gyr_g.X = gyr_g.Y; gyr_g.Y = temp;
|
||||
|
||||
if (other == null && !isPro) { // single joycon mode; Z do not swap, rest do
|
||||
if (isLeft) {
|
||||
acc_g.X = -acc_g.X;
|
||||
gyr_g.X = -gyr_g.X;
|
||||
} else {
|
||||
gyr_g.Y = -gyr_g.Y;
|
||||
}
|
||||
|
||||
float temp = acc_g.X; acc_g.X = acc_g.Y; acc_g.Y = temp;
|
||||
temp = gyr_g.X; gyr_g.X = gyr_g.Y; gyr_g.Y = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -855,31 +862,9 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
|
||||
private void dump_calibration_data() {
|
||||
byte[] buf_ = ReadSPI(0x80, (isLeft ? (byte)0x12 : (byte)0x1d), 9); // get user calibration data if possible
|
||||
bool found = false;
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (buf_[i] != 0xff) {
|
||||
form.AppendTextBox("Using user stick calibration data.\r\n");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
form.AppendTextBox("Using factory stick calibration data.\r\n");
|
||||
buf_ = ReadSPI(0x60, (isLeft ? (byte)0x3d : (byte)0x46), 9); // get user calibration data if possible
|
||||
}
|
||||
stick_cal[isLeft ? 0 : 2] = (UInt16)((buf_[1] << 8) & 0xF00 | buf_[0]); // X Axis Max above center
|
||||
stick_cal[isLeft ? 1 : 3] = (UInt16)((buf_[2] << 4) | (buf_[1] >> 4)); // Y Axis Max above center
|
||||
stick_cal[isLeft ? 2 : 4] = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]); // X Axis Center
|
||||
stick_cal[isLeft ? 3 : 5] = (UInt16)((buf_[5] << 4) | (buf_[4] >> 4)); // Y Axis Center
|
||||
stick_cal[isLeft ? 4 : 0] = (UInt16)((buf_[7] << 8) & 0xF00 | buf_[6]); // X Axis Min below center
|
||||
stick_cal[isLeft ? 5 : 1] = (UInt16)((buf_[8] << 4) | (buf_[7] >> 4)); // Y Axis Min below center
|
||||
|
||||
PrintArray(stick_cal, len: 6, start: 0, format: "Stick calibration data: {0:S}");
|
||||
|
||||
if (isPro) {
|
||||
buf_ = ReadSPI(0x80, (!isLeft ? (byte)0x12 : (byte)0x1d), 9); // get user calibration data if possible
|
||||
found = false;
|
||||
if(!isSnes) {
|
||||
byte[] buf_ = ReadSPI(0x80, (isLeft ? (byte)0x12 : (byte)0x1d), 9); // get user calibration data if possible
|
||||
bool found = false;
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (buf_[i] != 0xff) {
|
||||
form.AppendTextBox("Using user stick calibration data.\r\n");
|
||||
|
@ -889,69 +874,93 @@ namespace BetterJoyForCemu {
|
|||
}
|
||||
if (!found) {
|
||||
form.AppendTextBox("Using factory stick calibration data.\r\n");
|
||||
buf_ = ReadSPI(0x60, (!isLeft ? (byte)0x3d : (byte)0x46), 9); // get user calibration data if possible
|
||||
buf_ = ReadSPI(0x60, (isLeft ? (byte)0x3d : (byte)0x46), 9); // get user calibration data if possible
|
||||
}
|
||||
stick2_cal[!isLeft ? 0 : 2] = (UInt16)((buf_[1] << 8) & 0xF00 | buf_[0]); // X Axis Max above center
|
||||
stick2_cal[!isLeft ? 1 : 3] = (UInt16)((buf_[2] << 4) | (buf_[1] >> 4)); // Y Axis Max above center
|
||||
stick2_cal[!isLeft ? 2 : 4] = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]); // X Axis Center
|
||||
stick2_cal[!isLeft ? 3 : 5] = (UInt16)((buf_[5] << 4) | (buf_[4] >> 4)); // Y Axis Center
|
||||
stick2_cal[!isLeft ? 4 : 0] = (UInt16)((buf_[7] << 8) & 0xF00 | buf_[6]); // X Axis Min below center
|
||||
stick2_cal[!isLeft ? 5 : 1] = (UInt16)((buf_[8] << 4) | (buf_[7] >> 4)); // Y Axis Min below center
|
||||
stick_cal[isLeft ? 0 : 2] = (UInt16)((buf_[1] << 8) & 0xF00 | buf_[0]); // X Axis Max above center
|
||||
stick_cal[isLeft ? 1 : 3] = (UInt16)((buf_[2] << 4) | (buf_[1] >> 4)); // Y Axis Max above center
|
||||
stick_cal[isLeft ? 2 : 4] = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]); // X Axis Center
|
||||
stick_cal[isLeft ? 3 : 5] = (UInt16)((buf_[5] << 4) | (buf_[4] >> 4)); // Y Axis Center
|
||||
stick_cal[isLeft ? 4 : 0] = (UInt16)((buf_[7] << 8) & 0xF00 | buf_[6]); // X Axis Min below center
|
||||
stick_cal[isLeft ? 5 : 1] = (UInt16)((buf_[8] << 4) | (buf_[7] >> 4)); // Y Axis Min below center
|
||||
|
||||
PrintArray(stick2_cal, len: 6, start: 0, format: "Stick calibration data: {0:S}");
|
||||
PrintArray(stick_cal, len: 6, start: 0, format: "Stick calibration data: {0:S}");
|
||||
|
||||
buf_ = ReadSPI(0x60, (!isLeft ? (byte)0x86 : (byte)0x98), 16);
|
||||
deadzone2 = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]);
|
||||
}
|
||||
if (isPro) {
|
||||
buf_ = ReadSPI(0x80, (!isLeft ? (byte)0x12 : (byte)0x1d), 9); // get user calibration data if possible
|
||||
found = false;
|
||||
for (int i = 0; i < 9; ++i) {
|
||||
if (buf_[i] != 0xff) {
|
||||
form.AppendTextBox("Using user stick calibration data.\r\n");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
form.AppendTextBox("Using factory stick calibration data.\r\n");
|
||||
buf_ = ReadSPI(0x60, (!isLeft ? (byte)0x3d : (byte)0x46), 9); // get user calibration data if possible
|
||||
}
|
||||
stick2_cal[!isLeft ? 0 : 2] = (UInt16)((buf_[1] << 8) & 0xF00 | buf_[0]); // X Axis Max above center
|
||||
stick2_cal[!isLeft ? 1 : 3] = (UInt16)((buf_[2] << 4) | (buf_[1] >> 4)); // Y Axis Max above center
|
||||
stick2_cal[!isLeft ? 2 : 4] = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]); // X Axis Center
|
||||
stick2_cal[!isLeft ? 3 : 5] = (UInt16)((buf_[5] << 4) | (buf_[4] >> 4)); // Y Axis Center
|
||||
stick2_cal[!isLeft ? 4 : 0] = (UInt16)((buf_[7] << 8) & 0xF00 | buf_[6]); // X Axis Min below center
|
||||
stick2_cal[!isLeft ? 5 : 1] = (UInt16)((buf_[8] << 4) | (buf_[7] >> 4)); // Y Axis Min below center
|
||||
|
||||
buf_ = ReadSPI(0x60, (isLeft ? (byte)0x86 : (byte)0x98), 16);
|
||||
deadzone = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]);
|
||||
PrintArray(stick2_cal, len: 6, start: 0, format: "Stick calibration data: {0:S}");
|
||||
|
||||
buf_ = ReadSPI(0x80, 0x28, 10);
|
||||
acc_neutral[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
acc_neutral[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
acc_neutral[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
buf_ = ReadSPI(0x60, (!isLeft ? (byte)0x86 : (byte)0x98), 16);
|
||||
deadzone2 = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]);
|
||||
}
|
||||
|
||||
buf_ = ReadSPI(0x80, 0x2E, 10);
|
||||
acc_sensiti[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
acc_sensiti[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
acc_sensiti[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
buf_ = ReadSPI(0x60, (isLeft ? (byte)0x86 : (byte)0x98), 16);
|
||||
deadzone = (UInt16)((buf_[4] << 8) & 0xF00 | buf_[3]);
|
||||
|
||||
buf_ = ReadSPI(0x80, 0x34, 10);
|
||||
gyr_neutral[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
gyr_neutral[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
gyr_neutral[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
buf_ = ReadSPI(0x80, 0x3A, 10);
|
||||
gyr_sensiti[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
gyr_sensiti[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
gyr_sensiti[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
PrintArray(gyr_neutral, len: 3, d: DebugType.IMU, format: "User gyro neutral position: {0:S}");
|
||||
|
||||
// This is an extremely messy way of checking to see whether there is user stick calibration data present, but I've seen conflicting user calibration data on blank Joy-Cons. Worth another look eventually.
|
||||
if (gyr_neutral[0] + gyr_neutral[1] + gyr_neutral[2] == -3 || Math.Abs(gyr_neutral[0]) > 100 || Math.Abs(gyr_neutral[1]) > 100 || Math.Abs(gyr_neutral[2]) > 100) {
|
||||
buf_ = ReadSPI(0x60, 0x20, 10);
|
||||
buf_ = ReadSPI(0x80, 0x28, 10);
|
||||
acc_neutral[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
acc_neutral[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
acc_neutral[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
buf_ = ReadSPI(0x60, 0x26, 10);
|
||||
buf_ = ReadSPI(0x80, 0x2E, 10);
|
||||
acc_sensiti[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
acc_sensiti[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
acc_sensiti[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
buf_ = ReadSPI(0x60, 0x2C, 10);
|
||||
buf_ = ReadSPI(0x80, 0x34, 10);
|
||||
gyr_neutral[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
gyr_neutral[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
gyr_neutral[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
buf_ = ReadSPI(0x60, 0x32, 10);
|
||||
buf_ = ReadSPI(0x80, 0x3A, 10);
|
||||
gyr_sensiti[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
gyr_sensiti[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
gyr_sensiti[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
PrintArray(gyr_neutral, len: 3, d: DebugType.IMU, format: "Factory gyro neutral position: {0:S}");
|
||||
PrintArray(gyr_neutral, len: 3, d: DebugType.IMU, format: "User gyro neutral position: {0:S}");
|
||||
|
||||
// This is an extremely messy way of checking to see whether there is user stick calibration data present, but I've seen conflicting user calibration data on blank Joy-Cons. Worth another look eventually.
|
||||
if (gyr_neutral[0] + gyr_neutral[1] + gyr_neutral[2] == -3 || Math.Abs(gyr_neutral[0]) > 100 || Math.Abs(gyr_neutral[1]) > 100 || Math.Abs(gyr_neutral[2]) > 100) {
|
||||
buf_ = ReadSPI(0x60, 0x20, 10);
|
||||
acc_neutral[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
acc_neutral[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
acc_neutral[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
buf_ = ReadSPI(0x60, 0x26, 10);
|
||||
acc_sensiti[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
acc_sensiti[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
acc_sensiti[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
buf_ = ReadSPI(0x60, 0x2C, 10);
|
||||
gyr_neutral[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
gyr_neutral[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
gyr_neutral[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
buf_ = ReadSPI(0x60, 0x32, 10);
|
||||
gyr_sensiti[0] = (Int16)(buf_[0] | ((buf_[1] << 8) & 0xff00));
|
||||
gyr_sensiti[1] = (Int16)(buf_[2] | ((buf_[3] << 8) & 0xff00));
|
||||
gyr_sensiti[2] = (Int16)(buf_[4] | ((buf_[5] << 8) & 0xff00));
|
||||
|
||||
PrintArray(gyr_neutral, len: 3, d: DebugType.IMU, format: "Factory gyro neutral position: {0:S}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace BetterJoyForCemu {
|
|||
private const ushort product_l = 0x2006;
|
||||
private const ushort product_r = 0x2007;
|
||||
private const ushort product_pro = 0x2009;
|
||||
private const ushort product_snes = 0x2017;
|
||||
|
||||
public List<Joycon> j; // Array of all connected Joy-Cons
|
||||
static JoyconManager instance;
|
||||
|
@ -119,7 +120,9 @@ namespace BetterJoyForCemu {
|
|||
enumerate.product_id = product_pro;
|
||||
}
|
||||
|
||||
if ((enumerate.product_id == product_l || enumerate.product_id == product_r || enumerate.product_id == product_pro) && !ControllerAlreadyAdded(enumerate.path)) {
|
||||
bool validController = (enumerate.product_id == product_l || enumerate.product_id == product_r ||
|
||||
enumerate.product_id == product_pro || enumerate.product_id == product_snes);
|
||||
if (validController && !ControllerAlreadyAdded(enumerate.path)) {
|
||||
switch (enumerate.product_id) {
|
||||
case product_l:
|
||||
isLeft = true;
|
||||
|
@ -130,6 +133,9 @@ namespace BetterJoyForCemu {
|
|||
case product_pro:
|
||||
isLeft = true;
|
||||
form.AppendTextBox("Pro controller connected.\r\n"); break;
|
||||
case product_snes:
|
||||
isLeft = true;
|
||||
form.AppendTextBox("SNES controller connected.\r\n"); break;
|
||||
default:
|
||||
form.AppendTextBox("Non Joy-Con Nintendo input device skipped.\r\n"); break;
|
||||
}
|
||||
|
@ -168,8 +174,10 @@ namespace BetterJoyForCemu {
|
|||
break;
|
||||
}
|
||||
|
||||
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, enumerate.path, enumerate.serial_number, j.Count, enumerate.product_id == product_pro));
|
||||
|
||||
bool isPro = enumerate.product_id == product_pro;
|
||||
bool isSnes = enumerate.product_id == product_snes;
|
||||
j.Add(new Joycon(handle, EnableIMU, EnableLocalize & EnableIMU, 0.05f, isLeft, enumerate.path, enumerate.serial_number, j.Count, isPro, isSnes));
|
||||
|
||||
foundNew = true;
|
||||
j.Last().form = form;
|
||||
|
||||
|
@ -186,6 +194,8 @@ namespace BetterJoyForCemu {
|
|||
temp = Properties.Resources.jc_right_s; break;
|
||||
case (product_pro):
|
||||
temp = Properties.Resources.pro; break;
|
||||
case (product_snes):
|
||||
temp = Properties.Resources.snes; break;
|
||||
default:
|
||||
temp = Properties.Resources.cross; break;
|
||||
}
|
||||
|
@ -257,13 +267,12 @@ namespace BetterJoyForCemu {
|
|||
|
||||
jc.Attach(leds_: jc.LED);
|
||||
|
||||
bool on = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).AppSettings.Settings["HomeLEDOn"].Value.ToLower() == "true";
|
||||
foreach (Joycon j in Program.mgr.j)
|
||||
{
|
||||
j.SetHomeLight(on);
|
||||
}
|
||||
bool on = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).AppSettings.Settings["HomeLEDOn"].Value.ToLower() == "true";
|
||||
foreach (Joycon j in Program.mgr.j) {
|
||||
j.SetHomeLight(on);
|
||||
}
|
||||
|
||||
jc.Begin();
|
||||
jc.Begin();
|
||||
if (form.nonOriginal) {
|
||||
jc.getActiveData();
|
||||
}
|
||||
|
|
12
BetterJoyForCemu/Properties/Resources.Designer.cs
generated
12
BetterJoyForCemu/Properties/Resources.Designer.cs
generated
|
@ -19,7 +19,7 @@ namespace BetterJoyForCemu.Properties {
|
|||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
@ -129,5 +129,15 @@ namespace BetterJoyForCemu.Properties {
|
|||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||
/// </summary>
|
||||
internal static System.Drawing.Bitmap snes {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("snes", resourceCulture);
|
||||
return ((System.Drawing.Bitmap)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -118,6 +118,9 @@
|
|||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="snes" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Icons\snes.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
<data name="pro" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\Icons\pro.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
|
|
|
@ -220,4 +220,4 @@ Many thanks to [nefarius](https://github.com/nefarius/ViGEm) for his ViGEm proje
|
|||
A last thanks goes out to [dekuNukem](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering) for his documentation, especially on the SPI calibration data and the IMU sensor notes!
|
||||
|
||||
Icons (modified): "[Switch Pro Controller](https://thenounproject.com/term/nintendo-switch/930119/)", "[
|
||||
Switch Detachable Controller Left](https://thenounproject.com/remsing/uploads/?i=930115)", "[Switch Detachable Controller Right](https://thenounproject.com/remsing/uploads/?i=930121)" icons by Chad Remsing from [the Noun Project](http://thenounproject.com/).
|
||||
Switch Detachable Controller Left](https://thenounproject.com/remsing/uploads/?i=930115)", "[Switch Detachable Controller Right](https://thenounproject.com/remsing/uploads/?i=930121)" icons by Chad Remsing from [the Noun Project](http://thenounproject.com/). [Super Nintendo Controller](https://thenounproject.com/themizarkshow/collection/vectogram/?i=193592) icon by Mark Davis from the [the Noun Project](http://thenounproject.com/); icon modified by [Amy Alexander](https://www.linkedin.com/in/-amy-alexander/).
|
Loading…
Add table
Reference in a new issue