Compare commits

..

97 Commits

Author SHA1 Message Date
4qwerty7
8ccbb694dd [Registry Preview] Fix the issue of saving files without truncation (#27113) 2023-07-01 14:10:44 -07:00
Stefan Markovic
2dcaa526cb Revert "Revert "[File Explorer Add-ons] Fix file preview pane flickering on f… (#27093)" (#27122)
This reverts commit 217f3f9ff3.
2023-06-30 18:44:12 +02:00
Laszlo Nemeth
03a5a4200e [Installer] add priority settings to the task scheduler PT task. (#27058)
* Installer: add priority settings to the task scheduler PT task.

* Add priority settings for task creation (for Task Scheduler) to the runner as well

* Modifying priority value
2023-06-30 15:23:02 +02:00
Heiko
148f1df56c Update comment in EnvironmentHelper.cs (#27089)
* Update comment in EnvironmentHelper.cs

* fix typo
2023-06-30 11:06:03 +02:00
Andrey Nekrasov
cc83e2b3ee [Peek] Handle ThemeListener ctor exceptions (#27110) 2023-06-30 10:50:12 +02:00
Stefan Markovic
345486acda Bump System.Management to 7.0.2 (#27105) 2023-06-30 10:49:52 +02:00
Stefan Markovic
217f3f9ff3 Revert "[File Explorer Add-ons] Fix file preview pane flickering on f… (#27093)
* Revert "[File Explorer Add-ons] Fix file preview pane flickering on file selection and resizing (#26660)"

This reverts commit 9581cd7a27.

* Revert "[Build][FileExplorer]Add missing dwmapi.lib to Debug config (#26940)"

This reverts commit d190934d61.

* Revert "[Build]Fix dwamapi.lib linking error on VS (#26870)"

This reverts commit c7f8b696a6.
2023-06-28 21:57:03 +02:00
Stefan Markovic
cfc65e8c69 [release ci] Fix signing Peek/SharpCompress.dll (#27082) 2023-06-28 12:58:39 +02:00
microsoft-github-policy-service[bot]
cb4ee89623 Onboarding to GitOps.ResourceManagement (#26863)
* Add prIssueManagement.yml to onboard repo to GitOps.ResourceManagement as FabricBot replacement

* Deleting fabricbot.json

* Update resourceManagement.yml

* Update expect.txt

* Update .github/policies/resourceManagement.yml

Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com>

---------

Co-authored-by: microsoft-github-policy-service[bot] <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com>
Co-authored-by: Clint Rutkas <clint@rutkas.com>
Co-authored-by: Heiko <61519853+htcfreek@users.noreply.github.com>
2023-06-28 11:48:08 +02:00
Heiko
63c624b273 [Run] Fix environment helper for nested environment variables (#27034)
* Updates to EnvironmentHelper

* Revert "Updates to EnvironmentHelper"

This reverts commit 8af2441c34.

* Environment helper fix

* clean up usings

* fix spelling

* Update comment

* Update src/modules/launcher/PowerLauncher/Helper/EnvironmentHelper.cs

* Update src/modules/launcher/PowerLauncher/Helper/EnvironmentHelper.cs
2023-06-28 11:44:13 +02:00
Davide Giacometti
6ba8596d52 [Peek] Support for archives (#26839)
* support for archives in peek

* fix spellcheck

* horizontal scrolling

* fix height

* removed redundant helper
2023-06-28 09:38:53 +02:00
Seraphima Zykova
67ce81ded8 [Peek] Handle crash when opening app for Internet shortcuts (#26680)
* null check

* launch uri
2023-06-26 17:19:44 +02:00
Seraphima Zykova
397178deec [FancyZones] Fix blank layout error (#26828) 2023-06-26 16:14:14 +02:00
gokcekantarci
1b9094ae2b [Registry Preview] * Two settings folders reduces to one. (#26842)
* [Registry Preview] * Two settings folders reduces to one.
* Two settings files reduced to one.
* Folder creation if not exist added.

* Add size/position properties to fix saving from Settings app

* Separate settings.json and app-placement.json

---------

Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
2023-06-26 12:45:52 +02:00
Seraphima Zykova
8dcdcbaa37 [FancyZones] Retry monitor identification attempt (#27005)
* retry monitor identification

* check displays after retries

* reduce waiting time

* 30ms waiting time

* keep fallback values
2023-06-23 22:02:36 +02:00
Davide Giacometti
9511d17063 [Hosts] Handle maximum of 9 hosts per entry (#26862)
* handle maximum of 9 hosts per entry

* splitted entries teaching tip

* fix entry

* message changed
2023-06-23 21:54:45 +02:00
gokcekantarci
8cb632a0c2 [QuickAccent] A check is added to applications running under other ap… (#26808)
* [QuickAccent] A check is added to applications running under other applications with window name for excluding.

* [QuickAccent] Check moved under a general function and applied all modules includes excludeapp

* [QuickAccent] Function name revised

* [QuickAccent] check_excluded_app_with_title function moved to excluded_apps.h

* [QuickAccent] New function created for clean code.

* Reuse check_excluded_app_with_title

---------

Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
2023-06-23 21:53:15 +02:00
Jaime Bernardo
b8a253fda6 [PTRun]Remove unneeded registry key from installer (#27011) 2023-06-23 21:49:01 +02:00
Heiko
a32d6a688c [Peek] Window improvements (#26924)
* add min window size

* addd tool tip

* add more tool tips

* update window size and comment

* remove comment
2023-06-22 17:51:25 +02:00
Seraphima Zykova
cfaa3670db [FancyZones] Fix zone activation when the cursor is not moved (#26943) 2023-06-22 17:05:55 +02:00
Davide Giacometti
08215a8a77 Cleanup and NullReferenceException fix (#26956) 2023-06-22 14:28:13 +02:00
Jaime Bernardo
26bf4193f7 [Dev]Add missing ATL lib to .vsconfig (#26953) 2023-06-20 14:45:46 +01:00
Sven
46ed52eab6 [Settings] Reset Activation Key to Default Value (#26449)
* Add Default Value field to all controls

* Add reset button to Control field

* Improve button
Improve appearance
Add ToolTipService
Add AutomationProperties

* Move Reset button to Shortcut Dialog

* Fix Video Conferencing crash

* Change `Use Default` to `Reset`
2023-06-20 14:42:04 +01:00
Clint Rutkas
a883dcc283 [Chore]Upgrade Microsoft.Windows.Compatibility to 7.0.3 (#26950)
* Upgrading to latest Microsoft.Windows.Compatibility

* Update NOTICE.md
2023-06-20 14:38:23 +01:00
Jaime Bernardo
c598d93ad3 [PTRun]Remove default images (app.dark.png fix) (#26843) 2023-06-19 20:15:12 +01:00
Davide Giacometti
bc8e821ab4 [Chore]Bump Microsoft.CodeAnalysis.NetAnalyzers to 7.0.3 (#26865)
Disable "The .NET SDK has newer analyzers with version" warning
2023-06-19 20:07:14 +01:00
Stefan Markovic
d190934d61 [Build][FileExplorer]Add missing dwmapi.lib to Debug config (#26940) 2023-06-19 11:14:40 +01:00
Jaime Bernardo
c7f8b696a6 [Build]Fix dwamapi.lib linking error on VS (#26870) 2023-06-15 18:15:36 +01:00
Chek Wei Tan
9581cd7a27 [File Explorer Add-ons] Fix file preview pane flickering on file selection and resizing (#26660)
* Move color values to constant

* Fix MonacoPreview flickering on file selection and resizing

* Fix MarkdownPreview flickering on file selection and resizing

* Fix SvgPreview flickering on file selection and resizing

* Create Settings class and standardize background setting for MarkdownPreview

* Replace ColorTranslator.FromHtml with Color.FromArgb for constant color settings

* Use existing SetBackground

* Remove duplicate GetTheme function

* Update src/modules/previewpane/MarkdownPreviewHandler/Settings.cs
2023-06-14 14:15:17 +01:00
gokcekantarci
6ece812103 [Settings]Better errors when failing to backup (#26762)
* [Settings] settings.json files broken error is updated.

* [Settings] Related optional messages added to error logs

* Update src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
2023-06-14 10:56:56 +01:00
Laszlo Nemeth
2f130bcc62 [Runner]Fix network errors when checking for updates (#26742)
* General: re-implementing network error handling

* Remove unreferenced dead code

* Minor modification in the update procedure. Removing the code part which updates the UI before the real check on new version. UI will be updated after the real check is done.
2023-06-14 10:55:55 +01:00
gokcekantarci
293b06d083 [File locksmith]Add setting to show only in extended context menu (#26711)
* [File Locksmith] Move File Locksmith "What's using this file?" into the extended context menu

* [File Locksmith] Add FileLocksmithExt to directory background context menu

* [File Locksmith]
* Directory background right click crash fixed.
*Settings added.

* [File Locksmith] Remove uncessary things.

* [File Locksmith] Spell check correction
2023-06-14 10:06:44 +01:00
Laszlo Nemeth
a780e6ae72 [MWB]Fix keyboard hook capturing shortcuts with unneeded modifier keys (#26763)
* Fixing keyboard hook eagerness. capture ctrl+alt keys only if shift and win are NOT pressed.

* Update src/modules/MouseWithoutBorders/App/Class/InputHook.cs
2023-06-13 15:39:45 +01:00
Daniel Odrinski
40ef76a686 [Peek]Add up/down arrow key item navigation (#26644) 2023-06-13 10:37:02 +01:00
Basit Ali
c69c74a8ad [Fancy Zones] Middle click to toggle spanning multiple zones (#26079)
* Attempt to use middle click to toggle zone spanning

* Merge Middle and Secondary Button hooks

* Make mouse state variables more identifiable.
2023-06-13 11:31:22 +02:00
Laszlo Nemeth
06e4518742 [ColorPicker]Store color history in a separated file (#23146)
* [ColorPicker] Store color history in a separated file

* ColorPicker] Separated file for color history: use the list from the settings.json if there is no ColorHistory.json file (preventing loss of existing color history)

* Fix case when there is no history saved or no settings file at all.
2023-06-13 10:10:03 +01:00
Davide Giacometti
0adda35b4b revert content dialog work-around for titlebar overlap (#26648) 2023-06-11 19:51:22 +02:00
Davide Giacometti
97578a1b97 [Hosts]Fix first entry insert and improve UI for empty hosts file (#26671) 2023-06-11 16:59:30 +01:00
Niels Laute
852778daa5 [Settings] Mica & modern titlebar (#25936)
* Adding Mica

* Working Mica

* Fluent titlebar

* Modern titlebar

* Fixing OOBE

* Fix build issue

* Add missing entry to NOTICE.md

* Update App.xaml.cs
2023-06-11 16:54:01 +01:00
Ahnaf Mahmud
56cdd6dd40 [Settings]Update File Explorer module screenshots and instructions for Windows 11 (#26604)
* Update screenshot to Windows 11 Explorer

* Update OOBE screenshot

* Resize image

* Update instructions to reflect Windows 11

* Minor edit to instructions
2023-06-11 16:41:03 +01:00
gokcekantarci
284a5fb31f [ImageResizer]Use updated images from input when pressing Enter(#26292)
* [Image Resizer] HandleEnterKeyPress event added for image resizer.

* [Image Resizer]
* Comments are added to Button_KeyDown function
* Uncessary spaces are removed.

* [Image Resizer] Workaround reasons are added to function summary.
2023-06-11 16:17:59 +01:00
Randy
eddb617484 [Registry Preview] Adds application to Open with list for REG files (#26033)
* 25834

* Asociate Registry Preview with .reg files

* Add setting for making RP default app for .reg files

* Run spellcheck

* Run spellcheck again

* Fix build

---------

Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
2023-06-10 15:02:53 -07:00
Stefan Markovic
b6ff97f795 [Peek][build]Do not use deprecated call GetAppWindow(#26751) 2023-06-09 09:32:24 +01:00
Joseph Finney
d1d7c74440 Improve several small quality of life issues on Text Extractor (#26021) 2023-06-07 10:07:10 -05:00
Stefan Markovic
40335a6998 [Peek] Set button color on theme change (#26564)
* [WIP] Set button color manually

* Remove unused aliases
2023-06-07 15:52:47 +01:00
Seraphima Zykova
026db38457 [Peek]Preview .htm as .html (#26668) 2023-06-07 15:27:32 +01:00
Bradley Myers
13cc22336b [Runner]Partial fix for singleton crash when launching a second process (#25753) 2023-06-07 11:42:51 +01:00
Wilko Lühring
994bb15876 [QuickAccent] Add accent units and other signs (#26522)
---

Co-authored-by: WilkoLu <wilko.luehring@student.jde-hs.de>
Co-authored-by: Eike Rodenbaeck <eike.rodenbaeck@student.jade-hs.de>
Co-authored-by: Colin Sontag <colin.sontag@student.jade-hs.de>
Co-authored-by: Dennis Mehner <dennis.mehner@student.jade-hs.de>
2023-06-06 19:51:53 +01:00
EikeJoo
7e65caa83b [QuickAccent]Add the section sign (U+00A7) to S (#26446)
* add the section sign (U+00A7) to the menu for S

* Remove extra empty line
2023-06-06 16:59:41 +01:00
Davide Giacometti
f6f31c8c32 [Hosts]Don't parse commented lines with an address and host in the middle (#26415) 2023-06-06 16:16:06 +01:00
Davide Giacometti
9960d2d536 [Hosts]Add setting to select the file encoding (#26495) 2023-06-06 16:11:37 +01:00
Aaron Junker
177c58f494 [Monaco] Add support for gitignore files (#26331)
* [Monaco] Add support for gitignore files

* Update definition

* Fix

---------

Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
2023-06-06 16:54:06 +02:00
Aaron Junker
1e481b1162 [Monaco] Switch contect menu items (#26328) 2023-06-06 14:37:23 +02:00
gokcekantarci
ddaa348e5a [PTRun]Integrated lock mechanism for thread-safe Results updates. (#26104) 2023-06-06 13:11:09 +01:00
Aaron Junker
0f6ac52f99 [QuickAccent]Add opening exclamation mark to catalan and spanish language (#26325)
* [QuickAccent]Add opening exclamation mark to catalan and spanish language

* Remove redunant array definitions
2023-06-06 13:07:18 +01:00
Niels Laute
995a9ae7a8 [Chore] Upgrading to WinUIEx 2.2 (#26000)
* Upgrading to WinUIEx 2.2

* Replacing Mica

* Fix build

* Update notice.md

---------

Co-authored-by: Stefan Markovic <stefan@janeasystems.com>
2023-06-05 17:21:48 +02:00
Davide Giacometti
d426d9afde [Hosts] Add Keyboard Shortcuts (#26019)
* added keyboard shortcuts

* use x:Bind
2023-06-05 13:08:41 +01:00
gokcekantarci
4d5152f78a [Runner]Check for updates and bug report on background thread (#25978)
* [Runner] CheckForUpdatesCallback function and ID_REPORT_BUG_COMMAND case in tray_icon moved to threads.

* [Runner] Bool flag added to bug report thread.

* [Runner] Bool flag added to CheckForUpdatesCallback thread.

* [Runner] Review comments added. Uncessary mutex removed. compare_exchange_strong is used for atomic_bool variable checks.
2023-06-05 11:42:06 +01:00
Davide Giacometti
0f6305f5fa [Deps]Bump CommunityToolkit.Mvvm to 8.2.0 (#25992) 2023-06-05 11:02:32 +01:00
Alexander Ilin-Tomich
a012d591c2 [QuickAccent]Add multiplication and division signs (#25790)
* Add multiplication and division signs to Languages.cs

Adds multiplication (U+00D7, U+22C5) and division (U+00F7) signs to Languages.cs

* Add slash and asterisk to KeyboardListener.h

* Add slash, asterisk to KeyboardListener.idl

* Update Languages.cs

* VK_ASTERISK -> VK_MULTIPLY KeyboardListener.idl

* VK_ASTERISK -> VK_MULTIPLY Languages.cs

* VK_ASTERISK -> VK_MULTIPLY KeyboardListener.h

* Add VK_DIVIDE to Languages.cs

* Add VK_DIVIDE to KeyboardListener.h

* Add VK_DIVIDE to KeyboardListener.idl

* avoid protected names Languages.cs

* avoid protected names KeyboardListener.h

* avoid protected names KeyboardListener.idl
2023-06-05 10:03:52 +01:00
Clint Rutkas
792a77437e Test loc fix #2 (#26544)
* Test loc fix #2

* Propagate the name change to the rest of the project

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2023-06-01 19:04:15 -07:00
Clint Rutkas
2981dc67c3 Update README.md (#26577) 2023-06-01 18:22:04 -07:00
Andrey Nekrasov
e378f0cebc [MWB]Improve UX for Uninstall service when it's inaccessible (#26525) 2023-05-31 17:14:26 +01:00
Jaime Bernardo
88656a9fe0 [MWB]Simulate input to gain focus when hiding mouse (#26524)
* [MWB]Simulate input to gain focus when hiding mouse

* Little tooltip fix
2023-05-31 16:59:15 +01:00
Jaime Bernardo
0f04180912 [MWB]Work without service if service doesn't start (#26521) 2023-05-31 15:50:48 +01:00
Jaime Bernardo
f6a91dd073 [Installer]Keep MWB service on upgrade (#26517) 2023-05-31 13:55:13 +01:00
Andrey Nekrasov
4cc74da82f [MWB]Remove shortcut for deprecated VKMap functionality(#26484)
* Comment out code hooking Ctrl+Shift+Alt+K to toggle unused UseVKMap setting

* [MWB] Remove UseVKMap and VKMap completely

---------

Co-authored-by: David Taylor <davidt@yadt.co.uk>
2023-05-30 17:46:42 +01:00
Stefan Markovic
b50b587a63 [Peek] Fix race condition when setting preview (#26478) 2023-05-30 15:58:56 +01:00
Jaime Bernardo
ce87952058 [Peek]Close on activation shortcut if focused (#26480) 2023-05-30 15:58:42 +01:00
Jaime Bernardo
88b1203cd6 [Peek]Fix foreground window setting (#26473) 2023-05-30 14:58:32 +01:00
Andrey Nekrasov
1d23ed5811 [MWB]Prevent spurious wakeups so screens can turn off(#26476) 2023-05-30 14:56:45 +01:00
Seraphima Zykova
b72af5e247 [Peek] Fix crash when opening Peek with no files selected (#26470)
* catch exception

* Check count of items to avoid the exception being thrown

* Fix regression from #26364

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2023-05-30 11:56:07 +01:00
Jaime Bernardo
4905258c94 [MWB]Hide cursor when positioning to the top of screen (#26447) 2023-05-30 09:45:27 +01:00
gokcekantarci
0c69e3422c [Peek]Add setting to close after losing focus (#26364)
* [Peek] WindowActivationState checks are added for focus and close after losing focus.

* Add setting to activate the behavior

---------

Co-authored-by: Jaime Bernardo <jaime@janeasystems.com>
2023-05-30 09:44:58 +01:00
Seraphima Zykova
9786d08695 [Peek]Clear thumbnails (#26440) 2023-05-30 09:43:58 +01:00
Andrey Nekrasov
202bb4caf5 [MWB] fix layout resetting to one row (#26438) 2023-05-29 17:00:23 +01:00
Ryan
951d449204 [Dev]Winget Configuration File for PowerToys (#26259)
* configuration

* Update expect.txt

fixing spelling

* fix folder name

---------

Co-authored-by: Clint Rutkas <clint@rutkas.com>
2023-05-29 15:30:01 +01:00
Andrey Nekrasov
ecdf4217e4 [MWB] fix machine connection status highlighting (#26439) 2023-05-29 15:18:57 +01:00
Stefan Markovic
61073158c2 [monaco][dev files prev][Peek] Support .vbproj and .fsproj (#26431) 2023-05-29 14:52:02 +02:00
Aaron Junker
d7ff0d06ec [Monaco]Add vbs and certain ini compatible file extensions (#26373)
* [Monaco] Add vbs and inf file extensions

* Add githconfig, gitattributes, editorconfig
2023-05-29 12:27:13 +01:00
Stefan Markovic
850b8c1fb8 [Peek] Reset Image and Browser sources (#26361) 2023-05-29 10:01:20 +02:00
Samuel Chapleau
95a9a8a2b0 Use effective pixels for unsupported previewer (#26345) 2023-05-26 12:46:43 -07:00
Samuel Chapleau
6d676329ce [Peek]Center Peek window on File Explorer activated monitor (#26349) 2023-05-26 16:50:15 +01:00
Stefan Markovic
d3b1c0a067 [Peek] Reset Sources on Peek close (#26310)
* Reset Sources on Peek close

* Revert "Reset Sources on Peek close"

This reverts commit 6b63e809ef.

* Reset Source in OnPreviewerChanging
2023-05-26 10:17:50 +01:00
Seraphima Zykova
b56d22b9a2 [Peek]Fix blinking while loading dev files (#26342) 2023-05-26 09:47:32 +01:00
Stefan Markovic
5cff678322 [Monaco][Peek] Support .vsconfig, .sln, .vcproj, .vcxproj files (#26318) 2023-05-26 09:46:12 +02:00
Jaime Bernardo
42e707966d [Peek]Create Setting to run not elevated (#26308)
* [Peek]Create Setting to run not elevated

* Optionally add access permissions to the handles
2023-05-25 17:39:52 +01:00
Davide Giacometti
4560abe557 [Peek]Hide window with esc key (#26250) 2023-05-25 17:35:17 +01:00
Stefan Markovic
6f56b35a6c [General]Fix infinite loop: AutoReset global event in NativeEventWaiter (#26287) 2023-05-25 16:19:24 +01:00
Andrey Nekrasov
dbc11b8920 [MWB] add Name2IP field to Settings (#26290)
* [MWB] add Name2IP field to Settings

* f: add explanation

* f: spelling

* f: comment
2023-05-25 15:55:11 +01:00
Jaime Bernardo
0bf4cfd8b5 [Hotfix][Peek]Consume shortcut only on Desktop and Shell (#26222)
* [Peek]Consume shortcut only on Desktop and Shell

* Appease spellchecker
2023-05-25 10:27:21 +01:00
Jaime Bernardo
6a4a5c59d7 [BugReport][Install]Fix process lists for Peek and MWB (#26235) 2023-05-25 10:26:52 +01:00
Davide Giacometti
22e4c4ce2a [Installer][PTRun]Fix PowerToys plugin setup (#26157) 2023-05-25 10:26:21 +01:00
Niels Laute
667aad247a [Settings] MWB and Peek improvements (#26142)
* Improvements to MWB

* Adding link to Peek

* Address feedback

* Fix localization
2023-05-25 10:10:52 +01:00
Jaime Bernardo
675aac95d2 [ci]Fix winget automation by overriding scope (#26230) 2023-05-24 17:07:43 +01:00
Heiko
e87de7d9fc [Github templates] Add Peek and MouseWithoutBorders (#26153)
* Update translation_issue.yml

* Fix typo in translation.yml

* Update bug_report.yml

* Update version in translation_issue.yml

* Update version in bug_report.yml
2023-05-23 22:51:03 +02:00
Jaime Bernardo
aea02117fd 0.70 changelogs (#26124)
Co-authored-by: Clint Rutkas <clint@rutkas.com>
2023-05-23 08:28:05 -07:00
267 changed files with 5408 additions and 3268 deletions

View File

@@ -0,0 +1,34 @@
# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
# Reference: https://github.com/microsoft/PowerToys/blob/main/doc/devdocs/readme.md#compiling-powertoys
properties:
resources:
- resource: Microsoft.Windows.Developer/DeveloperMode
directives:
description: Enable Developer Mode
allowPrerelease: true
settings:
Ensure: Present
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: vsPackage
directives:
description: Install Visual Studio 2022 (any edition is OK)
allowPrerelease: true
settings:
id: Microsoft.VisualStudio.2022.Community
source: winget
- resource: Microsoft.VisualStudio.DSC/VSComponents
dependsOn:
- vsPackage
directives:
description: Install required VS workloads
allowPrerelease: true
settings:
productId: Microsoft.VisualStudio.Product.Community
channelId: VisualStudio.17.Release
vsConfigFile: '${WinGetConfigRoot}\..\.vsconfig'
configurationVersion: 0.2.0
# Next steps:
# Open a terminal
# Navigate to the folder you cloned PowerToys to.
# Run git submodule update --init --recursive

View File

@@ -10,7 +10,7 @@ body:
- type: input
attributes:
label: Microsoft PowerToys version
placeholder: 0.68.0
placeholder: 0.70.0
description: Hover over system tray icon or look at Settings
validations:
required: true
@@ -60,7 +60,9 @@ body:
- Installer
- Keyboard Manager
- Mouse Utilities
- Mouse Without Borders
- Paste as Plain Text
- Peek
- PowerRename
- PowerToys Run
- Quick Accent

View File

@@ -12,7 +12,7 @@ body:
- type: input
attributes:
label: Microsoft PowerToys version
placeholder: 0.68.0
placeholder: 0.70.0
description: Hover over system tray icon or look at Settings
validations:
required: true
@@ -34,7 +34,9 @@ body:
- Installer
- Keyboard Manager
- Mouse Utilities
- Mouse Without Borders
- Paste as Plain Text
- Peek
- PowerRename
- PowerToys Run
- Quick Accent

View File

@@ -91,7 +91,6 @@ APPIDS
appium
Applets
Applicationcan
applicationconfiguration
applicationframehost
appmanifest
APPNAME
@@ -158,7 +157,6 @@ BCB
BCCE
BCCEA
bck
Bcl
BDB
BDBAD
BDCC
@@ -239,7 +237,6 @@ Cangjie
CANRENAME
CAPTUREBLT
CAPTURECHANGED
CARRAY
CAtl
CBA
CBB
@@ -281,7 +278,6 @@ chdir
CHILDACTIVATE
CHILDWINDOW
chrdavis
Chromakey
Chrzan
CHT
cidl
@@ -424,7 +420,6 @@ Dac
dacl
DAF
damienleroy
DANGEROUSLYCOMMITMERELYTODISKCACHE
DARKPURPLE
DARKTEAL
DARKYELLOW
@@ -456,13 +451,11 @@ dcompi
DComposition
dcr
dcs
Dct
DDCDD
DDCE
DDEIf
DDevice
ddf
Dds
DDxgi
Deact
debian
@@ -494,8 +487,6 @@ depersist
deprioritized
depsfileslistspath
deref
READOBJECTS
WRITEOBJECTS
DESKTOPABSOLUTEEDITING
DESKTOPABSOLUTEPARSING
desktopshorcutinstalled
@@ -545,6 +536,7 @@ drawingcolor
dreamsofameaningfullife
drf
drivedetectionwarning
dsc
dshow
DSTINVERT
DUMMYUNIONNAME
@@ -622,6 +614,7 @@ Emoji
ENABLEDELAYEDEXPANSION
enabledisable
ENABLEDPOPUP
encodedlaunch
encryptor
endpointvolume
endregion
@@ -662,8 +655,6 @@ exabyte
examplehandler
examplepowertoy
EXAND
Excep
EXCEPINFO
EXCLUDEFROMCAPTURE
exdisp
executionpolicy
@@ -788,7 +779,6 @@ GETSTATE
GETTEXT
GETTEXTLENGTH
GHND
Globbing
GMEM
GNumber
google
@@ -833,7 +823,6 @@ HCRYPTHASH
HCRYPTPROV
hcwhite
hdc
HDR
hdrop
hdwwiz
HEB
@@ -915,17 +904,12 @@ HWNDPREV
hyjiacan
IBase
IBeam
IBitmap
IBlock
ICapture
ICEBLUE
IClass
IColor
ICONERROR
IContext
IData
IDD
IDecoder
IDesktop
IDirect
idl
@@ -934,7 +918,6 @@ IDOn
IDR
idx
IDXGI
IEncoder
IEnum
IExec
IEXPLORE
@@ -959,7 +942,6 @@ imageresizerinput
imageresizersettings
imagingdevices
ime
IMetadata
imeutil
inetcpl
Infobar
@@ -997,8 +979,6 @@ Interlop
INTRESOURCE
INVALIDARG
invalidoperatioexception
invalidkey
IPalette
ipc
ipcmanager
IPlugin
@@ -1007,8 +987,6 @@ IPREVIEW
ipreviewhandlervisualssetfont
IProperty
IPublic
IQuery
IReader
irprops
isbi
ISearch
@@ -1016,15 +994,14 @@ ISettings
isfinite
IShell
isocpp
ISource
iss
ISurface
ITask
ith
ITHUMBNAIL
IUI
IUnknown
IWbem
IWeb
IWIC
iwr
IYUV
@@ -1106,10 +1083,12 @@ lexon
lhs
lhwnd
LIBID
licate
LIGHTORANGE
LIGHTTURQUOISE
lindex
linkedin
LINKOVERLAY
linq
LINQTo
listview
@@ -1128,8 +1107,6 @@ LOCALPACKAGE
localport
LOCALSYSTEM
LOCATIONCHANGE
LOCKBYTES
LOCKTYPE
LOGFONT
LOGFONTW
logon
@@ -1151,12 +1128,12 @@ LPCWSTR
lpdw
lpfn
LPINPUT
LPQUERY
lpmi
LPMINMAXINFO
LPMONITORINFO
LPOSVERSIONINFOEXW
LPPOINT
LPQUERY
lprc
LPRECT
LPSAFEARRAY
@@ -1324,11 +1301,11 @@ Mul
MULTIPLEUSE
multizone
mvvm
mwb
MWBEx
myfile
MYICON
mysql
mwb
MWBEx
NAMECHANGE
nameof
namespaceanddescendants
@@ -1356,6 +1333,7 @@ NCRBUTTONUP
NCRENDERING
ndp
NEEDDISPATCH
needinfo
Nemeth
NESW
netcore
@@ -1401,7 +1379,6 @@ NONCONVERT
NONELEVATED
NONINFRINGEMENT
nonstd
NOOPEN
NOOWNERZORDER
NOPARENTNOTIFY
NOREDIRECTIONBITMAP
@@ -1441,6 +1418,7 @@ nullonfailure
numberbox
NUMLOCK
numpad
nupkg
nwc
Objbase
OBJID
@@ -1464,8 +1442,6 @@ OLEDB
OLIVEGREEN
onebranch
onenote
ONLYIFCURRENT
ONLYONCE
onstd
oobe
OOBEPT
@@ -1528,6 +1504,7 @@ pcs
PCWSTR
pdb
pdbonly
pdisp
pdo
pdto
pdtobj
@@ -1565,7 +1542,6 @@ pinvoke
pipename
PKBDLLHOOKSTRUCT
pkey
PKEY
plib
PLK
ploc
@@ -1598,7 +1574,6 @@ ppidl
ppmt
pprm
pproc
pprop
ppshv
ppsi
ppsid
@@ -1619,7 +1594,6 @@ previouscamera
PREVIOUSINSTALLFOLDER
PREVIOUSVERSIONSINSTALLED
prevpane
PRGBA
prgms
pri
PRINTCLIENT
@@ -1636,20 +1610,17 @@ PROGRAMFILES
projectname
PROPBAG
PROPERTYKEY
PROPERTYNOTFOUND
propkey
PROPVARIANT
propvarutil
prvpane
psapi
pscid
PSECURITY
psfgao
psfi
Psr
psrm
psrree
pstatstg
pstm
pstr
pstream
pstrm
@@ -1663,7 +1634,6 @@ PToy
ptstr
pui
PULONG
pvar
pwa
pwcs
pwsh
@@ -1703,6 +1673,7 @@ rclsid
RCONTROL
RCtrl
READMODE
READOBJECTS
READWRITE
RECTDESTINATION
RECTL
@@ -1748,6 +1719,7 @@ renamable
RENAMEONCOLLISION
Renamer
reparse
reportbug
requery
requerying
rescap
@@ -1765,7 +1737,6 @@ resw
resx
retval
rfc
RGBE
RGBQUAD
rgbs
rgelt
@@ -1808,7 +1779,6 @@ rungameid
RUNLEVEL
runsettings
runtimeclass
runtimeconfig
runtimedepsjsonpath
runtimeobject
runtimepack
@@ -1824,7 +1794,6 @@ ryanbodrug
saahmedm
sachaple
sacl
SAFEARRAY
safeprojectname
SAMEKEYPREVIOUSLYMAPPED
SAMESHORTCUTPREVIOUSLYMAPPED
@@ -1855,7 +1824,6 @@ sendvirtualinput
Seperate
Seraphima
serverside
Ses
SETCONTEXT
setcursor
setenv
@@ -1873,6 +1841,7 @@ setzero
sfgao
SFGAOF
SFP
SHANDLE
sharpkeys
SHCNE
SHCNF
@@ -1888,6 +1857,7 @@ shellscalingapi
SHFILEINFO
SHGDNF
SHGFI
shinfo
Shl
shldisp
shlobj
@@ -1943,7 +1913,6 @@ SMALLICON
smartphone
SMTO
snd
sni
snwprintf
softline
somil
@@ -1971,7 +1940,6 @@ SRCPAINT
sre
SResize
srf
SRGB
srme
srre
srw
@@ -2000,10 +1968,8 @@ STDMETHODCALLTYPE
STDMETHODIMP
stefan
Stereolithography
STGC
STGM
STGMEDIUM
STGTY
sticpl
stl
storelogo
@@ -2077,8 +2043,8 @@ taskschd
tchar
tcl
Tcollab
tcs
tcp
tcs
tcscpy
TCustom
tdbuild
@@ -2097,6 +2063,7 @@ TEXCOORD
textblock
TEXTEXTRACTOR
TEXTINCLUDE
tgz
themeresources
THH
THICKFRAME
@@ -2161,8 +2128,10 @@ uipi
UIs
ULARGE
ULONGLONG
unapply
unassign
uncompilable
Uncompress
UNCPRIORITY
UNDNAME
UNICODETEXT
@@ -2192,7 +2161,6 @@ Usb
USEDEFAULT
USEFILEATTRIBUTES
USERDATA
USERDEFINED
USERDOMAIN
userprofile
USESHOWWINDOW
@@ -2209,7 +2177,6 @@ vabdq
validmodulename
Vanara
variantassignment
VARTYPE
vcamp
vccorlib
vcdl
@@ -2229,7 +2196,6 @@ VERBSONLY
VERBW
VERIFYCONTEXT
verrsrc
VERSIONED
VERSIONINFO
Versioning
VFT
@@ -2329,8 +2295,8 @@ winget
wingetcreate
Winhook
winkey
winlogon
WINL
winlogon
winmd
winmm
WINNT
@@ -2387,6 +2353,7 @@ wregex
WReserved
WResize
writefile
WRITEOBJECTS
Wrk
wrl
WSAEADDRINUSE
@@ -2398,7 +2365,6 @@ wsh
wsl
wss
wstr
wsystem
wsz
wtoi
WTS
@@ -2442,7 +2408,6 @@ yinyue
YOffset
YPels
ypescript
YQuantized
YResolution
YStr
YUY

929
.github/fabricbot.json vendored
View File

@@ -1,929 +0,0 @@
{
"version": "1.0",
"tasks": [
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssuesOnlyResponder",
"version": "1.0",
"config": {
"taskName": "Add needs triage label to new issues",
"conditions": {
"operator": "and",
"operands": [
{
"name": "isAction",
"parameters": {
"action": "opened"
}
},
{
"operator": "not",
"operands": [
{
"name": "isPartOfProject",
"parameters": {}
}
]
},
{
"operator": "not",
"operands": [
{
"name": "isAssignedToSomeone",
"parameters": {}
}
]
}
]
},
"actions": [
{
"name": "addLabel",
"parameters": {
"label": "Needs-Triage"
}
}
],
"eventType": "issue",
"eventNames": [
"issues",
"project_card"
]
},
"id": "eUOhvA_62"
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssueCommentResponder",
"version": "1.0",
"config": {
"taskName": "Replace needs author feedback label with needs attention label when the author comments on an issue",
"conditions": {
"operator": "and",
"operands": [
{
"name": "isAction",
"parameters": {
"action": "created"
}
},
{
"name": "isActivitySender",
"parameters": {
"user": {
"type": "author"
}
}
},
{
"name": "hasLabel",
"parameters": {
"label": "Needs-Author-Feedback"
}
},
{
"name": "isOpen",
"parameters": {}
}
]
},
"actions": [
{
"name": "addLabel",
"parameters": {
"label": "Needs-Triage"
}
},
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Author-Feedback"
}
},
{
"name": "addLabel",
"parameters": {
"label": "Needs-Team-Response"
}
}
],
"eventType": "issue",
"eventNames": [
"issue_comment"
]
},
"id": "kgfxdBIu_9"
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssuesOnlyResponder",
"version": "1.0",
"config": {
"taskName": "Remove no recent activity label from issues",
"conditions": {
"operator": "and",
"operands": [
{
"operator": "not",
"operands": [
{
"name": "isAction",
"parameters": {
"action": "closed"
}
}
]
},
{
"name": "hasLabel",
"parameters": {
"label": "Status-No recent activity"
}
}
]
},
"actions": [
{
"name": "removeLabel",
"parameters": {
"label": "Status-No recent activity"
}
}
],
"eventType": "issue",
"eventNames": [
"issues",
"project_card"
]
},
"id": "eR-TaGJJzW",
"disabled": false
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssueCommentResponder",
"version": "1.0",
"config": {
"taskName": "Remove no recent activity label when an issue is commented on",
"conditions": {
"operator": "and",
"operands": [
{
"name": "hasLabel",
"parameters": {
"label": "Status-No recent activity"
}
}
]
},
"actions": [
{
"name": "removeLabel",
"parameters": {
"label": "Status-No recent activity"
}
}
],
"eventType": "issue",
"eventNames": [
"issue_comment"
]
},
"id": "tXKeoDht_g",
"disabled": false
},
{
"taskType": "scheduled",
"capabilityId": "ScheduledSearch",
"subCapability": "ScheduledSearch",
"version": "1.1",
"config": {
"taskName": "Close stale issues",
"frequency": [
{
"weekDay": 0,
"hours": [
1,
7,
13,
19
]
},
{
"weekDay": 1,
"hours": [
1,
7,
13,
19
]
},
{
"weekDay": 2,
"hours": [
1,
7,
13,
19
]
},
{
"weekDay": 3,
"hours": [
1,
7,
13,
19
]
},
{
"weekDay": 4,
"hours": [
1,
7,
13,
19
]
},
{
"weekDay": 5,
"hours": [
1,
7,
13,
19
]
},
{
"weekDay": 6,
"hours": [
1,
7,
13,
19
]
}
],
"searchTerms": [
{
"name": "isIssue",
"parameters": {}
},
{
"name": "isOpen",
"parameters": {}
},
{
"name": "hasLabel",
"parameters": {
"label": "Needs-Author-Feedback"
}
},
{
"name": "hasLabel",
"parameters": {
"label": "Status-No recent activity"
}
},
{
"name": "noActivitySince",
"parameters": {
"days": 5
}
}
],
"actions": [
{
"name": "closeIssue",
"parameters": {}
}
]
},
"id": "8yr-nVZj9k",
"disabled": false
},
{
"taskType": "scheduled",
"capabilityId": "ScheduledSearch",
"subCapability": "ScheduledSearch",
"version": "1.1",
"config": {
"taskName": "Add no recent activity label to issues",
"frequency": [
{
"weekDay": 0,
"hours": [
2,
8,
14,
20
]
},
{
"weekDay": 1,
"hours": [
2,
8,
14,
20
]
},
{
"weekDay": 2,
"hours": [
2,
8,
14,
20
]
},
{
"weekDay": 3,
"hours": [
2,
8,
14,
20
]
},
{
"weekDay": 4,
"hours": [
2,
8,
14,
20
]
},
{
"weekDay": 5,
"hours": [
2,
8,
14,
20
]
},
{
"weekDay": 6,
"hours": [
2,
8,
14,
20
]
}
],
"searchTerms": [
{
"name": "isIssue",
"parameters": {}
},
{
"name": "isOpen",
"parameters": {}
},
{
"name": "hasLabel",
"parameters": {
"label": "Needs-Author-Feedback"
}
},
{
"name": "noActivitySince",
"parameters": {
"days": 5
}
},
{
"name": "noLabel",
"parameters": {
"label": "Status-No recent activity"
}
}
],
"actions": [
{
"name": "addLabel",
"parameters": {
"label": "Status-No recent activity"
}
},
{
"name": "addReply",
"parameters": {
"comment": "This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **5 days**. It will be closed if no further activity occurs **within 5 days of this comment**."
}
}
]
},
"id": "DAhxoYjVcq",
"disabled": false
},
{
"taskType": "scheduled",
"capabilityId": "ScheduledSearch",
"subCapability": "ScheduledSearch",
"version": "1.1",
"config": {
"taskName": "Close duplicate issues",
"frequency": [
{
"weekDay": 0,
"hours": [
3,
9,
15,
21
]
},
{
"weekDay": 1,
"hours": [
3,
9,
15,
21
]
},
{
"weekDay": 2,
"hours": [
3,
9,
15,
21
]
},
{
"weekDay": 3,
"hours": [
3,
9,
15,
21
]
},
{
"weekDay": 4,
"hours": [
3,
9,
15,
21
]
},
{
"weekDay": 5,
"hours": [
3,
9,
15,
21
]
},
{
"weekDay": 6,
"hours": [
3,
9,
15,
21
]
}
],
"searchTerms": [
{
"name": "isIssue",
"parameters": {}
},
{
"name": "isOpen",
"parameters": {}
},
{
"name": "hasLabel",
"parameters": {
"label": "Resolution-Duplicate"
}
},
{
"name": "noActivitySince",
"parameters": {
"days": 1
}
}
],
"actions": [
{
"name": "addReply",
"parameters": {
"comment": "This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes."
}
},
{
"name": "closeIssue",
"parameters": {}
}
]
},
"id": "xGhARy1H0w"
},
{
"taskType": "trigger",
"capabilityId": "InPrLabel",
"subCapability": "InPrLabel",
"version": "1.0",
"config": {
"taskName": "Add 'In-PR' label on issue when an open pull request is targeting it",
"inPrLabelText": "Status: In PR",
"fixedLabelText": "Status: Fixed",
"fixedLabelEnabled": true,
"label_fixed": "Resolution-Fix-Committed",
"label_inPr": "In progress"
},
"id": "Rn1tANe62T"
},
{
"taskType": "trigger",
"capabilityId": "EmailCleanser",
"subCapability": "EmailCleanser",
"version": "1.0",
"id": "X0O-6aZ1v3_DAmhUIcNb2",
"config": {
"taskName": "Clean the email stuff"
}
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssueCommentResponder",
"version": "1.0",
"id": "VyV9JJSA8SbOyeWEwjyfL",
"config": {
"conditions": {
"operator": "and",
"operands": [
{
"name": "commentContains",
"parameters": {
"commentPattern": "\\/(bugreport|reportbug)",
"isRegex": true
}
},
{
"operator": "or",
"operands": [
{
"name": "activitySenderHasAssociation",
"parameters": {
"permissions": "admin",
"association": "MEMBER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "OWNER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "COLLABORATOR"
}
}
]
}
]
},
"eventType": "issue",
"eventNames": [
"issue_comment"
],
"taskName": "Ask for bug report zip file",
"actions": [
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Triage"
}
},
{
"name": "addLabel",
"parameters": {
"label": "Needs-Author-Feedback"
}
},
{
"name": "addReply",
"parameters": {
"comment": "Hi there!<br/><br/>We need a bit more information to really debug this issue. Can you add a \"Report Bug\" zip file here? You right click on our system tray icon and just go to report bug. Then drag the zipfile from your desktop onto the GitHub comment box in this issue. Thanks! <br/>![Report Bug](https://user-images.githubusercontent.com/11349917/133042052-4975be21-4699-4363-83c9-a8e1869d079d.png)"
}
},
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Team-Response"
}
}
]
}
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssueCommentResponder",
"version": "1.0",
"id": "bvMkigH2HPgUniYFCNco9",
"config": {
"conditions": {
"operator": "and",
"operands": [
{
"name": "commentContains",
"parameters": {
"isRegex": true,
"commentPattern": "\\/feedback[H|h]ub"
}
},
{
"operator": "or",
"operands": [
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "OWNER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "MEMBER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "COLLABORATOR"
}
}
]
}
]
},
"eventType": "issue",
"eventNames": [
"issue_comment"
],
"taskName": "Helper to mark as feedback hub",
"actions": [
{
"name": "addReply",
"parameters": {
"comment": "Hi! We've identified this issue that best is suited for Windows Feedback Hub. To do this on Windows, WinKey+F will bring it up!"
}
},
{
"name": "closeIssue",
"parameters": {}
},
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Triage"
}
},
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Team-Response"
}
},
{
"name": "addLabel",
"parameters": {
"label": "Resolution-Please File on Feedback Hub"
}
}
]
}
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssueCommentResponder",
"version": "1.0",
"id": "bvMkigH2HPgUniYFCNco8",
"config": {
"conditions": {
"operator": "and",
"operands": [
{
"name": "commentContains",
"parameters": {
"isRegex": true,
"commentPattern": "\\/dup(licate|e)?(\\s+of)?\\s+(#[\\d]+|https)"
}
},
{
"operator": "or",
"operands": [
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "OWNER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "MEMBER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "COLLABORATOR"
}
}
]
}
]
},
"eventType": "issue",
"eventNames": [
"issue_comment"
],
"taskName": "Helper to mark as duplicate",
"actions": [
{
"name": "addReply",
"parameters": {
"comment": "Hi! We've identified this issue as a duplicate of another one that already exists on this Issue Tracker. This specific instance is being closed in favor of tracking the concern over on the referenced thread. Thanks for your report!"
}
},
{
"name": "closeIssue",
"parameters": {}
},
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Triage"
}
},
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Team-Response"
}
},
{
"name": "addLabel",
"parameters": {
"label": "Resolution-Duplicate"
}
}
]
}
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssueCommentResponder",
"version": "1.0",
"id": "mgZxIoqeF7GWUo7-tZF56",
"config": {
"conditions": {
"operator": "and",
"operands": [
{
"name": "commentContains",
"parameters": {
"commentPattern": "\\/needinfo",
"isRegex": true
}
},
{
"operator": "or",
"operands": [
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "OWNER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "MEMBER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "COLLABORATOR"
}
}
]
}
]
},
"eventType": "issue",
"eventNames": [
"issue_comment"
],
"actions": [
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Triage"
}
},
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Team-Response"
}
},
{
"name": "addLabel",
"parameters": {
"label": "Needs-Author-Feedback"
}
}
],
"taskName": "Author Response needed"
}
},
{
"taskType": "trigger",
"capabilityId": "IssueResponder",
"subCapability": "IssueCommentResponder",
"version": "1.0",
"id": "mgZxIoqeF7GWUo7-t3773",
"config": {
"conditions": {
"operator": "and",
"operands": [
{
"name": "commentContains",
"parameters": {
"commentPattern": "\\/loc\\b",
"isRegex": true
}
},
{
"operator": "or",
"operands": [
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "OWNER"
}
},
{
"name": "activitySenderHasAssociation",
"parameters": {
"association": "MEMBER"
}
}
]
}
]
},
"eventType": "issue",
"eventNames": [
"issue_comment"
],
"actions": [
{
"name": "removeLabel",
"parameters": {
"label": "Needs-Triage"
}
},
{
"name": "addLabel",
"parameters": {
"label": "Loc-Sent To Team"
}
},
{
"name": "addReply",
"parameters": {
"comment": "Hi! Thanks for making us aware of the problem. We raised the issue with our internal localization team. This issue should be fixed hopefully in the next version of PowerToys."
}
}
],
"taskName": "Filed ADO item with Localization team"
}
}
],
"userGroups": []
}

214
.github/policies/resourceManagement.yml vendored Normal file
View File

@@ -0,0 +1,214 @@
id:
name: GitOps.PullRequestIssueManagement
description: GitOps.PullRequestIssueManagement primitive
owner:
resource: repository
disabled: false
where:
configuration:
resourceManagementConfiguration:
scheduledSearches:
- description:
frequencies:
- hourly:
hour: 6
filters:
- isIssue
- isOpen
- hasLabel:
label: Needs-Author-Feedback
- hasLabel:
label: Status-No recent activity
- noActivitySince:
days: 5
actions:
- closeIssue
- description:
frequencies:
- hourly:
hour: 6
filters:
- isIssue
- isOpen
- hasLabel:
label: Needs-Author-Feedback
- noActivitySince:
days: 5
- isNotLabeledWith:
label: Status-No recent activity
actions:
- addLabel:
label: Status-No recent activity
- addReply:
reply: This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for **5 days**. It will be closed if no further activity occurs **within 5 days of this comment**.
- description:
frequencies:
- hourly:
hour: 6
filters:
- isIssue
- isOpen
- hasLabel:
label: Resolution-Duplicate
- noActivitySince:
days: 1
actions:
- addReply:
reply: This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes.
- closeIssue
eventResponderTasks:
- if:
- payloadType: Issue_Comment
- isAction:
action: Created
- isActivitySender:
issueAuthor: True
- hasLabel:
label: Needs-Author-Feedback
- isOpen
then:
- addLabel:
label: Needs-Triage
- removeLabel:
label: Needs-Author-Feedback
- addLabel:
label: Needs-Team-Response
description:
- if:
- payloadType: Issues
- not:
isAction:
action: Closed
- hasLabel:
label: Status-No recent activity
then:
- removeLabel:
label: Status-No recent activity
description:
- if:
- payloadType: Issue_Comment
- hasLabel:
label: Status-No recent activity
then:
- removeLabel:
label: Status-No recent activity
description:
- if:
- payloadType: Pull_Request
then:
- inPrLabel:
label: Status-In progress
description:
- if:
- payloadType: Issue_Comment
then:
- cleanEmailReply
description:
- if:
- payloadType: Issue_Comment
- commentContains:
pattern: '\/(bugreport|reportbug)'
isRegex: True
- or:
- activitySenderHasAssociation:
association: Member
- activitySenderHasAssociation:
association: Owner
- activitySenderHasAssociation:
association: Collaborator
then:
- removeLabel:
label: Needs-Triage
- addLabel:
label: Needs-Author-Feedback
- addReply:
reply: Hi there!<br/><br/>We need a bit more information to really debug this issue. Can you add a "Report Bug" zip file here? You right click on our system tray icon and just go to report bug. Then drag the zipfile from your desktop onto the GitHub comment box in this issue. Thanks! <br/>![Report Bug](https://user-images.githubusercontent.com/11349917/133042052-4975be21-4699-4363-83c9-a8e1869d079d.png)
- removeLabel:
label: Needs-Team-Response
description:
- if:
- payloadType: Issue_Comment
- commentContains:
pattern: '\/feedback[H|h]ub'
isRegex: True
- or:
- activitySenderHasAssociation:
association: Owner
- activitySenderHasAssociation:
association: Member
- activitySenderHasAssociation:
association: Collaborator
then:
- addReply:
reply: Hi! We've identified this issue that best is suited for Windows Feedback Hub. To do this on Windows, WinKey+F will bring it up!
- closeIssue
- removeLabel:
label: Needs-Triage
- removeLabel:
label: Needs-Team-Response
- addLabel:
label: Resolution-Please File on Feedback Hub
description:
- if:
- payloadType: Issue_Comment
- commentContains:
pattern: '\/dup(licate|e)?(\s+of)?\s+(\#[\d]+|https)'
isRegex: True
- or:
- activitySenderHasAssociation:
association: Owner
- activitySenderHasAssociation:
association: Member
- activitySenderHasAssociation:
association: Collaborator
then:
- addReply:
reply: Hi! We've identified this issue as a duplicate of another one that already exists on this Issue Tracker. This specific instance is being closed in favor of tracking the concern over on the referenced thread. Thanks for your report!
- closeIssue
- removeLabel:
label: Needs-Triage
- removeLabel:
label: Needs-Team-Response
- addLabel:
label: Resolution-Duplicate
description:
- if:
- payloadType: Issue_Comment
- commentContains:
pattern: '\/needinfo'
isRegex: True
- or:
- activitySenderHasAssociation:
association: Owner
- activitySenderHasAssociation:
association: Member
- activitySenderHasAssociation:
association: Collaborator
then:
- removeLabel:
label: Needs-Triage
- removeLabel:
label: Needs-Team-Response
- addLabel:
label: Needs-Author-Feedback
description:
- if:
- payloadType: Issue_Comment
- commentContains:
pattern: '\/loc\b'
isRegex: True
- or:
- activitySenderHasAssociation:
association: Owner
- activitySenderHasAssociation:
association: Member
then:
- removeLabel:
label: Needs-Triage
- addLabel:
label: Loc-Sent To Team
- addReply:
reply: Hi! Thanks for making us aware of the problem. We raised the issue with our internal localization team. This issue should be fixed hopefully in the next version of PowerToys.
description:
onFailure:
onSuccess:

View File

@@ -28,4 +28,4 @@ jobs:
# getting latest wingetcreate file
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
.\wingetcreate.exe update $wingetPackage -s -v $ver -u $installerUserX64Url $installerMachineX64Url $installerUserArmUrl $installerMachineArmUrl -t $gitToken
.\wingetcreate.exe update $wingetPackage -s -v $ver -u "$installerUserX64Url|user" "$installerMachineX64Url|machine" "$installerUserArmUrl|user" "$installerMachineArmUrl|machine" -t $gitToken

View File

@@ -279,6 +279,7 @@
"modules\\MouseWithoutBorders\\MessagePack.Annotations.dll",
"modules\\MouseWithoutBorders\\MessagePack.dll",
"modules\\MouseWithoutBorders\\Nerdbank.Streams.dll",
"modules\\Peek\\SharpCompress.dll",
"Settings\\Microsoft.Graphics.Canvas.Interop.dll",
"Settings\\clrcompression.dll",
"Settings\\CommunityToolkit.Labs.WinUI.SettingsControls.dll",

View File

@@ -14,6 +14,7 @@
"Microsoft.VisualStudio.Component.VC.Runtimes.x86.x64.Spectre",
"Microsoft.VisualStudio.Component.VC.ATL.ARM64",
"Microsoft.VisualStudio.Component.VC.ATL.ARM64.Spectre",
"Microsoft.VisualStudio.Component.VC.ATL",
"Microsoft.VisualStudio.Component.VC.ATL.Spectre",
"Microsoft.VisualStudio.ComponentGroup.WindowsAppSDK.Cs"
]

View File

@@ -11,6 +11,7 @@
<PackageTags>PowerToys</PackageTags>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisMode>Recommended</AnalysisMode>
<_SkipUpgradeNetAnalyzersNuGetWarning>true</_SkipUpgradeNetAnalyzersNuGetWarning>
<PlatformTarget>$(Platform)</PlatformTarget>
</PropertyGroup>

View File

@@ -5,8 +5,9 @@
<ItemGroup>
<PackageVersion Include="Appium.WebDriver" Version="4.2.1" />
<PackageVersion Include="CommunityToolkit.Labs.WinUI.SettingsControls" Version="0.0.18" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.0.0" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.2.0" />
<PackageVersion Include="CommunityToolkit.WinUI.UI" Version="7.1.2" />
<PackageVersion Include="CommunityToolkit.WinUI.UI.Animations" Version="7.1.2" />
<PackageVersion Include="CommunityToolkit.WinUI.UI.Controls" Version="7.1.2" />
<PackageVersion Include="ControlzEx" Version="5.0.1" />
<PackageVersion Include="coverlet.collector" Version="1.3.0" />
@@ -18,7 +19,7 @@
<PackageVersion Include="LazyCache" Version="2.4.0" />
<PackageVersion Include="Mages" Version="2.0.1" />
<PackageVersion Include="Markdig.Signed" Version="0.27.0" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.1" />
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="7.0.3" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="7.0.0" />
<PackageVersion Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.4.336902" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
@@ -28,7 +29,7 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageVersion Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.1722.45" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="7.0.1" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="7.0.3" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.0.2" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" />
@@ -44,6 +45,7 @@
<PackageVersion Include="NLog.Extensions.Logging" Version="5.0.4" />
<PackageVersion Include="NLog.Schema" Version="5.0.4" />
<PackageVersion Include="ScipBe.Common.Office.OneNote" Version="3.0.1" />
<PackageVersion Include="SharpCompress" Version="0.33.0" />
<PackageVersion Include="StreamJsonRpc" Version="2.14.24" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.435" />
<PackageVersion Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
@@ -53,7 +55,7 @@
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
<PackageVersion Include="System.IO.Abstractions" Version="17.2.3" />
<PackageVersion Include="System.IO.Abstractions.TestingHelpers" Version="17.2.3" />
<PackageVersion Include="System.Management" Version="7.0.0" />
<PackageVersion Include="System.Management" Version="7.0.2" />
<PackageVersion Include="System.Reactive" Version="6.0.0-preview.9" />
<PackageVersion Include="System.Runtime.Caching" Version="7.0.0" />
<PackageVersion Include="System.ServiceProcess.ServiceController" Version="7.0.0" />
@@ -61,7 +63,7 @@
<PackageVersion Include="UnitsNet" Version="4.145.0" />
<PackageVersion Include="Vanara.PInvoke.User32" Version="3.4.11" />
<PackageVersion Include="Vanara.PInvoke.Shell32" Version="3.4.11" />
<PackageVersion Include="WinUIEx" Version="2.1.0" />
<PackageVersion Include="WinUIEx" Version="2.2.0" />
</ItemGroup>
<ItemGroup Condition="'$(IsExperimentationLive)'!=''">
<!-- Additional dependencies used by experimentation -->

View File

@@ -282,8 +282,9 @@ SOFTWARE.
## NuGet Packages used by PowerToys
- CommunityToolkit.Labs.WinUI.SettingsControls 0.0.18
- CommunityToolkit.Mvvm 8.0.0
- CommunityToolkit.Mvvm 8.2.0
- CommunityToolkit.WinUI.UI 7.1.2
- CommunityToolkit.WinUI.UI.Animations 7.1.2
- CommunityToolkit.WinUI.UI.Controls 7.1.2
- ControlzEx 5.0.1
- HelixToolkit 2.20.2
@@ -293,7 +294,7 @@ SOFTWARE.
- LazyCache 2.4.0
- Mages 2.0.1
- Markdig.Signed 0.27.0
- Microsoft.CodeAnalysis.NetAnalyzers 7.0.1
- Microsoft.CodeAnalysis.NetAnalyzers 7.0.3
- Microsoft.Data.Sqlite 7.0.0
- Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers 0.4.336902
- Microsoft.Extensions.DependencyInjection 7.0.0
@@ -303,7 +304,7 @@ SOFTWARE.
- Microsoft.NET.Test.Sdk 17.4.1
- Microsoft.Toolkit.Uwp.Notifications 7.1.2
- Microsoft.Web.WebView2 1.0.1722.45
- Microsoft.Windows.Compatibility 7.0.1
- Microsoft.Windows.Compatibility 7.0.3
- Microsoft.Windows.CsWin32 0.2.46-beta
- Microsoft.Windows.CsWinRT 2.0.2
- Microsoft.Windows.SDK.BuildTools 10.0.22621.755
@@ -317,6 +318,7 @@ SOFTWARE.
- NLog.Extensions.Logging 5.0.4
- NLog.Schema 5.0.4
- ScipBe.Common.Office.OneNote 3.0.1
- SharpCompress 0.33.0
- StreamJsonRpc 2.14.24
- StyleCop.Analyzers 1.2.0-beta.435
- System.CommandLine 2.0.0-beta4.22272.1
@@ -326,7 +328,7 @@ SOFTWARE.
- System.Drawing.Common 7.0.0
- System.IO.Abstractions 17.2.3
- System.IO.Abstractions.TestingHelpers 17.2.3
- System.Management 7.0.0
- System.Management 7.0.2
- System.Reactive 6.0.0-preview.9
- System.Runtime.Caching 7.0.0
- System.ServiceProcess.ServiceController 7.0.0
@@ -334,5 +336,5 @@ SOFTWARE.
- UnitsNet 4.145.0
- Vanara.PInvoke.Shell32 3.4.11
- Vanara.PInvoke.User32 3.4.11
- WinUIEx 2.1.0
- WinUIEx 2.2.0

158
README.md
View File

@@ -13,7 +13,7 @@
## About
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity. For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://learn.microsoft.com/windows/dev-environment/overview), head over to [learn.microsoft.com][usingPowerToys-docs-link]!
Microsoft PowerToys is a set of utilities for power users to tune and streamline their Windows experience for greater productivity. For more info on [PowerToys overviews and how to use the utilities][usingPowerToys-docs-link], or any other tools and resources for [Windows development environments](https://learn.microsoft.com/windows/dev-environment/overview), head over to [learn.microsoft.com][usingPowerToys-docs-link]!
| | Current utilities: | |
|--------------|--------------------|--------------|
@@ -36,11 +36,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
### Via GitHub with EXE [Recommended]
Go to [Microsoft PowerToys GitHub releases page][github-release-link], click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
- **For x64 processors (most common) per-user installer:** [PowerToysUserSetup-0.69.1-x64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysUserSetup-0.69.1-x64.exe)
- **For x64 processors per-machine installer:** [PowerToysSetup-0.69.1-x64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysSetup-0.69.1-x64.exe)
- **For ARM64 processors per-user installer:** [PowerToysUserSetup-0.69.1-arm64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysUserSetup-0.69.1-arm64.exe)
- **For ARM64 processors per-machine installer:** [PowerToysSetup-0.69.1-arm64.exe](https://github.com/microsoft/PowerToys/releases/download/v0.69.1/PowerToysSetup-0.69.1-arm64.exe)
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=issue+project%3Amicrosoft%2FPowerToys%2F43
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.70.1/PowerToysUserSetup-0.70.1-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.70.1/PowerToysUserSetup-0.70.1-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.70.1/PowerToysSetup-0.70.1-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.70.1/PowerToysSetup-0.70.1-arm64.exe
| Description | Filename | sha256 hash |
|----------------|----------|-------------|
| Per user - x64 | [PowerToysUserSetup-0.70.1-x64.exe][ptUserX64] | B8FD209310B9847DA3AC35C2C5A89F99CE5EA91F456D9D3595DD2840D62A1AC1 |
| Per user - ARM64 | [PowerToysUserSetup-0.70.1-arm64.exe][ptUserArm64] | 5155EA186230876EF1DA6F49DC33E40D552B2BFFA0E03F66FBA71FBEB8713594 |
| Machine wide - x64 | [PowerToysSetup-0.70.1-x64.exe][ptMachineX64] | 1BE4760558765EF363E12126282F1E3340A8ADFF657C5C51714F7E096F86EE50 |
| Machine wide - ARM64 | [PowerToysSetup-0.70.1-arm64.exe][ptMachineArm64] | 9F267B7AD91E5FAE86ED5050A08A24756CE3EA9875FFCFDE195F1F4F299F0933 |
This is our preferred method.
@@ -82,113 +90,117 @@ For guidance on developing for PowerToys, please read the [developer docs](/doc/
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
### 0.69 - March 2023 Update
### 0.70 - May 2023 Update
In this release, we focused on releasing new features, stability and improvements. Early notice for v0.70, we will be releasing it later in May 2023.
In this release, we focused on releasing new features, stability and improvements.
**Highlights**
- New utility: Registry Preview is a utility to visualize and edit Windows Registry files. Thanks [@randyrants](https://github.com/randyrants)!
- Support per-user scope installation.
- Awake: Quality-of-life improvements and introduced keeping system awake until expiration time and date. Thanks [@dend](https://github.com/dend)!
- PowerToys Run: Fix crashing issue caused by thumbnail image loading.
- New utility: Mouse Without Borders enables you to interact with other computers from the same keyboard and mouse and share clipboard and files between the machines. Weve upgraded it to .NET 7 and made a few small adjustments to fit inside the PowerToys model. Thanks [@truong2d](https://github.com/truong2d) and the rest of the contributors from the Microsoft Garage!
- New utility: Peek is a utility that shows a quick preview of files selected in File Explorer when you press a shortcut (`Ctrl`+`Space` by default). Thanks [@SamChaps](https://github.com/SamChaps)!
- Registry preview Quality of Life improvements. Thanks [@randyrants](https://github.com/randyrants)!
- Awake Quality of Life improvements. Thanks [@dend](https://github.com/dend)!
- Mouse Jump Quality of Life improvements. Thanks [@mikeclayton](https://github.com/mikeclayton)!
### General
- New utility: Registry Preview. Thanks [@randyrants](https://github.com/randyrants)!
- Fix issue causing folders to not be removed on uninstall.
- Support per-user scope installation.
- Companies can control this using the new GPO.
- New utility: Mouse Without Borders. Thanks [@truong2d](https://github.com/truong2d) and [other original contributors](https://github.com/microsoft/PowerToys/blob/main/COMMUNITY.md#mouse-without-borders-original-contributors)!
- New utility: Peek. Thanks [@SamChaps](https://github.com/SamChaps)!
- Fixed a bug causing saved settings to clear sometimes when upgrading PowerToys.
- Font, icon and corner radius adjustments in the UI across utilities. Thanks [@Jay-o-Way](https://github.com/Jay-o-Way)!
### Awake
- Quality-of-life improvements and introduced keeping system awake until expiration time and date. Thanks [@dend](https://github.com/dend)!
### Color Picker
- Fix issue sampling timing and grid issue causing Color Picker to sample the color of its own grid. Thanks [@IHorvalds](https://github.com/IHorvalds)!
- Update to command line output to match the arguments. Thanks [@rpr69](https://github.com/rpr69) for creating a PR to help fix this.
- Fix crash happening when setting an expiration date on time zones with a negative offset relative to UTC (This was a hotfix for 0.69).
- Fix missing logging file when installing (This was a hotfix for 0.69).
- Upgraded Awake to a new version, with Quality of Life improvements and fixing many issues regarding Awake not resetting or not keeping the computer awake when expected. Thanks [@dend](https://github.com/dend)!
### FancyZones
- Fix window cycling on multiple monitors issue.
- Fixed accessibility issues on the Editor.
### File Locksmith
- Add context menu icon. Thanks [@htcfreek](https://github.com/htcfreek)!
- Fixed tooltips having a transparent background (This was a hotfix for 0.69).
### Mouse Utils
### File Explorer add-ons
- Mouse Jump - Simulate mouse input event on mouse jump in addition to cursor move.
- Mouse Jump - Improve performance of screenshot generation. Thanks [@mikeclayton](https://github.com/mikeclayton)!
- Add a Setting to select a background for the SVG Preview. Thanks [@zanseb](https://github.com/zanseb)!
### Paste as Plain Text
### Installer
- Support Ctrl+V as activation shortcut. (This was a hotfix for 0.67)
- Repress modifier keys after plain paste. (This was a hotfix for 0.67) Thanks [@UnderKoen](https://github.com/UnderKoen)!
- Set default shortcut to Ctrl+Win+Alt+V. (This was a hotfix for 0.67)
- Update icons. Thanks [@niels9001](https://github.com/niels9001)!
- Added more utilities to terminate when installing to help prevent files that sometimes are leftover from uninstall.
### PowerRename
### Keyboard Manager
- Show PowerRename in directory background context menu.
- Fix the crash on clicking Select/UnselectAll checkbox while showing only files to be renamed.
- Improve performance on populating Renamed items when many items are being renamed.
- Fixed an issue causing mapping to media keys to type additional characters.
### Measure Tool
- Created a setting to specify the default measure tool. Thanks [@zanseb](https://github.com/zanseb)!
### Mouse Jump
- Reduced dependency on WinForms utility classes. Thanks [@mikeclayton](https://github.com/mikeclayton)!
- Improved popup responsiveness. Thanks [@mikeclayton](https://github.com/mikeclayton)!
- Added a setting to set a custom sized window. Thanks [@mikeclayton](https://github.com/mikeclayton)!
- Added some shortcuts for screen navigation. Thanks [@mikeclayton](https://github.com/mikeclayton)!
### Peek
- New utility: Peek. Thanks [@SamChaps](https://github.com/SamChaps), who drove the effort! Many thanks for all the contributors who made it possible: [@danielchau](https://github.com/danielchau), [@estebanm123](https://github.com/estebanm123), [@Joanna-Zhou](https://github.com/Joanna-Zhou), [@jth-ms](https://github.com/jth-ms), [@miksalmon](https://github.com/miksalmon), [@niels9001](https://github.com/niels9001), [@RobsonPontin](https://github.com/RobsonPontin), [@sujessie](https://github.com/sujessie), and [@Sytta](https://github.com/Sytta)!
### PowerToys Run
- Add setting to disable thumbnails generation for files. (This was a hotfix for 0.67)
- Calculator plugin - handle implied multiplication expressions. Thanks [@jjavierdguezas](https://github.com/jjavierdguezas)!
- Fix Calculator plugin unit tests to respect decimal separator locale. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Fix crashing caused by thumbnail image loading.
- Date & Time plugin - Add filename-compatible date & time format. Thanks [@Picazsoo](https://github.com/Picazsoo)!
- Improved the error message shown on plugin loading error. Thanks [@htcfreek](https://github.com/htcfreek)!
- Add a plugin to start other PowerToys. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Added code to the Shell plugin to use Windows Terminal. Currently accessible only through manipulating the settings file directly. Thanks [@phoenix172](https://github.com/phoenix172)!
### Quick Accent
- Fix existing and add missing Hebrew and Pinyin characters. Thanks [@stevenlele](https://github.com/stevenlele)!
- Added a missing character to the Welsh language.
### Registry Preview
- Added a new utility: Registry Preview.
- Thanks [@htcfreek](https://github.com/htcfreek)! for the help shipping this utility!
- Thanks [@niels9001](https://github.com/niels9001) for the help on the UI!
### Video Conference Mute
- Add toolbar DPI scaling support.
- Fix selecting overlay image when Settings app is running elevated.
- Add push-to-talk (and push-to-reverse) feature. Thanks [@pajawojciech](https://github.com/pajawojciech)!
- Specify minimum size / position values for the UI (This was a hotfix for 0.69). Thanks [@randyrants](https://github.com/randyrants)!
- Fixes in the UI command bar (This was a hotfix for 0.69). Thanks [@randyrants](https://github.com/randyrants)!
- Fix crash on opening a file picker when running elevated (This was a hotfix for 0.69). Thanks [@randyrants](https://github.com/randyrants)!
- Fixed tooltips having a transparent background (This was a hotfix for 0.69).
- Fixed a file size limit typo. Thanks [@idma88](https://github.com/idma88)!
- Improve hexadecimal value parsing. Thanks [@randyrants](https://github.com/randyrants)!
- Added a button to open the Registry Editor at a selected key. Thanks [@randyrants](https://github.com/randyrants)!
- Improve key and value parsing. Thanks [@randyrants](https://github.com/randyrants)!
- Better theme support for caption bar. Thanks [@randyrants](https://github.com/randyrants)!
- Fix an issue handling empty DWORD and QWORD values. Thanks [@randyrants](https://github.com/randyrants)!
### Settings
- Fix Experiment bitmap icon rendering on theme change and bump CommunityToolkit.Labs.WinUI.SettingsControls package version. Thanks [@niels9001](https://github.com/niels9001)!
- Video Conference Mute page improvements. Thanks [@Jay-o-Way](https://github.com/Jay-o-Way)!
- Add warning that PowerToys Run might get no focus if "Use centralized keyboard hook" settings is enabled. Thanks [@Aaron-Junker](https://github.com/Aaron-Junker)!
- Fix ShortcutControl issues related to keyboard input focus, theme change and missing error badge when invalid key is pressed. Thanks [@htcfreek](https://github.com/htcfreek)!
- Add warning when Ctrl+V and Ctrl+Shift+V is used as an activation shortcut for Paste as Plain Text. Thanks [@htcfreek](https://github.com/htcfreek)!
- Update the What's New screen to hide the installer hashes in the new format (This was a hotfix for 0.69).
- Fix crashes happening when using the Shortcut Control (This was a hotfix for 0.69).
- The Settings window now has a minimum width. Thanks [@niels9001](https://github.com/niels9001)!
- Prevent a second Settings instance from being opened on upgrade.
- Fix accessibility issues on many pages. Thanks [@niels9001](https://github.com/niels9001)!
### Documentation
- Update CONTRIBUTING.md with information about localization issues. Thanks [@Aaron-Junker](https://github.com/Aaron-Junker)!
- Remove localization from URLs. Thanks [@Jay-o-Way](https://github.com/Jay-o-Way)!
- Add dev docs for tools. Thanks [@Aaron-Junker](https://github.com/Aaron-Junker)!
- Fix a dead link in documentation that was pointing to the wrong settings specification. Thanks [@zanseb](https://github.com/zanseb)!
- Added some missing contributors to COMMUNITY.md
### Development
- Ignore spellcheck for MouseJumpUI/MainForm.resx file. (This was a hotfix for 0.67)
- Optimize versionAndSignCheck.ps1 script. Thanks [@snickler](https://github.com/snickler)!
- Upgraded NetAnalyzers to 7.0.1. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
- Move all DLL imports in Settings project to NativeMethods.cs file.
- Fix FancyZones tools build issues. Thanks [@Aaron-Junker](https://github.com/Aaron-Junker)!
- Centralize Logger used in C# projects. Thanks [@Aaron-Junker](https://github.com/Aaron-Junker)!
- Add missing project references. Thanks [@ACGNnsj](https://github.com/ACGNnsj)!
- Fixed the CI release pipelines hash generation (This was a hotfix for 0.69).
- Added per-user installers to the winget package submission script.
- Upgraded the Community Toolkit Labs dependency. Thanks [@niels9001](https://github.com/niels9001)!
- Fixed building with Visual Studio 17.6. Thanks [@snickler](https://github.com/snickler)!
- Upgraded the WebView 2 dependency.
- Upgraded the WinAppSDK dependency to 1.3.1.
- Fixed a typo preventing the clean up script to run. Thanks [@Sajad-Lx](https://github.com/Sajad-Lx)!
- Fixed encoding on a test file to fix running tests in some configurations. Thanks [@VisualBasist](https://github.com/VisualBasist)!
- Made the GPO release assets come named with a version in the build CI output.
#### What is being planned for version 0.70
#### What is being planned for version 0.71
For [v0.70][github-next-release-work], we'll work on below:
For [v0.71][github-next-release-work], we'll work on below:
- New utility: [PowerToys Peek](https://github.com/microsoft/PowerToys/issues/80)
- Stability / bug fixes
- Adjustments on feedback / stability / bug fixes
## PowerToys Community
@@ -215,5 +227,5 @@ The application logs basic telemetry. Our Telemetry Data page (Coming Soon) has
[usingPowerToys-docs-link]: https://aka.ms/powertoys-docs
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F43
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F42
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F44
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aopen+is%3Aissue+project%3Amicrosoft%2FPowerToys%2F43

View File

@@ -26,6 +26,9 @@
</RegistryKey>
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\Drive\ShellEx\ContextMenuHandlers\FileLocksmithExt">
<RegistryValue Type="string" Value="{84D68575-E186-46AD-B0CB-BAEB45EE29C0}"/>
</RegistryKey>
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\Directory\background\ShellEx\ContextMenuHandlers\FileLocksmithExt">
<RegistryValue Type="string" Value="{84D68575-E186-46AD-B0CB-BAEB45EE29C0}"/>
</RegistryKey>
</Component>
</DirectoryRef>

View File

@@ -194,7 +194,7 @@
</Custom>
<Custom Action="UninstallServicesTask" After="InstallFinalize">
Installed AND (REMOVE="ALL")
Installed AND (NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")
</Custom>
<!-- TODO: Use to activate embedded MSIX -->
<!--<Custom Action="UninstallEmbeddedMSIXTask" After="InstallFinalize">

View File

@@ -383,7 +383,16 @@
<RegistryValue Type="string" Name="Launcher_History_$(var.IdSafeLanguage)_Component" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="Launcher_History_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)modules\launcher\Plugins\History\$(var.Language)\Microsoft.PowerToys.Run.Plugin.History.resources.dll" />
</Component>
</Component>
<Component
Id="Launcher_PowerToys_$(var.IdSafeLanguage)_Component"
Directory="Resource$(var.IdSafeLanguage)PowerToysPluginFolder"
Guid="$(var.CompGUIDPrefix)1C">
<RegistryKey Root="$(var.RegistryScope)" Key="Software\Classes\powertoys\components">
<RegistryValue Type="string" Name="Launcher_PowerToys_$(var.IdSafeLanguage)_Component" Value="" KeyPath="yes"/>
</RegistryKey>
<File Id="Launcher_PowerToys_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)modules\launcher\Plugins\PowerToys\$(var.Language)\Microsoft.PowerToys.Run.Plugin.PowerToys.resources.dll" />
</Component>
<?undef IdSafeLanguage?>
<?undef CompGUIDPrefix?>
<?endforeach?>

View File

@@ -106,14 +106,6 @@
<?define PowerToysImagesCmpFilesPath=$(var.BinDir)modules\launcher\Plugins\PowerToys\Images\?>
<Fragment>
<Component Id="launcherShortcutComponent" Directory="LauncherInstallFolder" >
<!-- Toast Notification AUMID -->
<RegistryKey Root="$(var.RegistryScope)" Key="SOFTWARE\Classes\AppUserModelId\PowerToysRun">
<RegistryValue Type="string" Name="DisplayName" Value="PowerToys Run" />
<RegistryValue Type="string" Name="IconUri" Value="[LauncherImagesFolder]RunAsset.ico" />
</RegistryKey>
</Component>
<DirectoryRef Id="LauncherInstallFolder" FileSource="$(var.launcherFilesPath)">
<!-- Generated by generateFileComponents.ps1 -->
<!--launcherFiles_Component_Def-->
@@ -374,7 +366,6 @@
<RemoveFolder Id="RemoveFolderPowerToysPluginFolder" Directory="PowerToysPluginFolder" On="uninstall"/>
<RemoveFolder Id="RemoveFolderPowerToysImagesFolder" Directory="PowerToysImagesFolder" On="uninstall"/>
</Component>
<ComponentRef Id="launcherShortcutComponent" />
</ComponentGroup>
</Fragment>
</Wix>

View File

@@ -198,6 +198,11 @@ Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson ""$
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson """" -fileListName WinTermImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath ""$PSScriptRoot..\..\..\$platform\Release\modules\launcher\Plugins\WindowsTerminal\Images"""
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""WinTermCmpFiles"" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot"
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""WinTermImagesCmpFiles"" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot"
###PowerToys
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson ""$PSScriptRoot..\..\..\$platform\Release\modules\launcher\Plugins\PowerToys\Microsoft.PowerToys.Run.Plugin.PowerToys.deps.json"" -fileListName PowerToysCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -isLauncherPlugin 1"
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson """" -fileListName PowerToysImagesCmpFiles -wxsFilePath $PSScriptRoot\Run.wxs -depsPath ""$PSScriptRoot..\..\..\$platform\Release\modules\launcher\Plugins\PowerToys\Images"""
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""PowerToysCmpFiles"" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot"
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""PowerToysImagesCmpFiles"" -wxsFilePath $PSScriptRoot\Run.wxs -regroot $registryroot"
## Plugins
#ShortcutGuide

View File

@@ -50,7 +50,7 @@ if ($isWinAppSdkProj -eq $True) {
$fileExclusionList = @("*Test*", "*.pdb", "*.lastcodeanalysissucceeded", "createdump.exe") + $interopFilesList + $winAppSDKfilesList
$fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*png", "*gif", "*ico", "*cur", "*svg", "index.html", "reg.js", "monacoSpecialLanguages.js", "resources.pri")
$fileInclusionList = @("*.dll", "*.exe", "*.json", "*.msix", "*png", "*gif", "*ico", "*cur", "*svg", "index.html", "reg.js", "gitignore.js", "monacoSpecialLanguages.js", "resources.pri")
$dllsToIgnore = @("System.CodeDom.dll", "WindowsBase.dll")

View File

@@ -123,6 +123,8 @@ UINT __stdcall UnApplyModulesRegistryChangeSetsCA(MSIHANDLE hInstall)
changeSet.unApply();
}
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
ExitOnFailure(hr, "Failed to extract msix");
LExit:
@@ -387,6 +389,8 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall)
ExitOnFailure(hr, "Cannot put_ExecutionTimeLimit setting info: %x", hr);
hr = pSettings->put_DisallowStartIfOnBatteries(VARIANT_FALSE);
ExitOnFailure(hr, "Cannot put_DisallowStartIfOnBatteries setting info: %x", hr);
hr = pSettings->put_Priority(4);
ExitOnFailure(hr, "Cannot put_Priority setting info : %x", hr);
// ------------------------------------------------------
// Get the trigger collection to insert the logon trigger.
@@ -1466,9 +1470,9 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
L"PowerToys.PdfPreviewHandler.exe",
L"PowerToys.SvgPreviewHandler.exe",
L"PowerToys.Peek.UI.exe",
L"PowerToys.MouseWithoutBorders.exe"
L"PowerToys.MouseWithoutBordersHelper.exe"
L"PowerToys.MouseWithoutBordersService.exe"
L"PowerToys.MouseWithoutBorders.exe",
L"PowerToys.MouseWithoutBordersHelper.exe",
L"PowerToys.MouseWithoutBordersService.exe",
L"PowerToys.exe",
};

View File

@@ -8,6 +8,7 @@
#include <strsafe.h>
#include <msiquery.h>
#include <Msi.h>
#include <shlobj_core.h>
// WiX Header Files:
#include <wcautil.h>

View File

@@ -15,7 +15,7 @@ namespace Common.UI
{
new Thread(() =>
{
var eventHandle = new EventWaitHandle(false, EventResetMode.ManualReset, eventName);
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
while (true)
{
if (WaitHandle.WaitAny(new WaitHandle[] { cancel.WaitHandle, eventHandle }) == 1)

View File

@@ -20,6 +20,9 @@
<None Update="customLanguages\reg.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="customLanguages\gitignore.js">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="index.html">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>

View File

@@ -0,0 +1,13 @@
export function gitignoreDefinition() {
return {
defaultToken: 'invalid',
tokenizer: {
root: [
[/^#.*$/, 'comment'],
[/^\s*!.*/, 'invalid'],
[/^\s*[^#]+/, "tag"]
]
}
};
}

View File

@@ -95,9 +95,9 @@
// A rule to evaluate on top of the precondition in order to dispatch the keybindings.
keybindingContext: null,
contextMenuGroupId: 'navigation',
contextMenuGroupId: 'cutcopypaste',
contextMenuOrder: 1.5,
contextMenuOrder: 100,
// Method that will be executed when the action is triggered.
// @param editor The editor instance is passed in as a convenience

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,7 @@
#include "dwmapi.h"
#include <windows.h>
#include <vector>
#pragma comment (lib,"Dwmapi.lib")
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#define HKEY_WINDOWS_THEME L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"

View File

@@ -49,7 +49,6 @@ namespace // Strings in this namespace should not be localized
constexpr std::wstring_view TASK_NAME = L"PowerToysBackgroundNotificationsHandler";
constexpr std::wstring_view TASK_ENTRYPOINT = L"BackgroundActivator.BackgroundHandler";
constexpr std::wstring_view PACKAGED_APPLICATION_ID = L"PowerToys";
constexpr std::wstring_view APPIDS_REGISTRY = LR"(Software\Classes\AppUserModelId\)";
std::wstring APPLICATION_ID = L"Microsoft.PowerToysWin32";
constexpr std::wstring_view DEFAULT_TOAST_GROUP = L"PowerToysToastTag";
@@ -132,68 +131,6 @@ void notifications::run_desktop_app_activator_loop()
CoRevokeClassObject(token);
}
bool notifications::register_application_id(const std::wstring_view appName, const std::wstring_view iconPath)
{
std::wstring aumidPath{ APPIDS_REGISTRY };
aumidPath += APPLICATION_ID;
wil::unique_hkey aumidKey;
if (FAILED(RegCreateKeyW(HKEY_CURRENT_USER, aumidPath.c_str(), &aumidKey)))
{
return false;
}
if (FAILED(RegSetKeyValueW(aumidKey.get(),
nullptr,
L"DisplayName",
REG_SZ,
appName.data(),
static_cast<DWORD>((size(appName) + 1) * sizeof(wchar_t)))))
{
return false;
}
if (FAILED(RegSetKeyValueW(aumidKey.get(),
nullptr,
L"IconUri",
REG_SZ,
iconPath.data(),
static_cast<DWORD>((size(iconPath) + 1) * sizeof(wchar_t)))))
{
return false;
}
const std::wstring_view iconColor = L"FFDDDDDD";
if (FAILED(RegSetKeyValueW(aumidKey.get(),
nullptr,
L"IconBackgroundColor",
REG_SZ,
iconColor.data(),
static_cast<DWORD>((size(iconColor) + 1) * sizeof(wchar_t)))))
{
return false;
}
return true;
}
void notifications::unregister_application_id()
{
std::wstring aumidPath{ APPIDS_REGISTRY };
aumidPath += APPLICATION_ID;
wil::unique_hkey registryRoot;
RegOpenKeyW(HKEY_CURRENT_USER, aumidPath.c_str(), &registryRoot);
if (!registryRoot)
{
return;
}
RegDeleteTreeW(registryRoot.get(), nullptr);
registryRoot.reset();
RegOpenKeyW(HKEY_CURRENT_USER, APPIDS_REGISTRY.data(), &registryRoot);
if (!registryRoot)
{
return;
}
RegDeleteKeyW(registryRoot.get(), APPLICATION_ID.data());
}
void notifications::override_application_id(const std::wstring_view appID)
{
APPLICATION_ID = appID;

View File

@@ -14,9 +14,6 @@ namespace notifications
void override_application_id(const std::wstring_view appID);
void run_desktop_app_activator_loop();
bool register_application_id(const std::wstring_view appName, const std::wstring_view iconPath);
void unregister_application_id();
struct snooze_duration
{
std::wstring label;

View File

@@ -12,7 +12,8 @@ struct UpdateState
upToDate = 0,
errorDownloading = 1,
readyToDownload = 2,
readyToInstall = 3
readyToInstall = 3,
networkError = 4
} state = upToDate;
std::wstring releasePageUrl;
std::optional<std::time_t> githubUpdateLastCheckedDate;

View File

@@ -353,7 +353,7 @@ struct ProcessInfo
DWORD processID = {};
};
inline std::optional<ProcessInfo> RunNonElevatedFailsafe(const std::wstring& file, const std::wstring& params, const std::wstring& working_dir)
inline std::optional<ProcessInfo> RunNonElevatedFailsafe(const std::wstring& file, const std::wstring& params, const std::wstring& working_dir, DWORD handleAccess = 0)
{
bool launched = RunNonElevatedEx(file, params, working_dir);
if (!launched)
@@ -373,7 +373,7 @@ inline std::optional<ProcessInfo> RunNonElevatedFailsafe(const std::wstring& fil
}
}
auto handles = getProcessHandlesByName(std::filesystem::path{ file }.filename().wstring(), PROCESS_QUERY_INFORMATION | SYNCHRONIZE);
auto handles = getProcessHandlesByName(std::filesystem::path{ file }.filename().wstring(), PROCESS_QUERY_INFORMATION | SYNCHRONIZE | handleAccess );
if (handles.empty())
return std::nullopt;

View File

@@ -30,3 +30,36 @@ inline bool find_folder_in_path(const std::wstring& where, const std::vector<std
}
return false;
}
#define MAX_TITLE_LENGTH 255
inline bool check_excluded_app_with_title(const HWND& hwnd, std::wstring& processPath, const std::vector<std::wstring>& excludedApps)
{
WCHAR title[MAX_TITLE_LENGTH];
int len = GetWindowTextW(hwnd, title, MAX_TITLE_LENGTH);
if (len <= 0)
{
return false;
}
std::wstring titleStr(title);
auto lastBackslashPos = processPath.find_last_of(L'\\');
if (lastBackslashPos != std::wstring::npos)
{
processPath = processPath.substr(0, lastBackslashPos + 1); // retain up to the last backslash
processPath.append(titleStr); // append the title
}
CharUpperBuffW(processPath.data(), static_cast<DWORD>(processPath.length()));
return find_app_name_in_path(processPath, excludedApps);
}
inline bool check_excluded_app(const HWND& hwnd, std::wstring& processPath, const std::vector<std::wstring>& excludedApps)
{
bool res = find_app_name_in_path(processPath, excludedApps);
if (!res)
{
res = check_excluded_app_with_title(hwnd, processPath, excludedApps);
}
return res;
}

View File

@@ -192,6 +192,28 @@ inline registry::ChangeSet getStlThumbnailHandlerChangeSet(const std::wstring in
NonLocalizable::ExtSTL);
}
inline registry::ChangeSet getRegistryPreviewSetDefaultAppChangeSet(const std::wstring installationDir, const bool perUser)
{
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
using vec_t = std::vector<registry::ValueChange>;
vec_t changes;
std::wstring appName = L"Registry Preview";
std::wstring fullAppName = L"PowerToys.RegistryPreview";
std::wstring registryKeyPrefix = L"Software\\Classes\\";
std::wstring appPath = installationDir + L"\\modules\\RegistryPreview\\PowerToys.RegistryPreview.exe";
std::wstring command = appPath + L" \"----ms-protocol:ms-encodedlaunch:App?ContractId=Windows.File&Verb=open&File=%1\"";
changes.push_back({ scope, registryKeyPrefix + fullAppName + L"\\" + L"Application", L"ApplicationName", appName });
changes.push_back({ scope, registryKeyPrefix + fullAppName + L"\\" + L"DefaultIcon", std::nullopt, appPath });
changes.push_back({ scope, registryKeyPrefix + fullAppName + L"\\" + L"shell\\open\\command", std::nullopt, command });
changes.push_back({ scope, registryKeyPrefix + L".reg\\OpenWithProgIDs", fullAppName, L"" });
return { changes };
}
inline registry::ChangeSet getRegistryPreviewChangeSet(const std::wstring installationDir,const bool perUser)
{
const HKEY scope = perUser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
@@ -235,5 +257,6 @@ inline std::vector<registry::ChangeSet> getAllModulesChangeSets(const std::wstri
getPdfThumbnailHandlerChangeSet(installationDir, PER_USER),
getGcodeThumbnailHandlerChangeSet(installationDir, PER_USER),
getStlThumbnailHandlerChangeSet(installationDir, PER_USER),
getRegistryPreviewChangeSet(installationDir, PER_USER) };
getRegistryPreviewChangeSet(installationDir, PER_USER),
getRegistryPreviewSetDefaultAppChangeSet(installationDir, PER_USER) };
}

View File

@@ -20,6 +20,9 @@ namespace constants::nonlocalizable
// JSON key used to store whether the module is enabled
constexpr WCHAR JsonKeyEnabled[] = L"Enabled";
// JSON key used to store extended menu enabled
constexpr WCHAR JsonKeyShowInExtendedContextMenu[] = L"showInExtendedContextMenu";
// Path of the JSON file used to store settings
constexpr WCHAR DataFilePath[] = L"\\file-locksmith-settings.json";

View File

@@ -69,14 +69,25 @@ IFACEMETHODIMP ExplorerCommand::GetCanonicalName(GUID* pguidCommandName)
IFACEMETHODIMP ExplorerCommand::GetState(IShellItemArray* psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE* pCmdState)
{
if (globals::enabled)
{
*pCmdState = ECS_ENABLED;
}
else
if (!globals::enabled)
{
*pCmdState = ECS_HIDDEN;
}
if (FileLocksmithSettingsInstance().GetShowInExtendedContextMenu())
{
*pCmdState = ECS_HIDDEN;
return S_OK;
}
// When right clicking directory background, selection is empty.
if (nullptr == psiItemArray)
{
*pCmdState = ECS_HIDDEN;
return S_OK;
}
*pCmdState = ECS_ENABLED;
return S_OK;
}
@@ -101,8 +112,16 @@ IFACEMETHODIMP ExplorerCommand::EnumSubCommands(IEnumExplorerCommand** ppEnum)
IFACEMETHODIMP ExplorerCommand::Initialize(PCIDLIST_ABSOLUTE pidlFolder, IDataObject* pdtobj, HKEY hkeyProgID)
{
m_data_obj = pdtobj;
m_data_obj->AddRef();
if (!FileLocksmithSettingsInstance().GetEnabled())
{
return S_OK;
}
if (pdtobj)
{
m_data_obj = pdtobj;
m_data_obj->AddRef();
}
return S_OK;
}
@@ -116,6 +135,11 @@ IFACEMETHODIMP ExplorerCommand::QueryContextMenu(HMENU hmenu, UINT indexMenu, UI
return S_OK;
}
if (FileLocksmithSettingsInstance().GetShowInExtendedContextMenu() && !(uFlags & CMF_EXTENDEDVERBS))
{
return S_OK;
}
HRESULT hr = E_UNEXPECTED;
if (m_data_obj && !(uFlags & (CMF_DEFAULTONLY | CMF_VERBSONLY | CMF_OPTIMIZEFORINVOKE)))
{

View File

@@ -62,7 +62,8 @@ public:
PowerToysSettings::PowerToyValues values =
PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
// Currently, there are no settings, so we don't do anything.
toggle_extended_only(values.get_bool_value(L"bool_show_extended_menu").value());
save_settings();
}
catch (std::exception& e)
{
@@ -89,6 +90,18 @@ public:
return m_enabled;
}
virtual void toggle_extended_only(bool extended_only)
{
Logger::info(L"File Locksmith toggle extended only");
m_extended_only = extended_only;
save_settings();
}
virtual bool is_extended_only()
{
return m_extended_only;
}
virtual void destroy() override
{
delete this;
@@ -96,10 +109,12 @@ public:
private:
bool m_enabled;
bool m_extended_only;
void init_settings()
{
m_enabled = FileLocksmithSettingsInstance().GetEnabled();
m_extended_only = FileLocksmithSettingsInstance().GetShowInExtendedContextMenu();
Trace::EnableFileLocksmith(m_enabled);
}
@@ -107,6 +122,8 @@ private:
{
auto& settings = FileLocksmithSettingsInstance();
settings.SetEnabled(m_enabled);
settings.SetExtendedContextMenuOnly(m_extended_only);
settings.Save();
Trace::EnableFileLocksmith(m_enabled);
}

View File

@@ -30,6 +30,7 @@ void FileLocksmithSettings::Save()
json::JsonObject jsonData;
jsonData.SetNamedValue(constants::nonlocalizable::JsonKeyEnabled, json::value(settings.enabled));
jsonData.SetNamedValue(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::value(settings.showInExtendedContextMenu));
json::to_file(jsonFilePath, jsonData);
GetSystemTimeAsFileTime(&lastLoadedTime);
@@ -70,6 +71,11 @@ void FileLocksmithSettings::ParseJson()
{
settings.enabled = jsonSettings.GetNamedBoolean(constants::nonlocalizable::JsonKeyEnabled);
}
if (json::has(jsonSettings, constants::nonlocalizable::JsonKeyShowInExtendedContextMenu, json::JsonValueType::Boolean))
{
settings.showInExtendedContextMenu = jsonSettings.GetNamedBoolean(constants::nonlocalizable::JsonKeyShowInExtendedContextMenu);
}
}
catch (const winrt::hresult_error&)
{

View File

@@ -25,6 +25,16 @@ public:
Save();
}
inline bool GetShowInExtendedContextMenu() const
{
return settings.showInExtendedContextMenu;
}
inline void SetExtendedContextMenuOnly(bool extendedOnly)
{
settings.showInExtendedContextMenu = extendedOnly;
}
void Save();
void Load();
@@ -32,6 +42,7 @@ private:
struct Settings
{
bool enabled{ true };
bool showInExtendedContextMenu{ false };
};
void Reload();

View File

@@ -2,12 +2,7 @@
x:Class="FileLocksmithUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:converters="using:CommunityToolkit.WinUI.UI.Converters"
xmlns:converters1="using:PowerToys.FileLocksmithUI.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:interop="using:FileLocksmith.Interop"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:PowerToys.FileLocksmithUI.Views"
xmlns:winuiex="using:WinUIEx"
@@ -18,9 +13,9 @@
IsShownInSwitchers="True"
IsTitleBarVisible="True"
mc:Ignorable="d">
<winuiex:WindowEx.Backdrop>
<winuiex:MicaSystemBackdrop />
</winuiex:WindowEx.Backdrop>
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid>
<Grid.RowDefinitions>

View File

@@ -74,6 +74,8 @@ namespace Hosts.Tests
[DataRow("\t\thost\t\t10.1.1.1")]
[DataRow(" host 10.1.1.1")]
[DataRow("host 10.1.1.1")]
[DataRow("# comment 10.1.1.1 host # comment")]
[DataRow("10.1.1.1 host01 host02 host03 host04 host05 host06 host07 host08 host09 host10")]
public void Not_Valid_Entry(string line)
{
var entry = new Entry(0, line);

View File

@@ -69,9 +69,10 @@ namespace Hosts.Tests
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var (_, entries) = await service.ReadAsync();
var data = await service.ReadAsync();
var entries = data.Entries.ToList();
entries.Add(new Entry(0, "10.1.1.30", "host30 host30.local", "new entry", false));
await service.WriteAsync(string.Empty, entries);
await service.WriteAsync(data.AdditionalLines, entries);
var result = fileSystem.GetFile(service.HostsFilePath);
Assert.AreEqual(result.TextContents, contentResult);
@@ -94,9 +95,10 @@ namespace Hosts.Tests
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var (_, entries) = await service.ReadAsync();
var data = await service.ReadAsync();
var entries = data.Entries.ToList();
entries.RemoveAt(0);
await service.WriteAsync(string.Empty, entries);
await service.WriteAsync(data.AdditionalLines, entries);
var result = fileSystem.GetFile(service.HostsFilePath);
Assert.AreEqual(result.TextContents, contentResult);
@@ -120,13 +122,13 @@ namespace Hosts.Tests
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var (_, entries) = await service.ReadAsync();
var entry = entries[0];
var data = await service.ReadAsync();
var entry = data.Entries[0];
entry.Address = "10.1.1.10";
entry.Hosts = "host host.local host1.local";
entry.Comment = "updated comment";
entry.Active = false;
await service.WriteAsync(string.Empty, entries);
await service.WriteAsync(data.AdditionalLines, data.Entries);
var result = fileSystem.GetFile(service.HostsFilePath);
Assert.AreEqual(result.TextContents, contentResult);
@@ -168,12 +170,12 @@ namespace Hosts.Tests
var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>();
userSettings.Setup(m => m.AdditionalLinesPosition).Returns(AdditionalLinesPosition.Top);
userSettings.Setup(m => m.AdditionalLinesPosition).Returns(HostsAdditionalLinesPosition.Top);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var (additionalLines, entries) = await service.ReadAsync();
await service.WriteAsync(additionalLines, entries);
var data = await service.ReadAsync();
await service.WriteAsync(data.AdditionalLines, data.Entries);
var result = fileSystem.GetFile(service.HostsFilePath);
Assert.AreEqual(result.TextContents, contentResult);
@@ -200,13 +202,38 @@ namespace Hosts.Tests
var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>();
userSettings.Setup(m => m.AdditionalLinesPosition).Returns(AdditionalLinesPosition.Bottom);
userSettings.Setup(m => m.AdditionalLinesPosition).Returns(HostsAdditionalLinesPosition.Bottom);
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var (additionalLines, entries) = await service.ReadAsync();
await service.WriteAsync(additionalLines, entries);
var data = await service.ReadAsync();
await service.WriteAsync(data.AdditionalLines, data.Entries);
var result = fileSystem.GetFile(service.HostsFilePath);
Assert.AreEqual(result.TextContents, contentResult);
}
[TestMethod]
public async Task LongHosts_Splitted()
{
var content =
@"10.1.1.1 host01 host02 host03 host04 host05 host06 host07 host08 host09 host10 host11 host12 host13 host14 host15 host16 host17 host18 host19 # comment
";
var contentResult =
@"10.1.1.1 host01 host02 host03 host04 host05 host06 host07 host08 host09 # comment
10.1.1.1 host10 host11 host12 host13 host14 host15 host16 host17 host18 # comment
10.1.1.1 host19 # comment
";
var fileSystem = new CustomMockFileSystem();
var userSettings = new Mock<IUserSettings>();
var service = new HostsService(fileSystem, userSettings.Object, _elevationHelper.Object);
fileSystem.AddFile(service.HostsFilePath, new MockFileData(content));
var data = await service.ReadAsync();
await service.WriteAsync(data.AdditionalLines, data.Entries);
var result = fileSystem.GetFile(service.HostsFilePath);
Assert.AreEqual(result.TextContents, contentResult);

View File

@@ -0,0 +1,14 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace Hosts
{
public static class Consts
{
/// <summary>
/// Maximum number of hosts detected by the system in a single line
/// </summary>
public const int MaxHostsCount = 9;
}
}

View File

@@ -38,6 +38,8 @@ namespace Hosts.Helpers
public event EventHandler FileChanged;
public Encoding Encoding => _userSettings.Encoding == HostsEncoding.Utf8 ? new UTF8Encoding(false) : new UTF8Encoding(true);
public HostsService(
IFileSystem fileSystem,
IUserSettings userSettings,
@@ -62,17 +64,20 @@ namespace Hosts.Helpers
return _fileSystem.File.Exists(HostsFilePath);
}
public async Task<(string Unparsed, List<Entry> Entries)> ReadAsync()
public async Task<HostsData> ReadAsync()
{
var entries = new List<Entry>();
var unparsedBuilder = new StringBuilder();
var splittedEntries = false;
if (!Exists())
{
return (unparsedBuilder.ToString(), entries);
return new HostsData(entries, unparsedBuilder.ToString(), false);
}
var lines = await _fileSystem.File.ReadAllLinesAsync(HostsFilePath);
var lines = await _fileSystem.File.ReadAllLinesAsync(HostsFilePath, Encoding);
var id = 0;
for (var i = 0; i < lines.Length; i++)
{
@@ -83,11 +88,25 @@ namespace Hosts.Helpers
continue;
}
var entry = new Entry(i, line);
var entry = new Entry(id, line);
if (entry.Valid)
{
entries.Add(entry);
id++;
}
else if (entry.Validate(false))
{
foreach (var hostsChunk in entry.SplittedHosts.Chunk(Consts.MaxHostsCount))
{
var clonedEntry = entry.Clone();
clonedEntry.Id = id;
clonedEntry.Hosts = string.Join(' ', hostsChunk);
entries.Add(clonedEntry);
id++;
}
splittedEntries = true;
}
else
{
@@ -100,7 +119,7 @@ namespace Hosts.Helpers
}
}
return (unparsedBuilder.ToString(), entries);
return new HostsData(entries, unparsedBuilder.ToString(), splittedEntries);
}
public async Task<bool> WriteAsync(string additionalLines, IEnumerable<Entry> entries)
@@ -124,7 +143,7 @@ namespace Hosts.Helpers
if (!e.Valid)
{
lineBuilder.Append(e.GetLine());
lineBuilder.Append(e.Line);
}
else
{
@@ -153,11 +172,11 @@ namespace Hosts.Helpers
if (!string.IsNullOrWhiteSpace(additionalLines))
{
if (_userSettings.AdditionalLinesPosition == AdditionalLinesPosition.Top)
if (_userSettings.AdditionalLinesPosition == HostsAdditionalLinesPosition.Top)
{
lines.Insert(0, additionalLines);
}
else if (_userSettings.AdditionalLinesPosition == AdditionalLinesPosition.Bottom)
else if (_userSettings.AdditionalLinesPosition == HostsAdditionalLinesPosition.Bottom)
{
lines.Add(additionalLines);
}
@@ -174,7 +193,7 @@ namespace Hosts.Helpers
_backupDone = true;
}
await _fileSystem.File.WriteAllLinesAsync(HostsFilePath, lines);
await _fileSystem.File.WriteAllLinesAsync(HostsFilePath, lines, Encoding);
}
catch (Exception ex)
{

View File

@@ -15,7 +15,7 @@ namespace Hosts.Helpers
event EventHandler FileChanged;
Task<(string Unparsed, List<Entry> Entries)> ReadAsync();
Task<HostsData> ReadAsync();
Task<bool> WriteAsync(string additionalLines, IEnumerable<Entry> entries);

View File

@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Text.RegularExpressions;
namespace Hosts.Helpers
@@ -39,16 +40,23 @@ namespace Hosts.Helpers
/// <summary>
/// Determines whether the hosts are valid
/// </summary>
public static bool ValidHosts(string hosts)
public static bool ValidHosts(string hosts, bool validateHostsLength)
{
if (string.IsNullOrWhiteSpace(hosts))
{
return false;
}
foreach (var host in hosts.Split(' '))
var splittedHosts = hosts.Split(' ');
if (validateHostsLength && splittedHosts.Length > Consts.MaxHostsCount)
{
if (System.Uri.CheckHostName(host) == System.UriHostNameType.Unknown)
return false;
}
foreach (var host in splittedHosts)
{
if (Uri.CheckHostName(host) == UriHostNameType.Unknown)
{
return false;
}

View File

@@ -1,67 +0,0 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
namespace Hosts.Helpers
{
// Taken from https://github.com/microsoft/microsoft-ui-xaml/blob/main/test/MUXControlsTestApp/Utilities/VisualTreeUtils.cs
// Original copyright header:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
public static class VisualTreeUtils
{
public static T FindVisualChildByType<T>(this DependencyObject element)
where T : DependencyObject
{
if (element == null)
{
return null;
}
if (element is T elementAsT)
{
return elementAsT;
}
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childrenCount; i++)
{
var result = VisualTreeHelper.GetChild(element, i).FindVisualChildByType<T>();
if (result != null)
{
return result;
}
}
return null;
}
public static FrameworkElement FindVisualChildByName(this DependencyObject element, string name)
{
if (element == null || string.IsNullOrWhiteSpace(name))
{
return null;
}
if (element is FrameworkElement elementAsFE && elementAsFE.Name == name)
{
return elementAsFE;
}
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childrenCount; i++)
{
var result = VisualTreeHelper.GetChild(element, i).FindVisualChildByName(name);
if (result != null)
{
return result;
}
}
return null;
}
}
}

View File

@@ -12,9 +12,9 @@
MinWidth="480"
MinHeight="320"
mc:Ignorable="d">
<winuiex:WindowEx.Backdrop>
<winuiex:MicaSystemBackdrop />
</winuiex:WindowEx.Backdrop>
<Window.SystemBackdrop>
<MicaBackdrop />
</Window.SystemBackdrop>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="32" />

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using Hosts.Helpers;
using Microsoft.UI.Windowing;
using WinUIEx;
namespace Hosts

View File

@@ -12,32 +12,35 @@ namespace Hosts.Models
{
public partial class Entry : ObservableObject
{
private string _line;
private static readonly char[] _spaceCharacters = new char[] { ' ', '\t' };
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Valid))]
private string _address;
public string Address
partial void OnAddressChanged(string value)
{
get => _address;
set
if (ValidationHelper.ValidIPv4(value))
{
SetProperty(ref _address, value);
SetAddressType();
OnPropertyChanged(nameof(Valid));
Type = AddressType.IPv4;
}
else if (ValidationHelper.ValidIPv6(value))
{
Type = AddressType.IPv6;
}
else
{
Type = AddressType.Invalid;
}
}
[ObservableProperty]
[NotifyPropertyChangedFor(nameof(Valid))]
private string _hosts;
public string Hosts
partial void OnHostsChanged(string value)
{
get => _hosts;
set
{
SetProperty(ref _hosts, value);
OnPropertyChanged(nameof(Valid));
SplittedHosts = _hosts.Split(' ');
}
SplittedHosts = value.Split(' ');
}
[ObservableProperty]
@@ -55,7 +58,9 @@ namespace Hosts.Models
[ObservableProperty]
private bool _duplicate;
public bool Valid => ValidationHelper.ValidHosts(_hosts) && Type != AddressType.Invalid;
public bool Valid => Validate(true);
public string Line { get; private set; }
public AddressType Type { get; private set; }
@@ -70,7 +75,7 @@ namespace Hosts.Models
public Entry(int id, string line)
{
Id = id;
_line = line.Trim();
Line = line.Trim();
Parse();
}
@@ -85,9 +90,9 @@ namespace Hosts.Models
public void Parse()
{
Active = !_line.StartsWith("#", StringComparison.InvariantCultureIgnoreCase);
Active = !Line.StartsWith("#", StringComparison.InvariantCultureIgnoreCase);
var lineSplit = _line.TrimStart(' ', '#').Split('#');
var lineSplit = Line.TrimStart(' ', '#').Split('#');
if (lineSplit.Length == 0)
{
@@ -96,7 +101,7 @@ namespace Hosts.Models
var addressHost = lineSplit[0];
var addressHostSplit = addressHost.Split(' ', '\t');
var addressHostSplit = addressHost.Split(_spaceCharacters, StringSplitOptions.RemoveEmptyEntries);
var hostsBuilder = new StringBuilder();
var commentBuilder = new StringBuilder();
@@ -104,17 +109,9 @@ namespace Hosts.Models
{
var element = addressHostSplit[i].Trim();
if (string.IsNullOrWhiteSpace(element))
if (i == 0 && IPAddress.TryParse(element, out var _) && (element.Contains(':') || element.Contains('.')))
{
continue;
}
if (Address == null)
{
if (IPAddress.TryParse(element, out var _) && (element.Contains(':') || element.Contains('.')))
{
Address = element;
}
Address = element;
}
else
{
@@ -146,7 +143,7 @@ namespace Hosts.Models
{
return new Entry
{
_line = _line,
Line = Line,
Address = Address,
Hosts = Hosts,
Comment = Comment,
@@ -154,25 +151,9 @@ namespace Hosts.Models
};
}
public string GetLine()
public bool Validate(bool validateHostsLength)
{
return _line;
}
private void SetAddressType()
{
if (ValidationHelper.ValidIPv4(_address))
{
Type = AddressType.IPv4;
}
else if (ValidationHelper.ValidIPv6(_address))
{
Type = AddressType.IPv6;
}
else
{
Type = AddressType.Invalid;
}
return Type != AddressType.Invalid && ValidationHelper.ValidHosts(Hosts, validateHostsLength);
}
}
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Hosts.Models
{
/// <summary>
/// Represents the parsed hosts file
/// </summary>
public class HostsData
{
/// <summary>
/// Gets the parsed entries
/// </summary>
public ReadOnlyCollection<Entry> Entries { get; }
/// <summary>
/// Gets the lines that couldn't be parsed
/// </summary>
public string AdditionalLines { get; }
/// <summary>
/// Gets a value indicating whether some entries been splitted
/// </summary>
public bool SplittedEntries { get; }
public HostsData(List<Entry> entries, string additionalLines, bool splittedEntries)
{
Entries = entries.AsReadOnly();
AdditionalLines = additionalLines;
SplittedEntries = splittedEntries;
}
}
}

View File

@@ -13,7 +13,9 @@ namespace Hosts.Settings
public bool LoopbackDuplicates { get; }
public AdditionalLinesPosition AdditionalLinesPosition { get; }
public HostsAdditionalLinesPosition AdditionalLinesPosition { get; }
public HostsEncoding Encoding { get; }
event EventHandler LoopbackDuplicatesChanged;
}

View File

@@ -38,14 +38,17 @@ namespace Hosts.Settings
}
}
public AdditionalLinesPosition AdditionalLinesPosition { get; private set; }
public HostsAdditionalLinesPosition AdditionalLinesPosition { get; private set; }
public HostsEncoding Encoding { get; set; }
public UserSettings()
{
_settingsUtils = new SettingsUtils();
ShowStartupWarning = true;
LoopbackDuplicates = false;
AdditionalLinesPosition = AdditionalLinesPosition.Top;
AdditionalLinesPosition = HostsAdditionalLinesPosition.Top;
Encoding = HostsEncoding.Utf8;
LoadSettingsFromJson();
@@ -79,6 +82,7 @@ namespace Hosts.Settings
{
ShowStartupWarning = settings.Properties.ShowStartupWarning;
AdditionalLinesPosition = settings.Properties.AdditionalLinesPosition;
Encoding = settings.Properties.Encoding;
LoopbackDuplicates = settings.Properties.LoopbackDuplicates;
}

View File

@@ -132,6 +132,12 @@
<data name="AddEntryBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>New entry</value>
</data>
<data name="AddEntryBtn.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>New entry (CTRL+N)</value>
</data>
<data name="AddEntryLink.Content" xml:space="preserve">
<value>Add an entry</value>
</data>
<data name="AdditionalLinesBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Additional content</value>
</data>
@@ -164,6 +170,9 @@
<data name="ClearFiltersBtn.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Clear filters</value>
</data>
<data name="ClearFiltersLink.Content" xml:space="preserve">
<value>Clear filters</value>
</data>
<data name="Comment.Header" xml:space="preserve">
<value>Comment</value>
<comment>"Comment" refers to the comment of the entry</comment>
@@ -187,6 +196,16 @@
<data name="DuplicateEntryIcon.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Duplicate entry</value>
</data>
<data name="Edit.Text" xml:space="preserve">
<value>Edit</value>
</data>
<data name="EmptyFilterResults.Text" xml:space="preserve">
<value>No filter results</value>
</data>
<data name="EmptyHosts.Text" xml:space="preserve">
<value>No entries in the hosts file</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="Entries.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Entries</value>
</data>
@@ -212,7 +231,7 @@
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="Hosts.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip" xml:space="preserve">
<value>Seperate multiple hosts by space (e.g. server server.local).</value>
<value>Seperate multiple hosts by space (e.g. server server.local). Maximum 9 hosts per entry.</value>
<comment>Do not localize "server" and "server.local"</comment>
</data>
<data name="HostsFilter.Header" xml:space="preserve">
@@ -253,6 +272,17 @@
<data name="ShowOnlyDuplicates.Header" xml:space="preserve">
<value>Show only duplicates</value>
</data>
<data name="TooManyHostsTeachingTip.Subtitle" xml:space="preserve">
<value>Only 9 hosts per entry are supported</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="TooManyHostsTeachingTip.Title" xml:space="preserve">
<value>Entries with too many hosts found</value>
<comment>"Hosts" refers to the system hosts file, do not loc</comment>
</data>
<data name="TooManyHostsTeachingTipContent.Text" xml:space="preserve">
<value>The affected entries have been splitted. This will take effect on next change.</value>
</data>
<data name="UpdateBtn" xml:space="preserve">
<value>Update</value>
</data>

View File

@@ -65,23 +65,22 @@ namespace Hosts.ViewModels
[ObservableProperty]
private bool _filtered;
[ObservableProperty]
private bool _showOnlyDuplicates;
public bool ShowOnlyDuplicates
[ObservableProperty]
private bool _showSplittedEntriesTooltip;
partial void OnShowOnlyDuplicatesChanged(bool value)
{
get => _showOnlyDuplicates;
set
{
SetProperty(ref _showOnlyDuplicates, value);
ApplyFilters();
}
ApplyFilters();
}
private ObservableCollection<Entry> _entries;
public AdvancedCollectionView Entries { get; set; }
public int NextId => _entries.Max(e => e.Id) + 1;
public int NextId => _entries?.Count > 0 ? _entries.Max(e => e.Id) + 1 : 0;
public MainViewModel(IHostsService hostService, IUserSettings userSettings)
{
@@ -126,11 +125,11 @@ namespace Hosts.ViewModels
public void UpdateAdditionalLines(string lines)
{
_additionalLines = lines;
AdditionalLines = lines;
Task.Run(async () =>
{
var error = !await _hostsService.WriteAsync(_additionalLines, _entries);
var error = !await _hostsService.WriteAsync(AdditionalLines, _entries);
await _dispatcherQueue.EnqueueAsync(() => Error = error);
});
}
@@ -168,11 +167,13 @@ namespace Hosts.ViewModels
Task.Run(async () =>
{
_readingHosts = true;
(_additionalLines, var entries) = await _hostsService.ReadAsync();
var data = await _hostsService.ReadAsync();
await _dispatcherQueue.EnqueueAsync(() =>
{
_entries = new ObservableCollection<Entry>(entries);
ShowSplittedEntriesTooltip = data.SplittedEntries;
AdditionalLines = data.AdditionalLines;
_entries = new ObservableCollection<Entry>(data.Entries);
foreach (var e in _entries)
{
@@ -199,22 +200,22 @@ namespace Hosts.ViewModels
{
var expressions = new List<Expression<Func<object, bool>>>(4);
if (!string.IsNullOrWhiteSpace(_addressFilter))
if (!string.IsNullOrWhiteSpace(AddressFilter))
{
expressions.Add(e => ((Entry)e).Address.Contains(_addressFilter, StringComparison.OrdinalIgnoreCase));
expressions.Add(e => ((Entry)e).Address.Contains(AddressFilter, StringComparison.OrdinalIgnoreCase));
}
if (!string.IsNullOrWhiteSpace(_hostsFilter))
if (!string.IsNullOrWhiteSpace(HostsFilter))
{
expressions.Add(e => ((Entry)e).Hosts.Contains(_hostsFilter, StringComparison.OrdinalIgnoreCase));
expressions.Add(e => ((Entry)e).Hosts.Contains(HostsFilter, StringComparison.OrdinalIgnoreCase));
}
if (!string.IsNullOrWhiteSpace(_commentFilter))
if (!string.IsNullOrWhiteSpace(CommentFilter))
{
expressions.Add(e => ((Entry)e).Comment.Contains(_commentFilter, StringComparison.OrdinalIgnoreCase));
expressions.Add(e => ((Entry)e).Comment.Contains(CommentFilter, StringComparison.OrdinalIgnoreCase));
}
if (_showOnlyDuplicates)
if (ShowOnlyDuplicates)
{
expressions.Add(e => ((Entry)e).Duplicate);
}
@@ -238,16 +239,15 @@ namespace Hosts.ViewModels
HostsFilter = null;
CommentFilter = null;
ShowOnlyDuplicates = false;
Entries.Filter = null;
Entries.RefreshFilter();
ApplyFilters();
}
public async Task PingSelectedAsync()
{
var selected = _selected;
var selected = Selected;
selected.Ping = null;
selected.Pinging = true;
selected.Ping = await _hostsService.PingAsync(_selected.Address);
selected.Ping = await _hostsService.PingAsync(Selected.Address);
selected.Pinging = false;
}
@@ -289,7 +289,7 @@ namespace Hosts.ViewModels
Task.Run(async () =>
{
var error = !await _hostsService.WriteAsync(_additionalLines, _entries);
var error = !await _hostsService.WriteAsync(AdditionalLines, _entries);
await _dispatcherQueue.EnqueueAsync(() => Error = error);
});
}
@@ -298,7 +298,7 @@ namespace Hosts.ViewModels
{
Task.Run(async () =>
{
var error = !await _hostsService.WriteAsync(_additionalLines, _entries);
var error = !await _hostsService.WriteAsync(AdditionalLines, _entries);
await _dispatcherQueue.EnqueueAsync(() => Error = error);
});
}
@@ -350,12 +350,28 @@ namespace Hosts.ViewModels
return;
}
var hosts = entry.SplittedHosts;
var duplicate = false;
var duplicate = _entries.FirstOrDefault(e => e != entry
/*
* Duplicate are based on the following criteria:
* Entries with the same type and at least one host in common
* Entries with the same type and address, except when there is only one entry with less than 9 hosts for that type and address
*/
if (_entries.Any(e => e != entry
&& e.Type == entry.Type
&& (string.Equals(e.Address, entry.Address, StringComparison.OrdinalIgnoreCase)
|| hosts.Intersect(e.SplittedHosts, StringComparer.OrdinalIgnoreCase).Any())) != null;
&& entry.SplittedHosts.Intersect(e.SplittedHosts, StringComparer.OrdinalIgnoreCase).Any()))
{
duplicate = true;
}
else if (_entries.Any(e => e != entry
&& e.Type == entry.Type
&& string.Equals(e.Address, entry.Address, StringComparison.OrdinalIgnoreCase)))
{
duplicate = entry.SplittedHosts.Length < Consts.MaxHostsCount
&& _entries.Count(e => e.Type == entry.Type
&& string.Equals(e.Address, entry.Address, StringComparison.OrdinalIgnoreCase)
&& e.SplittedHosts.Length < Consts.MaxHostsCount) > 1;
}
_dispatcherQueue.TryEnqueue(() =>
{

View File

@@ -30,6 +30,11 @@
x:Key="BoolToInvertedVisibilityConverter"
TrueValue="Collapsed"
FalseValue="Visible" />
<converters:DoubleToVisibilityConverter
x:Key="DoubleToVisibilityConverter"
FalseValue="Visible"
GreaterThan="0"
TrueValue="Collapsed" />
</Page.Resources>
<Grid>
@@ -43,7 +48,7 @@
<Button
x:Uid="AddEntryBtn"
Height="36"
Margin="16,0,0,0"
Margin="18,0,0,0"
Command="{x:Bind NewDialogCommand}">
<StackPanel
Orientation="Horizontal"
@@ -56,10 +61,15 @@
Glyph="&#xe710;" />
<TextBlock x:Uid="AddEntry" />
</StackPanel>
<Button.KeyboardAccelerators>
<KeyboardAccelerator
Modifiers="Control"
Key="N" />
</Button.KeyboardAccelerators>
</Button>
<StackPanel
Padding="0,0,16,0"
Padding="0,0,18,0"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button
@@ -184,169 +194,239 @@
CanDragItems="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
CanReorderItems="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
-->
<ListView
x:Name="Entries"
x:Uid="Entries"
<Grid
Grid.Row="1"
Margin="16,8,16,16"
Background="{ThemeResource LayerFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="8"
IsItemClickEnabled="True"
ItemClick="Entries_ItemClick"
ItemsSource="{Binding Entries, Mode=TwoWay}"
SelectedItem="{Binding Selected, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Entry">
<Grid
AutomationProperties.Name="{x:Bind Address, Mode=OneWay}"
Background="Transparent"
IsRightTapEnabled="True"
RightTapped="Grid_RightTapped">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<FlyoutBase.AttachedFlyout>
<MenuFlyout>
<MenuFlyoutItem
x:Uid="Ping"
Click="Ping_Click"
Icon="TwoBars" />
<MenuFlyoutItem
x:Uid="MoveUp"
Click="ReorderButtonUp_Click"
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE74A;" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem
x:Uid="MoveDown"
Click="ReorderButtonDown_Click"
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE74B;" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="Delete"
Click="Delete_Click"
Icon="Delete" />
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<TextBlock
Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Address, Mode=OneWay}"
TextWrapping="Wrap" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind helpers:StringHelper.GetHostsWithComment(Hosts, Comment), Mode=OneWay}"
TextWrapping="WrapWholeWords" />
<ProgressRing
Grid.Column="2"
Width="20"
Height="20"
Margin="0,0,8,0"
IsActive="{x:Bind Pinging, Mode=OneWay}" />
<FontIcon
x:Uid="PingIcon"
x:Name="PingIcon"
Grid.Column="2"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="18"
Visibility="Collapsed">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior
Binding="{x:Bind Ping, Mode=OneWay}"
ComparisonCondition="Equal"
Value="True">
<ic:ChangePropertyAction
PropertyName="Glyph"
TargetObject="{Binding ElementName=PingIcon}"
Value="&#xe8fb;" />
<ic:ChangePropertyAction
PropertyName="Visibility"
TargetObject="{Binding ElementName=PingIcon}"
Value="Visible" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=PingIcon}"
Value="{StaticResource SystemFillColorSuccessBrush}" />
</ic:DataTriggerBehavior>
<ic:DataTriggerBehavior
Binding="{x:Bind Ping, Mode=OneWay}"
ComparisonCondition="Equal"
Value="False">
<ic:ChangePropertyAction
PropertyName="Glyph"
TargetObject="{Binding ElementName=PingIcon}"
Value="&#xe894;" />
<ic:ChangePropertyAction
PropertyName="Visibility"
TargetObject="{Binding ElementName=PingIcon}"
Value="Visible" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=PingIcon}"
Value="{StaticResource SystemFillColorCriticalBrush}" />
</ic:DataTriggerBehavior>
<ic:DataTriggerBehavior
Binding="{x:Bind Ping, Mode=OneWay}"
ComparisonCondition="Equal"
Value="{x:Null}">
<ic:ChangePropertyAction
PropertyName="Visibility"
TargetObject="{Binding ElementName=PingIcon}"
Value="Collapsed" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
</FontIcon>
<FontIcon
x:Uid="DuplicateEntryIcon"
Grid.Column="3"
Margin="0,0,8,0"
Foreground="{StaticResource SystemControlErrorTextForegroundBrush}"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="18"
Glyph="&#xe7BA;"
Visibility="{x:Bind Duplicate, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<ToggleSwitch
x:Uid="ActiveToggle"
Grid.Column="4"
Width="40"
MinWidth="0"
HorizontalAlignment="Right"
IsOn="{x:Bind Active, Mode=TwoWay}"
OffContent=""
OnContent="" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
<ListView
x:Name="Entries"
x:Uid="Entries"
Grid.Row="1"
Margin="16,8,16,16"
Background="{ThemeResource LayerFillColorDefaultBrush}"
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="8"
IsItemClickEnabled="True"
ItemClick="Entries_ItemClick"
KeyDown="Entries_KeyDown"
GotFocus="Entries_GotFocus"
ItemsSource="{x:Bind ViewModel.Entries, Mode=TwoWay}"
SelectedItem="{x:Bind ViewModel.Selected, Mode=TwoWay}"
Visibility="{x:Bind ViewModel.IsLoading, Converter={StaticResource BoolToInvertedVisibilityConverter}, Mode=OneWay}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Entry">
<Grid
AutomationProperties.Name="{x:Bind Address, Mode=OneWay}"
Background="Transparent"
IsRightTapEnabled="True"
RightTapped="Grid_RightTapped">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<FlyoutBase.AttachedFlyout>
<MenuFlyout Opened="MenuFlyout_Opened">
<MenuFlyoutItem
x:Uid="Edit"
Click="Edit_Click"
Icon="Edit">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator
Modifiers="Control"
Key="E" />
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
<MenuFlyoutItem
x:Uid="Ping"
Click="Ping_Click"
Icon="TwoBars">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator
Modifiers="Control"
Key="P" />
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
<MenuFlyoutItem
x:Uid="MoveUp"
Click="ReorderButtonUp_Click"
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE74A;" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutItem
x:Uid="MoveDown"
Click="ReorderButtonDown_Click"
IsEnabled="{Binding DataContext.Filtered, ElementName=Page, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<MenuFlyoutItem.Icon>
<FontIcon Glyph="&#xE74B;" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutSeparator />
<MenuFlyoutItem
x:Uid="Delete"
Click="Delete_Click"
Icon="Delete">
<MenuFlyoutItem.KeyboardAccelerators>
<KeyboardAccelerator Key="Delete" />
</MenuFlyoutItem.KeyboardAccelerators>
</MenuFlyoutItem>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<TextBlock
Grid.Column="0"
VerticalAlignment="Center"
Text="{x:Bind Address, Mode=OneWay}"
TextWrapping="Wrap" />
<TextBlock
Grid.Column="1"
VerticalAlignment="Center"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="{x:Bind helpers:StringHelper.GetHostsWithComment(Hosts, Comment), Mode=OneWay}"
TextWrapping="WrapWholeWords" />
<ProgressRing
Grid.Column="2"
Width="20"
Height="20"
Margin="0,0,8,0"
IsActive="{x:Bind Pinging, Mode=OneWay}" />
<FontIcon
x:Uid="PingIcon"
x:Name="PingIcon"
Grid.Column="2"
Margin="0,0,8,0"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="18"
Visibility="Collapsed">
<i:Interaction.Behaviors>
<ic:DataTriggerBehavior
Binding="{x:Bind Ping, Mode=OneWay}"
ComparisonCondition="Equal"
Value="True">
<ic:ChangePropertyAction
PropertyName="Glyph"
TargetObject="{Binding ElementName=PingIcon}"
Value="&#xe8fb;" />
<ic:ChangePropertyAction
PropertyName="Visibility"
TargetObject="{Binding ElementName=PingIcon}"
Value="Visible" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=PingIcon}"
Value="{StaticResource SystemFillColorSuccessBrush}" />
</ic:DataTriggerBehavior>
<ic:DataTriggerBehavior
Binding="{x:Bind Ping, Mode=OneWay}"
ComparisonCondition="Equal"
Value="False">
<ic:ChangePropertyAction
PropertyName="Glyph"
TargetObject="{Binding ElementName=PingIcon}"
Value="&#xe894;" />
<ic:ChangePropertyAction
PropertyName="Visibility"
TargetObject="{Binding ElementName=PingIcon}"
Value="Visible" />
<ic:ChangePropertyAction
PropertyName="Foreground"
TargetObject="{Binding ElementName=PingIcon}"
Value="{StaticResource SystemFillColorCriticalBrush}" />
</ic:DataTriggerBehavior>
<ic:DataTriggerBehavior
Binding="{x:Bind Ping, Mode=OneWay}"
ComparisonCondition="Equal"
Value="{x:Null}">
<ic:ChangePropertyAction
PropertyName="Visibility"
TargetObject="{Binding ElementName=PingIcon}"
Value="Collapsed" />
</ic:DataTriggerBehavior>
</i:Interaction.Behaviors>
</FontIcon>
<FontIcon
x:Uid="DuplicateEntryIcon"
Grid.Column="3"
Margin="0,0,8,0"
Foreground="{StaticResource SystemControlErrorTextForegroundBrush}"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
FontSize="18"
Glyph="&#xe7BA;"
Visibility="{x:Bind Duplicate, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<ToggleSwitch
x:Uid="ActiveToggle"
Grid.Column="4"
Width="40"
MinWidth="0"
HorizontalAlignment="Right"
IsOn="{x:Bind Active, Mode=TwoWay}"
OffContent=""
OnContent="" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{x:Bind ViewModel.Entries.Count, Mode=OneWay, Converter={StaticResource DoubleToVisibilityConverter}}">
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="8"
Visibility="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolToInvertedVisibilityConverter}}">
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="32"
Glyph="&#xe774;" />
<TextBlock
x:Uid="EmptyHosts"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<HyperlinkButton
x:Uid="AddEntryLink"
HorizontalAlignment="Center"
Command="{x:Bind NewDialogCommand}" />
</StackPanel>
<StackPanel
HorizontalAlignment="Center"
VerticalAlignment="Center"
Spacing="8"
Visibility="{x:Bind ViewModel.Filtered, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}">
<FontIcon
FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="32"
Glyph="&#xf78b;" />
<TextBlock
x:Uid="EmptyFilterResults"
HorizontalAlignment="Center"
TextWrapping="Wrap"
Foreground="{ThemeResource TextFillColorSecondaryBrush}" />
<HyperlinkButton
x:Uid="ClearFiltersLink"
HorizontalAlignment="Center"
Command="{x:Bind ViewModel.ClearFiltersCommand}" />
</StackPanel>
</StackPanel>
</Grid>
<ProgressRing
Width="48"
Height="48"
Grid.Row="1"
IsActive="{x:Bind ViewModel.IsLoading, Mode=OneWay}" />
<ContentDialog
x:Name="EntryDialog"
x:Uid="EntryDialog"
Loaded="ContentDialog_Loaded_ApplyMargin"
IsPrimaryButtonEnabled="{Binding Valid, Mode=TwoWay}"
IsPrimaryButtonEnabled="{Binding Valid, Mode=OneWay}"
PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
<ContentDialog.DataContext>
<models:Entry />
@@ -355,7 +435,7 @@
HorizontalScrollBarVisibility="Auto"
HorizontalScrollMode="Auto">
<StackPanel
MinWidth="480"
Width="480"
Margin="0,12,0,0"
HorizontalAlignment="Stretch"
Spacing="24">
@@ -366,10 +446,22 @@
<TextBox
x:Uid="Hosts"
IsSpellCheckEnabled="False"
AcceptsReturn="False"
TextWrapping="Wrap"
Height="100"
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"
Text="{Binding Hosts, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox
x:Uid="Comment"
IsSpellCheckEnabled="False"
IsSpellCheckEnabled="False"
AcceptsReturn="False"
TextWrapping="Wrap"
Height="100"
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"
Text="{Binding Comment, Mode=TwoWay}" />
<ToggleSwitch
x:Uid="Active"
@@ -391,7 +483,6 @@
<ContentDialog
x:Name="AdditionalLinesDialog"
x:Uid="AdditionalLinesDialog"
Loaded="ContentDialog_Loaded_ApplyMargin"
PrimaryButtonCommand="{x:Bind UpdateAdditionalLinesCommand}"
PrimaryButtonStyle="{StaticResource AccentButtonStyle}">
@@ -407,5 +498,20 @@
ScrollViewer.VerticalScrollMode="Enabled"
TextWrapping="Wrap" />
</ContentDialog>
<TeachingTip
x:Uid="TooManyHostsTeachingTip"
IsOpen="{x:Bind ViewModel.ShowSplittedEntriesTooltip, Mode=OneWay}"
PreferredPlacement="Top"
PlacementMargin="20">
<TeachingTip.IconSource>
<FontIconSource Glyph="&#xe946;" />
</TeachingTip.IconSource>
<TeachingTip.Content>
<TextBlock x:Uid="TooManyHostsTeachingTipContent"
TextWrapping="Wrap"
Margin="0,16,0,0" />
</TeachingTip.Content>
</TeachingTip>
</Grid>
</Page>

View File

@@ -1,20 +1,22 @@
// Copyright (c) Microsoft Corporation
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using Hosts.Models;
using Hosts.Settings;
using Hosts.ViewModels;
using ManagedCommon;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Input;
using Windows.ApplicationModel.Resources;
using Windows.System;
using Windows.UI.Core;
namespace Hosts.Views
{
@@ -60,9 +62,14 @@ namespace Hosts.Views
}
private async void Entries_ItemClick(object sender, ItemClickEventArgs e)
{
await ShowEditDialogAsync(e.ClickedItem as Entry);
}
public async Task ShowEditDialogAsync(Entry entry)
{
var resourceLoader = ResourceLoader.GetForViewIndependentUse();
ViewModel.Selected = e.ClickedItem as Entry;
ViewModel.Selected = entry;
EntryDialog.Title = resourceLoader.GetString("UpdateEntry_Title");
EntryDialog.PrimaryButtonText = resourceLoader.GetString("UpdateBtn");
EntryDialog.PrimaryButtonCommand = UpdateCommand;
@@ -111,21 +118,40 @@ namespace Hosts.Views
if (menuFlyoutItem != null)
{
var selectedEntry = menuFlyoutItem.DataContext as Entry;
ViewModel.Selected = selectedEntry;
DeleteDialog.Title = selectedEntry.Address;
await DeleteDialog.ShowAsync();
await ShowDeleteDialogAsync(menuFlyoutItem.DataContext as Entry);
}
}
public async Task ShowDeleteDialogAsync(Entry entry)
{
ViewModel.Selected = entry;
DeleteDialog.Title = entry.Address;
await DeleteDialog.ShowAsync();
}
private async void Ping_Click(object sender, RoutedEventArgs e)
{
var menuFlyoutItem = sender as MenuFlyoutItem;
if (menuFlyoutItem != null)
{
ViewModel.Selected = menuFlyoutItem.DataContext as Entry;
await ViewModel.PingSelectedAsync();
await PingAsync(menuFlyoutItem.DataContext as Entry);
}
}
private async Task PingAsync(Entry entry)
{
ViewModel.Selected = entry;
await ViewModel.PingSelectedAsync();
}
private async void Edit_Click(object sender, RoutedEventArgs e)
{
var menuFlyoutItem = sender as MenuFlyoutItem;
if (menuFlyoutItem != null)
{
await ShowEditDialogAsync(menuFlyoutItem.DataContext as Entry);
}
}
@@ -184,17 +210,54 @@ namespace Hosts.Views
}
}
private void ContentDialog_Loaded_ApplyMargin(object sender, RoutedEventArgs e)
/// <summary>
/// Handle the keyboard shortcuts at list view level since
/// KeyboardAccelerators in FlyoutBase.AttachedFlyout works only when the flyout is open
/// </summary>
private async void Entries_KeyDown(object sender, KeyRoutedEventArgs e)
{
try
var listView = sender as ListView;
if (listView != null && e.KeyStatus.WasKeyDown == false)
{
// Based on the template from dev/CommonStyles/ContentDialog_themeresources.xaml in https://github.com/microsoft/microsoft-ui-xaml
var border = Helpers.VisualTreeUtils.FindVisualChildByName(sender as ContentDialog, "BackgroundElement") as Border;
border.Margin = new Thickness(0, 32, 0, 0); // Should be the size reserved for the title bar as in MainWindow.xaml
var entry = listView.SelectedItem as Entry;
if (Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down))
{
if (e.Key == VirtualKey.E)
{
await ShowEditDialogAsync(entry);
}
else if (e.Key == VirtualKey.P)
{
await PingAsync(entry);
}
}
else if (e.Key == VirtualKey.Delete)
{
await ShowDeleteDialogAsync(entry);
}
}
catch (Exception ex)
}
/// <summary>
/// Focus the first item when the list view gets the focus with keyboard
/// </summary>
private void Entries_GotFocus(object sender, RoutedEventArgs e)
{
var listView = sender as ListView;
if (listView.SelectedItem == null && listView.Items.Count > 0)
{
Logger.LogError("Couldn't set the margin for a content dialog. It will appear on top of the title bar.", ex);
listView.SelectedIndex = 0;
}
}
private void MenuFlyout_Opened(object sender, object e)
{
// Focus the first item: required for workaround https://github.com/microsoft/PowerToys/issues/21263
var menuFlyout = sender as MenuFlyout;
if (menuFlyout != null && menuFlyout.Items.Count > 0)
{
menuFlyout.Items.First().Focus(FocusState.Programmatic);
}
}
}

View File

@@ -593,7 +593,8 @@ bool SuperSonar<D>::IsForegroundAppExcluded()
{
auto processPath = get_process_path(foregroundApp);
CharUpperBuffW(processPath.data(), static_cast<DWORD>(processPath.length()));
return find_app_name_in_path(processPath, m_excludedApps);
return check_excluded_app(foregroundApp, processPath, m_excludedApps);
}
else
{

View File

@@ -540,11 +540,6 @@ namespace MouseWithoutBorders
else
{
SendHeartBeat();
if (Setting.Values.BlockScreenSaverEx && lastInputEventCount == Common.InputEventCount && Common.DesMachineID == Common.MachineID)
{
PokeMyself();
}
}
lastInputEventCount = Common.InputEventCount;

View File

@@ -356,15 +356,7 @@ namespace MouseWithoutBorders.Class
if (Common.DesMachineID == ID.NONE || Common.DesMachineID == ID.ALL || Common.DesMachineID == Common.MachineID)
{
if (nCode >= 0 && Setting.Values.UseVKMap && Setting.Values.VKMap != null && Setting.Values.VKMap.ContainsKey(hookCallbackKeybdData.wVk) && !CtrlDown)
{
InputSimulation.SendKey(hookCallbackKeybdData);
return 1;
}
else
{
return NativeMethods.CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
return NativeMethods.CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
else
{
@@ -569,6 +561,13 @@ namespace MouseWithoutBorders.Class
Common.MainForm.Quit(false, false);
});
}
else if (shiftDown || winDown)
{
// The following else cases should work if control and alt modifiers are pressed. The hotkeys should still be captured.
// But if any of the other 2 modifiers (shift or win) are pressed, they hotkeys should not be activated.
// Issue #26597
return true;
}
else if (vkCode == Setting.Values.HotKeySwitchMachine ||
vkCode == Setting.Values.HotKeySwitchMachine + 1 ||
vkCode == Setting.Values.HotKeySwitchMachine + 2 ||
@@ -645,14 +644,6 @@ namespace MouseWithoutBorders.Class
}
}
}
else if (shiftDown && Setting.Values.VKMap != null && vkCode == (Setting.Values.VKMap.ContainsKey(0) ? (int)Setting.Values.VKMap[0] : 'K'))
{
if (Common.DesMachineID == Common.MachineID || Common.DesMachineID == ID.ALL)
{
Setting.Values.UseVKMap = !Setting.Values.UseVKMap;
return Common.DesMachineID == ID.ALL;
}
}
}
return true;

View File

@@ -96,11 +96,6 @@ namespace MouseWithoutBorders.Class
InputProcessKeyEx(kd.wVk, kd.dwFlags, out bool eatKey);
if (Setting.Values.UseVKMap && Setting.Values.VKMap != null && Setting.Values.VKMap.ContainsKey(kd.wVk) && !ctrlDown)
{
kd.wVk = (int)Setting.Values.VKMap[kd.wVk];
}
if (!eatKey)
{
InputHook.RealData = false;
@@ -380,15 +375,6 @@ namespace MouseWithoutBorders.Class
}
}
}
else if (Setting.Values.VKMap != null && vkCode == (Setting.Values.VKMap.ContainsKey(0) ? (int)Setting.Values.VKMap[0] : 'K'))
{
if (ctrlDown && altDown && shiftDown)
{
ctrlDown = altDown = shiftDown = false;
Setting.Values.UseVKMap = !Setting.Values.UseVKMap;
eatKey = true;
}
}
else if (vkCode == Setting.Values.HotKeyCaptureScreen && ctrlDown && shiftDown && !altDown)
{
ctrlDown = shiftDown = false;

View File

@@ -86,15 +86,25 @@ namespace MouseWithoutBorders.Class
// If we're started from the .dll module or from the service process, we should
// assume the service mode.
if (serviceMode || runningAsSystem)
if (serviceMode && !runningAsSystem)
{
if (!runningAsSystem)
try
{
var sc = new ServiceController(ServiceName);
sc.Start();
return;
}
catch (Exception ex)
{
Common.Log("Couldn't start the service. Will try to continue as not a service.");
Common.Log(ex);
serviceMode = false;
Setting.Values.UseService = false;
}
}
if (serviceMode || runningAsSystem)
{
if (args.Length > 2)
{
Helper.UserLocalAppDataPath = args[2].Trim();
@@ -350,7 +360,6 @@ namespace MouseWithoutBorders.Class
internal static void StartInputCallbackThread()
{
System.Collections.Hashtable dummy = Setting.Values.VKMap; // Reading from registry to memory.
Thread inputCallback = new(new ThreadStart(InputCallbackThread), "InputCallback Thread");
inputCallback.SetApartmentState(ApartmentState.STA);
inputCallback.Priority = ThreadPriority.Highest;

View File

@@ -303,7 +303,7 @@ namespace MouseWithoutBorders.Class
{
lock (_loadingSettingsLock)
{
_properties.MatrixOneRow = true;
_properties.MatrixOneRow = value;
if (!PauseInstantSaving)
{
SaveSettings();
@@ -501,25 +501,6 @@ namespace MouseWithoutBorders.Class
}
}
internal bool BlockScreenSaverEx
{
get
{
lock (_loadingSettingsLock)
{
return _properties.BlockScreenSaverOnOtherMachines;
}
}
set
{
lock (_loadingSettingsLock)
{
_properties.BlockScreenSaverOnOtherMachines = value;
}
}
}
internal bool MoveMouseRelatively
{
get
@@ -877,25 +858,6 @@ namespace MouseWithoutBorders.Class
}
}
internal bool UseVKMap
{
get
{
lock (_loadingSettingsLock)
{
return _properties.UseVKMap;
}
}
set
{
lock (_loadingSettingsLock)
{
_properties.UseVKMap = value;
}
}
}
internal bool FirstCtrlShiftS
{
get
@@ -915,15 +877,9 @@ namespace MouseWithoutBorders.Class
}
}
internal Hashtable VKMap
{
get
{
return new Hashtable();
}
}
internal bool StealFocusWhenSwitchingMachine => _properties.StealFocusWhenSwitchingMachine;
// Was a value read from registry on original Mouse Without Border, but default should be true. We wrongly released it as false, so we're forcing true here.
// This value wasn't changeable from UI, anyway.
internal bool StealFocusWhenSwitchingMachine => true;
private string deviceId;
@@ -1023,6 +979,30 @@ namespace MouseWithoutBorders.Class
}
}
// If starting the service fails, work in not service mode.
internal bool UseService
{
get
{
lock (_loadingSettingsLock)
{
return _properties.UseService;
}
}
set
{
lock (_loadingSettingsLock)
{
_properties.UseService = value;
if (!PauseInstantSaving)
{
SaveSettings();
}
}
}
}
internal bool SendErrorLogV2
{
get

View File

@@ -47,7 +47,7 @@ namespace MouseWithoutBorders
{
checkBoxEnabled.Checked = value;
Editable = value;
pictureBoxLogo.Image = value ? Resources.MachineEnabled : (System.Drawing.Image)Resources.MachineDisabled;
pictureBoxLogo.Image = value ? Images.MachineEnabled : (System.Drawing.Image)Images.MachineDisabled;
OnEnabledChanged(EventArgs.Empty); // Borrow this event since we do not use it for any other purpose:) (we can create one but l...:))
}
}

View File

@@ -74,7 +74,7 @@
//
// ComputerPictureBox
//
this.ComputerPictureBox.Image = global::MouseWithoutBorders.Properties.Resources.computer_connected;
this.ComputerPictureBox.Image = global::MouseWithoutBorders.Properties.Images.computer_connected;
this.ComputerPictureBox.Location = new System.Drawing.Point(5, 5);
this.ComputerPictureBox.Name = "ComputerPictureBox";
this.ComputerPictureBox.Padding = new System.Windows.Forms.Padding(0, 10, 0, 0);
@@ -86,12 +86,12 @@
// RemoveButton
//
this.RemoveButton.DisabledImage = null;
this.RemoveButton.DownImage = global::MouseWithoutBorders.Properties.Resources.red_close_button_click;
this.RemoveButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.red_close_button_hover;
this.RemoveButton.Image = global::MouseWithoutBorders.Properties.Resources.red_close_button_normal;
this.RemoveButton.DownImage = global::MouseWithoutBorders.Properties.Images.red_close_button_click;
this.RemoveButton.HoverImage = global::MouseWithoutBorders.Properties.Images.red_close_button_hover;
this.RemoveButton.Image = global::MouseWithoutBorders.Properties.Images.red_close_button_normal;
this.RemoveButton.Location = new System.Drawing.Point(224, 15);
this.RemoveButton.Name = "RemoveButton";
this.RemoveButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.red_close_button_normal;
this.RemoveButton.NormalImage = global::MouseWithoutBorders.Properties.Images.red_close_button_normal;
this.RemoveButton.Size = new System.Drawing.Size(12, 12);
this.RemoveButton.TabIndex = 5;
this.RemoveButton.TabStop = false;
@@ -101,12 +101,12 @@
//
this.OnButton.BackColor = System.Drawing.Color.Transparent;
this.OnButton.DisabledImage = null;
this.OnButton.DownImage = global::MouseWithoutBorders.Properties.Resources.switch_on_click;
this.OnButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.switch_on_hover;
this.OnButton.Image = global::MouseWithoutBorders.Properties.Resources.switch_on_normal;
this.OnButton.DownImage = global::MouseWithoutBorders.Properties.Images.switch_on_click;
this.OnButton.HoverImage = global::MouseWithoutBorders.Properties.Images.switch_on_hover;
this.OnButton.Image = global::MouseWithoutBorders.Properties.Images.switch_on_normal;
this.OnButton.Location = new System.Drawing.Point(277, 20);
this.OnButton.Name = "OnButton";
this.OnButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.switch_on_normal;
this.OnButton.NormalImage = global::MouseWithoutBorders.Properties.Images.switch_on_normal;
this.OnButton.Size = new System.Drawing.Size(30, 15);
this.OnButton.TabIndex = 3;
this.OnButton.TabStop = false;
@@ -116,12 +116,12 @@
//
this.OffButton.BackColor = System.Drawing.Color.Transparent;
this.OffButton.DisabledImage = null;
this.OffButton.DownImage = global::MouseWithoutBorders.Properties.Resources.switch_off_click;
this.OffButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.switch_off_hover;
this.OffButton.Image = global::MouseWithoutBorders.Properties.Resources.switch_off_normal;
this.OffButton.DownImage = global::MouseWithoutBorders.Properties.Images.switch_off_click;
this.OffButton.HoverImage = global::MouseWithoutBorders.Properties.Images.switch_off_hover;
this.OffButton.Image = global::MouseWithoutBorders.Properties.Images.switch_off_normal;
this.OffButton.Location = new System.Drawing.Point(241, 42);
this.OffButton.Name = "OffButton";
this.OffButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.switch_off_normal;
this.OffButton.NormalImage = global::MouseWithoutBorders.Properties.Images.switch_off_normal;
this.OffButton.Size = new System.Drawing.Size(30, 15);
this.OffButton.TabIndex = 4;
this.OffButton.TabStop = false;

View File

@@ -48,7 +48,7 @@
// SingleRowRadioButton
//
this.SingleRowRadioButton.Checked = true;
this.SingleRowRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.one_row_button_checked;
this.SingleRowRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Images.one_row_button_checked;
this.SingleRowRadioButton.ImageLocation = new System.Drawing.Point(0, 0);
this.SingleRowRadioButton.Location = new System.Drawing.Point(0, 0);
this.SingleRowRadioButton.Margin = new System.Windows.Forms.Padding(0);
@@ -57,13 +57,13 @@
this.SingleRowRadioButton.TabIndex = 4;
this.SingleRowRadioButton.TabStop = true;
this.SingleRowRadioButton.TextLocation = new System.Drawing.Point(0, 0);
this.SingleRowRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.one_row_button_unchecked;
this.SingleRowRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Images.one_row_button_unchecked;
this.SingleRowRadioButton.UseVisualStyleBackColor = true;
this.SingleRowRadioButton.CheckedChanged += new System.EventHandler(this.SingleRowRadioButtonCheckedChanged);
//
// TwoRowsRadioButton
//
this.TwoRowsRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.two_row_button_checked;
this.TwoRowsRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Images.two_row_button_checked;
this.TwoRowsRadioButton.ImageLocation = new System.Drawing.Point(0, 0);
this.TwoRowsRadioButton.Location = new System.Drawing.Point(0, 27);
this.TwoRowsRadioButton.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
@@ -71,7 +71,7 @@
this.TwoRowsRadioButton.Size = new System.Drawing.Size(27, 24);
this.TwoRowsRadioButton.TabIndex = 5;
this.TwoRowsRadioButton.TextLocation = new System.Drawing.Point(0, 0);
this.TwoRowsRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.two_row_button_unchecked;
this.TwoRowsRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Images.two_row_button_unchecked;
this.TwoRowsRadioButton.UseVisualStyleBackColor = true;
this.TwoRowsRadioButton.CheckedChanged += new System.EventHandler(this.TwoRowsRadioButtonCheckedChanged);
//

View File

@@ -40,8 +40,8 @@
//
this.closeWindowButton.BackColor = System.Drawing.Color.Transparent;
this.closeWindowButton.DisabledImage = null;
this.closeWindowButton.DownImage = global::MouseWithoutBorders.Properties.Resources.close_window_click;
this.closeWindowButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.close_window_hover;
this.closeWindowButton.DownImage = global::MouseWithoutBorders.Properties.Images.close_window_click;
this.closeWindowButton.HoverImage = global::MouseWithoutBorders.Properties.Images.close_window_hover;
this.closeWindowButton.Location = new System.Drawing.Point(454, 6);
this.closeWindowButton.Name = "closeWindowButton";
this.closeWindowButton.NormalImage = null;
@@ -67,7 +67,7 @@
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackgroundImage = global::MouseWithoutBorders.Properties.Resources.dialog_background;
this.BackgroundImage = global::MouseWithoutBorders.Properties.Images.dialog_background;
this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
this.ClientSize = new System.Drawing.Size(477, 476);
this.Controls.Add(this.closeWindowButton);

View File

@@ -52,12 +52,12 @@
// BackButton
//
this.BackButton.DisabledImage = null;
this.BackButton.DownImage = global::MouseWithoutBorders.Properties.Resources.back_button_click;
this.BackButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.back_button_hover;
this.BackButton.Image = global::MouseWithoutBorders.Properties.Resources.back_button_normal;
this.BackButton.DownImage = global::MouseWithoutBorders.Properties.Images.back_button_click;
this.BackButton.HoverImage = global::MouseWithoutBorders.Properties.Images.back_button_hover;
this.BackButton.Image = global::MouseWithoutBorders.Properties.Images.back_button_normal;
this.BackButton.Location = new System.Drawing.Point(6, 6);
this.BackButton.Name = "BackButton";
this.BackButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.back_button_normal;
this.BackButton.NormalImage = global::MouseWithoutBorders.Properties.Images.back_button_normal;
this.BackButton.Size = new System.Drawing.Size(24, 24);
this.BackButton.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
this.BackButton.TabIndex = 0;

View File

@@ -72,13 +72,13 @@
//
this.DoneButton.BackColor = System.Drawing.Color.Transparent;
this.DoneButton.DisabledImage = null;
this.DoneButton.DownImage = global::MouseWithoutBorders.Properties.Resources.done_button_click;
this.DoneButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.done_button_hover;
this.DoneButton.Image = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
this.DoneButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
this.DoneButton.DownImage = global::MouseWithoutBorders.Properties.Images.done_button_click;
this.DoneButton.HoverImage = global::MouseWithoutBorders.Properties.Images.done_button_hover;
this.DoneButton.Image = global::MouseWithoutBorders.Properties.Images.done_button_normal;
this.DoneButton.InitialImage = global::MouseWithoutBorders.Properties.Images.yes_button_normal;
this.DoneButton.Location = new System.Drawing.Point(199, 366);
this.DoneButton.Name = "DoneButton";
this.DoneButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
this.DoneButton.NormalImage = global::MouseWithoutBorders.Properties.Images.done_button_normal;
this.DoneButton.Size = new System.Drawing.Size(55, 55);
this.DoneButton.TabIndex = 8;
this.DoneButton.TabStop = false;
@@ -89,13 +89,13 @@
//
this.CloseButton.BackColor = System.Drawing.Color.Transparent;
this.CloseButton.DisabledImage = null;
this.CloseButton.DownImage = global::MouseWithoutBorders.Properties.Resources.close_button_click;
this.CloseButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.close_button_hover;
this.CloseButton.Image = global::MouseWithoutBorders.Properties.Resources.close_button_normal;
this.CloseButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
this.CloseButton.DownImage = global::MouseWithoutBorders.Properties.Images.close_button_click;
this.CloseButton.HoverImage = global::MouseWithoutBorders.Properties.Images.close_button_hover;
this.CloseButton.Image = global::MouseWithoutBorders.Properties.Images.close_button_normal;
this.CloseButton.InitialImage = global::MouseWithoutBorders.Properties.Images.yes_button_normal;
this.CloseButton.Location = new System.Drawing.Point(199, 366);
this.CloseButton.Name = "CloseButton";
this.CloseButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.close_button_normal;
this.CloseButton.NormalImage = global::MouseWithoutBorders.Properties.Images.close_button_normal;
this.CloseButton.Size = new System.Drawing.Size(55, 55);
this.CloseButton.TabIndex = 7;
this.CloseButton.TabStop = false;

View File

@@ -53,12 +53,12 @@
// AddComputerButton
//
this.AddComputerButton.DisabledImage = null;
this.AddComputerButton.DownImage = global::MouseWithoutBorders.Properties.Resources.computer_button_click;
this.AddComputerButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.computer_button_hover;
this.AddComputerButton.Image = global::MouseWithoutBorders.Properties.Resources.computer_button_normal;
this.AddComputerButton.DownImage = global::MouseWithoutBorders.Properties.Images.computer_button_click;
this.AddComputerButton.HoverImage = global::MouseWithoutBorders.Properties.Images.computer_button_hover;
this.AddComputerButton.Image = global::MouseWithoutBorders.Properties.Images.computer_button_normal;
this.AddComputerButton.Location = new System.Drawing.Point(50, 317);
this.AddComputerButton.Name = "AddComputerButton";
this.AddComputerButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.computer_button_normal;
this.AddComputerButton.NormalImage = global::MouseWithoutBorders.Properties.Images.computer_button_normal;
this.AddComputerButton.Size = new System.Drawing.Size(74, 23);
this.AddComputerButton.TabIndex = 9;
this.AddComputerButton.TabStop = false;
@@ -67,12 +67,12 @@
// KeyboardShortcutsButton
//
this.KeyboardShortcutsButton.DisabledImage = null;
this.KeyboardShortcutsButton.DownImage = global::MouseWithoutBorders.Properties.Resources.keyboard_button_click;
this.KeyboardShortcutsButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.keyboard_button_hover;
this.KeyboardShortcutsButton.Image = global::MouseWithoutBorders.Properties.Resources.keyboard_button_normal;
this.KeyboardShortcutsButton.DownImage = global::MouseWithoutBorders.Properties.Images.keyboard_button_click;
this.KeyboardShortcutsButton.HoverImage = global::MouseWithoutBorders.Properties.Images.keyboard_button_hover;
this.KeyboardShortcutsButton.Image = global::MouseWithoutBorders.Properties.Images.keyboard_button_normal;
this.KeyboardShortcutsButton.Location = new System.Drawing.Point(327, 317);
this.KeyboardShortcutsButton.Name = "KeyboardShortcutsButton";
this.KeyboardShortcutsButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.keyboard_button_normal;
this.KeyboardShortcutsButton.NormalImage = global::MouseWithoutBorders.Properties.Images.keyboard_button_normal;
this.KeyboardShortcutsButton.Size = new System.Drawing.Size(84, 23);
this.KeyboardShortcutsButton.TabIndex = 11;
this.KeyboardShortcutsButton.TabStop = false;
@@ -81,12 +81,12 @@
// AdvancedOptionsButton
//
this.AdvancedOptionsButton.DisabledImage = null;
this.AdvancedOptionsButton.DownImage = global::MouseWithoutBorders.Properties.Resources.advanced_button_click;
this.AdvancedOptionsButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.advanced_button_hover;
this.AdvancedOptionsButton.Image = global::MouseWithoutBorders.Properties.Resources.advanced_button_normal;
this.AdvancedOptionsButton.DownImage = global::MouseWithoutBorders.Properties.Images.advanced_button_click;
this.AdvancedOptionsButton.HoverImage = global::MouseWithoutBorders.Properties.Images.advanced_button_hover;
this.AdvancedOptionsButton.Image = global::MouseWithoutBorders.Properties.Images.advanced_button_normal;
this.AdvancedOptionsButton.Location = new System.Drawing.Point(244, 317);
this.AdvancedOptionsButton.Name = "AdvancedOptionsButton";
this.AdvancedOptionsButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.advanced_button_normal;
this.AdvancedOptionsButton.NormalImage = global::MouseWithoutBorders.Properties.Images.advanced_button_normal;
this.AdvancedOptionsButton.Size = new System.Drawing.Size(74, 23);
this.AdvancedOptionsButton.TabIndex = 12;
this.AdvancedOptionsButton.TabStop = false;
@@ -95,12 +95,12 @@
// LinkComputerButton
//
this.LinkComputerButton.DisabledImage = null;
this.LinkComputerButton.DownImage = global::MouseWithoutBorders.Properties.Resources.small_link_button_click;
this.LinkComputerButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.small_link_button_hover;
this.LinkComputerButton.Image = global::MouseWithoutBorders.Properties.Resources.small_link_button_normal;
this.LinkComputerButton.DownImage = global::MouseWithoutBorders.Properties.Images.small_link_button_click;
this.LinkComputerButton.HoverImage = global::MouseWithoutBorders.Properties.Images.small_link_button_hover;
this.LinkComputerButton.Image = global::MouseWithoutBorders.Properties.Images.small_link_button_normal;
this.LinkComputerButton.Location = new System.Drawing.Point(133, 317);
this.LinkComputerButton.Name = "LinkComputerButton";
this.LinkComputerButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.small_link_button_normal;
this.LinkComputerButton.NormalImage = global::MouseWithoutBorders.Properties.Images.small_link_button_normal;
this.LinkComputerButton.Size = new System.Drawing.Size(74, 23);
this.LinkComputerButton.TabIndex = 13;
this.LinkComputerButton.TabStop = false;

View File

@@ -67,7 +67,7 @@
// ShareClipboardCheckbox
//
this.ShareClipboardCheckbox.AutoSize = true;
this.ShareClipboardCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
this.ShareClipboardCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_checked;
this.ShareClipboardCheckbox.DisabledImage = null;
this.ShareClipboardCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
this.ShareClipboardCheckbox.Location = new System.Drawing.Point(54, 188);
@@ -76,14 +76,14 @@
this.ShareClipboardCheckbox.Size = new System.Drawing.Size(128, 34);
this.ShareClipboardCheckbox.TabIndex = 16;
this.ShareClipboardCheckbox.Text = "Share Clipboard (Text \r\nand Image)";
this.ShareClipboardCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
this.ShareClipboardCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_unchecked;
this.ShareClipboardCheckbox.UseVisualStyleBackColor = true;
this.ShareClipboardCheckbox.CheckedChanged += new System.EventHandler(this.ShareClipboardCheckbox_CheckedChanged);
//
// HideOnLoginCheckbox
//
this.HideOnLoginCheckbox.AutoSize = true;
this.HideOnLoginCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
this.HideOnLoginCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_checked;
this.HideOnLoginCheckbox.DisabledImage = null;
this.HideOnLoginCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
this.HideOnLoginCheckbox.Location = new System.Drawing.Point(54, 238);
@@ -92,14 +92,14 @@
this.HideOnLoginCheckbox.Size = new System.Drawing.Size(143, 34);
this.HideOnLoginCheckbox.TabIndex = 17;
this.HideOnLoginCheckbox.Text = "Hide Mouse w/o Borders \r\non the Login Desktop";
this.HideOnLoginCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
this.HideOnLoginCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_unchecked;
this.HideOnLoginCheckbox.UseVisualStyleBackColor = true;
this.HideOnLoginCheckbox.CheckedChanged += new System.EventHandler(this.HideOnLoginCheckbox_CheckedChanged);
//
// EnableEasyMouseCheckbox
//
this.EnableEasyMouseCheckbox.AutoSize = true;
this.EnableEasyMouseCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
this.EnableEasyMouseCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_checked;
this.EnableEasyMouseCheckbox.DisabledImage = null;
this.EnableEasyMouseCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
this.EnableEasyMouseCheckbox.Location = new System.Drawing.Point(54, 288);
@@ -108,14 +108,14 @@
this.EnableEasyMouseCheckbox.Size = new System.Drawing.Size(114, 19);
this.EnableEasyMouseCheckbox.TabIndex = 18;
this.EnableEasyMouseCheckbox.Text = "Enable Easy Mouse";
this.EnableEasyMouseCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
this.EnableEasyMouseCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_unchecked;
this.EnableEasyMouseCheckbox.UseVisualStyleBackColor = true;
this.EnableEasyMouseCheckbox.CheckedChanged += new System.EventHandler(this.EnableEasyMouseCheckbox_CheckedChanged);
//
// WrapMouseCheckbox
//
this.WrapMouseCheckbox.AutoSize = true;
this.WrapMouseCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
this.WrapMouseCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_checked;
this.WrapMouseCheckbox.DisabledImage = null;
this.WrapMouseCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.WrapMouseCheckbox.Location = new System.Drawing.Point(238, 288);
@@ -124,14 +124,14 @@
this.WrapMouseCheckbox.Size = new System.Drawing.Size(85, 19);
this.WrapMouseCheckbox.TabIndex = 19;
this.WrapMouseCheckbox.Text = "Wrap Mouse";
this.WrapMouseCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
this.WrapMouseCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_unchecked;
this.WrapMouseCheckbox.UseVisualStyleBackColor = true;
this.WrapMouseCheckbox.CheckedChanged += new System.EventHandler(this.WrapMouseCheckbox_CheckedChanged);
//
// DisableCADCheckbox
//
this.DisableCADCheckbox.AutoSize = true;
this.DisableCADCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
this.DisableCADCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_checked;
this.DisableCADCheckbox.DisabledImage = null;
this.DisableCADCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
this.DisableCADCheckbox.Location = new System.Drawing.Point(238, 188);
@@ -140,14 +140,14 @@
this.DisableCADCheckbox.Size = new System.Drawing.Size(154, 34);
this.DisableCADCheckbox.TabIndex = 20;
this.DisableCADCheckbox.Text = "Disable Ctrl+Alt+Del on the \r\nLogin Screen";
this.DisableCADCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
this.DisableCADCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_unchecked;
this.DisableCADCheckbox.UseVisualStyleBackColor = true;
this.DisableCADCheckbox.CheckedChanged += new System.EventHandler(this.DisableCADCheckbox_CheckedChanged);
//
// BlockScreenSaverCheckbox
//
this.BlockScreenSaverCheckbox.AutoSize = true;
this.BlockScreenSaverCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
this.BlockScreenSaverCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_checked;
this.BlockScreenSaverCheckbox.DisabledImage = null;
this.BlockScreenSaverCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
this.BlockScreenSaverCheckbox.Location = new System.Drawing.Point(238, 238);
@@ -156,7 +156,7 @@
this.BlockScreenSaverCheckbox.Size = new System.Drawing.Size(158, 34);
this.BlockScreenSaverCheckbox.TabIndex = 21;
this.BlockScreenSaverCheckbox.Text = "Block Screen Saver on Other\r\nMachines";
this.BlockScreenSaverCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
this.BlockScreenSaverCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Images.checkbox_unchecked;
this.BlockScreenSaverCheckbox.UseVisualStyleBackColor = true;
this.BlockScreenSaverCheckbox.CheckedChanged += new System.EventHandler(this.BlockScreenSaverCheckbox_CheckedChanged);
//

View File

@@ -212,7 +212,7 @@
// DisabledRadioButton
//
this.DisabledRadioButton.AutoSize = true;
this.DisabledRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_checked;
this.DisabledRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Images.radio_button_checked;
this.DisabledRadioButton.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.DisabledRadioButton.ForeColor = System.Drawing.Color.White;
this.DisabledRadioButton.ImageLocation = new System.Drawing.Point(0, 3);
@@ -222,14 +222,14 @@
this.DisabledRadioButton.TabIndex = 2;
this.DisabledRadioButton.Text = "Disabled";
this.DisabledRadioButton.TextLocation = new System.Drawing.Point(14, 0);
this.DisabledRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_unchecked;
this.DisabledRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Images.radio_button_unchecked;
this.DisabledRadioButton.UseVisualStyleBackColor = true;
this.DisabledRadioButton.CheckedChanged += new System.EventHandler(this.DisabledRadioButton_CheckedChanged);
//
// NumbersRadioButton
//
this.NumbersRadioButton.AutoSize = true;
this.NumbersRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_checked;
this.NumbersRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Images.radio_button_checked;
this.NumbersRadioButton.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.NumbersRadioButton.ForeColor = System.Drawing.Color.White;
this.NumbersRadioButton.ImageLocation = new System.Drawing.Point(0, 3);
@@ -239,14 +239,14 @@
this.NumbersRadioButton.TabIndex = 1;
this.NumbersRadioButton.Text = "1, 2, 3, 4";
this.NumbersRadioButton.TextLocation = new System.Drawing.Point(14, 0);
this.NumbersRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_unchecked;
this.NumbersRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Images.radio_button_unchecked;
this.NumbersRadioButton.UseVisualStyleBackColor = true;
this.NumbersRadioButton.CheckedChanged += new System.EventHandler(this.NumbersRadioButton_CheckedChanged);
//
// FKeysRadioButton
//
this.FKeysRadioButton.AutoSize = true;
this.FKeysRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_checked;
this.FKeysRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Images.radio_button_checked;
this.FKeysRadioButton.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.FKeysRadioButton.ForeColor = System.Drawing.Color.White;
this.FKeysRadioButton.ImageLocation = new System.Drawing.Point(0, 3);
@@ -256,7 +256,7 @@
this.FKeysRadioButton.TabIndex = 0;
this.FKeysRadioButton.Text = "F1, F2, F3, F4";
this.FKeysRadioButton.TextLocation = new System.Drawing.Point(14, 0);
this.FKeysRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_unchecked;
this.FKeysRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Images.radio_button_unchecked;
this.FKeysRadioButton.UseVisualStyleBackColor = true;
this.FKeysRadioButton.CheckedChanged += new System.EventHandler(this.FKeysRadioButton_CheckedChanged);
//

View File

@@ -110,13 +110,13 @@ namespace MouseWithoutBorders
//
this.NoButton.BackColor = System.Drawing.Color.Transparent;
this.NoButton.DisabledImage = null;
this.NoButton.DownImage = global::MouseWithoutBorders.Properties.Resources.no_button_click;
this.NoButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.no_button_hover;
this.NoButton.Image = global::MouseWithoutBorders.Properties.Resources.no_button_normal;
this.NoButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
this.NoButton.DownImage = global::MouseWithoutBorders.Properties.Images.no_button_click;
this.NoButton.HoverImage = global::MouseWithoutBorders.Properties.Images.no_button_hover;
this.NoButton.Image = global::MouseWithoutBorders.Properties.Images.no_button_normal;
this.NoButton.InitialImage = global::MouseWithoutBorders.Properties.Images.yes_button_normal;
this.NoButton.Location = new System.Drawing.Point(234, 366);
this.NoButton.Name = "NoButton";
this.NoButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.no_button_normal;
this.NoButton.NormalImage = global::MouseWithoutBorders.Properties.Images.no_button_normal;
this.NoButton.Size = new System.Drawing.Size(55, 55);
this.NoButton.TabIndex = 7;
this.NoButton.TabStop = false;
@@ -126,13 +126,13 @@ namespace MouseWithoutBorders
//
this.YesButton.BackColor = System.Drawing.Color.Transparent;
this.YesButton.DisabledImage = null;
this.YesButton.DownImage = global::MouseWithoutBorders.Properties.Resources.yes_button_click;
this.YesButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.yes_button_hover;
this.YesButton.Image = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
this.YesButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
this.YesButton.DownImage = global::MouseWithoutBorders.Properties.Images.yes_button_click;
this.YesButton.HoverImage = global::MouseWithoutBorders.Properties.Images.yes_button_hover;
this.YesButton.Image = global::MouseWithoutBorders.Properties.Images.yes_button_normal;
this.YesButton.InitialImage = global::MouseWithoutBorders.Properties.Images.yes_button_normal;
this.YesButton.Location = new System.Drawing.Point(164, 366);
this.YesButton.Name = "YesButton";
this.YesButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
this.YesButton.NormalImage = global::MouseWithoutBorders.Properties.Images.yes_button_normal;
this.YesButton.Size = new System.Drawing.Size(55, 55);
this.YesButton.TabIndex = 6;
this.YesButton.TabStop = false;
@@ -140,7 +140,7 @@ namespace MouseWithoutBorders
//
// pictureBox1
//
this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Resources.Mouse;
this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Images.Mouse;
this.pictureBox1.Location = new System.Drawing.Point(206, 40);
this.pictureBox1.Margin = new System.Windows.Forms.Padding(0);
this.pictureBox1.Name = "pictureBox1";

View File

@@ -98,14 +98,14 @@ namespace MouseWithoutBorders
//
// LinkButton
//
this.LinkButton.DisabledImage = global::MouseWithoutBorders.Properties.Resources.link_button_disabled;
this.LinkButton.DownImage = global::MouseWithoutBorders.Properties.Resources.link_button_click;
this.LinkButton.DisabledImage = global::MouseWithoutBorders.Properties.Images.link_button_disabled;
this.LinkButton.DownImage = global::MouseWithoutBorders.Properties.Images.link_button_click;
this.LinkButton.Enabled = false;
this.LinkButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.link_button_hover;
this.LinkButton.Image = global::MouseWithoutBorders.Properties.Resources.link_button_normal;
this.LinkButton.HoverImage = global::MouseWithoutBorders.Properties.Images.link_button_hover;
this.LinkButton.Image = global::MouseWithoutBorders.Properties.Images.link_button_normal;
this.LinkButton.Location = new System.Drawing.Point(199, 366);
this.LinkButton.Name = "LinkButton";
this.LinkButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.link_button_normal;
this.LinkButton.NormalImage = global::MouseWithoutBorders.Properties.Images.link_button_normal;
this.LinkButton.Size = new System.Drawing.Size(55, 55);
this.LinkButton.TabIndex = 15;
this.LinkButton.TabStop = false;
@@ -126,12 +126,12 @@ namespace MouseWithoutBorders
// ExpandHelpButton
//
this.ExpandHelpButton.DisabledImage = null;
this.ExpandHelpButton.DownImage = global::MouseWithoutBorders.Properties.Resources.expand_button_click;
this.ExpandHelpButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.expand_button_highlight;
this.ExpandHelpButton.Image = global::MouseWithoutBorders.Properties.Resources.expand_button_normal;
this.ExpandHelpButton.DownImage = global::MouseWithoutBorders.Properties.Images.expand_button_click;
this.ExpandHelpButton.HoverImage = global::MouseWithoutBorders.Properties.Images.expand_button_highlight;
this.ExpandHelpButton.Image = global::MouseWithoutBorders.Properties.Images.expand_button_normal;
this.ExpandHelpButton.Location = new System.Drawing.Point(360, 211);
this.ExpandHelpButton.Name = "ExpandHelpButton";
this.ExpandHelpButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.expand_button_normal;
this.ExpandHelpButton.NormalImage = global::MouseWithoutBorders.Properties.Images.expand_button_normal;
this.ExpandHelpButton.Size = new System.Drawing.Size(11, 11);
this.ExpandHelpButton.TabIndex = 24;
this.ExpandHelpButton.TabStop = false;
@@ -140,12 +140,12 @@ namespace MouseWithoutBorders
// CollapseHelpButton
//
this.CollapseHelpButton.DisabledImage = null;
this.CollapseHelpButton.DownImage = global::MouseWithoutBorders.Properties.Resources.collapse_button_click;
this.CollapseHelpButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.collapse_button_hover;
this.CollapseHelpButton.Image = global::MouseWithoutBorders.Properties.Resources.collapse_button_normal;
this.CollapseHelpButton.DownImage = global::MouseWithoutBorders.Properties.Images.collapse_button_click;
this.CollapseHelpButton.HoverImage = global::MouseWithoutBorders.Properties.Images.collapse_button_hover;
this.CollapseHelpButton.Image = global::MouseWithoutBorders.Properties.Images.collapse_button_normal;
this.CollapseHelpButton.Location = new System.Drawing.Point(360, 211);
this.CollapseHelpButton.Name = "CollapseHelpButton";
this.CollapseHelpButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.collapse_button_normal;
this.CollapseHelpButton.NormalImage = global::MouseWithoutBorders.Properties.Images.collapse_button_normal;
this.CollapseHelpButton.Size = new System.Drawing.Size(11, 11);
this.CollapseHelpButton.TabIndex = 25;
this.CollapseHelpButton.TabStop = false;

View File

@@ -99,7 +99,7 @@ namespace MouseWithoutBorders
//
// pictureBox1
//
this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Resources.Mouse;
this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Images.Mouse;
this.pictureBox1.Location = new System.Drawing.Point(206, 365);
this.pictureBox1.Margin = new System.Windows.Forms.Padding(0);
this.pictureBox1.Name = "pictureBox1";

View File

@@ -72,7 +72,7 @@ namespace MouseWithoutBorders
//
// ExamplePicture
//
this.ExamplePicture.Image = global::MouseWithoutBorders.Properties.Resources.copy_paste_example;
this.ExamplePicture.Image = global::MouseWithoutBorders.Properties.Images.copy_paste_example;
this.ExamplePicture.Location = new System.Drawing.Point(101, 251);
this.ExamplePicture.Name = "ExamplePicture";
this.ExamplePicture.Size = new System.Drawing.Size(251, 79);

View File

@@ -12,7 +12,7 @@ namespace MouseWithoutBorders
{
public partial class SetupPage3a : SettingsFormPage
{
private readonly Image[] _frames = { Resources.copy_paste_example, Resources.drag_example, Resources.keyboard_example };
private readonly Image[] _frames = { Images.copy_paste_example, Images.drag_example, Images.keyboard_example };
private readonly string[] _messages =
{
"Copy && paste across screens",

View File

@@ -78,7 +78,7 @@ namespace MouseWithoutBorders
//
// ExamplePicture
//
this.ExamplePicture.Image = global::MouseWithoutBorders.Properties.Resources.combined_example;
this.ExamplePicture.Image = global::MouseWithoutBorders.Properties.Images.combined_example;
this.ExamplePicture.Location = new System.Drawing.Point(75, 283);
this.ExamplePicture.Name = "ExamplePicture";
this.ExamplePicture.Size = new System.Drawing.Size(307, 25);
@@ -119,12 +119,12 @@ namespace MouseWithoutBorders
// NextButton
//
this.NextButton.DisabledImage = null;
this.NextButton.DownImage = global::MouseWithoutBorders.Properties.Resources.next_button_click;
this.NextButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.next_button_hover;
this.NextButton.Image = global::MouseWithoutBorders.Properties.Resources.next_button_normal;
this.NextButton.DownImage = global::MouseWithoutBorders.Properties.Images.next_button_click;
this.NextButton.HoverImage = global::MouseWithoutBorders.Properties.Images.next_button_hover;
this.NextButton.Image = global::MouseWithoutBorders.Properties.Images.next_button_normal;
this.NextButton.Location = new System.Drawing.Point(199, 366);
this.NextButton.Name = "NextButton";
this.NextButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.next_button_normal;
this.NextButton.NormalImage = global::MouseWithoutBorders.Properties.Images.next_button_normal;
this.NextButton.Size = new System.Drawing.Size(55, 55);
this.NextButton.TabIndex = 16;
this.NextButton.TabStop = false;

View File

@@ -43,7 +43,7 @@ namespace MouseWithoutBorders
//
// pictureBox1
//
this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Resources.Mouse;
this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Images.Mouse;
this.pictureBox1.Location = new System.Drawing.Point(206, 40);
this.pictureBox1.Margin = new System.Windows.Forms.Padding(0);
this.pictureBox1.Name = "pictureBox1";
@@ -106,12 +106,12 @@ namespace MouseWithoutBorders
// DoneButton
//
this.DoneButton.DisabledImage = null;
this.DoneButton.DownImage = global::MouseWithoutBorders.Properties.Resources.done_button_click;
this.DoneButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.done_button_hover;
this.DoneButton.Image = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
this.DoneButton.DownImage = global::MouseWithoutBorders.Properties.Images.done_button_click;
this.DoneButton.HoverImage = global::MouseWithoutBorders.Properties.Images.done_button_hover;
this.DoneButton.Image = global::MouseWithoutBorders.Properties.Images.done_button_normal;
this.DoneButton.Location = new System.Drawing.Point(199, 366);
this.DoneButton.Name = "DoneButton";
this.DoneButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
this.DoneButton.NormalImage = global::MouseWithoutBorders.Properties.Images.done_button_normal;
this.DoneButton.Size = new System.Drawing.Size(55, 56);
this.DoneButton.TabIndex = 26;
this.DoneButton.TabStop = false;

View File

@@ -42,7 +42,7 @@
// logoPictureBox
//
this.logoPictureBox.ErrorImage = null;
this.logoPictureBox.Image = global::MouseWithoutBorders.Properties.Resources.Logo;
this.logoPictureBox.Image = global::MouseWithoutBorders.Properties.Images.Logo;
this.logoPictureBox.Location = new System.Drawing.Point(12, 12);
this.logoPictureBox.Name = "logoPictureBox";
this.logoPictureBox.Size = new System.Drawing.Size(131, 136);

View File

@@ -452,6 +452,7 @@ namespace MouseWithoutBorders
//
// checkBoxVKMap
//
this.checkBoxVKMap.Enabled = false;
this.checkBoxVKMap.AutoSize = true;
this.checkBoxVKMap.Location = new System.Drawing.Point(268, 98);
this.checkBoxVKMap.Name = "checkBoxVKMap";

View File

@@ -411,8 +411,8 @@ namespace MouseWithoutBorders
AddNewMachine();
}
checkBoxVKMap.Checked = Setting.Values.UseVKMap;
// NOTE(@yuyoyuppe): this option is deprecated
// checkBoxVKMap.Checked = Setting.Values.UseVKMap;
foreach (Machine m in machines)
{
if (m.StatusClient != SocketStatus.NA)
@@ -729,8 +729,9 @@ namespace MouseWithoutBorders
checkBoxDrawMouse.Checked = Setting.Values.DrawMouse;
checkBoxReverseLookup.Checked = Setting.Values.ReverseLookup;
checkBoxSameSubNet.Checked = Setting.Values.SameSubNetOnly;
checkBoxVKMap.Checked = Setting.Values.UseVKMap;
// NOTE(@yuyoyuppe): this option is deprecated
// checkBoxVKMap.Checked = Setting.Values.UseVKMap;
foreach (Machine m in machines)
{
m.MachineName = string.Empty;
@@ -1088,7 +1089,8 @@ namespace MouseWithoutBorders
private void CheckBoxVKMap_CheckedChanged(object sender, EventArgs e)
{
Setting.Values.UseVKMap = checkBoxVKMap.Checked;
// NOTE(@yuyoyuppe): this option is deprecated
// Setting.Values.UseVKMap = checkBoxVKMap.Checked;
ShowUpdateMessage();
}

View File

@@ -237,7 +237,7 @@
// picLogonLogo
//
this.picLogonLogo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.picLogonLogo.Image = global::MouseWithoutBorders.Properties.Resources.MouseWithoutBorders;
this.picLogonLogo.Image = global::MouseWithoutBorders.Properties.Images.MouseWithoutBorders;
this.picLogonLogo.Location = new System.Drawing.Point(99, 62);
this.picLogonLogo.Name = "picLogonLogo";
this.picLogonLogo.Size = new System.Drawing.Size(95, 17);

View File

@@ -433,6 +433,11 @@ namespace MouseWithoutBorders
Program.DotForm.TopMost = true;
Program.DotForm.Show();
Application.DoEvents();
// Simulate input to help bring to the foreground, as it doesn't seem to work in every case otherwise.
NativeMethods.INPUT input = new NativeMethods.INPUT { type = (int)NativeMethods.InputType.INPUT_MOUSE, mi = { } };
NativeMethods.INPUT[] inputs = new NativeMethods.INPUT[] { input };
_ = NativeMethods.SendInput(1, inputs, Marshal.SizeOf(typeof(NativeMethods.INPUT)));
m.Result = SetForeGround() ? new IntPtr(1) : IntPtr.Zero;
break;

View File

@@ -405,7 +405,7 @@ namespace MouseWithoutBorders
CallingConvention = CallingConvention.StdCall)]
internal static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
private enum InputType
internal enum InputType
{
INPUT_MOUSE = 0,
INPUT_KEYBOARD = 1,

View File

@@ -22,14 +22,14 @@ namespace MouseWithoutBorders.Properties {
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
internal class Images {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
internal Images() {
}
/// <summary>
@@ -39,7 +39,7 @@ namespace MouseWithoutBorders.Properties {
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MouseWithoutBorders.Properties.Resources", typeof(Resources).Assembly);
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MouseWithoutBorders.Properties.Images", typeof(Images).Assembly);
resourceMan = temp;
}
return resourceMan;

View File

@@ -10,13 +10,14 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using PowerOCR.Helpers;
using PowerOCR.Models;
using Windows.Globalization;
using Windows.Graphics.Imaging;
using Windows.Media.Ocr;
@@ -26,6 +27,26 @@ namespace PowerOCR;
internal sealed class ImageMethods
{
internal static Bitmap PadImage(Bitmap image, int minW = 64, int minH = 64)
{
if (image.Height >= minH && image.Width >= minW)
{
return image;
}
int width = Math.Max(image.Width + 16, minW + 16);
int height = Math.Max(image.Height + 16, minH + 16);
// Create a compatible bitmap
Bitmap dest = new(width, height, image.PixelFormat);
using Graphics gd = Graphics.FromImage(dest);
gd.Clear(image.GetPixel(0, 0));
gd.DrawImageUnscaled(image, 8, 8);
return dest;
}
internal static ImageSource GetWindowBoundsImage(Window passedWindow)
{
bool isGrabFrame = false;
@@ -46,7 +67,7 @@ internal sealed class ImageMethods
windowHeight -= (int)(70 * dpi.DpiScaleY);
}
using Bitmap bmp = new Bitmap(windowWidth, windowHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using Bitmap bmp = new(windowWidth, windowHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(thisCorrectedLeft, thisCorrectedTop, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
@@ -55,7 +76,7 @@ internal sealed class ImageMethods
internal static async Task<string> GetRegionsText(Window? passedWindow, Rectangle selectedRegion, Language? preferredLanguage)
{
using Bitmap bmp = new Bitmap(selectedRegion.Width, selectedRegion.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Bitmap bmp = new(selectedRegion.Width, selectedRegion.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using Graphics g = Graphics.FromImage(bmp);
System.Windows.Point absPosPoint = passedWindow == null ? default(System.Windows.Point) : passedWindow.GetAbsolutePosition();
@@ -65,7 +86,7 @@ internal sealed class ImageMethods
g.CopyFromScreen(thisCorrectedLeft, thisCorrectedTop, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
// bmp = PadImage(bmp);
bmp = PadImage(bmp);
string? resultText = await ExtractText(bmp, preferredLanguage);
return resultText != null ? resultText.Trim() : string.Empty;
@@ -74,7 +95,7 @@ internal sealed class ImageMethods
internal static async Task<string> GetClickedWord(Window passedWindow, System.Windows.Point clickedPoint, Language? preferredLanguage)
{
DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow);
Bitmap bmp = new Bitmap((int)(passedWindow.ActualWidth * dpi.DpiScaleX), (int)(passedWindow.ActualHeight * dpi.DpiScaleY), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Bitmap bmp = new((int)(passedWindow.ActualWidth * dpi.DpiScaleX), (int)(passedWindow.ActualHeight * dpi.DpiScaleY), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bmp);
System.Windows.Point absPosPoint = passedWindow.GetAbsolutePosition();
@@ -91,35 +112,17 @@ internal sealed class ImageMethods
public static async Task<string> ExtractText(Bitmap bmp, Language? preferredLanguage, System.Windows.Point? singlePoint = null)
{
Language? selectedLanguage = preferredLanguage;
if (selectedLanguage == null)
{
selectedLanguage = GetOCRLanguage();
}
Language? selectedLanguage = preferredLanguage ?? GetOCRLanguage();
if (selectedLanguage == null)
{
return string.Empty;
}
bool isCJKLang = false;
if (selectedLanguage.LanguageTag.StartsWith("zh", StringComparison.InvariantCultureIgnoreCase) == true)
{
isCJKLang = true;
}
else if (selectedLanguage.LanguageTag.StartsWith("ja", StringComparison.InvariantCultureIgnoreCase) == true)
{
isCJKLang = true;
}
else if (selectedLanguage.LanguageTag.StartsWith("ko", StringComparison.InvariantCultureIgnoreCase) == true)
{
isCJKLang = true;
}
XmlLanguage lang = XmlLanguage.GetLanguage(selectedLanguage.LanguageTag);
CultureInfo culture = lang.GetEquivalentCulture();
bool isSpaceJoiningLang = LanguageHelper.IsLanguageSpaceJoining(selectedLanguage);
bool scaleBMP = true;
if (singlePoint != null
@@ -129,68 +132,38 @@ internal sealed class ImageMethods
}
using Bitmap scaledBitmap = scaleBMP ? ScaleBitmapUniform(bmp, 1.5) : ScaleBitmapUniform(bmp, 1.0);
StringBuilder text = new StringBuilder();
StringBuilder text = new();
await using (MemoryStream memory = new MemoryStream())
await using MemoryStream memoryStream = new();
using WrappingStream wrappingStream = new(memoryStream);
scaledBitmap.Save(wrappingStream, ImageFormat.Bmp);
wrappingStream.Position = 0;
BitmapDecoder bmpDecoder = await BitmapDecoder.CreateAsync(wrappingStream.AsRandomAccessStream());
SoftwareBitmap softwareBmp = await bmpDecoder.GetSoftwareBitmapAsync();
OcrEngine ocrEngine = OcrEngine.TryCreateFromLanguage(selectedLanguage);
OcrResult ocrResult = await ocrEngine.RecognizeAsync(softwareBmp);
GC.Collect();
if (singlePoint == null)
{
scaledBitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
BitmapDecoder bmpDecoder = await BitmapDecoder.CreateAsync(memory.AsRandomAccessStream());
SoftwareBitmap softwareBmp = await bmpDecoder.GetSoftwareBitmapAsync();
OcrEngine ocrEngine = OcrEngine.TryCreateFromLanguage(selectedLanguage);
OcrResult ocrResult = await ocrEngine.RecognizeAsync(softwareBmp);
if (singlePoint == null)
foreach (OcrLine ocrLine in ocrResult.Lines)
{
if (isCJKLang == false)
{
foreach (OcrLine line in ocrResult.Lines)
{
text.AppendLine(line.Text);
}
}
else
{
// Kanji, Hiragana, Katakana, Hankaku-Katakana do not need blank.(not only the symbol in CJKUnifiedIdeographs).
// Maybe there are more symbols that don't require spaces like \u3001 \u3002.
// var cjkRegex = new Regex(@"\p{IsCJKUnifiedIdeographs}|\p{IsHiragana}|\p{IsKatakana}|[\uFF61-\uFF9F]|[\u3000-\u3003]");
var cjkRegex = new Regex(@"\p{IsCJKUnifiedIdeographs}|\p{IsHiragana}|\p{IsKatakana}|[\uFF61-\uFF9F]");
foreach (OcrLine ocrLine in ocrResult.Lines)
{
bool isBeginning = true;
bool isCJKPrev = false;
foreach (OcrWord ocrWord in ocrLine.Words)
{
bool isCJK = cjkRegex.IsMatch(ocrWord.Text);
// Use spaces to separate non-CJK words.
if (!isBeginning && (!isCJK || !isCJKPrev))
{
_ = text.Append(' ');
}
_ = text.Append(ocrWord.Text);
isCJKPrev = isCJK;
isBeginning = false;
}
text.Append(Environment.NewLine);
}
}
ocrLine.GetTextFromOcrLine(isSpaceJoiningLang, text);
}
else
}
else
{
Windows.Foundation.Point fPoint = new Windows.Foundation.Point(singlePoint.Value.X, singlePoint.Value.Y);
foreach (OcrLine ocrLine in ocrResult.Lines)
{
Windows.Foundation.Point fPoint = new Windows.Foundation.Point(singlePoint.Value.X, singlePoint.Value.Y);
foreach (OcrLine ocrLine in ocrResult.Lines)
foreach (OcrWord ocrWord in ocrLine.Words)
{
foreach (OcrWord ocrWord in ocrLine.Words)
if (ocrWord.BoundingRect.Contains(fPoint))
{
if (ocrWord.BoundingRect.Contains(fPoint))
{
_ = text.Append(ocrWord.Text);
}
_ = text.Append(ocrWord.Text);
}
}
}
@@ -205,7 +178,7 @@ internal sealed class ImageMethods
{
List<string> wordArray = textLine.Split().ToList();
wordArray.Reverse();
_ = isCJKLang == true ? text.Append(string.Join(string.Empty, wordArray)) : text.Append(string.Join(' ', wordArray));
_ = text.Append(string.Join(' ', wordArray));
if (textLine.Length > 0)
{
@@ -223,27 +196,29 @@ internal sealed class ImageMethods
public static Bitmap ScaleBitmapUniform(Bitmap passedBitmap, double scale)
{
using MemoryStream memory = new MemoryStream();
passedBitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
using MemoryStream memoryStream = new();
using WrappingStream wrappingStream = new(memoryStream);
passedBitmap.Save(wrappingStream, ImageFormat.Bmp);
wrappingStream.Position = 0;
BitmapImage bitmapimage = new();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.StreamSource = wrappingStream;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
bitmapimage.Freeze();
TransformedBitmap transformedBmp = new TransformedBitmap();
TransformedBitmap transformedBmp = new();
transformedBmp.BeginInit();
transformedBmp.Source = bitmapimage;
transformedBmp.Transform = new ScaleTransform(scale, scale);
transformedBmp.EndInit();
transformedBmp.Freeze();
GC.Collect();
return BitmapSourceToBitmap(transformedBmp);
}
public static Bitmap BitmapSourceToBitmap(BitmapSource source)
{
Bitmap bmp = new Bitmap(
Bitmap bmp = new(
source.PixelWidth,
source.PixelHeight,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
@@ -257,21 +232,24 @@ internal sealed class ImageMethods
data.Height * data.Stride,
data.Stride);
bmp.UnlockBits(data);
GC.Collect();
return bmp;
}
internal static BitmapImage BitmapToImageSource(Bitmap bitmap)
{
using MemoryStream memory = new MemoryStream();
bitmap.Save(memory, ImageFormat.Bmp);
memory.Position = 0;
BitmapImage bitmapimage = new BitmapImage();
using MemoryStream memoryStream = new();
using WrappingStream wrappingStream = new(memoryStream);
bitmap.Save(wrappingStream, ImageFormat.Bmp);
wrappingStream.Position = 0;
BitmapImage bitmapimage = new();
bitmapimage.BeginInit();
bitmapimage.StreamSource = memory;
bitmapimage.StreamSource = wrappingStream;
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
bitmapimage.EndInit();
bitmapimage.Freeze();
GC.Collect();
return bitmapimage;
}
@@ -280,7 +258,7 @@ internal sealed class ImageMethods
// use currently selected Language
string inputLang = InputLanguageManager.Current.CurrentInputLanguage.Name;
Language? selectedLanguage = new Language(inputLang);
Language? selectedLanguage = new(inputLang);
List<Language> possibleOcrLanguages = OcrEngine.AvailableRecognizerLanguages.ToList();
if (possibleOcrLanguages.Count < 1)

View File

@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Windows.Globalization;
namespace PowerOCR.Helpers
{
internal static class LanguageHelper
{
public static bool IsLanguageSpaceJoining(Language selectedLanguage)
{
if (selectedLanguage.LanguageTag.StartsWith("zh", StringComparison.InvariantCultureIgnoreCase))
{
return false;
}
else if (selectedLanguage.LanguageTag.Equals("ja", StringComparison.OrdinalIgnoreCase))
{
return false;
}
return true;
}
}
}

View File

@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Text;
using System.Text.RegularExpressions;
using Windows.Media.Ocr;
namespace PowerOCR.Helpers
{
internal static class OcrExtensions
{
public static void GetTextFromOcrLine(this OcrLine ocrLine, bool isSpaceJoiningOCRLang, StringBuilder text)
{
// (when OCR language is zh or ja)
// matches words in a space-joining language, which contains:
// - one letter that is not in "other letters" (CJK characters are "other letters")
// - one number digit
// - any words longer than one character
// Chinese and Japanese characters are single-character words
// when a word is one punctuation/symbol, join it without spaces
if (isSpaceJoiningOCRLang)
{
text.AppendLine(ocrLine.Text);
}
else
{
bool isFirstWord = true;
bool isPrevWordSpaceJoining = false;
Regex regexSpaceJoiningWord = new(@"(^[\p{L}-[\p{Lo}]]|\p{Nd}$)|.{2,}");
foreach (OcrWord ocrWord in ocrLine.Words)
{
string wordString = ocrWord.Text;
bool isThisWordSpaceJoining = regexSpaceJoiningWord.IsMatch(wordString);
if (isFirstWord || (!isThisWordSpaceJoining && !isPrevWordSpaceJoining))
{
_ = text.Append(wordString);
}
else
{
_ = text.Append(' ').Append(wordString);
}
isFirstWord = false;
isPrevWordSpaceJoining = isThisWordSpaceJoining;
}
}
}
}
}

View File

@@ -0,0 +1,228 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
namespace PowerOCR.Models;
/// <summary>
/// A <see cref="Stream"/> that wraps another stream. The major feature of <see cref="WrappingStream"/> is that it does not dispose the
/// underlying stream when it is disposed; this is useful when using classes such as <see cref="BinaryReader"/> and
/// <see cref="System.Security.Cryptography.CryptoStream"/> that take ownership of the stream passed to their constructors.
/// </summary>
public class WrappingStream : Stream
{
private Stream? _streamBase;
/// <summary>
/// Initializes a new instance of the <see cref="WrappingStream"/> class.
/// </summary>
/// <param name="streamBase">The wrapped stream.</param>
public WrappingStream(Stream streamBase)
{
_streamBase = streamBase ?? throw new ArgumentNullException(nameof(streamBase));
}
/// <summary>
/// Gets a value indicating whether the current stream supports reading.
/// </summary>
/// <returns><c>true</c> if the stream supports reading; otherwise, <c>false</c>.</returns>
public override bool CanRead => _streamBase != null && _streamBase.CanRead;
/// <summary>
/// Gets a value indicating whether the current stream supports seeking.
/// </summary>
/// <returns><c>true</c> if the stream supports seeking; otherwise, <c>false</c>.</returns>
public override bool CanSeek => _streamBase != null && _streamBase.CanSeek;
/// <summary>
/// Gets a value indicating whether the current stream supports writing.
/// </summary>
/// <returns><c>true</c> if the stream supports writing; otherwise, <c>false</c>.</returns>
public override bool CanWrite => _streamBase != null && _streamBase.CanWrite;
/// <summary>
/// Gets the length in bytes of the stream.
/// </summary>
public override long Length
{
get
{
ThrowIfDisposed();
return _streamBase is not null ? _streamBase.Length : 0;
}
}
/// <summary>
/// Gets or sets the position within the current stream.
/// </summary>
public override long Position
{
get
{
ThrowIfDisposed();
return _streamBase is not null ? _streamBase.Position : 0;
}
set
{
ThrowIfDisposed();
if (_streamBase is not null)
{
_streamBase.Position = value;
}
}
}
/// <summary>
/// Begins an asynchronous read operation.
/// </summary>
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
ThrowIfDisposed();
return _streamBase is not null && callback is not null && state is not null
? _streamBase.BeginRead(buffer, offset, count, callback, state)
: new NullAsyncResult();
}
/// <summary>
/// Begins an asynchronous write operation.
/// </summary>
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
ThrowIfDisposed();
return _streamBase is not null && callback is not null && state is not null
? _streamBase.BeginWrite(buffer, offset, count, callback, state)
: new NullAsyncResult();
}
/// <summary>
/// Waits for the pending asynchronous read to complete.
/// </summary>
public override int EndRead(IAsyncResult asyncResult)
{
ThrowIfDisposed();
return _streamBase is not null ? _streamBase.EndRead(asyncResult) : 0;
}
/// <summary>
/// Ends an asynchronous write operation.
/// </summary>
public override void EndWrite(IAsyncResult asyncResult)
{
ThrowIfDisposed();
_streamBase?.EndWrite(asyncResult);
}
/// <summary>
/// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
/// </summary>
public override void Flush()
{
ThrowIfDisposed();
_streamBase?.Flush();
}
/// <summary>
/// Reads a sequence of bytes from the current stream and advances the position
/// within the stream by the number of bytes read.
/// </summary>
public override int Read(byte[] buffer, int offset, int count)
{
ThrowIfDisposed();
return _streamBase is not null ? _streamBase.Read(buffer, offset, count) : 0;
}
/// <summary>
/// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
/// </summary>
public override int ReadByte()
{
ThrowIfDisposed();
return _streamBase is not null ? _streamBase.ReadByte() : 0;
}
/// <summary>
/// Sets the position within the current stream.
/// </summary>
/// <param name="offset">A byte offset relative to the <paramref name="origin"/> parameter.</param>
/// <param name="origin">A value of type see System.IO.SeekOrigin indicating the reference point used to obtain the new position.</param>
/// <returns>The new position within the current stream.</returns>
public override long Seek(long offset, SeekOrigin origin)
{
ThrowIfDisposed();
return _streamBase is not null ? _streamBase.Seek(offset, origin) : 0;
}
/// <summary>
/// Sets the length of the current stream.
/// </summary>
/// <param name="value">The desired length of the current stream in bytes.</param>
public override void SetLength(long value)
{
ThrowIfDisposed();
_streamBase?.SetLength(value);
}
/// <summary>
/// Writes a sequence of bytes to the current stream and advances the current position
/// within this stream by the number of bytes written.
/// </summary>
public override void Write(byte[] buffer, int offset, int count)
{
ThrowIfDisposed();
_streamBase?.Write(buffer, offset, count);
}
/// <summary>
/// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
/// </summary>
public override void WriteByte(byte value)
{
ThrowIfDisposed();
_streamBase?.WriteByte(value);
}
/// <summary>
/// Gets the wrapped stream.
/// </summary>
/// <value>The wrapped stream.</value>
protected Stream? WrappedStream => _streamBase;
/// <summary>
/// Releases the unmanaged resources used by the <see cref="WrappingStream"/> and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
protected override void Dispose(bool disposing)
{
// doesn't close the base stream, but just prevents access to it through this WrappingStream
if (disposing)
{
_streamBase = null;
}
base.Dispose(disposing);
}
private void ThrowIfDisposed()
{
// throws an ObjectDisposedException if this object has been disposed
if (_streamBase == null)
{
throw new ObjectDisposedException(GetType().Name);
}
}
}

View File

@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Threading;
namespace PowerOCR.Models;
public class NullAsyncResult : IAsyncResult
{
public object? AsyncState => null;
public WaitHandle AsyncWaitHandle => new NullWaitHandle();
public bool CompletedSynchronously => true;
public bool IsCompleted => true;
}

View File

@@ -0,0 +1,11 @@
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Threading;
namespace PowerOCR.Models;
public class NullWaitHandle : WaitHandle
{
}

View File

@@ -30,7 +30,7 @@ public partial class OCROverlay : Window
private bool IsSelecting { get; set; }
private Border selectBorder = new Border();
private Border selectBorder = new();
private DpiScale? dpiScale;
@@ -57,7 +57,7 @@ public partial class OCROverlay : Window
{
InitializeComponent();
var userSettings = new UserSettings(new Helpers.ThrottledActionInvoker());
var userSettings = new UserSettings(new ThrottledActionInvoker());
string? selectedLanguageName = userSettings.PreferredLanguage.Value;
// build context menu
@@ -70,7 +70,7 @@ public partial class OCROverlay : Window
List<Language> possibleOcrLanguages = OcrEngine.AvailableRecognizerLanguages.ToList();
foreach (Language language in possibleOcrLanguages)
{
MenuItem menuItem = new MenuItem() { Header = language.NativeName, Tag = language, IsCheckable = true };
MenuItem menuItem = new() { Header = language.NativeName, Tag = language, IsCheckable = true };
menuItem.IsChecked = language.DisplayName.Equals(selectedLanguageName, StringComparison.Ordinal);
if (language.DisplayName.Equals(selectedLanguageName, StringComparison.Ordinal))
{
@@ -94,9 +94,8 @@ public partial class OCROverlay : Window
MenuItem menuItem = (MenuItem)sender;
foreach (var item in CanvasContextMenu.Items)
{
if (item is MenuItem)
if (item is MenuItem menuItemLoop)
{
MenuItem menuItemLoop = (MenuItem)item;
menuItemLoop.IsChecked = item.Equals(menuItem);
}
}
@@ -195,7 +194,7 @@ public partial class OCROverlay : Window
Canvas.SetTop(selectBorder, clickedPoint.Y);
var screens = System.Windows.Forms.Screen.AllScreens;
System.Drawing.Point formsPoint = new System.Drawing.Point((int)clickedPoint.X, (int)clickedPoint.Y);
System.Drawing.Point formsPoint = new((int)clickedPoint.X, (int)clickedPoint.Y);
foreach (var scr in screens)
{
if (scr.Bounds.Contains(formsPoint))
@@ -295,7 +294,7 @@ public partial class OCROverlay : Window
double xDimScaled = Canvas.GetLeft(selectBorder) * m.M11;
double yDimScaled = Canvas.GetTop(selectBorder) * m.M22;
System.Drawing.Rectangle regionScaled = new System.Drawing.Rectangle(
System.Drawing.Rectangle regionScaled = new(
(int)xDimScaled,
(int)yDimScaled,
(int)(selectBorder.Width * m.M11),

View File

@@ -24,7 +24,8 @@ bool isExcluded(HWND window)
{
auto processPath = get_process_path(window);
CharUpperBuffW(processPath.data(), static_cast<DWORD>(processPath.length()));
return find_app_name_in_path(processPath, AlwaysOnTopSettings::settings().excludedApps);
return check_excluded_app(window, processPath, AlwaysOnTopSettings::settings().excludedApps);
}
AlwaysOnTop::AlwaysOnTop(bool useLLKH) :

View File

@@ -3,11 +3,12 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.IO;
using System.IO.Abstractions;
using System.Linq;
using System.Text.Json;
using System.Threading;
using ColorPicker.Common;
using ManagedCommon;
@@ -23,6 +24,7 @@ namespace ColorPicker.Settings
{
private readonly ISettingsUtils _settingsUtils;
private const string ColorPickerModuleName = "ColorPicker";
private const string ColorPickerHistoryFilename = "colorHistory.json";
private const string DefaultActivationShortcut = "Ctrl + Break";
private const int MaxNumberOfRetry = 5;
private const int SettingsReadOnChangeDelayInMs = 300;
@@ -56,11 +58,7 @@ namespace ColorPicker.Settings
{
if (!_loadingColorsHistory)
{
var settings = _settingsUtils.GetSettingsOrDefault<ColorPickerSettings, ColorPickerSettingsVersion1>(ColorPickerModuleName, settingsUpgrader: ColorPickerSettings.UpgradeSettings);
ColorHistory.CollectionChanged -= ColorHistory_CollectionChanged;
settings.Properties.ColorHistory = ColorHistory.ToList();
ColorHistory.CollectionChanged += ColorHistory_CollectionChanged;
settings.Save(_settingsUtils);
_settingsUtils.SaveSettings(JsonSerializer.Serialize(ColorHistory, new JsonSerializerOptions { WriteIndented = true }), ColorPickerModuleName, ColorPickerHistoryFilename);
}
}
@@ -120,14 +118,31 @@ namespace ColorPicker.Settings
ColorHistoryLimit.Value = settings.Properties.ColorHistoryLimit;
ShowColorName.Value = settings.Properties.ShowColorName;
if (settings.Properties.ColorHistory == null)
List<string> savedColorHistory = new List<string>();
try
{
settings.Properties.ColorHistory = new System.Collections.Generic.List<string>();
string filePath = _settingsUtils.GetSettingsFilePath(ColorPickerModuleName, ColorPickerHistoryFilename);
if (!File.Exists(filePath))
{
if (settings.Properties.ColorHistory != null)
{
savedColorHistory = settings.Properties.ColorHistory;
}
}
else
{
string jsonSettingsString = System.IO.File.ReadAllText(filePath).Trim('\0');
savedColorHistory = JsonSerializer.Deserialize<List<string>>(jsonSettingsString);
}
}
catch (Exception)
{
Logger.LogInfo("ColorPicker colorHistory.json was missing or corrupt");
}
_loadingColorsHistory = true;
ColorHistory.Clear();
foreach (var item in settings.Properties.ColorHistory)
foreach (var item in savedColorHistory)
{
ColorHistory.Add(item);
}

View File

@@ -5,8 +5,9 @@
#include <FancyZonesLib/util.h>
DraggingState::DraggingState(const std::function<void()>& keyUpdateCallback) :
m_mouseState(false),
m_mouseHook(std::bind(&DraggingState::OnMouseDown, this)),
m_secondaryMouseState(false),
m_middleMouseState(false),
m_mouseHook(std::bind(&DraggingState::OnSecondaryMouseDown, this), std::bind(&DraggingState::OnMiddleMouseDown, this)),
m_leftShiftKeyState(keyUpdateCallback),
m_rightShiftKeyState(keyUpdateCallback),
m_ctrlKeyState(keyUpdateCallback),
@@ -45,7 +46,8 @@ void DraggingState::Disable()
}
m_dragging = false;
m_mouseState = false;
m_secondaryMouseState = false;
m_middleMouseState = false;
m_mouseHook.disable();
m_leftShiftKeyState.disable();
@@ -58,17 +60,28 @@ void DraggingState::UpdateDraggingState() noexcept
// This updates m_dragEnabled depending on if the shift key is being held down
if (FancyZonesSettings::settings().shiftDrag)
{
m_dragging = ((m_leftShiftKeyState.state() || m_rightShiftKeyState.state()) ^ m_mouseState);
m_dragging = ((m_leftShiftKeyState.state() || m_rightShiftKeyState.state()) ^ m_secondaryMouseState);
}
else
{
m_dragging = !((m_leftShiftKeyState.state() || m_rightShiftKeyState.state()) ^ m_mouseState);
m_dragging = !((m_leftShiftKeyState.state() || m_rightShiftKeyState.state()) ^ m_secondaryMouseState);
}
}
void DraggingState::OnMouseDown()
void DraggingState::OnSecondaryMouseDown()
{
m_mouseState = !m_mouseState;
m_secondaryMouseState = !m_secondaryMouseState;
m_keyUpdateCallback();
}
void DraggingState::OnMiddleMouseDown()
{
if (!this->IsDragging())
{
return;
}
m_middleMouseState = !m_middleMouseState;
m_keyUpdateCallback();
}
@@ -79,5 +92,5 @@ bool DraggingState::IsDragging() const noexcept
bool DraggingState::IsSelectManyZonesState() const noexcept
{
return m_ctrlKeyState.state();
return m_ctrlKeyState.state() || m_middleMouseState;
}

View File

@@ -1,7 +1,7 @@
#pragma once
#include <FancyZonesLib/KeyState.h>
#include <FancyZonesLib/SecondaryMouseButtonsHook.h>
#include <FancyZonesLib/MouseButtonsHook.h>
class DraggingState
{
@@ -17,10 +17,12 @@ public:
bool IsSelectManyZonesState() const noexcept;
private:
void OnMouseDown();
void OnSecondaryMouseDown();
void OnMiddleMouseDown();
std::atomic<bool> m_mouseState;
SecondaryMouseButtonsHook m_mouseHook;
std::atomic<bool> m_secondaryMouseState;
std::atomic<bool> m_middleMouseState;
MouseButtonsHook m_mouseHook;
KeyState<VK_LSHIFT> m_leftShiftKeyState;
KeyState<VK_RSHIFT> m_rightShiftKeyState;
KeyState<VK_LCONTROL, VK_RCONTROL> m_ctrlKeyState;

View File

@@ -1236,7 +1236,7 @@ bool FancyZones::ShouldProcessSnapHotkey(DWORD vkCode) noexcept
return false;
}
if (layout->Type() != FancyZonesDataTypes::ZoneSetLayoutType::Blank)
if (layout->Zones().size() > 0)
{
if (vkCode == VK_UP || vkCode == VK_DOWN)
{

View File

@@ -16,7 +16,7 @@ namespace FancyZonesDataTypes
{
enum class ZoneSetLayoutType : int
{
Blank = -1,
Blank,
Focus,
Columns,
Rows,

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