diff --git a/SteamController/App.config b/SteamController/App.config index fdc215d..4fea036 100644 --- a/SteamController/App.config +++ b/SteamController/App.config @@ -10,6 +10,9 @@ True + + True + \ No newline at end of file diff --git a/SteamController/Profiles/Context.cs b/SteamController/Context.cs similarity index 52% rename from SteamController/Profiles/Context.cs rename to SteamController/Context.cs index 5f16768..cabc28b 100644 --- a/SteamController/Profiles/Context.cs +++ b/SteamController/Context.cs @@ -1,11 +1,11 @@ using static CommonHelpers.Log; -namespace SteamController.Profiles +namespace SteamController { - public class Context : IDisposable + public partial class Context : IDisposable { public const double JoystickToMouseSensitivity = 1200; - public const double PadToMouseSensitivity = 200; + public const double PadToMouseSensitivity = 150; public const double PadToWhellSensitivity = 4; public const double ThumbToWhellSensitivity = 4; public static readonly TimeSpan ThumbToWhellFirstRepeat = TimeSpan.FromMilliseconds(30 * ThumbToWhellSensitivity); @@ -16,15 +16,19 @@ namespace SteamController.Profiles public Devices.KeyboardController Keyboard { get; private set; } public Devices.MouseController Mouse { get; private set; } - public List Profiles { get; } = new List(); + public List Profiles { get; } = new List(); + public List Managers { get; } = new List(); + + public List? orderedProfiles; public bool RequestEnable { get; set; } = true; public bool RequestDesktopMode { get; set; } = true; - public bool DisableDueToSteam { get; set; } = false; + public bool SteamRunning { get; set; } = false; + public bool SteamUsesController { get; set; } = false; public bool Enabled { - get { return RequestEnable && !DisableDueToSteam; } + get { return RequestEnable; } } public bool DesktopMode @@ -35,6 +39,16 @@ namespace SteamController.Profiles } } + public List OrderedProfiles + { + get + { + if (orderedProfiles == null) + orderedProfiles = Profiles.ToList(); + return orderedProfiles; + } + } + public Context() { Steam = new Devices.SteamController(); @@ -55,23 +69,21 @@ namespace SteamController.Profiles { X360.Tick(); - foreach (Profile profile in Profiles) + foreach (var manager in Managers) { - try { profile.Tick(this); } - catch (Exception e) { TraceLine("Profile: {0}. Exception: {1}", e); } + try + { + manager.Tick(this); + } + catch (Exception e) + { + TraceLine("Manager: {0}. Exception: {1}", e); + } } } public bool Update() { - if (!Enabled) - { - X360.Connected = false; - Steam.LizardButtons = true; - Steam.LizardMouse = true; - return true; - } - Steam.BeforeUpdate(); X360.BeforeUpdate(); Keyboard.BeforeUpdate(); @@ -79,25 +91,12 @@ namespace SteamController.Profiles try { - bool skip = false; - - foreach (Profile profile in Profiles) + foreach (var profile in OrderedProfiles) { - if (!profile.RunAlways && skip) + if (profile.Selected(this)) { - profile.Skipped(this); - continue; - } - - try - { - var status = profile.Run(this); - if (status == Profile.Status.Stop) - skip = true; - } - catch (Exception e) - { - TraceLine("Profile: Exception: {0}", e.Message); + profile.Run(this); + break; } } @@ -116,5 +115,46 @@ namespace SteamController.Profiles Mouse.Update(); } } + + public Profiles.Profile? FindProfile(String name) + { + return Profiles.Find((profile) => profile.Name == name); + } + + public bool SelectProfile(String name, bool enable = true) + { + var profile = FindProfile(name); + if (profile is null) + return false; + + var list = OrderedProfiles; + list.Remove(profile); + list.Insert(0, profile); + return true; + } + + public bool SelectNext() + { + bool firstSelected = false; + + var list = OrderedProfiles; + foreach (var profile in list) + { + if (!profile.Selected(this)) + continue; + + if (!firstSelected) + { + firstSelected = true; + continue; + } + + list.Remove(profile); + list.Insert(0, profile); + return true; + } + + return false; + } } } diff --git a/SteamController/Profiles/DebugProfile.cs b/SteamController/ContextDebug.cs similarity index 52% rename from SteamController/Profiles/DebugProfile.cs rename to SteamController/ContextDebug.cs index 3a24e91..16dbe67 100644 --- a/SteamController/Profiles/DebugProfile.cs +++ b/SteamController/ContextDebug.cs @@ -1,35 +1,30 @@ -using static CommonHelpers.Log; +using CommonHelpers; -namespace SteamController.Profiles +namespace SteamController { - public sealed class DebugProfile : Profile + public partial class Context { - public DebugProfile() - { - RunAlways = true; - } + List debugLastItems = new List(); - List lastItems = new List(); - - public override Status Run(Context c) + public void Debug() { var items = new List(); - if (c.DesktopMode) + if (DesktopMode) items.Add("[DESKTOP]"); else items.Add("[CONTROLLER]"); - if (c.Steam.LizardButtons) + if (Steam.LizardButtons) items.Add("[LB]"); - if (c.Steam.LizardMouse) + if (Steam.LizardMouse) items.Add("[LM]"); - if (c.X360.Connected) + if (X360.Connected) items.Add("[X360]"); - else if (c.X360.Valid) + else if (X360.Valid) items.Add("[no-X360]"); - foreach (var button in c.Steam.AllButtons) + foreach (var button in Steam.AllButtons) { if (button is null || !button.LastValue) continue; @@ -43,22 +38,21 @@ namespace SteamController.Profiles items.Add(text); } - foreach (var key in c.Keyboard.DownKeys) + foreach (var key in Keyboard.DownKeys) { items.Add(String.Format("Key{0}", key)); } - foreach (var mouse in c.Mouse.DownButtons) + foreach (var mouse in Mouse.DownButtons) { items.Add(String.Format("Mouse{0}", mouse)); } - if (!items.SequenceEqual(lastItems)) + if (!items.SequenceEqual(debugLastItems)) { - TraceLine("DEBUG: {0}", String.Join(" ", items)); - lastItems = items; + Log.TraceLine("DEBUG: {0}", String.Join(" ", items)); + debugLastItems = items; } - return Status.Continue; } } } diff --git a/SteamController/Controller.cs b/SteamController/Controller.cs index 6871814..7724c23 100644 --- a/SteamController/Controller.cs +++ b/SteamController/Controller.cs @@ -1,9 +1,9 @@ using CommonHelpers; using ExternalHelpers; +using SteamController.Helpers; using SteamController.Profiles; using System.ComponentModel; using System.Diagnostics; -using System.Runtime.InteropServices; namespace SteamController { @@ -19,12 +19,13 @@ namespace SteamController Context context = new Context() { Profiles = { - new Profiles.SteamShortcutsProfile(), new Profiles.DesktopProfile(), - new Profiles.ProcessProfile(), - new Profiles.SteamDetectProfile(), + new Profiles.SteamProfile(), new Profiles.X360Profile(), - new Profiles.DebugProfile() + }, + Managers = { + new Managers.ProcessManager(), + new Managers.SteamManager() } }; @@ -36,36 +37,49 @@ namespace SteamController TimeSpan lastUpdatesReset; readonly TimeSpan updateResetInterval = TimeSpan.FromSeconds(1); - [DllImport("sas.dll")] - static extern void SendSAS(bool asUser); - public Controller() { Instance.RunOnce(TitleWithVersion, "Global\\SteamController"); - SendSAS(true); var contextMenu = new ContextMenuStrip(components); var enabledItem = new ToolStripMenuItem("&Enabled"); enabledItem.Checked = context.RequestEnable; - enabledItem.Click += delegate { enabledItem.Checked = context.RequestEnable = !context.RequestEnable; }; + enabledItem.Click += delegate { context.RequestEnable = !context.RequestEnable; }; + contextMenu.Opening += delegate { enabledItem.Checked = context.RequestEnable; }; contextMenu.Items.Add(enabledItem); var desktopModeItem = new ToolStripMenuItem("&Desktop Mode"); desktopModeItem.Checked = context.RequestDesktopMode; - desktopModeItem.Click += delegate { desktopModeItem.Checked = context.RequestDesktopMode = !context.RequestDesktopMode; }; + desktopModeItem.Click += delegate { context.RequestDesktopMode = !context.RequestDesktopMode; }; + contextMenu.Opening += delegate { desktopModeItem.Checked = context.RequestDesktopMode; }; contextMenu.Items.Add(desktopModeItem); var steamDetectionItem = new ToolStripMenuItem("Auto-disable on &Steam"); steamDetectionItem.Checked = Settings.Default.EnableSteamDetection; steamDetectionItem.Click += delegate { - steamDetectionItem.Checked = Settings.Default.EnableSteamDetection = !Settings.Default.EnableSteamDetection; + Settings.Default.EnableSteamDetection = !Settings.Default.EnableSteamDetection; Settings.Default.Save(); }; + contextMenu.Opening += delegate { steamDetectionItem.Checked = Settings.Default.EnableSteamDetection; }; contextMenu.Items.Add(steamDetectionItem); contextMenu.Items.Add(new ToolStripSeparator()); + var lizardMouseItem = new ToolStripMenuItem("Use Lizard &Mouse"); + lizardMouseItem.Checked = SteamShortcutsProfile.SteamModeLizardMouse; + lizardMouseItem.Click += delegate { SteamShortcutsProfile.SteamModeLizardMouse = !SteamShortcutsProfile.SteamModeLizardMouse; }; + contextMenu.Opening += delegate { lizardMouseItem.Checked = SteamShortcutsProfile.SteamModeLizardMouse; }; + contextMenu.Items.Add(lizardMouseItem); + + var lizardButtonsItem = new ToolStripMenuItem("Use Lizard &Buttons"); + lizardButtonsItem.Checked = SteamShortcutsProfile.SteamModeLizardButtons; + lizardButtonsItem.Click += delegate { SteamShortcutsProfile.SteamModeLizardButtons = !SteamShortcutsProfile.SteamModeLizardButtons; }; + contextMenu.Opening += delegate { lizardButtonsItem.Checked = SteamShortcutsProfile.SteamModeLizardButtons; }; + contextMenu.Items.Add(lizardButtonsItem); + + contextMenu.Items.Add(new ToolStripSeparator()); + if (startupManager.IsAvailable) { var startupItem = new ToolStripMenuItem("Run On Startup"); @@ -115,6 +129,7 @@ namespace SteamController lock (context) { context.Update(); + context.Debug(); } if (!context.Enabled) @@ -141,16 +156,16 @@ namespace SteamController notifyIcon.Text = TitleWithVersion + ". Missing ViGEm?"; notifyIcon.Icon = Resources.microsoft_xbox_controller_red; } + else if (context.Enabled && context.SteamUsesController) + { + notifyIcon.Icon = context.DesktopMode ? Resources.monitor_off : Resources.microsoft_xbox_controller_off; + notifyIcon.Text = TitleWithVersion + ". Steam Detected"; + } else if (context.Enabled) { notifyIcon.Icon = context.DesktopMode ? Resources.monitor : Resources.microsoft_xbox_controller; notifyIcon.Text = TitleWithVersion; } - else if (context.DisableDueToSteam) - { - notifyIcon.Icon = context.DesktopMode ? Resources.monitor_off : Resources.microsoft_xbox_controller_off; - notifyIcon.Text = TitleWithVersion + ". Steam Detected"; - } else { notifyIcon.Icon = context.DesktopMode ? Resources.monitor_off : Resources.microsoft_xbox_controller_off; diff --git a/SteamController/Devices/SteamController.cs b/SteamController/Devices/SteamController.cs index c7f05f0..5906c46 100644 --- a/SteamController/Devices/SteamController.cs +++ b/SteamController/Devices/SteamController.cs @@ -1,3 +1,4 @@ +using CommonHelpers; using hidapi; using PowerControl.External; using static CommonHelpers.Log; @@ -36,21 +37,33 @@ namespace SteamController.Devices private void BeforeUpdate(byte[] buffer) { foreach (var action in AllActions) - action.BeforeUpdate(buffer, this); + action.BeforeUpdate(buffer); } internal void BeforeUpdate() { - byte[] data = neptuneDevice.Read(ReadTimeout); - if (data == null) + LizardButtons = true; + LizardMouse = true; + + try { + byte[] data = neptuneDevice.Read(ReadTimeout); + if (data == null) + { + Reset(); + Updated = false; + return; + } + + BeforeUpdate(data); + Updated = true; + } + catch (Exception e) + { + Log.TraceLine("STEAM: Exception: {0}", e); Reset(); Updated = false; - return; } - - BeforeUpdate(data); - Updated = true; } internal void Update() @@ -58,8 +71,17 @@ namespace SteamController.Devices foreach (var action in AllActions) action.Update(); - UpdateLizardButtons(); - UpdateLizardMouse(); + try + { + UpdateLizardButtons(); + UpdateLizardMouse(); + } + catch (Exception e) + { + Log.TraceLine("STEAM: Exception: {0}", e); + Reset(); + Updated = false; + } } } } diff --git a/SteamController/Devices/SteamControllerActions.cs b/SteamController/Devices/SteamControllerActions.cs index 3bbc68c..096152f 100644 --- a/SteamController/Devices/SteamControllerActions.cs +++ b/SteamController/Devices/SteamControllerActions.cs @@ -8,6 +8,7 @@ namespace SteamController.Devices { public abstract class SteamAction { + public SteamController? Controller { get; internal set; } public String Name { get; internal set; } = ""; /// This is action controlled by Lizard mode @@ -17,7 +18,7 @@ namespace SteamController.Devices public double DeltaTime { get; protected set; } internal abstract void Reset(); - internal abstract bool BeforeUpdate(byte[] buffer, SteamController controller); + internal abstract bool BeforeUpdate(byte[] buffer); internal abstract void Update(); protected void UpdateTime() @@ -27,13 +28,16 @@ namespace SteamController.Devices LastUpdated = now; } - protected bool UsedByLizard(SteamController controller) + protected bool ValueCanBeUsed { - if (LizardButton && controller.LizardButtons) + get + { + if (LizardButton && Controller?.LizardButtons == true) + return false; + if (LizardMouse && Controller?.LizardMouse == true) + return false; return true; - if (LizardMouse && controller.LizardMouse) - return true; - return false; + } } } @@ -43,8 +47,16 @@ namespace SteamController.Devices public static readonly TimeSpan DefaultFirstHold = TimeSpan.FromMilliseconds(75); public static readonly TimeSpan DefaultRepeatHold = TimeSpan.FromMilliseconds(150); - public bool Value { get; private set; } - public bool LastValue { get; private set; } + private bool rawValue, rawLastValue; + + public bool Value + { + get { return ValueCanBeUsed ? rawValue : false; } + } + public bool LastValue + { + get { return ValueCanBeUsed ? rawLastValue : false; } + } /// Last press was already consumed by other public object? Consumed { get; private set; } @@ -131,6 +143,17 @@ namespace SteamController.Devices return true; } + /// Generated when button was hold for a given period + /// but triggered exactly after previously being hold + public bool HoldNext(TimeSpan? duration, object previousConsume, object replaceConsme) + { + if (!Hold(duration, previousConsume)) + return false; + + Consumed = replaceConsme; + return true; + } + /// Generated when button was repeated for a given period /// but triggered exactly once public bool HoldRepeat(TimeSpan duration, TimeSpan repeatEvery, object consume) @@ -166,27 +189,27 @@ namespace SteamController.Devices internal override void Reset() { - LastValue = Value; - Value = false; + rawLastValue = rawValue; + rawValue = false; HoldSince = null; HoldRepeated = null; Consumed = null; } - internal void SetValue(bool value) + internal void SetValue(bool newValue) { - LastValue = Value; - Value = value; + rawLastValue = rawValue; + rawValue = newValue; UpdateTime(); - if (!LastValue && Value) + if (!rawLastValue && rawValue) { HoldSince = DateTime.Now; HoldRepeated = null; } } - internal override bool BeforeUpdate(byte[] buffer, SteamController controller) + internal override bool BeforeUpdate(byte[] buffer) { return true; } @@ -196,6 +219,13 @@ namespace SteamController.Devices if (!Value) Consumed = null; } + + public override string? ToString() + { + if (Name != "") + return String.Format("{0}: {1} (last: {2})", Name, Value, LastValue); + return base.ToString(); + } } public class SteamButton2 : SteamButton @@ -215,11 +245,8 @@ namespace SteamController.Devices } } - internal override bool BeforeUpdate(byte[] buffer, SteamController controller) + internal override bool BeforeUpdate(byte[] buffer) { - if (UsedByLizard(controller)) - return false; - if (offset < buffer.Length) { SetValue((buffer[offset] & mask) != 0); @@ -239,15 +266,23 @@ namespace SteamController.Devices public const short VirtualRightThreshold = short.MaxValue / 2; private int offset; + private short rawValue, rawLastValue; public SteamButton? ActiveButton { get; internal set; } public SteamButton? VirtualLeft { get; internal set; } public SteamButton? VirtualRight { get; internal set; } - public short Value { get; private set; } - public short LastValue { get; private set; } public short Deadzone { get; set; } public short MinChange { get; set; } + public short Value + { + get { return ValueCanBeUsed ? rawValue : (short)0; } + } + public short LastValue + { + get { return ValueCanBeUsed ? rawLastValue : (short)0; } + } + public SteamAxis(int offset) { this.offset = offset; @@ -331,32 +366,29 @@ namespace SteamController.Devices internal override void Reset() { - LastValue = Value; - Value = 0; + rawLastValue = rawValue; + rawValue = 0; } - internal void SetValue(short value) + internal void SetValue(short newValue) { - LastValue = Value; - Value = value; + rawLastValue = rawValue; + rawValue = newValue; UpdateTime(); // first time pressed, reset value as this is a Pad if (ActiveButton is not null && ActiveButton.JustPressed()) - LastValue = Value; + rawLastValue = newValue; if (VirtualRight is not null) - VirtualRight.SetValue(value > VirtualRightThreshold); + VirtualRight.SetValue(newValue > VirtualRightThreshold); if (VirtualLeft is not null) - VirtualLeft.SetValue(value < VirtualLeftThreshold); + VirtualLeft.SetValue(newValue < VirtualLeftThreshold); } - internal override bool BeforeUpdate(byte[] buffer, SteamController controller) + internal override bool BeforeUpdate(byte[] buffer) { - if (UsedByLizard(controller)) - return false; - if (offset + 1 < buffer.Length) { SetValue(BitConverter.ToInt16(buffer, offset)); @@ -372,6 +404,13 @@ namespace SteamController.Devices internal override void Update() { } + + public override string? ToString() + { + if (Name != "") + return String.Format("{0}: {1} (last: {2})", Name, Value, LastValue); + return base.ToString(); + } } public SteamAction?[] AllActions { get; private set; } @@ -398,6 +437,7 @@ namespace SteamController.Devices Select((field) => Tuple.Create(field, field.GetValue(this) as SteamAction)). ToList(); + allActions.ForEach((tuple) => tuple.Item2.Controller = this); allActions.ForEach((tuple) => tuple.Item2.Name = tuple.Item1.Name); AllActions = allActions.Select((tuple) => tuple.Item2).ToArray(); diff --git a/SteamController/Devices/SteamControllerLizard.cs b/SteamController/Devices/SteamControllerLizard.cs index ea091d3..5987d0b 100644 --- a/SteamController/Devices/SteamControllerLizard.cs +++ b/SteamController/Devices/SteamControllerLizard.cs @@ -22,10 +22,13 @@ namespace SteamController.Devices { // We need to explicitly disable lizard every some time // but don't fight enabling it, as someone else might be taking control (Steam?) - if (LizardMouse || lizardMouseUpdated.AddMilliseconds(LizardModeUpdateInterval) > DateTime.Now) + if (lizardMouseUpdated.AddMilliseconds(LizardModeUpdateInterval) > DateTime.Now) return; } + savedLizardMouse = LizardMouse; + lizardMouseUpdated = DateTime.Now; + if (LizardMouse) { //Enable mouse emulation @@ -38,9 +41,6 @@ namespace SteamController.Devices byte[] data = new byte[] { 0x87, 0x03, 0x08, 0x07 }; neptuneDevice.RequestFeatureReport(data); } - - savedLizardMouse = LizardMouse; - lizardMouseUpdated = DateTime.Now; } private void UpdateLizardButtons() @@ -49,10 +49,13 @@ namespace SteamController.Devices { // We need to explicitly disable lizard every some time // but don't fight enabling it, as someone else might be taking control (Steam?) - if (LizardButtons || lizardButtonUpdated.AddMilliseconds(LizardModeUpdateInterval) > DateTime.Now) + if (lizardButtonUpdated.AddMilliseconds(LizardModeUpdateInterval) > DateTime.Now) return; } + savedLizardButtons = LizardButtons; + lizardButtonUpdated = DateTime.Now; + if (LizardButtons) { //Enable keyboard/mouse button emulation @@ -65,9 +68,6 @@ namespace SteamController.Devices byte[] data = new byte[] { 0x81, 0x00 }; neptuneDevice.RequestFeatureReport(data); } - - savedLizardButtons = LizardButtons; - lizardButtonUpdated = DateTime.Now; } } } diff --git a/SteamController/Devices/Xbox360Controller.cs b/SteamController/Devices/Xbox360Controller.cs index f8b9ed0..9823184 100644 --- a/SteamController/Devices/Xbox360Controller.cs +++ b/SteamController/Devices/Xbox360Controller.cs @@ -55,6 +55,7 @@ namespace SteamController.Devices } submitReport = false; + Connected = false; } private void UpdateConnected() diff --git a/SteamController/Helpers/SteamManager.cs b/SteamController/Helpers/SteamProcess.cs similarity index 65% rename from SteamController/Helpers/SteamManager.cs rename to SteamController/Helpers/SteamProcess.cs index 8face96..803ad84 100644 --- a/SteamController/Helpers/SteamManager.cs +++ b/SteamController/Helpers/SteamProcess.cs @@ -1,9 +1,10 @@ using System.Diagnostics; +using System.Runtime.InteropServices; using Microsoft.Win32; namespace SteamController.Helpers { - internal static class SteamManager + internal static class SteamProcess { public const String SteamKey = @"Software\Valve\Steam"; public const String RunningAppIDValue = @"RunningAppID"; @@ -19,9 +20,15 @@ namespace SteamController.Helpers var value = GetValue(ActiveProcessKey, PIDValue); if (value is null) return null; - if (Process.GetProcessById(value.Value) is null) + try + { + Process.GetProcessById(value.Value); + return true; + } + catch (ArgumentException) + { return false; - return true; + } } } @@ -43,6 +50,18 @@ namespace SteamController.Helpers } } + public static bool IsGamePadUI + { + get + { + var steamWindow = FindWindow("SDL_app", "SP"); + if (steamWindow == null) + return false; + + return GetForegroundWindow() == steamWindow; + } + } + private static T? GetValue(string key, string value) where T : struct { try @@ -57,5 +76,11 @@ namespace SteamController.Helpers return null; } } + + [DllImport("user32.dll")] + private static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll", SetLastError = true)] + private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); } } \ No newline at end of file diff --git a/SteamController/Managers/Manager.cs b/SteamController/Managers/Manager.cs new file mode 100644 index 0000000..b1986ba --- /dev/null +++ b/SteamController/Managers/Manager.cs @@ -0,0 +1,9 @@ +using SteamController.Profiles; + +namespace SteamController.Managers +{ + public abstract class Manager + { + public abstract void Tick(Context context); + } +} diff --git a/SteamController/Profiles/ProcessProfile.cs b/SteamController/Managers/ProcessManager.cs similarity index 85% rename from SteamController/Profiles/ProcessProfile.cs rename to SteamController/Managers/ProcessManager.cs index f23df4a..122c0b3 100644 --- a/SteamController/Profiles/ProcessProfile.cs +++ b/SteamController/Managers/ProcessManager.cs @@ -1,8 +1,8 @@ using System.Diagnostics; -namespace SteamController.Profiles +namespace SteamController.Managers { - public sealed class ProcessProfile : Profile + public sealed class ProcessManager : Manager { public static readonly String[] ActivationProcessNames = new String[] { @@ -43,10 +43,5 @@ namespace SteamController.Profiles } } } - - public override Status Run(Context context) - { - return Status.Continue; - } } } diff --git a/SteamController/Managers/SteamManager.cs b/SteamController/Managers/SteamManager.cs new file mode 100644 index 0000000..01e57e0 --- /dev/null +++ b/SteamController/Managers/SteamManager.cs @@ -0,0 +1,35 @@ +using System.Diagnostics; +using SteamController.Helpers; + +namespace SteamController.Managers +{ + public sealed class SteamManager : Manager + { + public override void Tick(Context context) + { + if (!Settings.Default.EnableSteamDetection) + { + context.SteamRunning = true; + context.SteamUsesController = false; + return; + } + + var usesController = UsesController(); + + // if controller is used, disable due to Steam unless it is hidden + context.SteamRunning = usesController is not null; + context.SteamUsesController = usesController ?? false; + } + + private bool? UsesController() + { + if (!SteamProcess.IsRunning.GetValueOrDefault(false)) + return null; + + return + SteamProcess.IsBigPictureMode.GetValueOrDefault(false) || + SteamProcess.IsRunningGame.GetValueOrDefault(false) || + SteamProcess.IsGamePadUI; + } + } +} diff --git a/SteamController/Profiles/DefaultShortcutsProfile.cs b/SteamController/Profiles/DefaultShortcutsProfile.cs new file mode 100644 index 0000000..080a69a --- /dev/null +++ b/SteamController/Profiles/DefaultShortcutsProfile.cs @@ -0,0 +1,78 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using ExternalHelpers; +using WindowsInput; + +namespace SteamController.Profiles +{ + public abstract class DefaultShortcutsProfile : Profile + { + public const String ShortcutConsumed = "ShortcutsProfile"; + public readonly TimeSpan HoldForShorcuts = TimeSpan.FromMilliseconds(200); + private readonly TimeSpan HoldToSwitchProfile = TimeSpan.FromSeconds(1); + private readonly TimeSpan HoldToSwitchDesktop = TimeSpan.FromSeconds(3); + + public override Status Run(Context c) + { + // Steam + 3 dots simulate CTRL+ALT+DELETE + if (c.Steam.BtnSteam.Hold(HoldForShorcuts, ShortcutConsumed) && c.Steam.BtnQuickAccess.HoldOnce(HoldForShorcuts, ShortcutConsumed)) + { + // TODO: Not working due to missing `uiAccess=true` + c.Keyboard.KeyPress(new VirtualKeyCode[] { VirtualKeyCode.LCONTROL, VirtualKeyCode.LMENU }, VirtualKeyCode.DELETE); + SendSAS(true); + return Status.Done; + } + + // Hold options for 1s to use next profile, or 3 seconds to switch between desktop-mode + if (c.Steam.BtnOptions.HoldOnce(HoldToSwitchProfile, ShortcutConsumed)) + { + if (!c.SelectNext()) + { + c.RequestDesktopMode = !c.RequestDesktopMode; + } + return Status.Done; + } + else if (c.Steam.BtnOptions.HoldNext(HoldToSwitchDesktop, ShortcutConsumed, "SwitchToDesktop")) + { + c.RequestDesktopMode = !c.RequestDesktopMode; + return Status.Done; + } + + // Always consume 3 dots + if (c.Steam.BtnQuickAccess.Hold(HoldForShorcuts, ShortcutConsumed)) + { + return Status.Done; + } + + if (c.Steam.BtnSteam.Hold(HoldForShorcuts, ShortcutConsumed)) + { + if (AdditionalShortcuts(c)) + { + return Status.Done; + } + } + + return Status.Continue; + } + + private bool AdditionalShortcuts(Context c) + { + if (c.Steam.BtnMenu.Pressed()) + { + c.Keyboard.KeyPress(VirtualKeyCode.LWIN, VirtualKeyCode.TAB); + return true; + } + + if (c.Steam.BtnOptions.Pressed()) + { + c.Keyboard.KeyPress(VirtualKeyCode.F11); + return true; + } + + return false; + } + + [DllImport("sas.dll")] + private static extern void SendSAS(bool asUser); + } +} diff --git a/SteamController/Profiles/DesktopProfile.cs b/SteamController/Profiles/DesktopProfile.cs index 3f742ff..3db45e0 100644 --- a/SteamController/Profiles/DesktopProfile.cs +++ b/SteamController/Profiles/DesktopProfile.cs @@ -1,24 +1,25 @@ -using PowerControl.Helpers; using WindowsInput; namespace SteamController.Profiles { - public sealed class DesktopProfile : Profile + public sealed class DesktopProfile : SteamShortcutsProfile { - public const bool LizardButtons = false; - public const bool LizardMouse = true; - - public const String Consumed = "DesktopProfileOwner"; + private const String Consumed = "DesktopProfileOwner"; public DesktopProfile() { } + public override bool Selected(Context context) + { + return context.Enabled && context.DesktopMode && !context.SteamUsesController; + } + public override Status Run(Context c) { - if (!c.DesktopMode) + if (base.Run(c).IsDone) { - return Status.Continue; + return Status.Done; } if (!c.Mouse.Valid) @@ -27,24 +28,32 @@ namespace SteamController.Profiles // Enable emergency Lizard c.Steam.LizardButtons = true; c.Steam.LizardMouse = true; - return Status.Continue; + return Status.Done; } - c.Steam.LizardButtons = LizardButtons; - c.Steam.LizardMouse = LizardMouse; + c.Steam.LizardButtons = SteamModeLizardButtons; + c.Steam.LizardMouse = SteamModeLizardMouse; - EmulateLizardButtons(c); - EmulateLizardMouse(c); + EmulateScrollOnLPad(c); + EmulateScrollOnLStick(c); + EmulateMouseOnRPad(c); + EmulateMouseOnRStick(c); + EmulateDPadArrows(c); - if (c.Steam.LPadX) + if (c.Steam.BtnA.Pressed()) { - c.Mouse.HorizontalScroll(c.Steam.LPadX.Scaled(Context.PadToWhellSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta)); + c.Keyboard.KeyPress(VirtualKeyCode.RETURN); } - if (c.Steam.LPadY) + if (c.Steam.BtnB.Pressed()) { - c.Mouse.VerticalScroll(c.Steam.LPadY.Scaled(Context.PadToWhellSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta)); + c.Keyboard.KeyPress(VirtualKeyCode.BACK); } + return Status.Continue; + } + + private void EmulateScrollOnLStick(Context c) + { if (c.Steam.BtnVirtualLeftThumbUp.HoldRepeat(Context.ThumbToWhellFirstRepeat, Context.ThumbToWhellRepeat, Consumed)) { c.Mouse.VerticalScroll(Context.ThumbToWhellSensitivity); @@ -61,26 +70,11 @@ namespace SteamController.Profiles { c.Mouse.HorizontalScroll(Context.ThumbToWhellSensitivity); } - - if (c.Steam.BtnRStickTouch && (c.Steam.RightThumbX || c.Steam.RightThumbY)) - { - c.Mouse.MoveBy( - c.Steam.RightThumbX.Scaled(Context.JoystickToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.AbsoluteTime), - -c.Steam.RightThumbY.Scaled(Context.JoystickToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.AbsoluteTime) - ); - } - - return Status.Continue; } - private void EmulateLizardButtons(Context c) + private void EmulateDPadArrows(Context c) { - c.Mouse[Devices.MouseController.Button.Right] = c.Steam.BtnL2 || c.Steam.BtnLPadPress; - c.Mouse[Devices.MouseController.Button.Left] = c.Steam.BtnR2 || c.Steam.BtnRPadPress; - #if true - if (c.Steam.BtnA.Pressed()) - c.Keyboard.KeyPress(VirtualKeyCode.RETURN); if (c.Steam.BtnDpadLeft.HoldRepeat(Consumed)) c.Keyboard.KeyPress(VirtualKeyCode.LEFT); if (c.Steam.BtnDpadRight.HoldRepeat(Consumed)) @@ -97,16 +91,5 @@ namespace SteamController.Profiles c.Keyboard[VirtualKeyCode.DOWN] = c.Steam.BtnDpadDown; #endif } - - private void EmulateLizardMouse(Context c) - { - if (c.Steam.RPadX || c.Steam.RPadY) - { - c.Mouse.MoveBy( - c.Steam.RPadX.Scaled(Context.PadToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta), - -c.Steam.RPadY.Scaled(Context.PadToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta) - ); - } - } } } diff --git a/SteamController/Profiles/Profile.cs b/SteamController/Profiles/Profile.cs index 1ea19fe..7f71008 100644 --- a/SteamController/Profiles/Profile.cs +++ b/SteamController/Profiles/Profile.cs @@ -2,22 +2,18 @@ namespace SteamController.Profiles { public abstract class Profile { - public enum Status + public struct Status { - Continue, - Stop + public static readonly Status Continue = new Status() { IsDone = false }; + public static readonly Status Done = new Status() { IsDone = true }; + + public bool IsDone { get; set; } } - public bool RunAlways { get; set; } + public String Name { get; set; } = ""; + + public abstract bool Selected(Context context); public abstract Status Run(Context context); - - public virtual void Tick(Context context) - { - } - - public virtual void Skipped(Context context) - { - } } } diff --git a/SteamController/Profiles/SteamDetectProfile.cs b/SteamController/Profiles/SteamDetectProfile.cs deleted file mode 100644 index c5edd22..0000000 --- a/SteamController/Profiles/SteamDetectProfile.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Diagnostics; -using SteamController.Helpers; - -namespace SteamController.Profiles -{ - public sealed class SteamDetectProfile : Profile - { - public override void Tick(Context context) - { - if (!Settings.Default.EnableSteamDetection) - { - context.DisableDueToSteam = false; - return; - } - - var usesController = UsesController(); - - // if controller is used, disable due to Steam - context.DisableDueToSteam = usesController ?? true; - } - - private bool? UsesController() - { - if (!SteamManager.IsRunning.GetValueOrDefault(false)) - return null; - - return SteamManager.IsBigPictureMode.GetValueOrDefault(false) || SteamManager.IsRunningGame.GetValueOrDefault(false); - } - - public override Status Run(Context context) - { - return Status.Continue; - } - } -} diff --git a/SteamController/Profiles/SteamProfile.cs b/SteamController/Profiles/SteamProfile.cs new file mode 100644 index 0000000..9e5d731 --- /dev/null +++ b/SteamController/Profiles/SteamProfile.cs @@ -0,0 +1,26 @@ +using Nefarius.ViGEm.Client.Targets.Xbox360; + +namespace SteamController.Profiles +{ + public sealed class SteamProfile : DefaultShortcutsProfile + { + public override bool Selected(Context context) + { + return context.Enabled && context.SteamUsesController; + } + + public override Status Run(Context context) + { + // Steam does not use Lizard + context.Steam.LizardButtons = false; + context.Steam.LizardMouse = false; + + if (base.Run(context).IsDone) + { + return Status.Done; + } + + return Status.Continue; + } + } +} diff --git a/SteamController/Profiles/SteamShortcutsProfile.cs b/SteamController/Profiles/SteamShortcutsProfile.cs index c6cb4b6..6870961 100644 --- a/SteamController/Profiles/SteamShortcutsProfile.cs +++ b/SteamController/Profiles/SteamShortcutsProfile.cs @@ -1,52 +1,30 @@ using System.Diagnostics; +using System.Runtime.InteropServices; using ExternalHelpers; using PowerControl.Helpers; using WindowsInput; namespace SteamController.Profiles { - public sealed class SteamShortcutsProfile : Profile + public abstract class SteamShortcutsProfile : DefaultShortcutsProfile { - public const bool LizardButtons = true; - public const bool LizardMouse = false; + public static bool SteamModeLizardButtons = false; + public static bool SteamModeLizardMouse = true; - public const String Consumed = "SteamShortcutsProfile"; - public readonly TimeSpan HoldForShorcuts = TimeSpan.FromMilliseconds(200); public readonly TimeSpan HoldForKill = TimeSpan.FromSeconds(3); public readonly TimeSpan HoldForClose = TimeSpan.FromSeconds(1); - public readonly TimeSpan HoldToSwitchDesktop = TimeSpan.FromSeconds(1); - - public SteamShortcutsProfile() - { - RunAlways = true; - } public override Status Run(Context c) { - // Steam + 3 dots simulate CTRL+ALT+DELETE - if (c.Steam.BtnSteam.Hold(HoldForShorcuts, Consumed) && c.Steam.BtnQuickAccess.HoldOnce(HoldForShorcuts, Consumed)) + if (base.Run(c).IsDone) { - c.Keyboard.KeyPress(new VirtualKeyCode[] { VirtualKeyCode.LCONTROL, VirtualKeyCode.LMENU }, VirtualKeyCode.DELETE); + return Status.Done; } - if (c.Steam.BtnSteam.Hold(HoldForShorcuts, Consumed)) + if (c.Steam.BtnSteam.Hold(HoldForShorcuts, ShortcutConsumed)) { - c.Steam.LizardButtons = LizardButtons; - c.Steam.LizardMouse = LizardMouse; SteamShortcuts(c); - AdditionalShortcuts(c); - return Status.Stop; - } - - if (c.Steam.BtnOptions.HoldOnce(HoldToSwitchDesktop, Consumed)) - { - c.RequestDesktopMode = !c.RequestDesktopMode; - } - - if (c.Steam.BtnQuickAccess.Hold(HoldForShorcuts, Consumed)) - { - // nothing there, just consume - return Status.Stop; + return Status.Done; } return Status.Continue; @@ -54,19 +32,23 @@ namespace SteamController.Profiles private void SteamShortcuts(Context c) { - c.Steam.LizardButtons = false; - c.Steam.LizardMouse = true; + c.Steam.LizardButtons = SteamModeLizardButtons; + c.Steam.LizardMouse = SteamModeLizardMouse; + + EmulateScrollOnLPad(c); + EmulateMouseOnRPad(c); + EmulateMouseOnRStick(c); if (c.Steam.BtnA.Pressed()) { c.Keyboard.KeyPress(VirtualKeyCode.RETURN); } - if (c.Steam.BtnB.HoldOnce(HoldForKill, Consumed)) + if (c.Steam.BtnB.HoldOnce(HoldForKill, ShortcutConsumed)) { // kill application } - else if (c.Steam.BtnB.HoldOnce(HoldForClose, Consumed)) + else if (c.Steam.BtnB.HoldOnce(HoldForClose, ShortcutConsumed)) { // close application c.Keyboard.KeyPress(VirtualKeyCode.LMENU, VirtualKeyCode.F4); @@ -97,34 +79,12 @@ namespace SteamController.Profiles c.Keyboard.KeyPress(VirtualKeyCode.LWIN, VirtualKeyCode.SNAPSHOT); } - c.Mouse[Devices.MouseController.Button.Right] = c.Steam.BtnL2 || c.Steam.BtnLPadPress; - c.Mouse[Devices.MouseController.Button.Left] = c.Steam.BtnR2 || c.Steam.BtnRPadPress; - - if (c.Steam.BtnRStickTouch && (c.Steam.RightThumbX || c.Steam.RightThumbY)) - { - c.Mouse.MoveBy( - c.Steam.RightThumbX.Scaled(Context.JoystickToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.AbsoluteTime), - -c.Steam.RightThumbY.Scaled(Context.JoystickToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.AbsoluteTime) - ); - } - - if (c.Steam.LPadX) - { - c.Mouse.HorizontalScroll(c.Steam.LPadX.Scaled(Context.PadToWhellSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta)); - } - if (c.Steam.LPadY) - { - c.Mouse.VerticalScroll(c.Steam.LPadY.Scaled(Context.PadToWhellSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta)); - } - - EmulateLizardMouse(c); - - if (c.Steam.BtnVirtualLeftThumbUp.HoldRepeat(Consumed)) + if (c.Steam.BtnVirtualLeftThumbUp.HoldRepeat(ShortcutConsumed)) { WindowsSettingsBrightnessController.Increase(5); } - if (c.Steam.BtnVirtualLeftThumbDown.HoldRepeat(Consumed)) + if (c.Steam.BtnVirtualLeftThumbDown.HoldRepeat(ShortcutConsumed)) { WindowsSettingsBrightnessController.Increase(-5); } @@ -145,21 +105,42 @@ namespace SteamController.Profiles } } - private void AdditionalShortcuts(Context c) + protected void EmulateScrollOnLPad(Context c) { - if (c.Steam.BtnMenu.Pressed()) + if (c.Steam.LPadX) { - c.Keyboard.KeyPress(VirtualKeyCode.LWIN, VirtualKeyCode.TAB); + c.Mouse.HorizontalScroll(c.Steam.LPadX.Scaled(Context.PadToWhellSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta)); } - - if (c.Steam.BtnOptions.Pressed()) + if (c.Steam.LPadY) { - c.Keyboard.KeyPress(VirtualKeyCode.F11); + c.Mouse.VerticalScroll(c.Steam.LPadY.Scaled(Context.PadToWhellSensitivity, Devices.SteamController.SteamAxis.ScaledMode.Delta)); } } - private void EmulateLizardMouse(Context c) + protected void EmulateMouseOnRStick(Context c) { + if (c.Steam.RightThumbX || c.Steam.RightThumbY) + { + c.Mouse.MoveBy( + c.Steam.RightThumbX.Scaled(Context.JoystickToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.AbsoluteTime), + -c.Steam.RightThumbY.Scaled(Context.JoystickToMouseSensitivity, Devices.SteamController.SteamAxis.ScaledMode.AbsoluteTime) + ); + } + } + + protected void EmulateMouseOnRPad(Context c, bool useButtonTriggers = true) + { + if (useButtonTriggers) + { + c.Mouse[Devices.MouseController.Button.Right] = c.Steam.BtnL2 || c.Steam.BtnLPadPress; + c.Mouse[Devices.MouseController.Button.Left] = c.Steam.BtnR2 || c.Steam.BtnRPadPress; + } + else + { + c.Mouse[Devices.MouseController.Button.Right] = c.Steam.BtnLPadPress; + c.Mouse[Devices.MouseController.Button.Left] = c.Steam.BtnRPadPress; + } + if (c.Steam.RPadX || c.Steam.RPadY) { c.Mouse.MoveBy( diff --git a/SteamController/Profiles/X360Profile.cs b/SteamController/Profiles/X360Profile.cs index 6203af9..62c297f 100644 --- a/SteamController/Profiles/X360Profile.cs +++ b/SteamController/Profiles/X360Profile.cs @@ -2,28 +2,33 @@ using Nefarius.ViGEm.Client.Targets.Xbox360; namespace SteamController.Profiles { - public sealed class X360Profile : Profile + public sealed class X360Profile : SteamShortcutsProfile { - public override void Skipped(Context context) + public override bool Selected(Context context) { - if (!context.DesktopMode) - { - context.X360.Connected = true; - ControlButtons(context); - } + return context.Enabled && !context.DesktopMode; } public override Status Run(Context context) { - if (context.DesktopMode) + context.Steam.LizardButtons = false; + context.Steam.LizardMouse = SteamModeLizardMouse; + context.X360.Connected = true; + + // Controls + context.X360[Xbox360Button.Guide] = context.Steam.BtnSteam.Pressed(); + context.X360[Xbox360Button.Back] = context.Steam.BtnMenu; + context.X360[Xbox360Button.Start] = context.Steam.BtnOptions; + + if (base.Run(context).IsDone) { - context.X360.Connected = false; - return Status.Continue; + return Status.Done; } - context.Steam.LizardButtons = false; - context.Steam.LizardMouse = true; - context.X360.Connected = true; + // Default emulation + EmulateScrollOnLPad(context); + EmulateMouseOnRStick(context); + EmulateMouseOnRPad(context, false); // DPad context.X360[Xbox360Button.Up] = context.Steam.BtnDpadUp; @@ -51,16 +56,7 @@ namespace SteamController.Profiles context.X360[Xbox360Button.LeftShoulder] = context.Steam.BtnL1; context.X360[Xbox360Button.RightShoulder] = context.Steam.BtnR1; - ControlButtons(context); return Status.Continue; } - - private void ControlButtons(Context context) - { - // Controls - context.X360[Xbox360Button.Guide] = context.Steam.BtnSteam.Pressed(); - context.X360[Xbox360Button.Back] = context.Steam.BtnMenu; - context.X360[Xbox360Button.Start] = context.Steam.BtnOptions; - } } } diff --git a/SteamController/Settings.Designer.cs b/SteamController/Settings.Designer.cs index 62f28ea..b93d395 100644 --- a/SteamController/Settings.Designer.cs +++ b/SteamController/Settings.Designer.cs @@ -34,5 +34,17 @@ namespace SteamController { this["EnableSteamDetection"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("True")] + public bool EnableHidHide { + get { + return ((bool)(this["EnableHidHide"])); + } + set { + this["EnableHidHide"] = value; + } + } } } diff --git a/SteamController/Settings.settings b/SteamController/Settings.settings index cd0ffdd..ab55414 100644 --- a/SteamController/Settings.settings +++ b/SteamController/Settings.settings @@ -5,5 +5,8 @@ True + + True + \ No newline at end of file