mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-30 22:49:53 +08:00
Sdl backend (#670)
* [audio] added sdl audio backend and in-tree atrac9 decoder * [input] replaced per-platform pad readers with sdl gamepad input * [video] added sdl window and host display plumbing * [gui] added host display options and per-game render settings * [bink] synced host movie playback to the guest audio clock * [cpu] hooked windows write faults into guest image tracking * [perf] added guest and render profiling, reserved host cpu lanes * [kernel] fixed stale pthread mutex handle alias * [host] wired the sdl session, save-data paths and project references * [audio] hoisted ajm trace stackalloc out of its loop * [video] Add guest image sync setting * [build] Strip native symbols * reuse
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using SharpEmu.Libs.Pad;
|
||||
using SharpEmu.HLE.Host;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpEmu.Libs.Tests.Pad;
|
||||
@@ -9,11 +10,161 @@ namespace SharpEmu.Libs.Tests.Pad;
|
||||
public sealed class HostWindowInputTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(-1.0f, 0)]
|
||||
[InlineData(0.0f, 128)]
|
||||
[InlineData(1.0f, 255)]
|
||||
public void ToStickByteMapsFullSilkRange(float value, int expected)
|
||||
[InlineData(short.MinValue, 0)]
|
||||
[InlineData(0, 128)]
|
||||
[InlineData(short.MaxValue, 255)]
|
||||
public void ToStickByteMapsFullSdlRange(short value, int expected)
|
||||
{
|
||||
Assert.Equal((byte)expected, HostWindowInput.ToStickByte(value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConnectPublishesWindowKeyboardState()
|
||||
{
|
||||
HostWindowInput.Connect();
|
||||
try
|
||||
{
|
||||
HostWindowInput.SetKey(0x57, true);
|
||||
|
||||
var source = Assert.IsAssignableFrom<IHostWindowInputSource>(HostWindowInputSource.Current);
|
||||
Assert.True(source.HasKeyboardFocus);
|
||||
Assert.True(source.IsKeyDown(0x57));
|
||||
}
|
||||
finally
|
||||
{
|
||||
HostWindowInput.Disconnect();
|
||||
}
|
||||
|
||||
Assert.Null(HostWindowInputSource.Current);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ConnectedGamepadStateIsExposedByWindowSource()
|
||||
{
|
||||
var expected = new HostGamepadState(
|
||||
true,
|
||||
HostGamepadButtons.Cross | HostGamepadButtons.Options,
|
||||
64,
|
||||
128,
|
||||
192,
|
||||
128,
|
||||
0,
|
||||
255);
|
||||
HostWindowInput.Connect();
|
||||
try
|
||||
{
|
||||
HostWindowInput.SetGamepad("SDL test pad", expected);
|
||||
Span<HostGamepadState> states = stackalloc HostGamepadState[1];
|
||||
|
||||
var source = Assert.IsAssignableFrom<IHostWindowInputSource>(HostWindowInputSource.Current);
|
||||
Assert.Equal(1, source.GetGamepadStates(states));
|
||||
Assert.Equal(expected, states[0]);
|
||||
Assert.Equal("SDL test pad", source.DescribeConnectedGamepad());
|
||||
}
|
||||
finally
|
||||
{
|
||||
HostWindowInput.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ControllerOutputIsForwardedToSdlOwner()
|
||||
{
|
||||
var output = new RecordingGamepadOutput();
|
||||
var effect = new HostAdaptiveTriggerEffect(
|
||||
0x21, 0x04, 0, 0x07, 0, 0, 0, 0, 0, 0, 0, 255);
|
||||
HostWindowInput.Connect(output);
|
||||
try
|
||||
{
|
||||
var source = Assert.IsAssignableFrom<IHostWindowInputSource>(HostWindowInputSource.Current);
|
||||
source.SetRumble(10, 20);
|
||||
source.SetTriggerRumble(30, 40);
|
||||
source.SetAdaptiveTriggerEffect(effect, null);
|
||||
source.SetLightbar(50, 60, 70);
|
||||
source.ResetLightbar();
|
||||
|
||||
Assert.Equal((10, 20), output.Rumble);
|
||||
Assert.Equal(((byte?)30, (byte?)40), output.TriggerRumble);
|
||||
Assert.Equal(effect, output.LeftTriggerEffect);
|
||||
Assert.Null(output.RightTriggerEffect);
|
||||
Assert.Equal((50, 60, 70), output.Lightbar);
|
||||
Assert.True(output.LightbarReset);
|
||||
}
|
||||
finally
|
||||
{
|
||||
HostWindowInput.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CommonHostInputUsesPublishedWindowSource()
|
||||
{
|
||||
var output = new RecordingGamepadOutput();
|
||||
var expected = new HostGamepadState(
|
||||
true,
|
||||
HostGamepadButtons.Cross,
|
||||
32,
|
||||
64,
|
||||
96,
|
||||
128,
|
||||
160,
|
||||
192);
|
||||
var input = new WindowHostInput();
|
||||
HostWindowInput.Connect(output);
|
||||
try
|
||||
{
|
||||
HostWindowInput.SetKey(0x57, true);
|
||||
HostWindowInput.SetGamepad("SDL test pad", expected);
|
||||
Span<HostGamepadState> states = stackalloc HostGamepadState[1];
|
||||
|
||||
Assert.Equal(1, input.GetGamepadStates(states));
|
||||
Assert.Equal(expected, states[0]);
|
||||
Assert.Equal("SDL test pad", input.DescribeConnectedGamepad());
|
||||
Assert.True(input.IsHostWindowFocused());
|
||||
Assert.True(input.IsKeyDown(0x57));
|
||||
|
||||
input.SetRumble(10, 20);
|
||||
input.SetLightbar(30, 40, 50);
|
||||
Assert.Equal((10, 20), output.Rumble);
|
||||
Assert.Equal((30, 40, 50), output.Lightbar);
|
||||
}
|
||||
finally
|
||||
{
|
||||
HostWindowInput.Disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class RecordingGamepadOutput : IHostGamepadOutput
|
||||
{
|
||||
public (byte Large, byte Small) Rumble { get; private set; }
|
||||
|
||||
public (byte? Left, byte? Right) TriggerRumble { get; private set; }
|
||||
|
||||
public HostAdaptiveTriggerEffect? LeftTriggerEffect { get; private set; }
|
||||
|
||||
public HostAdaptiveTriggerEffect? RightTriggerEffect { get; private set; }
|
||||
|
||||
public (byte Red, byte Green, byte Blue) Lightbar { get; private set; }
|
||||
|
||||
public bool LightbarReset { get; private set; }
|
||||
|
||||
public void SetRumble(byte largeMotor, byte smallMotor) =>
|
||||
Rumble = (largeMotor, smallMotor);
|
||||
|
||||
public void SetTriggerRumble(byte? leftTrigger, byte? rightTrigger) =>
|
||||
TriggerRumble = (leftTrigger, rightTrigger);
|
||||
|
||||
public void SetAdaptiveTriggerEffect(
|
||||
HostAdaptiveTriggerEffect? leftTrigger,
|
||||
HostAdaptiveTriggerEffect? rightTrigger)
|
||||
{
|
||||
LeftTriggerEffect = leftTrigger;
|
||||
RightTriggerEffect = rightTrigger;
|
||||
}
|
||||
|
||||
public void SetLightbar(byte red, byte green, byte blue) =>
|
||||
Lightbar = (red, green, blue);
|
||||
|
||||
public void ResetLightbar() => LightbarReset = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user