Support auto-profile matching using both program path and application window title values. Support wildchar string match logic in auto-profile path and window title values. Re-wrote auto-profile checking thread to be less RAM hungry and better performance (caching to remember the previous application and window handle values)

This commit is contained in:
mika-n 2019-07-11 23:58:03 +03:00
parent 19a96973ff
commit e9d9e9f428
12 changed files with 947 additions and 296 deletions

View File

@ -39,12 +39,20 @@ namespace DS4Windows.Forms
protected CheckBox[] linkedProfileCB; protected CheckBox[] linkedProfileCB;
NonFormTimer hotkeysTimer = null;// new NonFormTimer(); NonFormTimer hotkeysTimer = null;// new NonFormTimer();
NonFormTimer autoProfilesTimer = null;// new NonFormTimer(); NonFormTimer autoProfilesTimer = null;// new NonFormTimer();
string tempProfileProgram = string.Empty;
double dpix, dpiy; double dpix, dpiy;
List<ProgramPathItem> programpaths = new List<ProgramPathItem>();
List<string> profilenames = new List<string>(); List<string> profilenames = new List<string>();
List<string> programpaths = new List<string>();
List<string>[] proprofiles; List<string>[] proprofiles;
List<bool> turnOffTempProfiles; List<bool> turnOffTempProfiles;
ProgramPathItem tempProfileProgram = null;
public static int autoProfileDebugLogLevel = 0; // 0=Dont log debug messages about active process and window titles to GUI Log screen. 1=Show debug log messages
private static IntPtr prevForegroundWnd = IntPtr.Zero;
private static uint prevForegroundProcessID = 0;
private static string prevForegroundWndTitleName = string.Empty;
private static string prevForegroundProcessName = string.Empty;
private static StringBuilder autoProfileCheckTextBuilder = null;
private bool systemShutdown = false; private bool systemShutdown = false;
private bool wasrunning = false; private bool wasrunning = false;
@ -87,6 +95,9 @@ namespace DS4Windows.Forms
[DllImport("psapi.dll")] [DllImport("psapi.dll")]
private static extern uint GetModuleFileNameEx(IntPtr hWnd, IntPtr hModule, StringBuilder lpFileName, int nSize); private static extern uint GetModuleFileNameEx(IntPtr hWnd, IntPtr hModule, StringBuilder lpFileName, int nSize);
[DllImport("user32.dll", CharSet= CharSet.Auto)]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nSize);
public DS4Form(string[] args) public DS4Form(string[] args)
{ {
Global.FindConfigLocation(); Global.FindConfigLocation();
@ -546,20 +557,87 @@ namespace DS4Windows.Forms
} }
} }
public static string GetTopWindowName() public static bool GetTopWindowName(out string topProcessName, out string topWndTitleName, bool autoProfileTimerCheck = false)
{ {
IntPtr hWnd = GetForegroundWindow(); IntPtr hWnd = GetForegroundWindow();
uint lpdwProcessId; if (hWnd == IntPtr.Zero)
{
// Top window unknown or cannot acquire a handle. Return FALSE and return unknown process and wndTitle values
prevForegroundWnd = IntPtr.Zero;
prevForegroundProcessID = 0;
topProcessName = topWndTitleName = String.Empty;
return false;
}
//
// If this function was called from "auto-profile watcher timer" then check cached "previous hWnd handle". If the current hWnd is the same
// as during the previous check then return cached previous wnd and name values (ie. foreground app and window are assumed to be the same, so no need to re-query names).
// This should optimize the auto-profile timer check process and causes less burden to .NET GC collector because StringBuffer is not re-allocated every second.
//
// Note! hWnd handles may be re-cycled but not during the lifetime of the window. This "cache" optimization still works because when an old window is closed
// then foreground window changes to something else and the cached prevForgroundWnd variable is updated to store the new hWnd handle.
// It doesn't matter even when the previously cached handle is recycled by WinOS to represent some other window (it is no longer used as a cached value anyway).
//
if(autoProfileTimerCheck)
{
if(hWnd == prevForegroundWnd)
{
// The active window is still the same. Return cached process and wndTitle values and FALSE to indicate caller that no changes since the last call of this method
topProcessName = prevForegroundProcessName;
topWndTitleName = prevForegroundWndTitleName;
return false;
}
prevForegroundWnd = hWnd;
}
IntPtr hProcess = IntPtr.Zero;
uint lpdwProcessId = 0;
GetWindowThreadProcessId(hWnd, out lpdwProcessId); GetWindowThreadProcessId(hWnd, out lpdwProcessId);
IntPtr hProcess = OpenProcess(0x0410, false, lpdwProcessId); if (autoProfileTimerCheck)
{
if (autoProfileCheckTextBuilder == null) autoProfileCheckTextBuilder = new StringBuilder(1000);
if (lpdwProcessId == prevForegroundProcessID)
{
topProcessName = prevForegroundProcessName;
}
else
{
prevForegroundProcessID = lpdwProcessId;
hProcess = OpenProcess(0x0410, false, lpdwProcessId);
if (hProcess != IntPtr.Zero) GetModuleFileNameEx(hProcess, IntPtr.Zero, autoProfileCheckTextBuilder, autoProfileCheckTextBuilder.Capacity);
else autoProfileCheckTextBuilder.Clear();
prevForegroundProcessName = topProcessName = autoProfileCheckTextBuilder.Replace('/', '\\').ToString().ToLower();
}
GetWindowText(hWnd, autoProfileCheckTextBuilder, autoProfileCheckTextBuilder.Capacity);
prevForegroundWndTitleName = topWndTitleName = autoProfileCheckTextBuilder.ToString().ToLower();
}
else
{
// Caller function was not the autoprofile timer check thread, so create a new buffer to make this call thread safe and always query process and window title names.
// Note! At the moment DS4Win app doesn't call this method with autoProfileTimerCheck=false option, but this is here just for potential future usage.
StringBuilder text = new StringBuilder(1000); StringBuilder text = new StringBuilder(1000);
GetModuleFileNameEx(hProcess, IntPtr.Zero, text, text.Capacity);
CloseHandle(hProcess); hProcess = OpenProcess(0x0410, false, lpdwProcessId);
if (hProcess != IntPtr.Zero) GetModuleFileNameEx(hProcess, IntPtr.Zero, text, text.Capacity);
else text.Clear();
topProcessName = text.ToString();
return text.ToString(); GetWindowText(hWnd, text, text.Capacity);
topWndTitleName = text.ToString();
}
if (hProcess != IntPtr.Zero) CloseHandle(hProcess);
if(DS4Form.autoProfileDebugLogLevel > 0 )
AppLogger.LogToGui($"DEBUG: Auto-Profile. PID={lpdwProcessId} Path={topProcessName} | WND={hWnd} Title={topWndTitleName}", false);
return true;
} }
private void PowerEventArrive(object sender, EventArrivedEventArgs e) private void PowerEventArrive(object sender, EventArrivedEventArgs e)
@ -651,27 +729,63 @@ namespace DS4Windows.Forms
private void CheckAutoProfiles(object sender, EventArgs e) private void CheckAutoProfiles(object sender, EventArgs e)
{ {
string topProcessName, topWindowTitle;
string[] newProfileName = new string[4] { String.Empty, String.Empty, String.Empty, String.Empty };
bool turnOffDS4WinApp = false;
ProgramPathItem matchingProgramPathItem = null;
autoProfilesTimer.Stop(); autoProfilesTimer.Stop();
//Check for process for auto profiles if (GetTopWindowName(out topProcessName, out topWindowTitle, true))
if (string.IsNullOrEmpty(tempProfileProgram))
{ {
string windowName = GetTopWindowName().ToLower().Replace('/', '\\'); // Find a profile match based on autoprofile program path and wnd title list.
// The same program may set different profiles for each of the controllers, so we need an array of newProfileName[controllerIdx] values.
for (int i = 0, pathsLen = programpaths.Count; i < pathsLen; i++) for (int i = 0, pathsLen = programpaths.Count; i < pathsLen; i++)
{ {
string name = programpaths[i].ToLower().Replace('/', '\\'); if (programpaths[i].IsMatch(topProcessName, topWindowTitle))
if (name == windowName)
{ {
if (DS4Form.autoProfileDebugLogLevel > 0)
AppLogger.LogToGui($"DEBUG: Auto-Profile. Rule#{i+1} Path={programpaths[i].path} Title={programpaths[i].title}", false);
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{ {
if (proprofiles[j][i] != "(none)" && proprofiles[j][i] != Properties.Resources.noneProfile) if (proprofiles[j][i] != "(none)" && proprofiles[j][i] != Properties.Resources.noneProfile)
{ {
LoadTempProfile(j, proprofiles[j][i], true, Program.rootHub); // j is controller index, i is filename newProfileName[j] = proprofiles[j][i]; // j is controller index, i is filename
//if (LaunchProgram[j] != string.Empty) Process.Start(LaunchProgram[j]);
} }
} }
if (turnOffTempProfiles[i]) // Matching autoprofile rule found
turnOffDS4WinApp = turnOffTempProfiles[i];
matchingProgramPathItem = programpaths[i];
break;
}
}
if (matchingProgramPathItem != null)
{
// Program match found. Check if the new profile is different than current profile of the controller. Load the new profile only if it is not already loaded.
for (int j = 0; j < 4; j++)
{
if (newProfileName[j] != String.Empty)
{
if ((Global.useTempProfile[j] && newProfileName[j] != Global.tempprofilename[j]) || (!Global.useTempProfile[j] && newProfileName[j] != Global.ProfilePath[j]))
{
if (DS4Form.autoProfileDebugLogLevel > 0)
AppLogger.LogToGui($"DEBUG: Auto-Profile. LoadProfile Controller {j+1}={newProfileName[j]}", false);
LoadTempProfile(j, newProfileName[j], true, Program.rootHub); // j is controller index, i is filename
//if (LaunchProgram[j] != string.Empty) Process.Start(LaunchProgram[j]);
}
else
{
if (DS4Form.autoProfileDebugLogLevel > 0)
AppLogger.LogToGui($"DEBUG: Auto-Profile. LoadProfile Controller {j + 1}={newProfileName[j]} (already loaded)", false);
}
}
}
if (turnOffDS4WinApp)
{ {
turnOffTemp = true; turnOffTemp = true;
if (btnStartStop.Text == Properties.Resources.StopText) if (btnStartStop.Text == Properties.Resources.StopText)
@ -681,7 +795,8 @@ namespace DS4Windows.Forms
ChangeAutoProfilesStatus(false); ChangeAutoProfilesStatus(false);
ChangeHotkeysStatus(false); ChangeHotkeysStatus(false);
this.Invoke((System.Action)(() => { this.Invoke((System.Action)(() =>
{
this.changingService = true; this.changingService = true;
BtnStartStop_Clicked(); BtnStartStop_Clicked();
})); }));
@ -701,19 +816,23 @@ namespace DS4Windows.Forms
} }
} }
tempProfileProgram = name; tempProfileProgram = matchingProgramPathItem;
break;
} }
} else if (tempProfileProgram != null)
}
else
{ {
string windowName = GetTopWindowName().ToLower().Replace('/', '\\'); // The current active program doesn't match any of the programs in autoprofile path list.
if (tempProfileProgram != windowName) // Unload temp profile if controller is not using the default profile already.
{ tempProfileProgram = null;
tempProfileProgram = string.Empty;
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
{
if (Global.useTempProfile[j])
{
if (DS4Form.autoProfileDebugLogLevel > 0)
AppLogger.LogToGui($"DEBUG: Auto-Profile. RestoreProfile Controller {j + 1}={Global.ProfilePath[j]} (default)", false);
LoadProfile(j, false, Program.rootHub); LoadProfile(j, false, Program.rootHub);
}
}
if (turnOffTemp) if (turnOffTemp)
{ {
@ -746,18 +865,25 @@ namespace DS4Windows.Forms
doc.Load(appdatapath + "\\Auto Profiles.xml"); doc.Load(appdatapath + "\\Auto Profiles.xml");
XmlNodeList programslist = doc.SelectNodes("Programs/Program"); XmlNodeList programslist = doc.SelectNodes("Programs/Program");
foreach (XmlNode x in programslist) foreach (XmlNode x in programslist)
programpaths.Add(x.Attributes["path"].Value); programpaths.Add(new ProgramPathItem(x.Attributes["path"]?.Value, x.Attributes["title"]?.Value));
foreach (string s in programpaths) int nodeIdx=0;
foreach (ProgramPathItem pathItem in programpaths)
{ {
XmlNode item;
nodeIdx++;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
proprofiles[i].Add(doc.SelectSingleNode("/Programs/Program[@path=\"" + s + "\"]" item = doc.SelectSingleNode($"/Programs/Program[{nodeIdx}]/Controller{i+1}");
+ "/Controller" + (i + 1)).InnerText); if (item != null)
proprofiles[i].Add(item.InnerText);
else
proprofiles[i].Add("(none)");
} }
XmlNode item = doc.SelectSingleNode("/Programs/Program[@path=\"" + s + "\"]" item = doc.SelectSingleNode($"/Programs/Program[{nodeIdx}]/TurnOff");
+ "/TurnOff");
bool turnOff; bool turnOff;
if (item != null && bool.TryParse(item.InnerText, out turnOff)) if (item != null && bool.TryParse(item.InnerText, out turnOff))
turnOffTempProfiles.Add(turnOff); turnOffTempProfiles.Add(turnOff);
@ -2701,4 +2827,78 @@ Properties.Resources.DS4Update, MessageBoxButtons.YesNo, MessageBoxIcon.Question
FlashWhenLateAt = (int)Math.Round(nUDLatency.Value); FlashWhenLateAt = (int)Math.Round(nUDLatency.Value);
} }
} }
//
// Class to store autoprofile path and title data. Path and Title are pre-stored as lowercase versions (case insensitive search) to speed up IsMatch method in autoprofile timer calls.
// AutoProfile thread monitors active processes and windows. Autoprofile search rule can define just a process path or both path and window title search keywords.
// Keyword syntax: xxxx = exact matach, ^xxxx = match to beginning of path or title string. xxxx$ = match to end of string. *xxxx = contains in a string search
//
public class ProgramPathItem
{
public string path;
public string title;
private string path_lowercase;
private string title_lowercase;
public ProgramPathItem(string pathStr, string titleStr)
{
// Initialize autoprofile search keywords (xxx_tolower). To improve performance the search keyword is pre-calculated in xxx_tolower variables,
// so autoprofile timer thread doesn't have to create substrings/replace/tolower string instances every second over and over again.
if (!string.IsNullOrEmpty(pathStr))
{
path = pathStr;
path_lowercase = path.ToLower().Replace('/', '\\');
if (path.Length >= 2)
{
if (path[0] == '^') path_lowercase = path_lowercase.Substring(1);
else if (path[path.Length - 1] == '$') path_lowercase = path_lowercase.Substring(0, path_lowercase.Length - 1);
else if (path[0] == '*') path_lowercase = path_lowercase.Substring(1);
}
}
else path = path_lowercase = String.Empty;
if (!string.IsNullOrEmpty(titleStr))
{
title = titleStr;
title_lowercase = title.ToLower();
if (title.Length >= 2)
{
if (title[0] == '^') title_lowercase = title_lowercase.Substring(1);
else if (title[title.Length - 1] == '$') title_lowercase = title_lowercase.Substring(0, title_lowercase.Length - 1);
else if (title[0] == '*') title_lowercase = title_lowercase.Substring(1);
}
}
else title = title_lowercase = String.Empty;
}
public bool IsMatch(string searchPath, string searchTitle)
{
bool bPathMatched = true;
bool bTitleMwatched = true;
if (!String.IsNullOrEmpty(path_lowercase))
{
bPathMatched = (path_lowercase == searchPath
|| (path[0] == '^' && searchPath.StartsWith(path_lowercase))
|| (path[path.Length - 1] == '$' && searchPath.EndsWith(path_lowercase))
|| (path[0] == '*' && searchPath.Contains(path_lowercase))
);
}
if (bPathMatched && !String.IsNullOrEmpty(title_lowercase))
{
bTitleMwatched = (title_lowercase == searchTitle
|| (title[0] == '^' && searchTitle.StartsWith(title_lowercase))
|| (title[title.Length - 1] == '$' && searchTitle.EndsWith(title_lowercase))
|| (title[0] == '*' && searchTitle.Contains(title_lowercase))
);
}
// If both path and title defined in autoprofile entry then do AND condition (ie. both path and title should match)
return bPathMatched && bTitleMwatched;
}
}
} }

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -631,4 +631,58 @@
<data name="lbID.Text" xml:space="preserve"> <data name="lbID.Text" xml:space="preserve">
<value>ID</value> <value>ID</value>
</data> </data>
<data name="lbPad2.Text" xml:space="preserve">
<value>Ohjain 2</value>
</data>
<data name="lbPad3.Text" xml:space="preserve">
<value>Ohjain 3</value>
</data>
<data name="lbPad4.Text" xml:space="preserve">
<value>Ohjain 4</value>
</data>
<data name="discon1toolStripMenuItem.Text" xml:space="preserve">
<value>Katkaise yhteys ohjain 1</value>
</data>
<data name="discon2ToolStripMenuItem.Text" xml:space="preserve">
<value>Katkaise yhteys ohjain 2</value>
</data>
<data name="discon3ToolStripMenuItem.Text" xml:space="preserve">
<value>Katkaise yhteys ohjain 3</value>
</data>
<data name="discon4ToolStripMenuItem.Text" xml:space="preserve">
<value>Katkaise yhteys ohjain 4</value>
</data>
<data name="lbLinkProfile.Text" xml:space="preserve">
<value>Linkitä profiili/ID</value>
</data>
<data name="mintoTaskCheckBox.Text" xml:space="preserve">
<value>Minimoi tehtäväpalkkiin</value>
</data>
<data name="openProgramFolderToolStripMenuItem.Text" xml:space="preserve">
<value>Avaa ohjelmakansio</value>
</data>
<data name="label2.Text" xml:space="preserve">
<value>Portti</value>
</data>
<data name="runStartProgRadio.Text" xml:space="preserve">
<value>Ohjelmana</value>
</data>
<data name="label1.Text" xml:space="preserve">
<value>Avaustapa:</value>
</data>
<data name="ckUdpServ.Text" xml:space="preserve">
<value>UDP palvelin</value>
</data>
<data name="runStartTaskRadio.Text" xml:space="preserve">
<value>Ajoitettuna tehtävänä</value>
</data>
<data name="cBCustomSteam.Text" xml:space="preserve">
<value>Käytä vaihtoehtoista Steam-kansiota</value>
</data>
<data name="cBUseWhiteIcon.Text" xml:space="preserve">
<value>Valkoinen DS4Windows-kuvake</value>
</data>
<data name="disconToolStripMenuItem.Text" xml:space="preserve">
<value>Yhteyskatkaisun menu</value>
</data>
</root> </root>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -126,4 +126,7 @@
<data name="tBProfile.Text" xml:space="preserve"> <data name="tBProfile.Text" xml:space="preserve">
<value>&lt;Uusi nimi tähän&gt;</value> <value>&lt;Uusi nimi tähän&gt;</value>
</data> </data>
<data name="$this.Text" xml:space="preserve">
<value>Kirjoita uuden profiilin nimi</value>
</data>
</root> </root>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -640,4 +640,19 @@
<data name="tPDeadzone.Text" xml:space="preserve"> <data name="tPDeadzone.Text" xml:space="preserve">
<value>Deadzone</value> <value>Deadzone</value>
</data> </data>
<data name="lblSteeringWheelEmulationRange.Text" xml:space="preserve">
<value>Rattiohjaimen kääntösäde</value>
</data>
<data name="lblSteeringWheelEmulationAxis.Text" xml:space="preserve">
<value>Rattiohjaimen akseli</value>
</data>
<data name="lbL2TrackS.Text" xml:space="preserve">
<value>Ohjaimen lukemat</value>
</data>
<data name="btnSteeringWheelEmulationCalibrate.Text" xml:space="preserve">
<value>Kalibroi...</value>
</data>
<data name="rBTPMouse.Text" xml:space="preserve">
<value>Käytä hiirenä</value>
</data>
</root> </root>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -201,4 +201,7 @@
<data name="lbUnloadTipKey.Text" xml:space="preserve"> <data name="lbUnloadTipKey.Text" xml:space="preserve">
<value>Kytke pois painamalla</value> <value>Kytke pois painamalla</value>
</data> </data>
<data name="cbProfileAutoUntrigger.Text" xml:space="preserve">
<value>Poiskytkentä liipaisimen vapautuksella</value>
</data>
</root> </root>

