This commit is contained in:
mika-n 2019-07-17 23:33:39 +03:00
commit 3c6b927e1a
12 changed files with 1108 additions and 300 deletions

View File

@ -39,13 +39,21 @@ namespace DS4Windows.Forms
protected CheckBox[] linkedProfileCB;
NonFormTimer hotkeysTimer = null;// new NonFormTimer();
NonFormTimer autoProfilesTimer = null;// new NonFormTimer();
string tempProfileProgram = string.Empty;
double dpix, dpiy;
List<ProgramPathItem> programpaths = new List<ProgramPathItem>();
List<string> profilenames = new List<string>();
List<string> programpaths = new List<string>();
List<string>[] proprofiles;
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 wasrunning = false;
Options opt;
@ -59,7 +67,7 @@ namespace DS4Windows.Forms
private ManagementEventWatcher managementEvWatcher;
private DS4Forms.LanguagePackComboBox languagePackComboBox1;
private AdvancedColorDialog advColorDialog;
Dictionary<Control, string> hoverTextDict = new Dictionary<Control, string>();
Dictionary<Control, string> hoverTextDict = new Dictionary<Control, string>();
// 0 index is used for application version text. 1 - 4 indices are used for controller status
string[] notifyText = new string[5]
{ "DS4Windows v" + FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion,
@ -68,6 +76,8 @@ namespace DS4Windows.Forms
private const string UPDATER_VERSION = "1.3.1";
private const int WM_QUERYENDSESSION = 0x11;
private const int WM_CLOSE = 0x10;
public const int WM_COPYDATA = 0x004A;
internal string updaterExe = Environment.Is64BitProcess ? "DS4Updater.exe" : "DS4Updater_x86.exe";
[DllImport("user32.dll")]
@ -85,6 +95,9 @@ namespace DS4Windows.Forms
[DllImport("psapi.dll")]
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)
{
Global.FindConfigLocation();
@ -386,6 +399,8 @@ namespace DS4Windows.Forms
if (!(StartMinimized || mini))
Form_Resize(null, null);
Program.CreateIPCClassNameMMF(this.Handle);
Program.rootHub.Debug += On_Debug;
AppLogger.GuiLog += On_Debug;
@ -542,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();
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);
IntPtr hProcess = OpenProcess(0x0410, false, lpdwProcessId);
if (autoProfileTimerCheck)
{
if (autoProfileCheckTextBuilder == null) autoProfileCheckTextBuilder = new StringBuilder(1000);
StringBuilder text = new StringBuilder(1000);
GetModuleFileNameEx(hProcess, IntPtr.Zero, text, text.Capacity);
if (lpdwProcessId == prevForegroundProcessID)
{
topProcessName = prevForegroundProcessName;
}
else
{
prevForegroundProcessID = lpdwProcessId;
CloseHandle(hProcess);
hProcess = OpenProcess(0x0410, false, lpdwProcessId);
if (hProcess != IntPtr.Zero) GetModuleFileNameEx(hProcess, IntPtr.Zero, autoProfileCheckTextBuilder, autoProfileCheckTextBuilder.Capacity);
else autoProfileCheckTextBuilder.Clear();
return text.ToString();
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);
hProcess = OpenProcess(0x0410, false, lpdwProcessId);
if (hProcess != IntPtr.Zero) GetModuleFileNameEx(hProcess, IntPtr.Zero, text, text.Capacity);
else text.Clear();
topProcessName = 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)
@ -652,69 +734,110 @@ namespace DS4Windows.Forms
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();
//Check for process for auto profiles
if (string.IsNullOrEmpty(tempProfileProgram))
if (GetTopWindowName(out topProcessName, out topWindowTitle, true))
{
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++)
{
string name = programpaths[i].ToLower().Replace('/', '\\');
if (name == windowName)
if (programpaths[i].IsMatch(topProcessName, topWindowTitle))
{
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++)
{
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
//if (LaunchProgram[j] != string.Empty) Process.Start(LaunchProgram[j]);
newProfileName[j] = proprofiles[j][i]; // j is controller index, i is filename
}
}
if (turnOffTempProfiles[i])
{
turnOffTemp = true;
if (btnStartStop.Text == Properties.Resources.StopText)
{
//autoProfilesTimer.Stop();
//hotkeysTimer.Stop();
ChangeAutoProfilesStatus(false);
ChangeHotkeysStatus(false);
this.Invoke((System.Action)(() => {
this.changingService = true;
BtnStartStop_Clicked();
}));
while (this.changingService)
{
Thread.SpinWait(500);
}
this.Invoke((System.Action)(() =>
{
//hotkeysTimer.Start();
ChangeHotkeysStatus(true);
ChangeAutoProfilesStatus(true);
//autoProfilesTimer.Start();
}));
}
}
tempProfileProgram = name;
// Matching autoprofile rule found
turnOffDS4WinApp = turnOffTempProfiles[i];
matchingProgramPathItem = programpaths[i];
break;
}
}
}
else
{
string windowName = GetTopWindowName().ToLower().Replace('/', '\\');
if (tempProfileProgram != windowName)
if (matchingProgramPathItem != null)
{
tempProfileProgram = string.Empty;
// 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++)
LoadProfile(j, false, Program.rootHub);
{
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;
if (btnStartStop.Text == Properties.Resources.StopText)
{
//autoProfilesTimer.Stop();
//hotkeysTimer.Stop();
ChangeAutoProfilesStatus(false);
ChangeHotkeysStatus(false);
this.Invoke((System.Action)(() =>
{
this.changingService = true;
BtnStartStop_Clicked();
}));
while (this.changingService)
{
Thread.SpinWait(500);
}
this.Invoke((System.Action)(() =>
{
//hotkeysTimer.Start();
ChangeHotkeysStatus(true);
ChangeAutoProfilesStatus(true);
//autoProfilesTimer.Start();
}));
}
}
tempProfileProgram = matchingProgramPathItem;
}
else if (tempProfileProgram != null)
{
// The current active program doesn't match any of the programs in autoprofile path list.
// Unload temp profile if controller is not using the default profile already.
tempProfileProgram = null;
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);
}
}
if (turnOffTemp)
{
@ -747,18 +870,25 @@ namespace DS4Windows.Forms
doc.Load(appdatapath + "\\Auto Profiles.xml");
XmlNodeList programslist = doc.SelectNodes("Programs/Program");
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++)
{
proprofiles[i].Add(doc.SelectSingleNode("/Programs/Program[@path=\"" + s + "\"]"
+ "/Controller" + (i + 1)).InnerText);
item = doc.SelectSingleNode($"/Programs/Program[{nodeIdx}]/Controller{i+1}");
if (item != null)
proprofiles[i].Add(item.InnerText);
else
proprofiles[i].Add("(none)");
}
XmlNode item = doc.SelectSingleNode("/Programs/Program[@path=\"" + s + "\"]"
+ "/TurnOff");
item = doc.SelectSingleNode($"/Programs/Program[{nodeIdx}]/TurnOff");
bool turnOff;
if (item != null && bool.TryParse(item.InnerText, out turnOff))
turnOffTempProfiles.Add(turnOff);
@ -1149,6 +1279,52 @@ Properties.Resources.DS4Update, MessageBoxButtons.YesNo, MessageBoxIcon.Question
systemShutdown = true;
break;
}
case WM_COPYDATA:
{
// Received InterProcessCommunication (IPC) message. DS4Win command is embedded as a string value in lpData buffer
Program.COPYDATASTRUCT cds = (Program.COPYDATASTRUCT)m.GetLParam(typeof(Program.COPYDATASTRUCT));
if (cds.cbData >= 4 && cds.cbData <= 256)
{
int tdevice = -1;
byte[] buffer = new byte[cds.cbData];
Marshal.Copy(cds.lpData, buffer, 0, cds.cbData);
string[] strData = Encoding.ASCII.GetString(buffer).Split('.');
if (strData.Length >= 1)
{
strData[0] = strData[0].ToLower();
if (strData[0] == "start")
ServiceStartup(true);
else if (strData[0] == "stop")
ServiceShutdown(true);
else if (strData[0] == "shutdown")
ScpForm_Closing(this, new FormClosingEventArgs(CloseReason.ApplicationExitCall, false));
else if ( (strData[0] == "loadprofile" || strData[0] == "loadtempprofile") && strData.Length >= 3)
{
// Command syntax: LoadProfile.device#.profileName (fex LoadProfile.1.GameSnake or LoadTempProfile.1.WebBrowserSet)
if(int.TryParse(strData[1], out tdevice)) tdevice--;
if (tdevice >= 0 && tdevice < ControlService.DS4_CONTROLLER_COUNT && File.Exists(Global.appdatapath + "\\Profiles\\" + strData[2] + ".xml"))
{
if (strData[0] == "loadprofile")
{
ProfilePath[tdevice] = strData[2];
LoadProfile(tdevice, true, Program.rootHub);
}
else
{
LoadTempProfile(tdevice, strData[2], true, Program.rootHub);
}
Program.rootHub.LogDebug(Properties.Resources.UsingProfile.Replace("*number*", (tdevice + 1).ToString()).Replace("*Profile name*", strData[2]));
}
}
}
}
break;
}
default: break;
}
@ -2663,4 +2839,78 @@ Properties.Resources.DS4Update, MessageBoxButtons.YesNo, MessageBoxIcon.Question
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>
<!--
Microsoft ResX Schema
@ -631,4 +631,58 @@
<data name="lbID.Text" xml:space="preserve">
<value>ID</value>
</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>

