2022-11-25 10:56:17 +01:00
using System.Diagnostics ;
2023-01-21 22:01:17 +01:00
using System.Runtime.InteropServices ;
using System.Text ;
2023-02-08 15:40:08 +01:00
using System.Text.RegularExpressions ;
2022-11-25 10:56:17 +01:00
using SteamController.Helpers ;
namespace SteamController.Managers
{
public sealed class SteamManager : Manager
{
2023-01-21 22:01:17 +01:00
private static readonly Classifier [ ] Classifiers = new Classifier [ ]
{
2023-05-21 17:46:34 +02:00
new Classifier ( ) { Type = "gamepadui" , ClassName = "SDL_app" , WindowText = "SP" , ProcessName = "steamwebhelper" , MaxVersion = 1674182294 - 1 } ,
new Classifier ( ) { Type = "possiblegamepadui" , ClassName = "SDL_app" , WindowTextPrefix = "SP" , ProcessName = "steamwebhelper" , MaxVersion = 1674182294 - 1 } ,
// Support Steam client released around 2023-05-21, version: 1684535786
new Classifier ( ) { Type = "bigpicturemode_2023_05_21" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , WindowTextSuffix = "Steam Big Picture Mode" , MinVersion = 1684535786 } ,
new Classifier ( ) { Type = "controller_layout_2023_05_21" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , WindowText = "Controller Layout" , MinVersion = 1684535786 } , // Controller Calibration
new Classifier ( ) { Type = "desktop_guide_layout_2023_05_21" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , WindowTextPrefix = "Steam Controller Configs -" , MinVersion = 1684535786 } , // Desktop and Guide
new Classifier ( ) { Type = "game_layout_2023_05_21" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , WindowTextSuffix = "- Controller Layout" , MinVersion = 1684535786 } , // for Game
2023-01-21 22:01:17 +01:00
// Support Steam client released around 2023-01-20, version: 1674182294
2023-05-21 17:46:34 +02:00
new Classifier ( ) { Type = "gamepadui_2023_05_21" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , WindowText = "Steam" , Forbid = true , MaxVersion = 1684535786 - 1 } ,
new Classifier ( ) { Type = "gamepadui_2023_05_21" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , WindowText = "Steam Settings" , Forbid = true , MaxVersion = 1684535786 - 1 } ,
new Classifier ( ) { Type = "gamepadui_2023_05_21" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , WindowText = "Special Offers" , Forbid = true , MaxVersion = 1684535786 - 1 } ,
new Classifier ( ) { Type = "gamepadui_2023_01_20" , ClassName = "SDL_app" , ProcessName = "steamwebhelper" , MaxVersion = 1684535786 - 1 } ,
new Classifier ( ) { Type = "controllerui_2023_01_20" , ClassName = "CUIEngineWin32" , ProcessName = "steam" , MaxVersion = 1684535786 - 1 } ,
2023-01-21 22:01:17 +01:00
// new Classifier() { Type = "possiblegamepadui_2023_01_20", ClassName = "SDL_app", WindowTextSuffix = "Controller Layout", ProcessName = "steamwebhelper" },
} ;
2022-12-04 21:14:08 +01:00
public const int DebounceStates = 1 ;
2022-12-04 20:43:57 +01:00
private string? lastState ;
2022-12-04 21:14:08 +01:00
private int stateChanged ;
2022-11-27 13:41:28 +01:00
2022-11-25 10:56:17 +01:00
public override void Tick ( Context context )
{
2023-01-21 21:41:55 +01:00
if ( Settings . Default . EnableSteamDetection ! = true )
2022-11-25 10:56:17 +01:00
{
2022-11-29 22:50:07 +01:00
context . State . SteamUsesSteamInput = false ;
context . State . SteamUsesX360Controller = false ;
2023-02-10 11:05:23 +01:00
context . State . SteamUsesDS4Controller = false ;
2022-12-04 20:43:57 +01:00
lastState = null ;
2022-12-04 21:14:08 +01:00
stateChanged = 0 ;
2022-11-25 10:56:17 +01:00
return ;
}
2022-12-04 20:43:57 +01:00
var usesController = UsesController ( ) ;
2022-11-27 13:41:28 +01:00
if ( lastState = = usesController )
2022-12-04 21:14:08 +01:00
{
stateChanged = 0 ;
return ;
}
else if ( stateChanged < DebounceStates )
{
stateChanged + + ;
2022-11-27 13:41:28 +01:00
return ;
2022-12-04 21:14:08 +01:00
}
2022-11-27 13:41:28 +01:00
2022-12-04 20:43:57 +01:00
if ( usesController is not null )
2022-11-27 13:41:28 +01:00
{
2022-11-29 22:50:07 +01:00
context . State . SteamUsesSteamInput = Helpers . SteamConfiguration . IsControllerBlacklisted (
2022-11-27 13:41:28 +01:00
Devices . SteamController . VendorID ,
Devices . SteamController . ProductID
) ! = true ;
2022-11-29 22:50:07 +01:00
context . State . SteamUsesX360Controller = Helpers . SteamConfiguration . IsControllerBlacklisted (
2022-11-27 13:41:28 +01:00
Devices . Xbox360Controller . VendorID ,
Devices . Xbox360Controller . ProductID
) ! = true ;
2023-02-10 11:05:23 +01:00
context . State . SteamUsesDS4Controller = Helpers . SteamConfiguration . IsControllerBlacklisted (
Devices . DS4Controller . VendorID ,
Devices . DS4Controller . ProductID
) ! = true ;
2022-11-27 13:41:28 +01:00
}
else
{
2022-11-29 22:50:07 +01:00
context . State . SteamUsesSteamInput = false ;
context . State . SteamUsesX360Controller = false ;
2023-02-10 11:05:23 +01:00
context . State . SteamUsesDS4Controller = false ;
2022-11-27 13:41:28 +01:00
}
2022-11-25 10:56:17 +01:00
2022-11-27 13:41:28 +01:00
lastState = usesController ;
2022-12-04 21:14:08 +01:00
stateChanged = 0 ;
2022-12-04 20:43:57 +01:00
#if DEBUG
CommonHelpers . Log . TraceLine (
2023-02-10 11:05:23 +01:00
"SteamManager: uses={0}, isRunning={1}, usesSteamInput={2}, usesX360={3}, usesDS4={4}" ,
2022-12-04 20:43:57 +01:00
usesController ,
SteamConfiguration . IsRunning ,
context . State . SteamUsesSteamInput ,
2023-02-10 11:05:23 +01:00
context . State . SteamUsesX360Controller ,
context . State . SteamUsesDS4Controller
2022-12-04 20:43:57 +01:00
) ;
#endif
2022-11-25 10:56:17 +01:00
}
2022-12-04 20:43:57 +01:00
private string? UsesController ( )
2022-11-25 10:56:17 +01:00
{
2022-11-28 20:28:21 +01:00
if ( ! SteamConfiguration . IsRunning )
2022-11-25 10:56:17 +01:00
return null ;
2022-12-04 20:43:57 +01:00
if ( SteamConfiguration . IsBigPictureMode . GetValueOrDefault ( false ) )
return "bigpicture" ;
if ( SteamConfiguration . IsRunningGame . GetValueOrDefault ( false ) )
return "game" ;
2023-01-21 22:01:17 +01:00
return ClassifyForegroundProcess ( ) ;
}
private string? ClassifyForegroundProcess ( )
{
IntPtr hWnd = GetForegroundWindow ( ) ;
if ( hWnd = = IntPtr . Zero )
return null ;
StringBuilder classNameBuilder = new StringBuilder ( 256 ) ;
if ( GetClassName ( hWnd , classNameBuilder , classNameBuilder . Capacity ) = = 0 )
return null ;
var className = classNameBuilder . ToString ( ) ;
StringBuilder windowTextBuilder = new StringBuilder ( 256 ) ;
if ( GetWindowText ( hWnd , windowTextBuilder , windowTextBuilder . Capacity ) = = 0 )
return null ;
var windowText = windowTextBuilder . ToString ( ) ;
var processName = ForegroundProcess . Find ( hWnd ) ? . ProcessName ;
if ( processName is null )
return null ;
2023-05-21 17:46:34 +02:00
var steamVersion = SteamConfiguration . SteamVersion ;
2023-01-21 22:01:17 +01:00
foreach ( var classifier in Classifiers )
{
2023-05-21 17:46:34 +02:00
if ( classifier . Match ( className , windowText , processName , steamVersion ) )
{
if ( classifier . Forbid )
return null ;
return String . Format ( "{0} (className={1}, windowText={2}, processName={3}, steamVersion={4})" ,
classifier . Type , className , windowText , processName , steamVersion ) ;
}
2023-01-21 22:01:17 +01:00
}
2022-12-04 20:43:57 +01:00
return null ;
2022-11-25 10:56:17 +01:00
}
2023-01-21 22:01:17 +01:00
private struct Classifier
{
public String Type { get ; set ; }
public String ? ClassName { get ; set ; }
public String ? WindowText { get ; set ; }
public String ? WindowTextPrefix { get ; set ; }
public String ? WindowTextSuffix { get ; set ; }
2023-02-08 15:40:08 +01:00
public Regex ? WindowTextRegex { get ; set ; }
2023-01-21 22:01:17 +01:00
public String ? ProcessName { get ; set ; }
2023-05-21 17:46:34 +02:00
public uint MinVersion { get ; set ; }
public uint MaxVersion { get ; set ; }
public bool Forbid { get ; set ; }
2023-01-21 22:01:17 +01:00
2023-05-21 17:46:34 +02:00
public bool Match ( string className , string windowText , string processName , uint steamVersion )
2023-01-21 22:01:17 +01:00
{
if ( ClassName is not null & & className ! = ClassName )
return false ;
if ( WindowText is not null & & windowText ! = WindowText )
return false ;
2023-05-21 17:46:34 +02:00
if ( WindowTextRegex is not null & & ! WindowTextRegex . IsMatch ( windowText ) )
2023-02-08 15:40:08 +01:00
return false ;
2023-01-21 22:01:17 +01:00
if ( WindowTextPrefix is not null & & ! windowText . StartsWith ( WindowTextPrefix ) )
return false ;
if ( WindowTextSuffix is not null & & ! windowText . EndsWith ( WindowTextSuffix ) )
return false ;
if ( ProcessName is not null & & ! processName . EndsWith ( ProcessName ) )
return false ;
2023-05-21 17:46:34 +02:00
if ( MinVersion > 0 & & steamVersion < MinVersion )
return false ;
if ( MaxVersion > 0 & & steamVersion > MaxVersion )
return false ;
2023-01-21 22:01:17 +01:00
return true ;
}
}
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow ( ) ;
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow ( string lpClassName , string lpWindowName ) ;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern int GetWindowText ( IntPtr hWnd , StringBuilder lpString , int nMaxCount ) ;
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName ( IntPtr hWnd , StringBuilder lpClassName , int nMaxCount ) ;
2022-11-25 10:56:17 +01:00
}
}