Skip to content

Commit

Permalink
Animation on controller movement
Browse files Browse the repository at this point in the history
  • Loading branch information
csutorasa committed Apr 23, 2018
1 parent f82c676 commit 938c5d0
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 12 deletions.
2 changes: 1 addition & 1 deletion XOutput/Devices/AbstractInputHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public AbstractInputHelper()
{
throw new ArgumentException("Type must be enum", nameof(T));
}
values = (T[])Enum.GetValues(typeof(T));
values = ((T[])Enum.GetValues(typeof(T))).Distinct();
buttons = values.Where(v => IsButton(v)).ToArray();
axes = values.Where(v => IsAxis(v)).ToArray();
dPad = values.Where(v => IsDPad(v)).ToArray();
Expand Down
20 changes: 20 additions & 0 deletions XOutput/Devices/DeviceInputChangedEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,26 @@ namespace XOutput.Devices

public class DeviceInputChangedEventArgs : EventArgs
{
public IEnumerable<Enum> ChangedValues => changedValues.ToArray();
public IEnumerable<int> ChangedDPads => changedDPads.ToArray();

protected IEnumerable<Enum> changedValues;
protected IEnumerable<int> changedDPads;

public DeviceInputChangedEventArgs(IEnumerable<Enum> changedValues, IEnumerable<int> changedDPads)
{
this.changedDPads = changedDPads;
this.changedValues = changedValues;
}

public bool HasValueChanged(Enum type)
{
return changedValues.Contains(type);
}

public bool HasDPadChanged(int dPadIndex)
{
return changedDPads.Contains(dPadIndex);
}
}
}
55 changes: 55 additions & 0 deletions XOutput/Devices/DeviceState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XOutput.Devices
{
public class DeviceState
{
public Dictionary<Enum, double> Values => values;
public IEnumerable<DPadDirection> DPads => dPads;
protected Dictionary<Enum, double> values = new Dictionary<Enum, double>();
protected DPadDirection[] dPads;

public DeviceState(IEnumerable<Enum> types, int dPadCount)
{
foreach (Enum type in types)
{
values.Add(type, 0);
}
dPads = new DPadDirection[dPadCount];
}

public IEnumerable<int> SetDPads(IEnumerable<DPadDirection> newDPads)
{
if (newDPads.Count() != dPads.Length)
throw new ArgumentException();
ICollection<int> changed = new HashSet<int>();
foreach (var x in newDPads.Select((d, i) => new { New = d, Old = dPads[i], Index = i }).ToArray())
{
if (x.New != x.Old)
{
dPads[x.Index] = x.New;
changed.Add(x.Index);
}
}
return changed;
}

public IEnumerable<Enum> SetValues(Dictionary<Enum, double> newValues)
{
ICollection<Enum> changed = new HashSet<Enum>();
foreach (var x in newValues.Select((d, i) => new { New = d.Value, Old = values[d.Key], Type = d.Key }).ToArray())
{
if (x.New != x.Old)
{
values[x.Type] = x.New;
changed.Add(x.Type);
}
}
return changed;
}
}
}
15 changes: 10 additions & 5 deletions XOutput/Devices/Input/DirectInput/DirectDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ public bool Connected
private readonly Enum[] axes;
private readonly Enum[] sliders;
private readonly DPadDirection[] dpads;
private readonly Enum[] allTypes;
private readonly DeviceState state;
private readonly EffectInfo force;
private readonly Dictionary<DeviceObjectInstance, Effect> actuators;
private bool connected = false;
Expand Down Expand Up @@ -96,6 +98,8 @@ public DirectDevice(DeviceInstance deviceInstance, Joystick joystick)
{
actuators = new Dictionary<DeviceObjectInstance, Effect>();
}
allTypes = buttons.Concat(axes).Concat(sliders).ToArray();
state = new DeviceState(allTypes, dpads.Length);
inputRefresher = new Thread(InputRefresher);
inputRefresher.Name = ToString() + " input reader";
inputRefresher.SetApartmentState(ApartmentState.STA);
Expand Down Expand Up @@ -223,11 +227,12 @@ public bool RefreshInput()
try
{
joystick.Poll();
foreach (var dpad in Enumerable.Range(0, dpads.Length))
{
dpads[dpad] = GetDPadValue(dpad);
}
InputChanged?.Invoke(this, new DeviceInputChangedEventArgs());
var newDPads = Enumerable.Range(0, dpads.Length).Select(i => GetDPadValue(i));
var newValues = allTypes.ToDictionary(t => t, t => Get(t));
var changedDPads = state.SetDPads(newDPads);
var changedValues = state.SetValues(newValues);
if (changedDPads.Any() || changedValues.Any())
InputChanged?.Invoke(this, new DeviceInputChangedEventArgs(changedValues, changedDPads));
return true;
}
catch
Expand Down
7 changes: 6 additions & 1 deletion XOutput/Devices/Input/Keyboard/Keyboard.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ public event DeviceDisconnectedHandler Disconnected { add { } remove { } }

