diff --git a/InputSimulatorPlus/WindowsInput/IKeyboardSimulator.cs b/InputSimulatorPlus/WindowsInput/IKeyboardSimulator.cs
index a8a2e00..19b6d2d 100644
--- a/InputSimulatorPlus/WindowsInput/IKeyboardSimulator.cs
+++ b/InputSimulatorPlus/WindowsInput/IKeyboardSimulator.cs
@@ -110,15 +110,13 @@ public interface IKeyboardSimulator
/// Calls the Win32 SendInput method with a KeyUp message
///
/// The to press
- /// Delay in ms between keydown and keyup of final keyCode.
- IKeyboardSimulator DelayedKeyPressUp(DirectInputKeyCode dikCode, int delay);
+ IKeyboardSimulator DelayedKeyPressUp(DirectInputKeyCode dikCode);
///
/// Calls the Win32 SendInput method with a KeyDown message
///
/// The to press
- /// Delay in ms between keydown and keyup of final keyCode.
- IKeyboardSimulator DelayedKeyPressDown(DirectInputKeyCode dikCode, int delay);
+ IKeyboardSimulator DelayedKeyPressDown(DirectInputKeyCode dikCode);
///
@@ -152,8 +150,7 @@ public interface IKeyboardSimulator
///
/// The list of modifier keys
/// The key to simulate
- /// Delay in ms between keydown and keyup of final keyCode.
- IKeyboardSimulator DelayedModifiedKeyStrokeDown(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode, int delay);
+ IKeyboardSimulator ModifiedKeyStrokeDown(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode);
///
@@ -162,8 +159,7 @@ public interface IKeyboardSimulator
///
/// The list of modifier keys
/// The key to simulate
- /// Delay in ms between keydown and keyup of final keyCode.
- IKeyboardSimulator DelayedModifiedKeyStrokeUp(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode, int delay);
+ IKeyboardSimulator ModifiedKeyStrokeUp(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode);
///
/// Simulates a modified keystroke where there is one modifier and multiple keys like CTRL-K-C where CTRL is the modifierKey and K and C are the keys.
diff --git a/InputSimulatorPlus/WindowsInput/KeyboardSimulator.cs b/InputSimulatorPlus/WindowsInput/KeyboardSimulator.cs
index f5ca121..d0f9f36 100644
--- a/InputSimulatorPlus/WindowsInput/KeyboardSimulator.cs
+++ b/InputSimulatorPlus/WindowsInput/KeyboardSimulator.cs
@@ -311,11 +311,11 @@ public IKeyboardSimulator KeyPress(DirectInputKeyCode dikCode)
/// Delay in ms between keydown and keyup of final keyCode. 50ms should be minimum
public IKeyboardSimulator DelayedKeyPress(DirectInputKeyCode dikCode, int delay)
{
- DelayedKeyPressDown(dikCode, delay);
+ DelayedKeyPressDown(dikCode);
Thread.Sleep(delay);
- DelayedKeyPressUp(dikCode, delay);
+ DelayedKeyPressUp(dikCode);
return this;
}
@@ -324,8 +324,7 @@ public IKeyboardSimulator DelayedKeyPress(DirectInputKeyCode dikCode, int delay)
/// Calls the Win32 SendInput method with a KeyDown message
///
/// The to press
- /// Delay in ms between keydown and keyup of final keyCode. 50ms should be minimum
- public IKeyboardSimulator DelayedKeyPressDown(DirectInputKeyCode dikCode, int delay)
+ public IKeyboardSimulator DelayedKeyPressDown(DirectInputKeyCode dikCode)
{
var inputList1 = new InputBuilder().AddKeyDown(dikCode).ToArray();
SendSimulatedInput(inputList1);
@@ -337,8 +336,7 @@ public IKeyboardSimulator DelayedKeyPressDown(DirectInputKeyCode dikCode, int de
/// Calls the Win32 SendInput method with a KeyUp message
///
/// The to press
- /// Delay in ms between keydown and keyup of final keyCode. 50ms should be minimum
- public IKeyboardSimulator DelayedKeyPressUp(DirectInputKeyCode dikCode, int delay)
+ public IKeyboardSimulator DelayedKeyPressUp(DirectInputKeyCode dikCode)
{
var inputList2 = new InputBuilder().AddKeyUp(dikCode).ToArray();
SendSimulatedInput(inputList2);
@@ -407,11 +405,11 @@ public IKeyboardSimulator ModifiedKeyStroke(IEnumerable modi
/// Delay in ms between keydown and keyup of final keyCode. 50ms should be minimum
public IKeyboardSimulator DelayedModifiedKeyStroke(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode, int delay)
{
- DelayedModifiedKeyStrokeDown(modifierDikCodes, dikCode, delay);
+ ModifiedKeyStrokeDown(modifierDikCodes, dikCode);
Thread.Sleep(delay);
- DelayedModifiedKeyStrokeUp(modifierDikCodes, dikCode, delay);
+ ModifiedKeyStrokeUp(modifierDikCodes, dikCode);
return this;
}
@@ -422,8 +420,7 @@ public IKeyboardSimulator DelayedModifiedKeyStroke(IEnumerable
/// The list of modifier keys
/// The list of keys to simulate
- /// Delay in ms between keydown and keyup of final keyCode. 50ms should be minimum
- public IKeyboardSimulator DelayedModifiedKeyStrokeDown(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode, int delay)
+ public IKeyboardSimulator ModifiedKeyStrokeDown(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode)
{
foreach (var keyCode in modifierDikCodes)
{
@@ -442,8 +439,7 @@ public IKeyboardSimulator DelayedModifiedKeyStrokeDown(IEnumerable
/// The list of modifier keys
/// The list of keys to simulate
- /// Delay in ms between keydown and keyup of final keyCode. 50ms should be minimum
- public IKeyboardSimulator DelayedModifiedKeyStrokeUp(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode, int delay)
+ public IKeyboardSimulator ModifiedKeyStrokeUp(IEnumerable modifierDikCodes, DirectInputKeyCode dikCode)
{
KeyUp(dikCode);
diff --git a/InputSimulatorPlus/WindowsInput/WindowsInput.csproj b/InputSimulatorPlus/WindowsInput/WindowsInput.csproj
index 9fab198..7b0d1bf 100644
--- a/InputSimulatorPlus/WindowsInput/WindowsInput.csproj
+++ b/InputSimulatorPlus/WindowsInput/WindowsInput.csproj
@@ -10,7 +10,7 @@
PropertiesWindowsInputWindowsInput
- v4.7.2
+ v4.8512
diff --git a/README.md b/README.md
index 390bf3a..6e3f7ae 100644
--- a/README.md
+++ b/README.md
@@ -14,18 +14,24 @@ The bound key is shown in the dropdown, localised for the current keyboard langu
Credit goes to https://github.com/SCToolsfactory/SCJMapper-V2 for all the code to get the `defaultProfile.xml` from the p4k file etc.
-The button works in a similar way, to the streamdeck 'Hotkey' button type.
+The static button works in a similar way, to the streamdeck 'Hotkey' button type.
So, there is only one image and there is no game state feedback for these buttons.
The differences with the 'Hotkey' buttons are, that it gets the keyboard binding from the game.
When the stream deck button is pushed, the 'key down' event is sent to the keyboard
and only after the stream deck button is released, the 'key up' event is sent to the keyboard.
+The plugin's multi-action button behaviour is different : when the stream deck button is pushed, the 'key down' event is sent to the keyboard.
+After a user-definable delay (default = 40 ms) the 'key up' event is sent to the keyboard.
+Nothing happens when the streamdeck button is released.
+
+Both the static- and multi-action buttons can be used inside the streamdeck built-in multi-action button's action list.
+
+The multi-action button can also be used as a regular streamdeck button, in case a fixed user-definable delay is required between the key down and key up events.
+
A sound can be played when pressing a button.
**You can clear the sound path, by clicking on the label in front of the file picker edit box.**
-The buttons can also be used with multi-action buttons.
-
You can, for example, use the 'multi-action switch' function, that is built into the streamdeck software, to set up a toggle function.
You can add the relevant function of this plugin to both the ON-and OFF-action of the 'multi-action switch' function.
You can then set up different images for each toggle state.
@@ -74,7 +80,7 @@ The plugin uses all the active keyboard bindings from `defaultProfile.xml` and t
`C:\Program Files\Roberts Space Industries\StarCitizen\LIVE\USER\Client\0\Profiles\default\actionmaps.xml`
-The `PropertyInspector\StarCitizen\Static.html` file is dynamically updated, in case more custom keyboard bindings were added to `actionmaps.xml`,
+The `PropertyInspector\StarCitizen\Static.html` and `PropertyInspector\StarCitizen\Macro.html` file is dynamically updated, in case more custom keyboard bindings were added to `actionmaps.xml`,
that didn't have any corresponding keyboard bindings in `defaultProfile.xml`.
If nothing happens, when pressing streamdeck buttons: you could try to start streamdeck.exe as administrator.
diff --git a/starcitizen/App.config b/starcitizen/App.config
index 880fc33..f42eca7 100644
--- a/starcitizen/App.config
+++ b/starcitizen/App.config
@@ -2,13 +2,13 @@
-
+
-
+
@@ -20,7 +20,7 @@
-
+
diff --git a/starcitizen/Buttons/Macro.cs b/starcitizen/Buttons/Macro.cs
new file mode 100644
index 0000000..959271a
--- /dev/null
+++ b/starcitizen/Buttons/Macro.cs
@@ -0,0 +1,159 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using WindowsInput.Native;
+using BarRaider.SdTools;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+
+// ReSharper disable StringLiteralTypo
+
+namespace starcitizen.Buttons
+{
+
+ [PluginActionId("com.mhwlng.starcitizen.macro")]
+ public class Macro : StarCitizenBase
+ {
+ protected class PluginSettings
+ {
+ public static PluginSettings CreateDefaultSettings()
+ {
+ var instance = new PluginSettings
+ {
+ Function = string.Empty,
+ };
+
+ return instance;
+ }
+
+ [JsonProperty(PropertyName = "function")]
+ public string Function { get; set; }
+
+ [FilenameProperty]
+ [JsonProperty(PropertyName = "clickSound")]
+ public string ClickSoundFilename { get; set; }
+
+ [JsonProperty(PropertyName = "delay")]
+ public string Delay { get; set; }
+
+ }
+
+
+ PluginSettings settings;
+ private CachedSound _clickSound = null;
+
+ private int? _delay = null;
+
+
+ public Macro(SDConnection connection, InitialPayload payload) : base(connection, payload)
+ {
+ if (payload.Settings == null || payload.Settings.Count == 0)
+ {
+ //Logger.Instance.LogMessage(TracingLevel.DEBUG, "Repeating Macro Constructor #1");
+
+ settings = PluginSettings.CreateDefaultSettings();
+ Connection.SetSettingsAsync(JObject.FromObject(settings)).Wait();
+
+ }
+ else
+ {
+ //Logger.Instance.LogMessage(TracingLevel.DEBUG, "Repeating Macro Constructor #2");
+
+ settings = payload.Settings.ToObject();
+ HandleFileNames();
+ }
+
+ }
+
+
+ public override void KeyPressed(KeyPayload payload)
+ {
+ if (InputRunning || Program.dpReader == null)
+ {
+ ForceStop = true;
+ return;
+ }
+
+ ForceStop = false;
+
+ var action = Program.dpReader.GetBinding(settings.Function);
+ if (action != null)
+ {
+ Logger.Instance.LogMessage(TracingLevel.INFO, CommandTools.ConvertKeyString(action.Keyboard));
+
+ SendKeypress(CommandTools.ConvertKeyString(action.Keyboard), _delay ?? 40);
+ }
+
+ if (_clickSound != null)
+ {
+ try
+ {
+ AudioPlaybackEngine.Instance.PlaySound(_clickSound);
+ }
+ catch (Exception ex)
+ {
+ Logger.Instance.LogMessage(TracingLevel.FATAL, $"PlaySound: {ex}");
+ }
+
+ }
+
+ }
+
+ public override void KeyReleased(KeyPayload payload)
+ {
+
+
+ }
+
+ public override void Dispose()
+ {
+ base.Dispose();
+
+ //Logger.Instance.LogMessage(TracingLevel.DEBUG, "Destructor called #1");
+ }
+
+
+ public override void ReceivedSettings(ReceivedSettingsPayload payload)
+ {
+ //Logger.Instance.LogMessage(TracingLevel.DEBUG, "ReceivedSettings");
+
+ // New in StreamDeck-Tools v2.0:
+ BarRaider.SdTools.Tools.AutoPopulateSettings(settings, payload.Settings);
+ HandleFileNames();
+ }
+
+ private void HandleFileNames()
+ {
+ _delay = null;
+
+ if (!string.IsNullOrEmpty(settings.Delay))
+ {
+ var ok = int.TryParse(settings.Delay, out var delay);
+ if (ok && (delay > 0))
+ {
+ _delay = delay;
+ }
+ }
+
+ _clickSound = null;
+
+ if (File.Exists(settings.ClickSoundFilename))
+ {
+ try
+ {
+ _clickSound = new CachedSound(settings.ClickSoundFilename);
+ }
+ catch (Exception ex)
+ {
+ Logger.Instance.LogMessage(TracingLevel.FATAL, $"CachedSound: {settings.ClickSoundFilename} {ex}");
+
+ _clickSound = null;
+ settings.ClickSoundFilename = null;
+ }
+ }
+
+ Connection.SetSettingsAsync(JObject.FromObject(settings)).Wait();
+ }
+ }
+}
diff --git a/starcitizen/Buttons/StarCitizenBase.cs b/starcitizen/Buttons/StarCitizenBase.cs
index d7322c5..b4d6b37 100644
--- a/starcitizen/Buttons/StarCitizenBase.cs
+++ b/starcitizen/Buttons/StarCitizenBase.cs
@@ -51,6 +51,19 @@ public override void OnTick()
public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload) { }
+ private void SendInput(string inputText, int delay)
+ {
+ var text = inputText;
+
+ for (var idx = 0; idx < text.Length && !ForceStop; idx++)
+ {
+ var macro = CommandTools.ExtractMacro(text, idx);
+ idx += macro.Length - 1;
+ macro = macro.Substring(1, macro.Length - 2);
+
+ HandleMacro(macro, delay);
+ }
+ }
private void SendInputDown(string inputText)
{
var text = inputText;
@@ -79,6 +92,33 @@ private void SendInputUp(string inputText)
}
}
+ public static void HandleMacro(string macro, int delay)
+ {
+ var keyStrokes = CommandTools.ExtractKeyStrokes(macro);
+
+ // Actually initiate the keystrokes
+ if (keyStrokes.Count > 0)
+ {
+ var iis = new InputSimulator();
+ var keyCode = keyStrokes.Last();
+ keyStrokes.Remove(keyCode);
+
+ if (keyStrokes.Count > 0)
+ {
+ //iis.Keyboard.ModifiedKeyStroke(keyStrokes.Select(ks => ks).ToArray(), keyCode);
+
+ iis.Keyboard.DelayedModifiedKeyStroke(keyStrokes.Select(ks => ks), keyCode, delay);
+
+ }
+ else // Single Keycode
+ {
+ //iis.Keyboard.KeyPress(keyCode);
+
+ iis.Keyboard.DelayedKeyPress(keyCode, delay);
+ }
+ }
+ }
+
private void HandleMacroDown(string macro)
{
var keyStrokes = CommandTools.ExtractKeyStrokes(macro);
@@ -92,12 +132,12 @@ private void HandleMacroDown(string macro)
if (keyStrokes.Count > 0)
{
- iis.Keyboard.DelayedModifiedKeyStrokeDown(keyStrokes.Select(ks => ks), keyCode, 40);
+ iis.Keyboard.ModifiedKeyStrokeDown(keyStrokes.Select(ks => ks), keyCode);
}
else // Single Keycode
{
- iis.Keyboard.DelayedKeyPressDown(keyCode, 40);
+ iis.Keyboard.DelayedKeyPressDown(keyCode);
}
}
}
@@ -116,16 +156,24 @@ private void HandleMacroUp(string macro)
if (keyStrokes.Count > 0)
{
- iis.Keyboard.DelayedModifiedKeyStrokeUp(keyStrokes.Select(ks => ks), keyCode, 40);
+ iis.Keyboard.ModifiedKeyStrokeUp(keyStrokes.Select(ks => ks), keyCode);
}
else // Single Keycode
{
- iis.Keyboard.DelayedKeyPressUp(keyCode, 40);
+ iis.Keyboard.DelayedKeyPressUp(keyCode);
}
}
}
+ protected void SendKeypress(string keyInfo, int delay)
+ {
+ if (!string.IsNullOrEmpty(keyInfo))
+ {
+ SendInput("{" + keyInfo + "}", delay);
+ }
+ }
+
protected void SendKeypressDown(string keyInfo)
{
if (!string.IsNullOrEmpty(keyInfo))
diff --git a/starcitizen/Program.cs b/starcitizen/Program.cs
index e7ad7db..6b4b76d 100644
--- a/starcitizen/Program.cs
+++ b/starcitizen/Program.cs
@@ -86,6 +86,8 @@ class Program
public static string statictemplate;
+ public static string macrotemplate;
+
public static void HandleKeyBindingEvents(object sender, object evt)
{
Logger.Instance.LogMessage(TracingLevel.INFO, $"Reloading Key Bindings");
@@ -116,6 +118,8 @@ private static void GetKeyBindings(Object threadContext)
dpReader.CreateStaticHtml(statictemplate);
+ dpReader.CreateMacroHtml(macrotemplate);
+
dpReader.CreateCsv();
Logger.Instance.LogMessage(TracingLevel.INFO, "monitoring key binding file" );
@@ -135,6 +139,8 @@ static void Main(string[] args)
statictemplate = File.ReadAllText("statictemplate.html");
+ macrotemplate = File.ReadAllText("macrotemplate.html");
+
profile = SCDefaultProfile.DefaultProfile();
GetKeyBindings(null);
diff --git a/starcitizen/Properties/AssemblyInfo.cs b/starcitizen/Properties/AssemblyInfo.cs
index 8a5da05..a970a02 100644
--- a/starcitizen/Properties/AssemblyInfo.cs
+++ b/starcitizen/Properties/AssemblyInfo.cs
@@ -31,5 +31,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.6.0")]
-[assembly: AssemblyFileVersion("1.0.6.0")]
+[assembly: AssemblyVersion("1.0.7.0")]
+[assembly: AssemblyFileVersion("1.0.7.0")]
diff --git a/starcitizen/PropertyInspector/StarCitizen/Macro.html b/starcitizen/PropertyInspector/StarCitizen/Macro.html
new file mode 100644
index 0000000..59a3527
--- /dev/null
+++ b/starcitizen/PropertyInspector/StarCitizen/Macro.html
@@ -0,0 +1,352 @@
+
+
+
+
+
+
+
+ Mhwlng's Star Citizen
+
+
+
+
+
+
+
+