View File

@ -31,7 +31,6 @@
this.components = new System.ComponentModel.Container(); this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(WinProgs)); System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(WinProgs));
this.bnAddPrograms = new System.Windows.Forms.Button(); this.bnAddPrograms = new System.Windows.Forms.Button();
this.lBProgramPath = new System.Windows.Forms.Label();
this.cBProfile1 = new System.Windows.Forms.ComboBox(); this.cBProfile1 = new System.Windows.Forms.ComboBox();
this.cBProfile2 = new System.Windows.Forms.ComboBox(); this.cBProfile2 = new System.Windows.Forms.ComboBox();
this.cBProfile3 = new System.Windows.Forms.ComboBox(); this.cBProfile3 = new System.Windows.Forms.ComboBox();
@ -47,6 +46,7 @@
this.lVPrograms = new System.Windows.Forms.ListView(); this.lVPrograms = new System.Windows.Forms.ListView();
this.nameHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.nameHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.PathHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.PathHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.WndTitleHeader = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.pBProfilesTip = new System.Windows.Forms.Label(); this.pBProfilesTip = new System.Windows.Forms.Label();
this.bnHideUnchecked = new System.Windows.Forms.Button(); this.bnHideUnchecked = new System.Windows.Forms.Button();
this.cMSPrograms = new System.Windows.Forms.ContextMenuStrip(this.components); this.cMSPrograms = new System.Windows.Forms.ContextMenuStrip(this.components);
@ -56,6 +56,10 @@
this.addDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.addDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.browseForOtherProgramsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.browseForOtherProgramsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.cBTurnOffDS4W = new System.Windows.Forms.CheckBox(); this.cBTurnOffDS4W = new System.Windows.Forms.CheckBox();
this.cBAutoProfileDebugLog = new System.Windows.Forms.CheckBox();
this.tBPath = new System.Windows.Forms.TextBox();
this.tBWndTitle = new System.Windows.Forms.TextBox();
this.lBDividerLine1 = new System.Windows.Forms.Label();
this.cMSPrograms.SuspendLayout(); this.cMSPrograms.SuspendLayout();
this.SuspendLayout(); this.SuspendLayout();
// //
@ -66,12 +70,6 @@
this.bnAddPrograms.UseVisualStyleBackColor = true; this.bnAddPrograms.UseVisualStyleBackColor = true;
this.bnAddPrograms.Click += new System.EventHandler(this.bnAddPrograms_Click); this.bnAddPrograms.Click += new System.EventHandler(this.bnAddPrograms_Click);
// //
// lBProgramPath
//
resources.ApplyResources(this.lBProgramPath, "lBProgramPath");
this.lBProgramPath.Name = "lBProgramPath";
this.lBProgramPath.TextChanged += new System.EventHandler(this.lBProgramPath_TextChanged);
//
// cBProfile1 // cBProfile1
// //
resources.ApplyResources(this.cBProfile1, "cBProfile1"); resources.ApplyResources(this.cBProfile1, "cBProfile1");
@ -154,7 +152,8 @@
this.lVPrograms.CheckBoxes = true; this.lVPrograms.CheckBoxes = true;
this.lVPrograms.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.lVPrograms.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.nameHeader, this.nameHeader,
this.PathHeader}); this.PathHeader,
this.WndTitleHeader});
this.lVPrograms.FullRowSelect = true; this.lVPrograms.FullRowSelect = true;
this.lVPrograms.HideSelection = false; this.lVPrograms.HideSelection = false;
this.lVPrograms.LargeImageList = this.iLIcons; this.lVPrograms.LargeImageList = this.iLIcons;
@ -164,7 +163,6 @@
this.lVPrograms.SmallImageList = this.iLIcons; this.lVPrograms.SmallImageList = this.iLIcons;
this.lVPrograms.UseCompatibleStateImageBehavior = false; this.lVPrograms.UseCompatibleStateImageBehavior = false;
this.lVPrograms.View = System.Windows.Forms.View.Details; this.lVPrograms.View = System.Windows.Forms.View.Details;
this.lVPrograms.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.listView1_ItemCheck);
this.lVPrograms.SelectedIndexChanged += new System.EventHandler(this.lBProgramPath_SelectedIndexChanged); this.lVPrograms.SelectedIndexChanged += new System.EventHandler(this.lBProgramPath_SelectedIndexChanged);
// //
// nameHeader // nameHeader
@ -175,6 +173,10 @@
// //
resources.ApplyResources(this.PathHeader, "PathHeader"); resources.ApplyResources(this.PathHeader, "PathHeader");
// //
// WndTitleHeader
//
resources.ApplyResources(this.WndTitleHeader, "WndTitleHeader");
//
// pBProfilesTip // pBProfilesTip
// //
resources.ApplyResources(this.pBProfilesTip, "pBProfilesTip"); resources.ApplyResources(this.pBProfilesTip, "pBProfilesTip");
@ -239,13 +241,42 @@
this.cBTurnOffDS4W.UseVisualStyleBackColor = true; this.cBTurnOffDS4W.UseVisualStyleBackColor = true;
this.cBTurnOffDS4W.CheckedChanged += new System.EventHandler(this.cBTurnOffDS4W_CheckedChanged); this.cBTurnOffDS4W.CheckedChanged += new System.EventHandler(this.cBTurnOffDS4W_CheckedChanged);
// //
// cBAutoProfileDebugLog
//
resources.ApplyResources(this.cBAutoProfileDebugLog, "cBAutoProfileDebugLog");
this.cBAutoProfileDebugLog.Name = "cBAutoProfileDebugLog";
this.cBAutoProfileDebugLog.UseVisualStyleBackColor = true;
this.cBAutoProfileDebugLog.CheckedChanged += new System.EventHandler(this.cBAutoProfileDebugLog_CheckedChanged);
//
// tBPath
//
resources.ApplyResources(this.tBPath, "tBPath");
this.tBPath.Name = "tBPath";
this.tBPath.TextChanged += new System.EventHandler(this.tBPath_TextChanged);
//
// tBWndTitle
//
resources.ApplyResources(this.tBWndTitle, "tBWndTitle");
this.tBWndTitle.Name = "tBWndTitle";
this.tBWndTitle.TextChanged += new System.EventHandler(this.tBPath_TextChanged);
//
// lBDividerLine1
//
resources.ApplyResources(this.lBDividerLine1, "lBDividerLine1");
this.lBDividerLine1.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.lBDividerLine1.Name = "lBDividerLine1";
//
// WinProgs // WinProgs
// //
resources.ApplyResources(this, "$this"); resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.Control; this.BackColor = System.Drawing.SystemColors.Control;
this.Controls.Add(this.cBTurnOffDS4W);
this.Controls.Add(this.pBProfilesTip); this.Controls.Add(this.pBProfilesTip);
this.Controls.Add(this.lBDividerLine1);
this.Controls.Add(this.tBWndTitle);
this.Controls.Add(this.tBPath);
this.Controls.Add(this.cBAutoProfileDebugLog);
this.Controls.Add(this.cBTurnOffDS4W);
this.Controls.Add(this.bnHideUnchecked); this.Controls.Add(this.bnHideUnchecked);
this.Controls.Add(this.bnAddPrograms); this.Controls.Add(this.bnAddPrograms);
this.Controls.Add(this.lVPrograms); this.Controls.Add(this.lVPrograms);
@ -257,7 +288,6 @@
this.Controls.Add(this.cBProfile3); this.Controls.Add(this.cBProfile3);
this.Controls.Add(this.cBProfile2); this.Controls.Add(this.cBProfile2);
this.Controls.Add(this.cBProfile1); this.Controls.Add(this.cBProfile1);
this.Controls.Add(this.lBProgramPath);
this.Controls.Add(this.bnDelete); this.Controls.Add(this.bnDelete);
this.Controls.Add(this.bnSave); this.Controls.Add(this.bnSave);
this.Name = "WinProgs"; this.Name = "WinProgs";
@ -270,7 +300,6 @@
#endregion #endregion
private System.Windows.Forms.Button bnAddPrograms; private System.Windows.Forms.Button bnAddPrograms;
private System.Windows.Forms.Label lBProgramPath;
private System.Windows.Forms.ComboBox cBProfile1; private System.Windows.Forms.ComboBox cBProfile1;
private System.Windows.Forms.ComboBox cBProfile2; private System.Windows.Forms.ComboBox cBProfile2;
private System.Windows.Forms.ComboBox cBProfile3; private System.Windows.Forms.ComboBox cBProfile3;
@ -295,5 +324,10 @@
private System.Windows.Forms.ToolStripMenuItem browseForOtherProgramsToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem browseForOtherProgramsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem addDirectoryToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem addDirectoryToolStripMenuItem;
private System.Windows.Forms.CheckBox cBTurnOffDS4W; private System.Windows.Forms.CheckBox cBTurnOffDS4W;
private System.Windows.Forms.CheckBox cBAutoProfileDebugLog;
private System.Windows.Forms.ColumnHeader WndTitleHeader;
private System.Windows.Forms.TextBox tBPath;
private System.Windows.Forms.TextBox tBWndTitle;
private System.Windows.Forms.Label lBDividerLine1;
} }
} }