private Thread inputRefresher;
private readonly Enum[] buttons;
private readonly DeviceState state;

public Keyboard()
{
buttons = KeyboardInputHelper.Instance.Buttons.Where(x => x != Key.None).OrderBy(x => x.ToString()).OfType<Enum>().ToArray();
state = new DeviceState(buttons, 0);
inputRefresher = new Thread(InputRefresher);
inputRefresher.Name = "Keyboard input notification";
inputRefresher.SetApartmentState(ApartmentState.STA);
Expand Down Expand Up @@ -79,7 +81,10 @@ private void InputRefresher()
{
while (true)
{
InputChanged?.Invoke(this, new DeviceInputChangedEventArgs());
var newValues = buttons.ToDictionary(t => t, t => Get(t));
var changedValues = state.SetValues(newValues);
if (changedValues.Any())
InputChanged?.Invoke(this, new DeviceInputChangedEventArgs(changedValues, new int[0]));
Thread.Sleep(1);
}
}
Expand Down
5 changes: 5 additions & 0 deletions XOutput/Devices/XInput/XInputHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ public static bool IsDPad(this XInputTypes input)
return XInputHelper.Instance.IsDPad(input);
}

public static bool IsButton(this XInputTypes input)
{
return XInputHelper.Instance.IsButton(input);
}

public static double GetDisableValue(this XInputTypes input)
{
return XInputHelper.Instance.GetDisableValue(input);
Expand Down
11 changes: 9 additions & 2 deletions XOutput/Devices/XInput/XOutputDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ namespace XOutput.Devices.XInput
/// </summary>
public sealed class XOutputDevice : IDevice
{
public const int DPadCount = 1;

/// <summary>
/// This event is invoked if the data from the device was updated
/// </summary>
Expand All @@ -26,7 +28,8 @@ public sealed class XOutputDevice : IDevice
private readonly Dictionary<XInputTypes, double> values = new Dictionary<XInputTypes, double>();
private readonly IInputDevice source;
private readonly InputMapperBase mapper;
private DPadDirection[] dPads = new DPadDirection[1];
private readonly DPadDirection[] dPads = new DPadDirection[DPadCount];
private readonly DeviceState state;

/// <summary>
/// Creates a new XDevice.
Expand All @@ -37,6 +40,7 @@ public XOutputDevice(IInputDevice source, Mapper.InputMapperBase mapper)
{
this.source = source;
this.mapper = mapper;
state = new DeviceState(XInputHelper.Instance.Values.OfType<Enum>().ToArray(), DPadCount);
source.InputChanged += SourceInputChanged;
}

Expand Down Expand Up @@ -94,7 +98,10 @@ public bool RefreshInput()
{
dPads[0] = DPadHelper.GetDirection(GetBool(XInputTypes.UP), GetBool(XInputTypes.DOWN), GetBool(XInputTypes.LEFT), GetBool(XInputTypes.RIGHT));
}
InputChanged?.Invoke(this, new DeviceInputChangedEventArgs());
var changedDPads = state.SetDPads(dPads);
var changedValues = state.SetValues(values.Where(t => !t.Key.IsDPad()).ToDictionary(x => (Enum)x.Key, x => x.Value));
if (changedDPads.Any() || changedValues.Any())
InputChanged?.Invoke(this, new DeviceInputChangedEventArgs(changedValues, changedDPads));
return true;
}

Expand Down
15 changes: 15 additions & 0 deletions XOutput/UI/Component/ControllerModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using XOutput.Devices;

namespace XOutput.UI.Component
Expand Down Expand Up @@ -63,6 +64,20 @@ public bool CanStart
}
}
}

