├── .gitattributes ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── feature_request.yml ├── .gitignore ├── Common └── Include │ ├── AdapterOption.h │ └── README.md ├── Community Installers ├── README.md └── VDD Panel │ ├── .editorconfig │ ├── .vsconfig │ ├── VDD Panel.Core │ ├── Contracts │ │ └── Services │ │ │ └── IFileService.cs │ ├── Helpers │ │ └── Json.cs │ ├── README.md │ ├── Services │ │ └── FileService.cs │ └── VDD Panel.Core.csproj │ ├── VDD Panel.sln │ └── VDD Panel │ ├── Activation │ ├── ActivationHandler.cs │ ├── AppNotificationActivationHandler.cs │ ├── DefaultActivationHandler.cs │ └── IActivationHandler.cs │ ├── App.xaml │ ├── App.xaml.cs │ ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.scale-200.png │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ ├── StoreLogo.png │ ├── Wide310x150Logo.scale-200.png │ └── WindowIcon.ico │ ├── Behaviors │ ├── NavigationViewHeaderBehavior.cs │ └── NavigationViewHeaderMode.cs │ ├── Contracts │ ├── Services │ │ ├── IActivationService.cs │ │ ├── IAppNotificationService.cs │ │ ├── ILocalSettingsService.cs │ │ ├── INavigationService.cs │ │ ├── INavigationViewService.cs │ │ ├── IPageService.cs │ │ ├── IThemeSelectorService.cs │ │ └── IWebViewService.cs │ └── ViewModels │ │ └── INavigationAware.cs │ ├── Helpers │ ├── EnumToBooleanConverter.cs │ ├── FrameExtensions.cs │ ├── NavigationHelper.cs │ ├── ResourceExtensions.cs │ ├── RuntimeHelper.cs │ ├── SettingsStorageExtensions.cs │ └── TitleBarHelper.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Models │ └── LocalSettingsOptions.cs │ ├── Package.appinstaller │ ├── Package.appxmanifest │ ├── Properties │ ├── PublishProfiles │ │ ├── win10-arm64.pubxml │ │ ├── win10-x64.pubxml │ │ └── win10-x86.pubxml │ └── launchsettings.json │ ├── README.md │ ├── Services │ ├── ActivationService.cs │ ├── AppNotificationService.cs │ ├── LocalSettingsService.cs │ ├── NavigationService.cs │ ├── NavigationViewService.cs │ ├── PageService.cs │ ├── ThemeSelectorService.cs │ └── WebViewService.cs │ ├── Strings │ └── en-us │ │ └── Resources.resw │ ├── Styles │ ├── FontSizes.xaml │ ├── TextBlock.xaml │ └── Thickness.xaml │ ├── TemplateStudio.xml │ ├── Usings.cs │ ├── VDD Panel.csproj │ ├── ViewModels │ ├── ConfigureViewModel.cs │ ├── GitHubViewModel.cs │ ├── MainViewModel.cs │ ├── SettingsViewModel.cs │ └── ShellViewModel.cs │ ├── Views │ ├── ConfigurePage.xaml │ ├── ConfigurePage.xaml.cs │ ├── GitHubPage.xaml │ ├── GitHubPage.xaml.cs │ ├── MainPage.xaml │ ├── MainPage.xaml.cs │ ├── SettingsPage.xaml │ ├── SettingsPage.xaml.cs │ ├── ShellPage.xaml │ └── ShellPage.xaml.cs │ ├── app.manifest │ └── appsettings.json ├── Community Scripts ├── HDRswitch-VDD.ps1 ├── README.md ├── changeres-VDD.ps1 ├── dep_fix.ps1 ├── primary-VDD.ps1 ├── refreshrate-VDD.ps1 ├── rotate-VDD.ps1 ├── scale-VDD.ps1 ├── toggle-VDD.ps1 └── winp-VDD.ps1 ├── LICENSE ├── README.md ├── Setup Installer ├── Universal Virtual Display Driver │ ├── LICENSE_nefcon.txt │ ├── NumberofMonitors.bat │ ├── Setup.bat │ ├── Setup.iss │ └── Universal Virtual Display Driver.ico ├── Virtual Display Driver HDR v1.0.0 │ ├── LICENSE_nefcon.txt │ ├── NumberofMonitors.bat │ ├── Setup.bat │ ├── Setup.iss │ └── Virtual Display Driver HDR.ico └── Virtual Display Driver v1.0.0 │ ├── LICENSE_nefcon.txt │ ├── NumberofMonitors.bat │ ├── Setup.bat │ ├── Setup.iss │ └── Virtual Display Driver.ico └── Virtual Display Driver (HDR) ├── 8K240HzHDR.edid ├── CppProperties.json ├── MttVDD.sln ├── MttVDD ├── Driver.cpp ├── Driver.h ├── MttVDD.inf ├── MttVDD.sln ├── MttVDD.vcxproj ├── MttVDD.vcxproj.filters ├── Trace.h └── readme.md ├── option.txt └── vdd_settings.xml /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [itsmikethetech, zjoasan] 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug report. 3 | title: "[Bug]: " 4 | labels: ["bug", "triage"] 5 | assignees: ["zjoasan", "bud3699", "itsmikethetech"] 6 | 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this bug report! 12 | - type: dropdown 13 | id: OS 14 | attributes: 15 | label: Which OS? 16 | description: What version of Windows are you running? 17 | options: 18 | - Win11 Pro 19 | - Win11 Home 20 | - Win10 Pro 21 | - Win10 Home 22 | - Other.. 23 | default: 0 24 | validations: 25 | required: true 26 | - type: dropdown 27 | id: Version 28 | attributes: 29 | label: Which release? 30 | description: What version of Windows are you running? 31 | options: 32 | - 24H2 33 | - 23H2 34 | - 22H2 35 | - 21H2 36 | - 1809 37 | - 1607 38 | - 1507 39 | - Other.. 40 | default: 0 41 | validations: 42 | required: true 43 | - type: markdown 44 | attributes: 45 | value: | 46 | If you struggle finding windows edition and version, Go to settings -> system -> about. Under windows specifications. 47 | - type: textarea 48 | id: bug-info 49 | attributes: 50 | label: Describe the bug 51 | description: Free text description. 52 | placeholder: | 53 | Tell us what you see! 54 | A clear and concise description of what the bug is. 55 | validations: 56 | required: true 57 | - type: textarea 58 | id: reproduce-info 59 | attributes: 60 | label: Steps to reproduce 61 | description: And if you can how to reproduce 62 | placeholder: | 63 | Tell us how to reproduce! 64 | Go to '...', 2. Click on '....', and so on. 65 | validations: 66 | required: false 67 | - type: textarea 68 | id: expected-info 69 | attributes: 70 | label: Expected behavior 71 | description: Please inform us about expected behavior. 72 | placeholder: | 73 | Description of behavior! 74 | When i Clicked... 75 | validations: 76 | required: false 77 | - type: textarea 78 | id: log-file 79 | attributes: 80 | label: Log File (Beta Only) 81 | description: Please attach the log file to help us diagnose the issue. You can drag and drop the file here or click to upload. The log can be retrieved by enabling the log file in the xml then restarting the driver. 82 | placeholder: Drag and drop the log file here or click to upload. 83 | validations: 84 | required: false 85 | 86 | - type: input 87 | id: contact 88 | attributes: 89 | label: Contact Details 90 | description: How can we get in touch with you if we need more info? 91 | placeholder: ex. email@example.com 92 | validations: 93 | required: false 94 | 95 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Request a new Feature. 3 | title: "[Feature]: " 4 | labels: ["remove", "customize", "companion", "enhancement", "newcode"] 5 | assignees: ["zjoasan", "bud3699", "itsmikethetech"] 6 | 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: | 11 | Thanks for taking the time to fill out this feature request report! 12 | - type: textarea 13 | id: frprob 14 | attributes: 15 | label: Is the feature related to a "problem"? 16 | description: Describe the problem, in detail. 17 | placeholder: Tell us how to reproduce 18 | value: "When start X I wish to.." 19 | validations: 20 | required: true 21 | - type: textarea 22 | id: your-solution 23 | attributes: 24 | label: Your suggestion 25 | description: Describe what would solve your problem, as detailed as possible. 26 | placeholder: Tell us how to progress! 27 | value: "Disable a specific VD via hotkey" 28 | validations: 29 | required: true 30 | - type: input 31 | id: contact 32 | attributes: 33 | label: Contact Details 34 | description: How can we get in touch with you if we need more info? 35 | placeholder: ex. email@example.com 36 | validations: 37 | required: false 38 | 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /Common/Include/AdapterOption.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include // For ComPtr 4 | #include // For IDXGIAdapter, IDXGIFactory1 5 | #include // For sort 6 | 7 | using namespace std; 8 | using namespace Microsoft::WRL; 9 | 10 | // Structure to vector gpus 11 | struct GPUInfo { 12 | wstring name; // GPU name 13 | ComPtr adapter;// COM pointer to the adapter 14 | DXGI_ADAPTER_DESC desc; // Adapter description 15 | }; 16 | 17 | // Sort function for GPUs by dedicated video memory 18 | bool CompareGPUs(const GPUInfo& a, const GPUInfo& b) { 19 | return a.desc.DedicatedVideoMemory > b.desc.DedicatedVideoMemory; 20 | } 21 | 22 | // Get a enumerate list of available GPUs 23 | vector getAvailableGPUs() { 24 | vector gpus; // Vector to hold all GPU's information 25 | 26 | ComPtr factory; 27 | if (!SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) { 28 | return gpus; 29 | } 30 | 31 | // Enumerate all adapters (GPUs) 32 | for (UINT i = 0;; i++) { 33 | ComPtr adapter; 34 | if (!SUCCEEDED(factory->EnumAdapters(i, &adapter))) { 35 | break; 36 | } 37 | 38 | DXGI_ADAPTER_DESC desc; 39 | 40 | if (!SUCCEEDED(adapter->GetDesc(&desc))) { 41 | continue; 42 | } 43 | 44 | // Add the adapter information to the list 45 | GPUInfo info{ desc.Description, adapter, desc }; 46 | gpus.push_back(info); 47 | } 48 | 49 | return gpus; 50 | } 51 | 52 | class AdapterOption { 53 | public: 54 | bool hasTargetAdapter{}; // Indicates if a target adapter is selected 55 | LUID adapterLuid{}; // Adapter's unique identifier (LUID) 56 | wstring target_name{}; // Target adapter name 57 | 58 | // Select the best GPU based on dedicated video memory 59 | wstring selectBestGPU() { 60 | auto gpus = getAvailableGPUs(); 61 | if (gpus.empty()) { 62 | return L""; // Error check for headless / vm 63 | } 64 | 65 | // Sort GPUs by dedicated video memory in descending order 66 | sort(gpus.begin(), gpus.end(), CompareGPUs); 67 | auto bestGPU = gpus.front(); // Get the GPU with the most memory 68 | 69 | return bestGPU.name; 70 | } 71 | 72 | // Load friendlyname from a file OR select the best GPU 73 | void load(const wchar_t* path) { 74 | ifstream ifs{ path }; 75 | 76 | if (!ifs.is_open()) { 77 | target_name = selectBestGPU(); 78 | } 79 | else { 80 | string line; 81 | getline(ifs, line); 82 | target_name.assign(line.begin(), line.end()); 83 | } 84 | 85 | // Find and set the adapter based on the target name 86 | if (!findAndSetAdapter(target_name)) { 87 | // If the adapter is not found, select the best GPU and retry 88 | target_name = selectBestGPU(); 89 | findAndSetAdapter(target_name); 90 | } 91 | } 92 | 93 | // Set the target adapter from a given name and validate it 94 | void xmlprovide(const wstring& xtarg) { 95 | target_name = xtarg; 96 | if (!findAndSetAdapter(target_name)) { 97 | // If the adapter is not found, select the best GPU and retry 98 | target_name = selectBestGPU(); 99 | findAndSetAdapter(target_name); 100 | } 101 | } 102 | 103 | // Apply the adapter settings to the specified adapter 104 | void apply(const IDDCX_ADAPTER& adapter) { 105 | if (hasTargetAdapter && IDD_IS_FUNCTION_AVAILABLE(IddCxAdapterSetRenderAdapter)) { 106 | IDARG_IN_ADAPTERSETRENDERADAPTER arg{}; 107 | arg.PreferredRenderAdapter = adapterLuid; 108 | IddCxAdapterSetRenderAdapter(adapter, &arg); 109 | } 110 | } 111 | 112 | private: 113 | // Find and set the adapter by its name 114 | bool findAndSetAdapter(const wstring& adapterName) { 115 | auto gpus = getAvailableGPUs(); 116 | 117 | // Iterate through all available GPUs 118 | for (const auto& gpu : gpus) { 119 | if (_wcsicmp(gpu.name.c_str(), adapterName.c_str()) == 0) { 120 | adapterLuid = gpu.desc.AdapterLuid; // Set the adapter LUID 121 | hasTargetAdapter = true; // Indicate that a target adapter is selected 122 | return true; 123 | } 124 | } 125 | 126 | hasTargetAdapter = false; // Indicate that no target adapter is selected 127 | return false; 128 | } 129 | }; 130 | -------------------------------------------------------------------------------- /Common/Include/README.md: -------------------------------------------------------------------------------- 1 | Required include(s). Plans to combine it into the driver to reduce includes. 2 | -------------------------------------------------------------------------------- /Community Installers/README.md: -------------------------------------------------------------------------------- 1 | Note: Some of the files included with installer files may use code from outside sources and as such, would not be covered by the open source license. Only the virtual display driver itself is fully FOSS, while other terms may apply based on the installer packaging method used. 2 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/.editorconfig: -------------------------------------------------------------------------------- 1 | # Rules in this file were initially inferred by Visual Studio IntelliCode from the Template Studio codebase. 2 | # You can modify the rules from these initially generated values to suit your own policies. 3 | # You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference. 4 | 5 | [*.cs] 6 | 7 | #Core editorconfig formatting - indentation 8 | 9 | #use soft tabs (spaces) for indentation 10 | indent_style = space 11 | 12 | #Formatting - new line options 13 | 14 | #place else statements on a new line 15 | csharp_new_line_before_else = true 16 | #require braces to be on a new line for lambdas, methods, control_blocks, types, properties, and accessors (also known as "Allman" style) 17 | csharp_new_line_before_open_brace = all 18 | 19 | #Formatting - organize using options 20 | 21 | #sort System.* using directives alphabetically, and place them before other usings 22 | dotnet_sort_system_directives_first = true 23 | 24 | #Formatting - spacing options 25 | 26 | #require NO space between a cast and the value 27 | csharp_space_after_cast = false 28 | #require a space before the colon for bases or interfaces in a type declaration 29 | csharp_space_after_colon_in_inheritance_clause = true 30 | #require a space after a keyword in a control flow statement such as a for loop 31 | csharp_space_after_keywords_in_control_flow_statements = true 32 | #require a space before the colon for bases or interfaces in a type declaration 33 | csharp_space_before_colon_in_inheritance_clause = true 34 | #remove space within empty argument list parentheses 35 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 36 | #remove space between method call name and opening parenthesis 37 | csharp_space_between_method_call_name_and_opening_parenthesis = false 38 | #do not place space characters after the opening parenthesis and before the closing parenthesis of a method call 39 | csharp_space_between_method_call_parameter_list_parentheses = false 40 | #remove space within empty parameter list parentheses for a method declaration 41 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 42 | #place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list. 43 | csharp_space_between_method_declaration_parameter_list_parentheses = false 44 | 45 | #Formatting - wrapping options 46 | 47 | #leave code block on separate lines 48 | csharp_preserve_single_line_blocks = false 49 | 50 | #Style - Code block preferences 51 | 52 | #prefer curly braces even for one line of code 53 | csharp_prefer_braces = true:suggestion 54 | 55 | #Style - expression bodied member options 56 | 57 | #prefer expression bodies for accessors 58 | csharp_style_expression_bodied_accessors = true:warning 59 | #prefer block bodies for constructors 60 | csharp_style_expression_bodied_constructors = false:suggestion 61 | #prefer expression bodies for methods 62 | csharp_style_expression_bodied_methods = when_on_single_line:silent 63 | #prefer expression-bodied members for properties 64 | csharp_style_expression_bodied_properties = true:warning 65 | 66 | #Style - expression level options 67 | 68 | #prefer out variables to be declared before the method call 69 | csharp_style_inlined_variable_declaration = false:suggestion 70 | #prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them 71 | dotnet_style_predefined_type_for_member_access = true:suggestion 72 | 73 | #Style - Expression-level preferences 74 | 75 | #prefer default over default(T) 76 | csharp_prefer_simple_default_expression = true:suggestion 77 | #prefer objects to be initialized using object initializers when possible 78 | dotnet_style_object_initializer = true:suggestion 79 | 80 | #Style - implicit and explicit types 81 | 82 | #prefer var over explicit type in all cases, unless overridden by another code style rule 83 | csharp_style_var_elsewhere = true:suggestion 84 | #prefer var is used to declare variables with built-in system types such as int 85 | csharp_style_var_for_built_in_types = true:suggestion 86 | #prefer var when the type is already mentioned on the right-hand side of a declaration expression 87 | csharp_style_var_when_type_is_apparent = true:suggestion 88 | 89 | #Style - language keyword and framework type options 90 | 91 | #prefer the language keyword for local variables, method parameters, and class members, instead of the type name, for types that have a keyword to represent them 92 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion 93 | 94 | #Style - Language rules 95 | csharp_style_implicit_object_creation_when_type_is_apparent = true:warning 96 | csharp_style_var_for_built_in_types = true:warning 97 | 98 | #Style - modifier options 99 | 100 | #prefer accessibility modifiers to be declared except for public interface members. This will currently not differ from always and will act as future proofing for if C# adds default interface methods. 101 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion 102 | 103 | #Style - Modifier preferences 104 | 105 | #when this rule is set to a list of modifiers, prefer the specified ordering. 106 | csharp_preferred_modifier_order = public,private,protected,internal,static,async,readonly,override,sealed,abstract,virtual:warning 107 | dotnet_style_readonly_field = true:warning 108 | 109 | #Style - Pattern matching 110 | 111 | #prefer pattern matching instead of is expression with type casts 112 | csharp_style_pattern_matching_over_as_with_null_check = true:warning 113 | 114 | #Style - qualification options 115 | 116 | #prefer events not to be prefaced with this. or Me. in Visual Basic 117 | dotnet_style_qualification_for_event = false:suggestion 118 | #prefer fields not to be prefaced with this. or Me. in Visual Basic 119 | dotnet_style_qualification_for_field = false:suggestion 120 | #prefer methods not to be prefaced with this. or Me. in Visual Basic 121 | dotnet_style_qualification_for_method = false:suggestion 122 | #prefer properties not to be prefaced with this. or Me. in Visual Basic 123 | dotnet_style_qualification_for_property = false:suggestion 124 | csharp_indent_labels = one_less_than_current 125 | csharp_using_directive_placement = outside_namespace:silent 126 | csharp_prefer_simple_using_statement = true:warning 127 | csharp_style_namespace_declarations = file_scoped:warning 128 | csharp_style_expression_bodied_operators = false:silent 129 | csharp_style_expression_bodied_indexers = true:silent 130 | csharp_style_expression_bodied_lambdas = true:silent 131 | csharp_style_expression_bodied_local_functions = false:silent 132 | 133 | [*.{cs,vb}] 134 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 135 | tab_width = 4 136 | indent_size = 4 137 | end_of_line = crlf 138 | dotnet_style_coalesce_expression = true:suggestion 139 | dotnet_style_null_propagation = true:suggestion 140 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 141 | dotnet_style_prefer_auto_properties = true:silent 142 | dotnet_style_object_initializer = true:suggestion 143 | dotnet_style_collection_initializer = true:suggestion 144 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 145 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 146 | dotnet_style_prefer_conditional_expression_over_return = true:silent 147 | [*.{cs,vb}] 148 | 149 | #Style - Unnecessary code rules 150 | csharp_style_unused_value_assignment_preference = discard_variable:warning 151 | 152 | #### Naming styles #### 153 | 154 | # Naming rules 155 | 156 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 157 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 158 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 159 | 160 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 161 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 162 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 163 | 164 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 165 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 166 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 167 | 168 | # Symbol specifications 169 | 170 | dotnet_naming_symbols.interface.applicable_kinds = interface 171 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 172 | dotnet_naming_symbols.interface.required_modifiers = 173 | 174 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 175 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 176 | dotnet_naming_symbols.types.required_modifiers = 177 | 178 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 179 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 180 | dotnet_naming_symbols.non_field_members.required_modifiers = 181 | 182 | # Naming styles 183 | 184 | dotnet_naming_style.begins_with_i.required_prefix = I 185 | dotnet_naming_style.begins_with_i.required_suffix = 186 | dotnet_naming_style.begins_with_i.word_separator = 187 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 188 | 189 | dotnet_naming_style.pascal_case.required_prefix = 190 | dotnet_naming_style.pascal_case.required_suffix = 191 | dotnet_naming_style.pascal_case.word_separator = 192 | dotnet_naming_style.pascal_case.capitalization = pascal_case 193 | 194 | dotnet_naming_style.pascal_case.required_prefix = 195 | dotnet_naming_style.pascal_case.required_suffix = 196 | dotnet_naming_style.pascal_case.word_separator = 197 | dotnet_naming_style.pascal_case.capitalization = pascal_case 198 | dotnet_style_explicit_tuple_names = true:suggestion 199 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 200 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 201 | dotnet_style_prefer_compound_assignment = true:warning 202 | dotnet_style_prefer_simplified_interpolation = true:suggestion 203 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/.vsconfig: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0", 3 | "components": [ 4 | "Microsoft.Component.MSBuild", 5 | "Microsoft.NetCore.Component.Runtime.7.0", 6 | "Microsoft.NetCore.Component.SDK", 7 | "Microsoft.VisualStudio.Component.ManagedDesktop.Core", 8 | "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites", 9 | "Microsoft.VisualStudio.Component.NuGet", 10 | "Microsoft.VisualStudio.Component.Windows10SDK.19041", 11 | "Microsoft.VisualStudio.Component.Windows10SDK", 12 | "Microsoft.VisualStudio.ComponentGroup.MSIX.Packaging", 13 | "Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs", 14 | "Microsoft.VisualStudio.Workload.ManagedDesktop" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel.Core/Contracts/Services/IFileService.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Core.Contracts.Services; 2 | 3 | public interface IFileService 4 | { 5 | T Read(string folderPath, string fileName); 6 | 7 | void Save(string folderPath, string fileName, T content); 8 | 9 | void Delete(string folderPath, string fileName); 10 | } 11 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel.Core/Helpers/Json.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace VDD_Panel.Core.Helpers; 4 | 5 | public static class Json 6 | { 7 | public static async Task ToObjectAsync(string value) 8 | { 9 | return await Task.Run(() => 10 | { 11 | return JsonConvert.DeserializeObject(value); 12 | }); 13 | } 14 | 15 | public static async Task StringifyAsync(object value) 16 | { 17 | return await Task.Run(() => 18 | { 19 | return JsonConvert.SerializeObject(value); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel.Core/README.md: -------------------------------------------------------------------------------- 1 | *Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)* 2 | 3 | ## Getting Started 4 | 5 | The Core project contains code that can be [reused across multiple application projects](https://docs.microsoft.com/dotnet/standard/net-standard#net-5-and-net-standard). 6 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel.Core/Services/FileService.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | 3 | using Newtonsoft.Json; 4 | 5 | using VDD_Panel.Core.Contracts.Services; 6 | 7 | namespace VDD_Panel.Core.Services; 8 | 9 | public class FileService : IFileService 10 | { 11 | public T Read(string folderPath, string fileName) 12 | { 13 | var path = Path.Combine(folderPath, fileName); 14 | if (File.Exists(path)) 15 | { 16 | var json = File.ReadAllText(path); 17 | return JsonConvert.DeserializeObject(json); 18 | } 19 | 20 | return default; 21 | } 22 | 23 | public void Save(string folderPath, string fileName, T content) 24 | { 25 | if (!Directory.Exists(folderPath)) 26 | { 27 | Directory.CreateDirectory(folderPath); 28 | } 29 | 30 | var fileContent = JsonConvert.SerializeObject(content); 31 | File.WriteAllText(Path.Combine(folderPath, fileName), fileContent, Encoding.UTF8); 32 | } 33 | 34 | public void Delete(string folderPath, string fileName) 35 | { 36 | if (fileName != null && File.Exists(Path.Combine(folderPath, fileName))) 37 | { 38 | File.Delete(Path.Combine(folderPath, fileName)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel.Core/VDD Panel.Core.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net7.0 4 | VDD_Panel.Core 5 | AnyCPU;x64;x86 6 | x86;x64;arm64;AnyCPU 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34622.214 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDD Panel", "VDD Panel\VDD Panel.csproj", "{5FA23A93-E3D0-46A3-89AA-A909685E2784}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDD Panel.Core", "VDD Panel.Core\VDD Panel.Core.csproj", "{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|arm64 = Debug|arm64 14 | Debug|x64 = Debug|x64 15 | Debug|x86 = Debug|x86 16 | Release|Any CPU = Release|Any CPU 17 | Release|arm64 = Release|arm64 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|Any CPU.ActiveCfg = Debug|x64 23 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|Any CPU.Build.0 = Debug|x64 24 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|Any CPU.Deploy.0 = Debug|x64 25 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|arm64.ActiveCfg = Debug|arm64 26 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|arm64.Build.0 = Debug|arm64 27 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|arm64.Deploy.0 = Debug|arm64 28 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x64.ActiveCfg = Debug|x64 29 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x64.Build.0 = Debug|x64 30 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x64.Deploy.0 = Debug|x64 31 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x86.ActiveCfg = Debug|x86 32 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x86.Build.0 = Debug|x86 33 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x86.Deploy.0 = Debug|x86 34 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|Any CPU.ActiveCfg = Release|x64 35 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|Any CPU.Build.0 = Release|x64 36 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|Any CPU.Deploy.0 = Release|x64 37 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|arm64.ActiveCfg = Release|arm64 38 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|arm64.Build.0 = Release|arm64 39 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|arm64.Deploy.0 = Release|arm64 40 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x64.ActiveCfg = Release|x64 41 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x64.Build.0 = Release|x64 42 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x64.Deploy.0 = Release|x64 43 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x86.ActiveCfg = Release|x86 44 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x86.Build.0 = Release|x86 45 | {5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x86.Deploy.0 = Release|x86 46 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|arm64.ActiveCfg = Debug|arm64 49 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|arm64.Build.0 = Debug|arm64 50 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x64.ActiveCfg = Debug|x64 51 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x64.Build.0 = Debug|x64 52 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x86.ActiveCfg = Debug|x86 53 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x86.Build.0 = Debug|x86 54 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|arm64.ActiveCfg = Release|arm64 57 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|arm64.Build.0 = Release|arm64 58 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x64.ActiveCfg = Release|x64 59 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x64.Build.0 = Release|x64 60 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x86.ActiveCfg = Release|x86 61 | {29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x86.Build.0 = Release|x86 62 | EndGlobalSection 63 | GlobalSection(SolutionProperties) = preSolution 64 | HideSolutionNode = FALSE 65 | EndGlobalSection 66 | GlobalSection(ExtensibilityGlobals) = postSolution 67 | SolutionGuid = {81C98471-4829-40B4-B60F-CEB2472667FC} 68 | EndGlobalSection 69 | EndGlobal 70 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Activation/ActivationHandler.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Activation; 2 | 3 | // Extend this class to implement new ActivationHandlers. See DefaultActivationHandler for an example. 4 | // https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/activation.md 5 | public abstract class ActivationHandler : IActivationHandler 6 | where T : class 7 | { 8 | // Override this method to add the logic for whether to handle the activation. 9 | protected virtual bool CanHandleInternal(T args) => true; 10 | 11 | // Override this method to add the logic for your activation handler. 12 | protected abstract Task HandleInternalAsync(T args); 13 | 14 | public bool CanHandle(object args) => args is T && CanHandleInternal((args as T)!); 15 | 16 | public async Task HandleAsync(object args) => await HandleInternalAsync((args as T)!); 17 | } 18 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Activation/AppNotificationActivationHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Dispatching; 2 | using Microsoft.UI.Xaml; 3 | using Microsoft.Windows.AppLifecycle; 4 | using Microsoft.Windows.AppNotifications; 5 | 6 | using VDD_Panel.Contracts.Services; 7 | using VDD_Panel.ViewModels; 8 | 9 | namespace VDD_Panel.Activation; 10 | 11 | public class AppNotificationActivationHandler : ActivationHandler 12 | { 13 | private readonly INavigationService _navigationService; 14 | private readonly IAppNotificationService _notificationService; 15 | 16 | public AppNotificationActivationHandler(INavigationService navigationService, IAppNotificationService notificationService) 17 | { 18 | _navigationService = navigationService; 19 | _notificationService = notificationService; 20 | } 21 | 22 | protected override bool CanHandleInternal(LaunchActivatedEventArgs args) 23 | { 24 | return AppInstance.GetCurrent().GetActivatedEventArgs()?.Kind == ExtendedActivationKind.AppNotification; 25 | } 26 | 27 | protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args) 28 | { 29 | // TODO: Handle notification activations. 30 | 31 | //// // Access the AppNotificationActivatedEventArgs. 32 | //// var activatedEventArgs = (AppNotificationActivatedEventArgs)AppInstance.GetCurrent().GetActivatedEventArgs().Data; 33 | 34 | //// // Navigate to a specific page based on the notification arguments. 35 | //// if (_notificationService.ParseArguments(activatedEventArgs.Argument)["action"] == "Settings") 36 | //// { 37 | //// // Queue navigation with low priority to allow the UI to initialize. 38 | //// App.MainWindow.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () => 39 | //// { 40 | //// _navigationService.NavigateTo(typeof(SettingsViewModel).FullName!); 41 | //// }); 42 | //// } 43 | 44 | App.MainWindow.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () => 45 | { 46 | App.MainWindow.ShowMessageDialogAsync("TODO: Handle notification activations.", "Notification Activation"); 47 | }); 48 | 49 | await Task.CompletedTask; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Activation/DefaultActivationHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | using VDD_Panel.Contracts.Services; 4 | using VDD_Panel.ViewModels; 5 | 6 | namespace VDD_Panel.Activation; 7 | 8 | public class DefaultActivationHandler : ActivationHandler 9 | { 10 | private readonly INavigationService _navigationService; 11 | 12 | public DefaultActivationHandler(INavigationService navigationService) 13 | { 14 | _navigationService = navigationService; 15 | } 16 | 17 | protected override bool CanHandleInternal(LaunchActivatedEventArgs args) 18 | { 19 | // None of the ActivationHandlers has handled the activation. 20 | return _navigationService.Frame?.Content == null; 21 | } 22 | 23 | protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args) 24 | { 25 | _navigationService.NavigateTo(typeof(MainViewModel).FullName!, args.Arguments); 26 | 27 | await Task.CompletedTask; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Activation/IActivationHandler.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Activation; 2 | 3 | public interface IActivationHandler 4 | { 5 | bool CanHandle(object args); 6 | 7 | Task HandleAsync(object args); 8 | } 9 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Hosting; 3 | using Microsoft.UI.Xaml; 4 | 5 | using VDD_Panel.Activation; 6 | using VDD_Panel.Contracts.Services; 7 | using VDD_Panel.Core.Contracts.Services; 8 | using VDD_Panel.Core.Services; 9 | using VDD_Panel.Helpers; 10 | using VDD_Panel.Models; 11 | using VDD_Panel.Notifications; 12 | using VDD_Panel.Services; 13 | using VDD_Panel.ViewModels; 14 | using VDD_Panel.Views; 15 | 16 | namespace VDD_Panel; 17 | 18 | // To learn more about WinUI 3, see https://docs.microsoft.com/windows/apps/winui/winui3/. 19 | public partial class App : Application 20 | { 21 | // The .NET Generic Host provides dependency injection, configuration, logging, and other services. 22 | // https://docs.microsoft.com/dotnet/core/extensions/generic-host 23 | // https://docs.microsoft.com/dotnet/core/extensions/dependency-injection 24 | // https://docs.microsoft.com/dotnet/core/extensions/configuration 25 | // https://docs.microsoft.com/dotnet/core/extensions/logging 26 | public IHost Host 27 | { 28 | get; 29 | } 30 | 31 | public static T GetService() 32 | where T : class 33 | { 34 | if ((App.Current as App)!.Host.Services.GetService(typeof(T)) is not T service) 35 | { 36 | throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs."); 37 | } 38 | 39 | return service; 40 | } 41 | 42 | public static WindowEx MainWindow { get; } = new MainWindow(); 43 | 44 | public static UIElement? AppTitlebar { get; set; } 45 | 46 | public App() 47 | { 48 | InitializeComponent(); 49 | 50 | Host = Microsoft.Extensions.Hosting.Host. 51 | CreateDefaultBuilder(). 52 | UseContentRoot(AppContext.BaseDirectory). 53 | ConfigureServices((context, services) => 54 | { 55 | // Default Activation Handler 56 | services.AddTransient, DefaultActivationHandler>(); 57 | 58 | // Other Activation Handlers 59 | services.AddTransient(); 60 | 61 | // Services 62 | services.AddSingleton(); 63 | services.AddSingleton(); 64 | services.AddSingleton(); 65 | services.AddTransient(); 66 | services.AddTransient(); 67 | 68 | services.AddSingleton(); 69 | services.AddSingleton(); 70 | services.AddSingleton(); 71 | 72 | // Core Services 73 | services.AddSingleton(); 74 | 75 | // Views and ViewModels 76 | services.AddTransient(); 77 | services.AddTransient(); 78 | services.AddTransient(); 79 | services.AddTransient(); 80 | services.AddTransient(); 81 | services.AddTransient(); 82 | services.AddTransient(); 83 | services.AddTransient(); 84 | services.AddTransient(); 85 | services.AddTransient(); 86 | 87 | // Configuration 88 | services.Configure(context.Configuration.GetSection(nameof(LocalSettingsOptions))); 89 | }). 90 | Build(); 91 | 92 | App.GetService().Initialize(); 93 | 94 | UnhandledException += App_UnhandledException; 95 | } 96 | 97 | private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e) 98 | { 99 | // TODO: Log and handle exceptions as appropriate. 100 | // https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception. 101 | } 102 | 103 | protected async override void OnLaunched(LaunchActivatedEventArgs args) 104 | { 105 | base.OnLaunched(args); 106 | 107 | App.GetService().Show(string.Format("AppNotificationSamplePayload".GetLocalized(), AppContext.BaseDirectory)); 108 | 109 | await App.GetService().ActivateAsync(args); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/StoreLogo.png -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Assets/WindowIcon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Community Installers/VDD Panel/VDD Panel/Assets/WindowIcon.ico -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Behaviors/NavigationViewHeaderBehavior.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | using Microsoft.UI.Xaml.Controls; 3 | using Microsoft.UI.Xaml.Navigation; 4 | using Microsoft.Xaml.Interactivity; 5 | 6 | using VDD_Panel.Contracts.Services; 7 | 8 | namespace VDD_Panel.Behaviors; 9 | 10 | public class NavigationViewHeaderBehavior : Behavior 11 | { 12 | private static NavigationViewHeaderBehavior? _current; 13 | 14 | private Page? _currentPage; 15 | 16 | public DataTemplate? DefaultHeaderTemplate 17 | { 18 | get; set; 19 | } 20 | 21 | public object DefaultHeader 22 | { 23 | get => GetValue(DefaultHeaderProperty); 24 | set => SetValue(DefaultHeaderProperty, value); 25 | } 26 | 27 | public static readonly DependencyProperty DefaultHeaderProperty = 28 | DependencyProperty.Register("DefaultHeader", typeof(object), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeader())); 29 | 30 | public static NavigationViewHeaderMode GetHeaderMode(Page item) => (NavigationViewHeaderMode)item.GetValue(HeaderModeProperty); 31 | 32 | public static void SetHeaderMode(Page item, NavigationViewHeaderMode value) => item.SetValue(HeaderModeProperty, value); 33 | 34 | public static readonly DependencyProperty HeaderModeProperty = 35 | DependencyProperty.RegisterAttached("HeaderMode", typeof(bool), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(NavigationViewHeaderMode.Always, (d, e) => _current!.UpdateHeader())); 36 | 37 | public static object GetHeaderContext(Page item) => item.GetValue(HeaderContextProperty); 38 | 39 | public static void SetHeaderContext(Page item, object value) => item.SetValue(HeaderContextProperty, value); 40 | 41 | public static readonly DependencyProperty HeaderContextProperty = 42 | DependencyProperty.RegisterAttached("HeaderContext", typeof(object), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeader())); 43 | 44 | public static DataTemplate GetHeaderTemplate(Page item) => (DataTemplate)item.GetValue(HeaderTemplateProperty); 45 | 46 | public static void SetHeaderTemplate(Page item, DataTemplate value) => item.SetValue(HeaderTemplateProperty, value); 47 | 48 | public static readonly DependencyProperty HeaderTemplateProperty = 49 | DependencyProperty.RegisterAttached("HeaderTemplate", typeof(DataTemplate), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeaderTemplate())); 50 | 51 | protected override void OnAttached() 52 | { 53 | base.OnAttached(); 54 | 55 | var navigationService = App.GetService(); 56 | navigationService.Navigated += OnNavigated; 57 | 58 | _current = this; 59 | } 60 | 61 | protected override void OnDetaching() 62 | { 63 | base.OnDetaching(); 64 | 65 | var navigationService = App.GetService(); 66 | navigationService.Navigated -= OnNavigated; 67 | } 68 | 69 | private void OnNavigated(object sender, NavigationEventArgs e) 70 | { 71 | if (sender is Frame frame && frame.Content is Page page) 72 | { 73 | _currentPage = page; 74 | 75 | UpdateHeader(); 76 | UpdateHeaderTemplate(); 77 | } 78 | } 79 | 80 | private void UpdateHeader() 81 | { 82 | if (_currentPage != null) 83 | { 84 | var headerMode = GetHeaderMode(_currentPage); 85 | if (headerMode == NavigationViewHeaderMode.Never) 86 | { 87 | AssociatedObject.Header = null; 88 | AssociatedObject.AlwaysShowHeader = false; 89 | } 90 | else 91 | { 92 | var headerFromPage = GetHeaderContext(_currentPage); 93 | if (headerFromPage != null) 94 | { 95 | AssociatedObject.Header = headerFromPage; 96 | } 97 | else 98 | { 99 | AssociatedObject.Header = DefaultHeader; 100 | } 101 | 102 | if (headerMode == NavigationViewHeaderMode.Always) 103 | { 104 | AssociatedObject.AlwaysShowHeader = true; 105 | } 106 | else 107 | { 108 | AssociatedObject.AlwaysShowHeader = false; 109 | } 110 | } 111 | } 112 | } 113 | 114 | private void UpdateHeaderTemplate() 115 | { 116 | if (_currentPage != null) 117 | { 118 | var headerTemplate = GetHeaderTemplate(_currentPage); 119 | AssociatedObject.HeaderTemplate = headerTemplate ?? DefaultHeaderTemplate; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Behaviors/NavigationViewHeaderMode.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Behaviors; 2 | 3 | public enum NavigationViewHeaderMode 4 | { 5 | Always, 6 | Never, 7 | Minimal 8 | } 9 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/IActivationService.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Contracts.Services; 2 | 3 | public interface IActivationService 4 | { 5 | Task ActivateAsync(object activationArgs); 6 | } 7 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/IAppNotificationService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Specialized; 2 | 3 | namespace VDD_Panel.Contracts.Services; 4 | 5 | public interface IAppNotificationService 6 | { 7 | void Initialize(); 8 | 9 | bool Show(string payload); 10 | 11 | NameValueCollection ParseArguments(string arguments); 12 | 13 | void Unregister(); 14 | } 15 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/ILocalSettingsService.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Contracts.Services; 2 | 3 | public interface ILocalSettingsService 4 | { 5 | Task ReadSettingAsync(string key); 6 | 7 | Task SaveSettingAsync(string key, T value); 8 | } 9 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/INavigationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | using Microsoft.UI.Xaml.Navigation; 3 | 4 | namespace VDD_Panel.Contracts.Services; 5 | 6 | public interface INavigationService 7 | { 8 | event NavigatedEventHandler Navigated; 9 | 10 | bool CanGoBack 11 | { 12 | get; 13 | } 14 | 15 | Frame? Frame 16 | { 17 | get; set; 18 | } 19 | 20 | bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false); 21 | 22 | bool GoBack(); 23 | } 24 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/INavigationViewService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | 3 | namespace VDD_Panel.Contracts.Services; 4 | 5 | public interface INavigationViewService 6 | { 7 | IList? MenuItems 8 | { 9 | get; 10 | } 11 | 12 | object? SettingsItem 13 | { 14 | get; 15 | } 16 | 17 | void Initialize(NavigationView navigationView); 18 | 19 | void UnregisterEvents(); 20 | 21 | NavigationViewItem? GetSelectedItem(Type pageType); 22 | } 23 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/IPageService.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Contracts.Services; 2 | 3 | public interface IPageService 4 | { 5 | Type GetPageType(string key); 6 | } 7 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/IThemeSelectorService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | namespace VDD_Panel.Contracts.Services; 4 | 5 | public interface IThemeSelectorService 6 | { 7 | ElementTheme Theme 8 | { 9 | get; 10 | } 11 | 12 | Task InitializeAsync(); 13 | 14 | Task SetThemeAsync(ElementTheme theme); 15 | 16 | Task SetRequestedThemeAsync(); 17 | } 18 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/Services/IWebViewService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | using Microsoft.Web.WebView2.Core; 3 | 4 | namespace VDD_Panel.Contracts.Services; 5 | 6 | public interface IWebViewService 7 | { 8 | Uri? Source 9 | { 10 | get; 11 | } 12 | 13 | bool CanGoBack 14 | { 15 | get; 16 | } 17 | 18 | bool CanGoForward 19 | { 20 | get; 21 | } 22 | 23 | event EventHandler? NavigationCompleted; 24 | 25 | void Initialize(WebView2 webView); 26 | 27 | void GoBack(); 28 | 29 | void GoForward(); 30 | 31 | void Reload(); 32 | 33 | void UnregisterEvents(); 34 | } 35 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Contracts/ViewModels/INavigationAware.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Contracts.ViewModels; 2 | 3 | public interface INavigationAware 4 | { 5 | void OnNavigatedTo(object parameter); 6 | 7 | void OnNavigatedFrom(); 8 | } 9 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Helpers/EnumToBooleanConverter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | using Microsoft.UI.Xaml.Data; 3 | 4 | namespace VDD_Panel.Helpers; 5 | 6 | public class EnumToBooleanConverter : IValueConverter 7 | { 8 | public EnumToBooleanConverter() 9 | { 10 | } 11 | 12 | public object Convert(object value, Type targetType, object parameter, string language) 13 | { 14 | if (parameter is string enumString) 15 | { 16 | if (!Enum.IsDefined(typeof(ElementTheme), value)) 17 | { 18 | throw new ArgumentException("ExceptionEnumToBooleanConverterValueMustBeAnEnum"); 19 | } 20 | 21 | var enumValue = Enum.Parse(typeof(ElementTheme), enumString); 22 | 23 | return enumValue.Equals(value); 24 | } 25 | 26 | throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName"); 27 | } 28 | 29 | public object ConvertBack(object value, Type targetType, object parameter, string language) 30 | { 31 | if (parameter is string enumString) 32 | { 33 | return Enum.Parse(typeof(ElementTheme), enumString); 34 | } 35 | 36 | throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName"); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Helpers/FrameExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | 3 | namespace VDD_Panel.Helpers; 4 | 5 | public static class FrameExtensions 6 | { 7 | public static object? GetPageViewModel(this Frame frame) => frame?.Content?.GetType().GetProperty("ViewModel")?.GetValue(frame.Content, null); 8 | } 9 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Helpers/NavigationHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | using Microsoft.UI.Xaml.Controls; 3 | 4 | namespace VDD_Panel.Helpers; 5 | 6 | // Helper class to set the navigation target for a NavigationViewItem. 7 | // 8 | // Usage in XAML: 9 | // 10 | // 11 | // Usage in code: 12 | // NavigationHelper.SetNavigateTo(navigationViewItem, typeof(MainViewModel).FullName); 13 | public class NavigationHelper 14 | { 15 | public static string GetNavigateTo(NavigationViewItem item) => (string)item.GetValue(NavigateToProperty); 16 | 17 | public static void SetNavigateTo(NavigationViewItem item, string value) => item.SetValue(NavigateToProperty, value); 18 | 19 | public static readonly DependencyProperty NavigateToProperty = 20 | DependencyProperty.RegisterAttached("NavigateTo", typeof(string), typeof(NavigationHelper), new PropertyMetadata(null)); 21 | } 22 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Helpers/ResourceExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Windows.ApplicationModel.Resources; 2 | 3 | namespace VDD_Panel.Helpers; 4 | 5 | public static class ResourceExtensions 6 | { 7 | private static readonly ResourceLoader _resourceLoader = new(); 8 | 9 | public static string GetLocalized(this string resourceKey) => _resourceLoader.GetString(resourceKey); 10 | } 11 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Helpers/RuntimeHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | using System.Text; 3 | 4 | namespace VDD_Panel.Helpers; 5 | 6 | public class RuntimeHelper 7 | { 8 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 9 | private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder? packageFullName); 10 | 11 | public static bool IsMSIX 12 | { 13 | get 14 | { 15 | var length = 0; 16 | 17 | return GetCurrentPackageFullName(ref length, null) != 15700L; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Helpers/SettingsStorageExtensions.cs: -------------------------------------------------------------------------------- 1 | using VDD_Panel.Core.Helpers; 2 | 3 | using Windows.Storage; 4 | using Windows.Storage.Streams; 5 | 6 | namespace VDD_Panel.Helpers; 7 | 8 | // Use these extension methods to store and retrieve local and roaming app data 9 | // More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/apps/design/app-settings/store-and-retrieve-app-data 10 | public static class SettingsStorageExtensions 11 | { 12 | private const string FileExtension = ".json"; 13 | 14 | public static bool IsRoamingStorageAvailable(this ApplicationData appData) 15 | { 16 | return appData.RoamingStorageQuota == 0; 17 | } 18 | 19 | public static async Task SaveAsync(this StorageFolder folder, string name, T content) 20 | { 21 | var file = await folder.CreateFileAsync(GetFileName(name), CreationCollisionOption.ReplaceExisting); 22 | var fileContent = await Json.StringifyAsync(content); 23 | 24 | await FileIO.WriteTextAsync(file, fileContent); 25 | } 26 | 27 | public static async Task ReadAsync(this StorageFolder folder, string name) 28 | { 29 | if (!File.Exists(Path.Combine(folder.Path, GetFileName(name)))) 30 | { 31 | return default; 32 | } 33 | 34 | var file = await folder.GetFileAsync($"{name}.json"); 35 | var fileContent = await FileIO.ReadTextAsync(file); 36 | 37 | return await Json.ToObjectAsync(fileContent); 38 | } 39 | 40 | public static async Task SaveAsync(this ApplicationDataContainer settings, string key, T value) 41 | { 42 | settings.SaveString(key, await Json.StringifyAsync(value)); 43 | } 44 | 45 | public static void SaveString(this ApplicationDataContainer settings, string key, string value) 46 | { 47 | settings.Values[key] = value; 48 | } 49 | 50 | public static async Task ReadAsync(this ApplicationDataContainer settings, string key) 51 | { 52 | object? obj; 53 | 54 | if (settings.Values.TryGetValue(key, out obj)) 55 | { 56 | return await Json.ToObjectAsync((string)obj); 57 | } 58 | 59 | return default; 60 | } 61 | 62 | public static async Task SaveFileAsync(this StorageFolder folder, byte[] content, string fileName, CreationCollisionOption options = CreationCollisionOption.ReplaceExisting) 63 | { 64 | if (content == null) 65 | { 66 | throw new ArgumentNullException(nameof(content)); 67 | } 68 | 69 | if (string.IsNullOrEmpty(fileName)) 70 | { 71 | throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName)); 72 | } 73 | 74 | var storageFile = await folder.CreateFileAsync(fileName, options); 75 | await FileIO.WriteBytesAsync(storageFile, content); 76 | return storageFile; 77 | } 78 | 79 | public static async Task ReadFileAsync(this StorageFolder folder, string fileName) 80 | { 81 | var item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false); 82 | 83 | if ((item != null) && item.IsOfType(StorageItemTypes.File)) 84 | { 85 | var storageFile = await folder.GetFileAsync(fileName); 86 | var content = await storageFile.ReadBytesAsync(); 87 | return content; 88 | } 89 | 90 | return null; 91 | } 92 | 93 | public static async Task ReadBytesAsync(this StorageFile file) 94 | { 95 | if (file != null) 96 | { 97 | using IRandomAccessStream stream = await file.OpenReadAsync(); 98 | using var reader = new DataReader(stream.GetInputStreamAt(0)); 99 | await reader.LoadAsync((uint)stream.Size); 100 | var bytes = new byte[stream.Size]; 101 | reader.ReadBytes(bytes); 102 | return bytes; 103 | } 104 | 105 | return null; 106 | } 107 | 108 | private static string GetFileName(string name) 109 | { 110 | return string.Concat(name, FileExtension); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Helpers/TitleBarHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | using Microsoft.UI; 4 | using Microsoft.UI.Xaml; 5 | using Microsoft.UI.Xaml.Media; 6 | 7 | using Windows.UI; 8 | using Windows.UI.ViewManagement; 9 | 10 | namespace VDD_Panel.Helpers; 11 | 12 | // Helper class to workaround custom title bar bugs. 13 | // DISCLAIMER: The resource key names and color values used below are subject to change. Do not depend on them. 14 | // https://github.com/microsoft/TemplateStudio/issues/4516 15 | internal class TitleBarHelper 16 | { 17 | private const int WAINACTIVE = 0x00; 18 | private const int WAACTIVE = 0x01; 19 | private const int WMACTIVATE = 0x0006; 20 | 21 | [DllImport("user32.dll")] 22 | private static extern IntPtr GetActiveWindow(); 23 | 24 | [DllImport("user32.dll", CharSet = CharSet.Auto)] 25 | private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam); 26 | 27 | public static void UpdateTitleBar(ElementTheme theme) 28 | { 29 | if (App.MainWindow.ExtendsContentIntoTitleBar) 30 | { 31 | if (theme == ElementTheme.Default) 32 | { 33 | var uiSettings = new UISettings(); 34 | var background = uiSettings.GetColorValue(UIColorType.Background); 35 | 36 | theme = background == Colors.White ? ElementTheme.Light : ElementTheme.Dark; 37 | } 38 | 39 | if (theme == ElementTheme.Default) 40 | { 41 | theme = Application.Current.RequestedTheme == ApplicationTheme.Light ? ElementTheme.Light : ElementTheme.Dark; 42 | } 43 | 44 | App.MainWindow.AppWindow.TitleBar.ButtonForegroundColor = theme switch 45 | { 46 | ElementTheme.Dark => Colors.White, 47 | ElementTheme.Light => Colors.Black, 48 | _ => Colors.Transparent 49 | }; 50 | 51 | App.MainWindow.AppWindow.TitleBar.ButtonHoverForegroundColor = theme switch 52 | { 53 | ElementTheme.Dark => Colors.White, 54 | ElementTheme.Light => Colors.Black, 55 | _ => Colors.Transparent 56 | }; 57 | 58 | App.MainWindow.AppWindow.TitleBar.ButtonHoverBackgroundColor = theme switch 59 | { 60 | ElementTheme.Dark => Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF), 61 | ElementTheme.Light => Color.FromArgb(0x33, 0x00, 0x00, 0x00), 62 | _ => Colors.Transparent 63 | }; 64 | 65 | App.MainWindow.AppWindow.TitleBar.ButtonPressedBackgroundColor = theme switch 66 | { 67 | ElementTheme.Dark => Color.FromArgb(0x66, 0xFF, 0xFF, 0xFF), 68 | ElementTheme.Light => Color.FromArgb(0x66, 0x00, 0x00, 0x00), 69 | _ => Colors.Transparent 70 | }; 71 | 72 | App.MainWindow.AppWindow.TitleBar.BackgroundColor = Colors.Transparent; 73 | 74 | var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow); 75 | if (hwnd == GetActiveWindow()) 76 | { 77 | SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero); 78 | SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero); 79 | } 80 | else 81 | { 82 | SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero); 83 | SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero); 84 | } 85 | } 86 | } 87 | 88 | public static void ApplySystemThemeToCaptionButtons() 89 | { 90 | var frame = App.AppTitlebar as FrameworkElement; 91 | if (frame != null) 92 | { 93 | UpdateTitleBar(frame.ActualTheme); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using VDD_Panel.Helpers; 2 | 3 | using Windows.UI.ViewManagement; 4 | 5 | namespace VDD_Panel; 6 | 7 | public sealed partial class MainWindow : WindowEx 8 | { 9 | private Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue; 10 | 11 | private UISettings settings; 12 | 13 | public MainWindow() 14 | { 15 | InitializeComponent(); 16 | 17 | AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/WindowIcon.ico")); 18 | Content = null; 19 | Title = "AppDisplayName".GetLocalized(); 20 | 21 | // Theme change code picked from https://github.com/microsoft/WinUI-Gallery/pull/1239 22 | dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); 23 | settings = new UISettings(); 24 | settings.ColorValuesChanged += Settings_ColorValuesChanged; // cannot use FrameworkElement.ActualThemeChanged event 25 | } 26 | 27 | // this handles updating the caption button colors correctly when indows system theme is changed 28 | // while the app is open 29 | private void Settings_ColorValuesChanged(UISettings sender, object args) 30 | { 31 | // This calls comes off-thread, hence we will need to dispatch it to current app's thread 32 | dispatcherQueue.TryEnqueue(() => 33 | { 34 | TitleBarHelper.ApplySystemThemeToCaptionButtons(); 35 | }); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Models/LocalSettingsOptions.cs: -------------------------------------------------------------------------------- 1 | namespace VDD_Panel.Models; 2 | 3 | public class LocalSettingsOptions 4 | { 5 | public string? ApplicationDataFolder 6 | { 7 | get; set; 8 | } 9 | 10 | public string? LocalSettingsFile 11 | { 12 | get; set; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Package.appinstaller: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 12 | 13 | 17 | 18 | 19 | 20 | 21 | VDD Panel 22 | alisa 23 | Assets\StoreLogo.png 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Properties/PublishProfiles/win10-arm64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | arm64 6 | win10-arm64 7 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ 8 | True 9 | False 10 | False 11 | True 12 | 13 | 14 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Properties/PublishProfiles/win10-x64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | x64 6 | win10-x64 7 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ 8 | True 9 | False 10 | False 11 | True 12 | 13 | 14 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Properties/PublishProfiles/win10-x86.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | FileSystem 5 | x86 6 | win10-x86 7 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ 8 | True 9 | False 10 | False 11 | True 12 | 13 | 14 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Properties/launchsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "VDD Panel (Package)": { 4 | "commandName": "MsixPackage" 5 | }, 6 | "VDD Panel (Unpackaged)": { 7 | "commandName": "Project" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/README.md: -------------------------------------------------------------------------------- 1 | *Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)* 2 | 3 | ## Getting Started 4 | 5 | Browse and address `TODO:` comments in `View -> Task List` to learn the codebase and understand next steps for turning the generated code into production code. 6 | 7 | Explore the [WinUI Gallery](https://www.microsoft.com/store/productId/9P3JFPWWDZRC) to learn about available controls and design patterns. 8 | 9 | Relaunch Template Studio to modify the project by right-clicking on the project in `View -> Solution Explorer` then selecting `Add -> New Item (Template Studio)`. 10 | 11 | ## Publishing 12 | 13 | For projects with MSIX packaging, right-click on the application project and select `Package and Publish -> Create App Packages...` to create an MSIX package. 14 | 15 | For projects without MSIX packaging, follow the [deployment guide](https://docs.microsoft.com/windows/apps/windows-app-sdk/deploy-unpackaged-apps) or add the `Self-Contained` Feature to enable xcopy deployment. 16 | 17 | ## CI Pipelines 18 | 19 | See [README.md](https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/pipelines/README.md) for guidance on building and testing projects in CI pipelines. 20 | 21 | ## Changelog 22 | 23 | See [releases](https://github.com/microsoft/TemplateStudio/releases) and [milestones](https://github.com/microsoft/TemplateStudio/milestones). 24 | 25 | ## Feedback 26 | 27 | Bugs and feature requests should be filed at https://aka.ms/templatestudio. 28 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/ActivationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | using Microsoft.UI.Xaml.Controls; 3 | 4 | using VDD_Panel.Activation; 5 | using VDD_Panel.Contracts.Services; 6 | using VDD_Panel.Views; 7 | 8 | namespace VDD_Panel.Services; 9 | 10 | public class ActivationService : IActivationService 11 | { 12 | private readonly ActivationHandler _defaultHandler; 13 | private readonly IEnumerable _activationHandlers; 14 | private readonly IThemeSelectorService _themeSelectorService; 15 | private UIElement? _shell = null; 16 | 17 | public ActivationService(ActivationHandler defaultHandler, IEnumerable activationHandlers, IThemeSelectorService themeSelectorService) 18 | { 19 | _defaultHandler = defaultHandler; 20 | _activationHandlers = activationHandlers; 21 | _themeSelectorService = themeSelectorService; 22 | } 23 | 24 | public async Task ActivateAsync(object activationArgs) 25 | { 26 | // Execute tasks before activation. 27 | await InitializeAsync(); 28 | 29 | // Set the MainWindow Content. 30 | if (App.MainWindow.Content == null) 31 | { 32 | _shell = App.GetService(); 33 | App.MainWindow.Content = _shell ?? new Frame(); 34 | } 35 | 36 | // Handle activation via ActivationHandlers. 37 | await HandleActivationAsync(activationArgs); 38 | 39 | // Activate the MainWindow. 40 | App.MainWindow.Activate(); 41 | 42 | // Execute tasks after activation. 43 | await StartupAsync(); 44 | } 45 | 46 | private async Task HandleActivationAsync(object activationArgs) 47 | { 48 | var activationHandler = _activationHandlers.FirstOrDefault(h => h.CanHandle(activationArgs)); 49 | 50 | if (activationHandler != null) 51 | { 52 | await activationHandler.HandleAsync(activationArgs); 53 | } 54 | 55 | if (_defaultHandler.CanHandle(activationArgs)) 56 | { 57 | await _defaultHandler.HandleAsync(activationArgs); 58 | } 59 | } 60 | 61 | private async Task InitializeAsync() 62 | { 63 | await _themeSelectorService.InitializeAsync().ConfigureAwait(false); 64 | await Task.CompletedTask; 65 | } 66 | 67 | private async Task StartupAsync() 68 | { 69 | await _themeSelectorService.SetRequestedThemeAsync(); 70 | await Task.CompletedTask; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/AppNotificationService.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Specialized; 2 | using System.Web; 3 | 4 | using Microsoft.Windows.AppNotifications; 5 | 6 | using VDD_Panel.Contracts.Services; 7 | using VDD_Panel.ViewModels; 8 | 9 | namespace VDD_Panel.Notifications; 10 | 11 | public class AppNotificationService : IAppNotificationService 12 | { 13 | private readonly INavigationService _navigationService; 14 | 15 | public AppNotificationService(INavigationService navigationService) 16 | { 17 | _navigationService = navigationService; 18 | } 19 | 20 | ~AppNotificationService() 21 | { 22 | Unregister(); 23 | } 24 | 25 | public void Initialize() 26 | { 27 | AppNotificationManager.Default.NotificationInvoked += OnNotificationInvoked; 28 | 29 | AppNotificationManager.Default.Register(); 30 | } 31 | 32 | public void OnNotificationInvoked(AppNotificationManager sender, AppNotificationActivatedEventArgs args) 33 | { 34 | // TODO: Handle notification invocations when your app is already running. 35 | 36 | //// // Navigate to a specific page based on the notification arguments. 37 | //// if (ParseArguments(args.Argument)["action"] == "Settings") 38 | //// { 39 | //// App.MainWindow.DispatcherQueue.TryEnqueue(() => 40 | //// { 41 | //// _navigationService.NavigateTo(typeof(SettingsViewModel).FullName!); 42 | //// }); 43 | //// } 44 | 45 | App.MainWindow.DispatcherQueue.TryEnqueue(() => 46 | { 47 | App.MainWindow.ShowMessageDialogAsync("TODO: Handle notification invocations when your app is already running.", "Notification Invoked"); 48 | 49 | App.MainWindow.BringToFront(); 50 | }); 51 | } 52 | 53 | public bool Show(string payload) 54 | { 55 | var appNotification = new AppNotification(payload); 56 | 57 | AppNotificationManager.Default.Show(appNotification); 58 | 59 | return appNotification.Id != 0; 60 | } 61 | 62 | public NameValueCollection ParseArguments(string arguments) 63 | { 64 | return HttpUtility.ParseQueryString(arguments); 65 | } 66 | 67 | public void Unregister() 68 | { 69 | AppNotificationManager.Default.Unregister(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/LocalSettingsService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | 3 | using VDD_Panel.Contracts.Services; 4 | using VDD_Panel.Core.Contracts.Services; 5 | using VDD_Panel.Core.Helpers; 6 | using VDD_Panel.Helpers; 7 | using VDD_Panel.Models; 8 | 9 | using Windows.ApplicationModel; 10 | using Windows.Storage; 11 | 12 | namespace VDD_Panel.Services; 13 | 14 | public class LocalSettingsService : ILocalSettingsService 15 | { 16 | private const string _defaultApplicationDataFolder = "VDD Panel/ApplicationData"; 17 | private const string _defaultLocalSettingsFile = "LocalSettings.json"; 18 | 19 | private readonly IFileService _fileService; 20 | private readonly LocalSettingsOptions _options; 21 | 22 | private readonly string _localApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); 23 | private readonly string _applicationDataFolder; 24 | private readonly string _localsettingsFile; 25 | 26 | private IDictionary _settings; 27 | 28 | private bool _isInitialized; 29 | 30 | public LocalSettingsService(IFileService fileService, IOptions options) 31 | { 32 | _fileService = fileService; 33 | _options = options.Value; 34 | 35 | _applicationDataFolder = Path.Combine(_localApplicationData, _options.ApplicationDataFolder ?? _defaultApplicationDataFolder); 36 | _localsettingsFile = _options.LocalSettingsFile ?? _defaultLocalSettingsFile; 37 | 38 | _settings = new Dictionary(); 39 | } 40 | 41 | private async Task InitializeAsync() 42 | { 43 | if (!_isInitialized) 44 | { 45 | _settings = await Task.Run(() => _fileService.Read>(_applicationDataFolder, _localsettingsFile)) ?? new Dictionary(); 46 | 47 | _isInitialized = true; 48 | } 49 | } 50 | 51 | public async Task ReadSettingAsync(string key) 52 | { 53 | if (RuntimeHelper.IsMSIX) 54 | { 55 | if (ApplicationData.Current.LocalSettings.Values.TryGetValue(key, out var obj)) 56 | { 57 | return await Json.ToObjectAsync((string)obj); 58 | } 59 | } 60 | else 61 | { 62 | await InitializeAsync(); 63 | 64 | if (_settings != null && _settings.TryGetValue(key, out var obj)) 65 | { 66 | return await Json.ToObjectAsync((string)obj); 67 | } 68 | } 69 | 70 | return default; 71 | } 72 | 73 | public async Task SaveSettingAsync(string key, T value) 74 | { 75 | if (RuntimeHelper.IsMSIX) 76 | { 77 | ApplicationData.Current.LocalSettings.Values[key] = await Json.StringifyAsync(value); 78 | } 79 | else 80 | { 81 | await InitializeAsync(); 82 | 83 | _settings[key] = await Json.StringifyAsync(value); 84 | 85 | await Task.Run(() => _fileService.Save(_applicationDataFolder, _localsettingsFile, _settings)); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/NavigationService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | using Microsoft.UI.Xaml.Navigation; 5 | 6 | using VDD_Panel.Contracts.Services; 7 | using VDD_Panel.Contracts.ViewModels; 8 | using VDD_Panel.Helpers; 9 | 10 | namespace VDD_Panel.Services; 11 | 12 | // For more information on navigation between pages see 13 | // https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/navigation.md 14 | public class NavigationService : INavigationService 15 | { 16 | private readonly IPageService _pageService; 17 | private object? _lastParameterUsed; 18 | private Frame? _frame; 19 | 20 | public event NavigatedEventHandler? Navigated; 21 | 22 | public Frame? Frame 23 | { 24 | get 25 | { 26 | if (_frame == null) 27 | { 28 | _frame = App.MainWindow.Content as Frame; 29 | RegisterFrameEvents(); 30 | } 31 | 32 | return _frame; 33 | } 34 | 35 | set 36 | { 37 | UnregisterFrameEvents(); 38 | _frame = value; 39 | RegisterFrameEvents(); 40 | } 41 | } 42 | 43 | [MemberNotNullWhen(true, nameof(Frame), nameof(_frame))] 44 | public bool CanGoBack => Frame != null && Frame.CanGoBack; 45 | 46 | public NavigationService(IPageService pageService) 47 | { 48 | _pageService = pageService; 49 | } 50 | 51 | private void RegisterFrameEvents() 52 | { 53 | if (_frame != null) 54 | { 55 | _frame.Navigated += OnNavigated; 56 | } 57 | } 58 | 59 | private void UnregisterFrameEvents() 60 | { 61 | if (_frame != null) 62 | { 63 | _frame.Navigated -= OnNavigated; 64 | } 65 | } 66 | 67 | public bool GoBack() 68 | { 69 | if (CanGoBack) 70 | { 71 | var vmBeforeNavigation = _frame.GetPageViewModel(); 72 | _frame.GoBack(); 73 | if (vmBeforeNavigation is INavigationAware navigationAware) 74 | { 75 | navigationAware.OnNavigatedFrom(); 76 | } 77 | 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | public bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false) 85 | { 86 | var pageType = _pageService.GetPageType(pageKey); 87 | 88 | if (_frame != null && (_frame.Content?.GetType() != pageType || (parameter != null && !parameter.Equals(_lastParameterUsed)))) 89 | { 90 | _frame.Tag = clearNavigation; 91 | var vmBeforeNavigation = _frame.GetPageViewModel(); 92 | var navigated = _frame.Navigate(pageType, parameter); 93 | if (navigated) 94 | { 95 | _lastParameterUsed = parameter; 96 | if (vmBeforeNavigation is INavigationAware navigationAware) 97 | { 98 | navigationAware.OnNavigatedFrom(); 99 | } 100 | } 101 | 102 | return navigated; 103 | } 104 | 105 | return false; 106 | } 107 | 108 | private void OnNavigated(object sender, NavigationEventArgs e) 109 | { 110 | if (sender is Frame frame) 111 | { 112 | var clearNavigation = (bool)frame.Tag; 113 | if (clearNavigation) 114 | { 115 | frame.BackStack.Clear(); 116 | } 117 | 118 | if (frame.GetPageViewModel() is INavigationAware navigationAware) 119 | { 120 | navigationAware.OnNavigatedTo(e.Parameter); 121 | } 122 | 123 | Navigated?.Invoke(sender, e); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/NavigationViewService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | 5 | using VDD_Panel.Contracts.Services; 6 | using VDD_Panel.Helpers; 7 | using VDD_Panel.ViewModels; 8 | 9 | namespace VDD_Panel.Services; 10 | 11 | public class NavigationViewService : INavigationViewService 12 | { 13 | private readonly INavigationService _navigationService; 14 | 15 | private readonly IPageService _pageService; 16 | 17 | private NavigationView? _navigationView; 18 | 19 | public IList? MenuItems => _navigationView?.MenuItems; 20 | 21 | public object? SettingsItem => _navigationView?.SettingsItem; 22 | 23 | public NavigationViewService(INavigationService navigationService, IPageService pageService) 24 | { 25 | _navigationService = navigationService; 26 | _pageService = pageService; 27 | } 28 | 29 | [MemberNotNull(nameof(_navigationView))] 30 | public void Initialize(NavigationView navigationView) 31 | { 32 | _navigationView = navigationView; 33 | _navigationView.BackRequested += OnBackRequested; 34 | _navigationView.ItemInvoked += OnItemInvoked; 35 | } 36 | 37 | public void UnregisterEvents() 38 | { 39 | if (_navigationView != null) 40 | { 41 | _navigationView.BackRequested -= OnBackRequested; 42 | _navigationView.ItemInvoked -= OnItemInvoked; 43 | } 44 | } 45 | 46 | public NavigationViewItem? GetSelectedItem(Type pageType) 47 | { 48 | if (_navigationView != null) 49 | { 50 | return GetSelectedItem(_navigationView.MenuItems, pageType) ?? GetSelectedItem(_navigationView.FooterMenuItems, pageType); 51 | } 52 | 53 | return null; 54 | } 55 | 56 | private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) => _navigationService.GoBack(); 57 | 58 | private void OnItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args) 59 | { 60 | if (args.IsSettingsInvoked) 61 | { 62 | _navigationService.NavigateTo(typeof(SettingsViewModel).FullName!); 63 | } 64 | else 65 | { 66 | var selectedItem = args.InvokedItemContainer as NavigationViewItem; 67 | 68 | if (selectedItem?.GetValue(NavigationHelper.NavigateToProperty) is string pageKey) 69 | { 70 | _navigationService.NavigateTo(pageKey); 71 | } 72 | } 73 | } 74 | 75 | private NavigationViewItem? GetSelectedItem(IEnumerable menuItems, Type pageType) 76 | { 77 | foreach (var item in menuItems.OfType()) 78 | { 79 | if (IsMenuItemForPageType(item, pageType)) 80 | { 81 | return item; 82 | } 83 | 84 | var selectedChild = GetSelectedItem(item.MenuItems, pageType); 85 | if (selectedChild != null) 86 | { 87 | return selectedChild; 88 | } 89 | } 90 | 91 | return null; 92 | } 93 | 94 | private bool IsMenuItemForPageType(NavigationViewItem menuItem, Type sourcePageType) 95 | { 96 | if (menuItem.GetValue(NavigationHelper.NavigateToProperty) is string pageKey) 97 | { 98 | return _pageService.GetPageType(pageKey) == sourcePageType; 99 | } 100 | 101 | return false; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/PageService.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | 5 | using VDD_Panel.Contracts.Services; 6 | using VDD_Panel.ViewModels; 7 | using VDD_Panel.Views; 8 | 9 | namespace VDD_Panel.Services; 10 | 11 | public class PageService : IPageService 12 | { 13 | private readonly Dictionary _pages = new(); 14 | 15 | public PageService() 16 | { 17 | Configure(); 18 | Configure(); 19 | Configure(); 20 | Configure(); 21 | } 22 | 23 | public Type GetPageType(string key) 24 | { 25 | Type? pageType; 26 | lock (_pages) 27 | { 28 | if (!_pages.TryGetValue(key, out pageType)) 29 | { 30 | throw new ArgumentException($"Page not found: {key}. Did you forget to call PageService.Configure?"); 31 | } 32 | } 33 | 34 | return pageType; 35 | } 36 | 37 | private void Configure() 38 | where VM : ObservableObject 39 | where V : Page 40 | { 41 | lock (_pages) 42 | { 43 | var key = typeof(VM).FullName!; 44 | if (_pages.ContainsKey(key)) 45 | { 46 | throw new ArgumentException($"The key {key} is already configured in PageService"); 47 | } 48 | 49 | var type = typeof(V); 50 | if (_pages.ContainsValue(type)) 51 | { 52 | throw new ArgumentException($"This type is already configured with key {_pages.First(p => p.Value == type).Key}"); 53 | } 54 | 55 | _pages.Add(key, type); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/ThemeSelectorService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | 3 | using VDD_Panel.Contracts.Services; 4 | using VDD_Panel.Helpers; 5 | 6 | namespace VDD_Panel.Services; 7 | 8 | public class ThemeSelectorService : IThemeSelectorService 9 | { 10 | private const string SettingsKey = "AppBackgroundRequestedTheme"; 11 | 12 | public ElementTheme Theme { get; set; } = ElementTheme.Default; 13 | 14 | private readonly ILocalSettingsService _localSettingsService; 15 | 16 | public ThemeSelectorService(ILocalSettingsService localSettingsService) 17 | { 18 | _localSettingsService = localSettingsService; 19 | } 20 | 21 | public async Task InitializeAsync() 22 | { 23 | Theme = await LoadThemeFromSettingsAsync(); 24 | await Task.CompletedTask; 25 | } 26 | 27 | public async Task SetThemeAsync(ElementTheme theme) 28 | { 29 | Theme = theme; 30 | 31 | await SetRequestedThemeAsync(); 32 | await SaveThemeInSettingsAsync(Theme); 33 | } 34 | 35 | public async Task SetRequestedThemeAsync() 36 | { 37 | if (App.MainWindow.Content is FrameworkElement rootElement) 38 | { 39 | rootElement.RequestedTheme = Theme; 40 | 41 | TitleBarHelper.UpdateTitleBar(Theme); 42 | } 43 | 44 | await Task.CompletedTask; 45 | } 46 | 47 | private async Task LoadThemeFromSettingsAsync() 48 | { 49 | var themeName = await _localSettingsService.ReadSettingAsync(SettingsKey); 50 | 51 | if (Enum.TryParse(themeName, out ElementTheme cacheTheme)) 52 | { 53 | return cacheTheme; 54 | } 55 | 56 | return ElementTheme.Default; 57 | } 58 | 59 | private async Task SaveThemeInSettingsAsync(ElementTheme theme) 60 | { 61 | await _localSettingsService.SaveSettingAsync(SettingsKey, theme.ToString()); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Services/WebViewService.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | using Microsoft.UI.Xaml.Controls; 4 | using Microsoft.Web.WebView2.Core; 5 | 6 | using VDD_Panel.Contracts.Services; 7 | 8 | namespace VDD_Panel.Services; 9 | 10 | public class WebViewService : IWebViewService 11 | { 12 | private WebView2? _webView; 13 | 14 | public Uri? Source => _webView?.Source; 15 | 16 | [MemberNotNullWhen(true, nameof(_webView))] 17 | public bool CanGoBack => _webView != null && _webView.CanGoBack; 18 | 19 | [MemberNotNullWhen(true, nameof(_webView))] 20 | public bool CanGoForward => _webView != null && _webView.CanGoForward; 21 | 22 | public event EventHandler? NavigationCompleted; 23 | 24 | public WebViewService() 25 | { 26 | } 27 | 28 | [MemberNotNull(nameof(_webView))] 29 | public void Initialize(WebView2 webView) 30 | { 31 | _webView = webView; 32 | _webView.NavigationCompleted += OnWebViewNavigationCompleted; 33 | } 34 | 35 | public void GoBack() => _webView?.GoBack(); 36 | 37 | public void GoForward() => _webView?.GoForward(); 38 | 39 | public void Reload() => _webView?.Reload(); 40 | 41 | public void UnregisterEvents() 42 | { 43 | if (_webView != null) 44 | { 45 | _webView.NavigationCompleted -= OnWebViewNavigationCompleted; 46 | } 47 | } 48 | 49 | private void OnWebViewNavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args) => NavigationCompleted?.Invoke(this, args.WebErrorStatus); 50 | } 51 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Strings/en-us/Resources.resw: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | text/microsoft-resx 51 | 52 | 53 | 2.0 54 | 55 | 56 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 57 | 58 | 59 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 60 | 61 | 62 | VDD Panel 63 | 64 | 65 | VDD Panel 66 | 67 | 68 | Main 69 | 70 | 71 | Configure 72 | 73 | 74 | Loading... 75 | 76 | 77 | Page failed to load. Check connection and reload. 78 | 79 | 80 | Browser back 81 | 82 | 83 | Browser back 84 | 85 | 86 | Browser forward 87 | 88 | 89 | Browser forward 90 | 91 | 92 | Reload 93 | 94 | 95 | Reload 96 | 97 | 98 | Reload 99 | 100 | 101 | Open in browser 102 | 103 | 104 | Open in browser 105 | 106 | 107 | GitHub 108 | 109 | 110 | Personalization 111 | 112 | 113 | Theme 114 | 115 | 116 | Light 117 | 118 | 119 | Dark 120 | 121 | 122 | Default 123 | 124 | 125 | About this application 126 | 127 | 128 | TODO: Replace with your app description. 129 | 130 | 131 | Privacy Statement 132 | 133 | 134 | https://YourPrivacyUrlGoesHere/ 135 | 136 | 137 | <toast launch="action=ToastClick"> 138 | <visual> 139 | <binding template="ToastGeneric"> 140 | <text>App Notification</text> 141 | <text></text> 142 | <image placement="appLogoOverride" hint-crop="circle" src="{0}Assets/WindowIcon.ico"/> 143 | </binding> 144 | </visual> 145 | <actions> 146 | <action content="Settings" arguments="action=Settings"/> 147 | </actions> 148 | </toast> 149 | 150 | 151 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Styles/FontSizes.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 24 6 | 7 | 16 8 | 9 | 10 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Styles/TextBlock.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 12 | 13 | 19 | 20 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Styles/Thickness.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 0,36,0,0 6 | 0,36,0,36 7 | 8 | 0,24,0,0 9 | 0,24,0,24 10 | 24,0,24,0 11 | 0,0,0,24 12 | 13 | 12,0,0,0 14 | 12,0,12,0 15 | 0,12,0,0 16 | 0,0,12,0 17 | 0,12,0,12 18 | 19 | 8,0,0,0 20 | 0,8,0,0 21 | 8,8,8,8 22 | 23 | 0,4,0,0 24 | 4,4,4,4 25 | 26 | 1,1,0,0 27 | 8,0,0,0 28 | 0,48,0,0 29 | 56,34,0,0 30 | 56,24,56,0 31 | 32 | 36,24,36,0 33 | 34 | -12,4,0,0 35 | 36 | 37 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/TemplateStudio.xml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Usings.cs: -------------------------------------------------------------------------------- 1 | global using WinUIEx; 2 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/VDD Panel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net7.0-windows10.0.19041.0 5 | 10.0.17763.0 6 | VDD_Panel 7 | Assets/WindowIcon.ico 8 | app.manifest 9 | x86;x64;arm64 10 | win10-x86;win10-x64;win10-arm64 11 | Properties\PublishProfiles\win10-$(Platform).pubxml 12 | enable 13 | enable 14 | true 15 | true 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | Always 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | true 46 | 47 | 48 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/ViewModels/ConfigureViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace VDD_Panel.ViewModels; 4 | 5 | public partial class ConfigureViewModel : ObservableRecipient 6 | { 7 | public ConfigureViewModel() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/ViewModels/GitHubViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | using CommunityToolkit.Mvvm.Input; 3 | 4 | using Microsoft.Web.WebView2.Core; 5 | 6 | using VDD_Panel.Contracts.Services; 7 | using VDD_Panel.Contracts.ViewModels; 8 | 9 | namespace VDD_Panel.ViewModels; 10 | 11 | // TODO: Review best practices and distribution guidelines for WebView2. 12 | // https://docs.microsoft.com/microsoft-edge/webview2/get-started/winui 13 | // https://docs.microsoft.com/microsoft-edge/webview2/concepts/developer-guide 14 | // https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution 15 | public partial class GitHubViewModel : ObservableRecipient, INavigationAware 16 | { 17 | // TODO: Set the default URL to display. 18 | [ObservableProperty] 19 | private Uri source = new("https://github.com/itsmikethetech/Virtual-Display-Driver"); 20 | 21 | [ObservableProperty] 22 | private bool isLoading = true; 23 | 24 | [ObservableProperty] 25 | private bool hasFailures; 26 | 27 | public IWebViewService WebViewService 28 | { 29 | get; 30 | } 31 | 32 | public GitHubViewModel(IWebViewService webViewService) 33 | { 34 | WebViewService = webViewService; 35 | } 36 | 37 | [RelayCommand] 38 | private async Task OpenInBrowser() 39 | { 40 | if (WebViewService.Source != null) 41 | { 42 | await Windows.System.Launcher.LaunchUriAsync(WebViewService.Source); 43 | } 44 | } 45 | 46 | [RelayCommand] 47 | private void Reload() 48 | { 49 | WebViewService.Reload(); 50 | } 51 | 52 | [RelayCommand(CanExecute = nameof(BrowserCanGoForward))] 53 | private void BrowserForward() 54 | { 55 | if (WebViewService.CanGoForward) 56 | { 57 | WebViewService.GoForward(); 58 | } 59 | } 60 | 61 | private bool BrowserCanGoForward() 62 | { 63 | return WebViewService.CanGoForward; 64 | } 65 | 66 | [RelayCommand(CanExecute = nameof(BrowserCanGoBack))] 67 | private void BrowserBack() 68 | { 69 | if (WebViewService.CanGoBack) 70 | { 71 | WebViewService.GoBack(); 72 | } 73 | } 74 | 75 | private bool BrowserCanGoBack() 76 | { 77 | return WebViewService.CanGoBack; 78 | } 79 | 80 | public void OnNavigatedTo(object parameter) 81 | { 82 | WebViewService.NavigationCompleted += OnNavigationCompleted; 83 | } 84 | 85 | public void OnNavigatedFrom() 86 | { 87 | WebViewService.UnregisterEvents(); 88 | WebViewService.NavigationCompleted -= OnNavigationCompleted; 89 | } 90 | 91 | private void OnNavigationCompleted(object? sender, CoreWebView2WebErrorStatus webErrorStatus) 92 | { 93 | IsLoading = false; 94 | BrowserBackCommand.NotifyCanExecuteChanged(); 95 | BrowserForwardCommand.NotifyCanExecuteChanged(); 96 | 97 | if (webErrorStatus != default) 98 | { 99 | HasFailures = true; 100 | } 101 | } 102 | 103 | [RelayCommand] 104 | private void OnRetry() 105 | { 106 | HasFailures = false; 107 | IsLoading = true; 108 | WebViewService?.Reload(); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/ViewModels/MainViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | namespace VDD_Panel.ViewModels; 4 | 5 | public partial class MainViewModel : ObservableRecipient 6 | { 7 | public MainViewModel() 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/ViewModels/SettingsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Windows.Input; 3 | 4 | using CommunityToolkit.Mvvm.ComponentModel; 5 | using CommunityToolkit.Mvvm.Input; 6 | 7 | using Microsoft.UI.Xaml; 8 | 9 | using VDD_Panel.Contracts.Services; 10 | using VDD_Panel.Helpers; 11 | 12 | using Windows.ApplicationModel; 13 | 14 | namespace VDD_Panel.ViewModels; 15 | 16 | public partial class SettingsViewModel : ObservableRecipient 17 | { 18 | private readonly IThemeSelectorService _themeSelectorService; 19 | 20 | [ObservableProperty] 21 | private ElementTheme _elementTheme; 22 | 23 | [ObservableProperty] 24 | private string _versionDescription; 25 | 26 | public ICommand SwitchThemeCommand 27 | { 28 | get; 29 | } 30 | 31 | public SettingsViewModel(IThemeSelectorService themeSelectorService) 32 | { 33 | _themeSelectorService = themeSelectorService; 34 | _elementTheme = _themeSelectorService.Theme; 35 | _versionDescription = GetVersionDescription(); 36 | 37 | SwitchThemeCommand = new RelayCommand( 38 | async (param) => 39 | { 40 | if (ElementTheme != param) 41 | { 42 | ElementTheme = param; 43 | await _themeSelectorService.SetThemeAsync(param); 44 | } 45 | }); 46 | } 47 | 48 | private static string GetVersionDescription() 49 | { 50 | Version version; 51 | 52 | if (RuntimeHelper.IsMSIX) 53 | { 54 | var packageVersion = Package.Current.Id.Version; 55 | 56 | version = new(packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision); 57 | } 58 | else 59 | { 60 | version = Assembly.GetExecutingAssembly().GetName().Version!; 61 | } 62 | 63 | return $"{"AppDisplayName".GetLocalized()} - {version.Major}.{version.Minor}.{version.Build}.{version.Revision}"; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/ViewModels/ShellViewModel.cs: -------------------------------------------------------------------------------- 1 | using CommunityToolkit.Mvvm.ComponentModel; 2 | 3 | using Microsoft.UI.Xaml.Navigation; 4 | 5 | using VDD_Panel.Contracts.Services; 6 | using VDD_Panel.Views; 7 | 8 | namespace VDD_Panel.ViewModels; 9 | 10 | public partial class ShellViewModel : ObservableRecipient 11 | { 12 | [ObservableProperty] 13 | private bool isBackEnabled; 14 | 15 | [ObservableProperty] 16 | private object? selected; 17 | 18 | public INavigationService NavigationService 19 | { 20 | get; 21 | } 22 | 23 | public INavigationViewService NavigationViewService 24 | { 25 | get; 26 | } 27 | 28 | public ShellViewModel(INavigationService navigationService, INavigationViewService navigationViewService) 29 | { 30 | NavigationService = navigationService; 31 | NavigationService.Navigated += OnNavigated; 32 | NavigationViewService = navigationViewService; 33 | } 34 | 35 | private void OnNavigated(object sender, NavigationEventArgs e) 36 | { 37 | IsBackEnabled = NavigationService.CanGoBack; 38 | 39 | if (e.SourcePageType == typeof(SettingsPage)) 40 | { 41 | Selected = NavigationViewService.SettingsItem; 42 | return; 43 | } 44 | 45 | var selectedItem = NavigationViewService.GetSelectedItem(e.SourcePageType); 46 | if (selectedItem != null) 47 | { 48 | Selected = selectedItem; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/ConfigurePage.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/ConfigurePage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | 3 | using VDD_Panel.ViewModels; 4 | 5 | namespace VDD_Panel.Views; 6 | 7 | public sealed partial class ConfigurePage : Page 8 | { 9 | public ConfigureViewModel ViewModel 10 | { 11 | get; 12 | } 13 | 14 | public ConfigurePage() 15 | { 16 | ViewModel = App.GetService(); 17 | InitializeComponent(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/GitHubPage.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 42 | 45 | 46 | 47 | 50 | 53 | 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/GitHubPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | 3 | using VDD_Panel.ViewModels; 4 | 5 | namespace VDD_Panel.Views; 6 | 7 | // To learn more about WebView2, see https://docs.microsoft.com/microsoft-edge/webview2/. 8 | public sealed partial class GitHubPage : Page 9 | { 10 | public GitHubViewModel ViewModel 11 | { 12 | get; 13 | } 14 | 15 | public GitHubPage() 16 | { 17 | ViewModel = App.GetService(); 18 | InitializeComponent(); 19 | 20 | ViewModel.WebViewService.Initialize(WebView); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/MainPage.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/MainPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | 3 | using VDD_Panel.ViewModels; 4 | 5 | namespace VDD_Panel.Views; 6 | 7 | public sealed partial class MainPage : Page 8 | { 9 | public MainViewModel ViewModel 10 | { 11 | get; 12 | } 13 | 14 | public MainPage() 15 | { 16 | ViewModel = App.GetService(); 17 | InitializeComponent(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/SettingsPage.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | 19 | 20 | 21 | 27 | 28 | Light 29 | 30 | 31 | 37 | 38 | Dark 39 | 40 | 41 | 47 | 48 | Default 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/SettingsPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml.Controls; 2 | 3 | using VDD_Panel.ViewModels; 4 | 5 | namespace VDD_Panel.Views; 6 | 7 | // TODO: Set the URL for your privacy policy by updating SettingsPage_PrivacyTermsLink.NavigateUri in Resources.resw. 8 | public sealed partial class SettingsPage : Page 9 | { 10 | public SettingsViewModel ViewModel 11 | { 12 | get; 13 | } 14 | 15 | public SettingsPage() 16 | { 17 | ViewModel = App.GetService(); 18 | InitializeComponent(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/ShellPage.xaml: -------------------------------------------------------------------------------- 1 |  11 | 12 | 13 | 18 | 22 | 27 | 28 | 38 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 68 | 69 | 70 | 71 | 72 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/Views/ShellPage.xaml.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.UI.Xaml; 2 | using Microsoft.UI.Xaml.Controls; 3 | using Microsoft.UI.Xaml.Input; 4 | using Microsoft.UI.Xaml.Media; 5 | 6 | using VDD_Panel.Contracts.Services; 7 | using VDD_Panel.Helpers; 8 | using VDD_Panel.ViewModels; 9 | 10 | using Windows.System; 11 | 12 | namespace VDD_Panel.Views; 13 | 14 | // TODO: Update NavigationViewItem titles and icons in ShellPage.xaml. 15 | public sealed partial class ShellPage : Page 16 | { 17 | public ShellViewModel ViewModel 18 | { 19 | get; 20 | } 21 | 22 | public ShellPage(ShellViewModel viewModel) 23 | { 24 | ViewModel = viewModel; 25 | InitializeComponent(); 26 | 27 | ViewModel.NavigationService.Frame = NavigationFrame; 28 | ViewModel.NavigationViewService.Initialize(NavigationViewControl); 29 | 30 | // TODO: Set the title bar icon by updating /Assets/WindowIcon.ico. 31 | // A custom title bar is required for full window theme and Mica support. 32 | // https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization 33 | App.MainWindow.ExtendsContentIntoTitleBar = true; 34 | App.MainWindow.SetTitleBar(AppTitleBar); 35 | App.MainWindow.Activated += MainWindow_Activated; 36 | AppTitleBarText.Text = "AppDisplayName".GetLocalized(); 37 | } 38 | 39 | private void OnLoaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e) 40 | { 41 | TitleBarHelper.UpdateTitleBar(RequestedTheme); 42 | 43 | KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.Left, VirtualKeyModifiers.Menu)); 44 | KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.GoBack)); 45 | } 46 | 47 | private void MainWindow_Activated(object sender, WindowActivatedEventArgs args) 48 | { 49 | App.AppTitlebar = AppTitleBarText as UIElement; 50 | } 51 | 52 | private void NavigationViewControl_DisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args) 53 | { 54 | AppTitleBar.Margin = new Thickness() 55 | { 56 | Left = sender.CompactPaneLength * (sender.DisplayMode == NavigationViewDisplayMode.Minimal ? 2 : 1), 57 | Top = AppTitleBar.Margin.Top, 58 | Right = AppTitleBar.Margin.Right, 59 | Bottom = AppTitleBar.Margin.Bottom 60 | }; 61 | } 62 | 63 | private static KeyboardAccelerator BuildKeyboardAccelerator(VirtualKey key, VirtualKeyModifiers? modifiers = null) 64 | { 65 | var keyboardAccelerator = new KeyboardAccelerator() { Key = key }; 66 | 67 | if (modifiers.HasValue) 68 | { 69 | keyboardAccelerator.Modifiers = modifiers.Value; 70 | } 71 | 72 | keyboardAccelerator.Invoked += OnKeyboardAcceleratorInvoked; 73 | 74 | return keyboardAccelerator; 75 | } 76 | 77 | private static void OnKeyboardAcceleratorInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args) 78 | { 79 | var navigationService = App.GetService(); 80 | 81 | var result = navigationService.GoBack(); 82 | 83 | args.Handled = result; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | true/PM 12 | PerMonitorV2, PerMonitor 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Community Installers/VDD Panel/VDD Panel/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "LocalSettingsOptions": { 3 | "ApplicationDataFolder": "VDD_Panel/ApplicationData", 4 | "LocalSettingsFile": "LocalSettings.json" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Community Scripts/HDRswitch-VDD.ps1: -------------------------------------------------------------------------------- 1 | # Self-elevate the script if required 2 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 4 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 5 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 6 | Exit 7 | } 8 | } 9 | 10 | $repoName = "PSGallery" 11 | $moduleName1 = "DisplayConfig" 12 | $moduleName2 = "MonitorConfig" 13 | if (!(Get-PSRepository -Name $repoName) -OR !(Find-Module -Name $moduleName1 | Where-Object {$_.Name -eq $moduleName1}) -OR !(Find-Module -Name $moduleName2 | Where-Object {$_.Name -eq $moduleName2})) { 14 | & .\dep_fix.ps1 15 | } 16 | 17 | # Import the local module 18 | $dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path 19 | import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue 20 | 21 | # Import the other localmodule 22 | $mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path 23 | import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue 24 | 25 | $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber 26 | $bpcc = Get-DisplayColorInfo -DisplayId $disp | Select-Object BitsPerColorChannel | Select-Object -ExpandProperty BitsPerColorChannel 27 | 28 | if ( $bpcc -is [int] ) { 29 | if ( $bpcc -gt 8 ) { 30 | Disable-DisplayAdvancedColor -DisplayId $disp 31 | break 32 | } 33 | if ( $bpcc -lt 10 ) { 34 | Enable-DisplayAdvancedColor -DisplayId $disp 35 | break 36 | } 37 | } 38 | else { write-error "Something went wrong in identifying the Colormode of the display." ; break } -------------------------------------------------------------------------------- /Community Scripts/README.md: -------------------------------------------------------------------------------- 1 | #Scripts 2 | 3 | This is a collection of Powershell scripts, written during the whole driver development. There haven't been a focus on keeping the scripts "up to date" all the time. Which means changes that might have occurred in the modules that these scripts depend upon, haven't been corrected either. 4 | 5 | This is more ment as a framework for "tinkers" to make use of Powershell to change settings on the fly. 6 | 7 | To use these, you should be at least be comfortable with Powershell and understand Admin privilegiets, risk/reward. 8 | 9 | PR's are welcome for improvements or other/more functions. -------------------------------------------------------------------------------- /Community Scripts/changeres-VDD.ps1: -------------------------------------------------------------------------------- 1 | # Self-elevate the script if required 2 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 4 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 5 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 6 | Exit 7 | } 8 | } 9 | 10 | $repoName = "PSGallery" 11 | $moduleName1 = "DisplayConfig" 12 | $moduleName2 = "MonitorConfig" 13 | if (!(Get-PSRepository -Name $repoName) -OR !(Find-Module -Name $moduleName1 | Where-Object {$_.Name -eq $moduleName1}) -OR !(Find-Module -Name $moduleName2 | Where-Object {$_.Name -eq $moduleName2})) { 14 | & .\dep_fix.ps1 15 | } 16 | 17 | 18 | # Import the local module 19 | $dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path 20 | import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 21 | 22 | # Import the other localmodule 23 | $mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path 24 | import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 25 | 26 | # Check if there are enough arguments 27 | $numArgs = $args.Count 28 | switch ($numArgs) { 29 | 0 { Write-Error "This script requires at least 2 arguments Xres Yres."; break } 30 | 1 { Write-Error "This script requires at least 2 arguments Xres Yres."; break } 31 | 2 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber 32 | $vres = $args[0] 33 | $hres = $args[1] 34 | continue 35 | } 36 | default { Write-Error "Invalid number of arguments: $numArgs"; break } 37 | } 38 | # Setting the resolution on the correct display. 39 | Get-DisplayConfig | Set-DisplayResolution -DisplayId $disp -Width $vres -Height $hres | Use-DisplayConfig -------------------------------------------------------------------------------- /Community Scripts/dep_fix.ps1: -------------------------------------------------------------------------------- 1 | # Define the repository name and URL 2 | $repoName = "PSGallery" 3 | $repoUrl = "https://www.powershellgallery.com/api/v2" 4 | 5 | # Check if the repository is registered 6 | if (-not (Get-PSRepository -Name $repoName)) { 7 | # Register the repository 8 | Register-PSRepository -Name $repoName -SourceLocation $repoUrl -Confirm:$false -InformationAction:Ignore -WarningAction:SilentlyContinue 9 | } 10 | #Trust the repo, either its allready installed or newly added 11 | Set-PSRepository -Name $repoName -InstallationPolicy Trusted -InformationAction:Ignore -WarningAction:SilentlyContinue 12 | 13 | # Define the module name and version 14 | $moduleName1 = "DisplayConfig" 15 | $version1 = "1.1.1" 16 | 17 | # Define the module name and version 18 | $moduleName2 = "MonitorConfig" 19 | $version2 = "1.0.3" 20 | 21 | # Check if the module1 is installed 22 | if (-not (Get-InstalledModule -Name $moduleName1 -MinimumVersion $version1)) { 23 | # Save the module 24 | Save-Module -Name $moduleName1 -Repository $repoName -RequiredVersion $version1 -Confirm:$false -InformationAction:Ignore -WarningAction:SilentlyContinue 25 | } 26 | 27 | # Check if the module2 is installed 28 | if (-not (Get-InstalledModule -Name $moduleName2 -MinimumVersion $version2)) { 29 | # Save the module 30 | Save-Module -Name $moduleName2 -Repository $repoName -RequiredVersion $version2 -Confirm:$false -InformationAction:Ignore -WarningAction:SilentlyContinue 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Community Scripts/primary-VDD.ps1: -------------------------------------------------------------------------------- 1 | # Self-elevate the script if required 2 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 4 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 5 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 6 | Exit 7 | } 8 | } 9 | 10 | $repoName = "PSGallery" 11 | $moduleName1 = "DisplayConfig" 12 | $moduleName2 = "MonitorConfig" 13 | if (!(Get-PSRepository -Name $repoName) -OR !(Find-Module -Name $moduleName1 | Where-Object {$_.Name -eq $moduleName1}) -OR !(Find-Module -Name $moduleName2 | Where-Object {$_.Name -eq $moduleName2})) { 14 | & .\dep_fix.ps1 15 | } 16 | 17 | 18 | # Import the local module 19 | $dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path; import-module -name $dpth 20 | 21 | # Import the other localmodule 22 | $mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path; import-module -name $mpth 23 | 24 | 25 | $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber 26 | Set-DisplayPrimary -DisplayId $disp -------------------------------------------------------------------------------- /Community Scripts/refreshrate-VDD.ps1: -------------------------------------------------------------------------------- 1 | # Self-elevate the script if required 2 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 4 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 5 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 6 | Exit 7 | } 8 | } 9 | 10 | $repoName = "PSGallery" 11 | $moduleName1 = "DisplayConfig" 12 | $moduleName2 = "MonitorConfig" 13 | if (!(Get-PSRepository -Name $repoName) -OR !(Find-Module -Name $moduleName1 | Where-Object {$_.Name -eq $moduleName1}) -OR !(Find-Module -Name $moduleName2 | Where-Object {$_.Name -eq $moduleName2})) { 14 | & .\dep_fix.ps1 15 | } 16 | 17 | 18 | # Import the local module 19 | $dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path 20 | import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 21 | 22 | # Import the other localmodule 23 | $mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path 24 | import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 25 | 26 | 27 | # Use the module's functions and cmdlets in your script 28 | # Check if there are enough arguments 29 | $numArgs = $args.Count 30 | switch ($numArgs) { 31 | 0 { Write-Error "This script requires a refreshrate above 59 or reset"; break } 32 | 1 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber 33 | $rate = $args[0] 34 | continue 35 | } 36 | default { Write-Error "Invalid number of arguments: $numArgs"; break } 37 | } 38 | # Setting the resolution on the correct display. 39 | Get-DisplayConfig | Set-DisplayRefreshRate -DisplayId $disp -RefreshRate $rate | Use-DisplayConfig -------------------------------------------------------------------------------- /Community Scripts/rotate-VDD.ps1: -------------------------------------------------------------------------------- 1 | # Self-elevate the script if required 2 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 4 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 5 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 6 | Exit 7 | } 8 | } 9 | 10 | $repoName = "PSGallery" 11 | $moduleName1 = "DisplayConfig" 12 | $moduleName2 = "MonitorConfig" 13 | if (!(Get-PSRepository -Name $repoName) -OR !(Find-Module -Name $moduleName1 | Where-Object {$_.Name -eq $moduleName1}) -OR !(Find-Module -Name $moduleName2 | Where-Object {$_.Name -eq $moduleName2})) { 14 | & .\dep_fix.ps1 15 | } 16 | 17 | 18 | # Import the local module 19 | $dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path 20 | import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 21 | 22 | # Import the other localmodule 23 | $mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path 24 | import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 25 | 26 | # Check if there are enough arguments 27 | $numArgs = $args.Count 28 | switch ($numArgs) { 29 | 0 { Write-Error "This script requires at least 1, rotation in degrees ex. 90/180/270."; break } 30 | 1 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber 31 | switch ($args[0]) { 32 | 90 { $degree = "Rotate90" 33 | continue 34 | } 35 | 180 { $degree = "Rotate180" 36 | continue 37 | } 38 | 270 { $degree = "Rotate270" 39 | continue 40 | } 41 | default { Write-Error "Invalid rotation angle(valid 90,180,270)."; break } 42 | } 43 | default { Write-Error "Invalid number of arguments: $numArgs"; break } 44 | } 45 | # Setting the resolution on the correct display. 46 | Get-DisplayConfig | Set-DisplayRotation -DisplayId $disp -Rotation $degree | Use-DisplayConfig -------------------------------------------------------------------------------- /Community Scripts/scale-VDD.ps1: -------------------------------------------------------------------------------- 1 | # Self-elevate the script if required 2 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 4 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 5 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 6 | Exit 7 | } 8 | } 9 | 10 | $repoName = "PSGallery" 11 | $moduleName1 = "DisplayConfig" 12 | $moduleName2 = "MonitorConfig" 13 | if (!(Get-PSRepository -Name $repoName) -OR !(Find-Module -Name $moduleName1 | Where-Object {$_.Name -eq $moduleName1}) -OR !(Find-Module -Name $moduleName2 | Where-Object {$_.Name -eq $moduleName2})) { 14 | & .\dep_fix.ps1 15 | } 16 | 17 | 18 | # Import the local module 19 | $dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path 20 | import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 21 | 22 | # Import the other localmodule 23 | $mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path 24 | import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 25 | 26 | # Check if there are enough arguments 27 | $numArgs = $args.Count 28 | switch ($numArgs) { 29 | 0 { Write-Error "This script requires a scale 'reset' or an accepted percfentage value (100, 125, 150, 175, 200, 225, 250, 300, 350, 400, 450, 500) limited by the device max scale."; break } 30 | 1 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber 31 | $maxscale = Get-DisplayScale -DisplayId $disp | Select-Object -ExpandProperty MaxScale 32 | if ( $args[0] -is [int] ) { 33 | if ( $args[0] -le $maxscale -And $args[0] -ge 100 ) { 34 | Set-DisplayScale -DisplayId $disp -Scale $args[0] 35 | break 36 | } 37 | else { 38 | Write-Error "Invalid scale percentage." 39 | break 40 | } 41 | } 42 | else { 43 | if ( $args[0] -eq "reset" ) { 44 | Set-DisplayScale -DisplayId $disp -Recommended 45 | break 46 | } 47 | else { 48 | Write-Error "Invalid arguments: 'reset' or a valid percentage value like 150 is acceptable." 49 | break 50 | } 51 | } 52 | } 53 | default { Write-Error "Invalid number of arguments: $numArgs"; break } 54 | } 55 | -------------------------------------------------------------------------------- /Community Scripts/toggle-VDD.ps1: -------------------------------------------------------------------------------- 1 | # submitted by zjoasan 2 | # Self-elevate the script if required 3 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 4 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 5 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 6 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 7 | Exit 8 | } 9 | } 10 | 11 | $device = get-pnpdevice -class Display -FriendlyName 'IddSampleDriver Device HDR' -ErrorAction SilentlyContinue 12 | 13 | if ($device) { 14 | if ($device.Status -eq 'OK') { 15 | Write-Host "Disabling device"; $device | disable-pnpdevice -Confirm:$false 16 | } else { 17 | Write-Host "Enabling device"; $device | enable-pnpdevice -Confirm:$false 18 | } 19 | } else { 20 | Write-Warning "Device not found" 21 | } 22 | -------------------------------------------------------------------------------- /Community Scripts/winp-VDD.ps1: -------------------------------------------------------------------------------- 1 | # Self-elevate the script if required 2 | if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) { 3 | if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) { 4 | $CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments 5 | Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine 6 | Exit 7 | } 8 | } 9 | 10 | $repoName = "PSGallery" 11 | $moduleName1 = "DisplayConfig" 12 | $moduleName2 = "MonitorConfig" 13 | if (!(Get-PSRepository -Name $repoName) -OR !(Find-Module -Name $moduleName1 | Where-Object {$_.Name -eq $moduleName1}) -OR !(Find-Module -Name $moduleName2 | Where-Object {$_.Name -eq $moduleName2})) { 14 | & .\dep_fix.ps1 15 | } 16 | 17 | 18 | # Import the local module 19 | $dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path 20 | import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 21 | 22 | # Import the other localmodule 23 | $mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path 24 | import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false 25 | 26 | 27 | $profi = Get-DisplayProfile 28 | 29 | if ( $profi -eq "Extend" ) { 30 | Set-DisplayProfile Clone 31 | break 32 | } 33 | if ( $profi -eq "Clone" ) { 34 | Set-DisplayProfile Extend 35 | break 36 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 |

