Skip to content

Commit

Permalink
Implemented starting phase of DsHidMini v3 ControlApp (#317)
Browse files Browse the repository at this point in the history
* Removed global .net 5.0 sdk requeriment

* Basic implementation of DsHidMini v3 ControlApp

* Changed how the Config. Manager's Profile List is accessed

* Made CreateNewProfile method return the created profile

* Renamed method

* Made it so setting a new profile does not require re-building profile list

* Added device's driver version to info tab

* Simplified title of Devices page

* Added link to troubleshooting website in Devices page

* added comments

* Renamed headers of settings groups

* Refactored code

* Added comments

* Removed FontAwesome nuget and references

* Re-introduced Last Pairing Status symbol in viewmodel

* Re-introduced genuine icon status in ViewModel

* Added status icon placeholder for each line of info in Device Info

* Added Unknown Hid Mode to Manager's SettingsContext Enum

* Implemented verifying expected Device's Hid Mode in config. manager

* Refactored code

* Replaced Device's expected hid mode variable with method

* Added check for mismatching current HID Mode

* Added checks for genuine and last pairing attempt status

* fixed incorrect symbol

* fixed view not updating correctly

* removed redundant word

* fixed ButtonsCombo copy method not copying IsEnabled

* Removed field

* Renamed DeviceSettings' properties

* Renamed variables and enums

* UI tweak

* Commented out genuine check

* Start implementation of App's main model

* Added MainModel as a service

* Removed HostRadio and ConfigManager services

* Initial implementation of ConnectedDeviceManager

* Fixed bug with ButtonsCombo copyCombo method

* Fixed bug when copying settings in Wireless SubSettings

* Creaded ViewModel for ButtonsCombo

* moved ButtonCombo validation to DshmConfig translation proccess

* fixed typo

* removed redundant line of code

* Removed setting LED authority based on HID mode

* fixed logic on preventing conflitcs in DS4W mode

* Changed icon on profile update snackbar message

* Fixed typo

* Removed workaround for combobox not updating accordingly to property value

* Update MainWindow.xaml.cs

* removed comment

* Fixed ButtonsCombo combobox not updating correctly when selecting repeated buttons

* Renamed class and file

* made DisconnectDevice method return success status

* renamed method

* made it so Devices List is only not null if devicelistener is active

* Made device in DeviceViewModel accessible via get only property

* Implemented verifying Hid Mismatch for connected controllers

* fixed bug

* Added message for devices with their hid modem mismatched

* Tweaked Devices list item template

* Added placeholder for device warning status in devices list

* UI tweaks

* Added placeholder for hid match warning

* UI change

* Limited profile name to 100 characteres

* UI tweaks

* Fixed preventing blank name for profile

* UI changes

* Save/Load DshmConfigUser from ProgramData/ControlApp folder

* Changed Hid Mismatch dialog

* Fixed missing file

* Updated Nefarius.Utilities.DeviceManagement nuget

* Start implementing serilog to file

* Fixed crash on BT hostradio not active

* Changed log minimum level to debug

* Added logging to DshmDevMan

* [DshmConfigManager] Added logging

* Fixed debug message conditions

* Tweaked log message

* Added logging to JsonDshmUserData

* Added logging to DshmConfig

* Added logging to DshmConfigSerialization

* Only update global profile mark if new global was set

* Added logging to ProfilesViewModel

* Added logging to ProfileViewModel

* Added logging to DevicesViewModel

* Added log message to ProfileViewModel

* Added logging to DeviceViewModel

* Update LockState of settings VM groups on constructor

* Commented line out

* Lock Leds and Rumble settings if in SXS mode

* Fixed bug

* Fixed method not executing on blank PropertyChanged

* Tweaked log message

* Tweaked log message

* Added ExpectedHidMode property

* Refactored code

* Tweaked log message

* Added placeholder for "restart as admin" btn

* Temporarely disabled debug log

* Refactored code

* Fixed comment

* Moved LeftMotorResc(...) range validation to ViewModel

* Moved all DeviceSettings to Driver format convertion to a single function

* Added property to DeviceViewModel

* Device settings editor will only be shown in Devices page if in custom mode

* Refactored code

* Refactored code

* Removed empty line

* fixed typo

* Implemented device property to app HID mode dictionary

* Refactored code

* fixed typo

* Moved driver to app dictionary

* Tweaked text

* Added class for general app state logic

* Implemented restarting app as admin from main window

* Updated WPF-UI to v3.0.4 (stable)

* Implemented reconnect HID mismatche devices on prompt confirmation

* Show MessageBox if failing to reconnect one or more devices

* Tweaked message

* Fixed dark mode theme

* Show MessageBox if restarting USB device without admin rights

* Changed power cycling button icon depending on device connection type

* Replaced power cycling attempt messagebox with snackbar message

* Tweaked snackbar message

* Deny apps/games from controlling LEDs by default

* Tweaked message

* Tweaked profiles page menu

* Format custom pairing address if valid

* Only accept valid characters for custom pairing address, truncate string if too big

* Show current Global profile in Device Settings View

* Removed leftover code

* Set max length for device custom pairing address textbox

* Changed connection type icon position

* Updated Button Combination App To Driver converstion

* Renamed button enums

* Updated default value for QuickDisconnect Hold Time

* Updated default value for AltRumbleMode Toggle combo

* Changed HoldTime and IdleDisconnectTime to ms

* Replaced individual combo buttons with array

* Removed Button.None

* Intialize Device custom pairing address as empty instead of null

* Fixed Alt rumble toggle combo default value

* Initialize _customPairingAddress with empty string on Device VM

* Fixed time conversion in Button Combo VM

* Updated dshm config file variables to match the ones expected by the driver

* Set maximum value of On and Off custom LED portion to 255

* fixed CycleDuration convertion

* Fixed Leds CopyCustoms method not copying OffPeriodCycles

* Changed variable type from byte to int

* Tweaked custom LEDs view

* Removed comment

* Reworked LEDs App to Driver conversion

* Updated App to Driver LED convertion to match driver

* Updated App to Driver LED conversion to properly set static LEDs

* Refactored code

* Tweaked General Rumble UserControl

* Renamed variables to match driver side

* Restructe driver format

* Renamed class

* Renamed variables to match what driver expects

* Renamed variables

* Rename variable

* fix setting conversion

* Always write to DisableRight and DisableLeft motors on conversion

* Always translate toggle combo variables if combo is enabled

* Add enums for DevicePairingMode

* Add property to DshmDeviceSettings

* Add device pairing mode translation dictionary

* Translate device pairing mode when updating dshm driver config

* Renamed property

* Start Implementing PairOnHotReload config

* Add property

* Implement property in device VM

* Set host address in view to unknown if last host request failed

* Add command for triggering hot pairing

* Format mac address when setting property

* Add contentDialogService to Device VM

* refactored

* Add using directive

* Show dialog when triggering pairing

* Updated view

* Inject _contentDialogService on DeviceVM construction

* Update dshidmini.sln

* Safely handle user data deserialization errors

* Update dshidmini.sln

* Updated dependencies

* Refined logger definition

* Removed legacy code

Replaced outdated URL

* Update .gitignore

* Added publish profile

* Added README

* Update release-win-x64.pubxml

* Added control app publishing to CI

* Update appveyor.yml

* Update ControlApp.csproj

* Do not run CA on CI

* Changed control app publish path

* Removed DSHMC from build config

* Allows setting same button on button combos

---------

Co-authored-by: Benjamin Höglinger-Stelzer <[email protected]>
  • Loading branch information
Kanuan and nefarius authored Jul 6, 2024
1 parent e0ae972 commit 90eb002
Show file tree
Hide file tree
Showing 88 changed files with 8,139 additions and 11 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,6 @@ healthchecksdb
/DSHMC.schema.json
/setup/DsHidMini Driver-SetupFiles
/setup/DsHidMini Driver-cache
/ControlApp
**/vcpkg_installed
**/*.g.wxs
/XInputBridge/exports
Expand Down
34 changes: 34 additions & 0 deletions ControlApp/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<Application
x:Class="Nefarius.DsHidMini.ControlApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helpers="clr-namespace:Nefarius.DsHidMini.ControlApp.Helpers"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
DispatcherUnhandledException="OnDispatcherUnhandledException"
Exit="OnExit"
Startup="OnStartup">
<Application.Resources>
<ResourceDictionary>
<BitmapImage x:Key="NormalRumbleModeImage" UriSource="\Resources\NormalRumbleMode.png" />
<BitmapImage x:Key="AltRumbleModeImage" UriSource="\Resources\AltRumbleMode.png" />
<helpers:VisibilityPerHidModeConverter x:Key="VisibilityPerHIDModeConverterKey" />
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<helpers:BooleanToVisibilityConverter
x:Key="BoolToVis_TC_FV"
False="Visible"
True="Collapsed" />
<helpers:BooleanToVisibilityConverter
x:Key="BoolToVis_TV_FC"
False="Collapsed"
True="Visible" />
<helpers:BooleanToVisibilityConverter
x:Key="BoolToVis_TV_FH"
False="Hidden"
True="Visible" />
<ResourceDictionary.MergedDictionaries>
<ui:ThemesDictionary Theme="Dark" />
<ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
116 changes: 116 additions & 0 deletions ControlApp/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.

using System.IO;
using System.Reflection;
using System.Windows.Threading;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Nefarius.DsHidMini.ControlApp.Models;
using Nefarius.DsHidMini.ControlApp.Models.DshmConfigManager;
using Nefarius.DsHidMini.ControlApp.Services;
using Nefarius.DsHidMini.ControlApp.ViewModels.Pages;
using Nefarius.DsHidMini.ControlApp.ViewModels.Windows;
using Nefarius.DsHidMini.ControlApp.Views.Pages;
using Nefarius.DsHidMini.ControlApp.Views.Windows;
using Nefarius.Utilities.Bluetooth;
using Nefarius.Utilities.DeviceManagement.PnP;

using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Sinks.File;

using Wpf.Ui;

namespace Nefarius.DsHidMini.ControlApp
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App
{
// The.NET Generic Host provides dependency injection, configuration, logging, and other services.
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
// https://docs.microsoft.com/dotnet/core/extensions/configuration
// https://docs.microsoft.com/dotnet/core/extensions/logging
private static readonly IHost _host = Host
.CreateDefaultBuilder()
.ConfigureAppConfiguration(c => { c.SetBasePath(Path.GetDirectoryName(Assembly.GetEntryAssembly()!.Location)); })
.ConfigureServices((context, services) =>
{
services.AddHostedService<ApplicationHostService>();

services.AddSingleton<MainWindow>();
services.AddSingleton<MainWindowViewModel>();
services.AddSingleton<INavigationService, NavigationService>();
services.AddSingleton<ISnackbarService, SnackbarService>();
services.AddSingleton<IContentDialogService, ContentDialogService>();

services.AddSingleton<DeviceNotificationListener>();
services.AddSingleton<AppSnackbarMessagesService>();

services.AddSingleton<DshmDevMan>();
services.AddSingleton<DshmConfigManager>();

services.AddSingleton<DevicesPage>();
services.AddSingleton<DevicesViewModel>();
services.AddSingleton<ProfilesPage>();
services.AddSingleton<ProfilesViewModel>();
services.AddSingleton<SettingsPage>();
services.AddSingleton<SettingsViewModel>();
services.AddSingleton<Main>();

Log.Logger = new LoggerConfiguration()
//.MinimumLevel.Debug()
.WriteTo.File(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
"DsHidMini\\Log\\ControlAppLog.txt"))
.CreateLogger();

services.AddSerilog(Log.Logger);
}).Build();

/// <summary>
/// Gets registered service.
/// </summary>
/// <typeparam name="T">Type of the service to get.</typeparam>
/// <returns>Instance of the service or <see langword="null"/>.</returns>
public static T GetService<T>()
where T : class
{
return _host.Services.GetService(typeof(T)) as T;
}

/// <summary>
/// Occurs when the application is loading.
/// </summary>
private void OnStartup(object sender, StartupEventArgs e)
{
Log.Logger.Information("App startup");
_host.Start();
}

/// <summary>
/// Occurs when the application is closing.
/// </summary>
private async void OnExit(object sender, ExitEventArgs e)
{
Log.Logger.Information("App exiting");
await _host.StopAsync();
_host.Dispose();
}

/// <summary>
/// Occurs when an exception is thrown by an application but not handled.
/// </summary>
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
{
// For more info see https://docs.microsoft.com/en-us/dotnet/api/system.windows.application.dispatcherunhandledexception?view=windowsdesktop-6.0
}
}
}
15 changes: 15 additions & 0 deletions ControlApp/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file, You can obtain one at https://opensource.org/licenses/MIT.
// Copyright (C) Leszek Pomianowski and WPF UI Contributors.
// All Rights Reserved.

using System.Windows;

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
Binary file added ControlApp/Assets/wpfui-icon-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ControlApp/Assets/wpfui-icon-256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
71 changes: 71 additions & 0 deletions ControlApp/ControlApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.17763.0</TargetFramework>
<ApplicationManifest>app.manifest</ApplicationManifest>
<ApplicationIcon>wpfui-icon.ico</ApplicationIcon>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<Platforms>AnyCPU;x64</Platforms>
<SupportedOSPlatformVersion>10.0.17763.0</SupportedOSPlatformVersion>
<RootNamespace>Nefarius.DsHidMini.ControlApp</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>3.0.0</Version>
</PropertyGroup>

<ItemGroup>
<Content Include="wpfui-icon.ico" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Nefarius.Utilities.Bluetooth" Version="1.4.8" />
<PackageReference Include="Nefarius.Utilities.DeviceManagement" Version="3.21.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="WPF-UI" Version="3.0.4" />
</ItemGroup>

<ItemGroup>
<None Remove="Assets\wpfui-icon-256.png" />
<None Remove="Assets\wpfui-icon-1024.png" />
<None Remove="Resources\AltRumbleMode.png" />
<None Remove="Resources\NormalRumbleMode.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Assets\wpfui-icon-256.png" />
<Resource Include="Assets\wpfui-icon-1024.png" />
<Resource Include="Resources\AltRumbleMode.png" />
<Resource Include="Resources\NormalRumbleMode.png" />
</ItemGroup>

<ItemGroup>
<Compile Update="Resources\test.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>test.resx</DependentUpon>
</Compile>
<Compile Update="Views\UserControls\ProfileUserControl.xaml.cs">
<SubType>Code</SubType>
</Compile>
<Compile Update="Views\UserControls\DeviceUserControl.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Update="Resources\test.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>test.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>

</Project>
3 changes: 3 additions & 0 deletions ControlApp/FodyWeavers.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ReactiveUI />
</Weavers>
26 changes: 26 additions & 0 deletions ControlApp/FodyWeavers.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ReactiveUI" minOccurs="0" maxOccurs="1" type="xs:anyType" />
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
36 changes: 36 additions & 0 deletions ControlApp/Helpers/BooleanConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Globalization;
using System.Windows.Data;

namespace Nefarius.DsHidMini.ControlApp.Helpers
{
public class BooleanConverter<T> : IValueConverter
{
public BooleanConverter(T trueValue, T falseValue)
{
True = trueValue;
False = falseValue;
}

public T True { get; set; }
public T False { get; set; }

public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is bool && ((bool)value) ? True : False;
}

public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is T && EqualityComparer<T>.Default.Equals((T)value, True);
}
}

public sealed class BooleanToVisibilityConverter : BooleanConverter<Visibility>
{
public BooleanToVisibilityConverter() :
base(Visibility.Visible, Visibility.Collapsed)
{ }
}


}
17 changes: 17 additions & 0 deletions ControlApp/Helpers/BooleanToReverseConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Globalization;
using System.Windows.Data;

namespace Nefarius.DsHidMini.ControlApp.Helpers
{
public class BooleanToReverseConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{

return !(bool?)value ?? true;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> !(value as bool?);
}
}
53 changes: 53 additions & 0 deletions ControlApp/Helpers/EnumBindingSourceExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Windows.Markup;

namespace Nefarius.DsHidMini.ControlApp.Helpers
{
public class EnumBindingSourceExtension : MarkupExtension
{
private Type _enumType;

public EnumBindingSourceExtension()
{
}

public EnumBindingSourceExtension(Type enumType)
{
EnumType = enumType;
}

public Type EnumType
{
get => _enumType;
set
{
if (value != _enumType)
{
if (null != value)
{
var enumType = Nullable.GetUnderlyingType(value) ?? value;
if (!enumType.IsEnum)
throw new ArgumentException("Type must be for an Enum.");
}

_enumType = value;
}
}
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
if (null == _enumType)
throw new InvalidOperationException("The EnumType must be specified.");

var actualEnumType = Nullable.GetUnderlyingType(_enumType) ?? _enumType;
var enumValues = Enum.GetValues(actualEnumType);

if (actualEnumType == _enumType)
return enumValues;

var tempArray = Array.CreateInstance(actualEnumType, enumValues.Length + 1);
enumValues.CopyTo(tempArray, 1);
return tempArray;
}
}
}
Loading

0 comments on commit 90eb002

Please sign in to comment.