mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-29 08:29:10 +01:00
Compare commits
30 Commits
leilzh/azt
...
lei
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9081bc7438 | ||
|
|
7307242396 | ||
|
|
630ed29700 | ||
|
|
41b0b850e1 | ||
|
|
96dc200324 | ||
|
|
9597f87dc4 | ||
|
|
7572586b4c | ||
|
|
3970e89ee7 | ||
|
|
74214f611e | ||
|
|
908a690316 | ||
|
|
6515374ce9 | ||
|
|
273a45ff1f | ||
|
|
17f3c12a11 | ||
|
|
fa4471a9e6 | ||
|
|
727de3e1fc | ||
|
|
c6f9701818 | ||
|
|
9453e38881 | ||
|
|
a1a02889d5 | ||
|
|
0592e74d3d | ||
|
|
9d148d0a3a | ||
|
|
0a51687b65 | ||
|
|
771fcaba96 | ||
|
|
82e386f63c | ||
|
|
91b53cdc13 | ||
|
|
5c2c74a6c9 | ||
|
|
cb5baad677 | ||
|
|
ec136d7bb7 | ||
|
|
e33efb7f10 | ||
|
|
68afc6623f | ||
|
|
5008d77105 |
6
.github/actions/spell-check/allow/code.txt
vendored
6
.github/actions/spell-check/allow/code.txt
vendored
@@ -263,6 +263,10 @@ onefuzz
|
||||
|
||||
# NameInCode
|
||||
leilzh
|
||||
mengyuanchen
|
||||
|
||||
# DllName
|
||||
testhost
|
||||
|
||||
#Tools
|
||||
OIP
|
||||
OIP
|
||||
|
||||
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
@@ -734,6 +734,7 @@ KEYBDINPUT
|
||||
keyboardeventhandlers
|
||||
keyboardmanagercommon
|
||||
KEYBOARDMANAGEREDITOR
|
||||
KEYBOARDMANAGEREDITORLIBRARYWRAPPER
|
||||
keyboardmanagerstate
|
||||
keyboardmanagerui
|
||||
KEYEVENTF
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
trigger: none
|
||||
pr: none
|
||||
schedules:
|
||||
- cron: "0 0 * * *" # every day at midnight
|
||||
displayName: "Daily midnight Build"
|
||||
branches:
|
||||
include:
|
||||
- main
|
||||
always: false # only run if there's code changes!
|
||||
|
||||
name: $(BuildDefinitionName)_$(date:yyMM).$(date:dd)$(rev:rrr)
|
||||
|
||||
@@ -15,7 +8,6 @@ parameters:
|
||||
type: object
|
||||
default:
|
||||
- x64
|
||||
- arm64
|
||||
- name: enableMsBuildCaching
|
||||
type: boolean
|
||||
displayName: "Enable MSBuild Caching"
|
||||
@@ -28,15 +20,6 @@ parameters:
|
||||
type: boolean
|
||||
displayName: "Build Using Visual Studio Preview"
|
||||
default: false
|
||||
- name: useLatestWinAppSDK
|
||||
type: boolean
|
||||
default: true
|
||||
- name: winAppSDKVersionNumber
|
||||
type: string
|
||||
default: 1.6
|
||||
- name: useExperimentalVersion
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
extends:
|
||||
template: templates/pipeline-ci-build.yml
|
||||
@@ -45,6 +28,3 @@ extends:
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
runTests: ${{ parameters.runTests }}
|
||||
useVSPreview: ${{ parameters.useVSPreview }}
|
||||
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
|
||||
winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }}
|
||||
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}
|
||||
|
||||
@@ -456,12 +456,6 @@ jobs:
|
||||
Copy-Item src\gpo\assets\* "$(JobOutputDirectory)/gpo" -Recurse
|
||||
displayName: Stage GPO files
|
||||
|
||||
- ${{ if eq(parameters.publishArtifacts, true) }}:
|
||||
- publish: $(JobOutputDirectory)
|
||||
artifact: $(JobOutputArtifactName)
|
||||
displayName: Publish all outputs
|
||||
condition: always()
|
||||
|
||||
# Running the tests may result in future jobs consuming artifacts out of this build
|
||||
- ${{ if eq(parameters.runTests, true) }}:
|
||||
- task: CopyFiles@2
|
||||
@@ -471,17 +465,8 @@ jobs:
|
||||
contents: '$(BuildPlatform)/$(BuildConfiguration)/**/*'
|
||||
targetFolder: '$(JobOutputDirectory)\$(BuildPlatform)\$(BuildConfiguration)'
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: Stage entire build output
|
||||
inputs:
|
||||
sourceFolder: $(JobOutputDirectory)
|
||||
contents: |-
|
||||
**
|
||||
!**\*.pdb
|
||||
!**\*.lib
|
||||
targetFolder: '$(JobOutputDirectory)\TestArtifacts'
|
||||
|
||||
- publish: $(JobOutputDirectory)\TestArtifacts
|
||||
artifact: $(JobOutputArtifactName)-TestArtifacts
|
||||
displayName: Publish all outputs for testing
|
||||
- ${{ if eq(parameters.publishArtifacts, true) }}:
|
||||
- publish: $(JobOutputDirectory)
|
||||
artifact: $(JobOutputArtifactName)
|
||||
displayName: Publish all outputs
|
||||
condition: always()
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
BuildPlatform: ${{ parameters.platform }}
|
||||
BuildConfiguration: ${{ parameters.configuration }}
|
||||
SrcPath: $(Build.Repository.LocalPath)
|
||||
TestArtifactsName: build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }}-TestArtifacts
|
||||
TestArtifactsName: build-${{ parameters.platform }}-${{ parameters.configuration }}${{ parameters.inputArtifactStem }}
|
||||
pool:
|
||||
${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
|
||||
${{ if ne(parameters.platform, 'ARM64') }}:
|
||||
@@ -61,13 +61,18 @@ jobs:
|
||||
reg add "HKLM\Software\Policies\Microsoft\Edge\WebView2\ReleaseChannels" /v PowerToys.exe /t REG_SZ /d "3"
|
||||
displayName: "Enable WebView2 Canary Channel"
|
||||
|
||||
- download: current
|
||||
displayName: Download artifacts
|
||||
artifact: $(TestArtifactsName)
|
||||
patterns: |-
|
||||
**
|
||||
!**\*.pdb
|
||||
!**\*.lib
|
||||
- ${{ if ne(parameters.platform, 'arm64') }}:
|
||||
- download: current
|
||||
displayName: Download artifacts
|
||||
artifact: $(TestArtifactsName)
|
||||
patterns: |-
|
||||
**
|
||||
!**\*.pdb
|
||||
!**\*.lib
|
||||
- ${{ else }}:
|
||||
- template: steps-download-artifacts-with-azure-cli.yml
|
||||
parameters:
|
||||
artifactName: $(TestArtifactsName)
|
||||
|
||||
- template: steps-ensure-dotnet-version.yml
|
||||
parameters:
|
||||
|
||||
@@ -43,43 +43,11 @@ stages:
|
||||
- template: job-ci-precheck.yml
|
||||
|
||||
- ${{ each platform in parameters.buildPlatforms }}:
|
||||
- stage: Build_${{ platform }}
|
||||
displayName: Build ${{ platform }}
|
||||
${{ if ne(variables['Build.Reason'], 'Manual') }}:
|
||||
dependsOn: [Precheck]
|
||||
condition: and(succeeded(), ne(dependencies.Precheck.outputs['Precheck.verifyBuildRequest.skipBuild'], 'Yes'))
|
||||
${{ else }}:
|
||||
dependsOn: []
|
||||
- stage: Test_${{ platform }}
|
||||
displayName: Test ${{ platform }}
|
||||
jobs:
|
||||
- template: job-build-project.yml
|
||||
- template: job-test-project.yml
|
||||
parameters:
|
||||
pool:
|
||||
${{ if eq(variables['System.CollectionId'], 'cb55739e-4afe-46a3-970f-1b49d8ee7564') }}:
|
||||
name: SHINE-INT-L
|
||||
${{ else }}:
|
||||
name: SHINE-OSS-L
|
||||
${{ if eq(parameters.useVSPreview, true) }}:
|
||||
demands: ImageOverride -equals SHINE-VS17-Preview
|
||||
buildPlatforms:
|
||||
- ${{ platform }}
|
||||
buildConfigurations: [Release]
|
||||
enablePackageCaching: true
|
||||
enableMsBuildCaching: ${{ parameters.enableMsBuildCaching }}
|
||||
runTests: ${{ parameters.runTests }}
|
||||
useVSPreview: ${{ parameters.useVSPreview }}
|
||||
useLatestWinAppSDK: ${{ parameters.useLatestWinAppSDK }}
|
||||
${{ if eq(parameters.useLatestWinAppSDK, true) }}:
|
||||
winAppSDKVersionNumber: ${{ parameters.winAppSDKVersionNumber }}
|
||||
useExperimentalVersion: ${{ parameters.useExperimentalVersion }}
|
||||
|
||||
- ${{ if eq(parameters.runTests, true) }}:
|
||||
- stage: Test_${{ platform }}
|
||||
displayName: Test ${{ platform }}
|
||||
dependsOn:
|
||||
- Build_${{platform}}
|
||||
jobs:
|
||||
- template: job-test-project.yml
|
||||
parameters:
|
||||
platform: ${{ platform }}
|
||||
configuration: Release
|
||||
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
|
||||
platform: ${{ platform }}
|
||||
configuration: Release
|
||||
useLatestWebView2: ${{ parameters.useLatestWebView2 }}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
parameters:
|
||||
- name: artifactName
|
||||
type: string
|
||||
default: ""
|
||||
|
||||
# Why use az cli to download? → The ARM agent may run into OutOfMemory issues.
|
||||
# Why use the Azure CLI ZIP version? → It comes with its own Python and works fine under emulation on ARM64.
|
||||
# Why not use AzureCLI@2 task? → It requires azureSubscription, which is unnecessary for downloading artifacts.
|
||||
|
||||
steps:
|
||||
- powershell: |
|
||||
Write-Host "Downloading Azure CLI ZIP..."
|
||||
$azCliUrl = "https://aka.ms/installazurecliwindowszipx64"
|
||||
$azCliZip = "$(Build.ArtifactStagingDirectory)\azure-cli.zip"
|
||||
|
||||
Invoke-WebRequest -Uri $azCliUrl -OutFile $azCliZip
|
||||
displayName: 'Install Azure CLI from ZIP'
|
||||
|
||||
- task: ExtractFiles@1
|
||||
inputs:
|
||||
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)\azure-cli.zip'
|
||||
destinationFolder: '$(Build.ArtifactStagingDirectory)\AzureCLI'
|
||||
|
||||
- pwsh: |
|
||||
$azureCliPath = "$(Build.ArtifactStagingDirectory)\AzureCLI\bin"
|
||||
$env:Path = "$azureCliPath;" + $env:Path
|
||||
Write-Host "Add azure-devops..."
|
||||
az extension add -n azure-devops
|
||||
Write-Host "Configuring Azure DevOps defaults..."
|
||||
az devops configure --defaults organization='$(System.TeamFoundationCollectionUri)' project='$(System.TeamProject)' --use-git-aliases true
|
||||
Write-Host "check permission"
|
||||
az pipelines list --org "$(System.TeamFoundationCollectionUri)" --project "$(System.TeamProject)" --output table
|
||||
Write-Host "Downloading artifacts..."
|
||||
if ($env:AZURE_DEVOPS_EXT_PAT -eq $null -or $env:AZURE_DEVOPS_EXT_PAT -eq "") {
|
||||
Write-Host "Error: AZURE_DEVOPS_EXT_PAT is not set."
|
||||
exit 1
|
||||
}
|
||||
az pipelines runs artifact download --artifact-name ${{parameters.artifactName}} --path "$(Pipeline.Workspace)/${{parameters.artifactName}}" --run-id 116384714 --debug
|
||||
displayName: 'Download artifacts with Azure CLI'
|
||||
env:
|
||||
AZURE_DEVOPS_EXT_PAT: $(System.AccessToken)
|
||||
@@ -15,7 +15,7 @@ Param(
|
||||
$referencedFileVersionsPerDll = @{}
|
||||
$totalFailures = 0
|
||||
|
||||
Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude UITests-FancyZones*,MouseJump.Common.UnitTests*,AdvancedPaste.FuzzTests* | ForEach-Object {
|
||||
Get-ChildItem $targetDir -Recurse -Filter *.deps.json -Exclude UITests-FancyZones*,MouseJump.Common.UnitTests*,*.FuzzTests* | ForEach-Object {
|
||||
# Temporarily exclude FancyZones UI tests because of Appium.WebDriver dependencies
|
||||
$depsJsonFullFileName = $_.FullName
|
||||
$depsJsonFileName = $_.Name
|
||||
|
||||
@@ -1322,6 +1322,7 @@ EXHIBIT A -Mozilla Public License.
|
||||
- Microsoft.CodeAnalysis.NetAnalyzers 9.0.0
|
||||
- Microsoft.Data.Sqlite 9.0.2
|
||||
- Microsoft.Diagnostics.Tracing.TraceEvent 3.1.16
|
||||
- Microsoft.DotNet.ILCompiler (A)
|
||||
- Microsoft.Extensions.DependencyInjection 9.0.2
|
||||
- Microsoft.Extensions.Hosting 9.0.2
|
||||
- Microsoft.Extensions.Hosting.WindowsServices 9.0.2
|
||||
|
||||
636
PowerToys.sln
636
PowerToys.sln
File diff suppressed because it is too large
Load Diff
91
doc/devdocs/UITests.md
Normal file
91
doc/devdocs/UITests.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# UI tests framework
|
||||
|
||||
A specialized UI test framework for PowerToys that makes it easy to write UI tests for PowerToys modules or settings. Let's start writing UI tests!
|
||||
|
||||
## Before running tests
|
||||
|
||||
- Install Windows Application Driver v1.2.1 from https://github.com/microsoft/WinAppDriver/releases/tag/v1.2.1 to the default directory (`C:\Program Files (x86)\Windows Application Driver`)
|
||||
|
||||
- Enable Developer Mode in Windows settings
|
||||
|
||||
## Running tests
|
||||
|
||||
- Exit PowerToys if it's running.
|
||||
|
||||
- Open `PowerToys.sln` in Visual Studio and build the solution.
|
||||
|
||||
- Run tests in the Test Explorer (`Test > Test Explorer` or `Ctrl+E, T`).
|
||||
|
||||
|
||||
## How to add the first UI tests for your modules
|
||||
|
||||
- Create a new project and add the following references to the project file. Change the OutputPath to your own module's path.
|
||||
```
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<!-- This is a UI test, so don't run as part of MSBuild -->
|
||||
<RunVSTest>false</RunVSTest>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\KeyboardManagerUITests\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MSTest" />
|
||||
<ProjectReference Include="..\..\..\common\UITestAutomation\UITestAutomation.csproj" />
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
```
|
||||
- Inherit your test class from UITestBase.
|
||||
>Set Scope: The default scope starts from the PowerToys settings UI. If you want to start from your own module, set the constructor as shown below:
|
||||
|
||||
>Specify Scope:
|
||||
```
|
||||
[TestClass]
|
||||
public class RunFancyZonesTest : UITestBase
|
||||
{
|
||||
public RunFancyZonesTest()
|
||||
: base(PowerToysModule.FancyZone)
|
||||
{
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Then you can start using session to perform the UI operations.
|
||||
|
||||
**Example**
|
||||
```
|
||||
using Microsoft.PowerToys.UITest;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace UITests_KeyboardManager
|
||||
{
|
||||
[TestClass]
|
||||
public class RunKeyboardManagerUITests : UITestBase
|
||||
{
|
||||
[TestMethod]
|
||||
public void OpenKeyboardManagerEditor()
|
||||
{
|
||||
// Open KeyboardManagerEditor
|
||||
this.Session.Find<Button>(By.Name("Remap a key")).Click();
|
||||
this.Session.Attach("Remap keys");
|
||||
|
||||
// Maximize window
|
||||
var window = Session.Find<Window>(By.Name("Remap keys")).Maximize();
|
||||
|
||||
// Add Key Remapping
|
||||
this.Session.Find<Button>(By.Name("Add key remapping")).Click();
|
||||
window.Close();
|
||||
|
||||
// Back to Settings
|
||||
this.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Extra tools and information
|
||||
|
||||
**Accessibility Tools**:
|
||||
While working on tests, you may need a tool that helps you to view the element's accessibility data, e.g. for finding the button to click. For this purpose, you could use [AccessibilityInsights](https://accessibilityinsights.io/docs/windows/overview)
|
||||
@@ -3,8 +3,9 @@
|
||||
- [ ] The plugin is a project under `modules\launcher\Plugins`
|
||||
- [ ] Microsoft plugin project name pattern: `Microsoft.PowerToys.Run.Plugin.{PluginName}`
|
||||
- [ ] Community plugin project name pattern: `Community.PowerToys.Run.Plugin.{PluginName}`
|
||||
- [ ] The plugin target framework should be `net8.0-windows`
|
||||
- [ ] The plugin target framework should be `net9.0-windows10.0.22621.0`
|
||||
- [ ] If the plugin uses any 3rd party dependencies the project file should import `DynamicPlugin.props`
|
||||
- [ ] 3rd party dependencies must be compatible with .NET 9
|
||||
- [ ] The plugin has to contain a `plugin.json` file of the following format in its root folder:
|
||||
|
||||
```json
|
||||
@@ -35,7 +36,6 @@ public static string PluginID => "xxxxxxx"; // The part xxxxxxx stands for the p
|
||||
- [ ] Plugin's output code and assets have to be included in the installer [`Product.wxs`](/installer/PowerToysSetup/Product.wxs)
|
||||
- [ ] Test the plugin with a local build. Build the installer, install, check that the plugin works as expected
|
||||
- [ ] All plugin's binaries have to be included in the signed build [`pipeline.user.windows.yml`](/.pipelines/pipeline.user.windows.yml)
|
||||
- [ ] The plugin target framework has to be net8.0-windows. All dependencies should be compatible with .NET 8.
|
||||
|
||||
Some localization steps can only be done after the first pass by the localization team to provide the localized resources.
|
||||
In the PR that adds a new plugin, reference a new issue to track the work for fully enabling localization for the new plugin.
|
||||
|
||||
@@ -4,18 +4,10 @@ Contains the executable starting point, initialization code and the list of know
|
||||
#### [`powertoy_module.h`](/src/runner/powertoy_module.h) and [`powertoy_module.cpp`](/src/runner/powertoy_module.cpp)
|
||||
Contains code for initializing and managing the PowerToy modules. `PowertoyModule` is a RAII-style holder for the `PowertoyModuleIface` pointer, which we got by [invoking module DLL's `powertoy_create` function](https://github.com/microsoft/PowerToys/blob/1760af50c8803588cb575167baae0439af38a9c1/src/runner/powertoy_module.cpp#L13-L24).
|
||||
|
||||
#### [`powertoys_events.cpp`](/src/runner/powertoys_events.cpp)
|
||||
Contains code that handles the various events listeners, and forwards those events to the PowerToys modules. You can learn more about the current event architecture in [shared hooks](/doc/devdocs/shared-hooks.md).
|
||||
|
||||
#### [`lowlevel_keyboard_event.cpp`](/src/runner/lowlevel_keyboard_event.cpp)
|
||||
Contains code for registering the low level keyboard event hook that listens for keyboard events. Please note that `signal_event` is called from the main thread for this event.
|
||||
|
||||
#### [`win_hook_event.cpp`](/src/runner/win_hook_event.cpp)
|
||||
Contains code for registering a Windows event hook through `SetWinEventHook`, that listens for various events raised when a window is interacted with. Please note, that `signal_event` is called from a separate `dispatch_thread_proc` worker thread, so you must provide thread-safety for your `signal_event` if you intend to receive it. This is a subject to change.
|
||||
|
||||
#### [`tray_icon.cpp`](/src/runner/tray_icon.cpp)
|
||||
Contains code for managing the PowerToys tray icon and its menu commands. Note that `dispatch_run_on_main_ui_thread` is used to
|
||||
transfer received json message from the [Settings window](/doc/devdocs/settings.md) to the main thread, since we're communicating with it from [a dedicated thread](https://github.com/microsoft/PowerToys/blob/7357e40d3f54de51176efe54fda6d57028837b8c/src/runner/settings_window.cpp#L267-L271).
|
||||
|
||||
#### [`settings_window.cpp`](/src/runner/settings_window.cpp)
|
||||
Contains code for starting the PowerToys settings window and communicating with it. Settings window is a separate process, so we're using [Windows pipes](https://learn.microsoft.com/windows/win32/ipc/pipes) as a transport for json messages.
|
||||
|
||||
@@ -33,3 +25,24 @@ Contains code for telemetry.
|
||||
|
||||
#### [`svgs`](/src/runner/svgs/)
|
||||
Contains the SVG assets used by the PowerToys modules.
|
||||
|
||||
#### [`bug_report.cpp`](/src/runner/bug_report.cpp)
|
||||
Contains logic to start bug report tool.
|
||||
|
||||
#### [`centralized_hotkeys.cpp`](/src/runner/centralized_hotkeys.cpp)
|
||||
Contains hot key logic registration and un-registration.
|
||||
|
||||
#### [`centralized_kb_hook.cpp`](/src/runner/centralized_kb_hook.cpp)
|
||||
Contains logic to handle PowerToys' keyboard shortcut functionality.
|
||||
|
||||
#### [`restart_elevated.cpp`](/src/runner/restart_elevated.cpp)
|
||||
Contains logic for restarting the current process with different elevation levels.
|
||||
|
||||
#### [`RestartManagement.cpp`](/src/runner/RestartManagement.cpp)
|
||||
Contains code for restarting a process.
|
||||
|
||||
#### [`settings_telemetry.cpp`](/src/runner/settings_telemetry.cpp)
|
||||
Contains logic that periodically triggers module-specific setting's telemetry delivery and manages timing and error handling for the process.
|
||||
|
||||
#### [`UpdateUtils.cpp`](/src/runner/UpdateUtils.cpp)
|
||||
Contains code to handle the automatic update checking, notification, and installation process for PowerToys.
|
||||
20
src/common/UITestAutomation/Element/Button.cs
Normal file
20
src/common/UITestAutomation/Element/Button.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// 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.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
using OpenQA.Selenium.Remote;
|
||||
using OpenQA.Selenium.Support.Events;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a button in the UI test environment.
|
||||
/// </summary>
|
||||
public class Button : Element
|
||||
{
|
||||
}
|
||||
}
|
||||
69
src/common/UITestAutomation/Element/By.cs
Normal file
69
src/common/UITestAutomation/Element/By.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
// 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 static OpenQA.Selenium.By;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// This class represents a By selector.
|
||||
/// </summary>
|
||||
public class By
|
||||
{
|
||||
private readonly OpenQA.Selenium.By by;
|
||||
|
||||
private By(OpenQA.Selenium.By by)
|
||||
{
|
||||
this.by = by;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a By object using the name attribute.
|
||||
/// </summary>
|
||||
/// <param name="name">The name attribute to search for.</param>
|
||||
/// <returns>A By object.</returns>
|
||||
public static By Name(string name) => new By(OpenQA.Selenium.By.Name(name));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a By object using the ID attribute.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID attribute to search for.</param>
|
||||
/// <returns>A By object.</returns>
|
||||
public static By Id(string id) => new By(OpenQA.Selenium.By.Id(id));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a By object using the XPath expression.
|
||||
/// </summary>
|
||||
/// <param name="xpath">The XPath expression to search for.</param>
|
||||
/// <returns>A By object.</returns>
|
||||
public static By XPath(string xpath) => new By(OpenQA.Selenium.By.XPath(xpath));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a By object using the CSS selector.
|
||||
/// </summary>
|
||||
/// <param name="cssSelector">The CSS selector to search for.</param>
|
||||
/// <returns>A By object.</returns>
|
||||
public static By CssSelector(string cssSelector) => new By(OpenQA.Selenium.By.CssSelector(cssSelector));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a By object using the link text.
|
||||
/// </summary>
|
||||
/// <param name="linkText">The link text to search for.</param>
|
||||
/// <returns>A By object.</returns>
|
||||
public static By LinkText(string linkText) => new By(OpenQA.Selenium.By.LinkText(linkText));
|
||||
|
||||
/// <summary>
|
||||
/// Creates a By object using the tag name.
|
||||
/// </summary>
|
||||
/// <param name="tagName">The tag name to search for.</param>
|
||||
/// <returns>A By object.</returns>
|
||||
public static By TagName(string tagName) => new By(OpenQA.Selenium.By.TagName(tagName));
|
||||
|
||||
/// <summary>
|
||||
/// Converts the By object to an OpenQA.Selenium.By object.
|
||||
/// </summary>
|
||||
/// <returns>An OpenQA.Selenium.By object.</returns>
|
||||
internal OpenQA.Selenium.By ToSeleniumBy() => by;
|
||||
}
|
||||
}
|
||||
185
src/common/UITestAutomation/Element/Element.cs
Normal file
185
src/common/UITestAutomation/Element/Element.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
// 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.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Appium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
using OpenQA.Selenium.Remote;
|
||||
using OpenQA.Selenium.Support.Events;
|
||||
using static Microsoft.PowerToys.UITest.UITestBase;
|
||||
|
||||
[assembly: InternalsVisibleTo("Session")]
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a basic UI element in the application.
|
||||
/// </summary>
|
||||
public class Element
|
||||
{
|
||||
private WindowsElement? windowsElement;
|
||||
private WindowsDriver<WindowsElement>? driver;
|
||||
|
||||
internal void SetWindowsElement(WindowsElement windowsElement) => this.windowsElement = windowsElement;
|
||||
|
||||
internal void SetSession(WindowsDriver<WindowsElement> driver) => this.driver = driver;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the UI element.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get { return GetAttribute("Name"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the text of the UI element.
|
||||
/// </summary>
|
||||
public string Text
|
||||
{
|
||||
get { return GetAttribute("Value"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the AutomationID of the UI element.
|
||||
/// </summary>
|
||||
public string AutomationId
|
||||
{
|
||||
get { return GetAttribute("AutomationId"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the class name of the UI element.
|
||||
/// </summary>
|
||||
public string ClassName
|
||||
{
|
||||
get { return GetAttribute("ClassName"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the help text of the UI element.
|
||||
/// </summary>
|
||||
public string HelpText
|
||||
{
|
||||
get { return GetAttribute("HelpText"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the control type of the UI element.
|
||||
/// </summary>
|
||||
public string ControlType
|
||||
{
|
||||
get { return GetAttribute("ControlType"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the UI element is enabled.
|
||||
/// </summary>
|
||||
/// <returns>True if the element is enabled; otherwise, false.</returns>
|
||||
public bool IsEnabled() => GetAttribute("IsEnabled") == "True";
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the UI element is selected.
|
||||
/// </summary>
|
||||
/// <returns>True if the element is selected; otherwise, false.</returns>
|
||||
public bool IsSelected() => GetAttribute("IsSelected") == "True";
|
||||
|
||||
/// <summary>
|
||||
/// Click the UI element.
|
||||
/// </summary>
|
||||
/// <param name="rightClick">If true, performs a right-click; otherwise, performs a left-click.</param>
|
||||
public void Click(bool rightClick = false)
|
||||
{
|
||||
PerformAction(actions =>
|
||||
{
|
||||
if (rightClick)
|
||||
{
|
||||
actions.ContextClick();
|
||||
}
|
||||
else
|
||||
{
|
||||
actions.Click();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the attribute value of the UI element.
|
||||
/// </summary>
|
||||
/// <param name="attributeName">The name of the attribute to get.</param>
|
||||
/// <returns>The value of the attribute.</returns>
|
||||
public string GetAttribute(string attributeName)
|
||||
{
|
||||
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method GetAttribute with parameter: attributeName = {attributeName}");
|
||||
var attributeValue = this.windowsElement.GetAttribute(attributeName);
|
||||
Assert.IsNotNull(attributeValue, $"Attribute '{attributeName}' is null.");
|
||||
return attributeValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds an element by the selector.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class type of the element to find.</typeparam>
|
||||
/// <param name="by">The selector to use for finding the element.</param>
|
||||
/// <param name="timeoutMS">The timeout in milliseconds.</param>
|
||||
/// <returns>The found element.</returns>
|
||||
public T Find<T>(By by, int timeoutMS = 3000)
|
||||
where T : Element, new()
|
||||
{
|
||||
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
|
||||
var foundElement = FindElementHelper.Find<T, AppiumWebElement>(
|
||||
() =>
|
||||
{
|
||||
var element = this.windowsElement.FindElement(by.ToSeleniumBy());
|
||||
Assert.IsNotNull(element, $"Element not found using selector: {by}");
|
||||
return element;
|
||||
},
|
||||
this.driver,
|
||||
timeoutMS);
|
||||
|
||||
return foundElement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all elements by the selector.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class type of the elements to find.</typeparam>
|
||||
/// <param name="by">The selector to use for finding the elements.</param>
|
||||
/// <param name="timeoutMS">The timeout in milliseconds.</param>
|
||||
/// <returns>A read-only collection of the found elements.</returns>
|
||||
public ReadOnlyCollection<T>? FindAll<T>(By by, int timeoutMS = 3000)
|
||||
where T : Element, new()
|
||||
{
|
||||
Assert.IsNotNull(this.windowsElement, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
|
||||
var foundElements = FindElementHelper.FindAll<T, AppiumWebElement>(
|
||||
() =>
|
||||
{
|
||||
var elements = this.windowsElement.FindElements(by.ToSeleniumBy());
|
||||
Assert.IsTrue(elements.Count > 0, $"Elements not found using selector: {by}");
|
||||
return elements;
|
||||
},
|
||||
this.driver,
|
||||
timeoutMS);
|
||||
|
||||
return foundElements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Simulates a manual operation on the element.
|
||||
/// </summary>
|
||||
private void PerformAction(Action<Actions> action)
|
||||
{
|
||||
var element = this.windowsElement;
|
||||
Actions actions = new Actions(this.driver);
|
||||
actions.MoveToElement(element);
|
||||
action(actions);
|
||||
actions.Build().Perform();
|
||||
}
|
||||
}
|
||||
}
|
||||
60
src/common/UITestAutomation/Element/FindElementHelper.cs
Normal file
60
src/common/UITestAutomation/Element/FindElementHelper.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Appium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
|
||||
[assembly: InternalsVisibleTo("Element")]
|
||||
[assembly: InternalsVisibleTo("Session")]
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for finding elements.
|
||||
/// </summary>
|
||||
internal static class FindElementHelper
|
||||
{
|
||||
public static T Find<T, TW>(Func<TW> findElementFunc, WindowsDriver<WindowsElement>? driver, int timeoutMS)
|
||||
where T : Element, new()
|
||||
{
|
||||
var item = findElementFunc() as WindowsElement;
|
||||
return NewElement<T>(item, driver, timeoutMS);
|
||||
}
|
||||
|
||||
public static ReadOnlyCollection<T>? FindAll<T, TW>(Func<ReadOnlyCollection<TW>> findElementsFunc, WindowsDriver<WindowsElement>? driver, int timeoutMS)
|
||||
where T : Element, new()
|
||||
{
|
||||
var items = findElementsFunc();
|
||||
var res = items.Select(item =>
|
||||
{
|
||||
var element = item as WindowsElement;
|
||||
return NewElement<T>(element, driver, timeoutMS);
|
||||
}).ToList();
|
||||
|
||||
return new ReadOnlyCollection<T>(res);
|
||||
}
|
||||
|
||||
public static T NewElement<T>(WindowsElement? element, WindowsDriver<WindowsElement>? driver, int timeoutMS)
|
||||
where T : Element, new()
|
||||
{
|
||||
Assert.IsNotNull(driver, $"New Element {typeof(T).Name} error: driver is null.");
|
||||
Assert.IsNotNull(element, $"New Element {typeof(T).Name} error: element is null.");
|
||||
|
||||
T newElement = new T();
|
||||
driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromMilliseconds(timeoutMS);
|
||||
newElement.SetSession(driver);
|
||||
newElement.SetWindowsElement(element);
|
||||
return newElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
92
src/common/UITestAutomation/Element/Window.cs
Normal file
92
src/common/UITestAutomation/Element/Window.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
// 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.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
using OpenQA.Selenium.Remote;
|
||||
using OpenQA.Selenium.Support.Events;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a window in the UI test environment.
|
||||
/// </summary>
|
||||
public class Window : Element
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximizes the window.
|
||||
/// </summary>
|
||||
/// <param name="byClickButton">If true, clicks the Maximize button; otherwise, sets the window state.</param>
|
||||
/// <returns>The current Window instance.</returns>
|
||||
public Window Maximize(bool byClickButton = true)
|
||||
{
|
||||
if (byClickButton)
|
||||
{
|
||||
Find<Button>(By.Name("Maximize")).Click();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Implement maximizing the window using an alternative method
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the window.
|
||||
/// </summary>
|
||||
/// <param name="byClickButton">If true, clicks the Restore button; otherwise, sets the window state.</param>
|
||||
/// <returns>The current Window instance.</returns>
|
||||
public Window Restore(bool byClickButton = true)
|
||||
{
|
||||
if (byClickButton)
|
||||
{
|
||||
Find<Button>(By.Name("Restore")).Click();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Implement restoring the window using an alternative method
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Minimizes the window.
|
||||
/// </summary>
|
||||
/// <param name="byClickButton">If true, clicks the Minimize button; otherwise, sets the window state.</param>
|
||||
/// <returns>The current Window instance.</returns>
|
||||
public Window Minimize(bool byClickButton = true)
|
||||
{
|
||||
if (byClickButton)
|
||||
{
|
||||
Find<Button>(By.Name("Minimize")).Click();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Implement minimizing the window using an alternative method
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes the window.
|
||||
/// </summary>
|
||||
/// <param name="byClickButton">If true, clicks the Close button; otherwise, closes the window using an alternative method.</param>
|
||||
public void Close(bool byClickButton = true)
|
||||
{
|
||||
if (byClickButton)
|
||||
{
|
||||
Find<Button>(By.Name("Close")).Click();
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Implement closing the window using an alternative method
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
72
src/common/UITestAutomation/ModuleConfigData.cs
Normal file
72
src/common/UITestAutomation/ModuleConfigData.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("UITestBase")]
|
||||
[assembly: InternalsVisibleTo("Session")]
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// This file manages the configuration of modules for UI tests.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// How to add a new module:
|
||||
/// 1. Define the new module in the PowerToysModule enum.
|
||||
/// 2. Add the exe window name to the ModuleWindowName dictionary in the ModuleConfigData constructor.
|
||||
/// 3. Add the exe path to the ModulePath dictionary in the ModuleConfigData constructor.
|
||||
/// </remarks>
|
||||
|
||||
/// <summary>
|
||||
/// Represents the modules in PowerToys.
|
||||
/// </summary>
|
||||
public enum PowerToysModule
|
||||
{
|
||||
PowerToysSettings,
|
||||
FancyZone,
|
||||
Hosts,
|
||||
}
|
||||
|
||||
internal class ModuleConfigData
|
||||
{
|
||||
private Dictionary<PowerToysModule, string> ModulePath { get; }
|
||||
|
||||
// Singleton instance of ModuleConfigData.
|
||||
private static readonly Lazy<ModuleConfigData> SingletonInstance = new Lazy<ModuleConfigData>(() => new ModuleConfigData());
|
||||
|
||||
public static ModuleConfigData Instance => SingletonInstance.Value;
|
||||
|
||||
public const string WindowsApplicationDriverUrl = "http://127.0.0.1:4723";
|
||||
|
||||
public Dictionary<PowerToysModule, string> ModuleWindowName { get; }
|
||||
|
||||
private ModuleConfigData()
|
||||
{
|
||||
// The exe window name for each module.
|
||||
ModuleWindowName = new Dictionary<PowerToysModule, string>
|
||||
{
|
||||
[PowerToysModule.PowerToysSettings] = "PowerToys Settings",
|
||||
[PowerToysModule.FancyZone] = "FancyZones Layout",
|
||||
[PowerToysModule.Hosts] = "Hosts File Editor",
|
||||
};
|
||||
|
||||
// Exe start path for the module if it exists.
|
||||
ModulePath = new Dictionary<PowerToysModule, string>
|
||||
{
|
||||
[PowerToysModule.PowerToysSettings] = @"\..\..\..\WinUI3Apps\PowerToys.Settings.exe",
|
||||
[PowerToysModule.FancyZone] = @"\..\..\..\PowerToys.FancyZonesEditor.exe",
|
||||
[PowerToysModule.Hosts] = @"\..\..\..\WinUI3Apps\PowerToys.Hosts.exe",
|
||||
};
|
||||
}
|
||||
|
||||
public string GetModulePath(PowerToysModule scope) => ModulePath[scope];
|
||||
|
||||
public string GetWindowsApplicationDriverUrl() => WindowsApplicationDriverUrl;
|
||||
|
||||
public string GetModuleWindowName(PowerToysModule scope) => ModuleWindowName[scope];
|
||||
}
|
||||
}
|
||||
129
src/common/UITestAutomation/Session.cs
Normal file
129
src/common/UITestAutomation/Session.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
// 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.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Appium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides interfaces for interacting with UI elements.
|
||||
/// </summary>
|
||||
public class Session
|
||||
{
|
||||
private WindowsDriver<WindowsElement> Root { get; set; }
|
||||
|
||||
private WindowsDriver<WindowsElement> WindowsDriver { get; set; }
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool SetForegroundWindow(nint hWnd);
|
||||
|
||||
public Session(WindowsDriver<WindowsElement> root, WindowsDriver<WindowsElement> windowsDriver)
|
||||
{
|
||||
this.Root = root;
|
||||
this.WindowsDriver = windowsDriver;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds an element by selector.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class of the element, should be Element or its derived class.</typeparam>
|
||||
/// <param name="by">The selector to find the element.</param>
|
||||
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
|
||||
/// <returns>The found element.</returns>
|
||||
public T Find<T>(By by, int timeoutMS = 3000)
|
||||
where T : Element, new()
|
||||
{
|
||||
Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method Find<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
|
||||
var foundElement = FindElementHelper.Find<T, WindowsElement>(
|
||||
() =>
|
||||
{
|
||||
var element = this.WindowsDriver.FindElement(by.ToSeleniumBy());
|
||||
Assert.IsNotNull(element, $"Element not found using selector: {by}");
|
||||
return element;
|
||||
},
|
||||
this.WindowsDriver,
|
||||
timeoutMS);
|
||||
|
||||
return foundElement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all elements by selector.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The class of the elements, should be Element or its derived class.</typeparam>
|
||||
/// <param name="by">The selector to find the elements.</param>
|
||||
/// <param name="timeoutMS">The timeout in milliseconds (default is 3000).</param>
|
||||
/// <returns>A read-only collection of the found elements.</returns>
|
||||
public ReadOnlyCollection<T>? FindAll<T>(By by, int timeoutMS = 3000)
|
||||
where T : Element, new()
|
||||
{
|
||||
Assert.IsNotNull(this.WindowsDriver, $"WindowsElement is null in method FindAll<{typeof(T).Name}> with parameters: by = {by}, timeoutMS = {timeoutMS}");
|
||||
var foundElements = FindElementHelper.FindAll<T, WindowsElement>(
|
||||
() =>
|
||||
{
|
||||
var elements = this.WindowsDriver.FindElements(by.ToSeleniumBy());
|
||||
Assert.IsTrue(elements.Count > 0, $"Elements not found using selector: {by}");
|
||||
return elements;
|
||||
},
|
||||
this.WindowsDriver,
|
||||
timeoutMS);
|
||||
|
||||
return foundElements;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches to an existing PowerToys module.
|
||||
/// </summary>
|
||||
/// <param name="module">The PowerToys module to attach to.</param>
|
||||
/// <returns>The attached session.</returns>
|
||||
public Session Attach(PowerToysModule module)
|
||||
{
|
||||
string windowName = ModuleConfigData.Instance.GetModuleWindowName(module);
|
||||
return this.Attach(windowName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attaches to an existing exe by string window name.
|
||||
/// The session should be attached when a new app is started.
|
||||
/// </summary>
|
||||
/// <param name="windowName">The window name to attach to.</param>
|
||||
/// <returns>The attached session.</returns>
|
||||
public Session Attach(string windowName)
|
||||
{
|
||||
if (this.Root != null)
|
||||
{
|
||||
var window = this.Root.FindElementByName(windowName);
|
||||
Assert.IsNotNull(window, $"Failed to attach. Window '{windowName}' not found");
|
||||
|
||||
var windowHandle = new nint(int.Parse(window.GetAttribute("NativeWindowHandle")));
|
||||
SetForegroundWindow(windowHandle);
|
||||
var hexWindowHandle = windowHandle.ToString("x");
|
||||
var appCapabilities = new AppiumOptions();
|
||||
appCapabilities.AddAdditionalCapability("appTopLevelWindow", hexWindowHandle);
|
||||
appCapabilities.AddAdditionalCapability("deviceName", "WindowsPC");
|
||||
this.WindowsDriver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), appCapabilities);
|
||||
Assert.IsNotNull(this.WindowsDriver, "Attach WindowsDriver is null");
|
||||
|
||||
// Set implicit timeout to make element search retry every 500 ms
|
||||
this.WindowsDriver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(3);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.IsNotNull(this.Root, $"Failed to attach to the window '{windowName}'. Root driver is null");
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
src/common/UITestAutomation/UITestAutomation.csproj
Normal file
21
src/common/UITestAutomation/UITestAutomation.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PublishAot>true</PublishAot>
|
||||
<InvariantGlobalization>true</InvariantGlobalization>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Appium.WebDriver" />
|
||||
<PackageReference Include="MSTest" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
130
src/common/UITestAutomation/UITestBase.cs
Normal file
130
src/common/UITestAutomation/UITestBase.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
// 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.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Appium;
|
||||
using OpenQA.Selenium.Appium.Windows;
|
||||
using OpenQA.Selenium.Interactions;
|
||||
|
||||
namespace Microsoft.PowerToys.UITest
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class that should be inherited by all Test Classes.
|
||||
/// </summary>
|
||||
public class UITestBase
|
||||
{
|
||||
public Session Session { get; set; }
|
||||
|
||||
private readonly TestInit testInit = new TestInit();
|
||||
|
||||
public UITestBase(PowerToysModule scope = PowerToysModule.PowerToysSettings)
|
||||
{
|
||||
this.testInit.SetScope(scope);
|
||||
this.testInit.Init();
|
||||
this.Session = new Session(this.testInit.GetRoot(), this.testInit.GetDriver());
|
||||
}
|
||||
|
||||
~UITestBase()
|
||||
{
|
||||
this.testInit.Cleanup();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Nested class for test initialization.
|
||||
/// </summary>
|
||||
private sealed class TestInit
|
||||
{
|
||||
private WindowsDriver<WindowsElement> Root { get; set; }
|
||||
|
||||
private WindowsDriver<WindowsElement>? Driver { get; set; }
|
||||
|
||||
private static Process? appDriver;
|
||||
|
||||
// Default session path is PowerToys settings dashboard
|
||||
private static string sessionPath = ModuleConfigData.Instance.GetModulePath(PowerToysModule.PowerToysSettings);
|
||||
|
||||
public TestInit()
|
||||
{
|
||||
appDriver = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = "C:\\Program Files (x86)\\Windows Application Driver\\WinAppDriver.exe",
|
||||
Verb = "runas",
|
||||
});
|
||||
|
||||
var desktopCapabilities = new AppiumOptions();
|
||||
desktopCapabilities.AddAdditionalCapability("app", "Root");
|
||||
this.Root = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), desktopCapabilities);
|
||||
|
||||
// Set default timeout to 5 seconds
|
||||
this.Root.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the test environment.
|
||||
/// </summary>
|
||||
[UnconditionalSuppressMessage("SingleFile", "IL3000:Avoid accessing Assembly file path when publishing as a single file", Justification = "<Pending>")]
|
||||
public void Init()
|
||||
{
|
||||
string? path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
this.StartExe(path + sessionPath);
|
||||
|
||||
Assert.IsNotNull(this.Driver, $"Failed to initialize the test environment. Driver is null.");
|
||||
|
||||
// Set default timeout to 5 seconds
|
||||
this.Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleans up the test environment.
|
||||
/// </summary>
|
||||
public void Cleanup()
|
||||
{
|
||||
try
|
||||
{
|
||||
appDriver?.Kill();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Handle exceptions if needed
|
||||
Debug.WriteLine($"Exception during Cleanup: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts a new exe and takes control of it.
|
||||
/// </summary>
|
||||
/// <param name="appPath">The path to the application executable.</param>
|
||||
public void StartExe(string appPath)
|
||||
{
|
||||
var opts = new AppiumOptions();
|
||||
opts.AddAdditionalCapability("app", appPath);
|
||||
this.Driver = new WindowsDriver<WindowsElement>(new Uri(ModuleConfigData.Instance.GetWindowsApplicationDriverUrl()), opts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets scope to the Test Class.
|
||||
/// </summary>
|
||||
/// <param name="scope">The PowerToys module to start.</param>
|
||||
public void SetScope(PowerToysModule scope)
|
||||
{
|
||||
sessionPath = ModuleConfigData.Instance.GetModulePath(scope);
|
||||
}
|
||||
|
||||
public WindowsDriver<WindowsElement> GetRoot() => this.Root;
|
||||
|
||||
public WindowsDriver<WindowsElement> GetDriver()
|
||||
{
|
||||
Assert.IsNotNull(this.Driver, $"Failed to get driver. Driver is null.");
|
||||
return this.Driver;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/modules/Hosts/Hosts.FuzzTests/Fuzz.md
Normal file
35
src/modules/Hosts/Hosts.FuzzTests/Fuzz.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Create Fuzzing Tests in your .NET Code Project
|
||||
|
||||
This document provides a step-by-step guide for integrating fuzzing tests into your .NET project.
|
||||
|
||||
### Step1: Add a Fuzzing Test Project
|
||||
Create a new test project within your module folder. Ensure the project name follows the format *.FuzzTests*.
|
||||
|
||||
### step2: Add FuzzTests and OneFuzzConfig.json to your fuzzing test project
|
||||
Follow the instructions in [Fuzz.md](https://github.com/microsoft/PowerToys/blob/main/src/modules/AdvancedPaste/AdvancedPaste.FuzzTests/Fuzz.md) from AdvancedPaste.FuzzTests to properly integrate fuzzing tests into your project.
|
||||
|
||||
Configuring **OneFuzzConfig.json**:
|
||||
1. Update the dll, class, method, and FuzzingTargetBinaries field in the fuzzers list.
|
||||
2. Modify the AssignedTo field in the adoTemplate list.
|
||||
3. Set the jobNotificationEmail to your Microsoft email account.
|
||||
4. Update the projectName and targetName fields in the oneFuzzJobs list.
|
||||
5. Define job dependencies in the following directory:
|
||||
Example:
|
||||
```PowerToys\x64\Debug\tests\Hosts.FuzzTests\net8.0-windows10.0.19041.0```
|
||||
|
||||
|
||||
# step3: Configure the OneFuzz Pipeline
|
||||
Modify the patterns in the job steps within [job-fuzz.yml](https://github.com/microsoft/PowerToys/blob/main/.pipelines/v2/templates/job-fuzz.yml) to match your fuzzing project name.
|
||||
|
||||
Example:
|
||||
```
|
||||
- download: current
|
||||
displayName: Download artifacts
|
||||
artifact: $(ArtifactName)
|
||||
patterns: |-
|
||||
**/tests/Hosts.FuzzTests/**
|
||||
```
|
||||
|
||||
|
||||
# step4: Submit OneFuzz Pipeline and Verify Results on the OneFuzz Platform
|
||||
After executing the tests, check your email for the job link. Click the link to review the fuzzing test results.
|
||||
101
src/modules/Hosts/Hosts.FuzzTests/FuzzTests.cs
Normal file
101
src/modules/Hosts/Hosts.FuzzTests/FuzzTests.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
// 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;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Hosts.Tests.Mocks;
|
||||
using HostsUILib.Helpers;
|
||||
using HostsUILib.Models;
|
||||
using HostsUILib.Settings;
|
||||
using Moq;
|
||||
|
||||
namespace Hosts.FuzzTests
|
||||
{
|
||||
public class FuzzTests
|
||||
{
|
||||
private static Mock<IUserSettings> _userSettings;
|
||||
private static Mock<IElevationHelper> _elevationHelper;
|
||||
|
||||
// Case1: Fuzzing method for ValidIPv4
|
||||
public static void FuzzValidIPv4(ReadOnlySpan<byte> input)
|
||||
{
|
||||
try
|
||||
{
|
||||
string address = System.Text.Encoding.UTF8.GetString(input);
|
||||
bool isValid = ValidationHelper.ValidIPv4(address);
|
||||
}
|
||||
catch (Exception ex) when (ex is RegexMatchTimeoutException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Case2: fuzzing method for ValidIPv6
|
||||
public static void FuzzValidIPv6(ReadOnlySpan<byte> input)
|
||||
{
|
||||
try
|
||||
{
|
||||
string address = System.Text.Encoding.UTF8.GetString(input);
|
||||
bool isValid = ValidationHelper.ValidIPv6(address);
|
||||
}
|
||||
catch (Exception ex) when (ex is RegexMatchTimeoutException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
// Case3: fuzzing method for ValidHosts
|
||||
public static void FuzzValidHosts(ReadOnlySpan<byte> input)
|
||||
{
|
||||
try
|
||||
{
|
||||
string hosts = System.Text.Encoding.UTF8.GetString(input);
|
||||
bool isValid = ValidationHelper.ValidHosts(hosts, true);
|
||||
}
|
||||
catch (Exception ex) when (ex is RegexMatchTimeoutException)
|
||||
{
|
||||
// It's important to filter out any *expected* exceptions from our code here.
|
||||
// However, catching all exceptions is considered an anti-pattern because it may suppress legitimate
|
||||
// issues, such as a NullReferenceException thrown by our code. In this case, we still re-throw
|
||||
// the exception, as the ToJsonFromXmlOrCsvAsync method is not expected to throw any exceptions.
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public static void FuzzWriteAsync(ReadOnlySpan<byte> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
_userSettings = new Mock<IUserSettings>();
|
||||
_elevationHelper = new Mock<IElevationHelper>();
|
||||
_elevationHelper.Setup(m => m.IsElevated).Returns(true);
|
||||
|
||||
var fileSystem = new CustomMockFileSystem();
|
||||
var service = new HostsService(fileSystem, _userSettings.Object, _elevationHelper.Object);
|
||||
|
||||
string input = System.Text.Encoding.UTF8.GetString(data);
|
||||
|
||||
// Since the WriteAsync method does not involve content parsing, we won't fuzz the additionalLines in the hosts file.
|
||||
string additionalLines = " ";
|
||||
string hosts = input;
|
||||
string address = input;
|
||||
string comments = input;
|
||||
var entries = new List<Entry>
|
||||
{
|
||||
new Entry(1, hosts, address, comments, true),
|
||||
};
|
||||
|
||||
// fuzzing WriteAsync
|
||||
_ = Task.Run(async () => await service.WriteAsync(additionalLines, entries));
|
||||
}
|
||||
catch (Exception ex) when (ex is ArgumentException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/modules/Hosts/Hosts.FuzzTests/Hosts.FuzzTests.csproj
Normal file
51
src/modules/Hosts/Hosts.FuzzTests/Hosts.FuzzTests.csproj
Normal file
@@ -0,0 +1,51 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\tests\Hosts.FuzzTests\</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\Hosts.Tests\Mocks\CustomMockFileSystem.cs" Link="CustomMockFileSystem.cs" />
|
||||
<Compile Include="..\Hosts.Tests\Mocks\MockFileSystemWatcher.cs" Link="MockFileSystemWatcher.cs" />
|
||||
<Compile Include="..\Hosts.Tests\Mocks\MockFileSystemWatcherFactory.cs" Link="MockFileSystemWatcherFactory.cs" />
|
||||
<Compile Include="..\HostsUILib\Consts.cs" Link="Consts.cs" />
|
||||
<Compile Include="..\HostsUILib\Helpers\ValidationHelper.cs" Link="ValidationHelper.cs" />
|
||||
<Compile Include="..\HostsUILib\Exceptions\NotRunningElevatedException.cs" Link="NotRunningElevatedException.cs" />
|
||||
<Compile Include="..\HostsUILib\Exceptions\ReadOnlyHostsException.cs" Link="ReadOnlyHostsException.cs" />
|
||||
<Compile Include="..\HostsUILib\Helpers\HostsService.cs" Link="HostsService.cs" />
|
||||
<Compile Include="..\HostsUILib\Helpers\IElevationHelper.cs" Link="IElevationHelper.cs" />
|
||||
<Compile Include="..\HostsUILib\Helpers\IHostsService.cs" Link="IHostsService.cs" />
|
||||
<Compile Include="..\HostsUILib\Helpers\ILogger.cs" Link="ILogger.cs" />
|
||||
<Compile Include="..\HostsUILib\Helpers\LoggerInstance.cs" Link="LoggerInstance.cs" />
|
||||
<Compile Include="..\HostsUILib\Models\AddressType.cs" Link="AddressType.cs" />
|
||||
<Compile Include="..\HostsUILib\Models\Entry.cs" Link="Entry.cs" />
|
||||
<Compile Include="..\HostsUILib\Models\HostsData.cs" Link="HostsData.cs" />
|
||||
<Compile Include="..\HostsUILib\Settings\HostsAdditionalLinesPosition.cs" Link="HostsAdditionalLinesPosition.cs" />
|
||||
<Compile Include="..\HostsUILib\Settings\HostsEncoding.cs" Link="HostsEncoding.cs" />
|
||||
<Compile Include="..\HostsUILib\Settings\IUserSettings.cs" Link="IUserSettings.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Moq" />
|
||||
<PackageReference Include="MSTest" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" />
|
||||
<PackageReference Include="System.IO.Abstractions.TestingHelpers" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="OneFuzzConfig.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
5
src/modules/Hosts/Hosts.FuzzTests/MSTestSettings.cs
Normal file
5
src/modules/Hosts/Hosts.FuzzTests/MSTestSettings.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
// 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.
|
||||
|
||||
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
|
||||
178
src/modules/Hosts/Hosts.FuzzTests/OneFuzzConfig.json
Normal file
178
src/modules/Hosts/Hosts.FuzzTests/OneFuzzConfig.json
Normal file
@@ -0,0 +1,178 @@
|
||||
{
|
||||
"configVersion": 3,
|
||||
"entries": [
|
||||
{
|
||||
"fuzzer": {
|
||||
"$type": "libfuzzerDotNet",
|
||||
"dll": "Hosts.FuzzTests.dll",
|
||||
"class": "Hosts.FuzzTests.FuzzTests",
|
||||
"method": "FuzzValidIPv4",
|
||||
"FuzzingTargetBinaries": [
|
||||
"PowerToys.Hosts.dll"
|
||||
]
|
||||
},
|
||||
"adoTemplate": {
|
||||
// supply the values appropriate to your
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "mengyuanchen@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
"jobNotificationEmail": "mengyuanchen@microsoft.com",
|
||||
"skip": false,
|
||||
"rebootAfterSetup": false,
|
||||
"oneFuzzJobs": [
|
||||
// at least one job is required
|
||||
{
|
||||
"projectName": "Hosts",
|
||||
"targetName": "Hosts-dotnet-fuzzer-Ipv4"
|
||||
}
|
||||
],
|
||||
"jobDependencies": [
|
||||
// this should contain, at minimum,
|
||||
// the DLL and PDB files
|
||||
// you will need to add any other files required
|
||||
// (globs are supported)
|
||||
"Hosts.FuzzTests.dll",
|
||||
"Hosts.FuzzTests.pdb",
|
||||
"Microsoft.Windows.SDK.NET.dll",
|
||||
"WinRT.Runtime.dll"
|
||||
],
|
||||
"SdlWorkItemId": 49911822
|
||||
},
|
||||
{
|
||||
"fuzzer": {
|
||||
"$type": "libfuzzerDotNet",
|
||||
"dll": "Hosts.FuzzTests.dll",
|
||||
"class": "Hosts.FuzzTests.FuzzTests",
|
||||
"method": "FuzzValidIPv6",
|
||||
"FuzzingTargetBinaries": [
|
||||
"PowerToys.Hosts.dll"
|
||||
]
|
||||
},
|
||||
"adoTemplate": {
|
||||
// supply the values appropriate to your
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "mengyuanchen@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
"jobNotificationEmail": "mengyuanchen@microsoft.com",
|
||||
"skip": false,
|
||||
"rebootAfterSetup": false,
|
||||
"oneFuzzJobs": [
|
||||
// at least one job is required
|
||||
{
|
||||
"projectName": "Hosts",
|
||||
"targetName": "Hosts-dotnet-fuzzer-Ipv6"
|
||||
}
|
||||
],
|
||||
"jobDependencies": [
|
||||
// this should contain, at minimum,
|
||||
// the DLL and PDB files
|
||||
// you will need to add any other files required
|
||||
// (globs are supported)
|
||||
"Hosts.FuzzTests.dll",
|
||||
"Hosts.FuzzTests.pdb",
|
||||
"Microsoft.Windows.SDK.NET.dll",
|
||||
"WinRT.Runtime.dll"
|
||||
],
|
||||
"SdlWorkItemId": 49911822
|
||||
},
|
||||
{
|
||||
"fuzzer": {
|
||||
"$type": "libfuzzerDotNet",
|
||||
"dll": "Hosts.FuzzTests.dll",
|
||||
"class": "Hosts.FuzzTests.FuzzTests",
|
||||
"method": "FuzzValidHosts",
|
||||
"FuzzingTargetBinaries": [
|
||||
"PowerToys.Hosts.dll"
|
||||
]
|
||||
},
|
||||
"adoTemplate": {
|
||||
// supply the values appropriate to your
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "mengyuanchen@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
"jobNotificationEmail": "mengyuanchen@microsoft.com",
|
||||
"skip": false,
|
||||
"rebootAfterSetup": false,
|
||||
"oneFuzzJobs": [
|
||||
// at least one job is required
|
||||
{
|
||||
"projectName": "Hosts",
|
||||
"targetName": "Hosts-dotnet-fuzzer-hosts"
|
||||
}
|
||||
],
|
||||
"jobDependencies": [
|
||||
// this should contain, at minimum,
|
||||
// the DLL and PDB files
|
||||
// you will need to add any other files required
|
||||
// (globs are supported)
|
||||
"Hosts.FuzzTests.dll",
|
||||
"Hosts.FuzzTests.pdb",
|
||||
"Microsoft.Windows.SDK.NET.dll",
|
||||
"WinRT.Runtime.dll"
|
||||
],
|
||||
"SdlWorkItemId": 49911822
|
||||
},
|
||||
{
|
||||
"fuzzer": {
|
||||
"$type": "libfuzzerDotNet",
|
||||
"dll": "Hosts.FuzzTests.dll",
|
||||
"class": "Hosts.FuzzTests.FuzzTests",
|
||||
"method": "FuzzWriteAsync",
|
||||
"FuzzingTargetBinaries": [
|
||||
"PowerToys.Hosts.dll"
|
||||
]
|
||||
},
|
||||
"adoTemplate": {
|
||||
// supply the values appropriate to your
|
||||
// project, where bugs will be filed
|
||||
"org": "microsoft",
|
||||
"project": "OS",
|
||||
"AssignedTo": "mengyuanchen@microsoft.com",
|
||||
"AreaPath": "OS\\Windows Client and Services\\WinPD\\DEEP-Developer Experience, Ecosystem and Partnerships\\SHINE\\PowerToys",
|
||||
"IterationPath": "OS\\Future"
|
||||
},
|
||||
"jobNotificationEmail": "mengyuanchen@microsoft.com",
|
||||
"skip": false,
|
||||
"rebootAfterSetup": false,
|
||||
"oneFuzzJobs": [
|
||||
// at least one job is required
|
||||
{
|
||||
"projectName": "Hosts",
|
||||
"targetName": "Hosts-dotnet-fuzzer-WriteAsync"
|
||||
}
|
||||
],
|
||||
"jobDependencies": [
|
||||
// this should contain, at minimum,
|
||||
// the DLL and PDB files
|
||||
// you will need to add any other files required
|
||||
// (globs are supported)
|
||||
"Hosts.FuzzTests.dll",
|
||||
"Hosts.FuzzTests.pdb",
|
||||
"Microsoft.Windows.SDK.NET.dll",
|
||||
"WinRT.Runtime.dll",
|
||||
"Moq.dll",
|
||||
"testhost.dll",
|
||||
"Castle.Core.dll",
|
||||
"System.IO.Abstractions.dll",
|
||||
"CommunityToolkit.Mvvm.dll",
|
||||
"System.IO.Abstractions.TestingHelpers.dll",
|
||||
"TestableIO.System.IO.Abstractions.dll",
|
||||
"TestableIO.System.IO.Abstractions.TestingHelpers.dll",
|
||||
"TestableIO.System.IO.Abstractions.Wrappers.dll"
|
||||
],
|
||||
"SdlWorkItemId": 49911822
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -233,6 +233,12 @@ void Highlighter::ClearDrawingPoint(MouseButton _button)
|
||||
{
|
||||
winrt::Windows::UI::Composition::CompositionSpriteShape circleShape{ nullptr };
|
||||
|
||||
if (nullptr == m_alwaysPointer)
|
||||
{
|
||||
// Guard against alwaysPointer not being initialized.
|
||||
return;
|
||||
}
|
||||
|
||||
// always
|
||||
circleShape = m_alwaysPointer;
|
||||
|
||||
@@ -265,6 +271,11 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
|
||||
// Clear AlwaysPointer only when it's enabled and RightPointer is not active
|
||||
instance->ClearDrawingPoint(MouseButton::None);
|
||||
}
|
||||
if (instance->m_leftButtonPressed)
|
||||
{
|
||||
// There might be a stray point from the user releasing the mouse button on an elevated window, which wasn't caught by us.
|
||||
instance->StartDrawingPointFading(MouseButton::Left);
|
||||
}
|
||||
instance->AddDrawingPoint(MouseButton::Left);
|
||||
instance->m_leftButtonPressed = true;
|
||||
// start a timer for the scenario, when the user clicks a pinned window which has no focus.
|
||||
@@ -284,6 +295,11 @@ LRESULT CALLBACK Highlighter::MouseHookProc(int nCode, WPARAM wParam, LPARAM lPa
|
||||
// Clear AlwaysPointer only when it's enabled and LeftPointer is not active
|
||||
instance->ClearDrawingPoint(MouseButton::None);
|
||||
}
|
||||
if (instance->m_rightButtonPressed)
|
||||
{
|
||||
// There might be a stray point from the user releasing the mouse button on an elevated window, which wasn't caught by us.
|
||||
instance->StartDrawingPointFading(MouseButton::Right);
|
||||
}
|
||||
instance->AddDrawingPoint(MouseButton::Right);
|
||||
instance->m_rightButtonPressed = true;
|
||||
// same as for the left button, start a timer for reposition ourselves to topmost position
|
||||
|
||||
@@ -431,7 +431,7 @@ namespace MouseWithoutBorders
|
||||
if (!IsConnectedByAClientSocketTo(remoteMachine))
|
||||
{
|
||||
Logger.Log($"No potential inbound connection from {MachineName} to {remoteMachine}, ask for a push back instead.");
|
||||
ID machineId = MachinePool.ResolveID(remoteMachine);
|
||||
ID machineId = MachineStuff.MachinePool.ResolveID(remoteMachine);
|
||||
|
||||
if (machineId != ID.NONE)
|
||||
{
|
||||
@@ -840,7 +840,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
Logger.LogDebug($"{nameof(ShakeHand)}: Connection from {name}:{package.Src}");
|
||||
|
||||
if (Common.MachinePool.ResolveID(name) == package.Src && Common.IsConnectedTo(package.Src))
|
||||
if (MachineStuff.MachinePool.ResolveID(name) == package.Src && Common.IsConnectedTo(package.Src))
|
||||
{
|
||||
clientPushData = package.Type == PackageType.ClipboardPush;
|
||||
postAction = package.PostAction;
|
||||
|
||||
@@ -1,409 +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 System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
|
||||
// <summary>
|
||||
// Drag/Drop implementation.
|
||||
// </summary>
|
||||
// <history>
|
||||
// 2008 created by Truong Do (ductdo).
|
||||
// 2009-... modified by Truong Do (TruongDo).
|
||||
// 2023- Included in PowerToys.
|
||||
// </history>
|
||||
using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
using Thread = MouseWithoutBorders.Core.Thread;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
/* Common.DragDrop.cs
|
||||
* Drag&Drop is one complicated implementation of the tool with some tricks.
|
||||
*
|
||||
* SEQUENCE OF EVENTS:
|
||||
* DragDropStep01: MachineX: Remember mouse down state since it could be a start of a dragging
|
||||
* DragDropStep02: MachineY: Send an message to the MachineX to ask it to check if it is
|
||||
* doing drag/drop
|
||||
* DragDropStep03: MachineX: Got explorerDragDrop, send WM_CHECK_EXPLORER_DRAG_DROP to its mainForm
|
||||
* DragDropStep04: MachineX: Show Mouse Without Borders Helper form at mouse cursor to get DragEnter event.
|
||||
* DragDropStepXX: MachineX: Mouse Without Borders Helper: Called by DragEnter, check if dragging a single file,
|
||||
* remember the file (set as its window caption)
|
||||
* DragDropStep05: MachineX: Get the file name from Mouse Without Borders Helper, hide Mouse Without Borders Helper window
|
||||
* DragDropStep06: MachineX: Broadcast a message saying that it has some drag file.
|
||||
* DragDropStep08: MachineY: Got ClipboardDragDrop, isDropping set, get the MachineX name from the package.
|
||||
* DragDropStep09: MachineY: Since isDropping is true, show up the drop form (looks like an icon).
|
||||
* DragDropStep10: MachineY: MouseUp, set isDropping to false, hide the drop "icon" and get data.
|
||||
* DragDropStep11: MachineX: Mouse move back without drop event, cancelling drag/dop
|
||||
* SendClipboardBeatDragDropEnd
|
||||
* DragDropStep12: MachineY: Hide the drop "icon" when received ClipboardDragDropEnd.
|
||||
*
|
||||
* FROM VERSION 1.6.3: Drag/Drop is temporary removed, Drop action cannot be done from a lower integrity app to a higher one.
|
||||
* We have to run a helper process...
|
||||
* http://forums.microsoft.com/MSDN/ShowPost.aspx?PageIndex=1&SiteID=1&PageID=1&PostID=736086
|
||||
*
|
||||
* 2008.10.28: Trying to restore the Drag/Drop feature by adding the drag/drop helper process. Coming in version
|
||||
* 1.6.5
|
||||
* */
|
||||
|
||||
internal partial class Common
|
||||
{
|
||||
private static bool isDragging;
|
||||
|
||||
internal static bool IsDragging
|
||||
{
|
||||
get => Common.isDragging;
|
||||
set => Common.isDragging = value;
|
||||
}
|
||||
|
||||
internal static void DragDropStep01(int wParam)
|
||||
{
|
||||
if (!Setting.Values.TransferFile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (wParam == WM_LBUTTONDOWN)
|
||||
{
|
||||
MouseDown = true;
|
||||
DragMachine = desMachineID;
|
||||
dropMachineID = ID.NONE;
|
||||
Logger.LogDebug("DragDropStep01: MouseDown");
|
||||
}
|
||||
else if (wParam == WM_LBUTTONUP)
|
||||
{
|
||||
MouseDown = false;
|
||||
Logger.LogDebug("DragDropStep01: MouseUp");
|
||||
}
|
||||
|
||||
if (wParam == WM_RBUTTONUP && IsDropping)
|
||||
{
|
||||
IsDropping = false;
|
||||
LastIDWithClipboardData = ID.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DragDropStep02()
|
||||
{
|
||||
if (desMachineID == MachineID)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep02: SendCheckExplorerDragDrop sent to myself");
|
||||
DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
SendCheckExplorerDragDrop();
|
||||
Logger.LogDebug("DragDropStep02: SendCheckExplorerDragDrop sent");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DragDropStep03(DATA package)
|
||||
{
|
||||
if (RunOnLogonDesktop || RunOnScrSaverDesktop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (package.Des == MachineID || package.Des == ID.ALL)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep03: ExplorerDragDrop Received.");
|
||||
dropMachineID = package.Src; // Drop machine is the machine that sent ExplorerDragDrop
|
||||
if (MouseDown || IsDropping)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep03: Mouse is down, check if dragging...sending WM_CHECK_EXPLORER_DRAG_DROP to myself...");
|
||||
DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int dragDropStep05ExCalledByIpc;
|
||||
|
||||
internal static void DragDropStep04()
|
||||
{
|
||||
if (!IsDropping)
|
||||
{
|
||||
IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT);
|
||||
if (h.ToInt32() > 0)
|
||||
{
|
||||
_ = Interlocked.Exchange(ref dragDropStep05ExCalledByIpc, 0);
|
||||
|
||||
MainForm.Hide();
|
||||
MainFormVisible = false;
|
||||
|
||||
Point p = default;
|
||||
|
||||
// NativeMethods.SetWindowText(h, "");
|
||||
_ = NativeMethods.SetWindowPos(h, NativeMethods.HWND_TOPMOST, 0, 0, 0, 0, NativeMethods.SWP_SHOWWINDOW);
|
||||
|
||||
for (int i = -10; i < 10; i++)
|
||||
{
|
||||
if (dragDropStep05ExCalledByIpc > 0)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep04: DragDropStep05ExCalledByIpc.");
|
||||
break;
|
||||
}
|
||||
|
||||
_ = NativeMethods.GetCursorPos(ref p);
|
||||
Logger.LogDebug("DragDropStep04: Moving Mouse Without Borders Helper to (" + p.X.ToString(CultureInfo.CurrentCulture) + ", " + p.Y.ToString(CultureInfo.CurrentCulture) + ")");
|
||||
_ = NativeMethods.SetWindowPos(h, NativeMethods.HWND_TOPMOST, p.X - 100 + i, p.Y - 100 + i, 200, 200, 0);
|
||||
_ = NativeMethods.SendMessage(h, 0x000F, IntPtr.Zero, IntPtr.Zero); // WM_PAINT
|
||||
Thread.Sleep(20);
|
||||
Application.DoEvents();
|
||||
|
||||
// if (GetText(h).Length > 1) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep04: Mouse without Borders Helper not found!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep04: IsDropping == true, skip checking");
|
||||
}
|
||||
|
||||
Logger.LogDebug("DragDropStep04: Got WM_CHECK_EXPLORER_DRAG_DROP, done with processing jump to DragDropStep05...");
|
||||
}
|
||||
|
||||
internal static void DragDropStep05Ex(string dragFileName)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep05 called.");
|
||||
|
||||
_ = Interlocked.Exchange(ref dragDropStep05ExCalledByIpc, 1);
|
||||
|
||||
if (RunOnLogonDesktop || RunOnScrSaverDesktop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDropping)
|
||||
{
|
||||
_ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(dragFileName) && (File.Exists(dragFileName) || Directory.Exists(dragFileName)))
|
||||
{
|
||||
Common.LastDragDropFile = dragFileName;
|
||||
/*
|
||||
* possibleDropMachineID is used as desID sent in DragDropStep06();
|
||||
* */
|
||||
if (dropMachineID == ID.NONE)
|
||||
{
|
||||
dropMachineID = newDesMachineID;
|
||||
}
|
||||
|
||||
DragDropStep06();
|
||||
Logger.LogDebug("DragDropStep05: File dragging: " + dragFileName);
|
||||
_ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DD_HELPER, (IntPtr)1, (IntPtr)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep05: File not found: [" + dragFileName + "]");
|
||||
_ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DD_HELPER, (IntPtr)0, (IntPtr)0);
|
||||
}
|
||||
|
||||
Logger.LogDebug("DragDropStep05: WM_HIDE_DDHelper sent");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep05: IsDropping == true, change drop machine...");
|
||||
IsDropping = false;
|
||||
MainFormVisible = true; // WM_HIDE_DRAG_DROP
|
||||
SendDropBegin(); // To dropMachineID set in DragDropStep03
|
||||
}
|
||||
|
||||
MouseDown = false;
|
||||
}
|
||||
|
||||
internal static void DragDropStep06()
|
||||
{
|
||||
IsDragging = true;
|
||||
Logger.LogDebug("DragDropStep06: SendClipboardBeatDragDrop");
|
||||
SendClipboardBeatDragDrop();
|
||||
SendDropBegin();
|
||||
}
|
||||
|
||||
internal static void DragDropStep08(DATA package)
|
||||
{
|
||||
Receiver.GetNameOfMachineWithClipboardData(package);
|
||||
Logger.LogDebug("DragDropStep08: ClipboardDragDrop Received. machine with drag file was set");
|
||||
}
|
||||
|
||||
internal static void DragDropStep08_2(DATA package)
|
||||
{
|
||||
if (package.Des == MachineID && !RunOnLogonDesktop && !RunOnScrSaverDesktop)
|
||||
{
|
||||
IsDropping = true;
|
||||
dropMachineID = MachineID;
|
||||
Logger.LogDebug("DragDropStep08_2: ClipboardDragDropOperation Received. IsDropping set");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DragDropStep09(int wParam)
|
||||
{
|
||||
if (wParam == WM_MOUSEMOVE && IsDropping)
|
||||
{
|
||||
// Show/Move form
|
||||
DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_SHOW_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
else if (wParam == WM_LBUTTONUP && (IsDropping || IsDragging))
|
||||
{
|
||||
if (IsDropping)
|
||||
{
|
||||
// Hide form, get data
|
||||
DragDropStep10();
|
||||
}
|
||||
else
|
||||
{
|
||||
IsDragging = false;
|
||||
LastIDWithClipboardData = ID.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DragDropStep10()
|
||||
{
|
||||
Logger.LogDebug("DragDropStep10: Hide the form and get data...");
|
||||
IsDropping = false;
|
||||
IsDragging = false;
|
||||
LastIDWithClipboardData = ID.NONE;
|
||||
|
||||
DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersDragAndDropEvent());
|
||||
GetRemoteClipboard("desktop");
|
||||
}
|
||||
|
||||
internal static void DragDropStep11()
|
||||
{
|
||||
Logger.LogDebug("DragDropStep11: Mouse drag coming back, canceling drag/drop");
|
||||
SendClipboardBeatDragDropEnd();
|
||||
IsDropping = false;
|
||||
IsDragging = false;
|
||||
DragMachine = (ID)1;
|
||||
LastIDWithClipboardData = ID.NONE;
|
||||
LastDragDropFile = null;
|
||||
MouseDown = false;
|
||||
}
|
||||
|
||||
internal static void DragDropStep12()
|
||||
{
|
||||
Logger.LogDebug("DragDropStep12: ClipboardDragDropEnd received");
|
||||
IsDropping = false;
|
||||
LastIDWithClipboardData = ID.NONE;
|
||||
|
||||
DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
|
||||
internal static void SendCheckExplorerDragDrop()
|
||||
{
|
||||
DATA package = new();
|
||||
package.Type = PackageType.ExplorerDragDrop;
|
||||
|
||||
/*
|
||||
* package.src = newDesMachineID:
|
||||
* sent from the master machine but the src must be the
|
||||
* new des machine since the previous des machine will get this and set
|
||||
* to possibleDropMachineID in DragDropStep3()
|
||||
* */
|
||||
package.Src = newDesMachineID;
|
||||
|
||||
package.Des = desMachineID;
|
||||
package.MachineName = MachineName;
|
||||
|
||||
SkSend(package, null, false);
|
||||
}
|
||||
|
||||
private static void ChangeDropMachine()
|
||||
{
|
||||
// desMachineID = current drop machine
|
||||
// newDesMachineID = new drop machine
|
||||
|
||||
// 1. Cancelling dropping in current drop machine
|
||||
if (dropMachineID == MachineID)
|
||||
{
|
||||
// Drag/Drop coming through me
|
||||
IsDropping = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Drag/Drop coming back
|
||||
SendClipboardBeatDragDropEnd();
|
||||
}
|
||||
|
||||
// 2. SendClipboardBeatDragDrop to new drop machine
|
||||
// new drop machine is not me
|
||||
if (newDesMachineID != MachineID)
|
||||
{
|
||||
dropMachineID = newDesMachineID;
|
||||
SendDropBegin();
|
||||
}
|
||||
|
||||
// New drop machine is me
|
||||
else
|
||||
{
|
||||
IsDropping = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SendClipboardBeatDragDrop()
|
||||
{
|
||||
SendPackage(ID.ALL, PackageType.ClipboardDragDrop);
|
||||
}
|
||||
|
||||
internal static void SendDropBegin()
|
||||
{
|
||||
Logger.LogDebug("SendDropBegin...");
|
||||
SendPackage(dropMachineID, PackageType.ClipboardDragDropOperation);
|
||||
}
|
||||
|
||||
internal static void SendClipboardBeatDragDropEnd()
|
||||
{
|
||||
if (desMachineID != MachineID)
|
||||
{
|
||||
SendPackage(desMachineID, PackageType.ClipboardDragDropEnd);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool isDropping;
|
||||
private static ID dragMachine;
|
||||
|
||||
internal static ID DragMachine
|
||||
{
|
||||
get => Common.dragMachine;
|
||||
set => Common.dragMachine = value;
|
||||
}
|
||||
|
||||
internal static bool IsDropping
|
||||
{
|
||||
get => Common.isDropping;
|
||||
set => Common.isDropping = value;
|
||||
}
|
||||
|
||||
internal static bool MouseDown { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
if (switchByMouseEnabled && Sk != null && (DesMachineID == MachineID || !Setting.Values.MoveMouseRelatively) && e.dwFlags == WM_MOUSEMOVE)
|
||||
{
|
||||
Point p = MoveToMyNeighbourIfNeeded(e.X, e.Y, desMachineID);
|
||||
Point p = MachineStuff.MoveToMyNeighbourIfNeeded(e.X, e.Y, MachineStuff.desMachineID);
|
||||
|
||||
if (!p.IsEmpty)
|
||||
{
|
||||
@@ -81,20 +81,20 @@ namespace MouseWithoutBorders
|
||||
Logger.LogDebug(string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
"***** Host Machine: newDesMachineIdEx set = [{0}]. Mouse is now at ({1},{2})",
|
||||
newDesMachineIdEx,
|
||||
MachineStuff.newDesMachineIdEx,
|
||||
e.X,
|
||||
e.Y));
|
||||
|
||||
myLastX = e.X;
|
||||
myLastY = e.Y;
|
||||
|
||||
PrepareToSwitchToMachine(newDesMachineIdEx, p);
|
||||
PrepareToSwitchToMachine(MachineStuff.newDesMachineIdEx, p);
|
||||
}
|
||||
}
|
||||
|
||||
if (desMachineID != MachineID && SwitchLocation.Count <= 0)
|
||||
if (MachineStuff.desMachineID != MachineID && MachineStuff.SwitchLocation.Count <= 0)
|
||||
{
|
||||
MousePackage.Des = desMachineID;
|
||||
MousePackage.Des = MachineStuff.desMachineID;
|
||||
MousePackage.Type = PackageType.Mouse;
|
||||
MousePackage.Md.dwFlags = e.dwFlags;
|
||||
MousePackage.Md.WheelDelta = e.WheelDelta;
|
||||
@@ -107,8 +107,8 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
else
|
||||
{
|
||||
MousePackage.Md.X = (e.X - primaryScreenBounds.Left) * 65535 / screenWidth;
|
||||
MousePackage.Md.Y = (e.Y - primaryScreenBounds.Top) * 65535 / screenHeight;
|
||||
MousePackage.Md.X = (e.X - MachineStuff.primaryScreenBounds.Left) * 65535 / screenWidth;
|
||||
MousePackage.Md.Y = (e.Y - MachineStuff.primaryScreenBounds.Top) * 65535 / screenHeight;
|
||||
}
|
||||
|
||||
SkSend(MousePackage, null, false);
|
||||
@@ -156,15 +156,15 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Logger.LogDebug($"PrepareToSwitchToMachine: newDesMachineID = {newDesMachineID}, desMachineXY = {desMachineXY}");
|
||||
|
||||
if (((GetTick() - lastJump < 100) && (GetTick() - lastJump > 0)) || desMachineID == ID.ALL)
|
||||
if (((GetTick() - MachineStuff.lastJump < 100) && (GetTick() - MachineStuff.lastJump > 0)) || MachineStuff.desMachineID == ID.ALL)
|
||||
{
|
||||
Logger.LogDebug("PrepareToSwitchToMachine: lastJump");
|
||||
return;
|
||||
}
|
||||
|
||||
lastJump = GetTick();
|
||||
MachineStuff.lastJump = GetTick();
|
||||
|
||||
string newDesMachineName = NameFromID(newDesMachineID);
|
||||
string newDesMachineName = MachineStuff.NameFromID(newDesMachineID);
|
||||
|
||||
if (!IsConnectedTo(newDesMachineID))
|
||||
{// Connection lost, cancel switching
|
||||
@@ -174,46 +174,46 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
else
|
||||
{
|
||||
Common.newDesMachineID = newDesMachineID;
|
||||
SwitchLocation.X = desMachineXY.X;
|
||||
SwitchLocation.Y = desMachineXY.Y;
|
||||
SwitchLocation.ResetCount();
|
||||
MachineStuff.newDesMachineID = newDesMachineID;
|
||||
MachineStuff.SwitchLocation.X = desMachineXY.X;
|
||||
MachineStuff.SwitchLocation.Y = desMachineXY.Y;
|
||||
MachineStuff.SwitchLocation.ResetCount();
|
||||
_ = EvSwitch.Set();
|
||||
|
||||
// PostMessage(mainForm.Handle, WM_SWITCH, IntPtr.Zero, IntPtr.Zero);
|
||||
if (newDesMachineID != DragMachine)
|
||||
if (newDesMachineID != DragDrop.DragMachine)
|
||||
{
|
||||
if (!IsDragging && !IsDropping)
|
||||
if (!DragDrop.IsDragging && !DragDrop.IsDropping)
|
||||
{
|
||||
if (MouseDown && !RunOnLogonDesktop && !RunOnScrSaverDesktop)
|
||||
if (DragDrop.MouseDown && !RunOnLogonDesktop && !RunOnScrSaverDesktop)
|
||||
{
|
||||
DragDropStep02();
|
||||
DragDrop.DragDropStep02();
|
||||
}
|
||||
}
|
||||
else if (DragMachine != (ID)1)
|
||||
else if (DragDrop.DragMachine != (ID)1)
|
||||
{
|
||||
ChangeDropMachine();
|
||||
DragDrop.ChangeDropMachine();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DragDropStep11();
|
||||
DragDrop.DragDropStep11();
|
||||
}
|
||||
|
||||
// Change des machine
|
||||
if (desMachineID != newDesMachineID)
|
||||
if (MachineStuff.desMachineID != newDesMachineID)
|
||||
{
|
||||
Logger.LogDebug("MouseEvent: Switching to new machine:" + newDesMachineName);
|
||||
|
||||
// Ask current machine to hide the Mouse cursor
|
||||
if (newDesMachineID != ID.ALL && desMachineID != MachineID)
|
||||
if (newDesMachineID != ID.ALL && MachineStuff.desMachineID != MachineID)
|
||||
{
|
||||
SendPackage(desMachineID, PackageType.HideMouse);
|
||||
SendPackage(MachineStuff.desMachineID, PackageType.HideMouse);
|
||||
}
|
||||
|
||||
DesMachineID = newDesMachineID;
|
||||
|
||||
if (desMachineID == MachineID)
|
||||
if (MachineStuff.desMachineID == MachineID)
|
||||
{
|
||||
if (GetTick() - clipboardCopiedTime < BIG_CLIPBOARD_DATA_TIMEOUT)
|
||||
{
|
||||
@@ -224,7 +224,7 @@ namespace MouseWithoutBorders
|
||||
else
|
||||
{
|
||||
// Ask the new active machine to get clipboard data (if the data is too big)
|
||||
SendPackage(desMachineID, PackageType.MachineSwitched);
|
||||
SendPackage(MachineStuff.desMachineID, PackageType.MachineSwitched);
|
||||
}
|
||||
|
||||
_ = Interlocked.Increment(ref switchCount);
|
||||
@@ -249,15 +249,15 @@ namespace MouseWithoutBorders
|
||||
try
|
||||
{
|
||||
PaintCount = 0;
|
||||
if (desMachineID != newDesMachineID)
|
||||
if (MachineStuff.desMachineID != MachineStuff.newDesMachineID)
|
||||
{
|
||||
Logger.LogDebug("KeybdEvent: Switching to new machine...");
|
||||
DesMachineID = newDesMachineID;
|
||||
DesMachineID = MachineStuff.newDesMachineID;
|
||||
}
|
||||
|
||||
if (desMachineID != MachineID)
|
||||
if (MachineStuff.desMachineID != MachineID)
|
||||
{
|
||||
KeybdPackage.Des = desMachineID;
|
||||
KeybdPackage.Des = MachineStuff.desMachineID;
|
||||
KeybdPackage.Type = PackageType.Keyboard;
|
||||
KeybdPackage.Kd = e;
|
||||
KeybdPackage.DateTime = GetTick();
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Windows.Forms;
|
||||
|
||||
@@ -87,35 +88,35 @@ namespace MouseWithoutBorders
|
||||
break;
|
||||
}
|
||||
|
||||
if (Common.NewDesMachineID != Common.MachineID && Common.NewDesMachineID != ID.ALL)
|
||||
if (MachineStuff.NewDesMachineID != Common.MachineID && MachineStuff.NewDesMachineID != ID.ALL)
|
||||
{
|
||||
HideMouseCursor(false);
|
||||
Common.MainFormDotEx(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Common.SwitchLocation.Count > 0)
|
||||
if (MachineStuff.SwitchLocation.Count > 0)
|
||||
{
|
||||
Common.SwitchLocation.Count--;
|
||||
MachineStuff.SwitchLocation.Count--;
|
||||
|
||||
// When we want to move mouse by pixels, we add 300k to x and y (search for XY_BY_PIXEL for other related code).
|
||||
Logger.LogDebug($"+++++ Moving mouse to {Common.SwitchLocation.X}, {Common.SwitchLocation.Y}");
|
||||
Logger.LogDebug($"+++++ Moving mouse to {MachineStuff.SwitchLocation.X}, {MachineStuff.SwitchLocation.Y}");
|
||||
|
||||
// MaxXY = 65535 so 100k is safe.
|
||||
if (Common.SwitchLocation.X > XY_BY_PIXEL - 100000 || Common.SwitchLocation.Y > XY_BY_PIXEL - 100000)
|
||||
if (MachineStuff.SwitchLocation.X > XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > XY_BY_PIXEL - 100000)
|
||||
{
|
||||
InputSimulation.MoveMouse(Common.SwitchLocation.X - XY_BY_PIXEL, Common.SwitchLocation.Y - XY_BY_PIXEL);
|
||||
InputSimulation.MoveMouse(MachineStuff.SwitchLocation.X - XY_BY_PIXEL, MachineStuff.SwitchLocation.Y - XY_BY_PIXEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
InputSimulation.MoveMouseEx(Common.SwitchLocation.X, Common.SwitchLocation.Y);
|
||||
InputSimulation.MoveMouseEx(MachineStuff.SwitchLocation.X, MachineStuff.SwitchLocation.Y);
|
||||
}
|
||||
|
||||
Common.MainFormDot();
|
||||
}
|
||||
}
|
||||
|
||||
if (Common.NewDesMachineID == Common.MachineID)
|
||||
if (MachineStuff.NewDesMachineID == Common.MachineID)
|
||||
{
|
||||
ReleaseAllKeys();
|
||||
}
|
||||
@@ -136,8 +137,8 @@ namespace MouseWithoutBorders
|
||||
|
||||
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
int left = Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2) - 1;
|
||||
int top = Setting.Values.HideMouse ? 3 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2);
|
||||
int left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 1;
|
||||
int top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2);
|
||||
|
||||
Common.MainFormVisible = true;
|
||||
|
||||
@@ -197,8 +198,8 @@ namespace MouseWithoutBorders
|
||||
DoSomethingInUIThread(
|
||||
() =>
|
||||
{
|
||||
MainForm.Left = Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2) - 2;
|
||||
MainForm.Top = Setting.Values.HideMouse ? 3 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2) - 1;
|
||||
MainForm.Left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 2;
|
||||
MainForm.Top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2) - 1;
|
||||
MainForm.Width = 3;
|
||||
MainForm.Height = 3;
|
||||
MainForm.Opacity = 0.11D;
|
||||
@@ -229,8 +230,8 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
_ = Common.SendMessageToHelper(0x408, IntPtr.Zero, IntPtr.Zero, false);
|
||||
|
||||
MainForm.Left = Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2) - 1;
|
||||
MainForm.Top = Setting.Values.HideMouse ? 3 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2);
|
||||
MainForm.Left = MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2) - 1;
|
||||
MainForm.Top = Setting.Values.HideMouse ? 3 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2);
|
||||
MainForm.Width = 1;
|
||||
MainForm.Height = 1;
|
||||
MainForm.Opacity = 0.15;
|
||||
@@ -380,7 +381,7 @@ namespace MouseWithoutBorders
|
||||
log += $"{Setting.Values.Username}/{GetDebugInfo(MyKey)}\r\n";
|
||||
log += $"{MachineName}/{MachineID}/{DesMachineID}\r\n";
|
||||
log += $"Id: {Setting.Values.DeviceId}\r\n";
|
||||
log += $"Matrix: {string.Join(",", MachineMatrix)}\r\n";
|
||||
log += $"Matrix: {string.Join(",", MachineStuff.MachineMatrix)}\r\n";
|
||||
log += $"McPool: {Setting.Values.MachinePoolString}\r\n";
|
||||
|
||||
log += "\r\nOPTIONS:\r\n";
|
||||
@@ -443,7 +444,31 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
_ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
|
||||
{
|
||||
Setting.Values.Username = WindowsIdentity.GetCurrent(true).Name;
|
||||
// See: https://stackoverflow.com/questions/19487541/how-to-get-windows-user-name-from-sessionid
|
||||
static string GetUsernameBySessionId(int sessionId)
|
||||
{
|
||||
string username = "SYSTEM";
|
||||
if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSUserName, out nint buffer, out int strLen) && strLen > 1)
|
||||
{
|
||||
username = Marshal.PtrToStringAnsi(buffer);
|
||||
NativeMethods.WTSFreeMemory(buffer);
|
||||
|
||||
if (NativeMethods.WTSQuerySessionInformation(IntPtr.Zero, sessionId, NativeMethods.WTSInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1)
|
||||
{
|
||||
username = @$"{Marshal.PtrToStringAnsi(buffer)}\{username}";
|
||||
NativeMethods.WTSFreeMemory(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
// The most direct way to fetch the username is WindowsIdentity.GetCurrent(true).Name
|
||||
// but GetUserName can run within an ExecutionContext.SuppressFlow block, which creates issues
|
||||
// with WindowsIdentity.GetCurrent.
|
||||
// See: https://stackoverflow.com/questions/76998988/exception-when-using-executioncontext-suppressflow-in-net-7
|
||||
// So we use WTSQuerySessionInformation as a workaround.
|
||||
Setting.Values.Username = GetUsernameBySessionId(Process.GetCurrentProcess().SessionId);
|
||||
});
|
||||
}
|
||||
else
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace MouseWithoutBorders
|
||||
internal static void UpdateMachineTimeAndID()
|
||||
{
|
||||
Common.MachineName = Common.MachineName.Trim();
|
||||
_ = Common.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
_ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
}
|
||||
|
||||
private static void InitializeMachinePoolFromSettings()
|
||||
@@ -59,13 +59,13 @@ namespace MouseWithoutBorders
|
||||
info[i].Name = info[i].Name.Trim();
|
||||
}
|
||||
|
||||
Common.MachinePool.Initialize(info);
|
||||
Common.MachinePool.ResetIPAddressesForDeadMachines(true);
|
||||
MachineStuff.MachinePool.Initialize(info);
|
||||
MachineStuff.MachinePool.ResetIPAddressesForDeadMachines(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Log(ex);
|
||||
Common.MachinePool.Clear();
|
||||
MachineStuff.MachinePool.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,16 +74,16 @@ namespace MouseWithoutBorders
|
||||
try
|
||||
{
|
||||
GetMachineName();
|
||||
DesMachineID = NewDesMachineID = MachineID;
|
||||
DesMachineID = MachineStuff.NewDesMachineID = MachineID;
|
||||
|
||||
// MessageBox.Show(machineID.ToString(CultureInfo.CurrentCulture)); // For test
|
||||
InitializeMachinePoolFromSettings();
|
||||
|
||||
Common.MachineName = Common.MachineName.Trim();
|
||||
_ = Common.MachinePool.LearnMachine(Common.MachineName);
|
||||
_ = Common.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
_ = MachineStuff.MachinePool.LearnMachine(Common.MachineName);
|
||||
_ = MachineStuff.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
|
||||
|
||||
Common.UpdateMachinePoolStringSetting();
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -154,7 +154,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Logger.TelemetryLogTrace($"{nameof(SystemEvents_PowerModeChanged)}: {e.Mode}", SeverityLevel.Information);
|
||||
LastResumeSuspendTime = DateTime.UtcNow;
|
||||
SwitchToMultipleMode(false, true);
|
||||
MachineStuff.SwitchToMultipleMode(false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
@@ -39,23 +38,31 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
else
|
||||
{
|
||||
// SuppressFlow fixes an issue on service mode, where WTSQueryUserToken runs successfully once and then fails
|
||||
// on subsequent calls. The reason appears to be an unknown issue with reverting the impersonation,
|
||||
// meaning that subsequent impersonation attempts run as the logged-on user and fail.
|
||||
// This is a workaround.
|
||||
using var asyncFlowControl = System.Threading.ExecutionContext.SuppressFlow();
|
||||
|
||||
uint dwSessionId;
|
||||
IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
dwSessionId = (uint)Process.GetCurrentProcess().SessionId;
|
||||
uint rv = NativeMethods.WTSQueryUserToken(dwSessionId, ref hUserToken);
|
||||
Logger.LogDebug("WTSQueryUserToken returned " + rv.ToString(CultureInfo.CurrentCulture));
|
||||
var lastError = rv == 0 ? Marshal.GetLastWin32Error() : 0;
|
||||
|
||||
Logger.LogDebug($"{nameof(NativeMethods.WTSQueryUserToken)} returned {rv.ToString(CultureInfo.CurrentCulture)}");
|
||||
|
||||
if (rv == 0)
|
||||
{
|
||||
Logger.LogDebug($"WTSQueryUserToken failed with: {Marshal.GetLastWin32Error()}.");
|
||||
Logger.Log($"{nameof(NativeMethods.WTSQueryUserToken)} failed with: {lastError}.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!NativeMethods.DuplicateToken(hUserToken, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref hUserTokenDup))
|
||||
{
|
||||
Logger.TelemetryLogTrace($"DuplicateToken Failed! {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
|
||||
Logger.TelemetryLogTrace($"{nameof(NativeMethods.DuplicateToken)} Failed! {Logger.GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
|
||||
_ = NativeMethods.CloseHandle(hUserToken);
|
||||
_ = NativeMethods.CloseHandle(hUserTokenDup);
|
||||
return false;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,7 +41,7 @@ namespace MouseWithoutBorders
|
||||
GetScreenConfig();
|
||||
}
|
||||
|
||||
private static readonly List<Point> SensitivePoints = new();
|
||||
internal static readonly List<Point> SensitivePoints = new();
|
||||
|
||||
private static bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeMethods.RECT lprcMonitor, IntPtr dwData)
|
||||
{
|
||||
@@ -162,21 +162,21 @@ namespace MouseWithoutBorders
|
||||
|
||||
// 1000 calls to EnumDisplayMonitors cost a dozen of milliseconds
|
||||
#endif
|
||||
Interlocked.Exchange(ref desktopBounds, newDesktopBounds);
|
||||
Interlocked.Exchange(ref primaryScreenBounds, newPrimaryScreenBounds);
|
||||
Interlocked.Exchange(ref MachineStuff.desktopBounds, newDesktopBounds);
|
||||
Interlocked.Exchange(ref MachineStuff.primaryScreenBounds, newPrimaryScreenBounds);
|
||||
|
||||
Logger.Log(string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
"logon = {0} PrimaryScreenBounds = {1},{2},{3},{4} desktopBounds = {5},{6},{7},{8}",
|
||||
Common.RunOnLogonDesktop,
|
||||
Common.PrimaryScreenBounds.Left,
|
||||
Common.PrimaryScreenBounds.Top,
|
||||
Common.PrimaryScreenBounds.Right,
|
||||
Common.PrimaryScreenBounds.Bottom,
|
||||
Common.DesktopBounds.Left,
|
||||
Common.DesktopBounds.Top,
|
||||
Common.DesktopBounds.Right,
|
||||
Common.DesktopBounds.Bottom));
|
||||
MachineStuff.PrimaryScreenBounds.Left,
|
||||
MachineStuff.PrimaryScreenBounds.Top,
|
||||
MachineStuff.PrimaryScreenBounds.Right,
|
||||
MachineStuff.PrimaryScreenBounds.Bottom,
|
||||
MachineStuff.DesktopBounds.Left,
|
||||
MachineStuff.DesktopBounds.Top,
|
||||
MachineStuff.DesktopBounds.Right,
|
||||
MachineStuff.DesktopBounds.Bottom));
|
||||
|
||||
Logger.Log("==================== GetScreenConfig ended");
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace MouseWithoutBorders
|
||||
internal const int JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999;
|
||||
|
||||
internal const int NETWORK_STREAM_BUF_SIZE = 1024 * 1024;
|
||||
private static readonly EventWaitHandle EvSwitch = new(false, EventResetMode.AutoReset);
|
||||
internal static readonly EventWaitHandle EvSwitch = new(false, EventResetMode.AutoReset);
|
||||
private static Point lastPos;
|
||||
private static int switchCount;
|
||||
private static long lastReconnectByHotKeyTime;
|
||||
@@ -236,12 +236,12 @@ namespace MouseWithoutBorders
|
||||
|
||||
internal static ID DesMachineID
|
||||
{
|
||||
get => Common.desMachineID;
|
||||
get => MachineStuff.desMachineID;
|
||||
|
||||
set
|
||||
{
|
||||
Common.desMachineID = value;
|
||||
Common.DesMachineName = Common.NameFromID(Common.desMachineID);
|
||||
MachineStuff.desMachineID = value;
|
||||
MachineStuff.DesMachineName = MachineStuff.NameFromID(MachineStuff.desMachineID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +351,7 @@ namespace MouseWithoutBorders
|
||||
Logger.TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}, restarting the process.", SeverityLevel.Warning, true);
|
||||
|
||||
string desktop = Common.GetMyDesktop();
|
||||
oneInstanceCheck?.Close();
|
||||
MachineStuff.oneInstanceCheck?.Close();
|
||||
_ = Process.Start(Application.ExecutablePath, desktop);
|
||||
Logger.LogDebug($"Started on desktop {desktop}");
|
||||
|
||||
@@ -619,12 +619,12 @@ namespace MouseWithoutBorders
|
||||
|
||||
internal static void ProcessByeByeMessage(DATA package)
|
||||
{
|
||||
if (package.Src == desMachineID)
|
||||
if (package.Src == MachineStuff.desMachineID)
|
||||
{
|
||||
SwitchToMachine(MachineName.Trim());
|
||||
MachineStuff.SwitchToMachine(MachineName.Trim());
|
||||
}
|
||||
|
||||
_ = RemoveDeadMachines(package.Src);
|
||||
_ = MachineStuff.RemoveDeadMachines(package.Src);
|
||||
}
|
||||
|
||||
internal static long GetTick() // ms
|
||||
@@ -644,12 +644,12 @@ namespace MouseWithoutBorders
|
||||
try
|
||||
{
|
||||
string fileName = GetMyStorageDir() + @"ScreenCaptureByMouseWithoutBorders.png";
|
||||
int w = desktopBounds.Right - desktopBounds.Left;
|
||||
int h = desktopBounds.Bottom - desktopBounds.Top;
|
||||
int w = MachineStuff.desktopBounds.Right - MachineStuff.desktopBounds.Left;
|
||||
int h = MachineStuff.desktopBounds.Bottom - MachineStuff.desktopBounds.Top;
|
||||
Bitmap bm = new(w, h);
|
||||
Graphics g = Graphics.FromImage(bm);
|
||||
Size s = new(w, h);
|
||||
g.CopyFromScreen(desktopBounds.Left, desktopBounds.Top, 0, 0, s);
|
||||
g.CopyFromScreen(MachineStuff.desktopBounds.Left, MachineStuff.desktopBounds.Top, 0, 0, s);
|
||||
bm.Save(fileName, ImageFormat.Png);
|
||||
bm.Dispose();
|
||||
return fileName;
|
||||
@@ -665,7 +665,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
if (!MouseDown && Common.SendMessageToHelper(0x401, IntPtr.Zero, IntPtr.Zero) > 0)
|
||||
if (!DragDrop.MouseDown && Common.SendMessageToHelper(0x401, IntPtr.Zero, IntPtr.Zero) > 0)
|
||||
{
|
||||
Common.MMSleep(0.2);
|
||||
InputSimulation.SendKey(new KEYBDDATA() { wVk = (int)VK.SNAPSHOT });
|
||||
@@ -675,10 +675,10 @@ namespace MouseWithoutBorders
|
||||
|
||||
_ = NativeMethods.MoveWindow(
|
||||
(IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT),
|
||||
Common.DesktopBounds.Left,
|
||||
Common.DesktopBounds.Top,
|
||||
Common.DesktopBounds.Right - Common.DesktopBounds.Left,
|
||||
Common.DesktopBounds.Bottom - Common.DesktopBounds.Top,
|
||||
MachineStuff.DesktopBounds.Left,
|
||||
MachineStuff.DesktopBounds.Top,
|
||||
MachineStuff.DesktopBounds.Right - MachineStuff.DesktopBounds.Left,
|
||||
MachineStuff.DesktopBounds.Bottom - MachineStuff.DesktopBounds.Top,
|
||||
false);
|
||||
|
||||
_ = Common.SendMessageToHelper(0x406, IntPtr.Zero, IntPtr.Zero, false);
|
||||
@@ -729,7 +729,7 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
else
|
||||
{
|
||||
ID id = Common.MachinePool.ResolveID(machine);
|
||||
ID id = MachineStuff.MachinePool.ResolveID(machine);
|
||||
if (id != ID.NONE)
|
||||
{
|
||||
SendPackage(id, PackageType.ClipboardCapture);
|
||||
@@ -753,7 +753,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
if (Setting.Values.FirstRun)
|
||||
{
|
||||
Common.Settings?.ShowTip(icon, tip, timeOutInMilliseconds);
|
||||
MachineStuff.Settings?.ShowTip(icon, tip, timeOutInMilliseconds);
|
||||
}
|
||||
|
||||
Common.MatrixForm?.ShowTip(icon, tip, timeOutInMilliseconds);
|
||||
@@ -882,7 +882,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
if (updateClientSockets)
|
||||
{
|
||||
UpdateClientSockets(nameof(IsConnectedTo));
|
||||
MachineStuff.UpdateClientSockets(nameof(IsConnectedTo));
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -921,7 +921,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
if (t != null && t.BackingSocket != null && (t.Status == SocketStatus.Connected || (t.Status == SocketStatus.Handshaking && includeHandShakingSockets)))
|
||||
{
|
||||
if (t.MachineId == (uint)data.Des || (data.Des == ID.ALL && t.MachineId != exceptDes && InMachineMatrix(t.MachineName)))
|
||||
if (t.MachineId == (uint)data.Des || (data.Des == ID.ALL && t.MachineId != exceptDes && MachineStuff.InMachineMatrix(t.MachineName)))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -952,20 +952,20 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Logger.LogDebug("********** No active connection found for the remote machine! **********" + data.Des.ToString());
|
||||
|
||||
if (data.Des == ID.NONE || RemoveDeadMachines(data.Des))
|
||||
if (data.Des == ID.NONE || MachineStuff.RemoveDeadMachines(data.Des))
|
||||
{
|
||||
// SwitchToMachine(MachineName.Trim());
|
||||
NewDesMachineID = DesMachineID = MachineID;
|
||||
SwitchLocation.X = XY_BY_PIXEL + myLastX;
|
||||
SwitchLocation.Y = XY_BY_PIXEL + myLastY;
|
||||
SwitchLocation.ResetCount();
|
||||
MachineStuff.NewDesMachineID = DesMachineID = MachineID;
|
||||
MachineStuff.SwitchLocation.X = XY_BY_PIXEL + myLastX;
|
||||
MachineStuff.SwitchLocation.Y = XY_BY_PIXEL + myLastY;
|
||||
MachineStuff.SwitchLocation.ResetCount();
|
||||
EvSwitch.Set();
|
||||
}
|
||||
}
|
||||
|
||||
if (updateClientSockets)
|
||||
{
|
||||
UpdateClientSockets("SkSend");
|
||||
MachineStuff.UpdateClientSockets("SkSend");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -1203,7 +1203,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
int machineCt = 0;
|
||||
|
||||
foreach (string m in Common.MachineMatrix)
|
||||
foreach (string m in MachineStuff.MachineMatrix)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(m.Trim()))
|
||||
{
|
||||
@@ -1211,15 +1211,15 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
}
|
||||
|
||||
if (machineCt < 2 && Common.Settings != null && (Common.Settings.GetCurrentPage() is SetupPage1 || Common.Settings.GetCurrentPage() is SetupPage2b))
|
||||
if (machineCt < 2 && MachineStuff.Settings != null && (MachineStuff.Settings.GetCurrentPage() is SetupPage1 || MachineStuff.Settings.GetCurrentPage() is SetupPage2b))
|
||||
{
|
||||
Common.MachineMatrix = new string[Common.MAX_MACHINE] { Common.MachineName.Trim(), desMachine, string.Empty, string.Empty };
|
||||
Logger.LogDebug("UpdateSetupMachineMatrix: " + string.Join(",", Common.MachineMatrix));
|
||||
MachineStuff.MachineMatrix = new string[MachineStuff.MAX_MACHINE] { Common.MachineName.Trim(), desMachine, string.Empty, string.Empty };
|
||||
Logger.LogDebug("UpdateSetupMachineMatrix: " + string.Join(",", MachineStuff.MachineMatrix));
|
||||
|
||||
Common.DoSomethingInUIThread(
|
||||
() =>
|
||||
{
|
||||
Common.Settings.SetControlPage(new SetupPage4());
|
||||
MachineStuff.Settings.SetControlPage(new SetupPage4());
|
||||
},
|
||||
true);
|
||||
}
|
||||
@@ -1255,7 +1255,7 @@ namespace MouseWithoutBorders
|
||||
SocketStuff.ClearBadIPs();
|
||||
}
|
||||
|
||||
UpdateClientSockets("ReopenSockets");
|
||||
MachineStuff.UpdateClientSockets("ReopenSockets");
|
||||
}
|
||||
},
|
||||
true);
|
||||
@@ -1473,17 +1473,17 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Logger.LogDebug("+++++ MoveMouseToCenter");
|
||||
InputSimulation.MoveMouse(
|
||||
Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2),
|
||||
Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2));
|
||||
MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2),
|
||||
MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2));
|
||||
}
|
||||
|
||||
internal static void HideMouseCursor(bool byHideMouseMessage)
|
||||
{
|
||||
Common.LastPos = new Point(
|
||||
Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2),
|
||||
Setting.Values.HideMouse ? 4 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2));
|
||||
MachineStuff.PrimaryScreenBounds.Left + ((MachineStuff.PrimaryScreenBounds.Right - MachineStuff.PrimaryScreenBounds.Left) / 2),
|
||||
Setting.Values.HideMouse ? 4 : MachineStuff.PrimaryScreenBounds.Top + ((MachineStuff.PrimaryScreenBounds.Bottom - MachineStuff.PrimaryScreenBounds.Top) / 2));
|
||||
|
||||
if ((desMachineID != MachineID && desMachineID != ID.ALL) || byHideMouseMessage)
|
||||
if ((MachineStuff.desMachineID != MachineID && MachineStuff.desMachineID != ID.ALL) || byHideMouseMessage)
|
||||
{
|
||||
_ = NativeMethods.SetCursorPos(Common.LastPos.X, Common.LastPos.Y);
|
||||
_ = NativeMethods.GetCursorPos(ref Common.lastPos);
|
||||
|
||||
@@ -154,7 +154,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
public void SendDragFile(string fileName)
|
||||
{
|
||||
Common.DragDropStep05Ex(fileName);
|
||||
DragDrop.DragDropStep05Ex(fileName);
|
||||
}
|
||||
|
||||
public void SendClipboardData(ByteArrayOrString data, bool isFilePath)
|
||||
|
||||
@@ -222,10 +222,10 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
Common.RealInputEventCount++;
|
||||
|
||||
if (Common.NewDesMachineID == Common.MachineID || Common.NewDesMachineID == ID.ALL)
|
||||
if (MachineStuff.NewDesMachineID == Common.MachineID || MachineStuff.NewDesMachineID == ID.ALL)
|
||||
{
|
||||
local = true;
|
||||
if (Common.MainFormVisible && !Common.IsDropping)
|
||||
if (Common.MainFormVisible && !DragDrop.IsDropping)
|
||||
{
|
||||
Common.MainFormDot();
|
||||
}
|
||||
@@ -265,19 +265,19 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Common.SwitchLocation.Count > 0 && Common.NewDesMachineID != Common.MachineID && Common.NewDesMachineID != ID.ALL)
|
||||
if (MachineStuff.SwitchLocation.Count > 0 && MachineStuff.NewDesMachineID != Common.MachineID && MachineStuff.NewDesMachineID != ID.ALL)
|
||||
{
|
||||
Common.SwitchLocation.Count--;
|
||||
MachineStuff.SwitchLocation.Count--;
|
||||
|
||||
if (Common.SwitchLocation.X > Common.XY_BY_PIXEL - 100000 || Common.SwitchLocation.Y > Common.XY_BY_PIXEL - 100000)
|
||||
if (MachineStuff.SwitchLocation.X > Common.XY_BY_PIXEL - 100000 || MachineStuff.SwitchLocation.Y > Common.XY_BY_PIXEL - 100000)
|
||||
{
|
||||
hookCallbackMouseData.X = Common.SwitchLocation.X - Common.XY_BY_PIXEL;
|
||||
hookCallbackMouseData.Y = Common.SwitchLocation.Y - Common.XY_BY_PIXEL;
|
||||
hookCallbackMouseData.X = MachineStuff.SwitchLocation.X - Common.XY_BY_PIXEL;
|
||||
hookCallbackMouseData.Y = MachineStuff.SwitchLocation.Y - Common.XY_BY_PIXEL;
|
||||
}
|
||||
else
|
||||
{
|
||||
hookCallbackMouseData.X = (Common.SwitchLocation.X * Common.ScreenWidth / 65535) + Common.PrimaryScreenBounds.Left;
|
||||
hookCallbackMouseData.Y = (Common.SwitchLocation.Y * Common.ScreenHeight / 65535) + Common.PrimaryScreenBounds.Top;
|
||||
hookCallbackMouseData.X = (MachineStuff.SwitchLocation.X * Common.ScreenWidth / 65535) + MachineStuff.PrimaryScreenBounds.Left;
|
||||
hookCallbackMouseData.Y = (MachineStuff.SwitchLocation.Y * Common.ScreenHeight / 65535) + MachineStuff.PrimaryScreenBounds.Top;
|
||||
}
|
||||
|
||||
Common.HideMouseCursor(false);
|
||||
@@ -290,22 +290,22 @@ namespace MouseWithoutBorders.Class
|
||||
hookCallbackMouseData.X += dx;
|
||||
hookCallbackMouseData.Y += dy;
|
||||
|
||||
if (hookCallbackMouseData.X < Common.PrimaryScreenBounds.Left)
|
||||
if (hookCallbackMouseData.X < MachineStuff.PrimaryScreenBounds.Left)
|
||||
{
|
||||
hookCallbackMouseData.X = Common.PrimaryScreenBounds.Left - 1;
|
||||
hookCallbackMouseData.X = MachineStuff.PrimaryScreenBounds.Left - 1;
|
||||
}
|
||||
else if (hookCallbackMouseData.X > Common.PrimaryScreenBounds.Right)
|
||||
else if (hookCallbackMouseData.X > MachineStuff.PrimaryScreenBounds.Right)
|
||||
{
|
||||
hookCallbackMouseData.X = Common.PrimaryScreenBounds.Right + 1;
|
||||
hookCallbackMouseData.X = MachineStuff.PrimaryScreenBounds.Right + 1;
|
||||
}
|
||||
|
||||
if (hookCallbackMouseData.Y < Common.PrimaryScreenBounds.Top)
|
||||
if (hookCallbackMouseData.Y < MachineStuff.PrimaryScreenBounds.Top)
|
||||
{
|
||||
hookCallbackMouseData.Y = Common.PrimaryScreenBounds.Top - 1;
|
||||
hookCallbackMouseData.Y = MachineStuff.PrimaryScreenBounds.Top - 1;
|
||||
}
|
||||
else if (hookCallbackMouseData.Y > Common.PrimaryScreenBounds.Bottom)
|
||||
else if (hookCallbackMouseData.Y > MachineStuff.PrimaryScreenBounds.Bottom)
|
||||
{
|
||||
hookCallbackMouseData.Y = Common.PrimaryScreenBounds.Bottom + 1;
|
||||
hookCallbackMouseData.Y = MachineStuff.PrimaryScreenBounds.Bottom + 1;
|
||||
}
|
||||
|
||||
dx += dx < 0 ? -Common.MOVE_MOUSE_RELATIVE : Common.MOVE_MOUSE_RELATIVE;
|
||||
@@ -315,8 +315,8 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
MouseEvent(hookCallbackMouseData, dx, dy);
|
||||
|
||||
Common.DragDropStep01(wParam);
|
||||
Common.DragDropStep09(wParam);
|
||||
DragDrop.DragDropStep01(wParam);
|
||||
DragDrop.DragDropStep09(wParam);
|
||||
}
|
||||
|
||||
if (local)
|
||||
@@ -432,7 +432,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (Common.DesMachineID != ID.ALL)
|
||||
{
|
||||
Common.SwitchToMachine(Common.MachineName.Trim());
|
||||
MachineStuff.SwitchToMachine(Common.MachineName.Trim());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -518,7 +518,7 @@ namespace MouseWithoutBorders.Class
|
||||
if (Common.HotkeyMatched(vkCode, winDown, CtrlDown, altDown, shiftDown, Setting.Values.HotKeySwitch2AllPC))
|
||||
{
|
||||
ResetLastSwitchKeys();
|
||||
Common.SwitchToMultipleMode(Common.DesMachineID != ID.ALL, true);
|
||||
MachineStuff.SwitchToMultipleMode(Common.DesMachineID != ID.ALL, true);
|
||||
}
|
||||
|
||||
if (Common.HotkeyMatched(vkCode, winDown, CtrlDown, altDown, shiftDown, Setting.Values.HotKeyToggleEasyMouse))
|
||||
@@ -543,7 +543,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
if (Common.GetTick() - lastHotKeyLockMachine < 500)
|
||||
{
|
||||
Common.SwitchToMultipleMode(true, true);
|
||||
MachineStuff.SwitchToMultipleMode(true, true);
|
||||
|
||||
var codes = GetVkCodesList(Setting.Values.HotKeyLockMachine);
|
||||
|
||||
@@ -561,7 +561,7 @@ namespace MouseWithoutBorders.Class
|
||||
KeyboardEvent(hookCallbackKeybdData);
|
||||
}
|
||||
|
||||
Common.SwitchToMultipleMode(false, true);
|
||||
MachineStuff.SwitchToMultipleMode(false, true);
|
||||
|
||||
_ = NativeMethods.LockWorkStation();
|
||||
}
|
||||
@@ -625,9 +625,9 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
private static bool Switch2(int index)
|
||||
{
|
||||
if (Common.MachineMatrix != null && Common.MachineMatrix.Length > index)
|
||||
if (MachineStuff.MachineMatrix != null && MachineStuff.MachineMatrix.Length > index)
|
||||
{
|
||||
string mcName = Common.MachineMatrix[index].Trim();
|
||||
string mcName = MachineStuff.MachineMatrix[index].Trim();
|
||||
if (!string.IsNullOrEmpty(mcName))
|
||||
{
|
||||
// Common.DoSomethingInUIThread(delegate()
|
||||
@@ -636,7 +636,7 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
|
||||
// );
|
||||
Common.SwitchToMachine(mcName);
|
||||
MachineStuff.SwitchToMachine(mcName);
|
||||
|
||||
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
|
||||
@@ -162,10 +162,10 @@ namespace MouseWithoutBorders.Class
|
||||
uint rv = 0;
|
||||
NativeMethods.INPUT mouse_input = default;
|
||||
|
||||
long w65535 = (Common.DesktopBounds.Right - Common.DesktopBounds.Left) * 65535 / Common.ScreenWidth;
|
||||
long h65535 = (Common.DesktopBounds.Bottom - Common.DesktopBounds.Top) * 65535 / Common.ScreenHeight;
|
||||
long l65535 = Common.DesktopBounds.Left * 65535 / Common.ScreenWidth;
|
||||
long t65535 = Common.DesktopBounds.Top * 65535 / Common.ScreenHeight;
|
||||
long w65535 = (MachineStuff.DesktopBounds.Right - MachineStuff.DesktopBounds.Left) * 65535 / Common.ScreenWidth;
|
||||
long h65535 = (MachineStuff.DesktopBounds.Bottom - MachineStuff.DesktopBounds.Top) * 65535 / Common.ScreenHeight;
|
||||
long l65535 = MachineStuff.DesktopBounds.Left * 65535 / Common.ScreenWidth;
|
||||
long t65535 = MachineStuff.DesktopBounds.Top * 65535 / Common.ScreenHeight;
|
||||
mouse_input.type = 0;
|
||||
long dx = (md.X * w65535 / 65535) + l65535;
|
||||
long dy = (md.Y * h65535 / 65535) + t65535;
|
||||
@@ -221,7 +221,7 @@ namespace MouseWithoutBorders.Class
|
||||
rv = SendInputEx(mouse_input);
|
||||
});
|
||||
|
||||
if (Common.MainFormVisible && !Common.IsDropping)
|
||||
if (Common.MainFormVisible && !DragDrop.IsDropping)
|
||||
{
|
||||
Common.MainFormDot();
|
||||
}
|
||||
@@ -233,10 +233,10 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
NativeMethods.INPUT mouse_input = default;
|
||||
|
||||
long w65535 = (Common.DesktopBounds.Right - Common.DesktopBounds.Left) * 65535 / Common.ScreenWidth;
|
||||
long h65535 = (Common.DesktopBounds.Bottom - Common.DesktopBounds.Top) * 65535 / Common.ScreenHeight;
|
||||
long l65535 = Common.DesktopBounds.Left * 65535 / Common.ScreenWidth;
|
||||
long t65535 = Common.DesktopBounds.Top * 65535 / Common.ScreenHeight;
|
||||
long w65535 = (MachineStuff.DesktopBounds.Right - MachineStuff.DesktopBounds.Left) * 65535 / Common.ScreenWidth;
|
||||
long h65535 = (MachineStuff.DesktopBounds.Bottom - MachineStuff.DesktopBounds.Top) * 65535 / Common.ScreenHeight;
|
||||
long l65535 = MachineStuff.DesktopBounds.Left * 65535 / Common.ScreenWidth;
|
||||
long t65535 = MachineStuff.DesktopBounds.Top * 65535 / Common.ScreenHeight;
|
||||
mouse_input.type = 0;
|
||||
long dx = (x * w65535 / 65535) + l65535;
|
||||
long dy = (y * h65535 / 65535) + t65535;
|
||||
|
||||
@@ -12,6 +12,8 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders.Class
|
||||
{
|
||||
/// <summary>
|
||||
@@ -113,10 +115,10 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
Name = list[i].Name,
|
||||
Id = list[i].Id,
|
||||
Time = list[i].Time > Common.GetTick() - Common.HEARTBEAT_TIMEOUT + 10000 ? Common.GetTick() - Common.HEARTBEAT_TIMEOUT + 10000 : list[i].Time,
|
||||
Time = list[i].Time > Common.GetTick() - MachineStuff.HEARTBEAT_TIMEOUT + 10000 ? Common.GetTick() - MachineStuff.HEARTBEAT_TIMEOUT + 10000 : list[i].Time,
|
||||
};
|
||||
|
||||
foundAndTimedOut = list[i].Time < Common.GetTick() - Common.HEARTBEAT_TIMEOUT + 10000 - 5000;
|
||||
foundAndTimedOut = list[i].Time < Common.GetTick() - MachineStuff.HEARTBEAT_TIMEOUT + 10000 - 5000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +159,7 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
else if (list.Count >= 4)
|
||||
{
|
||||
throw new ArgumentException($"The number of machines exceeded the maximum allowed limit of {Common.MAX_MACHINE}. Actual count: {list.Count}.");
|
||||
throw new ArgumentException($"The number of machines exceeded the maximum allowed limit of {MachineStuff.MAX_MACHINE}. Actual count: {list.Count}.");
|
||||
}
|
||||
|
||||
_ = LearnMachine(name);
|
||||
@@ -179,7 +181,7 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
else if (list.Count >= 4)
|
||||
{
|
||||
throw new ArgumentException($"The number of machines exceeded the maximum allowed limit of {Common.MAX_MACHINE}. Actual count: {list.Count}.");
|
||||
throw new ArgumentException($"The number of machines exceeded the maximum allowed limit of {MachineStuff.MAX_MACHINE}. Actual count: {list.Count}.");
|
||||
}
|
||||
|
||||
_ = LearnMachine(inf.Name);
|
||||
@@ -212,13 +214,13 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
}
|
||||
|
||||
if (list.Count >= Common.MAX_MACHINE)
|
||||
if (list.Count >= MachineStuff.MAX_MACHINE)
|
||||
{
|
||||
int slotFound = -1;
|
||||
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (!Common.InMachineMatrix(list[i].Name))
|
||||
if (!MachineStuff.InMachineMatrix(list[i].Name))
|
||||
{
|
||||
slotFound = i;
|
||||
break;
|
||||
@@ -289,7 +291,7 @@ namespace MouseWithoutBorders.Class
|
||||
List<MachineInf> machinePool = ListAllMachines();
|
||||
string rv = string.Join(",", machinePool.Select(m => $"{m.Name}:{m.Id}"));
|
||||
|
||||
for (int j = machinePool.Count; j < Common.MAX_MACHINE; j++)
|
||||
for (int j = machinePool.Count; j < MachineStuff.MAX_MACHINE; j++)
|
||||
{
|
||||
rv += ",:";
|
||||
}
|
||||
@@ -301,7 +303,7 @@ namespace MouseWithoutBorders.Class
|
||||
/// <param name="clockSkewInMS_forTesting">When doing unit tests it's nice to be able to fudge with the clock time, adding milliseconds, instead of sleeping.</param>
|
||||
internal static bool IsAlive(MachineInf inf, int clockSkewInMS_forTesting = 0)
|
||||
{
|
||||
return inf.Id != ID.NONE && (Common.GetTick() + clockSkewInMS_forTesting - inf.Time <= Common.HEARTBEAT_TIMEOUT || Common.IsConnectedTo(inf.Id));
|
||||
return inf.Id != ID.NONE && (Common.GetTick() + clockSkewInMS_forTesting - inf.Time <= MachineStuff.HEARTBEAT_TIMEOUT || Common.IsConnectedTo(inf.Id));
|
||||
}
|
||||
|
||||
private static bool NamesAreEqual(string name1, string name2)
|
||||
@@ -326,7 +328,7 @@ namespace MouseWithoutBorders.Class
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((firstLoaded && !Common.InMachineMatrix(list[i].Name)) || (!firstLoaded && (!Common.InMachineMatrix(list[i].Name) || !IsAlive(list[i]))))
|
||||
if ((firstLoaded && !MachineStuff.InMachineMatrix(list[i].Name)) || (!firstLoaded && (!MachineStuff.InMachineMatrix(list[i].Name) || !IsAlive(list[i]))))
|
||||
{
|
||||
list[i] =
|
||||
new MachineInf
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
using System;
|
||||
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders.Class
|
||||
{
|
||||
internal static class MachinePoolHelpers
|
||||
@@ -20,20 +22,20 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
string[] st = s.Split(Comma);
|
||||
|
||||
if (st.Length < Common.MAX_MACHINE)
|
||||
if (st.Length < MachineStuff.MAX_MACHINE)
|
||||
{
|
||||
throw new ArgumentException("Not enough elements in encoded MachinePool string");
|
||||
}
|
||||
|
||||
MachineInf[] rv = new MachineInf[Common.MAX_MACHINE];
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
MachineInf[] rv = new MachineInf[MachineStuff.MAX_MACHINE];
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
string[] mc = st[i].Split(Colon);
|
||||
if (mc.Length == 2)
|
||||
{
|
||||
rv[i].Name = mc[0];
|
||||
rv[i].Id = uint.TryParse(mc[1], out uint ip) ? (ID)ip : ID.NONE;
|
||||
rv[i].Time = rv[i].Id == ID.NONE ? Common.GetTick() - Common.HEARTBEAT_TIMEOUT : Common.GetTick();
|
||||
rv[i].Time = rv[i].Id == ID.NONE ? Common.GetTick() - MachineStuff.HEARTBEAT_TIMEOUT : Common.GetTick();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,41 @@ namespace MouseWithoutBorders.Class
|
||||
[DllImport("kernel32.dll")]
|
||||
internal static extern uint WTSGetActiveConsoleSessionId();
|
||||
|
||||
[DllImport("Wtsapi32.dll")]
|
||||
internal static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTSInfoClass infoClass, out IntPtr ppBuffer, out int pBytesReturned);
|
||||
|
||||
[DllImport("Wtsapi32.dll")]
|
||||
internal static extern void WTSFreeMemory(IntPtr pointer);
|
||||
|
||||
internal enum WTSInfoClass
|
||||
{
|
||||
WTSInitialProgram,
|
||||
WTSApplicationName,
|
||||
WTSWorkingDirectory,
|
||||
WTSOEMId,
|
||||
WTSSessionId,
|
||||
WTSUserName,
|
||||
WTSWinStationName,
|
||||
WTSDomainName,
|
||||
WTSConnectState,
|
||||
WTSClientBuildNumber,
|
||||
WTSClientName,
|
||||
WTSClientDirectory,
|
||||
WTSClientProductId,
|
||||
WTSClientHardwareId,
|
||||
WTSClientAddress,
|
||||
WTSClientDisplay,
|
||||
WTSClientProtocolType,
|
||||
WTSIdleTime,
|
||||
WTSLogonTime,
|
||||
WTSIncomingBytes,
|
||||
WTSOutgoingBytes,
|
||||
WTSIncomingFrames,
|
||||
WTSOutgoingFrames,
|
||||
WTSClientInfo,
|
||||
WTSSessionInfo,
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
@@ -812,7 +847,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
// [DllImport("kernel32.dll", SetLastError = true)]
|
||||
// internal static extern IntPtr CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID);
|
||||
[DllImport("Wtsapi32.dll")]
|
||||
[DllImport("Wtsapi32.dll", SetLastError = true)]
|
||||
internal static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
|
||||
|
||||
[SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Xml.Linq;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using MouseWithoutBorders.Core;
|
||||
using Newtonsoft.Json;
|
||||
using StreamJsonRpc;
|
||||
|
||||
@@ -135,7 +136,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (firstArg != string.Empty)
|
||||
{
|
||||
if (Common.CheckSecondInstance(Common.RunWithNoAdminRight))
|
||||
if (MachineStuff.CheckSecondInstance(Common.RunWithNoAdminRight))
|
||||
{
|
||||
Logger.Log("*** Second instance, exiting...");
|
||||
return;
|
||||
@@ -165,7 +166,7 @@ namespace MouseWithoutBorders.Class
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Common.CheckSecondInstance(true))
|
||||
if (MachineStuff.CheckSecondInstance(true))
|
||||
{
|
||||
Logger.Log("*** Second instance, exiting...");
|
||||
return;
|
||||
@@ -301,20 +302,20 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
Setting.Values.PauseInstantSaving = true;
|
||||
|
||||
Common.ClearComputerMatrix();
|
||||
MachineStuff.ClearComputerMatrix();
|
||||
Setting.Values.MyKey = securityKey;
|
||||
Common.MyKey = securityKey;
|
||||
Common.MagicNumber = Common.Get24BitHash(Common.MyKey);
|
||||
Common.MachineMatrix = new string[Common.MAX_MACHINE] { pcName.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };
|
||||
MachineStuff.MachineMatrix = new string[MachineStuff.MAX_MACHINE] { pcName.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };
|
||||
|
||||
string[] machines = Common.MachineMatrix;
|
||||
Common.MachinePool.Initialize(machines);
|
||||
Common.UpdateMachinePoolStringSetting();
|
||||
string[] machines = MachineStuff.MachineMatrix;
|
||||
MachineStuff.MachinePool.Initialize(machines);
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
|
||||
SocketStuff.InvalidKeyFound = false;
|
||||
Common.ReopenSocketDueToReadError = true;
|
||||
Common.ReopenSockets(true);
|
||||
Common.SendMachineMatrix();
|
||||
MachineStuff.SendMachineMatrix();
|
||||
|
||||
Setting.Values.PauseInstantSaving = false;
|
||||
Setting.Values.SaveSettings();
|
||||
@@ -325,7 +326,7 @@ namespace MouseWithoutBorders.Class
|
||||
Setting.Values.PauseInstantSaving = true;
|
||||
|
||||
Setting.Values.EasyMouse = (int)EasyMouseOption.Enable;
|
||||
Common.ClearComputerMatrix();
|
||||
MachineStuff.ClearComputerMatrix();
|
||||
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
|
||||
Common.GeneratedKey = true;
|
||||
|
||||
@@ -352,7 +353,7 @@ namespace MouseWithoutBorders.Class
|
||||
Common.MMSleep(0.2);
|
||||
}
|
||||
|
||||
Common.SendMachineMatrix();
|
||||
MachineStuff.SendMachineMatrix();
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace MouseWithoutBorders.Class
|
||||
if (!Enumerable.SequenceEqual(last_properties.MachineMatrixString, _settings.Properties.MachineMatrixString))
|
||||
{
|
||||
_properties.MachineMatrixString = _settings.Properties.MachineMatrixString;
|
||||
Common.MachineMatrix = null; // Forces read next time it's needed.
|
||||
MachineStuff.MachineMatrix = null; // Forces read next time it's needed.
|
||||
shouldSendMachineMatrix = true;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (shouldSendMachineMatrix)
|
||||
{
|
||||
Common.SendMachineMatrix();
|
||||
MachineStuff.SendMachineMatrix();
|
||||
shouldSaveNewSettingsValues = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
if (Common.DesMachineID != Common.MachineID)
|
||||
{
|
||||
Common.SwitchToMultipleMode(false, true);
|
||||
MachineStuff.SwitchToMultipleMode(false, true);
|
||||
}
|
||||
|
||||
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
|
||||
@@ -253,7 +253,7 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
if (Setting.Values.LastX == Common.JUST_GOT_BACK_FROM_SCREEN_SAVER)
|
||||
{
|
||||
Common.NewDesMachineID = Common.DesMachineID = Common.MachineID;
|
||||
MachineStuff.NewDesMachineID = Common.DesMachineID = Common.MachineID;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -263,11 +263,11 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (Common.RunOnLogonDesktop && Setting.Values.DesMachineID == (uint)ID.ALL)
|
||||
{
|
||||
Common.SwitchToMultipleMode(true, false);
|
||||
MachineStuff.SwitchToMultipleMode(true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
Common.SwitchToMultipleMode(false, false);
|
||||
MachineStuff.SwitchToMultipleMode(false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -804,11 +804,11 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
try
|
||||
{
|
||||
if (Common.MachineMatrix != null)
|
||||
if (MachineStuff.MachineMatrix != null)
|
||||
{
|
||||
Logger.LogDebug("MachineMatrix = " + string.Join(", ", Common.MachineMatrix));
|
||||
Logger.LogDebug("MachineMatrix = " + string.Join(", ", MachineStuff.MachineMatrix));
|
||||
|
||||
foreach (string st in Common.MachineMatrix)
|
||||
foreach (string st in MachineStuff.MachineMatrix)
|
||||
{
|
||||
string machineName = st.Trim();
|
||||
if (!string.IsNullOrEmpty(machineName) &&
|
||||
@@ -961,7 +961,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
UpdateTcpSockets(dummyTcp, SocketStatus.NA);
|
||||
|
||||
if (!Common.InMachineMatrix(machineName))
|
||||
if (!MachineStuff.InMachineMatrix(machineName))
|
||||
{
|
||||
// While Resolving from name to IP, user may have changed the machine name and clicked on Apply.
|
||||
return;
|
||||
@@ -1449,19 +1449,19 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
Common.SendHeartBeat(initial: true);
|
||||
|
||||
if (Common.MachinePool.TryFindMachineByName(remoteMachine, out MachineInf machineInfo))
|
||||
if (MachineStuff.MachinePool.TryFindMachineByName(remoteMachine, out MachineInf machineInfo))
|
||||
{
|
||||
Logger.LogDebug("Machine updated: " + remoteMachine + "/" + remoteID.ToString());
|
||||
|
||||
if (machineInfo.Name.Equals(Common.DesMachineName, StringComparison.OrdinalIgnoreCase))
|
||||
if (machineInfo.Name.Equals(MachineStuff.DesMachineName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Logger.LogDebug("Des ID updated: " + Common.DesMachineID.ToString() +
|
||||
"/" + remoteID.ToString());
|
||||
Common.NewDesMachineID = Common.DesMachineID = remoteID;
|
||||
MachineStuff.NewDesMachineID = Common.DesMachineID = remoteID;
|
||||
}
|
||||
|
||||
_ = Common.MachinePool.TryUpdateMachineID(remoteMachine, remoteID, true);
|
||||
Common.UpdateMachinePoolStringSetting();
|
||||
_ = MachineStuff.MachinePool.TryUpdateMachineID(remoteMachine, remoteID, true);
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1475,7 +1475,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (!isClient)
|
||||
{
|
||||
Common.UpdateClientSockets("MainTCPRoutine");
|
||||
MachineStuff.UpdateClientSockets("MainTCPRoutine");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1559,7 +1559,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (remoteID != ID.NONE)
|
||||
{
|
||||
_ = Common.RemoveDeadMachines(remoteID);
|
||||
_ = MachineStuff.RemoveDeadMachines(remoteID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1635,9 +1635,9 @@ namespace MouseWithoutBorders.Class
|
||||
{
|
||||
string remoteEndPoint = s.RemoteEndPoint.ToString();
|
||||
Logger.LogDebug("SendClipboardData: Request accepted: " + s.LocalEndPoint.ToString() + "/" + remoteEndPoint);
|
||||
Common.IsDropping = false;
|
||||
Common.IsDragging = false;
|
||||
Common.DragMachine = (ID)1;
|
||||
DragDrop.IsDropping = false;
|
||||
DragDrop.IsDragging = false;
|
||||
DragDrop.DragMachine = (ID)1;
|
||||
|
||||
bool clientPushData = true;
|
||||
ClipboardPostAction postAction = ClipboardPostAction.Other;
|
||||
@@ -2064,7 +2064,7 @@ namespace MouseWithoutBorders.Class
|
||||
|
||||
if (string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':'))
|
||||
{
|
||||
tcp.MachineName = Common.NameFromID((ID)tcp.MachineId);
|
||||
tcp.MachineName = MachineStuff.NameFromID((ID)tcp.MachineId);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':'))
|
||||
|
||||
404
src/modules/MouseWithoutBorders/App/Core/DragDrop.cs
Normal file
404
src/modules/MouseWithoutBorders/App/Core/DragDrop.cs
Normal file
@@ -0,0 +1,404 @@
|
||||
// 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.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using MouseWithoutBorders.Class;
|
||||
|
||||
// <summary>
|
||||
// Drag/Drop implementation.
|
||||
// </summary>
|
||||
// <history>
|
||||
// 2008 created by Truong Do (ductdo).
|
||||
// 2009-... modified by Truong Do (TruongDo).
|
||||
// 2023- Included in PowerToys.
|
||||
// </history>
|
||||
namespace MouseWithoutBorders.Core;
|
||||
|
||||
/* Common.DragDrop.cs
|
||||
* Drag&Drop is one complicated implementation of the tool with some tricks.
|
||||
*
|
||||
* SEQUENCE OF EVENTS:
|
||||
* DragDropStep01: MachineX: Remember mouse down state since it could be a start of a dragging
|
||||
* DragDropStep02: MachineY: Send an message to the MachineX to ask it to check if it is
|
||||
* doing drag/drop
|
||||
* DragDropStep03: MachineX: Got explorerDragDrop, send WM_CHECK_EXPLORER_DRAG_DROP to its mainForm
|
||||
* DragDropStep04: MachineX: Show Mouse Without Borders Helper form at mouse cursor to get DragEnter event.
|
||||
* DragDropStepXX: MachineX: Mouse Without Borders Helper: Called by DragEnter, check if dragging a single file,
|
||||
* remember the file (set as its window caption)
|
||||
* DragDropStep05: MachineX: Get the file name from Mouse Without Borders Helper, hide Mouse Without Borders Helper window
|
||||
* DragDropStep06: MachineX: Broadcast a message saying that it has some drag file.
|
||||
* DragDropStep08: MachineY: Got ClipboardDragDrop, isDropping set, get the MachineX name from the package.
|
||||
* DragDropStep09: MachineY: Since isDropping is true, show up the drop form (looks like an icon).
|
||||
* DragDropStep10: MachineY: MouseUp, set isDropping to false, hide the drop "icon" and get data.
|
||||
* DragDropStep11: MachineX: Mouse move back without drop event, cancelling drag/dop
|
||||
* SendClipboardBeatDragDropEnd
|
||||
* DragDropStep12: MachineY: Hide the drop "icon" when received ClipboardDragDropEnd.
|
||||
*
|
||||
* FROM VERSION 1.6.3: Drag/Drop is temporary removed, Drop action cannot be done from a lower integrity app to a higher one.
|
||||
* We have to run a helper process...
|
||||
* http://forums.microsoft.com/MSDN/ShowPost.aspx?PageIndex=1&SiteID=1&PageID=1&PostID=736086
|
||||
*
|
||||
* 2008.10.28: Trying to restore the Drag/Drop feature by adding the drag/drop helper process. Coming in version
|
||||
* 1.6.5
|
||||
* */
|
||||
|
||||
internal static class DragDrop
|
||||
{
|
||||
private static bool isDragging;
|
||||
|
||||
internal static bool IsDragging
|
||||
{
|
||||
get => DragDrop.isDragging;
|
||||
set => DragDrop.isDragging = value;
|
||||
}
|
||||
|
||||
internal static void DragDropStep01(int wParam)
|
||||
{
|
||||
if (!Setting.Values.TransferFile)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (wParam == Common.WM_LBUTTONDOWN)
|
||||
{
|
||||
MouseDown = true;
|
||||
DragMachine = MachineStuff.desMachineID;
|
||||
MachineStuff.dropMachineID = ID.NONE;
|
||||
Logger.LogDebug("DragDropStep01: MouseDown");
|
||||
}
|
||||
else if (wParam == Common.WM_LBUTTONUP)
|
||||
{
|
||||
MouseDown = false;
|
||||
Logger.LogDebug("DragDropStep01: MouseUp");
|
||||
}
|
||||
|
||||
if (wParam == Common.WM_RBUTTONUP && IsDropping)
|
||||
{
|
||||
IsDropping = false;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DragDropStep02()
|
||||
{
|
||||
if (MachineStuff.desMachineID == Common.MachineID)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep02: SendCheckExplorerDragDrop sent to myself");
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
SendCheckExplorerDragDrop();
|
||||
Logger.LogDebug("DragDropStep02: SendCheckExplorerDragDrop sent");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DragDropStep03(DATA package)
|
||||
{
|
||||
if (Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (package.Des == Common.MachineID || package.Des == ID.ALL)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep03: ExplorerDragDrop Received.");
|
||||
MachineStuff.dropMachineID = package.Src; // Drop machine is the machine that sent ExplorerDragDrop
|
||||
if (MouseDown || IsDropping)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep03: Mouse is down, check if dragging...sending WM_CHECK_EXPLORER_DRAG_DROP to myself...");
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int dragDropStep05ExCalledByIpc;
|
||||
|
||||
internal static void DragDropStep04()
|
||||
{
|
||||
if (!IsDropping)
|
||||
{
|
||||
IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT);
|
||||
if (h.ToInt32() > 0)
|
||||
{
|
||||
_ = Interlocked.Exchange(ref dragDropStep05ExCalledByIpc, 0);
|
||||
|
||||
Common.MainForm.Hide();
|
||||
Common.MainFormVisible = false;
|
||||
|
||||
Point p = default;
|
||||
|
||||
// NativeMethods.SetWindowText(h, "");
|
||||
_ = NativeMethods.SetWindowPos(h, NativeMethods.HWND_TOPMOST, 0, 0, 0, 0, NativeMethods.SWP_SHOWWINDOW);
|
||||
|
||||
for (int i = -10; i < 10; i++)
|
||||
{
|
||||
if (dragDropStep05ExCalledByIpc > 0)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep04: DragDropStep05ExCalledByIpc.");
|
||||
break;
|
||||
}
|
||||
|
||||
_ = NativeMethods.GetCursorPos(ref p);
|
||||
Logger.LogDebug("DragDropStep04: Moving Mouse Without Borders Helper to (" + p.X.ToString(CultureInfo.CurrentCulture) + ", " + p.Y.ToString(CultureInfo.CurrentCulture) + ")");
|
||||
_ = NativeMethods.SetWindowPos(h, NativeMethods.HWND_TOPMOST, p.X - 100 + i, p.Y - 100 + i, 200, 200, 0);
|
||||
_ = NativeMethods.SendMessage(h, 0x000F, IntPtr.Zero, IntPtr.Zero); // WM_PAINT
|
||||
Thread.Sleep(20);
|
||||
Application.DoEvents();
|
||||
|
||||
// if (GetText(h).Length > 1) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep04: Mouse without Borders Helper not found!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep04: IsDropping == true, skip checking");
|
||||
}
|
||||
|
||||
Logger.LogDebug("DragDropStep04: Got WM_CHECK_EXPLORER_DRAG_DROP, done with processing jump to DragDropStep05...");
|
||||
}
|
||||
|
||||
internal static void DragDropStep05Ex(string dragFileName)
|
||||
{
|
||||
Logger.LogDebug("DragDropStep05 called.");
|
||||
|
||||
_ = Interlocked.Exchange(ref dragDropStep05ExCalledByIpc, 1);
|
||||
|
||||
if (Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsDropping)
|
||||
{
|
||||
_ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(dragFileName) && (File.Exists(dragFileName) || Directory.Exists(dragFileName)))
|
||||
{
|
||||
Common.LastDragDropFile = dragFileName;
|
||||
/*
|
||||
* possibleDropMachineID is used as desID sent in DragDropStep06();
|
||||
* */
|
||||
if (MachineStuff.dropMachineID == ID.NONE)
|
||||
{
|
||||
MachineStuff.dropMachineID = MachineStuff.newDesMachineID;
|
||||
}
|
||||
|
||||
DragDropStep06();
|
||||
Logger.LogDebug("DragDropStep05: File dragging: " + dragFileName);
|
||||
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_HIDE_DD_HELPER, (IntPtr)1, (IntPtr)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep05: File not found: [" + dragFileName + "]");
|
||||
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_HIDE_DD_HELPER, (IntPtr)0, (IntPtr)0);
|
||||
}
|
||||
|
||||
Logger.LogDebug("DragDropStep05: WM_HIDE_DDHelper sent");
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("DragDropStep05: IsDropping == true, change drop machine...");
|
||||
IsDropping = false;
|
||||
Common.MainFormVisible = true; // WM_HIDE_DRAG_DROP
|
||||
SendDropBegin(); // To dropMachineID set in DragDropStep03
|
||||
}
|
||||
|
||||
MouseDown = false;
|
||||
}
|
||||
|
||||
private static void DragDropStep06()
|
||||
{
|
||||
IsDragging = true;
|
||||
Logger.LogDebug("DragDropStep06: SendClipboardBeatDragDrop");
|
||||
SendClipboardBeatDragDrop();
|
||||
SendDropBegin();
|
||||
}
|
||||
|
||||
internal static void DragDropStep08(DATA package)
|
||||
{
|
||||
Receiver.GetNameOfMachineWithClipboardData(package);
|
||||
Logger.LogDebug("DragDropStep08: ClipboardDragDrop Received. machine with drag file was set");
|
||||
}
|
||||
|
||||
internal static void DragDropStep08_2(DATA package)
|
||||
{
|
||||
if (package.Des == Common.MachineID && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
IsDropping = true;
|
||||
MachineStuff.dropMachineID = Common.MachineID;
|
||||
Logger.LogDebug("DragDropStep08_2: ClipboardDragDropOperation Received. IsDropping set");
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DragDropStep09(int wParam)
|
||||
{
|
||||
if (wParam == Common.WM_MOUSEMOVE && IsDropping)
|
||||
{
|
||||
// Show/Move form
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_SHOW_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
else if (wParam == Common.WM_LBUTTONUP && (IsDropping || IsDragging))
|
||||
{
|
||||
if (IsDropping)
|
||||
{
|
||||
// Hide form, get data
|
||||
DragDropStep10();
|
||||
}
|
||||
else
|
||||
{
|
||||
IsDragging = false;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DragDropStep10()
|
||||
{
|
||||
Logger.LogDebug("DragDropStep10: Hide the form and get data...");
|
||||
IsDropping = false;
|
||||
IsDragging = false;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_HIDE_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersDragAndDropEvent());
|
||||
Common.GetRemoteClipboard("desktop");
|
||||
}
|
||||
|
||||
internal static void DragDropStep11()
|
||||
{
|
||||
Logger.LogDebug("DragDropStep11: Mouse drag coming back, canceling drag/drop");
|
||||
SendClipboardBeatDragDropEnd();
|
||||
IsDropping = false;
|
||||
IsDragging = false;
|
||||
DragMachine = (ID)1;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
Common.LastDragDropFile = null;
|
||||
MouseDown = false;
|
||||
}
|
||||
|
||||
internal static void DragDropStep12()
|
||||
{
|
||||
Logger.LogDebug("DragDropStep12: ClipboardDragDropEnd received");
|
||||
IsDropping = false;
|
||||
Common.LastIDWithClipboardData = ID.NONE;
|
||||
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_HIDE_DRAG_DROP, (IntPtr)0, (IntPtr)0);
|
||||
});
|
||||
}
|
||||
|
||||
private static void SendCheckExplorerDragDrop()
|
||||
{
|
||||
DATA package = new();
|
||||
package.Type = PackageType.ExplorerDragDrop;
|
||||
|
||||
/*
|
||||
* package.src = newDesMachineID:
|
||||
* sent from the master machine but the src must be the
|
||||
* new des machine since the previous des machine will get this and set
|
||||
* to possibleDropMachineID in DragDropStep3()
|
||||
* */
|
||||
package.Src = MachineStuff.newDesMachineID;
|
||||
|
||||
package.Des = MachineStuff.desMachineID;
|
||||
package.MachineName = Common.MachineName;
|
||||
|
||||
Common.SkSend(package, null, false);
|
||||
}
|
||||
|
||||
internal static void ChangeDropMachine()
|
||||
{
|
||||
// desMachineID = current drop machine
|
||||
// newDesMachineID = new drop machine
|
||||
|
||||
// 1. Cancelling dropping in current drop machine
|
||||
if (MachineStuff.dropMachineID == Common.MachineID)
|
||||
{
|
||||
// Drag/Drop coming through me
|
||||
IsDropping = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Drag/Drop coming back
|
||||
SendClipboardBeatDragDropEnd();
|
||||
}
|
||||
|
||||
// 2. SendClipboardBeatDragDrop to new drop machine
|
||||
// new drop machine is not me
|
||||
if (MachineStuff.newDesMachineID != Common.MachineID)
|
||||
{
|
||||
MachineStuff.dropMachineID = MachineStuff.newDesMachineID;
|
||||
SendDropBegin();
|
||||
}
|
||||
|
||||
// New drop machine is me
|
||||
else
|
||||
{
|
||||
IsDropping = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void SendClipboardBeatDragDrop()
|
||||
{
|
||||
Common.SendPackage(ID.ALL, PackageType.ClipboardDragDrop);
|
||||
}
|
||||
|
||||
private static void SendDropBegin()
|
||||
{
|
||||
Logger.LogDebug("SendDropBegin...");
|
||||
Common.SendPackage(MachineStuff.dropMachineID, PackageType.ClipboardDragDropOperation);
|
||||
}
|
||||
|
||||
private static void SendClipboardBeatDragDropEnd()
|
||||
{
|
||||
if (MachineStuff.desMachineID != Common.MachineID)
|
||||
{
|
||||
Common.SendPackage(MachineStuff.desMachineID, PackageType.ClipboardDragDropEnd);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool isDropping;
|
||||
private static ID dragMachine;
|
||||
|
||||
internal static ID DragMachine
|
||||
{
|
||||
get => DragDrop.dragMachine;
|
||||
set => DragDrop.dragMachine = value;
|
||||
}
|
||||
|
||||
internal static bool IsDropping
|
||||
{
|
||||
get => DragDrop.isDropping;
|
||||
set => DragDrop.isDropping = value;
|
||||
}
|
||||
|
||||
internal static bool MouseDown { get; set; }
|
||||
}
|
||||
@@ -199,8 +199,11 @@ internal static class Logger
|
||||
|
||||
_ = Logger.PrivateDump(sb, AllLogs, "[Program logs]\r\n===============\r\n", 0, level, false);
|
||||
_ = Logger.PrivateDump(sb, new Common(), "[Other Logs]\r\n===============\r\n", 0, level, false);
|
||||
sb.AppendLine("[Logger]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Logger), 0, level);
|
||||
sb.AppendLine("[DragDrop]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(DragDrop), 0, level);
|
||||
sb.AppendLine("[MachineStuff]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(MachineStuff), 0, level);
|
||||
sb.AppendLine("[Receiver]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Receiver), 0, level);
|
||||
|
||||
|
||||
20
src/modules/MouseWithoutBorders/App/Core/MachineInf.cs
Normal file
20
src/modules/MouseWithoutBorders/App/Core/MachineInf.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// 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.
|
||||
|
||||
// <summary>
|
||||
// Machine setup/switching implementation.
|
||||
// </summary>
|
||||
// <history>
|
||||
// 2008 created by Truong Do (ductdo).
|
||||
// 2009-... modified by Truong Do (TruongDo).
|
||||
// 2023- Included in PowerToys.
|
||||
// </history>
|
||||
namespace MouseWithoutBorders.Core;
|
||||
|
||||
internal struct MachineInf
|
||||
{
|
||||
internal string Name;
|
||||
internal ID Id;
|
||||
internal long Time;
|
||||
}
|
||||
1122
src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs
Normal file
1122
src/modules/MouseWithoutBorders/App/Core/MachineStuff.cs
Normal file
File diff suppressed because it is too large
Load Diff
21
src/modules/MouseWithoutBorders/App/Core/MyRectangle.cs
Normal file
21
src/modules/MouseWithoutBorders/App/Core/MyRectangle.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
// <summary>
|
||||
// Machine setup/switching implementation.
|
||||
// </summary>
|
||||
// <history>
|
||||
// 2008 created by Truong Do (ductdo).
|
||||
// 2009-... modified by Truong Do (TruongDo).
|
||||
// 2023- Included in PowerToys.
|
||||
// </history>
|
||||
namespace MouseWithoutBorders.Core;
|
||||
|
||||
internal sealed class MyRectangle
|
||||
{
|
||||
internal int Left;
|
||||
internal int Top;
|
||||
internal int Right;
|
||||
internal int Bottom;
|
||||
}
|
||||
@@ -120,16 +120,16 @@ internal static class Receiver
|
||||
|
||||
if (package.Des == Common.MachineID || package.Des == ID.ALL)
|
||||
{
|
||||
if (Common.desMachineID != Common.MachineID)
|
||||
if (MachineStuff.desMachineID != Common.MachineID)
|
||||
{
|
||||
Common.NewDesMachineID = Common.DesMachineID = Common.MachineID;
|
||||
MachineStuff.NewDesMachineID = Common.DesMachineID = Common.MachineID;
|
||||
}
|
||||
|
||||
// NOTE(@yuyoyuppe): disabled to drop elevation requirement
|
||||
bool nonElevated = Common.RunWithNoAdminRight && false;
|
||||
if (nonElevated && Setting.Values.OneWayControlMode && package.Md.dwFlags != Common.WM_MOUSEMOVE)
|
||||
{
|
||||
if (!Common.IsDropping)
|
||||
if (!DragDrop.IsDropping)
|
||||
{
|
||||
if (package.Md.dwFlags is Common.WM_LBUTTONDOWN or Common.WM_RBUTTONDOWN)
|
||||
{
|
||||
@@ -138,7 +138,7 @@ internal static class Receiver
|
||||
}
|
||||
else if (package.Md.dwFlags is Common.WM_LBUTTONUP or Common.WM_RBUTTONUP)
|
||||
{
|
||||
Common.IsDropping = false;
|
||||
DragDrop.IsDropping = false;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -153,7 +153,7 @@ internal static class Receiver
|
||||
package.Md.Y < 0 ? package.Md.Y + Common.MOVE_MOUSE_RELATIVE : package.Md.Y - Common.MOVE_MOUSE_RELATIVE);
|
||||
_ = NativeMethods.GetCursorPos(ref lastXY);
|
||||
|
||||
Point p = Common.MoveToMyNeighbourIfNeeded(lastXY.X, lastXY.Y, Common.MachineID);
|
||||
Point p = MachineStuff.MoveToMyNeighbourIfNeeded(lastXY.X, lastXY.Y, Common.MachineID);
|
||||
|
||||
if (!p.IsEmpty)
|
||||
{
|
||||
@@ -162,11 +162,11 @@ internal static class Receiver
|
||||
Logger.LogDebug(string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
"***** Controlled Machine: newDesMachineIdEx set = [{0}]. Mouse is now at ({1},{2})",
|
||||
Common.newDesMachineIdEx,
|
||||
MachineStuff.newDesMachineIdEx,
|
||||
lastXY.X,
|
||||
lastXY.Y));
|
||||
|
||||
Common.SendNextMachine(package.Src, Common.newDesMachineIdEx, p);
|
||||
Common.SendNextMachine(package.Src, MachineStuff.newDesMachineIdEx, p);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -188,8 +188,8 @@ internal static class Receiver
|
||||
CustomCursor.ShowFakeMouseCursor(Common.LastX, Common.LastY);
|
||||
}
|
||||
|
||||
Common.DragDropStep01(package.Md.dwFlags);
|
||||
Common.DragDropStep09(package.Md.dwFlags);
|
||||
DragDrop.DragDropStep01(package.Md.dwFlags);
|
||||
DragDrop.DragDropStep09(package.Md.dwFlags);
|
||||
break;
|
||||
|
||||
case PackageType.NextMachine:
|
||||
@@ -204,7 +204,7 @@ internal static class Receiver
|
||||
|
||||
case PackageType.ExplorerDragDrop:
|
||||
Common.PackageReceived.ExplorerDragDrop++;
|
||||
Common.DragDropStep03(package);
|
||||
DragDrop.DragDropStep03(package);
|
||||
break;
|
||||
|
||||
case PackageType.Heartbeat:
|
||||
@@ -219,12 +219,12 @@ internal static class Receiver
|
||||
Common.SendPackage(ID.ALL, PackageType.Heartbeat_ex_l2);
|
||||
}
|
||||
|
||||
string desMachine = Common.AddToMachinePool(package);
|
||||
string desMachine = MachineStuff.AddToMachinePool(package);
|
||||
|
||||
if (Setting.Values.FirstRun && !string.IsNullOrEmpty(desMachine))
|
||||
{
|
||||
Common.UpdateSetupMachineMatrix(desMachine);
|
||||
Common.UpdateClientSockets("UpdateSetupMachineMatrix");
|
||||
MachineStuff.UpdateClientSockets("UpdateSetupMachineMatrix");
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -244,14 +244,14 @@ internal static class Receiver
|
||||
|
||||
case PackageType.Awake:
|
||||
Common.PackageReceived.Heartbeat++;
|
||||
_ = Common.AddToMachinePool(package);
|
||||
_ = MachineStuff.AddToMachinePool(package);
|
||||
Common.HumanBeingDetected();
|
||||
break;
|
||||
|
||||
case PackageType.Hello:
|
||||
Common.PackageReceived.Hello++;
|
||||
Common.SendHeartBeat();
|
||||
string newMachine = Common.AddToMachinePool(package);
|
||||
string newMachine = MachineStuff.AddToMachinePool(package);
|
||||
if (Setting.Values.MachineMatrixString == null)
|
||||
{
|
||||
string tip = newMachine + " saying Hello!";
|
||||
@@ -345,17 +345,17 @@ internal static class Receiver
|
||||
|
||||
case PackageType.ClipboardDragDrop:
|
||||
Common.PackageReceived.ClipboardDragDrop++;
|
||||
Common.DragDropStep08(package);
|
||||
DragDrop.DragDropStep08(package);
|
||||
break;
|
||||
|
||||
case PackageType.ClipboardDragDropOperation:
|
||||
Common.PackageReceived.ClipboardDragDrop++;
|
||||
Common.DragDropStep08_2(package);
|
||||
DragDrop.DragDropStep08_2(package);
|
||||
break;
|
||||
|
||||
case PackageType.ClipboardDragDropEnd:
|
||||
Common.PackageReceived.ClipboardDragDropEnd++;
|
||||
Common.DragDropStep12();
|
||||
DragDrop.DragDropStep12();
|
||||
break;
|
||||
|
||||
case PackageType.ClipboardText:
|
||||
@@ -391,7 +391,7 @@ internal static class Receiver
|
||||
if ((package.Type & PackageType.Matrix) == PackageType.Matrix)
|
||||
{
|
||||
Common.PackageReceived.Matrix++;
|
||||
Common.UpdateMachineMatrix(package);
|
||||
MachineStuff.UpdateMachineMatrix(package);
|
||||
break;
|
||||
}
|
||||
else
|
||||
@@ -406,7 +406,7 @@ internal static class Receiver
|
||||
internal static void GetNameOfMachineWithClipboardData(DATA package)
|
||||
{
|
||||
Common.LastIDWithClipboardData = package.Src;
|
||||
List<MachineInf> matchingMachines = Common.MachinePool.TryFindMachineByID(Common.LastIDWithClipboardData);
|
||||
List<MachineInf> matchingMachines = MachineStuff.MachinePool.TryFindMachineByID(Common.LastIDWithClipboardData);
|
||||
if (matchingMachines.Count >= 1)
|
||||
{
|
||||
Common.LastMachineWithClipboardData = matchingMachines[0].Name.Trim();
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
Common.Settings = null;
|
||||
MachineStuff.Settings = null;
|
||||
|
||||
if (_currentPage != null)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
using MouseWithoutBorders.Form.Settings;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
@@ -59,8 +60,8 @@ namespace MouseWithoutBorders
|
||||
MessageBoxDefaultButton.Button2) == DialogResult.Yes)
|
||||
{
|
||||
Setting.Values.FirstRun = false;
|
||||
Common.CloseSetupForm();
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.CloseSetupForm();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
using System;
|
||||
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
public partial class SetupPage1 : SettingsFormPage
|
||||
@@ -12,7 +14,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
Common.ClearComputerMatrix();
|
||||
MachineStuff.ClearComputerMatrix();
|
||||
}
|
||||
|
||||
private void NoButtonClick(object sender, EventArgs e)
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using MouseWithoutBorders.Class;
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
@@ -92,12 +93,12 @@ namespace MouseWithoutBorders
|
||||
SecurityCode = Common.MyKey;
|
||||
}
|
||||
|
||||
Common.MachineMatrix = new string[Common.MAX_MACHINE] { ComputerNameField.Text.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };
|
||||
MachineStuff.MachineMatrix = new string[MachineStuff.MAX_MACHINE] { ComputerNameField.Text.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };
|
||||
|
||||
string[] machines = Common.MachineMatrix;
|
||||
Common.MachinePool.Initialize(machines);
|
||||
string[] machines = MachineStuff.MachineMatrix;
|
||||
MachineStuff.MachinePool.Initialize(machines);
|
||||
|
||||
Common.UpdateMachinePoolStringSetting();
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
SendNextPage(new SetupPage3a { ReturnToSettings = !Setting.Values.FirstRun });
|
||||
}
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
ShowStatus($"Connecting...");
|
||||
|
||||
Common.SwitchToMultipleMode(false, false);
|
||||
MachineStuff.SwitchToMultipleMode(false, false);
|
||||
Common.ReopenSockets(true);
|
||||
|
||||
int timeOut = 0;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
using System;
|
||||
|
||||
using MouseWithoutBorders.Core;
|
||||
|
||||
namespace MouseWithoutBorders
|
||||
{
|
||||
public partial class SetupPage5 : SettingsFormPage
|
||||
@@ -16,8 +18,8 @@ namespace MouseWithoutBorders
|
||||
private void DoneButtonClick(object sender, EventArgs e)
|
||||
{
|
||||
// SendNextPage(new SettingsPage1());
|
||||
Common.CloseSetupForm();
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.CloseSetupForm();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,8 +76,8 @@ namespace MouseWithoutBorders
|
||||
return;
|
||||
}
|
||||
|
||||
string[] st = new string[Common.MAX_MACHINE];
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
string[] st = new string[MachineStuff.MAX_MACHINE];
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
if (machines[i].MachineEnabled)
|
||||
{
|
||||
@@ -98,7 +98,7 @@ namespace MouseWithoutBorders
|
||||
}
|
||||
}
|
||||
|
||||
Common.MachineMatrix = st;
|
||||
MachineStuff.MachineMatrix = st;
|
||||
Setting.Values.MatrixOneRow = matrixOneRow = !checkBoxTwoRow.Checked;
|
||||
|
||||
if (Process.GetCurrentProcess().SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
|
||||
@@ -124,7 +124,7 @@ namespace MouseWithoutBorders
|
||||
Common.MMSleep(0.2);
|
||||
}
|
||||
|
||||
Common.SendMachineMatrix();
|
||||
MachineStuff.SendMachineMatrix();
|
||||
}
|
||||
|
||||
buttonOK.Enabled = true;
|
||||
@@ -150,13 +150,13 @@ namespace MouseWithoutBorders
|
||||
bool meAdded = false;
|
||||
string machineName;
|
||||
|
||||
if (Common.MachineMatrix != null && Common.MachineMatrix.Length == Common.MAX_MACHINE)
|
||||
if (MachineStuff.MachineMatrix != null && MachineStuff.MachineMatrix.Length == MachineStuff.MAX_MACHINE)
|
||||
{
|
||||
Logger.LogDebug("LoadMachines: Machine Matrix: " + Setting.Values.MachineMatrixString);
|
||||
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
machineName = Common.MachineMatrix[i].Trim();
|
||||
machineName = MachineStuff.MachineMatrix[i].Trim();
|
||||
machines[i].MachineName = machineName;
|
||||
|
||||
if (string.IsNullOrEmpty(machineName))
|
||||
@@ -168,7 +168,7 @@ namespace MouseWithoutBorders
|
||||
machines[i].MachineEnabled = true;
|
||||
}
|
||||
|
||||
bool found = Common.MachinePool.TryFindMachineByName(machineName, out MachineInf machineInfo);
|
||||
bool found = MachineStuff.MachinePool.TryFindMachineByName(machineName, out MachineInf machineInfo);
|
||||
if (found)
|
||||
{
|
||||
if (machineInfo.Id == Common.MachineID)
|
||||
@@ -340,7 +340,7 @@ namespace MouseWithoutBorders
|
||||
string newMachine;
|
||||
Machine unUsedMachine;
|
||||
|
||||
foreach (MachineInf inf in Common.MachinePool.ListAllMachines())
|
||||
foreach (MachineInf inf in MachineStuff.MachinePool.ListAllMachines())
|
||||
{
|
||||
bool found = false;
|
||||
unUsedMachine = null;
|
||||
@@ -519,7 +519,7 @@ namespace MouseWithoutBorders
|
||||
return true;
|
||||
}
|
||||
|
||||
private readonly Machine[] machines = new Machine[Common.MAX_MACHINE];
|
||||
private readonly Machine[] machines = new Machine[MachineStuff.MAX_MACHINE];
|
||||
private Machine dragDropMachine;
|
||||
private Machine desMachine;
|
||||
private Machine desMachineX;
|
||||
@@ -530,7 +530,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
private void CreateMachines()
|
||||
{
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
Machine m = new();
|
||||
m.MouseDown += Machine_MouseDown;
|
||||
@@ -550,7 +550,7 @@ namespace MouseWithoutBorders
|
||||
int dx = (groupBoxMachineMatrix.Width - 40) / 4;
|
||||
int yOffset = groupBoxMachineMatrix.Height / 3;
|
||||
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
machines[i].Left = matrixOneRow ? 22 + (i * dx) : 22 + dx + ((i % 2) * dx);
|
||||
machines[i].Top = matrixOneRow ? yOffset : (yOffset / 2) + (i / 2 * (machines[i].Width + 2));
|
||||
@@ -649,7 +649,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
desMachineX = desMachineY = desMachine;
|
||||
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
if (machines[i] == dragDropMachine)
|
||||
{
|
||||
@@ -703,9 +703,9 @@ namespace MouseWithoutBorders
|
||||
dragDropMachine.Top = desMachinePos.Y;
|
||||
|
||||
Machine tmp;
|
||||
for (int i = 0; i < Common.MAX_MACHINE - 1; i++)
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE - 1; i++)
|
||||
{
|
||||
for (int j = 0; j < Common.MAX_MACHINE - 1 - i; j++)
|
||||
for (int j = 0; j < MachineStuff.MAX_MACHINE - 1 - i; j++)
|
||||
{
|
||||
if (machines[j + 1].Top < machines[j].Top || (machines[j + 1].Top == machines[j].Top && machines[j + 1].Left < machines[j].Left))
|
||||
{
|
||||
@@ -1041,7 +1041,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Setting.Values.MatrixCircle = checkBoxCircle.Checked;
|
||||
ShowUpdateMessage();
|
||||
Common.SendMachineMatrix();
|
||||
MachineStuff.SendMachineMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1187,8 +1187,8 @@ namespace MouseWithoutBorders
|
||||
ButtonCancel_Click(this, new EventArgs());
|
||||
Setting.Values.FirstRun = true;
|
||||
Setting.Values.EasyMouse = (int)EasyMouseOption.Enable;
|
||||
Common.ClearComputerMatrix();
|
||||
Common.ShowSetupForm(true);
|
||||
MachineStuff.ClearComputerMatrix();
|
||||
MachineStuff.ShowSetupForm(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace MouseWithoutBorders
|
||||
internal void MenuOnClick(object sender, EventArgs e)
|
||||
{
|
||||
string name = (sender as ToolStripMenuItem).Text;
|
||||
Common.SwitchToMachine(name);
|
||||
MachineStuff.SwitchToMachine(name);
|
||||
}
|
||||
|
||||
internal void UpdateMenu()
|
||||
@@ -199,11 +199,11 @@ namespace MouseWithoutBorders
|
||||
menuGetScreenCapture.DropDown.Items.Count - 1]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
string newMachine = Common.MachineMatrix[i].Trim();
|
||||
string newMachine = MachineStuff.MachineMatrix[i].Trim();
|
||||
|
||||
if (Common.MachinePool.TryFindMachineByName(newMachine, out MachineInf inf) && MachinePool.IsAlive(inf))
|
||||
if (MachineStuff.MachinePool.TryFindMachineByName(newMachine, out MachineInf inf) && MachinePool.IsAlive(inf))
|
||||
{
|
||||
ToolStripMenuItem newItem = new(
|
||||
newMachine,
|
||||
@@ -372,14 +372,14 @@ namespace MouseWithoutBorders
|
||||
Common.MyKey = Setting.Values.MyKey;
|
||||
}
|
||||
|
||||
Common.UpdateMachinePoolStringSetting();
|
||||
MachineStuff.UpdateMachinePoolStringSetting();
|
||||
|
||||
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && (Setting.Values.FirstRun || Common.KeyCorrupted))
|
||||
{
|
||||
if (!shownSetupFormOneTime)
|
||||
{
|
||||
shownSetupFormOneTime = true;
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
|
||||
if (Common.KeyCorrupted && !Setting.Values.FirstRun)
|
||||
{
|
||||
@@ -439,7 +439,7 @@ namespace MouseWithoutBorders
|
||||
Common.GetMachineName();
|
||||
Logger.LogDebug("Common.pleaseReopenSocket: " + Common.PleaseReopenSocket.ToString(CultureInfo.InvariantCulture));
|
||||
Common.ReopenSockets(false);
|
||||
Common.NewDesMachineID = Common.DesMachineID = Common.MachineID;
|
||||
MachineStuff.NewDesMachineID = Common.DesMachineID = Common.MachineID;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -457,7 +457,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Common.PleaseReopenSocket = 0;
|
||||
Thread.Sleep(1000);
|
||||
Common.UpdateClientSockets("REOPEN_WHEN_WSAECONNRESET");
|
||||
MachineStuff.UpdateClientSockets("REOPEN_WHEN_WSAECONNRESET");
|
||||
}
|
||||
|
||||
if (Common.RunOnLogonDesktop)
|
||||
@@ -496,7 +496,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
|
||||
Common.MatrixForm?.UpdateKeyTextBox();
|
||||
|
||||
@@ -511,7 +511,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
if (myKeyDaysToExpire <= 0)
|
||||
{
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
|
||||
Common.Sk?.Close(false);
|
||||
|
||||
@@ -532,7 +532,7 @@ namespace MouseWithoutBorders
|
||||
// if (Common.RunOnLogonDesktop) ShowMouseWithoutBordersUiOnWinLogonDesktop(false);
|
||||
#endif
|
||||
Common.CheckForDesktopSwitchEvent(true);
|
||||
Common.UpdateClientSockets("helperTimer_Tick"); // Sockets may be closed by the remote host when both machines switch desktop at the same time.
|
||||
MachineStuff.UpdateClientSockets("helperTimer_Tick"); // Sockets may be closed by the remote host when both machines switch desktop at the same time.
|
||||
}
|
||||
|
||||
count++;
|
||||
@@ -553,11 +553,11 @@ namespace MouseWithoutBorders
|
||||
Logger.LogAll();
|
||||
|
||||
// Need to review this code on why it is needed (moved from MoveToMyNeighbourIfNeeded(...))
|
||||
for (int i = 0; i < Common.MachineMatrix.Length; i++)
|
||||
for (int i = 0; i < MachineStuff.MachineMatrix.Length; i++)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Common.MachineMatrix[i]) && !Common.InMachineMatrix(Common.MachineName))
|
||||
if (string.IsNullOrEmpty(MachineStuff.MachineMatrix[i]) && !MachineStuff.InMachineMatrix(Common.MachineName))
|
||||
{
|
||||
Common.MachineMatrix[i] = Common.MachineName;
|
||||
MachineStuff.MachineMatrix[i] = Common.MachineName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ namespace MouseWithoutBorders
|
||||
if (Setting.Values.BlockScreenSaver || count % 3000 == 0)
|
||||
{
|
||||
Common.SendAwakeBeat();
|
||||
Common.RemoveDeadMachines();
|
||||
MachineStuff.RemoveDeadMachines();
|
||||
|
||||
// GC.Collect();
|
||||
// GC.WaitForPendingFinalizers();
|
||||
@@ -601,12 +601,12 @@ namespace MouseWithoutBorders
|
||||
|
||||
private void MenuMachineMatrix_Click(object sender, EventArgs e)
|
||||
{
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
}
|
||||
|
||||
private void FrmScreen_MouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (!Common.IsDropping)
|
||||
if (!Core.DragDrop.IsDropping)
|
||||
{
|
||||
if (Cursor != dotCur)
|
||||
{
|
||||
@@ -702,7 +702,7 @@ namespace MouseWithoutBorders
|
||||
internal void MenuAllPC_Click(object sender, EventArgs e)
|
||||
{
|
||||
Logger.LogDebug("menuAllPC_Click");
|
||||
Common.SwitchToMultipleMode(MenuAllPC.Checked, true);
|
||||
MachineStuff.SwitchToMultipleMode(MenuAllPC.Checked, true);
|
||||
CurIcon = MenuAllPC.Checked ? Common.ICON_ALL : Common.ICON_ONE;
|
||||
ChangeIcon(CurIcon);
|
||||
}
|
||||
@@ -711,7 +711,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
Common.DoSomethingInUIThread(() =>
|
||||
{
|
||||
MenuAllPC.Checked = Common.NewDesMachineID == ID.ALL;
|
||||
MenuAllPC.Checked = MachineStuff.NewDesMachineID == ID.ALL;
|
||||
CurIcon = MenuAllPC.Checked ? Common.ICON_ALL : Common.ICON_ONE;
|
||||
ChangeIcon(CurIcon);
|
||||
});
|
||||
@@ -819,7 +819,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
case NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP:
|
||||
Logger.LogDebug("Got WM_CHECK_EXPLORER_DRAG_DROP!");
|
||||
Common.DragDropStep04();
|
||||
Core.DragDrop.DragDropStep04();
|
||||
break;
|
||||
|
||||
case NativeMethods.WM_QUIT:
|
||||
@@ -841,7 +841,7 @@ namespace MouseWithoutBorders
|
||||
case NativeMethods.WM_SHOW_SETTINGS_FORM:
|
||||
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
|
||||
{
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -856,7 +856,7 @@ namespace MouseWithoutBorders
|
||||
{
|
||||
if (e.Button == MouseButtons.Left)
|
||||
{
|
||||
Common.ShowMachineMatrix();
|
||||
MachineStuff.ShowMachineMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,7 +872,7 @@ namespace MouseWithoutBorders
|
||||
|
||||
internal void UpdateNotifyIcon()
|
||||
{
|
||||
string[] x = Common.MachineMatrix;
|
||||
string[] x = MachineStuff.MachineMatrix;
|
||||
string iconText;
|
||||
if (x != null && (x[0].Length > 0 || x[1].Length > 0 || x[2].Length > 0 || x[3].Length > 0))
|
||||
{
|
||||
@@ -943,13 +943,13 @@ namespace MouseWithoutBorders
|
||||
string menuCaption = (sender as ToolStripMenuItem).Text;
|
||||
|
||||
// Send CaptureScreenCommand
|
||||
ID des = menuCaption.Equals("All", StringComparison.OrdinalIgnoreCase) ? ID.ALL : Common.IdFromName(menuCaption);
|
||||
ID des = menuCaption.Equals("All", StringComparison.OrdinalIgnoreCase) ? ID.ALL : MachineStuff.IdFromName(menuCaption);
|
||||
Common.SendPackage(des, PackageType.CaptureScreenCommand);
|
||||
}
|
||||
|
||||
private void FrmScreen_Shown(object sender, EventArgs e)
|
||||
{
|
||||
Common.AssertOneInstancePerDesktopSession();
|
||||
MachineStuff.AssertOneInstancePerDesktopSession();
|
||||
|
||||
Common.MainForm = this;
|
||||
Hide();
|
||||
@@ -1057,11 +1057,11 @@ namespace MouseWithoutBorders
|
||||
r.Right = Common.ScreenWidth - (Common.ScreenWidth / 5);
|
||||
r.Bottom = 20;
|
||||
|
||||
for (int i = 0; i < Common.MAX_MACHINE; i++)
|
||||
for (int i = 0; i < MachineStuff.MAX_MACHINE; i++)
|
||||
{
|
||||
string newMachine = Common.MachineMatrix[i].Trim();
|
||||
string newMachine = MachineStuff.MachineMatrix[i].Trim();
|
||||
|
||||
if (Common.MachinePool.TryFindMachineByName(newMachine, out MachineInf inf) && MachinePool.IsAlive(inf))
|
||||
if (MachineStuff.MachinePool.TryFindMachineByName(newMachine, out MachineInf inf) && MachinePool.IsAlive(inf))
|
||||
{
|
||||
machineMatrix += "[" + inf.Name.Trim() + "]";
|
||||
}
|
||||
|
||||
@@ -68,11 +68,6 @@ avgSendTime = 0
|
||||
maxSendTime = 0
|
||||
totalSendCount = 0
|
||||
totalSendTime = 0
|
||||
isDragging = False
|
||||
dragDropStep05ExCalledByIpc = 0
|
||||
isDropping = False
|
||||
dragMachine = NONE
|
||||
<MouseDown>k__BackingField = False
|
||||
magicNumber = 0
|
||||
ran = System.Random
|
||||
--_impl = System.Random+XoshiroImpl
|
||||
@@ -163,35 +158,6 @@ ReopenSocketDueToReadError = False
|
||||
--MaxValue = 31/12/9999 23:59:59
|
||||
--UnixEpoch = 01/01/1970 00:00:00
|
||||
lastReleaseAllKeysCall = 0
|
||||
McMatrixLock = Lock
|
||||
--_owningThreadId = 0
|
||||
--_state = 0
|
||||
--_recursionCount = 0
|
||||
--_spinCount = 22
|
||||
--_waiterStartTimeMs = 0
|
||||
--s_contentionCount = 0
|
||||
--s_maxSpinCount = 22
|
||||
--s_minSpinCountForAdaptiveSpin = -100
|
||||
desMachineID = NONE
|
||||
DesMachineName =
|
||||
newDesMachineID = NONE
|
||||
newDesMachineIdEx = NONE
|
||||
dropMachineID = NONE
|
||||
lastJump = ????????????
|
||||
desktopBounds = MouseWithoutBorders.MyRectangle
|
||||
--Left = 0
|
||||
--Top = 0
|
||||
--Right = 0
|
||||
--Bottom = 0
|
||||
primaryScreenBounds = MouseWithoutBorders.MyRectangle
|
||||
--Left = 0
|
||||
--Top = 0
|
||||
--Right = 0
|
||||
--Bottom = 0
|
||||
SwitchLocation = MouseWithoutBorders.Class.MouseLocation
|
||||
--<X>k__BackingField = 0
|
||||
--<Y>k__BackingField = 0
|
||||
--<Count>k__BackingField = 0
|
||||
PackageSent = MouseWithoutBorders.PackageMonitor
|
||||
--Keyboard = 0
|
||||
--Mouse = 0
|
||||
@@ -259,11 +225,6 @@ SymAlBlockSize = 16
|
||||
PW_LENGTH = 16
|
||||
HELPER_FORM_TEXT = Mouse without Borders Helper
|
||||
HelperProcessName = PowerToys.MouseWithoutBordersHelper
|
||||
MAX_MACHINE = 4
|
||||
MAX_SOCKET = 8
|
||||
HEARTBEAT_TIMEOUT = 1500000
|
||||
SKIP_PIXELS = 1
|
||||
JUMP_PIXELS = 2
|
||||
PACKAGE_SIZE = 32
|
||||
PACKAGE_SIZE_EX = 64
|
||||
WP_PACKAGE_SIZE = 6
|
||||
@@ -358,6 +319,49 @@ MAX_LOG = 10000
|
||||
MaxLogExceptionPerHour = 1000
|
||||
HeaderSENT = Be{0},Ke{1},Mo{2},He{3},Mx{4},Tx{5},Im{6},By{7},Cl{8},Dr{9},De{10},Ed{11},Ie{12},Ni{13}
|
||||
HeaderRECEIVED = Be{0},Ke{1},Mo{2},He{3},Mx{4},Tx{5},Im{6},By{7},Cl{8},Dr{9},De{10},Ed{11},In{12},Ni{13},Pc{14}/{15}
|
||||
[DragDrop]
|
||||
===============
|
||||
isDragging = False
|
||||
dragDropStep05ExCalledByIpc = 0
|
||||
isDropping = False
|
||||
dragMachine = NONE
|
||||
<MouseDown>k__BackingField = False
|
||||
[MachineStuff]
|
||||
===============
|
||||
McMatrixLock = Lock
|
||||
--_owningThreadId = 0
|
||||
--_state = 0
|
||||
--_recursionCount = 0
|
||||
--_spinCount = 22
|
||||
--_waiterStartTimeMs = 0
|
||||
--s_contentionCount = 0
|
||||
--s_maxSpinCount = 22
|
||||
--s_minSpinCountForAdaptiveSpin = -100
|
||||
desMachineID = NONE
|
||||
DesMachineName =
|
||||
newDesMachineID = NONE
|
||||
newDesMachineIdEx = NONE
|
||||
dropMachineID = NONE
|
||||
lastJump = ????????????
|
||||
desktopBounds = MouseWithoutBorders.Core.MyRectangle
|
||||
--Left = 0
|
||||
--Top = 0
|
||||
--Right = 0
|
||||
--Bottom = 0
|
||||
primaryScreenBounds = MouseWithoutBorders.Core.MyRectangle
|
||||
--Left = 0
|
||||
--Top = 0
|
||||
--Right = 0
|
||||
--Bottom = 0
|
||||
SwitchLocation = MouseWithoutBorders.Class.MouseLocation
|
||||
--<X>k__BackingField = 0
|
||||
--<Y>k__BackingField = 0
|
||||
--<Count>k__BackingField = 0
|
||||
MAX_MACHINE = 4
|
||||
MAX_SOCKET = 8
|
||||
HEARTBEAT_TIMEOUT = 1500000
|
||||
SKIP_PIXELS = 1
|
||||
JUMP_PIXELS = 2
|
||||
[Receiver]
|
||||
===============
|
||||
QUEUE_SIZE = 50
|
||||
|
||||
@@ -120,6 +120,10 @@ public static class LoggerTests
|
||||
_ = Logger.PrivateDump(sb, new Common(), "[Other Logs]\r\n===============\r\n", 0, settingsDumpObjectsLevel, false);
|
||||
sb.AppendLine("[Logger]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Logger), 0, settingsDumpObjectsLevel);
|
||||
sb.AppendLine("[DragDrop]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(DragDrop), 0, settingsDumpObjectsLevel);
|
||||
sb.AppendLine("[MachineStuff]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(MachineStuff), 0, settingsDumpObjectsLevel);
|
||||
sb.AppendLine("[Receiver]\r\n===============");
|
||||
Logger.DumpType(sb, typeof(Receiver), 0, settingsDumpObjectsLevel);
|
||||
var actual = sb.ToString();
|
||||
|
||||
@@ -62,11 +62,10 @@ namespace PlacementHelper
|
||||
else
|
||||
{
|
||||
placement.showCmd = SW_RESTORE;
|
||||
|
||||
ScreenToWorkAreaCoords(window, monitor, rect);
|
||||
placement.rcNormalPosition = rect;
|
||||
}
|
||||
|
||||
ScreenToWorkAreaCoords(window, monitor, rect);
|
||||
placement.rcNormalPosition = rect;
|
||||
placement.flags |= WPF_ASYNCWINDOWPLACEMENT;
|
||||
|
||||
auto result = ::SetWindowPlacement(window, &placement);
|
||||
@@ -430,9 +429,11 @@ bool WindowArranger::moveWindow(HWND window, const WorkspacesData::WorkspacesPro
|
||||
Logger::error(L"No monitor saved for launching the app");
|
||||
return false;
|
||||
}
|
||||
UINT snapDPI = snapMonitorIter->dpi;
|
||||
|
||||
bool launchMinimized = app.isMinimized;
|
||||
bool launchMaximized = app.isMaximized;
|
||||
RECT rect = app.position.toRect();
|
||||
|
||||
HMONITOR currentMonitor{};
|
||||
UINT currentDpi = DPIAware::DEFAULT_DPI;
|
||||
@@ -446,12 +447,18 @@ bool WindowArranger::moveWindow(HWND window, const WorkspacesData::WorkspacesPro
|
||||
{
|
||||
currentMonitor = MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY);
|
||||
DPIAware::GetScreenDPIForMonitor(currentMonitor, currentDpi);
|
||||
snapDPI = DPIAware::DEFAULT_DPI;
|
||||
launchMinimized = true;
|
||||
launchMaximized = false;
|
||||
MONITORINFOEX monitorInfo;
|
||||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
if (GetMonitorInfo(currentMonitor, &monitorInfo))
|
||||
{
|
||||
rect = monitorInfo.rcWork;
|
||||
}
|
||||
}
|
||||
|
||||
RECT rect = app.position.toRect();
|
||||
float mult = static_cast<float>(snapMonitorIter->dpi) / currentDpi;
|
||||
float mult = static_cast<float>(snapDPI) / currentDpi;
|
||||
rect.left = static_cast<long>(std::round(rect.left * mult));
|
||||
rect.right = static_cast<long>(std::round(rect.right * mult));
|
||||
rect.top = static_cast<long>(std::round(rect.top * mult));
|
||||
|
||||
@@ -1820,7 +1820,7 @@ INT_PTR CALLBACK OptionsTabProc( HWND hDlg, UINT message,
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
if( (hTextPreview = GetDlgItem( hDlg, IDC_TEXT_FONT ))) {
|
||||
if( (hTextPreview = GetDlgItem( hDlg, IDC_TEXT_FONT )) != 0 ) {
|
||||
|
||||
// 16-pt preview
|
||||
LOGFONT _lf = g_LogFont;
|
||||
|
||||
@@ -83,9 +83,7 @@
|
||||
<Border
|
||||
x:Name="MonitorItem"
|
||||
Width="{Binding DisplayWidth}"
|
||||
Height="{Binding DisplayHeight}"
|
||||
AutomationProperties.HelpText="{Binding Index}"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Monitor}">
|
||||
Height="{Binding DisplayHeight}">
|
||||
<Border.ToolTip>
|
||||
<ToolTip>
|
||||
<StackPanel>
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
using FancyZonesEditor.Properties;
|
||||
using FancyZonesEditor.ViewModels;
|
||||
|
||||
namespace FancyZonesEditor.Utils
|
||||
@@ -14,6 +16,8 @@ namespace FancyZonesEditor.Utils
|
||||
{
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
private static readonly CompositeFormat MonitorIndexFormat = CompositeFormat.Parse(Resources.Monitor_Index);
|
||||
|
||||
public MonitorInfoModel(int index, int height, int width, int dpi, bool selected = false)
|
||||
{
|
||||
Index = index;
|
||||
@@ -24,6 +28,10 @@ namespace FancyZonesEditor.Utils
|
||||
Selected = selected;
|
||||
}
|
||||
|
||||
public string AccessibleName => string.Format(CultureInfo.CurrentCulture, MonitorIndexFormat, Index);
|
||||
|
||||
public string AccessibleHelpText => $"{Resources.Dimensions} {Dimensions}, {Resources.Scaling} {Scaling}";
|
||||
|
||||
public int Index { get; set; }
|
||||
|
||||
public int ScreenBoundsHeight { get; set; }
|
||||
|
||||
@@ -276,6 +276,15 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Dimensions.
|
||||
/// </summary>
|
||||
public static string Dimensions {
|
||||
get {
|
||||
return ResourceManager.GetString("Dimensions", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Highlight distance.
|
||||
/// </summary>
|
||||
@@ -539,7 +548,7 @@ namespace FancyZonesEditor.Properties {
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to
|
||||
///• [Shift]+S to split currently focused zone.
|
||||
///• Shift+S to split currently focused zone.
|
||||
///• Ctrl+Tab to focus zones/resizers.
|
||||
///• Tab to cycle zones and resizers.
|
||||
///• Delete to remove the focused resizer.
|
||||
@@ -554,8 +563,8 @@ namespace FancyZonesEditor.Properties {
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to
|
||||
///• Ctrl+Tab to switch focus between dialog and zones.
|
||||
///• [Shift]+Arrows to resize the focused zone by 10px (5px per edge).
|
||||
///• Ctrl+[Shift]+Arrows to resize the focused zone by 2px (1px per edge).
|
||||
///• Shift+Arrows to resize the focused zone by 10px (5px per edge).
|
||||
///• Ctrl+Shift+Arrows to resize the focused zone by 2px (1px per edge).
|
||||
///• Arrows to move the focused zone by 10px.
|
||||
///• Ctrl+Arrows to move the focused zone by 1px..
|
||||
/// </summary>
|
||||
@@ -655,6 +664,15 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Monitor {0}.
|
||||
/// </summary>
|
||||
public static string Monitor_Index {
|
||||
get {
|
||||
return ResourceManager.GetString("Monitor_Index", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Name.
|
||||
/// </summary>
|
||||
@@ -790,6 +808,15 @@ namespace FancyZonesEditor.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Scaling.
|
||||
/// </summary>
|
||||
public static string Scaling {
|
||||
get {
|
||||
return ResourceManager.GetString("Scaling", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Set layout as a default for horizontal monitor orientation.
|
||||
/// </summary>
|
||||
|
||||
@@ -282,6 +282,15 @@
|
||||
<data name="Monitor" xml:space="preserve">
|
||||
<value>Monitor</value>
|
||||
</data>
|
||||
<data name="Monitor_Index" xml:space="preserve">
|
||||
<value>Monitor {0}</value>
|
||||
</data>
|
||||
<data name="Dimensions" xml:space="preserve">
|
||||
<value>Dimensions</value>
|
||||
</data>
|
||||
<data name="Scaling" xml:space="preserve">
|
||||
<value>Scaling</value>
|
||||
</data>
|
||||
<data name="Settings" xml:space="preserve">
|
||||
<value>Template settings</value>
|
||||
</data>
|
||||
|
||||
@@ -26,11 +26,11 @@
|
||||
<Style x:Key="MonitorItemContainerStyle" TargetType="ui:GridViewItem">
|
||||
<Setter Property="Background" Value="{DynamicResource LayoutItemBackgroundBrush}" />
|
||||
<Setter Property="IsSelected" Value="{Binding Selected, Mode=OneWay}" />
|
||||
<Setter Property="AutomationProperties.Name" Value="{Binding Index}" />
|
||||
<Setter Property="AutomationProperties.Name" Value="{Binding AccessibleName}" />
|
||||
<Setter Property="AutomationProperties.HelpText" Value="{Binding AccessibleHelpText}" />
|
||||
<Setter Property="KeyboardNavigation.TabNavigation" Value="Local" />
|
||||
<Setter Property="MinWidth" Value="0" />
|
||||
<Setter Property="MinHeight" Value="0" />
|
||||
<!--<Setter Property="IsHoldingEnabled" Value="True" />-->
|
||||
<Setter Property="CornerRadius" Value="4" />
|
||||
<Setter Property="Margin" Value="8" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="{DynamicResource UseSystemFocusVisuals}" />
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
<v:SizeTypeToVisibilityConverter x:Key="SizeTypeToVisibilityConverter" />
|
||||
<v:SizeTypeToHelpTextConverter x:Key="SizeTypeToHelpTextConverter" />
|
||||
<v:EnumValueConverter x:Key="EnumValueConverter" />
|
||||
<v:AutoDoubleConverter x:Key="AutoDoubleConverter" />
|
||||
<v:BoolValueConverter x:Key="BoolValueConverter" />
|
||||
|
||||
@@ -254,6 +254,7 @@ namespace ImageResizer.Properties
|
||||
{
|
||||
_selectedSizeIndex = value;
|
||||
NotifyPropertyChanged();
|
||||
NotifyPropertyChanged(nameof(SelectedSize));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,12 +22,19 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
AutomationProperties.HelpText="{Binding Settings.SelectedSize, Converter={StaticResource SizeTypeToHelpTextConverter}}"
|
||||
AutomationProperties.Name="{x:Static p:Resources.Image_Sizes}"
|
||||
ItemsSource="{Binding Settings.AllSizes}"
|
||||
SelectedIndex="{Binding Settings.SelectedSizeIndex}">
|
||||
<ComboBox.ItemContainerStyle>
|
||||
<Style BasedOn="{StaticResource {x:Type ComboBoxItem}}" TargetType="ComboBoxItem">
|
||||
<Setter Property="AutomationProperties.Name" Value="{Binding Name}" />
|
||||
<Setter Property="AutomationProperties.HelpText" Value="{Binding ., Converter={StaticResource SizeTypeToHelpTextConverter}}" />
|
||||
</Style>
|
||||
</ComboBox.ItemContainerStyle>
|
||||
<ComboBox.Resources>
|
||||
<DataTemplate DataType="{x:Type m:ResizeSize}">
|
||||
<Grid VerticalAlignment="Center" AutomationProperties.Name="{Binding Name}">
|
||||
<Grid VerticalAlignment="Center">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -55,7 +62,7 @@
|
||||
</DataTemplate>
|
||||
|
||||
<DataTemplate DataType="{x:Type m:CustomSize}">
|
||||
<Grid VerticalAlignment="Center" AutomationProperties.Name="{Binding Name}">
|
||||
<Grid VerticalAlignment="Center">
|
||||
<TextBlock FontWeight="SemiBold" Text="{Binding Name}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// 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.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
using ImageResizer.Models;
|
||||
|
||||
namespace ImageResizer.Views;
|
||||
|
||||
[ValueConversion(typeof(ResizeSize), typeof(string))]
|
||||
public sealed partial class SizeTypeToHelpTextConverter : IValueConverter
|
||||
{
|
||||
private const char MultiplicationSign = '\u00D7';
|
||||
|
||||
private readonly EnumValueConverter _enumConverter = new();
|
||||
private readonly AutoDoubleConverter _autoDoubleConverter = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is not ResizeSize size)
|
||||
{
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
|
||||
string EnumToString(Enum value, string parameter = null) =>
|
||||
_enumConverter.Convert(value, typeof(string), parameter, culture) as string;
|
||||
|
||||
string DoubleToString(double value) =>
|
||||
_autoDoubleConverter.Convert(value, typeof(string), null, culture) as string;
|
||||
|
||||
var fit = EnumToString(size.Fit, "ThirdPersonSingular");
|
||||
var width = DoubleToString(size.Width);
|
||||
var unit = EnumToString(size.Unit);
|
||||
|
||||
return size.ShowHeight ?
|
||||
$"{fit} {width} {MultiplicationSign} {DoubleToString(size.Height)} {unit}" :
|
||||
$"{fit} {width} {unit}";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
=> throw new NotImplementedException();
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include "pch.h"
|
||||
#include "KeyboardManagerEditorLibraryWrapper.h"
|
||||
|
||||
#include <common/utils/logger_helper.h>
|
||||
#include <keyboardmanager/KeyboardManagerEditor/KeyboardManagerEditor.h>
|
||||
|
||||
// Test function to call the remapping helper function
|
||||
|
||||
bool CheckIfRemappingsAreValid()
|
||||
{
|
||||
RemapBuffer remapBuffer;
|
||||
|
||||
// Mock valid key to key remappings
|
||||
remapBuffer.push_back(RemapBufferRow{ RemapBufferItem({ (DWORD)0x41, (DWORD)0x42 }), std::wstring() });
|
||||
remapBuffer.push_back(RemapBufferRow{ RemapBufferItem({ (DWORD)0x42, (DWORD)0x43 }), std::wstring() });
|
||||
|
||||
auto result = LoadingAndSavingRemappingHelper::CheckIfRemappingsAreValid(remapBuffer);
|
||||
|
||||
return result == ShortcutErrorType::NoError;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <keyboardmanager/common/Helpers.h>
|
||||
#include <keyboardmanager/common/Input.h>
|
||||
#include <keyboardmanager/common/MappingConfiguration.h>
|
||||
|
||||
extern "C" __declspec(dllexport) bool CheckIfRemappingsAreValid();
|
||||
@@ -0,0 +1,260 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|ARM64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>ARM64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{4382a954-179a-4078-92af-715187dfff50}</ProjectGuid>
|
||||
<RootNamespace>KeyboardManagerEditorLibraryWrapper</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>NotSet</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<AllProjectBMIsArePublic>true</AllProjectBMIsArePublic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<AllProjectBMIsArePublic>true</AllProjectBMIsArePublic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;KEYBOARDMANAGEREDITORLIBRARYWRAPPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;KEYBOARDMANAGEREDITORLIBRARYWRAPPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;KEYBOARDMANAGEREDITORLIBRARYWRAPPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;KEYBOARDMANAGEREDITORLIBRARYWRAPPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<CompileAsWinRT>false</CompileAsWinRT>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;KEYBOARDMANAGEREDITORLIBRARYWRAPPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<SupportJustMyCode>true</SupportJustMyCode>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
<AdditionalLibraryDirectories>$(SolutionDir)$(Platform)\$(ConfigurationName);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;KEYBOARDMANAGEREDITORLIBRARYWRAPPER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>false</ConformanceMode>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>./;$(SolutionDir)src\modules\;$(SolutionDir)src\modules\KeyboardManager\KeyboardManagerEditorLibrary\;$(SolutionDir)src\common\Display;$(SolutionDir)src\common\inc;$(SolutionDir)src\common\Telemetry;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h" />
|
||||
<ClInclude Include="KeyboardManagerEditorLibraryWrapper.h" />
|
||||
<ClInclude Include="pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp" />
|
||||
<ClCompile Include="KeyboardManagerEditorLibraryWrapper.cpp" />
|
||||
<ClCompile Include="pch.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
|
||||
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\common\KeyboardManagerCommon.vcxproj">
|
||||
<Project>{8affa899-0b73-49ec-8c50-0fadda57b2fc}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\KeyboardManagerEditorLibrary\KeyboardManagerEditorLibrary.vcxproj">
|
||||
<Project>{23d2070d-e4ad-4add-85a7-083d9c76ad49}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="..\..\..\..\deps\spdlog.props" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" />
|
||||
</ImportGroup>
|
||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
||||
<PropertyGroup>
|
||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
||||
</PropertyGroup>
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.240111.5\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="framework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyboardManagerEditorLibraryWrapper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardManagerEditorLibraryWrapper.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,19 @@
|
||||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "pch.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files
|
||||
#include <windows.h>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.Windows.CppWinRT" version="2.0.240111.5" targetFramework="native" />
|
||||
</packages>
|
||||
@@ -0,0 +1,5 @@
|
||||
// pch.cpp: source file corresponding to the pre-compiled header
|
||||
|
||||
#include "pch.h"
|
||||
|
||||
// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
|
||||
@@ -0,0 +1,18 @@
|
||||
// pch.h: This is a precompiled header file.
|
||||
// Files listed below are compiled only once, improving build performance for future builds.
|
||||
// This also affects IntelliSense performance, including code completion and many code browsing features.
|
||||
// However, files listed here are ALL re-compiled if any one of them is updated between builds.
|
||||
// Do not add files here that you will be updating frequently as this negates the performance advantage.
|
||||
|
||||
#ifndef PCH_H
|
||||
#define PCH_H
|
||||
|
||||
// add headers that you want to pre-compile here
|
||||
#include "framework.h"
|
||||
#include <winrt/base.h>
|
||||
#include "../KeyboardManagerEditorLibrary/LoadingAndSavingRemappingHelper.h"
|
||||
|
||||
#include <common/logger/logger.h>
|
||||
#include <common/utils/resources.h>
|
||||
|
||||
#endif //PCH_H
|
||||
16
src/modules/keyboardmanager/KeyboardManagerEditorUI/App.xaml
Normal file
16
src/modules/keyboardmanager/KeyboardManagerEditorUI/App.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Application
|
||||
x:Class="KeyboardManagerEditorUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:KeyboardManagerEditorUI">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<!-- Other app resources here -->
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -0,0 +1,55 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.UI.Xaml.Shapes;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
namespace KeyboardManagerEditorUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
Logger.InitializeLogger("\\Keyboard Manager\\WinUI3Editor\\Logs");
|
||||
Logger.LogInfo("keyboard-manager WinUI3 editor logger is initialized");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched.
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
|
||||
{
|
||||
window = new MainWindow();
|
||||
window.Activate();
|
||||
Logger.LogInfo("keyboard-manager WinUI3 editor window is launched");
|
||||
}
|
||||
|
||||
private Window? window;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="..\..\..\Common.Dotnet.CsWinRT.props" />
|
||||
<Import Project="..\..\..\Common.SelfContained.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>KeyboardManagerEditorUI</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
<Nullable>enable</Nullable>
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<AssemblyName>PowerToys.KeyboardManagerEditorUI</AssemblyName>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\$(MSBuildProjectName)</OutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored.
|
||||
-->
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\..\settings-ui\Settings.UI.Library\Settings.UI.Library.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
|
||||
Explorer "Package and Publish" context menu entry to be enabled for this project even if
|
||||
the Windows App SDK Nuget package has not yet been restored.
|
||||
-->
|
||||
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Window
|
||||
x:Class="KeyboardManagerEditorUI.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:KeyboardManagerEditorUI"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="KeyboardManagerEditorUI"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal">
|
||||
<Button x:Name="myButton" Click="MyButton_Click">Click Me</Button>
|
||||
</StackPanel>
|
||||
</Window>
|
||||
@@ -0,0 +1,42 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
|
||||
namespace KeyboardManagerEditorUI
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainWindow : Window
|
||||
{
|
||||
[DllImport("KeyboardManagerEditorLibraryWrapper.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern bool CheckIfRemappingsAreValid();
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void MyButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Call the C++ function to check if the current remappings are valid
|
||||
myButton.Content = CheckIfRemappingsAreValid() ? "Valid" : "Invalid";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity
|
||||
Name="edb1d2cd-ef93-4f89-9db6-4edf04ff20a5"
|
||||
Publisher="CN=haoliuu"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="edb1d2cd-ef93-4f89-9db6-4edf04ff20a5" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>KeyboardManagerEditorUI</DisplayName>
|
||||
<PublisherDisplayName>haoliuu</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="KeyboardManagerEditorUI"
|
||||
Description="KeyboardManagerEditorUI"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="KeyboardManagerEditorUI.app"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
|
||||
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
|
||||
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||
@@ -341,5 +341,92 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.UnitTests
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("rad(30)", "(180 / pi) * (30)")]
|
||||
[DataRow("rad( 30 )", "(180 / pi) * ( 30 )")]
|
||||
[DataRow("deg(30)", "(30)")]
|
||||
[DataRow("grad(30)", "(9 / 10) * (30)")]
|
||||
[DataRow("rad( 30)", "(180 / pi) * ( 30)")]
|
||||
[DataRow("rad(30 )", "(180 / pi) * (30 )")]
|
||||
[DataRow("rad( 30 )", "(180 / pi) * ( 30 )")]
|
||||
[DataRow("rad(deg(30))", "(180 / pi) * ((30))")]
|
||||
[DataRow("deg(rad(30))", "((180 / pi) * (30))")]
|
||||
[DataRow("grad(rad(30))", "(9 / 10) * ((180 / pi) * (30))")]
|
||||
[DataRow("rad(grad(30))", "(180 / pi) * ((9 / 10) * (30))")]
|
||||
[DataRow("rad(30) + deg(45)", "(180 / pi) * (30) + (45)")]
|
||||
[DataRow("sin(rad(30))", "sin((180 / pi) * (30))")]
|
||||
[DataRow("cos( rad( 45 ) )", "cos( (180 / pi) * ( 45 ) )")]
|
||||
[DataRow("tan(rad(grad(90)))", "tan((180 / pi) * ((9 / 10) * (90)))")]
|
||||
[DataRow("rad(30) + rad(45)", "(180 / pi) * (30) + (180 / pi) * (45)")]
|
||||
[DataRow("rad(30) * grad(90)", "(180 / pi) * (30) * (9 / 10) * (90)")]
|
||||
[DataRow("rad(30)/rad(45)", "(180 / pi) * (30)/(180 / pi) * (45)")]
|
||||
public void ExpandTrigConversions_Degrees(string input, string expectedResult)
|
||||
{
|
||||
// Call ExpandTrigConversions in degrees mode
|
||||
string result = CalculateHelper.ExpandTrigConversions(input, CalculateEngine.TrigMode.Degrees);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("rad(30)", "(30)")]
|
||||
[DataRow("rad( 30 )", "( 30 )")]
|
||||
[DataRow("deg(30)", "(pi / 180) * (30)")]
|
||||
[DataRow("grad(30)", "(pi / 200) * (30)")]
|
||||
[DataRow("rad( 30)", "( 30)")]
|
||||
[DataRow("rad(30 )", "(30 )")]
|
||||
[DataRow("rad( 30 )", "( 30 )")]
|
||||
[DataRow("rad(deg(30))", "((pi / 180) * (30))")]
|
||||
[DataRow("deg(rad(30))", "(pi / 180) * ((30))")]
|
||||
[DataRow("grad(rad(30))", "(pi / 200) * ((30))")]
|
||||
[DataRow("rad(grad(30))", "((pi / 200) * (30))")]
|
||||
[DataRow("rad(30) + deg(45)", "(30) + (pi / 180) * (45)")]
|
||||
[DataRow("sin(rad(30))", "sin((30))")]
|
||||
[DataRow("cos( rad( 45 ) )", "cos( ( 45 ) )")]
|
||||
[DataRow("tan(rad(grad(90)))", "tan(((pi / 200) * (90)))")]
|
||||
[DataRow("rad(30) + rad(45)", "(30) + (45)")]
|
||||
[DataRow("rad(30) * grad(90)", "(30) * (pi / 200) * (90)")]
|
||||
[DataRow("rad(30)/rad(45)", "(30)/(45)")]
|
||||
public void ExpandTrigConversions_Radians(string input, string expectedResult)
|
||||
{
|
||||
// Call ExpandTrigConversions in radians mode
|
||||
string result = CalculateHelper.ExpandTrigConversions(input, CalculateEngine.TrigMode.Radians);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("rad(30)", "(200 / pi) * (30)")]
|
||||
[DataRow("rad( 30 )", "(200 / pi) * ( 30 )")]
|
||||
[DataRow("deg(30)", "(10 / 9) * (30)")]
|
||||
[DataRow("grad(30)", "(30)")]
|
||||
[DataRow("rad( 30)", "(200 / pi) * ( 30)")]
|
||||
[DataRow("rad(30 )", "(200 / pi) * (30 )")]
|
||||
[DataRow("rad( 30 )", "(200 / pi) * ( 30 )")]
|
||||
[DataRow("rad(deg(30))", "(200 / pi) * ((10 / 9) * (30))")]
|
||||
[DataRow("deg(rad(30))", "(10 / 9) * ((200 / pi) * (30))")]
|
||||
[DataRow("grad(rad(30))", "((200 / pi) * (30))")]
|
||||
[DataRow("rad(grad(30))", "(200 / pi) * ((30))")]
|
||||
[DataRow("rad(30) + deg(45)", "(200 / pi) * (30) + (10 / 9) * (45)")]
|
||||
[DataRow("sin(rad(30))", "sin((200 / pi) * (30))")]
|
||||
[DataRow("cos( rad( 45 ) )", "cos( (200 / pi) * ( 45 ) )")]
|
||||
[DataRow("tan(rad(grad(90)))", "tan((200 / pi) * ((90)))")]
|
||||
[DataRow("rad(30) + rad(45)", "(200 / pi) * (30) + (200 / pi) * (45)")]
|
||||
[DataRow("rad(30) * grad(90)", "(200 / pi) * (30) * (90)")]
|
||||
[DataRow("rad(30)/rad(45)", "(200 / pi) * (30)/(200 / pi) * (45)")]
|
||||
public void ExpandTrigConversions_Gradians(string input, string expectedResult)
|
||||
{
|
||||
// Call ExpandTrigConversions in gradians mode
|
||||
string result = CalculateHelper.ExpandTrigConversions(input, CalculateEngine.TrigMode.Gradians);
|
||||
|
||||
// Assert
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(expectedResult, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator.UnitTests
|
||||
[DataRow("5,2+6", "5.2+6")]
|
||||
[DataRow("round(2,5)", "round(2.5)")]
|
||||
[DataRow("3,3333", "3.3333")]
|
||||
[DataRow("max(2;3)", "max(2,3)")]
|
||||
public void Translate_NoErrors_WhenCalled(string input, string expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -59,8 +59,14 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
|
||||
input = CalculateHelper.FixHumanMultiplicationExpressions(input);
|
||||
|
||||
// Get the user selected trigonometry unit
|
||||
TrigMode trigMode = Main.GetTrigMode();
|
||||
|
||||
// Modify trig functions depending on angle unit setting
|
||||
input = CalculateHelper.UpdateTrigFunctions(input, Main.GetTrigMode());
|
||||
input = CalculateHelper.UpdateTrigFunctions(input, trigMode);
|
||||
|
||||
// Expand conversions between trig units
|
||||
input = CalculateHelper.ExpandTrigConversions(input, trigMode);
|
||||
|
||||
var result = _magesEngine.Interpret(input);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using static Microsoft.PowerToys.Run.Plugin.Calculator.CalculateEngine;
|
||||
|
||||
namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
{
|
||||
@@ -18,6 +19,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
@"factorial\s*\(|sign\s*\(|round\s*\(|rand\s*\(\)|randi\s*\([^\)]|" +
|
||||
@"sin\s*\(|cos\s*\(|tan\s*\(|arcsin\s*\(|arccos\s*\(|arctan\s*\(|" +
|
||||
@"sinh\s*\(|cosh\s*\(|tanh\s*\(|arsinh\s*\(|arcosh\s*\(|artanh\s*\(|" +
|
||||
@"rad\s*\(|deg\s*\(|grad\s*\(|" + /* trigonometry unit conversion macros */
|
||||
@"pi|" +
|
||||
@"==|~=|&&|\|\||" +
|
||||
@"((-?(\d+(\.\d*)?)|-?(\.\d+))[Ee](-?\d+))|" + /* expression from CheckScientificNotation between parenthesis */
|
||||
@@ -26,7 +28,9 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
RegexOptions.Compiled);
|
||||
|
||||
private const string DegToRad = "(pi / 180) * ";
|
||||
private const string DegToGrad = "(10 / 9) * ";
|
||||
private const string GradToRad = "(pi / 200) * ";
|
||||
private const string GradToDeg = "(9 / 10) * ";
|
||||
private const string RadToDeg = "(180 / pi) * ";
|
||||
private const string RadToGrad = "(200 / pi) * ";
|
||||
|
||||
@@ -266,10 +270,10 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
return input;
|
||||
}
|
||||
|
||||
public static string UpdateTrigFunctions(string input, CalculateEngine.TrigMode mode)
|
||||
public static string UpdateTrigFunctions(string input, TrigMode mode)
|
||||
{
|
||||
string modifiedInput = input;
|
||||
if (mode == CalculateEngine.TrigMode.Degrees)
|
||||
if (mode == TrigMode.Degrees)
|
||||
{
|
||||
modifiedInput = ModifyTrigFunction(modifiedInput, "sin", DegToRad);
|
||||
modifiedInput = ModifyTrigFunction(modifiedInput, "cos", DegToRad);
|
||||
@@ -278,7 +282,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
modifiedInput = ModifyTrigFunction(modifiedInput, "arccos", RadToDeg);
|
||||
modifiedInput = ModifyTrigFunction(modifiedInput, "arctan", RadToDeg);
|
||||
}
|
||||
else if (mode == CalculateEngine.TrigMode.Gradians)
|
||||
else if (mode == TrigMode.Gradians)
|
||||
{
|
||||
modifiedInput = ModifyTrigFunction(modifiedInput, "sin", GradToRad);
|
||||
modifiedInput = ModifyTrigFunction(modifiedInput, "cos", GradToRad);
|
||||
@@ -290,5 +294,39 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
|
||||
return modifiedInput;
|
||||
}
|
||||
|
||||
private static string ModifyMathFunction(string input, string function, string modification)
|
||||
{
|
||||
// Create the pattern to match the function, opening bracket, and any spaces in between
|
||||
string pattern = $@"{function}\s*\(";
|
||||
return Regex.Replace(input, pattern, modification + "(");
|
||||
}
|
||||
|
||||
public static string ExpandTrigConversions(string input, TrigMode mode)
|
||||
{
|
||||
string modifiedInput = input;
|
||||
|
||||
// Expand "rad", "deg" and "grad" to their respective conversions for the current trig unit
|
||||
if (mode == TrigMode.Radians)
|
||||
{
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "deg", DegToRad);
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "grad", GradToRad);
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "rad", string.Empty);
|
||||
}
|
||||
else if (mode == TrigMode.Degrees)
|
||||
{
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "deg", string.Empty);
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "grad", GradToDeg);
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "rad", RadToDeg);
|
||||
}
|
||||
else if (mode == TrigMode.Gradians)
|
||||
{
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "deg", DegToGrad);
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "grad", string.Empty);
|
||||
modifiedInput = ModifyMathFunction(modifiedInput, "rad", RadToGrad);
|
||||
}
|
||||
|
||||
return modifiedInput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace Microsoft.PowerToys.Run.Plugin.Calculator
|
||||
outputBuilder.Append(
|
||||
decimal.TryParse(token, NumberStyles.Number, cultureFrom, out number)
|
||||
? (new string('0', leadingZeroCount) + number.ToString(cultureTo))
|
||||
: token);
|
||||
: token.Replace(cultureFrom.TextInfo.ListSeparator, cultureTo.TextInfo.ListSeparator));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,72 +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 System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace PowerLauncher.Helper
|
||||
{
|
||||
public static class ThemeExtensions
|
||||
{
|
||||
public static Theme GetCurrentTheme()
|
||||
{
|
||||
// Check for high-contrast mode
|
||||
Theme highContrastTheme = GetHighContrastBaseType();
|
||||
if (highContrastTheme != Theme.Light)
|
||||
{
|
||||
return highContrastTheme;
|
||||
}
|
||||
|
||||
// Check if the system is using dark or light mode
|
||||
return IsSystemDarkMode() ? Theme.Dark : Theme.Light;
|
||||
}
|
||||
|
||||
private static bool IsSystemDarkMode()
|
||||
{
|
||||
const string registryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
|
||||
const string registryValue = "AppsUseLightTheme";
|
||||
|
||||
// Retrieve the registry value, which is a DWORD (0 or 1)
|
||||
object registryValueObj = Registry.GetValue(registryKey, registryValue, null);
|
||||
if (registryValueObj != null)
|
||||
{
|
||||
// 0 = Dark mode, 1 = Light mode
|
||||
bool isLightMode = Convert.ToBoolean((int)registryValueObj, CultureInfo.InvariantCulture);
|
||||
return !isLightMode; // Invert because 0 = Dark
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default to Light theme if the registry key is missing
|
||||
return false; // Default to dark mode assumption
|
||||
}
|
||||
}
|
||||
|
||||
public static Theme GetHighContrastBaseType()
|
||||
{
|
||||
const string registryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes";
|
||||
const string registryValue = "CurrentTheme";
|
||||
|
||||
string themePath = (string)Registry.GetValue(registryKey, registryValue, string.Empty);
|
||||
if (string.IsNullOrEmpty(themePath))
|
||||
{
|
||||
return Theme.Light; // Default to light theme if missing
|
||||
}
|
||||
|
||||
string theme = themePath.Split('\\').Last().Split('.').First().ToLowerInvariant();
|
||||
|
||||
return theme switch
|
||||
{
|
||||
"hc1" => Theme.HighContrastOne,
|
||||
"hc2" => Theme.HighContrastTwo,
|
||||
"hcwhite" => Theme.HighContrastWhite,
|
||||
"hcblack" => Theme.HighContrastBlack,
|
||||
_ => Theme.Light,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
137
src/modules/launcher/PowerLauncher/Helper/ThemeHelper.cs
Normal file
137
src/modules/launcher/PowerLauncher/Helper/ThemeHelper.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ManagedCommon;
|
||||
using PowerLauncher.Services;
|
||||
|
||||
[assembly: InternalsVisibleTo("Wox.Test")]
|
||||
|
||||
namespace PowerLauncher.Helper;
|
||||
|
||||
/// <summary>
|
||||
/// Provides functionality for determining the application's theme based on system settings, user
|
||||
/// preferences, and High Contrast mode detection.
|
||||
/// </summary>
|
||||
public class ThemeHelper
|
||||
{
|
||||
private const string ThemesKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes";
|
||||
private const string PersonalizeKey = ThemesKey + "\\Personalize";
|
||||
|
||||
internal const int AppsUseLightThemeLight = 1;
|
||||
internal const int AppsUseLightThemeDark = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Default value for the "AppsUseLightTheme" registry setting. This value represents Light
|
||||
/// mode and will be used if the registry value is invalid or cannot be read.
|
||||
/// </summary>
|
||||
internal const int AppsUseLightThemeDefault = AppsUseLightThemeLight;
|
||||
|
||||
private readonly IRegistryService _registryService;
|
||||
|
||||
private readonly Dictionary<string, Theme> _highContrastThemeMap =
|
||||
new(StringComparer.InvariantCultureIgnoreCase)
|
||||
{
|
||||
{ "hc1", Theme.HighContrastOne },
|
||||
{ "hc2", Theme.HighContrastTwo },
|
||||
{ "hcwhite", Theme.HighContrastWhite },
|
||||
{ "hcblack", Theme.HighContrastBlack },
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ThemeHelper"/> class.
|
||||
/// </summary>
|
||||
/// <param name="registryService">The service used to query registry values. If <c>null</c>, a
|
||||
/// default implementation is used, which queries the Windows registry. This allows for
|
||||
/// dependency injection and unit testing.</param>
|
||||
public ThemeHelper(IRegistryService registryService = null)
|
||||
{
|
||||
_registryService = registryService ?? RegistryServiceFactory.Create();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines the theme to apply, prioritizing an active High Contrast theme.
|
||||
/// </summary>
|
||||
/// <param name="settingsTheme">The theme selected in application settings.</param>
|
||||
/// <returns>The resolved <see cref="Theme"/> based on the following priority order:
|
||||
/// 1. If a default High Contrast Windows theme is active, return the corresponding High
|
||||
/// Contrast <see cref="Theme"/>.
|
||||
/// 2. If "Windows default" is selected in application settings, return the Windows app theme
|
||||
/// (<see cref="Theme.Dark"/> or <see cref="Theme.Light"/>).
|
||||
/// 3. If the user explicitly selected "Light" or "Dark", return their chosen theme.
|
||||
/// 4. If the theme cannot be determined, return <see cref="Theme.Light"/>.
|
||||
/// </returns>
|
||||
public Theme DetermineTheme(Theme settingsTheme) =>
|
||||
GetHighContrastTheme() ??
|
||||
(settingsTheme == Theme.System ? GetAppsTheme() : ValidateTheme(settingsTheme));
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the provided <see cref="Theme"/> value is valid.
|
||||
/// </summary>
|
||||
/// <param name="theme">The <see cref="Theme"/> value to validate.</param>
|
||||
/// <returns>The provided theme if it is a defined enum value; otherwise, defaults to
|
||||
/// <see cref="Theme.Light"/>.
|
||||
private Theme ValidateTheme(Theme theme) => Enum.IsDefined(theme) ? theme : Theme.Light;
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a High Contrast theme is currently active and returns the corresponding
|
||||
/// <see cref="Theme"/>.
|
||||
/// </summary>
|
||||
/// <returns>The detected High Contrast <see cref="Theme"/> (e.g.
|
||||
/// <see cref="Theme.HighContrastOne"/>, or <c>null</c> if no recognized High Contrast theme
|
||||
/// is active.
|
||||
/// </returns>
|
||||
internal Theme? GetHighContrastTheme()
|
||||
{
|
||||
try
|
||||
{
|
||||
var themePath = Convert.ToString(
|
||||
_registryService.GetValue(ThemesKey, "CurrentTheme", string.Empty),
|
||||
CultureInfo.InvariantCulture);
|
||||
|
||||
if (!string.IsNullOrEmpty(themePath) && _highContrastThemeMap.TryGetValue(
|
||||
Path.GetFileNameWithoutExtension(themePath), out var theme))
|
||||
{
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Fall through to return null. Ignore exception.
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the Windows app theme preference from the registry.
|
||||
/// </summary>
|
||||
/// <returns><see cref="Theme.Dark"/> if the user has selected Dark mode for apps,
|
||||
/// <see cref="Theme.Light"/> otherwise. If the registry value cannot be read or is invalid,
|
||||
/// the default value (<see cref="Theme.Light"/>) is used.
|
||||
/// </returns>
|
||||
internal Theme GetAppsTheme()
|
||||
{
|
||||
try
|
||||
{
|
||||
// "AppsUseLightTheme" registry value:
|
||||
// - 0 = Dark mode
|
||||
// - 1 (or missing/invalid) = Light mode
|
||||
var regValue = _registryService.GetValue(
|
||||
PersonalizeKey,
|
||||
"AppsUseLightTheme",
|
||||
AppsUseLightThemeDefault);
|
||||
|
||||
return regValue is int intValue && intValue == 0 ? Theme.Dark : Theme.Light;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Theme.Light;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using ManagedCommon;
|
||||
@@ -17,10 +17,11 @@ namespace PowerLauncher.Helper
|
||||
{
|
||||
private readonly PowerToysRunSettings _settings;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private ManagedCommon.Theme _currentTheme;
|
||||
private readonly ThemeHelper _themeHelper = new();
|
||||
|
||||
private bool _disposed;
|
||||
|
||||
public ManagedCommon.Theme CurrentTheme => _currentTheme;
|
||||
public Theme CurrentTheme { get; private set; }
|
||||
|
||||
public event Common.UI.ThemeChangedHandler ThemeChanged;
|
||||
|
||||
@@ -40,23 +41,25 @@ namespace PowerLauncher.Helper
|
||||
}
|
||||
}
|
||||
|
||||
private void SetSystemTheme(ManagedCommon.Theme theme)
|
||||
private void SetSystemTheme(Theme theme)
|
||||
{
|
||||
_mainWindow.Background = OSVersionHelper.IsWindows11() is false ? SystemColors.WindowBrush : null;
|
||||
_mainWindow.Background = !OSVersionHelper.IsWindows11() ? SystemColors.WindowBrush : null;
|
||||
|
||||
// Need to disable WPF0001 since setting Application.Current.ThemeMode is experimental
|
||||
// https://learn.microsoft.com/en-us/dotnet/desktop/wpf/whats-new/net90#set-in-code
|
||||
#pragma warning disable WPF0001
|
||||
Application.Current.ThemeMode = theme is ManagedCommon.Theme.Light ? ThemeMode.Light : ThemeMode.Dark;
|
||||
if (theme is ManagedCommon.Theme.Dark or ManagedCommon.Theme.Light)
|
||||
Application.Current.ThemeMode = theme == Theme.Light ? ThemeMode.Light : ThemeMode.Dark;
|
||||
#pragma warning restore WPF0001
|
||||
|
||||
if (theme is Theme.Dark or Theme.Light)
|
||||
{
|
||||
if (!OSVersionHelper.IsWindows11())
|
||||
{
|
||||
// Apply background only on Windows 10
|
||||
// Windows theme does not work properly for dark and light mode so right now set the background color manual.
|
||||
// Windows theme does not work properly for dark and light mode so right now set the background color manually.
|
||||
_mainWindow.Background = new SolidColorBrush
|
||||
{
|
||||
Color = theme is ManagedCommon.Theme.Dark ? (Color)ColorConverter.ConvertFromString("#202020") : (Color)ColorConverter.ConvertFromString("#fafafa"),
|
||||
Color = (Color)ColorConverter.ConvertFromString(theme == Theme.Dark ? "#202020" : "#fafafa"),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -64,49 +67,46 @@ namespace PowerLauncher.Helper
|
||||
{
|
||||
string styleThemeString = theme switch
|
||||
{
|
||||
ManagedCommon.Theme.Light => "Themes/Light.xaml",
|
||||
ManagedCommon.Theme.Dark => "Themes/Dark.xaml",
|
||||
ManagedCommon.Theme.HighContrastOne => "Themes/HighContrast1.xaml",
|
||||
ManagedCommon.Theme.HighContrastTwo => "Themes/HighContrast2.xaml",
|
||||
ManagedCommon.Theme.HighContrastWhite => "Themes/HighContrastWhite.xaml",
|
||||
_ => "Themes/HighContrastBlack.xaml",
|
||||
Theme.HighContrastOne => "Themes/HighContrast1.xaml",
|
||||
Theme.HighContrastTwo => "Themes/HighContrast2.xaml",
|
||||
Theme.HighContrastWhite => "Themes/HighContrastWhite.xaml",
|
||||
Theme.HighContrastBlack => "Themes/HighContrastBlack.xaml",
|
||||
_ => "Themes/Light.xaml",
|
||||
};
|
||||
|
||||
_mainWindow.Resources.MergedDictionaries.Clear();
|
||||
_mainWindow.Resources.MergedDictionaries.Add(new ResourceDictionary
|
||||
{
|
||||
Source = new Uri(styleThemeString, UriKind.Relative),
|
||||
});
|
||||
ResourceDictionary test = new ResourceDictionary
|
||||
{
|
||||
Source = new Uri(styleThemeString, UriKind.Relative),
|
||||
};
|
||||
|
||||
if (OSVersionHelper.IsWindows11())
|
||||
{
|
||||
// Apply background only on Windows 11 to keep the same style as WPFUI
|
||||
_mainWindow.Background = new SolidColorBrush
|
||||
{
|
||||
Color = (Color)_mainWindow.FindResource("LauncherBackgroundColor"), // Use your DynamicResource key here
|
||||
Color = (Color)_mainWindow.FindResource("LauncherBackgroundColor"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
ImageLoader.UpdateIconPath(theme);
|
||||
ThemeChanged?.Invoke(_currentTheme, theme);
|
||||
_currentTheme = theme;
|
||||
ThemeChanged?.Invoke(CurrentTheme, theme);
|
||||
CurrentTheme = theme;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the application's theme based on system settings and user preferences.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This considers:
|
||||
/// - Whether a High Contrast theme is active in Windows.
|
||||
/// - The system-wide app mode preference (Light or Dark).
|
||||
/// - The user's preference override for Light or Dark mode in the application settings.
|
||||
/// </remarks>
|
||||
public void UpdateTheme()
|
||||
{
|
||||
ManagedCommon.Theme newTheme = _settings.Theme;
|
||||
ManagedCommon.Theme theme = ThemeExtensions.GetHighContrastBaseType();
|
||||
if (theme != ManagedCommon.Theme.Light)
|
||||
{
|
||||
newTheme = theme;
|
||||
}
|
||||
else if (_settings.Theme == ManagedCommon.Theme.System)
|
||||
{
|
||||
newTheme = ThemeExtensions.GetCurrentTheme();
|
||||
}
|
||||
Theme newTheme = _themeHelper.DetermineTheme(_settings.Theme);
|
||||
|
||||
_mainWindow.Dispatcher.Invoke(() =>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// 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 Microsoft.Win32;
|
||||
|
||||
namespace PowerLauncher.Services;
|
||||
|
||||
#nullable enable
|
||||
|
||||
/// <summary>
|
||||
/// Provides methods for interacting with the Windows Registry or an equivalent key-value data
|
||||
/// store.
|
||||
/// </summary>
|
||||
public interface IRegistryService
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the value associated with the specified name, in the specified registry key.
|
||||
/// If the name is not found in the specified key, returns the specified default value, or
|
||||
/// <c>null</c> if the specified key does not exist.
|
||||
/// </summary>
|
||||
/// <param name="keyName">The full registry path of the key, beginning with a valid registry
|
||||
/// root, such as "HKEY_CURRENT_USER".</param>
|
||||
/// <param name="valueName">The name of the name/value pair.</param>
|
||||
/// <param name="defaultValue">The value to return if <see cref="valueName"/> does not exist.
|
||||
/// </param>
|
||||
/// <returns><c>null</c> if the subkey specified by <paramref name="keyName"/> does not exist;
|
||||
/// otherwise, the value associated with <paramref name="valueName"/>, or
|
||||
/// <paramref name="defaultValue"/> if <paramref name="valueName"/> is not found.</returns>
|
||||
/// <exception cref="ArgumentException"><paramref name="keyName"/> does not begin with a valid
|
||||
/// registry root.</exception>
|
||||
/// <exception cref="UnauthorizedAccessException">Thrown if access to the registry or
|
||||
/// equivalent store is denied.</exception>
|
||||
/// <remarks>Implementations may throw additional exceptions depending on their internal
|
||||
/// storage mechanism.</remarks>
|
||||
object? GetValue(string keyName, string? valueName, object? defaultValue);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the specified name/value pair on the specified registry key. If the specified key does
|
||||
/// not exist, it is created.
|
||||
/// </summary>
|
||||
/// <param name="keyName">The full registry path of the key, beginning with a valid registry
|
||||
/// root, such as "HKEY_CURRENT_USER".</param>
|
||||
/// <param name="valueName">The name of the name/value pair.</param>
|
||||
/// <param name="value">The value to be stored.</param>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="keyName"/> does not begin with a valid registry root.
|
||||
///
|
||||
/// -or-
|
||||
///
|
||||
/// <paramref name="keyName"> is longer than the maximum length allowed (255 characters).
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">Access to the key is denied; for example,
|
||||
/// it is a root-level node, or the key has not been opened with write access.</exception>
|
||||
void SetValue(string keyName, string? valueName, object value);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the specified name/value pair on the specified registry key. If the specified key does
|
||||
/// not exist, it is created.
|
||||
/// </summary>
|
||||
/// <param name="keyName">The full registry path of the key, beginning with a valid registry
|
||||
/// root, such as "HKEY_CURRENT_USER".</param>
|
||||
/// <param name="valueName">The name of the name/value pair.</param>
|
||||
/// <param name="value">The value to be stored.</param>
|
||||
/// <param name="valueKind">The registry data type to use when storing the data.</param>
|
||||
/// <exception cref="ArgumentException">
|
||||
/// <paramref name="keyName"/> does not begin with a valid registry root.
|
||||
///
|
||||
/// -or-
|
||||
///
|
||||
/// <paramref name="keyName"> is longer than the maximum length allowed (255 characters).
|
||||
///
|
||||
/// -or-
|
||||
///
|
||||
/// The type of <paramref name="value"/> did not match the registry data type specified by
|
||||
/// <paramref name="valueKind"/>, therefore the data could not be converted properly.
|
||||
/// </exception>
|
||||
/// <exception cref="UnauthorizedAccessException">Access to the key is denied; for example,
|
||||
/// it is a root-level node, or the key has not been opened with write access.</exception>
|
||||
void SetValue(string keyName, string? valueName, object value, RegistryValueKind valueKind);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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.IO;
|
||||
using System.Security;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace PowerLauncher.Services;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class RegistryService : IRegistryService
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
/// <exception cref="SecurityException">The user does not have the permissions required to read
|
||||
/// from the registry key.</exception>
|
||||
/// <exception cref="IOException">The <see cref="RegistryKey"/> that contains the specified
|
||||
/// value has been marked for deletion.</exception>
|
||||
public object? GetValue(string keyName, string? valueName, object? defaultValue) =>
|
||||
Registry.GetValue(keyName, valueName, defaultValue);
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <exception cref="SecurityException">The user does not have the permissions required to
|
||||
/// create or modify registry keys.</exception>"
|
||||
public void SetValue(string keyName, string? valueName, object value) =>
|
||||
Registry.SetValue(keyName, valueName, value);
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <exception cref="SecurityException">The user does not have the permissions required to
|
||||
/// create or modify registry keys.</exception>
|
||||
public void SetValue(string keyName, string? valueName, object value, RegistryValueKind valueKind) =>
|
||||
Registry.SetValue(keyName, valueName, value, valueKind);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// 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 PowerLauncher.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating instances of <see cref="IRegistryService"/>.
|
||||
/// </summary>
|
||||
public static class RegistryServiceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the default implementation of <see cref="IRegistryService"/>.
|
||||
/// </summary>
|
||||
/// <returns>An instance of the default <see cref="IRegistryService"/> implementation.</returns>
|
||||
public static IRegistryService Create() => new RegistryService();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user