private Brush background;
public Brush Background
{
get => background;
set
{
if (background != value)
{
background = value;
OnPropertyChanged(nameof(Background));
}
}
}
public string DisplayName { get { return Controller.ToString(); } }
}
}
2 changes: 1 addition & 1 deletion XOutput/UI/Component/ControllerView.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
d:DataContext="{d:DesignInstance Type=local:ControllerViewModel, IsDesignTimeCreatable=False}"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="300">
<Grid>
<Grid Background="{Binding Model.Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
Expand Down
28 changes: 27 additions & 1 deletion XOutput/UI/Component/ControllerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,28 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Windows.Threading;
using XOutput.Devices;
using XOutput.UI.Windows;

namespace XOutput.UI.Component
{
public class ControllerViewModel : ViewModelBase<ControllerModel>
public class ControllerViewModel : ViewModelBase<ControllerModel>, IDisposable
{
private const int BackgroundDelayMS = 500;
private readonly Action<string> log;
private readonly DispatcherTimer timer = new DispatcherTimer();

public ControllerViewModel(ControllerModel model, GameController controller, Action<string> log) : base(model)
{
this.log = log;
Model.Controller = controller;
Model.ButtonText = "Start";
Model.Background = Brushes.White;
Model.Controller.InputDevice.InputChanged += InputDevice_InputChanged;
timer.Interval = TimeSpan.FromMilliseconds(BackgroundDelayMS);
timer.Tick += Timer_Tick;
}

public void Edit()
Expand Down Expand Up @@ -57,5 +65,23 @@ public void Start()
Model.Started = controllerCount != 0;
}
}

public void Dispose()
{
timer.Tick -= Timer_Tick;
Model.Controller.InputDevice.InputChanged -= InputDevice_InputChanged;
}

private void Timer_Tick(object sender, EventArgs e)
{
Model.Background = Brushes.White;
}

private void InputDevice_InputChanged(object sender, DeviceInputChangedEventArgs e)
{
Model.Background = Brushes.LightGreen;
timer.Stop();
timer.Start();
}
}
}
2 changes: 1 addition & 1 deletion XOutput/UI/Windows/AutoConfigureViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private void ReadValues(object sender, DeviceInputChangedEventArgs e)
{
Enum maxType = null;
double maxDiff = 0;
foreach (var type in inputTypes)
foreach (var type in e.ChangedValues)
{
double oldValue = referenceValues[type];
double newValue = controller.InputDevice.Get(type);
Expand Down
1 change: 1 addition & 0 deletions XOutput/UI/Windows/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public void RefreshGameControllers()
var controller = controllerView.ViewModel.Model.Controller;
if (controller.InputDevice is DirectDevice && (!instances.Any(x => x.InstanceGuid == ((DirectDevice)controller.InputDevice).Id) || !controller.InputDevice.Connected))
{
controllerView.ViewModel.Dispose();
controller.Dispose();
Model.Controllers.Remove(controllerView);
logger.Info($"{controller.ToString()} is disconnected.");
Expand Down
1 change: 1 addition & 0 deletions XOutput/XOutput.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="Devices\DeviceState.cs" />
<Compile Include="Tools\ArgumentParser.cs" />
<Compile Include="Devices\DeviceInputChangedEventArgs.cs" />
<Compile Include="Tools\Helper.cs" />
Expand Down

0 comments on commit 938c5d0

Please sign in to comment.