Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DS4Windows/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,7 @@ private void ApplicationStartupCore(object sender, StartupEventArgs e)
logger.Info($"DS4Windows version {version}");
logger.Info($"DS4Windows exe file: {DS4Windows.Global.exeFileName}");
logger.Info($"DS4Windows Assembly Architecture: {(Environment.Is64BitProcess ? "x64" : "x86")}");
logger.Info(DS4Windows.InstallationModeInfo.Read());
foreach (string line in DS4Windows.WindowsVersionInfo.Read().LogLines)
logger.Info(line);
logger.Info($"System Architecture: {(Environment.Is64BitOperatingSystem ? "x64" : "x86")}");
Expand Down
15 changes: 13 additions & 2 deletions DS4Windows/DS4Control/ControlService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,7 +1012,7 @@ private void DS4Devices_RequestElevation(RequestElevationArgs args)
LogDebug($"{ExeName} was not added to HidHide: {rejection}", warning: true);
return;
}
LogDebug("HidHide control device found");
LogDebug("HidHide control device found; driver " + DriverDiagnostics.Describe("HidHide"));
lock (hidHideDriverMutationLock)
{
using (HidHideAPIDevice hidHideDevice = new HidHideAPIDevice())
Expand Down Expand Up @@ -2866,7 +2866,18 @@ private bool StartCore(bool showlog)
}

LogDebug($"Using output KB+M handler: {Global.outputKBMHandler.GetFullDisplayName()}");
LogDebug("VIIPER virtual-controller backend ready");
try
{
var backendStatus = ViiperSetupManager.GetStatus();
foreach (string line in ViiperStartupDiagnostics.Describe(backendStatus))
LogDebug(line, warning: !backendStatus.Ready);
LogDebug("USB/IP virtual host driver (usbip2_ude): " + DriverDiagnostics.Describe("usbip2_ude"));
LogDebug("USB/IP filter driver (usbip2_filter): " + DriverDiagnostics.Describe("usbip2_filter"));
}
catch (Exception error)
{
LogDebug("VIIPER/USB/IP diagnostics unavailable: " + error.Message, warning: true);
}

DS4Devices.isExclusiveMode = getUseExclusiveMode(); //Re-enable Exclusive Mode

Expand Down
9 changes: 9 additions & 0 deletions DS4Windows/DS4Control/DTOXml/AppSettingsDTO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,13 @@ public string CloseMinimizesString
}
}

private string lastSettingsSection = "General";
public string LastSettingsSection
{
get => lastSettingsSection;
set => lastSettingsSection = SettingsSectionInfo.Normalize(value);
}

