2017-08-20 01:48:06 +02:00
using System ;
2014-05-28 21:47:25 +02:00
using System.Collections.Generic ;
using System.Drawing ;
using System.Text ;
using System.Windows.Forms ;
using System.IO ;
2015-02-08 22:51:52 +01:00
2014-05-28 21:47:25 +02:00
using System.Xml ;
2014-06-09 01:41:36 +02:00
using System.Runtime.InteropServices ;
2018-01-26 07:41:20 +01:00
using System.Threading ;
using System.Diagnostics ;
using System.Threading.Tasks ;
2019-04-20 17:47:29 +02:00
using static DS4Windows . Global ;
2014-05-28 21:47:25 +02:00
2019-04-30 21:29:50 +02:00
namespace DS4Windows.Forms
2014-05-28 21:47:25 +02:00
{
public partial class WinProgs : Form
{
2014-05-30 22:39:39 +02:00
ComboBox [ ] cbs ;
2014-11-18 22:23:41 +01:00
public DS4Form form ;
2014-06-09 01:41:36 +02:00
//C:\ProgramData\Microsoft\Windows\Start Menu\Programs
string steamgamesdir , origingamesdir ;
protected String m_Profile = Global . appdatapath + "\\Auto Profiles.xml" ;
2019-07-11 22:58:03 +02:00
ProgramPathItem selectedProgramPathItem = null ;
2014-06-06 22:38:52 +02:00
List < string > lodsf = new List < string > ( ) ;
bool appsloaded = false ;
2019-04-20 17:42:09 +02:00
public const string steamCommx86Loc = @"C:\Program Files (x86)\Steam\steamapps\common" ;
public const string steamCommLoc = @"C:\Program Files\Steam\steamapps\common" ;
2018-06-23 09:21:48 +02:00
const string originx86Loc = @"C:\Program Files (x86)\Origin Games" ;
const string originLoc = @"C:\Program Files\Origin Games" ;
2014-06-06 22:38:52 +02:00
2014-11-14 20:44:50 +01:00
public WinProgs ( string [ ] oc , DS4Form main )
2014-05-28 21:47:25 +02:00
{
2019-07-11 22:58:03 +02:00
ToolTip tp = new ToolTip ( ) ;
2014-05-28 21:47:25 +02:00
InitializeComponent ( ) ;
2019-07-11 22:58:03 +02:00
2015-11-28 06:47:26 +01:00
openProgram . Filter = Properties . Resources . Programs + "|*.exe|" + Properties . Resources . Shortcuts + "|*.lnk" ;
2014-06-06 22:38:52 +02:00
form = main ;
cbs = new ComboBox [ 4 ] { cBProfile1 , cBProfile2 , cBProfile3 , cBProfile4 } ;
2014-05-30 22:39:39 +02:00
for ( int i = 0 ; i < 4 ; i + + )
{
cbs [ i ] . Items . AddRange ( oc ) ;
2014-08-17 00:09:15 +02:00
cbs [ i ] . Items . Add ( Properties . Resources . noneProfile ) ;
2014-06-06 22:38:52 +02:00
cbs [ i ] . SelectedIndex = cbs [ i ] . Items . Count - 1 ;
2014-05-30 22:39:39 +02:00
}
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
tp . SetToolTip ( cBAutoProfileDebugLog , Properties . Resources . ShowAutoProfileDebugLogTip ) ;
tp . SetToolTip ( tBPath , Properties . Resources . AutoProfilePathAndWindowTitleEditTip ) ;
tp . SetToolTip ( tBWndTitle , Properties . Resources . AutoProfilePathAndWindowTitleEditTip ) ;
2014-05-28 21:47:25 +02:00
if ( ! File . Exists ( Global . appdatapath + @"\Auto Profiles.xml" ) )
Create ( ) ;
2017-08-20 01:48:06 +02:00
2014-06-06 22:38:52 +02:00
LoadP ( ) ;
2014-06-09 01:41:36 +02:00
2019-04-20 17:47:29 +02:00
if ( UseCustomSteamFolder & & Directory . Exists ( CustomSteamFolder ) )
steamgamesdir = CustomSteamFolder ;
else if ( Directory . Exists ( steamCommx86Loc ) )
2018-06-23 09:21:48 +02:00
steamgamesdir = steamCommx86Loc ;
else if ( Directory . Exists ( steamCommLoc ) )
steamgamesdir = steamCommLoc ;
2014-06-09 01:41:36 +02:00
else
cMSPrograms . Items . Remove ( addSteamGamesToolStripMenuItem ) ;
2018-06-23 09:21:48 +02:00
if ( Directory . Exists ( originx86Loc ) )
origingamesdir = originx86Loc ;
else if ( Directory . Exists ( originLoc ) )
origingamesdir = originLoc ;
2014-06-09 01:41:36 +02:00
else
cMSPrograms . Items . Remove ( addOriginGamesToolStripMenuItem ) ;
2019-07-11 22:58:03 +02:00
cBAutoProfileDebugLog . Checked = ( DS4Form . autoProfileDebugLogLevel > 0 ) ;
selectedProgramPathItem = null ;
UpdateProfileComboListValues ( null ) ;
2014-06-09 01:41:36 +02:00
}
2014-05-28 21:47:25 +02:00
public bool Create ( )
{
2017-08-20 01:48:06 +02:00
bool Saved = true ;
2014-05-28 21:47:25 +02:00
try
{
XmlNode Node ;
2019-07-11 22:58:03 +02:00
XmlDocument doc = new XmlDocument ( ) ;
2014-05-28 21:47:25 +02:00
2019-07-11 22:58:03 +02:00
Node = doc . CreateXmlDeclaration ( "1.0" , "utf-8" , String . Empty ) ;
doc . AppendChild ( Node ) ;
2014-05-28 21:47:25 +02:00
2019-07-11 22:58:03 +02:00
Node = doc . CreateComment ( String . Format ( " Auto-Profile Configuration Data. {0} " , DateTime . Now ) ) ;
doc . AppendChild ( Node ) ;
2014-05-28 21:47:25 +02:00
2019-07-11 22:58:03 +02:00
Node = doc . CreateWhitespace ( "\r\n" ) ;
doc . AppendChild ( Node ) ;
2014-05-28 21:47:25 +02:00
2019-07-11 22:58:03 +02:00
Node = doc . CreateNode ( XmlNodeType . Element , "Programs" , "" ) ;
doc . AppendChild ( Node ) ;
doc . Save ( m_Profile ) ;
2014-05-28 21:47:25 +02:00
}
catch { Saved = false ; }
return Saved ;
}
2014-06-06 22:38:52 +02:00
2014-11-18 22:23:41 +01:00
public void ShowMainWindow ( )
{
form . Show ( ) ;
2014-11-18 23:07:27 +01:00
form . WindowState = FormWindowState . Normal ;
form . Focus ( ) ;
2014-11-18 22:23:41 +01:00
}
2014-06-06 22:38:52 +02:00
public void LoadP ( )
2014-05-28 21:47:25 +02:00
{
2019-07-11 22:58:03 +02:00
try
{
XmlDocument doc = new XmlDocument ( ) ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
iLIcons . Images . Clear ( ) ;
if ( ! File . Exists ( Global . appdatapath + "\\Auto Profiles.xml" ) )
return ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
doc . Load ( Global . appdatapath + "\\Auto Profiles.xml" ) ;
XmlNodeList programslist = doc . SelectNodes ( "Programs/Program" ) ;
int index ;
ListViewItem lvi ;
string progPath , progTitle ;
lVPrograms . BeginUpdate ( ) ;
foreach ( XmlNode progNode in programslist )
2014-05-28 21:47:25 +02:00
{
2019-07-11 22:58:03 +02:00
progPath = progNode . Attributes [ "path" ] ? . Value ;
progTitle = progNode . Attributes [ "title" ] ? . Value ;
if ( ! string . IsNullOrEmpty ( progPath ) )
2014-06-14 21:14:27 +02:00
{
2019-07-11 22:58:03 +02:00
index = iLIcons . Images . IndexOfKey ( progPath ) ;
if ( index < 0 & & File . Exists ( progPath ) )
{
iLIcons . Images . Add ( progPath , Icon . ExtractAssociatedIcon ( progPath ) ) ;
index = iLIcons . Images . Count - 1 ;
}
2018-06-23 09:21:48 +02:00
2019-07-11 22:58:03 +02:00
if ( index > = 0 )
lvi = new ListViewItem ( Path . GetFileNameWithoutExtension ( progPath ) , index ) ;
else
lvi = new ListViewItem ( Path . GetFileNameWithoutExtension ( progPath ) ) ;
2018-06-23 09:21:48 +02:00
2019-07-11 22:58:03 +02:00
lvi . Checked = true ;
lvi . SubItems . Add ( progPath ) ;
if ( ! String . IsNullOrEmpty ( progTitle ) )
lvi . SubItems . Add ( progTitle ) ;
2018-06-23 09:21:48 +02:00
2019-07-11 22:58:03 +02:00
lVPrograms . Items . Add ( lvi ) ;
}
}
}
catch ( Exception e )
{
// Eat all exceptions while reading auto-profile file because we don't want to crash DS4Win app just because there are some permissions or other issues with the file
AppLogger . LogToGui ( $"ERROR. Auto-profile XML file {Global.appdatapath}\\Auto Profiles.xml reading failed. {e.Message}" , true ) ;
}
finally
{
lVPrograms . EndUpdate ( ) ;
}
2014-06-06 22:38:52 +02:00
}
2014-05-28 21:47:25 +02:00
2014-06-09 01:41:36 +02:00
private void GetApps ( string path )
2014-06-06 22:38:52 +02:00
{
2014-06-09 01:41:36 +02:00
lodsf . Clear ( ) ;
2015-06-01 21:04:22 +02:00
lodsf . AddRange ( Directory . GetFiles ( path , "*.exe" , SearchOption . TopDirectoryOnly ) ) ;
foreach ( string s in Directory . GetDirectories ( path , "*" , SearchOption . TopDirectoryOnly ) )
{
try
{
lodsf . AddRange ( Directory . GetFiles ( s , "*.exe" , SearchOption . TopDirectoryOnly ) ) ;
lodsf . AddRange ( GetAppsR ( s ) ) ;
}
catch { }
}
2017-08-20 01:48:06 +02:00
2014-06-06 22:38:52 +02:00
appsloaded = true ;
2014-06-09 01:41:36 +02:00
}
2015-06-01 21:04:22 +02:00
private List < string > GetAppsR ( string path )
{
List < string > lods = new List < string > ( ) ;
foreach ( string s in Directory . GetDirectories ( path , "*" , SearchOption . TopDirectoryOnly ) )
{
try
{
lods . AddRange ( Directory . GetFiles ( s , "*.exe" , SearchOption . TopDirectoryOnly ) ) ;
lods . AddRange ( GetAppsR ( s ) ) ;
}
catch { }
}
2017-08-20 01:48:06 +02:00
2015-06-01 21:04:22 +02:00
return lods ;
}
2017-08-20 01:48:06 +02:00
2014-06-09 01:41:36 +02:00
private void GetShortcuts ( string path )
{
lodsf . Clear ( ) ;
lodsf . AddRange ( Directory . GetFiles ( path , "*.lnk" , SearchOption . AllDirectories ) ) ;
2018-01-29 06:38:10 +01:00
lodsf . AddRange ( Directory . GetFiles ( Environment . GetFolderPath ( Environment . SpecialFolder . CommonStartMenu ) + "\\Programs" , "*.lnk" , SearchOption . AllDirectories ) ) ;
2014-06-09 01:41:36 +02:00
for ( int i = 0 ; i < lodsf . Count ; i + + )
lodsf [ i ] = GetTargetPath ( lodsf [ i ] ) ;
2017-08-20 01:48:06 +02:00
2014-06-09 01:41:36 +02:00
appsloaded = true ;
}
2014-06-06 22:38:52 +02:00
2019-07-11 22:58:03 +02:00
int AddLoadedApps ( bool autoremoveSetupApps = true )
2014-06-06 22:38:52 +02:00
{
2019-07-11 22:58:03 +02:00
int numOfAppsAdded = 0 ;
2014-06-06 22:38:52 +02:00
if ( appsloaded )
{
2014-08-17 00:09:15 +02:00
bnAddPrograms . Text = Properties . Resources . AddingToList ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
if ( autoremoveSetupApps )
2017-08-20 01:48:06 +02:00
{
2019-07-11 22:58:03 +02:00
for ( int i = lodsf . Count - 1 ; i > = 0 ; i - - )
2017-08-20 01:48:06 +02:00
{
2019-07-11 22:58:03 +02:00
if ( lodsf [ i ] . Contains ( "etup" ) | | lodsf [ i ] . Contains ( "dotnet" ) | | lodsf [ i ] . Contains ( "SETUP" )
| | lodsf [ i ] . Contains ( "edist" ) | | lodsf [ i ] . Contains ( "nstall" ) | | String . IsNullOrEmpty ( lodsf [ i ] ) )
2014-06-06 22:38:52 +02:00
lodsf . RemoveAt ( i ) ;
2017-08-20 01:48:06 +02:00
}
2019-07-11 22:58:03 +02:00
// Remove existing program entries from a list of new app paths (no need to add the same path twice)
for ( int i = lodsf . Count - 1 ; i > = 0 ; i - - )
{
for ( int j = 0 ; j < lVPrograms . Items . Count ; j + + )
{
if ( string . Equals ( lVPrograms . Items [ j ] . SubItems [ 1 ] . Text , lodsf [ i ] , StringComparison . OrdinalIgnoreCase ) )
{
lodsf . RemoveAt ( i ) ;
break ;
}
}
}
2017-08-20 01:48:06 +02:00
}
2019-07-11 22:58:03 +02:00
try
2014-06-06 22:38:52 +02:00
{
2019-07-11 22:58:03 +02:00
ListViewItem lvi ;
int index ;
lVPrograms . BeginUpdate ( ) ;
foreach ( string st in lodsf )
2014-06-09 01:41:36 +02:00
{
2019-07-11 22:58:03 +02:00
if ( File . Exists ( st ) )
{
index = iLIcons . Images . IndexOfKey ( st ) ;
if ( index < 0 )
{
iLIcons . Images . Add ( st , Icon . ExtractAssociatedIcon ( st ) ) ;
index = iLIcons . Images . Count - 1 ;
}
if ( index > = 0 )
lvi = new ListViewItem ( Path . GetFileNameWithoutExtension ( st ) , index ) ;
else
lvi = new ListViewItem ( Path . GetFileNameWithoutExtension ( st ) ) ;
lvi . SubItems . Add ( st ) ;
lvi . ToolTipText = st ;
lVPrograms . Items . Add ( lvi ) ;
numOfAppsAdded + + ;
}
2014-06-09 01:41:36 +02:00
}
2014-06-06 22:38:52 +02:00
}
2019-07-11 22:58:03 +02:00
catch ( Exception e )
{
// Eat all exceptions while processing added apps because we don't want to crash DS4Win app just because there are some permissions or other issues with the file
AppLogger . LogToGui ( $"ERROR. Failed to add selected applications to an auto-profile list. {e.Message}" , true ) ;
}
finally
{
lVPrograms . EndUpdate ( ) ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
bnAddPrograms . Text = Properties . Resources . AddPrograms ;
bnAddPrograms . Enabled = true ;
appsloaded = false ;
}
2014-06-06 22:38:52 +02:00
}
2019-07-11 22:58:03 +02:00
return numOfAppsAdded ;
}
private XmlNode FindProgramXMLItem ( XmlDocument doc , string programPath , string windowTitle )
{
// Try to find a specified programPath+windowTitle program entry from an autoprofile XML file list
foreach ( XmlNode item in doc . SelectNodes ( "/Programs/Program" ) )
{
XmlAttribute xmlAttrTitle = item . Attributes [ "title" ] ;
if ( item . Attributes [ "path" ] . InnerText = = programPath )
{
if ( String . IsNullOrEmpty ( windowTitle ) & & ( xmlAttrTitle = = null | | String . IsNullOrEmpty ( xmlAttrTitle . InnerText ) ) )
return item ;
else if ( ! String . IsNullOrEmpty ( windowTitle ) & & xmlAttrTitle ! = null & & xmlAttrTitle . InnerText = = windowTitle )
return item ;
}
}
return null ;
2014-06-06 22:38:52 +02:00
}
2019-07-11 22:58:03 +02:00
public void Save ( ProgramPathItem progPathItem )
2014-06-06 22:38:52 +02:00
{
2019-07-11 22:58:03 +02:00
XmlDocument doc = new XmlDocument ( ) ;
2014-06-06 22:38:52 +02:00
XmlNode Node ;
2019-07-11 22:58:03 +02:00
string newPath , newTitle ;
2014-06-06 22:38:52 +02:00
2019-07-11 22:58:03 +02:00
newPath = tBPath . Text . Trim ( ) ;
newTitle = tBWndTitle . Text ;
if ( progPathItem = = null | | String . IsNullOrEmpty ( progPathItem . path ) | | String . IsNullOrEmpty ( newPath ) )
return ;
2017-08-20 01:48:06 +02:00
2014-06-06 22:38:52 +02:00
try
{
2019-07-11 22:58:03 +02:00
doc . Load ( m_Profile ) ;
Node = doc . CreateComment ( String . Format ( " Auto-Profile Configuration Data. {0} " , DateTime . Now ) ) ;
foreach ( XmlNode node in doc . SelectNodes ( "//comment()" ) )
node . ParentNode . ReplaceChild ( Node , node ) ;
// Find the existing XML program entry using the old path and title value as a search key and replace it with new path and title values (or add a new entry if this was a new program path)
XmlNode oldxmlprocess = FindProgramXMLItem ( doc , progPathItem . path , progPathItem . title ) ;
Node = doc . SelectSingleNode ( "Programs" ) ;
XmlElement el = doc . CreateElement ( "Program" ) ;
el . SetAttribute ( "path" , newPath ) ;
if ( ! String . IsNullOrEmpty ( newTitle ) )
el . SetAttribute ( "title" , newTitle ) ;
el . AppendChild ( doc . CreateElement ( "Controller1" ) ) . InnerText = cBProfile1 . Text ;
el . AppendChild ( doc . CreateElement ( "Controller2" ) ) . InnerText = cBProfile2 . Text ;
el . AppendChild ( doc . CreateElement ( "Controller3" ) ) . InnerText = cBProfile3 . Text ;
el . AppendChild ( doc . CreateElement ( "Controller4" ) ) . InnerText = cBProfile4 . Text ;
el . AppendChild ( doc . CreateElement ( "TurnOff" ) ) . InnerText = cBTurnOffDS4W . Checked . ToString ( ) ;
if ( oldxmlprocess ! = null )
Node . ReplaceChild ( el , oldxmlprocess ) ;
else
Node . AppendChild ( el ) ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
doc . AppendChild ( Node ) ;
doc . Save ( m_Profile ) ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
if ( selectedProgramPathItem ! = null )
{
selectedProgramPathItem . path = newPath ;
selectedProgramPathItem . title = newTitle ;
}
if ( lVPrograms . SelectedItems . Count > 0 )
{
lVPrograms . SelectedItems [ 0 ] . Checked = true ;
lVPrograms . SelectedItems [ 0 ] . SubItems [ 0 ] . Text = Path . GetFileNameWithoutExtension ( newPath ) ;
lVPrograms . SelectedItems [ 0 ] . SubItems [ 1 ] . Text = newPath ;
if ( lVPrograms . SelectedItems [ 0 ] . SubItems . Count < 3 )
if ( ! String . IsNullOrEmpty ( newTitle ) )
lVPrograms . SelectedItems [ 0 ] . SubItems . Add ( newTitle ) ;
else
lVPrograms . SelectedItems [ 0 ] . SubItems [ 2 ] . Text = newTitle ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
if ( ! String . IsNullOrEmpty ( newTitle ) )
lVPrograms . SelectedItems [ 0 ] . ToolTipText = $"{newPath} [{newTitle}]" ;
else
lVPrograms . SelectedItems [ 0 ] . ToolTipText = newPath ;
}
form . LoadP ( ) ;
}
catch ( Exception e )
{
// Eat all exceptions while writing auto-profile file because we don't want to crash DS4Win app just because there are some permissions or other issues with the file
AppLogger . LogToGui ( $"ERROR. Auto-profile XML file {Global.appdatapath}\\Auto Profiles.xml writing failed. {e.Message}" , true ) ;
}
2014-06-09 01:41:36 +02:00
}
2014-06-06 22:38:52 +02:00
2019-07-11 22:58:03 +02:00
public void LoadP ( ProgramPathItem loadProgPathItem )
{
if ( loadProgPathItem = = null )
return ;
try
2014-05-30 22:39:39 +02:00
{
2019-07-11 22:58:03 +02:00
XmlDocument doc = new XmlDocument ( ) ;
doc . Load ( m_Profile ) ;
XmlNode programItem = FindProgramXMLItem ( doc , loadProgPathItem . path , loadProgPathItem . title ) ;
if ( programItem ! = null )
2014-05-30 22:39:39 +02:00
{
2019-07-11 22:58:03 +02:00
XmlNode profileItem ;
for ( int i = 0 ; i < 4 ; i + + )
2017-08-20 01:48:06 +02:00
{
2019-07-11 22:58:03 +02:00
profileItem = programItem . SelectSingleNode ( $".//Controller{i + 1}" ) ;
if ( profileItem ! = null )
2017-08-20 01:48:06 +02:00
{
2019-07-11 22:58:03 +02:00
for ( int j = 0 ; j < cbs [ i ] . Items . Count ; j + + )
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
{
2019-07-11 22:58:03 +02:00
if ( cbs [ i ] . Items [ j ] . ToString ( ) = = profileItem . InnerText )
{
cbs [ i ] . SelectedIndex = j ;
break ;
}
else
cbs [ i ] . SelectedIndex = cbs [ i ] . Items . Count - 1 ;
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
}
2017-08-20 01:48:06 +02:00
}
2019-07-11 22:58:03 +02:00
else
cbs [ i ] . SelectedIndex = cbs [ i ] . Items . Count - 1 ;
}
bool turnOff ;
profileItem = programItem . SelectSingleNode ( $".//TurnOff" ) ;
if ( profileItem ! = null & & bool . TryParse ( profileItem . InnerText , out turnOff ) )
{
cBTurnOffDS4W . Checked = turnOff ;
2017-08-20 01:48:06 +02:00
}
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
else
2019-07-11 22:58:03 +02:00
cBTurnOffDS4W . Checked = false ;
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
}
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
tBPath . Text = loadProgPathItem . path ;
tBWndTitle . Text = loadProgPathItem . title ;
}
catch ( Exception e )
{
// Eat all exceptions while reading auto-profile file because we don't want to crash DS4Win app just because there are some permissions or other issues with the file
AppLogger . LogToGui ( $"ERROR. Failed to read {loadProgPathItem.path} {loadProgPathItem.title} XML entry. {e.Message}" , true ) ;
}
bnSave . Enabled = false ;
}
public void RemoveP ( ProgramPathItem removeProgPathItem , bool uncheck )
{
bnSave . Enabled = false ;
if ( removeProgPathItem = = null )
return ;
try
{
XmlDocument doc = new XmlDocument ( ) ;
doc . Load ( m_Profile ) ;
XmlNode programItem = FindProgramXMLItem ( doc , removeProgPathItem . path , removeProgPathItem . title ) ;
if ( programItem ! = null )
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
{
2019-07-11 22:58:03 +02:00
XmlNode parentNode = programItem . ParentNode ;
if ( parentNode ! = null )
{
parentNode . RemoveChild ( programItem ) ;
doc . AppendChild ( parentNode ) ;
doc . Save ( m_Profile ) ;
}
2014-05-30 22:39:39 +02:00
}
2019-07-11 22:58:03 +02:00
if ( lVPrograms . SelectedItems . Count > 0 & & uncheck )
lVPrograms . SelectedItems [ 0 ] . Checked = false ;
2014-05-30 22:39:39 +02:00
}
2019-07-11 22:58:03 +02:00
catch ( Exception e )
2014-06-06 22:38:52 +02:00
{
2019-07-11 22:58:03 +02:00
// Eat all exceptions while updating auto-profile file because we don't want to crash DS4Win app just because there are some permissions or other issues with the file
AppLogger . LogToGui ( $"ERROR. Failed to remove {removeProgPathItem.path} {removeProgPathItem.title} XML entry. {e.Message}" , true ) ;
2014-06-06 22:38:52 +02:00
}
2019-07-11 22:58:03 +02:00
UpdateProfileComboListValues ( null ) ;
2014-05-30 22:39:39 +02:00
}
2019-07-11 22:58:03 +02:00
private void UpdateProfileComboListValues ( ProgramPathItem progItem )
2014-05-28 21:47:25 +02:00
{
2019-07-11 22:58:03 +02:00
if ( progItem ! = null )
{
for ( int i = 0 ; i < 4 ; i + + )
cbs [ i ] . Enabled = true ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
tBPath . Enabled = tBWndTitle . Enabled = cBTurnOffDS4W . Enabled = true ;
LoadP ( progItem ) ;
bnDelete . Enabled = true ;
}
else
{
int last = cbs [ 0 ] . Items . Count - 1 ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
// Set all profile combox values to "none" value (ie. the last item in a controller combobox list)
for ( int i = 0 ; i < 4 ; i + + )
{
cbs [ i ] . Enabled = false ;
if ( cbs [ i ] . SelectedIndex ! = last )
cbs [ i ] . SelectedIndex = last ;
}
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
bnSave . Enabled = bnDelete . Enabled = false ;
tBPath . Enabled = tBWndTitle . Enabled = cBTurnOffDS4W . Enabled = false ;
tBPath . Text = tBWndTitle . Text = "" ;
cBTurnOffDS4W . Checked = false ;
}
2014-06-09 01:41:36 +02:00
}
2014-06-06 22:38:52 +02:00
private void CBProfile_IndexChanged ( object sender , EventArgs e )
{
2019-07-11 22:58:03 +02:00
if ( selectedProgramPathItem ! = null & & lVPrograms . SelectedItems . Count > 0 )
2014-06-06 22:38:52 +02:00
bnSave . Enabled = true ;
2014-05-28 21:47:25 +02:00
}
private void bnSave_Click ( object sender , EventArgs e )
{
2019-07-11 22:58:03 +02:00
if ( selectedProgramPathItem ! = null )
{
// Path cannot be empty. If user tried to clear it then re-use the original path value
if ( String . IsNullOrEmpty ( tBPath . Text ) )
tBPath . Text = selectedProgramPathItem . path ;
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
Save ( selectedProgramPathItem ) ;
}
2014-06-06 22:38:52 +02:00
bnSave . Enabled = false ;
2014-05-28 21:47:25 +02:00
}
2014-06-06 22:38:52 +02:00
private void bnAddPrograms_Click ( object sender , EventArgs e )
{
2014-06-09 01:41:36 +02:00
cMSPrograms . Show ( bnAddPrograms , new Point ( 0 , bnAddPrograms . Height ) ) ;
2014-06-06 22:38:52 +02:00
}
private void bnDelete_Click ( object sender , EventArgs e )
{
2019-07-11 22:58:03 +02:00
RemoveP ( selectedProgramPathItem , true ) ;
selectedProgramPathItem = null ;
bnSave . Enabled = bnDelete . Enabled = false ;
if ( lVPrograms . SelectedItems . Count > 0 )
lVPrograms . SelectedItems [ 0 ] . Selected = lVPrograms . SelectedItems [ 0 ] . Focused = false ;
2014-06-06 22:38:52 +02:00
}
private void lBProgramPath_SelectedIndexChanged ( object sender , EventArgs e )
{
2019-07-11 22:58:03 +02:00
if ( lVPrograms . SelectedItems . Count > 0 & & lVPrograms . SelectedIndices [ 0 ] > - 1 )
2014-06-06 22:38:52 +02:00
{
2019-07-11 22:58:03 +02:00
if ( selectedProgramPathItem = = null ) selectedProgramPathItem = new ProgramPathItem ( String . Empty , String . Empty ) ;
selectedProgramPathItem . path = lVPrograms . SelectedItems [ 0 ] . SubItems [ 1 ] . Text ;
if ( lVPrograms . SelectedItems [ 0 ] . SubItems . Count > = 3 )
selectedProgramPathItem . title = lVPrograms . SelectedItems [ 0 ] . SubItems [ 2 ] . Text ;
else
selectedProgramPathItem . title = String . Empty ;
UpdateProfileComboListValues ( selectedProgramPathItem ) ;
2014-06-06 22:38:52 +02:00
}
else
2019-07-11 22:58:03 +02:00
{
selectedProgramPathItem = null ;
UpdateProfileComboListValues ( null ) ;
}
2014-06-06 22:38:52 +02:00
}
private void bnHideUnchecked_Click ( object sender , EventArgs e )
{
2019-07-11 22:58:03 +02:00
// Remove all unchecked items from autoprofile XML file and listView list
foreach ( ListViewItem lvi in lVPrograms . Items )
{
if ( ! lvi . Checked )
{
RemoveP ( new ProgramPathItem ( lvi . SubItems [ 1 ] ? . Text , ( lvi . SubItems . Count > = 3 ? lvi . SubItems [ 2 ] ? . Text : null ) ) , false ) ;
}
}
selectedProgramPathItem = null ;
2014-06-06 22:38:52 +02:00
form . RefreshAutoProfilesPage ( ) ;
}
2017-08-23 12:12:36 +02:00
private async void addSteamGamesToolStripMenuItem_Click ( object sender , EventArgs e )
2014-06-09 01:41:36 +02:00
{
2014-08-17 00:09:15 +02:00
bnAddPrograms . Text = Properties . Resources . Loading ;
2014-06-09 01:41:36 +02:00
bnAddPrograms . Enabled = false ;
cMSPrograms . Items . Remove ( addSteamGamesToolStripMenuItem ) ;
2018-01-26 07:41:20 +01:00
await Task . Run ( ( ) = > GetApps ( steamgamesdir ) ) ;
2018-06-23 09:21:48 +02:00
AddLoadedApps ( ) ;
2014-06-09 01:41:36 +02:00
}
2015-06-01 21:04:22 +02:00
2017-08-23 12:12:36 +02:00
private async void addDirectoryToolStripMenuItem_Click ( object sender , EventArgs e )
2015-06-01 21:04:22 +02:00
{
2015-07-31 05:51:16 +02:00
FolderBrowserDialog fbd = new FolderBrowserDialog ( ) ;
if ( fbd . ShowDialog ( ) = = DialogResult . OK )
2015-06-01 21:04:22 +02:00
{
bnAddPrograms . Text = Properties . Resources . Loading ;
bnAddPrograms . Enabled = false ;
2018-01-26 07:41:20 +01:00
await Task . Run ( ( ) = > GetApps ( fbd . SelectedPath ) ) ;
2018-06-23 09:21:48 +02:00
AddLoadedApps ( ) ;
2015-07-31 05:51:16 +02:00
}
2015-06-01 21:04:22 +02:00
}
2014-06-09 01:41:36 +02:00
private void browseForOtherProgramsToolStripMenuItem_Click ( object sender , EventArgs e )
{
2015-07-31 05:51:16 +02:00
if ( openProgram . ShowDialog ( ) = = DialogResult . OK )
2014-06-09 01:41:36 +02:00
{
string file = openProgram . FileName ;
if ( file . EndsWith ( ".lnk" ) )
{
file = GetTargetPath ( file ) ;
}
2017-08-20 01:48:06 +02:00
2019-07-11 22:58:03 +02:00
if ( lVPrograms . SelectedItems . Count > 0 )
lVPrograms . SelectedItems [ 0 ] . Selected = lVPrograms . SelectedItems [ 0 ] . Focused = false ;
lodsf . Clear ( ) ;
lodsf . Add ( file ) ;
appsloaded = true ;
if ( AddLoadedApps ( false ) > 0 & & lVPrograms . Items . Count > 0 )
{
lVPrograms . Items [ lVPrograms . Items . Count - 1 ] . Focused = true ;
lVPrograms . Items [ lVPrograms . Items . Count - 1 ] . Selected = true ;
}
2014-06-09 01:41:36 +02:00
}
}
2017-08-23 12:12:36 +02:00
private async void addOriginGamesToolStripMenuItem_Click ( object sender , EventArgs e )
2014-06-09 01:41:36 +02:00
{
2014-08-17 00:09:15 +02:00
bnAddPrograms . Text = Properties . Resources . Loading ;
2014-06-09 01:41:36 +02:00
bnAddPrograms . Enabled = false ;
cMSPrograms . Items . Remove ( addOriginGamesToolStripMenuItem ) ;
2018-01-26 07:41:20 +01:00
await Task . Run ( ( ) = > GetApps ( origingamesdir ) ) ;
2018-06-23 09:21:48 +02:00
AddLoadedApps ( ) ;
2014-06-09 01:41:36 +02:00
}
2017-08-23 12:12:36 +02:00
private async void addProgramsFromStartMenuToolStripMenuItem_Click ( object sender , EventArgs e )
2014-06-09 01:41:36 +02:00
{
2014-08-17 00:09:15 +02:00
bnAddPrograms . Text = Properties . Resources . Loading ;
2014-06-09 01:41:36 +02:00
bnAddPrograms . Enabled = false ;
cMSPrograms . Items . Remove ( addProgramsFromStartMenuToolStripMenuItem ) ;
2018-01-26 07:41:20 +01:00
await Task . Run ( ( ) = > GetShortcuts ( Environment . GetFolderPath ( Environment . SpecialFolder . StartMenu ) + "\\Programs" ) ) ;
2018-06-23 09:21:48 +02:00
AddLoadedApps ( ) ;
2014-06-09 01:41:36 +02:00
}
public static string GetTargetPath ( string filePath )
{
string targetPath = ResolveMsiShortcut ( filePath ) ;
if ( targetPath = = null )
{
targetPath = ResolveShortcut ( filePath ) ;
}
return targetPath ;
}
public static string GetInternetShortcut ( string filePath )
{
string url = "" ;
using ( TextReader reader = new StreamReader ( filePath ) )
{
string line = "" ;
while ( ( line = reader . ReadLine ( ) ) ! = null )
{
if ( line . StartsWith ( "URL=" ) )
{
string [ ] splitLine = line . Split ( '=' ) ;
if ( splitLine . Length > 0 )
{
url = splitLine [ 1 ] ;
break ;
}
}
}
}
return url ;
}
2014-12-13 21:12:03 +01:00
public static string ResolveShortcut ( string filePath )
2014-06-09 01:41:36 +02:00
{
2018-01-26 07:41:20 +01:00
Type t = Type . GetTypeFromCLSID ( new Guid ( "72C24DD5-D70A-438B-8A42-98424B88AFB8" ) ) ; // Windows Script Host Shell Object
dynamic shell = Activator . CreateInstance ( t ) ;
string result ;
2014-06-09 01:41:36 +02:00
try
{
2018-01-26 07:41:20 +01:00
var shortcut = shell . CreateShortcut ( filePath ) ;
result = shortcut . TargetPath ;
Marshal . FinalReleaseComObject ( shortcut ) ;
2014-06-09 01:41:36 +02:00
}
catch ( COMException )
{
// A COMException is thrown if the file is not a valid shortcut (.lnk) file
2018-01-26 07:41:20 +01:00
result = null ;
2014-06-09 01:41:36 +02:00
}
2018-01-26 07:41:20 +01:00
finally
{
Marshal . FinalReleaseComObject ( shell ) ;
}
return result ;
2014-06-09 01:41:36 +02:00
}
2014-12-13 21:12:03 +01:00
public static string ResolveShortcutAndArgument ( string filePath )
{
2018-01-26 07:41:20 +01:00
Type t = Type . GetTypeFromCLSID ( new Guid ( "72C24DD5-D70A-438B-8A42-98424B88AFB8" ) ) ; // Windows Script Host Shell Object
dynamic shell = Activator . CreateInstance ( t ) ;
string result ;
2014-12-13 21:12:03 +01:00
try
{
2018-01-26 07:41:20 +01:00
var shortcut = shell . CreateShortcut ( filePath ) ;
result = shortcut . TargetPath + " " + shortcut . Arguments ;
Marshal . FinalReleaseComObject ( shortcut ) ;
2014-12-13 21:12:03 +01:00
}
catch ( COMException )
{
// A COMException is thrown if the file is not a valid shortcut (.lnk) file
2018-01-26 07:41:20 +01:00
result = null ;
}
finally
{
Marshal . FinalReleaseComObject ( shell ) ;
2014-12-13 21:12:03 +01:00
}
2018-01-26 07:49:28 +01:00
2018-01-26 07:41:20 +01:00
return result ;
2014-12-13 21:12:03 +01:00
}
Version 1.4.5
Added support for the New DS4 USB Adapater (Thanks to boganhobo and
Chamilsaan)
Implemented teokp's amazing fix for hide ds4 not working on the
anniversary update of Windows 10: when a controller fails to enter
exclusive mode, DS4Windows will ask for admin privilages to fix the
issue.
Now (near)unlimited Special Actions can be made from the previous limit
of 50
Special Action Xbox Game DVR is now no longer limited to Windows 10,
renamed multi action button: Assign a macro to single tap, double tap,
and holding down a button
Added option for White DS4Windows Icon in the notification tray (While
not merged from, thanks to tehmantra)
Added option to temporarily turn off DS4Windows when using a certain
program (togglable in the Auto Profiles Tab) (Same case as above but
thanks to dedChar to bring to light)
Fixed Options crashes in certain locales where decimal points are
repesented with commas, such as German (Thanks to kiliansch)
Added/Updated translations for many languauges, now including Japanese,
Slovenian, Hungarian, Greek, Finnish, Czech, Indonesian, and Ukrainian
2016-09-22 03:38:38 +02:00
private void cBTurnOffDS4W_CheckedChanged ( object sender , EventArgs e )
{
CBProfile_IndexChanged ( sender , e ) ;
}
2019-07-11 22:58:03 +02:00
private void cBAutoProfileDebugLog_CheckedChanged ( object sender , EventArgs e )
{
DS4Form . autoProfileDebugLogLevel = cBAutoProfileDebugLog . Checked ? 1 : 0 ;
}
private void tBPath_TextChanged ( object sender , EventArgs e )
{
int last = cbs [ 0 ] . Items . Count - 1 ;
if ( cbs [ 0 ] . SelectedIndex ! = last | | cbs [ 1 ] . SelectedIndex ! = last | | cbs [ 2 ] . SelectedIndex ! = last | | cbs [ 3 ] . SelectedIndex ! = last | | ! cBTurnOffDS4W . Checked )
{
// Content of path or wndTitle editbox changed. Enable SAVE button if it is disabled at the moment and there is an active selection in a listView
if ( selectedProgramPathItem ! = null & & bnSave . Enabled = = false & & lVPrograms . SelectedItems . Count > 0 )
bnSave . Enabled = true ;
}
}
2014-12-13 21:12:03 +01:00
public static string ResolveMsiShortcut ( string file )
2014-06-09 01:41:36 +02:00
{
2015-02-08 22:51:52 +01:00
StringBuilder product = new StringBuilder ( NativeMethods2 . MaxGuidLength + 1 ) ;
StringBuilder feature = new StringBuilder ( NativeMethods2 . MaxFeatureLength + 1 ) ;
StringBuilder component = new StringBuilder ( NativeMethods2 . MaxGuidLength + 1 ) ;
2014-06-09 01:41:36 +02:00
2015-02-08 22:51:52 +01:00
NativeMethods2 . MsiGetShortcutTarget ( file , product , feature , component ) ;
2014-06-09 01:41:36 +02:00
2015-02-08 22:51:52 +01:00
int pathLength = NativeMethods2 . MaxPathLength ;
2014-06-09 01:41:36 +02:00
StringBuilder path = new StringBuilder ( pathLength ) ;
2015-02-08 22:51:52 +01:00
NativeMethods2 . InstallState installState = NativeMethods2 . MsiGetComponentPath ( product . ToString ( ) , component . ToString ( ) , path , ref pathLength ) ;
if ( installState = = NativeMethods2 . InstallState . Local )
2014-06-09 01:41:36 +02:00
{
return path . ToString ( ) ;
}
else
{
return null ;
}
}
}
2017-08-20 01:48:06 +02:00
2015-02-08 22:51:52 +01:00
class NativeMethods2
2014-06-09 01:41:36 +02:00
{
[DllImport("msi.dll", CharSet = CharSet.Auto)]
public static extern uint MsiGetShortcutTarget ( string targetFile , StringBuilder productCode , StringBuilder featureID , StringBuilder componentCode ) ;
[DllImport("msi.dll", CharSet = CharSet.Auto)]
public static extern InstallState MsiGetComponentPath ( string productCode , string componentCode , StringBuilder componentPath , ref int componentPathBufferSize ) ;
public const int MaxFeatureLength = 38 ;
public const int MaxGuidLength = 38 ;
public const int MaxPathLength = 1024 ;
public enum InstallState
{
NotUsed = - 7 ,
BadConfig = - 6 ,
Incomplete = - 5 ,
SourceAbsent = - 4 ,
MoreData = - 3 ,
InvalidArg = - 2 ,
Unknown = - 1 ,
Broken = 0 ,
Advertised = 1 ,
Removed = 1 ,
Absent = 2 ,
Local = 3 ,
Source = 4 ,
Default = 5
}
2014-05-28 21:47:25 +02:00
}
}