Compare commits

...
Author SHA1 Message Date
Bud cb98721da4 Update README.md 2024-12-24 17:50:07 +00:00
Bud 3e65bc8749 23H2, ITS 23H2!!!
1.10 	0x1A00 	Add HDR10 and SDR Wide Color Gamut (WCG) support - Windows 11 23H2
2024-12-22 17:11:54 +00:00
Bud 8de4f3b000 Update Submit-To-SignPath.yml 2024-12-20 00:09:37 +00:00
Bud 79810cb48d allow arm64 2024-12-19 16:16:15 +00:00
Bud a3564fbf01 Action Tweak
Action tweak
2024-12-19 13:21:28 +00:00
Bud 6c125361ac Action tweak 2024-12-19 13:19:06 +00:00
Mike Rodriguez 266b4a01c3 Merge pull request #217 from zjoasan/patch-1
Update toggle-VDD.ps1
2024-12-17 06:54:32 -08:00
Bud 0d36d2a655 workflow on pr
Added trigger workflow on pr creation to make sure no conflicting code
2024-12-17 14:54:23 +00:00
Bud 5dc87774c5 Fixed Error checking in yml
Sometimes installing dependencies dont work for some reason 🤷🏻‍♂️
2024-12-17 14:18:55 +00:00
Bud 68b92409a6 Moved rest of signpath to variables 2024-12-17 14:08:44 +00:00
Joakim Sandström 80861064e8 Update toggle-VDD.ps1
Supporting old and new driver
2024-12-17 14:50:26 +01:00
Joakim Sandström 2fd04a231b Update toggle-VDD.ps1
Changed the Friendlyname of the driver, script was OLD
2024-12-17 13:52:26 +01:00
Mike Rodriguez 1ef82c3e6a Update Submit-To-SignPath.yml 2024-12-17 04:23:22 -08:00
Bud 3895ea6b4b Upload signpath signed to github artifacts 2024-12-15 16:18:40 +00:00
Bud 13bb8cc323 json release param 2024-12-15 11:00:48 +00:00
Bud f9f95e319c Changed names to make it easier 2024-12-15 10:23:06 +00:00
Bud 22535e68de Uploaded manual workflow dispatching to signpath 2024-12-15 10:22:02 +00:00
Bud fc73feaa47 Update compile.yml 2024-12-14 10:30:46 +00:00
Bud 698c735bdf Fixed Silly mistake on action workflow 2024-12-14 10:29:10 +00:00
Bud 9cb856f645 Removed Debug 2024-12-14 09:45:15 +00:00
Bud cdc9ed24d3 Build workflow (W/o signpath)
- Without sign path to make sure build works
- Workflow on dispatch ( save on vm time)
2024-12-13 21:59:23 +00:00
Mike Rodriguez 9f90a294ee Create LICENSE 2024-12-09 23:41:29 -08:00
Bud 2f3f3c044c Update README.md 2024-12-04 23:10:15 +00:00
Bud 63c3899826 Added global refreshrates
XML function will be re-written soon

left 30hz in each one just to make it easier if users want to add per resolution
2024-12-03 21:40:00 +00:00
Bud a28ec0eb51 Pipe function Update 2024-12-03 12:54:21 +00:00
Bud d03bf38ff6 LUID with log text (In case multiple gpus) 2024-12-02 09:47:57 +00:00
Bud 4bc7e80234 Update README.md 2024-12-01 01:29:58 +00:00
Bud 25a53cab3a Update README.md 2024-12-01 01:28:44 +00:00
Mike Rodriguez 88d36bc1b5 Removed script. 2024-11-23 20:26:16 -08:00
Mike Rodriguez 68712353e3 Updated Display Preview build to reduce size and dependencies. 2024-11-23 20:14:02 -08:00
Mike Rodriguez ec5c792903 Removed requirement for FFMPEG dependency. 2024-11-23 20:07:56 -08:00
Mike Rodriguez 5573a5f24f Maintain screen aspect ratios. 2024-11-23 19:39:09 -08:00
Mike Rodriguez 73007aefab Removed Dist. 2024-11-23 16:40:24 -08:00
Mike Rodriguez df6395d96a Delete DisplayPreview.7z 2024-11-23 16:39:57 -08:00
Mike Rodriguez 9d64535682 Update README.md 2024-11-23 16:36:15 -08:00
Mike Rodriguez 3d025bbe3e Create README.md 2024-11-23 16:34:37 -08:00
Mike Rodriguez 4f391cde0a Added Display Preview (Early Beta) 2024-11-23 16:32:03 -08:00
Bud 532d16317f Pipe Update + Options fix
- Added pipe settings for setting gpu & setting display count
- Fixed sdr10bit toggle in pipe
- Took option.txt out of loop
- If options.txt is empty then fallback on driver to prevent error
2024-11-02 15:23:16 +00:00
Bud 8d28e02634 Update README.md 2024-10-27 09:09:04 +00:00
Bud 15c7136651 Updated Pipe
- Pipe updated for new options
- Explained why I left logging disabled even if logs are disabled (Its to delete the log folder if logs are live disabled via the pipe)
2024-10-27 08:26:42 +00:00
Bud 39ecdb0385 Moved log query out of logging function
- Removed log query inside of logging function to prevent unnecessary function calls. This will mean you NEED to restart adapter in order for logs to enable however this is done in favour of performance

- Support for live changing moved to companion app only due to above reasons
2024-10-27 06:37:17 +00:00
Bud 978d62abe8 Wide colour space
Ensure driver sets both IDDCX_TARGET_CAPS_HIGH_COLOR_SPACE and IDDCX_TARGET_CAPS_WIDE_COLOR_SPACE. Supporting high colour space requires handling gamut functionality and appropriate transfer curves for displays.

(Aka having High caps colour space means we already have support for wide colour space and high colour space is not a replacement for wide colour space therefore we should also set wide colour space)
2024-10-26 10:04:14 +01:00
Bud 6da06791a5 Added cea extension override
- When enabled this will force the custom edid to be 256 bytes enabling cea-extension features built into the hardcoded edid block.

For example: When emulating an old display (for example: Acer FP751 analogue display 128 bytes) it will force the display to have a cea extension to keep the HDR Feature (256 bytes)

Note: As of now, this will remove any other cea extensions from edids which are 256 bytes in size. This should only be used to force HDR Capability onto virtual monitors
2024-10-25 07:42:47 +01:00
Bud ce6e51fa54 Added support to prevent spoof
- Added support to prevent manufacturer spoofing (This may help in some cases)
2024-10-25 06:30:04 +01:00
Mike Rodriguez 6655bcffc0 Delete .github/CONTRIBUTORS.yml 2024-10-20 00:29:17 -07:00
Mike Rodriguez fc54221dd3 Create CONTRIBUTORS.yml 2024-10-20 00:27:09 -07:00
Bud 22d12a29fc - added log iddcx version to pipe 2024-10-20 05:01:52 +01:00
Bud 2b2794611a - Added default
- Just prevents the pipe from messing up xml when changing values
2024-10-20 04:42:27 +01:00
Bud d65a9cda83 Transitioned code base to VirtualDisplayDriver from sample
- Moving away from being a sample
2024-10-20 04:08:00 +01:00
Bud cf9d5e9a06 Added SDR10 Warning
- When both SDR10-bit and HDRPlus are enabled, there’s a conflict because the display system cannot simultaneously handle both high dynamic range 12-bit and standard dynamic range 10-bit settings. This results in the system defaulting to HDR10-bit, the closest compatible setting, to maintain some level of HDR capability without completely reverting to SDR. It’s a compromise to ensure compatibility and functionality.
2024-10-20 03:56:24 +01:00
Bud e8a25180d6 Added defaults
This should never matter, but just in case
2024-10-20 03:20:14 +01:00
Bud 08ecea131d - Added SDR 10 bit support
- Added SDR 10 bit support to allow for 10 bit without HDR
- Adjusted code to use queries instead of if statements
2024-10-20 03:14:30 +01:00
Bud 47bc4acf91 - Query Optimisations
- Added query optimisations
- Switched to maps for queries
2024-10-20 02:57:21 +01:00
Bud e65c36ec5f - Pipe Update + Optimisations
- Updated Pipe to have PING Function which returns PONG to buffer
- Added new Send To Pipe Function
- Optimised toggling between HDR+ and hdr
2024-10-20 00:55:42 +01:00
Bud d27adb9539 Capital B because it’s been annoying me :) 2024-10-18 13:55:42 +01:00
Bud c38f348740 Pipe Controls updated
- Added dedicated reload driver function with hpipe
- Added HDR+ Toggle to pipe
- Added Custom Edid toggle to pipe
- Added hardware Cursor toggle to pipe

