Compare commits

..

397 Commits
v0.30 ... v0.72

Author SHA1 Message Date
Serge
20e7d220e5 Added APU slider 2023-05-29 22:07:08 +02:00
Serge
2f5543ce84 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-29 19:39:00 +02:00
Serge
4c55e16f2e UI tweaks 2023-05-29 19:38:57 +02:00
Serge
30544e74d7 Update README.md 2023-05-29 19:18:25 +02:00
Serge
f5925accb3 Merge pull request #475 from MDowski/patch-2
Update to Polish translation
2023-05-29 15:31:29 +02:00
MD
842ea2a92d Update to Polish translation
Tweaks in declination and words shortening.
2023-05-29 14:58:37 +02:00
Serge
1ca97bd3f4 Updated translations 2023-05-29 14:36:55 +02:00
Serge
8a1dd9f137 Bumped version number 2023-05-29 13:15:54 +02:00
Serge
325f16cf55 Added optimization service to debloat.bat 2023-05-29 13:15:23 +02:00
Serge
42cc1bdb98 Added option to stop all GPU apps before setting Eco 2023-05-29 12:16:19 +02:00
Serge
83a2d1dc9f Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-28 21:43:26 +02:00
Serge
3aae223b15 Added Ctr+Shif+F12 binding to toggle app window 2023-05-28 21:43:24 +02:00
Serge
b22d2f8ceb Update README.md 2023-05-28 21:26:05 +02:00
Serge
2041861a14 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-28 16:09:46 +02:00
Serge
dfc3c0e515 UI tweaks 2023-05-28 16:09:44 +02:00
Serge
796ec34284 Update README.md 2023-05-28 14:06:12 +02:00
Serge
50894a59d3 USB adjustment 2023-05-28 12:15:43 +02:00
Serge
1472004d4b Backlight timeouts 2023-05-28 12:02:29 +02:00
Serge
36c42ed05f Merge pull request #468 from etylix/main
Add Vietnamese translations
2023-05-28 11:45:04 +02:00
Hoang Pham Anh Duy
66220351f1 Add Vietnamese translations 2023-05-28 16:40:49 +07:00
Serge
8f2c8842e0 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-27 22:44:55 +02:00
Serge
1cda822820 Backlight control fix 2023-05-27 22:44:54 +02:00
Serge
2afba74dd5 Update README.md 2023-05-26 11:52:29 +02:00
Serge
e69f9d1014 Update README.md 2023-05-26 11:48:13 +02:00
Serge
47d96aca61 Keybinding fix 2023-05-25 13:30:33 +02:00
Serge
f36fb6ca55 Hide GPU fans from UI if they don't exist in system 2023-05-24 23:47:08 +02:00
Serge
e765b4f037 Tweaks and fixes 2023-05-24 14:34:43 +02:00
Serge
f395c706f6 UI tweaks 2023-05-23 20:49:56 +02:00
Serge
444fdcdd97 Backlight fix 2023-05-23 15:27:00 +02:00
Serge
b874900393 French language fixes 2023-05-23 11:14:03 +02:00
Serge
05aad0f1ad Matrix tweaks 2023-05-23 10:58:27 +02:00
Serge
a34cc1cb03 Animatrix clock fix 2023-05-22 21:57:21 +02:00
Serge
8c557344db Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-22 17:57:08 +02:00
Serge
5b2a4cb065 UI tweaks 2023-05-22 17:57:06 +02:00
Serge
51bcad8bbe Merge pull request #434 from marcelomijas/main
Spanish translation of new key functions
2023-05-22 16:26:13 +02:00
Marcelo Moreno
125aa44e6c Spanish translation of new key functions 2023-05-22 16:21:58 +02:00
Serge
9e6ca7c2e2 Bumped version to 0.67 2023-05-22 16:15:24 +02:00
Serge
252cc9d868 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-22 13:31:03 +02:00
Serge
0b03b62a2d Extended support for Z13 external keyboard 2023-05-22 13:31:01 +02:00
Serge
ff7a5463d6 Update README.md 2023-05-22 11:44:10 +02:00
Serge
5134aaca9d Native brightness OSD 2023-05-22 11:18:57 +02:00
Serge
2a5c2e02ac Anime matrix fix 2023-05-21 21:23:55 +02:00
Serge
80e3971dad m1,m2 bindings 2023-05-21 20:44:04 +02:00
Serge
ac60986646 Sleep Fix 2023-05-21 19:19:26 +02:00
Serge
1e0169a71d Added M1/M2 keys and keyboard init 2023-05-21 19:01:43 +02:00
Serge
e0346a8af8 UI Tweaks 2023-05-21 18:06:41 +02:00
Serge
4ee97fdbc4 XGM Fixes 2023-05-21 17:42:15 +02:00
Serge
34075b67d4 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-21 12:27:54 +02:00
Serge
4ed9675d99 Refactoring 2023-05-21 12:27:52 +02:00
Serge
af3538e105 Update README.md 2023-05-21 00:24:57 +02:00
Serge
d818405e04 Bumped version to 0.65 2023-05-20 23:14:15 +02:00
Serge
9794229f3f Extra icons for OSD 2023-05-20 22:59:17 +02:00
Serge
9f56959c67 Some OSD notifications 2023-05-20 21:51:02 +02:00
Serge
09e6676b7c Merge pull request #418 from marcelomijas/main
Update Spanish translation
2023-05-20 20:51:57 +02:00
Serge
6adb2e2fcf Keyboard Reading 2023-05-20 20:50:58 +02:00
Marcelo Moreno
08cc4409a9 Update Spanish translation 2023-05-20 20:37:54 +02:00
Serge
1ac0f2be08 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-20 14:28:08 +02:00
Serge
05e66d3b95 Tweaks 2023-05-20 14:28:05 +02:00
Serge
0f8f1e9ce5 Merge pull request #300 from tbateson/main
Add GitHub workflows
2023-05-20 11:51:42 +02:00
Thomas Bateson
d37b46c588 Add GitHub workflows 2023-05-19 13:32:31 -05:00
Serge
020a7d074f Some renamings 2023-05-19 19:14:07 +02:00
Serge
7eb7cc9f78 UI tweaks 2023-05-19 16:09:27 +02:00
Serge
38d60e88ea Fixed anime matrix crash 2023-05-19 13:46:49 +02:00
Serge
0cc16765b6 Update README.md 2023-05-19 11:27:24 +02:00
Serge
96f705806b Update README.md 2023-05-19 11:17:27 +02:00
Serge
d1cceda2ab UI Tweaks 2023-05-19 10:40:16 +02:00
Serge
381b4dd3e8 Merge pull request #409 from TomBonnot/main
Adding French and Português Version
2023-05-19 00:16:11 +02:00
Tom Bonnot
a99dcbf445 Last changes on portuguese-brazilian version + deleting .idea files 2023-05-18 18:12:44 -04:00
Tom Bonnot
4751383a3a Saving progress on pt-br translation 2023-05-18 15:50:32 -04:00
Serge
06320afcb3 Audio visualizer 2023-05-18 18:21:09 +02:00
Serge
0eb6209eda Matrix audio visualizer 2023-05-18 17:42:19 +02:00
Tom Bonnot
a342cab9a6 Final version for French translation 2023-05-18 11:40:02 -04:00
Tom Bonnot
12c6482f61 Adding pt-br and completion of fr version (might need some corrections) 2023-05-18 10:30:05 -04:00
Tom Bonnot
20933bfd8d First commit - French version 2023-05-18 09:51:30 -04:00
Serge
c66c8e9030 Custom keybinding for mode toggle 2023-05-17 20:33:41 +02:00
Serge
14b677514b Update README.md 2023-05-17 17:17:13 +02:00
Serge
ce266ffe07 Merge pull request #402 from IceStormNG/german-translation
German translation
2023-05-17 16:51:04 +02:00
Serge
f29410fa2a Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-17 14:52:09 +02:00
Serge
7117b58746 ACPI events listener 2023-05-17 14:52:06 +02:00
Carsten Braun
0456fa013c Improbed a few translations and fixed typos. 2023-05-17 13:11:11 +02:00
Carsten Braun
6a4aa4e138 Localize fan speed labels in the main window 2023-05-17 10:47:41 +02:00
IceStormNG
d75067b40c Merge branch 'seerge:main' into german-translation 2023-05-17 10:39:02 +02:00
Carsten Braun
de45038911 Translated the App to German. Added a few additional resources for localization 2023-05-16 16:20:00 +02:00
Serge
e23c727e79 Update README.md 2023-05-16 15:44:30 +02:00
Serge
2f2c534278 Merge pull request #394 from lswlc33/main
Update Strings.zh-CN.resx
2023-05-16 15:21:34 +02:00
Serge
bdbec79aba UI tweaks 2023-05-16 15:19:53 +02:00
雪中明月
e3d0a04fa4 Update Strings.zh-CN.resx 2023-05-16 21:12:58 +08:00
Serge
4dd7d41cf4 Merge pull request #392 from IceStormNG/windows-power-plan-changes-optional
Windows power plan changes optional
2023-05-16 14:53:58 +02:00
Carsten Braun
8370217cef This is not a perf config but a regular config value. 2023-05-16 13:34:40 +02:00
Carsten Braun
63c1829edd We can reference the checkbox directly 2023-05-16 13:34:26 +02:00
Carsten Braun
69e5a0448e Accomodate for non-exitent settings value 2023-05-16 13:30:08 +02:00
Carsten Braun
b74b9ae257 Fix nullability 2023-05-16 13:29:48 +02:00
Carsten Braun
71e007d8ad Fixed UI that VS Forms Designer broke 2023-05-16 13:29:31 +02:00
Carsten Braun
6896166c3c Fixed French translation value 2023-05-16 12:36:26 +02:00
Carsten Braun
fd89d9c13a Changed string to "Power Mode" instead of "power plan" 2023-05-16 12:33:15 +02:00
Carsten Braun
8bec153da8 Fixed localization key for french 2023-05-16 12:30:57 +02:00
Carsten Braun
7d968f5f08 Do not set default value. 2023-05-16 12:24:06 +02:00
Carsten Braun
ac5fc3f96e Revert "Revert "Adjustment of Windows Power Overlay is now optional""
This reverts commit 8804d19567.
2023-05-16 12:21:28 +02:00
Serge
8590d0301a Merge pull request #391 from seerge/revert-385-windows-power-plan-changes-optional
Revert "Adjustment of Windows Power Overlay is now optional"
2023-05-16 11:39:41 +02:00
Serge
8804d19567 Revert "Adjustment of Windows Power Overlay is now optional" 2023-05-16 11:38:17 +02:00
Serge
57ce0631a3 Merge pull request #385 from IceStormNG/windows-power-plan-changes-optional
Adjustment of Windows Power Overlay is now optional
2023-05-16 11:30:41 +02:00
Carsten Braun
b796f9f9d4 Moved checkbox to 2023-05-16 10:41:02 +02:00
Serge
f39563fcdf Added touchpad toggle for tablet mode on x13/x16 2023-05-15 23:59:21 +02:00
Serge
853d0c231d Auto update 2023-05-15 22:23:16 +02:00
Serge
df3324d641 Auto update 2023-05-15 22:21:41 +02:00
Serge
75c90ee155 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-15 22:11:29 +02:00
Serge
4015e0a7f7 Added auto-update checker 2023-05-15 22:11:27 +02:00
Carsten Braun
2a82e41894 Adjustment of Windows Power Overlay is now optional 2023-05-15 13:23:20 +02:00
Serge
a5541dfe10 Update README.md 2023-05-14 19:52:02 +02:00
Serge
fd3a139c47 Aura tweaks 2023-05-14 10:28:48 +02:00
Serge
608b8571d4 Fix for turkish keyboard, tweak for default fan curves 2023-05-13 22:13:00 +02:00
Serge
82a39bcfa1 Merge pull request #375 from IceStormNG/animematrix-for-GU604
Supports AniMeMatrix for Zephyrus M16 2023 (GU604)
2023-05-13 18:24:37 +02:00
Carsten Braun
f9ccd92dc6 Supports AniMeMatrix for Zephyrus M16 2023 (GU604) 2023-05-13 18:10:18 +02:00
Serge
1fadc6c31e Hotfix for possible crash 2023-05-13 09:43:26 +02:00
Serge
0b7dd42a5d UI tweak 2023-05-12 17:21:04 +02:00
Serge
51cd700e25 Improved GPU restart 2023-05-12 15:51:57 +02:00
Serge
7484253007 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-12 14:06:19 +02:00
Serge
f5cf768017 Display workaround 2023-05-12 14:06:15 +02:00
Serge
ca57669596 NV Clocks tweaks 2023-05-11 19:38:53 +02:00
Serge
35f1a3a25b Clock tweak 2023-05-11 11:18:42 +02:00
Serge
b7afe94b8d Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-11 10:52:41 +02:00
Serge
97c97e8e19 Eco tweaks 2023-05-11 10:52:40 +02:00
Serge
ffc5a6f641 Update README.md 2023-05-11 00:40:30 +02:00
Serge
f87e6c5c88 Update README.md 2023-05-11 00:39:07 +02:00
Serge
22f136fe9e Crash fix 2023-05-11 00:35:03 +02:00
Serge
6d85376734 Extra logs 2023-05-10 23:24:54 +02:00
Serge
62512a7c05 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-10 18:38:51 +02:00
Serge
7a6301328c GPU Restart 2023-05-10 18:38:49 +02:00
Serge
3c6c4d122d Update README.md 2023-05-10 15:31:20 +02:00
Serge
0142c25929 Overclocking logic, added restart-gpu workaround 2023-05-10 14:06:33 +02:00
Serge
27bc7339d8 Merge pull request #351 from marcelomijas/main
Update Spanish translation
2023-05-09 22:11:44 +02:00
Marcelo Moreno
2985fe378c Small fix... 2023-05-09 22:09:36 +02:00
Marcelo Moreno
71daba25a8 Update Spanish translation
Update the Spanish translation file so it has the same fields as the original "Strings.resx", and translated the new items. :)
2023-05-09 22:01:09 +02:00
Serge
16feeb05a1 Clocks fixes 2023-05-09 18:21:07 +02:00
Serge
c69bf65c84 Clocks fixes 2023-05-09 18:02:59 +02:00
Serge
56ea434626 Aura fix 2023-05-09 17:16:10 +02:00
Serge
432508cfc5 GPU settings tweaks 2023-05-09 16:51:15 +02:00
Serge
deb515066d Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-09 16:13:40 +02:00
Serge
ac19a822f7 GPU eco check 2023-05-09 16:13:35 +02:00
Serge
41caaefc97 Improved aura logging 2023-05-09 16:05:57 +02:00
Serge
a4488fa93b GPU Settings will be saved and auto-applied for each mode 2023-05-09 14:29:52 +02:00
Serge
57c893ef77 XGMobile backlight control 2023-05-08 19:33:49 +02:00
Serge
07020c3561 Extra aura control 2023-05-08 11:00:41 +02:00
Serge
ea134b640b Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-08 10:39:11 +02:00
Serge
5c3f1259f6 Extra Backlight control 2023-05-08 10:39:09 +02:00
Serge
09fd4e4a13 Update README.md 2023-05-08 09:58:36 +02:00
Serge
31c48eb998 Update README.md 2023-05-07 21:12:38 +02:00
Serge
0c1f216853 Update README.md 2023-05-07 20:54:07 +02:00
Serge
83dc491b64 Update README.md 2023-05-07 19:42:52 +02:00
Serge
a75d1ad604 Eco mode overclocking fix 2023-05-07 18:12:15 +02:00
Serge
88f466103e Eco mode overclocking fix 2023-05-07 18:10:18 +02:00
Serge
efb9b73ff5 Anime matrix clock fix 2023-05-07 12:14:49 +02:00
Serge
2c4bdb87aa Typo fix 2023-05-07 11:53:22 +02:00
Serge
832f13d8e4 UI tweaks 2023-05-07 11:17:45 +02:00
Serge
479572e39d Startup admin restarter 2023-05-07 00:24:47 +02:00
Serge
460267aac7 GPU overclocking fixes 2023-05-07 00:14:26 +02:00
Serge
e71c8e32ef GPU boost / temp limits control 2023-05-06 19:12:50 +02:00
Serge
6fe6492df3 GPU clocks tweaks 2023-05-06 18:17:37 +02:00
Serge
c61f4d1608 Experimental GPU overclock 2023-05-06 14:40:52 +02:00
Serge
8e1099545a Overdrive fix 2023-05-05 12:35:55 +02:00
Serge
7740678cd4 Added on/off control for aura lightbar, lid and logo 2023-05-05 11:44:33 +02:00
Serge
c6faec9628 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-04 13:55:50 +02:00
Serge
3a5c4de9b6 Context menu 2023-05-04 13:55:49 +02:00
Serge
f90fec24b9 Update README.md 2023-05-03 19:56:58 +02:00
Serge
240537dbd4 Merge pull request #315 from marcelomijas/main
Added Spanish translation for new options
2023-05-03 19:56:17 +02:00
Marcelo Moreno
cc3c16cdf1 Added Spanish translation for new options
Added Spanish translation for the new options:
- dGPU off in Optimized mode when on USB-charger.
- Minilled related options.
2023-05-03 19:19:17 +02:00
Serge
a7c662a0d4 Merge branch 'main' of https://github.com/seerge/g-helper 2023-05-03 18:18:44 +02:00
Serge
b0958cb2fc Translations fix 2023-05-03 18:18:42 +02:00
Serge
29f27ed4d6 Update README.md 2023-05-03 18:07:31 +02:00
Serge
801096299b Anime matrix tweaks 2023-05-03 17:53:21 +02:00
Serge
5ed1de0fcf Added option to keep dGPU off on usb-c 2023-05-03 16:49:12 +02:00
Serge
0ec0a382e9 Merge 2023-05-01 15:13:15 +02:00
Serge
e810adb358 Added Screen Toggle feature for M3 button 2023-05-01 15:12:08 +02:00
Serge
dc6c94fe4a Merge pull request #305 from sklynic/main
Minor update of zh-CN translation
2023-05-01 12:04:24 +02:00
sklynic
8479c129ff Update translation of zh-CN 2023-05-01 17:58:47 +08:00
Serge
3173c2e688 Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-27 10:14:15 +02:00
Serge
730ba0a2f9 Matrix logging 2023-04-27 10:14:13 +02:00
Serge
d26a83287d Update README.md 2023-04-22 22:42:11 +02:00
Serge
47deb669d1 UI tweaks 2023-04-22 00:09:22 +02:00
Serge
a30f5d801b UI tweaks 2023-04-21 23:32:02 +02:00
Serge
75f4b9f2c5 Update README.md 2023-04-21 16:19:26 +02:00
Serge
2289f36ba5 Create FUNDING.yml 2023-04-21 16:13:27 +02:00
Serge
6322e25e78 Merge pull request #279 from marcelomijas/main
Spanish translation fix for v0.55
2023-04-21 15:01:10 +02:00
seerge
62c0147548 - 2023-04-21 14:59:19 +02:00
seerge
9bd2688da2 UI tweaks 2023-04-21 14:59:06 +02:00
Marcelo Moreno
9649814085 Add files via upload 2023-04-21 14:46:03 +02:00
seerge
1ebc2021f6 KB Brightness control for TUF models 2023-04-20 14:53:37 +02:00
seerge
52b165f250 Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-19 17:42:01 +02:00
seerge
b2ed390bdf XGMobile support 2023-04-19 17:41:59 +02:00
Serge
1588f84c97 Update README.md 2023-04-19 16:46:28 +02:00
seerge
a3a2fdfe14 Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-18 17:50:12 +02:00
seerge
2c867eb960 UI tweaks 2023-04-18 17:50:10 +02:00
Serge
6fbf4f2a49 Merge pull request #258 from lswlc33/main
Update Strings.zh-CN.resx
2023-04-16 19:01:35 +02:00
Serge
d4ecb2bcf3 Merge pull request #259 from lswlc33/patch-2
Update README.zh-CN.md
2023-04-16 19:01:26 +02:00
雪中明月
c70c6ef4d6 Update README.zh-CN.md 2023-04-16 21:30:14 +08:00
雪中明月
5d77d5c700 Update Strings.zh-CN.resx 2023-04-16 21:23:01 +08:00
seerge
89f096778d Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-16 13:55:03 +02:00
seerge
2b9fc913ad TUF keyboard adjustment 2023-04-16 13:55:01 +02:00
Serge
4acbf5adf1 Merge pull request #256 from lswlc33/main
update readme.md's language switch button
2023-04-16 13:03:47 +02:00
seerge
48ea1b588f Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-16 13:01:36 +02:00
seerge
cb15161fc4 Warning label when custom fan profile is not supported 2023-04-16 13:01:34 +02:00
雪中明月
d95a612788 Update README.md 2023-04-16 18:55:46 +08:00
雪中明月
0a724926ee update readme.md's language switch button 2023-04-16 10:50:20 +00:00
Serge
353ed998db Update README.md 2023-04-16 11:44:23 +02:00
seerge
0afee18f20 Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-15 20:12:35 +02:00
seerge
8154883d49 It's fine 2023-04-15 20:12:33 +02:00
Serge
feb4198c0f Merge pull request #250 from marcelomijas/main
"Keyboard backlight" extra options Spanish translation fix
2023-04-15 19:48:25 +02:00
Marcelo Moreno
6edf2d9447 Add files via upload 2023-04-15 19:42:51 +02:00
seerge
25f0af1103 AdjustAllLevels fixes 2023-04-15 16:02:07 +02:00
Serge
4f9cc4a94e Merge pull request #237 from hungqbui/main
Add fan levels auto-adjust
2023-04-15 01:12:15 +02:00
Serge
e973f09f4e Update README.md 2023-04-15 01:11:40 +02:00
Serge
cd0662e11f Update README.md 2023-04-14 17:58:09 +02:00
seerge
ee43af2824 Clock fix for devices with low DPI 2023-04-14 17:50:26 +02:00
Serge
d620ca010c Update README.md 2023-04-13 21:10:57 +02:00
seerge
6bd77ab45b UI tweaks 2023-04-13 18:53:14 +02:00
Hung Bui
99a490996d Fix OutOfBounds error, and correct variables name 2023-04-13 11:23:56 -05:00
seerge
096ea3b8e9 Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-13 18:01:29 +02:00
Serge
5f10f5b1e8 Update README.md 2023-04-13 19:25:58 +02:00
seerge
36219383ce UI tweaks 2023-04-13 18:01:27 +02:00
seerge
78862c6558 Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-13 17:21:27 +02:00
Serge
b53a46bb3b Update README.md 2023-04-13 18:21:28 +02:00
seerge
15a681af3b G513 fix 2023-04-13 17:21:25 +02:00
Serge
6341ec7d34 Update README.md 2023-04-13 11:37:31 +02:00
Hung Bui
596c47d371 Add fan levels auto-adjust 2023-04-12 19:07:53 -05:00
seerge
7ff8fec35c Fix for zw-TW translation 2023-04-12 21:51:11 +02:00
seerge
b96185222c Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-12 14:40:47 +02:00
seerge
3346bd5f0e Fans tip fix 2023-04-12 14:40:45 +02:00
Serge
34404feb5b Update bug_report.md 2023-04-12 13:06:07 +02:00
seerge
552bc1020d Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-12 12:05:59 +02:00
seerge
6d0bb5bef7 Boost dropdown fix 2023-04-12 12:05:57 +02:00
Serge
00d80ce7a9 Update bug_report.md 2023-04-12 11:19:52 +02:00
seerge
08e1ed54cd Added fix for Traditional Chinese 2023-04-11 23:25:46 +02:00
seerge
97a22c59f7 - 2023-04-11 22:46:13 +02:00
seerge
d2aa5e9c42 UI tweaks 2023-04-11 22:40:13 +02:00
seerge
2cb0ffab4b Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-11 22:30:19 +02:00
seerge
e3cb2bb4a1 Minor tweaks 2023-04-11 22:30:17 +02:00
Serge
5a734c00c1 Update README.zh-CN.md 2023-04-11 22:19:03 +02:00
Serge
d85ec73a27 Update README.zh-CN.md 2023-04-11 22:18:17 +02:00
Serge
4b9eb99870 Merge pull request #223 from marcelomijas/main
Spanish translation length fix
2023-04-11 21:15:31 +02:00
Marcelo Moreno
c9b939b876 Add files via upload 2023-04-11 20:57:06 +02:00
seerge
9562f77c6f Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-11 19:42:47 +02:00
seerge
7120d2a009 GPU usage tweak 2023-04-11 19:42:44 +02:00
Serge
4fa4295748 Update README.md 2023-04-11 19:31:35 +02:00
Serge
23f28a8ce5 Update README.md 2023-04-11 19:29:47 +02:00
Serge
a94321df04 Merge pull request #221 from sklynic/main
Added zh-CN translation for README and minor edit
2023-04-11 19:25:18 +02:00
sklynic
9917f5543c Synchronized translation for readme 2023-04-12 01:20:40 +08:00
sklynic
78367727ae Merge branch 'seerge:main' into main 2023-04-12 01:14:12 +08:00
Serge
32b83d724d Update README.md 2023-04-11 19:13:41 +02:00
Serge
77b420483d Update README.md 2023-04-11 19:12:46 +02:00
sklynic
9b7842a5e9 Added zh-CN for readme and minor edit 2023-04-12 01:11:45 +08:00
seerge
bee7f35475 Custom Power schemes support 2023-04-11 18:50:12 +02:00
seerge
2daf1f5434 Translations - es 2023-04-11 16:43:07 +02:00
Serge
e979bf708f Merge pull request #219 from marcelomijas/main
Spanish translation
2023-04-11 16:42:09 +02:00
Marcelo Moreno
4d60b1f36d Spanish translation 2023-04-11 16:26:28 +02:00
Serge
8a7c35c7cc Merge pull request #218 from hkaancaliskan/patch-1
Turkish language support
2023-04-11 14:12:40 +02:00
hkaancaliskan
2ecdcd196d pass 2 for turkish 2023-04-11 14:44:00 +03:00
hkaancaliskan
fdd2373b37 first pass for turkish 2023-04-11 14:39:05 +03:00
seerge
ca7ed6c7e9 - 2023-04-11 12:39:48 +02:00
seerge
0cad6bd7a9 Translations 2023-04-11 12:39:31 +02:00
Serge
4545eac93d Merge pull request #217 from lswlc33/main
Improve Chinese translation
2023-04-11 12:36:45 +02:00
Serge
c43e4937d6 Update README.md 2023-04-11 12:33:29 +02:00
雪中明月
e74d730f0c Update Strings.zh.resx 2023-04-11 13:12:36 +08:00
lswlc33
676da38b5f Improve Chinese translation 2023-04-11 09:56:23 +08:00
seerge
b3563e0857 Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-11 01:25:41 +02:00
seerge
b2a01a8bdc Translations 2023-04-11 01:25:39 +02:00
Serge
74fd05d048 Update bug_report.md 2023-04-10 18:42:48 +02:00
Serge
12dc05c5b9 Delete custom.md 2023-04-10 18:41:53 +02:00
seerge
e82dab5e7c Fix for FX507 models 2023-04-09 15:24:09 +02:00
seerge
602dfea1a6 - 2023-04-09 12:26:38 +02:00
seerge
c13a6e9ded Custom keybinds for performance modes 2023-04-09 12:14:47 +02:00
seerge
e11027963f UI tweaks 2023-04-08 13:45:27 +02:00
seerge
9d2b8b506e Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-07 13:37:02 +02:00
seerge
988c9e11dd Theme change fix 2023-04-07 13:37:00 +02:00
Serge
2c6bb32e4a Update README.md 2023-04-07 12:10:19 +02:00
Serge
e33a0d05ed Update README.md 2023-04-07 12:06:11 +02:00
Serge
1c283766aa Update README.md 2023-04-06 23:41:08 +02:00
Serge
f2ef6d197f Update README.md 2023-04-06 14:31:51 +02:00
seerge
13ec0f8911 GPU use simplified for now 2023-04-06 12:19:32 +02:00
seerge
fcf213f1a0 - 2023-04-06 00:02:17 +02:00
seerge
c73b4fce97 Added NVidia GPU usage 2023-04-05 20:25:05 +02:00
seerge
aab1e08729 IsUsedGPU fix 2023-04-05 19:59:10 +02:00
seerge
cf3a84aa3d Added GPU usage check 2023-04-05 19:33:53 +02:00
seerge
8d119b386d - 2023-04-05 13:02:02 +02:00
seerge
0605e63433 UI tweaks 2023-04-04 16:36:26 +02:00
seerge
4634404ed4 Fans + power ui simplification 2023-04-03 21:17:16 +02:00
seerge
dcfaf665cd Force GPU mode 2023-04-02 22:50:13 +02:00
seerge
15e791cbfd Merge branch 'main' of https://github.com/seerge/g-helper 2023-04-02 11:57:01 +02:00
seerge
5d86c821f6 Minor fixes 2023-04-02 11:56:59 +02:00
Serge
e5de404e5c Update README.md 2023-04-01 17:48:46 +02:00
Serge
13aa98e954 Update README.md 2023-04-01 17:40:36 +02:00
seerge
75c397d7a4 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-31 23:08:06 +02:00
seerge
0ad8efdb7d GPU temp reading 2023-03-31 23:08:04 +02:00
Serge
2064f29433 Update README.md 2023-03-31 23:07:43 +02:00
seerge
890c50d90e Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-31 20:05:16 +02:00
seerge
bd207113f8 Fix for possible fan issues on old laptops 2023-03-31 20:05:14 +02:00
Serge
650a5ff5c0 Update bug_report.md 2023-03-31 17:29:57 +02:00
Serge
01ce91a474 Update bug_report.md 2023-03-31 15:58:28 +02:00
seerge
253e1eb095 Added Strix/Scar built in aura modes 2023-03-31 13:50:10 +02:00
seerge
b95768d547 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-31 11:45:48 +02:00
seerge
dfbfd16d23 Clock fix 2023-03-31 11:45:46 +02:00
Serge
3eeac0353a Update README.md 2023-03-30 22:03:21 +02:00
Serge
5e7c9a4191 Update README.md 2023-03-30 21:56:59 +02:00
seerge
ee84ba6304 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-30 21:10:36 +02:00
seerge
d15c6cb073 Improved logging 2023-03-30 21:10:35 +02:00
Serge
1e683a0884 Update README.md 2023-03-30 15:00:04 +02:00
Serge
1ad48bf763 Update README.md 2023-03-30 13:54:53 +02:00
Serge
dcc052a574 Update README.md 2023-03-30 13:54:40 +02:00
Serge
38fca560df Update README.md 2023-03-30 12:14:29 +02:00
seerge
7e0459bd44 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-30 11:57:13 +02:00
seerge
228ad70b8d UI tweaks 2023-03-30 11:57:11 +02:00
Serge
b42e565cd6 Update README.md 2023-03-30 11:53:54 +02:00
Serge
e021d59737 Update README.md 2023-03-30 11:20:50 +02:00
Serge
dba7967ad5 Update README.md 2023-03-30 11:12:24 +02:00
seerge
a7a7170676 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-30 00:00:22 +02:00
seerge
1d43ca3ce4 Max fan RPM auto calibration 2023-03-30 00:00:20 +02:00
Serge
ff7618f16f Update README.md 2023-03-29 23:33:14 +02:00
seerge
bb947bf8bf Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-29 23:32:14 +02:00
seerge
63092d8415 Removed unsupported aura modes for some models 2023-03-29 23:32:12 +02:00
Serge
6fbce2f495 Update README.md 2023-03-29 21:06:36 +02:00
seerge
8d89a04608 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-29 17:51:28 +02:00
seerge
0cbc48d526 Added old cpu temp reading as fallback 2023-03-29 17:51:25 +02:00
Serge
81013ca0be Update README.md 2023-03-29 17:32:07 +02:00
seerge
af2509fc17 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-29 17:04:24 +02:00
seerge
136b5b4f55 Added native temp sensors, brightness controll, etc 2023-03-29 17:04:22 +02:00
Serge
4e2abff942 Update README.md 2023-03-29 13:58:03 +02:00
Serge
2c8a11fc24 Update README.md 2023-03-29 12:26:19 +02:00
seerge
8af8823ee4 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-29 12:19:02 +02:00
seerge
ec0a1b710e New slider 2023-03-29 12:19:00 +02:00
Serge
2ac2e84161 Update README.md 2023-03-28 22:09:06 +02:00
seerge
14dc1741f7 New battery slider 2023-03-28 20:11:30 +02:00
seerge
fbed195194 - 2023-03-28 16:35:20 +02:00
seerge
0d002edf65 Animatrix fix for 2020/2021 models 2023-03-28 16:05:24 +02:00
seerge
28a17562a8 CPU boost per mode 2023-03-28 14:19:51 +02:00
seerge
583cb677d0 Added option to disable screen overdrive 2023-03-27 15:21:52 +02:00
seerge
1888fe7bd9 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-27 14:28:31 +02:00
seerge
089b339e61 Minor tweaks 2023-03-27 14:28:28 +02:00
Serge
cab4a04339 Update README.md 2023-03-27 13:02:14 +02:00
seerge
7ab3b450cd Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-26 19:31:43 +02:00
seerge
ea2dc7b75d Animatrix tweaks 2023-03-26 19:31:41 +02:00
Serge
ccd69a8628 Update README.md 2023-03-26 14:40:12 +02:00
Serge
c1d23159a0 Update debloat.bat 2023-03-26 14:17:53 +02:00
Serge
1c865624e6 Update debloat.bat 2023-03-26 14:06:13 +02:00
seerge
4853c09c2c Added model name, and custom fan+ in profile names 2023-03-25 20:28:27 +01:00
seerge
08704d6826 Added sleep/awake/boot/shutdown control for keyboards 2023-03-25 16:21:47 +01:00
seerge
6edbcf5ecd Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-25 14:37:40 +01:00
seerge
7702dc8e38 Support for TUF RGB keyboards and other fixes 2023-03-25 14:37:37 +01:00
Serge
94391358ef Update README.md 2023-03-25 09:49:48 +01:00
Serge
feecd193ac Update README.md 2023-03-25 01:14:34 +01:00
Serge
444f7c76f0 Update README.md 2023-03-24 21:19:14 +01:00
Serge
701423fa0e Update README.md 2023-03-24 17:29:29 +01:00
Serge
7b3a6d319b Update README.md 2023-03-24 12:52:14 +01:00
seerge
8bc9325b3f Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-24 11:20:51 +01:00
seerge
64195c5082 Prevent multiple auto-applies when windows calls power event too often 2023-03-24 11:20:48 +01:00
Serge
2297532323 Update README.md 2023-03-23 22:17:47 +01:00
Serge
daac8b0a45 Update README.md 2023-03-23 22:16:25 +01:00
Serge
f061e3f43a Update README.md 2023-03-23 22:14:29 +01:00
seerge
85e02549f1 Update checker fixes 2023-03-23 20:04:25 +01:00
seerge
9053764930 Speedup update checker 2023-03-23 13:26:09 +01:00
seerge
64871e5554 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-23 00:38:06 +01:00
seerge
b1c778b30d Minor tweaks 2023-03-23 00:38:03 +01:00
Serge
6932bb1889 Update README.md 2023-03-22 17:55:10 +01:00
seerge
c90a342ce8 Fixed possible memory leack with clock ticks 2023-03-22 17:28:09 +01:00
seerge
f223ca4a33 Added informational toolip 2023-03-22 17:15:20 +01:00
seerge
023607da4b Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-22 14:38:04 +01:00
seerge
264631ab77 Added animatrix Clock 2023-03-22 14:38:01 +01:00
Serge
1bd5d79983 Update README.md 2023-03-21 17:40:06 +01:00
seerge
83b184a061 - 2023-03-21 15:23:41 +01:00
seerge
9ff572b8f6 UI tweaks, mid fan support 2023-03-21 13:14:53 +01:00
seerge
cdb633be04 Anime matrix fixes 2023-03-21 11:11:31 +01:00
seerge
7cb9b1f64f Mid Fan support 2023-03-21 01:24:42 +01:00
seerge
06be8c726e Improved Animatrix rendering 2023-03-20 23:27:13 +01:00
seerge
265c6ce417 - 2023-03-20 21:09:11 +01:00
seerge
add852ce5d Animatrix tweaks 2023-03-20 21:07:05 +01:00
seerge
d4a5164b16 - 2023-03-20 19:18:07 +01:00
seerge
14618ee19e Possible fix for theme switching 2023-03-20 19:04:41 +01:00
seerge
0b3a75e373 Minor tweaks 2023-03-20 18:02:38 +01:00
seerge
64e390a61f UI tweaks 2023-03-20 17:10:18 +01:00
seerge
1cd808de07 Auto theme change 2023-03-20 16:42:51 +01:00
seerge
d82f1c8d70 Fix crash for gputemp reader 2023-03-20 15:43:51 +01:00
seerge
9189cf0a46 Dark Theme 2023-03-20 14:38:56 +01:00
seerge
3a7c4278a0 Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-20 14:32:47 +01:00
seerge
7065ba8661 Dark Theme 2023-03-20 14:32:45 +01:00
Serge
1bce4a4b51 Update README.md 2023-03-20 11:45:16 +01:00
Serge
468f9c4034 Update bug_report.md 2023-03-19 23:45:02 +01:00
seerge
4d347df45c Attempt to fix auto gpu switch 2023-03-19 21:59:22 +01:00
seerge
d7f1d1d5fd Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-19 17:39:32 +01:00
seerge
6800ae38dd Custom fan-axis for 401 model 2023-03-19 17:39:30 +01:00
Serge
9b2b96fbf0 Update README.md 2023-03-19 13:57:02 +01:00
seerge
04b3a15d8f Merge branch 'main' of https://github.com/seerge/g-helper 2023-03-19 10:27:35 +01:00
seerge
aae0570340 - 2023-03-19 10:27:32 +01:00
Serge
b142d566da Update README.md 2023-03-18 20:56:37 +01:00
seerge
a9115d0dff Screenshot 2023-03-18 18:46:35 +01:00
Serge
e3a3e81245 Merge pull request #96 from seerge/new_ui
New UI
2023-03-18 18:38:35 +01:00
seerge
c50c1807ca UI fixes, tooltips for fan control 2023-03-18 17:57:09 +01:00
seerge
5767320437 Fixes for scaling, and layout 2023-03-18 15:13:34 +01:00
seerge
74846097db Optimized icons 2023-03-17 22:39:53 +01:00
seerge
5b89556ed3 New UI 2023-03-17 22:28:33 +01:00
488 changed files with 56237 additions and 2628 deletions

13
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
custom: https://www.paypal.com/donate/?hosted_button_id=4HMSHS4EBQWTA

View File

@@ -1,38 +1,42 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
## NOTE
Bug reports without clear information or scenario to reproduce and logs from ``%AppData%\GHelper`` will be closed without answer.
Please respect time of the developer. Thanks.
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
**Clear scenario to Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
4. Explanation of an error or a bug
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
**App Logs**
Please include and attach log.txt from ``%AppData%\GHelper``
**Screenshots or screencasts**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
- OS: [e.g. Windows 11]
- Laptop model
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Asus software**
- Armoury crate (or it's services installed)
- MyASUS installed
- Other Asus services running in background
**Additional context**
Add any other context about the problem here.

View File

@@ -1,10 +0,0 @@
---
name: Custom issue template
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---

25
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
name: Build
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:
permissions:
contents: read
jobs:
build:
runs-on: windows-2022
steps:
- uses: actions/checkout@v3
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
7.0.x
- name: Build
run: |
dotnet build app/GHelper.sln

28
.github/workflows/codeql.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: CodeQL
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '34 18 * * 3'
permissions:
actions: read
contents: read
security-events: write
jobs:
codeql:
runs-on: windows-2022
steps:
- uses: actions/checkout@v3
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: c#
- name: Autobuild
uses: github/codeql-action/autobuild@v2
- name: Analyze
uses: github/codeql-action/analyze@v2

28
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
name: Release
on:
release:
types: [ published ]
permissions:
contents: write
jobs:
release:
runs-on: windows-2022
steps:
- uses: actions/checkout@v3
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: |
7.0.x
- name: Publish
run: |
dotnet publish app/GHelper.sln --configuration Release --runtime win-x64 -p:PublishSingleFile=true --no-self-contained
powershell Compress-Archive app/bin/x64/Release/net7.0-windows8.0/win-x64/publish/GHelper.exe GHelper.zip
- name: Upload
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release upload ${{ github.ref_name }} app/bin/x64/Release/net7.0-windows8.0/win-x64/publish/GHelper.exe GHelper.zip

View File

@@ -1,223 +0,0 @@
using System.Management;
using System.Runtime.InteropServices;
public class ASUSWmi
{
const string FILE_NAME = @"\\.\\ATKACPI";
const uint CONTROL_CODE = 0x0022240C;
const uint DSTS = 0x53545344;
const uint DEVS = 0x53564544;
public const uint CPU_Fan = 0x00110013;
public const uint GPU_Fan = 0x00110014;
public const uint PerformanceMode = 0x00120075; // Thermal Control
public const uint GPUEco = 0x00090020;
public const uint GPUMux = 0x00090016;
public const uint BatteryLimit = 0x00120057;
public const uint ScreenOverdrive = 0x00050019;
public const uint DevsCPUFanCurve = 0x00110024;
public const uint DevsGPUFanCurve = 0x00110025;
public const int PPT_TotalA0 = 0x001200A0; // Total PPT on 2022 and CPU PPT on 2021
public const int PPT_EDCA1 = 0x001200A1; // CPU EDC
public const int PPT_TDCA2 = 0x001200A2; // CPU TDC
public const int PPT_APUA3 = 0x001200A3; // APU PPT ON 2021, doesn't work on 2022
public const int PPT_CPUB0 = 0x001200B0; // CPU PPT on 2022
public const int PPT_CPUB1 = 0x001200B1; // APU PPT on 2022
public const int PPT_APUC1 = 0x001200C1;
public const int PPT_APUC2 = 0x001200C2;
public const int PerformanceBalanced = 0;
public const int PerformanceTurbo = 1;
public const int PerformanceSilent = 2;
public const int GPUModeEco = 0;
public const int GPUModeStandard = 1;
public const int GPUModeUltimate = 2;
public const int MaxTotal = 150;
public const int MinTotal = 5;
public const int DefaultTotal = 125;
public const int MaxCPU = 90;
public const int MinCPU = 5;
public const int DefaultCPU = 80;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
byte[] lpOutBuffer,
uint nOutBufferSize,
ref uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint OPEN_EXISTING = 3;
private const uint FILE_ATTRIBUTE_NORMAL = 0x80;
private const uint FILE_SHARE_READ = 1;
private const uint FILE_SHARE_WRITE = 2;
private IntPtr handle;
public ASUSWmi()
{
handle = CreateFile(
FILE_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero
);
if (handle == new IntPtr(-1))
{
throw new Exception("Can't connect to ACPI");
}
}
public void Control(uint dwIoControlCode, byte[] lpInBuffer, byte[] lpOutBuffer)
{
uint lpBytesReturned = 0;
bool result = DeviceIoControl(
handle,
dwIoControlCode,
lpInBuffer,
(uint)lpInBuffer.Length,
lpOutBuffer,
(uint)lpOutBuffer.Length,
ref lpBytesReturned,
IntPtr.Zero
);
}
public void Close()
{
CloseHandle(handle);
}
protected byte[] CallMethod(uint MethodID, byte[] args)
{
byte[] acpiBuf = new byte[8 + args.Length];
byte[] outBuffer = new byte[20];
BitConverter.GetBytes((uint)MethodID).CopyTo(acpiBuf, 0);
BitConverter.GetBytes((uint)args.Length).CopyTo(acpiBuf, 4);
Array.Copy(args, 0, acpiBuf, 8, args.Length);
// if (MethodID == DEVS) Debug.WriteLine(BitConverter.ToString(acpiBuf, 0, acpiBuf.Length));
Control(CONTROL_CODE, acpiBuf, outBuffer);
return outBuffer;
}
public void DeviceSet(uint DeviceID, int Status)
{
byte[] args = new byte[8];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
BitConverter.GetBytes((uint)Status).CopyTo(args, 4);
CallMethod(DEVS, args);
}
public void DeviceSet(uint DeviceID, byte[] Params)
{
byte[] args = new byte[4 + Params.Length];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
Params.CopyTo(args, 4);
CallMethod(DEVS, args);
}
public int DeviceGet(uint DeviceID)
{
byte[] args = new byte[8];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
byte[] status = CallMethod(DSTS, args);
return BitConverter.ToInt32(status, 0) - 65536;
}
public byte[] DeviceGetBuffer(uint DeviceID, uint Status = 0)
{
byte[] args = new byte[8];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
BitConverter.GetBytes((uint)Status).CopyTo(args, 4);
return CallMethod(DSTS, args);
}
public void SetFanCurve(int device, byte[] curve)
{
if (curve.Length != 16) return;
if (curve.All(singleByte => singleByte == 0)) return;
Logger.WriteLine("Fans" + ((device == 1) ? "GPU" : "CPU") + " " + BitConverter.ToString(curve));
if (device == 1)
DeviceSet(DevsGPUFanCurve, curve);
else
DeviceSet(DevsCPUFanCurve, curve);
}
public byte[] GetFanCurve(int device, int mode = 0)
{
uint fan_mode;
// because it's asus, and modes are swapped here
switch (mode)
{
case 1: fan_mode = 2; break;
case 2: fan_mode = 1; break;
default: fan_mode = 0; break;
}
if (device == 1)
return DeviceGetBuffer(DevsGPUFanCurve, fan_mode);
else
return DeviceGetBuffer(DevsCPUFanCurve, fan_mode);
}
public void SubscribeToEvents(Action<object, EventArrivedEventArgs> EventHandler)
{
ManagementEventWatcher watcher = new ManagementEventWatcher();
watcher.EventArrived += new EventArrivedEventHandler(EventHandler);
watcher.Scope = new ManagementScope("root\\wmi");
watcher.Query = new WqlEventQuery("SELECT * FROM AsusAtkWmiEvent");
watcher.Start();
}
}

View File

@@ -0,0 +1,312 @@
using NAudio.CoreAudioApi;
using NAudio.Wave;
using Starlight.AnimeMatrix;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Timers;
namespace GHelper.AnimeMatrix
{
public class AniMatrix
{
System.Timers.Timer matrixTimer = default!;
AnimeMatrixDevice mat;
double[] AudioValues;
WasapiCapture AudioDevice;
public bool IsValid => mat != null;
private long lastPresent;
private List<double> maxes = new List<double>();
public AniMatrix()
{
try
{
mat = new AnimeMatrixDevice();
Task.Run(mat.WakeUp);
matrixTimer = new System.Timers.Timer(100);
matrixTimer.Elapsed += MatrixTimer_Elapsed;
}
catch
{
mat = null;
}
}
public void SetMatrix()
{
if (!IsValid) return;
int brightness = AppConfig.getConfig("matrix_brightness");
int running = AppConfig.getConfig("matrix_running");
bool auto = AppConfig.getConfig("matrix_auto") == 1;
if (brightness < 0) brightness = 0;
if (running < 0) running = 0;
BuiltInAnimation animation = new BuiltInAnimation(
(BuiltInAnimation.Running)running,
BuiltInAnimation.Sleeping.Starfield,
BuiltInAnimation.Shutdown.SeeYa,
BuiltInAnimation.Startup.StaticEmergence
);
StopMatrixTimer();
StopMatrixAudio();
mat.SetProvider();
if (brightness == 0 || (auto && SystemInformation.PowerStatus.PowerLineStatus != PowerLineStatus.Online))
{
mat.SetDisplayState(false);
Logger.WriteLine("Matrix Off");
}
else
{
mat.SetDisplayState(true);
mat.SetBrightness((BrightnessMode)brightness);
switch (running)
{
case 2:
SetMatrixPicture(AppConfig.getConfigString("matrix_picture"));
break;
case 3:
SetMatrixClock();
break;
case 4:
SetMatrixAudio();
break;
default:
mat.SetBuiltInAnimation(true, animation);
Logger.WriteLine("Matrix builtin " + animation.AsByte);
break;
}
//mat.SetBrightness((BrightnessMode)brightness);
}
}
private void StartMatrixTimer(int interval = 100)
{
matrixTimer.Interval = interval;
matrixTimer.Start();
}
private void StopMatrixTimer()
{
matrixTimer.Stop();
}
private void MatrixTimer_Elapsed(object? sender, ElapsedEventArgs e)
{
//if (!IsValid) return;
switch (AppConfig.getConfig("matrix_running"))
{
case 2:
mat.PresentNextFrame();
break;
case 3:
mat.PresentClock();
break;
}
}
public void SetMatrixClock()
{
mat.SetBuiltInAnimation(false);
StartMatrixTimer(1000);
Logger.WriteLine("Matrix Clock");
}
public void Dispose()
{
StopMatrixAudio();
}
void StopMatrixAudio()
{
if (AudioDevice is not null)
{
try
{
AudioDevice.StopRecording();
AudioDevice.Dispose();
}
catch (Exception ex)
{
Logger.WriteLine(ex.ToString());
}
}
}
void SetMatrixAudio()
{
if (!IsValid) return;
mat.SetBuiltInAnimation(false);
StopMatrixTimer();
StopMatrixAudio();
try
{
using (var enumerator = new MMDeviceEnumerator())
using (MMDevice device = enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console))
{
AudioDevice = new WasapiLoopbackCapture(device);
WaveFormat fmt = AudioDevice.WaveFormat;
AudioValues = new double[fmt.SampleRate / 1000];
AudioDevice.DataAvailable += WaveIn_DataAvailable;
AudioDevice.StartRecording();
Logger.WriteLine("Matrix Audio");
}
}
catch (Exception ex)
{
Logger.WriteLine(ex.ToString());
}
}
private void WaveIn_DataAvailable(object? sender, WaveInEventArgs e)
{
int bytesPerSamplePerChannel = AudioDevice.WaveFormat.BitsPerSample / 8;
int bytesPerSample = bytesPerSamplePerChannel * AudioDevice.WaveFormat.Channels;
int bufferSampleCount = e.Buffer.Length / bytesPerSample;
if (bufferSampleCount >= AudioValues.Length)
{
bufferSampleCount = AudioValues.Length;
}
if (bytesPerSamplePerChannel == 2 && AudioDevice.WaveFormat.Encoding == WaveFormatEncoding.Pcm)
{
for (int i = 0; i < bufferSampleCount; i++)
AudioValues[i] = BitConverter.ToInt16(e.Buffer, i * bytesPerSample);
}
else if (bytesPerSamplePerChannel == 4 && AudioDevice.WaveFormat.Encoding == WaveFormatEncoding.Pcm)
{
for (int i = 0; i < bufferSampleCount; i++)
AudioValues[i] = BitConverter.ToInt32(e.Buffer, i * bytesPerSample);
}
else if (bytesPerSamplePerChannel == 4 && AudioDevice.WaveFormat.Encoding == WaveFormatEncoding.IeeeFloat)
{
for (int i = 0; i < bufferSampleCount; i++)
AudioValues[i] = BitConverter.ToSingle(e.Buffer, i * bytesPerSample);
}
double[] paddedAudio = FftSharp.Pad.ZeroPad(AudioValues);
double[] fftMag = FftSharp.Transform.FFTmagnitude(paddedAudio);
PresentAudio(fftMag);
}
private void DrawBar(int pos, double h)
{
int dx = pos * 2;
int dy = 20;
byte color;
for (int y = 0; y < h - (h % 2); y++)
for (int x = 0; x < 2 - (y % 2); x++)
{
//color = (byte)(Math.Min(1,(h - y - 2)*2) * 255);
mat.SetLedPlanar(x + dx, dy + y, (byte)(h * 255 / 30));
mat.SetLedPlanar(x + dx, dy - y, 255);
}
}
void PresentAudio(double[] audio)
{
if (Math.Abs(DateTimeOffset.Now.ToUnixTimeMilliseconds() - lastPresent) < 70) return;
lastPresent = DateTimeOffset.Now.ToUnixTimeMilliseconds();
mat.Clear();
int size = 20;
double[] bars = new double[size];
double max = 2, maxAverage;
for (int i = 0; i < size; i++)
{
bars[i] = Math.Sqrt(audio[i] * 10000);
if (bars[i] > max) max = bars[i];
}
maxes.Add(max);
if (maxes.Count > 20) maxes.RemoveAt(0);
maxAverage = maxes.Average();
for (int i = 0; i < size; i++) DrawBar(20 - i, bars[i]*20/maxAverage);
mat.Present();
}
public void SetMatrixPicture(string fileName)
{
if (!IsValid) return;
StopMatrixTimer();
Image image;
try
{
using (var fs = new FileStream(fileName, FileMode.Open))
{
var ms = new MemoryStream();
fs.CopyTo(ms);
ms.Position = 0;
image = Image.FromStream(ms);
}
}
catch
{
Debug.WriteLine("Error loading picture");
return;
}
mat.SetBuiltInAnimation(false);
mat.ClearFrames();
FrameDimension dimension = new FrameDimension(image.FrameDimensionsList[0]);
int frameCount = image.GetFrameCount(dimension);
if (frameCount > 1)
{
for (int i = 0; i < frameCount; i++)
{
image.SelectActiveFrame(dimension, i);
mat.GenerateFrame(image);
mat.AddFrame();
}
StartMatrixTimer();
Logger.WriteLine("Matrix GIF " + fileName);
}
else
{
mat.GenerateFrame(image);
mat.Present();
Logger.WriteLine("Matrix " + fileName);
}
}
}
}

View File

@@ -1,9 +1,11 @@
// Source thanks to https://github.com/vddCore/Starlight with some adjustments from me
using Starlight.Communication;
using System.Diagnostics;
using System.Text;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Globalization;
using System.Management;
using System.Text;
namespace Starlight.AnimeMatrix
{
@@ -57,6 +59,15 @@ namespace Starlight.AnimeMatrix
}
}
public enum AnimeType
{
GA401,
GA402,
GU604
}
public enum BrightnessMode : byte
{
Off = 0,
@@ -68,35 +79,57 @@ namespace Starlight.AnimeMatrix
public class AnimeMatrixDevice : Device
{
private const int UpdatePageLength = 0x0278;
int UpdatePageLength = 490;
int LedCount = 1450;
public int LedCount => 1450;
byte[] _displayBuffer;
List<byte[]> frames = new List<byte[]>();
private byte[] _displayBuffer = new byte[UpdatePageLength * 3];
private List<byte[]> frames = new List<byte[]>();
private int pages = 3;
public int MaxColumns = 34;
public int MaxRows = 61;
//public int FullRows = 11;
//public int FullEvenRows = -1;
public int FullRows = 11;
public int dx = 0;
//Shifts the whole frame to the left or right to align with the diagonal cut
public int frameShiftX = 0;
public int MaxColumns = 34;
private int frameIndex = 0;
private static AnimeType _model = AnimeType.GA402;
public AnimeMatrixDevice()
: base(0x0B05, 0x193B, 640)
{
string model = GetModel();
Debug.WriteLine(model);
if (model is not null && model.Contains("401"))
if (model.Contains("401"))
{
pages = 2;
FullRows = 6;
_model = AnimeType.GA401;
MaxColumns = 33;
dx = 1;
MaxRows = 55;
LedCount = 1245;
UpdatePageLength = 410;
}
if (model.Contains("GU604"))
{
_model = AnimeType.GU604;
MaxColumns = 39;
MaxRows = 92;
LedCount = 1711;
frameShiftX = -5;
UpdatePageLength = 630;
}
_displayBuffer = new byte[LedCount];
}
@@ -119,7 +152,6 @@ namespace Starlight.AnimeMatrix
public void PresentNextFrame()
{
//Debug.WriteLine(frameIndex);
if (frameIndex >= frames.Count) frameIndex = 0;
_displayBuffer = frames[frameIndex];
Present();
@@ -143,31 +175,80 @@ namespace Starlight.AnimeMatrix
}
public int EmptyColumns(int row)
public static int FirstX(int y)
{
return (int)Math.Ceiling(Math.Max(0, row - FullRows) / 2.0);
}
public int Columns(int row)
{
EnsureRowInRange(row);
return MaxColumns - EmptyColumns(row);
}
public int RowToLinearAddress(int row)
{
EnsureRowInRange(row);
var ret = 0;
if (row > 0)
switch (_model)
{
for (var i = 0; i < row; i++)
ret += Columns(i);
case AnimeType.GA401:
if (y < 5)
{
return 0;
}
else
{
return (y + 1) / 2 - 3;
}
case AnimeType.GU604:
return (int)Math.Ceiling(Math.Max(0, y - 9) / 2F);
default:
return (int)Math.Ceiling(Math.Max(0, y - 11) / 2F);
}
}
public static int Width(int y)
{
switch (_model)
{
case AnimeType.GA401:
return 33;
case AnimeType.GU604:
return 39;
default:
return 34;
}
}
public static int Pitch(int y)
{
switch (_model)
{
case AnimeType.GA401:
switch (y)
{
case 0:
case 2:
case 4:
return 33;
case 1:
case 3:
return 35;
default:
return 36 - y / 2;
}
default:
return Width(y) - FirstX(y);
}
}
public int RowToLinearAddress(int y)
{
int ret = 0;
for (var i = 0; i < y; i++)
ret += Pitch(i);
return ret;
}
public void SetLedPlanar(int x, int y, byte value)
{
if (!IsRowInRange(y)) return;
if (x >= FirstX(y) && x < Width(y))
SetLedLinear(RowToLinearAddress(y) - FirstX(y) + x + dx + frameShiftX, value);
}
public void WakeUp()
{
Set(Packet<AnimeMatrixPacket>(Encoding.ASCII.GetBytes("ASUS Tech.Inc.")));
@@ -175,13 +256,13 @@ namespace Starlight.AnimeMatrix
public void SetLedLinear(int address, byte value)
{
EnsureAddressableLed(address);
if (!IsAddressableLed(address)) return;
_displayBuffer[address] = value;
}
public void SetLedLinearImmediate(int address, byte value)
{
EnsureAddressableLed(address);
if (!IsAddressableLed(address)) return;
_displayBuffer[address] = value;
Set(Packet<AnimeMatrixPacket>(0xC0, 0x02)
@@ -193,14 +274,7 @@ namespace Starlight.AnimeMatrix
Set(Packet<AnimeMatrixPacket>(0xC0, 0x03));
}
public void SetLedPlanar(int x, int y, byte value)
{
EnsureRowInRange(y);
var start = RowToLinearAddress(y) - EmptyColumns(y);
if (x > EmptyColumns(y))
SetLedLinear(start + x, value);
}
public void Clear(bool present = false)
{
@@ -214,26 +288,23 @@ namespace Starlight.AnimeMatrix
public void Present()
{
Set(Packet<AnimeMatrixPacket>(0xC0, 0x02)
.AppendData(BitConverter.GetBytes((ushort)(UpdatePageLength * 0 + 1)))
.AppendData(BitConverter.GetBytes((ushort)UpdatePageLength))
.AppendData(_displayBuffer[(UpdatePageLength * 0)..(UpdatePageLength * 1)])
);
int page = 0;
int start, end;
Set(Packet<AnimeMatrixPacket>(0xC0, 0x02)
.AppendData(BitConverter.GetBytes((ushort)(UpdatePageLength * 1 + 1)))
.AppendData(BitConverter.GetBytes((ushort)UpdatePageLength))
.AppendData(_displayBuffer[(UpdatePageLength * 1)..(UpdatePageLength * 2)])
);
while (page * UpdatePageLength < LedCount)
{
start = page * UpdatePageLength;
end = Math.Min(LedCount, (page + 1) * UpdatePageLength);
if (pages > 2)
Set(Packet<AnimeMatrixPacket>(0xC0, 0x02)
.AppendData(BitConverter.GetBytes((ushort)(UpdatePageLength * 2 + 1)))
.AppendData(BitConverter.GetBytes((ushort)(LedCount - UpdatePageLength * 2)))
.AppendData(
_displayBuffer[(UpdatePageLength * 2)..(UpdatePageLength * 2 + (LedCount - UpdatePageLength * 2))])
.AppendData(BitConverter.GetBytes((ushort)(start + 1)))
.AppendData(BitConverter.GetBytes((ushort)(end - start)))
.AppendData(_displayBuffer[start..end])
);
page++;
}
Set(Packet<AnimeMatrixPacket>(0xC0, 0x03));
}
@@ -270,55 +341,168 @@ namespace Starlight.AnimeMatrix
Set(Packet<AnimeMatrixPacket>(0xC5, animation.AsByte));
}
public void GenerateFrame(Image image)
public void PresentClock()
{
int second = DateTime.Now.Second;
string time;
if (CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern.Contains("H"))
time = DateTime.Now.ToString("H" + ((second % 2 == 0) ? ":" : " ") + "mm");
else
time = DateTime.Now.ToString("h" + ((second % 2 == 0) ? ":" : " ") + "mmtt");
if (_model == AnimeType.GA401)
PresentText(time);
else
PresentTextDiagonal(time);
}
public void PresentText(string text1, string text2 = "")
{
using (Bitmap bmp = new Bitmap(MaxColumns * 3, MaxRows))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.AntiAlias;
using (Font font = new Font("Consolas", 24F, FontStyle.Regular, GraphicsUnit.Pixel))
{
SizeF textSize = g.MeasureString(text1, font);
g.DrawString(text1, font, Brushes.White, (MaxColumns * 3 - textSize.Width) + 3, -4);
}
if (text2.Length > 0)
using (Font font = new Font("Consolas", 18F, GraphicsUnit.Pixel))
{
SizeF textSize = g.MeasureString(text2, font);
g.DrawString(text2, font, Brushes.White, (MaxColumns * 3 - textSize.Width) + 1, 25);
}
}
GenerateFrame(bmp, InterpolationMode.Bicubic);
Present();
}
}
public void GenerateFrame(Image image, InterpolationMode interpolation = InterpolationMode.High)
{
int width = MaxColumns * 3;
int width = MaxColumns / 2 * 6;
int height = MaxRows;
int targetWidth = MaxColumns * 2;
float scale;
Bitmap canvas = new Bitmap(width, height);
scale = Math.Min((float)width / (float)image.Width, (float)height / (float)image.Height);
var graph = Graphics.FromImage(canvas);
var scaleWidth = (int)(image.Width * scale);
var scaleHeight = (int)(image.Height * scale);
graph.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
graph.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
graph.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
graph.DrawImage(image, ((int)width - scaleWidth), ((int)height - scaleHeight) / 2, scaleWidth, scaleHeight);
Bitmap bmp = new Bitmap(canvas, MaxColumns, MaxRows);
for (int y = 0; y < bmp.Height; y++)
using (Bitmap bmp = new Bitmap(targetWidth, height))
{
for (int x = 0; x < bmp.Width; x++)
scale = Math.Min((float)width / (float)image.Width, (float)height / (float)image.Height);
using (var graph = Graphics.FromImage(bmp))
{
var pixel = bmp.GetPixel(x, y);
byte color = (byte)(Math.Max((pixel.R + pixel.G + pixel.B) / 3 - 10, 0));
SetLedPlanar(x, y, color);
var scaleWidth = (float)(image.Width * scale);
var scaleHeight = (float)(image.Height * scale);
graph.InterpolationMode = interpolation;
graph.CompositingQuality = CompositingQuality.HighQuality;
graph.SmoothingMode = SmoothingMode.AntiAlias;
graph.DrawImage(image, (float)Math.Round(targetWidth - scaleWidth * targetWidth / width), 0, (float)Math.Round(scaleWidth * targetWidth / width), scaleHeight);
}
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
if (x % 2 == (y + dx) % 2)
{
var pixel = bmp.GetPixel(x, y);
var color = (pixel.R + pixel.G + pixel.B) / 3;
if (color < 10) color = 0;
SetLedPlanar(x / 2, y, (byte)color);
}
}
}
}
public void SetLedDiagonal(int x, int y, byte color, int delta = 10)
{
//x+=delta;
y -= delta;
int dx = (x - y) / 2;
int dy = x + y;
SetLedPlanar(dx, dy, color);
}
public void PresentTextDiagonal(string text)
{
Clear();
InstalledFontCollection installedFontCollection = new InstalledFontCollection();
string familyName;
string familyList = "";
FontFamily[] fontFamilies;
// Get the array of FontFamily objects.
fontFamilies = installedFontCollection.Families;
int count = fontFamilies.Length;
for (int j = 0; j < count; ++j)
{
familyName = fontFamilies[j].Name;
familyList = familyList + familyName;
familyList = familyList + ", ";
}
int maxX = (int)Math.Sqrt(MaxRows * MaxRows + MaxColumns * MaxColumns);
using (Bitmap bmp = new Bitmap(maxX, MaxRows))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.CompositingQuality = CompositingQuality.HighQuality;
g.SmoothingMode = SmoothingMode.AntiAlias;
using (Font font = new Font("Consolas", 13F, FontStyle.Regular, GraphicsUnit.Pixel))
{
SizeF textSize = g.MeasureString(text, font);
g.DrawString(text, font, Brushes.White, 4, 1);
}
}
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
var pixel = bmp.GetPixel(x, y);
var color = (pixel.R + pixel.G + pixel.B) / 3;
SetLedDiagonal(x, y, (byte)color);
}
}
}
Present();
}
private void EnsureRowInRange(int row)
private bool IsRowInRange(int row)
{
if (row < 0 || row >= MaxRows)
{
throw new IndexOutOfRangeException($"Y-coordinate should fall in range of [0, {MaxRows - 1}].");
}
return (row >= 0 && row < MaxRows);
}
private void EnsureAddressableLed(int address)
private bool IsAddressableLed(int address)
{
if (address < 0 || address >= LedCount)
{
throw new IndexOutOfRangeException($"Linear LED address must be in range of [0, {LedCount - 1}].");
}
return (address >= 0 && address < LedCount);
}
}
}

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<System.Windows.Forms.ApplicationConfigurationSection>
<add key="DpiAwareness" value="System" />
<add key="DpiAwareness" value="PerMonitorV2" />
</System.Windows.Forms.ApplicationConfigurationSection>
<appSettings>
<add key="EnableWindowsFormsHighDpiAutoResizing" value="true" />

View File

@@ -1,17 +1,19 @@
using System.Text.Json;
using System.Diagnostics;
using System.Management;
using System.Text.Json;
public class AppConfig
public static class AppConfig
{
public string appPath;
string configFile;
private static string configFile;
private static string? _model;
public Dictionary<string, object> config = new Dictionary<string, object>();
private static Dictionary<string, object> config = new Dictionary<string, object>();
public AppConfig()
static AppConfig()
{
appPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\GHelper";
string appPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\GHelper";
configFile = appPath + "\\config.json";
if (!System.IO.Directory.Exists(appPath))
@@ -36,7 +38,32 @@ public class AppConfig
}
private void initConfig()
public static string GetModel()
{
if (_model is null)
{
_model = "";
using (var searcher = new ManagementObjectSearcher(@"Select * from Win32_ComputerSystem"))
{
foreach (var process in searcher.Get())
{
_model = process["Model"].ToString();
break;
}
}
}
return _model;
}
public static bool ContainsModel(string contains)
{
GetModel();
return (_model is not null && _model.Contains(contains));
}
private static void initConfig()
{
config = new Dictionary<string, object>();
config["performance_mode"] = 0;
@@ -44,49 +71,78 @@ public class AppConfig
File.WriteAllText(configFile, jsonString);
}
public int getConfig(string name, bool performance = false)
public static int getConfig(string name, int empty = -1)
{
if (config.ContainsKey(name))
return int.Parse(config[name].ToString());
else return -1;
else return empty;
}
public string getConfigString(string name)
public static bool isConfig(string name)
{
return getConfig(name) == 1;
}
public static string getConfigString(string name, string empty = null)
{
if (config.ContainsKey(name))
return config[name].ToString();
else return null;
else return empty;
}
public void setConfig(string name, int value)
public static void setConfig(string name, int value)
{
config[name] = value;
string jsonString = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(configFile, jsonString);
try
{
File.WriteAllText(configFile, jsonString);
} catch (Exception e)
{
Debug.Write(e.ToString());
}
}
public void setConfig(string name, string value)
public static void setConfig(string name, string value)
{
config[name] = value;
string jsonString = JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(configFile, jsonString);
try
{
File.WriteAllText(configFile, jsonString);
}
catch (Exception e)
{
Debug.Write(e.ToString());
}
}
public string getParamName(int device, string paramName = "fan_profile")
public static string getParamName(AsusFan device, string paramName = "fan_profile")
{
int mode = getConfig("performance_mode");
string name;
if (device == 1)
name = "gpu";
else
name = "cpu";
switch (device)
{
case AsusFan.GPU:
name = "gpu";
break;
case AsusFan.Mid:
name = "mid";
break;
case AsusFan.XGM:
name = "xgm";
break;
default:
name = "cpu";
break;
}
return paramName + "_" + name + "_" + mode;
}
public byte[] getFanConfig(int device)
public static byte[] getFanConfig(AsusFan device)
{
string curveString = getConfigString(getParamName(device));
byte[] curve = { };
@@ -97,7 +153,7 @@ public class AppConfig
return curve;
}
public void setFanConfig(int device, byte[] curve)
public static void setFanConfig(AsusFan device, byte[] curve)
{
string bitCurve = BitConverter.ToString(curve);
setConfig(getParamName(device), bitCurve);
@@ -112,7 +168,7 @@ public class AppConfig
return array;
}
public byte[] getDefaultCurve(int device)
public static byte[] getDefaultCurve(AsusFan device)
{
int mode = getConfig("performance_mode");
byte[] curve;
@@ -120,19 +176,19 @@ public class AppConfig
switch (mode)
{
case 1:
if (device == 1)
if (device == AsusFan.GPU)
curve = StringToBytes("14-3F-44-48-4C-50-54-62-16-1F-26-2D-39-47-55-5F");
else
curve = StringToBytes("14-3F-44-48-4C-50-54-62-11-1A-22-29-34-43-51-5A");
break;
case 2:
if (device == 1)
if (device == AsusFan.GPU)
curve = StringToBytes("3C-41-42-46-47-4B-4C-62-08-11-11-1D-1D-26-26-2D");
else
curve = StringToBytes("3C-41-42-46-47-4B-4C-62-03-0C-0C-16-16-22-22-29");
break;
default:
if (device == 1)
if (device == AsusFan.GPU)
curve = StringToBytes("3A-3D-40-44-48-4D-51-62-0C-16-1D-1F-26-2D-34-4A");
else
curve = StringToBytes("3A-3D-40-44-48-4D-51-62-08-11-16-1A-22-29-30-45");
@@ -142,13 +198,19 @@ public class AppConfig
return curve;
}
public int getConfigPerf(string name)
public static string getConfigPerfString(string name)
{
int mode = getConfig("performance_mode");
return getConfigString(name + "_" + mode);
}
public static int getConfigPerf(string name)
{
int mode = getConfig("performance_mode");
return getConfig(name + "_" + mode);
}
public void setConfigPerf(string name, int value)
public static void setConfigPerf(string name, int value)
{
int mode = getConfig("performance_mode");
setConfig(name + "_" + mode, value);

472
app/AsusACPI.cs Normal file
View File

@@ -0,0 +1,472 @@
using System.Management;
using System.Runtime.InteropServices;
public enum AsusFan
{
CPU = 0,
GPU = 1,
Mid = 2,
XGM = 3
}
public enum AsusMode
{
Balanced = 0,
Turbo = 1,
Silent = 2
}
public enum AsusGPU
{
Eco = 0,
Standard = 1,
Ultimate = 2
}
public class AsusACPI
{
const string FILE_NAME = @"\\.\\ATKACPI";
const uint CONTROL_CODE = 0x0022240C;
const uint DSTS = 0x53545344;
const uint DEVS = 0x53564544;
const uint INIT = 0x54494E49;
public const uint UniversalControl = 0x00100021;
public const int KB_Light_Up = 0xc4;
public const int KB_Light_Down = 0xc5;
public const int Touchpad_Toggle = 0x6B;
public const int ChargerMode = 0x0012006C;
public const int ChargerUSB = 2;
public const int ChargerBarrel = 1;
public const uint CPU_Fan = 0x00110013;
public const uint GPU_Fan = 0x00110014;
public const uint Mid_Fan = 0x00110031;
public const uint PerformanceMode = 0x00120075; // Thermal Control
public const uint GPUEco = 0x00090020;
public const uint GPUXGConnected = 0x00090018;
public const uint GPUXG = 0x00090019;
public const uint GPUMux = 0x00090016;
public const uint BatteryLimit = 0x00120057;
public const uint ScreenOverdrive = 0x00050019;
public const uint ScreenMiniled = 0x0005001E;
public const uint DevsCPUFanCurve = 0x00110024;
public const uint DevsGPUFanCurve = 0x00110025;
public const uint DevsMidFanCurve = 0x00110032;
public const int Temp_CPU = 0x00120094;
public const int Temp_GPU = 0x00120097;
public const int PPT_TotalA0 = 0x001200A0; // Total PPT on 2022 (PPT_LIMIT_SLOW ) and CPU PPT on 2021
public const int PPT_EDCA1 = 0x001200A1; // CPU EDC
public const int PPT_TDCA2 = 0x001200A2; // CPU TDC
public const int PPT_APUA3 = 0x001200A3; // APU PPT ON 2021, doesn't work on 2022
public const int PPT_CPUB0 = 0x001200B0; // CPU PPT on 2022 (PPT_LIMIT_APU)
public const int PPT_CPUB1 = 0x001200B1; // Total PPT on 2022 (PPT_LIMIT_SLOW)
public const int PPT_GPUC0 = 0x001200C0; // NVIDIA GPU Boost
public const int PPT_APUC1 = 0x001200C1; // Actual Power Limit (PPT_LIMIT_FAST) AND Sustained Power Limit (STAPM_LIMIT)
public const int PPT_GPUC2 = 0x001200C2; // NVIDIA GPU Temp Target (75.. 87 C)
public const int TUF_KB_BRIGHTNESS = 0x00050021;
public const int TUF_KB = 0x00100056;
public const int TUF_KB_STATE = 0x00100057;
public const int TabletState = 0x00060077;
public const int Tablet_Notebook = 0;
public const int Tablet_Tablet = 1;
public const int Tablet_Tent = 2;
public const int Tablet_Rotated = 3;
public const int PerformanceBalanced = 0;
public const int PerformanceTurbo = 1;
public const int PerformanceSilent = 2;
public const int GPUModeEco = 0;
public const int GPUModeStandard = 1;
public const int GPUModeUltimate = 2;
public const int MaxTotal = 250;
public const int MinTotal = 5;
public const int DefaultTotal = 125;
public const int MaxCPU = 130;
public const int MinCPU = 5;
public const int DefaultCPU = 80;
public const int MinGPUBoost = 5;
public const int MaxGPUBoost = 25;
public const int MinGPUTemp = 75;
public const int MaxGPUTemp = 87;
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
uint nInBufferSize,
byte[] lpOutBuffer,
uint nOutBufferSize,
ref uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hObject);
private const uint GENERIC_READ = 0x80000000;
private const uint GENERIC_WRITE = 0x40000000;
private const uint OPEN_EXISTING = 3;
private const uint FILE_ATTRIBUTE_NORMAL = 0x80;
private const uint FILE_SHARE_READ = 1;
private const uint FILE_SHARE_WRITE = 2;
private IntPtr handle;
// Event handling attempt
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateEvent(IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);
private IntPtr eventHandle;
// still works only with asus optimization service on , if someone knows how to get ACPI events from asus without that - let me know
public void RunListener()
{
eventHandle = CreateEvent(IntPtr.Zero, false, false, "ATK4001");
byte[] outBuffer = new byte[16];
byte[] data = new byte[8];
bool result;
data[0] = BitConverter.GetBytes(eventHandle.ToInt32())[0];
data[1] = BitConverter.GetBytes(eventHandle.ToInt32())[1];
result = Control(0x222400, data, outBuffer);
Logger.WriteLine("ACPI " + result + ":" + BitConverter.ToString(data) + "|" + BitConverter.ToString(outBuffer));
while (true)
{
WaitForSingleObject(eventHandle, Timeout.Infinite);
Control(0x222408, new byte[0], outBuffer);
int code = BitConverter.ToInt32(outBuffer);
Logger.WriteLine("ACPI Code: " + code);
}
}
public AsusACPI()
{
handle = CreateFile(
FILE_NAME,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
IntPtr.Zero
);
if (handle == new IntPtr(-1))
{
throw new Exception("Can't connect to ACPI");
}
}
public bool Control(uint dwIoControlCode, byte[] lpInBuffer, byte[] lpOutBuffer)
{
uint lpBytesReturned = 0;
return DeviceIoControl(
handle,
dwIoControlCode,
lpInBuffer,
(uint)lpInBuffer.Length,
lpOutBuffer,
(uint)lpOutBuffer.Length,
ref lpBytesReturned,
IntPtr.Zero
);
}
public void Close()
{
CloseHandle(handle);
}
protected byte[] CallMethod(uint MethodID, byte[] args)
{
byte[] acpiBuf = new byte[8 + args.Length];
byte[] outBuffer = new byte[20];
BitConverter.GetBytes((uint)MethodID).CopyTo(acpiBuf, 0);
BitConverter.GetBytes((uint)args.Length).CopyTo(acpiBuf, 4);
Array.Copy(args, 0, acpiBuf, 8, args.Length);
// if (MethodID == DEVS) Debug.WriteLine(BitConverter.ToString(acpiBuf, 0, acpiBuf.Length));
Control(CONTROL_CODE, acpiBuf, outBuffer);
return outBuffer;
}
public byte[] DeviceInit()
{
byte[] args = new byte[8];
return CallMethod(INIT, args);
}
public int DeviceSet(uint DeviceID, int Status, string logName)
{
byte[] args = new byte[8];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
BitConverter.GetBytes((uint)Status).CopyTo(args, 4);
byte[] status = CallMethod(DEVS, args);
int result = BitConverter.ToInt32(status, 0);
Logger.WriteLine(logName + " = " + Status + " : " + (result == 1 ? "OK" : result));
return result;
}
public int DeviceSet(uint DeviceID, byte[] Params, string logName)
{
byte[] args = new byte[4 + Params.Length];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
Params.CopyTo(args, 4);
byte[] status = CallMethod(DEVS, args);
int result = BitConverter.ToInt32(status, 0);
Logger.WriteLine(logName + " = " + BitConverter.ToString(Params) + " : " + (result == 1 ? "OK" : result));
return BitConverter.ToInt32(status, 0);
}
public int DeviceGet(uint DeviceID)
{
byte[] args = new byte[8];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
byte[] status = CallMethod(DSTS, args);
return BitConverter.ToInt32(status, 0) - 65536;
}
public byte[] DeviceGetBuffer(uint DeviceID, uint Status = 0)
{
byte[] args = new byte[8];
BitConverter.GetBytes((uint)DeviceID).CopyTo(args, 0);
BitConverter.GetBytes((uint)Status).CopyTo(args, 4);
return CallMethod(DSTS, args);
}
public int SetGPUEco(int eco)
{
int ecoFlag = DeviceGet(GPUEco);
if (ecoFlag < 0) return -1;
if (ecoFlag == 1 && eco == 0)
return DeviceSet(GPUEco, eco, "GPUEco");
if (ecoFlag == 0 && eco == 1)
return DeviceSet(GPUEco, eco, "GPUEco");
return -1;
}
public int SetFanCurve(AsusFan device, byte[] curve)
{
if (curve.Length != 16) return -1;
if (curve.All(singleByte => singleByte == 0)) return -1;
int result;
for (int i = 8; i < curve.Length; i++)
curve[i] = Math.Max((byte)0, Math.Min((byte)99, curve[i])); // it seems to be a bug, when some old model's bios can go nuts if fan is set to 100%
switch (device)
{
case AsusFan.GPU:
result = DeviceSet(DevsGPUFanCurve, curve, "FanGPU");
break;
case AsusFan.Mid:
result = DeviceSet(DevsMidFanCurve, curve, "FanMid");
break;
default:
result = DeviceSet(DevsCPUFanCurve, curve, "FanCPU");
break;
}
return result;
}
public byte[] GetFanCurve(AsusFan device, int mode = 0)
{
uint fan_mode;
// because it's asus, and modes are swapped here
switch (mode)
{
case 1: fan_mode = 2; break;
case 2: fan_mode = 1; break;
default: fan_mode = 0; break;
}
switch (device)
{
case AsusFan.GPU:
return DeviceGetBuffer(DevsGPUFanCurve, fan_mode);
case AsusFan.Mid:
return DeviceGetBuffer(DevsMidFanCurve, fan_mode);
default:
return DeviceGetBuffer(DevsCPUFanCurve, fan_mode);
}
}
public static bool IsInvalidCurve(byte[] curve)
{
return curve.Length != 16 || IsEmptyCurve(curve);
}
public static bool IsEmptyCurve(byte[] curve)
{
return curve.All(singleByte => singleByte == 0);
}
public static byte[] FixFanCurve(byte[] curve)
{
if (curve.Length != 16) throw new Exception("Incorrect curve");
var points = new Dictionary<byte, byte>();
for (int i = 0; i < 8; i++) points[curve[i]] = curve[i + 8];
var pointsFixed = new Dictionary<byte, byte>();
bool fix = false;
int count = 0;
foreach (var pair in points.OrderBy(x => x.Key))
{
if (count == 0 && pair.Key >= 40)
{
fix = true;
pointsFixed.Add(20, 0);
}
if (count != 3 || !fix)
pointsFixed.Add(pair.Key, pair.Value);
count++;
}
count = 0;
foreach (var pair in pointsFixed.OrderBy(x => x.Key))
{
curve[count] = pair.Key;
curve[count + 8] = pair.Value;
count++;
}
return curve;
}
public bool IsXGConnected()
{
//return true;
return DeviceGet(GPUXGConnected) == 1;
}
public void TUFKeyboardBrightness(int brightness)
{
int param = 0x80 | (brightness & 0x7F);
DeviceSet(TUF_KB_BRIGHTNESS, param, "TUF Brightness");
}
public void TUFKeyboardRGB(int mode, Color color, int speed)
{
byte[] setting = new byte[12];
setting[0] = (byte)0xB4;
setting[1] = (byte)mode;
setting[2] = color.R;
setting[3] = color.G;
setting[4] = color.B;
setting[5] = (byte)speed;
DeviceSet(TUF_KB, setting, "TUF RGB");
//Debug.WriteLine(BitConverter.ToString(setting));
}
const int ASUS_WMI_KEYBOARD_POWER_BOOT = 0x03 << 16;
const int ASUS_WMI_KEYBOARD_POWER_AWAKE = 0x0C << 16;
const int ASUS_WMI_KEYBOARD_POWER_SLEEP = 0x30 << 16;
const int ASUS_WMI_KEYBOARD_POWER_SHUTDOWN = 0xC0 << 16;
public void TUFKeyboardPower(bool awake = true, bool boot = false, bool sleep = false, bool shutdown = false)
{
int state = 0xbd;
if (boot) state = state | ASUS_WMI_KEYBOARD_POWER_BOOT;
if (awake) state = state | ASUS_WMI_KEYBOARD_POWER_AWAKE;
if (sleep) state = state | ASUS_WMI_KEYBOARD_POWER_SLEEP;
if (shutdown) state = state | ASUS_WMI_KEYBOARD_POWER_SHUTDOWN;
state = state | 0x01 << 8;
DeviceSet(TUF_KB_STATE, state, "TUF_KB");
}
public void SubscribeToEvents(Action<object, EventArrivedEventArgs> EventHandler)
{
try
{
ManagementEventWatcher watcher = new ManagementEventWatcher();
watcher.EventArrived += new EventArrivedEventHandler(EventHandler);
watcher.Scope = new ManagementScope("root\\wmi");
watcher.Query = new WqlEventQuery("SELECT * FROM AsusAtkWmiEvent");
watcher.Start();
}
catch
{
Logger.WriteLine("Can't connect to ASUS WMI events");
}
}
}

407
app/AsusUSB.cs Normal file
View File

@@ -0,0 +1,407 @@
using HidLibrary;
using System.Text;
namespace GHelper
{
[Flags]
public enum AuraDev19b6 : uint
{
BootLogo = 1,
BootKeyb = 1 << 1,
AwakeLogo = 1 << 2,
AwakeKeyb = 1 << 3,
SleepLogo = 1 << 4,
SleepKeyb = 1 << 5,
ShutdownLogo = 1 << 6,
ShutdownKeyb = 1 << 7,
BootBar = 1u << (7 + 2),
AwakeBar = 1u << (7 + 3),
SleepBar = 1u << (7 + 4),
ShutdownBar = 1u << (7 + 5),
BootLid = 1u << (15 + 1),
AwakeLid = 1u << (15 + 2),
SleepLid = 1u << (15 + 3),
ShutdownLid = 1u << (15 + 4)
}
public static class AuraDev19b6Extensions
{
public static byte[] ToBytes(this AuraDev19b6[] controls)
{
uint a = 0;
foreach (var n in controls)
{
a |= (uint)n;
}
return new byte[] { 0x5d, 0xbd, 0x01, (byte)(a & 0xff), (byte)((a & 0xff00) >> 8), (byte)((a & 0xff0000) >> 16) };
}
public static ushort BitOr(this AuraDev19b6 self, AuraDev19b6 rhs)
{
return (ushort)(self | rhs);
}
public static ushort BitAnd(this AuraDev19b6 self, AuraDev19b6 rhs)
{
return (ushort)(self & rhs);
}
}
public static class AsusUSB
{
public const int ASUS_ID = 0x0b05;
public const byte INPUT_HID_ID = 0x5a;
public const byte AURA_HID_ID = 0x5d;
public static readonly byte[] LED_INIT1 = new byte[] { AURA_HID_ID, 0xb9 };
public static readonly byte[] LED_INIT2 = Encoding.ASCII.GetBytes("]ASUS Tech.Inc.");
public static readonly byte[] LED_INIT3 = new byte[] { AURA_HID_ID, 0x05, 0x20, 0x31, 0, 0x08 };
public static readonly byte[] LED_INIT4 = Encoding.ASCII.GetBytes("^ASUS Tech.Inc.");
public static readonly byte[] LED_INIT5 = new byte[] { 0x5e, 0x05, 0x20, 0x31, 0, 0x08 };
static byte[] MESSAGE_SET = { AURA_HID_ID, 0xb5, 0, 0, 0 };
static byte[] MESSAGE_APPLY = { AURA_HID_ID, 0xb4 };
static int[] deviceIds = { 0x1a30, 0x1854, 0x1869, 0x1866, 0x19b6, 0x1822, 0x1837, 0x1854, 0x184a, 0x183d, 0x8502, 0x1807, 0x17e0, 0x18c6 };
private static int mode = 0;
private static int speed = 1;
public static Color Color1 = Color.White;
public static Color Color2 = Color.Black;
public static Dictionary<int, string> GetSpeeds()
{
return new Dictionary<int, string>
{
{ 0, Properties.Strings.AuraSlow },
{ 1, Properties.Strings.AuraNormal },
{ 2, Properties.Strings.AuraFast }
};
}
static Dictionary<int, string> _modes = new Dictionary<int, string>
{
{ 0, Properties.Strings.AuraStatic },
{ 1, Properties.Strings.AuraBreathe },
{ 2, Properties.Strings.AuraColorCycle },
{ 3, Properties.Strings.AuraRainbow },
{ 10, Properties.Strings.AuraStrobe },
};
static Dictionary<int, string> _modesStrix = new Dictionary<int, string>
{
{ 0, Properties.Strings.AuraStatic },
{ 1, Properties.Strings.AuraBreathe },
{ 2, Properties.Strings.AuraColorCycle },
{ 3, Properties.Strings.AuraRainbow },
{ 4, "Star" },
{ 5, "Rain" },
{ 6, "Highlight" },
{ 7, "Laser" },
{ 8, "Ripple" },
{ 10, Properties.Strings.AuraStrobe},
{ 11, "Comet" },
{ 12, "Flash" },
};
public static Dictionary<int, string> GetModes()
{
if (AppConfig.ContainsModel("TUF"))
{
_modes.Remove(3);
}
if (AppConfig.ContainsModel("401"))
{
_modes.Remove(2);
_modes.Remove(3);
}
if (AppConfig.ContainsModel("Strix") || AppConfig.ContainsModel("Scar"))
{
return _modesStrix;
}
return _modes;
}
public static int Mode
{
get { return mode; }
set
{
if (GetModes().ContainsKey(value))
mode = value;
else
mode = 0;
}
}
public static bool HasSecondColor()
{
return (mode == 1 && !AppConfig.ContainsModel("TUF"));
}
public static int Speed
{
get { return speed; }
set
{
if (GetSpeeds().ContainsKey(value))
speed = value;
else
speed = 1;
}
}
public static void SetColor(int colorCode)
{
Color1 = Color.FromArgb(colorCode);
}
public static void SetColor2(int colorCode)
{
Color2 = Color.FromArgb(colorCode);
}
private static IEnumerable<HidDevice> GetHidDevices(int[] deviceIds, int minInput = 18, int minFeatures = 1)
{
HidDevice[] HidDeviceList = HidDevices.Enumerate(ASUS_ID, deviceIds).ToArray();
foreach (HidDevice device in HidDeviceList)
if (device.IsConnected
&& device.Capabilities.FeatureReportByteLength >= minFeatures
&& device.Capabilities.InputReportByteLength >= minInput)
yield return device;
}
public static HidDevice? GetDevice(byte reportID = INPUT_HID_ID)
{
HidDevice[] HidDeviceList = HidDevices.Enumerate(ASUS_ID, deviceIds).ToArray();
HidDevice input = null;
foreach (HidDevice device in HidDeviceList)
if (device.ReadFeatureData(out byte[] data, reportID))
{
input = device;
//Logger.WriteLine("HID Device("+ reportID + ")" + + device.Capabilities.FeatureReportByteLength + "|" + device.Capabilities.InputReportByteLength + device.DevicePath);
}
return input;
}
public static bool TouchpadToggle()
{
HidDevice? input = GetDevice();
if (input != null) return input.WriteFeatureData(new byte[] { INPUT_HID_ID, 0xf4, 0x6b });
return false;
}
public static byte[] AuraMessage(int mode, Color color, Color color2, int speed)
{
byte[] msg = new byte[17];
msg[0] = AURA_HID_ID;
msg[1] = 0xb3;
msg[2] = 0x00; // Zone
msg[3] = (byte)mode; // Aura Mode
msg[4] = (byte)(color.R); // R
msg[5] = (byte)(color.G); // G
msg[6] = (byte)(color.B); // B
msg[7] = (byte)speed; // aura.speed as u8;
msg[8] = 0; // aura.direction as u8;
msg[10] = (byte)(color2.R); // R
msg[11] = (byte)(color2.G); // G
msg[12] = (byte)(color2.B); // B
return msg;
}
public static void Init()
{
Task.Run(async () =>
{
var devices = GetHidDevices(deviceIds, 0);
foreach (HidDevice device in devices)
{
device.OpenDevice();
device.WriteFeatureData(LED_INIT1);
device.WriteFeatureData(LED_INIT2);
device.WriteFeatureData(LED_INIT3);
device.WriteFeatureData(LED_INIT4);
device.WriteFeatureData(LED_INIT5);
device.CloseDevice();
}
});
}
public static void ApplyBrightness(int brightness)
{
if (AppConfig.ContainsModel("TUF"))
Program.acpi.TUFKeyboardBrightness(brightness);
Task.Run(async () =>
{
byte[] msg = { AURA_HID_ID, 0xba, 0xc5, 0xc4, (byte)brightness };
var devices = GetHidDevices(deviceIds);
foreach (HidDevice device in devices)
{
device.OpenDevice();
device.WriteFeatureData(msg);
Logger.WriteLine("KB Backlight:" + BitConverter.ToString(msg));
device.CloseDevice();
}
// Backup payload for old models
if (AppConfig.ContainsModel("503"))
{
byte[] msgBackup = { INPUT_HID_ID, 0xba, 0xc5, 0xc4, (byte)brightness };
var devicesBackup = GetHidDevices(deviceIds, 0);
foreach (HidDevice device in devicesBackup)
{
device.OpenDevice();
device.WriteFeatureData(msgBackup);
device.CloseDevice();
}
}
});
}
public static void ApplyAuraPower(List<AuraDev19b6> flags)
{
byte[] msg = AuraDev19b6Extensions.ToBytes(flags.ToArray());
var devices = GetHidDevices(deviceIds);
//Logger.WriteLine("USB-KB = " + BitConverter.ToString(msg));
foreach (HidDevice device in devices)
{
device.OpenDevice();
device.WriteFeatureData(msg);
Logger.WriteLine("USB-KB " + device.Attributes.ProductHexId + ":" + BitConverter.ToString(msg));
device.CloseDevice();
}
if (AppConfig.ContainsModel("TUF"))
Program.acpi.TUFKeyboardPower(
flags.Contains(AuraDev19b6.AwakeKeyb),
flags.Contains(AuraDev19b6.BootKeyb),
flags.Contains(AuraDev19b6.SleepKeyb),
flags.Contains(AuraDev19b6.ShutdownKeyb));
}
public static void ApplyAura()
{
int _speed;
switch (Speed)
{
case 1:
_speed = 0xeb;
break;
case 2:
_speed = 0xf5;
break;
default:
_speed = 0xe1;
break;
}
byte[] msg = AuraMessage(Mode, Color1, Color2, _speed);
var devices = GetHidDevices(deviceIds);
if (devices.Count() == 0)
{
Logger.WriteLine("USB-KB : not found");
devices = GetHidDevices(deviceIds, 1);
}
foreach (HidDevice device in devices)
{
device.OpenDevice();
device.WriteFeatureData(msg);
device.WriteFeatureData(MESSAGE_SET);
device.WriteFeatureData(MESSAGE_APPLY);
device.CloseDevice();
Logger.WriteLine("USB-KB " + device.Capabilities.FeatureReportByteLength + "|" + device.Capabilities.InputReportByteLength + device.Description + device.DevicePath + ":" + BitConverter.ToString(msg));
}
if (AppConfig.ContainsModel("TUF"))
Program.acpi.TUFKeyboardRGB(Mode, Color1, _speed);
}
// Reference : thanks to https://github.com/RomanYazvinsky/ for initial discovery of XGM payloads
public static int SetXGM(byte[] msg)
{
//Logger.WriteLine("XGM Payload :" + BitConverter.ToString(msg));
var payload = new byte[300];
Array.Copy(msg, payload, msg.Length);
foreach (HidDevice device in GetHidDevices(new int[] { 0x1970 }, 0, 300))
{
device.OpenDevice();
Logger.WriteLine("XGM " + device.Attributes.ProductHexId + "|" + device.Capabilities.FeatureReportByteLength + ":" + BitConverter.ToString(msg));
device.WriteFeatureData(payload);
device.CloseDevice();
//return 1;
}
return 0;
}
public static void ApplyXGMLight(bool status)
{
SetXGM(new byte[] { 0x5e, 0xc5, status ? (byte)0x50 : (byte)0 });
}
public static int ResetXGM()
{
return SetXGM(new byte[] { 0x5e, 0xd1, 0x02 });
}
public static int SetXGMFan(byte[] curve)
{
if (AsusACPI.IsInvalidCurve(curve)) return -1;
byte[] msg = new byte[19];
Array.Copy(new byte[] { 0x5e, 0xd1, 0x01 }, msg, 3);
Array.Copy(curve, 0, msg, 3, curve.Length);
return SetXGM(msg);
}
}
}

View File

@@ -1,78 +0,0 @@
using HidLibrary;
public class Aura
{
static byte[] MESSAGE_SET = { 0x5d, 0xb5, 0,0,0 };
static byte[] MESSAGE_APPLY = { 0x5d, 0xb4};
public const int Static = 0;
public const int Breathe = 1;
public const int Strobe = 2;
public const int Rainbow = 3;
public const int Dingding = 4;
public const int SpeedSlow = 0xe1;
public const int SpeedMedium = 0xeb;
public const int SpeedHigh = 0xf5;
public static int Mode = Static;
public static Color Color1 = Color.White;
public static Color Color2 = Color.Black;
public static int Speed = SpeedSlow;
public static byte[] AuraMessage(int mode, Color color, Color color2, int speed)
{
byte[] msg = new byte[17];
msg[0] = 0x5d;
msg[1] = 0xb3;
msg[2] = 0x00; // Zone
msg[3] = (byte)mode; // Aura Mode
msg[4] = (byte)(color.R); // R
msg[5] = (byte)(color.G); // G
msg[6] = (byte)(color.B); // B
msg[7] = (byte)speed; // aura.speed as u8;
msg[8] = 0; // aura.direction as u8;
msg[10] = (byte)(color2.R); // R
msg[11] = (byte)(color2.G); // G
msg[12] = (byte)(color2.B); // B
return msg;
}
public static void ApplyAura()
{
HidDevice[] HidDeviceList;
int[] deviceIds = { 0x1854, 0x1869, 0x1866, 0x19b6, 0x1822, 0x1837, 0x1854, 0x184a, 0x183d, 0x8502, 0x1807, 0x17e0 };
HidDeviceList = HidDevices.Enumerate(0x0b05, deviceIds).ToArray();
if (Mode == Dingding)
{
Mode = 10;
Speed = SpeedMedium;
}
else if (Mode == Rainbow)
{
Speed = SpeedMedium;
}
else
{
Speed = SpeedSlow;
}
foreach (HidDevice device in HidDeviceList)
{
if (device.IsConnected && device.Description.Contains("HID"))
{
device.OpenDevice();
byte[] msg = AuraMessage(Mode, Color1, Color2, Speed);
device.Write(msg);
device.Write(MESSAGE_SET);
device.Write(MESSAGE_APPLY);
device.CloseDevice();
}
}
}
}

170
app/ControlHelper.cs Normal file
View File

@@ -0,0 +1,170 @@
using CustomControls;
using System.Drawing.Drawing2D;
using System.Windows.Forms.DataVisualization.Charting;
using WinFormsSliderBar;
public static class ControlHelper
{
static bool _invert = false;
static float _scale = 1;
public static void Adjust(RForm container, bool invert = false)
{
container.BackColor = RForm.formBack;
container.ForeColor = RForm.foreMain;
_invert = invert;
AdjustControls(container.Controls);
_invert = false;
}
public static void Resize(RForm container, float baseScale = 2)
{
_scale = GetDpiScale(container).Value / baseScale;
if (Math.Abs(_scale - 1) > 0.2) ResizeControls(container.Controls);
}
private static void ResizeControls(Control.ControlCollection controls)
{
foreach (Control control in controls)
{
var button = control as RButton;
if (button != null && button.Image is not null)
button.Image = ResizeImage(button.Image);
/*
var pictureBox = control as PictureBox;
if (pictureBox != null && pictureBox.BackgroundImage is not null)
pictureBox.BackgroundImage = ResizeImage(pictureBox.BackgroundImage);
*/
ResizeControls(control.Controls);
}
}
private static void AdjustControls(Control.ControlCollection controls)
{
foreach (Control control in controls)
{
var button = control as RButton;
if (button != null)
{
button.BackColor = button.Secondary ? RForm.buttonSecond : RForm.buttonMain;
button.ForeColor = RForm.foreMain;
button.FlatStyle = FlatStyle.Flat;
button.FlatAppearance.BorderColor = RForm.borderMain;
if (button.Image is not null)
button.Image = AdjustImage(button.Image);
}
var pictureBox = control as PictureBox;
if (pictureBox != null && pictureBox.BackgroundImage is not null)
pictureBox.BackgroundImage = AdjustImage(pictureBox.BackgroundImage);
var combo = control as RComboBox;
if (combo != null)
{
combo.BackColor = RForm.buttonMain;
combo.ForeColor = RForm.foreMain;
combo.BorderColor = RForm.buttonMain;
combo.ButtonColor = RForm.buttonMain;
combo.ArrowColor = RForm.foreMain;
}
var gb = control as GroupBox;
if (gb != null)
{
gb.ForeColor = RForm.foreMain;
}
var sl = control as Slider;
if (sl != null)
{
sl.borderColor = RForm.buttonMain;
}
var chk = control as CheckBox;
if (chk != null && chk.Padding.Right > 5)
{
chk.BackColor = RForm.buttonSecond;
}
var chart = control as Chart;
if (chart != null)
{
chart.BackColor = RForm.chartMain;
chart.ChartAreas[0].BackColor = RForm.chartMain;
chart.ChartAreas[0].AxisX.TitleForeColor = RForm.foreMain;
chart.ChartAreas[0].AxisY.TitleForeColor = RForm.foreMain;
chart.ChartAreas[0].AxisX.LabelStyle.ForeColor = RForm.foreMain;
chart.ChartAreas[0].AxisY.LabelStyle.ForeColor = RForm.foreMain;
chart.ChartAreas[0].AxisX.MajorTickMark.LineColor = RForm.foreMain;
chart.ChartAreas[0].AxisY.MajorTickMark.LineColor = RForm.foreMain;
chart.ChartAreas[0].AxisX.MajorGrid.LineColor = RForm.chartGrid;
chart.ChartAreas[0].AxisY.MajorGrid.LineColor = RForm.chartGrid;
chart.ChartAreas[0].AxisX.LineColor = RForm.chartGrid;
chart.ChartAreas[0].AxisY.LineColor = RForm.chartGrid;
chart.Titles[0].ForeColor = RForm.foreMain;
}
AdjustControls(control.Controls);
}
}
public static Lazy<float> GetDpiScale(Control control)
{
return new Lazy<float>(() =>
{
using (var graphics = control.CreateGraphics())
return graphics.DpiX / 96.0f;
});
}
private static Image ResizeImage(Image image)
{
var newSize = new Size((int)(image.Width * _scale), (int)(image.Height * _scale));
var pic = new Bitmap(newSize.Width, newSize.Height);
using (var g = Graphics.FromImage(pic))
{
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(image, new Rectangle(new Point(), newSize));
}
return pic;
}
private static Image AdjustImage(Image image)
{
var pic = new Bitmap(image);
if (_invert)
{
for (int y = 0; (y <= (pic.Height - 1)); y++)
{
for (int x = 0; (x <= (pic.Width - 1)); x++)
{
Color col = pic.GetPixel(x, y);
pic.SetPixel(x, y, Color.FromArgb(col.A, (255 - col.R), (255 - col.G), (255 - col.B)));
}
}
}
return pic;
}
}

35
app/CustomContextMenu.cs Normal file
View File

@@ -0,0 +1,35 @@
using System.Runtime.InteropServices;
namespace GHelper
{
class CustomContextMenu : ContextMenuStrip
{
[DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern long DwmSetWindowAttribute(IntPtr hwnd,
DWMWINDOWATTRIBUTE attribute,
ref DWM_WINDOW_CORNER_PREFERENCE pvAttribute,
uint cbAttribute);
public CustomContextMenu()
{
var preference = DWM_WINDOW_CORNER_PREFERENCE.DWMWCP_ROUNDSMALL; //change as you want
DwmSetWindowAttribute(Handle,
DWMWINDOWATTRIBUTE.DWMWA_WINDOW_CORNER_PREFERENCE,
ref preference,
sizeof(uint));
}
public enum DWMWINDOWATTRIBUTE
{
DWMWA_WINDOW_CORNER_PREFERENCE = 33
}
public enum DWM_WINDOW_CORNER_PREFERENCE
{
DWMWA_DEFAULT = 0,
DWMWCP_DONOTROUND = 1,
DWMWCP_ROUND = 2,
DWMWCP_ROUNDSMALL = 3,
}
}
}

396
app/CustomControls.cs Normal file
View File

@@ -0,0 +1,396 @@
using Microsoft.Win32;
using System.ComponentModel;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
namespace CustomControls
{
public class RForm : Form
{
public static Color colorEco = Color.FromArgb(255, 6, 180, 138);
public static Color colorStandard = Color.FromArgb(255, 58, 174, 239);
public static Color colorTurbo = Color.FromArgb(255, 255, 32, 32);
public static Color buttonMain;
public static Color buttonSecond;
public static Color formBack;
public static Color foreMain;
public static Color borderMain;
public static Color chartMain;
public static Color chartGrid;
[DllImport("UXTheme.dll", SetLastError = true, EntryPoint = "#138")]
public static extern bool CheckSystemDarkModeStatus();
[DllImport("DwmApi")] //System.Runtime.InteropServices
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, int[] attrValue, int attrSize);
public bool darkTheme = false;
public static void InitColors(bool darkTheme)
{
if (darkTheme)
{
buttonMain = Color.FromArgb(255, 55, 55, 55);
buttonSecond = Color.FromArgb(255, 38, 38, 38);
formBack = Color.FromArgb(255, 28, 28, 28);
foreMain = Color.FromArgb(255, 240, 240, 240);
borderMain = Color.FromArgb(255, 50, 50, 50);
chartMain = Color.FromArgb(255, 35, 35, 35);
chartGrid = Color.FromArgb(255, 70, 70, 70);
}
else
{
buttonMain = SystemColors.ControlLightLight;
buttonSecond = SystemColors.ControlLight;
formBack = SystemColors.Control;
foreMain = SystemColors.ControlText;
borderMain = Color.LightGray;
chartMain = SystemColors.ControlLightLight;
chartGrid = Color.LightGray;
}
}
private static bool IsDarkTheme()
{
using var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize");
var registryValueObject = key?.GetValue("AppsUseLightTheme");
if (registryValueObject == null) return false;
return (int)registryValueObject <= 0;
}
public bool InitTheme(bool setDPI = false)
{
bool newDarkTheme = CheckSystemDarkModeStatus();
bool changed = (darkTheme != newDarkTheme);
darkTheme = newDarkTheme;
InitColors(darkTheme);
if (setDPI)
ControlHelper.Resize(this);
if (changed)
{
DwmSetWindowAttribute(this.Handle, 20, new[] { darkTheme ? 1 : 0 }, 4);
ControlHelper.Adjust(this, changed);
}
return changed;
}
}
public class RCheckBox : CheckBox
{
}
public class RComboBox : ComboBox
{
private Color borderColor = Color.Gray;
[DefaultValue(typeof(Color), "Gray")]
public Color BorderColor
{
get { return borderColor; }
set
{
if (borderColor != value)
{
borderColor = value;
Invalidate();
}
}
}
private Color buttonColor = Color.FromArgb(255, 255, 255, 255);
[DefaultValue(typeof(Color), "255, 255, 255")]
public Color ButtonColor
{
get { return buttonColor; }
set
{
if (buttonColor != value)
{
buttonColor = value;
Invalidate();
}
}
}
private Color arrowColor = Color.Black;
[DefaultValue(typeof(Color), "Black")]
public Color ArrowColor
{
get { return arrowColor; }
set
{
if (arrowColor != value)
{
arrowColor = value;
Invalidate();
}
}
}
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PAINT && DropDownStyle != ComboBoxStyle.Simple)
{
var clientRect = ClientRectangle;
var dropDownButtonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
var outerBorder = new Rectangle(clientRect.Location,
new Size(clientRect.Width - 1, clientRect.Height - 1));
var innerBorder = new Rectangle(outerBorder.X + 1, outerBorder.Y + 1,
outerBorder.Width - dropDownButtonWidth - 2, outerBorder.Height - 2);
var innerInnerBorder = new Rectangle(innerBorder.X + 1, innerBorder.Y + 1,
innerBorder.Width - 2, innerBorder.Height - 2);
var dropDownRect = new Rectangle(innerBorder.Right + 1, innerBorder.Y,
dropDownButtonWidth, innerBorder.Height + 1);
if (RightToLeft == RightToLeft.Yes)
{
innerBorder.X = clientRect.Width - innerBorder.Right;
innerInnerBorder.X = clientRect.Width - innerInnerBorder.Right;
dropDownRect.X = clientRect.Width - dropDownRect.Right;
dropDownRect.Width += 1;
}
var innerBorderColor = Enabled ? BackColor : SystemColors.Control;
var outerBorderColor = Enabled ? BorderColor : SystemColors.ControlDark;
var buttonColor = Enabled ? ButtonColor : SystemColors.Control;
var middle = new Point(dropDownRect.Left + dropDownRect.Width / 2,
dropDownRect.Top + dropDownRect.Height / 2);
var arrow = new Point[]
{
new Point(middle.X - 3, middle.Y - 2),
new Point(middle.X + 4, middle.Y - 2),
new Point(middle.X, middle.Y + 2)
};
var ps = new PAINTSTRUCT();
bool shoulEndPaint = false;
IntPtr dc;
if (m.WParam == IntPtr.Zero)
{
dc = BeginPaint(Handle, ref ps);
m.WParam = dc;
shoulEndPaint = true;
}
else
{
dc = m.WParam;
}
var rgn = CreateRectRgn(innerInnerBorder.Left, innerInnerBorder.Top,
innerInnerBorder.Right, innerInnerBorder.Bottom);
SelectClipRgn(dc, rgn);
DefWndProc(ref m);
DeleteObject(rgn);
rgn = CreateRectRgn(clientRect.Left, clientRect.Top,
clientRect.Right, clientRect.Bottom);
SelectClipRgn(dc, rgn);
using (var g = Graphics.FromHdc(dc))
{
using (var b = new SolidBrush(buttonColor))
{
g.FillRectangle(b, dropDownRect);
}
using (var b = new SolidBrush(arrowColor))
{
g.FillPolygon(b, arrow);
}
using (var p = new Pen(innerBorderColor))
{
g.DrawRectangle(p, innerBorder);
g.DrawRectangle(p, innerInnerBorder);
}
using (var p = new Pen(outerBorderColor))
{
g.DrawRectangle(p, outerBorder);
}
}
if (shoulEndPaint)
EndPaint(Handle, ref ps);
DeleteObject(rgn);
}
else
base.WndProc(ref m);
}
private const int WM_PAINT = 0xF;
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int L, T, R, B;
}
[StructLayout(LayoutKind.Sequential)]
public struct PAINTSTRUCT
{
public IntPtr hdc;
public bool fErase;
public int rcPaint_left;
public int rcPaint_top;
public int rcPaint_right;
public int rcPaint_bottom;
public bool fRestore;
public bool fIncUpdate;
public int reserved1;
public int reserved2;
public int reserved3;
public int reserved4;
public int reserved5;
public int reserved6;
public int reserved7;
public int reserved8;
}
[DllImport("user32.dll")]
private static extern IntPtr BeginPaint(IntPtr hWnd,
[In, Out] ref PAINTSTRUCT lpPaint);
[DllImport("user32.dll")]
private static extern bool EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint);
[DllImport("gdi32.dll")]
public static extern int SelectClipRgn(IntPtr hDC, IntPtr hRgn);
[DllImport("user32.dll")]
public static extern int GetUpdateRgn(IntPtr hwnd, IntPtr hrgn, bool fErase);
public enum RegionFlags
{
ERROR = 0,
NULLREGION = 1,
SIMPLEREGION = 2,
COMPLEXREGION = 3,
}
[DllImport("gdi32.dll")]
internal static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateRectRgn(int x1, int y1, int x2, int y2);
}
public class RButton : Button
{
//Fields
private int borderSize = 5;
private int borderRadius = 5;
public int BorderRadius
{
get { return borderRadius; }
set
{
borderRadius = value;
}
}
private Color borderColor = Color.Transparent;
public Color BorderColor
{
get { return borderColor; }
set
{
borderColor = value;
}
}
private bool activated = false;
public bool Activated
{
get { return activated; }
set
{
if (activated != value)
this.Invalidate();
activated = value;
}
}
private bool secondary = false;
public bool Secondary
{
get { return secondary; }
set
{
secondary = value;
}
}
public RButton()
{
DoubleBuffered = true;
FlatStyle = FlatStyle.Flat;
FlatAppearance.BorderSize = 0;
}
private GraphicsPath GetFigurePath(Rectangle rect, int radius)
{
GraphicsPath path = new GraphicsPath();
float curveSize = radius * 2F;
path.StartFigure();
path.AddArc(rect.X, rect.Y, curveSize, curveSize, 180, 90);
path.AddArc(rect.Right - curveSize, rect.Y, curveSize, curveSize, 270, 90);
path.AddArc(rect.Right - curveSize, rect.Bottom - curveSize, curveSize, curveSize, 0, 90);
path.AddArc(rect.X, rect.Bottom - curveSize, curveSize, curveSize, 90, 90);
path.CloseFigure();
return path;
}
protected override void OnPaint(PaintEventArgs pevent)
{
base.OnPaint(pevent);
float ratio = pevent.Graphics.DpiX / 192.0f;
int border = (int)(ratio * borderSize);
Rectangle rectSurface = this.ClientRectangle;
Rectangle rectBorder = Rectangle.Inflate(rectSurface, -border, -border);
Color borderDrawColor = activated ? borderColor : Color.Transparent;
using (GraphicsPath pathSurface = GetFigurePath(rectSurface, borderRadius + border))
using (GraphicsPath pathBorder = GetFigurePath(rectBorder, borderRadius))
using (Pen penSurface = new Pen(this.Parent.BackColor, border))
using (Pen penBorder = new Pen(borderDrawColor, border))
{
penBorder.Alignment = PenAlignment.Outset;
pevent.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
this.Region = new Region(pathSurface);
pevent.Graphics.DrawPath(penSurface, pathSurface);
pevent.Graphics.DrawPath(penBorder, pathBorder);
}
if (!Enabled && ForeColor != SystemColors.ControlText)
{
var rect = pevent.ClipRectangle;
if (Image is not null)
{
rect.Y += Image.Height;
rect.Height -= Image.Height;
}
TextFormatFlags flags = TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.WordBreak;
TextRenderer.DrawText(pevent.Graphics, this.Text, this.Font, rect, Color.Gray, flags);
}
}
}
}

120
app/CustomControls.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<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>
</root>

863
app/Extra.Designer.cs generated Normal file
View File

@@ -0,0 +1,863 @@
using CustomControls;
using GHelper.Properties;
namespace GHelper
{
partial class Extra
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
groupBindings = new GroupBox();
tableKeys = new TableLayoutPanel();
textM2 = new TextBox();
textM1 = new TextBox();
comboM1 = new RComboBox();
labelM1 = new Label();
labelFNF4 = new Label();
comboFNF4 = new RComboBox();
comboM4 = new RComboBox();
comboM3 = new RComboBox();
textFNF4 = new TextBox();
textM4 = new TextBox();
textM3 = new TextBox();
labelM4 = new Label();
labelM3 = new Label();
labelM2 = new Label();
comboM2 = new RComboBox();
pictureHelp = new PictureBox();
groupLight = new GroupBox();
panelBacklightExtra = new Panel();
numericBacklightPluggedTime = new NumericUpDown();
labelBacklightTimeoutPlugged = new Label();
numericBacklightTime = new NumericUpDown();
labelBacklightTimeout = new Label();
labelBrightness = new Label();
trackBrightness = new TrackBar();
labelSpeed = new Label();
comboKeyboardSpeed = new RComboBox();
panelXMG = new Panel();
checkXMG = new CheckBox();
tableBacklight = new TableLayoutPanel();
labelBacklight = new Label();
checkAwake = new CheckBox();
checkBoot = new CheckBox();
checkSleep = new CheckBox();
checkShutdown = new CheckBox();
labelBacklightLogo = new Label();
checkAwakeLogo = new CheckBox();
checkBootLogo = new CheckBox();
checkSleepLogo = new CheckBox();
checkShutdownLogo = new CheckBox();
labelBacklightBar = new Label();
checkAwakeBar = new CheckBox();
checkBootBar = new CheckBox();
checkSleepBar = new CheckBox();
checkShutdownBar = new CheckBox();
labelBacklightLid = new Label();
checkAwakeLid = new CheckBox();
checkBootLid = new CheckBox();
checkSleepLid = new CheckBox();
checkShutdownLid = new CheckBox();
groupOther = new GroupBox();
checkGpuApps = new CheckBox();
checkAutoApplyWindowsPowerMode = new CheckBox();
checkKeyboardAuto = new CheckBox();
checkUSBC = new CheckBox();
checkNoOverdrive = new CheckBox();
checkTopmost = new CheckBox();
groupBindings.SuspendLayout();
tableKeys.SuspendLayout();
((System.ComponentModel.ISupportInitialize)pictureHelp).BeginInit();
groupLight.SuspendLayout();
panelBacklightExtra.SuspendLayout();
((System.ComponentModel.ISupportInitialize)numericBacklightPluggedTime).BeginInit();
((System.ComponentModel.ISupportInitialize)numericBacklightTime).BeginInit();
((System.ComponentModel.ISupportInitialize)trackBrightness).BeginInit();
panelXMG.SuspendLayout();
tableBacklight.SuspendLayout();
groupOther.SuspendLayout();
SuspendLayout();
//
// groupBindings
//
groupBindings.Controls.Add(tableKeys);
groupBindings.Controls.Add(pictureHelp);
groupBindings.Dock = DockStyle.Top;
groupBindings.Location = new Point(10, 10);
groupBindings.Name = "groupBindings";
groupBindings.Size = new Size(954, 324);
groupBindings.TabIndex = 0;
groupBindings.TabStop = false;
groupBindings.Text = "Key Bindings";
//
// tableKeys
//
tableKeys.ColumnCount = 3;
tableKeys.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 20F));
tableKeys.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40F));
tableKeys.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 40F));
tableKeys.Controls.Add(textM2, 2, 1);
tableKeys.Controls.Add(textM1, 2, 0);
tableKeys.Controls.Add(comboM1, 1, 0);
tableKeys.Controls.Add(labelM1, 0, 0);
tableKeys.Controls.Add(labelFNF4, 0, 4);
tableKeys.Controls.Add(comboFNF4, 1, 4);
tableKeys.Controls.Add(comboM4, 1, 3);
tableKeys.Controls.Add(comboM3, 1, 2);
tableKeys.Controls.Add(textFNF4, 2, 4);
tableKeys.Controls.Add(textM4, 2, 3);
tableKeys.Controls.Add(textM3, 2, 2);
tableKeys.Controls.Add(labelM4, 0, 3);
tableKeys.Controls.Add(labelM3, 0, 2);
tableKeys.Controls.Add(labelM2, 0, 1);
tableKeys.Controls.Add(comboM2, 1, 1);
tableKeys.Location = new Point(13, 38);
tableKeys.Name = "tableKeys";
tableKeys.Padding = new Padding(10);
tableKeys.RowCount = 5;
tableKeys.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
tableKeys.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
tableKeys.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
tableKeys.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
tableKeys.RowStyles.Add(new RowStyle(SizeType.Absolute, 50F));
tableKeys.Size = new Size(897, 266);
tableKeys.TabIndex = 10;
//
// textM2
//
textM2.Location = new Point(538, 63);
textM2.Name = "textM2";
textM2.PlaceholderText = "action";
textM2.Size = new Size(346, 39);
textM2.TabIndex = 14;
//
// textM1
//
textM1.Location = new Point(538, 13);
textM1.Name = "textM1";
textM1.PlaceholderText = "action";
textM1.Size = new Size(346, 39);
textM1.TabIndex = 13;
//
// comboM1
//
comboM1.BorderColor = Color.White;
comboM1.ButtonColor = Color.FromArgb(255, 255, 255);
comboM1.FormattingEnabled = true;
comboM1.Items.AddRange(new object[] { Strings.Default, Strings.VolumeMute, Strings.PlayPause, Strings.PrintScreen, Strings.ToggleAura, Strings.Custom });
comboM1.Location = new Point(188, 13);
comboM1.Name = "comboM1";
comboM1.Size = new Size(312, 40);
comboM1.TabIndex = 11;
//
// labelM1
//
labelM1.AutoSize = true;
labelM1.Location = new Point(13, 10);
labelM1.Name = "labelM1";
labelM1.Size = new Size(54, 32);
labelM1.TabIndex = 9;
labelM1.Text = "M1:";
//
// labelFNF4
//
labelFNF4.AutoSize = true;
labelFNF4.Location = new Point(13, 210);
labelFNF4.Name = "labelFNF4";
labelFNF4.Size = new Size(90, 32);
labelFNF4.TabIndex = 6;
labelFNF4.Text = "FN+F4:";
//
// comboFNF4
//
comboFNF4.BorderColor = Color.White;
comboFNF4.ButtonColor = Color.FromArgb(255, 255, 255);
comboFNF4.FormattingEnabled = true;
comboFNF4.Location = new Point(188, 213);
comboFNF4.Name = "comboFNF4";
comboFNF4.Size = new Size(312, 40);
comboFNF4.TabIndex = 7;
//
// comboM4
//
comboM4.BorderColor = Color.White;
comboM4.ButtonColor = Color.FromArgb(255, 255, 255);
comboM4.FormattingEnabled = true;
comboM4.Items.AddRange(new object[] { Strings.PerformanceMode, Strings.OpenGHelper, Strings.Custom });
comboM4.Location = new Point(188, 163);
comboM4.Name = "comboM4";
comboM4.Size = new Size(312, 40);
comboM4.TabIndex = 3;
//
// comboM3
//
comboM3.BorderColor = Color.White;
comboM3.ButtonColor = Color.FromArgb(255, 255, 255);
comboM3.FormattingEnabled = true;
comboM3.Items.AddRange(new object[] { Strings.Default, Strings.VolumeMute, Strings.PlayPause, Strings.PrintScreen, Strings.ToggleAura, Strings.Custom });
comboM3.Location = new Point(188, 113);
comboM3.Name = "comboM3";
comboM3.Size = new Size(312, 40);
comboM3.TabIndex = 1;
//
// textFNF4
//
textFNF4.Location = new Point(538, 213);
textFNF4.Name = "textFNF4";
textFNF4.PlaceholderText = "action";
textFNF4.Size = new Size(346, 39);
textFNF4.TabIndex = 8;
//
// textM4
//
textM4.Location = new Point(538, 163);
textM4.Name = "textM4";
textM4.PlaceholderText = "action";
textM4.Size = new Size(346, 39);
textM4.TabIndex = 5;
//
// textM3
//
textM3.Location = new Point(538, 113);
textM3.Name = "textM3";
textM3.PlaceholderText = "action";
textM3.Size = new Size(346, 39);
textM3.TabIndex = 4;
//
// labelM4
//
labelM4.AutoSize = true;
labelM4.Location = new Point(13, 160);
labelM4.Name = "labelM4";
labelM4.Size = new Size(54, 32);
labelM4.TabIndex = 2;
labelM4.Text = "M4:";
//
// labelM3
//
labelM3.AutoSize = true;
labelM3.Location = new Point(13, 110);
labelM3.Name = "labelM3";
labelM3.Size = new Size(54, 32);
labelM3.TabIndex = 0;
labelM3.Text = "M3:";
//
// labelM2
//
labelM2.AutoSize = true;
labelM2.Location = new Point(13, 60);
labelM2.Name = "labelM2";
labelM2.Size = new Size(54, 32);
labelM2.TabIndex = 10;
labelM2.Text = "M2:";
//
// comboM2
//
comboM2.BorderColor = Color.White;
comboM2.ButtonColor = Color.FromArgb(255, 255, 255);
comboM2.FormattingEnabled = true;
comboM2.Items.AddRange(new object[] { Strings.Default, Strings.VolumeMute, Strings.PlayPause, Strings.PrintScreen, Strings.ToggleAura, Strings.Custom });
comboM2.Location = new Point(188, 63);
comboM2.Name = "comboM2";
comboM2.Size = new Size(312, 40);
comboM2.TabIndex = 12;
//
// pictureHelp
//
pictureHelp.BackgroundImage = Resources.icons8_help_64;
pictureHelp.BackgroundImageLayout = ImageLayout.Zoom;
pictureHelp.Cursor = Cursors.Hand;
pictureHelp.Location = new Point(906, 51);
pictureHelp.Name = "pictureHelp";
pictureHelp.Size = new Size(32, 32);
pictureHelp.TabIndex = 9;
pictureHelp.TabStop = false;
//
// groupLight
//
groupLight.AutoSize = true;
groupLight.Controls.Add(panelBacklightExtra);
groupLight.Controls.Add(panelXMG);
groupLight.Controls.Add(tableBacklight);
groupLight.Dock = DockStyle.Top;
groupLight.Location = new Point(10, 334);
groupLight.Name = "groupLight";
groupLight.Size = new Size(954, 563);
groupLight.TabIndex = 1;
groupLight.TabStop = false;
groupLight.Text = "Keyboard Backlight";
//
// panelBacklightExtra
//
panelBacklightExtra.Controls.Add(numericBacklightPluggedTime);
panelBacklightExtra.Controls.Add(labelBacklightTimeoutPlugged);
panelBacklightExtra.Controls.Add(numericBacklightTime);
panelBacklightExtra.Controls.Add(labelBacklightTimeout);
panelBacklightExtra.Controls.Add(labelBrightness);
panelBacklightExtra.Controls.Add(trackBrightness);
panelBacklightExtra.Controls.Add(labelSpeed);
panelBacklightExtra.Controls.Add(comboKeyboardSpeed);
panelBacklightExtra.Dock = DockStyle.Top;
panelBacklightExtra.Location = new Point(3, 319);
panelBacklightExtra.Name = "panelBacklightExtra";
panelBacklightExtra.Size = new Size(948, 241);
panelBacklightExtra.TabIndex = 43;
//
// numericBacklightPluggedTime
//
numericBacklightPluggedTime.Location = new Point(655, 181);
numericBacklightPluggedTime.Maximum = new decimal(new int[] { 3600, 0, 0, 0 });
numericBacklightPluggedTime.Name = "numericBacklightPluggedTime";
numericBacklightPluggedTime.Size = new Size(240, 39);
numericBacklightPluggedTime.TabIndex = 49;
//
// labelBacklightTimeoutPlugged
//
labelBacklightTimeoutPlugged.Location = new Point(13, 183);
labelBacklightTimeoutPlugged.Name = "labelBacklightTimeoutPlugged";
labelBacklightTimeoutPlugged.Size = new Size(636, 45);
labelBacklightTimeoutPlugged.TabIndex = 48;
labelBacklightTimeoutPlugged.Text = "Seconds to turn off backlight when plugged";
//
// numericBacklightTime
//
numericBacklightTime.Location = new Point(655, 133);
numericBacklightTime.Maximum = new decimal(new int[] { 3600, 0, 0, 0 });
numericBacklightTime.Name = "numericBacklightTime";
numericBacklightTime.Size = new Size(240, 39);
numericBacklightTime.TabIndex = 47;
//
// labelBacklightTimeout
//
labelBacklightTimeout.Location = new Point(13, 135);
labelBacklightTimeout.Name = "labelBacklightTimeout";
labelBacklightTimeout.Size = new Size(636, 45);
labelBacklightTimeout.TabIndex = 46;
labelBacklightTimeout.Text = "Seconds to turn off backlight on battery";
//
// labelBrightness
//
labelBrightness.Location = new Point(13, 75);
labelBrightness.Name = "labelBrightness";
labelBrightness.Size = new Size(336, 43);
labelBrightness.TabIndex = 41;
labelBrightness.Text = "Brightness";
//
// trackBrightness
//
trackBrightness.LargeChange = 1;
trackBrightness.Location = new Point(355, 60);
trackBrightness.Maximum = 3;
trackBrightness.Name = "trackBrightness";
trackBrightness.Size = new Size(558, 90);
trackBrightness.TabIndex = 42;
trackBrightness.TickStyle = TickStyle.TopLeft;
//
// labelSpeed
//
labelSpeed.Location = new Point(13, 15);
labelSpeed.Name = "labelSpeed";
labelSpeed.Size = new Size(538, 40);
labelSpeed.TabIndex = 44;
labelSpeed.Text = "Animation Speed";
//
// comboKeyboardSpeed
//
comboKeyboardSpeed.BorderColor = Color.White;
comboKeyboardSpeed.ButtonColor = SystemColors.ControlLight;
comboKeyboardSpeed.FlatStyle = FlatStyle.Flat;
comboKeyboardSpeed.Font = new Font("Segoe UI", 9F, FontStyle.Regular, GraphicsUnit.Point);
comboKeyboardSpeed.FormattingEnabled = true;
comboKeyboardSpeed.ItemHeight = 32;
comboKeyboardSpeed.Items.AddRange(new object[] { "Slow", "Normal", "Fast" });
comboKeyboardSpeed.Location = new Point(607, 15);
comboKeyboardSpeed.Margin = new Padding(4, 10, 4, 8);
comboKeyboardSpeed.Name = "comboKeyboardSpeed";
comboKeyboardSpeed.Size = new Size(291, 40);
comboKeyboardSpeed.TabIndex = 43;
comboKeyboardSpeed.TabStop = false;
//
// panelXMG
//
panelXMG.Controls.Add(checkXMG);
panelXMG.Dock = DockStyle.Top;
panelXMG.Location = new Point(3, 261);
panelXMG.Name = "panelXMG";
panelXMG.Size = new Size(948, 58);
panelXMG.TabIndex = 42;
//
// checkXMG
//
checkXMG.AutoSize = true;
checkXMG.Location = new Point(3, 10);
checkXMG.Name = "checkXMG";
checkXMG.Padding = new Padding(15, 2, 5, 2);
checkXMG.Size = new Size(178, 40);
checkXMG.TabIndex = 2;
checkXMG.Text = "XG Mobile";
checkXMG.UseVisualStyleBackColor = true;
//
// tableBacklight
//
tableBacklight.AutoSize = true;
tableBacklight.ColumnCount = 4;
tableBacklight.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
tableBacklight.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
tableBacklight.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
tableBacklight.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 25F));
tableBacklight.Controls.Add(labelBacklight, 0, 0);
tableBacklight.Controls.Add(checkAwake, 0, 1);
tableBacklight.Controls.Add(checkBoot, 0, 2);
tableBacklight.Controls.Add(checkSleep, 0, 3);
tableBacklight.Controls.Add(checkShutdown, 0, 4);
tableBacklight.Controls.Add(labelBacklightLogo, 1, 0);
tableBacklight.Controls.Add(checkAwakeLogo, 1, 1);
tableBacklight.Controls.Add(checkBootLogo, 1, 2);
tableBacklight.Controls.Add(checkSleepLogo, 1, 3);
tableBacklight.Controls.Add(checkShutdownLogo, 1, 4);
tableBacklight.Controls.Add(labelBacklightBar, 2, 0);
tableBacklight.Controls.Add(checkAwakeBar, 2, 1);
tableBacklight.Controls.Add(checkBootBar, 2, 2);
tableBacklight.Controls.Add(checkSleepBar, 2, 3);
tableBacklight.Controls.Add(checkShutdownBar, 2, 4);
tableBacklight.Controls.Add(labelBacklightLid, 3, 0);
tableBacklight.Controls.Add(checkAwakeLid, 3, 1);
tableBacklight.Controls.Add(checkBootLid, 3, 2);
tableBacklight.Controls.Add(checkSleepLid, 3, 3);
tableBacklight.Controls.Add(checkShutdownLid, 3, 4);
tableBacklight.Dock = DockStyle.Top;
tableBacklight.Location = new Point(3, 35);
tableBacklight.Margin = new Padding(0);
tableBacklight.Name = "tableBacklight";
tableBacklight.RowCount = 5;
tableBacklight.RowStyles.Add(new RowStyle());
tableBacklight.RowStyles.Add(new RowStyle());
tableBacklight.RowStyles.Add(new RowStyle());
tableBacklight.RowStyles.Add(new RowStyle());
tableBacklight.RowStyles.Add(new RowStyle());
tableBacklight.Size = new Size(948, 226);
tableBacklight.TabIndex = 41;
//
// labelBacklight
//
labelBacklight.Dock = DockStyle.Fill;
labelBacklight.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
labelBacklight.Location = new Point(3, 0);
labelBacklight.Name = "labelBacklight";
labelBacklight.Padding = new Padding(10, 5, 5, 5);
labelBacklight.Size = new Size(231, 42);
labelBacklight.TabIndex = 6;
labelBacklight.Text = "Keyboard";
//
// checkAwake
//
checkAwake.Dock = DockStyle.Fill;
checkAwake.Location = new Point(3, 45);
checkAwake.Name = "checkAwake";
checkAwake.Padding = new Padding(15, 2, 5, 2);
checkAwake.Size = new Size(231, 40);
checkAwake.TabIndex = 1;
checkAwake.Text = Strings.Awake;
checkAwake.UseVisualStyleBackColor = true;
//
// checkBoot
//
checkBoot.Dock = DockStyle.Fill;
checkBoot.Location = new Point(3, 91);
checkBoot.Name = "checkBoot";
checkBoot.Padding = new Padding(15, 2, 5, 2);
checkBoot.Size = new Size(231, 40);
checkBoot.TabIndex = 2;
checkBoot.Text = Strings.Boot;
checkBoot.UseVisualStyleBackColor = true;
//
// checkSleep
//
checkSleep.Dock = DockStyle.Fill;
checkSleep.Location = new Point(3, 137);
checkSleep.Name = "checkSleep";
checkSleep.Padding = new Padding(15, 2, 5, 2);
checkSleep.Size = new Size(231, 40);
checkSleep.TabIndex = 3;
checkSleep.Text = "Sleep";
checkSleep.UseVisualStyleBackColor = true;
//
// checkShutdown
//
checkShutdown.Dock = DockStyle.Fill;
checkShutdown.Location = new Point(3, 183);
checkShutdown.Name = "checkShutdown";
checkShutdown.Padding = new Padding(15, 2, 5, 2);
checkShutdown.Size = new Size(231, 40);
checkShutdown.TabIndex = 4;
checkShutdown.Text = Strings.Shutdown;
checkShutdown.UseVisualStyleBackColor = true;
//
// labelBacklightLogo
//
labelBacklightLogo.Dock = DockStyle.Fill;
labelBacklightLogo.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
labelBacklightLogo.Location = new Point(240, 0);
labelBacklightLogo.Name = "labelBacklightLogo";
labelBacklightLogo.Padding = new Padding(10, 5, 5, 5);
labelBacklightLogo.Size = new Size(231, 42);
labelBacklightLogo.TabIndex = 21;
labelBacklightLogo.Text = "Logo";
//
// checkAwakeLogo
//
checkAwakeLogo.Dock = DockStyle.Fill;
checkAwakeLogo.Location = new Point(240, 45);
checkAwakeLogo.Name = "checkAwakeLogo";
checkAwakeLogo.Padding = new Padding(15, 2, 5, 2);
checkAwakeLogo.Size = new Size(231, 40);
checkAwakeLogo.TabIndex = 17;
checkAwakeLogo.Text = Strings.Awake;
checkAwakeLogo.UseVisualStyleBackColor = true;
//
// checkBootLogo
//
checkBootLogo.Dock = DockStyle.Fill;
checkBootLogo.Location = new Point(240, 91);
checkBootLogo.Name = "checkBootLogo";
checkBootLogo.Padding = new Padding(15, 2, 5, 2);
checkBootLogo.Size = new Size(231, 40);
checkBootLogo.TabIndex = 18;
checkBootLogo.Text = Strings.Boot;
checkBootLogo.UseVisualStyleBackColor = true;
//
// checkSleepLogo
//
checkSleepLogo.Dock = DockStyle.Fill;
checkSleepLogo.Location = new Point(240, 137);
checkSleepLogo.Name = "checkSleepLogo";
checkSleepLogo.Padding = new Padding(15, 2, 5, 2);
checkSleepLogo.Size = new Size(231, 40);
checkSleepLogo.TabIndex = 19;
checkSleepLogo.Text = Strings.Sleep;
checkSleepLogo.UseVisualStyleBackColor = true;
//
// checkShutdownLogo
//
checkShutdownLogo.Dock = DockStyle.Fill;
checkShutdownLogo.Location = new Point(240, 183);
checkShutdownLogo.Name = "checkShutdownLogo";
checkShutdownLogo.Padding = new Padding(15, 2, 5, 2);
checkShutdownLogo.Size = new Size(231, 40);
checkShutdownLogo.TabIndex = 20;
checkShutdownLogo.Text = Strings.Shutdown;
checkShutdownLogo.UseVisualStyleBackColor = true;
//
// labelBacklightBar
//
labelBacklightBar.Dock = DockStyle.Fill;
labelBacklightBar.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
labelBacklightBar.Location = new Point(477, 0);
labelBacklightBar.Name = "labelBacklightBar";
labelBacklightBar.Padding = new Padding(10, 5, 5, 5);
labelBacklightBar.Size = new Size(231, 42);
labelBacklightBar.TabIndex = 11;
labelBacklightBar.Text = "Lightbar";
//
// checkAwakeBar
//
checkAwakeBar.Dock = DockStyle.Fill;
checkAwakeBar.Location = new Point(477, 45);
checkAwakeBar.Name = "checkAwakeBar";
checkAwakeBar.Padding = new Padding(15, 2, 5, 2);
checkAwakeBar.Size = new Size(231, 40);
checkAwakeBar.TabIndex = 7;
checkAwakeBar.Text = Strings.Awake;
checkAwakeBar.UseVisualStyleBackColor = true;
//
// checkBootBar
//
checkBootBar.Dock = DockStyle.Fill;
checkBootBar.Location = new Point(477, 91);
checkBootBar.Name = "checkBootBar";
checkBootBar.Padding = new Padding(15, 2, 5, 2);
checkBootBar.Size = new Size(231, 40);
checkBootBar.TabIndex = 8;
checkBootBar.Text = Strings.Boot;
checkBootBar.UseVisualStyleBackColor = true;
//
// checkSleepBar
//
checkSleepBar.Dock = DockStyle.Fill;
checkSleepBar.Location = new Point(477, 137);
checkSleepBar.Name = "checkSleepBar";
checkSleepBar.Padding = new Padding(15, 2, 5, 2);
checkSleepBar.Size = new Size(231, 40);
checkSleepBar.TabIndex = 9;
checkSleepBar.Text = Strings.Sleep;
checkSleepBar.UseVisualStyleBackColor = true;
//
// checkShutdownBar
//
checkShutdownBar.Dock = DockStyle.Fill;
checkShutdownBar.Location = new Point(477, 183);
checkShutdownBar.Name = "checkShutdownBar";
checkShutdownBar.Padding = new Padding(15, 2, 5, 2);
checkShutdownBar.Size = new Size(231, 40);
checkShutdownBar.TabIndex = 10;
checkShutdownBar.Text = Strings.Shutdown;
checkShutdownBar.UseVisualStyleBackColor = true;
//
// labelBacklightLid
//
labelBacklightLid.Dock = DockStyle.Fill;
labelBacklightLid.Font = new Font("Segoe UI", 9F, FontStyle.Bold, GraphicsUnit.Point);
labelBacklightLid.Location = new Point(714, 0);
labelBacklightLid.Name = "labelBacklightLid";
labelBacklightLid.Padding = new Padding(10, 5, 5, 5);
labelBacklightLid.Size = new Size(231, 42);
labelBacklightLid.TabIndex = 16;
labelBacklightLid.Text = "Lid";
//
// checkAwakeLid
//
checkAwakeLid.Dock = DockStyle.Fill;
checkAwakeLid.Location = new Point(714, 45);
checkAwakeLid.Name = "checkAwakeLid";
checkAwakeLid.Padding = new Padding(15, 2, 5, 2);
checkAwakeLid.Size = new Size(231, 40);
checkAwakeLid.TabIndex = 12;
checkAwakeLid.Text = Strings.Awake;
checkAwakeLid.UseVisualStyleBackColor = true;
//
// checkBootLid
//
checkBootLid.Dock = DockStyle.Fill;
checkBootLid.Location = new Point(714, 91);
checkBootLid.Name = "checkBootLid";
checkBootLid.Padding = new Padding(15, 2, 5, 2);
checkBootLid.Size = new Size(231, 40);
checkBootLid.TabIndex = 13;
checkBootLid.Text = Strings.Boot;
checkBootLid.UseVisualStyleBackColor = true;
//
// checkSleepLid
//
checkSleepLid.Dock = DockStyle.Fill;
checkSleepLid.Location = new Point(714, 137);
checkSleepLid.Name = "checkSleepLid";
checkSleepLid.Padding = new Padding(15, 2, 5, 2);
checkSleepLid.Size = new Size(231, 40);
checkSleepLid.TabIndex = 14;
checkSleepLid.Text = Strings.Sleep;
checkSleepLid.UseVisualStyleBackColor = true;
//
// checkShutdownLid
//
checkShutdownLid.Dock = DockStyle.Fill;
checkShutdownLid.Location = new Point(714, 183);
checkShutdownLid.Name = "checkShutdownLid";
checkShutdownLid.Padding = new Padding(15, 2, 5, 2);
checkShutdownLid.Size = new Size(231, 40);
checkShutdownLid.TabIndex = 15;
checkShutdownLid.Text = Strings.Shutdown;
checkShutdownLid.UseVisualStyleBackColor = true;
//
// groupOther
//
groupOther.Controls.Add(checkGpuApps);
groupOther.Controls.Add(checkAutoApplyWindowsPowerMode);
groupOther.Controls.Add(checkKeyboardAuto);
groupOther.Controls.Add(checkUSBC);
groupOther.Controls.Add(checkNoOverdrive);
groupOther.Controls.Add(checkTopmost);
groupOther.Dock = DockStyle.Top;
groupOther.Location = new Point(10, 897);
groupOther.Name = "groupOther";
groupOther.Size = new Size(954, 310);
groupOther.TabIndex = 2;
groupOther.TabStop = false;
groupOther.Text = "Other";
//
// checkGpuApps
//
checkGpuApps.AutoSize = true;
checkGpuApps.Location = new Point(25, 220);
checkGpuApps.Name = "checkGpuApps";
checkGpuApps.Size = new Size(544, 36);
checkGpuApps.TabIndex = 48;
checkGpuApps.Text = "Stop all apps using GPU when switching to Eco";
checkGpuApps.UseVisualStyleBackColor = true;
//
// checkAutoApplyWindowsPowerMode
//
checkAutoApplyWindowsPowerMode.AutoSize = true;
checkAutoApplyWindowsPowerMode.Location = new Point(25, 268);
checkAutoApplyWindowsPowerMode.Name = "checkAutoApplyWindowsPowerMode";
checkAutoApplyWindowsPowerMode.Size = new Size(416, 36);
checkAutoApplyWindowsPowerMode.TabIndex = 47;
checkAutoApplyWindowsPowerMode.Text = "Auto Adjust Windows Power Mode";
checkAutoApplyWindowsPowerMode.UseVisualStyleBackColor = true;
//
// checkKeyboardAuto
//
checkKeyboardAuto.AutoSize = true;
checkKeyboardAuto.Location = new Point(25, 40);
checkKeyboardAuto.MaximumSize = new Size(780, 0);
checkKeyboardAuto.Name = "checkKeyboardAuto";
checkKeyboardAuto.Size = new Size(712, 36);
checkKeyboardAuto.TabIndex = 46;
checkKeyboardAuto.Text = Strings.KeyboardAuto;
checkKeyboardAuto.UseVisualStyleBackColor = true;
//
// checkUSBC
//
checkUSBC.AutoSize = true;
checkUSBC.Location = new Point(25, 85);
checkUSBC.Name = "checkUSBC";
checkUSBC.Size = new Size(659, 36);
checkUSBC.TabIndex = 4;
checkUSBC.Text = "Keep GPU disabled on USB-C charger in Optimized mode";
checkUSBC.UseVisualStyleBackColor = true;
//
// checkNoOverdrive
//
checkNoOverdrive.AutoSize = true;
checkNoOverdrive.Location = new Point(25, 130);
checkNoOverdrive.Name = "checkNoOverdrive";
checkNoOverdrive.Size = new Size(307, 36);
checkNoOverdrive.TabIndex = 3;
checkNoOverdrive.Text = Strings.DisableOverdrive;
checkNoOverdrive.UseVisualStyleBackColor = true;
//
// checkTopmost
//
checkTopmost.AutoSize = true;
checkTopmost.Location = new Point(25, 175);
checkTopmost.Name = "checkTopmost";
checkTopmost.Size = new Size(390, 36);
checkTopmost.TabIndex = 1;
checkTopmost.Text = Strings.WindowTop;
checkTopmost.UseVisualStyleBackColor = true;
//
// Extra
//
AutoScaleDimensions = new SizeF(13F, 32F);
AutoScaleMode = AutoScaleMode.Font;
AutoSize = true;
AutoSizeMode = AutoSizeMode.GrowAndShrink;
ClientSize = new Size(974, 1220);
Controls.Add(groupOther);
Controls.Add(groupLight);
Controls.Add(groupBindings);
FormBorderStyle = FormBorderStyle.FixedSingle;
MaximizeBox = false;
MdiChildrenMinimizedAnchorBottom = false;
MinimizeBox = false;
MinimumSize = new Size(1000, 0);
Name = "Extra";
Padding = new Padding(10);
ShowIcon = false;
ShowInTaskbar = false;
Text = "Extra Settings";
groupBindings.ResumeLayout(false);
tableKeys.ResumeLayout(false);
tableKeys.PerformLayout();
((System.ComponentModel.ISupportInitialize)pictureHelp).EndInit();
groupLight.ResumeLayout(false);
groupLight.PerformLayout();
panelBacklightExtra.ResumeLayout(false);
panelBacklightExtra.PerformLayout();
((System.ComponentModel.ISupportInitialize)numericBacklightPluggedTime).EndInit();
((System.ComponentModel.ISupportInitialize)numericBacklightTime).EndInit();
((System.ComponentModel.ISupportInitialize)trackBrightness).EndInit();
panelXMG.ResumeLayout(false);
panelXMG.PerformLayout();
tableBacklight.ResumeLayout(false);
groupOther.ResumeLayout(false);
groupOther.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private GroupBox groupBindings;
private Label labelM3;
private RComboBox comboM3;
private RComboBox comboM4;
private Label labelM4;
private TextBox textM4;
private TextBox textM3;
private TextBox textFNF4;
private RComboBox comboFNF4;
private Label labelFNF4;
private GroupBox groupLight;
private GroupBox groupOther;
private CheckBox checkTopmost;
private CheckBox checkNoOverdrive;
private PictureBox pictureHelp;
private CheckBox checkUSBC;
private TableLayoutPanel tableBacklight;
private CheckBox checkShutdown;
private CheckBox checkAwake;
private CheckBox checkBoot;
private CheckBox checkSleep;
private CheckBox checkBootLid;
private Label labelBacklight;
private CheckBox checkSleepBar;
private CheckBox checkShutdownBar;
private Label labelBacklightBar;
private CheckBox checkAwakeBar;
private CheckBox checkBootBar;
private CheckBox checkSleepLid;
private CheckBox checkShutdownLid;
private Label labelBacklightLid;
private CheckBox checkAwakeLid;
private Label labelBacklightLogo;
private CheckBox checkAwakeLogo;
private CheckBox checkBootLogo;
private CheckBox checkSleepLogo;
private CheckBox checkShutdownLogo;
private Panel panelBacklightExtra;
private Label labelBrightness;
private TrackBar trackBrightness;
private Label labelSpeed;
private RComboBox comboKeyboardSpeed;
private Panel panelXMG;
private CheckBox checkXMG;
private Label labelBacklightTimeout;
private NumericUpDown numericBacklightTime;
private CheckBox checkKeyboardAuto;
private CheckBox checkAutoApplyWindowsPowerMode;
private TableLayoutPanel tableKeys;
private Label labelM1;
private Label labelM2;
private RComboBox comboM1;
private RComboBox comboM2;
private TextBox textM2;
private TextBox textM1;
private NumericUpDown numericBacklightPluggedTime;
private Label labelBacklightTimeoutPlugged;
private CheckBox checkGpuApps;
}
}

352
app/Extra.cs Normal file
View File

@@ -0,0 +1,352 @@
using CustomControls;
using System.Diagnostics;
namespace GHelper
{
public partial class Extra : RForm
{
Dictionary<string, string> customActions = new Dictionary<string, string>
{
{"","--------------" },
{"mute", Properties.Strings.VolumeMute},
{"screenshot", Properties.Strings.PrintScreen},
{"play", Properties.Strings.PlayPause},
{"aura", Properties.Strings.ToggleAura},
{"performance", Properties.Strings.PerformanceMode},
{"screen", Properties.Strings.ToggleScreen},
{"miniled", Properties.Strings.ToggleMiniled},
{"custom", Properties.Strings.Custom}
};
private void SetKeyCombo(ComboBox combo, TextBox txbox, string name)
{
switch (name)
{
case "m1":
customActions[""] = Properties.Strings.VolumeDown;
break;
case "m2":
customActions[""] = Properties.Strings.VolumeUp;
break;
case "m3":
customActions[""] = Properties.Strings.MuteMic;
break;
case "m4":
customActions[""] = Properties.Strings.OpenGHelper;
break;
case "fnf4":
customActions[""] = Properties.Strings.ToggleAura;
customActions.Remove("aura");
break;
}
combo.DropDownStyle = ComboBoxStyle.DropDownList;
combo.DataSource = new BindingSource(customActions, null);
combo.DisplayMember = "Value";
combo.ValueMember = "Key";
string action = AppConfig.getConfigString(name);
combo.SelectedValue = (action is not null) ? action : "";
if (combo.SelectedValue is null) combo.SelectedValue = "";
combo.SelectedValueChanged += delegate
{
if (combo.SelectedValue is not null)
AppConfig.setConfig(name, combo.SelectedValue.ToString());
if (name == "m1" || name == "m2")
Program.inputDispatcher.RegisterKeys();
};
txbox.Text = AppConfig.getConfigString(name + "_custom");
txbox.TextChanged += delegate
{
AppConfig.setConfig(name + "_custom", txbox.Text);
};
}
public Extra()
{
InitializeComponent();
groupBindings.Text = Properties.Strings.KeyBindings;
groupLight.Text = " " + Properties.Strings.LaptopBacklight;
groupOther.Text = Properties.Strings.Other;
checkAwake.Text = Properties.Strings.Awake;
checkSleep.Text = Properties.Strings.Sleep;
checkBoot.Text = Properties.Strings.Boot;
checkShutdown.Text = Properties.Strings.Shutdown;
labelSpeed.Text = Properties.Strings.AnimationSpeed;
labelBrightness.Text = Properties.Strings.Brightness;
labelBacklightTimeout.Text = Properties.Strings.BacklightTimeout;
labelBacklightTimeoutPlugged.Text = Properties.Strings.BacklightTimeoutPlugged;
checkKeyboardAuto.Text = Properties.Strings.KeyboardAuto;
checkNoOverdrive.Text = Properties.Strings.DisableOverdrive;
checkTopmost.Text = Properties.Strings.WindowTop;
checkUSBC.Text = Properties.Strings.OptimizedUSBC;
checkAutoApplyWindowsPowerMode.Text = Properties.Strings.ApplyWindowsPowerPlan;
labelBacklight.Text = Properties.Strings.Keyboard;
labelBacklightBar.Text = Properties.Strings.Lightbar;
labelBacklightLid.Text = Properties.Strings.Lid;
labelBacklightLogo.Text = Properties.Strings.Logo;
checkGpuApps.Text = Properties.Strings.KillGpuApps;
Text = Properties.Strings.ExtraSettings;
InitTheme();
SetKeyCombo(comboM1, textM1, "m1");
SetKeyCombo(comboM2, textM2, "m2");
SetKeyCombo(comboM3, textM3, "m3");
SetKeyCombo(comboM4, textM4, "m4");
SetKeyCombo(comboFNF4, textFNF4, "fnf4");
Shown += Keyboard_Shown;
comboKeyboardSpeed.DropDownStyle = ComboBoxStyle.DropDownList;
comboKeyboardSpeed.DataSource = new BindingSource(AsusUSB.GetSpeeds(), null);
comboKeyboardSpeed.DisplayMember = "Value";
comboKeyboardSpeed.ValueMember = "Key";
comboKeyboardSpeed.SelectedValue = AsusUSB.Speed;
comboKeyboardSpeed.SelectedValueChanged += ComboKeyboardSpeed_SelectedValueChanged;
// Keyboard
checkAwake.Checked = !(AppConfig.getConfig("keyboard_awake") == 0);
checkBoot.Checked = !(AppConfig.getConfig("keyboard_boot") == 0);
checkSleep.Checked = !(AppConfig.getConfig("keyboard_sleep") == 0);
checkShutdown.Checked = !(AppConfig.getConfig("keyboard_shutdown") == 0);
// Lightbar
checkAwakeBar.Checked = !(AppConfig.getConfig("keyboard_awake_bar") == 0);
checkBootBar.Checked = !(AppConfig.getConfig("keyboard_boot_bar") == 0);
checkSleepBar.Checked = !(AppConfig.getConfig("keyboard_sleep_bar") == 0);
checkShutdownBar.Checked = !(AppConfig.getConfig("keyboard_shutdown_bar") == 0);
// Lid
checkAwakeLid.Checked = !(AppConfig.getConfig("keyboard_awake_lid") == 0);
checkBootLid.Checked = !(AppConfig.getConfig("keyboard_boot_lid") == 0);
checkSleepLid.Checked = !(AppConfig.getConfig("keyboard_sleep_lid") == 0);
checkShutdownLid.Checked = !(AppConfig.getConfig("keyboard_shutdown_lid") == 0);
// Logo
checkAwakeLogo.Checked = !(AppConfig.getConfig("keyboard_awake_logo") == 0);
checkBootLogo.Checked = !(AppConfig.getConfig("keyboard_boot_logo") == 0);
checkSleepLogo.Checked = !(AppConfig.getConfig("keyboard_sleep_logo") == 0);
checkShutdownLogo.Checked = !(AppConfig.getConfig("keyboard_shutdown_logo") == 0);
checkAwake.CheckedChanged += CheckPower_CheckedChanged;
checkBoot.CheckedChanged += CheckPower_CheckedChanged;
checkSleep.CheckedChanged += CheckPower_CheckedChanged;
checkShutdown.CheckedChanged += CheckPower_CheckedChanged;
checkAwakeBar.CheckedChanged += CheckPower_CheckedChanged;
checkBootBar.CheckedChanged += CheckPower_CheckedChanged;
checkSleepBar.CheckedChanged += CheckPower_CheckedChanged;
checkShutdownBar.CheckedChanged += CheckPower_CheckedChanged;
checkAwakeLid.CheckedChanged += CheckPower_CheckedChanged;
checkBootLid.CheckedChanged += CheckPower_CheckedChanged;
checkSleepLid.CheckedChanged += CheckPower_CheckedChanged;
checkShutdownLid.CheckedChanged += CheckPower_CheckedChanged;
checkAwakeLogo.CheckedChanged += CheckPower_CheckedChanged;
checkBootLogo.CheckedChanged += CheckPower_CheckedChanged;
checkSleepLogo.CheckedChanged += CheckPower_CheckedChanged;
checkShutdownLogo.CheckedChanged += CheckPower_CheckedChanged;
if (!AppConfig.ContainsModel("Strix"))
{
labelBacklightBar.Visible = false;
checkAwakeBar.Visible = false;
checkBootBar.Visible = false;
checkSleepBar.Visible = false;
checkShutdownBar.Visible = false;
if (!AppConfig.ContainsModel("Z13"))
{
labelBacklightLid.Visible = false;
checkAwakeLid.Visible = false;
checkBootLid.Visible = false;
checkSleepLid.Visible = false;
checkShutdownLid.Visible = false;
labelBacklightLogo.Visible = false;
checkAwakeLogo.Visible = false;
checkBootLogo.Visible = false;
checkSleepLogo.Visible = false;
checkShutdownLogo.Visible = false;
}
}
checkTopmost.Checked = (AppConfig.getConfig("topmost") == 1);
checkTopmost.CheckedChanged += CheckTopmost_CheckedChanged; ;
checkKeyboardAuto.Checked = (AppConfig.getConfig("keyboard_auto") == 1);
checkKeyboardAuto.CheckedChanged += CheckKeyboardAuto_CheckedChanged;
checkNoOverdrive.Checked = (AppConfig.getConfig("no_overdrive") == 1);
checkNoOverdrive.CheckedChanged += CheckNoOverdrive_CheckedChanged;
checkUSBC.Checked = (AppConfig.getConfig("optimized_usbc") == 1);
checkUSBC.CheckedChanged += CheckUSBC_CheckedChanged;
checkAutoApplyWindowsPowerMode.Checked = (AppConfig.getConfig("auto_apply_power_plan") != 0);
checkAutoApplyWindowsPowerMode.CheckedChanged += checkAutoApplyWindowsPowerMode_CheckedChanged;
int kb_brightness = AppConfig.getConfig("keyboard_brightness");
trackBrightness.Value = (kb_brightness >= 0 && kb_brightness <= 3) ? kb_brightness : 3;
pictureHelp.Click += PictureHelp_Click;
trackBrightness.Scroll += TrackBrightness_Scroll;
panelXMG.Visible = (Program.acpi.DeviceGet(AsusACPI.GPUXGConnected) == 1);
checkXMG.Checked = !(AppConfig.getConfig("xmg_light") == 0);
checkXMG.CheckedChanged += CheckXMG_CheckedChanged;
numericBacklightTime.Value = AppConfig.getConfig("keyboard_timeout", 60);
numericBacklightPluggedTime.Value = AppConfig.getConfig("keyboard_ac_timeout", 0);
numericBacklightTime.ValueChanged += NumericBacklightTime_ValueChanged;
numericBacklightPluggedTime.ValueChanged += NumericBacklightTime_ValueChanged;
checkGpuApps.Checked = AppConfig.isConfig("kill_gpu_apps");
checkGpuApps.CheckedChanged += CheckGpuApps_CheckedChanged;
}
private void CheckGpuApps_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("kill_gpu_apps", (checkGpuApps.Checked ? 1 : 0));
}
private void NumericBacklightTime_ValueChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("keyboard_timeout", (int)numericBacklightTime.Value);
AppConfig.setConfig("keyboard_ac_timeout", (int)numericBacklightPluggedTime.Value);
Program.inputDispatcher.InitBacklightTimer();
}
private void CheckXMG_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("xmg_light", (checkXMG.Checked ? 1 : 0));
AsusUSB.ApplyXGMLight(checkXMG.Checked);
}
private void CheckUSBC_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("optimized_usbc", (checkUSBC.Checked ? 1 : 0));
}
private void TrackBrightness_Scroll(object? sender, EventArgs e)
{
AppConfig.setConfig("keyboard_brightness", trackBrightness.Value);
AsusUSB.ApplyBrightness(trackBrightness.Value);
}
private void PictureHelp_Click(object? sender, EventArgs e)
{
Process.Start(new ProcessStartInfo("https://github.com/seerge/g-helper#custom-hotkey-actions") { UseShellExecute = true });
}
private void CheckNoOverdrive_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("no_overdrive", (checkNoOverdrive.Checked ? 1 : 0));
Program.settingsForm.AutoScreen(true);
}
private void CheckKeyboardAuto_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("keyboard_auto", (checkKeyboardAuto.Checked ? 1 : 0));
}
private void CheckTopmost_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("topmost", (checkTopmost.Checked ? 1 : 0));
Program.settingsForm.TopMost = checkTopmost.Checked;
}
private void CheckPower_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("keyboard_awake", (checkAwake.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_boot", (checkBoot.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_sleep", (checkSleep.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_shutdown", (checkShutdown.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_awake_bar", (checkAwakeBar.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_boot_bar", (checkBootBar.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_sleep_bar", (checkSleepBar.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_shutdown_bar", (checkShutdownBar.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_awake_lid", (checkAwakeLid.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_boot_lid", (checkBootLid.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_sleep_lid", (checkSleepLid.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_shutdown_lid", (checkShutdownLid.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_awake_logo", (checkAwakeLogo.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_boot_logo", (checkBootLogo.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_sleep_logo", (checkSleepLogo.Checked ? 1 : 0));
AppConfig.setConfig("keyboard_shutdown_logo", (checkShutdownLogo.Checked ? 1 : 0));
List<AuraDev19b6> flags = new List<AuraDev19b6>();
if (checkAwake.Checked) flags.Add(AuraDev19b6.AwakeKeyb);
if (checkBoot.Checked) flags.Add(AuraDev19b6.BootKeyb);
if (checkSleep.Checked) flags.Add(AuraDev19b6.SleepKeyb);
if (checkShutdown.Checked) flags.Add(AuraDev19b6.ShutdownKeyb);
if (checkAwakeBar.Checked) flags.Add(AuraDev19b6.AwakeBar);
if (checkBootBar.Checked) flags.Add(AuraDev19b6.BootBar);
if (checkSleepBar.Checked) flags.Add(AuraDev19b6.SleepBar);
if (checkShutdownBar.Checked) flags.Add(AuraDev19b6.ShutdownBar);
if (checkAwakeLid.Checked) flags.Add(AuraDev19b6.AwakeLid);
if (checkBootLid.Checked) flags.Add(AuraDev19b6.BootLid);
if (checkSleepLid.Checked) flags.Add(AuraDev19b6.SleepLid);
if (checkShutdownLid.Checked) flags.Add(AuraDev19b6.ShutdownLid);
if (checkAwakeLogo.Checked) flags.Add(AuraDev19b6.AwakeLogo);
if (checkBootLogo.Checked) flags.Add(AuraDev19b6.BootLogo);
if (checkSleepLogo.Checked) flags.Add(AuraDev19b6.SleepLogo);
if (checkShutdownLogo.Checked) flags.Add(AuraDev19b6.ShutdownLogo);
AsusUSB.ApplyAuraPower(flags);
}
private void ComboKeyboardSpeed_SelectedValueChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("aura_speed", (int)comboKeyboardSpeed.SelectedValue);
Program.settingsForm.SetAura();
}
private void Keyboard_Shown(object? sender, EventArgs e)
{
if (Height > Program.settingsForm.Height)
{
Top = Program.settingsForm.Top + Program.settingsForm.Height - Height;
}
else
{
Top = Program.settingsForm.Top;
}
Left = Program.settingsForm.Left - Width - 5;
}
private void checkAutoApplyWindowsPowerMode_CheckedChanged(object? sender, EventArgs e)
{
AppConfig.setConfig("auto_apply_power_plan", checkAutoApplyWindowsPowerMode.Checked ? 1 : 0);
}
}
}

120
app/Extra.resx Normal file
View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<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>
</root>

1051
app/Fans.Designer.cs generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,52 +1,295 @@
using System;
using CustomControls;
using GHelper.Gpu;
using System.Diagnostics;
using System.Windows.Forms.DataVisualization.Charting;
namespace GHelper
{
public partial class Fans : Form
public partial class Fans : RForm
{
DataPoint curPoint = null;
Series seriesCPU;
Series seriesGPU;
Series seriesMid;
Series seriesXGM;
void SetChart(Chart chart, int device)
static int MinRPM, MaxRPM;
static bool powerVisible = true, gpuVisible = true;
const int fansMax = 100;
NvidiaGpuControl? nvControl = null;
public Fans()
{
string title;
InitializeComponent();
if (device == 1)
title = "GPU Fan Profile";
Text = Properties.Strings.FansAndPower;
labelPowerLimits.Text = Properties.Strings.PowerLimits;
labelInfo.Text = Properties.Strings.PPTExperimental;
checkApplyPower.Text = Properties.Strings.ApplyPowerLimits;
labelFans.Text = Properties.Strings.FanCurves;
labelBoost.Text = Properties.Strings.CPUBoost;
buttonReset.Text = Properties.Strings.FactoryDefaults;
checkApplyFans.Text = Properties.Strings.ApplyFanCurve;
labelGPU.Text = Properties.Strings.GPUSettings;
labelGPUCoreTitle.Text = Properties.Strings.GPUCoreClockOffset;
labelGPUMemoryTitle.Text = Properties.Strings.GPUMemoryClockOffset;
labelGPUBoostTitle.Text = Properties.Strings.GPUBoost;
labelGPUTempTitle.Text = Properties.Strings.GPUTempTarget;
InitTheme();
MinRPM = 18;
MaxRPM = HardwareControl.GetFanMax();
labelTip.Visible = false;
labelTip.BackColor = Color.Transparent;
FormClosing += Fans_FormClosing;
seriesCPU = chartCPU.Series.Add("CPU");
seriesGPU = chartGPU.Series.Add("GPU");
seriesMid = chartMid.Series.Add("Mid");
seriesXGM = chartXGM.Series.Add("XGM");
seriesCPU.Color = colorStandard;
seriesGPU.Color = colorTurbo;
seriesMid.Color = colorEco;
seriesXGM.Color = Color.Orange;
chartCPU.MouseMove += ChartCPU_MouseMove;
chartCPU.MouseUp += ChartCPU_MouseUp;
chartGPU.MouseMove += ChartCPU_MouseMove;
chartGPU.MouseUp += ChartCPU_MouseUp;
chartMid.MouseMove += ChartCPU_MouseMove;
chartMid.MouseUp += ChartCPU_MouseUp;
chartXGM.MouseMove += ChartCPU_MouseMove;
chartXGM.MouseUp += ChartCPU_MouseUp;
buttonReset.Click += ButtonReset_Click;
trackTotal.Maximum = AsusACPI.MaxTotal;
trackTotal.Minimum = AsusACPI.MinTotal;
trackCPU.Maximum = AsusACPI.MaxCPU;
trackCPU.Minimum = AsusACPI.MinCPU;
trackAPU.Maximum = AsusACPI.MaxCPU;
trackAPU.Minimum = AsusACPI.MinCPU;
trackAPU.Scroll += TrackPower_Scroll;
trackCPU.Scroll += TrackPower_Scroll;
trackTotal.Scroll += TrackPower_Scroll;
trackAPU.MouseUp += TrackPower_MouseUp;
trackCPU.MouseUp += TrackPower_MouseUp;
trackTotal.MouseUp += TrackPower_MouseUp;
checkApplyFans.Click += CheckApplyFans_Click;
checkApplyPower.Click += CheckApplyPower_Click;
trackGPUCore.Minimum = NvidiaGpuControl.MinCoreOffset;
trackGPUCore.Maximum = NvidiaGpuControl.MaxCoreOffset;
trackGPUMemory.Minimum = NvidiaGpuControl.MinMemoryOffset;
trackGPUMemory.Maximum = NvidiaGpuControl.MaxMemoryOffset;
trackGPUBoost.Minimum = AsusACPI.MinGPUBoost;
trackGPUBoost.Maximum = AsusACPI.MaxGPUBoost;
trackGPUTemp.Minimum = AsusACPI.MinGPUTemp;
trackGPUTemp.Maximum = AsusACPI.MaxGPUTemp;
trackGPUCore.Scroll += trackGPU_Scroll;
trackGPUMemory.Scroll += trackGPU_Scroll;
trackGPUBoost.Scroll += trackGPUPower_Scroll;
trackGPUTemp.Scroll += trackGPUPower_Scroll;
trackGPUCore.MouseUp += TrackGPU_MouseUp;
trackGPUMemory.MouseUp += TrackGPU_MouseUp;
trackGPUBoost.MouseUp += TrackGPU_MouseUp;
trackGPUTemp.MouseUp += TrackGPU_MouseUp;
//labelInfo.MaximumSize = new Size(280, 0);
labelInfo.Text = Properties.Strings.PPTExperimental;
labelFansResult.Visible = false;
InitFans();
InitPower();
InitBoost();
InitGPU(true);
comboBoost.SelectedValueChanged += ComboBoost_Changed;
Shown += Fans_Shown;
}
private void TrackGPU_MouseUp(object? sender, MouseEventArgs e)
{
Program.settingsForm.SetGPUPower();
Program.settingsForm.SetGPUClocks(true);
}
public void InitGPU(bool readClocks = false)
{
if (HardwareControl.GpuControl is not null && HardwareControl.GpuControl.IsNvidia)
{
nvControl = (NvidiaGpuControl)HardwareControl.GpuControl;
}
else
title = "CPU Fan Profile";
{
gpuVisible = panelGPU.Visible = false;
return;
}
try
{
gpuVisible = panelGPU.Visible = true;
int gpu_boost = AppConfig.getConfigPerf("gpu_boost");
int gpu_temp = AppConfig.getConfigPerf("gpu_temp");
int core = AppConfig.getConfigPerf("gpu_core");
int memory = AppConfig.getConfigPerf("gpu_memory");
if (gpu_boost < 0) gpu_boost = AsusACPI.MaxGPUBoost;
if (gpu_temp < 0) gpu_temp = AsusACPI.MaxGPUTemp;
if (core == -1) core = 0;
if (memory == -1) memory = 0;
//if (readClocks)
//{
int status = nvControl.GetClocks(out int current_core, out int current_memory);
if (status != -1)
{
core = current_core;
memory = current_memory;
}
try
{
labelGPU.Text = nvControl.FullName;
}
catch
{
}
//}
trackGPUCore.Value = Math.Max(Math.Min(core, NvidiaGpuControl.MaxCoreOffset), NvidiaGpuControl.MinCoreOffset);
trackGPUMemory.Value = Math.Max(Math.Min(memory, NvidiaGpuControl.MaxMemoryOffset), NvidiaGpuControl.MinMemoryOffset);
trackGPUBoost.Value = Math.Max(Math.Min(gpu_boost, AsusACPI.MaxGPUBoost), AsusACPI.MinGPUBoost);
trackGPUTemp.Value = Math.Max(Math.Min(gpu_temp, AsusACPI.MaxGPUTemp), AsusACPI.MinGPUTemp);
panelGPUBoost.Visible = (Program.acpi.DeviceGet(AsusACPI.PPT_GPUC0) >= 0);
panelGPUTemp.Visible = (Program.acpi.DeviceGet(AsusACPI.PPT_GPUC2) >= 0);
VisualiseGPUSettings();
}
catch (Exception ex)
{
Logger.WriteLine(ex.ToString());
gpuVisible = panelGPU.Visible = false;
}
}
private void VisualiseGPUSettings()
{
labelGPUCore.Text = $"{trackGPUCore.Value} MHz";
labelGPUMemory.Text = $"{trackGPUMemory.Value} MHz";
labelGPUBoost.Text = $"{trackGPUBoost.Value}W";
labelGPUTemp.Text = $"{trackGPUTemp.Value}°C";
}
private void trackGPU_Scroll(object? sender, EventArgs e)
{
if (sender is null) return;
TrackBar track = (TrackBar)sender;
track.Value = (int)Math.Round((float)track.Value / 5) * 5;
AppConfig.setConfigPerf("gpu_core", trackGPUCore.Value);
AppConfig.setConfigPerf("gpu_memory", trackGPUMemory.Value);
VisualiseGPUSettings();
}
private void trackGPUPower_Scroll(object? sender, EventArgs e)
{
AppConfig.setConfigPerf("gpu_boost", trackGPUBoost.Value);
AppConfig.setConfigPerf("gpu_temp", trackGPUTemp.Value);
VisualiseGPUSettings();
}
static string ChartPercToRPM(int percentage, string unit = "")
{
if (percentage == 0) return "OFF";
return (200 * Math.Round((float)(MinRPM * 100 + (MaxRPM - MinRPM) * percentage) / 200)).ToString() + unit;
}
void SetChart(Chart chart, AsusFan device)
{
string title = "";
switch (device)
{
case AsusFan.CPU:
title = Properties.Strings.FanProfileCPU;
break;
case AsusFan.GPU:
title = Properties.Strings.FanProfileGPU;
break;
case AsusFan.Mid:
title = Properties.Strings.FanProfileMid;
break;
case AsusFan.XGM:
title = "XG Mobile";
break;
}
if (Program.settingsForm.perfName.Length > 0)
labelFans.Text = "Fan Profiles: " + Program.settingsForm.perfName;
labelFans.Text = Properties.Strings.FanProfiles + ": " + Program.settingsForm.perfName;
if (chart.Titles.Count > 0)
chart.Titles[0].Text = title;
else
chart.Titles.Add(title);
chart.ChartAreas[0].AxisX.MajorGrid.LineColor = Color.LightGray;
chart.ChartAreas[0].AxisY.MajorGrid.LineColor = Color.LightGray;
chart.Titles[0].Text = title;
chart.ChartAreas[0].AxisX.Minimum = 10;
chart.ChartAreas[0].AxisX.Maximum = 100;
chart.ChartAreas[0].AxisX.Interval = 10;
chart.ChartAreas[0].AxisY.Minimum = 0;
chart.ChartAreas[0].AxisY.Maximum = 100;
chart.ChartAreas[0].AxisY.Maximum = fansMax;
chart.ChartAreas[0].AxisY.LabelStyle.Font = new Font("Arial", 7F);
chart.ChartAreas[0].AxisY.CustomLabels.Add(-2, 2, "OFF");
chart.ChartAreas[0].AxisX.MajorGrid.LineColor = chartGrid;
chart.ChartAreas[0].AxisY.MajorGrid.LineColor = chartGrid;
chart.ChartAreas[0].AxisX.LineColor = chartGrid;
chart.ChartAreas[0].AxisY.LineColor = chartGrid;
for (int i = 1; i <= 9; i++)
chart.ChartAreas[0].AxisY.CustomLabels.Add(i * 10 - 2, i * 10 + 2, (1800 + 400 * i).ToString());
for (int i = 0; i <= fansMax - 10; i += 10)
chart.ChartAreas[0].AxisY.CustomLabels.Add(i - 2, i + 2, ChartPercToRPM(i));
chart.ChartAreas[0].AxisY.CustomLabels.Add(98, 102, "RPM");
chart.ChartAreas[0].AxisY.CustomLabels.Add(fansMax - 2, fansMax + 2, Properties.Strings.RPM);
chart.ChartAreas[0].AxisY.Interval = 10;
@@ -55,70 +298,33 @@ namespace GHelper
}
private void Fans_Shown(object? sender, EventArgs e)
public void FormPosition()
{
panelSliders.Visible = gpuVisible || powerVisible;
if (Height > Program.settingsForm.Height)
{
Top = Program.settingsForm.Top + Program.settingsForm.Height - Height;
}
else
{
MinimumSize = new Size(0, Program.settingsForm.Height);
Size = MinimumSize = new Size(0, Program.settingsForm.Height);
Height = Program.settingsForm.Height;
Top = Program.settingsForm.Top;
}
Left = Program.settingsForm.Left - Width - 5;
}
public Fans()
private void Fans_Shown(object? sender, EventArgs e)
{
FormPosition();
}
InitializeComponent();
FormClosing += Fans_FormClosing;
seriesCPU = chartCPU.Series.Add("CPU");
seriesGPU = chartGPU.Series.Add("GPU");
seriesCPU.Color = Color.Blue;
seriesGPU.Color = Color.Red;
chartCPU.MouseMove += ChartCPU_MouseMove;
chartCPU.MouseUp += ChartCPU_MouseUp;
chartGPU.MouseMove += ChartCPU_MouseMove;
chartGPU.MouseUp += ChartCPU_MouseUp;
buttonReset.Click += ButtonReset_Click;
buttonApply.Click += ButtonApply_Click;
trackTotal.Maximum = ASUSWmi.MaxTotal;
trackTotal.Minimum = ASUSWmi.MinTotal;
trackCPU.Maximum = ASUSWmi.MaxCPU;
trackCPU.Minimum = ASUSWmi.MinCPU;
trackCPU.Scroll += TrackCPU_Scroll;
trackTotal.Scroll += TrackTotal_Scroll;
buttonApplyPower.Click += ButtonApplyPower_Click;
checkAuto.Click += CheckAuto_Click;
checkApplyPower.Click += CheckApplyPower_Click;
//labelInfo.MaximumSize = new Size(280, 0);
labelInfo.Text = "Power Limits (PPT) is\nexperimental feature.\n\nUse carefully and\non your own risk!";
InitFans();
InitPower();
InitBoost();
comboBoost.SelectedIndexChanged += ComboBoost_Changed;
Shown += Fans_Shown;
private void TrackPower_MouseUp(object? sender, MouseEventArgs e)
{
Program.settingsForm.AutoPower();
}
@@ -126,142 +332,206 @@ namespace GHelper
{
int boost = NativeMethods.GetCPUBoost();
if (boost >= 0)
comboBoost.SelectedIndex = boost;
comboBoost.SelectedIndex = Math.Min(boost, comboBoost.Items.Count - 1);
}
private void ComboBoost_Changed(object? sender, EventArgs e)
{
if (sender is null) return;
ComboBox cmb = (ComboBox)sender;
NativeMethods.SetCPUBoost(cmb.SelectedIndex);
if (AppConfig.getConfigPerf("auto_boost") != comboBoost.SelectedIndex)
{
NativeMethods.SetCPUBoost(comboBoost.SelectedIndex);
AppConfig.setConfigPerf("auto_boost", comboBoost.SelectedIndex);
}
}
private void CheckApplyPower_Click(object? sender, EventArgs e)
{
if (sender is null) return;
CheckBox chk = (CheckBox)sender;
Program.config.setConfigPerf("auto_apply_power", chk.Checked ? 1 : 0);
AppConfig.setConfigPerf("auto_apply_power", chk.Checked ? 1 : 0);
if (chk.Checked)
{
Program.settingsForm.AutoPower();
}
else
{
Program.acpi.DeviceSet(AsusACPI.PerformanceMode, AppConfig.getConfig("performance_mode"), "PerfMode");
Program.settingsForm.AutoFans();
}
}
private void CheckAuto_Click(object? sender, EventArgs e)
private void CheckApplyFans_Click(object? sender, EventArgs e)
{
if (sender is null) return;
CheckBox chk = (CheckBox)sender;
Program.config.setConfigPerf("auto_apply", chk.Checked ? 1 : 0);
AppConfig.setConfigPerf("auto_apply", chk.Checked ? 1 : 0);
if (chk.Checked)
{
Program.settingsForm.AutoFans();
}
else
{
Program.acpi.DeviceSet(AsusACPI.PerformanceMode, AppConfig.getConfig("performance_mode"), "PerfMode");
Program.settingsForm.AutoPower();
}
}
public void LabelFansResult(string text)
{
labelFansResult.Text = text;
labelFansResult.Visible = (text.Length > 0);
}
private void Fans_FormClosing(object? sender, FormClosingEventArgs e)
{
/*
if (e.CloseReason == CloseReason.UserClosing)
{
e.Cancel = true;
Hide();
}
}*/
}
private void ButtonApplyPower_Click(object? sender, EventArgs e)
{
Program.settingsForm.SetPower();
ApplyLabel(true);
}
public void InitPower(bool changed = false)
{
bool cpuBmode = (Program.wmi.DeviceGet(ASUSWmi.PPT_CPUB0) >= 0); // 2022 model +
bool cpuAmode = (Program.wmi.DeviceGet(ASUSWmi.PPT_TotalA0) >= 0); // 2021 model +
bool cpuAmode = (Program.acpi.DeviceGet(AsusACPI.PPT_TotalA0) >= 0); // 2021 model +
bool cpuBmode = (Program.acpi.DeviceGet(AsusACPI.PPT_CPUB0) >= 0); // 2022 model +
bool apuMode = (Program.acpi.DeviceGet(AsusACPI.PPT_APUC1) >= 0);
panelPower.Visible = cpuAmode;
powerVisible = panelPower.Visible = cpuAmode;
panelCPU.Visible = cpuBmode;
panelAPU.Visible = apuMode;
// Yes, that's stupid, but Total slider on 2021 model actually adjusts CPU PPT
if (!cpuBmode)
{
label1.Text = "CPU SPPT";
labelLeftPlatform.Text = "CPU";
}
int limit_total;
int limit_cpu;
bool apply = Program.config.getConfigPerf("auto_apply_power") == 1;
int limit_apu;
bool apply = AppConfig.getConfigPerf("auto_apply_power") == 1;
if (changed)
{
limit_total = trackTotal.Value;
limit_cpu = trackCPU.Value;
ApplyLabel(false);
limit_apu = trackAPU.Value;
}
else
{
limit_total = Program.config.getConfigPerf("limit_total");
limit_cpu = Program.config.getConfigPerf("limit_cpu");
ApplyLabel(apply);
limit_total = AppConfig.getConfigPerf("limit_total");
limit_cpu = AppConfig.getConfigPerf("limit_cpu");
limit_apu = AppConfig.getConfigPerf("limit_apu");
}
if (limit_total < 0) limit_total = ASUSWmi.DefaultTotal;
if (limit_total > ASUSWmi.MaxTotal) limit_total = ASUSWmi.MaxTotal;
if (limit_total < ASUSWmi.MinTotal) limit_total = ASUSWmi.MinTotal;
if (limit_total < 0) limit_total = AsusACPI.DefaultTotal;
if (limit_total > AsusACPI.MaxTotal) limit_total = AsusACPI.MaxTotal;
if (limit_total < AsusACPI.MinTotal) limit_total = AsusACPI.MinTotal;
if (limit_cpu < 0) limit_cpu = ASUSWmi.DefaultCPU;
if (limit_cpu > ASUSWmi.MaxCPU) limit_cpu = ASUSWmi.MaxCPU;
if (limit_cpu < ASUSWmi.MinCPU) limit_cpu = ASUSWmi.MinCPU;
if (limit_cpu < 0) limit_cpu = AsusACPI.DefaultCPU;
if (limit_cpu > AsusACPI.MaxCPU) limit_cpu = AsusACPI.MaxCPU;
if (limit_cpu < AsusACPI.MinCPU) limit_cpu = AsusACPI.MinCPU;
if (limit_cpu > limit_total) limit_cpu = limit_total;
if (limit_apu < 0) limit_apu = AsusACPI.DefaultCPU;
if (limit_apu > AsusACPI.MaxCPU) limit_apu = AsusACPI.MaxCPU;
if (limit_apu < AsusACPI.MinCPU) limit_apu = AsusACPI.MinCPU;
if (limit_apu > limit_total) limit_apu = limit_total;
trackTotal.Value = limit_total;
trackCPU.Value = limit_cpu;
trackAPU.Value = limit_apu;
checkApplyPower.Checked = apply;
labelTotal.Text = trackTotal.Value.ToString() + "W";
labelCPU.Text = trackCPU.Value.ToString() + "W";
pictureFine.Visible = (limit_cpu > 85 || limit_total > 145);
labelAPU.Text = trackAPU.Value.ToString() + "W";
AppConfig.setConfigPerf("limit_total", limit_total);
AppConfig.setConfigPerf("limit_cpu", limit_cpu);
AppConfig.setConfigPerf("limit_apu", limit_apu);
Program.config.setConfigPerf("limit_total", limit_total);
Program.config.setConfigPerf("limit_cpu", limit_cpu);
}
private void TrackTotal_Scroll(object? sender, EventArgs e)
private void TrackPower_Scroll(object? sender, EventArgs e)
{
InitPower(true);
}
private void TrackCPU_Scroll(object? sender, EventArgs e)
{
InitPower(true);
}
public void ApplyLabel(bool applied = false)
{
if (applied)
{
labelApplied.ForeColor = Color.Blue;
labelApplied.Text = "Applied";
}
else
{
labelApplied.ForeColor = Color.Red;
labelApplied.Text = "Not Applied";
}
}
public void InitFans()
{
SetChart(chartCPU, 0);
SetChart(chartGPU, 1);
int chartCount = 2;
LoadProfile(seriesCPU, 0);
LoadProfile(seriesGPU, 1);
// Middle / system fan check
if (!AsusACPI.IsEmptyCurve(Program.acpi.GetFanCurve(AsusFan.Mid)))
{
AppConfig.setConfig("mid_fan", 1);
chartCount++;
chartMid.Visible = true;
SetChart(chartMid, AsusFan.Mid);
LoadProfile(seriesMid, AsusFan.Mid);
}
else
{
AppConfig.setConfig("mid_fan", 0);
}
int auto_apply = Program.config.getConfigPerf("auto_apply");
// XG Mobile Fan check
if (Program.acpi.IsXGConnected())
{
AppConfig.setConfig("xgm_fan", 1);
chartCount++;
chartXGM.Visible = true;
SetChart(chartXGM, AsusFan.XGM);
LoadProfile(seriesXGM, AsusFan.XGM);
}
else
{
AppConfig.setConfig("xgm_fan", 0);
}
checkAuto.Checked = (auto_apply == 1);
try
{
if (chartCount > 2)
Size = MinimumSize = new Size(0, (int)(ControlHelper.GetDpiScale(this).Value * (chartCount * 200 + 100)));
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
SetChart(chartCPU, AsusFan.CPU);
SetChart(chartGPU, AsusFan.GPU);
LoadProfile(seriesCPU, AsusFan.CPU);
LoadProfile(seriesGPU, AsusFan.GPU);
int auto_apply = AppConfig.getConfigPerf("auto_apply");
checkApplyFans.Checked = (auto_apply == 1);
}
void LoadProfile(Series series, int device, int def = 0)
void LoadProfile(Series series, AsusFan device, bool reset = false)
{
series.ChartType = SeriesChartType.Line;
@@ -270,14 +540,19 @@ namespace GHelper
series.Points.Clear();
int mode = Program.config.getConfig("performance_mode");
byte[] curve = Program.config.getFanConfig(device);
int mode = AppConfig.getConfig("performance_mode");
byte[] curve = AppConfig.getFanConfig(device);
if (def == 1 || curve.Length != 16)
curve = Program.wmi.GetFanCurve(device, mode);
if (reset || AsusACPI.IsInvalidCurve(curve))
{
curve = Program.acpi.GetFanCurve(device, mode);
if (curve.Length != 16 || curve.All(singleByte => singleByte == 0))
curve = Program.config.getDefaultCurve(device);
if (AsusACPI.IsInvalidCurve(curve))
curve = AppConfig.getDefaultCurve(device);
curve = AsusACPI.FixFanCurve(curve);
}
//Debug.WriteLine(BitConverter.ToString(curve));
@@ -289,9 +564,11 @@ namespace GHelper
old = curve[i];
}
SaveProfile(series, device);
}
void ApplyProfile(Series series, int device)
void SaveProfile(Series series, AsusFan device)
{
byte[] curve = new byte[16];
int i = 0;
@@ -302,90 +579,206 @@ namespace GHelper
i++;
}
Program.config.setFanConfig(device, curve);
Program.wmi.SetFanCurve(device, curve);
AppConfig.setFanConfig(device, curve);
//Program.wmi.SetFanCurve(device, curve);
}
private void ButtonApply_Click(object? sender, EventArgs e)
{
ApplyProfile(seriesCPU, 0);
ApplyProfile(seriesGPU, 1);
}
private void ButtonReset_Click(object? sender, EventArgs e)
{
LoadProfile(seriesCPU, 0, 1);
LoadProfile(seriesGPU, 1, 1);
LoadProfile(seriesCPU, AsusFan.CPU, true);
LoadProfile(seriesGPU, AsusFan.GPU, true);
checkAuto.Checked = false;
if (AppConfig.isConfig("mid_fan"))
LoadProfile(seriesMid, AsusFan.Mid, true);
if (AppConfig.isConfig("xgm_fan"))
LoadProfile(seriesXGM, AsusFan.XGM, true);
checkApplyFans.Checked = false;
checkApplyPower.Checked = false;
Program.config.setConfigPerf("auto_apply", 0);
Program.config.setConfigPerf("auto_apply_power", 0);
AppConfig.setConfigPerf("auto_apply", 0);
AppConfig.setConfigPerf("auto_apply_power", 0);
Program.wmi.DeviceSet(ASUSWmi.PerformanceMode, Program.config.getConfig("performance_mode"));
Program.acpi.DeviceSet(AsusACPI.PerformanceMode, AppConfig.getConfig("performance_mode"), "PerfMode");
if (Program.acpi.IsXGConnected()) AsusUSB.ResetXGM();
ApplyLabel(false);
trackGPUCore.Value = 0;
trackGPUMemory.Value = 0;
trackGPUBoost.Value = AsusACPI.MaxGPUBoost;
trackGPUTemp.Value = AsusACPI.MaxGPUTemp;
AppConfig.setConfigPerf("gpu_boost", trackGPUBoost.Value);
AppConfig.setConfigPerf("gpu_temp", trackGPUTemp.Value);
AppConfig.setConfigPerf("gpu_core", trackGPUCore.Value);
AppConfig.setConfigPerf("gpu_memory", trackGPUMemory.Value);
VisualiseGPUSettings();
Program.settingsForm.SetGPUClocks(true);
Program.settingsForm.SetGPUPower();
}
private void ChartCPU_MouseUp(object? sender, MouseEventArgs e)
{
curPoint = null;
labelTip.Visible = false;
SaveProfile(seriesCPU, AsusFan.CPU);
SaveProfile(seriesGPU, AsusFan.GPU);
if (AppConfig.isConfig("mid_fan"))
SaveProfile(seriesMid, AsusFan.Mid);
if (AppConfig.isConfig("xgm_fan"))
SaveProfile(seriesXGM, AsusFan.XGM);
Program.settingsForm.AutoFans();
}
private void ChartCPU_MouseMove(object? sender, MouseEventArgs e)
{
if (sender is null) return;
Chart chart = (Chart)sender;
if (e.Button.HasFlag(MouseButtons.Left))
ChartArea ca = chart.ChartAreas[0];
Axis ax = ca.AxisX;
Axis ay = ca.AxisY;
bool tip = false;
HitTestResult hit = chart.HitTest(e.X, e.Y);
if (hit.Series is not null && hit.PointIndex >= 0)
{
ChartArea ca = chart.ChartAreas[0];
Axis ax = ca.AxisX;
Axis ay = ca.AxisY;
HitTestResult hit = chart.HitTest(e.X, e.Y);
if (hit.Series is not null && hit.PointIndex >= 0)
curPoint = hit.Series.Points[hit.PointIndex];
curPoint = hit.Series.Points[hit.PointIndex];
tip = true;
}
if (curPoint != null)
if (curPoint != null)
{
double dx, dy, dymin;
try
{
dx = ax.PixelPositionToValue(e.X);
dy = ay.PixelPositionToValue(e.Y);
Series s = hit.Series;
double dx, dy, dymin;
if (dx < 20) dx = 20;
if (dx > 100) dx = 100;
try
if (dy < 0) dy = 0;
if (dy > fansMax) dy = fansMax;
dymin = (dx - 65) * 1.2;
if (dy < dymin) dy = dymin;
if (e.Button.HasFlag(MouseButtons.Left))
{
dx = ax.PixelPositionToValue(e.X);
dy = ay.PixelPositionToValue(e.Y);
if (dx < 20) dx = 20;
if (dx > 100) dx = 100;
if (dy < 0) dy = 0;
if (dy > 100) dy = 100;
dymin = (dx - 60) * 1.2;
if (dy < dymin) dy = dymin;
curPoint.XValue = dx;
curPoint.YValues[0] = dy;
if (hit.Series is not null)
AdjustAllLevels(hit.PointIndex, dx, dy, hit.Series);
tip = true;
}
catch
labelTip.Text = Math.Round(curPoint.XValue) + "C, " + ChartPercToRPM((int)curPoint.YValues[0], " " + Properties.Strings.RPM);
labelTip.Top = e.Y + ((Control)sender).Top;
labelTip.Left = e.X - 50;
}
catch
{
Debug.WriteLine(e.Y);
tip = false;
}
}
labelTip.Visible = tip;
}
private void AdjustAllLevels(int index, double curXVal, double curYVal, Series series)
{
// Get the neighboring DataPoints of the hit point
DataPoint upperPoint = null;
DataPoint lowerPoint = null;
if (index > 0)
{
lowerPoint = series.Points[index - 1];
}
if (index < series.Points.Count - 1)
{
upperPoint = series.Points[index + 1];
}
// Adjust the values according to the comparison between the value and its neighbors
if (upperPoint != null)
{
if (curYVal > upperPoint.YValues[0])
{
for (int i = index + 1; i < series.Points.Count; i++)
{
Debug.WriteLine(e.Y);
DataPoint curUpper = series.Points[i];
if (curUpper.YValues[0] >= curYVal) break;
curUpper.YValues[0] = curYVal;
}
}
if (curXVal > upperPoint.XValue)
{
for (int i = index + 1; i < series.Points.Count; i++)
{
DataPoint curUpper = series.Points[i];
if (curUpper.XValue >= curXVal) break;
curUpper.XValue = curXVal;
}
}
}
if (lowerPoint != null)
{
//Debug.WriteLine(curYVal + " <? " + Math.Floor(lowerPoint.YValues[0]));
if (curYVal <= Math.Floor(lowerPoint.YValues[0]))
{
for (int i = index - 1; i >= 0; i--)
{
DataPoint curLower = series.Points[i];
if (curLower.YValues[0] < curYVal) break;
curLower.YValues[0] = Math.Floor(curYVal);
}
}
if (curXVal < lowerPoint.XValue)
{
for (int i = index - 1; i >= 0; i--)
{
DataPoint curLower = series.Points[i];
if (curLower.XValue <= curXVal) break;
curLower.XValue = curXVal;
}
}
}
}
}
}

View File

@@ -1,4 +1,64 @@
<root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing"">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<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">

View File

@@ -13,12 +13,34 @@
<Platforms>AnyCPU;x64</Platforms>
<SupportedOSPlatformVersion>8.0</SupportedOSPlatformVersion>
<AssemblyName>GHelper</AssemblyName>
<PlatformTarget>x64</PlatformTarget>
<PlatformTarget>AnyCPU</PlatformTarget>
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<AssemblyVersion>0.29</AssemblyVersion>
<AssemblyVersion>0.72</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<Compile Remove="screenshots\**" />
<EmbeddedResource Remove="screenshots\**" />
<None Remove="screenshots\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Resources\eco.ico" />
<None Remove="Resources\icons8-charging-battery-48.png" />
@@ -37,21 +59,13 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="FftSharp" Version="2.0.0" />
<PackageReference Include="hidlibrary" Version="3.3.40" />
<PackageReference Include="HidSharpCore" Version="1.2.1.1" />
<PackageReference Include="NvAPIWrapper.Net" Version="0.8.1.101" />
<PackageReference Include="System.Management" Version="7.0.0" />
<PackageReference Include="NAudio" Version="2.1.0" />
<PackageReference Include="System.Management" Version="7.0.1" />
<PackageReference Include="TaskScheduler" Version="2.10.1" />
<PackageReference Include="WinForms.DataVisualization" Version="1.7.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.Management.Infrastructure">
<HintPath>..\..\.nuget\packages\microsoft.management.infrastructure\2.0.0\ref\net451\Microsoft.Management.Infrastructure.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Management.Infrastructure.Native">
<HintPath>..\..\.nuget\packages\microsoft.management.infrastructure.runtime.win\2.0.0\runtimes\win10-x64\lib\netstandard1.6\Microsoft.Management.Infrastructure.Native.dll</HintPath>
</Reference>
<PackageReference Include="WinForms.DataVisualization" Version="1.8.0" />
</ItemGroup>
<ItemGroup>
@@ -81,6 +95,11 @@
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Update="Properties\Strings.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Strings.resx</DependentUpon>
</Compile>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
@@ -89,6 +108,20 @@
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Properties\Resources.uk.resx">
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Properties\Resources.uk.resx">
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Properties\Strings.uk.resx">
<LastGenOutput>Strings.uk.Designer.cs</LastGenOutput>
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
<EmbeddedResource Update="Properties\Strings.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
<EmbeddedResource Update="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
@@ -102,8 +135,4 @@
</None>
</ItemGroup>
<ItemGroup>
<Folder Include="screenshots\" />
</ItemGroup>
</Project>

View File

@@ -20,8 +20,8 @@ Global
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Debug|Any CPU.ActiveCfg = Debug|x64
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Debug|Any CPU.Build.0 = Debug|x64
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Debug|x64.ActiveCfg = Release|x64
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Debug|x64.Build.0 = Release|x64
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Debug|x64.ActiveCfg = Debug|Any CPU
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Debug|x64.Build.0 = Debug|Any CPU
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Release|Any CPU.ActiveCfg = Release|x64
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Release|Any CPU.Build.0 = Release|x64
{D6138BB1-8FDB-4835-87EF-2FE41A3DD604}.Release|x64.ActiveCfg = Release|x64

View File

@@ -4,12 +4,15 @@ using AmdAdl2;
namespace GHelper.Gpu;
// Reference: https://github.com/GPUOpen-LibrariesAndSDKs/display-library/blob/master/Sample-Managed/Program.cs
public class AmdGpuTemperatureProvider : IGpuTemperatureProvider {
public class AmdGpuControl : IGpuControl {
private bool _isReady;
private IntPtr _adlContextHandle;
private readonly ADLAdapterInfo _internalDiscreteAdapter;
public AmdGpuTemperatureProvider() {
public bool IsNvidia => false;
public string FullName => _internalDiscreteAdapter!.AdapterName;
public AmdGpuControl() {
if (!Adl2.Load())
return;
@@ -73,6 +76,24 @@ public class AmdGpuTemperatureProvider : IGpuTemperatureProvider {
return temperatureSensor.Value;
}
public int? GetGpuUse()
{
if (!IsValid)
return null;
if (Adl2.NativeMethods.ADL2_New_QueryPMLogData_Get(_adlContextHandle, _internalDiscreteAdapter.AdapterIndex, out ADLPMLogDataOutput adlpmLogDataOutput) != Adl2.ADL_SUCCESS)
return null;
ADLSingleSensorData gpuUsage = adlpmLogDataOutput.Sensors[(int)ADLSensorType.PMLOG_INFO_ACTIVITY_GFX];
if (gpuUsage.Supported == 0)
return null;
return gpuUsage.Value;
}
private void ReleaseUnmanagedResources() {
if (_adlContextHandle != IntPtr.Zero) {
Adl2.NativeMethods.ADL2_Main_Control_Destroy(_adlContextHandle);
@@ -86,7 +107,7 @@ public class AmdGpuTemperatureProvider : IGpuTemperatureProvider {
GC.SuppressFinalize(this);
}
~AmdGpuTemperatureProvider() {
~AmdGpuControl() {
ReleaseUnmanagedResources();
}
}

9
app/Gpu/IGpuControl.cs Normal file
View File

@@ -0,0 +1,9 @@
namespace GHelper.Gpu;
public interface IGpuControl : IDisposable {
bool IsNvidia { get; }
bool IsValid { get; }
public string FullName { get; }
int? GetCurrentTemperature();
int? GetGpuUse();
}

View File

@@ -1,6 +0,0 @@
namespace GHelper.Gpu;
public interface IGpuTemperatureProvider : IDisposable {
bool IsValid { get; }
int? GetCurrentTemperature();
}

235
app/Gpu/NvidiaGpuControl.cs Normal file
View File

@@ -0,0 +1,235 @@
using NvAPIWrapper;
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Delegates;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
using NvAPIWrapper.Native.Interfaces.GPU;
using System;
using System.Diagnostics;
using System.Management;
using static NvAPIWrapper.Native.GPU.Structures.PerformanceStates20InfoV1;
namespace GHelper.Gpu;
public class NvidiaGpuControl : IGpuControl
{
public const int MaxCoreOffset = 250;
public const int MaxMemoryOffset = 250;
public const int MinCoreOffset = -250;
public const int MinMemoryOffset = -250;
private static PhysicalGPU? _internalGpu;
public NvidiaGpuControl()
{
_internalGpu = GetInternalDiscreteGpu();
}
public bool IsValid => _internalGpu != null;
public bool IsNvidia => IsValid;
public string FullName => _internalGpu!.FullName;
public int? GetCurrentTemperature()
{
if (!IsValid) return null;
PhysicalGPU internalGpu = _internalGpu!;
IThermalSensor? gpuSensor =
GPUApi.GetThermalSettings(internalGpu.Handle).Sensors
.FirstOrDefault(s => s.Target == ThermalSettingsTarget.GPU);
return gpuSensor?.CurrentTemperature;
}
public void Dispose()
{
}
public void KillGPUApps()
{
if (!IsValid) return;
PhysicalGPU internalGpu = _internalGpu!;
try
{
Process[] processes = internalGpu.GetActiveApplications();
foreach (Process process in processes)
{
try
{
process?.Kill();
Logger.WriteLine("Stopped: " + process.ProcessName);
}
catch (Exception ex)
{
Logger.WriteLine(ex.Message);
}
}
}
catch (Exception ex)
{
Logger.WriteLine(ex.Message);
}
//NVIDIA.RestartDisplayDriver();
}
public int GetClocks(out int core, out int memory)
{
PhysicalGPU internalGpu = _internalGpu!;
//Logger.WriteLine(internalGpu.FullName);
//Logger.WriteLine(internalGpu.ArchitectInformation.ToString());
try
{
IPerformanceStates20Info states = GPUApi.GetPerformanceStates20(internalGpu.Handle);
core = states.Clocks[PerformanceStateId.P0_3DPerformance][0].FrequencyDeltaInkHz.DeltaValue / 1000;
memory = states.Clocks[PerformanceStateId.P0_3DPerformance][1].FrequencyDeltaInkHz.DeltaValue / 1000;
Logger.WriteLine($"GET GPU CLOCKS: {core}, {memory}");
return 0;
} catch (Exception ex)
{
Logger.WriteLine("GET GPU CLOCKS:" + ex.Message);
core = memory = 0;
return -1;
}
}
private static void RunCMD(string name, string args)
{
var cmd = new Process();
cmd.StartInfo.UseShellExecute = false;
cmd.StartInfo.CreateNoWindow = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
cmd.StartInfo.FileName = name;
cmd.StartInfo.Arguments = args;
cmd.Start();
Logger.WriteLine(cmd.StandardOutput.ReadToEnd());
cmd.WaitForExit();
}
public bool RestartGPUPnP()
{
if (!IsValid) return false;
try
{
PhysicalGPU internalGpu = _internalGpu!;
var pnpDeviceId = internalGpu.BusInformation.PCIIdentifiers.ToString();
Logger.WriteLine("Device ID:" + pnpDeviceId);
RunCMD("pnputil", $"/disable-device /deviceid \"{pnpDeviceId}\"");
Thread.Sleep(3000);
RunCMD("pnputil", $"/enable-device /deviceid \"{pnpDeviceId}\"");
Thread.Sleep(2000);
return true;
}
catch (Exception ex)
{
Logger.WriteLine(ex.ToString());
return false;
}
}
public bool RestartGPU()
{
try
{
string script = @"$device = Get-PnpDevice | Where-Object { $_.FriendlyName -imatch 'NVIDIA' -and $_.Class -eq 'Display' }; Disable-PnpDevice $device.InstanceId -Confirm:$false; Start-Sleep -Seconds 3; Enable-PnpDevice $device.InstanceId -Confirm:$false";
Logger.WriteLine(script);
RunCMD("powershell", script);
//Thread.Sleep(2000);
return true;
}
catch (Exception ex )
{
Logger.WriteLine(ex.ToString());
return false;
}
}
public int SetClocksFromConfig()
{
int core = AppConfig.getConfig("gpu_core");
int memory = AppConfig.getConfig("gpu_memory");
int status = SetClocks(core, memory);
return status;
}
public int SetClocks(int core, int memory)
{
if (core < MinCoreOffset || core > MaxCoreOffset) return 0;
if (memory < MinMemoryOffset || memory > MaxMemoryOffset) return 0;
PhysicalGPU internalGpu = _internalGpu!;
var coreClock = new PerformanceStates20ClockEntryV1(PublicClockDomain.Graphics, new PerformanceStates20ParameterDelta(core * 1000));
var memoryClock = new PerformanceStates20ClockEntryV1(PublicClockDomain.Memory, new PerformanceStates20ParameterDelta(memory * 1000));
PerformanceStates20ClockEntryV1[] clocks = { coreClock, memoryClock };
PerformanceStates20BaseVoltageEntryV1[] voltages = { };
PerformanceState20[] performanceStates = { new PerformanceState20(PerformanceStateId.P0_3DPerformance, clocks, voltages) };
var overclock = new PerformanceStates20InfoV1(performanceStates, 2, 0);
try
{
Logger.WriteLine($"SET GPU CLOCKS: {core}, {memory}");
GPUApi.SetPerformanceStates20(internalGpu.Handle, overclock);
}
catch (Exception ex)
{
Logger.WriteLine("SET GPU CLOCKS: "+ex.Message);
return -1;
}
return 1;
}
private static PhysicalGPU? GetInternalDiscreteGpu()
{
try
{
return PhysicalGPU
.GetPhysicalGPUs()
.FirstOrDefault(gpu => gpu.SystemType == SystemType.Laptop);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
return null;
}
}
public int? GetGpuUse()
{
if (!IsValid)
return null;
PhysicalGPU internalGpu = _internalGpu!;
IUtilizationDomainInfo? gpuUsage = GPUApi.GetUsages(internalGpu.Handle).GPU;
return (int?)gpuUsage?.Percentage;
}
}

View File

@@ -1,42 +0,0 @@
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace GHelper.Gpu;
public class NvidiaGpuTemperatureProvider : IGpuTemperatureProvider {
private readonly PhysicalGPU? _internalGpu;
public NvidiaGpuTemperatureProvider() {
_internalGpu = GetInternalDiscreteGpu();
}
public bool IsValid => _internalGpu != null;
public int? GetCurrentTemperature() {
if (!IsValid)
return null;
PhysicalGPU internalGpu = _internalGpu!;
IThermalSensor? gpuSensor =
GPUApi.GetThermalSettings(internalGpu.Handle).Sensors
.FirstOrDefault(s => s.Target == ThermalSettingsTarget.GPU);
return gpuSensor?.CurrentTemperature;
}
public void Dispose() {
}
private static PhysicalGPU? GetInternalDiscreteGpu() {
try {
return PhysicalGPU
.GetPhysicalGPUs()
.FirstOrDefault(gpu => gpu.SystemType == SystemType.Laptop);
} catch {
return null;
}
}
}

182
app/HardwareControl.cs Normal file
View File

@@ -0,0 +1,182 @@
using GHelper;
using GHelper.Gpu;
using System.Diagnostics;
public static class HardwareControl
{
public static IGpuControl? GpuControl;
public static float? cpuTemp = -1;
public static float? batteryDischarge = -1;
public static int? gpuTemp = null;
public static string? cpuFan;
public static string? gpuFan;
public static string? midFan;
public static int? gpuUse;
public static int GetFanMax()
{
int max = 58;
if (AppConfig.ContainsModel("401")) max = 72;
else if (AppConfig.ContainsModel("503")) max = 68;
return Math.Max(max, AppConfig.getConfig("fan_max"));
}
public static void SetFanMax(int fan)
{
AppConfig.setConfig("fan_max", fan);
}
private static string FormatFan(int fan)
{
// fix for old models
if (fan < 0)
{
fan += 65536;
if (fan <= 0 || fan > 100) return null; //nothing reasonable
}
int fanMax = GetFanMax();
if (fan > fanMax && fan < 110) SetFanMax(fan);
if (AppConfig.getConfig("fan_rpm") == 1)
return GHelper.Properties.Strings.FanSpeed + (fan * 100).ToString() + "RPM";
else
return GHelper.Properties.Strings.FanSpeed + Math.Min(Math.Round((float)fan / fanMax * 100), 100).ToString() + "%"; // relatively to 6000 rpm
}
private static int GetGpuUse()
{
try
{
int? gpuUse = GpuControl?.GetGpuUse();
Logger.WriteLine("GPU usage: " + GpuControl?.FullName + " " + gpuUse + "%");
if (gpuUse is not null) return (int)gpuUse;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
return 0;
}
public static void ReadSensors()
{
batteryDischarge = -1;
gpuTemp = -1;
gpuUse = -1;
cpuFan = FormatFan(Program.acpi.DeviceGet(AsusACPI.CPU_Fan));
gpuFan = FormatFan(Program.acpi.DeviceGet(AsusACPI.GPU_Fan));
midFan = FormatFan(Program.acpi.DeviceGet(AsusACPI.Mid_Fan));
cpuTemp = Program.acpi.DeviceGet(AsusACPI.Temp_CPU);
if (cpuTemp < 0) try
{
using (var ct = new PerformanceCounter("Thermal Zone Information", "Temperature", @"\_TZ.THRM", true))
{
cpuTemp = ct.NextValue() - 273;
}
}
catch (Exception ex)
{
Debug.WriteLine("Failed reading CPU temp :" + ex.Message);
}
try
{
gpuTemp = GpuControl?.GetCurrentTemperature();
}
catch (Exception ex)
{
gpuTemp = -1;
Debug.WriteLine("Failed reading GPU temp :" + ex.Message);
}
if (gpuTemp is null || gpuTemp < 0)
gpuTemp = Program.acpi.DeviceGet(AsusACPI.Temp_GPU);
try
{
using (var cb = new PerformanceCounter("Power Meter", "Power", "Power Meter (0)", true))
{
batteryDischarge = cb.NextValue() / 1000;
}
}
catch
{
Debug.WriteLine("Failed reading Battery discharge");
}
}
public static bool IsUsedGPU(int threshold = 10)
{
if (GetGpuUse() > threshold)
{
Thread.Sleep(1000);
return (GetGpuUse() > threshold);
}
return false;
}
public static NvidiaGpuControl? GetNvidiaGpuControl()
{
if ((bool)GpuControl?.IsNvidia)
return (NvidiaGpuControl)GpuControl;
else
return null;
}
public static void RecreateGpuControlWithDelay(int delay = 5)
{
// Re-enabling the discrete GPU takes a bit of time,
// so a simple workaround is to refresh again after that happens
Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(delay));
RecreateGpuControl();
});
}
public static void RecreateGpuControl()
{
try
{
GpuControl?.Dispose();
IGpuControl _gpuControl = new NvidiaGpuControl();
if (_gpuControl.IsValid)
{
GpuControl = _gpuControl;
Logger.WriteLine(GpuControl.FullName);
return;
}
_gpuControl.Dispose();
_gpuControl = new AmdGpuControl();
if (_gpuControl.IsValid)
{
GpuControl = _gpuControl;
Logger.WriteLine(GpuControl.FullName);
return;
}
_gpuControl.Dispose();
GpuControl = null;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
}
}
}

View File

@@ -1,86 +0,0 @@
using System.Diagnostics;
using GHelper.Gpu;
public static class HardwareMonitor
{
private static IGpuTemperatureProvider? GpuTemperatureProvider;
public static float? cpuTemp = -1;
public static float? batteryDischarge = -1;
public static int? gpuTemp = null;
public static void ReadSensors()
{
cpuTemp = -1;
batteryDischarge = -1;
try
{
var ct = new PerformanceCounter("Thermal Zone Information", "Temperature", @"\_TZ.THRM", true);
cpuTemp = ct.NextValue() - 273;
ct.Dispose();
} catch
{
Logger.WriteLine("Failed reading CPU temp");
}
try
{
var cb = new PerformanceCounter("Power Meter", "Power", "Power Meter (0)", true);
batteryDischarge = cb.NextValue() / 1000;
cb.Dispose();
} catch
{
Logger.WriteLine("Failed reading Battery discharge");
}
try
{
gpuTemp = GpuTemperatureProvider?.GetCurrentTemperature();
} catch (Exception ex) {
gpuTemp = null;
Logger.WriteLine("Failed reading GPU temp");
Logger.WriteLine(ex.ToString());
}
}
public static void RecreateGpuTemperatureProviderWithRetry() {
RecreateGpuTemperatureProvider();
// Re-enabling the discrete GPU takes a bit of time,
// so a simple workaround is to refresh again after that happens
Task.Run(async () => {
await Task.Delay(TimeSpan.FromSeconds(3));
RecreateGpuTemperatureProvider();
});
}
public static void RecreateGpuTemperatureProvider() {
try {
GpuTemperatureProvider?.Dispose();
// Detect valid GPU temperature provider.
// We start with NVIDIA because there's always at least an integrated AMD GPU
IGpuTemperatureProvider gpuTemperatureProvider = new NvidiaGpuTemperatureProvider();
if (gpuTemperatureProvider.IsValid) {
GpuTemperatureProvider = gpuTemperatureProvider;
return;
}
gpuTemperatureProvider.Dispose();
gpuTemperatureProvider = new AmdGpuTemperatureProvider();
if (gpuTemperatureProvider.IsValid) {
GpuTemperatureProvider = gpuTemperatureProvider;
return;
}
gpuTemperatureProvider.Dispose();
GpuTemperatureProvider = null;
} finally {
Logger.WriteLine($"GpuTemperatureProvider: {GpuTemperatureProvider?.GetType().Name}");
}
}
}

361
app/InputDispatcher.cs Normal file
View File

@@ -0,0 +1,361 @@
using HidLibrary;
using Microsoft.Win32;
using NAudio.CoreAudioApi;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management;
using Tools;
namespace GHelper
{
public class KeyboardListener
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
public KeyboardListener(Action<int> KeyHandler)
{
HidDevice? input = AsusUSB.GetDevice();
if (input == null) return;
Logger.WriteLine($"Input: {input.DevicePath}");
var task = Task.Run(() =>
{
try
{
while (!cancellationTokenSource.Token.IsCancellationRequested)
{
var data = input.Read().Data;
if (data.Length > 1 && data[0] == AsusUSB.INPUT_HID_ID && data[1] > 0)
{
Logger.WriteLine($"Key: {data[1]}");
KeyHandler(data[1]);
}
}
Logger.WriteLine("Listener stopped");
}
catch (Exception ex)
{
Logger.WriteLine(ex.ToString());
}
});
}
public void Dispose()
{
cancellationTokenSource?.Cancel();
}
}
public class InputDispatcher
{
System.Timers.Timer timer = new System.Timers.Timer(1000);
public bool backlight = true;
private static nint windowHandle;
public static Keys keyProfile = Keys.F5;
public static Keys keyApp = Keys.F12;
KeyboardListener listener;
KeyHandler m1, m2, handlerProfile, handlerApp;
public InputDispatcher(nint handle)
{
windowHandle = handle;
byte[] result = Program.acpi.DeviceInit();
Debug.WriteLine($"Init: {BitConverter.ToString(result)}");
Program.acpi.SubscribeToEvents(WatcherEventArrived);
//Task.Run(Program.acpi.RunListener);
// CTRL + SHIFT + F5 to cycle profiles
if (AppConfig.getConfig("keybind_profile") != -1) keyProfile = (Keys)AppConfig.getConfig("keybind_profile");
handlerProfile = new KeyHandler(KeyHandler.SHIFT | KeyHandler.CTRL, keyProfile, windowHandle);
handlerApp = new KeyHandler(KeyHandler.SHIFT | KeyHandler.CTRL, keyApp, windowHandle);
m1 = new KeyHandler(KeyHandler.NOMOD, Keys.VolumeDown, windowHandle);
m2 = new KeyHandler(KeyHandler.NOMOD, Keys.VolumeUp, windowHandle);
RegisterKeys();
timer.Elapsed += Timer_Elapsed;
}
private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
TimeSpan iddle = NativeMethods.GetIdleTime();
int kb_timeout;
if (SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online)
kb_timeout = AppConfig.getConfig("keyboard_ac_timeout", 0);
else
kb_timeout = AppConfig.getConfig("keyboard_timeout", 60);
if (kb_timeout == 0) return;
if (backlight && iddle.TotalSeconds > kb_timeout)
{
backlight = false;
AsusUSB.ApplyBrightness(0);
}
if (!backlight && iddle.TotalSeconds < kb_timeout)
{
backlight = true;
AsusUSB.ApplyBrightness(AppConfig.getConfig("keyboard_brightness"));
}
//Debug.WriteLine(iddle.TotalSeconds);
}
public void Init()
{
if (listener is not null) listener.Dispose();
Program.acpi.DeviceInit();
if (!OptimizationService.IsRunning())
listener = new KeyboardListener(HandleEvent);
InitBacklightTimer();
}
public void InitBacklightTimer()
{
timer.Enabled = (AppConfig.getConfig("keyboard_timeout") > 0 && SystemInformation.PowerStatus.PowerLineStatus != PowerLineStatus.Online) ||
(AppConfig.getConfig("keyboard_ac_timeout") > 0 && SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online);
}
public void RegisterKeys()
{
string actionM1 = AppConfig.getConfigString("m1");
string actionM2 = AppConfig.getConfigString("m2");
handlerProfile.Unregiser();
m1.Unregiser();
m2.Unregiser();
if (keyProfile != Keys.None) handlerProfile.Register();
if (keyApp != Keys.None) handlerApp.Register();
if (actionM1 is not null && actionM1.Length > 0) m1.Register();
if (actionM2 is not null && actionM2.Length > 0) m2.Register();
}
static void CustomKey(string configKey = "m3")
{
string command = AppConfig.getConfigString(configKey + "_custom");
int intKey;
try
{
intKey = Convert.ToInt32(command, 16);
}
catch
{
intKey = -1;
}
if (intKey > 0)
NativeMethods.KeyPress(intKey);
else
LaunchProcess(command);
}
public static void KeyProcess(string name = "m3")
{
string action = AppConfig.getConfigString(name);
if (action is null || action.Length <= 1)
{
if (name == "m4")
action = "ghelper";
if (name == "fnf4")
action = "aura";
if (name == "fnf5")
action = "performance";
if (name == "m3" && !OptimizationService.IsRunning())
action = "micmute";
}
switch (action)
{
case "mute":
NativeMethods.KeyPress(NativeMethods.VK_VOLUME_MUTE);
break;
case "play":
NativeMethods.KeyPress(NativeMethods.VK_MEDIA_PLAY_PAUSE);
break;
case "screenshot":
NativeMethods.KeyPress(NativeMethods.VK_SNAPSHOT);
break;
case "screen":
NativeMethods.TurnOffScreen(Program.settingsForm.Handle);
break;
case "miniled":
Program.settingsForm.BeginInvoke(Program.settingsForm.ToogleMiniled);
break;
case "aura":
Program.settingsForm.BeginInvoke(Program.settingsForm.CycleAuraMode);
break;
case "performance":
Program.settingsForm.BeginInvoke(Program.settingsForm.CyclePerformanceMode);
break;
case "ghelper":
Program.settingsForm.BeginInvoke(delegate
{
Program.SettingsToggle();
});
break;
case "custom":
CustomKey(name);
break;
case "micmute":
using (var enumerator = new MMDeviceEnumerator())
{
var commDevice = enumerator.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Communications);
bool muteStatus = !commDevice.AudioEndpointVolume.Mute;
commDevice.AudioEndpointVolume.Mute = muteStatus;
Program.settingsForm.BeginInvoke(Program.settingsForm.RunToast, muteStatus ? "Muted" : "Unmuted", muteStatus ? ToastIcon.MicrophoneMute : ToastIcon.Microphone);
}
break;
default:
break;
}
}
static bool GetTouchpadState()
{
using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\PrecisionTouchPad\Status", false))
{
return (key?.GetValue("Enabled")?.ToString() == "1");
}
}
static void TabletMode()
{
bool touchpadState = GetTouchpadState();
bool tabletState = Program.acpi.DeviceGet(AsusACPI.TabletState) > 0;
Logger.WriteLine("Tablet: " + tabletState + " Touchpad: " + touchpadState);
if ((tabletState && touchpadState) || (!tabletState && !touchpadState)) AsusUSB.TouchpadToggle();
}
static void HandleEvent(int EventID)
{
switch (EventID)
{
case 124: // M3
KeyProcess("m3");
return;
case 56: // M4 / Rog button
KeyProcess("m4");
return;
case 174: // FN+F5
Program.settingsForm.BeginInvoke(Program.settingsForm.CyclePerformanceMode);
return;
case 179: // FN+F4
case 178: // FN+F4
KeyProcess("fnf4");
return;
case 189: // Tablet mode
TabletMode();
return;
}
if (OptimizationService.IsRunning()) return;
// Asus Optimization service Events
int backlight = AppConfig.getConfig("keyboard_brightness");
string[] backlightNames = new string[] { "Off", "Low", "Mid", "Max" };
switch (EventID)
{
case 197: // FN+F2
backlight = Math.Max(0, backlight - 1);
AppConfig.setConfig("keyboard_brightness", backlight);
AsusUSB.ApplyBrightness(backlight);
Program.settingsForm.BeginInvoke(Program.settingsForm.RunToast, backlightNames[backlight], ToastIcon.BacklightDown);
break;
case 196: // FN+F3
backlight = Math.Min(3, backlight + 1);
AppConfig.setConfig("keyboard_brightness", backlight);
AsusUSB.ApplyBrightness(backlight);
Program.settingsForm.BeginInvoke(Program.settingsForm.RunToast, backlightNames[backlight], ToastIcon.BacklightUp);
break;
case 199: // ON Z13 - FN+F11 - cycles backlight
if (++backlight > 3) backlight = 0;
AppConfig.setConfig("keyboard_brightness", backlight);
AsusUSB.ApplyBrightness(backlight);
Program.settingsForm.BeginInvoke(Program.settingsForm.RunToast, backlightNames[backlight], ToastIcon.BacklightUp);
break;
case 16: // FN+F7
Program.acpi.DeviceSet(AsusACPI.UniversalControl, 0x10, "Brightness");
break;
case 32: // FN+F8
Program.acpi.DeviceSet(AsusACPI.UniversalControl, 0x20, "Brightness");
break;
case 107: // FN+F10
bool touchpadState = GetTouchpadState();
AsusUSB.TouchpadToggle();
Program.settingsForm.BeginInvoke(Program.settingsForm.RunToast, touchpadState ? "Off" : "On", ToastIcon.Touchpad);
break;
case 108: // FN+F11
Program.acpi.DeviceSet(AsusACPI.UniversalControl, 0x6c, "Sleep");
//NativeMethods.SetSuspendState(false, true, true);
break;
}
}
static void LaunchProcess(string command = "")
{
try
{
string executable = command.Split(' ')[0];
string arguments = command.Substring(executable.Length).Trim();
Process proc = Process.Start(executable, arguments);
}
catch
{
Logger.WriteLine("Failed to run " + command);
}
}
static void WatcherEventArrived(object sender, EventArrivedEventArgs e)
{
if (e.NewEvent is null) return;
int EventID = int.Parse(e.NewEvent["EventID"].ToString());
Logger.WriteLine("WMI event " + EventID);
HandleEvent(EventID);
}
}
}

173
app/Keyboard.Designer.cs generated
View File

@@ -1,173 +0,0 @@
namespace GHelper
{
partial class Keyboard
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
groupBox1 = new GroupBox();
textM4 = new TextBox();
textM3 = new TextBox();
comboM4 = new ComboBox();
labelM4 = new Label();
comboM3 = new ComboBox();
labelM3 = new Label();
textFNF4 = new TextBox();
comboFNF4 = new ComboBox();
labelFNF4 = new Label();
groupBox1.SuspendLayout();
SuspendLayout();
//
// groupBox1
//
groupBox1.Controls.Add(textFNF4);
groupBox1.Controls.Add(comboFNF4);
groupBox1.Controls.Add(labelFNF4);
groupBox1.Controls.Add(textM4);
groupBox1.Controls.Add(textM3);
groupBox1.Controls.Add(comboM4);
groupBox1.Controls.Add(labelM4);
groupBox1.Controls.Add(comboM3);
groupBox1.Controls.Add(labelM3);
groupBox1.Dock = DockStyle.Top;
groupBox1.Location = new Point(10, 10);
groupBox1.Name = "groupBox1";
groupBox1.Size = new Size(751, 242);
groupBox1.TabIndex = 0;
groupBox1.TabStop = false;
groupBox1.Text = "Key Bindings";
//
// textM4
//
textM4.Location = new Point(411, 113);
textM4.Name = "textM4";
textM4.PlaceholderText = "action";
textM4.Size = new Size(320, 39);
textM4.TabIndex = 5;
//
// textM3
//
textM3.Location = new Point(411, 54);
textM3.Name = "textM3";
textM3.PlaceholderText = "notepad /p \"file.txt\"";
textM3.Size = new Size(320, 39);
textM3.TabIndex = 4;
//
// comboM4
//
comboM4.FormattingEnabled = true;
comboM4.Items.AddRange(new object[] { "Performance Mode", "Open G-Helper window", "Custom" });
comboM4.Location = new Point(93, 112);
comboM4.Name = "comboM4";
comboM4.Size = new Size(312, 40);
comboM4.TabIndex = 3;
//
// labelM4
//
labelM4.AutoSize = true;
labelM4.Location = new Point(25, 116);
labelM4.Name = "labelM4";
labelM4.Size = new Size(54, 32);
labelM4.TabIndex = 2;
labelM4.Text = "M4:";
//
// comboM3
//
comboM3.FormattingEnabled = true;
comboM3.Items.AddRange(new object[] { "Default", "Volume Mute", "Play / Pause", "PrintScreen", "Toggle Aura", "Custom" });
comboM3.Location = new Point(93, 54);
comboM3.Name = "comboM3";
comboM3.Size = new Size(312, 40);
comboM3.TabIndex = 1;
//
// labelM3
//
labelM3.AutoSize = true;
labelM3.Location = new Point(25, 58);
labelM3.Name = "labelM3";
labelM3.Size = new Size(54, 32);
labelM3.TabIndex = 0;
labelM3.Text = "M3:";
//
// textFNF4
//
textFNF4.Location = new Point(411, 176);
textFNF4.Name = "textFNF4";
textFNF4.PlaceholderText = "action";
textFNF4.Size = new Size(320, 39);
textFNF4.TabIndex = 8;
//
// comboFNF4
//
comboFNF4.FormattingEnabled = true;
comboFNF4.Location = new Point(93, 175);
comboFNF4.Name = "comboFNF4";
comboFNF4.Size = new Size(312, 40);
comboFNF4.TabIndex = 7;
//
// labelFNF4
//
labelFNF4.AutoSize = true;
labelFNF4.Location = new Point(2, 178);
labelFNF4.Name = "labelFNF4";
labelFNF4.Size = new Size(90, 32);
labelFNF4.TabIndex = 6;
labelFNF4.Text = "FN+F4:";
//
// Keyboard
//
AutoScaleDimensions = new SizeF(13F, 32F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(771, 858);
Controls.Add(groupBox1);
FormBorderStyle = FormBorderStyle.FixedSingle;
MaximizeBox = false;
MdiChildrenMinimizedAnchorBottom = false;
MinimizeBox = false;
Name = "Keyboard";
Padding = new Padding(10);
ShowIcon = false;
ShowInTaskbar = false;
Text = "Keyboard";
groupBox1.ResumeLayout(false);
groupBox1.PerformLayout();
ResumeLayout(false);
}
#endregion
private GroupBox groupBox1;
private Label labelM3;
private ComboBox comboM3;
private ComboBox comboM4;
private Label labelM4;
private TextBox textM4;
private TextBox textM3;
private TextBox textFNF4;
private ComboBox comboFNF4;
private Label labelFNF4;
}
}

View File

@@ -1,69 +0,0 @@
namespace GHelper
{
public partial class Keyboard : Form
{
Dictionary<string, string> customActions = new Dictionary<string, string>
{
{"","--------------" },
{"mute", "Volume Mute"},
{"screenshot", "Screenshot"},
{"play", "Play/Pause"},
{"aura", "Aura"},
{"ghelper", "Open GHelper"},
{"custom", "Custom"}
};
private void SetKeyCombo(ComboBox combo, TextBox txbox, string name)
{
if (name == "m4")
customActions[""] = "Performance";
if (name == "fnf4")
{
customActions[""] = "Aura";
customActions.Remove("aura");
}
combo.DropDownStyle = ComboBoxStyle.DropDownList;
combo.DataSource = new BindingSource(customActions, null);
combo.DisplayMember = "Value";
combo.ValueMember = "Key";
string action = Program.config.getConfigString(name);
combo.SelectedValue = (action is not null) ? action : "";
if (combo.SelectedValue is null) combo.SelectedValue = "";
combo.SelectedValueChanged += delegate
{
if (combo.SelectedValue is not null)
Program.config.setConfig(name, combo.SelectedValue.ToString());
};
txbox.Text = Program.config.getConfigString(name + "_custom");
txbox.TextChanged += delegate
{
Program.config.setConfig(name + "_custom", txbox.Text);
};
}
public Keyboard()
{
InitializeComponent();
SetKeyCombo(comboM3, textM3, "m3");
SetKeyCombo(comboM4, textM4, "m4");
SetKeyCombo(comboFNF4, textFNF4, "fnf4");
Shown += Keyboard_Shown;
}
private void Keyboard_Shown(object? sender, EventArgs e)
{
Top = Program.settingsForm.Top;
Left = Program.settingsForm.Left - Width - 5;
}
}
}

View File

@@ -1,60 +0,0 @@
<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>
</root>

View File

@@ -1,10 +1,55 @@
using System.ComponentModel;
using GHelper;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.TrackBar;
using static Tools.ScreenInterrogatory;
namespace Tools
{
public class KeyHandler
{
public const int NOMOD = 0x0000;
public const int ALT = 0x0001;
public const int CTRL = 0x0002;
public const int SHIFT = 0x0004;
public const int WIN = 0x0008;
public const int WM_HOTKEY_MSG_ID = 0x0312;
[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);
[DllImport("user32.dll")]
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
private int modifier;
private int key;
private IntPtr hWnd;
private int id;
public KeyHandler(int modifier, Keys key, nint handle)
{
this.modifier = modifier;
this.key = (int)key;
this.hWnd = handle;
id = this.GetHashCode();
}
public override int GetHashCode()
{
return modifier ^ key ^ hWnd.ToInt32();
}
public bool Register()
{
return RegisterHotKey(hWnd, id, modifier, key);
}
public bool Unregiser()
{
return UnregisterHotKey(hWnd, id);
}
}
public static class ScreenInterrogatory
{
public const int ERROR_SUCCESS = 0;
@@ -307,6 +352,52 @@ namespace Tools
public class NativeMethods
{
internal struct LASTINPUTINFO
{
public uint cbSize;
public uint dwTime;
}
[DllImport("User32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
public static TimeSpan GetIdleTime()
{
LASTINPUTINFO lastInPut = new LASTINPUTINFO();
lastInPut.cbSize = (uint)Marshal.SizeOf(lastInPut);
GetLastInputInfo(ref lastInPut);
return TimeSpan.FromMilliseconds((uint)Environment.TickCount - lastInPut.dwTime);
}
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_MONITORPOWER = 0xF170;
private const int MONITOR_OFF = 2;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern uint FormatMessage(uint dwFlags, IntPtr lpSource, uint dwMessageId, uint dwLanguageId, out string lpBuffer, uint nSize, IntPtr Arguments);
public static void TurnOffScreen(IntPtr handle)
{
IntPtr result = SendMessage(handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)MONITOR_OFF);
if (result == IntPtr.Zero)
{
int error = Marshal.GetLastWin32Error();
string message = "";
uint formatFlags = 0x00001000 | 0x00000200 | 0x00000100 | 0x00000080;
uint formatResult = FormatMessage(formatFlags, IntPtr.Zero, (uint)error, 0, out message, 0, IntPtr.Zero);
if (formatResult == 0)
{
message = "Unknown error.";
}
Logger.WriteLine($"Failed to turn off screen. Error code: {error}. {message}");
}
}
// Monitor Power detection
internal const uint DEVICE_NOTIFY_WINDOW_HANDLE = 0x0;
@@ -364,6 +455,10 @@ public class NativeMethods
}
[DllImport("Powrprof.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool SetSuspendState(bool hiberate, bool forceCritical, bool disableWakeEvent);
public const int KEYEVENTF_EXTENDEDKEY = 1;
public const int KEYEVENTF_KEYUP = 2;
@@ -576,19 +671,21 @@ public class NativeMethods
//Logger.WriteLine(screen.DeviceName);
count++;
}
if (displayNum > 0 && count == 0) laptopScreen = defaultDevice;
}
catch (Exception ex)
{
Logger.WriteLine(ex.ToString());
Logger.WriteLine("Can't detect internal screen");
//laptopScreen = Screen.PrimaryScreen.DeviceName;
laptopScreen = Screen.PrimaryScreen.DeviceName;
}
return laptopScreen;
}
public static int GetRefreshRate()
public static int GetRefreshRate(bool max = false)
{
DEVMODE dm = CreateDevmode();
@@ -598,10 +695,23 @@ public class NativeMethods
if (laptopScreen is null)
return -1;
if (0 != NativeMethods.EnumDisplaySettingsEx(laptopScreen, NativeMethods.ENUM_CURRENT_SETTINGS, ref dm))
if (max)
{
frequency = dm.dmDisplayFrequency;
int i = 0;
while (0 != NativeMethods.EnumDisplaySettingsEx(laptopScreen, i, ref dm))
{
if (dm.dmDisplayFrequency > frequency) frequency = dm.dmDisplayFrequency;
i++;
}
}
else
{
if (0 != NativeMethods.EnumDisplaySettingsEx(laptopScreen, NativeMethods.ENUM_CURRENT_SETTINGS, ref dm))
{
frequency = dm.dmDisplayFrequency;
}
}
return frequency;
}
@@ -618,6 +728,8 @@ public class NativeMethods
{
dm.dmDisplayFrequency = frequency;
int iRet = NativeMethods.ChangeDisplaySettingsEx(laptopScreen, ref dm, IntPtr.Zero, DisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero);
Logger.WriteLine("Screen = " + frequency.ToString() + "Hz : " + (iRet == 0 ? "OK" : iRet));
return iRet;
}
@@ -660,7 +772,6 @@ public class NativeMethods
PowerSetActiveScheme(IntPtr.Zero, activeSchemeGuid);
/*
var hrDC = PowerWriteDCValueIndex(
IntPtr.Zero,
activeSchemeGuid,
@@ -669,8 +780,15 @@ public class NativeMethods
boost);
PowerSetActiveScheme(IntPtr.Zero, activeSchemeGuid);
*/
Logger.WriteLine("Boost " + boost);
}
public static void SetPowerScheme(string scheme)
{
PowerSetActiveScheme(IntPtr.Zero, new Guid(scheme));
PowerSetActiveOverlayScheme(new Guid(scheme));
Logger.WriteLine(scheme);
}
public static void SetPowerScheme(int mode)

View File

@@ -0,0 +1,200 @@
using System;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Interfaces.Display;
namespace NvAPIWrapper.Display
{
/// <inheritdoc cref="IColorData" />
public class ColorData : IColorData, IEquatable<ColorData>
{
/// <summary>
/// Creates an instance of <see cref="ColorData" /> to modify the color data
/// </summary>
/// <param name="colorFormat">The color data color format.</param>
/// <param name="colorimetry">The color data color space.</param>
/// <param name="dynamicRange">The color data dynamic range.</param>
/// <param name="colorDepth">The color data color depth.</param>
/// <param name="colorSelectionPolicy">The color data selection policy.</param>
/// <param name="desktopColorDepth">The color data desktop color depth.</param>
public ColorData(
ColorDataFormat colorFormat = ColorDataFormat.Auto,
ColorDataColorimetry colorimetry = ColorDataColorimetry.Auto,
ColorDataDynamicRange? dynamicRange = null,
ColorDataDepth? colorDepth = null,
ColorDataSelectionPolicy? colorSelectionPolicy = null,
ColorDataDesktopDepth? desktopColorDepth = null
)
{
ColorFormat = colorFormat;
Colorimetry = colorimetry;
DynamicRange = dynamicRange;
ColorDepth = colorDepth;
SelectionPolicy = colorSelectionPolicy;
DesktopColorDepth = desktopColorDepth;
}
internal ColorData(IColorData colorData)
{
ColorDepth = colorData.ColorDepth;
DynamicRange = colorData.DynamicRange;
ColorFormat = colorData.ColorFormat;
Colorimetry = colorData.Colorimetry;
SelectionPolicy = colorData.SelectionPolicy;
DesktopColorDepth = colorData.DesktopColorDepth;
}
/// <inheritdoc />
public ColorDataDepth? ColorDepth { get; }
/// <inheritdoc />
public ColorDataFormat ColorFormat { get; }
/// <inheritdoc />
public ColorDataColorimetry Colorimetry { get; }
/// <inheritdoc />
public ColorDataDesktopDepth? DesktopColorDepth { get; }
/// <inheritdoc />
public ColorDataDynamicRange? DynamicRange { get; }
/// <inheritdoc />
public ColorDataSelectionPolicy? SelectionPolicy { get; }
/// <inheritdoc />
public bool Equals(ColorData other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ColorDepth == other.ColorDepth &&
ColorFormat == other.ColorFormat &&
Colorimetry == other.Colorimetry &&
DesktopColorDepth == other.DesktopColorDepth &&
DynamicRange == other.DynamicRange &&
SelectionPolicy == other.SelectionPolicy;
}
/// <summary>
/// Compares two instances of <see cref="ColorData" /> for equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>true if two instances are equal; otherwise false.</returns>
public static bool operator ==(ColorData left, ColorData right)
{
return left?.Equals(right) == true;
}
/// <summary>
/// Compares two instances of <see cref="ColorData" /> for inequality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>true if two instances are not equal; otherwise false.</returns>
public static bool operator !=(ColorData left, ColorData right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((ColorData) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = ColorDepth.GetHashCode();
hashCode = (hashCode * 397) ^ (int) ColorFormat;
hashCode = (hashCode * 397) ^ (int) Colorimetry;
hashCode = (hashCode * 397) ^ DesktopColorDepth.GetHashCode();
hashCode = (hashCode * 397) ^ DynamicRange.GetHashCode();
hashCode = (hashCode * 397) ^ SelectionPolicy.GetHashCode();
return hashCode;
}
}
internal ColorDataV1 AsColorDataV1(ColorDataCommand command)
{
return new ColorDataV1(
command,
ColorFormat,
Colorimetry
);
}
internal ColorDataV2 AsColorDataV2(ColorDataCommand command)
{
return new ColorDataV2(
command,
ColorFormat,
Colorimetry,
DynamicRange ?? ColorDataDynamicRange.Auto
);
}
internal ColorDataV3 AsColorDataV3(ColorDataCommand command)
{
return new ColorDataV3(
command,
ColorFormat,
Colorimetry,
DynamicRange ?? ColorDataDynamicRange.Auto,
ColorDepth ?? ColorDataDepth.Default
);
}
internal ColorDataV4 AsColorDataV4(ColorDataCommand command)
{
return new ColorDataV4(
command,
ColorFormat,
Colorimetry,
DynamicRange ?? ColorDataDynamicRange.Auto,
ColorDepth ?? ColorDataDepth.Default,
SelectionPolicy ?? ColorDataSelectionPolicy.Default
);
}
internal ColorDataV5 AsColorDataV5(ColorDataCommand command)
{
return new ColorDataV5(
command,
ColorFormat,
Colorimetry,
DynamicRange ?? ColorDataDynamicRange.Auto,
ColorDepth ?? ColorDataDepth.Default,
SelectionPolicy ?? ColorDataSelectionPolicy.Default,
DesktopColorDepth ?? ColorDataDesktopDepth.Default
);
}
}
}

View File

@@ -0,0 +1,245 @@
using System;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Hold information about a custom display resolution
/// </summary>
public class CustomResolution : IEquatable<CustomResolution>
{
/// <summary>
/// Creates an instance of <see cref="CustomResolution" />.
/// </summary>
/// <param name="width">The screen width.</param>
/// <param name="height">The screen height.</param>
/// <param name="colorFormat">The color format.</param>
/// <param name="timing">The resolution timing.</param>
/// <param name="xRatio">The horizontal scaling ratio.</param>
/// <param name="yRatio">The vertical scaling ratio.</param>
public CustomResolution(
uint width,
uint height,
ColorFormat colorFormat,
Timing timing,
float xRatio = 1,
float yRatio = 1
)
{
if (xRatio <= 0)
{
throw new ArgumentOutOfRangeException(nameof(xRatio));
}
if (yRatio <= 0)
{
throw new ArgumentOutOfRangeException(nameof(yRatio));
}
Width = width;
Height = height;
ColorFormat = colorFormat;
XRatio = xRatio;
YRatio = yRatio;
Timing = timing;
switch (ColorFormat)
{
case ColorFormat.P8:
ColorDepth = 8;
break;
case ColorFormat.R5G6B5:
ColorDepth = 16;
break;
case ColorFormat.A8R8G8B8:
ColorDepth = 24;
break;
case ColorFormat.A16B16G16R16F:
ColorDepth = 32;
break;
default:
throw new ArgumentException("Color format is invalid.", nameof(colorFormat));
}
}
/// <summary>
/// Creates an instance of <see cref="CustomResolution" />.
/// </summary>
/// <param name="width">The screen width.</param>
/// <param name="height">The screen height.</param>
/// <param name="colorDepth">The color depth.</param>
/// <param name="timing">The resolution timing.</param>
/// <param name="xRatio">The horizontal scaling ratio.</param>
/// <param name="yRatio">The vertical scaling ratio.</param>
public CustomResolution(
uint width,
uint height,
uint colorDepth,
Timing timing,
float xRatio = 1,
float yRatio = 1)
{
if (xRatio <= 0)
{
throw new ArgumentOutOfRangeException(nameof(xRatio));
}
if (yRatio <= 0)
{
throw new ArgumentOutOfRangeException(nameof(yRatio));
}
if (colorDepth != 0 && colorDepth != 8 && colorDepth != 16 && colorDepth != 24 && colorDepth != 32)
{
throw new ArgumentOutOfRangeException(nameof(colorDepth));
}
Width = width;
Height = height;
ColorDepth = colorDepth;
ColorFormat = ColorFormat.Unknown;
XRatio = xRatio;
YRatio = yRatio;
Timing = timing;
}
internal CustomResolution(CustomDisplay customDisplay)
{
Width = customDisplay.Width;
Height = customDisplay.Height;
ColorDepth = customDisplay.Depth;
ColorFormat = customDisplay.ColorFormat;
Timing = customDisplay.Timing;
XRatio = customDisplay.XRatio;
YRatio = customDisplay.YRatio;
}
/// <summary>
/// Gets the source surface color depth. "0" means all 8/16/32bpp.
/// </summary>
public uint ColorDepth { get; }
/// <summary>
/// Gets the color format (optional)
/// </summary>
public ColorFormat ColorFormat { get; }
/// <summary>
/// Gets the source surface (source mode) height.
/// </summary>
public uint Height { get; }
/// <summary>
/// Gets the timing used to program TMDS/DAC/LVDS/HDMI/TVEncoder, etc.
/// </summary>
public Timing Timing { get; }
/// <summary>
/// Gets the source surface (source mode) width.
/// </summary>
public uint Width { get; }
/// <summary>
/// Gets the horizontal scaling ratio.
/// </summary>
public float XRatio { get; }
/// <summary>
/// Gets the vertical scaling ratio.
/// </summary>
public float YRatio { get; }
/// <inheritdoc />
public bool Equals(CustomResolution other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Width == other.Width &&
Height == other.Height &&
ColorDepth == other.ColorDepth &&
Timing.Equals(other.Timing) &&
ColorFormat == other.ColorFormat &&
XRatio.Equals(other.XRatio) &&
YRatio.Equals(other.YRatio);
}
/// <summary>
/// Compares two instance of <see cref="CustomResolution" /> for equality.
/// </summary>
/// <param name="left">An first instance of <see cref="CustomResolution" /> to compare.</param>
/// <param name="right">An Second instance of <see cref="CustomResolution" /> to compare.</param>
/// <returns>True if both instances are equal, otherwise false.</returns>
public static bool operator ==(CustomResolution left, CustomResolution right)
{
return Equals(left, right);
}
/// <summary>
/// Compares two instance of <see cref="CustomResolution" /> for inequality.
/// </summary>
/// <param name="left">An first instance of <see cref="CustomResolution" /> to compare.</param>
/// <param name="right">An Second instance of <see cref="CustomResolution" /> to compare.</param>
/// <returns>True if both instances are not equal, otherwise false.</returns>
public static bool operator !=(CustomResolution left, CustomResolution right)
{
return !Equals(left, right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((CustomResolution) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = (int) Width;
hashCode = (hashCode * 397) ^ (int) Height;
hashCode = (hashCode * 397) ^ (int) ColorDepth;
hashCode = (hashCode * 397) ^ Timing.GetHashCode();
hashCode = (hashCode * 397) ^ (int) ColorFormat;
hashCode = (hashCode * 397) ^ XRatio.GetHashCode();
hashCode = (hashCode * 397) ^ YRatio.GetHashCode();
return hashCode;
}
}
internal CustomDisplay AsCustomDisplay(bool hardwareModeSetOnly)
{
return new CustomDisplay(Width, Height, ColorDepth, ColorFormat, XRatio, YRatio, Timing,
hardwareModeSetOnly);
}
}
}

View File

@@ -0,0 +1,325 @@
using System;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.Display;
namespace NvAPIWrapper.Display
{
/// <summary>
/// This class contains and provides a way to modify the Digital Vibrance Control information regarding the
/// saturation level of the display or the output
/// </summary>
public class DVCInformation : IDisplayDVCInfo
{
private readonly DisplayHandle _displayHandle = DisplayHandle.DefaultHandle;
private readonly OutputId _outputId = OutputId.Invalid;
private bool? _isLegacy;
/// <summary>
/// Creates a new instance of the class using a DisplayHandle
/// </summary>
/// <param name="displayHandle">The handle of the display.</param>
public DVCInformation(DisplayHandle displayHandle)
{
_displayHandle = displayHandle;
}
/// <summary>
/// Creates a new instance of this class using a OutputId
/// </summary>
/// <param name="outputId">The output identification of a display or an output</param>
public DVCInformation(OutputId outputId)
{
_outputId = outputId;
}
/// <summary>
/// Gets and sets the normalized saturation level in the [-1,1] inclusive range.
/// a -1 value corresponds to the minimum saturation level and maximum under-saturation and the
/// a 1 value corresponds to the maximum saturation level and maximum over-saturation.
/// The value of 0 indicates the default saturation level.
/// </summary>
public double NormalizedLevel
{
get
{
var info = GetInfo();
if (info == null)
{
return double.NaN;
}
var deviance = info.CurrentLevel - info.DefaultLevel;
var range = deviance >= 0
? info.MaximumLevel - info.DefaultLevel
: info.DefaultLevel - info.MinimumLevel;
if (deviance == 0 || range == 0)
{
return 0;
}
return Math.Max(Math.Min((double) deviance / range, 1), -1);
}
set
{
if (double.IsNaN(value) || double.IsInfinity(value))
{
throw new ArgumentOutOfRangeException(nameof(value));
}
var info = GetInfo();
if (info == null)
{
return;
}
var range = value >= 0 ? info.MaximumLevel - info.DefaultLevel : info.DefaultLevel - info.MinimumLevel;
var level = Math.Max(Math.Min((int) (value * range) + info.DefaultLevel, info.MaximumLevel), info.MinimumLevel);
if (level == info.CurrentLevel)
{
return;
}
SetLevel(level);
}
}
/// <summary>
/// Gets and sets the current saturation level
/// </summary>
public int CurrentLevel
{
get => GetInfo()?.CurrentLevel ?? 0;
set
{
var info = GetInfo();
if (info == null)
{
return;
}
value = Math.Max(Math.Min(value, info.MaximumLevel), info.MinimumLevel);
if (info.CurrentLevel == value)
{
return;
}
SetLevel(value);
}
}
/// <inheritdoc />
public int DefaultLevel
{
get => GetInfo()?.DefaultLevel ?? 0;
}
/// <inheritdoc />
public int MaximumLevel
{
get => GetInfo()?.MaximumLevel ?? 0;
}
/// <inheritdoc />
public int MinimumLevel
{
get => GetInfo()?.MinimumLevel ?? 0;
}
/// <inheritdoc />
public override string ToString()
{
return
$"{CurrentLevel:D} @ [{MinimumLevel:D} <= {DefaultLevel:D} <= {MaximumLevel:D}] = {NormalizedLevel:F2}";
}
private IDisplayDVCInfo GetInfo()
{
if (_isLegacy == true)
{
return GetLegacyInfo();
}
if (_isLegacy == false)
{
return GetModernInfo();
}
var info = GetModernInfo() ?? GetLegacyInfo();
if (info == null)
{
// exception occured on both, force a mode
_isLegacy = false;
return GetInfo();
}
return info;
}
private IDisplayDVCInfo GetLegacyInfo()
{
try
{
var info = _outputId == OutputId.Invalid
? DisplayApi.GetDVCInfo(_displayHandle)
: DisplayApi.GetDVCInfo(_outputId);
if (info.MaximumLevel == 0 && info.MinimumLevel == 0 && info.CurrentLevel == 0)
{
return null;
}
if (!_isLegacy.HasValue)
{
_isLegacy = true;
}
return info;
}
catch (Exception)
{
if (_isLegacy == true)
{
throw;
}
// ignore
}
return null;
}
private IDisplayDVCInfo GetModernInfo()
{
try
{
var info = _outputId == OutputId.Invalid
? DisplayApi.GetDVCInfoEx(_displayHandle)
: DisplayApi.GetDVCInfoEx(_outputId);
if (info.MaximumLevel == 0 && info.MinimumLevel == 0 && info.CurrentLevel == 0)
{
return null;
}
if (!_isLegacy.HasValue)
{
_isLegacy = false;
}
return info;
}
catch (Exception)
{
if (_isLegacy == false)
{
throw;
}
// ignore
}
return null;
}
private bool SetLegacyLevel(int level)
{
try
{
if (_outputId == OutputId.Invalid)
{
DisplayApi.SetDVCLevel(_displayHandle, level);
}
else
{
DisplayApi.SetDVCLevel(_outputId, level);
}
if (!_isLegacy.HasValue)
{
_isLegacy = true;
}
return true;
}
catch (Exception)
{
if (_isLegacy == true)
{
throw;
}
// ignore
}
return false;
}
private void SetLevel(int level)
{
if (_isLegacy == true)
{
SetLegacyLevel(level);
}
else if (_isLegacy == false)
{
SetModernLevel(level);
}
else
{
var success = SetModernLevel(level) || SetLegacyLevel(level);
if (!success)
{
// exception occured on both, force a mode
_isLegacy = false;
SetLevel(level);
}
}
}
private bool SetModernLevel(int level)
{
try
{
if (_outputId == OutputId.Invalid)
{
DisplayApi.SetDVCLevelEx(_displayHandle, level);
}
else
{
DisplayApi.SetDVCLevelEx(_outputId, level);
}
if (!_isLegacy.HasValue)
{
_isLegacy = false;
}
return true;
}
catch (Exception)
{
if (_isLegacy == false)
{
throw;
}
// ignore
}
return false;
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Linq;
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.Display;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents an attached display
/// </summary>
public class Display : IEquatable<Display>
{
/// <summary>
/// Creates a new Display
/// </summary>
/// <param name="handle">Handle of the display device</param>
public Display(DisplayHandle handle)
{
Handle = handle;
}
/// <summary>
/// Creates a new Display
/// </summary>
/// <param name="displayName">Name of the display device</param>
public Display(string displayName)
{
Handle = DisplayApi.GetAssociatedNvidiaDisplayHandle(displayName);
}
/// <summary>
/// Gets the corresponding Digital Vibrance Control information
/// </summary>
public DVCInformation DigitalVibranceControl
{
get => new DVCInformation(Handle);
}
/// <summary>
/// Gets corresponding DisplayDevice based on display name
/// </summary>
public DisplayDevice DisplayDevice
{
get => new DisplayDevice(Name);
}
/// <summary>
/// Gets display driver build title
/// </summary>
public string DriverBuildTitle
{
get => DisplayApi.GetDisplayDriverBuildTitle(Handle);
}
/// <summary>
/// Gets display handle
/// </summary>
public DisplayHandle Handle { get; }
/// <summary>
/// Gets the display HDMI support information
/// </summary>
public IHDMISupportInfo HDMISupportInfo
{
get
{
var outputId = OutputId.Invalid;
try
{
outputId = DisplayApi.GetAssociatedDisplayOutputId(Handle);
}
catch (NVIDIAApiException)
{
// ignore
}
return DisplayApi.GetHDMISupportInfo(Handle, outputId);
}
}
/// <summary>
/// Gets the corresponding HUE information
/// </summary>
public HUEInformation HUEControl
{
get => new HUEInformation(Handle);
}
/// <summary>
/// Gets the driving logical GPU
/// </summary>
public LogicalGPU LogicalGPU
{
get => new LogicalGPU(GPUApi.GetLogicalGPUFromDisplay(Handle));
}
/// <summary>
/// Gets display name
/// </summary>
public string Name
{
get => DisplayApi.GetAssociatedNvidiaDisplayName(Handle);
}
/// <summary>
/// Gets the connected GPU output
/// </summary>
public GPUOutput Output
{
get => new GPUOutput(DisplayApi.GetAssociatedDisplayOutputId(Handle), PhysicalGPUs.FirstOrDefault());
}
/// <summary>
/// Gets the list of all physical GPUs responsible for this display, with the first GPU returned as the one with the
/// attached active output.
/// </summary>
public PhysicalGPU[] PhysicalGPUs
{
get => GPUApi.GetPhysicalGPUsFromDisplay(Handle).Select(handle => new PhysicalGPU(handle)).ToArray();
}
/// <inheritdoc />
public bool Equals(Display other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Handle.Equals(other.Handle);
}
/// <summary>
/// This function returns all NVIDIA displays
/// Note: Display handles can get invalidated on a modeset.
/// </summary>
/// <returns>An array of Display objects</returns>
public static Display[] GetDisplays()
{
return DisplayApi.EnumNvidiaDisplayHandle().Select(handle => new Display(handle)).ToArray();
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(Display left, Display right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(Display left, Display right)
{
return !(right == left);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((Display) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return Name;
}
/// <summary>
/// Gets all the supported NVIDIA display views (nView and Dualview modes) for this display.
/// </summary>
/// <returns></returns>
public TargetViewMode[] GetSupportedViews()
{
return DisplayApi.GetSupportedViews(Handle);
}
/// <summary>
/// Overrides the refresh rate on this display.
/// The new refresh rate can be applied right away or deferred to be applied with the next OS
/// mode-set.
/// The override is good for only one mode-set (regardless whether it's deferred or immediate).
/// </summary>
/// <param name="refreshRate">The refresh rate to be applied.</param>
/// <param name="isDeferred">
/// A boolean value indicating if the refresh rate override should be deferred to the next OS
/// mode-set.
/// </param>
public void OverrideRefreshRate(float refreshRate, bool isDeferred = false)
{
DisplayApi.SetRefreshRateOverride(Handle, refreshRate, isDeferred);
}
}
}

View File

@@ -0,0 +1,893 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
using NvAPIWrapper.Native.Interfaces.Display;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents an NVIDIA display device
/// </summary>
public class DisplayDevice : IEquatable<DisplayDevice>
{
/// <summary>
/// Creates a new DisplayDevice
/// </summary>
/// <param name="displayId">Display identification of the device</param>
public DisplayDevice(uint displayId)
{
DisplayId = displayId;
var extraInformation = PhysicalGPU.GetDisplayDevices().FirstOrDefault(ids => ids.DisplayId == DisplayId);
if (extraInformation != null)
{
IsAvailable = true;
ScanOutInformation = new ScanOutInformation(this);
ConnectionType = extraInformation.ConnectionType;
IsDynamic = extraInformation.IsDynamic;
IsMultiStreamRootNode = extraInformation.IsMultiStreamRootNode;
IsActive = extraInformation.IsActive;
IsCluster = extraInformation.IsCluster;
IsOSVisible = extraInformation.IsOSVisible;
IsWFD = extraInformation.IsWFD;
IsConnected = extraInformation.IsConnected;
IsPhysicallyConnected = extraInformation.IsPhysicallyConnected;
}
}
/// <summary>
/// Creates a new DisplayDevice
/// </summary>
/// <param name="displayIds">Display identification and attributes of the display device</param>
public DisplayDevice(IDisplayIds displayIds)
{
IsAvailable = true;
DisplayId = displayIds.DisplayId;
ScanOutInformation = new ScanOutInformation(this);
ConnectionType = displayIds.ConnectionType;
IsDynamic = displayIds.IsDynamic;
IsMultiStreamRootNode = displayIds.IsMultiStreamRootNode;
IsActive = displayIds.IsActive;
IsCluster = displayIds.IsCluster;
IsOSVisible = displayIds.IsOSVisible;
IsWFD = displayIds.IsWFD;
IsConnected = displayIds.IsConnected;
IsPhysicallyConnected = displayIds.IsPhysicallyConnected;
}
/// <summary>
/// Creates a new DisplayDevice
/// </summary>
/// <param name="displayName">Display name of the display device</param>
public DisplayDevice(string displayName) : this(DisplayApi.GetDisplayIdByDisplayName(displayName))
{
}
/// <summary>
/// Gets the display device connection type
/// </summary>
public MonitorConnectionType ConnectionType { get; }
/// <summary>
/// Gets the current display color data
/// </summary>
public ColorData CurrentColorData
{
get
{
var instances = new IColorData[]
{
new ColorDataV5(ColorDataCommand.Get),
new ColorDataV4(ColorDataCommand.Get),
new ColorDataV3(ColorDataCommand.Get),
new ColorDataV2(ColorDataCommand.Get),
new ColorDataV1(ColorDataCommand.Get)
};
var instance = DisplayApi.ColorControl(DisplayId, instances);
return new ColorData(instance);
}
}
/// <summary>
/// Gets the current display device timing
/// </summary>
public Timing CurrentTiming
{
get => DisplayApi.GetTiming(DisplayId, new TimingInput(TimingOverride.Current));
}
/// <summary>
/// Gets the default display color data
/// </summary>
public ColorData DefaultColorData
{
get
{
var instances = new IColorData[]
{
new ColorDataV5(ColorDataCommand.GetDefault),
new ColorDataV4(ColorDataCommand.GetDefault),
new ColorDataV3(ColorDataCommand.GetDefault),
new ColorDataV2(ColorDataCommand.GetDefault),
new ColorDataV1(ColorDataCommand.GetDefault)
};
var instance = DisplayApi.ColorControl(DisplayId, instances);
return new ColorData(instance);
}
}
/// <summary>
/// Gets the NVIDIA display identification
/// </summary>
public uint DisplayId { get; }
/// <summary>
/// Gets the monitor Display port capabilities
/// </summary>
public MonitorColorData[] DisplayPortColorCapabilities
{
get
{
if (ConnectionType != MonitorConnectionType.DisplayPort)
{
return null;
}
return DisplayApi.GetMonitorColorCapabilities(DisplayId);
}
}
/// <summary>
/// Gets the display driver EDID specified HDR capabilities
/// </summary>
public HDRCapabilitiesV1 DriverHDRCapabilities
{
get => DisplayApi.GetHDRCapabilities(DisplayId, true);
}
/// <summary>
/// Gets the display currently effective HDR capabilities
/// </summary>
public HDRCapabilitiesV1 EffectiveHDRCapabilities
{
get => DisplayApi.GetHDRCapabilities(DisplayId, false);
}
/// <summary>
/// Gets the HDMI audio info-frame current information
/// </summary>
public InfoFrameAudio? HDMIAudioFrameCurrentInformation
{
get
{
try
{
var infoFrame = new InfoFrameData(InfoFrameCommand.Get, InfoFrameDataType.AudioInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.AudioInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the HDMI audio info-frame default information
/// </summary>
public InfoFrameAudio? HDMIAudioFrameDefaultInformation
{
get
{
try
{
var infoFrame = new InfoFrameData(InfoFrameCommand.GetDefault, InfoFrameDataType.AudioInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.AudioInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the HDMI audio info-frame override information
/// </summary>
public InfoFrameAudio? HDMIAudioFrameOverrideInformation
{
get
{
try
{
var infoFrame = new InfoFrameData(InfoFrameCommand.GetOverride, InfoFrameDataType.AudioInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.AudioInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the HDMI audio info-frame property information
/// </summary>
public InfoFrameProperty? HDMIAudioFramePropertyInformation
{
get
{
try
{
var infoFrame = new InfoFrameData(InfoFrameCommand.GetProperty, InfoFrameDataType.AudioInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.PropertyInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the device HDMI support information
/// </summary>
public IHDMISupportInfo HDMISupportInfo
{
get => DisplayApi.GetHDMISupportInfo(DisplayId);
}
/// <summary>
/// Gets the HDMI auxiliary video info-frame current information
/// </summary>
public InfoFrameVideo? HDMIVideoFrameCurrentInformation
{
get
{
try
{
var infoFrame =
new InfoFrameData(InfoFrameCommand.Get, InfoFrameDataType.AuxiliaryVideoInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.AuxiliaryVideoInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the HDMI auxiliary video info-frame default information
/// </summary>
public InfoFrameVideo? HDMIVideoFrameDefaultInformation
{
get
{
try
{
var infoFrame = new InfoFrameData(InfoFrameCommand.GetDefault,
InfoFrameDataType.AuxiliaryVideoInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.AuxiliaryVideoInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the HDMI auxiliary video info-frame override information
/// </summary>
public InfoFrameVideo? HDMIVideoFrameOverrideInformation
{
get
{
try
{
var infoFrame = new InfoFrameData(InfoFrameCommand.GetOverride,
InfoFrameDataType.AuxiliaryVideoInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.AuxiliaryVideoInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the HDMI auxiliary video info-frame property information
/// </summary>
public InfoFrameProperty? HDMIVideoFramePropertyInformation
{
get
{
try
{
var infoFrame = new InfoFrameData(InfoFrameCommand.GetProperty,
InfoFrameDataType.AuxiliaryVideoInformation);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
return infoFrame.PropertyInformation;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Gets the HDR color data, or null if the HDR is disabled or unavailable
/// </summary>
public HDRColorData HDRColorData
{
get
{
try
{
var instances = new IHDRColorData[]
{
new HDRColorDataV2(ColorDataHDRCommand.Get),
new HDRColorDataV1(ColorDataHDRCommand.Get)
};
var instance = DisplayApi.HDRColorControl(DisplayId, instances);
if (instance.HDRMode == ColorDataHDRMode.Off)
{
return null;
}
return new HDRColorData(instance);
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return null;
}
throw;
}
}
}
/// <summary>
/// Indicates if the display is being actively driven
/// </summary>
public bool IsActive { get; }
/// <summary>
/// Indicates if the display device is currently available
/// </summary>
public bool IsAvailable { get; }
/// <summary>
/// Indicates if the display is the representative display
/// </summary>
public bool IsCluster { get; }
/// <summary>
/// Indicates if the display is connected
/// </summary>
public bool IsConnected { get; }
/// <summary>
/// Indicates if the display is part of MST topology and it's a dynamic
/// </summary>
public bool IsDynamic { get; }
/// <summary>
/// Indicates if the display identification belongs to a multi stream enabled connector (root node). Note that when
/// multi stream is enabled and a single multi stream capable monitor is connected to it, the monitor will share the
/// display id with the RootNode.
/// When there is more than one monitor connected in a multi stream topology, then the root node will have a separate
/// displayId.
/// </summary>
public bool IsMultiStreamRootNode { get; }
/// <summary>
/// Indicates if the display is reported to the OS
/// </summary>
public bool IsOSVisible { get; }
/// <summary>
/// Indicates if the display is a physically connected display; Valid only when IsConnected is true
/// </summary>
public bool IsPhysicallyConnected { get; }
/// <summary>
/// Indicates if the display is wireless
/// </summary>
public bool IsWFD { get; }
/// <summary>
/// Gets the connected GPU output
/// </summary>
public GPUOutput Output
{
get
{
PhysicalGPUHandle handle;
var outputId = GPUApi.GetGPUAndOutputIdFromDisplayId(DisplayId, out handle);
return new GPUOutput(outputId, new PhysicalGPU(handle));
}
}
/// <summary>
/// Gets the connected physical GPU
/// </summary>
public PhysicalGPU PhysicalGPU
{
get
{
try
{
var gpuHandle = GPUApi.GetPhysicalGPUFromDisplayId(DisplayId);
return new PhysicalGPU(gpuHandle);
}
catch
{
// ignored
}
return Output.PhysicalGPU;
}
}
/// <summary>
/// Gets information regarding the scan-out settings of this display device
/// </summary>
public ScanOutInformation ScanOutInformation { get; }
/// <summary>
/// Gets monitor capabilities from the Video Capability Data Block if available, otherwise null
/// </summary>
public MonitorVCDBCapabilities? VCDBMonitorCapabilities
{
get => DisplayApi.GetMonitorCapabilities(DisplayId, MonitorCapabilitiesType.VCDB)?.VCDBCapabilities;
}
/// <summary>
/// Gets monitor capabilities from the Vendor Specific Data Block if available, otherwise null
/// </summary>
public MonitorVSDBCapabilities? VSDBMonitorCapabilities
{
get => DisplayApi.GetMonitorCapabilities(DisplayId, MonitorCapabilitiesType.VSDB)?.VSDBCapabilities;
}
/// <inheritdoc />
public bool Equals(DisplayDevice other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return DisplayId == other.DisplayId;
}
/// <summary>
/// Deletes a custom resolution.
/// </summary>
/// <param name="customResolution">The custom resolution to delete.</param>
/// <param name="displayIds">A list of display ids to remove the custom resolution from.</param>
public static void DeleteCustomResolution(CustomResolution customResolution, uint[] displayIds)
{
var customDisplay = customResolution.AsCustomDisplay(false);
DisplayApi.DeleteCustomDisplay(displayIds, customDisplay);
}
/// <summary>
/// Returns an instance of <see cref="DisplayDevice" /> representing the primary GDI display device.
/// </summary>
/// <returns>An instance of <see cref="DisplayDevice" />.</returns>
public static DisplayDevice GetGDIPrimaryDisplayDevice()
{
var displayId = DisplayApi.GetGDIPrimaryDisplayId();
if (displayId == 0)
{
return null;
}
return new DisplayDevice(displayId);
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(DisplayDevice left, DisplayDevice right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(DisplayDevice left, DisplayDevice right)
{
return !(right == left);
}
/// <summary>
/// Reverts the custom resolution currently on trial.
/// </summary>
/// <param name="displayIds">A list of display ids to revert the custom resolution from.</param>
public static void RevertCustomResolution(uint[] displayIds)
{
DisplayApi.RevertCustomDisplayTrial(displayIds);
}
/// <summary>
/// Saves the custom resolution currently on trial.
/// </summary>
/// <param name="displayIds">A list of display ids to save the custom resolution for.</param>
/// <param name="isThisOutputIdOnly">
/// If set, the saved custom display will only be applied on the monitor with the same
/// outputId.
/// </param>
/// <param name="isThisMonitorOnly">
/// If set, the saved custom display will only be applied on the monitor with the same EDID
/// ID or the same TV connector in case of analog TV.
/// </param>
public static void SaveCustomResolution(uint[] displayIds, bool isThisOutputIdOnly, bool isThisMonitorOnly)
{
DisplayApi.SaveCustomDisplay(displayIds, isThisOutputIdOnly, isThisMonitorOnly);
}
/// <summary>
/// Applies a custom resolution into trial
/// </summary>
/// <param name="customResolution">The custom resolution to apply.</param>
/// <param name="displayIds">A list of display ids to apply the custom resolution on.</param>
/// <param name="hardwareModeSetOnly">
/// A boolean value indicating that a hardware mode-set without OS update should be
/// performed.
/// </param>
public static void TrialCustomResolution(
CustomResolution customResolution,
uint[] displayIds,
bool hardwareModeSetOnly = true)
{
var customDisplay = customResolution.AsCustomDisplay(hardwareModeSetOnly);
DisplayApi.TryCustomDisplay(displayIds.ToDictionary(u => u, u => customDisplay));
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((DisplayDevice) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
return (int) DisplayId;
}
/// <inheritdoc />
public override string ToString()
{
return $"Display #{DisplayId}";
}
/// <summary>
/// Calculates a valid timing based on the argument passed
/// </summary>
/// <param name="width">The preferred width.</param>
/// <param name="height">The preferred height.</param>
/// <param name="refreshRate">The preferred refresh rate.</param>
/// <param name="isInterlaced">The boolean value indicating if the preferred resolution is an interlaced resolution.</param>
/// <returns>Returns a valid instance of <see cref="Timing" />.</returns>
public Timing CalculateTiming(uint width, uint height, float refreshRate, bool isInterlaced)
{
return DisplayApi.GetTiming(
DisplayId,
new TimingInput(width, height, refreshRate, TimingOverride.Auto, isInterlaced)
);
}
/// <summary>
/// Deletes a custom resolution.
/// </summary>
/// <param name="customResolution">The custom resolution to delete.</param>
public void DeleteCustomResolution(CustomResolution customResolution)
{
DeleteCustomResolution(customResolution, new[] {DisplayId});
}
/// <summary>
/// Retrieves the list of custom resolutions saved for this display device
/// </summary>
/// <returns>A list of <see cref="CustomResolution" /> instances.</returns>
public IEnumerable<CustomResolution> GetCustomResolutions()
{
return DisplayApi.EnumCustomDisplays(DisplayId).Select(custom => new CustomResolution(custom));
}
/// <summary>
/// Checks if a color data is supported on this display
/// </summary>
/// <param name="colorData">The color data to be checked.</param>
/// <returns>true if the color data passed is supported; otherwise false</returns>
public bool IsColorDataSupported(ColorData colorData)
{
var instances = new IColorData[]
{
colorData.AsColorDataV5(ColorDataCommand.IsSupportedColor),
colorData.AsColorDataV4(ColorDataCommand.IsSupportedColor),
colorData.AsColorDataV3(ColorDataCommand.IsSupportedColor),
colorData.AsColorDataV2(ColorDataCommand.IsSupportedColor),
colorData.AsColorDataV1(ColorDataCommand.IsSupportedColor)
};
try
{
DisplayApi.ColorControl(DisplayId, instances);
return true;
}
catch (NVIDIAApiException e)
{
if (e.Status == Status.NotSupported)
{
return false;
}
throw;
}
}
/// <summary>
/// Resets the HDMI audio info-frame information to default
/// </summary>
public void ResetHDMIAudioFrameInformation()
{
var infoFrame = new InfoFrameData(
InfoFrameCommand.Reset,
InfoFrameDataType.AudioInformation
);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
}
/// <summary>
/// Resets the HDMI auxiliary video info-frame information to default
/// </summary>
public void ResetHDMIVideoFrameInformation()
{
var infoFrame = new InfoFrameData(
InfoFrameCommand.Reset,
InfoFrameDataType.AuxiliaryVideoInformation
);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
}
/// <summary>
/// Reverts the custom resolution currently on trial.
/// </summary>
public void RevertCustomResolution()
{
RevertCustomResolution(new[] {DisplayId});
}
/// <summary>
/// Saves the custom resolution currently on trial.
/// </summary>
/// <param name="isThisOutputIdOnly">
/// If set, the saved custom display will only be applied on the monitor with the same
/// outputId.
/// </param>
/// <param name="isThisMonitorOnly">
/// If set, the saved custom display will only be applied on the monitor with the same EDID
/// ID or the same TV connector in case of analog TV.
/// </param>
public void SaveCustomResolution(bool isThisOutputIdOnly = true, bool isThisMonitorOnly = true)
{
SaveCustomResolution(new[] {DisplayId}, isThisOutputIdOnly, isThisMonitorOnly);
}
/// <summary>
/// Changes the display current color data configuration
/// </summary>
/// <param name="colorData">The color data to be set.</param>
public void SetColorData(ColorData colorData)
{
var instances = new IColorData[]
{
colorData.AsColorDataV5(ColorDataCommand.Set),
colorData.AsColorDataV4(ColorDataCommand.Set),
colorData.AsColorDataV3(ColorDataCommand.Set),
colorData.AsColorDataV2(ColorDataCommand.Set),
colorData.AsColorDataV1(ColorDataCommand.Set)
};
DisplayApi.ColorControl(DisplayId, instances);
}
/// <summary>
/// Sets the HDMI video info-frame current or override information
/// </summary>
/// <param name="audio">The new information.</param>
/// <param name="isOverride">A boolean value indicating if the changes should persist mode-set and OS restart.</param>
public void SetHDMIAudioFrameInformation(InfoFrameAudio audio, bool isOverride = false)
{
var infoFrame = new InfoFrameData(
isOverride ? InfoFrameCommand.SetOverride : InfoFrameCommand.Set,
audio
);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
}
/// <summary>
/// Sets the HDMI audio info-frame property information
/// </summary>
/// <param name="property">The new property information.</param>
public void SetHDMIAudioFramePropertyInformation(InfoFrameProperty property)
{
var infoFrame = new InfoFrameData(
InfoFrameCommand.SetProperty,
InfoFrameDataType.AudioInformation,
property
);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
}
/// <summary>
/// Sets the HDMI auxiliary video info-frame current or override information
/// </summary>
/// <param name="video">The new information.</param>
/// <param name="isOverride">A boolean value indicating if the changes should persist mode-set and OS restart.</param>
public void SetHDMIVideoFrameInformation(InfoFrameVideo video, bool isOverride = false)
{
var infoFrame = new InfoFrameData(
isOverride ? InfoFrameCommand.SetOverride : InfoFrameCommand.Set,
video
);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
}
/// <summary>
/// Sets the HDMI auxiliary video info-frame property information
/// </summary>
/// <param name="property">The new property information.</param>
public void SetHDMIVideoFramePropertyInformation(InfoFrameProperty property)
{
var infoFrame = new InfoFrameData(
InfoFrameCommand.SetProperty,
InfoFrameDataType.AuxiliaryVideoInformation,
property
);
DisplayApi.InfoFrameControl(DisplayId, ref infoFrame);
}
/// <summary>
/// Changes the display HDR color data configuration
/// </summary>
/// <param name="colorData">The color data to be set.</param>
public void SetHDRColorData(HDRColorData colorData)
{
var instances = new IHDRColorData[]
{
colorData.AsHDRColorDataV2(ColorDataHDRCommand.Set),
colorData.AsHDRColorDataV1(ColorDataHDRCommand.Set)
};
DisplayApi.HDRColorControl(DisplayId, instances);
}
/// <summary>
/// Applies a custom resolution into trial.
/// </summary>
/// <param name="customResolution">The custom resolution to apply.</param>
/// <param name="hardwareModeSetOnly">
/// A boolean value indicating that a hardware mode-set without OS update should be
/// performed.
/// </param>
public void TrialCustomResolution(CustomResolution customResolution, bool hardwareModeSetOnly = true)
{
TrialCustomResolution(customResolution, new[] {DisplayId}, hardwareModeSetOnly);
}
}
}

View File

@@ -0,0 +1,183 @@
using System;
using System.Linq;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents a texture of float values
/// </summary>
public class FloatTexture : IEquatable<FloatTexture>
{
/// <summary>
/// Underlying float array containing the values of all channels in all pixels
/// </summary>
protected readonly float[] UnderlyingArray;
/// <summary>
/// Creates a new instance of <see cref="FloatTexture" />.
/// </summary>
/// <param name="width">The texture width.</param>
/// <param name="height">The texture height.</param>
/// <param name="channels">The number of texture channels.</param>
public FloatTexture(int width, int height, int channels) : this(width, height, channels, null)
{
}
/// <summary>
/// Creates a new instance of <see cref="FloatTexture" />.
/// </summary>
/// <param name="width">The texture width.</param>
/// <param name="height">The texture height.</param>
/// <param name="channels">The number of texture channels.</param>
/// <param name="array">The underlying array containing all float values.</param>
// ReSharper disable once TooManyDependencies
protected FloatTexture(int width, int height, int channels, float[] array)
{
Width = width;
Height = height;
Channels = channels;
UnderlyingArray = array ?? new float[width * height * channels];
}
/// <summary>
/// Gets the number of texture channels
/// </summary>
public int Channels { get; }
/// <summary>
/// Gets the texture height in pixel
/// </summary>
public int Height { get; }
/// <summary>
/// Gets the texture width in pixels
/// </summary>
public int Width { get; }
/// <inheritdoc />
public bool Equals(FloatTexture other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (other.UnderlyingArray.Length != UnderlyingArray.Length)
{
return false;
}
if (other.Width != Width || other.Height != Height || other.Channels != Channels)
{
return false;
}
return !UnderlyingArray.Where((t, i) => Math.Abs(other.UnderlyingArray[i] - t) > 0.0001).Any();
}
/// <summary>
/// Returns a new instance of FloatTexture from the passed array of float values.
/// </summary>
/// <param name="width">The texture width.</param>
/// <param name="height">The texture height.</param>
/// <param name="channels">The texture channels.</param>
/// <param name="floats">The array of float values.</param>
/// <returns>A new instance of <see cref="FloatTexture" />.</returns>
// ReSharper disable once TooManyArguments
public static FloatTexture FromFloatArray(int width, int height, int channels, float[] floats)
{
if (floats.Length != width * height * channels)
{
throw new ArgumentOutOfRangeException(nameof(floats));
}
return new FloatTexture(width, height, channels, floats.ToArray());
}
/// <summary>
/// Compares two instance of <see cref="FloatTexture" /> for equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns><see langword="true" /> if both instances are equal, otherwise <see langword="false" /></returns>
public static bool operator ==(FloatTexture left, FloatTexture right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
/// <summary>
/// Compares two instance of <see cref="FloatTexture" /> for in-equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns><see langword="true" /> if both instances are not equal, otherwise <see langword="false" /></returns>
public static bool operator !=(FloatTexture left, FloatTexture right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as FloatTexture);
}
/// <inheritdoc />
public override int GetHashCode()
{
return UnderlyingArray.GetHashCode();
}
/// <summary>
/// Gets the values of each channel at a specific location
/// </summary>
/// <param name="x">The horizontal location.</param>
/// <param name="y">The vertical location.</param>
/// <returns>An array of float values each representing a channel value.</returns>
public float[] GetValues(int x, int y)
{
return UnderlyingArray.Skip(y * Width + x).Take(Channels).ToArray();
}
/// <summary>
/// Sets the value of each channel at a specific location
/// </summary>
/// <param name="x">The horizontal location.</param>
/// <param name="y">The vertical location.</param>
/// <param name="floats">An array of float values each representing a channel value.</param>
public void SetValues(int x, int y, params float[] floats)
{
var index = y * Width + x;
for (var i = 0; i < Math.Min(Channels, floats.Length); i++)
{
UnderlyingArray[index + i] = floats[i];
}
}
/// <summary>
/// Returns this instance of <see cref="FloatTexture" /> as an array of float values.
/// </summary>
/// <returns>An array of float values representing this instance of <see cref="FloatTexture" />.</returns>
public float[] ToFloatArray()
{
// Returns a copy of the underlying array
return UnderlyingArray.ToArray();
}
}
}

View File

@@ -0,0 +1,157 @@
using System;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Interfaces.Display;
namespace NvAPIWrapper.Display
{
/// <inheritdoc cref="IHDRColorData" />
public class HDRColorData : IHDRColorData, IEquatable<HDRColorData>
{
/// <summary>
/// Creates an instance of <see cref="HDRColorData" />.
/// </summary>
/// <param name="hdrMode">The hdr mode.</param>
/// <param name="masteringDisplayData">The display color space configurations.</param>
/// <param name="colorFormat">The color data color format.</param>
/// <param name="dynamicRange">The color data dynamic range.</param>
/// <param name="colorDepth">The color data color depth.</param>
public HDRColorData(
ColorDataHDRMode hdrMode,
MasteringDisplayColorData masteringDisplayData,
ColorDataFormat? colorFormat = null,
ColorDataDynamicRange? dynamicRange = null,
ColorDataDepth? colorDepth = null
)
{
HDRMode = hdrMode;
MasteringDisplayData = masteringDisplayData;
ColorFormat = colorFormat;
DynamicRange = dynamicRange;
ColorDepth = colorDepth;
}
internal HDRColorData(IHDRColorData colorData)
{
HDRMode = colorData.HDRMode;
MasteringDisplayData = colorData.MasteringDisplayData;
ColorDepth = colorData.ColorDepth;
ColorFormat = colorData.ColorFormat;
DynamicRange = colorData.DynamicRange;
}
/// <inheritdoc />
public bool Equals(HDRColorData other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return ColorDepth == other.ColorDepth &&
ColorFormat == other.ColorFormat &&
DynamicRange == other.DynamicRange &&
HDRMode == other.HDRMode &&
MasteringDisplayData.Equals(other.MasteringDisplayData);
}
/// <inheritdoc />
public ColorDataDepth? ColorDepth { get; }
/// <inheritdoc />
public ColorDataFormat? ColorFormat { get; }
/// <inheritdoc />
public ColorDataDynamicRange? DynamicRange { get; }
/// <inheritdoc />
public ColorDataHDRMode HDRMode { get; }
/// <inheritdoc />
public MasteringDisplayColorData MasteringDisplayData { get; }
/// <summary>
/// Compares two instances of <see cref="HDRColorData" /> for equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>true if two instances are equal; otherwise false.</returns>
public static bool operator ==(HDRColorData left, HDRColorData right)
{
return left?.Equals(right) == true;
}
/// <summary>
/// Compares two instances of <see cref="HDRColorData" /> for inequality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns>true if two instances are not equal; otherwise false.</returns>
public static bool operator !=(HDRColorData left, HDRColorData right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((HDRColorData) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = ColorDepth.GetHashCode();
hashCode = (hashCode * 397) ^ ColorFormat.GetHashCode();
hashCode = (hashCode * 397) ^ DynamicRange.GetHashCode();
hashCode = (hashCode * 397) ^ (int) HDRMode;
hashCode = (hashCode * 397) ^ MasteringDisplayData.GetHashCode();
return hashCode;
}
}
internal HDRColorDataV1 AsHDRColorDataV1(ColorDataHDRCommand command)
{
return new HDRColorDataV1(
command,
HDRMode,
MasteringDisplayData
);
}
internal HDRColorDataV2 AsHDRColorDataV2(ColorDataHDRCommand command)
{
return new HDRColorDataV2(
command,
HDRMode,
MasteringDisplayData,
ColorFormat ?? ColorDataFormat.Auto,
DynamicRange ?? ColorDataDynamicRange.Auto,
ColorDepth ?? ColorDataDepth.Default
);
}
}
}

View File

@@ -0,0 +1,97 @@
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.Display
{
/// <summary>
/// This class contains and provides a way to modify the HUE angle
/// </summary>
public class HUEInformation
{
private readonly DisplayHandle _displayHandle = DisplayHandle.DefaultHandle;
private readonly OutputId _outputId = OutputId.Invalid;
/// <summary>
/// Creates a new instance of the class using a DisplayHandle
/// </summary>
/// <param name="displayHandle">The handle of the display.</param>
public HUEInformation(DisplayHandle displayHandle)
{
_displayHandle = displayHandle;
}
/// <summary>
/// Creates a new instance of this class using a OutputId
/// </summary>
/// <param name="outputId">The output identification of a display or an output</param>
public HUEInformation(OutputId outputId)
{
_outputId = outputId;
}
/// <summary>
/// Gets or sets the current HUE offset angle [0-359]
/// </summary>
public int CurrentAngle
{
get
{
PrivateDisplayHUEInfo? hueInfo = null;
if (_displayHandle != DisplayHandle.DefaultHandle)
{
hueInfo = DisplayApi.GetHUEInfo(_displayHandle);
}
else if (_outputId != OutputId.Invalid)
{
hueInfo = DisplayApi.GetHUEInfo(_outputId);
}
return hueInfo?.CurrentAngle ?? 0;
}
set
{
value %= 360;
if (_displayHandle != DisplayHandle.DefaultHandle)
{
DisplayApi.SetHUEAngle(_displayHandle, value);
}
else if (_outputId != OutputId.Invalid)
{
DisplayApi.SetHUEAngle(_outputId, value);
}
}
}
/// <summary>
/// Gets the default HUE offset angle [0-359]
/// </summary>
public int DefaultAngle
{
get
{
PrivateDisplayHUEInfo? hueInfo = null;
if (_displayHandle != DisplayHandle.DefaultHandle)
{
hueInfo = DisplayApi.GetHUEInfo(_displayHandle);
}
else if (_outputId != OutputId.Invalid)
{
hueInfo = DisplayApi.GetHUEInfo(_outputId);
}
return hueInfo?.DefaultAngle ?? 0;
}
}
/// <inheritdoc />
public override string ToString()
{
return $"{CurrentAngle:D}º [{DefaultAngle:D}º]";
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.Linq;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents a texture of intensity values
/// </summary>
public class IntensityTexture : FloatTexture
{
/// <summary>
/// Creates a new instance of <see cref="IntensityTexture" />.
/// </summary>
/// <param name="width">The texture width.</param>
/// <param name="height">The texture height.</param>
public IntensityTexture(int width, int height) : base(width, height, 3)
{
}
private IntensityTexture(int width, int height, float[] floats) : base(width, height, 3, floats)
{
}
/// <summary>
/// Returns a new instance of FloatTexture from the passed array of float values.
/// </summary>
/// <param name="width">The texture width.</param>
/// <param name="height">The texture height.</param>
/// <param name="floats">The array of float values.</param>
/// <returns>A new instance of <see cref="FloatTexture" />.</returns>
// ReSharper disable once TooManyArguments
public static IntensityTexture FromFloatArray(int width, int height, float[] floats)
{
if (floats.Length != width * height * 3)
{
throw new ArgumentOutOfRangeException(nameof(floats));
}
return new IntensityTexture(width, height, floats.ToArray());
}
/// <summary>
/// Gets the value of intensity pixel at a specific location.
/// </summary>
/// <param name="x">The horizontal location.</param>
/// <param name="y">The vertical location.</param>
/// <returns>An instance of <see cref="IntensityTexturePixel" />.</returns>
public IntensityTexturePixel GetPixel(int x, int y)
{
return IntensityTexturePixel.FromFloatArray(UnderlyingArray, y * Width + x);
}
/// <summary>
/// Sets the value of intensity pixel at a specific location
/// </summary>
/// <param name="x">The horizontal location.</param>
/// <param name="y">The vertical location.</param>
/// <param name="pixel">An instance of <see cref="IntensityTexturePixel" />.</param>
public void SetPixel(int x, int y, IntensityTexturePixel pixel)
{
var index = y * Width + x;
var floats = pixel.ToFloatArray();
for (var i = 0; i < Math.Min(Channels, floats.Length); i++)
{
UnderlyingArray[index + i] = floats[i];
}
}
}
}

View File

@@ -0,0 +1,117 @@
using System;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents a RGB intensity texture pixel
/// </summary>
public class IntensityTexturePixel : IEquatable<IntensityTexturePixel>
{
/// <summary>
/// Creates a new instance of <see cref="IntensityTexturePixel" />.
/// </summary>
/// <param name="redIntensity">The intensity of the red light (0-1)</param>
/// <param name="greenIntensity">The intensity of the green light (0-1)</param>
/// <param name="blueIntensity">The intensity of the blue light (0-1)</param>
public IntensityTexturePixel(float redIntensity, float greenIntensity, float blueIntensity)
{
RedIntensity = Math.Max(Math.Min(redIntensity, 1), 0);
GreenIntensity = Math.Max(Math.Min(greenIntensity, 1), 0);
BlueIntensity = Math.Max(Math.Min(blueIntensity, 1), 0);
}
/// <summary>
/// Gets the intensity of the blue light (0-1)
/// </summary>
public float BlueIntensity { get; }
/// <summary>
/// Gets the intensity of the green light (0-1)
/// </summary>
public float GreenIntensity { get; }
/// <summary>
/// Gets the intensity of the red light (0-1)
/// </summary>
public float RedIntensity { get; }
/// <inheritdoc />
public bool Equals(IntensityTexturePixel other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Math.Abs(RedIntensity - other.RedIntensity) < 0.0001 &&
Math.Abs(GreenIntensity - other.GreenIntensity) < 0.0001 &&
Math.Abs(BlueIntensity - other.BlueIntensity) < 0.0001;
}
/// <summary>
/// Compares two instance of <see cref="IntensityTexturePixel" /> for equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns><see langword="true" /> if both instances are equal, otherwise <see langword="false" /></returns>
public static bool operator ==(IntensityTexturePixel left, IntensityTexturePixel right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
/// <summary>
/// Compares two instance of <see cref="IntensityTexturePixel" /> for in-equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns><see langword="true" /> if both instances are not equal, otherwise <see langword="false" /></returns>
public static bool operator !=(IntensityTexturePixel left, IntensityTexturePixel right)
{
return !(left == right);
}
internal static IntensityTexturePixel FromFloatArray(float[] floats, int index)
{
return new IntensityTexturePixel(floats[index], floats[index + 1], floats[index + 2]);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as IntensityTexturePixel);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = RedIntensity.GetHashCode();
hashCode = (hashCode * 397) ^ GreenIntensity.GetHashCode();
hashCode = (hashCode * 397) ^ BlueIntensity.GetHashCode();
return hashCode;
}
}
internal float[] ToFloatArray()
{
return new[] {RedIntensity, GreenIntensity, BlueIntensity};
}
}
}

View File

@@ -0,0 +1,288 @@
using System;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces.Display;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents a configuration path
/// </summary>
public class PathInfo : IEquatable<PathInfo>
{
/// <summary>
/// Creates a new PathInfo
/// </summary>
/// <param name="resolution">Display resolution</param>
/// <param name="colorFormat">Display color format</param>
/// <param name="targetInfos">Target configuration informations</param>
public PathInfo(Resolution resolution, ColorFormat colorFormat, PathTargetInfo[] targetInfos)
{
Resolution = resolution;
ColorFormat = colorFormat;
TargetsInfo = targetInfos;
}
/// <summary>
/// Creates a new PathInfo
/// </summary>
/// <param name="info">IPathInfo implamented object</param>
public PathInfo(IPathInfo info)
{
SourceId = info.SourceId;
Resolution = info.SourceModeInfo.Resolution;
ColorFormat = info.SourceModeInfo.ColorFormat;
Position = info.SourceModeInfo.Position;
SpanningOrientation = info.SourceModeInfo.SpanningOrientation;
IsGDIPrimary = info.SourceModeInfo.IsGDIPrimary;
IsSLIFocus = info.SourceModeInfo.IsSLIFocus;
TargetsInfo =
info.TargetsInfo.Select(targetInfo => new PathTargetInfo(targetInfo)).ToArray();
if (info is PathInfoV2)
{
OSAdapterLUID = ((PathInfoV2) info).OSAdapterLUID;
}
}
/// <summary>
/// Gets or sets the display color format
/// </summary>
public ColorFormat ColorFormat { get; set; }
/// <summary>
/// Gets or sets a boolean value indicating if the this is the primary GDI display
/// </summary>
public bool IsGDIPrimary { get; set; }
/// <summary>
/// Gets or sets a boolean value indicating if the this is the SLI focus display
/// </summary>
public bool IsSLIFocus { get; set; }
/// <summary>
/// Gets OS Adapter of LUID for Non-NVIDIA adapters
/// </summary>
public LUID? OSAdapterLUID { get; }
/// <summary>
/// Gets or sets the display position
/// </summary>
public Position Position { get; set; }
/// <summary>
/// Gets or sets the display resolution
/// </summary>
public Resolution Resolution { get; set; }
/// <summary>
/// Gets or sets the Windows CCD display source identification. This can be optionally set.
/// </summary>
public uint SourceId { get; set; }
/// <summary>
/// Gets or sets the display spanning orientation, valid for XP only
/// </summary>
public SpanningOrientation SpanningOrientation { get; set; }
/// <summary>
/// Gets information about path targets
/// </summary>
public PathTargetInfo[] TargetsInfo { get; }
/// <summary>
/// Checks for equality with a PathInfo instance
/// </summary>
/// <param name="other">The PathInfo object to check with</param>
/// <returns>true if both objects are equal, otherwise false</returns>
public bool Equals(PathInfo other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Resolution.Equals(other.Resolution) &&
ColorFormat == other.ColorFormat &&
Position.Equals(other.Position) &&
SpanningOrientation == other.SpanningOrientation &&
IsGDIPrimary == other.IsGDIPrimary &&
IsSLIFocus == other.IsSLIFocus &&
TargetsInfo.SequenceEqual(other.TargetsInfo);
}
/// <summary>
/// Creates and fills a PathInfo object
/// </summary>
/// <returns>The newly created PathInfo object</returns>
public static PathInfo[] GetDisplaysConfig()
{
var configs = DisplayApi.GetDisplayConfig();
var logicalDisplays = configs.Select(info => new PathInfo(info)).ToArray();
configs.DisposeAll();
return logicalDisplays;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(PathInfo left, PathInfo right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(PathInfo left, PathInfo right)
{
return !(left == right);
}
/// <summary>
/// Applies one or more path information configurations
/// </summary>
/// <param name="pathInfos">An array of path information configuration</param>
/// <param name="flags">DisplayConfigFlags flags</param>
public static void SetDisplaysConfig(PathInfo[] pathInfos, DisplayConfigFlags flags)
{
try
{
var configsV2 = pathInfos.Select(config => config.GetPathInfoV2()).Cast<IPathInfo>().ToArray();
DisplayApi.SetDisplayConfig(configsV2, flags);
configsV2.DisposeAll();
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
var configsV1 = pathInfos.Select(config => config.GetPathInfoV1()).Cast<IPathInfo>().ToArray();
DisplayApi.SetDisplayConfig(configsV1, flags);
configsV1.DisposeAll();
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((PathInfo) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = Resolution.GetHashCode();
hashCode = (hashCode * 397) ^ (int) ColorFormat;
hashCode = (hashCode * 397) ^ Position.GetHashCode();
hashCode = (hashCode * 397) ^ (int) SpanningOrientation;
hashCode = (hashCode * 397) ^ IsGDIPrimary.GetHashCode();
hashCode = (hashCode * 397) ^ IsSLIFocus.GetHashCode();
hashCode = (hashCode * 397) ^ (TargetsInfo?.GetHashCode() ?? 0);
return hashCode;
}
}
/// <inheritdoc />
public override string ToString()
{
return $"{Resolution} @ {Position} [{TargetsInfo.Length}]";
}
/// <summary>
/// Creates and fills a GetPathInfoV1 object
/// </summary>
/// <returns>The newly created GetPathInfoV1 object</returns>
public PathInfoV1 GetPathInfoV1()
{
var sourceModeInfo = GetSourceModeInfo();
var pathTargetInfoV1 = GetPathTargetInfoV1Array();
return new PathInfoV1(pathTargetInfoV1, sourceModeInfo, SourceId);
}
/// <summary>
/// Creates and fills a GetPathInfoV2 object
/// </summary>
/// <returns>The newly created GetPathInfoV2 object</returns>
public PathInfoV2 GetPathInfoV2()
{
var sourceModeInfo = GetSourceModeInfo();
var pathTargetInfoV2 = GetPathTargetInfoV2Array();
return new PathInfoV2(pathTargetInfoV2, sourceModeInfo, SourceId);
}
/// <summary>
/// Creates and fills an array of GetPathTargetInfoV1 object
/// </summary>
/// <returns>The newly created array of GetPathTargetInfoV1 objects</returns>
public PathTargetInfoV1[] GetPathTargetInfoV1Array()
{
return TargetsInfo.Select(config => config.GetPathTargetInfoV1()).ToArray();
}
/// <summary>
/// Creates and fills an array of GetPathTargetInfoV2 object
/// </summary>
/// <returns>The newly created array of GetPathTargetInfoV2 objects</returns>
public PathTargetInfoV2[] GetPathTargetInfoV2Array()
{
return TargetsInfo.Select(config => config.GetPathTargetInfoV2()).ToArray();
}
/// <summary>
/// Creates and fills a SourceModeInfo object
/// </summary>
/// <returns>The newly created SourceModeInfo object</returns>
public SourceModeInfo GetSourceModeInfo()
{
return new SourceModeInfo(Resolution, ColorFormat, Position, SpanningOrientation, IsGDIPrimary, IsSLIFocus);
}
}
}

View File

@@ -0,0 +1,304 @@
using System;
using System.Collections.Generic;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.Display;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents a display configuration on a path
/// </summary>
public class PathTargetInfo : IEquatable<PathTargetInfo>
{
private TimingOverride _timingOverride;
/// <summary>
/// Creates a new PathTargetInfo
/// </summary>
/// <param name="info">IPathTargetInfo implamented object</param>
public PathTargetInfo(IPathTargetInfo info)
{
DisplayDevice = new DisplayDevice(info.DisplayId);
if (info.Details.HasValue)
{
Rotation = info.Details.Value.Rotation;
Scaling = info.Details.Value.Scaling;
TVConnectorType = info.Details.Value.ConnectorType;
TVFormat = info.Details.Value.TVFormat;
RefreshRateInMillihertz = info.Details.Value.RefreshRateInMillihertz;
TimingOverride = info.Details.Value.TimingOverride;
IsInterlaced = info.Details.Value.IsInterlaced;
IsClonePrimary = info.Details.Value.IsClonePrimary;
IsClonePanAndScanTarget = info.Details.Value.IsClonePanAndScanTarget;
DisableVirtualModeSupport = info.Details.Value.DisableVirtualModeSupport;
IsPreferredUnscaledTarget = info.Details.Value.IsPreferredUnscaledTarget;
}
if (info is PathTargetInfoV2)
{
WindowsCCDTargetId = ((PathTargetInfoV2) info).WindowsCCDTargetId;
}
}
/// <summary>
/// Creates a new PathTargetInfo
/// </summary>
/// <param name="device">DisplayDevice object</param>
public PathTargetInfo(DisplayDevice device)
{
DisplayDevice = device;
}
/// <summary>
/// Gets or sets the virtual mode support
/// </summary>
public bool DisableVirtualModeSupport { get; set; }
/// <summary>
/// Gets corresponding DisplayDevice
/// </summary>
public DisplayDevice DisplayDevice { get; }
/// <summary>
/// Gets or sets the pan and scan is availability. Valid only when the target is part of clone
/// topology.
/// </summary>
public bool IsClonePanAndScanTarget { get; set; }
/// <summary>
/// Gets or sets the primary display in clone configuration. This is *NOT* GDI Primary.
/// Only one target can be primary per source. If no primary is specified, the first target will automatically be
/// primary.
/// </summary>
public bool IsClonePrimary { get; set; }
/// <summary>
/// Gets or sets the interlaced mode flag, ignored if refreshRate == 0
/// </summary>
public bool IsInterlaced { get; set; }
/// <summary>
/// Gets or sets the preferred unscaled mode of target
/// </summary>
public bool IsPreferredUnscaledTarget { get; set; }
/// <summary>
/// Gets and sets the non-interlaced Refresh Rate of the mode, multiplied by 1000, 0 = ignored
/// This is the value which driver reports to the OS.
/// </summary>
public uint RefreshRateInMillihertz { get; set; }
/// <summary>
/// Gets and sets the rotation setting
/// </summary>
public Rotate Rotation { get; set; }
/// <summary>
/// Gets and sets the scaling setting
/// </summary>
public Scaling Scaling { get; set; }
/// <summary>
/// Gets and sets the custom timing of display
/// Ignored if TimingOverride == TimingOverride.Current
/// </summary>
public TimingOverride TimingOverride
{
get => _timingOverride;
set
{
if (value == TimingOverride.Custom)
{
throw new NVIDIANotSupportedException("Custom timing is not supported yet.");
}
_timingOverride = value;
}
}
/// <summary>
/// Gets and sets the connector type. For TV only, ignored if TVFormat == TVFormat.None.
/// </summary>
public ConnectorType TVConnectorType { get; set; }
/// <summary>
/// Gets and sets the TV format. For TV only, otherwise set to TVFormat.None
/// </summary>
public TVFormat TVFormat { get; set; }
/// <summary>
/// Gets the Windows CCD target ID. Must be present only for non-NVIDIA adapter, for NVIDIA adapter this parameter is
/// ignored.
/// </summary>
public uint WindowsCCDTargetId { get; }
/// <summary>
/// Checks for equality with a PathTargetInfo instance
/// </summary>
/// <param name="other">The PathTargetInfo object to check with</param>
/// <returns>true if both objects are equal, otherwise false</returns>
public bool Equals(PathTargetInfo other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return _timingOverride == other._timingOverride &&
Rotation == other.Rotation &&
Scaling == other.Scaling &&
RefreshRateInMillihertz == other.RefreshRateInMillihertz &&
(TVFormat == TVFormat.None || TVConnectorType == other.TVConnectorType) &&
TVFormat == other.TVFormat &&
DisplayDevice.Equals(other.DisplayDevice) &&
IsInterlaced == other.IsInterlaced &&
IsClonePrimary == other.IsClonePrimary &&
IsClonePanAndScanTarget == other.IsClonePanAndScanTarget &&
DisableVirtualModeSupport == other.DisableVirtualModeSupport &&
IsPreferredUnscaledTarget == other.IsPreferredUnscaledTarget;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(PathTargetInfo left, PathTargetInfo right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(PathTargetInfo left, PathTargetInfo right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((PathTargetInfo) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = (int) _timingOverride;
hashCode = (hashCode * 397) ^ (int) Rotation;
hashCode = (hashCode * 397) ^ (int) Scaling;
hashCode = (hashCode * 397) ^ (int) RefreshRateInMillihertz;
hashCode = (hashCode * 397) ^ (int) TVFormat;
hashCode = (hashCode * 397) ^ (TVFormat != TVFormat.None ? (int) TVConnectorType : 0);
hashCode = (hashCode * 397) ^ (DisplayDevice?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ IsInterlaced.GetHashCode();
hashCode = (hashCode * 397) ^ IsClonePrimary.GetHashCode();
hashCode = (hashCode * 397) ^ IsClonePanAndScanTarget.GetHashCode();
hashCode = (hashCode * 397) ^ DisableVirtualModeSupport.GetHashCode();
hashCode = (hashCode * 397) ^ IsPreferredUnscaledTarget.GetHashCode();
return hashCode;
}
}
/// <inheritdoc />
public override string ToString()
{
var strs = new List<string>
{
DisplayDevice.ToString()
};
if (RefreshRateInMillihertz > 0)
{
strs.Add($"@ {RefreshRateInMillihertz / 1000}hz");
}
if (TVFormat != TVFormat.None)
{
strs.Add($"- TV {TVFormat}");
}
strs.Add(IsInterlaced ? "Interlaced" : "Progressive");
if (Rotation != Rotate.Degree0)
{
strs.Add($"- Rotation: {Rotation}");
}
return string.Join(" ", strs);
}
/// <summary>
/// Creates and fills a PathAdvancedTargetInfo object
/// </summary>
/// <returns>The newly created PathAdvancedTargetInfo object</returns>
public PathAdvancedTargetInfo GetPathAdvancedTargetInfo()
{
if (TVFormat == TVFormat.None)
{
return new PathAdvancedTargetInfo(Rotation, Scaling, RefreshRateInMillihertz, TimingOverride,
IsInterlaced, IsClonePrimary, IsClonePanAndScanTarget, DisableVirtualModeSupport,
IsPreferredUnscaledTarget);
}
return new PathAdvancedTargetInfo(Rotation, Scaling, TVFormat, TVConnectorType, RefreshRateInMillihertz,
TimingOverride, IsInterlaced, IsClonePrimary, IsClonePanAndScanTarget, DisableVirtualModeSupport,
IsPreferredUnscaledTarget);
}
/// <summary>
/// Creates and fills a PathTargetInfoV1 object
/// </summary>
/// <returns>The newly created PathTargetInfoV1 object</returns>
public PathTargetInfoV1 GetPathTargetInfoV1()
{
var pathAdvancedTargetInfo = GetPathAdvancedTargetInfo();
return new PathTargetInfoV1(DisplayDevice.DisplayId, pathAdvancedTargetInfo);
}
/// <summary>
/// Creates and fills a PathTargetInfoV2 object
/// </summary>
/// <returns>The newly created PathTargetInfoV2 object</returns>
public PathTargetInfoV2 GetPathTargetInfoV2()
{
var pathAdvancedTargetInfo = GetPathAdvancedTargetInfo();
return new PathTargetInfoV2(DisplayDevice.DisplayId, WindowsCCDTargetId, pathAdvancedTargetInfo);
}
}
}

View File

@@ -0,0 +1,218 @@
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display;
using NvAPIWrapper.Native.Display.Structures;
using NvAPIWrapper.Native.General.Structures;
using Rectangle = NvAPIWrapper.Native.General.Structures.Rectangle;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Contains information regarding the scan-out buffer settings of a display device
/// </summary>
public class ScanOutInformation
{
internal ScanOutInformation(DisplayDevice displayDevice)
{
DisplayDevice = displayDevice;
}
/// <summary>
/// Gets the clone importance assigned to the target if the target is a cloned view of the SourceDesktopRectangle
/// (0:primary,1 secondary,...).
/// </summary>
public uint CloneImportance
{
get => DisplayApi.GetScanOutConfiguration(DisplayDevice.DisplayId).CloneImportance;
}
/// <summary>
/// Gets the display device that this instance describes
/// </summary>
public DisplayDevice DisplayDevice { get; }
/// <summary>
/// Gets a boolean value indicating if the display device scan out output is warped
/// </summary>
public bool IsDisplayWarped
{
get => DisplayApi.GetScanOutWarpingState(DisplayDevice.DisplayId).IsEnabled;
}
/// <summary>
/// Gets a boolean value indicating if the display device intensity is modified
/// </summary>
public bool IsIntensityModified
{
get => DisplayApi.GetScanOutIntensityState(DisplayDevice.DisplayId).IsEnabled;
}
/// <summary>
/// Gets the operating system display device rectangle in desktop coordinates displayId is scanning out from.
/// </summary>
public Rectangle SourceDesktopRectangle
{
get => DisplayApi.GetScanOutConfiguration(DisplayDevice.DisplayId).SourceDesktopRectangle;
}
/// <summary>
/// Gets the rotation performed between the SourceViewPortRectangle and the TargetViewPortRectangle.
/// </summary>
public Rotate SourceToTargetRotation
{
get => DisplayApi.GetScanOutConfiguration(DisplayDevice.DisplayId).SourceToTargetRotation;
}
/// <summary>
/// Gets the area inside the SourceDesktopRectangle which is scanned out to the display.
/// </summary>
public Rectangle SourceViewPortRectangle
{
get => DisplayApi.GetScanOutConfiguration(DisplayDevice.DisplayId).SourceViewPortRectangle;
}
/// <summary>
/// Gets the vertical size of the active resolution scanned out to the display.
/// </summary>
public uint TargetDisplayHeight
{
get => DisplayApi.GetScanOutConfiguration(DisplayDevice.DisplayId).TargetDisplayHeight;
}
/// <summary>
/// Gets the horizontal size of the active resolution scanned out to the display.
/// </summary>
public uint TargetDisplayWidth
{
get => DisplayApi.GetScanOutConfiguration(DisplayDevice.DisplayId).TargetDisplayWidth;
}
/// <summary>
/// Gets the area inside the rectangle described by targetDisplayWidth/Height SourceViewPortRectangle is scanned out
/// to.
/// </summary>
public Rectangle TargetViewPortRectangle
{
get => DisplayApi.GetScanOutConfiguration(DisplayDevice.DisplayId).TargetViewPortRectangle;
}
/// <summary>
/// Disables the intensity modification on the display device scan-out buffer.
/// </summary>
/// <param name="isSticky">A boolean value that indicates whether the settings will be kept over a reboot.</param>
public void DisableIntensityModifications(out bool isSticky)
{
DisplayApi.SetScanOutIntensity(DisplayDevice.DisplayId, null, out isSticky);
}
/// <summary>
/// Disables the warping of display device scan-out buffer.
/// </summary>
/// <param name="isSticky">A boolean value that indicates whether the settings will be kept over a reboot.</param>
public void DisableWarping(out bool isSticky)
{
var vorticesCount = 0;
DisplayApi.SetScanOutWarping(DisplayDevice.DisplayId, null, ref vorticesCount, out isSticky);
}
/// <summary>
/// Enables the intensity modification on the display device scan-out buffer.
/// </summary>
/// <param name="intensityTexture">The intensity texture to apply to the scan-out buffer.</param>
/// <param name="isSticky">A boolean value that indicates whether the settings will be kept over a reboot.</param>
public void EnableIntensityModifications(IntensityTexture intensityTexture, out bool isSticky)
{
using (
var intensity = new ScanOutIntensityV1(
(uint) intensityTexture.Width,
(uint) intensityTexture.Height,
intensityTexture.ToFloatArray()
)
)
{
DisplayApi.SetScanOutIntensity(DisplayDevice.DisplayId, intensity, out isSticky);
}
}
/// <summary>
/// Enables the intensity modification on the display device scan-out buffer.
/// </summary>
/// <param name="intensityTexture">The intensity texture to apply to the scan-out buffer.</param>
/// <param name="offsetTexture">The offset texture to apply to the scan-out buffer.</param>
/// <param name="isSticky">A boolean value that indicates whether the settings will be kept over a reboot.</param>
public void EnableIntensityModifications(
IntensityTexture intensityTexture,
FloatTexture offsetTexture,
out bool isSticky)
{
using (
var intensity = new ScanOutIntensityV2(
(uint) intensityTexture.Width,
(uint) intensityTexture.Height,
intensityTexture.ToFloatArray(),
(uint) offsetTexture.Channels,
offsetTexture.ToFloatArray()
)
)
{
DisplayApi.SetScanOutIntensity(DisplayDevice.DisplayId, intensity, out isSticky);
}
}
/// <summary>
/// Enables the warping of display device scan-out buffer
/// </summary>
/// <param name="warpingVerticeFormat">The type of warping vortexes.</param>
/// <param name="vortices">An array of warping vortexes.</param>
/// <param name="textureRectangle">The rectangle in desktop coordinates describing the source area for the warping.</param>
/// <param name="isSticky">A boolean value that indicates whether the settings will be kept over a reboot.</param>
// ReSharper disable once TooManyArguments
public void EnableWarping(
WarpingVerticeFormat warpingVerticeFormat,
XYUVRQVortex[] vortices,
Rectangle textureRectangle,
out bool isSticky)
{
using (
var warping = new ScanOutWarpingV1(
warpingVerticeFormat,
vortices.SelectMany(vortex => vortex.AsFloatArray()).ToArray(),
textureRectangle
)
)
{
var vorticesCount = vortices.Length;
DisplayApi.SetScanOutWarping(DisplayDevice.DisplayId, warping, ref vorticesCount, out isSticky);
}
}
/// <summary>
/// Queries the current state of one of the various scan-out composition parameters.
/// </summary>
/// <param name="parameter">The scan-out composition parameter.</param>
/// <param name="additionalValue">The additional value included with the parameter value.</param>
/// <returns>The scan-out composition parameter value.</returns>
public ScanOutCompositionParameterValue GetCompositionParameterValue(
ScanOutCompositionParameter parameter,
out float additionalValue)
{
return DisplayApi.GetScanOutCompositionParameter(DisplayDevice.DisplayId, parameter, out additionalValue);
}
/// <summary>
/// Sets the current state of one of the various scan-out composition parameters.
/// </summary>
/// <param name="parameter">The scan-out composition parameter.</param>
/// <param name="parameterValue">The scan-out composition parameter value.</param>
/// <param name="additionalValue">The additional value included with the parameter value.</param>
public void SetCompositionParameterValue(
ScanOutCompositionParameter parameter,
ScanOutCompositionParameterValue parameterValue,
float additionalValue)
{
DisplayApi.SetScanOutCompositionParameter(DisplayDevice.DisplayId, parameter, parameterValue,
ref additionalValue);
}
}
}

View File

@@ -0,0 +1,150 @@
using System;
using System.Linq;
using NvAPIWrapper.GPU;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Display.Structures;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents an unattached display
/// </summary>
public class UnAttachedDisplay : IEquatable<UnAttachedDisplay>
{
/// <summary>
/// Creates a new UnAttachedDisplay
/// </summary>
/// <param name="handle">Handle of the unattached display device</param>
public UnAttachedDisplay(UnAttachedDisplayHandle handle)
{
Handle = handle;
}
/// <summary>
/// Creates a new UnAttachedDisplay
/// </summary>
/// <param name="displayName">Name of the unattached display device</param>
public UnAttachedDisplay(string displayName)
{
Handle = DisplayApi.GetAssociatedUnAttachedNvidiaDisplayHandle(displayName);
}
/// <summary>
/// Gets display handle
/// </summary>
public UnAttachedDisplayHandle Handle { get; }
/// <summary>
/// Gets display name
/// </summary>
public string Name
{
get => DisplayApi.GetUnAttachedAssociatedDisplayName(Handle);
}
/// <summary>
/// Gets corresponding physical GPU
/// </summary>
public PhysicalGPU PhysicalGPU
{
get => new PhysicalGPU(GPUApi.GetPhysicalGPUFromUnAttachedDisplay(Handle));
}
/// <summary>
/// Checks for equality with a UnAttachedDisplay instance
/// </summary>
/// <param name="other">The Display object to check with</param>
/// <returns>true if both objects are equal, otherwise false</returns>
public bool Equals(UnAttachedDisplay other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Handle.Equals(other.Handle);
}
/// <summary>
/// This function returns all unattached NVIDIA displays
/// Note: Display handles can get invalidated on a modeset.
/// </summary>
/// <returns>An array of Display objects</returns>
public static UnAttachedDisplay[] GetUnAttachedDisplays()
{
return
DisplayApi.EnumNvidiaUnAttachedDisplayHandle().Select(handle => new UnAttachedDisplay(handle))
.ToArray();
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(UnAttachedDisplay left, UnAttachedDisplay right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(UnAttachedDisplay left, UnAttachedDisplay right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((UnAttachedDisplay) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return Name;
}
/// <summary>
/// Creates a new active attached display from this unattached display
/// At least one GPU must be present in the system and running an NVIDIA display driver.
/// </summary>
/// <returns>An active attached display</returns>
public Display CreateDisplay()
{
return new Display(DisplayApi.CreateDisplayFromUnAttachedDisplay(Handle));
}
}
}

View File

@@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
namespace NvAPIWrapper.Display
{
/// <summary>
/// Represents a XYUVRQ scan-out warping vortex
/// </summary>
public class XYUVRQVortex : IEquatable<XYUVRQVortex>
{
/// <summary>
/// Creates a new instance of <see cref="XYUVRQVortex" />.
/// </summary>
/// <param name="x">The target view port mesh horizontal coordinate</param>
/// <param name="y">The target view port mesh vertical coordinate</param>
/// <param name="u">The desktop view port texture horizontal coordinate</param>
/// <param name="v">The desktop view port texture vertical coordinate</param>
/// <param name="r">The 3D warp perspective R factor</param>
/// <param name="q">The 3D warp perspective Q factor</param>
// ReSharper disable once TooManyDependencies
public XYUVRQVortex(int x, int y, int u, int v, float r, float q)
{
X = x;
Y = y;
U = u;
V = v;
R = r;
Q = q;
}
/// <summary>
/// 3D warp perspective Q factor
/// </summary>
public float Q { get; }
/// <summary>
/// 3D warp perspective R factor
/// </summary>
public float R { get; }
/// <summary>
/// Desktop view port texture horizontal coordinate
/// </summary>
public int U { get; }
/// <summary>
/// Desktop view port texture vertical coordinate
/// </summary>
public int V { get; }
/// <summary>
/// Target view port mesh horizontal coordinate
/// </summary>
public int X { get; }
/// <summary>
/// Target view port mesh vertical coordinate
/// </summary>
public int Y { get; }
/// <inheritdoc />
public bool Equals(XYUVRQVortex other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Math.Abs(Q - other.Q) < 0.0001 &&
Math.Abs(R - other.R) < 0.0001 &&
U == other.U &&
V == other.V &&
X == other.X &&
Y == other.Y;
}
/// <summary>
/// Parses an array of floats and returns the corresponding <see cref="XYUVRQVortex" />s.
/// </summary>
/// <param name="floats">The array of float representing one or more <see cref="XYUVRQVortex" />s.</param>
/// <returns>Instances of <see cref="XYUVRQVortex" />.</returns>
public static IEnumerable<XYUVRQVortex> FromFloatArray(float[] floats)
{
for (var i = 0; i + 6 <= floats.Length; i += 6)
{
yield return new XYUVRQVortex(
(int) floats[i],
(int) floats[i + 1],
(int) floats[i + 2],
(int) floats[i + 3],
floats[i + 4],
floats[i + 5]
);
}
}
/// <summary>
/// Compares two instance of <see cref="XYUVRQVortex" /> for equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns><see langword="true" /> if both instances are equal, otherwise <see langword="false" /></returns>
public static bool operator ==(XYUVRQVortex left, XYUVRQVortex right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
/// <summary>
/// Compares two instance of <see cref="XYUVRQVortex" /> for in-equality.
/// </summary>
/// <param name="left">The first instance.</param>
/// <param name="right">The second instance.</param>
/// <returns><see langword="true" /> if both instances are not equal, otherwise <see langword="false" /></returns>
public static bool operator !=(XYUVRQVortex left, XYUVRQVortex right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as XYUVRQVortex);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = Q.GetHashCode();
hashCode = (hashCode * 397) ^ R.GetHashCode();
hashCode = (hashCode * 397) ^ U;
hashCode = (hashCode * 397) ^ V;
hashCode = (hashCode * 397) ^ X;
hashCode = (hashCode * 397) ^ Y;
return hashCode;
}
}
/// <summary>
/// Returns this instance of <see cref="XYUVRQVortex"/> as a float array.
/// </summary>
/// <returns>An array of float values representing this instance of <see cref="XYUVRQVortex"/>.</returns>
public float[] AsFloatArray()
{
return new[] {X, Y, U, V, R, Q};
}
}
}

View File

@@ -0,0 +1,30 @@
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the accelerated graphics connection
/// </summary>
public class AGPInformation
{
internal AGPInformation(int aperture, int currentRate)
{
ApertureInMB = aperture;
CurrentRate = currentRate;
}
/// <summary>
/// Gets AGP aperture in megabytes
/// </summary>
public int ApertureInMB { get; }
/// <summary>
/// Gets current AGP Rate (0 = AGP not present, 1 = 1x, 2 = 2x, etc.)
/// </summary>
public int CurrentRate { get; }
/// <inheritdoc />
public override string ToString()
{
return $"AGP Aperture: {ApertureInMB}MB, Current Rate: {CurrentRate}x";
}
}
}

View File

@@ -0,0 +1,201 @@
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the ECC memory
/// </summary>
public class ECCMemoryInformation
{
internal ECCMemoryInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the number of aggregated ECC memory double bit errors
/// </summary>
public ulong AggregatedDoubleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).AggregatedErrors.DoubleBitErrors;
}
}
/// <summary>
/// Gets the number of aggregated ECC memory single bit errors
/// </summary>
public ulong AggregatedSingleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).AggregatedErrors.SingleBitErrors;
}
}
/// <summary>
/// Gets the ECC memory configuration in regard to how changes are applied
/// </summary>
public ECCConfiguration Configuration
{
get
{
try
{
return GPUApi.GetECCStatusInfo(PhysicalGPU.Handle).ConfigurationOptions;
}
catch
{
return ECCConfiguration.NotSupported;
}
}
}
/// <summary>
/// Gets the number of current ECC memory double bit errors
/// </summary>
public ulong CurrentDoubleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).CurrentErrors.DoubleBitErrors;
}
}
/// <summary>
/// Gets the number of current ECC memory single bit errors
/// </summary>
public ulong CurrentSingleBitErrors
{
get
{
if (!IsSupported || !IsEnabled)
{
return 0;
}
return GPUApi.GetECCErrorInfo(PhysicalGPU.Handle).CurrentErrors.SingleBitErrors;
}
}
/// <summary>
/// Gets a boolean value indicating if ECC memory error correction is enabled
/// </summary>
public bool IsEnabled
{
get => IsSupported &&
GPUApi.GetECCStatusInfo(PhysicalGPU.Handle).IsEnabled &&
GPUApi.GetECCConfigurationInfo(PhysicalGPU.Handle).IsEnabled;
}
/// <summary>
/// Gets a boolean value indicating if ECC memory is enabled by default
/// </summary>
public bool IsEnabledByDefault
{
get => IsSupported &&
GPUApi.GetECCConfigurationInfo(PhysicalGPU.Handle).IsEnabledByDefault;
}
/// <summary>
/// Gets a boolean value indicating if ECC memory is supported and available
/// </summary>
public bool IsSupported
{
get
{
try
{
return GPUApi.GetECCStatusInfo(PhysicalGPU.Handle).IsSupported;
}
catch
{
return false;
}
}
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public override string ToString()
{
if (!IsSupported)
{
return "[Not Supported]";
}
if (!IsEnabled)
{
return "[Disabled]";
}
return
$"{CurrentSingleBitErrors}, {CurrentDoubleBitErrors} ({AggregatedSingleBitErrors}, {AggregatedDoubleBitErrors})";
}
/// <summary>
/// Clears aggregated error counters.
/// </summary>
public void ClearAggregatedErrors()
{
GPUApi.ResetECCErrorInfo(PhysicalGPU.Handle, false, true);
}
/// <summary>
/// Clears current error counters.
/// </summary>
public void ClearCurrentErrors()
{
GPUApi.ResetECCErrorInfo(PhysicalGPU.Handle, true, false);
}
/// <summary>
/// Clears all error counters.
/// </summary>
public void ClearErrors()
{
GPUApi.ResetECCErrorInfo(PhysicalGPU.Handle, true, true);
}
/// <summary>
/// Disables ECC memory error correction.
/// </summary>
/// <param name="immediate">A boolean value to indicate if this change should get applied immediately</param>
public void Disable(bool immediate)
{
GPUApi.SetECCConfiguration(PhysicalGPU.Handle, false, immediate);
}
/// <summary>
/// Enables ECC memory error correction.
/// </summary>
/// <param name="immediate">A boolean value to indicate if this change should get applied immediately</param>
public void Enable(bool immediate)
{
GPUApi.SetECCConfiguration(PhysicalGPU.Handle, true, immediate);
}
}
}

View File

@@ -0,0 +1,115 @@
using NvAPIWrapper.Native;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains physical GPU architect information
/// </summary>
public class GPUArchitectInformation
{
internal GPUArchitectInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets total number of cores defined for this GPU, or zero for older architectures
/// </summary>
public int NumberOfCores
{
get => (int) GPUApi.GetGPUCoreCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of graphics processing clusters (aka GPU Partitions)
/// </summary>
public int NumberOfGPC
{
get => (int) GPUApi.GetPartitionCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of render output units
/// </summary>
public int NumberOfROPs
{
get => (int) GPUApi.GetROPCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of shader pipelines
/// </summary>
public int NumberOfShaderPipelines
{
get => (int) GPUApi.GetShaderPipeCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of shader sub pipelines
/// </summary>
public int NumberOfShaderSubPipelines
{
get => (int) GPUApi.GetShaderSubPipeCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the number of video processing engines
/// </summary>
public int NumberOfVPEs
{
get => (int) GPUApi.GetVPECount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the GPU revision number (should be displayed as a hex string)
/// </summary>
public int Revision
{
get => (int) GPUApi.GetArchitectInfo(PhysicalGPU.Handle).Revision;
}
/// <summary>
/// Gets the GPU short name (aka Codename)
/// </summary>
public string ShortName
{
get => GPUApi.GetShortName(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the total number of streaming multiprocessors
/// </summary>
public int TotalNumberOfSMs
{
get => (int) GPUApi.GetTotalSMCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the total number of streaming processors
/// </summary>
public int TotalNumberOfSPs
{
get => (int) GPUApi.GetTotalSPCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the total number of texture processing clusters
/// </summary>
public int TotalNumberOfTPCs
{
get => (int) GPUApi.GetTotalTPCCount(PhysicalGPU.Handle);
}
/// <inheritdoc />
public override string ToString()
{
return $"[{ShortName} REV{Revision:X}] Cores: {NumberOfCores}";
}
}
}

View File

@@ -0,0 +1,118 @@
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the GPU bus
/// </summary>
public class GPUBusInformation
{
internal GPUBusInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets accelerated graphics port information
/// </summary>
public AGPInformation AGPInformation
{
get
{
if (BusType != GPUBusType.AGP)
{
return null;
}
return new AGPInformation(
GPUApi.GetAGPAperture(PhysicalGPU.Handle),
GPUApi.GetCurrentAGPRate(PhysicalGPU.Handle)
);
}
}
/// <summary>
/// Gets the bus identification
/// </summary>
public int BusId
{
get => GPUApi.GetBusId(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the bus slot identification
/// </summary>
public int BusSlot
{
get => GPUApi.GetBusSlotId(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the the bus type
/// </summary>
public GPUBusType BusType
{
get => GPUApi.GetBusType(PhysicalGPU.Handle);
}
/// <summary>
/// Gets number of PCIe lanes being used for the PCIe interface downstream
/// </summary>
public int CurrentPCIeLanes
{
get
{
if (BusType == GPUBusType.PCIExpress)
{
return GPUApi.GetCurrentPCIEDownStreamWidth(PhysicalGPU.Handle);
}
return 0;
}
}
/// <summary>
/// Gets GPU interrupt number
/// </summary>
public int IRQ
{
get => GPUApi.GetIRQ(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the PCI identifiers
/// </summary>
public PCIIdentifiers PCIIdentifiers
{
get
{
if (BusType == GPUBusType.FPCI || BusType == GPUBusType.PCI || BusType == GPUBusType.PCIExpress)
{
GPUApi.GetPCIIdentifiers(
PhysicalGPU.Handle,
out var deviceId,
out var subSystemId,
out var revisionId,
out var extDeviceId
);
return new PCIIdentifiers(deviceId, subSystemId, revisionId, (int) extDeviceId);
}
return null;
}
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public override string ToString()
{
return $"[{BusType}] Bus #{BusId}, Slot #{BusSlot}";
}
}
}

View File

@@ -0,0 +1,130 @@
using System;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a GPU cooler entry
/// </summary>
public class GPUCooler
{
internal GPUCooler(int coolerId, PrivateCoolerSettingsV1.CoolerSetting coolerSetting, int currentRPM = -1)
{
CoolerId = coolerId;
CurrentLevel = (int) coolerSetting.CurrentLevel;
DefaultMinimumLevel = (int) coolerSetting.DefaultMinimumLevel;
DefaultMaximumLevel = (int) coolerSetting.DefaultMaximumLevel;
CurrentMinimumLevel = (int) coolerSetting.CurrentMinimumLevel;
CurrentMaximumLevel = (int) coolerSetting.CurrentMaximumLevel;
CoolerType = coolerSetting.CoolerType;
CoolerController = coolerSetting.CoolerController;
DefaultPolicy = coolerSetting.DefaultPolicy;
CurrentPolicy = coolerSetting.CurrentPolicy;
Target = coolerSetting.Target;
ControlMode = coolerSetting.ControlMode;
CurrentFanSpeedInRPM = currentRPM;
}
// ReSharper disable once TooManyDependencies
internal GPUCooler(
PrivateFanCoolersInfoV1.FanCoolersInfoEntry infoEntry,
PrivateFanCoolersStatusV1.FanCoolersStatusEntry statusEntry,
PrivateFanCoolersControlV1.FanCoolersControlEntry controlEntry)
{
if (infoEntry.CoolerId != statusEntry.CoolerId || statusEntry.CoolerId != controlEntry.CoolerId)
{
throw new ArgumentException("Passed arguments are meant to be for different coolers.");
}
CoolerId = (int) statusEntry.CoolerId;
CurrentLevel = (int) statusEntry.CurrentLevel;
DefaultMinimumLevel = (int) statusEntry.CurrentMinimumLevel;
DefaultMaximumLevel = (int) statusEntry.CurrentMaximumLevel;
CurrentMinimumLevel = (int) statusEntry.CurrentMinimumLevel;
CurrentMaximumLevel = (int) statusEntry.CurrentMaximumLevel;
CoolerType = CoolerType.Fan;
CoolerController = CoolerController.Internal;
DefaultPolicy = CoolerPolicy.None;
CurrentPolicy = controlEntry.ControlMode == FanCoolersControlMode.Manual
? CoolerPolicy.Manual
: CoolerPolicy.None;
Target = CoolerTarget.All;
ControlMode = CoolerControlMode.Variable;
CurrentFanSpeedInRPM = (int) statusEntry.CurrentRPM;
}
/// <summary>
/// Gets the cooler control mode
/// </summary>
public CoolerControlMode ControlMode { get; }
/// <summary>
/// Gets the cooler controller
/// </summary>
public CoolerController CoolerController { get; }
/// <summary>
/// Gets the cooler identification number or index
/// </summary>
public int CoolerId { get; }
/// <summary>
/// Gets the cooler type
/// </summary>
public CoolerType CoolerType { get; }
/// <summary>
/// Gets the GPU fan speed in revolutions per minute
/// </summary>
public int CurrentFanSpeedInRPM { get; }
/// <summary>
/// Gets the cooler current level in percentage
/// </summary>
public int CurrentLevel { get; }
/// <summary>
/// Gets the cooler current maximum level in percentage
/// </summary>
public int CurrentMaximumLevel { get; }
/// <summary>
/// Gets the cooler current minimum level in percentage
/// </summary>
public int CurrentMinimumLevel { get; }
/// <summary>
/// Gets the cooler current policy
/// </summary>
public CoolerPolicy CurrentPolicy { get; }
/// <summary>
/// Gets the cooler default maximum level in percentage
/// </summary>
public int DefaultMaximumLevel { get; }
/// <summary>
/// Gets the cooler default minimum level in percentage
/// </summary>
public int DefaultMinimumLevel { get; }
/// <summary>
/// Gets the cooler default policy
/// </summary>
public CoolerPolicy DefaultPolicy { get; }
/// <summary>
/// Gets the cooler target
/// </summary>
public CoolerTarget Target { get; }
/// <inheritdoc />
public override string ToString()
{
return $"[{CoolerId} @ {CoolerController}] {Target}: {CurrentLevel}%";
}
}
}

View File

@@ -0,0 +1,340 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the GPU coolers and current fan speed
/// </summary>
public class GPUCoolerInformation
{
internal GPUCoolerInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
// TODO: Add Support For Pascal Only Policy Table Method
// TODO: GPUApi.GetCoolerPolicyTable & GPUApi.SetCoolerPolicyTable & GPUApi.RestoreCoolerPolicyTable
// TODO: Better support of ClientFanCoolers set of APIs
}
/// <summary>
/// Gets a list of all available coolers along with their current settings and status
/// </summary>
public IEnumerable<GPUCooler> Coolers
{
get
{
PrivateCoolerSettingsV1? settings = null;
try
{
settings = GPUApi.GetCoolerSettings(PhysicalGPU.Handle);
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
if (settings != null)
{
for (var i = 0; i < settings.Value.CoolerSettings.Length; i++)
{
if (i == 0)
{
var currentRPM = -1;
try
{
currentRPM = (int)GPUApi.GetTachReading(PhysicalGPU.Handle);
}
catch (NVIDIAApiException)
{
// ignored
}
if (currentRPM >= 0)
{
yield return new GPUCooler(
i,
settings.Value.CoolerSettings[i],
currentRPM
);
continue;
}
}
yield return new GPUCooler(
i,
settings.Value.CoolerSettings[i]
);
}
yield break;
}
PrivateFanCoolersStatusV1? status = null;
PrivateFanCoolersInfoV1? info = null;
PrivateFanCoolersControlV1? control = null;
try
{
status = GPUApi.GetClientFanCoolersStatus(PhysicalGPU.Handle);
info = GPUApi.GetClientFanCoolersInfo(PhysicalGPU.Handle);
control = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
if (status != null && info != null && control != null)
{
for (var i = 0; i < status.Value.FanCoolersStatusEntries.Length; i++)
{
if (info.Value.FanCoolersInfoEntries.Length > i &&
control.Value.FanCoolersControlEntries.Length > i)
{
yield return new GPUCooler(
info.Value.FanCoolersInfoEntries[i],
status.Value.FanCoolersStatusEntries[i],
control.Value.FanCoolersControlEntries[i]
);
}
}
yield break;
}
throw new NVIDIAApiException(Status.NotSupported);
}
}
/// <summary>
/// Gets the GPU fan speed in revolutions per minute
/// </summary>
public int CurrentFanSpeedInRPM
{
get
{
try
{
return (int) GPUApi.GetTachReading(PhysicalGPU.Handle);
}
catch
{
return Coolers.FirstOrDefault(cooler => cooler.Target == CoolerTarget.All)?.CurrentFanSpeedInRPM ??
0;
}
}
}
/// <summary>
/// Gets the current fan speed in percentage if available
/// </summary>
public int CurrentFanSpeedLevel
{
get
{
try
{
return (int) GPUApi.GetCurrentFanSpeedLevel(PhysicalGPU.Handle);
}
catch
{
return Coolers.FirstOrDefault(cooler => cooler.Target == CoolerTarget.All)?.CurrentLevel ?? 0;
}
}
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public override string ToString()
{
return $"{CurrentFanSpeedInRPM} RPM ({CurrentFanSpeedLevel}%)";
}
/// <summary>
/// Resets all cooler settings to default.
/// </summary>
public void RestoreCoolerSettingsToDefault()
{
RestoreCoolerSettingsToDefault(Coolers.Select(cooler => cooler.CoolerId).ToArray());
}
/// <summary>
/// Resets one or more cooler settings to default.
/// </summary>
/// <param name="coolerIds">The cooler identification numbers (indexes) to reset their settings to default.</param>
public void RestoreCoolerSettingsToDefault(params int[] coolerIds)
{
var availableCoolerIds = Coolers.Select(cooler => cooler.CoolerId).ToArray();
if (coolerIds.Any(i => !availableCoolerIds.Contains(i)))
{
throw new ArgumentException("Invalid cooler identification number provided.", nameof(coolerIds));
}
try
{
GPUApi.RestoreCoolerSettings(PhysicalGPU.Handle, coolerIds.Select(i => (uint) i).ToArray());
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
var currentControl = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
var newControl = new PrivateFanCoolersControlV1(
currentControl.FanCoolersControlEntries.Select(
entry => coolerIds.Contains((int) entry.CoolerId)
? new PrivateFanCoolersControlV1.FanCoolersControlEntry(
entry.CoolerId,
FanCoolersControlMode.Auto
)
: entry
)
.ToArray(),
currentControl.UnknownUInt
);
GPUApi.SetClientFanCoolersControl(PhysicalGPU.Handle, newControl);
}
/// <summary>
/// Changes a cooler settings by modifying the policy and the current level
/// </summary>
/// <param name="coolerId">The cooler identification number (index) to change the settings.</param>
/// <param name="policy">The new cooler policy.</param>
/// <param name="newLevel">The new cooler level. Valid only if policy is set to manual.</param>
// ReSharper disable once TooManyDeclarations
public void SetCoolerSettings(int coolerId, CoolerPolicy policy, int newLevel)
{
if (Coolers.All(cooler => cooler.CoolerId != coolerId))
{
throw new ArgumentException("Invalid cooler identification number provided.", nameof(coolerId));
}
try
{
GPUApi.SetCoolerLevels(
PhysicalGPU.Handle,
(uint) coolerId,
new PrivateCoolerLevelsV1(new[]
{
new PrivateCoolerLevelsV1.CoolerLevel(policy, (uint) newLevel)
}
),
1
);
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
var currentControl = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
var newControl = new PrivateFanCoolersControlV1(
currentControl.FanCoolersControlEntries.Select(
entry => entry.CoolerId == coolerId
? new PrivateFanCoolersControlV1.FanCoolersControlEntry(
entry.CoolerId,
policy == CoolerPolicy.Manual
? FanCoolersControlMode.Manual
: FanCoolersControlMode.Auto,
policy == CoolerPolicy.Manual ? (uint)newLevel : 0u)
: entry
)
.ToArray(),
currentControl.UnknownUInt
);
GPUApi.SetClientFanCoolersControl(PhysicalGPU.Handle, newControl);
}
/// <summary>
/// Changes a cooler setting by modifying the policy
/// </summary>
/// <param name="coolerId">The cooler identification number (index) to change the settings.</param>
/// <param name="policy">The new cooler policy.</param>
// ReSharper disable once TooManyDeclarations
public void SetCoolerSettings(int coolerId, CoolerPolicy policy)
{
if (Coolers.All(cooler => cooler.CoolerId != coolerId))
{
throw new ArgumentException("Invalid cooler identification number provided.", nameof(coolerId));
}
try
{
GPUApi.SetCoolerLevels(
PhysicalGPU.Handle,
(uint) coolerId,
new PrivateCoolerLevelsV1(new[]
{
new PrivateCoolerLevelsV1.CoolerLevel(policy)
}
),
1
);
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.NotSupported)
{
throw;
}
}
var currentControl = GPUApi.GetClientFanCoolersControl(PhysicalGPU.Handle);
var newControl = new PrivateFanCoolersControlV1(
currentControl.FanCoolersControlEntries.Select(
entry => entry.CoolerId == coolerId
? new PrivateFanCoolersControlV1.FanCoolersControlEntry(
entry.CoolerId,
policy == CoolerPolicy.Manual
? FanCoolersControlMode.Manual
: FanCoolersControlMode.Auto)
: entry
)
.ToArray(),
currentControl.UnknownUInt
);
GPUApi.SetClientFanCoolersControl(PhysicalGPU.Handle, newControl);
}
/// <summary>
/// Changes a cooler settings by modifying the policy to manual and sets a new level
/// </summary>
/// <param name="coolerId">The cooler identification number (index) to change the settings.</param>
/// <param name="newLevel">The new cooler level.</param>
public void SetCoolerSettings(int coolerId, int newLevel)
{
SetCoolerSettings(coolerId, CoolerPolicy.Manual, newLevel);
}
}
}

View File

@@ -0,0 +1,222 @@
using System;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information regarding the available and total memory as well as the type of memory and other information
/// regarding the GPU RAM and frame buffer
/// </summary>
public class GPUMemoryInformation : IDisplayDriverMemoryInfo
{
internal GPUMemoryInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the frame buffer bandwidth
/// </summary>
public int FrameBufferBandwidth
{
get
{
GPUApi.GetFrameBufferWidthAndLocation(PhysicalGPU.Handle, out var width, out _);
return (int) width;
}
}
/// <summary>
/// Gets the frame buffer location index
/// </summary>
public int FrameBufferLocation
{
get
{
GPUApi.GetFrameBufferWidthAndLocation(PhysicalGPU.Handle, out _, out var location);
return (int) location;
}
}
/// <summary>
/// Gets the internal clock to bus clock factor based on the type of RAM
/// </summary>
public int InternalClockToBusClockFactor
{
get => GetMemoryBusClockFactor(RAMType);
}
/// <summary>
/// Gets the internal clock to transfer rate factor based on the type of RAM
/// </summary>
public int InternalClockToTransferRateFactor
{
get => GetMemoryTransferRateFactor(RAMType);
}
/// <summary>
/// Gets GPU physical frame buffer size in KB. This does NOT include any system RAM that may be dedicated for use by
/// the GPU.
/// </summary>
public int PhysicalFrameBufferSizeInkB
{
get => GPUApi.GetPhysicalFrameBufferSize(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the number of memory banks
/// </summary>
public uint RAMBanks
{
get => GPUApi.GetRAMBankCount(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the memory bus width
/// </summary>
public uint RAMBusWidth
{
get => GPUApi.GetRAMBusWidth(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the memory maker (brand)
/// </summary>
public GPUMemoryMaker RAMMaker
{
get => GPUApi.GetRAMMaker(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the memory type
/// </summary>
public GPUMemoryType RAMType
{
get => GPUApi.GetRAMType(PhysicalGPU.Handle);
}
/// <summary>
/// Gets virtual size of frame-buffer in KB for this GPU. This includes the physical RAM plus any system RAM that has
/// been dedicated for use by the GPU.
/// </summary>
public int VirtualFrameBufferSizeInkB
{
get => GPUApi.GetVirtualFrameBufferSize(PhysicalGPU.Handle);
}
/// <inheritdoc />
public uint AvailableDedicatedVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).AvailableDedicatedVideoMemoryInkB;
}
/// <inheritdoc />
public uint CurrentAvailableDedicatedVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).CurrentAvailableDedicatedVideoMemoryInkB;
}
/// <inheritdoc />
public uint DedicatedVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).DedicatedVideoMemoryInkB;
}
/// <inheritdoc />
public uint SharedSystemMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).SharedSystemMemoryInkB;
}
/// <inheritdoc />
public uint SystemVideoMemoryInkB
{
get => GPUApi.GetMemoryInfo(PhysicalGPU.Handle).SystemVideoMemoryInkB;
}
/// <summary>
/// Gets the memory bus clock to internal memory clock factor
/// </summary>
/// <param name="memoryType"></param>
/// <returns>The value of X in X(InternalMemoryClock)=(BusMemoryClock)</returns>
public static int GetMemoryBusClockFactor(GPUMemoryType memoryType)
{
switch (memoryType)
{
case GPUMemoryType.SDRAM:
// Bus Clocks Per Internal Clock = 1
return 1;
case GPUMemoryType.DDR1:
case GPUMemoryType.DDR2:
case GPUMemoryType.DDR3:
case GPUMemoryType.GDDR2:
case GPUMemoryType.GDDR3:
case GPUMemoryType.GDDR4:
case GPUMemoryType.LPDDR2:
case GPUMemoryType.GDDR5:
case GPUMemoryType.GDDR5X:
// Bus Clocks Per Internal Clock = 2
return 2;
default:
throw new ArgumentOutOfRangeException(nameof(memoryType));
}
}
/// <summary>
/// Gets the number of transfers per internal memory clock factor
/// </summary>
/// <param name="memoryType"></param>
/// <returns>The value of X in X(InternalMemoryClock)=(OperationsPerSecond)</returns>
public static int GetMemoryTransferRateFactor(GPUMemoryType memoryType)
{
switch (memoryType)
{
case GPUMemoryType.SDRAM:
// Transfers Per Internal Clock = 1
return 1;
case GPUMemoryType.DDR1:
case GPUMemoryType.DDR2:
case GPUMemoryType.DDR3:
case GPUMemoryType.GDDR2:
case GPUMemoryType.GDDR3:
case GPUMemoryType.GDDR4:
case GPUMemoryType.LPDDR2:
// Transfers Per Internal Clock = 1
return 2;
case GPUMemoryType.GDDR5:
// Transfers Per Internal Clock = 2
return 4;
case GPUMemoryType.GDDR5X:
// Transfers Per Internal Clock = 4
return 8;
default:
throw new ArgumentOutOfRangeException(nameof(memoryType));
}
}
/// <inheritdoc />
public override string ToString()
{
return
$"[{RAMMaker} {RAMType}] Total: {AvailableDedicatedVideoMemoryInkB:N0} kB - Available: {CurrentAvailableDedicatedVideoMemoryInkB:N0} kB";
}
}
}

View File

@@ -0,0 +1,264 @@
using System;
using NvAPIWrapper.Display;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a single GPU output
/// </summary>
public class GPUOutput : IEquatable<GPUOutput>
{
internal GPUOutput(OutputId outputId, PhysicalGPUHandle gpuHandle)
{
OutputId = outputId;
OutputType = !gpuHandle.IsNull ? GPUApi.GetOutputType(gpuHandle, outputId) : OutputType.Unknown;
PhysicalGPU = new PhysicalGPU(gpuHandle);
}
internal GPUOutput(OutputId outputId, PhysicalGPU gpu)
: this(outputId, gpu?.Handle ?? PhysicalGPUHandle.DefaultHandle)
{
PhysicalGPU = gpu;
}
/// <summary>
/// Gets the corresponding Digital Vibrance Control information
/// </summary>
public DVCInformation DigitalVibranceControl
{
get => new DVCInformation(OutputId);
}
/// <summary>
/// Gets the corresponding HUE information
/// </summary>
public HUEInformation HUEControl
{
get => new HUEInformation(OutputId);
}
/// <summary>
/// Gets the output identification as a single bit unsigned integer
/// </summary>
public OutputId OutputId { get; }
/// <summary>
/// Gets the output type
/// </summary>
public OutputType OutputType { get; }
/// <summary>
/// Gets the corresponding physical GPU
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <inheritdoc />
public bool Equals(GPUOutput other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return PhysicalGPU.Equals(other.PhysicalGPU) && OutputId == other.OutputId;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(GPUOutput left, GPUOutput right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(GPUOutput left, GPUOutput right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((GPUOutput) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
return ((PhysicalGPU != null ? PhysicalGPU.GetHashCode() : 0) * 397) ^ (int) OutputId;
}
}
/// <inheritdoc />
public override string ToString()
{
return $"{OutputId} {OutputType} @ {PhysicalGPU}";
}
/// <summary>
/// Overrides the refresh rate on this output.
/// The new refresh rate can be applied right away or deferred to be applied with the next OS
/// mode-set.
/// The override is good for only one mode-set (regardless whether it's deferred or immediate).
/// </summary>
/// <param name="refreshRate">The refresh rate to be applied.</param>
/// <param name="isDeferred">
/// A boolean value indicating if the refresh rate override should be deferred to the next OS
/// mode-set.
/// </param>
public void OverrideRefreshRate(float refreshRate, bool isDeferred = false)
{
DisplayApi.SetRefreshRateOverride(OutputId, refreshRate, isDeferred);
}
/// <summary>
/// Reads data from the I2C bus
/// </summary>
/// <param name="portId">The port id on which device is connected</param>
/// <param name="useDDCPort">A boolean value indicating that the DDC port should be used instead of the communication port</param>
/// <param name="deviceAddress">The device I2C slave address</param>
/// <param name="registerAddress">The target I2C register address</param>
/// <param name="readDataLength">The length of the buffer to allocate for the read operation.</param>
/// <param name="speed">The target speed of the transaction in kHz</param>
public byte[] ReadI2C(
byte? portId,
bool useDDCPort,
byte deviceAddress,
byte[] registerAddress,
uint readDataLength,
I2CSpeed speed = I2CSpeed.Default
)
{
try
{
// ReSharper disable once InconsistentNaming
var i2cInfoV3 = new I2CInfoV3(
OutputId,
portId,
useDDCPort,
deviceAddress,
registerAddress,
readDataLength,
speed
);
return PhysicalGPU.ReadI2C(i2cInfoV3);
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.IncompatibleStructureVersion || portId != null)
{
throw;
}
// ignore
}
// ReSharper disable once InconsistentNaming
var i2cInfoV2 = new I2CInfoV2(
OutputId,
useDDCPort,
deviceAddress,
registerAddress,
readDataLength,
speed
);
return PhysicalGPU.ReadI2C(i2cInfoV2);
}
/// <summary>
/// Writes data to the I2C bus
/// </summary>
/// <param name="portId">The port id on which device is connected</param>
/// <param name="useDDCPort">A boolean value indicating that the DDC port should be used instead of the communication port</param>
/// <param name="deviceAddress">The device I2C slave address</param>
/// <param name="registerAddress">The target I2C register address</param>
/// <param name="data">The payload data</param>
/// <param name="speed">The target speed of the transaction in kHz</param>
public void WriteI2C(
byte? portId,
bool useDDCPort,
byte deviceAddress,
byte[] registerAddress,
byte[] data,
I2CSpeed speed = I2CSpeed.Default
)
{
try
{
// ReSharper disable once InconsistentNaming
var i2cInfoV3 = new I2CInfoV3(
OutputId,
portId,
useDDCPort,
deviceAddress,
registerAddress,
data,
speed
);
PhysicalGPU.WriteI2C(i2cInfoV3);
return;
}
catch (NVIDIAApiException e)
{
if (e.Status != Status.IncompatibleStructureVersion || portId != null)
{
throw;
}
// ignore
}
// ReSharper disable once InconsistentNaming
var i2cInfoV2 = new I2CInfoV2(
OutputId,
useDDCPort,
deviceAddress,
registerAddress,
data,
speed
);
PhysicalGPU.WriteI2C(i2cInfoV2);
}
}
}

View File

@@ -0,0 +1,124 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information regarding the GPU performance control and limitations
/// </summary>
public class GPUPerformanceControl
{
internal GPUPerformanceControl(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the current active performance limitation
/// </summary>
public PerformanceLimit CurrentActiveLimit
{
get => GPUApi.PerformancePoliciesGetStatus(PhysicalGPU.Handle).PerformanceLimit;
}
/// <summary>
/// Gets the current performance decrease reason
/// </summary>
public PerformanceDecreaseReason CurrentPerformanceDecreaseReason
{
get => GPUApi.GetPerformanceDecreaseInfo(PhysicalGPU.Handle);
}
/// <summary>
/// Gets a boolean value indicating if no load limit is supported with this GPU
/// </summary>
public bool IsNoLoadLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsNoLoadLimitSupported;
}
/// <summary>
/// Gets a boolean value indicating if power limit is supported with this GPU
/// </summary>
public bool IsPowerLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsPowerLimitSupported;
}
/// <summary>
/// Gets a boolean value indicating if temperature limit is supported with this GPU
/// </summary>
public bool IsTemperatureLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsTemperatureLimitSupported;
}
/// <summary>
/// Gets a boolean value indicating if voltage limit is supported with this GPU
/// </summary>
public bool IsVoltageLimitSupported
{
get => GPUApi.PerformancePoliciesGetInfo(PhysicalGPU.Handle).IsVoltageLimitSupported;
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets information regarding possible power limit policies and their acceptable range
/// </summary>
public IEnumerable<GPUPowerLimitInfo> PowerLimitInformation
{
get
{
return GPUApi.ClientPowerPoliciesGetInfo(PhysicalGPU.Handle).PowerPolicyInfoEntries
.Select(entry => new GPUPowerLimitInfo(entry));
}
}
/// <summary>
/// Gets the current active power limit policies
/// </summary>
public IEnumerable<GPUPowerLimitPolicy> PowerLimitPolicies
{
get
{
// TODO: GPUApi.ClientPowerPoliciesSetStatus();
return GPUApi.ClientPowerPoliciesGetStatus(PhysicalGPU.Handle).PowerPolicyStatusEntries
.Select(entry => new GPUPowerLimitPolicy(entry));
}
}
/// <summary>
/// Gets information regarding possible thermal limit policies and their acceptable range
/// </summary>
public IEnumerable<GPUThermalLimitInfo> ThermalLimitInformation
{
get
{
return GPUApi.GetThermalPoliciesInfo(PhysicalGPU.Handle).ThermalPoliciesInfoEntries
.Select(entry => new GPUThermalLimitInfo(entry));
}
}
/// <summary>
/// Gets the current active thermal limit policies
/// </summary>
public IEnumerable<GPUThermalLimitPolicy> ThermalLimitPolicies
{
get
{
// TODO: GPUApi.SetThermalPoliciesStatus();
return GPUApi.GetThermalPoliciesStatus(PhysicalGPU.Handle).ThermalPoliciesStatusEntries
.Select(entry => new GPUThermalLimitPolicy(entry));
}
}
}
}

View File

@@ -0,0 +1,70 @@
using System.Linq;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a performance state
/// </summary>
public class GPUPerformanceState
{
// ReSharper disable once TooManyDependencies
internal GPUPerformanceState(
int index,
IPerformanceState20 performanceState,
IPerformanceStates20ClockEntry[] statesClockEntries,
IPerformanceStates20VoltageEntry[] baseVoltageEntries,
PCIeInformation pcieInformation)
{
StateIndex = index;
StateId = performanceState.StateId;
IsReadOnly = !performanceState.IsEditable;
Clocks = statesClockEntries.Select(entry => new GPUPerformanceStateClock(entry)).ToArray();
Voltages = baseVoltageEntries.Select(entry => new GPUPerformanceStateVoltage(entry)).ToArray();
PCIeInformation = pcieInformation;
}
/// <summary>
/// Gets a list of clocks associated with this performance state
/// </summary>
public GPUPerformanceStateClock[] Clocks { get; }
/// <summary>
/// Gets a boolean value indicating if this performance state is readonly
/// </summary>
public bool IsReadOnly { get; }
/// <summary>
/// Gets the PCI-e information regarding this performance state.
/// </summary>
public PCIeInformation PCIeInformation { get; }
/// <summary>
/// Gets the performance state identification
/// </summary>
public PerformanceStateId StateId { get; }
/// <summary>
/// Gets the state index
/// </summary>
public int StateIndex { get; }
/// <summary>
/// Gets a list of voltages associated with this performance state
/// </summary>
public GPUPerformanceStateVoltage[] Voltages { get; }
/// <inheritdoc />
public override string ToString()
{
if (IsReadOnly)
{
return $"{StateId} (ReadOnly)";
}
return StateId.ToString();
}
}
}

View File

@@ -0,0 +1,99 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a performance state clock settings
/// </summary>
public class GPUPerformanceStateClock
{
internal GPUPerformanceStateClock(IPerformanceStates20ClockEntry states20ClockEntry)
{
ClockDomain = states20ClockEntry.DomainId;
IsReadOnly = !states20ClockEntry.IsEditable;
ClockDeltaInkHz = states20ClockEntry.FrequencyDeltaInkHz.DeltaValue;
ClockDeltaRangeInkHz = new GPUPerformanceStateValueRange(
states20ClockEntry.FrequencyDeltaInkHz.DeltaRange.Minimum,
states20ClockEntry.FrequencyDeltaInkHz.DeltaRange.Maximum
);
if (states20ClockEntry.ClockType == PerformanceStates20ClockType.Range)
{
CurrentClockInkHz = new GPUPerformanceStateValueRange(
states20ClockEntry.FrequencyRange.MinimumFrequencyInkHz,
states20ClockEntry.FrequencyRange.MaximumFrequencyInkHz
);
BaseClockInkHz = new GPUPerformanceStateValueRange(
CurrentClockInkHz.Minimum - ClockDeltaInkHz,
CurrentClockInkHz.Maximum - ClockDeltaInkHz
);
DependentVoltageDomain = states20ClockEntry.FrequencyRange.VoltageDomainId;
DependentVoltageRangeInMicroVolt = new GPUPerformanceStateValueRange(
states20ClockEntry.FrequencyRange.MinimumVoltageInMicroVolt,
states20ClockEntry.FrequencyRange.MaximumVoltageInMicroVolt
);
}
else
{
CurrentClockInkHz = new GPUPerformanceStateValueRange(
states20ClockEntry.SingleFrequency.FrequencyInkHz
);
BaseClockInkHz = new GPUPerformanceStateValueRange(
CurrentClockInkHz.Minimum - ClockDeltaInkHz
);
DependentVoltageDomain = PerformanceVoltageDomain.Undefined;
DependentVoltageRangeInMicroVolt = null;
}
}
/// <summary>
/// Gets the base clock frequency in kHz
/// </summary>
public GPUPerformanceStateValueRange BaseClockInkHz { get; }
/// <summary>
/// Gets the clock frequency delta in kHz
/// </summary>
public int ClockDeltaInkHz { get; }
/// <summary>
/// Gets the clock frequency delta range in kHz
/// </summary>
public GPUPerformanceStateValueRange ClockDeltaRangeInkHz { get; }
/// <summary>
/// Gets the clock domain
/// </summary>
public PublicClockDomain ClockDomain { get; }
/// <summary>
/// Gets the current clock frequency in kHz
/// </summary>
public GPUPerformanceStateValueRange CurrentClockInkHz { get; }
/// <summary>
/// Gets the dependent voltage domain
/// </summary>
public PerformanceVoltageDomain DependentVoltageDomain { get; }
/// <summary>
/// Gets the dependent voltage range in uV
/// </summary>
public GPUPerformanceStateValueRange DependentVoltageRangeInMicroVolt { get; }
/// <summary>
/// Gets a boolean value indicating if this clock setting is readonly
/// </summary>
public bool IsReadOnly { get; }
/// <inheritdoc />
public override string ToString()
{
var title = IsReadOnly ? $"{ClockDomain} (ReadOnly)" : ClockDomain.ToString();
return
$"{title}: {BaseClockInkHz} + ({ClockDeltaInkHz}) = {CurrentClockInkHz}";
}
}
}

View File

@@ -0,0 +1,115 @@
using System;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents an integer value range
/// </summary>
public class GPUPerformanceStateValueRange : IEquatable<GPUPerformanceStateValueRange>
{
/// <summary>
/// Creates a new instance of <see cref="GPUPerformanceStateValueRange" />.
/// </summary>
/// <param name="min">The lower bound of the range.</param>
/// <param name="max">The upper bound of the range.</param>
public GPUPerformanceStateValueRange(long min, long max)
{
Minimum = min;
Maximum = max;
}
/// <summary>
/// Creates a new single value instance of <see cref="GPUPerformanceStateValueRange" />.
/// </summary>
/// <param name="value">The only value in the range</param>
public GPUPerformanceStateValueRange(long value)
{
Minimum = value;
Maximum = value;
}
/// <summary>
/// Gets the upper bound of the inclusive range
/// </summary>
public long Maximum { get; }
/// <summary>
/// Gets the lower bound of the inclusive range
/// </summary>
public long Minimum { get; }
/// <inheritdoc />
public bool Equals(GPUPerformanceStateValueRange other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Maximum == other.Maximum && Minimum == other.Minimum;
}
/// <summary>
/// Checks two instances of <see cref="GPUPerformanceStateValueRange" /> for equality.
/// </summary>
/// <param name="left">The left side of the comparison.</param>
/// <param name="right">The right side of the comparison.</param>
/// <returns>true if instances are equal, otherwise false</returns>
public static bool operator ==(GPUPerformanceStateValueRange left, GPUPerformanceStateValueRange right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
/// <summary>
/// Checks two instances of <see cref="GPUPerformanceStateValueRange" /> for inequality.
/// </summary>
/// <param name="left">The left side of the comparison.</param>
/// <param name="right">The right side of the comparison.</param>
/// <returns>true if instances are in-equal, otherwise false</returns>
public static bool operator !=(GPUPerformanceStateValueRange left, GPUPerformanceStateValueRange right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as GPUPerformanceStateValueRange);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
return ((int) Maximum * 397) ^ (int) Minimum;
}
}
/// <inheritdoc />
public override string ToString()
{
if (Minimum == Maximum)
{
return $"({Minimum})";
}
return $"[({Minimum}) - ({Maximum})]";
}
}
}

View File

@@ -0,0 +1,65 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a performance state voltage settings
/// </summary>
public class GPUPerformanceStateVoltage
{
internal GPUPerformanceStateVoltage(IPerformanceStates20VoltageEntry states20BaseVoltageEntry)
{
VoltageDomain = states20BaseVoltageEntry.DomainId;
IsReadOnly = !states20BaseVoltageEntry.IsEditable;
CurrentVoltageInMicroVolt = states20BaseVoltageEntry.ValueInMicroVolt;
VoltageDeltaInMicroVolt = states20BaseVoltageEntry.ValueDeltaInMicroVolt.DeltaValue;
BaseVoltageInMicroVolt = (int) (CurrentVoltageInMicroVolt - VoltageDeltaInMicroVolt);
VoltageDeltaRangeInMicroVolt = new GPUPerformanceStateValueRange(
states20BaseVoltageEntry.ValueDeltaInMicroVolt.DeltaRange.Minimum,
states20BaseVoltageEntry.ValueDeltaInMicroVolt.DeltaRange.Maximum
);
}
/// <summary>
/// Gets the base voltage in uV
/// </summary>
public int BaseVoltageInMicroVolt { get; }
/// <summary>
/// Gets the current voltage in uV
/// </summary>
public uint CurrentVoltageInMicroVolt { get; }
/// <summary>
/// Gets a boolean value indicating if this voltage is readonly
/// </summary>
public bool IsReadOnly { get; }
/// <summary>
/// Gets the voltage delta in uV
/// </summary>
public int VoltageDeltaInMicroVolt { get; }
/// <summary>
/// Gets the voltage delta range in uV
/// </summary>
public GPUPerformanceStateValueRange VoltageDeltaRangeInMicroVolt { get; }
/// <summary>
/// Gets the voltage domain
/// </summary>
public PerformanceVoltageDomain VoltageDomain { get; }
/// <inheritdoc />
public override string ToString()
{
var title = IsReadOnly ? $"{VoltageDomain} (ReadOnly)" : VoltageDomain.ToString();
return
$"{title}: ({BaseVoltageInMicroVolt}) + ({VoltageDeltaInMicroVolt}) = ({CurrentVoltageInMicroVolt})";
}
}
}

View File

@@ -0,0 +1,107 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds the retrieved performance states information
/// </summary>
public class GPUPerformanceStatesInformation
{
internal GPUPerformanceStatesInformation(
IPerformanceStates20Info states20Info,
PerformanceStateId currentPerformanceStateId,
PrivatePCIeInfoV2? pciInformation)
{
IsReadOnly = !states20Info.IsEditable;
GlobalVoltages = states20Info.GeneralVoltages
.Select(entry => new GPUPerformanceStateVoltage(entry))
.ToArray();
var clocks = states20Info.Clocks;
var baseVoltages = states20Info.Voltages;
PerformanceStates = states20Info.PerformanceStates.Select((state20, i) =>
{
PCIeInformation statePCIeInfo = null;
if (pciInformation != null && pciInformation.Value.PCIePerformanceStateInfos.Length > i)
{
statePCIeInfo = new PCIeInformation(pciInformation.Value.PCIePerformanceStateInfos[i]);
}
return new GPUPerformanceState(
i,
state20,
clocks[state20.StateId],
baseVoltages[state20.StateId],
statePCIeInfo
);
}).ToArray();
CurrentPerformanceState =
PerformanceStates.FirstOrDefault(performanceState =>
performanceState.StateId == currentPerformanceStateId);
}
/// <summary>
/// Gets the currently active performance state
/// </summary>
public GPUPerformanceState CurrentPerformanceState { get; }
/// <summary>
/// Gets a list of global voltage settings
/// </summary>
public GPUPerformanceStateVoltage[] GlobalVoltages { get; }
/// <summary>
/// Gets a boolean value indicating if performance states are readonly
/// </summary>
public bool IsReadOnly { get; }
/// <summary>
/// Gets a list of all available performance states
/// </summary>
public GPUPerformanceState[] PerformanceStates { get; }
/// <inheritdoc />
public override string ToString()
{
if (PerformanceStates.Length == 0)
{
return "No Performance State Available";
}
return string.Join(
", ",
PerformanceStates
.Select(
state =>
{
var attributes = new List<string>();
if (state.IsReadOnly)
{
attributes.Add("ReadOnly");
}
if (CurrentPerformanceState.StateId == state.StateId)
{
attributes.Add("Active");
}
if (attributes.Any())
{
return $"{state.StateId} ({string.Join(" - ", attributes)})";
}
return state.StateId.ToString();
})
);
}
}
}

View File

@@ -0,0 +1,70 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a possible power limit policy and its acceptable range
/// </summary>
public class GPUPowerLimitInfo
{
internal GPUPowerLimitInfo(PrivatePowerPoliciesInfoV1.PowerPolicyInfoEntry powerPolicyInfoEntry)
{
PerformanceStateId = powerPolicyInfoEntry.PerformanceStateId;
MinimumPowerInPCM = powerPolicyInfoEntry.MinimumPowerInPCM;
DefaultPowerInPCM = powerPolicyInfoEntry.DefaultPowerInPCM;
MaximumPowerInPCM = powerPolicyInfoEntry.MaximumPowerInPCM;
}
/// <summary>
/// Gets the default policy target power in per cent mille (PCM)
/// </summary>
public uint DefaultPowerInPCM { get; }
/// <summary>
/// Gets the default policy target power in percentage
/// </summary>
public float DefaultPowerInPercent
{
get => DefaultPowerInPCM / 1000f;
}
/// <summary>
/// Gets the maximum possible policy target power in per cent mille (PCM)
/// </summary>
public uint MaximumPowerInPCM { get; }
/// <summary>
/// Gets the maximum possible policy target power in percentage
/// </summary>
public float MaximumPowerInPercent
{
get => MaximumPowerInPCM / 1000f;
}
/// <summary>
/// Gets the minimum possible policy target power in per cent mille (PCM)
/// </summary>
public uint MinimumPowerInPCM { get; }
/// <summary>
/// Gets the minimum possible policy target power in percentage
/// </summary>
public float MinimumPowerInPercent
{
get => MinimumPowerInPCM / 1000f;
}
/// <summary>
/// Gets the corresponding performance state identification
/// </summary>
public PerformanceStateId PerformanceStateId { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"[{PerformanceStateId}] Default: {DefaultPowerInPercent}% - Range: ({MinimumPowerInPercent}% - {MaximumPowerInPercent}%)";
}
}
}

View File

@@ -0,0 +1,41 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a currently active power limit policy
/// </summary>
public class GPUPowerLimitPolicy
{
internal GPUPowerLimitPolicy(PrivatePowerPoliciesStatusV1.PowerPolicyStatusEntry powerPolicyStatusEntry)
{
PerformanceStateId = powerPolicyStatusEntry.PerformanceStateId;
PowerTargetInPCM = powerPolicyStatusEntry.PowerTargetInPCM;
}
/// <summary>
/// Gets the corresponding performance state identification
/// </summary>
public PerformanceStateId PerformanceStateId { get; }
/// <summary>
/// Gets the current policy target power in per cent mille (PCM)
/// </summary>
public uint PowerTargetInPCM { get; }
/// <summary>
/// Gets the current policy target power in percentage
/// </summary>
public float PowerTargetInPercent
{
get => PowerTargetInPCM / 1000f;
}
/// <inheritdoc />
public override string ToString()
{
return $"{PerformanceStateId} Target: {PowerTargetInPercent}%";
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding current power topology and their current power usage
/// </summary>
public class GPUPowerTopologyInformation
{
internal GPUPowerTopologyInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the current power topology entries
/// </summary>
public IEnumerable<GPUPowerTopologyStatus> PowerTopologyEntries
{
get
{
return GPUApi.ClientPowerTopologyGetStatus(PhysicalGPU.Handle).PowerPolicyStatusEntries
.Select(entry => new GPUPowerTopologyStatus(entry));
}
}
}
}

View File

@@ -0,0 +1,42 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about a power domain usage
/// </summary>
public class GPUPowerTopologyStatus
{
internal GPUPowerTopologyStatus(
PrivatePowerTopologiesStatusV1.PowerTopologiesStatusEntry powerTopologiesStatusEntry)
{
Domain = powerTopologiesStatusEntry.Domain;
PowerUsageInPCM = powerTopologiesStatusEntry.PowerUsageInPCM;
}
/// <summary>
/// Gets the power usage domain
/// </summary>
public PowerTopologyDomain Domain { get; }
/// <summary>
/// Gets the current power usage in per cent mille (PCM)
/// </summary>
public uint PowerUsageInPCM { get; }
/// <summary>
/// Gets the current power usage in percentage
/// </summary>
public float PowerUsageInPercent
{
get => PowerUsageInPCM / 1000f;
}
/// <inheritdoc />
public override string ToString()
{
return $"[{Domain}] {PowerUsageInPercent}%";
}
}
}

View File

@@ -0,0 +1,42 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding the available thermal sensors and current thermal level of a GPU
/// </summary>
public class GPUThermalInformation
{
internal GPUThermalInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the current thermal level of the GPU
/// </summary>
public int CurrentThermalLevel
{
get => (int) GPUApi.GetCurrentThermalLevel(PhysicalGPU.Handle);
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets the list of available thermal sensors
/// </summary>
public IEnumerable<GPUThermalSensor> ThermalSensors
{
get
{
return GPUApi.GetThermalSettings(PhysicalGPU.Handle).Sensors
.Select((sensor, i) => new GPUThermalSensor(i, sensor));
}
}
}
}

View File

@@ -0,0 +1,47 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a possible thermal limit policy and its acceptable range
/// </summary>
public class GPUThermalLimitInfo
{
internal GPUThermalLimitInfo(PrivateThermalPoliciesInfoV2.ThermalPoliciesInfoEntry policiesInfoEntry)
{
Controller = policiesInfoEntry.Controller;
MinimumTemperature = policiesInfoEntry.MinimumTemperature;
DefaultTemperature = policiesInfoEntry.DefaultTemperature;
MaximumTemperature = policiesInfoEntry.MaximumTemperature;
}
/// <summary>
/// Gets the policy's thermal controller
/// </summary>
public ThermalController Controller { get; }
/// <summary>
/// Gets the default policy target temperature in degree Celsius
/// </summary>
public int DefaultTemperature { get; }
/// <summary>
/// Gets the maximum possible policy target temperature in degree Celsius
/// </summary>
public int MaximumTemperature { get; }
/// <summary>
/// Gets the minimum possible policy target temperature in degree Celsius
/// </summary>
public int MinimumTemperature { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"[{Controller}] Default: {DefaultTemperature}°C - Range: ({MinimumTemperature}°C - {MaximumTemperature}°C)";
}
}
}

View File

@@ -0,0 +1,40 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information regarding a currently active temperature limit policy
/// </summary>
public class GPUThermalLimitPolicy
{
internal GPUThermalLimitPolicy(PrivateThermalPoliciesStatusV2.ThermalPoliciesStatusEntry thermalPoliciesEntry)
{
Controller = thermalPoliciesEntry.Controller;
PerformanceStateId = thermalPoliciesEntry.PerformanceStateId;
TargetTemperature = thermalPoliciesEntry.TargetTemperature;
}
/// <summary>
/// Gets the policy's thermal controller
/// </summary>
public ThermalController Controller { get; }
/// <summary>
/// Gets the corresponding performance state identification
/// </summary>
public PerformanceStateId PerformanceStateId { get; }
/// <summary>
/// Gets the current policy target temperature in degree Celsius
/// </summary>
public int TargetTemperature { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"{PerformanceStateId} [{Controller}] Target: {TargetTemperature}°C";
}
}
}

View File

@@ -0,0 +1,48 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a thermal sensor
/// </summary>
public class GPUThermalSensor : IThermalSensor
{
internal GPUThermalSensor(int sensorId, IThermalSensor thermalSensor)
{
SensorId = sensorId;
Controller = thermalSensor.Controller;
DefaultMinimumTemperature = thermalSensor.DefaultMinimumTemperature;
DefaultMaximumTemperature = thermalSensor.DefaultMaximumTemperature;
CurrentTemperature = thermalSensor.CurrentTemperature;
Target = thermalSensor.Target;
}
/// <summary>
/// Gets the sensor identification number or index
/// </summary>
public int SensorId { get; set; }
/// <inheritdoc />
public ThermalController Controller { get; }
/// <inheritdoc />
public int CurrentTemperature { get; }
/// <inheritdoc />
public int DefaultMaximumTemperature { get; }
/// <inheritdoc />
public int DefaultMinimumTemperature { get; }
/// <inheritdoc />
public ThermalSettingsTarget Target { get; }
/// <inheritdoc />
public override string ToString()
{
return
$"[{Target} @ {Controller}] Current: {CurrentTemperature}°C - Default Range: [({DefaultMinimumTemperature}°C) , ({DefaultMaximumTemperature}°C)]";
}
}
}

View File

@@ -0,0 +1,33 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information about a utilization domain
/// </summary>
public class GPUUsageDomainStatus
{
internal GPUUsageDomainStatus(UtilizationDomain domain, IUtilizationDomainInfo utilizationDomainInfo)
{
Domain = domain;
Percentage = (int) utilizationDomainInfo.Percentage;
}
/// <summary>
/// Gets the utilization domain that this instance describes
/// </summary>
public UtilizationDomain Domain { get; }
/// <summary>
/// Gets the percentage of time where the domain is considered busy in the last 1 second interval.
/// </summary>
public int Percentage { get; }
/// <inheritdoc />
public override string ToString()
{
return $"[{Domain}] {Percentage}%";
}
}
}

View File

@@ -0,0 +1,99 @@
using System.Collections.Generic;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Holds information about the GPU utilization domains
/// </summary>
public class GPUUsageInformation
{
internal GPUUsageInformation(PhysicalGPU physicalGPU)
{
PhysicalGPU = physicalGPU;
}
/// <summary>
/// Gets the Bus interface (BUS) utilization
/// </summary>
public GPUUsageDomainStatus BusInterface
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.BusInterface);
}
/// <summary>
/// Gets the frame buffer (FB) utilization
/// </summary>
public GPUUsageDomainStatus FrameBuffer
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.FrameBuffer);
}
/// <summary>
/// Gets the graphic engine (GPU) utilization
/// </summary>
public GPUUsageDomainStatus GPU
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.GPU);
}
/// <summary>
/// Gets a boolean value indicating if the dynamic performance states is enabled
/// </summary>
public bool IsDynamicPerformanceStatesEnabled
{
get => GPUApi.GetDynamicPerformanceStatesInfoEx(PhysicalGPU.Handle).IsDynamicPerformanceStatesEnabled;
}
/// <summary>
/// Gets the physical GPU that this instance describes
/// </summary>
public PhysicalGPU PhysicalGPU { get; }
/// <summary>
/// Gets all valid utilization domains and information
/// </summary>
public IEnumerable<GPUUsageDomainStatus> UtilizationDomainsStatus
{
get
{
try
{
var dynamicPerformanceStates = GPUApi.GetDynamicPerformanceStatesInfoEx(PhysicalGPU.Handle);
if (dynamicPerformanceStates.IsDynamicPerformanceStatesEnabled)
{
return dynamicPerformanceStates.Domains
.Select(pair => new GPUUsageDomainStatus(pair.Key, pair.Value));
}
}
catch
{
// ignored
}
return GPUApi.GetUsages(PhysicalGPU.Handle).Domains
.Select(pair => new GPUUsageDomainStatus(pair.Key, pair.Value));
}
}
/// <summary>
/// Gets the Video engine (VID) utilization
/// </summary>
public GPUUsageDomainStatus VideoEngine
{
get => UtilizationDomainsStatus.FirstOrDefault(status => status.Domain == UtilizationDomain.VideoEngine);
}
/// <summary>
/// Enables dynamic performance states
/// </summary>
public void EnableDynamicPerformanceStates()
{
GPUApi.EnableDynamicPStates(PhysicalGPU.Handle);
}
}
}

View File

@@ -0,0 +1,119 @@
using System;
using System.Linq;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a logical NVIDIA GPU
/// </summary>
public class LogicalGPU : IEquatable<LogicalGPU>
{
/// <summary>
/// Creates a new LogicalGPU
/// </summary>
/// <param name="handle">Logical GPU handle</param>
public LogicalGPU(LogicalGPUHandle handle)
{
Handle = handle;
}
/// <summary>
/// Gets a list of all corresponding physical GPUs
/// </summary>
public PhysicalGPU[] CorrespondingPhysicalGPUs
{
get
{
return GPUApi.GetPhysicalGPUsFromLogicalGPU(Handle).Select(handle => new PhysicalGPU(handle)).ToArray();
}
}
/// <summary>
/// Gets the logical GPU handle
/// </summary>
public LogicalGPUHandle Handle { get; }
/// <inheritdoc />
public bool Equals(LogicalGPU other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Handle.Equals(other.Handle);
}
/// <summary>
/// Gets all logical GPUs
/// </summary>
/// <returns>An array of logical GPUs</returns>
public static LogicalGPU[] GetLogicalGPUs()
{
return GPUApi.EnumLogicalGPUs().Select(handle => new LogicalGPU(handle)).ToArray();
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(LogicalGPU left, LogicalGPU right)
{
return right?.Equals(left) ?? ReferenceEquals(left, null);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(LogicalGPU left, LogicalGPU right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((LogicalGPU) obj);
}
/// <inheritdoc />
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return
$"Logical GPU [{CorrespondingPhysicalGPUs.Length}] {{{string.Join(", ", CorrespondingPhysicalGPUs.Select(gpu => gpu.FullName).ToArray())}}}";
}
}
}

View File

@@ -0,0 +1,114 @@
using System;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the PCI connection
/// </summary>
public class PCIIdentifiers : IEquatable<PCIIdentifiers>
{
// ReSharper disable once TooManyDependencies
internal PCIIdentifiers(uint deviceId, uint subSystemId, uint revisionId, int externalDeviceId = 0)
{
DeviceId = deviceId;
SubSystemId = subSystemId;
RevisionId = revisionId;
if (externalDeviceId > 0)
{
ExternalDeviceId = (ushort) externalDeviceId;
}
else
{
ExternalDeviceId = (ushort) (deviceId >> 16);
}
VendorId = (ushort) ((DeviceId << 16) >> 16);
}
/// <summary>
/// Gets the internal PCI device identifier
/// </summary>
public uint DeviceId { get; }
/// <summary>
/// Gets the external PCI device identifier
/// </summary>
public ushort ExternalDeviceId { get; }
/// <summary>
/// Gets the internal PCI device-specific revision identifier
/// </summary>
public uint RevisionId { get; }
/// <summary>
/// Gets the internal PCI subsystem identifier
/// </summary>
public uint SubSystemId { get; }
/// <summary>
/// Gets the vendor identification calculated from internal device identification
/// </summary>
public ushort VendorId { get; }
/// <inheritdoc />
public bool Equals(PCIIdentifiers other)
{
return DeviceId == other.DeviceId &&
SubSystemId == other.SubSystemId &&
RevisionId == other.RevisionId;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(PCIIdentifiers left, PCIIdentifiers right)
{
return left.Equals(right);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(PCIIdentifiers left, PCIIdentifiers right)
{
return !left.Equals(right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is PCIIdentifiers identifiers && Equals(identifiers);
}
/// <inheritdoc />
public override int GetHashCode()
{
unchecked
{
var hashCode = (int) DeviceId;
hashCode = (hashCode * 397) ^ (int) SubSystemId;
hashCode = (hashCode * 397) ^ (int) RevisionId;
return hashCode;
}
}
/// <inheritdoc />
public override string ToString()
{
return $"PCI\\VEN_{VendorId:X}&DEV_{ExternalDeviceId:X}&SUBSYS_{SubSystemId:X}&REV_{RevisionId:X}";
}
}
}

View File

@@ -0,0 +1,67 @@
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the PCI-e connection
/// </summary>
public class PCIeInformation
{
internal PCIeInformation(PrivatePCIeInfoV2.PCIePerformanceStateInfo stateInfo)
{
TransferRateInMTps = stateInfo.TransferRateInMTps;
Generation = stateInfo.Generation;
Lanes = stateInfo.Lanes;
Version = stateInfo.Version;
}
/// <summary>
/// Gets the PCI-e generation
/// </summary>
public PCIeGeneration Generation { get; }
/// <summary>
/// Gets the PCI-e down stream lanes
/// </summary>
public uint Lanes { get; }
/// <summary>
/// Gets the PCIe transfer rate in Mega Transfers per Second
/// </summary>
public uint TransferRateInMTps { get; }
/// <summary>
/// Gets the PCI-e version
/// </summary>
public PCIeGeneration Version { get; }
/// <inheritdoc />
public override string ToString()
{
var v = "Unknown";
switch (Version)
{
case PCIeGeneration.PCIe1:
v = "PCIe 1.0";
break;
case PCIeGeneration.PCIe1Minor1:
v = "PCIe 1.1";
break;
case PCIeGeneration.PCIe2:
v = "PCIe 2.0";
break;
case PCIeGeneration.PCIe3:
v = "PCIe 3.0";
break;
}
return $"{v} x{Lanes} - {TransferRateInMTps} MTps";
}
}
}

View File

@@ -0,0 +1,559 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using NvAPIWrapper.Display;
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.Exceptions;
using NvAPIWrapper.Native.General;
using NvAPIWrapper.Native.GPU;
using NvAPIWrapper.Native.GPU.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces.GPU;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Represents a physical NVIDIA GPU
/// </summary>
public class PhysicalGPU : IEquatable<PhysicalGPU>
{
/// <summary>
/// Creates a new PhysicalGPU
/// </summary>
/// <param name="handle">Physical GPU handle</param>
public PhysicalGPU(PhysicalGPUHandle handle)
{
Handle = handle;
UsageInformation = new GPUUsageInformation(this);
ThermalInformation = new GPUThermalInformation(this);
BusInformation = new GPUBusInformation(this);
ArchitectInformation = new GPUArchitectInformation(this);
MemoryInformation = new GPUMemoryInformation(this);
CoolerInformation = new GPUCoolerInformation(this);
ECCMemoryInformation = new ECCMemoryInformation(this);
PerformanceControl = new GPUPerformanceControl(this);
PowerTopologyInformation = new GPUPowerTopologyInformation(this);
}
/// <summary>
/// Gets all active outputs of this GPU
/// </summary>
public GPUOutput[] ActiveOutputs
{
get
{
var outputs = new List<GPUOutput>();
var allOutputs = GPUApi.GetActiveOutputs(Handle);
foreach (OutputId outputId in Enum.GetValues(typeof(OutputId)))
{
if (outputId != OutputId.Invalid && allOutputs.HasFlag(outputId))
{
outputs.Add(new GPUOutput(outputId, this));
}
}
return outputs.ToArray();
}
}
/// <summary>
/// Gets GPU architect information
/// </summary>
public GPUArchitectInformation ArchitectInformation { get; }
/// <summary>
/// Gets GPU base clock frequencies
/// </summary>
public IClockFrequencies BaseClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.BaseClock));
}
/// <summary>
/// Gets GPU video BIOS information
/// </summary>
public VideoBIOS Bios
{
get => new VideoBIOS(
GPUApi.GetVBIOSRevision(Handle),
(int) GPUApi.GetVBIOSOEMRevision(Handle),
GPUApi.GetVBIOSVersionString(Handle)
);
}
/// <summary>
/// Gets the board information
/// </summary>
public BoardInfo Board
{
get
{
try
{
return GPUApi.GetBoardInfo(Handle);
}
catch (NVIDIAApiException ex)
{
if (ex.Status == Status.NotSupported)
{
return default;
}
throw;
}
}
}
/// <summary>
/// Gets GPU boost clock frequencies
/// </summary>
public IClockFrequencies BoostClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.BoostClock));
}
/// <summary>
/// Gets GPU bus information
/// </summary>
public GPUBusInformation BusInformation { get; }
/// <summary>
/// Gets GPU coolers information
/// </summary>
public GPUCoolerInformation CoolerInformation { get; }
/// <summary>
/// Gets corresponding logical GPU
/// </summary>
public LogicalGPU CorrespondingLogicalGPU
{
get => new LogicalGPU(GPUApi.GetLogicalGPUFromPhysicalGPU(Handle));
}
/// <summary>
/// Gets GPU current clock frequencies
/// </summary>
public IClockFrequencies CurrentClockFrequencies
{
get => GPUApi.GetAllClockFrequencies(Handle, new ClockFrequenciesV2(ClockType.CurrentClock));
}
/// <summary>
/// Gets the driver model number for this GPU
/// </summary>
public uint DriverModel
{
get => GPUApi.GetDriverModel(Handle);
}
/// <summary>
/// Gets GPU ECC memory information
/// </summary>
public ECCMemoryInformation ECCMemoryInformation { get; }
/// <summary>
/// Gets the chipset foundry
/// </summary>
public GPUFoundry Foundry
{
get => GPUApi.GetFoundry(Handle);
}
/// <summary>
/// Gets GPU full name
/// </summary>
public string FullName
{
get => GPUApi.GetFullName(Handle);
}
/// <summary>
/// Gets the GPU identification number
/// </summary>
public uint GPUId
{
get => GPUApi.GetGPUIDFromPhysicalGPU(Handle);
}
/// <summary>
/// Gets GPU type
/// </summary>
public GPUType GPUType
{
get => GPUApi.GetGPUType(Handle);
}
/// <summary>
/// Gets the physical GPU handle
/// </summary>
public PhysicalGPUHandle Handle { get; }
/// <summary>
/// Gets a boolean value indicating the Quadro line of products
/// </summary>
public bool IsQuadro
{
get => GPUApi.GetQuadroStatus(Handle);
}
/// <summary>
/// Gets GPU memory and RAM information as well as frame-buffer information
/// </summary>
public GPUMemoryInformation MemoryInformation { get; }
/// <summary>
/// Gets GPU performance control status and configurations
/// </summary>
public GPUPerformanceControl PerformanceControl { get; }
/// <summary>
/// Gets the GPU performance states information and configurations
/// </summary>
public GPUPerformanceStatesInformation PerformanceStatesInfo
{
get
{
var performanceStates20Info = GPUApi.GetPerformanceStates20(Handle);
var currentPerformanceState = GPUApi.GetCurrentPerformanceState(Handle);
PrivatePCIeInfoV2? pcieInformation = null;
if (BusInformation.BusType == GPUBusType.PCIExpress)
{
try
{
pcieInformation = GPUApi.GetPCIEInfo(Handle);
}
catch
{
// ignore
}
}
return new GPUPerformanceStatesInformation(performanceStates20Info, currentPerformanceState,
pcieInformation);
}
}
/// <summary>
/// Gets GPU coolers information
/// </summary>
public GPUPowerTopologyInformation PowerTopologyInformation { get; }
/// <summary>
/// Gets GPU system type
/// </summary>
public SystemType SystemType
{
get => GPUApi.GetSystemType(Handle);
}
/// <summary>
/// Gets GPU thermal sensors information
/// </summary>
public GPUThermalInformation ThermalInformation { get; }
/// <summary>
/// Gets the GPU utilization domains and usages
/// </summary>
public GPUUsageInformation UsageInformation { get; }
/// <inheritdoc />
public bool Equals(PhysicalGPU other)
{
if (other == null)
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
return Handle.Equals(other.Handle);
}
/// <summary>
/// Gets the corresponding <see cref="PhysicalGPU" /> instance from a GPU identification number.
/// </summary>
/// <param name="gpuId">The GPU identification number.</param>
/// <returns>An instance of <see cref="PhysicalGPU" /> or <see langword="null" /> if operation failed.</returns>
public static PhysicalGPU FromGPUId(uint gpuId)
{
var handle = GPUApi.GetPhysicalGPUFromGPUID(gpuId);
if (handle.IsNull)
{
return null;
}
return new PhysicalGPU(handle);
}
/// <summary>
/// Gets all physical GPUs
/// </summary>
/// <returns>An array of physical GPUs</returns>
public static PhysicalGPU[] GetPhysicalGPUs()
{
return GPUApi.EnumPhysicalGPUs().Select(handle => new PhysicalGPU(handle)).ToArray();
}
/// <summary>
/// Gets all physical GPUs in TCC state
/// </summary>
/// <returns>An array of physical GPUs</returns>
public static PhysicalGPU[] GetTCCPhysicalGPUs()
{
return GPUApi.EnumTCCPhysicalGPUs().Select(handle => new PhysicalGPU(handle)).ToArray();
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(PhysicalGPU left, PhysicalGPU right)
{
return Equals(left, right) || left?.Equals(right) == true;
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(PhysicalGPU left, PhysicalGPU right)
{
return !(left == right);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
return Equals(obj as PhysicalGPU);
}
/// <inheritdoc />
public override int GetHashCode()
{
return Handle.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return FullName;
}
/// <summary>
/// Get a list of all active applications for this GPU
/// </summary>
/// <returns>An array of processes</returns>
public Process[] GetActiveApplications()
{
return GPUApi.QueryActiveApps(Handle).Select(app => Process.GetProcessById(app.ProcessId)).ToArray();
}
/// <summary>
/// Get a list of all connected display devices on this GPU
/// </summary>
/// <param name="flags">ConnectedIdsFlag flag</param>
/// <returns>An array of display devices</returns>
public DisplayDevice[] GetConnectedDisplayDevices(ConnectedIdsFlag flags)
{
return GPUApi.GetConnectedDisplayIds(Handle, flags).Select(display => new DisplayDevice(display)).ToArray();
}
/// <summary>
/// Get the display device connected to a specific GPU output
/// </summary>
/// <param name="output">The GPU output to get connected display device for</param>
/// <returns>DisplayDevice connected to the specified GPU output</returns>
public DisplayDevice GetDisplayDeviceByOutput(GPUOutput output)
{
return new DisplayDevice(GPUApi.GetDisplayIdFromGPUAndOutputId(Handle, output.OutputId));
}
/// <summary>
/// Get a list of all display devices on any possible output
/// </summary>
/// <returns>An array of display devices</returns>
public DisplayDevice[] GetDisplayDevices()
{
return GPUApi.GetAllDisplayIds(Handle).Select(display => new DisplayDevice(display)).ToArray();
}
/// <summary>
/// Reads EDID data of an output
/// </summary>
/// <param name="output">The GPU output to read EDID information for</param>
/// <returns>A byte array containing EDID data</returns>
public byte[] ReadEDIDData(GPUOutput output)
{
try
{
var data = new byte[0];
var identification = 0;
var totalSize = EDIDV3.MaxDataSize;
for (var offset = 0; offset < totalSize; offset += EDIDV3.MaxDataSize)
{
var edid = GPUApi.GetEDID(Handle, output.OutputId, offset, identification);
identification = edid.Identification;
totalSize = edid.TotalSize;
var edidData = edid.Data;
Array.Resize(ref data, data.Length + edidData.Length);
Array.Copy(edidData, 0, data, data.Length - edidData.Length, edidData.Length);
}
return data;
}
catch (NVIDIAApiException ex)
{
if (ex.Status == Status.IncompatibleStructureVersion)
{
return GPUApi.GetEDID(Handle, output.OutputId).Data;
}
throw;
}
}
/// <summary>
/// Reads data from the I2C bus
/// </summary>
/// <param name="i2cInfo">Information required to read from the I2C bus.</param>
/// <returns>The returned payload.</returns>
// ReSharper disable once InconsistentNaming
public byte[] ReadI2C(II2CInfo i2cInfo)
{
GPUApi.I2CRead(Handle, ref i2cInfo);
return i2cInfo.Data;
}
/// <summary>
/// Validates a set of GPU outputs to check if they can be active simultaneously
/// </summary>
/// <param name="outputs">GPU outputs to check</param>
/// <returns>true if all specified outputs can be active simultaneously, otherwise false</returns>
public bool ValidateOutputCombination(GPUOutput[] outputs)
{
var gpuOutpudIds =
outputs.Aggregate(OutputId.Invalid, (current, gpuOutput) => current | gpuOutput.OutputId);
return GPUApi.ValidateOutputCombination(Handle, gpuOutpudIds);
}
/// <summary>
/// Writes EDID data of an output
/// </summary>
/// <param name="output">The GPU output to write EDID information for</param>
/// <param name="edidData">A byte array containing EDID data</param>
public void WriteEDIDData(GPUOutput output, byte[] edidData)
{
WriteEDIDData((uint) output.OutputId, edidData);
}
/// <summary>
/// Writes EDID data of an display
/// </summary>
/// <param name="display">The display device to write EDID information for</param>
/// <param name="edidData">A byte array containing EDID data</param>
public void WriteEDIDData(DisplayDevice display, byte[] edidData)
{
WriteEDIDData(display.DisplayId, edidData);
}
/// <summary>
/// Writes data to the I2C bus
/// </summary>
/// <param name="i2cInfo">Information required to write to the I2C bus including data payload.</param>
// ReSharper disable once InconsistentNaming
public void WriteI2C(II2CInfo i2cInfo)
{
GPUApi.I2CWrite(Handle, i2cInfo);
}
private void WriteEDIDData(uint displayOutputId, byte[] edidData)
{
try
{
if (edidData.Length == 0)
{
var instance = typeof(EDIDV3).Instantiate<EDIDV3>();
GPUApi.SetEDID(Handle, displayOutputId, instance);
}
for (var offset = 0; offset < edidData.Length; offset += EDIDV3.MaxDataSize)
{
var array = new byte[Math.Min(EDIDV3.MaxDataSize, edidData.Length - offset)];
Array.Copy(edidData, offset, array, 0, array.Length);
var instance = EDIDV3.CreateWithData(0, (uint) offset, array, edidData.Length);
GPUApi.SetEDID(Handle, displayOutputId, instance);
}
return;
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
try
{
if (edidData.Length == 0)
{
var instance = typeof(EDIDV2).Instantiate<EDIDV2>();
GPUApi.SetEDID(Handle, displayOutputId, instance);
}
for (var offset = 0; offset < edidData.Length; offset += EDIDV2.MaxDataSize)
{
var array = new byte[Math.Min(EDIDV2.MaxDataSize, edidData.Length - offset)];
Array.Copy(edidData, offset, array, 0, array.Length);
GPUApi.SetEDID(Handle, displayOutputId, EDIDV2.CreateWithData(array, edidData.Length));
}
return;
}
catch (NVIDIAApiException ex)
{
if (ex.Status != Status.IncompatibleStructureVersion)
{
throw;
}
}
catch (NVIDIANotSupportedException)
{
// ignore
}
GPUApi.SetEDID(Handle, displayOutputId, EDIDV1.CreateWithData(edidData));
}
}
}

View File

@@ -0,0 +1,52 @@
using System;
namespace NvAPIWrapper.GPU
{
/// <summary>
/// Contains information about the GPU Video BIOS
/// </summary>
public class VideoBIOS
{
internal VideoBIOS(uint revision, int oemRevision, string versionString)
{
Revision = revision;
OEMRevision = oemRevision;
VersionString = versionString.ToUpper();
}
/// <summary>
/// Gets the the OEM revision of the video BIOS
/// </summary>
public int OEMRevision { get; }
/// <summary>
/// Gets the revision of the video BIOS
/// </summary>
public uint Revision { get; }
/// <summary>
/// Gets the full video BIOS version string
/// </summary>
public string VersionString { get; }
/// <inheritdoc />
public override string ToString()
{
return AsVersion().ToString();
}
/// <summary>
/// Returns the video BIOS version as a .Net Version object
/// </summary>
/// <returns>A Version object representing the video BIOS version</returns>
public Version AsVersion()
{
return new Version(
(int) ((Revision >> 28) + ((Revision << 4) >> 28) * 16), // 8 bit little endian
(int) (((Revision << 8) >> 28) + ((Revision << 12) >> 28) * 16), // 8 bit little endian
(int) ((Revision << 16) >> 16), // 16 bit big endian
OEMRevision // 8 bit integer
);
}
}
}

BIN
app/NvAPIWrapper/Icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -0,0 +1,81 @@
using NvAPIWrapper.Native;
using NvAPIWrapper.Native.General.Structures;
using NvAPIWrapper.Native.Interfaces.General;
namespace NvAPIWrapper
{
/// <summary>
/// .Net friendly version of system and general functions of NVAPI library
/// </summary>
public static class NVIDIA
{
/// <summary>
/// Gets information about the system's chipset.
/// </summary>
public static IChipsetInfo ChipsetInfo
{
get => GeneralApi.GetChipsetInfo();
}
/// <summary>
/// Gets NVIDIA driver branch version as string
/// </summary>
public static string DriverBranchVersion
{
get
{
GeneralApi.GetDriverAndBranchVersion(out var branchVersion);
return branchVersion;
}
}
/// <summary>
/// Gets NVIDIA driver version
/// </summary>
public static uint DriverVersion
{
get => GeneralApi.GetDriverAndBranchVersion(out _);
}
/// <summary>
/// Gets NVAPI interface version as string
/// </summary>
public static string InterfaceVersionString
{
get => GeneralApi.GetInterfaceVersionString();
}
/// <summary>
/// Gets the current lid and dock information.
/// </summary>
public static LidDockParameters LidAndDockParameters
{
get => GeneralApi.GetLidAndDockInfo();
}
/// <summary>
/// Initializes the NvAPI library (if not already initialized) but always increments the ref-counter.
/// </summary>
public static void Initialize()
{
GeneralApi.Initialize();
}
/// <summary>
/// PRIVATE - Requests to restart the display driver
/// </summary>
public static void RestartDisplayDriver()
{
GeneralApi.RestartDisplayDriver();
}
/// <summary>
/// Decrements the ref-counter and when it reaches ZERO, unloads NVAPI library.
/// </summary>
public static void Unload()
{
GeneralApi.Unload();
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
namespace NvAPIWrapper.Native.Attributes
{
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Delegate)]
internal class AcceptsAttribute : Attribute
{
public AcceptsAttribute(params Type[] types)
{
Types = types;
}
public Type[] Types { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using NvAPIWrapper.Native.Helpers;
namespace NvAPIWrapper.Native.Attributes
{
[AttributeUsage(AttributeTargets.Delegate)]
internal class FunctionIdAttribute : Attribute
{
public FunctionIdAttribute(FunctionId functionId)
{
FunctionId = functionId;
}
public FunctionId FunctionId { get; set; }
}
}

View File

@@ -0,0 +1,19 @@
using System;
namespace NvAPIWrapper.Native.Attributes
{
[AttributeUsage(AttributeTargets.Struct)]
internal class StructureVersionAttribute : Attribute
{
public StructureVersionAttribute()
{
}
public StructureVersionAttribute(int versionNumber)
{
VersionNumber = versionNumber;
}
public int VersionNumber { get; set; }
}
}

View File

@@ -0,0 +1,8 @@
namespace NvAPIWrapper.Native.Constants
{
internal static class Display
{
public const int AdvancedDisplayHeads = 4;
public const int MaxDisplayHeads = 2;
}
}

View File

@@ -0,0 +1,8 @@
namespace NvAPIWrapper.Native.Constants
{
internal static class General
{
public const int BinaryDataMax = 4096;
public const int UnicodeStringLength = 2048;
}
}

View File

@@ -0,0 +1,28 @@
namespace NvAPIWrapper.Native.DRS
{
/// <summary>
/// Holds possible values for the setting location
/// </summary>
public enum DRSSettingLocation : uint
{
/// <summary>
/// Setting is part of the current profile
/// </summary>
CurrentProfile = 0,
/// <summary>
/// Setting is part of the global profile
/// </summary>
GlobalProfile,
/// <summary>
/// Setting is part of the base profile
/// </summary>
BaseProfile,
/// <summary>
/// Setting is part of the default profile
/// </summary>
DefaultProfile
}
}

View File

@@ -0,0 +1,28 @@
namespace NvAPIWrapper.Native.DRS
{
/// <summary>
/// Holds a list of possible setting value types
/// </summary>
public enum DRSSettingType : uint
{
/// <summary>
/// Integer value type
/// </summary>
Integer = 0,
/// <summary>
/// Binary value type
/// </summary>
Binary,
/// <summary>
/// ASCII string value type
/// </summary>
String,
/// <summary>
/// Unicode string value type
/// </summary>
UnicodeString
}
}

View File

@@ -0,0 +1,77 @@
using System;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Attributes;
using NvAPIWrapper.Native.General.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces;
using NvAPIWrapper.Native.Interfaces.DRS;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <inheritdoc cref="IDRSApplication" />
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[StructureVersion(1)]
public struct DRSApplicationV1 : IInitializable, IDRSApplication
{
internal StructureVersion _Version;
internal uint _IsPredefined;
internal UnicodeString _ApplicationName;
internal UnicodeString _FriendlyName;
internal UnicodeString _LauncherName;
/// <summary>
/// Creates a new instance of <see cref="DRSApplicationV1" />
/// </summary>
/// <param name="applicationName">The application file name.</param>
/// <param name="friendlyName">The application friendly name.</param>
/// <param name="launcherName">The application launcher name.</param>
public DRSApplicationV1(
string applicationName,
string friendlyName = null,
string launcherName = null
)
{
this = typeof(DRSApplicationV1).Instantiate<DRSApplicationV1>();
IsPredefined = false;
ApplicationName = applicationName;
FriendlyName = friendlyName ?? string.Empty;
LauncherName = launcherName ?? string.Empty;
}
/// <inheritdoc />
public bool IsPredefined
{
get => _IsPredefined > 0;
private set => _IsPredefined = value ? 1u : 0u;
}
/// <inheritdoc />
public string ApplicationName
{
get => _ApplicationName.Value;
private set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Name can not be empty or null.");
}
_ApplicationName = new UnicodeString(value);
}
}
/// <inheritdoc />
public string FriendlyName
{
get => _FriendlyName.Value;
private set => _FriendlyName = new UnicodeString(value);
}
/// <inheritdoc />
public string LauncherName
{
get => _LauncherName.Value;
private set => _LauncherName = new UnicodeString(value);
}
}
}

View File

@@ -0,0 +1,93 @@
using System;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Attributes;
using NvAPIWrapper.Native.General.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces;
using NvAPIWrapper.Native.Interfaces.DRS;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <inheritdoc cref="IDRSApplication" />
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[StructureVersion(2)]
public struct DRSApplicationV2 : IInitializable, IDRSApplication
{
internal const char FileInFolderSeparator = ':';
internal StructureVersion _Version;
internal uint _IsPredefined;
internal UnicodeString _ApplicationName;
internal UnicodeString _FriendlyName;
internal UnicodeString _LauncherName;
internal UnicodeString _FileInFolder;
/// <summary>
/// Creates a new instance of <see cref="DRSApplicationV2" />
/// </summary>
/// <param name="applicationName">The application file name.</param>
/// <param name="friendlyName">The application friendly name.</param>
/// <param name="launcherName">The application launcher name.</param>
/// <param name="fileInFolders">The list of files that are necessary to be present in the application parent directory.</param>
// ReSharper disable once TooManyDependencies
public DRSApplicationV2(
string applicationName,
string friendlyName = null,
string launcherName = null,
string[] fileInFolders = null
)
{
this = typeof(DRSApplicationV2).Instantiate<DRSApplicationV2>();
IsPredefined = false;
ApplicationName = applicationName;
FriendlyName = friendlyName ?? string.Empty;
LauncherName = launcherName ?? string.Empty;
FilesInFolder = fileInFolders ?? new string[0];
}
/// <inheritdoc />
public bool IsPredefined
{
get => _IsPredefined > 0;
private set => _IsPredefined = value ? 1u : 0u;
}
/// <inheritdoc />
public string ApplicationName
{
get => _ApplicationName.Value;
private set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Name can not be empty or null.");
}
_ApplicationName = new UnicodeString(value);
}
}
/// <inheritdoc />
public string FriendlyName
{
get => _FriendlyName.Value;
private set => _FriendlyName = new UnicodeString(value);
}
/// <inheritdoc />
public string LauncherName
{
get => _LauncherName.Value;
private set => _LauncherName = new UnicodeString(value);
}
/// <summary>
/// Gets the list of files that are necessary to be present in the application parent directory.
/// </summary>
public string[] FilesInFolder
{
get => _FileInFolder.Value?.Split(new[] {FileInFolderSeparator}, StringSplitOptions.RemoveEmptyEntries) ??
new string[0];
private set => _FileInFolder = new UnicodeString(string.Join(FileInFolderSeparator.ToString(), value));
}
}
}

View File

@@ -0,0 +1,114 @@
using System;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Attributes;
using NvAPIWrapper.Native.General.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces;
using NvAPIWrapper.Native.Interfaces.DRS;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <inheritdoc cref="IDRSApplication" />
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[StructureVersion(3)]
public struct DRSApplicationV3 : IInitializable, IDRSApplication
{
internal const char FileInFolderSeparator = DRSApplicationV2.FileInFolderSeparator;
internal StructureVersion _Version;
internal uint _IsPredefined;
internal UnicodeString _ApplicationName;
internal UnicodeString _FriendlyName;
internal UnicodeString _LauncherName;
internal UnicodeString _FileInFolder;
internal uint _Flags;
/// <summary>
/// Creates a new instance of <see cref="DRSApplicationV3" />
/// </summary>
/// <param name="applicationName">The application file name.</param>
/// <param name="friendlyName">The application friendly name.</param>
/// <param name="launcherName">The application launcher name.</param>
/// <param name="fileInFolders">The list of files that are necessary to be present in the application parent directory.</param>
/// <param name="isMetro">A boolean value indicating if this application is a metro application.</param>
// ReSharper disable once TooManyDependencies
public DRSApplicationV3(
string applicationName,
string friendlyName = null,
string launcherName = null,
string[] fileInFolders = null,
bool isMetro = false
)
{
this = typeof(DRSApplicationV3).Instantiate<DRSApplicationV3>();
IsPredefined = false;
ApplicationName = applicationName;
FriendlyName = friendlyName ?? string.Empty;
LauncherName = launcherName ?? string.Empty;
FilesInFolder = fileInFolders ?? new string[0];
IsMetroApplication = isMetro;
}
/// <inheritdoc />
public bool IsPredefined
{
get => _IsPredefined > 0;
private set => _IsPredefined = value ? 1u : 0u;
}
/// <summary>
/// Gets a boolean value indicating if this application is a metro application
/// </summary>
public bool IsMetroApplication
{
get => _Flags.GetBit(0);
private set => _Flags = _Flags.SetBit(0, value);
}
/// <summary>
/// Gets a boolean value indicating if this application has command line arguments
/// </summary>
public bool HasCommandLine
{
get => _Flags.GetBit(1);
}
/// <inheritdoc />
public string ApplicationName
{
get => _ApplicationName.Value;
private set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Name can not be empty or null.");
}
_ApplicationName = new UnicodeString(value);
}
}
/// <inheritdoc />
public string FriendlyName
{
get => _FriendlyName.Value;
private set => _FriendlyName = new UnicodeString(value);
}
/// <inheritdoc />
public string LauncherName
{
get => _LauncherName.Value;
private set => _LauncherName = new UnicodeString(value);
}
/// <summary>
/// Gets the list of files that are necessary to be present in the application parent directory.
/// </summary>
public string[] FilesInFolder
{
get => _FileInFolder.Value?.Split(new[] {FileInFolderSeparator}, StringSplitOptions.RemoveEmptyEntries) ??
new string[0];
private set => _FileInFolder = new UnicodeString(string.Join(FileInFolderSeparator.ToString(), value));
}
}
}

View File

@@ -0,0 +1,148 @@
using System;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Attributes;
using NvAPIWrapper.Native.General.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces;
using NvAPIWrapper.Native.Interfaces.DRS;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <inheritdoc cref="IDRSApplication" />
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[StructureVersion(4)]
public struct DRSApplicationV4 : IInitializable, IDRSApplication
{
internal const char FileInFolderSeparator = DRSApplicationV3.FileInFolderSeparator;
internal StructureVersion _Version;
internal uint _IsPredefined;
internal UnicodeString _ApplicationName;
internal UnicodeString _FriendlyName;
internal UnicodeString _LauncherName;
internal UnicodeString _FileInFolder;
internal uint _Flags;
internal UnicodeString _CommandLine;
/// <summary>
/// Creates a new instance of <see cref="DRSApplicationV4" />
/// </summary>
/// <param name="applicationName">The application file name.</param>
/// <param name="friendlyName">The application friendly name.</param>
/// <param name="launcherName">The application launcher name.</param>
/// <param name="fileInFolders">The list of files that are necessary to be present in the application parent directory.</param>
/// <param name="isMetro">A boolean value indicating if this application is a metro application.</param>
/// <param name="commandLine">The application's command line arguments.</param>
// ReSharper disable once TooManyDependencies
public DRSApplicationV4(
string applicationName,
string friendlyName = null,
string launcherName = null,
string[] fileInFolders = null,
bool isMetro = false,
string commandLine = null
)
{
this = typeof(DRSApplicationV4).Instantiate<DRSApplicationV4>();
IsPredefined = false;
ApplicationName = applicationName;
FriendlyName = friendlyName ?? string.Empty;
LauncherName = launcherName ?? string.Empty;
FilesInFolder = fileInFolders ?? new string[0];
IsMetroApplication = isMetro;
ApplicationCommandLine = commandLine ?? string.Empty;
}
/// <inheritdoc />
public bool IsPredefined
{
get => _IsPredefined > 0;
private set => _IsPredefined = value ? 1u : 0u;
}
/// <summary>
/// Gets a boolean value indicating if this application is a metro application
/// </summary>
public bool IsMetroApplication
{
get => _Flags.GetBit(0);
private set => _Flags = _Flags.SetBit(0, value);
}
/// <summary>
/// Gets a boolean value indicating if this application has command line arguments
/// </summary>
public bool HasCommandLine
{
get => _Flags.GetBit(1);
private set => _Flags = _Flags.SetBit(1, value);
}
/// <inheritdoc />
public string ApplicationName
{
get => _ApplicationName.Value;
private set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("Name can not be empty or null.");
}
_ApplicationName = new UnicodeString(value);
}
}
/// <summary>
/// Gets the application command line arguments
/// </summary>
public string ApplicationCommandLine
{
get => (HasCommandLine ? _CommandLine.Value : null) ?? string.Empty;
private set
{
if (string.IsNullOrEmpty(value))
{
_CommandLine = new UnicodeString(null);
if (HasCommandLine)
{
HasCommandLine = false;
}
}
else
{
_CommandLine = new UnicodeString(value);
if (!HasCommandLine)
{
HasCommandLine = true;
}
}
}
}
/// <inheritdoc />
public string FriendlyName
{
get => _FriendlyName.Value;
private set => _FriendlyName = new UnicodeString(value);
}
/// <inheritdoc />
public string LauncherName
{
get => _LauncherName.Value;
private set => _LauncherName = new UnicodeString(value);
}
/// <summary>
/// Gets the list of files that are necessary to be present in the application parent directory.
/// </summary>
public string[] FilesInFolder
{
get => _FileInFolder.Value?.Split(new[] {FileInFolderSeparator}, StringSplitOptions.RemoveEmptyEntries) ??
new string[0];
private set => _FileInFolder = new UnicodeString(string.Join(FileInFolderSeparator.ToString(), value));
}
}
}

View File

@@ -0,0 +1,71 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Helpers;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <summary>
/// Contains a list of supported GPU series by a NVIDIA driver setting profile
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 8)]
public struct DRSGPUSupport
{
internal uint _Flags;
/// <summary>
/// Gets or sets a value indicating if the GeForce line of products are supported
/// </summary>
public bool IsGeForceSupported
{
get => _Flags.GetBit(0);
set => _Flags = _Flags.SetBit(0, value);
}
/// <summary>
/// Gets or sets a value indicating if the Quadro line of products are supported
/// </summary>
public bool IsQuadroSupported
{
get => _Flags.GetBit(1);
set => _Flags = _Flags.SetBit(1, value);
}
/// <summary>
/// Gets or sets a value indicating if the NVS line of products are supported
/// </summary>
public bool IsNVSSupported
{
get => _Flags.GetBit(2);
set => _Flags = _Flags.SetBit(2, value);
}
/// <inheritdoc />
public override string ToString()
{
var supportedGPUs = new List<string>();
if (IsGeForceSupported)
{
supportedGPUs.Add("GeForce");
}
if (IsQuadroSupported)
{
supportedGPUs.Add("Quadro");
}
if (IsNVSSupported)
{
supportedGPUs.Add("NVS");
}
if (supportedGPUs.Any())
{
return $"[{_Flags}] = {string.Join(", ", supportedGPUs)}";
}
return $"[{_Flags}]";
}
}
}

View File

@@ -0,0 +1,100 @@
using System;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Interfaces;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <summary>
/// DRSProfileHandle is a reference to a DRS profile.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct DRSProfileHandle : IHandle, IEquatable<DRSProfileHandle>
{
internal readonly IntPtr _MemoryAddress;
private DRSProfileHandle(IntPtr memoryAddress)
{
_MemoryAddress = memoryAddress;
}
/// <inheritdoc />
public bool Equals(DRSProfileHandle other)
{
return _MemoryAddress.Equals(other._MemoryAddress);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is DRSProfileHandle handle && Equals(handle);
}
/// <inheritdoc />
public override int GetHashCode()
{
return _MemoryAddress.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return $"DRSProfileHandle #{MemoryAddress.ToInt64()}";
}
/// <inheritdoc />
public IntPtr MemoryAddress
{
get => _MemoryAddress;
}
/// <inheritdoc />
public bool IsNull
{
get => _MemoryAddress == IntPtr.Zero;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(DRSProfileHandle left, DRSProfileHandle right)
{
return left.Equals(right);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(DRSProfileHandle left, DRSProfileHandle right)
{
return !left.Equals(right);
}
/// <summary>
/// Gets default DRSProfileHandle with a null pointer
/// </summary>
public static DRSProfileHandle DefaultHandle
{
get => default(DRSProfileHandle);
}
/// <summary>
/// Gets the default global profile handle
/// </summary>
public static DRSProfileHandle DefaultGlobalProfileHandle
{
get => new DRSProfileHandle(new IntPtr(-1));
}
}
}

View File

@@ -0,0 +1,76 @@
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Attributes;
using NvAPIWrapper.Native.General.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <summary>
/// Represents a NVIDIA driver settings profile
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[StructureVersion(1)]
public struct DRSProfileV1 : IInitializable
{
internal StructureVersion _Version;
internal UnicodeString _ProfileName;
internal DRSGPUSupport _GPUSupport;
internal uint _IsPredefined;
internal uint _NumberOfApplications;
internal uint _NumberOfSettings;
/// <summary>
/// Creates a new instance of <see cref="DRSProfileV1" /> with the passed name and GPU series support list.
/// </summary>
/// <param name="name">The name of the profile.</param>
/// <param name="gpuSupport">An instance of <see cref="DRSGPUSupport" /> containing the list of supported GPU series.</param>
public DRSProfileV1(string name, DRSGPUSupport gpuSupport)
{
this = typeof(DRSProfileV1).Instantiate<DRSProfileV1>();
_ProfileName = new UnicodeString(name);
_GPUSupport = gpuSupport;
}
/// <summary>
/// Gets the name of the profile
/// </summary>
public string Name
{
get => _ProfileName.Value;
}
/// <summary>
/// Gets or sets the GPU series support list
/// </summary>
public DRSGPUSupport GPUSupport
{
get => _GPUSupport;
set => _GPUSupport = value;
}
/// <summary>
/// Gets a boolean value indicating if this profile is predefined
/// </summary>
public bool IsPredefined
{
get => _IsPredefined > 0;
}
/// <summary>
/// Gets the number of applications registered under this profile
/// </summary>
public int NumberOfApplications
{
get => (int) _NumberOfApplications;
}
/// <summary>
/// Gets the number of setting registered under this profile
/// </summary>
public int NumberOfSettings
{
get => (int) _NumberOfSettings;
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Interfaces;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <summary>
/// DRSSessionHandle is a reference to a DRS session.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct DRSSessionHandle : IHandle, IEquatable<DRSSessionHandle>
{
internal readonly IntPtr _MemoryAddress;
/// <inheritdoc />
public bool Equals(DRSSessionHandle other)
{
return _MemoryAddress.Equals(other._MemoryAddress);
}
/// <inheritdoc />
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is DRSSessionHandle handle && Equals(handle);
}
/// <inheritdoc />
public override int GetHashCode()
{
return _MemoryAddress.GetHashCode();
}
/// <inheritdoc />
public override string ToString()
{
return $"DRSSessionHandle #{MemoryAddress.ToInt64()}";
}
/// <inheritdoc />
public IntPtr MemoryAddress
{
get => _MemoryAddress;
}
/// <inheritdoc />
public bool IsNull
{
get => _MemoryAddress == IntPtr.Zero;
}
/// <summary>
/// Checks for equality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are equal, otherwise false</returns>
public static bool operator ==(DRSSessionHandle left, DRSSessionHandle right)
{
return left.Equals(right);
}
/// <summary>
/// Checks for inequality between two objects of same type
/// </summary>
/// <param name="left">The first object</param>
/// <param name="right">The second object</param>
/// <returns>true, if both objects are not equal, otherwise false</returns>
public static bool operator !=(DRSSessionHandle left, DRSSessionHandle right)
{
return !left.Equals(right);
}
/// <summary>
/// Gets default DRSSessionHandle with a null pointer
/// </summary>
public static DRSSessionHandle DefaultHandle
{
get => default(DRSSessionHandle);
}
}
}

View File

@@ -0,0 +1,329 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using NvAPIWrapper.Native.Attributes;
using NvAPIWrapper.Native.General.Structures;
using NvAPIWrapper.Native.Helpers;
using NvAPIWrapper.Native.Interfaces;
namespace NvAPIWrapper.Native.DRS.Structures
{
/// <summary>
/// Represents a NVIDIA driver setting
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[StructureVersion(1)]
public struct DRSSettingV1 : IInitializable
{
internal StructureVersion _Version;
internal UnicodeString _SettingName;
internal uint _SettingId;
internal DRSSettingType _SettingType;
internal DRSSettingLocation _SettingLocation;
internal uint _IsCurrentPredefined;
internal uint _IsPredefinedValid;
internal DRSSettingValue _PredefinedValue;
internal DRSSettingValue _CurrentValue;
/// <summary>
/// Creates a new instance of <see cref="DRSSettingV1" /> containing the passed value.
/// </summary>
/// <param name="id">The setting identification number.</param>
/// <param name="settingType">The type of the setting's value</param>
/// <param name="value">The setting's value</param>
public DRSSettingV1(uint id, DRSSettingType settingType, object value)
{
this = typeof(DRSSettingV1).Instantiate<DRSSettingV1>();
Id = id;
IsPredefinedValueValid = false;
_SettingType = settingType;
CurrentValue = value;
}
/// <summary>
/// Creates a new instance of <see cref="DRSSettingV1" /> containing the passed value.
/// </summary>
/// <param name="id">The setting identification number.</param>
/// <param name="value">The setting's value</param>
public DRSSettingV1(uint id, string value) : this(id, DRSSettingType.String, value)
{
}
/// <summary>
/// Creates a new instance of <see cref="DRSSettingV1" /> containing the passed value.
/// </summary>
/// <param name="id">The setting identification number.</param>
/// <param name="value">The setting's value</param>
public DRSSettingV1(uint id, uint value) : this(id, DRSSettingType.Integer, value)
{
}
/// <summary>
/// Creates a new instance of <see cref="DRSSettingV1" /> containing the passed value.
/// </summary>
/// <param name="id">The setting identification number.</param>
/// <param name="value">The setting's value</param>
public DRSSettingV1(uint id, byte[] value) : this(id, DRSSettingType.Binary, value)
{
}
/// <summary>
/// Gets the name of the setting
/// </summary>
public string Name
{
get => _SettingName.Value;
}
/// <summary>
/// Gets the identification number of the setting
/// </summary>
public uint Id
{
get => _SettingId;
private set => _SettingId = value;
}
/// <summary>
/// Gets the setting's value type
/// </summary>
public DRSSettingType SettingType
{
get => _SettingType;
private set => _SettingType = value;
}
/// <summary>
/// Gets the setting location
/// </summary>
public DRSSettingLocation SettingLocation
{
get => _SettingLocation;
}
/// <summary>
/// Gets a boolean value indicating if the current value is the predefined value
/// </summary>
public bool IsCurrentValuePredefined
{
get => _IsCurrentPredefined > 0;
private set => _IsCurrentPredefined = value ? 1u : 0u;
}
/// <summary>
/// Gets a boolean value indicating if the predefined value is available and valid
/// </summary>
public bool IsPredefinedValueValid
{
get => _IsPredefinedValid > 0;
private set => _IsPredefinedValid = value ? 1u : 0u;
}
/// <summary>
/// Returns the predefined value as an integer
/// </summary>
/// <returns>An integer representing the predefined value</returns>
public uint GetPredefinedValueAsInteger()
{
return _PredefinedValue.AsInteger();
}
/// <summary>
/// Returns the predefined value as an array of bytes
/// </summary>
/// <returns>An byte array representing the predefined value</returns>
public byte[] GetPredefinedValueAsBinary()
{
return _PredefinedValue.AsBinary();
}
/// <summary>
/// Returns the predefined value as an unicode string
/// </summary>
/// <returns>An unicode string representing the predefined value</returns>
public string GetPredefinedValueAsUnicodeString()
{
return _PredefinedValue.AsUnicodeString();
}
/// <summary>
/// Gets the setting's predefined value
/// </summary>
public object PredefinedValue
{
get
{
if (!IsPredefinedValueValid)
{
return null;
}
switch (_SettingType)
{
case DRSSettingType.Integer:
return GetPredefinedValueAsInteger();
case DRSSettingType.Binary:
return GetPredefinedValueAsBinary();
case DRSSettingType.String:
case DRSSettingType.UnicodeString:
return GetPredefinedValueAsUnicodeString();
default:
throw new ArgumentOutOfRangeException(nameof(SettingType));
}
}
}
/// <summary>
/// Returns the current value as an integer
/// </summary>
/// <returns>An integer representing the current value</returns>
public uint GetCurrentValueAsInteger()
{
return _CurrentValue.AsInteger();
}
/// <summary>
/// Returns the current value as an array of bytes
/// </summary>
/// <returns>An byte array representing the current value</returns>
public byte[] GetCurrentValueAsBinary()
{
return _CurrentValue.AsBinary();
}
/// <summary>
/// Returns the current value as an unicode string
/// </summary>
/// <returns>An unicode string representing the current value</returns>
public string GetCurrentValueAsUnicodeString()
{
return _CurrentValue.AsUnicodeString();
}
/// <summary>
/// Sets the passed value as the current value
/// </summary>
/// <param name="value">The new value for the setting</param>
public void SetCurrentValueAsInteger(uint value)
{
if (SettingType != DRSSettingType.Integer)
{
throw new ArgumentOutOfRangeException(nameof(value), "Passed argument is invalid for this setting.");
}
_CurrentValue = new DRSSettingValue(value);
IsCurrentValuePredefined = IsPredefinedValueValid && (uint) CurrentValue == (uint) PredefinedValue;
}
/// <summary>
/// Sets the passed value as the current value
/// </summary>
/// <param name="value">The new value for the setting</param>
public void SetCurrentValueAsBinary(byte[] value)
{
if (SettingType != DRSSettingType.Binary)
{
throw new ArgumentOutOfRangeException(nameof(value), "Passed argument is invalid for this setting.");
}
_CurrentValue = new DRSSettingValue(value);
IsCurrentValuePredefined =
IsPredefinedValueValid &&
((byte[]) CurrentValue)?.SequenceEqual((byte[]) PredefinedValue ?? new byte[0]) == true;
}
/// <summary>
/// Sets the passed value as the current value
/// </summary>
/// <param name="value">The new value for the setting</param>
public void SetCurrentValueAsUnicodeString(string value)
{
if (SettingType != DRSSettingType.UnicodeString)
{
throw new ArgumentOutOfRangeException(nameof(value), "Passed argument is invalid for this setting.");
}
_CurrentValue = new DRSSettingValue(value);
IsCurrentValuePredefined =
IsPredefinedValueValid &&
string.Equals(
(string) CurrentValue,
(string) PredefinedValue,
StringComparison.InvariantCulture
);
}
/// <summary>
/// Gets or sets the setting's current value
/// </summary>
public object CurrentValue
{
get
{
switch (_SettingType)
{
case DRSSettingType.Integer:
return GetCurrentValueAsInteger();
case DRSSettingType.Binary:
return GetCurrentValueAsBinary();
case DRSSettingType.String:
case DRSSettingType.UnicodeString:
return GetCurrentValueAsUnicodeString();
default:
throw new ArgumentOutOfRangeException(nameof(SettingType));
}
}
private set
{
if (value is int intValue)
{
SetCurrentValueAsInteger((uint) intValue);
}
else if (value is uint unsignedIntValue)
{
SetCurrentValueAsInteger(unsignedIntValue);
}
else if (value is short shortValue)
{
SetCurrentValueAsInteger((uint) shortValue);
}
else if (value is ushort unsignedShortValue)
{
SetCurrentValueAsInteger(unsignedShortValue);
}
else if (value is long longValue)
{
SetCurrentValueAsInteger((uint) longValue);
}
else if (value is ulong unsignedLongValue)
{
SetCurrentValueAsInteger((uint) unsignedLongValue);
}
else if (value is byte byteValue)
{
SetCurrentValueAsInteger(byteValue);
}
else if (value is string stringValue)
{
SetCurrentValueAsUnicodeString(stringValue);
}
else if (value is byte[] binaryValue)
{
SetCurrentValueAsBinary(binaryValue);
}
else
{
throw new ArgumentException("Unacceptable argument type.", nameof(value));
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More