// Default UseLang to empty string. Not null
public string UseLang
{
Expand Down Expand Up @@ -939,6 +946,7 @@ public void MapFrom(BackingStore source)
PreferredViiperPath = source.preferredViiperPath;
CloseMinimizes = source.closeMini;
UseLang = source.useLang;
LastSettingsSection = source.lastSettingsSection;
DownloadLang = source.downloadLang;
FlashWhenLate = source.flashWhenLate;
FlashWhenLateAt = source.flashWhenLateAt;
Expand Down Expand Up @@ -1052,6 +1060,7 @@ public void MapTo(BackingStore destination)
string.Empty;
destination.closeMini = CloseMinimizes;
destination.useLang = UseLang;
destination.lastSettingsSection = LastSettingsSection;
destination.downloadLang = DownloadLang;
destination.flashWhenLate = FlashWhenLate;
destination.flashWhenLateAt = FlashWhenLateAt;
Expand Down
105 changes: 105 additions & 0 deletions DS4Windows/DS4Control/DriverDiagnostics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32;

namespace DS4Windows
{
internal static class DriverDiagnostics
{
internal static string Describe(string serviceName)
{
string version;
try
{
using var key = Registry.LocalMachine.OpenSubKey(
@"SYSTEM\CurrentControlSet\Services\" + serviceName);
if (key == null) return "not installed";
string path = ViiperSetupManager.ResolveSystemDriverPath(
key.GetValue("ImagePath", null, RegistryValueOptions.DoNotExpandEnvironmentNames) as string);
version = !string.IsNullOrEmpty(path) && File.Exists(path)
? FileVersionInfo.GetVersionInfo(path).FileVersion : null;
if (!string.IsNullOrWhiteSpace(version))
version = "file version " + version;
else if (!string.IsNullOrEmpty(path) && File.Exists(path))
{
// usbip-win2's SYS projects have no VERSIONINFO resource.
// Read only the INF beside the registered driver image,
// not an unrelated/staged package or the app version.
string inf = Path.ChangeExtension(path, ".inf");
string packageVersion = File.Exists(inf) ? ReadInfVersion(File.ReadLines(inf)) : null;
if (packageVersion != null) version = "package version " + packageVersion + " (INF)";
}
}
catch (Exception error)
{
return "version/status unavailable (" + error.Message + ")";
}
return $"{(string.IsNullOrWhiteSpace(version) ? "version metadata unavailable" : version)}; {ReadState(serviceName)}";
}

internal static string ReadInfVersion(System.Collections.Generic.IEnumerable<string> lines)
{
bool inVersion = false;
foreach (string raw in lines)
{
string line = raw.Split(';')[0].Trim();
if (line.StartsWith("[", StringComparison.Ordinal))
{
inVersion = line.Equals("[Version]", StringComparison.OrdinalIgnoreCase);
continue;
}
int equals = line.IndexOf('=');
if (!inVersion || equals < 0 ||
!line.Substring(0, equals).Trim().Equals("DriverVer", StringComparison.OrdinalIgnoreCase)) continue;
string[] parts = line.Substring(equals + 1).Split(',');
if (parts.Length == 2 && Version.TryParse(parts[1].Trim(), out var version) && version.Revision >= 0)
return version.ToString();
}
return null;
}

private static string ReadState(string serviceName)
{
IntPtr manager = IntPtr.Zero, service = IntPtr.Zero;
try
{
manager = OpenSCManager(null, null, 0x0001); // SC_MANAGER_CONNECT
if (manager == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error());
service = OpenService(manager, serviceName, 0x0004); // SERVICE_QUERY_STATUS
if (service == IntPtr.Zero) throw new Win32Exception(Marshal.GetLastWin32Error());
if (!QueryServiceStatus(service, out var status)) throw new Win32Exception(Marshal.GetLastWin32Error());
return status.CurrentState switch
{
1 => "stopped", 2 => "starting", 3 => "stopping", 4 => "running",
5 => "continuing", 6 => "pausing", 7 => "paused", _ => "state unknown"
};
}
catch (Exception error) { return "status unavailable (" + error.Message + ")"; }
finally
{
if (service != IntPtr.Zero) CloseServiceHandle(service);
if (manager != IntPtr.Zero) CloseServiceHandle(manager);
}
}

[StructLayout(LayoutKind.Sequential)]
private struct ServiceStatus
{
public uint ServiceType, CurrentState, ControlsAccepted, Win32ExitCode,
ServiceSpecificExitCode, CheckPoint, WaitHint;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr OpenSCManager(string machineName, string databaseName, uint access);
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern IntPtr OpenService(IntPtr manager, string serviceName, uint access);
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool QueryServiceStatus(IntPtr service, out ServiceStatus status);
[DllImport("advapi32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CloseServiceHandle(IntPtr handle);
}
}
7 changes: 7 additions & 0 deletions DS4Windows/DS4Control/ScpUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1923,6 +1923,12 @@
get { return m_Config.formLocationY; }
}

public static string LastSettingsSection
{
get => SettingsSectionInfo.Normalize(m_Config.lastSettingsSection);
set => m_Config.lastSettingsSection = SettingsSectionInfo.Normalize(value);
}

public static string UseLang
{
set { m_Config.useLang = value; }
Expand Down Expand Up @@ -5022,6 +5028,7 @@
new Dictionary<string, int>(), new Dictionary<string, int>(), new Dictionary<string, int>(), new Dictionary<string, int>(), new Dictionary<string, int>(), new Dictionary<string, int>() };

public string useLang = "";
public string lastSettingsSection = "General";
public bool downloadLang = true;
public TrayIconChoice useIconChoice;
public const bool DEFAULT_FLASH_WHEN_LATE = true;
Expand Down Expand Up @@ -9426,7 +9433,7 @@

PostProcessLoad();
}
catch (InvalidOperationException e)

Check warning on line 9436 in DS4Windows/DS4Control/ScpUtil.cs

View workflow job for this annotation

GitHub Actions / build (x64)

The variable 'e' is declared but never used

Check warning on line 9436 in DS4Windows/DS4Control/ScpUtil.cs

View workflow job for this annotation

GitHub Actions / build (x64)

The variable 'e' is declared but never used
{
AppLogger.LogToGui("Failed to load Profiles.xml.", false);
loaded = false;
Expand Down
19 changes: 19 additions & 0 deletions DS4Windows/DS4Control/Viiper/ViiperStartupDiagnostics.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Collections.Generic;

namespace DS4Windows
{
internal static class ViiperStartupDiagnostics
{
internal static IEnumerable<string> Describe(ViiperPrerequisiteStatus status)
{
yield return $"USB/IP (usbip-win2): installed version {status.UsbipVersion ?? "unknown or missing"}; required {ViiperSetupManager.RequiredUsbipVersion}";
yield return $"USB/IP runtime: {(status.UsbipRuntimeReady ? "ready (driver communication succeeded)" : "not ready")}";
if (!status.UsbipRuntimeReady && !string.IsNullOrWhiteSpace(status.UsbipProbeMessage))
yield return "USB/IP diagnostic: " + status.UsbipProbeMessage;
yield return $"USB/IP package verification: {(status.UsbipExecutableSafe && status.UsbipDriverFilesSafe ? "passed" : "not passed")}";
yield return $"VIIPER: supported version {ViiperSetupManager.SupportedViiperReleaseTag.TrimStart('v')}; selected executable {(status.ViiperPackageCurrent ? "verified" : "not verified")}; server {(status.ServerRunning ? "running and reachable" : "not ready")}";
yield return status.Ready ? "VIIPER virtual-controller backend ready"
: "VIIPER virtual-controller backend not ready: " + status.DisplayText;
}
}
}
10 changes: 5 additions & 5 deletions DS4Windows/DS4Forms/AutoProfiles.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -277,10 +277,11 @@
<TextBox Text="{Binding Path, UpdateSourceTrigger=PropertyChanged}" Margin="{StaticResource spaceMargin}" ToolTip="{lex:Loc AutoProfPathTip}"
TextWrapping="Wrap" AcceptsReturn="False" VerticalScrollBarVisibility="Auto" MaxHeight="90"/>

<Grid>
<TextBox x:Name="mainTxtBox" Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}" Margin="{StaticResource spaceMargin}" ToolTip="{lex:Loc AutoProfTitleTip}" />
<Grid Margin="{StaticResource spaceMargin}">
<TextBox x:Name="mainTxtBox" Text="{Binding Title, UpdateSourceTrigger=PropertyChanged}"
VerticalContentAlignment="Center" ToolTip="{lex:Loc AutoProfTitleTip}" />

<TextBlock Margin="5,2" MinWidth="50" Text="Window title..." Foreground="{DynamicResource ForegroundColor}" Opacity="0.7" IsHitTestVisible="False">
<TextBlock Margin="7,0" VerticalAlignment="Center" MinWidth="50" Text="Window title..." Foreground="{DynamicResource ForegroundColor}" Opacity="0.7" IsHitTestVisible="False">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
Expand Down Expand Up @@ -333,8 +334,7 @@
Foreground="{DynamicResource MutedForegroundColor}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBox x:Name="autoProfilesSearchTextBox" Grid.Column="1"
BorderThickness="0" Background="Transparent"
Padding="2,8" VerticalContentAlignment="Center"
Style="{DynamicResource BridgeSearchTextBoxStyle}"
TextChanged="AutoProfilesSearchTextBox_TextChanged"
ToolTip="Search by profile, window title, executable, or path" />
<Button x:Name="clearAutoProfilesSearchBtn" Grid.Column="2" Content="&#xE711;"
Expand Down
22 changes: 18 additions & 4 deletions DS4Windows/DS4Forms/LanguagePackControl.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,29 @@
lex:ResxLocalizationProvider.DefaultDictionary="Strings"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="340">
<StackPanel Orientation="Horizontal">
<Label x:Name="label1" Content="{lex:Loc LangPackControl.UseLangPack}" ContentStringFormat="{}{0}:" />
<ComboBox x:Name="cbCulture" Width="200" Margin="10,0,0,0"
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label x:Name="label1" Content="{lex:Loc LangPackControl.UseLangPack}" ContentStringFormat="{}{0}:"
VerticalAlignment="Center" Padding="0" Margin="0,0,16,0" />
<ComboBox x:Name="cbCulture" Grid.Column="1" Width="220"
Style="{DynamicResource BridgeSettingsComboBoxStyle}"
ItemsSource="{Binding LangPackList}" SelectedIndex="{Binding SelectedIndex,FallbackValue=0}" IsEnabled="False">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding NativeName}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<TextBlock x:Name="languageRestartHint" Grid.Row="1" Grid.ColumnSpan="2"
Text="Restart required to apply the selected language."
Visibility="Collapsed" Margin="0,12,0,0" TextWrapping="Wrap"
FontWeight="SemiBold" Foreground="{DynamicResource AccentColor}" />
</Grid>
</UserControl>
7 changes: 2 additions & 5 deletions DS4Windows/DS4Forms/LanguagePackControl.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,8 @@ public LanguagePackControl()

private void CheckForCultureChange(object sender, EventArgs e)
{
if (langPackVM.ChangeLanguagePack())
{
MessageBox.Show(Properties.Resources.LanguagePackApplyRestartRequired,
"DS4Windows", MessageBoxButton.OK, MessageBoxImage.Information);
}
langPackVM.ChangeLanguagePack();
languageRestartHint.Visibility = langPackVM.RequiresRestart ? Visibility.Visible : Visibility.Collapsed;
}

private void LangPackVM_ScanFinished(object sender, EventArgs e)
Expand Down
Loading
Loading