Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -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.
##
Expand Down Expand Up @@ -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/

Expand Down
6 changes: 5 additions & 1 deletion RB4InstrumentMapper.CLI/Arguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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}'");
Expand Down Expand Up @@ -221,7 +225,7 @@ public static void PrintHelp()
Console.WriteLine();
Console.WriteLine("Options:");
Console.WriteLine(" --mode <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).");
Expand Down
32 changes: 27 additions & 5 deletions RB4InstrumentMapper.Core/Mapping/MapperFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public enum MappingMode
ViGEmBus = 1,
vJoy = 2,
RPCS3 = 3,
shadPS4 = 4,
}

/// <summary>
Expand Down Expand Up @@ -150,7 +151,7 @@ public static DeviceMapper GetByInterfaceIds(IBackendClient client, HashSet<Guid
}

private static DeviceMapper GetMapper(IBackendClient client, CreateMapper createViGEm, CreateMapper createvJoy,
CreateMapper createRpcs3)
CreateMapper createRpcs3, CreateMapper createshadPS4)
{
DeviceMapper mapper;
bool devicesAvailable;
Expand All @@ -167,6 +168,11 @@ private static DeviceMapper GetMapper(IBackendClient client, CreateMapper create
mapper = ViGEmInstance.AreDevicesAvailable ? createRpcs3(client) : null;
devicesAvailable = ViGEmInstance.AreDevicesAvailable;
break;

case MappingMode.shadPS4:
mapper = ViGEmInstance.AreDevicesAvailable ? createshadPS4(client) : null;
devicesAvailable = ViGEmInstance.AreDevicesAvailable;
break;

case MappingMode.vJoy:
mapper = vJoyInstance.AreDevicesAvailable ? createvJoy(client) : null;
Expand Down Expand Up @@ -194,7 +200,8 @@ public static DeviceMapper GetGamepadMapper(IBackendClient client)
return GetMapper(client,
(c) => 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
Expand All @@ -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)
);

Expand All @@ -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)
);
}
}
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// Maps Riffmaster guitar inputs to a ViGEmBus device with modifications to support shadPS4.
/// </summary>
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<byte> data)
{
switch (command)
{
case XboxRiffmasterInput.CommandId:
return ParseInput(data);

default:
return XboxResult.Success;
}
}

private unsafe XboxResult ParseInput(ReadOnlySpan<byte> data)
{
if (!ParsingUtils.TryRead(data, out XboxRiffmasterInput guitarReport))
return XboxResult.InvalidMessage;

HandleReport(device, guitarReport);

// Send data
return SubmitReport();
}

/// <summary>
/// Maps guitar input data to an Xbox 360 controller.
/// </summary>
internal static void HandleReport(IXbox360Controller device, in XboxRiffmasterInput report)
{
// Guitar inputs
GuitarViGEmMapper.HandleReport(device, report.Base);
Comment on lines +49 to +50
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This call as-is is going to cause duplicate inputs with whammy/tilt, as GuitarViGEmMapper.HandleReport puts whammy on right stick X instead of left thumb Y, and the additional code here does nothing to account for that.

I'd prefer if the code in GuitarViGEmMapper.HandleReport was duplicated in its entirety into here, and modified to suit shadPS4's mapping requirements.


// 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));
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would somewhat prefer if there was a way to use GuitarViGEmMapper.CalculatePickupSwitch, instead of copying the constants from there as magic values with no context.

}

