Skip to content

Commit

Permalink
Add functionality to repeat a button press a number of times; added t…
Browse files Browse the repository at this point in the history
…ext box and label; new repeat count property on button; new events for repeat; display icon in Activity list;
  • Loading branch information
joekolodz committed Aug 15, 2022
1 parent 568946d commit 0299ad4
Show file tree
Hide file tree
Showing 15 changed files with 223 additions and 27 deletions.
7 changes: 6 additions & 1 deletion src/Controls/MacroTransport.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@
Margin="0,2,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<CheckBox Margin="0,2,0,0" IsChecked="{Binding IsOneShot}">One Shot</CheckBox>

<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,0,0">
<CheckBox Margin="0,2,0,0" IsChecked="{Binding IsOneShot}">One Shot</CheckBox>
<Label Content="Repeats" Foreground="{StaticResource TextBrush}" Margin="81,0,0,0"/>
<TextBox Text="{Binding RepeatCount}" ToolTip="Number of times to repeat this button press. -1 for infinite" ToolTipService.InitialShowDelay="800" Foreground="{StaticResource TextBrush}" CaretBrush="{StaticResource TextBrush}" Margin="0,0,2,0" Width="100" Height="20" FontSize="12" Background="{StaticResource WindowBackgroundBrush}" BorderBrush="{StaticResource NormalBorderBrush}"/>
</StackPanel>
</StackPanel>
</UserControl>
1 change: 1 addition & 0 deletions src/Models/HOTASButton.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public enum ButtonType
public int ShiftModePage { get; set; }
public bool IsShift { get; set; }
public bool IsOneShot { get; set; }
public int RepeatCount{ get; set; }