Virtual Display Driver

3 |

4 | Add virtual monitors to your windows 10/11 device! 5 |
6 | Works with VR, OBS, Sunshine, and/or any desktop sharing software. 7 |
8 | Now with an easy to follow setup wizard! 9 |

10 |

11 | 12 |
13 | 14 | ## ℹ About 15 | 16 | This project is based on the "Virtual Display Driver" project and tries to improve on it. 17 | 18 | > Based on Microsoft Indirect Display Driver Sample. This creates a virtual display in Windows that acts and functions just like a real one. It's useful for streaming, virtual reality applications, recording, headless servers, etc. The benefit over a physical display is the ability to adjust resolutions and refresh rates beyond the physical displays capabilities. For example, this would enable the ability to stream a game from your home PC using game streaming software at 240hz at 8K while owning a 60hz 1080p monitor (unrealistic, but explains the abilities well). For servers without displays, this enabled remote desktop and screen streaming to other systems as if there were a display installed. 19 | 20 | > Supports emulating resolutions from 640 x 480 to 7680 x 4320 (8K), and refresh rates including 60hz, 75hz, 90hz, 120hz, 144hz, 165hz, 240hz, 480hz, and 500hz. 21 | 22 | > This project uses the official Windows Indirect Display Driver combined with the IddCx class extension driver. 23 | 24 | This project adds an easy to follow setup wizard and installer to install your Virtual Display. The setup wizard also lets you specify how many displays you want to add to your system without having to change any config file yourself. 25 | 26 | I hope you enjoy this project and if you do i would appreciate a star rating :-) 27 | 28 | ## Download Stable Version 29 | 30 | > [!IMPORTANT] 31 | > Please make sure you download the correct version for your operating system! 32 | 33 | - [Windows 10 and 11 (no HDR)](https://github.com/timminator/Virtual-Display-Driver/releases/tag/v1.0.1) 34 | - [Windows 11 23H2+ (HDR)](https://github.com/timminator/Virtual-Display-Driver/releases/tag/v1.0.1) 35 | 36 | ## Download Beta 37 | - [Universal Driver - 24.10.27 (Windows 10/11)](https://github.com/timminator/Virtual-Display-Driver/releases/tag/24.11.01) 38 | 39 | ## Steps to get it running: 40 | 41 | 1. Download the latest release and follow the instructions of the Setup Wizard. 42 | 43 | That's all you have to do! A Virtual Display should be added to your system! 44 | 45 | ## Notes: 46 | 47 | - If you receive a Windows Defender Smartscreen prompt when executing the setup, click on "More info" and then on "Run anyway". 48 | 49 | ## Acknowledgements 50 | 51 | - Huge shootout to the project [nefcon](https://github.com/nefarius/nefcon) by [nefarius](https://github.com/nefarius) and his contributors. 52 | Without this project this unattended installer would not have been possible! 53 | Please check it out aswell. 54 | 55 | ## Further notes for building the installer yourself 56 | 57 | - The installer does not use the latest version of the nefconw.exe because the Virtual Display Driver was not uninstalled correctly using version v1.11.0. Instead version v1.10.0 is used while building the installer using Inno Setup. 58 | 59 | 60 | ## Acknowledgements of the original repo: 61 | 62 | Shoutout to **[Bud](https://github.com/bud3699)** and **[zjoasan](https://github.com/zjoasan)** for jumping on the team and helping with not just support, but lots of great new features! 63 | 64 | Shoutout to **[Roshkins](https://github.com/roshkins/IddSampleDriver)** for the original repo. 65 | 66 | Shoutout to **[Baloukj](https://github.com/baloukj/IddSampleDriver)** for the 8-bit / 10-bit support. (Also, first to push the new Microsoft Driver public!) 67 | 68 | Shoutout to **[Anakngtokwa](https://github.com/Anakngtokwa)** for assisting with finding driver sources. 69 | 70 | **[Microsoft](https://github.com/microsoft/Windows-driver-samples/tree/master/video/IndirectDisplay)** Indirect Display Driver/Sample (Driver code) 71 | 72 | Thanks to **[AKATrevorJay](https://github.com/akatrevorjay/edid-generator)** for the hi-res EDID. -------------------------------------------------------------------------------- /Setup Installer/Universal Virtual Display Driver/LICENSE_nefcon.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2021 Nefarius Software Solutions e.U. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Setup Installer/Universal Virtual Display Driver/NumberofMonitors.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Check if the user has provided an argument 3 | if "%~1"=="" ( 4 | echo Usage: %0 [number between 1 and 9] 5 | exit /b 1 6 | ) 7 | 8 | REM Get the new number from the command line argument 9 | set newNumber=%~1 10 | 11 | REM Validate the new number (must be between 1 and 9) 12 | if "%newNumber%" lss "1" ( 13 | echo Error: The number must be between 1 and 9. 14 | exit /b 1 15 | ) 16 | if "%newNumber%" gtr "9" ( 17 | echo Error: The number must be between 1 and 9. 18 | exit /b 1 19 | ) 20 | 21 | REM Paths to the XML input and temporary output files 22 | set inputFile=vdd_settings.xml 23 | set tempFile=temp.xml 24 | 25 | REM Counter for line number 26 | set lineNumber=0 27 | 28 | REM Read the file and replace the fourth line if it contains only "1" 29 | ( 30 | for /f "delims=" %%a in ('type "%inputFile%"') do ( 31 | set /a lineNumber+=1 32 | set "line=%%a" 33 | setlocal enabledelayedexpansion 34 | 35 | if !lineNumber! equ 4 ( 36 | if "!line!"==" 1" ( 37 | echo ^%newNumber%^ 38 | ) else ( 39 | echo:!line! 40 | ) 41 | ) else ( 42 | echo:!line! 43 | ) 44 | 45 | endlocal 46 | ) 47 | ) > "%tempFile%" 48 | 49 | REM Replace the original file with the modified version and suppress output 50 | move /Y "%tempFile%" "%inputFile%" >nul 2>&1 -------------------------------------------------------------------------------- /Setup Installer/Universal Virtual Display Driver/Setup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | set CERTIFICATE="%~dp0Virtual_Display_Driver.cer" 5 | 6 | IF "%1"=="install" ( 7 | rem Run install 8 | C:\VirtualDisplayDriver\nefconw.exe --remove-device-node --hardware-id Root\MttVDD --class-guid 4d36e968-e325-11ce-bfc1-08002be10318 9 | certutil -addstore -f root %CERTIFICATE% 10 | certutil -addstore -f TrustedPublisher %CERTIFICATE% 11 | C:\VirtualDisplayDriver\nefconw.exe --create-device-node --hardware-id Root\MttVDD --class-name Display --class-guid 4D36E968-E325-11CE-BFC1-08002BE10318 12 | C:\VirtualDisplayDriver\nefconw.exe --install-driver --inf-path C:\VirtualDisplayDriver\MttVDD.inf 13 | ) 14 | 15 | IF "%1"=="uninstall" ( 16 | rem Run uninstall commands 17 | C:\VirtualDisplayDriver\nefconw.exe --remove-device-node --hardware-id Root\MttVDD --class-guid 4d36e968-e325-11ce-bfc1-08002be10318 18 | ) 19 | 20 | IF "%1"=="" ( 21 | echo Missing argument! Valid arguments are "install" or "uninstall". 22 | ) 23 | 24 | endlocal -------------------------------------------------------------------------------- /Setup Installer/Universal Virtual Display Driver/Setup.iss: -------------------------------------------------------------------------------- 1 | #define MyAppName "Universal Virtual Display Driver" 2 | #define MyAppPublisher "MikeTheTech" 3 | #define MyAppVersion "1.0.0" 4 | #define MyAppURL "https://github.com/timminator/Virtual-Display-Driver" 5 | #define InstallPath "C:\VirtualDisplayDriver" 6 | 7 | [Setup] 8 | SignTool=signtool $f 9 | AppId={{85ECF661-C369-443D-846B-285CFB698447} 10 | AppName={#MyAppName} 11 | AppVersion={#MyAppVersion} 12 | AppPublisher={#MyAppPublisher} 13 | AppPublisherURL={#MyAppURL} 14 | AppSupportURL={#MyAppURL} 15 | AppUpdatesURL={#MyAppURL} 16 | DefaultDirName={#InstallPath} 17 | DisableDirPage=yes 18 | UsePreviousAppDir=yes 19 | LicenseFile=..\LICENSE 20 | DisableProgramGroupPage=yes 21 | PrivilegesRequired=admin 22 | OutputBaseFilename={#MyAppName}-v{#MyAppVersion}-setup-x64 23 | SetupIconFile=..\{#MyAppName}.ico 24 | Compression=lzma 25 | SolidCompression=yes 26 | WizardStyle=classic 27 | UninstallDisplayName={#MyAppName} 28 | UninstallDisplayIcon={uninstallexe} 29 | 30 | [Languages] 31 | Name: "english"; MessagesFile: "compiler:Default.isl" 32 | 33 | [Dirs] 34 | Name: "{app}"; Permissions: everyone-full 35 | 36 | [Files] 37 | Source: "..\mttvdd.cat"; DestDir: "{app}"; Flags: ignoreversion 38 | Source: "..\MttVDD.dll"; DestDir: "{app}"; Flags: ignoreversion 39 | Source: "..\Virtual_Display_Driver.cer"; DestDir: "{app}"; Flags: ignoreversion 40 | Source: "..\MttVDD.inf"; DestDir: "{app}"; Flags: ignoreversion 41 | Source: "..\Setup.bat"; DestDir: "{app}"; Flags: ignoreversion 42 | Source: "..\vdd_settings.xml"; DestDir: "{app}"; Flags: ignoreversion 43 | Source: "..\NumberofMonitors.bat"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: AfterInstall 44 | Source: "..\nefconw.exe"; DestDir: "{app}"; Flags: ignoreversion 45 | Source: "..\LICENSE_nefcon.txt"; Flags: dontcopy 46 | 47 | [Code] 48 | var 49 | LicenseAcceptedRadioButtons: array of TRadioButton; 50 | 51 | procedure CheckLicenseAccepted(Sender: TObject); 52 | begin 53 | // Update Next button when user (un)accepts the license 54 | WizardForm.NextButton.Enabled := 55 | LicenseAcceptedRadioButtons[TComponent(Sender).Tag].Checked; 56 | end; 57 | 58 | procedure LicensePageActivate(Sender: TWizardPage); 59 | begin 60 | // Update Next button when user gets to second license page 61 | CheckLicenseAccepted(LicenseAcceptedRadioButtons[Sender.Tag]); 62 | end; 63 | 64 | function CloneLicenseRadioButton( 65 | Page: TWizardPage; Source: TRadioButton): TRadioButton; 66 | begin 67 | Result := TRadioButton.Create(WizardForm); 68 | Result.Parent := Page.Surface; 69 | Result.Caption := Source.Caption; 70 | Result.Left := Source.Left; 71 | Result.Top := Source.Top; 72 | Result.Width := Source.Width; 73 | Result.Height := Source.Height; 74 | // Needed for WizardStyle=modern / WizardResizable=yes 75 | Result.Anchors := Source.Anchors; 76 | Result.OnClick := @CheckLicenseAccepted; 77 | Result.Tag := Page.Tag; 78 | end; 79 | 80 | var 81 | LicenseAfterPage: Integer; 82 | 83 | procedure AddLicensePage(LicenseFileName: string); 84 | var 85 | Idx: Integer; 86 | Page: TOutputMsgMemoWizardPage; 87 | LicenseFilePath: string; 88 | RadioButton: TRadioButton; 89 | begin 90 | Idx := GetArrayLength(LicenseAcceptedRadioButtons); 91 | SetArrayLength(LicenseAcceptedRadioButtons, Idx + 1); 92 | 93 | Page := 94 | CreateOutputMsgMemoPage( 95 | LicenseAfterPage, SetupMessage(msgWizardLicense), 96 | SetupMessage(msgLicenseLabel), SetupMessage(msgLicenseLabel3), ''); 97 | Page.Tag := Idx; 98 | 99 | // Shrink license box to make space for radio buttons 100 | Page.RichEditViewer.Height := WizardForm.LicenseMemo.Height; 101 | Page.OnActivate := @LicensePageActivate; 102 | 103 | // Load license 104 | // Loading ex-post, as Lines.LoadFromFile supports UTF-8, 105 | // contrary to LoadStringFromFile. 106 | ExtractTemporaryFile(LicenseFileName); 107 | LicenseFilePath := ExpandConstant('{tmp}\' + LicenseFileName); 108 | Page.RichEditViewer.Lines.LoadFromFile(LicenseFilePath); 109 | DeleteFile(LicenseFilePath); 110 | 111 | // Clone accept/do not accept radio buttons 112 | RadioButton := 113 | CloneLicenseRadioButton(Page, WizardForm.LicenseAcceptedRadio); 114 | LicenseAcceptedRadioButtons[Idx] := RadioButton; 115 | 116 | RadioButton := 117 | CloneLicenseRadioButton(Page, WizardForm.LicenseNotAcceptedRadio); 118 | // Initially not accepted 119 | RadioButton.Checked := True; 120 | 121 | LicenseAfterPage := Page.ID; 122 | end; 123 | 124 | var 125 | Page: TWizardPage; 126 | MonitorsEdit: TEdit; 127 | MonitorsLabel: TLabel; 128 | 129 | procedure InitializeWizard(); 130 | begin 131 | LicenseAfterPage := wpLicense; 132 | AddLicensePage('LICENSE_nefcon.txt'); 133 | // Create a custom page 134 | Page := CreateCustomPage(LicenseAfterPage, 'Virtual Display Configuration', 135 | 'Choose how many virtual displays you want to add to your system.'); 136 | 137 | // Create a label for the message 138 | MonitorsLabel := TLabel.Create(Page); 139 | MonitorsLabel.Parent := Page.Surface; 140 | MonitorsLabel.Caption := 'Choose how many virtual displays you want to add to your system.'#13#10'A maximum of 4 displays is recommended.'; 141 | MonitorsLabel.Left := 10; 142 | MonitorsLabel.Top := 10; 143 | MonitorsLabel.Width := Page.SurfaceWidth - 20; 144 | MonitorsLabel.AutoSize := True; 145 | MonitorsLabel.WordWrap := True; 146 | 147 | // Create an edit box for user input 148 | MonitorsEdit := TEdit.Create(Page); 149 | MonitorsEdit.Parent := Page.Surface; 150 | MonitorsEdit.Left := 10; 151 | MonitorsEdit.Top := MonitorsLabel.Top + MonitorsLabel.Height + 10; 152 | MonitorsEdit.Width := Page.SurfaceWidth - 20; 153 | MonitorsEdit.Text := '1'; // Default value 154 | end; 155 | 156 | procedure RunBatchFile(FileName: String; Params: String); 157 | var 158 | ResultCode: Integer; 159 | begin 160 | Exec(ExpandConstant(FileName), Params, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); 161 | end; 162 | 163 | procedure AfterInstall; 164 | var 165 | NumberOfMonitors: String; 166 | begin 167 | // Get the number of monitors from the user input 168 | NumberOfMonitors := MonitorsEdit.Text; 169 | 170 | // Run the batch file with the user input as an argument 171 | RunBatchFile(ExpandConstant('{app}\NumberofMonitors.bat'), NumberOfMonitors); 172 | end; 173 | 174 | var 175 | isSilent: Boolean; 176 | 177 | function InitializeSetup(): Boolean; 178 | var 179 | j: Integer; 180 | begin 181 | Result := True; 182 | IsSilent := False; 183 | for j := 1 to ParamCount do 184 | begin 185 | if (CompareText(ParamStr(j), '/verysilent') = 0) or 186 | (CompareText(ParamStr(j), '/silent') = 0) then 187 | begin 188 | IsSilent := True; 189 | Break; 190 | end; 191 | end; 192 | end; 193 | 194 | procedure CurPageChanged(CurPageID: Integer); 195 | var 196 | I: Integer; 197 | begin 198 | // Automatically accept licenses if running in silent mode 199 | if IsSilent then 200 | begin 201 | for I := 0 to GetArrayLength(LicenseAcceptedRadioButtons) - 1 do 202 | begin 203 | LicenseAcceptedRadioButtons[I].Checked := True; 204 | end; 205 | end; 206 | end; 207 | 208 | [Run] 209 | Filename: "{app}\Setup.bat"; Parameters: "install"; Flags: runhidden 210 | 211 | [UninstallRun] 212 | Filename: "{app}\Setup.bat"; Parameters: "uninstall"; Flags: runhidden -------------------------------------------------------------------------------- /Setup Installer/Universal Virtual Display Driver/Universal Virtual Display Driver.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Setup Installer/Universal Virtual Display Driver/Universal Virtual Display Driver.ico -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver HDR v1.0.0/LICENSE_nefcon.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2021 Nefarius Software Solutions e.U. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver HDR v1.0.0/NumberofMonitors.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Check if the user has provided an argument 3 | if "%~1"=="" ( 4 | echo Usage: %0 [number between 1 and 9] 5 | exit /b 1 6 | ) 7 | 8 | REM Get the new number from the command line argument 9 | set newNumber=%~1 10 | 11 | REM Validate the new number (must be between 1 and 9) 12 | if "%newNumber%" lss "1" ( 13 | echo Error: The number must be between 1 and 9. 14 | exit /b 1 15 | ) 16 | if "%newNumber%" gtr "9" ( 17 | echo Error: The number must be between 1 and 9. 18 | exit /b 1 19 | ) 20 | 21 | REM Path to the input and temporary files 22 | set inputFile=option.txt 23 | set tempFile=temp.txt 24 | 25 | REM Read the first line and replace it with the new number 26 | > %tempFile% ( 27 | echo %newNumber% 28 | more +1 %inputFile% 29 | ) 30 | 31 | REM Replace the original file with the updated file and suppress output 32 | move /Y %tempFile% %inputFile% >nul 2>&1 -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver HDR v1.0.0/Setup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | set CERTIFICATE="%~dp0Virtual_Display_Driver.cer" 5 | 6 | IF "%1"=="install" ( 7 | rem Run install 8 | C:\IddSampleDriver\nefconw.exe --remove-device-node --hardware-id ROOT\iddsampledriver --class-guid 4d36e968-e325-11ce-bfc1-08002be10318 9 | certutil -addstore -f root %CERTIFICATE% 10 | certutil -addstore -f TrustedPublisher %CERTIFICATE% 11 | C:\IddSampleDriver\nefconw.exe --create-device-node --hardware-id ROOT\iddsampledriver --class-name Display --class-guid 4D36E968-E325-11CE-BFC1-08002BE10318 12 | C:\IddSampleDriver\nefconw.exe --install-driver --inf-path C:\IddSampleDriver\IddSampleDriver.inf 13 | ) 14 | 15 | IF "%1"=="uninstall" ( 16 | rem Run uninstall commands 17 | C:\IddSampleDriver\nefconw.exe --remove-device-node --hardware-id ROOT\iddsampledriver --class-guid 4d36e968-e325-11ce-bfc1-08002be10318 18 | del "%~dp0option.txt" 19 | ) 20 | 21 | IF "%1"=="" ( 22 | echo Missing argument! Valid arguments are "install" or "uninstall". 23 | ) 24 | 25 | endlocal -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver HDR v1.0.0/Setup.iss: -------------------------------------------------------------------------------- 1 | #define MyAppName "Virtual Display Driver HDR" 2 | #define MyAppVersion "1.0.1" 3 | #define MyAppURL "https://github.com/timminator/Virtual-Display-Driver" 4 | #define InstallPath "C:\IddSampleDriver" 5 | 6 | [Setup] 7 | SignTool=signtool $f 8 | AppId={{3A1D1EE3-1A2D-4EA2-AA99-58D631C25263} 9 | AppName={#MyAppName} 10 | AppVersion={#MyAppVersion} 11 | AppPublisherURL={#MyAppURL} 12 | AppSupportURL={#MyAppURL} 13 | AppUpdatesURL={#MyAppURL} 14 | DefaultDirName={#InstallPath} 15 | MinVersion=10.0.22621 16 | DisableDirPage=yes 17 | UsePreviousAppDir=yes 18 | LicenseFile=..\..\LICENSE 19 | DisableProgramGroupPage=yes 20 | PrivilegesRequired=admin 21 | OutputBaseFilename={#MyAppName}-v{#MyAppVersion}-setup-x64 22 | SetupIconFile=..\{#MyAppName}.ico 23 | Compression=lzma 24 | SolidCompression=yes 25 | WizardStyle=classic 26 | UninstallDisplayName={#MyAppName} 27 | UninstallDisplayIcon={uninstallexe} 28 | 29 | [Languages] 30 | Name: "english"; MessagesFile: "compiler:Default.isl" 31 | 32 | [Dirs] 33 | Name: "{app}"; Permissions: everyone-full 34 | 35 | [Files] 36 | Source: ".\iddsampledriver.cat"; DestDir: "{app}"; Flags: ignoreversion 37 | Source: ".\IddSampleDriver.dll"; DestDir: "{app}"; Flags: ignoreversion 38 | Source: ".\Virtual_Display_Driver.cer"; DestDir: "{app}"; Flags: ignoreversion 39 | Source: ".\IddSampleDriver.inf"; DestDir: "{app}"; Flags: ignoreversion 40 | Source: ".\Setup.bat"; DestDir: "{app}"; Flags: ignoreversion 41 | Source: ".\option.txt"; DestDir: "{app}"; Flags: ignoreversion 42 | Source: ".\NumberofMonitors.bat"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: AfterInstall 43 | Source: ".\nefconw.exe"; DestDir: "{app}"; Flags: ignoreversion 44 | Source: ".\LICENSE_nefcon.txt"; Flags: dontcopy 45 | 46 | [Code] 47 | var 48 | LicenseAcceptedRadioButtons: array of TRadioButton; 49 | 50 | procedure CheckLicenseAccepted(Sender: TObject); 51 | begin 52 | // Update Next button when user (un)accepts the license 53 | WizardForm.NextButton.Enabled := 54 | LicenseAcceptedRadioButtons[TComponent(Sender).Tag].Checked; 55 | end; 56 | 57 | procedure LicensePageActivate(Sender: TWizardPage); 58 | begin 59 | // Update Next button when user gets to second license page 60 | CheckLicenseAccepted(LicenseAcceptedRadioButtons[Sender.Tag]); 61 | end; 62 | 63 | function CloneLicenseRadioButton( 64 | Page: TWizardPage; Source: TRadioButton): TRadioButton; 65 | begin 66 | Result := TRadioButton.Create(WizardForm); 67 | Result.Parent := Page.Surface; 68 | Result.Caption := Source.Caption; 69 | Result.Left := Source.Left; 70 | Result.Top := Source.Top; 71 | Result.Width := Source.Width; 72 | Result.Height := Source.Height; 73 | // Needed for WizardStyle=modern / WizardResizable=yes 74 | Result.Anchors := Source.Anchors; 75 | Result.OnClick := @CheckLicenseAccepted; 76 | Result.Tag := Page.Tag; 77 | end; 78 | 79 | var 80 | LicenseAfterPage: Integer; 81 | 82 | procedure AddLicensePage(LicenseFileName: string); 83 | var 84 | Idx: Integer; 85 | Page: TOutputMsgMemoWizardPage; 86 | LicenseFilePath: string; 87 | RadioButton: TRadioButton; 88 | begin 89 | Idx := GetArrayLength(LicenseAcceptedRadioButtons); 90 | SetArrayLength(LicenseAcceptedRadioButtons, Idx + 1); 91 | 92 | Page := 93 | CreateOutputMsgMemoPage( 94 | LicenseAfterPage, SetupMessage(msgWizardLicense), 95 | SetupMessage(msgLicenseLabel), SetupMessage(msgLicenseLabel3), ''); 96 | Page.Tag := Idx; 97 | 98 | // Shrink license box to make space for radio buttons 99 | Page.RichEditViewer.Height := WizardForm.LicenseMemo.Height; 100 | Page.OnActivate := @LicensePageActivate; 101 | 102 | // Load license 103 | // Loading ex-post, as Lines.LoadFromFile supports UTF-8, 104 | // contrary to LoadStringFromFile. 105 | ExtractTemporaryFile(LicenseFileName); 106 | LicenseFilePath := ExpandConstant('{tmp}\' + LicenseFileName); 107 | Page.RichEditViewer.Lines.LoadFromFile(LicenseFilePath); 108 | DeleteFile(LicenseFilePath); 109 | 110 | // Clone accept/do not accept radio buttons 111 | RadioButton := 112 | CloneLicenseRadioButton(Page, WizardForm.LicenseAcceptedRadio); 113 | LicenseAcceptedRadioButtons[Idx] := RadioButton; 114 | 115 | RadioButton := 116 | CloneLicenseRadioButton(Page, WizardForm.LicenseNotAcceptedRadio); 117 | // Initially not accepted 118 | RadioButton.Checked := True; 119 | 120 | LicenseAfterPage := Page.ID; 121 | end; 122 | 123 | var 124 | Page: TWizardPage; 125 | MonitorsEdit: TEdit; 126 | MonitorsLabel: TLabel; 127 | 128 | procedure InitializeWizard(); 129 | begin 130 | LicenseAfterPage := wpLicense; 131 | AddLicensePage('LICENSE_nefcon.txt'); 132 | // Create a custom page 133 | Page := CreateCustomPage(LicenseAfterPage, 'Virtual Display Configuration', 134 | 'Choose how many virtual displays you want to add to your system.'); 135 | 136 | // Create a label for the message 137 | MonitorsLabel := TLabel.Create(Page); 138 | MonitorsLabel.Parent := Page.Surface; 139 | MonitorsLabel.Caption := 'Choose how many virtual displays you want to add to your system.'#13#10'A maximum of 4 displays is recommended.'; 140 | MonitorsLabel.Left := 10; 141 | MonitorsLabel.Top := 10; 142 | MonitorsLabel.Width := Page.SurfaceWidth - 20; 143 | MonitorsLabel.AutoSize := True; 144 | MonitorsLabel.WordWrap := True; 145 | 146 | // Create an edit box for user input 147 | MonitorsEdit := TEdit.Create(Page); 148 | MonitorsEdit.Parent := Page.Surface; 149 | MonitorsEdit.Left := 10; 150 | MonitorsEdit.Top := MonitorsLabel.Top + MonitorsLabel.Height + 10; 151 | MonitorsEdit.Width := Page.SurfaceWidth - 20; 152 | MonitorsEdit.Text := '1'; // Default value 153 | end; 154 | 155 | procedure RunBatchFile(FileName: String; Params: String); 156 | var 157 | ResultCode: Integer; 158 | begin 159 | Exec(ExpandConstant(FileName), Params, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); 160 | end; 161 | 162 | procedure AfterInstall; 163 | var 164 | NumberOfMonitors: String; 165 | begin 166 | // Get the number of monitors from the user input 167 | NumberOfMonitors := MonitorsEdit.Text; 168 | 169 | // Run the batch file with the user input as an argument 170 | RunBatchFile(ExpandConstant('{app}\NumberofMonitors.bat'), NumberOfMonitors); 171 | end; 172 | 173 | var 174 | isSilent: Boolean; 175 | 176 | function InitializeSetup(): Boolean; 177 | var 178 | j: Integer; 179 | begin 180 | Result := True; 181 | IsSilent := False; 182 | for j := 1 to ParamCount do 183 | begin 184 | if (CompareText(ParamStr(j), '/verysilent') = 0) or 185 | (CompareText(ParamStr(j), '/silent') = 0) then 186 | begin 187 | IsSilent := True; 188 | Break; 189 | end; 190 | end; 191 | end; 192 | 193 | procedure CurPageChanged(CurPageID: Integer); 194 | var 195 | I: Integer; 196 | begin 197 | // Automatically accept licenses if running in silent mode 198 | if IsSilent then 199 | begin 200 | for I := 0 to GetArrayLength(LicenseAcceptedRadioButtons) - 1 do 201 | begin 202 | LicenseAcceptedRadioButtons[I].Checked := True; 203 | end; 204 | end; 205 | end; 206 | 207 | [Run] 208 | Filename: "{app}\Setup.bat"; Parameters: "install"; Flags: runhidden 209 | 210 | [UninstallRun] 211 | Filename: "{app}\Setup.bat"; Parameters: "uninstall"; Flags: runhidden -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver HDR v1.0.0/Virtual Display Driver HDR.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Setup Installer/Virtual Display Driver HDR v1.0.0/Virtual Display Driver HDR.ico -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver v1.0.0/LICENSE_nefcon.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018-2021 Nefarius Software Solutions e.U. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver v1.0.0/NumberofMonitors.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | REM Check if the user has provided an argument 3 | if "%~1"=="" ( 4 | echo Usage: %0 [number between 1 and 9] 5 | exit /b 1 6 | ) 7 | 8 | REM Get the new number from the command line argument 9 | set newNumber=%~1 10 | 11 | REM Validate the new number (must be between 1 and 9) 12 | if "%newNumber%" lss "1" ( 13 | echo Error: The number must be between 1 and 9. 14 | exit /b 1 15 | ) 16 | if "%newNumber%" gtr "9" ( 17 | echo Error: The number must be between 1 and 9. 18 | exit /b 1 19 | ) 20 | 21 | REM Path to the input and temporary files 22 | set inputFile=option.txt 23 | set tempFile=temp.txt 24 | 25 | REM Read the first line and replace it with the new number 26 | > %tempFile% ( 27 | echo %newNumber% 28 | more +1 %inputFile% 29 | ) 30 | 31 | REM Replace the original file with the updated file and suppress output 32 | move /Y %tempFile% %inputFile% >nul 2>&1 -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver v1.0.0/Setup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | set CERTIFICATE="%~dp0Virtual_Display_Driver.cer" 5 | 6 | IF "%1"=="install" ( 7 | rem Run install 8 | C:\IddSampleDriver\nefconw.exe --remove-device-node --hardware-id ROOT\iddsampledriver --class-guid 4d36e968-e325-11ce-bfc1-08002be10318 9 | certutil -addstore -f root %CERTIFICATE% 10 | certutil -addstore -f TrustedPublisher %CERTIFICATE% 11 | C:\IddSampleDriver\nefconw.exe --create-device-node --hardware-id ROOT\iddsampledriver --class-name Display --class-guid 4D36E968-E325-11CE-BFC1-08002BE10318 12 | C:\IddSampleDriver\nefconw.exe --install-driver --inf-path C:\IddSampleDriver\IddSampleDriver.inf 13 | ) 14 | 15 | IF "%1"=="uninstall" ( 16 | rem Run uninstall commands 17 | C:\IddSampleDriver\nefconw.exe --remove-device-node --hardware-id ROOT\iddsampledriver --class-guid 4d36e968-e325-11ce-bfc1-08002be10318 18 | del "%~dp0option.txt" 19 | ) 20 | 21 | IF "%1"=="" ( 22 | echo Missing argument! Valid arguments are "install" or "uninstall". 23 | ) 24 | 25 | endlocal -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver v1.0.0/Setup.iss: -------------------------------------------------------------------------------- 1 | #define MyAppName "Virtual Display Driver" 2 | #define MyAppVersion "1.0.1" 3 | #define MyAppURL "https://github.com/timminator/Virtual-Display-Driver" 4 | #define InstallPath "C:\IddSampleDriver" 5 | 6 | [Setup] 7 | SignTool=signtool $f 8 | AppId={{3A1D1EE3-1A2D-4EA2-AA99-58D631C25263} 9 | AppName={#MyAppName} 10 | AppVersion={#MyAppVersion} 11 | AppPublisherURL={#MyAppURL} 12 | AppSupportURL={#MyAppURL} 13 | AppUpdatesURL={#MyAppURL} 14 | DefaultDirName={#InstallPath} 15 | MinVersion=10.0.14393 16 | DisableDirPage=yes 17 | UsePreviousAppDir=yes 18 | LicenseFile=..\..\LICENSE 19 | DisableProgramGroupPage=yes 20 | PrivilegesRequired=admin 21 | OutputBaseFilename={#MyAppName}-v{#MyAppVersion}-setup-x64 22 | SetupIconFile=..\{#MyAppName}.ico 23 | Compression=lzma 24 | SolidCompression=yes 25 | WizardStyle=classic 26 | UninstallDisplayName={#MyAppName} 27 | UninstallDisplayIcon={uninstallexe} 28 | 29 | [Languages] 30 | Name: "english"; MessagesFile: "compiler:Default.isl" 31 | 32 | [Dirs] 33 | Name: "{app}"; Permissions: everyone-full 34 | 35 | [Files] 36 | Source: ".\iddsampledriver.cat"; DestDir: "{app}"; Flags: ignoreversion 37 | Source: ".\IddSampleDriver.dll"; DestDir: "{app}"; Flags: ignoreversion 38 | Source: ".\Virtual_Display_Driver.cer"; DestDir: "{app}"; Flags: ignoreversion 39 | Source: ".\IddSampleDriver.inf"; DestDir: "{app}"; Flags: ignoreversion 40 | Source: ".\Setup.bat"; DestDir: "{app}"; Flags: ignoreversion 41 | Source: ".\option.txt"; DestDir: "{app}"; Flags: ignoreversion 42 | Source: ".\NumberofMonitors.bat"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: AfterInstall 43 | Source: ".\nefconw.exe"; DestDir: "{app}"; Flags: ignoreversion 44 | Source: ".\LICENSE_nefcon.txt"; Flags: dontcopy 45 | 46 | [Code] 47 | var 48 | LicenseAcceptedRadioButtons: array of TRadioButton; 49 | 50 | procedure CheckLicenseAccepted(Sender: TObject); 51 | begin 52 | // Update Next button when user (un)accepts the license 53 | WizardForm.NextButton.Enabled := 54 | LicenseAcceptedRadioButtons[TComponent(Sender).Tag].Checked; 55 | end; 56 | 57 | procedure LicensePageActivate(Sender: TWizardPage); 58 | begin 59 | // Update Next button when user gets to second license page 60 | CheckLicenseAccepted(LicenseAcceptedRadioButtons[Sender.Tag]); 61 | end; 62 | 63 | function CloneLicenseRadioButton( 64 | Page: TWizardPage; Source: TRadioButton): TRadioButton; 65 | begin 66 | Result := TRadioButton.Create(WizardForm); 67 | Result.Parent := Page.Surface; 68 | Result.Caption := Source.Caption; 69 | Result.Left := Source.Left; 70 | Result.Top := Source.Top; 71 | Result.Width := Source.Width; 72 | Result.Height := Source.Height; 73 | // Needed for WizardStyle=modern / WizardResizable=yes 74 | Result.Anchors := Source.Anchors; 75 | Result.OnClick := @CheckLicenseAccepted; 76 | Result.Tag := Page.Tag; 77 | end; 78 | 79 | var 80 | LicenseAfterPage: Integer; 81 | 82 | procedure AddLicensePage(LicenseFileName: string); 83 | var 84 | Idx: Integer; 85 | Page: TOutputMsgMemoWizardPage; 86 | LicenseFilePath: string; 87 | RadioButton: TRadioButton; 88 | begin 89 | Idx := GetArrayLength(LicenseAcceptedRadioButtons); 90 | SetArrayLength(LicenseAcceptedRadioButtons, Idx + 1); 91 | 92 | Page := 93 | CreateOutputMsgMemoPage( 94 | LicenseAfterPage, SetupMessage(msgWizardLicense), 95 | SetupMessage(msgLicenseLabel), SetupMessage(msgLicenseLabel3), ''); 96 | Page.Tag := Idx; 97 | 98 | // Shrink license box to make space for radio buttons 99 | Page.RichEditViewer.Height := WizardForm.LicenseMemo.Height; 100 | Page.OnActivate := @LicensePageActivate; 101 | 102 | // Load license 103 | // Loading ex-post, as Lines.LoadFromFile supports UTF-8, 104 | // contrary to LoadStringFromFile. 105 | ExtractTemporaryFile(LicenseFileName); 106 | LicenseFilePath := ExpandConstant('{tmp}\' + LicenseFileName); 107 | Page.RichEditViewer.Lines.LoadFromFile(LicenseFilePath); 108 | DeleteFile(LicenseFilePath); 109 | 110 | // Clone accept/do not accept radio buttons 111 | RadioButton := 112 | CloneLicenseRadioButton(Page, WizardForm.LicenseAcceptedRadio); 113 | LicenseAcceptedRadioButtons[Idx] := RadioButton; 114 | 115 | RadioButton := 116 | CloneLicenseRadioButton(Page, WizardForm.LicenseNotAcceptedRadio); 117 | // Initially not accepted 118 | RadioButton.Checked := True; 119 | 120 | LicenseAfterPage := Page.ID; 121 | end; 122 | 123 | var 124 | Page: TWizardPage; 125 | MonitorsEdit: TEdit; 126 | MonitorsLabel: TLabel; 127 | 128 | procedure InitializeWizard(); 129 | begin 130 | LicenseAfterPage := wpLicense; 131 | AddLicensePage('LICENSE_nefcon.txt'); 132 | // Create a custom page 133 | Page := CreateCustomPage(LicenseAfterPage, 'Virtual Display Configuration', 134 | 'Choose how many virtual displays you want to add to your system.'); 135 | 136 | // Create a label for the message 137 | MonitorsLabel := TLabel.Create(Page); 138 | MonitorsLabel.Parent := Page.Surface; 139 | MonitorsLabel.Caption := 'Choose how many virtual displays you want to add to your system.'#13#10'A maximum of 4 displays is recommended.'; 140 | MonitorsLabel.Left := 10; 141 | MonitorsLabel.Top := 10; 142 | MonitorsLabel.Width := Page.SurfaceWidth - 20; 143 | MonitorsLabel.AutoSize := True; 144 | MonitorsLabel.WordWrap := True; 145 | 146 | // Create an edit box for user input 147 | MonitorsEdit := TEdit.Create(Page); 148 | MonitorsEdit.Parent := Page.Surface; 149 | MonitorsEdit.Left := 10; 150 | MonitorsEdit.Top := MonitorsLabel.Top + MonitorsLabel.Height + 10; 151 | MonitorsEdit.Width := Page.SurfaceWidth - 20; 152 | MonitorsEdit.Text := '1'; // Default value 153 | end; 154 | 155 | procedure RunBatchFile(FileName: String; Params: String); 156 | var 157 | ResultCode: Integer; 158 | begin 159 | Exec(ExpandConstant(FileName), Params, '', SW_HIDE, ewWaitUntilTerminated, ResultCode); 160 | end; 161 | 162 | procedure AfterInstall; 163 | var 164 | NumberOfMonitors: String; 165 | begin 166 | // Get the number of monitors from the user input 167 | NumberOfMonitors := MonitorsEdit.Text; 168 | 169 | // Run the batch file with the user input as an argument 170 | RunBatchFile(ExpandConstant('{app}\NumberofMonitors.bat'), NumberOfMonitors); 171 | end; 172 | 173 | var 174 | isSilent: Boolean; 175 | 176 | function InitializeSetup(): Boolean; 177 | var 178 | j: Integer; 179 | begin 180 | Result := True; 181 | IsSilent := False; 182 | for j := 1 to ParamCount do 183 | begin 184 | if (CompareText(ParamStr(j), '/verysilent') = 0) or 185 | (CompareText(ParamStr(j), '/silent') = 0) then 186 | begin 187 | IsSilent := True; 188 | Break; 189 | end; 190 | end; 191 | end; 192 | 193 | procedure CurPageChanged(CurPageID: Integer); 194 | var 195 | I: Integer; 196 | begin 197 | // Automatically accept licenses if running in silent mode 198 | if IsSilent then 199 | begin 200 | for I := 0 to GetArrayLength(LicenseAcceptedRadioButtons) - 1 do 201 | begin 202 | LicenseAcceptedRadioButtons[I].Checked := True; 203 | end; 204 | end; 205 | end; 206 | 207 | [Run] 208 | Filename: "{app}\Setup.bat"; Parameters: "install"; Flags: runhidden 209 | 210 | [UninstallRun] 211 | Filename: "{app}\Setup.bat"; Parameters: "uninstall"; Flags: runhidden -------------------------------------------------------------------------------- /Setup Installer/Virtual Display Driver v1.0.0/Virtual Display Driver.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Setup Installer/Virtual Display Driver v1.0.0/Virtual Display Driver.ico -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/8K240HzHDR.edid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Virtual Display Driver (HDR)/8K240HzHDR.edid -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/CppProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "inheritEnvironments": [ 5 | "msvc_x64" 6 | ], 7 | "name": "x64-Debug", 8 | "includePath": [ 9 | "${env.INCLUDE}", 10 | "${workspaceRoot}\\**" 11 | ], 12 | "defines": [ 13 | "WIN32", 14 | "_DEBUG", 15 | "UNICODE", 16 | "_UNICODE" 17 | ], 18 | "intelliSenseMode": "windows-msvc-x64" 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/MttVDD.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31129.286 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MttVDD", "MttVDD\MttVDD.vcxproj", "{2D54CB75-8B17-4F11-97DC-847B0244CD46}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.ActiveCfg = Debug|x64 21 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Build.0 = Debug|x64 22 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Deploy.0 = Debug|x64 23 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.ActiveCfg = Debug|ARM64 24 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Build.0 = Debug|ARM64 25 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Deploy.0 = Debug|ARM64 26 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.ActiveCfg = Debug|x64 27 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Build.0 = Debug|x64 28 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Deploy.0 = Debug|x64 29 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.ActiveCfg = Debug|Win32 30 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Build.0 = Debug|Win32 31 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Deploy.0 = Debug|Win32 32 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.ActiveCfg = Release|ARM 33 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Build.0 = Release|ARM 34 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Deploy.0 = Release|ARM 35 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.ActiveCfg = Release|ARM64 36 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Build.0 = Release|ARM64 37 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Deploy.0 = Release|ARM64 38 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.ActiveCfg = Release|x64 39 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Build.0 = Release|x64 40 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Deploy.0 = Release|x64 41 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.ActiveCfg = Release|Win32 42 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Build.0 = Release|Win32 43 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Deploy.0 = Release|Win32 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {DE75497E-BE4F-4215-8345-84C5F8358E3B} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/MttVDD/Driver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NOMINMAX 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "Trace.h" 19 | 20 | namespace Microsoft 21 | { 22 | namespace WRL 23 | { 24 | namespace Wrappers 25 | { 26 | // Adds a wrapper for thread handles to the existing set of WRL handle wrapper classes 27 | typedef HandleT Thread; 28 | } 29 | } 30 | } 31 | 32 | namespace Microsoft 33 | { 34 | namespace IndirectDisp 35 | { 36 | /// 37 | /// Manages the creation and lifetime of a Direct3D render device. 38 | /// 39 | struct Direct3DDevice 40 | { 41 | Direct3DDevice(LUID AdapterLuid); 42 | Direct3DDevice(); 43 | HRESULT Init(); 44 | 45 | LUID AdapterLuid; 46 | Microsoft::WRL::ComPtr DxgiFactory; 47 | Microsoft::WRL::ComPtr Adapter; 48 | Microsoft::WRL::ComPtr Device; 49 | Microsoft::WRL::ComPtr DeviceContext; 50 | }; 51 | 52 | /// 53 | /// Manages a thread that consumes buffers from an indirect display swap-chain object. 54 | /// 55 | class SwapChainProcessor 56 | { 57 | public: 58 | SwapChainProcessor(IDDCX_SWAPCHAIN hSwapChain, std::shared_ptr Device, HANDLE NewFrameEvent); 59 | ~SwapChainProcessor(); 60 | 61 | private: 62 | static DWORD CALLBACK RunThread(LPVOID Argument); 63 | 64 | void Run(); 65 | void RunCore(); 66 | 67 | public: 68 | IDDCX_SWAPCHAIN m_hSwapChain; 69 | std::shared_ptr m_Device; 70 | HANDLE m_hAvailableBufferEvent; 71 | Microsoft::WRL::Wrappers::Thread m_hThread; 72 | Microsoft::WRL::Wrappers::Event m_hTerminateEvent; 73 | }; 74 | 75 | /// 76 | /// Provides a sample implementation of an indirect display driver. 77 | /// 78 | class IndirectDeviceContext 79 | { 80 | public: 81 | IndirectDeviceContext(_In_ WDFDEVICE WdfDevice); 82 | virtual ~IndirectDeviceContext(); 83 | 84 | void InitAdapter(); 85 | void FinishInit(); 86 | 87 | void CreateMonitor(unsigned int index); 88 | 89 | void AssignSwapChain(IDDCX_MONITOR& Monitor, IDDCX_SWAPCHAIN SwapChain, LUID RenderAdapter, HANDLE NewFrameEvent); 90 | void UnassignSwapChain(); 91 | 92 | protected: 93 | 94 | WDFDEVICE m_WdfDevice; 95 | IDDCX_ADAPTER m_Adapter; 96 | IDDCX_MONITOR m_Monitor; 97 | IDDCX_MONITOR m_Monitor2; 98 | 99 | std::unique_ptr m_ProcessingThread; 100 | 101 | public: 102 | static const DISPLAYCONFIG_VIDEO_SIGNAL_INFO s_KnownMonitorModes[]; 103 | static std::vector s_KnownMonitorEdid; 104 | }; 105 | } 106 | } -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/MttVDD/MttVDD.inf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timminator/Virtual-Display-Driver/f9087c5d74fa6307f9b93d98528cdce361da29a7/Virtual Display Driver (HDR)/MttVDD/MttVDD.inf -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/MttVDD/MttVDD.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.9.34622.214 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IddSampleDriver", "IddSampleDriver.vcxproj", "{2D54CB75-8B17-4F11-97DC-847B0244CD46}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|ARM = Debug|ARM 11 | Debug|ARM64 = Debug|ARM64 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|ARM = Release|ARM 15 | Release|ARM64 = Release|ARM64 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.ActiveCfg = Debug|ARM 21 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Build.0 = Debug|ARM 22 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM.Deploy.0 = Debug|ARM 23 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.ActiveCfg = Debug|ARM64 24 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Build.0 = Debug|ARM64 25 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|ARM64.Deploy.0 = Debug|ARM64 26 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.ActiveCfg = Debug|x64 27 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Build.0 = Debug|x64 28 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x64.Deploy.0 = Debug|x64 29 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.ActiveCfg = Debug|Win32 30 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Build.0 = Debug|Win32 31 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Debug|x86.Deploy.0 = Debug|Win32 32 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.ActiveCfg = Release|ARM 33 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Build.0 = Release|ARM 34 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM.Deploy.0 = Release|ARM 35 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.ActiveCfg = Release|ARM64 36 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Build.0 = Release|ARM64 37 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|ARM64.Deploy.0 = Release|ARM64 38 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.ActiveCfg = Release|x64 39 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x64.Build.0 = Release|x64 40 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.ActiveCfg = Release|Win32 41 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Build.0 = Release|Win32 42 | {2D54CB75-8B17-4F11-97DC-847B0244CD46}.Release|x86.Deploy.0 = Release|Win32 43 | EndGlobalSection 44 | GlobalSection(SolutionProperties) = preSolution 45 | HideSolutionNode = FALSE 46 | EndGlobalSection 47 | GlobalSection(ExtensibilityGlobals) = postSolution 48 | SolutionGuid = {9A8BE7D9-9F0F-40A2-BA2D-8AE9E35890DB} 49 | EndGlobalSection 50 | EndGlobal 51 | -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/MttVDD/MttVDD.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {8E41214B-6785-4CFE-B992-037D68949A14} 18 | inf;inv;inx;mof;mc; 19 | 20 | 21 | 22 | 23 | Driver Files 24 | 25 | 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | 38 | 39 | Source Files 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Resource Files 48 | 49 | 50 | -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/MttVDD/Trace.h: -------------------------------------------------------------------------------- 1 | /*++ 2 | 3 | Module Name: 4 | 5 | Internal.h 6 | 7 | Abstract: 8 | 9 | This module contains the local type definitions for the 10 | driver. 11 | 12 | Environment: 13 | 14 | Windows User-Mode Driver Framework 2 15 | 16 | --*/ 17 | 18 | // 19 | // Define the tracing flags. 20 | // 21 | // Tracing GUID - b254994f-46e6-4718-80a0-0a3aa50d6ce4 22 | // 23 | 24 | #define WPP_CONTROL_GUIDS \ 25 | WPP_DEFINE_CONTROL_GUID( \ 26 | MyDriver1TraceGuid, (b254994f,46e6,4718,80a0,0a3aa50d6ce4), \ 27 | \ 28 | WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ 29 | WPP_DEFINE_BIT(TRACE_DRIVER) \ 30 | WPP_DEFINE_BIT(TRACE_DEVICE) \ 31 | WPP_DEFINE_BIT(TRACE_QUEUE) \ 32 | ) 33 | 34 | #define WPP_FLAG_LEVEL_LOGGER(flag, level) \ 35 | WPP_LEVEL_LOGGER(flag) 36 | 37 | #define WPP_FLAG_LEVEL_ENABLED(flag, level) \ 38 | (WPP_LEVEL_ENABLED(flag) && \ 39 | WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) 40 | 41 | #define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ 42 | WPP_LEVEL_LOGGER(flags) 43 | 44 | #define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ 45 | (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) 46 | 47 | // 48 | // This comment block is scanned by the trace preprocessor to define our 49 | // Trace function. 50 | // 51 | // begin_wpp config 52 | // FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); 53 | // FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); 54 | // end_wpp 55 | 56 | // 57 | // 58 | // Driver specific #defines 59 | // 60 | #if UMDF_VERSION_MAJOR == 2 && UMDF_VERSION_MINOR == 0 61 | // TODO: Update the name of the tracing provider 62 | #define MYDRIVER_TRACING_ID L"Microsoft\\UMDF2.0\\IddSampleDriver V1.0" 63 | #endif -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/MttVDD/readme.md: -------------------------------------------------------------------------------- 1 | # Get 5 virtual monitors for the price of zero! 2 | 3 | # Steps (for experienced pros only!!!) 4 | 1. Download the latest release as a zip file. 5 | 6 | 2. As an administrator, Run the *.bat file to add the driver certificate as a trusted root certificate. 7 | 8 | 3. Don't install the inf. Open device manager, click on any device, then click on the "Action" menu and click "Add Legacy Hardware" 9 | 10 | 4. Select "Add hardware from a list (Advanced)" and then select Display adapters 11 | 12 | 5. Click "Have Disk..." and click the "Browse..." button. Navigate to the extracted files and select the inf file. 13 | 14 | 6. You are done! Go to display settings to customize the resolution of the additional displays. These displays show up in Oculus and should be able to be streamed from. -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/option.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 1920, 1080, 60 3 | 1920, 1080, 75 4 | 1920, 1080, 90 5 | 1920, 1080, 120 6 | 1920, 1080, 144 7 | 1920, 1080, 165 8 | 1920, 1080, 240 9 | 1920, 1080, 480 10 | 640, 480, 60 11 | 800, 600, 60 12 | 1024, 768, 60 13 | 1152, 864, 60 14 | 1280, 600, 60 15 | 1280, 720, 60 16 | 1280, 768, 60 17 | 1280, 800, 60 18 | 1280, 960, 60 19 | 1280, 1024, 60 20 | 1360, 768, 60 21 | 1366, 768, 60 22 | 1400, 1050, 60 23 | 1440, 900, 60 24 | 1600, 900, 60 25 | 1680, 1050, 60 26 | 1600, 1024, 60 27 | 1920, 1200, 60 28 | 1920, 1440, 60 29 | 2560, 1440, 60 30 | 2560, 1440, 120 31 | 2560, 1440, 144 32 | 2560, 1440, 165 33 | 2560, 1440, 240 34 | 2560, 1600, 60 35 | 2732, 2048, 60 36 | 2880, 1620, 60 37 | 2880, 1800, 60 38 | 3008, 1692, 60 39 | 3200, 1800, 60 40 | 3200, 2400, 60 41 | 3840, 2160, 60 42 | 3840, 2160, 120 43 | 3840, 2160, 144 44 | 3840, 2160, 165 45 | 3840, 2160, 240 46 | 3840, 2400, 60 47 | 4096, 2304, 60 48 | 4096, 2560, 60 49 | 5120, 2880, 60 50 | 6016, 3384, 60 51 | 7680, 4320, 60 52 | 2560, 1080, 60 53 | 2880, 1200, 60 54 | 3440, 1440, 60 55 | 3440, 1440, 120 56 | 3840, 1600, 60 57 | 4320, 1800, 60 58 | 5120, 2160, 60 59 | 5760, 2400, 60 60 | 6880, 2880, 60 61 | 7680, 3200, 60 62 | 8640, 3600, 60 63 | 3840, 1080, 60 64 | 3840, 1200, 60 65 | 4320, 1200, 60 66 | 5120, 1440, 60 67 | 5120, 1600, 60 68 | 5760, 1600, 60 69 | 5760, 1800, 60 70 | 6400, 1800, 60 71 | 6480, 1800, 60 72 | 7680, 2160, 60 73 | 7680, 2400, 60 74 | 8640, 2400, 60 75 | 2388, 1668, 60 76 | 2400, 1080, 60 77 | 3456, 2234, 60 78 | -------------------------------------------------------------------------------- /Virtual Display Driver (HDR)/vdd_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1 5 | 6 | 7 | default 8 | 9 | 10 | 11 | 800 12 | 600 13 | 30 14 | 60 15 | 90 16 | 120 17 | 144 18 | 165 19 | 20 | 21 | 1366 22 | 768 23 | 30 24 | 60 25 | 90 26 | 120 27 | 144 28 | 165 29 | 30 | 31 | 1920 32 | 1080 33 | 30 34 | 60 35 | 90 36 | 120 37 | 144 38 | 165 39 | 40 | 41 | 2560 42 | 1440 43 | 30 44 | 60 45 | 90 46 | 120 47 | 144 48 | 165 49 | 50 | 51 | 3840 52 | 2160 53 | 30 54 | 60 55 | 90 56 | 120 57 | 144 58 | 165 59 | 60 | 61 | 62 | 63 | 64 | false 65 | false 66 | false 67 | true 68 | false 69 | false 70 | false 71 | 72 | false 73 | 74 | 75 | 76 | 77 | 78 | --------------------------------------------------------------------------------