View File

@ -16,14 +16,13 @@ namespace DS4Windows.Forms
{ {
public partial class WinProgs : Form public partial class WinProgs : Form
{ {
ToolTip tp = new ToolTip();
ComboBox[] cbs; ComboBox[] cbs;
public DS4Form form; public DS4Form form;
//C:\ProgramData\Microsoft\Windows\Start Menu\Programs //C:\ProgramData\Microsoft\Windows\Start Menu\Programs
string steamgamesdir, origingamesdir; string steamgamesdir, origingamesdir;
protected String m_Profile = Global.appdatapath + "\\Auto Profiles.xml"; protected String m_Profile = Global.appdatapath + "\\Auto Profiles.xml";
protected XmlDocument m_Xdoc = new XmlDocument();
List<string> programpaths = new List<string>(); ProgramPathItem selectedProgramPathItem = null;
List<string> lodsf = new List<string>(); List<string> lodsf = new List<string>();
bool appsloaded = false; bool appsloaded = false;
public const string steamCommx86Loc = @"C:\Program Files (x86)\Steam\steamapps\common"; public const string steamCommx86Loc = @"C:\Program Files (x86)\Steam\steamapps\common";
@ -33,7 +32,9 @@ namespace DS4Windows.Forms
public WinProgs(string[] oc, DS4Form main) public WinProgs(string[] oc, DS4Form main)
{ {
ToolTip tp = new ToolTip();
InitializeComponent(); InitializeComponent();
openProgram.Filter = Properties.Resources.Programs+"|*.exe|" + Properties.Resources.Shortcuts + "|*.lnk"; openProgram.Filter = Properties.Resources.Programs+"|*.exe|" + Properties.Resources.Shortcuts + "|*.lnk";
form = main; form = main;
cbs = new ComboBox[4] { cBProfile1, cBProfile2, cBProfile3, cBProfile4 }; cbs = new ComboBox[4] { cBProfile1, cBProfile2, cBProfile3, cBProfile4 };
@ -44,6 +45,10 @@ namespace DS4Windows.Forms
cbs[i].SelectedIndex = cbs[i].Items.Count - 1; cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
} }
tp.SetToolTip(cBAutoProfileDebugLog, Properties.Resources.ShowAutoProfileDebugLogTip);
tp.SetToolTip(tBPath, Properties.Resources.AutoProfilePathAndWindowTitleEditTip);
tp.SetToolTip(tBWndTitle, Properties.Resources.AutoProfilePathAndWindowTitleEditTip);
if (!File.Exists(Global.appdatapath + @"\Auto Profiles.xml")) if (!File.Exists(Global.appdatapath + @"\Auto Profiles.xml"))
Create(); Create();
@ -64,6 +69,10 @@ namespace DS4Windows.Forms
origingamesdir = originLoc; origingamesdir = originLoc;
else else
cMSPrograms.Items.Remove(addOriginGamesToolStripMenuItem); cMSPrograms.Items.Remove(addOriginGamesToolStripMenuItem);
cBAutoProfileDebugLog.Checked = (DS4Form.autoProfileDebugLogLevel > 0);
selectedProgramPathItem = null;
UpdateProfileComboListValues(null);
} }
public bool Create() public bool Create()
@ -73,19 +82,20 @@ namespace DS4Windows.Forms
try try
{ {
XmlNode Node; XmlNode Node;
XmlDocument doc = new XmlDocument();
Node = m_Xdoc.CreateXmlDeclaration("1.0", "utf-8", String.Empty); Node = doc.CreateXmlDeclaration("1.0", "utf-8", String.Empty);
m_Xdoc.AppendChild(Node); doc.AppendChild(Node);
Node = m_Xdoc.CreateComment(String.Format(" Auto-Profile Configuration Data. {0} ", DateTime.Now)); Node = doc.CreateComment(String.Format(" Auto-Profile Configuration Data. {0} ", DateTime.Now));
m_Xdoc.AppendChild(Node); doc.AppendChild(Node);
Node = m_Xdoc.CreateWhitespace("\r\n"); Node = doc.CreateWhitespace("\r\n");
m_Xdoc.AppendChild(Node); doc.AppendChild(Node);
Node = m_Xdoc.CreateNode(XmlNodeType.Element, "Programs", ""); Node = doc.CreateNode(XmlNodeType.Element, "Programs", "");
m_Xdoc.AppendChild(Node); doc.AppendChild(Node);
m_Xdoc.Save(m_Profile); doc.Save(m_Profile);
} }
catch { Saved = false; } catch { Saved = false; }
@ -100,40 +110,61 @@ namespace DS4Windows.Forms
} }
public void LoadP() public void LoadP()
{
try
{ {
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
programpaths.Clear();
iLIcons.Images.Clear();
if (!File.Exists(Global.appdatapath + "\\Auto Profiles.xml")) if (!File.Exists(Global.appdatapath + "\\Auto Profiles.xml"))
return; return;
doc.Load(Global.appdatapath + "\\Auto Profiles.xml"); doc.Load(Global.appdatapath + "\\Auto Profiles.xml");
XmlNodeList programslist = doc.SelectNodes("Programs/Program"); XmlNodeList programslist = doc.SelectNodes("Programs/Program");
foreach (XmlNode x in programslist)
programpaths.Add(x.Attributes["path"].Value); int index;
ListViewItem lvi;
string progPath, progTitle;
lVPrograms.BeginUpdate(); lVPrograms.BeginUpdate();
int index = 0; foreach (XmlNode progNode in programslist)
foreach (string st in programpaths)
{ {
if (!string.IsNullOrEmpty(st)) progPath = progNode.Attributes["path"]?.Value;
progTitle = progNode.Attributes["title"]?.Value;
if (!string.IsNullOrEmpty(progPath))
{ {
if (File.Exists(st)) index = iLIcons.Images.IndexOfKey(progPath);
if (index < 0 && File.Exists(progPath))
{ {
iLIcons.Images.Add(Icon.ExtractAssociatedIcon(st)); iLIcons.Images.Add(progPath, Icon.ExtractAssociatedIcon(progPath));
index = iLIcons.Images.Count - 1;
} }
ListViewItem lvi = new ListViewItem(Path.GetFileNameWithoutExtension(st), index); if(index >= 0)
lvi = new ListViewItem(Path.GetFileNameWithoutExtension(progPath), index);
else
lvi = new ListViewItem(Path.GetFileNameWithoutExtension(progPath));
lvi.Checked = true; lvi.Checked = true;
lvi.ToolTipText = st; lvi.SubItems.Add(progPath);
lvi.SubItems.Add(st); if (!String.IsNullOrEmpty(progTitle))
lvi.SubItems.Add(progTitle);
lVPrograms.Items.Add(lvi); lVPrograms.Items.Add(lvi);
} }
index++;
} }
}
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(); lVPrograms.EndUpdate();
} }
}
private void GetApps(string path) private void GetApps(string path)
{ {
@ -179,11 +210,16 @@ namespace DS4Windows.Forms
appsloaded = true; appsloaded = true;
} }
void AddLoadedApps() int AddLoadedApps(bool autoremoveSetupApps = true)
{ {
int numOfAppsAdded = 0;
if (appsloaded) if (appsloaded)
{ {
bnAddPrograms.Text = Properties.Resources.AddingToList; bnAddPrograms.Text = Properties.Resources.AddingToList;
if (autoremoveSetupApps)
{
for (int i = lodsf.Count - 1; i >= 0; i--) for (int i = lodsf.Count - 1; i >= 0; i--)
{ {
if (lodsf[i].Contains("etup") || lodsf[i].Contains("dotnet") || lodsf[i].Contains("SETUP") if (lodsf[i].Contains("etup") || lodsf[i].Contains("dotnet") || lodsf[i].Contains("SETUP")
@ -191,28 +227,56 @@ namespace DS4Windows.Forms
lodsf.RemoveAt(i); lodsf.RemoveAt(i);
} }
// 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 i = lodsf.Count - 1; i >= 0; i--)
{ {
for (int j = programpaths.Count - 1; j >= 0; j--) for (int j = 0; j < lVPrograms.Items.Count; j++)
{
if(string.Equals(lVPrograms.Items[j].SubItems[1].Text, lodsf[i], StringComparison.OrdinalIgnoreCase))
{ {
if (lodsf[i].ToLower().Replace('/', '\\') == programpaths[j].ToLower().Replace('/', '\\'))
lodsf.RemoveAt(i); lodsf.RemoveAt(i);
break;
} }
} }
}
}
try
{
ListViewItem lvi;
int index;
lVPrograms.BeginUpdate(); lVPrograms.BeginUpdate();
foreach (string st in lodsf) foreach (string st in lodsf)
{ {
if (File.Exists(st)) if (File.Exists(st))
{ {
int index = programpaths.IndexOf(st); index = iLIcons.Images.IndexOfKey(st);
iLIcons.Images.Add(Icon.ExtractAssociatedIcon(st)); if (index < 0)
ListViewItem lvi = new ListViewItem(Path.GetFileNameWithoutExtension(st), iLIcons.Images.Count + index); {
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.SubItems.Add(st);
lvi.ToolTipText = st; lvi.ToolTipText = st;
lVPrograms.Items.Add(lvi); lVPrograms.Items.Add(lvi);
numOfAppsAdded++;
} }
} }
}
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(); lVPrograms.EndUpdate();
bnAddPrograms.Text = Properties.Resources.AddPrograms; bnAddPrograms.Text = Properties.Resources.AddPrograms;
@ -221,61 +285,127 @@ namespace DS4Windows.Forms
} }
} }
public void Save(string name) return numOfAppsAdded;
}
private XmlNode FindProgramXMLItem(XmlDocument doc, string programPath, string windowTitle)
{ {
m_Xdoc.Load(m_Profile); // 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;
}
public void Save(ProgramPathItem progPathItem)
{
XmlDocument doc = new XmlDocument();
XmlNode Node; XmlNode Node;
string newPath, newTitle;
Node = m_Xdoc.CreateComment(String.Format(" Auto-Profile Configuration Data. {0} ", DateTime.Now)); newPath = tBPath.Text.Trim();
foreach (XmlNode node in m_Xdoc.SelectNodes("//comment()")) newTitle = tBWndTitle.Text;
node.ParentNode.ReplaceChild(Node, node);
Node = m_Xdoc.SelectSingleNode("Programs"); if (progPathItem == null || String.IsNullOrEmpty(progPathItem.path) || String.IsNullOrEmpty(newPath))
string programname; return;
programname = Path.GetFileNameWithoutExtension(name);
XmlElement el = m_Xdoc.CreateElement("Program");
el.SetAttribute("path", name);
el.AppendChild(m_Xdoc.CreateElement("Controller1")).InnerText = cBProfile1.Text;
el.AppendChild(m_Xdoc.CreateElement("Controller2")).InnerText = cBProfile2.Text;
el.AppendChild(m_Xdoc.CreateElement("Controller3")).InnerText = cBProfile3.Text;
el.AppendChild(m_Xdoc.CreateElement("Controller4")).InnerText = cBProfile4.Text;
el.AppendChild(m_Xdoc.CreateElement("TurnOff")).InnerText = cBTurnOffDS4W.Checked.ToString();
try try
{ {
XmlNode oldxmlprocess = m_Xdoc.SelectSingleNode("/Programs/Program[@path=\"" + lBProgramPath.Text + "\"]"); doc.Load(m_Profile);
Node.ReplaceChild(el, oldxmlprocess); Node = doc.CreateComment(String.Format(" Auto-Profile Configuration Data. {0} ", DateTime.Now));
} foreach (XmlNode node in doc.SelectNodes("//comment()"))
catch { Node.AppendChild(el); } node.ParentNode.ReplaceChild(Node, node);
m_Xdoc.AppendChild(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)
m_Xdoc.Save(m_Profile); 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);
doc.AppendChild(Node);
doc.Save(m_Profile);
if(selectedProgramPathItem != null)
{
selectedProgramPathItem.path = newPath;
selectedProgramPathItem.title = newTitle;
}
if (lVPrograms.SelectedItems.Count > 0) if (lVPrograms.SelectedItems.Count > 0)
{
lVPrograms.SelectedItems[0].Checked = true; 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;
if (!String.IsNullOrEmpty(newTitle))
lVPrograms.SelectedItems[0].ToolTipText = $"{newPath} [{newTitle}]";
else
lVPrograms.SelectedItems[0].ToolTipText = newPath;
}
form.LoadP(); 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);
}
}
public void LoadP(string name) public void LoadP(ProgramPathItem loadProgPathItem)
{
if (loadProgPathItem == null)
return;
try
{ {
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.Load(m_Profile); doc.Load(m_Profile);
XmlNodeList programs = doc.SelectNodes("Programs/Program");
XmlNode Item = doc.SelectSingleNode("/Programs/Program[@path=\"" + name + "\"]"); XmlNode programItem = FindProgramXMLItem(doc, loadProgPathItem.path, loadProgPathItem.title);
if (Item != null) if (programItem != null)
{ {
XmlNode profileItem;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
Item = doc.SelectSingleNode("/Programs/Program[@path=\"" + name + "\"]" + "/Controller" + (i + 1)); profileItem = programItem.SelectSingleNode($".//Controller{i + 1}");
if (Item != null) if (profileItem != null)
{ {
for (int j = 0; j < cbs[i].Items.Count; j++) for (int j = 0; j < cbs[i].Items.Count; j++)
{ {
if (cbs[i].Items[j].ToString() == Item.InnerText) if (cbs[i].Items[j].ToString() == profileItem.InnerText)
{ {
cbs[i].SelectedIndex = j; cbs[i].SelectedIndex = j;
bnSave.Enabled = false;
break; break;
} }
else else
@ -286,61 +416,108 @@ namespace DS4Windows.Forms
cbs[i].SelectedIndex = cbs[i].Items.Count - 1; cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
} }
Item = doc.SelectSingleNode("/Programs/Program[@path=\"" + name + "\"]" + "/TurnOff");
bool turnOff; bool turnOff;
if (Item != null && bool.TryParse(Item.InnerText, out turnOff)) profileItem = programItem.SelectSingleNode($".//TurnOff");
if (profileItem != null && bool.TryParse(profileItem.InnerText, out turnOff))
{ {
cBTurnOffDS4W.Checked = turnOff; cBTurnOffDS4W.Checked = turnOff;
} }
else else
cBTurnOffDS4W.Checked = false; cBTurnOffDS4W.Checked = false;
} }
else
{
for (int i = 0; i < 4; i++)
cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
cBTurnOffDS4W.Checked = false; 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; bnSave.Enabled = false;
} }
}
public void RemoveP(string name, bool uncheck) public void RemoveP(ProgramPathItem removeProgPathItem, bool uncheck)
{
bnSave.Enabled = false;
if (removeProgPathItem == null)
return;
try
{ {
XmlDocument doc = new XmlDocument(); XmlDocument doc = new XmlDocument();
doc.Load(m_Profile); doc.Load(m_Profile);
XmlNode Node = doc.SelectSingleNode("Programs");
XmlNode Item = doc.SelectSingleNode("/Programs/Program[@path=\"" + name + "\"]");
if (Item != null)
Node.RemoveChild(Item);
doc.AppendChild(Node); XmlNode programItem = FindProgramXMLItem(doc, removeProgPathItem.path, removeProgPathItem.title);
if (programItem != null)
{
XmlNode parentNode = programItem.ParentNode;
if (parentNode != null)
{
parentNode.RemoveChild(programItem);
doc.AppendChild(parentNode);
doc.Save(m_Profile); doc.Save(m_Profile);
}
}
if (lVPrograms.SelectedItems.Count > 0 && uncheck) if (lVPrograms.SelectedItems.Count > 0 && uncheck)
lVPrograms.SelectedItems[0].Checked = false; lVPrograms.SelectedItems[0].Checked = false;
}
catch (Exception e)
{
// 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);
}
UpdateProfileComboListValues(null);
}
private void UpdateProfileComboListValues(ProgramPathItem progItem)
{
if (progItem != null)
{
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
cbs[i].SelectedIndex = cbs[i].Items.Count - 1; cbs[i].Enabled = true;
bnSave.Enabled = false; tBPath.Enabled = tBWndTitle.Enabled = cBTurnOffDS4W.Enabled = true;
LoadP(progItem);
bnDelete.Enabled = true;
}
else
{
int last = cbs[0].Items.Count - 1;
// 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;
}
bnSave.Enabled = bnDelete.Enabled = false;
tBPath.Enabled = tBWndTitle.Enabled = cBTurnOffDS4W.Enabled = false;
tBPath.Text = tBWndTitle.Text = "";
cBTurnOffDS4W.Checked = false;
}
} }
private void CBProfile_IndexChanged(object sender, EventArgs e) private void CBProfile_IndexChanged(object sender, EventArgs e)
{ {
int last = cbs[0].Items.Count - 1; if (selectedProgramPathItem != null && lVPrograms.SelectedItems.Count > 0)
if (lBProgramPath.Text != string.Empty)
bnSave.Enabled = true; bnSave.Enabled = true;
if (cbs[0].SelectedIndex == last && cbs[1].SelectedIndex == last &&
cbs[2].SelectedIndex == last && cbs[3].SelectedIndex == last && !cBTurnOffDS4W.Checked)
bnSave.Enabled = false;
} }
private void bnSave_Click(object sender, EventArgs e) private void bnSave_Click(object sender, EventArgs e)
{ {
if (lBProgramPath.Text != "") if (selectedProgramPathItem != null)
Save(lBProgramPath.Text); {
// 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;
Save(selectedProgramPathItem);
}
bnSave.Enabled = false; bnSave.Enabled = false;
} }
@ -349,41 +526,48 @@ namespace DS4Windows.Forms
cMSPrograms.Show(bnAddPrograms, new Point(0, bnAddPrograms.Height)); cMSPrograms.Show(bnAddPrograms, new Point(0, bnAddPrograms.Height));
} }
private void lBProgramPath_TextChanged(object sender, EventArgs e)
{
if (lBProgramPath.Text != "")
LoadP(lBProgramPath.Text);
else
{
for (int i = 0; i < 4; i++)
cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
}
}
private void bnDelete_Click(object sender, EventArgs e) private void bnDelete_Click(object sender, EventArgs e)
{ {
RemoveP(lBProgramPath.Text, true); RemoveP(selectedProgramPathItem, true);
selectedProgramPathItem = null;
bnSave.Enabled = bnDelete.Enabled = false;
if (lVPrograms.SelectedItems.Count > 0)
lVPrograms.SelectedItems[0].Selected = lVPrograms.SelectedItems[0].Focused = false;
} }
private void lBProgramPath_SelectedIndexChanged(object sender, EventArgs e) private void lBProgramPath_SelectedIndexChanged(object sender, EventArgs e)
{ {
if (lVPrograms.SelectedItems.Count > 0) if (lVPrograms.SelectedItems.Count > 0 && lVPrograms.SelectedIndices[0] > -1)
{ {
if (lVPrograms.SelectedIndices[0] > -1) if (selectedProgramPathItem == null) selectedProgramPathItem = new ProgramPathItem(String.Empty, String.Empty);
lBProgramPath.Text = lVPrograms.SelectedItems[0].SubItems[1].Text;
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);
} }
else else
lBProgramPath.Text = "";
}
private void listView1_ItemCheck(object sender, ItemCheckEventArgs e)
{ {
if (lVPrograms.Items[e.Index].Checked) selectedProgramPathItem = null;
RemoveP(lVPrograms.Items[e.Index].SubItems[1].Text, false); UpdateProfileComboListValues(null);
}
} }
private void bnHideUnchecked_Click(object sender, EventArgs e) private void bnHideUnchecked_Click(object sender, EventArgs e)
{ {
// 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;
form.RefreshAutoProfilesPage(); form.RefreshAutoProfilesPage();
} }
@ -418,11 +602,18 @@ namespace DS4Windows.Forms
file = GetTargetPath(file); file = GetTargetPath(file);
} }
lBProgramPath.Text = file; if (lVPrograms.SelectedItems.Count > 0)
iLIcons.Images.Add(Icon.ExtractAssociatedIcon(file)); lVPrograms.SelectedItems[0].Selected = lVPrograms.SelectedItems[0].Focused = false;
ListViewItem lvi = new ListViewItem(Path.GetFileNameWithoutExtension(file), lVPrograms.Items.Count);
lvi.SubItems.Add(file); lodsf.Clear();
lVPrograms.Items.Insert(0, lvi); 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;
}
} }
} }
@ -534,6 +725,22 @@ namespace DS4Windows.Forms
CBProfile_IndexChanged(sender, e); CBProfile_IndexChanged(sender, e);
} }
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;
}
}
public static string ResolveMsiShortcut(string file) public static string ResolveMsiShortcut(string file)
{ {
StringBuilder product = new StringBuilder(NativeMethods2.MaxGuidLength + 1); StringBuilder product = new StringBuilder(NativeMethods2.MaxGuidLength + 1);

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
@ -165,4 +165,16 @@
<data name="pBProfilesTip.Text" xml:space="preserve"> <data name="pBProfilesTip.Text" xml:space="preserve">
<value>Valitse profiilit tästä</value> <value>Valitse profiilit tästä</value>
</data> </data>
<data name="WndTitleHeader.Text" xml:space="preserve">
<value>Ikkunan otsikko</value>
</data>
<data name="cBTurnOffDS4W.Text" xml:space="preserve">
<value>Pysäytä DS4Windows väliaikaisesti</value>
</data>
<data name="cBAutoProfileDebugLog.Text" xml:space="preserve">
<value>Näytä auto-profiilien virheseurannan viestit</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>Auto-Profiilit</value>
</data>
</root> </root>

View File

@ -141,36 +141,9 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;bnAddPrograms.ZOrder" xml:space="preserve"> <data name="&gt;&gt;bnAddPrograms.ZOrder" xml:space="preserve">
<value>4</value> <value>8</value>
</data> </data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="lBProgramPath.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="lBProgramPath.Location" type="System.Drawing.Point, System.Drawing">
<value>519, 195</value>
</data>
<data name="lBProgramPath.Size" type="System.Drawing.Size, System.Drawing">
<value>205, 18</value>
</data>
<data name="lBProgramPath.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="lBProgramPath.Visible" type="System.Boolean, mscorlib">
<value>False</value>
</data>
<data name="&gt;&gt;lBProgramPath.Name" xml:space="preserve">
<value>lBProgramPath</value>
</data>
<data name="&gt;&gt;lBProgramPath.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;lBProgramPath.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;lBProgramPath.ZOrder" xml:space="preserve">
<value>14</value>
</data>
<data name="cBProfile1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="cBProfile1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
</data> </data>
@ -193,7 +166,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;cBProfile1.ZOrder" xml:space="preserve"> <data name="&gt;&gt;cBProfile1.ZOrder" xml:space="preserve">
<value>13</value> <value>17</value>
</data> </data>
<data name="cBProfile2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="cBProfile2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -217,7 +190,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;cBProfile2.ZOrder" xml:space="preserve"> <data name="&gt;&gt;cBProfile2.ZOrder" xml:space="preserve">
<value>12</value> <value>16</value>
</data> </data>
<data name="cBProfile3.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="cBProfile3.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -241,7 +214,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;cBProfile3.ZOrder" xml:space="preserve"> <data name="&gt;&gt;cBProfile3.ZOrder" xml:space="preserve">
<value>11</value> <value>15</value>
</data> </data>
<data name="cBProfile4.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="cBProfile4.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -265,7 +238,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;cBProfile4.ZOrder" xml:space="preserve"> <data name="&gt;&gt;cBProfile4.ZOrder" xml:space="preserve">
<value>10</value> <value>14</value>
</data> </data>
<data name="bnSave.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="bnSave.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -295,7 +268,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;bnSave.ZOrder" xml:space="preserve"> <data name="&gt;&gt;bnSave.ZOrder" xml:space="preserve">
<value>16</value> <value>19</value>
</data> </data>
<data name="lBController1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="lBController1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -325,7 +298,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;lBController1.ZOrder" xml:space="preserve"> <data name="&gt;&gt;lBController1.ZOrder" xml:space="preserve">
<value>9</value> <value>13</value>
</data> </data>
<data name="lBController2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="lBController2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -355,7 +328,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;lBController2.ZOrder" xml:space="preserve"> <data name="&gt;&gt;lBController2.ZOrder" xml:space="preserve">
<value>8</value> <value>12</value>
</data> </data>
<data name="lBController3.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="lBController3.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -385,7 +358,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;lBController3.ZOrder" xml:space="preserve"> <data name="&gt;&gt;lBController3.ZOrder" xml:space="preserve">
<value>7</value> <value>11</value>
</data> </data>
<data name="lBController4.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="lBController4.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -415,7 +388,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;lBController4.ZOrder" xml:space="preserve"> <data name="&gt;&gt;lBController4.ZOrder" xml:space="preserve">
<value>6</value> <value>10</value>
</data> </data>
<metadata name="openProgram.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="openProgram.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value> <value>17, 17</value>
@ -448,7 +421,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;bnDelete.ZOrder" xml:space="preserve"> <data name="&gt;&gt;bnDelete.ZOrder" xml:space="preserve">
<value>15</value> <value>18</value>
</data> </data>
<metadata name="iLIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="iLIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>143, 17</value> <value>143, 17</value>
@ -469,13 +442,19 @@
<value>Path</value> <value>Path</value>
</data> </data>
<data name="PathHeader.Width" type="System.Int32, mscorlib"> <data name="PathHeader.Width" type="System.Int32, mscorlib">
<value>358</value> <value>400</value>
</data>
<data name="WndTitleHeader.Text" xml:space="preserve">
<value>Window Title</value>
</data>
<data name="WndTitleHeader.Width" type="System.Int32, mscorlib">
<value>140</value>
</data> </data>
<data name="lVPrograms.Location" type="System.Drawing.Point, System.Drawing"> <data name="lVPrograms.Location" type="System.Drawing.Point, System.Drawing">
<value>5, 28</value> <value>5, 28</value>
</data> </data>
<data name="lVPrograms.Size" type="System.Drawing.Size, System.Drawing"> <data name="lVPrograms.Size" type="System.Drawing.Size, System.Drawing">
<value>505, 190</value> <value>505, 261</value>
</data> </data>
<data name="lVPrograms.TabIndex" type="System.Int32, mscorlib"> <data name="lVPrograms.TabIndex" type="System.Int32, mscorlib">
<value>12</value> <value>12</value>
@ -490,7 +469,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;lVPrograms.ZOrder" xml:space="preserve"> <data name="&gt;&gt;lVPrograms.ZOrder" xml:space="preserve">
<value>5</value> <value>9</value>
</data> </data>
<data name="pBProfilesTip.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms"> <data name="pBProfilesTip.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value> <value>Top, Right</value>
@ -520,7 +499,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;pBProfilesTip.ZOrder" xml:space="preserve"> <data name="&gt;&gt;pBProfilesTip.ZOrder" xml:space="preserve">
<value>2</value> <value>1</value>
</data> </data>
<data name="bnHideUnchecked.Location" type="System.Drawing.Point, System.Drawing"> <data name="bnHideUnchecked.Location" type="System.Drawing.Point, System.Drawing">
<value>99, 2</value> <value>99, 2</value>
@ -544,7 +523,7 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;bnHideUnchecked.ZOrder" xml:space="preserve"> <data name="&gt;&gt;bnHideUnchecked.ZOrder" xml:space="preserve">
<value>3</value> <value>7</value>
</data> </data>
<metadata name="cMSPrograms.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"> <metadata name="cMSPrograms.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>232, 17</value> <value>232, 17</value>
@ -592,13 +571,13 @@
<value>Top, Right</value> <value>Top, Right</value>
</data> </data>
<data name="cBTurnOffDS4W.Location" type="System.Drawing.Point, System.Drawing"> <data name="cBTurnOffDS4W.Location" type="System.Drawing.Point, System.Drawing">
<value>514, 152</value> <value>514, 151</value>
</data> </data>
<data name="cBTurnOffDS4W.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms"> <data name="cBTurnOffDS4W.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>2, 2, 2, 2</value> <value>2, 2, 2, 2</value>
</data> </data>
<data name="cBTurnOffDS4W.Size" type="System.Drawing.Size, System.Drawing"> <data name="cBTurnOffDS4W.Size" type="System.Drawing.Size, System.Drawing">
<value>215, 41</value> <value>215, 24</value>
</data> </data>
<data name="cBTurnOffDS4W.TabIndex" type="System.Int32, mscorlib"> <data name="cBTurnOffDS4W.TabIndex" type="System.Int32, mscorlib">
<value>13</value> <value>13</value>
@ -616,7 +595,109 @@
<value>$this</value> <value>$this</value>
</data> </data>
<data name="&gt;&gt;cBTurnOffDS4W.ZOrder" xml:space="preserve"> <data name="&gt;&gt;cBTurnOffDS4W.ZOrder" xml:space="preserve">
<value>1</value> <value>6</value>
</data>
<data name="cBAutoProfileDebugLog.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="cBAutoProfileDebugLog.Location" type="System.Drawing.Point, System.Drawing">
<value>514, 255</value>
</data>
<data name="cBAutoProfileDebugLog.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>2, 2, 2, 2</value>
</data>
<data name="cBAutoProfileDebugLog.Size" type="System.Drawing.Size, System.Drawing">
<value>215, 20</value>
</data>
<data name="cBAutoProfileDebugLog.TabIndex" type="System.Int32, mscorlib">
<value>14</value>
</data>
<data name="cBAutoProfileDebugLog.Text" xml:space="preserve">
<value>Show auto-profile debug messages</value>
</data>
<data name="&gt;&gt;cBAutoProfileDebugLog.Name" xml:space="preserve">
<value>cBAutoProfileDebugLog</value>
</data>
<data name="&gt;&gt;cBAutoProfileDebugLog.Type" xml:space="preserve">
<value>System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;cBAutoProfileDebugLog.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;cBAutoProfileDebugLog.ZOrder" xml:space="preserve">
<value>5</value>
</data>
<data name="tBPath.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="tBPath.Location" type="System.Drawing.Point, System.Drawing">
<value>514, 186</value>
</data>
<data name="tBPath.Size" type="System.Drawing.Size, System.Drawing">
<value>216, 20</value>
</data>
<data name="tBPath.TabIndex" type="System.Int32, mscorlib">
<value>15</value>
</data>
<data name="&gt;&gt;tBPath.Name" xml:space="preserve">
<value>tBPath</value>
</data>
<data name="&gt;&gt;tBPath.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;tBPath.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;tBPath.ZOrder" xml:space="preserve">
<value>4</value>
</data>
<data name="tBWndTitle.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="tBWndTitle.Location" type="System.Drawing.Point, System.Drawing">
<value>514, 212</value>
</data>
<data name="tBWndTitle.Size" type="System.Drawing.Size, System.Drawing">
<value>215, 20</value>
</data>
<data name="tBWndTitle.TabIndex" type="System.Int32, mscorlib">
<value>16</value>
</data>
<data name="&gt;&gt;tBWndTitle.Name" xml:space="preserve">
<value>tBWndTitle</value>
</data>
<data name="&gt;&gt;tBWndTitle.Type" xml:space="preserve">
<value>System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;tBWndTitle.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;tBWndTitle.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="lBDividerLine1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
</data>
<data name="lBDividerLine1.Location" type="System.Drawing.Point, System.Drawing">
<value>514, 248</value>
</data>
<data name="lBDividerLine1.Size" type="System.Drawing.Size, System.Drawing">
<value>218, 5</value>
</data>
<data name="lBDividerLine1.TabIndex" type="System.Int32, mscorlib">
<value>17</value>
</data>
<data name="&gt;&gt;lBDividerLine1.Name" xml:space="preserve">
<value>lBDividerLine1</value>
</data>
<data name="&gt;&gt;lBDividerLine1.Type" xml:space="preserve">
<value>System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;lBDividerLine1.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="&gt;&gt;lBDividerLine1.ZOrder" xml:space="preserve">
<value>2</value>
</data> </data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"> <metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value> <value>True</value>
@ -625,7 +706,7 @@
<value>6, 13</value> <value>6, 13</value>
</data> </data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing"> <data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>736, 222</value> <value>736, 293</value>
</data> </data>
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms"> <data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value> <value>4, 4, 4, 4</value>
@ -657,6 +738,12 @@
<data name="&gt;&gt;PathHeader.Type" xml:space="preserve"> <data name="&gt;&gt;PathHeader.Type" xml:space="preserve">
<value>System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data> </data>
<data name="&gt;&gt;WndTitleHeader.Name" xml:space="preserve">
<value>WndTitleHeader</value>
</data>
<data name="&gt;&gt;WndTitleHeader.Type" xml:space="preserve">
<value>System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;addProgramsFromStartMenuToolStripMenuItem.Name" xml:space="preserve"> <data name="&gt;&gt;addProgramsFromStartMenuToolStripMenuItem.Name" xml:space="preserve">
<value>addProgramsFromStartMenuToolStripMenuItem</value> <value>addProgramsFromStartMenuToolStripMenuItem</value>
</data> </data>

View File

@ -154,6 +154,15 @@ namespace DS4Windows.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to ^ABC = Match at the beginning of string (^) | ABC$ = Match at the end of string ($) | *ABC =Contains a string (*).
/// </summary>
public static string AutoProfilePathAndWindowTitleEditTip {
get {
return ResourceManager.GetString("AutoProfilePathAndWindowTitleEditTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized resource of type System.Drawing.Bitmap. /// Looks up a localized resource of type System.Drawing.Bitmap.
/// </summary> /// </summary>
@ -1800,6 +1809,15 @@ namespace DS4Windows.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to If enabled then Log tab page shows detailed messages of auto-profile events..
/// </summary>
public static string ShowAutoProfileDebugLogTip {
get {
return ResourceManager.GetString("ShowAutoProfileDebugLogTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Click for advanced Sixaxis reading. /// Looks up a localized string similar to Click for advanced Sixaxis reading.
/// </summary> /// </summary>

View File

@ -603,4 +603,16 @@
<data name="UdpServer" xml:space="preserve"> <data name="UdpServer" xml:space="preserve">
<value>Aktivoi UDP palvelu. Palvelun osoite ja portti. Osoitevaihtoehdot: 127.0.0.1 paikallinen | 0.0.0.0 kaikki liittymät | Tietty palvelinnimi tai IP numero.</value> <value>Aktivoi UDP palvelu. Palvelun osoite ja portti. Osoitevaihtoehdot: 127.0.0.1 paikallinen | 0.0.0.0 kaikki liittymät | Tietty palvelinnimi tai IP numero.</value>
</data> </data>
<data name="AutoProfilePathAndWindowTitleEditTip" xml:space="preserve">
<value>^ABC = Täsmää merkkijonon alusta (^) | ABC$ = Täsmää merkkijonon lopusta ($) | *ABC = Sisältää merkkijonon.</value>
</data>
<data name="ShowAutoProfileDebugLogTip" xml:space="preserve">
<value>Näytä automaattiprofiilivalintojen tarkempia valvontaviestejä Loki-välilehdellä.</value>
</data>
<data name="OutContNotice" xml:space="preserve">
<value>Valitse virtuaaliohjaimen tyyppi (muutos tulee voimaan profiilin tallennuksen jälkeen)</value>
</data>
<data name="EnableTouchToggle" xml:space="preserve">
<value>Salli kosketuslevyhiiriohjaimen päälle-pois kytkentä PS + kosketuslevynapautuksella.</value>
</data>
</root> </root>

View File

@ -826,4 +826,10 @@
<data name="UdpServer" xml:space="preserve"> <data name="UdpServer" xml:space="preserve">
<value>Enable UDP server. Server listen address and port. Address value options: 127.0.0.1 localhost only | 0.0.0.0 all addresses | Specific host name or IP address.</value> <value>Enable UDP server. Server listen address and port. Address value options: 127.0.0.1 localhost only | 0.0.0.0 all addresses | Specific host name or IP address.</value>
</data> </data>
<data name="AutoProfilePathAndWindowTitleEditTip" xml:space="preserve">
<value>^ABC = Match at the beginning of string (^) | ABC$ = Match at the end of string ($) | *ABC =Contains a string (*)</value>
</data>
<data name="ShowAutoProfileDebugLogTip" xml:space="preserve">
<value>If enabled then Log tab page shows detailed messages of auto-profile events.</value>
</data>
</root> </root>