diff --git a/.gitignore b/.gitignore index 7350d1d..493247f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,3 @@ -# VS Code configuration folder -.vscode/ - ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## @@ -34,6 +31,11 @@ bld/ # Visual Studio 2015/2017 cache/options directory .vs/ +# VS Code configuration directory +.vscode/ +# JetBrains cache/options directory +.idea/ + # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ diff --git a/RB4InstrumentMapper.CLI/Arguments.cs b/RB4InstrumentMapper.CLI/Arguments.cs index 22f5eaf..819c528 100644 --- a/RB4InstrumentMapper.CLI/Arguments.cs +++ b/RB4InstrumentMapper.CLI/Arguments.cs @@ -109,6 +109,10 @@ public static bool TryParse(string[] args, out Arguments parsed) { parsed.MappingMode = MappingMode.RPCS3; } + else if (modeStr.Equals("shadps4", StringComparison.OrdinalIgnoreCase)) + { + parsed.MappingMode = MappingMode.shadPS4; + } else { Console.WriteLine($"Error: Invalid mapping mode '{modeStr}'"); @@ -221,7 +225,7 @@ public static void PrintHelp() Console.WriteLine(); Console.WriteLine("Options:"); Console.WriteLine(" --mode The mapping mode to use."); - Console.WriteLine(" - mode: one of 'vigembus', 'vigem', 'vjoy', or 'rpcs3', case insensitive."); + Console.WriteLine(" - mode: one of 'vigem'/'vigembus', 'vjoy', 'rpcs3', or 'shadps4', case insensitive."); Console.WriteLine(" --accurate-drums Use hardware-accurate drum mappings for ViGEmBus mode."); Console.WriteLine(); Console.WriteLine(" --wait-for-devices [timeout] Wait for devices to be detected before starting (default timeout: 30s)."); diff --git a/RB4InstrumentMapper.Core/Mapping/MapperFactory.cs b/RB4InstrumentMapper.Core/Mapping/MapperFactory.cs index 88e05f6..b8e08f2 100644 --- a/RB4InstrumentMapper.Core/Mapping/MapperFactory.cs +++ b/RB4InstrumentMapper.Core/Mapping/MapperFactory.cs @@ -10,6 +10,7 @@ public enum MappingMode ViGEmBus = 1, vJoy = 2, RPCS3 = 3, + shadPS4 = 4, } /// @@ -150,7 +151,7 @@ public static DeviceMapper GetByInterfaceIds(IBackendClient client, HashSet new GamepadViGEmMapper(c), (c) => new GamepadvJoyMapper(c), - // No RPCS3 mapper, as this is for testing only + // No RPCS3 or shadPS4 mapper, as this is for testing only + (c) => new GamepadViGEmMapper(c), (c) => new GamepadViGEmMapper(c) ); #else @@ -215,24 +222,37 @@ public static DeviceMapper GetGuitarMapper(IBackendClient client) createViGEm = (c) => new RiffmasterViGEmMapper(c); else createViGEm = (c) => new GuitarViGEmMapper(c); + + // I (aoiyu_) am not 100% sure if the base guitars share the same problems as the Riffmaster. + // Sorry if they do, I just don't have a non-Riffmaster to test on. + CreateMapper createshadPS4; + if (isRiffmaster) + createshadPS4 = (c) => new RiffmastershadPS4Mapper(c); + else + createshadPS4 = (c) => new GuitarViGEmMapper(c); return GetMapper(client, createViGEm, (c) => new GuitarvJoyMapper(c), - (c) => new GuitarRPCS3Mapper(c) + (c) => new GuitarRPCS3Mapper(c), + createshadPS4 ); } public static DeviceMapper GetDrumsMapper(IBackendClient client) => GetMapper(client, (c) => new DrumsViGEmMapper(c), (c) => new DrumsvJoyMapper(c), - (c) => new DrumsRPCS3Mapper(c) + (c) => new DrumsRPCS3Mapper(c), + // No mapping differences that I (aoiyu_) know of. + (c) => new DrumsViGEmMapper(c) ); public static DeviceMapper GetGHLGuitarMapper(IBackendClient client) => GetMapper(client, (c) => new GHLGuitarViGEmMapper(c), (c) => new GHLGuitarvJoyMapper(c), // No mapping differences between RPCS3 and ViGEm modes + (c) => new GHLGuitarViGEmMapper(c), + // No mapping differences that I (aoiyu_) know of. (c) => new GHLGuitarViGEmMapper(c) ); @@ -246,7 +266,9 @@ public static DeviceMapper GetWirelessLegacyMapper(IBackendClient client) public static DeviceMapper GetFallbackMapper(IBackendClient client) => GetMapper(client, (c) => new FallbackViGEmMapper(c), (c) => new FallbackvJoyMapper(c), - (c) => new FallbackRPCS3Mapper(c) + (c) => new FallbackRPCS3Mapper(c), + // No mapping differences that I (aoiyu_) know of. + (c) => new FallbackViGEmMapper(c) ); } } \ No newline at end of file diff --git a/RB4InstrumentMapper.Core/Mapping/Mappers/shadPS4/RiffmastershadPS4Mapper.cs b/RB4InstrumentMapper.Core/Mapping/Mappers/shadPS4/RiffmastershadPS4Mapper.cs new file mode 100644 index 0000000..5a04210 --- /dev/null +++ b/RB4InstrumentMapper.Core/Mapping/Mappers/shadPS4/RiffmastershadPS4Mapper.cs @@ -0,0 +1,82 @@ +using System; +using Nefarius.ViGEm.Client.Targets; +using Nefarius.ViGEm.Client.Targets.Xbox360; +using RB4InstrumentMapper.Core.Parsing; + +namespace RB4InstrumentMapper.Core.Mapping +{ + /// + /// Maps Riffmaster guitar inputs to a ViGEmBus device with modifications to support shadPS4. + /// + internal class RiffmastershadPS4Mapper : ViGEmMapper + { + public RiffmastershadPS4Mapper(IBackendClient client) + : base(client) + { + } + + private static int currentPickup = 0; + private static bool pickupDown = false; + + protected override XboxResult OnMessageReceived(byte command, ReadOnlySpan data) + { + switch (command) + { + case XboxRiffmasterInput.CommandId: + return ParseInput(data); + + default: + return XboxResult.Success; + } + } + + private unsafe XboxResult ParseInput(ReadOnlySpan data) + { + if (!ParsingUtils.TryRead(data, out XboxRiffmasterInput guitarReport)) + return XboxResult.InvalidMessage; + + HandleReport(device, guitarReport); + + // Send data + return SubmitReport(); + } + + /// + /// Maps guitar input data to an Xbox 360 controller. + /// + internal static void HandleReport(IXbox360Controller device, in XboxRiffmasterInput report) + { + // Guitar inputs + GuitarViGEmMapper.HandleReport(device, report.Base); + + // Whammy Bar + device.SetAxisValue(Xbox360Axis.LeftThumbY, report.Base.WhammyBar.ScaleToPositiveInt16()); + + // Tilt + device.SetAxisValue(Xbox360Axis.RightThumbY, (-1 * (int)Math.Round(report.Base.Tilt.ScaleToInt16() * BackendSettings.RiffmasterSensitivity)).ClampToShort()); + + // Joystick + device.SetButtonState(Xbox360Button.LeftThumb, report.JoystickClick | report.Base.LowerFretsPressed); + + // Pickup + HandlePickup(report); + device.SetSliderValue(Xbox360Slider.LeftTrigger, (byte)(currentPickup * 51 - 25)); + } + + private static void HandlePickup(XboxRiffmasterInput report) + { + bool pickupSetDown = ((XboxGamepadButton)report.Base.Buttons).HasFlag(XboxGamepadButton.LeftStickPress); + if (pickupSetDown && !pickupDown) + { + pickupDown = true; + currentPickup++; + if (currentPickup > 4) + currentPickup = 0; + } + else if (!pickupSetDown && pickupDown) + { + pickupDown = false; + } + } + } +} diff --git a/RB4InstrumentMapper.Core/MappingSettings.cs b/RB4InstrumentMapper.Core/MappingSettings.cs index b3c1263..91e63fe 100644 --- a/RB4InstrumentMapper.Core/MappingSettings.cs +++ b/RB4InstrumentMapper.Core/MappingSettings.cs @@ -21,5 +21,6 @@ public static class BackendSettings /// Whether packets should be logged to the console. /// public static bool LogPackets { get; set; } = false; + public static double RiffmasterSensitivity { get; set; } = 1.5; } } \ No newline at end of file diff --git a/RB4InstrumentMapper.Core/Parsing/ParsingUtils.cs b/RB4InstrumentMapper.Core/Parsing/ParsingUtils.cs index fb4ceb1..984f462 100644 --- a/RB4InstrumentMapper.Core/Parsing/ParsingUtils.cs +++ b/RB4InstrumentMapper.Core/Parsing/ParsingUtils.cs @@ -107,6 +107,14 @@ public static short ScaleToInt16(this byte input) { return (short)(((input ^ 0x80) << 8) | input); } + + /// + /// Scales a byte to a short, starting from 0. + /// + public static short ScaleToPositiveInt16(this byte input) + { + return (short)(((input / 2) << 8) | input); + } /// /// Scales a byte to an unsigned short. @@ -115,5 +123,17 @@ public static ushort ScaleToUInt16(this byte input) { return (ushort)((input << 8) | input); } + + /// + /// Clamps an int to a short. + /// + public static short ClampToShort(this int input) + { + if (input > short.MaxValue) + return short.MaxValue; + else if (input < short.MinValue) + return short.MinValue; + return (short)input; + } } } diff --git a/RB4InstrumentMapper.GUI/Properties/Settings.Designer.cs b/RB4InstrumentMapper.GUI/Properties/Settings.Designer.cs index 9ec6844..8269e86 100644 --- a/RB4InstrumentMapper.GUI/Properties/Settings.Designer.cs +++ b/RB4InstrumentMapper.GUI/Properties/Settings.Designer.cs @@ -70,5 +70,20 @@ public bool accurateDrumMaps { this["accurateDrumMaps"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("1.5")] + public double riffmasterTiltSensitivity + { + get + { + return ((double)(this["riffmasterTiltSensitivity"])); + } + set + { + this["riffmasterTiltSensitivity"] = value; + } + } } } diff --git a/RB4InstrumentMapper.GUI/Windows/MainWindow.xaml b/RB4InstrumentMapper.GUI/Windows/MainWindow.xaml index 53c6dd8..31e6b10 100644 --- a/RB4InstrumentMapper.GUI/Windows/MainWindow.xaml +++ b/RB4InstrumentMapper.GUI/Windows/MainWindow.xaml @@ -37,6 +37,7 @@ +