mirror of
https://github.com/cemu-project/DS4Windows.git
synced 2024-11-25 10:46:51 +01:00
3019 lines
119 KiB
C#
3019 lines
119 KiB
C#
using System;
|
|
using System.Windows.Forms;
|
|
using System.Runtime.InteropServices;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Collections.Generic;
|
|
using System.Net;
|
|
using System.Drawing;
|
|
using System.Diagnostics;
|
|
using System.Xml;
|
|
using System.Text;
|
|
using Microsoft.Win32.TaskScheduler;
|
|
using System.Security.Principal;
|
|
using System.Threading;
|
|
using System.Drawing.Drawing2D;
|
|
using TaskRunner = System.Threading.Tasks.Task;
|
|
using NonFormTimer = System.Timers.Timer;
|
|
using static DS4Windows.Global;
|
|
using System.Security;
|
|
using System.Management;
|
|
|
|
namespace DS4Windows.Forms
|
|
{
|
|
[SuppressUnmanagedCodeSecurity]
|
|
public partial class DS4Form : Form
|
|
{
|
|
public string[] cmdArguments;
|
|
delegate void LogDebugDelegate(DateTime Time, String Data, bool warning);
|
|
delegate void NotificationDelegate(object sender, DebugEventArgs args);
|
|
delegate void DeviceStatusChangedDelegate(object sender, DeviceStatusChangeEventArgs args);
|
|
delegate void DeviceSerialChangedDelegate(object sender, SerialChangeArgs args);
|
|
private Label[] Pads, Batteries;
|
|
private ComboBox[] cbs;
|
|
private Button[] ebns;
|
|
private Button[] lights;
|
|
private PictureBox[] statPB;
|
|
private PictureBox[] exclusivePB;
|
|
private ToolStripMenuItem[] shortcuts;
|
|
private ToolStripMenuItem[] disconnectShortcuts;
|
|
protected CheckBox[] linkedProfileCB;
|
|
NonFormTimer hotkeysTimer = null;// new NonFormTimer();
|
|
NonFormTimer autoProfilesTimer = null;// new NonFormTimer();
|
|
double dpix, dpiy;
|
|
|
|
List<ProgramPathItem> programpaths = new List<ProgramPathItem>();
|
|
List<string> profilenames = 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;
|
|
private bool optPop;
|
|
public Size oldsize;
|
|
bool contextclose;
|
|
bool turnOffTemp;
|
|
bool runningBat;
|
|
private bool changingService;
|
|
private IntPtr regHandle = new IntPtr();
|
|
private ManagementEventWatcher managementEvWatcher;
|
|
private DS4Forms.LanguagePackComboBox languagePackComboBox1;
|
|
private AdvancedColorDialog advColorDialog;
|
|
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,
|
|
string.Empty, string.Empty, string.Empty, string.Empty };
|
|
|
|
private const string UPDATER_VERSION = "1.4.0";
|
|
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")]
|
|
private static extern IntPtr GetForegroundWindow();
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
|
|
|
|
[DllImport("kernel32.dll")]
|
|
private static extern bool CloseHandle(IntPtr handle);
|
|
|
|
[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();
|
|
|
|
bool firstRun = Global.firstRun;
|
|
if (Global.firstRun)
|
|
{
|
|
new SaveWhere(Global.multisavespots).ShowDialog();
|
|
}
|
|
|
|
Global.Load();
|
|
Global.SetCulture(UseLang);
|
|
|
|
InitializeComponent();
|
|
advColorDialog = new AdvancedColorDialog();
|
|
|
|
this.languagePackComboBox1 = new DS4Forms.LanguagePackComboBox();
|
|
this.languagePackComboBox1.AutoValidate = System.Windows.Forms.AutoValidate.Disable;
|
|
this.languagePackComboBox1.BackColor = System.Drawing.SystemColors.Window;
|
|
this.languagePackComboBox1.CausesValidation = false;
|
|
this.languagePackComboBox1.Name = "languagePackComboBox1";
|
|
this.languagePackComboBox1.SelectedValueChanged += new System.EventHandler(this.languagePackComboBox1_SelectedValueChanged);
|
|
this.langPanel.Controls.Add(languagePackComboBox1);
|
|
|
|
bnEditC1.Tag = 0;
|
|
bnEditC2.Tag = 1;
|
|
bnEditC3.Tag = 2;
|
|
bnEditC4.Tag = 3;
|
|
|
|
StartWindowsCheckBox.CheckedChanged -= StartWindowsCheckBox_CheckedChanged;
|
|
|
|
saveProfiles.Filter = Properties.Resources.XMLFiles + "|*.xml";
|
|
openProfiles.Filter = Properties.Resources.XMLFiles + "|*.xml";
|
|
cmdArguments = args;
|
|
|
|
Pads = new Label[4] { lbPad1, lbPad2, lbPad3, lbPad4 };
|
|
Batteries = new Label[4] { lbBatt1, lbBatt2, lbBatt3, lbBatt4 };
|
|
cbs = new ComboBox[4] { cBController1, cBController2, cBController3, cBController4 };
|
|
ebns = new Button[4] { bnEditC1, bnEditC2, bnEditC3, bnEditC4 };
|
|
lights = new Button[4] { bnLight1, bnLight2, bnLight3, bnLight4 };
|
|
statPB = new PictureBox[4] { pBStatus1, pBStatus2, pBStatus3, pBStatus4 };
|
|
exclusivePB = new PictureBox[4] { exclusivePB1, exclusivePB2, exclusivePB3, exclusivePB4 };
|
|
shortcuts = new ToolStripMenuItem[4] { (ToolStripMenuItem)notifyIcon1.ContextMenuStrip.Items[0],
|
|
(ToolStripMenuItem)notifyIcon1.ContextMenuStrip.Items[1],
|
|
(ToolStripMenuItem)notifyIcon1.ContextMenuStrip.Items[2],
|
|
(ToolStripMenuItem)notifyIcon1.ContextMenuStrip.Items[3] };
|
|
disconnectShortcuts = new ToolStripMenuItem[4]
|
|
{
|
|
discon1toolStripMenuItem, discon2ToolStripMenuItem,
|
|
discon3ToolStripMenuItem, discon4ToolStripMenuItem
|
|
};
|
|
|
|
linkedProfileCB = new CheckBox[4] { linkCB1, linkCB2, linkCB3, linkCB4 };
|
|
|
|
WqlEventQuery q = new WqlEventQuery();
|
|
ManagementScope scope = new ManagementScope("root\\CIMV2");
|
|
q.EventClassName = "Win32_PowerManagementEvent";
|
|
try
|
|
{
|
|
scope.Connect();
|
|
}
|
|
catch (COMException) { }
|
|
|
|
if (scope.IsConnected)
|
|
{
|
|
managementEvWatcher = new ManagementEventWatcher(scope, q);
|
|
managementEvWatcher.EventArrived += PowerEventArrive;
|
|
managementEvWatcher.Start();
|
|
}
|
|
else
|
|
{
|
|
LogDebug(DateTime.Now,
|
|
"Could not connect to Windows Management Instrumentation service. Suspend support not enabled.", true);
|
|
}
|
|
|
|
tSOptions.Visible = false;
|
|
|
|
TaskRunner.Run(() => CheckDrivers());
|
|
|
|
if (string.IsNullOrEmpty(appdatapath))
|
|
{
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
Graphics g = CreateGraphics();
|
|
try
|
|
{
|
|
dpix = g.DpiX / 100f * 1.041666666667f;
|
|
dpiy = g.DpiY / 100f * 1.041666666667f;
|
|
}
|
|
finally
|
|
{
|
|
g.Dispose();
|
|
}
|
|
|
|
blankControllerTab();
|
|
|
|
Directory.CreateDirectory(appdatapath);
|
|
if (firstRun && !Save()) //if can't write to file
|
|
{
|
|
if (MessageBox.Show("Cannot write at current location\nCopy Settings to appdata?", "DS4Windows",
|
|
MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
|
|
{
|
|
try
|
|
{
|
|
Directory.CreateDirectory(appDataPpath);
|
|
File.Copy(exepath + "\\Profiles.xml", appDataPpath + "\\Profiles.xml");
|
|
File.Copy(exepath + "\\Auto Profiles.xml", appDataPpath + "\\Auto Profiles.xml");
|
|
Directory.CreateDirectory(appDataPpath + "\\Profiles");
|
|
foreach (string s in Directory.GetFiles(exepath + "\\Profiles"))
|
|
{
|
|
File.Copy(s, appDataPpath + "\\Profiles\\" + Path.GetFileName(s));
|
|
}
|
|
}
|
|
catch { }
|
|
MessageBox.Show("Copy complete, please relaunch DS4Windows and remove settings from Program Directory", "DS4Windows");
|
|
}
|
|
else
|
|
{
|
|
MessageBox.Show("DS4Windows cannot edit settings here, This will now close", "DS4Windows");
|
|
}
|
|
|
|
appdatapath = null;
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
cBUseWhiteIcon.Checked = UseWhiteIcon;
|
|
Icon = Properties.Resources.DS4W;
|
|
notifyIcon1.Icon = UseWhiteIcon ? Properties.Resources.DS4W___White : Properties.Resources.DS4W;
|
|
populateNotifyText();
|
|
foreach (ToolStripMenuItem t in shortcuts)
|
|
t.DropDownItemClicked += Profile_Changed_Menu;
|
|
|
|
hideDS4CheckBox.CheckedChanged -= hideDS4CheckBox_CheckedChanged;
|
|
hideDS4CheckBox.Checked = UseExclusiveMode;
|
|
hideDS4CheckBox.CheckedChanged += hideDS4CheckBox_CheckedChanged;
|
|
|
|
cBDisconnectBT.Checked = DCBTatStop;
|
|
cBQuickCharge.Checked = QuickCharge;
|
|
cBCustomSteam.Checked = UseCustomSteamFolder;
|
|
tBSteamFolder.Text = CustomSteamFolder;
|
|
// New settings
|
|
this.Width = FormWidth;
|
|
this.Height = FormHeight;
|
|
Location = new Point(FormLocationX, FormLocationY);
|
|
startMinimizedCheckBox.CheckedChanged -= startMinimizedCheckBox_CheckedChanged;
|
|
startMinimizedCheckBox.Checked = StartMinimized;
|
|
startMinimizedCheckBox.CheckedChanged += startMinimizedCheckBox_CheckedChanged;
|
|
|
|
mintoTaskCheckBox.Checked = Global.MinToTaskbar;
|
|
mintoTaskCheckBox.CheckedChanged += MintoTaskCheckBox_CheckedChanged;
|
|
|
|
cBCloseMini.Checked = CloseMini;
|
|
|
|
cBFlashWhenLate.Checked = FlashWhenLate;
|
|
nUDLatency.Value = FlashWhenLateAt;
|
|
|
|
if (!LoadActions()) //if first no actions have been made yet, create PS+Option to D/C and save it to every profile
|
|
{
|
|
Global.CreateStdActions();
|
|
}
|
|
|
|
bool start = true;
|
|
bool mini = false;
|
|
for (int i = 0, argslen = cmdArguments.Length; i < argslen; i++)
|
|
{
|
|
if (cmdArguments[i] == "-stop")
|
|
start = false;
|
|
else if (cmdArguments[i] == "-m")
|
|
mini = true;
|
|
|
|
if (mini && start)
|
|
break;
|
|
}
|
|
|
|
if (startMinimizedCheckBox.Checked || mini)
|
|
{
|
|
WindowState = FormWindowState.Minimized;
|
|
}
|
|
|
|
RefreshProfiles();
|
|
/*opt = new Options(this);
|
|
opt.Icon = this.Icon;
|
|
opt.TopLevel = false;
|
|
opt.Dock = DockStyle.None;
|
|
opt.FormBorderStyle = FormBorderStyle.None;
|
|
*/
|
|
//tabProfiles.Controls.Add(opt);
|
|
|
|
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
|
|
string version = fvi.FileVersion;
|
|
LogDebug(DateTime.Now, "DS4Windows version " + version, false);
|
|
|
|
Global.BatteryStatusChange += BatteryStatusUpdate;
|
|
Global.ControllerRemoved += ControllerRemovedChange;
|
|
Global.DeviceStatusChange += DeviceStatusChanged;
|
|
Global.DeviceSerialChange += DeviceSerialChanged;
|
|
|
|
Enable_Controls(0, false);
|
|
Enable_Controls(1, false);
|
|
Enable_Controls(2, false);
|
|
Enable_Controls(3, false);
|
|
btnStartStop.Text = Properties.Resources.StartText;
|
|
|
|
startToolStripMenuItem.Text = btnStartStop.Text;
|
|
cBoxNotifications.SelectedIndex = Notifications;
|
|
//cBSwipeProfiles.Checked = SwipeProfiles;
|
|
int checkwhen = CheckWhen;
|
|
cBUpdate.Checked = checkwhen > 0;
|
|
if (checkwhen > 23)
|
|
{
|
|
cBUpdateTime.SelectedIndex = 1;
|
|
nUDUpdateTime.Value = checkwhen / 24;
|
|
}
|
|
else
|
|
{
|
|
cBUpdateTime.SelectedIndex = 0;
|
|
nUDUpdateTime.Value = checkwhen;
|
|
}
|
|
|
|
if (File.Exists(exepath + "\\Updater.exe"))
|
|
{
|
|
Thread.Sleep(2000);
|
|
File.Delete(exepath + "\\Updater.exe");
|
|
}
|
|
|
|
bool isElevated = IsAdministrator();
|
|
if (!isElevated)
|
|
{
|
|
Image tempImg = new Bitmap(uacPictureBox.Width, uacPictureBox.Height);
|
|
AddUACShieldToImage(tempImg);
|
|
uacPictureBox.BackgroundImage = tempImg;
|
|
uacPictureBox.Visible = true;
|
|
new ToolTip().SetToolTip(uacPictureBox, Properties.Resources.UACTask);
|
|
runStartTaskRadio.Enabled = false;
|
|
}
|
|
else
|
|
{
|
|
runStartTaskRadio.Enabled = true;
|
|
}
|
|
|
|
if (File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\DS4Windows.lnk"))
|
|
{
|
|
StartWindowsCheckBox.Checked = true;
|
|
runStartupPanel.Visible = true;
|
|
|
|
string lnkpath = WinProgs.ResolveShortcutAndArgument(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\DS4Windows.lnk");
|
|
string onlylnkpath = WinProgs.ResolveShortcut(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\DS4Windows.lnk");
|
|
if (!lnkpath.EndsWith("-runtask"))
|
|
{
|
|
runStartProgRadio.Checked = true;
|
|
}
|
|
else
|
|
{
|
|
runStartTaskRadio.Checked = true;
|
|
}
|
|
|
|
if (onlylnkpath != Process.GetCurrentProcess().MainModule.FileName)
|
|
{
|
|
string ds4lnkpath = Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\DS4Windows.lnk";
|
|
if (!new FileInfo(ds4lnkpath).IsReadOnly)
|
|
{
|
|
File.Delete(ds4lnkpath);
|
|
appShortcutToStartup();
|
|
changeStartupRoutine();
|
|
}
|
|
else
|
|
{
|
|
StartWindowsCheckBox.Checked = false;
|
|
runStartupPanel.Visible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
StartWindowsCheckBox.CheckedChanged += new EventHandler(StartWindowsCheckBox_CheckedChanged);
|
|
new ToolTip().SetToolTip(StartWindowsCheckBox, Properties.Resources.RunAtStartup);
|
|
|
|
ckUdpServ.Checked = nUDUdpPortNum.Enabled = tBUdpListenAddress.Enabled = isUsingUDPServer();
|
|
nUDUdpPortNum.Value = getUDPServerPortNum();
|
|
tBUdpListenAddress.Text = getUDPServerListenAddress();
|
|
new ToolTip().SetToolTip(ckUdpServ, Properties.Resources.UdpServer);
|
|
|
|
ckUdpServ.CheckedChanged += CkUdpServ_CheckedChanged;
|
|
nUDUdpPortNum.Leave += NUDUdpPortNum_Leave;
|
|
tBUdpListenAddress.Leave += TBUdpListenAddress_Leave;
|
|
|
|
populateHoverTextDict();
|
|
|
|
cBController1.KeyPress += CBController_KeyPress;
|
|
cBController2.KeyPress += CBController_KeyPress;
|
|
cBController3.KeyPress += CBController_KeyPress;
|
|
cBController4.KeyPress += CBController_KeyPress;
|
|
|
|
foreach (Control control in fLPSettings.Controls)
|
|
{
|
|
string tempst;
|
|
if (control.HasChildren)
|
|
{
|
|
foreach (Control ctrl in control.Controls)
|
|
{
|
|
if (hoverTextDict.TryGetValue(ctrl, out tempst))
|
|
{
|
|
ctrl.MouseHover += Items_MouseHover;
|
|
}
|
|
else
|
|
{
|
|
ctrl.MouseHover += ClearLastMessage;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (hoverTextDict.TryGetValue(control, out tempst))
|
|
control.MouseHover += Items_MouseHover;
|
|
else
|
|
control.MouseHover += ClearLastMessage;
|
|
}
|
|
}
|
|
|
|
this.Resize += Form_Resize;
|
|
this.LocationChanged += TrackLocationChanged;
|
|
|
|
Program.CreateIPCClassNameMMF(this.Handle);
|
|
|
|
Program.rootHub.Debug += On_Debug;
|
|
|
|
AppLogger.GuiLog += On_Debug;
|
|
AppLogger.TrayIconLog += ShowNotification;
|
|
LoadLinkedProfiles();
|
|
|
|
TaskRunner.Delay(50).ContinueWith((t) =>
|
|
{
|
|
if (checkwhen > 0 && DateTime.Now >= LastChecked + TimeSpan.FromHours(checkwhen))
|
|
{
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
// Sorry other devs, gonna have to find your own server
|
|
Uri url = new Uri("https://raw.githubusercontent.com/Ryochan7/DS4Windows/jay/DS4Windows/newest.txt");
|
|
WebClient wc = new WebClient();
|
|
wc.DownloadFileAsync(url, appdatapath + "\\version.txt");
|
|
wc.DownloadFileCompleted += (sender, e) => { TaskRunner.Run(() => Check_Version(sender, e)); };
|
|
LastChecked = DateTime.Now;
|
|
}));
|
|
}
|
|
|
|
UpdateTheUpdater();
|
|
});
|
|
|
|
if (btnStartStop.Enabled && start)
|
|
{
|
|
TaskRunner.Delay(100).ContinueWith((t) => {
|
|
this.BeginInvoke((System.Action)(() => BtnStartStop_Clicked()));
|
|
});
|
|
}
|
|
|
|
Thread timerThread = new Thread(() =>
|
|
{
|
|
hotkeysTimer = new NonFormTimer();
|
|
hotkeysTimer.Interval = 20;
|
|
//hotkeysTimer.Elapsed += Hotkeys;
|
|
hotkeysTimer.AutoReset = false;
|
|
if (SwipeProfiles)
|
|
{
|
|
ChangeHotkeysStatus(true);
|
|
//hotkeysTimer.Start();
|
|
}
|
|
|
|
autoProfilesTimer = new NonFormTimer();
|
|
//autoProfilesTimer.Elapsed += CheckAutoProfiles;
|
|
autoProfilesTimer.Interval = 1000;
|
|
autoProfilesTimer.AutoReset = false;
|
|
|
|
LoadP();
|
|
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
cBSwipeProfiles.Checked = SwipeProfiles;
|
|
}));
|
|
});
|
|
timerThread.IsBackground = true;
|
|
timerThread.Priority = ThreadPriority.Lowest;
|
|
timerThread.Start();
|
|
|
|
// Have Form_Resize run to honor minimize setting
|
|
Show();
|
|
}
|
|
|
|
private void TBUdpListenAddress_Leave(object sender, EventArgs e)
|
|
{
|
|
setUDPServerListenAddress(tBUdpListenAddress.Text.Trim());
|
|
}
|
|
|
|
private void populateHoverTextDict()
|
|
{
|
|
hoverTextDict.Clear();
|
|
hoverTextDict[cBSwipeProfiles] = Properties.Resources.TwoFingerSwipe;
|
|
hoverTextDict[cBQuickCharge] = Properties.Resources.QuickCharge;
|
|
hoverTextDict[cBCloseMini] = Properties.Resources.CloseMinimize;
|
|
hoverTextDict[uacPictureBox] = Properties.Resources.UACTask;
|
|
hoverTextDict[StartWindowsCheckBox] = Properties.Resources.RunAtStartup;
|
|
}
|
|
|
|
private void AddUACShieldToImage(Image image)
|
|
{
|
|
Bitmap shield = SystemIcons.Shield.ToBitmap();
|
|
shield.MakeTransparent();
|
|
|
|
Graphics g = Graphics.FromImage(image);
|
|
g.CompositingMode = CompositingMode.SourceOver;
|
|
double aspectRatio = shield.Width / (double)shield.Height;
|
|
int finalWidth = Convert.ToInt32(image.Height * aspectRatio);
|
|
int finalHeight = Convert.ToInt32(image.Width / aspectRatio);
|
|
g.DrawImage(shield, new Rectangle(0, 0, finalWidth, finalHeight));
|
|
}
|
|
|
|
private void ClearLastMessage(object sender, EventArgs e)
|
|
{
|
|
lbLastMessage.Text = "";
|
|
lbLastMessage.ForeColor = SystemColors.GrayText;
|
|
}
|
|
|
|
private void ChangeAutoProfilesStatus(bool state)
|
|
{
|
|
if (state)
|
|
{
|
|
autoProfilesTimer.Elapsed += CheckAutoProfiles;
|
|
autoProfilesTimer.Start();
|
|
}
|
|
else
|
|
{
|
|
autoProfilesTimer.Stop();
|
|
autoProfilesTimer.Elapsed -= CheckAutoProfiles;
|
|
}
|
|
}
|
|
|
|
private void ChangeHotkeysStatus(bool state)
|
|
{
|
|
if (state)
|
|
{
|
|
hotkeysTimer.Elapsed += Hotkeys;
|
|
hotkeysTimer.Start();
|
|
}
|
|
else
|
|
{
|
|
hotkeysTimer.Stop();
|
|
hotkeysTimer.Elapsed -= Hotkeys;
|
|
}
|
|
}
|
|
|
|
private void blankControllerTab()
|
|
{
|
|
for (int Index = 0, PadsLen = Pads.Length;
|
|
Index < PadsLen; Index++)
|
|
{
|
|
if (Index < ControlService.DS4_CONTROLLER_COUNT)
|
|
{
|
|
statPB[Index].Visible = false;
|
|
exclusivePB[Index].Visible = false;
|
|
toolTip1.SetToolTip(statPB[Index], "");
|
|
Batteries[Index].Text = Properties.Resources.NA;
|
|
Pads[Index].Text = Properties.Resources.Disconnected;
|
|
Enable_Controls(Index, false);
|
|
}
|
|
}
|
|
|
|
lbNoControllers.Visible = true;
|
|
tLPControllers.Visible = false;
|
|
}
|
|
|
|
private void UpdateTheUpdater()
|
|
{
|
|
if (File.Exists(exepath + "\\Update Files\\DS4Updater.exe"))
|
|
{
|
|
Process[] processes = Process.GetProcessesByName("DS4Updater");
|
|
while (processes.Length > 0)
|
|
{
|
|
Thread.Sleep(500);
|
|
processes = Process.GetProcessesByName("DS4Updater");
|
|
}
|
|
|
|
File.Delete(exepath + "\\DS4Updater.exe");
|
|
File.Move(exepath + "\\Update Files\\DS4Updater.exe", exepath + "\\DS4Updater.exe");
|
|
Directory.Delete(exepath + "\\Update Files");
|
|
}
|
|
}
|
|
|
|
public static bool GetTopWindowName(out string topProcessName, out string topWndTitleName, bool autoProfileTimerCheck = false)
|
|
{
|
|
IntPtr hWnd = GetForegroundWindow();
|
|
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);
|
|
|
|
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);
|
|
|
|
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)
|
|
{
|
|
short evType = Convert.ToInt16(e.NewEvent.GetPropertyValue("EventType"));
|
|
switch (evType)
|
|
{
|
|
// Wakeup from Suspend
|
|
case 7:
|
|
{
|
|
if (btnStartStop.Text == Properties.Resources.StartText && wasrunning)
|
|
{
|
|
DS4LightBar.shuttingdown = false;
|
|
wasrunning = false;
|
|
Program.rootHub.suspending = false;
|
|
Thread.Sleep(16000);
|
|
//this.Invoke((System.Action)(() => BtnStartStop_Clicked()));
|
|
changingService = true;
|
|
SynchronizationContext uiContext = null;
|
|
Invoke((System.Action)(() => {
|
|
uiContext = SynchronizationContext.Current;
|
|
btnStartStop.Enabled = false;
|
|
}));
|
|
|
|
Program.rootHub.Start(uiContext);
|
|
|
|
Invoke((System.Action)(() => {
|
|
ServiceStartupFinish();
|
|
}));
|
|
|
|
changingService = false;
|
|
}
|
|
|
|
break;
|
|
}
|
|
// Entering Suspend
|
|
case 4:
|
|
{
|
|
if (btnStartStop.Text == Properties.Resources.StopText)
|
|
{
|
|
DS4LightBar.shuttingdown = true;
|
|
Program.rootHub.suspending = true;
|
|
changingService = true;
|
|
|
|
Program.rootHub.Stop(true);
|
|
|
|
Invoke((System.Action)(() => {
|
|
ServiceShutdownFinish();
|
|
btnStartStop.Enabled = false;
|
|
}));
|
|
changingService = false;
|
|
wasrunning = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Hotkeys(object sender, EventArgs e)
|
|
{
|
|
hotkeysTimer.Stop();
|
|
|
|
if (SwipeProfiles)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
string slide = Program.rootHub.TouchpadSlide(i);
|
|
if (slide == "left")
|
|
{
|
|
int ind = i;
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
if (cbs[ind].SelectedIndex <= 0)
|
|
cbs[ind].SelectedIndex = cbs[ind].Items.Count - 2;
|
|
else
|
|
cbs[ind].SelectedIndex--;
|
|
}));
|
|
}
|
|
else if (slide == "right")
|
|
{
|
|
int ind = i;
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
if (cbs[ind].SelectedIndex == cbs[ind].Items.Count - 2)
|
|
cbs[ind].SelectedIndex = 0;
|
|
else
|
|
cbs[ind].SelectedIndex++;
|
|
}));
|
|
}
|
|
|
|
if (slide.Contains("t"))
|
|
{
|
|
int ind = i;
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
ShowNotification(this, Properties.Resources.UsingProfile.Replace("*number*", (ind + 1).ToString()).Replace("*Profile name*", cbs[ind].Text));
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bat != null && bat.HasExited && runningBat)
|
|
{
|
|
Process.Start("explorer.exe");
|
|
bat = null;
|
|
runningBat = false;
|
|
}
|
|
|
|
hotkeysTimer.Start();
|
|
}
|
|
|
|
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();
|
|
|
|
if (GetTopWindowName(out topProcessName, out topWindowTitle, true))
|
|
{
|
|
// 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++)
|
|
{
|
|
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)
|
|
{
|
|
newProfileName[j] = proprofiles[j][i]; // j is controller index, i is filename
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
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)
|
|
{
|
|
turnOffTemp = false;
|
|
if (btnStartStop.Text == Properties.Resources.StartText)
|
|
{
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
BtnStartStop_Clicked();
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
autoProfilesTimer.Start();
|
|
//GC.Collect();
|
|
}
|
|
|
|
public void LoadP()
|
|
{
|
|
XmlDocument doc = new XmlDocument();
|
|
proprofiles = new List<string>[4] { new List<string>(), new List<string>(),
|
|
new List<string>(), new List<string>() };
|
|
turnOffTempProfiles = new List<bool>();
|
|
programpaths.Clear();
|
|
if (!File.Exists(appdatapath + "\\Auto Profiles.xml"))
|
|
return;
|
|
|
|
doc.Load(appdatapath + "\\Auto Profiles.xml");
|
|
XmlNodeList programslist = doc.SelectNodes("Programs/Program");
|
|
foreach (XmlNode x in programslist)
|
|
programpaths.Add(new ProgramPathItem(x.Attributes["path"]?.Value, x.Attributes["title"]?.Value));
|
|
|
|
int nodeIdx=0;
|
|
foreach (ProgramPathItem pathItem in programpaths)
|
|
{
|
|
XmlNode item;
|
|
|
|
nodeIdx++;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
item = doc.SelectSingleNode($"/Programs/Program[{nodeIdx}]/Controller{i+1}");
|
|
if (item != null)
|
|
proprofiles[i].Add(item.InnerText);
|
|
else
|
|
proprofiles[i].Add("(none)");
|
|
}
|
|
|
|
item = doc.SelectSingleNode($"/Programs/Program[{nodeIdx}]/TurnOff");
|
|
|
|
bool turnOff;
|
|
if (item != null && bool.TryParse(item.InnerText, out turnOff))
|
|
turnOffTempProfiles.Add(turnOff);
|
|
else
|
|
turnOffTempProfiles.Add(false);
|
|
}
|
|
|
|
int pathCount = programpaths.Count;
|
|
bool timerEnabled = autoProfilesTimer.Enabled;
|
|
if (pathCount > 0 && !timerEnabled)
|
|
{
|
|
ChangeAutoProfilesStatus(true);
|
|
//autoProfilesTimer.Start();
|
|
}
|
|
else if (pathCount == 0 && timerEnabled)
|
|
{
|
|
//autoProfilesTimer.Stop();
|
|
ChangeAutoProfilesStatus(false);
|
|
}
|
|
}
|
|
|
|
string originalsettingstext;
|
|
private void CheckDrivers()
|
|
{
|
|
originalsettingstext = tabSettings.Text;
|
|
bool deriverinstalled = false;
|
|
deriverinstalled = Global.IsViGEmBusInstalled();
|
|
if (!deriverinstalled)
|
|
{
|
|
Process p = new Process();
|
|
p.StartInfo.FileName = Assembly.GetExecutingAssembly().Location;
|
|
p.StartInfo.Arguments = "driverinstall";
|
|
p.StartInfo.Verb = "runas";
|
|
try { p.Start(); }
|
|
catch { }
|
|
}
|
|
}
|
|
|
|
private void Check_Version(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
|
|
{
|
|
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
|
|
string version = fvi.FileVersion;
|
|
string newversion = File.ReadAllText(appdatapath + "\\version.txt").Trim();
|
|
bool launchUpdate = false;
|
|
if (!string.IsNullOrWhiteSpace(newversion) && version.Replace(',', '.').CompareTo(newversion) != 0)
|
|
{
|
|
DialogResult result = DialogResult.No;
|
|
this.Invoke((System.Action)(() =>
|
|
{
|
|
result = MessageBox.Show(Properties.Resources.DownloadVersion.Replace("*number*", newversion),
|
|
Properties.Resources.DS4Update, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
|
}));
|
|
|
|
if (result == DialogResult.Yes)
|
|
{
|
|
launchUpdate = true;
|
|
if (!File.Exists(exepath + "\\DS4Updater.exe") || (File.Exists(exepath + "\\DS4Updater.exe")
|
|
&& (FileVersionInfo.GetVersionInfo(exepath + "\\DS4Updater.exe").FileVersion.CompareTo(UPDATER_VERSION) != 0)))
|
|
{
|
|
Uri url2 = new Uri($"https://github.com/Ryochan7/DS4Updater/releases/download/v{UPDATER_VERSION}/{updaterExe}");
|
|
WebClient wc2 = new WebClient();
|
|
if (appdatapath == exepath)
|
|
{
|
|
wc2.DownloadFile(url2, exepath + "\\DS4Updater.exe");
|
|
}
|
|
else
|
|
{
|
|
this.BeginInvoke((System.Action)(() => MessageBox.Show(Properties.Resources.PleaseDownloadUpdater)));
|
|
Process.Start($"https://github.com/Ryochan7/DS4Updater/releases/download/v{UPDATER_VERSION}/{updaterExe}");
|
|
launchUpdate = false;
|
|
}
|
|
}
|
|
|
|
if (launchUpdate)
|
|
{
|
|
using (Process p = new Process())
|
|
{
|
|
p.StartInfo.FileName = exepath + "\\DS4Updater.exe";
|
|
p.StartInfo.Arguments = "-autolaunch";
|
|
if (AdminNeeded())
|
|
p.StartInfo.Verb = "runas";
|
|
|
|
try { p.Start(); }
|
|
catch (Exception) { launchUpdate = false; }
|
|
}
|
|
}
|
|
|
|
if (launchUpdate)
|
|
{
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
contextclose = true;
|
|
Close();
|
|
}));
|
|
}
|
|
}
|
|
else
|
|
File.Delete(appdatapath + "\\version.txt");
|
|
}
|
|
else
|
|
File.Delete(appdatapath + "\\version.txt");
|
|
}
|
|
|
|
public void RefreshProfiles()
|
|
{
|
|
try
|
|
{
|
|
profilenames.Clear();
|
|
string[] profiles = Directory.GetFiles(appdatapath + @"\Profiles\");
|
|
foreach (string s in profiles)
|
|
{
|
|
if (s.EndsWith(".xml"))
|
|
profilenames.Add(Path.GetFileNameWithoutExtension(s));
|
|
}
|
|
|
|
lBProfiles.Items.Clear();
|
|
lBProfiles.Items.AddRange(profilenames.ToArray());
|
|
if (lBProfiles.Items.Count == 0)
|
|
{
|
|
SaveProfile(0, "Default");
|
|
ProfilePath[0] = OlderProfilePath[0] = "Default";
|
|
RefreshProfiles();
|
|
return;
|
|
}
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
cbs[i].Items.Clear();
|
|
shortcuts[i].DropDownItems.Clear();
|
|
cbs[i].Items.AddRange(profilenames.ToArray());
|
|
foreach (string s in profilenames)
|
|
shortcuts[i].DropDownItems.Add(s);
|
|
|
|
for (int j = 0, itemCount = cbs[i].Items.Count; j < itemCount; j++)
|
|
{
|
|
if (cbs[i].Items[j].ToString() == Path.GetFileNameWithoutExtension(ProfilePath[i]))
|
|
{
|
|
cbs[i].SelectedIndex = j;
|
|
((ToolStripMenuItem)shortcuts[i].DropDownItems[j]).Checked = true;
|
|
ProfilePath[i] = OlderProfilePath[i] = cbs[i].Text;
|
|
shortcuts[i].Text = Properties.Resources.ContextEdit.Replace("*number*", (i + 1).ToString());
|
|
ebns[i].Text = Properties.Resources.EditProfile;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
cbs[i].Text = "(" + Properties.Resources.NoProfileLoaded + ")";
|
|
shortcuts[i].Text = Properties.Resources.ContextNew.Replace("*number*", (i + 1).ToString());
|
|
ebns[i].Text = Properties.Resources.New;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (DirectoryNotFoundException)
|
|
{
|
|
Directory.CreateDirectory(appdatapath + @"\Profiles\");
|
|
SaveProfile(0, "Default");
|
|
ProfilePath[0] = OlderProfilePath[0] = "Default";
|
|
RefreshProfiles();
|
|
return;
|
|
}
|
|
finally
|
|
{
|
|
if (!(cbs[0].Items.Count > 0 && cbs[0].Items[cbs[0].Items.Count - 1].ToString() == "+" + Properties.Resources.PlusNewProfile))
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
cbs[i].Items.Add("+" + Properties.Resources.PlusNewProfile);
|
|
shortcuts[i].DropDownItems.Add("-");
|
|
shortcuts[i].DropDownItems.Add("+" + Properties.Resources.PlusNewProfile);
|
|
}
|
|
RefreshAutoProfilesPage();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public void RefreshAutoProfilesPage()
|
|
{
|
|
tabAutoProfiles.Controls.Clear();
|
|
WinProgs WP = new WinProgs(profilenames.ToArray(), this);
|
|
WP.TopLevel = false;
|
|
WP.FormBorderStyle = FormBorderStyle.None;
|
|
WP.Visible = true;
|
|
WP.Dock = DockStyle.Fill;
|
|
tabAutoProfiles.Controls.Add(WP);
|
|
}
|
|
|
|
protected void LogDebug(DateTime Time, String Data, bool warning)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
LogDebugDelegate d = new LogDebugDelegate(LogDebug);
|
|
try
|
|
{
|
|
// Make sure to invoke method asynchronously instead of waiting for result
|
|
this.BeginInvoke(d, new object[] { Time, Data, warning });
|
|
//this.Invoke(d, new object[] { Time, Data, warning });
|
|
}
|
|
catch { }
|
|
}
|
|
else
|
|
{
|
|
String Posted = Time.ToString("G");
|
|
lvDebug.Items.Add(new ListViewItem(new String[] { Posted, Data })).EnsureVisible();
|
|
if (warning) lvDebug.Items[lvDebug.Items.Count - 1].ForeColor = Color.Red;
|
|
// Added alternative
|
|
lbLastMessage.Text = Data;
|
|
lbLastMessage.ForeColor = (warning ? Color.Red : SystemColors.GrayText);
|
|
}
|
|
}
|
|
|
|
protected void ShowNotification(object sender, DebugEventArgs args)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
NotificationDelegate d = new NotificationDelegate(ShowNotification);
|
|
|
|
try
|
|
{
|
|
// Make sure to invoke method asynchronously instead of waiting for result
|
|
this.BeginInvoke(d, new object[] { sender, args });
|
|
}
|
|
catch { }
|
|
}
|
|
else
|
|
{
|
|
if (Form.ActiveForm != this && (Notifications == 2 || (Notifications == 1 && args.Warning) || sender != null))
|
|
{
|
|
this.notifyIcon1.BalloonTipText = args.Data;
|
|
notifyIcon1.BalloonTipTitle = "DS4Windows";
|
|
notifyIcon1.ShowBalloonTip(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void ShowNotification(object sender, string text)
|
|
{
|
|
if (Form.ActiveForm != this && Notifications == 2)
|
|
{
|
|
this.notifyIcon1.BalloonTipText = text;
|
|
notifyIcon1.BalloonTipTitle = "DS4Windows";
|
|
notifyIcon1.ShowBalloonTip(1);
|
|
}
|
|
}
|
|
|
|
protected void Form_Resize(object sender, EventArgs e)
|
|
{
|
|
bool minToTask = GetMinToTaskbar();
|
|
if (FormWindowState.Minimized == WindowState && !minToTask)
|
|
{
|
|
Hide();
|
|
ShowInTaskbar = false;
|
|
FormBorderStyle = FormBorderStyle.None;
|
|
}
|
|
|
|
else if (FormWindowState.Normal == WindowState && !minToTask)
|
|
{
|
|
//mAllowVisible = true;
|
|
Show();
|
|
ShowInTaskbar = true;
|
|
FormBorderStyle = FormBorderStyle.Sizable;
|
|
}
|
|
|
|
if (WindowState != FormWindowState.Minimized)
|
|
{
|
|
FormWidth = Width;
|
|
FormHeight = Height;
|
|
}
|
|
|
|
chData.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
|
|
}
|
|
|
|
private void TrackLocationChanged(object sender, EventArgs e)
|
|
{
|
|
if (WindowState != FormWindowState.Minimized)
|
|
{
|
|
FormLocationX = Location.X;
|
|
FormLocationY = Location.Y;
|
|
}
|
|
}
|
|
|
|
private void BtnStartStop_Click(object sender, EventArgs e)
|
|
{
|
|
BtnStartStop_Clicked();
|
|
}
|
|
|
|
private void ServiceStartup(bool log)
|
|
{
|
|
var uiContext = SynchronizationContext.Current;
|
|
changingService = true;
|
|
btnStartStop.Enabled = false;
|
|
TaskRunner.Run(() =>
|
|
{
|
|
//Thread.CurrentThread.Priority = ThreadPriority.AboveNormal;
|
|
Program.rootHub.Start(uiContext, log);
|
|
Invoke((System.Action)(() => { ServiceStartupFinish(); }));
|
|
changingService = false;
|
|
});
|
|
}
|
|
|
|
private void ServiceStartupFinish()
|
|
{
|
|
if (SwipeProfiles && !hotkeysTimer.Enabled)
|
|
{
|
|
ChangeHotkeysStatus(true);
|
|
//hotkeysTimer.Start();
|
|
}
|
|
|
|
if (programpaths.Count > 0 && !autoProfilesTimer.Enabled)
|
|
{
|
|
ChangeAutoProfilesStatus(true);
|
|
//autoProfilesTimer.Start();
|
|
}
|
|
|
|
startToolStripMenuItem.Text = btnStartStop.Text = Properties.Resources.StopText;
|
|
btnStartStop.Enabled = true;
|
|
}
|
|
|
|
private void ServiceShutdown(bool log)
|
|
{
|
|
changingService = true;
|
|
btnStartStop.Enabled = false;
|
|
TaskRunner.Run(() =>
|
|
{
|
|
Program.rootHub.Stop(log);
|
|
Invoke((System.Action)(() => { ServiceShutdownFinish(); }));
|
|
changingService = false;
|
|
});
|
|
}
|
|
|
|
private void ServiceShutdownFinish()
|
|
{
|
|
ChangeAutoProfilesStatus(false);
|
|
ChangeHotkeysStatus(false);
|
|
//hotkeysTimer.Stop();
|
|
//autoProfilesTimer.Stop();
|
|
startToolStripMenuItem.Text = btnStartStop.Text = Properties.Resources.StartText;
|
|
btnStartStop.Enabled = true;
|
|
blankControllerTab();
|
|
populateFullNotifyText();
|
|
}
|
|
|
|
public void BtnStartStop_Clicked(bool log = true)
|
|
{
|
|
if (btnStartStop.Text == Properties.Resources.StartText)
|
|
{
|
|
ServiceStartup(log);
|
|
}
|
|
else if (btnStartStop.Text == Properties.Resources.StopText)
|
|
{
|
|
blankControllerTab();
|
|
ServiceShutdown(log);
|
|
}
|
|
}
|
|
|
|
protected void BtnClear_Click(object sender, EventArgs e)
|
|
{
|
|
lvDebug.Items.Clear();
|
|
lbLastMessage.Text = string.Empty;
|
|
}
|
|
|
|
private bool inHotPlug = false;
|
|
private int hotplugCounter = 0;
|
|
private object hotplugCounterLock = new object();
|
|
private const int DBT_DEVNODES_CHANGED = 0x0007;
|
|
private const int DBT_DEVICEARRIVAL = 0x8000;
|
|
private const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
|
|
protected override void WndProc(ref Message m)
|
|
{
|
|
switch (m.Msg)
|
|
{
|
|
case Util.WM_CREATE:
|
|
{
|
|
Guid hidGuid = new Guid();
|
|
NativeMethods.HidD_GetHidGuid(ref hidGuid);
|
|
bool result = Util.RegisterNotify(this.Handle, hidGuid, ref regHandle);
|
|
if (!result)
|
|
{
|
|
ScpForm_Closing(this,
|
|
new FormClosingEventArgs(CloseReason.ApplicationExitCall, false));
|
|
}
|
|
break;
|
|
}
|
|
case Util.WM_DEVICECHANGE:
|
|
{
|
|
if (runHotPlug)
|
|
{
|
|
Int32 Type = m.WParam.ToInt32();
|
|
if (Type == DBT_DEVICEARRIVAL ||
|
|
Type == DBT_DEVICEREMOVECOMPLETE)
|
|
{
|
|
lock (hotplugCounterLock)
|
|
{
|
|
hotplugCounter++;
|
|
}
|
|
|
|
if (!inHotPlug)
|
|
{
|
|
inHotPlug = true;
|
|
TaskRunner.Run(() => { InnerHotplug2(); });
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case WM_QUERYENDSESSION:
|
|
{
|
|
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;
|
|
}
|
|
|
|
// If this is WM_QUERYENDSESSION, the closing event should be
|
|
// raised in the base WndProc.
|
|
base.WndProc(ref m);
|
|
}
|
|
|
|
private void InnerHotplug2()
|
|
{
|
|
inHotPlug = true;
|
|
|
|
bool loopHotplug = false;
|
|
lock (hotplugCounterLock)
|
|
{
|
|
loopHotplug = hotplugCounter > 0;
|
|
}
|
|
|
|
while (loopHotplug == true)
|
|
{
|
|
Thread.Sleep(1500);
|
|
Program.rootHub.HotPlug();
|
|
//TaskRunner.Run(() => { Program.rootHub.HotPlug(uiContext); });
|
|
lock (hotplugCounterLock)
|
|
{
|
|
hotplugCounter--;
|
|
loopHotplug = hotplugCounter > 0;
|
|
}
|
|
}
|
|
|
|
inHotPlug = false;
|
|
}
|
|
|
|
protected void BatteryStatusUpdate(object sender, BatteryReportArgs args)
|
|
{
|
|
string battery;
|
|
int level = args.getLevel();
|
|
bool charging = args.isCharging();
|
|
int Index = args.getIndex();
|
|
if (charging)
|
|
{
|
|
if (level >= 100)
|
|
battery = Properties.Resources.Full;
|
|
else
|
|
battery = level + "%+";
|
|
}
|
|
else
|
|
{
|
|
battery = level + "%";
|
|
}
|
|
|
|
Batteries[args.getIndex()].Text = battery;
|
|
|
|
// Update device battery level display for tray icon
|
|
generateDeviceNotifyText(args.getIndex());
|
|
populateNotifyText();
|
|
}
|
|
|
|
protected void populateFullNotifyText()
|
|
{
|
|
for (int i = 0; i < ControlService.DS4_CONTROLLER_COUNT; i++)
|
|
{
|
|
string temp = Program.rootHub.getShortDS4ControllerInfo(i);
|
|
if (temp != Properties.Resources.NoneText)
|
|
{
|
|
notifyText[i + 1] = (i + 1) + ": " + temp;
|
|
}
|
|
else
|
|
{
|
|
notifyText[i + 1] = string.Empty;
|
|
}
|
|
}
|
|
|
|
populateNotifyText();
|
|
}
|
|
|
|
protected void generateDeviceNotifyText(int index)
|
|
{
|
|
string temp = Program.rootHub.getShortDS4ControllerInfo(index);
|
|
if (temp != Properties.Resources.NoneText)
|
|
{
|
|
notifyText[index + 1] = (index + 1) + ": " + temp;
|
|
}
|
|
else
|
|
{
|
|
notifyText[index + 1] = string.Empty;
|
|
}
|
|
}
|
|
|
|
protected void populateNotifyText()
|
|
{
|
|
string tooltip = notifyText[0];
|
|
for (int i = 1; i < 5; i++)
|
|
{
|
|
string temp = notifyText[i];
|
|
if (!string.IsNullOrEmpty(temp))
|
|
{
|
|
tooltip += "\n" + notifyText[i];
|
|
}
|
|
}
|
|
|
|
notifyIcon1.Text = tooltip.Length > 63 ? tooltip.Substring(0, 63) : tooltip; // Carefully stay under the 63 character limit.
|
|
}
|
|
|
|
protected void DeviceSerialChanged(object sender, SerialChangeArgs args)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
DeviceSerialChangedDelegate d = new DeviceSerialChangedDelegate(DeviceSerialChanged);
|
|
this.BeginInvoke(d, new object[] { sender, args });
|
|
}
|
|
else
|
|
{
|
|
int devIndex = args.getIndex();
|
|
string serial = args.getSerial();
|
|
DS4Device device = (devIndex >= 0 && devIndex < ControlService.DS4_CONTROLLER_COUNT) ?
|
|
Program.rootHub.DS4Controllers[devIndex] : null;
|
|
if (device != null)
|
|
{
|
|
Pads[devIndex].Text = serial;
|
|
if (device.isSynced())
|
|
{
|
|
linkedProfileCB[devIndex].Enabled = true;
|
|
}
|
|
else
|
|
{
|
|
linkedProfileCB[devIndex].Enabled = false;
|
|
}
|
|
|
|
if (device.isValidSerial() && containsLinkedProfile(device.getMacAddress()))
|
|
{
|
|
ProfilePath[devIndex] = getLinkedProfile(device.getMacAddress());
|
|
int profileIndex = cbs[devIndex].FindString(ProfilePath[devIndex]);
|
|
if (profileIndex >= 0)
|
|
{
|
|
cbs[devIndex].SelectedIndex = profileIndex;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ProfilePath[devIndex] = OlderProfilePath[devIndex];
|
|
}
|
|
|
|
linkedProfileCB[devIndex].Checked = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
protected void DeviceStatusChanged(object sender, DeviceStatusChangeEventArgs args)
|
|
{
|
|
if (this.InvokeRequired)
|
|
{
|
|
DeviceStatusChangedDelegate d = new DeviceStatusChangedDelegate(DeviceStatusChanged);
|
|
this.BeginInvoke(d, new object[] { sender, args });
|
|
}
|
|
else
|
|
{
|
|
bool nocontrollers = true;
|
|
for (int i = 0, arlen = Program.rootHub.DS4Controllers.Length; nocontrollers && i < arlen; i++)
|
|
{
|
|
DS4Device dev = Program.rootHub.DS4Controllers[i];
|
|
if (dev != null)
|
|
{
|
|
nocontrollers = false;
|
|
}
|
|
}
|
|
|
|
//string tooltip = "DS4Windows v" + FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
|
|
int Index = args.getIndex();
|
|
if (Index >= 0 && Index < ControlService.DS4_CONTROLLER_COUNT)
|
|
{
|
|
Pads[Index].Text = Program.rootHub.getDS4MacAddress(Index);
|
|
|
|
linkedProfileCB[Index].CheckedChanged -= linkCB_CheckedChanged;
|
|
if (DS4Device.isValidSerial(Pads[Index].Text))
|
|
{
|
|
linkedProfileCB[Index].Checked = containsLinkedProfile(Pads[Index].Text);
|
|
linkedProfileCB[Index].Enabled = true;
|
|
}
|
|
else
|
|
{
|
|
linkedProfileCB[Index].Checked = false;
|
|
linkedProfileCB[Index].Enabled = false;
|
|
}
|
|
|
|
linkedProfileCB[Index].CheckedChanged += linkCB_CheckedChanged;
|
|
|
|
switch (Program.rootHub.getDS4Status(Index))
|
|
{
|
|
case "USB": statPB[Index].Visible = true; statPB[Index].Image = Properties.Resources.USB; toolTip1.SetToolTip(statPB[Index], ""); break;
|
|
case "BT": statPB[Index].Visible = true; statPB[Index].Image = Properties.Resources.BT; toolTip1.SetToolTip(statPB[Index], "Right click to disconnect"); break;
|
|
case "SONYWA": statPB[Index].Visible = true; statPB[Index].Image = Properties.Resources.BT; toolTip1.SetToolTip(statPB[Index], "Right click to disconnect"); break;
|
|
default: statPB[Index].Visible = false; toolTip1.SetToolTip(statPB[Index], ""); break;
|
|
}
|
|
|
|
DS4Device dev = Program.rootHub.DS4Controllers[Index];
|
|
if (dev != null)
|
|
{
|
|
exclusivePB[Index].Visible = true;
|
|
exclusivePB[Index].Image = dev.IsExclusive ? Properties.Resources._checked : Properties.Resources.cancel;
|
|
}
|
|
else
|
|
{
|
|
exclusivePB[Index].Visible = false;
|
|
exclusivePB[Index].Image = Properties.Resources.cancel;
|
|
}
|
|
|
|
Batteries[Index].Text = Program.rootHub.getDS4Battery(Index);
|
|
int profileIndex = cbs[Index].FindStringExact(ProfilePath[Index]);
|
|
if (profileIndex >= 0)
|
|
{
|
|
cbs[Index].SelectedValueChanged -= Profile_Changed;
|
|
cbs[Index].SelectedIndex = profileIndex;
|
|
cbs[Index].SelectedValueChanged += Profile_Changed;
|
|
}
|
|
|
|
if (UseCustomLed[Index])
|
|
lights[Index].BackColor = CustomColor[Index].ToColorA;
|
|
else
|
|
lights[Index].BackColor = MainColor[Index].ToColorA;
|
|
|
|
if (Pads[Index].Text != String.Empty)
|
|
{
|
|
if (runningBat)
|
|
{
|
|
SendKeys.Send("A");
|
|
runningBat = false;
|
|
}
|
|
|
|
Pads[Index].Enabled = true;
|
|
if (Pads[Index].Text != Properties.Resources.Connecting)
|
|
{
|
|
Enable_Controls(Index, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Pads[Index].Text = Properties.Resources.Disconnected;
|
|
Enable_Controls(Index, false);
|
|
}
|
|
|
|
generateDeviceNotifyText(Index);
|
|
populateNotifyText();
|
|
}
|
|
|
|
lbNoControllers.Visible = nocontrollers;
|
|
tLPControllers.Visible = !nocontrollers;
|
|
}
|
|
}
|
|
|
|
protected void ControllerRemovedChange(object sender, ControllerRemovedArgs args)
|
|
{
|
|
int devIndex = args.getIndex();
|
|
Pads[devIndex].Text = Properties.Resources.Disconnected;
|
|
Enable_Controls(devIndex, false);
|
|
statPB[devIndex].Visible = false;
|
|
exclusivePB[devIndex].Visible = false;
|
|
toolTip1.SetToolTip(statPB[devIndex], "");
|
|
|
|
DS4Device[] devices = Program.rootHub.DS4Controllers;
|
|
int controllerLen = devices.Length;
|
|
bool nocontrollers = true;
|
|
for (Int32 i = 0, PadsLen = Pads.Length; nocontrollers && i < PadsLen; i++)
|
|
{
|
|
DS4Device d = devices[i];
|
|
if (d != null)
|
|
{
|
|
nocontrollers = false;
|
|
}
|
|
}
|
|
|
|
lbNoControllers.Visible = nocontrollers;
|
|
tLPControllers.Visible = !nocontrollers;
|
|
|
|
// Update device battery level display for tray icon
|
|
generateDeviceNotifyText(devIndex);
|
|
populateNotifyText();
|
|
}
|
|
|
|
private void pBStatus_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
int i = Convert.ToInt32(((PictureBox)sender).Tag);
|
|
DS4Device d = Program.rootHub.DS4Controllers[i];
|
|
if (d != null)
|
|
{
|
|
if (e.Button == MouseButtons.Right && Program.rootHub.getDS4Status(i) == "BT" && !d.Charging)
|
|
{
|
|
d.DisconnectBT();
|
|
}
|
|
else if (e.Button == MouseButtons.Right &&
|
|
Program.rootHub.getDS4Status(i) == "SONYWA" && !d.Charging)
|
|
{
|
|
d.DisconnectDongle();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void Enable_Controls(int device, bool on)
|
|
{
|
|
DS4Device dev = Program.rootHub.DS4Controllers[device];
|
|
ConnectionType conType = ConnectionType.USB;
|
|
if (dev != null)
|
|
conType = dev.ConnectionType;
|
|
|
|
Pads[device].Visible = on;
|
|
ebns[device].Visible = on;
|
|
lights[device].Visible = on;
|
|
cbs[device].Visible = on;
|
|
shortcuts[device].Visible = on;
|
|
Batteries[device].Visible = on;
|
|
linkedProfileCB[device].Visible = on;
|
|
disconnectShortcuts[device].Visible = on && conType != ConnectionType.USB;
|
|
}
|
|
|
|
protected void On_Debug(object sender, DebugEventArgs e)
|
|
{
|
|
LogDebug(e.Time, e.Data, e.Warning);
|
|
}
|
|
|
|
private void lBProfiles_MouseDoubleClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (lBProfiles.SelectedIndex >= 0)
|
|
ShowOptions(4, lBProfiles.SelectedItem.ToString());
|
|
}
|
|
|
|
|
|
private void lBProfiles_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (lBProfiles.SelectedIndex >= 0 && optPop && !opt.Visible)
|
|
{
|
|
if (e.KeyValue == 13)
|
|
ShowOptions(4, lBProfiles.SelectedItem.ToString());
|
|
else if (e.KeyValue == 46)
|
|
tsBDeleteProfle_Click(this, e);
|
|
else if (e.KeyValue == 68 && e.Modifiers == Keys.Control)
|
|
tSBDupProfile_Click(this, e);
|
|
}
|
|
}
|
|
|
|
private void assignToController1ToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
cbs[0].SelectedIndex = lBProfiles.SelectedIndex;
|
|
}
|
|
|
|
private void assignToController2ToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
cbs[1].SelectedIndex = lBProfiles.SelectedIndex;
|
|
}
|
|
|
|
private void assignToController3ToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
cbs[2].SelectedIndex = lBProfiles.SelectedIndex;
|
|
}
|
|
|
|
private void assignToController4ToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
cbs[3].SelectedIndex = lBProfiles.SelectedIndex;
|
|
}
|
|
|
|
private void tsBNewProfile_Click(object sender, EventArgs e) //Also used for context menu
|
|
{
|
|
ShowOptions(4, "");
|
|
}
|
|
|
|
private void tsBNEditProfile_Click(object sender, EventArgs e)
|
|
{
|
|
if (lBProfiles.SelectedIndex >= 0)
|
|
ShowOptions(4, lBProfiles.SelectedItem.ToString());
|
|
}
|
|
|
|
private void tsBDeleteProfle_Click(object sender, EventArgs e)
|
|
{
|
|
if (lBProfiles.SelectedIndex >= 0)
|
|
{
|
|
string filename = lBProfiles.SelectedItem.ToString();
|
|
if (MessageBox.Show(Properties.Resources.ProfileCannotRestore.Replace("*Profile name*", "\"" + filename + "\""),
|
|
Properties.Resources.DeleteProfile,
|
|
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
|
|
{
|
|
File.Delete(appdatapath + @"\Profiles\" + filename + ".xml");
|
|
RefreshProfiles();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void tSBDupProfile_Click(object sender, EventArgs e)
|
|
{
|
|
string filename = "";
|
|
if (lBProfiles.SelectedIndex >= 0)
|
|
{
|
|
filename = lBProfiles.SelectedItem.ToString();
|
|
DupBox MTB = new DupBox(filename, this);
|
|
MTB.TopLevel = false;
|
|
MTB.Dock = DockStyle.Top;
|
|
MTB.Visible = true;
|
|
MTB.FormBorderStyle = FormBorderStyle.None;
|
|
tabProfiles.Controls.Add(MTB);
|
|
lBProfiles.SendToBack();
|
|
toolStrip1.SendToBack();
|
|
toolStrip1.Enabled = false;
|
|
lBProfiles.Enabled = false;
|
|
MTB.FormClosed += delegate { toolStrip1.Enabled = true; lBProfiles.Enabled = true; };
|
|
}
|
|
}
|
|
|
|
private void tSBImportProfile_Click(object sender, EventArgs e)
|
|
{
|
|
if (appdatapath == Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName)
|
|
openProfiles.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\DS4Tool" + @"\Profiles\";
|
|
else
|
|
openProfiles.InitialDirectory = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName + @"\Profiles\";
|
|
|
|
if (openProfiles.ShowDialog() == DialogResult.OK)
|
|
{
|
|
string[] files = openProfiles.FileNames;
|
|
for (int i = 0, arlen = files.Length; i < arlen; i++)
|
|
File.Copy(openProfiles.FileNames[i], appdatapath + "\\Profiles\\" + Path.GetFileName(files[i]), true);
|
|
|
|
RefreshProfiles();
|
|
}
|
|
}
|
|
|
|
private void tSBExportProfile_Click(object sender, EventArgs e)
|
|
{
|
|
if (lBProfiles.SelectedIndex >= 0)
|
|
{
|
|
Stream stream;
|
|
Stream profile = new StreamReader(appdatapath + "\\Profiles\\" + lBProfiles.SelectedItem.ToString() + ".xml").BaseStream;
|
|
if (saveProfiles.ShowDialog() == DialogResult.OK)
|
|
{
|
|
if ((stream = saveProfiles.OpenFile()) != null)
|
|
{
|
|
profile.CopyTo(stream);
|
|
profile.Close();
|
|
stream.Close();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ShowOptions(int devID, string profile)
|
|
{
|
|
Show();
|
|
|
|
lBProfiles.Visible = false;
|
|
|
|
WindowState = FormWindowState.Normal;
|
|
toolStrip1.Enabled = false;
|
|
tSOptions.Visible = true;
|
|
toolStrip1.Visible = false;
|
|
if (profile != "")
|
|
tSTBProfile.Text = profile;
|
|
else
|
|
tSTBProfile.Text = "<" + Properties.Resources.TypeProfileName + ">";
|
|
|
|
opt = new Options(this);
|
|
opt.Icon = this.Icon;
|
|
opt.TopLevel = false;
|
|
opt.Dock = DockStyle.Fill;
|
|
opt.FormBorderStyle = FormBorderStyle.None;
|
|
|
|
tabProfiles.Controls.Add(opt);
|
|
optPop = true;
|
|
//opt.Dock = DockStyle.Fill;
|
|
//lBProfiles.SendToBack();
|
|
//toolStrip1.SendToBack();
|
|
//tSOptions.SendToBack();
|
|
opt.BringToFront();
|
|
oldsize = Size;
|
|
{
|
|
if (Size.Height < (int)(90 * dpiy) + Options.mSize.Height)
|
|
Size = new Size(Size.Width, (int)(90 * dpiy) + Options.mSize.Height);
|
|
|
|
if (Size.Width < (int)(20 * dpix) + Options.mSize.Width)
|
|
Size = new Size((int)(20 * dpix) + Options.mSize.Width, Size.Height);
|
|
}
|
|
|
|
opt.Reload(devID, profile);
|
|
|
|
opt.inputtimer.Start();
|
|
opt.Visible = true;
|
|
|
|
tabMain.SelectedIndex = 1;
|
|
}
|
|
|
|
public void OptionsClosed()
|
|
{
|
|
RefreshProfiles();
|
|
|
|
if (!lbNoControllers.Visible)
|
|
tabMain.SelectedIndex = 0;
|
|
|
|
Size = oldsize;
|
|
oldsize = new Size(0, 0);
|
|
tSBKeepSize.Text = Properties.Resources.KeepThisSize;
|
|
tSBKeepSize.Image = Properties.Resources.size;
|
|
tSBKeepSize.Enabled = true;
|
|
tSOptions.Visible = false;
|
|
toolStrip1.Visible = true;
|
|
toolStrip1.Enabled = true;
|
|
lbLastMessage.ForeColor = SystemColors.GrayText;
|
|
|
|
opt.Dock = DockStyle.None;
|
|
tabProfiles.Controls.Remove(opt);
|
|
optPop = false; opt = null;
|
|
|
|
lBProfiles.Visible = true;
|
|
}
|
|
|
|
private void editButtons_Click(object sender, EventArgs e)
|
|
{
|
|
Button bn = (Button)sender;
|
|
//int i = Int32.Parse(bn.Tag.ToString());
|
|
int i = Convert.ToInt32(bn.Tag);
|
|
string profileText = cbs[i].Text;
|
|
if (profileText != "(" + Properties.Resources.NoProfileLoaded + ")")
|
|
ShowOptions(i, profileText);
|
|
else
|
|
ShowOptions(i, "");
|
|
}
|
|
|
|
private void editMenu_Click(object sender, EventArgs e)
|
|
{
|
|
Show();
|
|
WindowState = FormWindowState.Normal;
|
|
ToolStripMenuItem em = (ToolStripMenuItem)sender;
|
|
int i = Convert.ToInt32(em.Tag);
|
|
if (em.Text == Properties.Resources.ContextNew.Replace("*number*", (i + 1).ToString()))
|
|
ShowOptions(i, "");
|
|
else
|
|
{
|
|
for (int t = 0, itemCount = em.DropDownItems.Count - 2; t < itemCount; t++)
|
|
{
|
|
if (((ToolStripMenuItem)em.DropDownItems[t]).Checked)
|
|
ShowOptions(i, ((ToolStripMenuItem)em.DropDownItems[t]).Text);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void lnkControllers_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
{
|
|
Process.Start("control", "joy.cpl");
|
|
}
|
|
|
|
private void hideDS4CheckBox_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
// Prevent the Game Controllers window from throwing an error when controllers are un/hidden
|
|
Process[] rundll64 = Process.GetProcessesByName("rundll64");
|
|
foreach (Process rundll64Instance in rundll64)
|
|
{
|
|
foreach (ProcessModule module in rundll64Instance.Modules)
|
|
{
|
|
if (module.FileName.Contains("joy.cpl"))
|
|
module.Dispose();
|
|
}
|
|
}
|
|
|
|
bool exclusiveMode = hideDS4CheckBox.Checked;
|
|
UseExclusiveMode = exclusiveMode;
|
|
|
|
hideDS4CheckBox.Enabled = false;
|
|
Save();
|
|
BtnStartStop_Clicked(false);
|
|
finishHideDS4Check();
|
|
}
|
|
|
|
private async void finishHideDS4Check()
|
|
{
|
|
await TaskRunner.Factory.StartNew(() =>
|
|
{
|
|
while (changingService)
|
|
{
|
|
Thread.Sleep(10);
|
|
}
|
|
});
|
|
|
|
BtnStartStop_Clicked(false);
|
|
|
|
await TaskRunner.Factory.StartNew(() =>
|
|
{
|
|
while (changingService)
|
|
{
|
|
Thread.Sleep(10);
|
|
}
|
|
});
|
|
|
|
hideDS4CheckBox.Enabled = true;
|
|
}
|
|
|
|
private void startMinimizedCheckBox_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
StartMinimized = startMinimizedCheckBox.Checked;
|
|
Save();
|
|
}
|
|
|
|
private void lvDebug_ItemActivate(object sender, EventArgs e)
|
|
{
|
|
MessageBox.Show(((ListView)sender).FocusedItem.SubItems[1].Text, "Log");
|
|
}
|
|
|
|
private void Profile_Changed(object sender, EventArgs e) //cbs[i] changed
|
|
{
|
|
ComboBox cb = (ComboBox)sender;
|
|
int tdevice = Convert.ToInt32(cb.Tag);
|
|
if (cb.Items[cb.Items.Count - 1].ToString() == "+" + Properties.Resources.PlusNewProfile)
|
|
{
|
|
if (cb.SelectedIndex < cb.Items.Count - 1)
|
|
{
|
|
for (int i = 0, arlen = shortcuts[tdevice].DropDownItems.Count; i < arlen; i++)
|
|
{
|
|
if (!(shortcuts[tdevice].DropDownItems[i] is ToolStripSeparator))
|
|
((ToolStripMenuItem)shortcuts[tdevice].DropDownItems[i]).Checked = false;
|
|
}
|
|
|
|
((ToolStripMenuItem)shortcuts[tdevice].DropDownItems[cb.SelectedIndex]).Checked = true;
|
|
LogDebug(DateTime.Now, Properties.Resources.UsingProfile.Replace("*number*", (tdevice + 1).ToString()).Replace("*Profile name*", cb.Text), false);
|
|
shortcuts[tdevice].Text = Properties.Resources.ContextEdit.Replace("*number*", (tdevice + 1).ToString());
|
|
ProfilePath[tdevice] = cb.Items[cb.SelectedIndex].ToString();
|
|
Save();
|
|
LoadProfile(tdevice, true, Program.rootHub);
|
|
if (UseCustomLed[tdevice])
|
|
lights[tdevice].BackColor = CustomColor[tdevice].ToColorA;
|
|
else
|
|
lights[tdevice].BackColor = MainColor[tdevice].ToColorA;
|
|
|
|
if (linkedProfileCB[tdevice].Checked)
|
|
{
|
|
DS4Device device = Program.rootHub.DS4Controllers[tdevice];
|
|
if (device != null && device.isValidSerial())
|
|
{
|
|
changeLinkedProfile(device.getMacAddress(), ProfilePath[tdevice]);
|
|
SaveLinkedProfiles();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OlderProfilePath[tdevice] = ProfilePath[tdevice];
|
|
}
|
|
}
|
|
else if (cb.SelectedIndex == cb.Items.Count - 1 && cb.Items.Count > 1) //if +New Profile selected
|
|
ShowOptions(tdevice, "");
|
|
|
|
if (cb.Text == "(" + Properties.Resources.NoProfileLoaded + ")")
|
|
ebns[tdevice].Text = Properties.Resources.New;
|
|
else
|
|
ebns[tdevice].Text = Properties.Resources.EditProfile;
|
|
}
|
|
|
|
OnDeviceStatusChanged(this, tdevice); //to update profile name in notify icon
|
|
}
|
|
|
|
private void Profile_Changed_Menu(object sender, ToolStripItemClickedEventArgs e)
|
|
{
|
|
ToolStripMenuItem tS = (ToolStripMenuItem)sender;
|
|
int tdevice = Convert.ToInt32(tS.Tag);
|
|
if (!(e.ClickedItem is ToolStripSeparator))
|
|
{
|
|
if (e.ClickedItem != tS.DropDownItems[tS.DropDownItems.Count - 1]) //if +New Profile not selected
|
|
cbs[tdevice].SelectedIndex = tS.DropDownItems.IndexOf(e.ClickedItem);
|
|
else //if +New Profile selected
|
|
ShowOptions(tdevice, "");
|
|
}
|
|
}
|
|
|
|
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
contextclose = true;
|
|
Close();
|
|
}
|
|
|
|
private void openToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Show();
|
|
Focus();
|
|
WindowState = FormWindowState.Normal;
|
|
}
|
|
|
|
private void startToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
BtnStartStop_Clicked();
|
|
}
|
|
|
|
private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Middle)
|
|
{
|
|
contextclose = true;
|
|
Close();
|
|
}
|
|
}
|
|
|
|
private void notifyIcon1_BalloonTipClicked(object sender, EventArgs e)
|
|
{
|
|
Show();
|
|
WindowState = FormWindowState.Normal;
|
|
}
|
|
|
|
private void llbHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
{
|
|
Hotkeys hotkeysForm = new Hotkeys();
|
|
hotkeysForm.Icon = this.Icon;
|
|
hotkeysForm.Text = llbHelp.Text;
|
|
hotkeysForm.ShowDialog();
|
|
}
|
|
|
|
private void StartWindowsCheckBox_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
bool isChecked = StartWindowsCheckBox.Checked;
|
|
if (isChecked && !File.Exists(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\DS4Windows.lnk"))
|
|
{
|
|
appShortcutToStartup();
|
|
}
|
|
else if (!isChecked)
|
|
{
|
|
File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\DS4Windows.lnk");
|
|
}
|
|
|
|
if (isChecked)
|
|
{
|
|
runStartupPanel.Visible = true;
|
|
}
|
|
else
|
|
{
|
|
runStartupPanel.Visible = false;
|
|
runStartTaskRadio.Checked = false;
|
|
runStartProgRadio.Checked = true;
|
|
}
|
|
|
|
changeStartupRoutine();
|
|
}
|
|
|
|
private void appShortcutToStartup()
|
|
{
|
|
Type t = Type.GetTypeFromCLSID(new Guid("72C24DD5-D70A-438B-8A42-98424B88AFB8")); // Windows Script Host Shell Object
|
|
dynamic shell = Activator.CreateInstance(t);
|
|
try
|
|
{
|
|
var lnk = shell.CreateShortcut(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\DS4Windows.lnk");
|
|
try
|
|
{
|
|
string app = Assembly.GetExecutingAssembly().Location;
|
|
lnk.TargetPath = Assembly.GetExecutingAssembly().Location;
|
|
|
|
if (runStartProgRadio.Checked)
|
|
{
|
|
lnk.Arguments = "-m";
|
|
}
|
|
else if (runStartTaskRadio.Checked)
|
|
{
|
|
lnk.Arguments = "-runtask";
|
|
}
|
|
|
|
//lnk.TargetPath = Assembly.GetExecutingAssembly().Location;
|
|
//lnk.Arguments = "-m";
|
|
lnk.IconLocation = app.Replace('\\', '/');
|
|
lnk.Save();
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FinalReleaseComObject(lnk);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
Marshal.FinalReleaseComObject(shell);
|
|
}
|
|
}
|
|
|
|
private void tabMain_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
TabPage currentTab = tabMain.SelectedTab;
|
|
lbLastMessage.Visible = currentTab != tabLog;
|
|
if (currentTab == tabLog)
|
|
chData.AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
|
|
|
|
if (currentTab == tabSettings)
|
|
{
|
|
lbLastMessage.ForeColor = SystemColors.GrayText;
|
|
lbLastMessage.Text = Properties.Resources.HoverOverItems;
|
|
}
|
|
else if (lvDebug.Items.Count > 0)
|
|
lbLastMessage.Text = lvDebug.Items[lvDebug.Items.Count - 1].SubItems[1].Text;
|
|
else
|
|
lbLastMessage.Text = "";
|
|
}
|
|
|
|
private void Items_MouseHover(object sender, EventArgs e)
|
|
{
|
|
string hoverText = Properties.Resources.HoverOverItems;
|
|
string temp = "";
|
|
if (hoverTextDict.TryGetValue((Control)sender, out temp))
|
|
{
|
|
hoverText = temp;
|
|
}
|
|
|
|
lbLastMessage.Text = hoverText;
|
|
if (hoverText != Properties.Resources.HoverOverItems)
|
|
lbLastMessage.ForeColor = Color.Black;
|
|
else
|
|
lbLastMessage.ForeColor = SystemColors.GrayText;
|
|
}
|
|
|
|
private void lBProfiles_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
lBProfiles.SelectedIndex = lBProfiles.IndexFromPoint(e.X, e.Y);
|
|
if (e.Button == MouseButtons.Right)
|
|
{
|
|
if (lBProfiles.SelectedIndex < 0)
|
|
{
|
|
cMProfile.ShowImageMargin = false;
|
|
assignToController1ToolStripMenuItem.Visible = false;
|
|
assignToController2ToolStripMenuItem.Visible = false;
|
|
assignToController3ToolStripMenuItem.Visible = false;
|
|
assignToController4ToolStripMenuItem.Visible = false;
|
|
deleteToolStripMenuItem.Visible = false;
|
|
editToolStripMenuItem.Visible = false;
|
|
duplicateToolStripMenuItem.Visible = false;
|
|
exportToolStripMenuItem.Visible = false;
|
|
}
|
|
else
|
|
{
|
|
cMProfile.ShowImageMargin = true;
|
|
assignToController1ToolStripMenuItem.Visible = true;
|
|
assignToController2ToolStripMenuItem.Visible = true;
|
|
assignToController3ToolStripMenuItem.Visible = true;
|
|
assignToController4ToolStripMenuItem.Visible = true;
|
|
ToolStripMenuItem[] assigns = { assignToController1ToolStripMenuItem,
|
|
assignToController2ToolStripMenuItem,
|
|
assignToController3ToolStripMenuItem,
|
|
assignToController4ToolStripMenuItem };
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if (lBProfiles.SelectedIndex == cbs[i].SelectedIndex)
|
|
assigns[i].Checked = true;
|
|
else
|
|
assigns[i].Checked = false;
|
|
}
|
|
|
|
deleteToolStripMenuItem.Visible = true;
|
|
editToolStripMenuItem.Visible = true;
|
|
duplicateToolStripMenuItem.Visible = true;
|
|
exportToolStripMenuItem.Visible = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void tBProfile_TextChanged(object sender, EventArgs e)
|
|
{
|
|
if (tSTBProfile.Text != null && tSTBProfile.Text != "" &&
|
|
!tSTBProfile.Text.Contains("\\") && !tSTBProfile.Text.Contains("/") &&
|
|
!tSTBProfile.Text.Contains(":") && !tSTBProfile.Text.Contains("*") &&
|
|
!tSTBProfile.Text.Contains("?") && !tSTBProfile.Text.Contains("\"") &&
|
|
!tSTBProfile.Text.Contains("<") && !tSTBProfile.Text.Contains(">") &&
|
|
!tSTBProfile.Text.Contains("|"))
|
|
tSTBProfile.ForeColor = SystemColors.WindowText;
|
|
else
|
|
tSTBProfile.ForeColor = SystemColors.GrayText;
|
|
}
|
|
|
|
private void tBProfile_Enter(object sender, EventArgs e)
|
|
{
|
|
if (tSTBProfile.Text == "<" + Properties.Resources.TypeProfileName + ">")
|
|
tSTBProfile.Text = "";
|
|
}
|
|
|
|
private void tBProfile_Leave(object sender, EventArgs e)
|
|
{
|
|
if (tSTBProfile.Text == "")
|
|
tSTBProfile.Text = "<" + Properties.Resources.TypeProfileName + ">";
|
|
}
|
|
|
|
private void tSBCancel_Click(object sender, EventArgs e)
|
|
{
|
|
if (optPop && opt.Visible)
|
|
opt.Close();
|
|
}
|
|
|
|
private void tSBSaveProfile_Click(object sender, EventArgs e)
|
|
{
|
|
if (optPop && opt.Visible)
|
|
{
|
|
opt.saving = true;
|
|
opt.Set();
|
|
|
|
if (tSTBProfile.Text != null && tSTBProfile.Text != "" &&
|
|
!tSTBProfile.Text.Contains("\\") && !tSTBProfile.Text.Contains("/") &&
|
|
!tSTBProfile.Text.Contains(":") && !tSTBProfile.Text.Contains("*") &&
|
|
!tSTBProfile.Text.Contains("?") && !tSTBProfile.Text.Contains("\"") &&
|
|
!tSTBProfile.Text.Contains("<") && !tSTBProfile.Text.Contains(">") &&
|
|
!tSTBProfile.Text.Contains("|"))
|
|
{
|
|
File.Delete(appdatapath + @"\Profiles\" + opt.filename + ".xml");
|
|
ProfilePath[opt.device] = tSTBProfile.Text;
|
|
SaveProfile(opt.device, tSTBProfile.Text);
|
|
cacheProfileCustomsFlags(opt.device);
|
|
Save();
|
|
opt.Close();
|
|
}
|
|
else
|
|
MessageBox.Show(Properties.Resources.ValidName, Properties.Resources.NotValid, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
|
|
}
|
|
}
|
|
|
|
private void tSBKeepSize_Click(object sender, EventArgs e)
|
|
{
|
|
oldsize = Size;
|
|
tSBKeepSize.Text = Properties.Resources.WillKeep;
|
|
tSBKeepSize.Image = Properties.Resources._checked;
|
|
tSBKeepSize.Enabled = false;
|
|
}
|
|
|
|
private void cBUpdate_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
if (!cBUpdate.Checked)
|
|
{
|
|
nUDUpdateTime.Value = 0;
|
|
pNUpdate.Enabled = false;
|
|
}
|
|
else
|
|
{
|
|
nUDUpdateTime.Value = 1;
|
|
cBUpdateTime.SelectedIndex = 0;
|
|
pNUpdate.Enabled = true;
|
|
}
|
|
}
|
|
|
|
private void cBCustomSteam_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
UseCustomSteamFolder = cBCustomSteam.Checked;
|
|
tBSteamFolder.Enabled = cBCustomSteam.Checked;
|
|
}
|
|
|
|
private void tBSteamFolder_TextChanged(object sender, EventArgs e)
|
|
{
|
|
CustomSteamFolder = tBSteamFolder.Text;
|
|
}
|
|
|
|
private void nUDUpdateTime_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
int currentIndex = cBUpdateTime.SelectedIndex;
|
|
if (currentIndex == 0)
|
|
CheckWhen = (int)nUDUpdateTime.Value;
|
|
else if (currentIndex == 1)
|
|
CheckWhen = (int)nUDUpdateTime.Value * 24;
|
|
|
|
if (nUDUpdateTime.Value < 1)
|
|
cBUpdate.Checked = false;
|
|
|
|
if (nUDUpdateTime.Value == 1)
|
|
{
|
|
int index = currentIndex;
|
|
cBUpdateTime.BeginUpdate();
|
|
cBUpdateTime.Items.Clear();
|
|
cBUpdateTime.Items.Add(Properties.Resources.Hour);
|
|
cBUpdateTime.Items.Add(Properties.Resources.Day);
|
|
cBUpdateTime.SelectedIndex = index;
|
|
cBUpdateTime.EndUpdate();
|
|
}
|
|
else if (cBUpdateTime.Items[0].ToString() == Properties.Resources.Hour)
|
|
{
|
|
int index = currentIndex;
|
|
cBUpdateTime.BeginUpdate();
|
|
cBUpdateTime.Items.Clear();
|
|
cBUpdateTime.Items.Add(Properties.Resources.Hours);
|
|
cBUpdateTime.Items.Add(Properties.Resources.Days);
|
|
cBUpdateTime.SelectedIndex = index;
|
|
cBUpdateTime.EndUpdate();
|
|
}
|
|
}
|
|
|
|
private void cBUpdateTime_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
int index = cBUpdateTime.SelectedIndex;
|
|
if (index == 0)
|
|
CheckWhen = (int)nUDUpdateTime.Value;
|
|
else if (index == 1)
|
|
CheckWhen = (int)nUDUpdateTime.Value * 24;
|
|
}
|
|
|
|
private void lLBUpdate_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
{
|
|
// Sorry other devs, gonna have to find your own server
|
|
Uri url = new Uri("https://raw.githubusercontent.com/Ryochan7/DS4Windows/jay/DS4Windows/newest.txt");
|
|
WebClient wct = new WebClient();
|
|
wct.DownloadFileAsync(url, appdatapath + "\\version.txt");
|
|
wct.DownloadFileCompleted += (sender2, e2) => TaskRunner.Run(() => wct_DownloadFileCompleted(sender2, e2));
|
|
}
|
|
|
|
private void cBDisconnectBT_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
DCBTatStop = cBDisconnectBT.Checked;
|
|
}
|
|
|
|
void wct_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
|
|
{
|
|
LastChecked = DateTime.Now;
|
|
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
|
|
string version2 = fvi.FileVersion;
|
|
string newversion2 = File.ReadAllText(appdatapath + "\\version.txt").Trim();
|
|
bool launchUpdate = false;
|
|
if (!string.IsNullOrWhiteSpace(newversion2) && version2.Replace(',', '.').CompareTo(newversion2) != 0)
|
|
{
|
|
DialogResult result = DialogResult.No;
|
|
this.Invoke((System.Action)(() =>
|
|
{
|
|
result = MessageBox.Show(Properties.Resources.DownloadVersion.Replace("*number*", newversion2),
|
|
Properties.Resources.DS4Update, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
|
|
}));
|
|
|
|
if (result == DialogResult.Yes)
|
|
{
|
|
launchUpdate = true;
|
|
if (!File.Exists(exepath + "\\DS4Updater.exe") || (File.Exists(exepath + "\\DS4Updater.exe")
|
|
&& (FileVersionInfo.GetVersionInfo(exepath + "\\DS4Updater.exe").FileVersion.CompareTo(UPDATER_VERSION) != 0)))
|
|
{
|
|
Uri url2 = new Uri($"https://github.com/Ryochan7/DS4Updater/releases/download/v{UPDATER_VERSION}/{updaterExe}");
|
|
WebClient wc2 = new WebClient();
|
|
if (appdatapath == exepath)
|
|
wc2.DownloadFile(url2, exepath + "\\DS4Updater.exe");
|
|
else
|
|
{
|
|
this.BeginInvoke((System.Action)(() => MessageBox.Show(Properties.Resources.PleaseDownloadUpdater)));
|
|
Process.Start($"https://github.com/Ryochan7/DS4Updater/releases/download/v{UPDATER_VERSION}/{updaterExe}");
|
|
launchUpdate = false;
|
|
}
|
|
}
|
|
|
|
if (launchUpdate)
|
|
{
|
|
using (Process p = new Process())
|
|
{
|
|
p.StartInfo.FileName = exepath + "\\DS4Updater.exe";
|
|
p.StartInfo.Arguments = "-autolaunch";
|
|
if (AdminNeeded())
|
|
p.StartInfo.Verb = "runas";
|
|
|
|
try { p.Start(); }
|
|
catch (Exception) { launchUpdate = false; }
|
|
}
|
|
}
|
|
|
|
if (launchUpdate)
|
|
{
|
|
this.BeginInvoke((System.Action)(() =>
|
|
{
|
|
contextclose = true;
|
|
Close();
|
|
}));
|
|
}
|
|
}
|
|
else
|
|
File.Delete(appdatapath + "\\version.txt");
|
|
}
|
|
else
|
|
{
|
|
File.Delete(appdatapath + "\\version.txt");
|
|
this.BeginInvoke((System.Action)(() => MessageBox.Show(Properties.Resources.UpToDate, "DS4Windows Updater")));
|
|
}
|
|
}
|
|
|
|
private void linkProfiles_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
{
|
|
Process.Start(appdatapath + "\\Profiles");
|
|
}
|
|
|
|
private void cBoxNotifications_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
Notifications = cBoxNotifications.SelectedIndex;
|
|
}
|
|
|
|
private void lLSetup_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
|
{
|
|
DriverSetupPrep();
|
|
|
|
tabSettings.Text = originalsettingstext;
|
|
linkSetup.LinkColor = Color.Blue;
|
|
}
|
|
|
|
private void DriverSetupPrep()
|
|
{
|
|
if (btnStartStop.Text == Properties.Resources.StopText)
|
|
BtnStartStop_Clicked(false);
|
|
|
|
TaskRunner.Run(() =>
|
|
{
|
|
while (changingService)
|
|
{
|
|
Thread.SpinWait(1000);
|
|
}
|
|
|
|
Process p = new Process();
|
|
p.StartInfo.FileName = Assembly.GetExecutingAssembly().Location;
|
|
p.StartInfo.Arguments = "-driverinstall";
|
|
p.StartInfo.Verb = "runas";
|
|
try { p.Start(); }
|
|
catch { }
|
|
//WelcomeDialog wd = new WelcomeDialog();
|
|
//wd.ShowDialog();
|
|
});
|
|
}
|
|
|
|
bool tempBool = false;
|
|
private void ScpForm_Closing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if (optPop)
|
|
{
|
|
opt.Close();
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
|
|
bool closeMini = tempBool = cBCloseMini.Checked;
|
|
bool userClosing = e.CloseReason == CloseReason.UserClosing;
|
|
DS4Device d = null;
|
|
bool nocontrollers = tempBool = true;
|
|
//in case user accidentally clicks on the close button whilst "Close Minimizes" checkbox is unchecked
|
|
if (userClosing && !closeMini && !contextclose)
|
|
{
|
|
for (int i = 0, PadsLen = Pads.Length; tempBool && i < PadsLen; i++)
|
|
{
|
|
d = Program.rootHub.DS4Controllers[i];
|
|
tempBool = (d != null) ? false : tempBool;
|
|
}
|
|
|
|
nocontrollers = tempBool;
|
|
if (!nocontrollers)
|
|
{
|
|
if (MessageBox.Show(Properties.Resources.CloseConfirm, Properties.Resources.Confirm,
|
|
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Util.UnregisterNotify(regHandle);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Util.UnregisterNotify(regHandle);
|
|
}
|
|
}
|
|
else if (userClosing && closeMini && !contextclose)
|
|
{
|
|
WindowState = FormWindowState.Minimized;
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
|
|
if (systemShutdown)
|
|
// Reset the variable because the user might cancel the
|
|
// shutdown.
|
|
{
|
|
systemShutdown = false;
|
|
DS4LightBar.shuttingdown = true;
|
|
}
|
|
|
|
Global.ControllerRemoved -= ControllerRemovedChange;
|
|
|
|
if (!string.IsNullOrEmpty(appdatapath))
|
|
{
|
|
Save();
|
|
blankControllerTab();
|
|
}
|
|
|
|
TaskRunner.Run(() => Program.rootHub.Stop()).Wait();
|
|
// Make sure to stop event generation routines. Should fix odd crashes on shutdown
|
|
Application.Exit();
|
|
}
|
|
|
|
private void cBSwipeProfiles_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
bool swipe = false;
|
|
SwipeProfiles = swipe = cBSwipeProfiles.Checked;
|
|
bool timerEnabled = hotkeysTimer.Enabled;
|
|
if (swipe && !timerEnabled)
|
|
{
|
|
ChangeHotkeysStatus(true);
|
|
//hotkeysTimer.Start();
|
|
}
|
|
else if (!swipe && timerEnabled)
|
|
{
|
|
ChangeHotkeysStatus(false);
|
|
//hotkeysTimer.Stop();
|
|
}
|
|
}
|
|
|
|
private void cBQuickCharge_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
QuickCharge = cBQuickCharge.Checked;
|
|
}
|
|
|
|
private void lbLastMessage_MouseHover(object sender, EventArgs e)
|
|
{
|
|
toolTip1.Show(lbLastMessage.Text, lbLastMessage, -3, -3);
|
|
}
|
|
|
|
private void pnlButton_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
toolTip1.Hide(lbLastMessage);
|
|
}
|
|
|
|
private void cBCloseMini_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
CloseMini = cBCloseMini.Checked;
|
|
}
|
|
|
|
private void Pads_MouseHover(object sender, EventArgs e)
|
|
{
|
|
Label lb = (Label)sender;
|
|
int i = Convert.ToInt32(lb.Tag);
|
|
DS4Device d = Program.rootHub.DS4Controllers[i];
|
|
if (d != null)
|
|
{
|
|
double latency = d.Latency;
|
|
toolTip1.Hide(Pads[i]);
|
|
toolTip1.Show(Properties.Resources.InputDelay.Replace("*number*", latency.ToString()), lb, lb.Size.Width, 0);
|
|
}
|
|
}
|
|
|
|
private void Pads_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
toolTip1.Hide((Label)sender);
|
|
}
|
|
|
|
Process bat;
|
|
|
|
int currentCustomLed;
|
|
private void EditCustomLed(object sender, EventArgs e)
|
|
{
|
|
Button btn = (Button)sender;
|
|
currentCustomLed = Convert.ToInt32(btn.Tag);
|
|
bool customLedChecked = UseCustomLed[currentCustomLed];
|
|
useCustomColorToolStripMenuItem.Checked = customLedChecked;
|
|
useProfileColorToolStripMenuItem.Checked = !customLedChecked;
|
|
cMCustomLed.Show(btn, new Point(0, btn.Height));
|
|
}
|
|
|
|
private void useProfileColorToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
UseCustomLed[currentCustomLed] = false;
|
|
lights[currentCustomLed].BackColor = MainColor[currentCustomLed].ToColorA;
|
|
Global.Save();
|
|
}
|
|
|
|
private void useCustomColorToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
advColorDialog.Color = CustomColor[currentCustomLed].ToColor;
|
|
AdvancedColorDialog.ColorUpdateHandler tempDel =
|
|
new AdvancedColorDialog.ColorUpdateHandler(advColor_CustomColorUpdate);
|
|
|
|
advColorDialog.OnUpdateColor += tempDel;
|
|
if (advColorDialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
lights[currentCustomLed].BackColor = new DS4Color(advColorDialog.Color).ToColorA;
|
|
CustomColor[currentCustomLed] = new DS4Color(advColorDialog.Color);
|
|
UseCustomLed[currentCustomLed] = true;
|
|
Global.Save();
|
|
}
|
|
|
|
advColorDialog.OnUpdateColor -= tempDel;
|
|
DS4LightBar.forcedFlash[currentCustomLed] = 0;
|
|
DS4LightBar.forcelight[currentCustomLed] = false;
|
|
}
|
|
|
|
private void advColor_CustomColorUpdate(Color color, EventArgs e)
|
|
{
|
|
if (currentCustomLed < 4)
|
|
{
|
|
DS4Color dcolor = new DS4Color { red = color.R, green = color.G, blue = color.B };
|
|
DS4LightBar.forcedColor[currentCustomLed] = dcolor;
|
|
DS4LightBar.forcedFlash[currentCustomLed] = 0;
|
|
DS4LightBar.forcelight[currentCustomLed] = true;
|
|
}
|
|
}
|
|
|
|
private void cBUseWhiteIcon_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
UseWhiteIcon = cBUseWhiteIcon.Checked;
|
|
notifyIcon1.Icon = UseWhiteIcon ? Properties.Resources.DS4W___White : Properties.Resources.DS4W;
|
|
}
|
|
|
|
private void advColorDialog_OnUpdateColor(object sender, EventArgs e)
|
|
{
|
|
if (sender is Color)
|
|
{
|
|
Color color = (Color)sender;
|
|
DS4Color dcolor = new DS4Color(color);
|
|
Console.WriteLine(dcolor);
|
|
DS4LightBar.forcedColor[currentCustomLed] = dcolor;
|
|
DS4LightBar.forcedFlash[currentCustomLed] = 0;
|
|
DS4LightBar.forcelight[currentCustomLed] = true;
|
|
}
|
|
}
|
|
|
|
private void lBProfiles_SelectedIndexChanged(object sender, EventArgs e)
|
|
{
|
|
int index = lBProfiles.SelectedIndex;
|
|
if (index >= 0)
|
|
{
|
|
tsBNewProfle.Enabled = true;
|
|
tsBEditProfile.Enabled = true;
|
|
tsBDeleteProfile.Enabled = true;
|
|
tSBDupProfile.Enabled = true;
|
|
tSBImportProfile.Enabled = true;
|
|
tSBExportProfile.Enabled = true;
|
|
}
|
|
else
|
|
{
|
|
tsBNewProfle.Enabled = true;
|
|
tsBEditProfile.Enabled = false;
|
|
tsBDeleteProfile.Enabled = false;
|
|
tSBDupProfile.Enabled = false;
|
|
tSBImportProfile.Enabled = true;
|
|
tSBExportProfile.Enabled = false;
|
|
}
|
|
}
|
|
|
|
private void runStartProgRadio_Click(object sender, EventArgs e)
|
|
{
|
|
appShortcutToStartup();
|
|
changeStartupRoutine();
|
|
}
|
|
|
|
private void runStartTaskRadio_Click(object sender, EventArgs e)
|
|
{
|
|
appShortcutToStartup();
|
|
changeStartupRoutine();
|
|
}
|
|
|
|
private void changeStartupRoutine()
|
|
{
|
|
if (runStartTaskRadio.Checked)
|
|
{
|
|
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
|
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
|
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
|
|
{
|
|
TaskService ts = new TaskService();
|
|
Task tasker = ts.FindTask("RunDS4Windows");
|
|
if (tasker != null)
|
|
{
|
|
ts.RootFolder.DeleteTask("RunDS4Windows");
|
|
}
|
|
|
|
TaskDefinition td = ts.NewTask();
|
|
td.Actions.Add(new ExecAction(@"%windir%\System32\cmd.exe",
|
|
"/c start \"RunDS4Windows\" \"" + Process.GetCurrentProcess().MainModule.FileName + "\" -m",
|
|
new FileInfo(Process.GetCurrentProcess().MainModule.FileName).DirectoryName));
|
|
|
|
td.Principal.RunLevel = TaskRunLevel.Highest;
|
|
ts.RootFolder.RegisterTaskDefinition("RunDS4Windows", td);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WindowsIdentity identity = WindowsIdentity.GetCurrent();
|
|
WindowsPrincipal principal = new WindowsPrincipal(identity);
|
|
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
|
|
{
|
|
TaskService ts = new TaskService();
|
|
Task tasker = ts.FindTask("RunDS4Windows");
|
|
if (tasker != null)
|
|
{
|
|
ts.RootFolder.DeleteTask("RunDS4Windows");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void linkCB_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
CheckBox linkCb = (CheckBox)sender;
|
|
int i = Convert.ToInt32(linkCb.Tag);
|
|
bool check = linkCb.Checked;
|
|
Global.linkedProfileCheck[i] = check;
|
|
DS4Device device = Program.rootHub.DS4Controllers[i];
|
|
if (device != null && device.isSynced())
|
|
{
|
|
if (check)
|
|
{
|
|
if (device.isValidSerial())
|
|
{
|
|
changeLinkedProfile(device.getMacAddress(), ProfilePath[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
removeLinkedProfile(device.getMacAddress());
|
|
ProfilePath[i] = OlderProfilePath[i];
|
|
int profileIndex = cbs[i].FindString(ProfilePath[i]);
|
|
if (profileIndex >= 0)
|
|
{
|
|
cbs[i].SelectedIndex = profileIndex;
|
|
}
|
|
}
|
|
|
|
SaveLinkedProfiles();
|
|
}
|
|
}
|
|
|
|
private void exportLogTxtBtn_Click(object sender, EventArgs e)
|
|
{
|
|
SaveFileDialog dialog = new SaveFileDialog();
|
|
dialog.AddExtension = true;
|
|
dialog.DefaultExt = ".txt";
|
|
dialog.Filter = "Text Documents (*.txt)|*.txt";
|
|
dialog.Title = "Select Export File";
|
|
dialog.InitialDirectory = Global.appdatapath;
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
{
|
|
string outputFile = dialog.FileName;
|
|
List < string > outputLines = new List<string>();
|
|
ListViewItem item = null;
|
|
for (int i = 0, len = lvDebug.Items.Count; i < len; i++)
|
|
{
|
|
item = lvDebug.Items[i];
|
|
outputLines.Add(item.SubItems[0].Text + ": " + item.SubItems[1].Text);
|
|
}
|
|
|
|
try
|
|
{
|
|
StreamWriter stream = new StreamWriter(outputFile);
|
|
string line = string.Empty;
|
|
for (int i = 0, len = outputLines.Count; i < len; i++)
|
|
{
|
|
line = outputLines[i];
|
|
stream.WriteLine(line);
|
|
}
|
|
stream.Close();
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
|
|
private void languagePackComboBox1_SelectedValueChanged(object sender, EventArgs e)
|
|
{
|
|
string newValue = ((DS4Forms.LanguagePackComboBox)sender).SelectedValue.ToString();
|
|
if (newValue != UseLang)
|
|
{
|
|
UseLang = newValue;
|
|
Save();
|
|
MessageBox.Show(Properties.Resources.LanguagePackApplyRestartRequired, Text, MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
private void OpenProgramFolderToolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
Process temp = new Process();
|
|
temp.StartInfo.FileName = "explorer.exe";
|
|
temp.StartInfo.Arguments = @"/select, " + Assembly.GetExecutingAssembly().Location;
|
|
try { temp.Start(); }
|
|
catch { }
|
|
}
|
|
|
|
private void DiscontoolStripMenuItem_Click(object sender, EventArgs e)
|
|
{
|
|
ToolStripMenuItem item = (ToolStripMenuItem)sender;
|
|
int i = Convert.ToInt32(item.Tag);
|
|
DS4Device d = Program.rootHub.DS4Controllers[i];
|
|
if (d != null)
|
|
{
|
|
if (d.ConnectionType == ConnectionType.BT && !d.Charging)
|
|
{
|
|
d.DisconnectBT();
|
|
}
|
|
else if (d.ConnectionType == ConnectionType.SONYWA && !d.Charging)
|
|
{
|
|
d.DisconnectDongle();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void MintoTaskCheckBox_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
MinToTaskbar = mintoTaskCheckBox.Checked;
|
|
Save();
|
|
}
|
|
|
|
private void CBController_KeyPress(object sender, KeyPressEventArgs e)
|
|
{
|
|
e.Handled = true;
|
|
}
|
|
|
|
private async void CkUdpServ_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
bool state = ckUdpServ.Checked;
|
|
setUsingUDPServer(state);
|
|
if (!state)
|
|
{
|
|
Program.rootHub.ChangeMotionEventStatus(state);
|
|
await TaskRunner.Delay(100).ContinueWith((t) =>
|
|
{
|
|
Program.rootHub.ChangeUDPStatus(state);
|
|
});
|
|
}
|
|
else
|
|
{
|
|
Program.rootHub.ChangeUDPStatus(state);
|
|
await TaskRunner.Delay(100).ContinueWith((t) =>
|
|
{
|
|
Program.rootHub.ChangeMotionEventStatus(state);
|
|
});
|
|
}
|
|
|
|
nUDUdpPortNum.Enabled = state;
|
|
tBUdpListenAddress.Enabled = state;
|
|
}
|
|
|
|
private void NUDUdpPortNum_Leave(object sender, EventArgs e)
|
|
{
|
|
int curValue = (int)nUDUdpPortNum.Value;
|
|
if (curValue != getUDPServerPortNum())
|
|
{
|
|
setUDPServerPort(curValue);
|
|
nUDUdpPortNum.Enabled = false;
|
|
tBUdpListenAddress.Enabled = false;
|
|
WaitUDPPortChange();
|
|
}
|
|
}
|
|
|
|
private async void WaitUDPPortChange()
|
|
{
|
|
await TaskRunner.Delay(100);
|
|
if (isUsingUDPServer())
|
|
{
|
|
await TaskRunner.Run(() => Program.rootHub.UseUDPPort());
|
|
nUDUdpPortNum.Enabled = true;
|
|
tBUdpListenAddress.Enabled = true;
|
|
}
|
|
}
|
|
|
|
private void cBFlashWhenLate_CheckedChanged(object sender, EventArgs e)
|
|
{
|
|
FlashWhenLate = cBFlashWhenLate.Checked;
|
|
nUDLatency.Enabled = cBFlashWhenLate.Checked;
|
|
lbMsLatency.Enabled = cBFlashWhenLate.Checked;
|
|
}
|
|
|
|
private void nUDLatency_ValueChanged(object sender, EventArgs e)
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|