private static void HandlePickup(XboxRiffmasterInput report)
{
bool pickupSetDown = ((XboxGamepadButton)report.Base.Buttons).HasFlag(XboxGamepadButton.LeftStickPress);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use Enum.HasFlag, as it has performance problems due to being non-generic and boxing its values to the heap (causing GC allocations). Use a bit-test instead:

Suggested change
bool pickupSetDown = ((XboxGamepadButton)report.Base.Buttons).HasFlag(XboxGamepadButton.LeftStickPress);
bool pickupSetDown = (report.Base.Buttons & (ushort)XboxGamepadButton.LeftStickPress) != 0;

(Casting the constant to ushort is more concise, but casting the Buttons field to XboxGamepadButton instead has the same result:)

Suggested change
bool pickupSetDown = ((XboxGamepadButton)report.Base.Buttons).HasFlag(XboxGamepadButton.LeftStickPress);
bool pickupSetDown = ((XboxGamepadButton)report.Base.Buttons & XboxGamepadButton.LeftStickPress) != 0;

if (pickupSetDown && !pickupDown)
{
pickupDown = true;
currentPickup++;
if (currentPickup > 4)
currentPickup = 0;
}
else if (!pickupSetDown && pickupDown)
{
pickupDown = false;
}
}
}
}
1 change: 1 addition & 0 deletions RB4InstrumentMapper.Core/MappingSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ public static class BackendSettings
/// Whether packets should be logged to the console.
/// </summary>
public static bool LogPackets { get; set; } = false;
public static double RiffmasterSensitivity { get; set; } = 1.5;
}
}
20 changes: 20 additions & 0 deletions RB4InstrumentMapper.Core/Parsing/ParsingUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ public static short ScaleToInt16(this byte input)
{
return (short)(((input ^ 0x80) << 8) | input);
}

/// <summary>
/// Scales a byte to a short, starting from 0.
/// </summary>
public static short ScaleToPositiveInt16(this byte input)
{
return (short)(((input / 2) << 8) | input);
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done equivalently with just bit-shift operations:

Suggested change
return (short)(((input / 2) << 8) | input);
return (short)((input << 7) | (input >> 1));

}

/// <summary>
/// Scales a byte to an unsigned short.
Expand All @@ -115,5 +123,17 @@ public static ushort ScaleToUInt16(this byte input)
{
return (ushort)((input << 8) | input);
}

/// <summary>
/// Clamps an int to a short.
/// </summary>
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;
}
}
}
15 changes: 15 additions & 0 deletions RB4InstrumentMapper.GUI/Properties/Settings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions RB4InstrumentMapper.GUI/Windows/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
<ComboBoxItem x:Name="vjoyDeviceTypeOption" Content="vJoy" IsEnabled="False"/>
<ComboBoxItem x:Name="vigemDeviceTypeOption" Content="ViGEmBus" IsEnabled="False"/>
<ComboBoxItem x:Name="rpcs3DeviceTypeOption" Content="ViGEmBus (RPCS3 compatibility)" IsEnabled="False"/>
<ComboBoxItem x:Name="shadPS4DeviceTypeOption" Content="ViGeEmBus (shadPS4 compatibility)" IsEnabled="False"/>
</ComboBox>
<Button x:Name="startButton" Content="Start" FontSize="18" Height="40" Width="160" Margin="0,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Right" IsEnabled="False" Click="startButton_Click"/>
</Grid>
Expand Down
22 changes: 21 additions & 1 deletion RB4InstrumentMapper.GUI/Windows/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ private enum ControllerType
None = -1,
vJoy = 0,
ViGEmBus = 1,
RPCS3 = 2
RPCS3 = 2,
shadPS4 = 3,
}

public MainWindow()
Expand Down Expand Up @@ -88,6 +89,7 @@ private void Window_Loaded(object sender, RoutedEventArgs e)
Console.WriteLine("ViGEmBus found!");
vigemDeviceTypeOption.IsEnabled = true;
rpcs3DeviceTypeOption.IsEnabled = true;
shadPS4DeviceTypeOption.IsEnabled = true;
}
else
{
Expand All @@ -96,6 +98,8 @@ private void Window_Loaded(object sender, RoutedEventArgs e)
vigemDeviceTypeOption.IsSelected = false;
rpcs3DeviceTypeOption.IsEnabled = false;
rpcs3DeviceTypeOption.IsSelected = false;
shadPS4DeviceTypeOption.IsEnabled = false;
shadPS4DeviceTypeOption.IsSelected = false;
}