public Guid ActionId
{
Expand Down
40 changes: 31 additions & 9 deletions src/Models/HOTASCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ public class HOTASCollection : IHOTASCollection
public virtual event EventHandler<KeystrokeSentEventArgs> KeystrokeUpSent;
public virtual event EventHandler<MacroStartedEventArgs> MacroStarted;
public virtual event EventHandler<MacroCancelledEventArgs> MacroCancelled;
public virtual event EventHandler<RepeatStartedEventArgs> RepeatStarted;
public virtual event EventHandler<RepeatCancelledEventArgs> RepeatCancelled;
public virtual event EventHandler<ButtonPressedEventArgs> ButtonPressed;
public virtual event EventHandler<AxisChangedEventArgs> AxisChanged;
public virtual event EventHandler<ModeChangedEventArgs> ModeChanged;
Expand Down Expand Up @@ -120,15 +122,7 @@ private void StopDevice(IHOTASDevice device)
{
if (device == null) return;

device.ButtonPressed -= Device_ButtonPressed;
device.AxisChanged -= Device_AxisChanged;
device.KeystrokeDownSent -= Device_KeystrokeDownSent;
device.KeystrokeUpSent -= Device_KeystrokeUpSent;
device.MacroStarted -= Device_MacroStarted;
device.MacroCancelled -= Device_MacroCancelled;
device.ModeSelected -= device_modeSelected;
device.ShiftReleased -= Device_ShiftReleased;
device.LostConnectionToDevice -= Device_LostConnectionToDevice;
RemoveHandlers(device);

device.Stop();
}
Expand Down Expand Up @@ -163,12 +157,16 @@ public void ListenToAllDevices()

public void ListenToDevice(IHOTASDevice device)
{
RemoveHandlers(device);

device.ButtonPressed += Device_ButtonPressed;
device.AxisChanged += Device_AxisChanged;
device.KeystrokeDownSent += Device_KeystrokeDownSent;
device.KeystrokeUpSent += Device_KeystrokeUpSent;
device.MacroStarted += Device_MacroStarted;
device.MacroCancelled += Device_MacroCancelled;
device.RepeatStarted += Device_RepeatStarted;
device.RepeatCancelled += Device_RepeatCancelled;
device.ModeSelected += device_modeSelected;
device.ShiftReleased += Device_ShiftReleased;
device.LostConnectionToDevice += Device_LostConnectionToDevice;
Expand All @@ -177,6 +175,21 @@ public void ListenToDevice(IHOTASDevice device)
device.ListenAsync();
}

private void RemoveHandlers(IHOTASDevice device)
{
device.ButtonPressed -= Device_ButtonPressed;
device.AxisChanged -= Device_AxisChanged;
device.KeystrokeDownSent -= Device_KeystrokeDownSent;
device.KeystrokeUpSent -= Device_KeystrokeUpSent;
device.MacroStarted -= Device_MacroStarted;
device.MacroCancelled -= Device_MacroCancelled;
device.RepeatStarted -= Device_RepeatStarted;
device.RepeatCancelled -= Device_RepeatCancelled;
device.ModeSelected -= device_modeSelected;
device.ShiftReleased -= Device_ShiftReleased;
device.LostConnectionToDevice -= Device_LostConnectionToDevice;
}

private void Device_LostConnectionToDevice(object sender, LostConnectionToDeviceEventArgs e)
{
LostConnectionToDevice?.Invoke(sender, e);
Expand Down Expand Up @@ -252,6 +265,15 @@ private void Device_MacroCancelled(object sender, MacroCancelledEventArgs e)
{
MacroCancelled?.Invoke(sender, e);
}
private void Device_RepeatStarted(object sender, RepeatStartedEventArgs e)
{
Logging.Log.Debug("HOTASCollection - repeat started event");
RepeatStarted?.Invoke(sender, e);
}
private void Device_RepeatCancelled(object sender, RepeatCancelledEventArgs e)
{
RepeatCancelled?.Invoke(sender, e);
}

public void ForceButtonPress(IHOTASDevice device, JoystickOffset offset, bool isDown)
{
Expand Down
16 changes: 16 additions & 0 deletions src/Models/HOTASDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public class HOTASDevice : IHOTASDevice
public event EventHandler<KeystrokeSentEventArgs> KeystrokeUpSent;
public event EventHandler<MacroStartedEventArgs> MacroStarted;
public event EventHandler<MacroCancelledEventArgs> MacroCancelled;
public event EventHandler<RepeatStartedEventArgs> RepeatStarted;
public event EventHandler<RepeatCancelledEventArgs> RepeatCancelled;
public event EventHandler<ButtonPressedEventArgs> ButtonPressed;
public event EventHandler<ModeSelectedEventArgs> ModeSelected;
public event EventHandler<EventArgs> ShiftReleased;
Expand Down Expand Up @@ -228,6 +230,8 @@ private void AddQueueHandlers()
_hotasQueue.KeystrokeUpSent += OnKeystrokeUpSent;
_hotasQueue.MacroStarted += OnMacroStarted;
_hotasQueue.MacroCancelled += OnMacroCancelled;
_hotasQueue.RepeatStarted += OnRepeatStarted;
_hotasQueue.RepeatCancelled += OnRepeatCancelled;
_hotasQueue.ButtonPressed += OnButtonPress;
_hotasQueue.AxisChanged += OnAxisChanged;
_hotasQueue.ModeSelected += onModeSelected;
Expand All @@ -241,6 +245,8 @@ private void RemoveQueueHandlers()
_hotasQueue.KeystrokeUpSent -= OnKeystrokeUpSent;
_hotasQueue.MacroStarted -= OnMacroStarted;
_hotasQueue.MacroCancelled -= OnMacroCancelled;
_hotasQueue.RepeatStarted -= OnRepeatStarted;
_hotasQueue.RepeatCancelled -= OnRepeatCancelled;
_hotasQueue.ButtonPressed -= OnButtonPress;
_hotasQueue.AxisChanged -= OnAxisChanged;
_hotasQueue.ModeSelected -= onModeSelected;
Expand Down Expand Up @@ -473,6 +479,16 @@ private void OnMacroCancelled(object sender, MacroCancelledEventArgs e)
MacroCancelled?.Invoke(sender, e);
}

private void OnRepeatStarted(object sender, RepeatStartedEventArgs e)
{
Logging.Log.Debug("HOTASDevice - repeat started event");
RepeatStarted?.Invoke(sender, e);
}
private void OnRepeatCancelled(object sender, RepeatCancelledEventArgs e)
{
RepeatCancelled?.Invoke(sender, e);
}

private void OnButtonPress(object sender, ButtonPressedEventArgs e)
{
ButtonPressed?.Invoke(this, new ButtonPressedEventArgs() { ButtonId = e.ButtonId, Device = this });
Expand Down
108 changes: 96 additions & 12 deletions src/Models/HOTASQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ public class HOTASQueue : IHOTASQueue
public event EventHandler<KeystrokeSentEventArgs> KeystrokeDownSent;
public event EventHandler<MacroStartedEventArgs> MacroStarted;
public event EventHandler<MacroCancelledEventArgs> MacroCancelled;
public event EventHandler<RepeatStartedEventArgs> RepeatStarted;
public event EventHandler<RepeatCancelledEventArgs> RepeatCancelled;
public event EventHandler<ButtonPressedEventArgs> ButtonPressed;
public event EventHandler<ButtonPressedEventArgs> ButtonReleased;
public event EventHandler<AxisChangedEventArgs> AxisChanged;
Expand Down Expand Up @@ -82,7 +84,7 @@ public static int TranslatePointOfViewOffset(JoystickOffset offset, int value)
return translatedOffset;
}

private void ListenLoop()
private async Task ListenLoop()
{
while (!_isStopRequested)
{
Expand Down Expand Up @@ -110,7 +112,7 @@ private void ListenLoop()
if (offset >= JoystickOffset.Button1 && offset <= JoystickOffset.Button128)
{
Logging.Log.Debug($"Offset:{offset}({state.RawOffset}), Seq:{state.Sequence}, Value:{state.Value}");
HandleStandardButton((int)offset, state.Value);
await HandleStandardButton((int)offset, state.Value);
continue;
}

Expand All @@ -120,7 +122,7 @@ private void ListenLoop()
offset == JoystickOffset.POV4)
{
Logging.Log.Debug($"Offset:{offset}({state.RawOffset}), POV:{TranslatePointOfViewOffset(offset, state.Value)}, Seq:{state.Sequence}, Value:{state.Value}");
HandlePovButton((JoystickOffset)state.Offset, state.Value);
await HandlePovButton((JoystickOffset)state.Offset, state.Value);
continue;
}

Expand All @@ -141,7 +143,7 @@ private void ListenLoop()
}
if (_jitterDetectionDictionary[state.RawOffset].IsJitter(state.Value)) continue;

HandleAxis(state);
await HandleAxis(state);
OnAxisChanged(state);
continue;
}
Expand Down Expand Up @@ -196,7 +198,7 @@ private bool IsButtonDown(int value)
}