- Added logging unknown command is false pipe command is retrieved to provide mode log support
2024-10-17 18:28:07 +01:00
Bud 72cc4d23d2 Added Direct3D Feature levels
- Added feature levels to improve compatibility to prevent it from choosing highest available feature set
- Added TESTING into log function for temp testing or function which should not be called for user environment
2024-10-17 18:02:58 +01:00
Mike Rodriguez be01feae42 Update README.md 2024-10-16 00:47:51 -07:00
Mike Rodriguez ecef4b9c22 Update README.md 2024-10-16 00:46:43 -07:00
Mike Rodriguez 31dfd6d41d Update README.md 2024-10-16 00:46:02 -07:00
Mike Rodriguez e0a8343b77 Update README.md 2024-10-16 00:45:31 -07:00
Mike Rodriguez d01f5f7734 Update README.md 2024-10-16 00:43:40 -07:00
Bud 4723b29257 Toggle for hardware cursor 2024-10-16 08:26:54 +01:00
Bud f96c5940fc Update README.md 2024-10-16 08:08:38 +01:00
Bud 2a8081d6d4 Added ARM64 Support
- Properly added ARM64 Support
2024-10-16 01:02:37 +01:00
Bud c89559acf7 Added floating point refresh rates
Added floating point refresh rates
(Easier for users than fractional)
Added floating point refresh rates for HDR too (Second target modes
2024-10-16 00:10:47 +01:00
Bud 2d3749635b Custom Edid Support
- Added custom edid support
- Toggle edid in xml or master in registry
- Live edid modification to easily identify emulated displays
- Checksum checks to make sure data isn't corrupt
- Converted edid to static vector instead to allow custom edid
2024-10-15 22:43:23 +01:00
Bud 2bfbb0e043 HDR+ Toggle
- Added support for HDR10+ support toggle in xml (12 bit depth)
- Added xml as resource file (Easier to edit)
2024-10-15 20:49:54 +01:00
Bud 76f6893d69 Update README.md 2024-10-15 18:59:20 +01:00
Bud 82ee302db4 HWCursor + others
- Changed EndPointDiagnostics to Virtual display driver
- Remove re-initialise of confpath
- Added hardware Cursor
- Changed path to VirtualDisplayDriver from IddSampleDriver
- Removed broken log logging in old directory
2024-10-15 18:32:46 +01:00
Mike Rodriguez c4045b7c79 Update README.md 2024-10-09 20:19:37 -07:00
Bud 9abbcd1270 Merge pull request #165 from zjoasan/namechange
Renaming
2024-10-10 03:17:13 +01:00
Bud e889902057 Removed old windows 10 build (In favour of universal)
RIP Non-HDR build
2024-10-10 03:15:21 +01:00
Bud 4c31aae067 Changed wording to avoid confusion README.md 2024-10-09 07:10:46 +01:00
Bud 97f06feb43 Update README.md
Clearer warning to download correct version
2024-10-09 05:15:47 +01:00
Bud a918f82607 Post build options for nonhdr 2024-10-09 02:54:52 +01:00
Joakim Sandström 54380dddee enhancement in label for feature request.
Update feature_request.yml
squashed and merge
2024-10-09 02:42:28 +01:00
Bud 354dde53f6 Updated Bug report 2024-10-08 17:03:36 +01:00
Mike Rodriguez 796d737969 Merge pull request #169 from zjoasan/isstempl
Fresh templates, bug and feature request
2024-10-08 00:42:52 -07:00
Mike Rodriguez ba44d43e6e Merge pull request #167 from zjoasan/scripts
Updated Scripts
2024-10-08 00:42:17 -07:00
Mike Rodriguez f476bedae9 Delete Community Scripts/README.md 2024-10-08 00:42:06 -07:00
Mike Rodriguez be5d4044e5 Delete AUTHORS.md 2024-10-08 00:37:26 -07:00
Mike Rodriguez db81ae9a5a Create AUTHORS.md 2024-10-08 00:37:12 -07:00
Mike Rodriguez b564dfdda2 Delete .github/AUTHORS.md 2024-10-08 00:36:55 -07:00
Mike Rodriguez 3c82dc1d84 Create AUTHORS.md 2024-10-08 00:35:50 -07:00
Mike Rodriguez 9630f90bba Create README.md 2024-10-08 00:26:17 -07:00
Mike Rodriguez e79a2fff9f Rename readme.md to README.md 2024-10-08 00:25:20 -07:00
Mike Rodriguez fcacb8fe40 Create README.md 2024-10-08 00:24:39 -07:00
Mike Rodriguez 5a04c82cbd Transition to Universal Driver in source. Clean-up of unused content. 2024-10-08 00:16:58 -07:00
Bud 116e72c0a9 Updated Post Build Options 2024-10-08 02:57:43 +01:00
Joakim Sandström 7b8b0daee2 Fresh templates, bug and feature request
Based on the github(beta) form-templates, mught add a free type later
2024-10-07 18:59:43 +02:00
Joakim Sandström 2b9e65edaf Create README.md
For users
2024-10-07 01:38:37 +02:00
Joakim Sandström 2290b1368b Fixed debug compile error
FileDigest and PreproccessorDefinaitionsw
2024-10-07 01:14:00 +02:00
Joakim Sandström f0f70d12c8 Compiled now
Had to change the path variable to a wide (L)
2024-10-07 00:46:26 +02:00
Joakim Sandström bd5992a49c Forgot inf rename, and build trial of non-hdr
Still not building due to Adapteroption::load in driver.cpp and adapteroption.h.

Feel not as vital as hdr, so PR non building.
2024-10-06 23:48:49 +02:00
Joakim Sandström c2622b1208 Renameing and buildt 2024-10-06 23:28:59 +02:00
Mike Rodriguez 52d9d7ad2e Update README.md
New beta release.
2024-10-06 05:21:22 -07:00
Joakim Sandström a92c69c37f A few scripts
Don't remember if this is for which manufacture name theses were, but if you know powershell you can easily changge the lnx000 to mttvdd or vice versa (this info is from memory, been awhile since i did the scripts)
2024-10-06 04:06:13 +02:00
Bud a1adb08f0d Fixed Folder output of previous commit 2024-10-03 12:36:37 +01:00
Bud b42b774af1 Logging off by default 2024-10-03 12:34:20 +01:00
Bud 1168e1d9d5 Copy XML to build output 2024-10-03 12:33:11 +01:00
Bud ad9693a667 Updated code to c++ 17
- Updated the code to c++
- Removed codecvt
- Added built in function for converting wstring to string for logging
- changed failed to read reg to a warning instead of info
2024-09-26 14:52:52 +01:00
Bud d1f762ee5d Pipe Pushed + Logging + Updated XML with new options
Works in testing
2024-09-18 13:50:09 +01:00
Mike Rodriguez 0db50a948e Merge pull request #149 from zjoasan/ReadMe-uninstall-update
Updaterd uninstall to mention safemode
2024-09-11 06:00:37 -07:00
Mike Rodriguez faec71ff99 Add files via upload 2024-09-11 05:59:28 -07:00
Mike Rodriguez 3e1af20b7d Update README.md 2024-09-11 05:58:42 -07:00
Mike Rodriguez 70cbbdfa88 Update README.md 2024-09-11 05:58:00 -07:00
Mike Rodriguez ba57a9f150 Update README.md 2024-09-11 05:56:33 -07:00
Mike Rodriguez 282959aa2b Update README.md 2024-09-05 16:06:37 -07:00
Joakim Sandström 224f2a05d4 Update README.md
Made enumeration of line was correct
2024-08-31 10:59:00 +02:00
Joakim Sandström 58a942f7be Update README.md
Added extra instructions to try in safemode if uninstall still left Virtual displays.
2024-08-31 10:54:03 +02:00
Mike Rodriguez 3d8bd68f05 Update README.md 2024-08-06 09:50:49 -07:00
Bud 7670fb9f5c GPU fallback and XML + EDID update
GPU fallback and XML + EDID update
2024-08-06 17:20:39 +01:00
Bud b18c2e99a7 Corrected tuple locations + added 165 hz again 2024-08-06 16:27:46 +01:00
Bud de33359baf remove unnecessary standard definition 2024-08-04 17:20:43 +01:00
Joakim Sandström 540ad48f26 Here is the whole bit working
Checks for Regkey:
HKLM\SOFTWARE\MikeTheTech\VirtualDisplayDriver\VDDPATH  which is a D-word containing the install path. (tested)

if not exist, fall back to install path = C:\\IddSampleDriver (tested)

Next looks in install path for xml, grabs data and starts. If xml is missing, look for options.txt and adapter.txt, if any txt file is missing sane defaults are added.

EDID has HDR data and 1600 nits, and newer names.

NOTE!!!
Any installer should replace %fullpath% with install path:
"reg add "HKLM\SOFTWARE\MikeTheTech\VirtualDisplayDriver" /v VDDPATH /t REG_SZ /d "%fullpath%" /f"
2024-07-31 23:36:07 +02:00
Joakim Sandström a8742af494 ops options txt
wrong filename in load
2024-07-30 21:36:48 +02:00
Joakim Sandström a04f2ddbee Rest of loadsettings
loadsettings completed and loadoptions removed
2024-07-30 21:04:45 +02:00
Joakim Sandström 41f9d6a1a0 GPU fallback and XML
Here is the changes I did to AdapterOptions.xml and Driver.cpp, To read settings xml and insert it into AdapterOptions.H from xmlvalue.
if xml is not found, search for adapter.txt.

if wrong GPU name in either, autoselect the best one (vram based)

loadsettings is meant to replace loadoptions, but is missing alot of code since ths is the order you asked me to present it. So no fallbck for missing xml or options.tx in this pr
2024-07-27 10:28:41 +02:00
Mike Rodriguez 7d13448595 Update README.md 2024-07-19 03:59:11 -07:00
Mike Rodriguez 7ffb7c34e0 Update README.md 2024-07-19 03:58:50 -07:00
Mike Rodriguez ada3f545f8 Update README.md 2024-07-19 03:57:55 -07:00
Mike Rodriguez 191bfaff5c Merge branch 'master' of https://github.com/itsmikethetech/Virtual-Display-Driver 2024-07-19 02:22:38 -07:00
Mike Rodriguez de85ea2b41 First update to support 10/11 in a single driver. 2024-07-19 02:22:34 -07:00
Mike Rodriguez bb671c2375 Update README.md 2024-07-18 22:26:21 -07:00
Mike Rodriguez 001b869de9 Update README.md 2024-07-18 22:24:33 -07:00
Mike Rodriguez 23e991bb39 Update README.md 2024-05-29 16:22:33 -07:00
Mike Rodriguez a27ae38d60 Update README.md 2024-05-29 16:22:14 -07:00
Mike Rodriguez be9433b7a3 Update README.md 2024-05-29 16:21:57 -07:00
Mike Rodriguez 24fe31b934 Update README.md 2024-05-29 16:21:18 -07:00
Mike Rodriguez c733e68325 Update README.md 2024-05-29 16:20:49 -07:00
Mike Rodriguez 519936dbd9 Merge pull request #96 from Sajidur78/master
Add support for picking render adapter
2024-05-29 16:04:50 -07:00
Sajid 3e911fa113 Add support for picking render adapter 2024-05-29 01:59:41 +06:00
Mike Rodriguez c391cddfa8 Update FUNDING.yml 2024-05-12 04:03:08 -07:00
Mike Rodriguez a3aa68f5a1 Added VDD Panel Base 2024-04-27 01:34:08 -07:00
Mike Rodriguez 132528a678 Create readme.md 2024-04-22 01:10:18 -07:00
Mike Rodriguez 8b1992e028 Added installer folders. 2024-04-22 00:47:12 -07:00
Mike Rodriguez dc34d7d472 Added GMS2 prototype installer. Not yet complete. 2024-04-22 00:43:47 -07:00
Mike Rodriguez 8df9e6c2fb Merge branch 'master' of https://github.com/itsmikethetech/Virtual-Display-Driver 2024-04-22 00:41:26 -07:00
Mike Rodriguez 85c56c3e69 Reorganization 2024-04-22 00:41:18 -07:00
131 changed files with 6947 additions and 5807 deletions

No files matched your search

+1 -1
View File
@@ -1,3 +1,3 @@
# These are supported funding model platforms
github: [itsmikethetech, zjoasan, bud3699]
github: [itsmikethetech, zjoasan]
+94
View File
@@ -0,0 +1,94 @@
name: Bug Report
description: File a bug report.
title: "[Bug]: "
labels: ["bug", "triage"]
assignees: ["zjoasan", "bud3699", "itsmikethetech"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
- type: dropdown
id: OS
attributes:
label: Which OS?
description: What version of Windows are you running?
options:
- Win11 Pro
- Win11 Home
- Win10 Pro
- Win10 Home
- Other..
default: 0
validations:
required: true
- type: dropdown
id: Version
attributes:
label: Which release?
description: What version of Windows are you running?
options:
- 24H2
- 23H2
- 22H2
- 21H2
- 1809
- 1607
- 1507
- Other..
default: 0
validations:
required: true
- type: markdown
attributes:
value: |
If you struggle finding windows edition and version, Go to settings -> system -> about. Under windows specifications.
- type: textarea
id: bug-info
attributes:
label: Describe the bug
description: Free text description.
placeholder: |
Tell us what you see!
A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: reproduce-info
attributes:
label: Steps to reproduce
description: And if you can how to reproduce
placeholder: |
Tell us how to reproduce!
Go to '...', 2. Click on '....', and so on.
validations:
required: false
- type: textarea
id: expected-info
attributes:
label: Expected behavior
description: Please inform us about expected behavior.
placeholder: |
Description of behavior!
When i Clicked...
validations:
required: false
- type: textarea
id: log-file
attributes:
label: Log File (Beta Only)
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.
placeholder: Drag and drop the log file here or click to upload.
validations:
required: false
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
@@ -0,0 +1,38 @@
name: Feature Request
description: Request a new Feature.
title: "[Feature]: "
labels: ["remove", "customize", "companion", "enhancement", "newcode"]
assignees: ["zjoasan", "bud3699", "itsmikethetech"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this feature request report!
- type: textarea
id: frprob
attributes:
label: Is the feature related to a "problem"?
description: Describe the problem, in detail.
placeholder: Tell us how to reproduce
value: "When start X I wish to.."
validations:
required: true
- type: textarea
id: your-solution
attributes:
label: Your suggestion
description: Describe what would solve your problem, as detailed as possible.
placeholder: Tell us how to progress!
value: "Disable a specific VD via hotkey"
validations:
required: true
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
+141
View File
@@ -0,0 +1,141 @@
name: Virtual Display Driver Signpath Request
on:
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
configuration: [Release]
platform: [x64, ARM64]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1
- name: Check Chocolatey installation
run: choco --version
- name: Install Visual Studio 2022 dependencies
run: |
choco install visualstudio2022-workload-manageddesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-nativedesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-vctools -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install windowsdriverkit11 -y
if ($LASTEXITCODE -ne 0) { exit 1 }
- name: Build the driver
run: |
msbuild "Virtual Display Driver (HDR)/MTTVDD.sln" /p:Configuration=${{ matrix.configuration }} /p:Platform=${{ matrix.platform }}
- name: List build directory
run: dir "Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD"
- name: Upload built driver
id: upload_artifact
uses: actions/upload-artifact@v4
with:
name: Built-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.dll
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.inf
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\mttvdd.cat
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\vdd_settings.xml
- name: Generate release tag
id: generate_tag
run: |
$releaseTag = (Get-Date).ToString('yy.MM.dd')
echo "RELEASE_TAG=$releaseTag" >> $env:GITHUB_ENV
- name: Show generated release tag
run: |
echo "Generated Release Tag: ${{ env.RELEASE_TAG }}"
- name: Verify Built Artifacts
run: dir 'Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD'
- name: Submit signing request to SignPath
id: signpath_request
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
project-slug: '${{ vars.SIGNPATH_PROJECT_SLUG }}'
signing-policy-slug: '${{ vars.SIGNPATH_POLICY_SLUG }}'
github-artifact-id: '${{ steps.upload_artifact.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '${{ vars.SIGNPATH_OUTPUT_DIR }}'
parameters: |
Version: ${{ toJSON(matrix.configuration) }}
Release_Tag: "${{ env.RELEASE_TAG }}"
- name: Verify Signed Artifacts
run: dir '${{ vars.SIGNPATH_OUTPUT_DIR }}'
- name: Upload signed artifacts
id: upload_signed_artifacts
uses: actions/upload-artifact@v4
with:
name: Signed-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
${{ vars.SIGNPATH_OUTPUT_DIR }}\MttVDD.dll
${{ vars.SIGNPATH_OUTPUT_DIR }}\MttVDD.inf
${{ vars.SIGNPATH_OUTPUT_DIR }}\mttvdd.cat
${{ vars.SIGNPATH_OUTPUT_DIR }}\vdd_settings.xml
- name: Prepare Setup Repository
run: |
git clone https://${{ secrets.READ_REPO }}@github.com/VirtualDisplay/vdd-innosetupscript.git inno-setup
- name: Prepare Setup
run: |
copy "${{ vars.SIGNPATH_OUTPUT_DIR }}\*" inno-setup\input\
$platform = "${{ matrix.platform }}"
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace '1.0.0', '${{ env.RELEASE_TAG }}' } |
Set-Content "inno-setup\Setup.iss"
if ($platform -eq 'ARM64') {
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace 'x64compatible', 'arm64' } |
Set-Content "inno-setup\Setup.iss"
(Get-Content "inno-setup\Setup.iss") |
ForEach-Object { $_ -replace '-x64', '-arm64' } |
Set-Content "inno-setup\Setup.iss"
if (Test-Path "inno-setup\input\Companion\VDDSysTray.exe") {Remove-Item "inno-setup\input\Companion\VDDSysTray.exe"}
copy "inno-setup\input\Companion\arm64\VDDSysTray.exe" "inno-setup\input\Companion\"
}
- name: Compile Installer
uses: Minionguyjpro/Inno-Setup-Action@v1.2.2
with:
path: inno-setup\Setup.iss
options: /O+
- name: Upload Installer as artifact
uses: actions/upload-artifact@v4
with:
name: Installer-${{ matrix.configuration }}-${{ matrix.platform }}
path: inno-setup\output\*.exe
celebrate:
runs-on: ubuntu-latest
steps:
- name: Celebrate
run: |
echo "Bud is a god, also hi if you're looking at this!"
+73
View File
@@ -0,0 +1,73 @@
name: Virtual Display Driver Building
on:
workflow_dispatch:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
configuration: [Debug, Release]
platform: [x64, ARM64]
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup MSBuild
uses: microsoft/setup-msbuild@v1
- name: Check Chocolatey installation
run: choco --version
- name: Install Visual Studio 2022 dependencies
run: |
choco install visualstudio2022-workload-manageddesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-nativedesktop -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install visualstudio2022-workload-vctools -y
if ($LASTEXITCODE -ne 0) { exit 1 }
choco install windowsdriverkit11 -y
if ($LASTEXITCODE -ne 0) { exit 1 }
- name: Build the driver
run: |
msbuild "Virtual Display Driver (HDR)/MTTVDD.sln" /p:Configuration=${{ matrix.configuration }} /p:Platform=${{ matrix.platform }}
- name: List build directory
run: dir "Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD"
- name: Upload built driver
id: upload_artifact
uses: actions/upload-artifact@v4
with:
name: Built-Driver-${{ matrix.configuration }}-${{ matrix.platform }}
path: |
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.dll
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\MttVDD.inf
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\mttvdd.cat
Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD\vdd_settings.xml
- name: Generate release tag
id: generate_tag
run: |
$releaseTag = (Get-Date).ToString('yy.MM.dd')
echo "RELEASE_TAG=$releaseTag" >> $env:GITHUB_ENV
- name: Show generated release tag
run: |
echo "Generated Release Tag: ${{ env.RELEASE_TAG }}"
- name: Verify Built Artifacts
run: dir 'Virtual Display Driver (HDR)\${{ matrix.platform }}\${{ matrix.configuration }}\MttVDD'
+129
View File
@@ -0,0 +1,129 @@
#pragma once
#include <wrl/client.h> // For ComPtr
#include <dxgi.h> // For IDXGIAdapter, IDXGIFactory1
#include <algorithm> // For sort
using namespace std;
using namespace Microsoft::WRL;
// Structure to vector gpus
struct GPUInfo {
wstring name; // GPU name
ComPtr<IDXGIAdapter> adapter;// COM pointer to the adapter
DXGI_ADAPTER_DESC desc; // Adapter description
};
// Sort function for GPUs by dedicated video memory
bool CompareGPUs(const GPUInfo& a, const GPUInfo& b) {
return a.desc.DedicatedVideoMemory > b.desc.DedicatedVideoMemory;
}
// Get a enumerate list of available GPUs
vector<GPUInfo> getAvailableGPUs() {
vector<GPUInfo> gpus; // Vector to hold all GPU's information
ComPtr<IDXGIFactory1> factory;
if (!SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(&factory)))) {
return gpus;
}
// Enumerate all adapters (GPUs)
for (UINT i = 0;; i++) {
ComPtr<IDXGIAdapter> adapter;
if (!SUCCEEDED(factory->EnumAdapters(i, &adapter))) {
break;
}
DXGI_ADAPTER_DESC desc;
if (!SUCCEEDED(adapter->GetDesc(&desc))) {
continue;
}
// Add the adapter information to the list
GPUInfo info{ desc.Description, adapter, desc };
gpus.push_back(info);
}
return gpus;
}
class AdapterOption {
public:
bool hasTargetAdapter{}; // Indicates if a target adapter is selected
LUID adapterLuid{}; // Adapter's unique identifier (LUID)
wstring target_name{}; // Target adapter name
// Select the best GPU based on dedicated video memory
wstring selectBestGPU() {
auto gpus = getAvailableGPUs();
if (gpus.empty()) {
return L""; // Error check for headless / vm
}
// Sort GPUs by dedicated video memory in descending order
sort(gpus.begin(), gpus.end(), CompareGPUs);
auto bestGPU = gpus.front(); // Get the GPU with the most memory
return bestGPU.name;
}
// Load friendlyname from a file OR select the best GPU
void load(const wchar_t* path) {
ifstream ifs{ path };
if (!ifs.is_open()) {
target_name = selectBestGPU();
}
else {
string line;
getline(ifs, line);
target_name.assign(line.begin(), line.end());
}
// Find and set the adapter based on the target name
if (!findAndSetAdapter(target_name)) {
// If the adapter is not found, select the best GPU and retry
target_name = selectBestGPU();
findAndSetAdapter(target_name);
}
}
// Set the target adapter from a given name and validate it
void xmlprovide(const wstring& xtarg) {
target_name = xtarg;
if (!findAndSetAdapter(target_name)) {
// If the adapter is not found, select the best GPU and retry
target_name = selectBestGPU();
findAndSetAdapter(target_name);
}
}
// Apply the adapter settings to the specified adapter
void apply(const IDDCX_ADAPTER& adapter) {
if (hasTargetAdapter && IDD_IS_FUNCTION_AVAILABLE(IddCxAdapterSetRenderAdapter)) {
IDARG_IN_ADAPTERSETRENDERADAPTER arg{};
arg.PreferredRenderAdapter = adapterLuid;
IddCxAdapterSetRenderAdapter(adapter, &arg);
}
}
private:
// Find and set the adapter by its name
bool findAndSetAdapter(const wstring& adapterName) {
auto gpus = getAvailableGPUs();
// Iterate through all available GPUs
for (const auto& gpu : gpus) {
if (_wcsicmp(gpu.name.c_str(), adapterName.c_str()) == 0) {
adapterLuid = gpu.desc.AdapterLuid; // Set the adapter LUID
hasTargetAdapter = true; // Indicate that a target adapter is selected
return true;
}
}
hasTargetAdapter = false; // Indicate that no target adapter is selected
return false;
}
};
+1
View File
@@ -0,0 +1 @@
Required include(s). Plans to combine it into the driver to reduce includes.
+1
View File
@@ -0,0 +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.
@@ -0,0 +1,202 @@
# Rules in this file were initially inferred by Visual Studio IntelliCode from the Template Studio codebase.
# You can modify the rules from these initially generated values to suit your own policies.
# You can learn more about editorconfig here: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference.
[*.cs]
#Core editorconfig formatting - indentation
#use soft tabs (spaces) for indentation
indent_style = space
#Formatting - new line options
#place else statements on a new line
csharp_new_line_before_else = true
#require braces to be on a new line for lambdas, methods, control_blocks, types, properties, and accessors (also known as "Allman" style)
csharp_new_line_before_open_brace = all
#Formatting - organize using options
#sort System.* using directives alphabetically, and place them before other usings
dotnet_sort_system_directives_first = true
#Formatting - spacing options
#require NO space between a cast and the value
csharp_space_after_cast = false
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_after_colon_in_inheritance_clause = true
#require a space after a keyword in a control flow statement such as a for loop
csharp_space_after_keywords_in_control_flow_statements = true
#require a space before the colon for bases or interfaces in a type declaration
csharp_space_before_colon_in_inheritance_clause = true
#remove space within empty argument list parentheses
csharp_space_between_method_call_empty_parameter_list_parentheses = false
#remove space between method call name and opening parenthesis
csharp_space_between_method_call_name_and_opening_parenthesis = false
#do not place space characters after the opening parenthesis and before the closing parenthesis of a method call
csharp_space_between_method_call_parameter_list_parentheses = false
#remove space within empty parameter list parentheses for a method declaration
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
#place a space character after the opening parenthesis and before the closing parenthesis of a method declaration parameter list.
csharp_space_between_method_declaration_parameter_list_parentheses = false
#Formatting - wrapping options
#leave code block on separate lines
csharp_preserve_single_line_blocks = false
#Style - Code block preferences
#prefer curly braces even for one line of code
csharp_prefer_braces = true:suggestion
#Style - expression bodied member options
#prefer expression bodies for accessors
csharp_style_expression_bodied_accessors = true:warning
#prefer block bodies for constructors
csharp_style_expression_bodied_constructors = false:suggestion
#prefer expression bodies for methods
csharp_style_expression_bodied_methods = when_on_single_line:silent
#prefer expression-bodied members for properties
csharp_style_expression_bodied_properties = true:warning
#Style - expression level options
#prefer out variables to be declared before the method call
csharp_style_inlined_variable_declaration = false:suggestion
#prefer the language keyword for member access expressions, instead of the type name, for types that have a keyword to represent them
dotnet_style_predefined_type_for_member_access = true:suggestion
#Style - Expression-level preferences
#prefer default over default(T)
csharp_prefer_simple_default_expression = true:suggestion
#prefer objects to be initialized using object initializers when possible
dotnet_style_object_initializer = true:suggestion
#Style - implicit and explicit types
#prefer var over explicit type in all cases, unless overridden by another code style rule
csharp_style_var_elsewhere = true:suggestion
#prefer var is used to declare variables with built-in system types such as int
csharp_style_var_for_built_in_types = true:suggestion
#prefer var when the type is already mentioned on the right-hand side of a declaration expression
csharp_style_var_when_type_is_apparent = true:suggestion
#Style - language keyword and framework type options
#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
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
#Style - Language rules
csharp_style_implicit_object_creation_when_type_is_apparent = true:warning
csharp_style_var_for_built_in_types = true:warning
#Style - modifier options
#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.
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
#Style - Modifier preferences
#when this rule is set to a list of modifiers, prefer the specified ordering.
csharp_preferred_modifier_order = public,private,protected,internal,static,async,readonly,override,sealed,abstract,virtual:warning
dotnet_style_readonly_field = true:warning
#Style - Pattern matching
#prefer pattern matching instead of is expression with type casts
csharp_style_pattern_matching_over_as_with_null_check = true:warning
#Style - qualification options
#prefer events not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_event = false:suggestion
#prefer fields not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_field = false:suggestion
#prefer methods not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_method = false:suggestion
#prefer properties not to be prefaced with this. or Me. in Visual Basic
dotnet_style_qualification_for_property = false:suggestion
csharp_indent_labels = one_less_than_current
csharp_using_directive_placement = outside_namespace:silent
csharp_prefer_simple_using_statement = true:warning
csharp_style_namespace_declarations = file_scoped:warning
csharp_style_expression_bodied_operators = false:silent
csharp_style_expression_bodied_indexers = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
[*.{cs,vb}]
dotnet_style_operator_placement_when_wrapping = beginning_of_line
tab_width = 4
indent_size = 4
end_of_line = crlf
dotnet_style_coalesce_expression = true:suggestion
dotnet_style_null_propagation = true:suggestion
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
dotnet_style_prefer_auto_properties = true:silent
dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
dotnet_style_prefer_conditional_expression_over_return = true:silent
[*.{cs,vb}]
#Style - Unnecessary code rules
csharp_style_unused_value_assignment_preference = discard_variable:warning
#### Naming styles ####
# Naming rules
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
# Symbol specifications
dotnet_naming_symbols.interface.applicable_kinds = interface
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.interface.required_modifiers =
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.types.required_modifiers =
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
dotnet_naming_symbols.non_field_members.required_modifiers =
# Naming styles
dotnet_naming_style.begins_with_i.required_prefix = I
dotnet_naming_style.begins_with_i.required_suffix =
dotnet_naming_style.begins_with_i.word_separator =
dotnet_naming_style.begins_with_i.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.pascal_case.required_prefix =
dotnet_naming_style.pascal_case.required_suffix =
dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_style_explicit_tuple_names = true:suggestion
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
dotnet_style_prefer_compound_assignment = true:warning
dotnet_style_prefer_simplified_interpolation = true:suggestion
+16
View File
@@ -0,0 +1,16 @@
{
"version": "1.0",
"components": [
"Microsoft.Component.MSBuild",
"Microsoft.NetCore.Component.Runtime.7.0",
"Microsoft.NetCore.Component.SDK",
"Microsoft.VisualStudio.Component.ManagedDesktop.Core",
"Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites",
"Microsoft.VisualStudio.Component.NuGet",
"Microsoft.VisualStudio.Component.Windows10SDK.19041",
"Microsoft.VisualStudio.Component.Windows10SDK",
"Microsoft.VisualStudio.ComponentGroup.MSIX.Packaging",
"Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs",
"Microsoft.VisualStudio.Workload.ManagedDesktop"
]
}
@@ -0,0 +1,10 @@
namespace VDD_Panel.Core.Contracts.Services;
public interface IFileService
{
T Read<T>(string folderPath, string fileName);
void Save<T>(string folderPath, string fileName, T content);
void Delete(string folderPath, string fileName);
}
@@ -0,0 +1,22 @@
using Newtonsoft.Json;
namespace VDD_Panel.Core.Helpers;
public static class Json
{
public static async Task<T> ToObjectAsync<T>(string value)
{
return await Task.Run<T>(() =>
{
return JsonConvert.DeserializeObject<T>(value);
});
}
public static async Task<string> StringifyAsync(object value)
{
return await Task.Run<string>(() =>
{
return JsonConvert.SerializeObject(value);
});
}
}
@@ -0,0 +1,5 @@
*Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)*
## Getting Started
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).
@@ -0,0 +1,41 @@
using System.Text;
using Newtonsoft.Json;
using VDD_Panel.Core.Contracts.Services;
namespace VDD_Panel.Core.Services;
public class FileService : IFileService
{
public T Read<T>(string folderPath, string fileName)
{
var path = Path.Combine(folderPath, fileName);
if (File.Exists(path))
{
var json = File.ReadAllText(path);
return JsonConvert.DeserializeObject<T>(json);
}
return default;
}
public void Save<T>(string folderPath, string fileName, T content)
{
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
var fileContent = JsonConvert.SerializeObject(content);
File.WriteAllText(Path.Combine(folderPath, fileName), fileContent, Encoding.UTF8);
}
public void Delete(string folderPath, string fileName)
{
if (fileName != null && File.Exists(Path.Combine(folderPath, fileName)))
{
File.Delete(Path.Combine(folderPath, fileName));
}
}
}
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<RootNamespace>VDD_Panel.Core</RootNamespace>
<Platforms>AnyCPU;x64;x86</Platforms>
<Platforms>x86;x64;arm64;AnyCPU</Platforms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
</ItemGroup>
</Project>
@@ -0,0 +1,69 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34622.214
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDD Panel", "VDD Panel\VDD Panel.csproj", "{5FA23A93-E3D0-46A3-89AA-A909685E2784}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VDD Panel.Core", "VDD Panel.Core\VDD Panel.Core.csproj", "{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|arm64 = Debug|arm64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|arm64 = Release|arm64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|Any CPU.ActiveCfg = Debug|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|Any CPU.Build.0 = Debug|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|Any CPU.Deploy.0 = Debug|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|arm64.ActiveCfg = Debug|arm64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|arm64.Build.0 = Debug|arm64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|arm64.Deploy.0 = Debug|arm64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x64.ActiveCfg = Debug|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x64.Build.0 = Debug|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x64.Deploy.0 = Debug|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x86.ActiveCfg = Debug|x86
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x86.Build.0 = Debug|x86
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Debug|x86.Deploy.0 = Debug|x86
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|Any CPU.ActiveCfg = Release|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|Any CPU.Build.0 = Release|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|Any CPU.Deploy.0 = Release|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|arm64.ActiveCfg = Release|arm64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|arm64.Build.0 = Release|arm64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|arm64.Deploy.0 = Release|arm64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x64.ActiveCfg = Release|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x64.Build.0 = Release|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x64.Deploy.0 = Release|x64
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x86.ActiveCfg = Release|x86
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x86.Build.0 = Release|x86
{5FA23A93-E3D0-46A3-89AA-A909685E2784}.Release|x86.Deploy.0 = Release|x86
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|arm64.ActiveCfg = Debug|arm64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|arm64.Build.0 = Debug|arm64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x64.ActiveCfg = Debug|x64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x64.Build.0 = Debug|x64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x86.ActiveCfg = Debug|x86
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Debug|x86.Build.0 = Debug|x86
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|Any CPU.Build.0 = Release|Any CPU
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|arm64.ActiveCfg = Release|arm64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|arm64.Build.0 = Release|arm64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x64.ActiveCfg = Release|x64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x64.Build.0 = Release|x64
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x86.ActiveCfg = Release|x86
{29E3EAF5-65AE-4ACA-B550-983DBCE38E03}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {81C98471-4829-40B4-B60F-CEB2472667FC}
EndGlobalSection
EndGlobal
@@ -0,0 +1,17 @@
namespace VDD_Panel.Activation;
// Extend this class to implement new ActivationHandlers. See DefaultActivationHandler for an example.
// https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/activation.md
public abstract class ActivationHandler<T> : IActivationHandler
where T : class
{
// Override this method to add the logic for whether to handle the activation.
protected virtual bool CanHandleInternal(T args) => true;
// Override this method to add the logic for your activation handler.
protected abstract Task HandleInternalAsync(T args);
public bool CanHandle(object args) => args is T && CanHandleInternal((args as T)!);
public async Task HandleAsync(object args) => await HandleInternalAsync((args as T)!);
}
@@ -0,0 +1,51 @@
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.Windows.AppLifecycle;
using Microsoft.Windows.AppNotifications;
using VDD_Panel.Contracts.Services;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Activation;
public class AppNotificationActivationHandler : ActivationHandler<LaunchActivatedEventArgs>
{
private readonly INavigationService _navigationService;
private readonly IAppNotificationService _notificationService;
public AppNotificationActivationHandler(INavigationService navigationService, IAppNotificationService notificationService)
{
_navigationService = navigationService;
_notificationService = notificationService;
}
protected override bool CanHandleInternal(LaunchActivatedEventArgs args)
{
return AppInstance.GetCurrent().GetActivatedEventArgs()?.Kind == ExtendedActivationKind.AppNotification;
}
protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args)
{
// TODO: Handle notification activations.
//// // Access the AppNotificationActivatedEventArgs.
//// var activatedEventArgs = (AppNotificationActivatedEventArgs)AppInstance.GetCurrent().GetActivatedEventArgs().Data;
//// // Navigate to a specific page based on the notification arguments.
//// if (_notificationService.ParseArguments(activatedEventArgs.Argument)["action"] == "Settings")
//// {
//// // Queue navigation with low priority to allow the UI to initialize.
//// App.MainWindow.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
//// {
//// _navigationService.NavigateTo(typeof(SettingsViewModel).FullName!);
//// });
//// }
App.MainWindow.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
App.MainWindow.ShowMessageDialogAsync("TODO: Handle notification activations.", "Notification Activation");
});
await Task.CompletedTask;
}
}
@@ -0,0 +1,29 @@
using Microsoft.UI.Xaml;
using VDD_Panel.Contracts.Services;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Activation;
public class DefaultActivationHandler : ActivationHandler<LaunchActivatedEventArgs>
{
private readonly INavigationService _navigationService;
public DefaultActivationHandler(INavigationService navigationService)
{
_navigationService = navigationService;
}
protected override bool CanHandleInternal(LaunchActivatedEventArgs args)
{
// None of the ActivationHandlers has handled the activation.
return _navigationService.Frame?.Content == null;
}
protected async override Task HandleInternalAsync(LaunchActivatedEventArgs args)
{
_navigationService.NavigateTo(typeof(MainViewModel).FullName!, args.Arguments);
await Task.CompletedTask;
}
}
@@ -0,0 +1,8 @@
namespace VDD_Panel.Activation;
public interface IActivationHandler
{
bool CanHandle(object args);
Task HandleAsync(object args);
}
@@ -0,0 +1,15 @@
<Application
x:Class="VDD_Panel.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<ResourceDictionary Source="/Styles/FontSizes.xaml" />
<ResourceDictionary Source="/Styles/Thickness.xaml" />
<ResourceDictionary Source="/Styles/TextBlock.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
@@ -0,0 +1,111 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.UI.Xaml;
using VDD_Panel.Activation;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Core.Contracts.Services;
using VDD_Panel.Core.Services;
using VDD_Panel.Helpers;
using VDD_Panel.Models;
using VDD_Panel.Notifications;
using VDD_Panel.Services;
using VDD_Panel.ViewModels;
using VDD_Panel.Views;
namespace VDD_Panel;
// To learn more about WinUI 3, see https://docs.microsoft.com/windows/apps/winui/winui3/.
public partial class App : Application
{
// The .NET Generic Host provides dependency injection, configuration, logging, and other services.
// https://docs.microsoft.com/dotnet/core/extensions/generic-host
// https://docs.microsoft.com/dotnet/core/extensions/dependency-injection
// https://docs.microsoft.com/dotnet/core/extensions/configuration
// https://docs.microsoft.com/dotnet/core/extensions/logging
public IHost Host
{
get;
}
public static T GetService<T>()
where T : class
{
if ((App.Current as App)!.Host.Services.GetService(typeof(T)) is not T service)
{
throw new ArgumentException($"{typeof(T)} needs to be registered in ConfigureServices within App.xaml.cs.");
}
return service;
}
public static WindowEx MainWindow { get; } = new MainWindow();
public static UIElement? AppTitlebar { get; set; }
public App()
{
InitializeComponent();
Host = Microsoft.Extensions.Hosting.Host.
CreateDefaultBuilder().
UseContentRoot(AppContext.BaseDirectory).
ConfigureServices((context, services) =>
{
// Default Activation Handler
services.AddTransient<ActivationHandler<LaunchActivatedEventArgs>, DefaultActivationHandler>();
// Other Activation Handlers
services.AddTransient<IActivationHandler, AppNotificationActivationHandler>();
// Services
services.AddSingleton<IAppNotificationService, AppNotificationService>();
services.AddSingleton<ILocalSettingsService, LocalSettingsService>();
services.AddSingleton<IThemeSelectorService, ThemeSelectorService>();
services.AddTransient<IWebViewService, WebViewService>();
services.AddTransient<INavigationViewService, NavigationViewService>();
services.AddSingleton<IActivationService, ActivationService>();
services.AddSingleton<IPageService, PageService>();
services.AddSingleton<INavigationService, NavigationService>();
// Core Services
services.AddSingleton<IFileService, FileService>();
// Views and ViewModels
services.AddTransient<SettingsViewModel>();
services.AddTransient<SettingsPage>();
services.AddTransient<GitHubViewModel>();
services.AddTransient<GitHubPage>();
services.AddTransient<ConfigureViewModel>();
services.AddTransient<ConfigurePage>();
services.AddTransient<MainViewModel>();
services.AddTransient<MainPage>();
services.AddTransient<ShellPage>();
services.AddTransient<ShellViewModel>();
// Configuration
services.Configure<LocalSettingsOptions>(context.Configuration.GetSection(nameof(LocalSettingsOptions)));
}).
Build();
App.GetService<IAppNotificationService>().Initialize();
UnhandledException += App_UnhandledException;
}
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
// TODO: Log and handle exceptions as appropriate.
// https://docs.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.application.unhandledexception.
}
protected async override void OnLaunched(LaunchActivatedEventArgs args)
{
base.OnLaunched(args);
App.GetService<IAppNotificationService>().Show(string.Format("AppNotificationSamplePayload".GetLocalized(), AppContext.BaseDirectory));
await App.GetService<IActivationService>().ActivateAsync(args);
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

@@ -0,0 +1,122 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.Xaml.Interactivity;
using VDD_Panel.Contracts.Services;
namespace VDD_Panel.Behaviors;
public class NavigationViewHeaderBehavior : Behavior<NavigationView>
{
private static NavigationViewHeaderBehavior? _current;
private Page? _currentPage;
public DataTemplate? DefaultHeaderTemplate
{
get; set;
}
public object DefaultHeader
{
get => GetValue(DefaultHeaderProperty);
set => SetValue(DefaultHeaderProperty, value);
}
public static readonly DependencyProperty DefaultHeaderProperty =
DependencyProperty.Register("DefaultHeader", typeof(object), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeader()));
public static NavigationViewHeaderMode GetHeaderMode(Page item) => (NavigationViewHeaderMode)item.GetValue(HeaderModeProperty);
public static void SetHeaderMode(Page item, NavigationViewHeaderMode value) => item.SetValue(HeaderModeProperty, value);
public static readonly DependencyProperty HeaderModeProperty =
DependencyProperty.RegisterAttached("HeaderMode", typeof(bool), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(NavigationViewHeaderMode.Always, (d, e) => _current!.UpdateHeader()));
public static object GetHeaderContext(Page item) => item.GetValue(HeaderContextProperty);
public static void SetHeaderContext(Page item, object value) => item.SetValue(HeaderContextProperty, value);
public static readonly DependencyProperty HeaderContextProperty =
DependencyProperty.RegisterAttached("HeaderContext", typeof(object), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeader()));
public static DataTemplate GetHeaderTemplate(Page item) => (DataTemplate)item.GetValue(HeaderTemplateProperty);
public static void SetHeaderTemplate(Page item, DataTemplate value) => item.SetValue(HeaderTemplateProperty, value);
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.RegisterAttached("HeaderTemplate", typeof(DataTemplate), typeof(NavigationViewHeaderBehavior), new PropertyMetadata(null, (d, e) => _current!.UpdateHeaderTemplate()));
protected override void OnAttached()
{
base.OnAttached();
var navigationService = App.GetService<INavigationService>();
navigationService.Navigated += OnNavigated;
_current = this;
}
protected override void OnDetaching()
{
base.OnDetaching();
var navigationService = App.GetService<INavigationService>();
navigationService.Navigated -= OnNavigated;
}
private void OnNavigated(object sender, NavigationEventArgs e)
{
if (sender is Frame frame && frame.Content is Page page)
{
_currentPage = page;
UpdateHeader();
UpdateHeaderTemplate();
}
}
private void UpdateHeader()
{
if (_currentPage != null)
{
var headerMode = GetHeaderMode(_currentPage);
if (headerMode == NavigationViewHeaderMode.Never)
{
AssociatedObject.Header = null;
AssociatedObject.AlwaysShowHeader = false;
}
else
{
var headerFromPage = GetHeaderContext(_currentPage);
if (headerFromPage != null)
{
AssociatedObject.Header = headerFromPage;
}
else
{
AssociatedObject.Header = DefaultHeader;
}
if (headerMode == NavigationViewHeaderMode.Always)
{
AssociatedObject.AlwaysShowHeader = true;
}
else
{
AssociatedObject.AlwaysShowHeader = false;
}
}
}
}
private void UpdateHeaderTemplate()
{
if (_currentPage != null)
{
var headerTemplate = GetHeaderTemplate(_currentPage);
AssociatedObject.HeaderTemplate = headerTemplate ?? DefaultHeaderTemplate;
}
}
}
@@ -0,0 +1,8 @@
namespace VDD_Panel.Behaviors;
public enum NavigationViewHeaderMode
{
Always,
Never,
Minimal
}
@@ -0,0 +1,6 @@
namespace VDD_Panel.Contracts.Services;
public interface IActivationService
{
Task ActivateAsync(object activationArgs);
}
@@ -0,0 +1,14 @@
using System.Collections.Specialized;
namespace VDD_Panel.Contracts.Services;
public interface IAppNotificationService
{
void Initialize();
bool Show(string payload);
NameValueCollection ParseArguments(string arguments);
void Unregister();
}
@@ -0,0 +1,8 @@
namespace VDD_Panel.Contracts.Services;
public interface ILocalSettingsService
{
Task<T?> ReadSettingAsync<T>(string key);
Task SaveSettingAsync<T>(string key, T value);
}
@@ -0,0 +1,23 @@
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
namespace VDD_Panel.Contracts.Services;
public interface INavigationService
{
event NavigatedEventHandler Navigated;
bool CanGoBack
{
get;
}
Frame? Frame
{
get; set;
}
bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false);
bool GoBack();
}
@@ -0,0 +1,22 @@
using Microsoft.UI.Xaml.Controls;
namespace VDD_Panel.Contracts.Services;
public interface INavigationViewService
{
IList<object>? MenuItems
{
get;
}
object? SettingsItem
{
get;
}
void Initialize(NavigationView navigationView);
void UnregisterEvents();
NavigationViewItem? GetSelectedItem(Type pageType);
}
@@ -0,0 +1,6 @@
namespace VDD_Panel.Contracts.Services;
public interface IPageService
{
Type GetPageType(string key);
}
@@ -0,0 +1,17 @@
using Microsoft.UI.Xaml;
namespace VDD_Panel.Contracts.Services;
public interface IThemeSelectorService
{
ElementTheme Theme
{
get;
}
Task InitializeAsync();
Task SetThemeAsync(ElementTheme theme);
Task SetRequestedThemeAsync();
}
@@ -0,0 +1,34 @@
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
namespace VDD_Panel.Contracts.Services;
public interface IWebViewService
{
Uri? Source
{
get;
}
bool CanGoBack
{
get;
}
bool CanGoForward
{
get;
}
event EventHandler<CoreWebView2WebErrorStatus>? NavigationCompleted;
void Initialize(WebView2 webView);
void GoBack();
void GoForward();
void Reload();
void UnregisterEvents();
}
@@ -0,0 +1,8 @@
namespace VDD_Panel.Contracts.ViewModels;
public interface INavigationAware
{
void OnNavigatedTo(object parameter);
void OnNavigatedFrom();
}
@@ -0,0 +1,38 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
namespace VDD_Panel.Helpers;
public class EnumToBooleanConverter : IValueConverter
{
public EnumToBooleanConverter()
{
}
public object Convert(object value, Type targetType, object parameter, string language)
{
if (parameter is string enumString)
{
if (!Enum.IsDefined(typeof(ElementTheme), value))
{
throw new ArgumentException("ExceptionEnumToBooleanConverterValueMustBeAnEnum");
}
var enumValue = Enum.Parse(typeof(ElementTheme), enumString);
return enumValue.Equals(value);
}
throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName");
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
if (parameter is string enumString)
{
return Enum.Parse(typeof(ElementTheme), enumString);
}
throw new ArgumentException("ExceptionEnumToBooleanConverterParameterMustBeAnEnumName");
}
}
@@ -0,0 +1,8 @@
using Microsoft.UI.Xaml.Controls;
namespace VDD_Panel.Helpers;
public static class FrameExtensions
{
public static object? GetPageViewModel(this Frame frame) => frame?.Content?.GetType().GetProperty("ViewModel")?.GetValue(frame.Content, null);
}
@@ -0,0 +1,21 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
namespace VDD_Panel.Helpers;
// Helper class to set the navigation target for a NavigationViewItem.
//
// Usage in XAML:
// <NavigationViewItem x:Uid="Shell_Main" Icon="Document" helpers:NavigationHelper.NavigateTo="AppName.ViewModels.MainViewModel" />
//
// Usage in code:
// NavigationHelper.SetNavigateTo(navigationViewItem, typeof(MainViewModel).FullName);
public class NavigationHelper
{
public static string GetNavigateTo(NavigationViewItem item) => (string)item.GetValue(NavigateToProperty);
public static void SetNavigateTo(NavigationViewItem item, string value) => item.SetValue(NavigateToProperty, value);
public static readonly DependencyProperty NavigateToProperty =
DependencyProperty.RegisterAttached("NavigateTo", typeof(string), typeof(NavigationHelper), new PropertyMetadata(null));
}
@@ -0,0 +1,10 @@
using Microsoft.Windows.ApplicationModel.Resources;
namespace VDD_Panel.Helpers;
public static class ResourceExtensions
{
private static readonly ResourceLoader _resourceLoader = new();
public static string GetLocalized(this string resourceKey) => _resourceLoader.GetString(resourceKey);
}
@@ -0,0 +1,20 @@
using System.Runtime.InteropServices;
using System.Text;
namespace VDD_Panel.Helpers;
public class RuntimeHelper
{
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder? packageFullName);
public static bool IsMSIX
{
get
{
var length = 0;
return GetCurrentPackageFullName(ref length, null) != 15700L;
}
}
}
@@ -0,0 +1,112 @@
using VDD_Panel.Core.Helpers;
using Windows.Storage;
using Windows.Storage.Streams;
namespace VDD_Panel.Helpers;
// Use these extension methods to store and retrieve local and roaming app data
// More details regarding storing and retrieving app data at https://docs.microsoft.com/windows/apps/design/app-settings/store-and-retrieve-app-data
public static class SettingsStorageExtensions
{
private const string FileExtension = ".json";
public static bool IsRoamingStorageAvailable(this ApplicationData appData)
{
return appData.RoamingStorageQuota == 0;
}
public static async Task SaveAsync<T>(this StorageFolder folder, string name, T content)
{
var file = await folder.CreateFileAsync(GetFileName(name), CreationCollisionOption.ReplaceExisting);
var fileContent = await Json.StringifyAsync(content);
await FileIO.WriteTextAsync(file, fileContent);
}
public static async Task<T?> ReadAsync<T>(this StorageFolder folder, string name)
{
if (!File.Exists(Path.Combine(folder.Path, GetFileName(name))))
{
return default;
}
var file = await folder.GetFileAsync($"{name}.json");
var fileContent = await FileIO.ReadTextAsync(file);
return await Json.ToObjectAsync<T>(fileContent);
}
public static async Task SaveAsync<T>(this ApplicationDataContainer settings, string key, T value)
{
settings.SaveString(key, await Json.StringifyAsync(value));
}
public static void SaveString(this ApplicationDataContainer settings, string key, string value)
{
settings.Values[key] = value;
}
public static async Task<T?> ReadAsync<T>(this ApplicationDataContainer settings, string key)
{
object? obj;
if (settings.Values.TryGetValue(key, out obj))
{
return await Json.ToObjectAsync<T>((string)obj);
}
return default;
}
public static async Task<StorageFile> SaveFileAsync(this StorageFolder folder, byte[] content, string fileName, CreationCollisionOption options = CreationCollisionOption.ReplaceExisting)
{
if (content == null)
{
throw new ArgumentNullException(nameof(content));
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentException("File name is null or empty. Specify a valid file name", nameof(fileName));
}
var storageFile = await folder.CreateFileAsync(fileName, options);
await FileIO.WriteBytesAsync(storageFile, content);
return storageFile;
}
public static async Task<byte[]?> ReadFileAsync(this StorageFolder folder, string fileName)
{
var item = await folder.TryGetItemAsync(fileName).AsTask().ConfigureAwait(false);
if ((item != null) && item.IsOfType(StorageItemTypes.File))
{
var storageFile = await folder.GetFileAsync(fileName);
var content = await storageFile.ReadBytesAsync();
return content;
}
return null;
}
public static async Task<byte[]?> ReadBytesAsync(this StorageFile file)
{
if (file != null)
{
using IRandomAccessStream stream = await file.OpenReadAsync();
using var reader = new DataReader(stream.GetInputStreamAt(0));
await reader.LoadAsync((uint)stream.Size);
var bytes = new byte[stream.Size];
reader.ReadBytes(bytes);
return bytes;
}
return null;
}
private static string GetFileName(string name)
{
return string.Concat(name, FileExtension);
}
}
@@ -0,0 +1,96 @@
using System.Runtime.InteropServices;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Windows.UI;
using Windows.UI.ViewManagement;
namespace VDD_Panel.Helpers;
// Helper class to workaround custom title bar bugs.
// DISCLAIMER: The resource key names and color values used below are subject to change. Do not depend on them.
// https://github.com/microsoft/TemplateStudio/issues/4516
internal class TitleBarHelper
{
private const int WAINACTIVE = 0x00;
private const int WAACTIVE = 0x01;
private const int WMACTIVATE = 0x0006;
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
public static void UpdateTitleBar(ElementTheme theme)
{
if (App.MainWindow.ExtendsContentIntoTitleBar)
{
if (theme == ElementTheme.Default)
{
var uiSettings = new UISettings();
var background = uiSettings.GetColorValue(UIColorType.Background);
theme = background == Colors.White ? ElementTheme.Light : ElementTheme.Dark;
}
if (theme == ElementTheme.Default)
{
theme = Application.Current.RequestedTheme == ApplicationTheme.Light ? ElementTheme.Light : ElementTheme.Dark;
}
App.MainWindow.AppWindow.TitleBar.ButtonForegroundColor = theme switch
{
ElementTheme.Dark => Colors.White,
ElementTheme.Light => Colors.Black,
_ => Colors.Transparent
};
App.MainWindow.AppWindow.TitleBar.ButtonHoverForegroundColor = theme switch
{
ElementTheme.Dark => Colors.White,
ElementTheme.Light => Colors.Black,
_ => Colors.Transparent
};
App.MainWindow.AppWindow.TitleBar.ButtonHoverBackgroundColor = theme switch
{
ElementTheme.Dark => Color.FromArgb(0x33, 0xFF, 0xFF, 0xFF),
ElementTheme.Light => Color.FromArgb(0x33, 0x00, 0x00, 0x00),
_ => Colors.Transparent
};
App.MainWindow.AppWindow.TitleBar.ButtonPressedBackgroundColor = theme switch
{
ElementTheme.Dark => Color.FromArgb(0x66, 0xFF, 0xFF, 0xFF),
ElementTheme.Light => Color.FromArgb(0x66, 0x00, 0x00, 0x00),
_ => Colors.Transparent
};
App.MainWindow.AppWindow.TitleBar.BackgroundColor = Colors.Transparent;
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(App.MainWindow);
if (hwnd == GetActiveWindow())
{
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero);
SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero);
}
else
{
SendMessage(hwnd, WMACTIVATE, WAACTIVE, IntPtr.Zero);
SendMessage(hwnd, WMACTIVATE, WAINACTIVE, IntPtr.Zero);
}
}
}
public static void ApplySystemThemeToCaptionButtons()
{
var frame = App.AppTitlebar as FrameworkElement;
if (frame != null)
{
UpdateTitleBar(frame.ActualTheme);
}
}
}
@@ -0,0 +1,16 @@
<windowex:WindowEx
x:Class="VDD_Panel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:VDD_Panel"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:windowex="using:WinUIEx"
MinWidth="500"
MinHeight="500"
PersistenceId="MainWindow"
mc:Ignorable="d">
<Window.SystemBackdrop>
<MicaBackdrop/>
</Window.SystemBackdrop>
</windowex:WindowEx>
@@ -0,0 +1,37 @@
using VDD_Panel.Helpers;
using Windows.UI.ViewManagement;
namespace VDD_Panel;
public sealed partial class MainWindow : WindowEx
{
private Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue;
private UISettings settings;
public MainWindow()
{
InitializeComponent();
AppWindow.SetIcon(Path.Combine(AppContext.BaseDirectory, "Assets/WindowIcon.ico"));
Content = null;
Title = "AppDisplayName".GetLocalized();
// Theme change code picked from https://github.com/microsoft/WinUI-Gallery/pull/1239
dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
settings = new UISettings();
settings.ColorValuesChanged += Settings_ColorValuesChanged; // cannot use FrameworkElement.ActualThemeChanged event
}
// this handles updating the caption button colors correctly when indows system theme is changed
// while the app is open
private void Settings_ColorValuesChanged(UISettings sender, object args)
{
// This calls comes off-thread, hence we will need to dispatch it to current app's thread
dispatcherQueue.TryEnqueue(() =>
{
TitleBarHelper.ApplySystemThemeToCaptionButtons();
});
}
}
@@ -0,0 +1,14 @@
namespace VDD_Panel.Models;
public class LocalSettingsOptions
{
public string? ApplicationDataFolder
{
get; set;
}
public string? LocalSettingsFile
{
get; set;
}
}
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<AppInstaller Uri="{AppInstallerUri}"
Version="{Version}"
xmlns="http://schemas.microsoft.com/appx/appinstaller/2017/2">
<!-- Read more about updating settings with Package.appinstaller at https://docs.microsoft.com/windows/msix/app-installer/update-settings -->
<MainBundle Name="{Name}"
Version="{Version}"
Publisher="{Publisher}"
Uri="{MainPackageUri}"/>
<UpdateSettings>
<OnLaunch HoursBetweenUpdateChecks="0" />
</UpdateSettings>
</AppInstaller>
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:genTemplate="http://schemas.microsoft.com/appx/developer/templatestudio"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
IgnorableNamespaces="uap rescap genTemplate">
<Identity
Name="a7aa779e-510d-4d11-aad6-4cb00d23c8a5"
Publisher="CN=alisa"
Version="1.0.0.0" />
<mp:PhoneIdentity PhoneProductId="a7aa779e-510d-4d11-aad6-4cb00d23c8a5" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
<Properties>
<DisplayName>VDD Panel</DisplayName>
<PublisherDisplayName>alisa</PublisherDisplayName>
<Logo>Assets\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="ms-resource:AppDisplayName"
Description="ms-resource:AppDescription"
BackgroundColor="transparent"
Square150x150Logo="Assets\Square150x150Logo.png"
Square44x44Logo="Assets\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
<uap:SplashScreen Image="Assets\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<desktop:Extension Category="windows.toastNotificationActivation">
<desktop:ToastNotificationActivation ToastActivatorCLSID="17b96de3-608c-4471-85f1-1e9db4531575" />
</desktop:Extension>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="VDD Panel.exe" Arguments="----AppNotificationActivated:" DisplayName="Toast activator">
<com:Class Id="17b96de3-608c-4471-85f1-1e9db4531575" DisplayName="Toast activator"/>
</com:ExeServer>
</com:ComServer>
</com:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
<genTemplate:Metadata>
<genTemplate:Item Name="generator" Value="Template Studio"/>
<genTemplate:Item Name="wizardVersion" Version="v5.5" />
<genTemplate:Item Name="projectType" Value="NavView" />
<genTemplate:Item Name="framework" Value="MVVMToolkit" />
<genTemplate:Item Name="platform" Value="WinUI" />
<genTemplate:Item Name="appmodel" Value="Desktop" />
</genTemplate:Metadata>
</Package>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>arm64</Platform>
<RuntimeIdentifier>win10-arm64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>True</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
</PropertyGroup>
</Project>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x64</Platform>
<RuntimeIdentifier>win10-x64</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>True</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
</PropertyGroup>
</Project>
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<PublishProtocol>FileSystem</PublishProtocol>
<Platform>x86</Platform>
<RuntimeIdentifier>win10-x86</RuntimeIdentifier>
<PublishDir>bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\</PublishDir>
<SelfContained>True</SelfContained>
<PublishSingleFile>False</PublishSingleFile>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
</PropertyGroup>
</Project>
@@ -0,0 +1,10 @@
{
"profiles": {
"VDD Panel (Package)": {
"commandName": "MsixPackage"
},
"VDD Panel (Unpackaged)": {
"commandName": "Project"
}
}
}
@@ -0,0 +1,27 @@
*Recommended Markdown Viewer: [Markdown Editor](https://marketplace.visualstudio.com/items?itemName=MadsKristensen.MarkdownEditor2)*
## Getting Started
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.
Explore the [WinUI Gallery](https://www.microsoft.com/store/productId/9P3JFPWWDZRC) to learn about available controls and design patterns.
Relaunch Template Studio to modify the project by right-clicking on the project in `View -> Solution Explorer` then selecting `Add -> New Item (Template Studio)`.
## Publishing
For projects with MSIX packaging, right-click on the application project and select `Package and Publish -> Create App Packages...` to create an MSIX package.
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.
## CI Pipelines
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.
## Changelog
See [releases](https://github.com/microsoft/TemplateStudio/releases) and [milestones](https://github.com/microsoft/TemplateStudio/milestones).
## Feedback
Bugs and feature requests should be filed at https://aka.ms/templatestudio.
@@ -0,0 +1,72 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using VDD_Panel.Activation;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Views;
namespace VDD_Panel.Services;
public class ActivationService : IActivationService
{
private readonly ActivationHandler<LaunchActivatedEventArgs> _defaultHandler;
private readonly IEnumerable<IActivationHandler> _activationHandlers;
private readonly IThemeSelectorService _themeSelectorService;
private UIElement? _shell = null;
public ActivationService(ActivationHandler<LaunchActivatedEventArgs> defaultHandler, IEnumerable<IActivationHandler> activationHandlers, IThemeSelectorService themeSelectorService)
{
_defaultHandler = defaultHandler;
_activationHandlers = activationHandlers;
_themeSelectorService = themeSelectorService;
}
public async Task ActivateAsync(object activationArgs)
{
// Execute tasks before activation.
await InitializeAsync();
// Set the MainWindow Content.
if (App.MainWindow.Content == null)
{
_shell = App.GetService<ShellPage>();
App.MainWindow.Content = _shell ?? new Frame();
}
// Handle activation via ActivationHandlers.
await HandleActivationAsync(activationArgs);
// Activate the MainWindow.
App.MainWindow.Activate();
// Execute tasks after activation.
await StartupAsync();
}
private async Task HandleActivationAsync(object activationArgs)
{
var activationHandler = _activationHandlers.FirstOrDefault(h => h.CanHandle(activationArgs));
if (activationHandler != null)
{
await activationHandler.HandleAsync(activationArgs);
}
if (_defaultHandler.CanHandle(activationArgs))
{
await _defaultHandler.HandleAsync(activationArgs);
}
}
private async Task InitializeAsync()
{
await _themeSelectorService.InitializeAsync().ConfigureAwait(false);
await Task.CompletedTask;
}
private async Task StartupAsync()
{
await _themeSelectorService.SetRequestedThemeAsync();
await Task.CompletedTask;
}
}
@@ -0,0 +1,71 @@
using System.Collections.Specialized;
using System.Web;
using Microsoft.Windows.AppNotifications;
using VDD_Panel.Contracts.Services;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Notifications;
public class AppNotificationService : IAppNotificationService
{
private readonly INavigationService _navigationService;
public AppNotificationService(INavigationService navigationService)
{
_navigationService = navigationService;
}
~AppNotificationService()
{
Unregister();
}
public void Initialize()
{
AppNotificationManager.Default.NotificationInvoked += OnNotificationInvoked;
AppNotificationManager.Default.Register();
}
public void OnNotificationInvoked(AppNotificationManager sender, AppNotificationActivatedEventArgs args)
{
// TODO: Handle notification invocations when your app is already running.
//// // Navigate to a specific page based on the notification arguments.
//// if (ParseArguments(args.Argument)["action"] == "Settings")
//// {
//// App.MainWindow.DispatcherQueue.TryEnqueue(() =>
//// {
//// _navigationService.NavigateTo(typeof(SettingsViewModel).FullName!);
//// });
//// }
App.MainWindow.DispatcherQueue.TryEnqueue(() =>
{
App.MainWindow.ShowMessageDialogAsync("TODO: Handle notification invocations when your app is already running.", "Notification Invoked");
App.MainWindow.BringToFront();
});
}
public bool Show(string payload)
{
var appNotification = new AppNotification(payload);
AppNotificationManager.Default.Show(appNotification);
return appNotification.Id != 0;
}
public NameValueCollection ParseArguments(string arguments)
{
return HttpUtility.ParseQueryString(arguments);
}
public void Unregister()
{
AppNotificationManager.Default.Unregister();
}
}
@@ -0,0 +1,88 @@
using Microsoft.Extensions.Options;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Core.Contracts.Services;
using VDD_Panel.Core.Helpers;
using VDD_Panel.Helpers;
using VDD_Panel.Models;
using Windows.ApplicationModel;
using Windows.Storage;
namespace VDD_Panel.Services;
public class LocalSettingsService : ILocalSettingsService
{
private const string _defaultApplicationDataFolder = "VDD Panel/ApplicationData";
private const string _defaultLocalSettingsFile = "LocalSettings.json";
private readonly IFileService _fileService;
private readonly LocalSettingsOptions _options;
private readonly string _localApplicationData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
private readonly string _applicationDataFolder;
private readonly string _localsettingsFile;
private IDictionary<string, object> _settings;
private bool _isInitialized;
public LocalSettingsService(IFileService fileService, IOptions<LocalSettingsOptions> options)
{
_fileService = fileService;
_options = options.Value;
_applicationDataFolder = Path.Combine(_localApplicationData, _options.ApplicationDataFolder ?? _defaultApplicationDataFolder);
_localsettingsFile = _options.LocalSettingsFile ?? _defaultLocalSettingsFile;
_settings = new Dictionary<string, object>();
}
private async Task InitializeAsync()
{
if (!_isInitialized)
{
_settings = await Task.Run(() => _fileService.Read<IDictionary<string, object>>(_applicationDataFolder, _localsettingsFile)) ?? new Dictionary<string, object>();
_isInitialized = true;
}
}
public async Task<T?> ReadSettingAsync<T>(string key)
{
if (RuntimeHelper.IsMSIX)
{
if (ApplicationData.Current.LocalSettings.Values.TryGetValue(key, out var obj))
{
return await Json.ToObjectAsync<T>((string)obj);
}
}
else
{
await InitializeAsync();
if (_settings != null && _settings.TryGetValue(key, out var obj))
{
return await Json.ToObjectAsync<T>((string)obj);
}
}
return default;
}
public async Task SaveSettingAsync<T>(string key, T value)
{
if (RuntimeHelper.IsMSIX)
{
ApplicationData.Current.LocalSettings.Values[key] = await Json.StringifyAsync(value);
}
else
{
await InitializeAsync();
_settings[key] = await Json.StringifyAsync(value);
await Task.Run(() => _fileService.Save(_applicationDataFolder, _localsettingsFile, _settings));
}
}
}
@@ -0,0 +1,126 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Navigation;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Contracts.ViewModels;
using VDD_Panel.Helpers;
namespace VDD_Panel.Services;
// For more information on navigation between pages see
// https://github.com/microsoft/TemplateStudio/blob/main/docs/WinUI/navigation.md
public class NavigationService : INavigationService
{
private readonly IPageService _pageService;
private object? _lastParameterUsed;
private Frame? _frame;
public event NavigatedEventHandler? Navigated;
public Frame? Frame
{
get
{
if (_frame == null)
{
_frame = App.MainWindow.Content as Frame;
RegisterFrameEvents();
}
return _frame;
}
set
{
UnregisterFrameEvents();
_frame = value;
RegisterFrameEvents();
}
}
[MemberNotNullWhen(true, nameof(Frame), nameof(_frame))]
public bool CanGoBack => Frame != null && Frame.CanGoBack;
public NavigationService(IPageService pageService)
{
_pageService = pageService;
}
private void RegisterFrameEvents()
{
if (_frame != null)
{
_frame.Navigated += OnNavigated;
}
}
private void UnregisterFrameEvents()
{
if (_frame != null)
{
_frame.Navigated -= OnNavigated;
}
}
public bool GoBack()
{
if (CanGoBack)
{
var vmBeforeNavigation = _frame.GetPageViewModel();
_frame.GoBack();
if (vmBeforeNavigation is INavigationAware navigationAware)
{
navigationAware.OnNavigatedFrom();
}
return true;
}
return false;
}
public bool NavigateTo(string pageKey, object? parameter = null, bool clearNavigation = false)
{
var pageType = _pageService.GetPageType(pageKey);
if (_frame != null && (_frame.Content?.GetType() != pageType || (parameter != null && !parameter.Equals(_lastParameterUsed))))
{
_frame.Tag = clearNavigation;
var vmBeforeNavigation = _frame.GetPageViewModel();
var navigated = _frame.Navigate(pageType, parameter);
if (navigated)
{
_lastParameterUsed = parameter;
if (vmBeforeNavigation is INavigationAware navigationAware)
{
navigationAware.OnNavigatedFrom();
}
}
return navigated;
}
return false;
}
private void OnNavigated(object sender, NavigationEventArgs e)
{
if (sender is Frame frame)
{
var clearNavigation = (bool)frame.Tag;
if (clearNavigation)
{
frame.BackStack.Clear();
}
if (frame.GetPageViewModel() is INavigationAware navigationAware)
{
navigationAware.OnNavigatedTo(e.Parameter);
}
Navigated?.Invoke(sender, e);
}
}
}
@@ -0,0 +1,103 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.UI.Xaml.Controls;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Helpers;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Services;
public class NavigationViewService : INavigationViewService
{
private readonly INavigationService _navigationService;
private readonly IPageService _pageService;
private NavigationView? _navigationView;
public IList<object>? MenuItems => _navigationView?.MenuItems;
public object? SettingsItem => _navigationView?.SettingsItem;
public NavigationViewService(INavigationService navigationService, IPageService pageService)
{
_navigationService = navigationService;
_pageService = pageService;
}
[MemberNotNull(nameof(_navigationView))]
public void Initialize(NavigationView navigationView)
{
_navigationView = navigationView;
_navigationView.BackRequested += OnBackRequested;
_navigationView.ItemInvoked += OnItemInvoked;
}
public void UnregisterEvents()
{
if (_navigationView != null)
{
_navigationView.BackRequested -= OnBackRequested;
_navigationView.ItemInvoked -= OnItemInvoked;
}
}
public NavigationViewItem? GetSelectedItem(Type pageType)
{
if (_navigationView != null)
{
return GetSelectedItem(_navigationView.MenuItems, pageType) ?? GetSelectedItem(_navigationView.FooterMenuItems, pageType);
}
return null;
}
private void OnBackRequested(NavigationView sender, NavigationViewBackRequestedEventArgs args) => _navigationService.GoBack();
private void OnItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
{
if (args.IsSettingsInvoked)
{
_navigationService.NavigateTo(typeof(SettingsViewModel).FullName!);
}
else
{
var selectedItem = args.InvokedItemContainer as NavigationViewItem;
if (selectedItem?.GetValue(NavigationHelper.NavigateToProperty) is string pageKey)
{
_navigationService.NavigateTo(pageKey);
}
}
}
private NavigationViewItem? GetSelectedItem(IEnumerable<object> menuItems, Type pageType)
{
foreach (var item in menuItems.OfType<NavigationViewItem>())
{
if (IsMenuItemForPageType(item, pageType))
{
return item;
}
var selectedChild = GetSelectedItem(item.MenuItems, pageType);
if (selectedChild != null)
{
return selectedChild;
}
}
return null;
}
private bool IsMenuItemForPageType(NavigationViewItem menuItem, Type sourcePageType)
{
if (menuItem.GetValue(NavigationHelper.NavigateToProperty) is string pageKey)
{
return _pageService.GetPageType(pageKey) == sourcePageType;
}
return false;
}
}
@@ -0,0 +1,58 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml.Controls;
using VDD_Panel.Contracts.Services;
using VDD_Panel.ViewModels;
using VDD_Panel.Views;
namespace VDD_Panel.Services;
public class PageService : IPageService
{
private readonly Dictionary<string, Type> _pages = new();
public PageService()
{
Configure<MainViewModel, MainPage>();
Configure<ConfigureViewModel, ConfigurePage>();
Configure<GitHubViewModel, GitHubPage>();
Configure<SettingsViewModel, SettingsPage>();
}
public Type GetPageType(string key)
{
Type? pageType;
lock (_pages)
{
if (!_pages.TryGetValue(key, out pageType))
{
throw new ArgumentException($"Page not found: {key}. Did you forget to call PageService.Configure?");
}
}
return pageType;
}
private void Configure<VM, V>()
where VM : ObservableObject
where V : Page
{
lock (_pages)
{
var key = typeof(VM).FullName!;
if (_pages.ContainsKey(key))
{
throw new ArgumentException($"The key {key} is already configured in PageService");
}
var type = typeof(V);
if (_pages.ContainsValue(type))
{
throw new ArgumentException($"This type is already configured with key {_pages.First(p => p.Value == type).Key}");
}
_pages.Add(key, type);
}
}
}
@@ -0,0 +1,63 @@
using Microsoft.UI.Xaml;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Helpers;
namespace VDD_Panel.Services;
public class ThemeSelectorService : IThemeSelectorService
{
private const string SettingsKey = "AppBackgroundRequestedTheme";
public ElementTheme Theme { get; set; } = ElementTheme.Default;
private readonly ILocalSettingsService _localSettingsService;
public ThemeSelectorService(ILocalSettingsService localSettingsService)
{
_localSettingsService = localSettingsService;
}
public async Task InitializeAsync()
{
Theme = await LoadThemeFromSettingsAsync();
await Task.CompletedTask;
}
public async Task SetThemeAsync(ElementTheme theme)
{
Theme = theme;
await SetRequestedThemeAsync();
await SaveThemeInSettingsAsync(Theme);
}
public async Task SetRequestedThemeAsync()
{
if (App.MainWindow.Content is FrameworkElement rootElement)
{
rootElement.RequestedTheme = Theme;
TitleBarHelper.UpdateTitleBar(Theme);
}
await Task.CompletedTask;
}
private async Task<ElementTheme> LoadThemeFromSettingsAsync()
{
var themeName = await _localSettingsService.ReadSettingAsync<string>(SettingsKey);
if (Enum.TryParse(themeName, out ElementTheme cacheTheme))
{
return cacheTheme;
}
return ElementTheme.Default;
}
private async Task SaveThemeInSettingsAsync(ElementTheme theme)
{
await _localSettingsService.SaveSettingAsync(SettingsKey, theme.ToString());
}
}
@@ -0,0 +1,50 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
using VDD_Panel.Contracts.Services;
namespace VDD_Panel.Services;
public class WebViewService : IWebViewService
{
private WebView2? _webView;
public Uri? Source => _webView?.Source;
[MemberNotNullWhen(true, nameof(_webView))]
public bool CanGoBack => _webView != null && _webView.CanGoBack;
[MemberNotNullWhen(true, nameof(_webView))]
public bool CanGoForward => _webView != null && _webView.CanGoForward;
public event EventHandler<CoreWebView2WebErrorStatus>? NavigationCompleted;
public WebViewService()
{
}
[MemberNotNull(nameof(_webView))]
public void Initialize(WebView2 webView)
{
_webView = webView;
_webView.NavigationCompleted += OnWebViewNavigationCompleted;
}
public void GoBack() => _webView?.GoBack();
public void GoForward() => _webView?.GoForward();
public void Reload() => _webView?.Reload();
public void UnregisterEvents()
{
if (_webView != null)
{
_webView.NavigationCompleted -= OnWebViewNavigationCompleted;
}
}
private void OnWebViewNavigationCompleted(WebView2 sender, CoreWebView2NavigationCompletedEventArgs args) => NavigationCompleted?.Invoke(this, args.WebErrorStatus);
}
@@ -0,0 +1,150 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="AppDisplayName" xml:space="preserve">
<value>VDD Panel</value>
</data>
<data name="AppDescription" xml:space="preserve">
<value>VDD Panel</value>
</data>
<data name="Shell_Main.Content" xml:space="preserve">
<value>Main</value>
</data>
<data name="Shell_Configure.Content" xml:space="preserve">
<value>Configure</value>
</data>
<data name="WebView_Loading.Text" xml:space="preserve">
<value>Loading...</value>
</data>
<data name="WebView_FailedMessage.Text" xml:space="preserve">
<value>Page failed to load. Check connection and reload.</value>
</data>
<data name="BrowserBackButton.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Browser back</value>
</data>
<data name="BrowserBackButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Browser back</value>
</data>
<data name="BrowserForwardButton.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Browser forward</value>
</data>
<data name="BrowserForwardButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Browser forward</value>
</data>
<data name="WebView_Reload.Content" xml:space="preserve">
<value>Reload</value>
</data>
<data name="ReloadButton.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Reload</value>
</data>
<data name="ReloadButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Reload</value>
</data>
<data name="OpenInBrowserButton.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Open in browser</value>
</data>
<data name="OpenInBrowserButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Open in browser</value>
</data>
<data name="Shell_GitHub.Content" xml:space="preserve">
<value>GitHub</value>
</data>
<data name="Settings_Personalization.Text" xml:space="preserve">
<value>Personalization</value>
</data>
<data name="Settings_Theme.Text" xml:space="preserve">
<value>Theme</value>
</data>
<data name="Settings_Theme_Light.Content" xml:space="preserve">
<value>Light</value>
</data>
<data name="Settings_Theme_Dark.Content" xml:space="preserve">
<value>Dark</value>
</data>
<data name="Settings_Theme_Default.Content" xml:space="preserve">
<value>Default</value>
</data>
<data name="Settings_About.Text" xml:space="preserve">
<value>About this application</value>
</data>
<data name="Settings_AboutDescription.Text" xml:space="preserve">
<value>TODO: Replace with your app description.</value>
</data>
<data name="SettingsPage_PrivacyTermsLink.Content" xml:space="preserve">
<value>Privacy Statement</value>
</data>
<data name="SettingsPage_PrivacyTermsLink.NavigateUri" xml:space="preserve">
<value>https://YourPrivacyUrlGoesHere/</value>
</data>
<data name="AppNotificationSamplePayload" xml:space="preserve">
<value>&lt;toast launch="action=ToastClick"&gt;
&lt;visual&gt;
&lt;binding template="ToastGeneric"&gt;
&lt;text&gt;App Notification&lt;/text&gt;
&lt;text&gt;&lt;/text&gt;
&lt;image placement="appLogoOverride" hint-crop="circle" src="{0}Assets/WindowIcon.ico"/&gt;
&lt;/binding&gt;
&lt;/visual&gt;
&lt;actions&gt;
&lt;action content="Settings" arguments="action=Settings"/&gt;
&lt;/actions&gt;
&lt;/toast&gt;</value>
</data>
</root>
@@ -0,0 +1,9 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<x:Double x:Key="LargeFontSize">24</x:Double>
<x:Double x:Key="MediumFontSize">16</x:Double>
</ResourceDictionary>
@@ -0,0 +1,20 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="PageTitleStyle" TargetType="TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="SemiLight" />
<Setter Property="FontSize" Value="{StaticResource LargeFontSize}" />
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
<Setter Property="TextWrapping" Value="NoWrap" />
</Style>
<Style x:Key="BodyTextStyle" TargetType="TextBlock">
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{StaticResource MediumFontSize}" />
<Setter Property="TextTrimming" Value="CharacterEllipsis" />
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</ResourceDictionary>
@@ -0,0 +1,36 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Thickness x:Key="LargeTopMargin">0,36,0,0</Thickness>
<Thickness x:Key="LargeTopBottomMargin">0,36,0,36</Thickness>
<Thickness x:Key="MediumTopMargin">0,24,0,0</Thickness>
<Thickness x:Key="MediumTopBottomMargin">0,24,0,24</Thickness>
<Thickness x:Key="MediumLeftRightMargin">24,0,24,0</Thickness>
<Thickness x:Key="MediumBottomMargin">0,0,0,24</Thickness>
<Thickness x:Key="SmallLeftMargin">12,0,0,0</Thickness>
<Thickness x:Key="SmallLeftRightMargin">12,0,12,0</Thickness>
<Thickness x:Key="SmallTopMargin">0,12,0,0</Thickness>
<Thickness x:Key="SmallRightMargin">0,0,12,0</Thickness>
<Thickness x:Key="SmallTopBottomMargin">0,12,0,12</Thickness>
<Thickness x:Key="XSmallLeftMargin">8,0,0,0</Thickness>
<Thickness x:Key="XSmallTopMargin">0,8,0,0</Thickness>
<Thickness x:Key="XSmallLeftTopRightBottomMargin">8,8,8,8</Thickness>
<Thickness x:Key="XXSmallTopMargin">0,4,0,0</Thickness>
<Thickness x:Key="XXSmallLeftTopRightBottomMargin">4,4,4,4</Thickness>
<Thickness x:Key="NavigationViewContentGridBorderThickness">1,1,0,0</Thickness>
<CornerRadius x:Key="NavigationViewContentGridCornerRadius">8,0,0,0</CornerRadius>
<Thickness x:Key="NavigationViewContentMargin">0,48,0,0</Thickness>
<Thickness x:Key="NavigationViewHeaderMargin">56,34,0,0</Thickness>
<Thickness x:Key="NavigationViewPageContentMargin">56,24,56,0</Thickness>
<Thickness x:Key="MenuBarContentMargin">36,24,36,0</Thickness>
<Thickness x:Key="SettingsPageHyperlinkButtonMargin">-12,4,0,0</Thickness>
</ResourceDictionary>
@@ -0,0 +1,11 @@
<xml
xmlns:genTemplate="http://schemas.microsoft.com/appx/developer/templatestudio">
<genTemplate:Metadata>
<genTemplate:Item Name="generator" Value="Template Studio"/>
<genTemplate:Item Name="wizardVersion" Version="v5.5" />
<genTemplate:Item Name="projectType" Value="NavView" />
<genTemplate:Item Name="framework" Value="MVVMToolkit" />
<genTemplate:Item Name="platform" Value="WinUI" />
<genTemplate:Item Name="appmodel" Value="Desktop" />
</genTemplate:Metadata>
</xml>
@@ -0,0 +1 @@
global using WinUIEx;
@@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>VDD_Panel</RootNamespace>
<ApplicationIcon>Assets/WindowIcon.ico</ApplicationIcon>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;arm64</Platforms>
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
<PublishProfile>Properties\PublishProfiles\win10-$(Platform).pubxml</PublishProfile>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
</PropertyGroup>
<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="6.0.1" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.4.231008000" />
<PackageReference Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageReference Include="WinUIEx" Version="2.3.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\VDD Panel.Core\VDD Panel.Core.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>
</Project>
@@ -0,0 +1,10 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace VDD_Panel.ViewModels;
public partial class ConfigureViewModel : ObservableRecipient
{
public ConfigureViewModel()
{
}
}
@@ -0,0 +1,110 @@
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Web.WebView2.Core;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Contracts.ViewModels;
namespace VDD_Panel.ViewModels;
// TODO: Review best practices and distribution guidelines for WebView2.
// https://docs.microsoft.com/microsoft-edge/webview2/get-started/winui
// https://docs.microsoft.com/microsoft-edge/webview2/concepts/developer-guide
// https://docs.microsoft.com/microsoft-edge/webview2/concepts/distribution
public partial class GitHubViewModel : ObservableRecipient, INavigationAware
{
// TODO: Set the default URL to display.
[ObservableProperty]
private Uri source = new("https://github.com/itsmikethetech/Virtual-Display-Driver");
[ObservableProperty]
private bool isLoading = true;
[ObservableProperty]
private bool hasFailures;
public IWebViewService WebViewService
{
get;
}
public GitHubViewModel(IWebViewService webViewService)
{
WebViewService = webViewService;
}
[RelayCommand]
private async Task OpenInBrowser()
{
if (WebViewService.Source != null)
{
await Windows.System.Launcher.LaunchUriAsync(WebViewService.Source);
}
}
[RelayCommand]
private void Reload()
{
WebViewService.Reload();
}
[RelayCommand(CanExecute = nameof(BrowserCanGoForward))]
private void BrowserForward()
{
if (WebViewService.CanGoForward)
{
WebViewService.GoForward();
}
}
private bool BrowserCanGoForward()
{
return WebViewService.CanGoForward;
}
[RelayCommand(CanExecute = nameof(BrowserCanGoBack))]
private void BrowserBack()
{
if (WebViewService.CanGoBack)
{
WebViewService.GoBack();
}
}
private bool BrowserCanGoBack()
{
return WebViewService.CanGoBack;
}
public void OnNavigatedTo(object parameter)
{
WebViewService.NavigationCompleted += OnNavigationCompleted;
}
public void OnNavigatedFrom()
{
WebViewService.UnregisterEvents();
WebViewService.NavigationCompleted -= OnNavigationCompleted;
}
private void OnNavigationCompleted(object? sender, CoreWebView2WebErrorStatus webErrorStatus)
{
IsLoading = false;
BrowserBackCommand.NotifyCanExecuteChanged();
BrowserForwardCommand.NotifyCanExecuteChanged();
if (webErrorStatus != default)
{
HasFailures = true;
}
}
[RelayCommand]
private void OnRetry()
{
HasFailures = false;
IsLoading = true;
WebViewService?.Reload();
}
}
@@ -0,0 +1,10 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace VDD_Panel.ViewModels;
public partial class MainViewModel : ObservableRecipient
{
public MainViewModel()
{
}
}
@@ -0,0 +1,65 @@
using System.Reflection;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.UI.Xaml;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Helpers;
using Windows.ApplicationModel;
namespace VDD_Panel.ViewModels;
public partial class SettingsViewModel : ObservableRecipient
{
private readonly IThemeSelectorService _themeSelectorService;
[ObservableProperty]
private ElementTheme _elementTheme;
[ObservableProperty]
private string _versionDescription;
public ICommand SwitchThemeCommand
{
get;
}
public SettingsViewModel(IThemeSelectorService themeSelectorService)
{
_themeSelectorService = themeSelectorService;
_elementTheme = _themeSelectorService.Theme;
_versionDescription = GetVersionDescription();
SwitchThemeCommand = new RelayCommand<ElementTheme>(
async (param) =>
{
if (ElementTheme != param)
{
ElementTheme = param;
await _themeSelectorService.SetThemeAsync(param);
}
});
}
private static string GetVersionDescription()
{
Version version;
if (RuntimeHelper.IsMSIX)
{
var packageVersion = Package.Current.Id.Version;
version = new(packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision);
}
else
{
version = Assembly.GetExecutingAssembly().GetName().Version!;
}
return $"{"AppDisplayName".GetLocalized()} - {version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
}
}
@@ -0,0 +1,51 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.UI.Xaml.Navigation;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Views;
namespace VDD_Panel.ViewModels;
public partial class ShellViewModel : ObservableRecipient
{
[ObservableProperty]
private bool isBackEnabled;
[ObservableProperty]
private object? selected;
public INavigationService NavigationService
{
get;
}
public INavigationViewService NavigationViewService
{
get;
}
public ShellViewModel(INavigationService navigationService, INavigationViewService navigationViewService)
{
NavigationService = navigationService;
NavigationService.Navigated += OnNavigated;
NavigationViewService = navigationViewService;
}
private void OnNavigated(object sender, NavigationEventArgs e)
{
IsBackEnabled = NavigationService.CanGoBack;
if (e.SourcePageType == typeof(SettingsPage))
{
Selected = NavigationViewService.SettingsItem;
return;
}
var selectedItem = NavigationViewService.GetSelectedItem(e.SourcePageType);
if (selectedItem != null)
{
Selected = selectedItem;
}
}
}
@@ -0,0 +1,12 @@
<Page
x:Class="VDD_Panel.Views.ConfigurePage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="ContentArea">
</Grid>
</Page>
@@ -0,0 +1,19 @@
using Microsoft.UI.Xaml.Controls;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Views;
public sealed partial class ConfigurePage : Page
{
public ConfigureViewModel ViewModel
{
get;
}
public ConfigurePage()
{
ViewModel = App.GetService<ConfigureViewModel>();
InitializeComponent();
}
}
@@ -0,0 +1,56 @@
<Page
x:Class="VDD_Panel.Views.GitHubPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:behaviors="using:VDD_Panel.Behaviors"
behaviors:NavigationViewHeaderBehavior.HeaderMode="Never"
mc:Ignorable="d">
<Grid x:Name="ContentArea">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<WebView2
x:Name="WebView"
Source="{x:Bind ViewModel.Source, Mode=OneWay}" />
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{x:Bind ViewModel.IsLoading, Mode=OneWay}">
<ProgressRing IsActive="{x:Bind ViewModel.IsLoading, Mode=OneWay}" />
<TextBlock x:Uid="WebView_Loading" />
</StackPanel>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{x:Bind ViewModel.HasFailures, Mode=OneWay}">
<TextBlock x:Uid="WebView_FailedMessage" HorizontalAlignment="Center" TextWrapping="WrapWholeWords" />
<HyperlinkButton x:Uid="WebView_Reload" Command="{x:Bind ViewModel.ReloadCommand}" HorizontalAlignment="Center" />
</StackPanel>
<Grid Grid.Row="1">
<StackPanel Orientation="Horizontal">
<Button x:Uid="BrowserBackButton" Command="{x:Bind ViewModel.BrowserBackCommand, Mode=OneWay}" Margin="{StaticResource XSmallLeftTopRightBottomMargin}" Padding="{StaticResource XXSmallLeftTopRightBottomMargin}">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE72B;" />
</Button>
<Button x:Uid="BrowserForwardButton" Command="{x:Bind ViewModel.BrowserForwardCommand, Mode=OneWay}" Margin="{StaticResource XSmallLeftTopRightBottomMargin}" Padding="{StaticResource XXSmallLeftTopRightBottomMargin}">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE72A;" />
</Button>
</StackPanel >
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Uid="ReloadButton" Command="{x:Bind ViewModel.ReloadCommand}" Margin="{StaticResource XSmallLeftTopRightBottomMargin}" Padding="{StaticResource XXSmallLeftTopRightBottomMargin}">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE72C;" />
</Button>
<Button x:Uid="OpenInBrowserButton" Command="{x:Bind ViewModel.OpenInBrowserCommand}" Margin="{StaticResource XSmallLeftTopRightBottomMargin}" Padding="{StaticResource XXSmallLeftTopRightBottomMargin}">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xE774;" />
</Button>
</StackPanel>
</Grid>
</Grid>
</Page>
@@ -0,0 +1,22 @@
using Microsoft.UI.Xaml.Controls;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Views;
// To learn more about WebView2, see https://docs.microsoft.com/microsoft-edge/webview2/.
public sealed partial class GitHubPage : Page
{
public GitHubViewModel ViewModel
{
get;
}
public GitHubPage()
{
ViewModel = App.GetService<GitHubViewModel>();
InitializeComponent();
ViewModel.WebViewService.Initialize(WebView);
}
}
@@ -0,0 +1,12 @@
<Page
x:Class="VDD_Panel.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid x:Name="ContentArea">
</Grid>
</Page>
@@ -0,0 +1,19 @@
using Microsoft.UI.Xaml.Controls;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Views;
public sealed partial class MainPage : Page
{
public MainViewModel ViewModel
{
get;
}
public MainPage()
{
ViewModel = App.GetService<MainViewModel>();
InitializeComponent();
}
}
@@ -0,0 +1,67 @@
<Page
x:Class="VDD_Panel.Views.SettingsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:helpers="using:VDD_Panel.Helpers"
xmlns:xaml="using:Microsoft.UI.Xaml"
mc:Ignorable="d">
<Page.Resources>
<helpers:EnumToBooleanConverter x:Key="EnumToBooleanConverter" />
</Page.Resources>
<Grid>
<StackPanel
x:Name="ContentArea">
<TextBlock x:Uid="Settings_Personalization" Style="{ThemeResource SubtitleTextBlockStyle}" />
<StackPanel Margin="{StaticResource SmallTopBottomMargin}">
<TextBlock x:Uid="Settings_Theme" />
<StackPanel Margin="{StaticResource XSmallTopMargin}">
<RadioButton
x:Uid="Settings_Theme_Light"
Command="{x:Bind ViewModel.SwitchThemeCommand}"
IsChecked="{x:Bind ViewModel.ElementTheme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Light, Mode=OneWay}"
FontSize="15"
GroupName="AppTheme">
<RadioButton.CommandParameter>
<xaml:ElementTheme>Light</xaml:ElementTheme>
</RadioButton.CommandParameter>
</RadioButton>
<RadioButton
x:Uid="Settings_Theme_Dark"
Command="{x:Bind ViewModel.SwitchThemeCommand}"
IsChecked="{x:Bind ViewModel.ElementTheme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Dark, Mode=OneWay}"
FontSize="15"
GroupName="AppTheme">
<RadioButton.CommandParameter>
<xaml:ElementTheme>Dark</xaml:ElementTheme>
</RadioButton.CommandParameter>
</RadioButton>
<RadioButton
x:Uid="Settings_Theme_Default"
Command="{x:Bind ViewModel.SwitchThemeCommand}"
IsChecked="{x:Bind ViewModel.ElementTheme, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter=Default, Mode=OneWay}"
FontSize="15"
GroupName="AppTheme">
<RadioButton.CommandParameter>
<xaml:ElementTheme>Default</xaml:ElementTheme>
</RadioButton.CommandParameter>
</RadioButton>
</StackPanel>
</StackPanel>
<TextBlock x:Uid="Settings_About" Style="{ThemeResource SubtitleTextBlockStyle}" />
<StackPanel Margin="{StaticResource XSmallTopMargin}">
<TextBlock Text="{x:Bind ViewModel.VersionDescription, Mode=OneWay}" Style="{ThemeResource BodyTextBlockStyle}" />
<TextBlock
x:Uid="Settings_AboutDescription"
Margin="{StaticResource XSmallTopMargin}"
Style="{ThemeResource BodyTextBlockStyle}" />
<HyperlinkButton x:Uid="SettingsPage_PrivacyTermsLink" Margin="{StaticResource SettingsPageHyperlinkButtonMargin}" />
</StackPanel>
</StackPanel>
</Grid>
</Page>
@@ -0,0 +1,20 @@
using Microsoft.UI.Xaml.Controls;
using VDD_Panel.ViewModels;
namespace VDD_Panel.Views;
// TODO: Set the URL for your privacy policy by updating SettingsPage_PrivacyTermsLink.NavigateUri in Resources.resw.
public sealed partial class SettingsPage : Page
{
public SettingsViewModel ViewModel
{
get;
}
public SettingsPage()
{
ViewModel = App.GetService<SettingsViewModel>();
InitializeComponent();
}
}
@@ -0,0 +1,90 @@
<Page
x:Class="VDD_Panel.Views.ShellPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:helpers="using:VDD_Panel.Helpers"
xmlns:behaviors="using:VDD_Panel.Behaviors"
xmlns:i="using:Microsoft.Xaml.Interactivity"
Loaded="OnLoaded">
<Grid>
<Grid x:Name="AppTitleBar"
Canvas.ZIndex="1"
Height="{Binding ElementName=NavigationViewControl, Path=CompactPaneLength}"
IsHitTestVisible="True"
VerticalAlignment="Top">
<Image Source="/Assets/WindowIcon.ico"
HorizontalAlignment="Left"
Width="16"
Height="16" />
<TextBlock x:Name="AppTitleBarText"
VerticalAlignment="Center"
TextWrapping="NoWrap"
Style="{StaticResource CaptionTextBlockStyle}"
Margin="28,0,0,0"/>
</Grid>
<NavigationView
x:Name="NavigationViewControl"
Canvas.ZIndex="0"
IsBackButtonVisible="Visible"
IsBackEnabled="{x:Bind ViewModel.IsBackEnabled, Mode=OneWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=OneWay}"
IsSettingsVisible="True"
ExpandedModeThresholdWidth="1280"
DisplayModeChanged="NavigationViewControl_DisplayModeChanged"
Header="{x:Bind ((ContentControl)ViewModel.Selected).Content, Mode=OneWay}">
<NavigationView.MenuItems>
<!--
TODO: Update item titles by updating <x:Uid>.Content entries in Strings/en-us/Resources.resw.
https://docs.microsoft.com/windows/uwp/app-resources/localize-strings-ui-manifest#refer-to-a-string-resource-identifier-from-xaml
TODO: Update item icons by updating FontIcon.Glyph properties.
https://docs.microsoft.com/windows/apps/design/style/segoe-fluent-icons-font#icon-list
-->
<NavigationViewItem x:Uid="Shell_Main" helpers:NavigationHelper.NavigateTo="VDD_Panel.ViewModels.MainViewModel">
<NavigationViewItem.Icon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xe7c3;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem x:Uid="Shell_Configure" helpers:NavigationHelper.NavigateTo="VDD_Panel.ViewModels.ConfigureViewModel">
<NavigationViewItem.Icon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xe7c3;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
<NavigationViewItem x:Uid="Shell_GitHub" helpers:NavigationHelper.NavigateTo="VDD_Panel.ViewModels.GitHubViewModel">
<NavigationViewItem.Icon>
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}" Glyph="&#xe774;"/>
</NavigationViewItem.Icon>
</NavigationViewItem>
</NavigationView.MenuItems>
<NavigationView.HeaderTemplate>
<DataTemplate>
<Grid>
<TextBlock
Text="{Binding}"
Style="{ThemeResource TitleTextBlockStyle}" />
</Grid>
</DataTemplate>
</NavigationView.HeaderTemplate>
<i:Interaction.Behaviors>
<behaviors:NavigationViewHeaderBehavior
DefaultHeader="{x:Bind ((ContentControl)ViewModel.Selected).Content, Mode=OneWay}">
<behaviors:NavigationViewHeaderBehavior.DefaultHeaderTemplate>
<DataTemplate>
<Grid>
<TextBlock
Text="{Binding}"
Style="{ThemeResource TitleTextBlockStyle}" />
</Grid>
</DataTemplate>
</behaviors:NavigationViewHeaderBehavior.DefaultHeaderTemplate>
</behaviors:NavigationViewHeaderBehavior>
</i:Interaction.Behaviors>
<Grid Margin="{StaticResource NavigationViewPageContentMargin}">
<Frame x:Name="NavigationFrame" />
</Grid>
</NavigationView>
</Grid>
</Page>
@@ -0,0 +1,85 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using VDD_Panel.Contracts.Services;
using VDD_Panel.Helpers;
using VDD_Panel.ViewModels;
using Windows.System;
namespace VDD_Panel.Views;
// TODO: Update NavigationViewItem titles and icons in ShellPage.xaml.
public sealed partial class ShellPage : Page
{
public ShellViewModel ViewModel
{
get;
}
public ShellPage(ShellViewModel viewModel)
{
ViewModel = viewModel;
InitializeComponent();
ViewModel.NavigationService.Frame = NavigationFrame;
ViewModel.NavigationViewService.Initialize(NavigationViewControl);
// TODO: Set the title bar icon by updating /Assets/WindowIcon.ico.
// A custom title bar is required for full window theme and Mica support.
// https://docs.microsoft.com/windows/apps/develop/title-bar?tabs=winui3#full-customization
App.MainWindow.ExtendsContentIntoTitleBar = true;
App.MainWindow.SetTitleBar(AppTitleBar);
App.MainWindow.Activated += MainWindow_Activated;
AppTitleBarText.Text = "AppDisplayName".GetLocalized();
}
private void OnLoaded(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
{
TitleBarHelper.UpdateTitleBar(RequestedTheme);
KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.Left, VirtualKeyModifiers.Menu));
KeyboardAccelerators.Add(BuildKeyboardAccelerator(VirtualKey.GoBack));
}
private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
{
App.AppTitlebar = AppTitleBarText as UIElement;
}
private void NavigationViewControl_DisplayModeChanged(NavigationView sender, NavigationViewDisplayModeChangedEventArgs args)
{
AppTitleBar.Margin = new Thickness()
{
Left = sender.CompactPaneLength * (sender.DisplayMode == NavigationViewDisplayMode.Minimal ? 2 : 1),
Top = AppTitleBar.Margin.Top,
Right = AppTitleBar.Margin.Right,
Bottom = AppTitleBar.Margin.Bottom
};
}
private static KeyboardAccelerator BuildKeyboardAccelerator(VirtualKey key, VirtualKeyModifiers? modifiers = null)
{
var keyboardAccelerator = new KeyboardAccelerator() { Key = key };
if (modifiers.HasValue)
{
keyboardAccelerator.Modifiers = modifiers.Value;
}
keyboardAccelerator.Invoked += OnKeyboardAcceleratorInvoked;
return keyboardAccelerator;
}
private static void OnKeyboardAcceleratorInvoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
var navigationService = App.GetService<INavigationService>();
var result = navigationService.GoBack();
args.Handled = result;
}
}
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="VDD_Panel.app"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
</windowsSettings>
</application>
</assembly>
@@ -0,0 +1,6 @@
{
"LocalSettingsOptions": {
"ApplicationDataFolder": "VDD_Panel/ApplicationData",
"LocalSettingsFile": "LocalSettings.json"
}
}
+38
View File
@@ -0,0 +1,38 @@
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
$repoName = "PSGallery"
$moduleName1 = "DisplayConfig"
$moduleName2 = "MonitorConfig"
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})) {
& .\dep_fix.ps1
}
# Import the local module
$dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path
import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue
# Import the other localmodule
$mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path
import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue
$disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber
$bpcc = Get-DisplayColorInfo -DisplayId $disp | Select-Object BitsPerColorChannel | Select-Object -ExpandProperty BitsPerColorChannel
if ( $bpcc -is [int] ) {
if ( $bpcc -gt 8 ) {
Disable-DisplayAdvancedColor -DisplayId $disp
break
}
if ( $bpcc -lt 10 ) {
Enable-DisplayAdvancedColor -DisplayId $disp
break
}
}
else { write-error "Something went wrong in identifying the Colormode of the display." ; break }
+9
View File
@@ -0,0 +1,9 @@
#Scripts
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.
This is more ment as a framework for "tinkers" to make use of Powershell to change settings on the fly.
To use these, you should be at least be comfortable with Powershell and understand Admin privilegiets, risk/reward.
PR's are welcome for improvements or other/more functions.
+39
View File
@@ -0,0 +1,39 @@
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
$repoName = "PSGallery"
$moduleName1 = "DisplayConfig"
$moduleName2 = "MonitorConfig"
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})) {
& .\dep_fix.ps1
}
# Import the local module
$dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path
import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Import the other localmodule
$mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path
import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Check if there are enough arguments
$numArgs = $args.Count
switch ($numArgs) {
0 { Write-Error "This script requires at least 2 arguments Xres Yres."; break }
1 { Write-Error "This script requires at least 2 arguments Xres Yres."; break }
2 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber
$vres = $args[0]
$hres = $args[1]
continue
}
default { Write-Error "Invalid number of arguments: $numArgs"; break }
}
# Setting the resolution on the correct display.
Get-DisplayConfig | Set-DisplayResolution -DisplayId $disp -Width $vres -Height $hres | Use-DisplayConfig
+32
View File
@@ -0,0 +1,32 @@
# Define the repository name and URL
$repoName = "PSGallery"
$repoUrl = "https://www.powershellgallery.com/api/v2"
# Check if the repository is registered
if (-not (Get-PSRepository -Name $repoName)) {
# Register the repository
Register-PSRepository -Name $repoName -SourceLocation $repoUrl -Confirm:$false -InformationAction:Ignore -WarningAction:SilentlyContinue
}
#Trust the repo, either its allready installed or newly added
Set-PSRepository -Name $repoName -InstallationPolicy Trusted -InformationAction:Ignore -WarningAction:SilentlyContinue
# Define the module name and version
$moduleName1 = "DisplayConfig"
$version1 = "1.1.1"
# Define the module name and version
$moduleName2 = "MonitorConfig"
$version2 = "1.0.3"
# Check if the module1 is installed
if (-not (Get-InstalledModule -Name $moduleName1 -MinimumVersion $version1)) {
# Save the module
Save-Module -Name $moduleName1 -Repository $repoName -RequiredVersion $version1 -Confirm:$false -InformationAction:Ignore -WarningAction:SilentlyContinue
}
# Check if the module2 is installed
if (-not (Get-InstalledModule -Name $moduleName2 -MinimumVersion $version2)) {
# Save the module
Save-Module -Name $moduleName2 -Repository $repoName -RequiredVersion $version2 -Confirm:$false -InformationAction:Ignore -WarningAction:SilentlyContinue
}
+26
View File
@@ -0,0 +1,26 @@
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
$repoName = "PSGallery"
$moduleName1 = "DisplayConfig"
$moduleName2 = "MonitorConfig"
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})) {
& .\dep_fix.ps1
}
# Import the local module
$dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path; import-module -name $dpth
# Import the other localmodule
$mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path; import-module -name $mpth
$disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber
Set-DisplayPrimary -DisplayId $disp
+39
View File
@@ -0,0 +1,39 @@
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
$repoName = "PSGallery"
$moduleName1 = "DisplayConfig"
$moduleName2 = "MonitorConfig"
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})) {
& .\dep_fix.ps1
}
# Import the local module
$dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path
import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Import the other localmodule
$mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path
import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Use the module's functions and cmdlets in your script
# Check if there are enough arguments
$numArgs = $args.Count
switch ($numArgs) {
0 { Write-Error "This script requires a refreshrate above 59 or reset"; break }
1 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber
$rate = $args[0]
continue
}
default { Write-Error "Invalid number of arguments: $numArgs"; break }
}
# Setting the resolution on the correct display.
Get-DisplayConfig | Set-DisplayRefreshRate -DisplayId $disp -RefreshRate $rate | Use-DisplayConfig
+46
View File
@@ -0,0 +1,46 @@
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
$repoName = "PSGallery"
$moduleName1 = "DisplayConfig"
$moduleName2 = "MonitorConfig"
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})) {
& .\dep_fix.ps1
}
# Import the local module
$dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path
import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Import the other localmodule
$mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path
import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Check if there are enough arguments
$numArgs = $args.Count
switch ($numArgs) {
0 { Write-Error "This script requires at least 1, rotation in degrees ex. 90/180/270."; break }
1 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber
switch ($args[0]) {
90 { $degree = "Rotate90"
continue
}
180 { $degree = "Rotate180"
continue
}
270 { $degree = "Rotate270"
continue
}
default { Write-Error "Invalid rotation angle(valid 90,180,270)."; break }
}
default { Write-Error "Invalid number of arguments: $numArgs"; break }
}
# Setting the resolution on the correct display.
Get-DisplayConfig | Set-DisplayRotation -DisplayId $disp -Rotation $degree | Use-DisplayConfig
+54
View File
@@ -0,0 +1,54 @@
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
$repoName = "PSGallery"
$moduleName1 = "DisplayConfig"
$moduleName2 = "MonitorConfig"
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})) {
& .\dep_fix.ps1
}
# Import the local module
$dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path
import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Import the other localmodule
$mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path
import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Check if there are enough arguments
$numArgs = $args.Count
switch ($numArgs) {
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 }
1 { $disp = Get-Monitor | Select-String -Pattern "MTT1337" | Select-Object LineNumber | Select-Object -ExpandProperty LineNumber
$maxscale = Get-DisplayScale -DisplayId $disp | Select-Object -ExpandProperty MaxScale
if ( $args[0] -is [int] ) {
if ( $args[0] -le $maxscale -And $args[0] -ge 100 ) {
Set-DisplayScale -DisplayId $disp -Scale $args[0]
break
}
else {
Write-Error "Invalid scale percentage."
break
}
}
else {
if ( $args[0] -eq "reset" ) {
Set-DisplayScale -DisplayId $disp -Recommended
break
}
else {
Write-Error "Invalid arguments: 'reset' or a valid percentage value like 150 is acceptable."
break
}
}
}
default { Write-Error "Invalid number of arguments: $numArgs"; break }
}
@@ -1,3 +1,4 @@
# submitted by zjoasan
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
@@ -7,7 +8,7 @@
}
}
$device = get-pnpdevice -class Display -FriendlyName 'IddSampleDriver Device HDR' -ErrorAction SilentlyContinue
$device = Get-PnpDevice -Class Display -ErrorAction SilentlyContinue | Where-Object { $_.FriendlyName -eq 'IddSampleDriver Device HDR' -or $_.FriendlyName -eq 'Virtual Display Driver' }
if ($device) {
if ($device.Status -eq 'OK') {
+36
View File
@@ -0,0 +1,36 @@
# Self-elevate the script if required
if (-Not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] 'Administrator')) {
if ([int](Get-CimInstance -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber) -ge 6000) {
$CommandLine = "-File `"" + $MyInvocation.MyCommand.Path + "`" " + $MyInvocation.UnboundArguments
Start-Process -FilePath PowerShell.exe -Verb Runas -ArgumentList $CommandLine
Exit
}
}
$repoName = "PSGallery"
$moduleName1 = "DisplayConfig"
$moduleName2 = "MonitorConfig"
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})) {
& .\dep_fix.ps1
}
# Import the local module
$dpth = Get-Module -ListAvailable $moduleName1 | select path | Select-Object -ExpandProperty path
import-module -name $dpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
# Import the other localmodule
$mpth = Get-Module -ListAvailable $moduleName2 | select path | Select-Object -ExpandProperty path
import-module -name $mpth -InformationAction:Ignore -Verbose:$false -WarningAction:SilentlyContinue -Confirm:$false
$profi = Get-DisplayProfile
if ( $profi -eq "Extend" ) {
Set-DisplayProfile Clone
break
}
if ( $profi -eq "Clone" ) {
Set-DisplayProfile Extend
break
}
Loaded 100 of 131 files, more files were not shown because too many files have changed in this diff. Show more