// Exit if neither ViGEmBus nor vJoy are installed
Expand Down Expand Up @@ -130,6 +134,7 @@ private void LoadBackendSettings()
{
SetDeviceType((ControllerType)Settings.Default.controllerDeviceType);
BackendSettings.UseAccurateDrumMappings = Settings.Default.accurateDrumMaps;
BackendSettings.RiffmasterSensitivity = Settings.Default.riffmasterTiltSensitivity;
}

/// <summary>
Expand Down Expand Up @@ -306,6 +311,21 @@ private void SetDeviceType(ControllerType type)
return;
}
break;

case ControllerType.shadPS4:
if (shadPS4DeviceTypeOption.IsEnabled && ViGEmInstance.Initialized)
{
BackendSettings.MapperMode = MappingMode.shadPS4;
}
else
{
// Reset device type selection
// Setting this fires off the handler again, no extra handling is needed
BackendSettings.MapperMode = MappingMode.NotSet;
controllerDeviceTypeCombo.SelectedIndex = -1;
return;
}
break;

case ControllerType.None:
BackendSettings.MapperMode = MappingMode.NotSet;
Expand Down
4 changes: 3 additions & 1 deletion RB4InstrumentMapper.GUI/Windows/SettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@
xmlns:local="clr-namespace:RB4InstrumentMapper.GUI"
mc:Ignorable="d"
Title="Settings"
Height="140" Width="350"
Height="180" Width="350"
ResizeMode="NoResize" WindowStartupLocation="CenterOwner"
Loaded="WindowLoaded" Closed="WindowClosed">
<Grid Margin="10,10,10,10">
<CheckBox x:Name="autoStartCheckBox" Content="Auto-start on load" Margin="0,0,0,0" VerticalAlignment="Top" HorizontalAlignment="Stretch"
ToolTip="Automatically starts capture/mapping when RB4InstrumentMapper starts up."/>
<CheckBox x:Name="accurateDrumMapsCheckBox" Content="Use accurate drum mappings (ViGEmBus)" Margin="0,22,0,0" VerticalAlignment="Top" HorizontalAlignment="Stretch"
ToolTip="Changes mappings for drums in ViGEmBus mode to match how Xbox 360 drumkits behave, for compatibility with tools like rb4.app which require accurate behavior. This may cause issues in games and should only be enabled if it's necessary."/>
<Label Margin="0, 44, 0, 0" Padding="0, 0, 0, 0" BorderThickness="0">Riffmaster Overdrive Sensitivity</Label>
<Slider x:Name="riffmasterTiltSensitivity" Margin="0, 66, 0, 0" Minimum="1" Maximum="2"></Slider>
<Button x:Name="saveButton" Content="Save" Height="25" Width="75" Margin="0,0,0,0" VerticalAlignment="Bottom" HorizontalAlignment="Right" Click="saveButton_Click"/>
<Button x:Name="cancelButton" Content="Cancel" Height="25" Width="75" Margin="0,0,85,0" VerticalAlignment="Bottom" HorizontalAlignment="Right" Click="cancelButton_Click"/>
</Grid>
Expand Down
4 changes: 3 additions & 1 deletion RB4InstrumentMapper.GUI/Windows/SettingsWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ private void WindowLoaded(object sender, RoutedEventArgs e)
{
autoStartCheckBox.IsChecked = Settings.Default.autoStart;
accurateDrumMapsCheckBox.IsChecked = Settings.Default.accurateDrumMaps;
riffmasterTiltSensitivity.Value = Settings.Default.riffmasterTiltSensitivity;
}

private void WindowClosed(object sender, EventArgs e)
Expand All @@ -29,7 +30,8 @@ private void saveButton_Click(object sender, RoutedEventArgs args)
{
Settings.Default.autoStart = autoStartCheckBox.IsChecked.GetValueOrDefault();
Settings.Default.accurateDrumMaps = accurateDrumMapsCheckBox.IsChecked.GetValueOrDefault();

Settings.Default.riffmasterTiltSensitivity = riffmasterTiltSensitivity.Value;

Close();
}

Expand Down