private static readonly ConcurrentDictionary<JoystickOffset, int> _lastPovButton = new ConcurrentDictionary<JoystickOffset, int>();
private void HandlePovButton(JoystickOffset offset, int value)
private async Task HandlePovButton(JoystickOffset offset, int value)
{
if (_lastPovButton.ContainsKey(offset) || value == (int)JoystickOffsetValues.PointOfViewPositionValues.Released)
{
Expand All @@ -218,22 +220,23 @@ private void HandlePovButton(JoystickOffset offset, int value)

if (!(GetMap(translatedOffset) is HOTASButton map)) return;

HandleButtonPressed(map, translatedOffset);
await HandleButtonPressed(map, translatedOffset);
OnButtonPress(translatedOffset);
}
}

private static readonly ConcurrentDictionary<int, bool> _activeRepeat = new ConcurrentDictionary<int, bool>();
private static readonly ConcurrentDictionary<int, bool> _activeMacros = new ConcurrentDictionary<int, bool>();
private static readonly ConcurrentDictionary<int, Task> _activeButtons = new ConcurrentDictionary<int, Task>();
private void HandleStandardButton(int offset, int value)
private async Task HandleStandardButton(int offset, int value)
{
var map = GetMap(offset) as HOTASButton;
if (IsButtonDown(value))
{
if (map != null && (map.ActionCatalogItem.Actions.Count > 0 || map.ShiftModePage > 0))
{
//if action list has a timer in it, then it is a macro and executes on another thread independently. does not interrupt other buttons
HandleButtonPressed(map, offset);
await HandleButtonPressed(map, offset);
}
else
{
Expand All @@ -243,7 +246,7 @@ private void HandleStandardButton(int offset, int value)
map = GetMapFromParentMode(_modeActivationButtons[_mode].InheritFromMode, offset) as HOTASButton;
if (map != null)
{
HandleButtonPressed(map, offset);
await HandleButtonPressed(map, offset);
}
}
}
Expand All @@ -257,10 +260,17 @@ private void HandleStandardButton(int offset, int value)
}
}