View File

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

View File

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

View File

@ -31,7 +31,6 @@
this.components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(WinProgs));
this.bnAddPrograms = new System.Windows.Forms.Button();
this.lBProgramPath = new System.Windows.Forms.Label();
this.cBProfile1 = new System.Windows.Forms.ComboBox();
this.cBProfile2 = new System.Windows.Forms.ComboBox();
this.cBProfile3 = new System.Windows.Forms.ComboBox();
@ -47,6 +46,7 @@
this.lVPrograms = new System.Windows.Forms.ListView();
this.nameHeader = ((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.bnHideUnchecked = new System.Windows.Forms.Button();
this.cMSPrograms = new System.Windows.Forms.ContextMenuStrip(this.components);
@ -56,6 +56,10 @@
this.addDirectoryToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.browseForOtherProgramsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
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.SuspendLayout();
//
@ -66,12 +70,6 @@
this.bnAddPrograms.UseVisualStyleBackColor = true;
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
//
resources.ApplyResources(this.cBProfile1, "cBProfile1");
@ -154,7 +152,8 @@
this.lVPrograms.CheckBoxes = true;
this.lVPrograms.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.nameHeader,
this.PathHeader});
this.PathHeader,
this.WndTitleHeader});
this.lVPrograms.FullRowSelect = true;
this.lVPrograms.HideSelection = false;
this.lVPrograms.LargeImageList = this.iLIcons;
@ -164,7 +163,6 @@
this.lVPrograms.SmallImageList = this.iLIcons;
this.lVPrograms.UseCompatibleStateImageBehavior = false;
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);
//
// nameHeader
@ -175,6 +173,10 @@
//
resources.ApplyResources(this.PathHeader, "PathHeader");
//
// WndTitleHeader
//
resources.ApplyResources(this.WndTitleHeader, "WndTitleHeader");
//
// pBProfilesTip
//
resources.ApplyResources(this.pBProfilesTip, "pBProfilesTip");
@ -239,13 +241,42 @@
this.cBTurnOffDS4W.UseVisualStyleBackColor = true;
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
//
resources.ApplyResources(this, "$this");
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.SystemColors.Control;
this.Controls.Add(this.cBTurnOffDS4W);
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.bnAddPrograms);
this.Controls.Add(this.lVPrograms);
@ -257,7 +288,6 @@
this.Controls.Add(this.cBProfile3);
this.Controls.Add(this.cBProfile2);
this.Controls.Add(this.cBProfile1);
this.Controls.Add(this.lBProgramPath);
this.Controls.Add(this.bnDelete);
this.Controls.Add(this.bnSave);
this.Name = "WinProgs";
@ -270,7 +300,6 @@
#endregion
private System.Windows.Forms.Button bnAddPrograms;
private System.Windows.Forms.Label lBProgramPath;
private System.Windows.Forms.ComboBox cBProfile1;
private System.Windows.Forms.ComboBox cBProfile2;
private System.Windows.Forms.ComboBox cBProfile3;
@ -295,5 +324,10 @@
private System.Windows.Forms.ToolStripMenuItem browseForOtherProgramsToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem addDirectoryToolStripMenuItem;
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
{
ToolTip tp = new ToolTip();
ComboBox[] cbs;
public DS4Form form;
//C:\ProgramData\Microsoft\Windows\Start Menu\Programs
string steamgamesdir, origingamesdir;
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>();
bool appsloaded = false;
public const string steamCommx86Loc = @"C:\Program Files (x86)\Steam\steamapps\common";
@ -33,7 +32,9 @@ namespace DS4Windows.Forms
public WinProgs(string[] oc, DS4Form main)
{
ToolTip tp = new ToolTip();
InitializeComponent();
openProgram.Filter = Properties.Resources.Programs+"|*.exe|" + Properties.Resources.Shortcuts + "|*.lnk";
form = main;
cbs = new ComboBox[4] { cBProfile1, cBProfile2, cBProfile3, cBProfile4 };
@ -44,6 +45,10 @@ namespace DS4Windows.Forms
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"))
Create();
@ -64,6 +69,10 @@ namespace DS4Windows.Forms
origingamesdir = originLoc;
else
cMSPrograms.Items.Remove(addOriginGamesToolStripMenuItem);
cBAutoProfileDebugLog.Checked = (DS4Form.autoProfileDebugLogLevel > 0);
selectedProgramPathItem = null;
UpdateProfileComboListValues(null);
}
public bool Create()
@ -73,19 +82,20 @@ namespace DS4Windows.Forms
try
{
XmlNode Node;
XmlDocument doc = new XmlDocument();
Node = m_Xdoc.CreateXmlDeclaration("1.0", "utf-8", String.Empty);
m_Xdoc.AppendChild(Node);
Node = doc.CreateXmlDeclaration("1.0", "utf-8", String.Empty);
doc.AppendChild(Node);
Node = m_Xdoc.CreateComment(String.Format(" Auto-Profile Configuration Data. {0} ", DateTime.Now));
m_Xdoc.AppendChild(Node);
Node = doc.CreateComment(String.Format(" Auto-Profile Configuration Data. {0} ", DateTime.Now));
doc.AppendChild(Node);
Node = m_Xdoc.CreateWhitespace("\r\n");
m_Xdoc.AppendChild(Node);
Node = doc.CreateWhitespace("\r\n");
doc.AppendChild(Node);
Node = m_Xdoc.CreateNode(XmlNodeType.Element, "Programs", "");
m_Xdoc.AppendChild(Node);
m_Xdoc.Save(m_Profile);
Node = doc.CreateNode(XmlNodeType.Element, "Programs", "");
doc.AppendChild(Node);
doc.Save(m_Profile);
}
catch { Saved = false; }
@ -101,38 +111,59 @@ namespace DS4Windows.Forms
public void LoadP()
{
XmlDocument doc = new XmlDocument();
programpaths.Clear();
if (!File.Exists(Global.appdatapath + "\\Auto Profiles.xml"))
return;
doc.Load(Global.appdatapath + "\\Auto Profiles.xml");
XmlNodeList programslist = doc.SelectNodes("Programs/Program");
foreach (XmlNode x in programslist)
programpaths.Add(x.Attributes["path"].Value);
lVPrograms.BeginUpdate();
int index = 0;
foreach (string st in programpaths)
try
{
if (!string.IsNullOrEmpty(st))
XmlDocument doc = new XmlDocument();
iLIcons.Images.Clear();
if (!File.Exists(Global.appdatapath + "\\Auto Profiles.xml"))
return;
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)
{
if (File.Exists(st))
progPath = progNode.Attributes["path"]?.Value;
progTitle = progNode.Attributes["title"]?.Value;
if (!string.IsNullOrEmpty(progPath))
{
iLIcons.Images.Add(Icon.ExtractAssociatedIcon(st));
index = iLIcons.Images.IndexOfKey(progPath);
if (index < 0 && File.Exists(progPath))
{
iLIcons.Images.Add(progPath, Icon.ExtractAssociatedIcon(progPath));
index = iLIcons.Images.Count - 1;
}
if(index >= 0)
lvi = new ListViewItem(Path.GetFileNameWithoutExtension(progPath), index);
else
lvi = new ListViewItem(Path.GetFileNameWithoutExtension(progPath));
lvi.Checked = true;
lvi.SubItems.Add(progPath);
if (!String.IsNullOrEmpty(progTitle))
lvi.SubItems.Add(progTitle);
lVPrograms.Items.Add(lvi);
}
ListViewItem lvi = new ListViewItem(Path.GetFileNameWithoutExtension(st), index);
lvi.Checked = true;
lvi.ToolTipText = st;
lvi.SubItems.Add(st);
lVPrograms.Items.Add(lvi);
}
index++;
}
lVPrograms.EndUpdate();
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();
}
}
private void GetApps(string path)
@ -179,168 +210,318 @@ namespace DS4Windows.Forms
appsloaded = true;
}
void AddLoadedApps()
int AddLoadedApps(bool autoremoveSetupApps = true)
{
int numOfAppsAdded = 0;
if (appsloaded)
{
bnAddPrograms.Text = Properties.Resources.AddingToList;
for (int i = lodsf.Count - 1; i >= 0; i--)
{
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]))
lodsf.RemoveAt(i);
}
for (int i = lodsf.Count - 1; i >= 0; i--)
if (autoremoveSetupApps)
{
for (int j = programpaths.Count - 1; j >= 0; j--)
for (int i = lodsf.Count - 1; i >= 0; i--)
{
if (lodsf[i].ToLower().Replace('/', '\\') == programpaths[j].ToLower().Replace('/', '\\'))
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]))
lodsf.RemoveAt(i);
}
}
lVPrograms.BeginUpdate();
foreach (string st in lodsf)
{
if (File.Exists(st))
// 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--)
{
int index = programpaths.IndexOf(st);
iLIcons.Images.Add(Icon.ExtractAssociatedIcon(st));
ListViewItem lvi = new ListViewItem(Path.GetFileNameWithoutExtension(st), iLIcons.Images.Count + index);
lvi.SubItems.Add(st);
lvi.ToolTipText = st;
lVPrograms.Items.Add(lvi);
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;
}
}
}
}
lVPrograms.EndUpdate();
bnAddPrograms.Text = Properties.Resources.AddPrograms;
bnAddPrograms.Enabled = true;
appsloaded = false;
try
{
ListViewItem lvi;
int index;
lVPrograms.BeginUpdate();
foreach (string st in lodsf)
{
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++;
}
}
}
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();
bnAddPrograms.Text = Properties.Resources.AddPrograms;
bnAddPrograms.Enabled = true;
appsloaded = false;
}
}
return numOfAppsAdded;
}
public void Save(string name)
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;
string newPath, newTitle;
Node = m_Xdoc.CreateComment(String.Format(" Auto-Profile Configuration Data. {0} ", DateTime.Now));
foreach (XmlNode node in m_Xdoc.SelectNodes("//comment()"))
node.ParentNode.ReplaceChild(Node, node);
newPath = tBPath.Text.Trim();
newTitle = tBWndTitle.Text;
Node = m_Xdoc.SelectSingleNode("Programs");
string programname;
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();
if (progPathItem == null || String.IsNullOrEmpty(progPathItem.path) || String.IsNullOrEmpty(newPath))
return;
try
{
XmlNode oldxmlprocess = m_Xdoc.SelectSingleNode("/Programs/Program[@path=\"" + lBProgramPath.Text + "\"]");
Node.ReplaceChild(el, oldxmlprocess);
}
catch { Node.AppendChild(el); }
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);
m_Xdoc.AppendChild(Node);
m_Xdoc.Save(m_Profile);
// 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");
if (lVPrograms.SelectedItems.Count > 0)
lVPrograms.SelectedItems[0].Checked = true;
XmlElement el = doc.CreateElement("Program");
el.SetAttribute("path", newPath);
if (!String.IsNullOrEmpty(newTitle))
el.SetAttribute("title", newTitle);
form.LoadP();
}
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();
public void LoadP(string name)
{
XmlDocument doc = new XmlDocument();
doc.Load(m_Profile);
XmlNodeList programs = doc.SelectNodes("Programs/Program");
XmlNode Item = doc.SelectSingleNode("/Programs/Program[@path=\"" + name + "\"]");
if (Item != null)
{
for (int i = 0; i < 4; i++)
if (oldxmlprocess != null)
Node.ReplaceChild(el, oldxmlprocess);
else
Node.AppendChild(el);
doc.AppendChild(Node);
doc.Save(m_Profile);
if(selectedProgramPathItem != null)
{
Item = doc.SelectSingleNode("/Programs/Program[@path=\"" + name + "\"]" + "/Controller" + (i + 1));
if (Item != 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)
{
for (int j = 0; j < cbs[i].Items.Count; j++)
{
if (cbs[i].Items[j].ToString() == Item.InnerText)
{
cbs[i].SelectedIndex = j;
bnSave.Enabled = false;
break;
}
else
cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
}
if (!String.IsNullOrEmpty(newTitle))
lVPrograms.SelectedItems[0].SubItems.Add(newTitle);
}
else
cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
{
lVPrograms.SelectedItems[0].SubItems[2].Text = newTitle;
}
if (!String.IsNullOrEmpty(newTitle))
lVPrograms.SelectedItems[0].ToolTipText = $"{newPath} [{newTitle}]";
else
lVPrograms.SelectedItems[0].ToolTipText = newPath;
}
Item = doc.SelectSingleNode("/Programs/Program[@path=\"" + name + "\"]" + "/TurnOff");
bool turnOff;
if (Item != null && bool.TryParse(Item.InnerText, out turnOff))
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(ProgramPathItem loadProgPathItem)
{
if (loadProgPathItem == null)
return;
try
{
XmlDocument doc = new XmlDocument();
doc.Load(m_Profile);
XmlNode programItem = FindProgramXMLItem(doc, loadProgPathItem.path, loadProgPathItem.title);
if (programItem != null)
{
cBTurnOffDS4W.Checked = turnOff;
XmlNode profileItem;
for (int i = 0; i < 4; i++)
{
profileItem = programItem.SelectSingleNode($".//Controller{i + 1}");
if (profileItem != null)
{
for (int j = 0; j < cbs[i].Items.Count; j++)
{
if (cbs[i].Items[j].ToString() == profileItem.InnerText)
{
cbs[i].SelectedIndex = j;
break;
}
else
cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
}
}
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;
}
else
cBTurnOffDS4W.Checked = false;
}
else
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;
}
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)
{
XmlNode parentNode = programItem.ParentNode;
if (parentNode != null)
{
parentNode.RemoveChild(programItem);
doc.AppendChild(parentNode);
doc.Save(m_Profile);
}
}
if (lVPrograms.SelectedItems.Count > 0 && uncheck)
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++)
cbs[i].Enabled = true;
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].SelectedIndex = cbs[i].Items.Count - 1;
{
cbs[i].Enabled = false;
if (cbs[i].SelectedIndex != last)
cbs[i].SelectedIndex = last;
}
cBTurnOffDS4W.Checked = false;
bnSave.Enabled = false;
bnSave.Enabled = bnDelete.Enabled = false;
tBPath.Enabled = tBWndTitle.Enabled = cBTurnOffDS4W.Enabled = false;
tBPath.Text = tBWndTitle.Text = "";
cBTurnOffDS4W.Checked = false;
}
}
public void RemoveP(string name, bool uncheck)
{
XmlDocument doc = new XmlDocument();
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);
doc.Save(m_Profile);
if (lVPrograms.SelectedItems.Count > 0 && uncheck)
lVPrograms.SelectedItems[0].Checked = false;
for (int i = 0; i < 4; i++)
cbs[i].SelectedIndex = cbs[i].Items.Count - 1;
bnSave.Enabled = false;
}
private void CBProfile_IndexChanged(object sender, EventArgs e)
{
int last = cbs[0].Items.Count - 1;
if (lBProgramPath.Text != string.Empty)
if (selectedProgramPathItem != null && lVPrograms.SelectedItems.Count > 0)
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)
{
if (lBProgramPath.Text != "")
Save(lBProgramPath.Text);
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;
Save(selectedProgramPathItem);
}
bnSave.Enabled = false;
}
@ -349,41 +530,48 @@ namespace DS4Windows.Forms
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)
{
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)
{
if (lVPrograms.SelectedItems.Count > 0)
if (lVPrograms.SelectedItems.Count > 0 && lVPrograms.SelectedIndices[0] > -1)
{
if (lVPrograms.SelectedIndices[0] > -1)
lBProgramPath.Text = lVPrograms.SelectedItems[0].SubItems[1].Text;
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);
}
else
lBProgramPath.Text = "";
}
private void listView1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (lVPrograms.Items[e.Index].Checked)
RemoveP(lVPrograms.Items[e.Index].SubItems[1].Text, false);
{
selectedProgramPathItem = null;
UpdateProfileComboListValues(null);
}
}
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();
}
@ -418,11 +606,18 @@ namespace DS4Windows.Forms
file = GetTargetPath(file);
}
lBProgramPath.Text = file;
iLIcons.Images.Add(Icon.ExtractAssociatedIcon(file));
ListViewItem lvi = new ListViewItem(Path.GetFileNameWithoutExtension(file), lVPrograms.Items.Count);
lvi.SubItems.Add(file);
lVPrograms.Items.Insert(0, lvi);
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;
}
}
}
@ -534,6 +729,22 @@ namespace DS4Windows.Forms
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)
{
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>
<!--
Microsoft ResX Schema
@ -165,4 +165,16 @@
<data name="pBProfilesTip.Text" xml:space="preserve">
<value>Valitse profiilit tästä</value>
</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>

View File

@ -141,36 +141,9 @@
<value>$this</value>
</data>
<data name="&gt;&gt;bnAddPrograms.ZOrder" xml:space="preserve">
<value>4</value>
<value>8</value>
</data>
<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">
<value>Top, Right</value>
</data>
@ -193,7 +166,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;cBProfile1.ZOrder" xml:space="preserve">
<value>13</value>
<value>17</value>
</data>
<data name="cBProfile2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -217,7 +190,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;cBProfile2.ZOrder" xml:space="preserve">
<value>12</value>
<value>16</value>
</data>
<data name="cBProfile3.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -241,7 +214,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;cBProfile3.ZOrder" xml:space="preserve">
<value>11</value>
<value>15</value>
</data>
<data name="cBProfile4.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -265,7 +238,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;cBProfile4.ZOrder" xml:space="preserve">
<value>10</value>
<value>14</value>
</data>
<data name="bnSave.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -295,7 +268,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;bnSave.ZOrder" xml:space="preserve">
<value>16</value>
<value>19</value>
</data>
<data name="lBController1.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -325,7 +298,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;lBController1.ZOrder" xml:space="preserve">
<value>9</value>
<value>13</value>
</data>
<data name="lBController2.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -355,7 +328,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;lBController2.ZOrder" xml:space="preserve">
<value>8</value>
<value>12</value>
</data>
<data name="lBController3.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -385,7 +358,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;lBController3.ZOrder" xml:space="preserve">
<value>7</value>
<value>11</value>
</data>
<data name="lBController4.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -415,7 +388,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;lBController4.ZOrder" xml:space="preserve">
<value>6</value>
<value>10</value>
</data>
<metadata name="openProgram.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
@ -448,7 +421,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;bnDelete.ZOrder" xml:space="preserve">
<value>15</value>
<value>18</value>
</data>
<metadata name="iLIcons.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>143, 17</value>
@ -469,13 +442,19 @@
<value>Path</value>
</data>
<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 name="lVPrograms.Location" type="System.Drawing.Point, System.Drawing">
<value>5, 28</value>
</data>
<data name="lVPrograms.Size" type="System.Drawing.Size, System.Drawing">
<value>505, 190</value>
<value>505, 261</value>
</data>
<data name="lVPrograms.TabIndex" type="System.Int32, mscorlib">
<value>12</value>
@ -490,7 +469,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;lVPrograms.ZOrder" xml:space="preserve">
<value>5</value>
<value>9</value>
</data>
<data name="pBProfilesTip.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Right</value>
@ -520,7 +499,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;pBProfilesTip.ZOrder" xml:space="preserve">
<value>2</value>
<value>1</value>
</data>
<data name="bnHideUnchecked.Location" type="System.Drawing.Point, System.Drawing">
<value>99, 2</value>
@ -544,7 +523,7 @@
<value>$this</value>
</data>
<data name="&gt;&gt;bnHideUnchecked.ZOrder" xml:space="preserve">
<value>3</value>
<value>7</value>
</data>
<metadata name="cMSPrograms.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>232, 17</value>
@ -592,13 +571,13 @@
<value>Top, Right</value>
</data>
<data name="cBTurnOffDS4W.Location" type="System.Drawing.Point, System.Drawing">
<value>514, 152</value>
<value>514, 151</value>
</data>
<data name="cBTurnOffDS4W.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>2, 2, 2, 2</value>
</data>
<data name="cBTurnOffDS4W.Size" type="System.Drawing.Size, System.Drawing">
<value>215, 41</value>
<value>215, 24</value>
</data>
<data name="cBTurnOffDS4W.TabIndex" type="System.Int32, mscorlib">
<value>13</value>
@ -616,7 +595,109 @@
<value>$this</value>
</data>
<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>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
@ -625,7 +706,7 @@
<value>6, 13</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>736, 222</value>
<value>736, 293</value>
</data>
<data name="$this.Margin" type="System.Windows.Forms.Padding, System.Windows.Forms">
<value>4, 4, 4, 4</value>
@ -657,6 +738,12 @@
<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>
</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">
<value>addProgramsFromStartMenuToolStripMenuItem</value>
</data>

View File

@ -6,11 +6,30 @@ using Process = System.Diagnostics.Process;
using System.ComponentModel;
using System.Globalization;
using Microsoft.Win32.TaskScheduler;
using System.IO.MemoryMappedFiles;
using System.Text;
namespace DS4Windows
{
static class Program
{
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", EntryPoint = "FindWindow")]
private static extern IntPtr FindWindow(string sClass, string sWindow);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, ref COPYDATASTRUCT lParam);
[StructLayout(LayoutKind.Sequential)]
public struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
// Add "global\" in front of the EventName, then only one instance is allowed on the
// whole system, including other users. But the application can not be brought
// into view, of course.
@ -22,6 +41,9 @@ namespace DS4Windows
private static Thread controlThread;
private static Form ds4form;
private static MemoryMappedFile ipcClassNameMMF = null; // MemoryMappedFile for inter-process communication used to hold className of DS4Form window
private static MemoryMappedViewAccessor ipcClassNameMMA = null;
/// <summary>
/// The main entry point for the application.
/// </summary>
@ -66,6 +88,50 @@ namespace DS4Windows
Environment.ExitCode = 0;
return;
}
else if (s == "command" || s == "-command")
{
i++;
IntPtr hWndDS4WindowsForm = IntPtr.Zero;
if (args[i].Length > 0 && args[i].Length <= 256)
{
// Find the main DS4Form window handle and post WM_COPYDATA inter-process message. IPCClasName.dat file was created by the main DS4Windows process
// and it contains the name of the DS4Form .NET window class name string (the hash key part of the string is dynamically generated by .NET engine and it may change,
// so that's why the main process re-creates the file if the window class name is changed by .NET framework). Finding the WND handle usig both class name and window name
// limits chances that WM_COPYDATA message is sent to a wrong window.
hWndDS4WindowsForm = FindWindow(ReadIPCClassNameMMF(), "DS4Windows");
if (hWndDS4WindowsForm != IntPtr.Zero)
{
COPYDATASTRUCT cds;
cds.lpData = IntPtr.Zero;
try
{
cds.dwData = IntPtr.Zero;
cds.cbData = args[i].Length;
cds.lpData = Marshal.StringToHGlobalAnsi(args[i]);
SendMessage(hWndDS4WindowsForm, Forms.DS4Form.WM_COPYDATA, IntPtr.Zero, ref cds);
}
finally
{
if(cds.lpData != IntPtr.Zero)
Marshal.FreeHGlobal(cds.lpData);
}
}
else
{
Environment.ExitCode = 2;
}
}
else
{
Environment.ExitCode = 1;
}
return;
}
}
try
@ -119,6 +185,9 @@ namespace DS4Windows
while (testThread.IsAlive)
Thread.SpinWait(500);
threadComEvent.Close();
if (ipcClassNameMMA != null) ipcClassNameMMA.Dispose();
if (ipcClassNameMMF != null) ipcClassNameMMF.Dispose();
}
private static void createControlService()
@ -174,5 +243,54 @@ namespace DS4Windows
temp.WindowState = FormWindowState.Normal;
}
}
public static void CreateIPCClassNameMMF(IntPtr hWnd)
{
if (ipcClassNameMMA != null) return; // Already holding a handle to MMF file. No need to re-write the data
try
{
StringBuilder wndClassNameStr = new StringBuilder(128);
if (GetClassName(hWnd, wndClassNameStr, wndClassNameStr.Capacity) != 0 && wndClassNameStr.Length > 0)
{
byte[] buffer = ASCIIEncoding.ASCII.GetBytes(wndClassNameStr.ToString());
ipcClassNameMMF = MemoryMappedFile.CreateNew("DS4Windows_IPCClassName.dat", 128);
ipcClassNameMMA = ipcClassNameMMF.CreateViewAccessor(0, buffer.Length);
ipcClassNameMMA.WriteArray(0, buffer, 0, buffer.Length);
// The MMF file is alive as long this process holds the file handle open
}
}
catch (Exception)
{
/* Eat all exceptions because errors here are not fatal for DS4Win */
}
}
private static string ReadIPCClassNameMMF()
{
MemoryMappedFile mmf = null;
MemoryMappedViewAccessor mma = null;
try
{
byte[] buffer = new byte[128];
mmf = MemoryMappedFile.OpenExisting("DS4Windows_IPCClassName.dat");
mma = mmf.CreateViewAccessor(0, 128);
mma.ReadArray(0, buffer, 0, buffer.Length);
return ASCIIEncoding.ASCII.GetString(buffer);
}
catch (Exception)
{
// Eat all exceptions
}
finally
{
if (mma != null) mma.Dispose();
if (mmf != null) mmf.Dispose();
}
return null;
}
}
}

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>
/// Looks up a localized resource of type System.Drawing.Bitmap.
/// </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>
/// Looks up a localized string similar to Click for advanced Sixaxis reading.
/// </summary>

View File

@ -603,4 +603,16 @@
<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>
</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>

View File

@ -826,4 +826,10 @@
<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>
</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>