private void HandleButtonPressed(HOTASButton button, int offset)
private async Task HandleButtonPressed(HOTASButton button, int offset)
{
if (button == null) return;

//macros and oneshots can be repeated so check repeats first
if (button.RepeatCount != 0)
{
HandleRepeat(button, offset);
return;
}

if (button.IsOneShot)
{
HandleOneShot(button, offset);
Expand All @@ -282,6 +292,80 @@ private void HandleButtonPressed(HOTASButton button, int offset)
_actionJobs.Add(new ActionJobItem() { Offset = offset, MapId = button.MapId, Actions = button.ActionCatalogItem.Actions });
}

private void HandleRepeat(HOTASButton button, int offset)
{
if (_activeRepeat.TryGetValue(offset, out _))
{
//cancel a repeat already in progress
_activeRepeat.TryRemove(offset, out _);
RepeatCancelled?.Invoke(this, new RepeatCancelledEventArgs(offset, (int)Win32Structures.ScanCodeShort.REPEAT_CANCELLED));
return;
}

_activeRepeat.TryAdd(offset, true);

Task.Run(() => PlayRepeat(button, offset));
}

private async Task PlayRepeat(HOTASButton button, int offset)
{
Logging.Log.Debug("HOTASQueue - repeat started event");
RepeatStarted?.Invoke(this, new RepeatStartedEventArgs(offset, (int)Win32Structures.ScanCodeShort.REPEAT_STARTED));

var repeatedButton = new HOTASButton()
{
RepeatCount = 0,
ActionCatalogItem = button.ActionCatalogItem,
ActionId = button.ActionId,
ActionName = button.ActionName,
IsOneShot = button.IsOneShot,
IsShift = button.IsShift,
MapId = button.MapId,
MapName = button.MapName,
ShiftModePage = button.ShiftModePage,
Type = button.Type
};


var repeatsLeft = button.RepeatCount;

if (repeatsLeft == -1)
{
while (true)
{
if (await BaseRepeat(button, offset, repeatedButton)) break;
}
}
else
{
while (repeatsLeft-- > 0)
{
if (await BaseRepeat(button, offset, repeatedButton)) break;
}
}

_activeRepeat.TryRemove(offset, out _);
}

private async Task<bool> BaseRepeat(HOTASButton button, int offset, HOTASButton repeatedButton)
{
await HandleButtonPressed(repeatedButton, offset);

if (_activeRepeat.ContainsKey(offset) == false) return true;

if (button.IsMacro)
{
while (_activeMacros.ContainsKey(offset))
{
await Task.Delay(500);
if (_activeRepeat.ContainsKey(offset) == false) break;
}
}

return false;
}


private void HandleMacro(HOTASButton button, int offset)
{
if (_activeMacros.TryGetValue(offset, out _))
Expand Down Expand Up @@ -382,7 +466,7 @@ private void HandleButtonReleased(HOTASButton button, int offset)
_actionJobs.Add(new ActionJobItem() { Offset = offset, MapId = mapId, Actions = null });
}

private void HandleAxis(JoystickUpdate state)
private async Task HandleAxis(JoystickUpdate state)
{
var offset = (int)state.Offset;

Expand All @@ -393,7 +477,7 @@ private void HandleAxis(JoystickUpdate state)
if (!axis.IsSegmentChanged) return;

var map = axis.GetButtonMapFromRawValue(state.Value);
HandleButtonPressed(map, offset);
await HandleButtonPressed(map, offset);
HandleButtonReleased(map, offset);
}

Expand Down
2 changes: 2 additions & 0 deletions src/Models/IHOTASCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public interface IHOTASCollection
event EventHandler<KeystrokeSentEventArgs> KeystrokeUpSent;
event EventHandler<MacroStartedEventArgs> MacroStarted;
event EventHandler<MacroCancelledEventArgs> MacroCancelled;
event EventHandler<RepeatStartedEventArgs> RepeatStarted;
event EventHandler<RepeatCancelledEventArgs> RepeatCancelled;
event EventHandler<ButtonPressedEventArgs> ButtonPressed;
event EventHandler<AxisChangedEventArgs> AxisChanged;
event EventHandler<ModeChangedEventArgs> ModeChanged;
Expand Down
2 changes: 2 additions & 0 deletions src/Models/IHOTASDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public interface IHOTASDevice
event EventHandler<KeystrokeSentEventArgs> KeystrokeUpSent;
event EventHandler<MacroStartedEventArgs> MacroStarted;
event EventHandler<MacroCancelledEventArgs> MacroCancelled;
event EventHandler<RepeatStartedEventArgs> RepeatStarted;
event EventHandler<RepeatCancelledEventArgs> RepeatCancelled;
event EventHandler<ButtonPressedEventArgs> ButtonPressed;
event EventHandler<ModeSelectedEventArgs> ModeSelected;
event EventHandler<EventArgs> ShiftReleased;
Expand Down
2 changes: 2 additions & 0 deletions src/Models/IHOTASQueue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public interface IHOTASQueue
event EventHandler<KeystrokeSentEventArgs> KeystrokeDownSent;
event EventHandler<MacroCancelledEventArgs> MacroCancelled;
event EventHandler<MacroStartedEventArgs> MacroStarted;
event EventHandler<RepeatStartedEventArgs> RepeatStarted;
event EventHandler<RepeatCancelledEventArgs> RepeatCancelled;
event EventHandler<ButtonPressedEventArgs> ButtonPressed;
event EventHandler<ButtonPressedEventArgs> ButtonReleased;
event EventHandler<AxisChangedEventArgs> AxisChanged;
Expand Down
16 changes: 16 additions & 0 deletions src/Models/RecordStartedEventArgs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace SierraHOTAS.Models
{
public class RepeatStartedEventArgs : EventArgs
{
public int Offset { get; set; }
public int Code { get; set; }

public RepeatStartedEventArgs(int offset, int code)
{
Offset = offset;
Code = code;
}
}
}
Loading

0 comments on commit 0299ad4

Please sign in to comment.