mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
New color picker module - integrated from github.com/martinchrzan/Col… (#4778)
* New color picker module - integrated from github.com/martinchrzan/ColorPicker * Trying to fix build in github * Replaced icon in the settings to use font icon instead of path icon * Closing ColorPicker.exe when PowerToys process closed, added color picker project into runner dependencies, restoring cursors on exit, added ManagedCommon as a dependency into installer * User/ryanbod/fix colorpicker release (#5046) * Changing configuration to x64 instead of AnyCPU. The previous configuration was preventing the ManagedCommon binary from being loaded in Release. * Updating MSI Installer with new icons (#4998) * Adding missed dll into installer * Fixed potential exception * Creating settings.json on the first start when there are none, fixed default keyboard shortcut * Added ColorPicker.exe.config into installer * Start filewatcher after default settings file is created * Fixing build Co-authored-by: ryanbodrug-microsoft <56318517+ryanbodrug-microsoft@users.noreply.github.com>
This commit is contained in:
@@ -15,6 +15,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner
|
|||||||
{0485F45C-EA7A-4BB5-804B-3E8D14699387} = {0485F45C-EA7A-4BB5-804B-3E8D14699387}
|
{0485F45C-EA7A-4BB5-804B-3E8D14699387} = {0485F45C-EA7A-4BB5-804B-3E8D14699387}
|
||||||
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D} = {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}
|
{D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D} = {D29DDD63-E2CF-4657-9FD5-2AEDE4257E5D}
|
||||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481} = {5CCC8468-DEC8-4D36-99D4-5C891BEBD481}
|
||||||
|
{BA58206B-1493-4C75-BFEA-A85768A1E156} = {BA58206B-1493-4C75-BFEA-A85768A1E156}
|
||||||
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
|
{0B593A6C-4143-4337-860E-DB5710FB87DB} = {0B593A6C-4143-4337-860E-DB5710FB87DB}
|
||||||
{E364F67B-BB12-4E91-B639-355866EBCD8B} = {E364F67B-BB12-4E91-B639-355866EBCD8B}
|
{E364F67B-BB12-4E91-B639-355866EBCD8B} = {E364F67B-BB12-4E91-B639-355866EBCD8B}
|
||||||
{DA425894-6E13-404F-8DCB-78584EC0557A} = {DA425894-6E13-404F-8DCB-78584EC0557A}
|
{DA425894-6E13-404F-8DCB-78584EC0557A} = {DA425894-6E13-404F-8DCB-78584EC0557A}
|
||||||
@@ -28,6 +29,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "runner", "src\runner\runner
|
|||||||
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
{17DA04DF-E393-4397-9CF0-84DABE11032E} = {17DA04DF-E393-4397-9CF0-84DABE11032E}
|
||||||
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
|
{F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99} = {F9C68EDF-AC74-4B77-9AF1-005D9C9F6A99}
|
||||||
{07C389E3-6BC8-41CF-923E-307B1265FA2D} = {07C389E3-6BC8-41CF-923E-307B1265FA2D}
|
{07C389E3-6BC8-41CF-923E-307B1265FA2D} = {07C389E3-6BC8-41CF-923E-307B1265FA2D}
|
||||||
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA} = {655C9AF2-18D3-4DA6-80E4-85504A7722BA}
|
||||||
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9} = {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}
|
{89F34AF7-1C34-4A72-AA6E-534BCF972BD9} = {89F34AF7-1C34-4A72-AA6E-534BCF972BD9}
|
||||||
{E6410BFC-B341-498C-8C67-312C20CDD8D5} = {E6410BFC-B341-498C-8C67-312C20CDD8D5}
|
{E6410BFC-B341-498C-8C67-312C20CDD8D5} = {E6410BFC-B341-498C-8C67-312C20CDD8D5}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
@@ -255,6 +257,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "KeyboardManagerTest", "src\
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ManagedCommon", "src\common\ManagedCommon\ManagedCommon.csproj", "{4AED67B6-55FD-486F-B917-E543DEE2CB3C}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ManagedCommon", "src\common\ManagedCommon\ManagedCommon.csproj", "{4AED67B6-55FD-486F-B917-E543DEE2CB3C}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ColorPicker", "src\modules\colorPicker\ColorPicker\ColorPicker.vcxproj", "{655C9AF2-18D3-4DA6-80E4-85504A7722BA}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorPickerUI", "src\modules\colorPicker\ColorPickerUI\ColorPickerUI.csproj", "{BA58206B-1493-4C75-BFEA-A85768A1E156}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "colorpicker", "colorpicker", "{1D78B84B-CA39-406C-98F4-71F7EC266CC0}"
|
||||||
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Plugin.Program.UnitTests", "src\modules\launcher\Plugins\Microsoft.Plugin.Program.UnitTests\Microsoft.Plugin.Program.UnitTests.csproj", "{42851751-CBC8-45A6-97F5-7A0753F7B4D1}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Plugin.Program.UnitTests", "src\modules\launcher\Plugins\Microsoft.Plugin.Program.UnitTests\Microsoft.Plugin.Program.UnitTests.csproj", "{42851751-CBC8-45A6-97F5-7A0753F7B4D1}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
@@ -503,6 +511,14 @@ Global
|
|||||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.Build.0 = Debug|x64
|
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Debug|x64.Build.0 = Debug|x64
|
||||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.ActiveCfg = Release|x64
|
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.ActiveCfg = Release|x64
|
||||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.Build.0 = Release|x64
|
{4AED67B6-55FD-486F-B917-E543DEE2CB3C}.Release|x64.Build.0 = Release|x64
|
||||||
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA}.Release|x64.Build.0 = Release|x64
|
||||||
|
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{BA58206B-1493-4C75-BFEA-A85768A1E156}.Release|x64.Build.0 = Release|x64
|
||||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.ActiveCfg = Debug|x64
|
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.Build.0 = Debug|x64
|
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Debug|x64.Build.0 = Debug|x64
|
||||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.ActiveCfg = Release|x64
|
{42851751-CBC8-45A6-97F5-7A0753F7B4D1}.Release|x64.ActiveCfg = Release|x64
|
||||||
@@ -577,6 +593,9 @@ Global
|
|||||||
{E6410BFC-B341-498C-8C67-312C20CDD8D5} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
{E6410BFC-B341-498C-8C67-312C20CDD8D5} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||||
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
{62173D9A-6724-4C00-A1C8-FB646480A9EC} = {38BDB927-829B-4C65-9CD9-93FB05D66D65}
|
||||||
{4AED67B6-55FD-486F-B917-E543DEE2CB3C} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
{4AED67B6-55FD-486F-B917-E543DEE2CB3C} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||||
|
{655C9AF2-18D3-4DA6-80E4-85504A7722BA} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
|
||||||
|
{BA58206B-1493-4C75-BFEA-A85768A1E156} = {1D78B84B-CA39-406C-98F4-71F7EC266CC0}
|
||||||
|
{1D78B84B-CA39-406C-98F4-71F7EC266CC0} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||||
{42851751-CBC8-45A6-97F5-7A0753F7B4D1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
{42851751-CBC8-45A6-97F5-7A0753F7B4D1} = {4AFC9975-2456-4C70-94A4-84073C1CED93}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<?define KeyboardManagerProjectName="KeyboardManager"?>
|
<?define KeyboardManagerProjectName="KeyboardManager"?>
|
||||||
<?define PowerRenameProjectName="PowerRename"?>
|
<?define PowerRenameProjectName="PowerRename"?>
|
||||||
<?define ShortcutGuideProjectName="ShortcutGuide"?>
|
<?define ShortcutGuideProjectName="ShortcutGuide"?>
|
||||||
|
<?define ColorPickerProjectName="ColorPicker"?>
|
||||||
|
|
||||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||||
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
<?define BinX64Dir="$(var.RepoDir)x64\$(var.Configuration)\" ?>
|
||||||
@@ -241,6 +242,9 @@
|
|||||||
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
<Directory Id="FileExplorerPreviewInstallFolder" Name="FileExplorerPreview" />
|
||||||
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
<Directory Id="FancyZonesInstallFolder" Name="$(var.FancyZonesProjectName)" />
|
||||||
<Directory Id="KeyboardManagerInstallFolder" Name="$(var.KeyboardManagerProjectName)" />
|
<Directory Id="KeyboardManagerInstallFolder" Name="$(var.KeyboardManagerProjectName)" />
|
||||||
|
<Directory Id="ColorPickerInstallFolder" Name="$(var.ColorPickerProjectName)">
|
||||||
|
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
|
||||||
|
</Directory>
|
||||||
<Directory Id="LauncherInstallFolder" Name="launcher">
|
<Directory Id="LauncherInstallFolder" Name="launcher">
|
||||||
<Directory Id="AssetsFolder" Name="Assets" />
|
<Directory Id="AssetsFolder" Name="Assets" />
|
||||||
<Directory Id="LauncherImagesFolder" Name="Images" />
|
<Directory Id="LauncherImagesFolder" Name="Images" />
|
||||||
@@ -583,6 +587,22 @@
|
|||||||
</Component>
|
</Component>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
|
|
||||||
|
<DirectoryRef Id="ColorPickerInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)">
|
||||||
|
<Component Id="Module_ColorPicker" Guid="8A52A69E-37B2-4BEA-9D73-77763066052F" Win64="yes">
|
||||||
|
<?foreach File in ColorPicker.dll;ColorPicker.exe;ColorPicker.exe.config;Microsoft.Bcl.AsyncInterfaces.dll;Microsoft.Expression.Interactions.dll;Microsoft.PowerToys.Settings.UI.Lib.dll;PowerToysInterop.dll;System.Buffers.dll;System.Memory.dll;System.Numerics.Vectors.dll;System.Text.Encodings.Web.dll;System.Text.Json.dll;System.Threading.Tasks.Extensions.dll;System.ValueTuple.dll;System.Windows.Interactivity.dll;Telemetry.dll;ManagedCommon.dll;System.Runtime.CompilerServices.Unsafe.dll?>
|
||||||
|
<File Id="ColorPickerFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)\$(var.File)" />
|
||||||
|
<?endforeach?>
|
||||||
|
</Component>
|
||||||
|
</DirectoryRef>
|
||||||
|
|
||||||
|
<DirectoryRef Id="ColorPickerResourcesFolder" FileSource="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)\Resources">
|
||||||
|
<Component Id="Module_ColorPicker_Resources" Guid="7544BD0F-1DB6-4C53-89D3-ADAD472FDCC1">
|
||||||
|
<?foreach File in colorPicker.cur;icon.ico?>
|
||||||
|
<File Id="ColorPickerFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.ColorPickerProjectName)\Resources\$(var.File)" />
|
||||||
|
<?endforeach?>
|
||||||
|
</Component>
|
||||||
|
</DirectoryRef>
|
||||||
|
|
||||||
<DirectoryRef Id="FileExplorerPreviewInstallFolder" FileSource="$(var.RepoDir)\modules\FileExplorerPreview\">
|
<DirectoryRef Id="FileExplorerPreviewInstallFolder" FileSource="$(var.RepoDir)\modules\FileExplorerPreview\">
|
||||||
<Component Id="Module_PowerPreview" Guid="FF1700D5-1B07-4E07-9A62-4D206645EEA9" Win64="yes">
|
<Component Id="Module_PowerPreview" Guid="FF1700D5-1B07-4E07-9A62-4D206645EEA9" Win64="yes">
|
||||||
<!-- Component to include PowerPreview Module Source dll's -->
|
<!-- Component to include PowerPreview Module Source dll's -->
|
||||||
@@ -741,6 +761,8 @@
|
|||||||
<ComponentRef Id="Module_PowerPreview" />
|
<ComponentRef Id="Module_PowerPreview" />
|
||||||
<ComponentRef Id="Module_PowerPreview_PerUserRegistry" />
|
<ComponentRef Id="Module_PowerPreview_PerUserRegistry" />
|
||||||
<ComponentRef Id="Module_KeyboardManager" />
|
<ComponentRef Id="Module_KeyboardManager" />
|
||||||
|
<ComponentRef Id="Module_ColorPicker" />
|
||||||
|
<ComponentRef Id="Module_ColorPicker_Resources"/>
|
||||||
<ComponentRef Id="SettingsV2" />
|
<ComponentRef Id="SettingsV2" />
|
||||||
<ComponentRef Id="SettingsV2Assets" />
|
<ComponentRef Id="SettingsV2Assets" />
|
||||||
<ComponentRef Id="SettingsV2Controls" />
|
<ComponentRef Id="SettingsV2Controls" />
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||||
|
{
|
||||||
|
public enum ColorRepresentationType
|
||||||
|
{
|
||||||
|
HEX = 0,
|
||||||
|
RGB = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ColorPickerProperties
|
||||||
|
{
|
||||||
|
public ColorPickerProperties()
|
||||||
|
{
|
||||||
|
ActivationShortcut = new HotkeySettings(false, true, false, false, "Break", 3);
|
||||||
|
ChangeCursor = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeySettings ActivationShortcut { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("changecursor")]
|
||||||
|
[JsonConverter(typeof(BoolPropertyJsonConverter))]
|
||||||
|
public bool ChangeCursor { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("copiedcolorrepresentation")]
|
||||||
|
public ColorRepresentationType CopiedColorRepresentation { get; set; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return JsonSerializer.Serialize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Lib
|
||||||
|
{
|
||||||
|
public class ColorPickerSettings : BasePTModuleSettings
|
||||||
|
{
|
||||||
|
public const string ModuleName = "ColorPicker";
|
||||||
|
|
||||||
|
public ColorPickerProperties properties { get; set; }
|
||||||
|
|
||||||
|
public ColorPickerSettings()
|
||||||
|
{
|
||||||
|
properties = new ColorPickerProperties();
|
||||||
|
version = "1";
|
||||||
|
name = ModuleName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToJsonString()
|
||||||
|
{
|
||||||
|
return JsonSerializer.Serialize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Save()
|
||||||
|
{
|
||||||
|
// Save settings to file
|
||||||
|
var options = new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
SettingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,6 +96,7 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
|
|||||||
}
|
}
|
||||||
|
|
||||||
private bool keyboardManager = true;
|
private bool keyboardManager = true;
|
||||||
|
|
||||||
[JsonPropertyName("Keyboard Manager")]
|
[JsonPropertyName("Keyboard Manager")]
|
||||||
public bool KeyboardManager
|
public bool KeyboardManager
|
||||||
{
|
{
|
||||||
@@ -124,7 +125,23 @@ namespace Microsoft.PowerToys.Settings.UI.Lib
|
|||||||
this.powerLauncher = value;
|
this.powerLauncher = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool colorPicker = true;
|
||||||
|
|
||||||
|
[JsonPropertyName("ColorPicker")]
|
||||||
|
public bool ColorPicker
|
||||||
|
{
|
||||||
|
get => this.colorPicker;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (this.colorPicker != value)
|
||||||
|
{
|
||||||
|
LogTelemetryEvent(value);
|
||||||
|
this.colorPicker = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string ToJsonString()
|
public string ToJsonString()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -111,6 +111,7 @@
|
|||||||
<Compile Include="Helpers\ResourceExtensions.cs" />
|
<Compile Include="Helpers\ResourceExtensions.cs" />
|
||||||
<Compile Include="Services\ActivationService.cs" />
|
<Compile Include="Services\ActivationService.cs" />
|
||||||
<Compile Include="Services\NavigationService.cs" />
|
<Compile Include="Services\NavigationService.cs" />
|
||||||
|
<Compile Include="ViewModels\ColorPickerViewModel.cs" />
|
||||||
<Compile Include="ViewModels\Commands\ButtonClickCommand.cs" />
|
<Compile Include="ViewModels\Commands\ButtonClickCommand.cs" />
|
||||||
<Compile Include="ViewModels\GeneralViewModel.cs" />
|
<Compile Include="ViewModels\GeneralViewModel.cs" />
|
||||||
<Compile Include="ViewModels\FancyZonesViewModel.cs" />
|
<Compile Include="ViewModels\FancyZonesViewModel.cs" />
|
||||||
@@ -121,6 +122,9 @@
|
|||||||
<Compile Include="ViewModels\PowerLauncherViewModel.cs" />
|
<Compile Include="ViewModels\PowerLauncherViewModel.cs" />
|
||||||
<Compile Include="ViewModels\ShellViewModel.cs" />
|
<Compile Include="ViewModels\ShellViewModel.cs" />
|
||||||
<Compile Include="ViewModels\ShortcutGuideViewModel.cs" />
|
<Compile Include="ViewModels\ShortcutGuideViewModel.cs" />
|
||||||
|
<Compile Include="Views\ColorPickerPage.xaml.cs">
|
||||||
|
<DependentUpon>ColorPickerPage.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Views\GeneralPage.xaml.cs">
|
<Compile Include="Views\GeneralPage.xaml.cs">
|
||||||
<DependentUpon>GeneralPage.xaml</DependentUpon>
|
<DependentUpon>GeneralPage.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -241,6 +245,10 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Views\ColorPickerPage.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Views\GeneralPage.xaml">
|
<Page Include="Views\GeneralPage.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|||||||
@@ -157,6 +157,10 @@
|
|||||||
<value>Image Resizer</value>
|
<value>Image Resizer</value>
|
||||||
<comment>Navigation view item name for Image Resizer</comment>
|
<comment>Navigation view item name for Image Resizer</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Shell_ColorPicker.Content" xml:space="preserve">
|
||||||
|
<value>Color Picker</value>
|
||||||
|
<comment>Navigation view item name for Color Picker</comment>
|
||||||
|
</data>
|
||||||
<data name="Shell_KeyboardManager.Content" xml:space="preserve">
|
<data name="Shell_KeyboardManager.Content" xml:space="preserve">
|
||||||
<value>Keyboard Manager</value>
|
<value>Keyboard Manager</value>
|
||||||
<comment>Navigation view item name for Keyboard Manager</comment>
|
<comment>Navigation view item name for Keyboard Manager</comment>
|
||||||
@@ -193,6 +197,21 @@
|
|||||||
<value>Remap shortcuts</value>
|
<value>Remap shortcuts</value>
|
||||||
<comment>Keyboard Manager remap shortcuts header</comment>
|
<comment>Keyboard Manager remap shortcuts header</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ColorPicker_Description.Text" xml:space="preserve">
|
||||||
|
<value>Quick and simple system-wide color picker</value>
|
||||||
|
</data>
|
||||||
|
<data name="ColorPicker_EnableColorPicker.Header" xml:space="preserve">
|
||||||
|
<value>Enable Color Picker</value>
|
||||||
|
</data>
|
||||||
|
<data name="ColorPicker_ChangeCursor.Header" xml:space="preserve">
|
||||||
|
<value>Change cursor when picking a color</value>
|
||||||
|
</data>
|
||||||
|
<data name="ColorPicker_CopiedColorRepresentation.Header" xml:space="preserve">
|
||||||
|
<value>Copied color representation</value>
|
||||||
|
</data>
|
||||||
|
<data name="ColorPicker_ActivationShortcut.Header" xml:space="preserve">
|
||||||
|
<value>Activation shortcut</value>
|
||||||
|
</data>
|
||||||
<data name="PowerLauncher_Description.Text" xml:space="preserve">
|
<data name="PowerLauncher_Description.Text" xml:space="preserve">
|
||||||
<value>A quick launcher that has additional capabilities without sacrificing performance.</value>
|
<value>A quick launcher that has additional capabilities without sacrificing performance.</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -569,6 +588,9 @@
|
|||||||
<data name="About_KeyboardManager.Text" xml:space="preserve">
|
<data name="About_KeyboardManager.Text" xml:space="preserve">
|
||||||
<value>About Keyboard Manager</value>
|
<value>About Keyboard Manager</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="About_ColorPicker.Text" xml:space="preserve">
|
||||||
|
<value>About Color Picker</value>
|
||||||
|
</data>
|
||||||
<data name="About_PowerLauncher.Text" xml:space="preserve">
|
<data name="About_PowerLauncher.Text" xml:space="preserve">
|
||||||
<value>About PowerToys Run</value>
|
<value>About PowerToys Run</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Views;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
||||||
|
{
|
||||||
|
public class ColorPickerViewModel : Observable
|
||||||
|
{
|
||||||
|
private ColorPickerSettings _colorPickerSettings;
|
||||||
|
private bool _isEnabled;
|
||||||
|
|
||||||
|
public ColorPickerViewModel()
|
||||||
|
{
|
||||||
|
if (SettingsUtils.SettingsExists(ColorPickerSettings.ModuleName))
|
||||||
|
{
|
||||||
|
_colorPickerSettings = SettingsUtils.GetSettings<ColorPickerSettings>(ColorPickerSettings.ModuleName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_colorPickerSettings = new ColorPickerSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SettingsUtils.SettingsExists())
|
||||||
|
{
|
||||||
|
var generalSettings = SettingsUtils.GetSettings<GeneralSettings>();
|
||||||
|
_isEnabled = generalSettings.Enabled.ColorPicker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabled
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _isEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_isEnabled != value)
|
||||||
|
{
|
||||||
|
_isEnabled = value;
|
||||||
|
OnPropertyChanged(nameof(IsEnabled));
|
||||||
|
|
||||||
|
// grab the latest version of settings
|
||||||
|
var generalSettings = SettingsUtils.GetSettings<GeneralSettings>();
|
||||||
|
generalSettings.Enabled.ColorPicker = value;
|
||||||
|
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettings);
|
||||||
|
ShellPage.DefaultSndMSGCallback(outgoing.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ChangeCursor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _colorPickerSettings.properties.ChangeCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_colorPickerSettings.properties.ChangeCursor != value)
|
||||||
|
{
|
||||||
|
_colorPickerSettings.properties.ChangeCursor = value;
|
||||||
|
OnPropertyChanged(nameof(ChangeCursor));
|
||||||
|
NotifySettingsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public HotkeySettings ActivationShortcut
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _colorPickerSettings.properties.ActivationShortcut;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_colorPickerSettings.properties.ActivationShortcut != value)
|
||||||
|
{
|
||||||
|
_colorPickerSettings.properties.ActivationShortcut = value;
|
||||||
|
OnPropertyChanged(nameof(ActivationShortcut));
|
||||||
|
NotifySettingsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CopiedColorRepresentationIndex
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (int)_colorPickerSettings.properties.CopiedColorRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_colorPickerSettings.properties.CopiedColorRepresentation != (ColorRepresentationType)value)
|
||||||
|
{
|
||||||
|
_colorPickerSettings.properties.CopiedColorRepresentation = (ColorRepresentationType)value;
|
||||||
|
OnPropertyChanged(nameof(CopiedColorRepresentationIndex));
|
||||||
|
NotifySettingsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void NotifySettingsChanged()
|
||||||
|
{
|
||||||
|
ShellPage.DefaultSndMSGCallback(
|
||||||
|
string.Format("{{ \"powertoys\": {{ \"{0}\": {1} }} }}", ColorPickerSettings.ModuleName, JsonSerializer.Serialize(_colorPickerSettings)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
<Page
|
||||||
|
x:Class="Microsoft.PowerToys.Settings.UI.Views.ColorPickerPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="using:Microsoft.PowerToys.Settings.UI.Views"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Custom="using:Microsoft.PowerToys.Settings.UI.Controls"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="300"
|
||||||
|
d:DesignWidth="400"
|
||||||
|
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
|
||||||
|
<Grid ColumnSpacing="{StaticResource DefaultColumnSpacing}" RowSpacing="{StaticResource DefaultRowSpacing}">
|
||||||
|
<VisualStateManager.VisualStateGroups>
|
||||||
|
<VisualStateGroup x:Name="LayoutVisualStates">
|
||||||
|
<VisualState x:Name="WideLayout">
|
||||||
|
<VisualState.StateTriggers>
|
||||||
|
<AdaptiveTrigger MinWindowWidth="{StaticResource WideLayoutMinWidth}" />
|
||||||
|
</VisualState.StateTriggers>
|
||||||
|
<VisualState.Setters>
|
||||||
|
<Setter Target="SidePanel.(Grid.Column)" Value="1" />
|
||||||
|
<Setter Target="SidePanel.(Grid.Row)" Value="0" />
|
||||||
|
<Setter Target="SidePanel.Width" Value="{StaticResource SidePanelWidth}" />
|
||||||
|
</VisualState.Setters>
|
||||||
|
</VisualState>
|
||||||
|
<VisualState x:Name="SmallLayout">
|
||||||
|
<VisualState.StateTriggers>
|
||||||
|
<AdaptiveTrigger MinWindowWidth="{StaticResource SmallLayoutMinWidth}" />
|
||||||
|
</VisualState.StateTriggers>
|
||||||
|
<VisualState.Setters>
|
||||||
|
<Setter Target="SidePanel.(Grid.Column)" Value="0" />
|
||||||
|
<Setter Target="SidePanel.(Grid.Row)" Value="1" />
|
||||||
|
<Setter Target="SidePanel.Width" Value="Auto" />
|
||||||
|
</VisualState.Setters>
|
||||||
|
</VisualState>
|
||||||
|
</VisualStateGroup>
|
||||||
|
</VisualStateManager.VisualStateGroups>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<TextBlock x:Uid="ColorPicker_Description"
|
||||||
|
TextWrapping="Wrap"/>
|
||||||
|
|
||||||
|
<ToggleSwitch x:Uid="ColorPicker_EnableColorPicker"
|
||||||
|
IsOn="{Binding IsEnabled, Mode=TwoWay}"
|
||||||
|
Margin="{StaticResource MediumTopMargin}"/>
|
||||||
|
|
||||||
|
<Custom:HotkeySettingsControl x:Uid="ColorPicker_ActivationShortcut"
|
||||||
|
Width="240"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Margin="{StaticResource SmallTopMargin}"
|
||||||
|
HotkeySettings="{x:Bind Path=ViewModel.ActivationShortcut, Mode=TwoWay}"
|
||||||
|
IsEnabled="{Binding IsEnabled}"/>
|
||||||
|
|
||||||
|
<ComboBox x:Uid="ColorPicker_CopiedColorRepresentation"
|
||||||
|
SelectedIndex="{Binding CopiedColorRepresentationIndex, Mode=TwoWay}"
|
||||||
|
Width="240"
|
||||||
|
Margin="{StaticResource SmallTopMargin}"
|
||||||
|
IsEnabled="{Binding IsEnabled}">
|
||||||
|
<ComboBoxItem Content="HEX - #FFAA00"/>
|
||||||
|
<ComboBoxItem Content="RGB - RGB(100, 50, 75)"/>
|
||||||
|
</ComboBox>
|
||||||
|
|
||||||
|
<ToggleSwitch x:Uid="ColorPicker_ChangeCursor"
|
||||||
|
IsOn="{Binding ChangeCursor, Mode=TwoWay}"
|
||||||
|
Margin="{StaticResource MediumTopMargin}"
|
||||||
|
IsEnabled="{Binding IsEnabled}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel
|
||||||
|
x:Name="SidePanel"
|
||||||
|
Orientation="Vertical"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Width="{StaticResource SidePanelWidth}"
|
||||||
|
Grid.Column="1">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
x:Uid="About_ColorPicker"
|
||||||
|
Style="{StaticResource SettingsGroupTitleStyle}"
|
||||||
|
Margin="{StaticResource XSmallBottomMargin}"/>
|
||||||
|
|
||||||
|
<HyperlinkButton NavigateUri="https://aka.ms/PowerToysOverview_ColorPicker">
|
||||||
|
<TextBlock x:Uid="Module_overview" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
|
||||||
|
<HyperlinkButton NavigateUri="https://github.com/microsoft/PowerToys/issues">
|
||||||
|
<TextBlock x:Uid="Give_Feedback" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
x:Uid="AttributionTitle"
|
||||||
|
Style="{StaticResource SettingsGroupTitleStyle}" />
|
||||||
|
|
||||||
|
<HyperlinkButton
|
||||||
|
NavigateUri="https://github.com/martinchrzan/ColorPicker/">
|
||||||
|
<TextBlock Text="Martin Chrzan's Color Picker" TextWrapping="Wrap" />
|
||||||
|
</HyperlinkButton>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Page>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||||
|
using Windows.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||||
|
{
|
||||||
|
public sealed partial class ColorPickerPage : Page
|
||||||
|
{
|
||||||
|
public ColorPickerViewModel ViewModel { get; set; }
|
||||||
|
|
||||||
|
public ColorPickerPage()
|
||||||
|
{
|
||||||
|
ViewModel = new ColorPickerViewModel();
|
||||||
|
DataContext = ViewModel;
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,6 +94,12 @@
|
|||||||
</winui:NavigationViewItem.Icon>
|
</winui:NavigationViewItem.Icon>
|
||||||
</winui:NavigationViewItem>
|
</winui:NavigationViewItem>
|
||||||
|
|
||||||
|
<winui:NavigationViewItem x:Uid="Shell_ColorPicker" helpers:NavHelper.NavigateTo="views:ColorPickerPage">
|
||||||
|
<winui:NavigationViewItem.Icon>
|
||||||
|
<FontIcon Glyph=""/>
|
||||||
|
</winui:NavigationViewItem.Icon>
|
||||||
|
</winui:NavigationViewItem>
|
||||||
|
|
||||||
</winui:NavigationView.MenuItems>
|
</winui:NavigationView.MenuItems>
|
||||||
<i:Interaction.Behaviors>
|
<i:Interaction.Behaviors>
|
||||||
<behaviors:NavigationViewHeaderBehavior
|
<behaviors:NavigationViewHeaderBehavior
|
||||||
|
|||||||
@@ -159,6 +159,7 @@
|
|||||||
<Compile Include="Generated Files\AssemblyInfo.cs">
|
<Compile Include="Generated Files\AssemblyInfo.cs">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="ViewModelTests\ColorPicker.cs" />
|
||||||
<Compile Include="ViewModelTests\FancyZones.cs" />
|
<Compile Include="ViewModelTests\FancyZones.cs" />
|
||||||
<Compile Include="ViewModelTests\General.cs" />
|
<Compile Include="ViewModelTests\General.cs" />
|
||||||
<Compile Include="ModelsTests\HelperTest.cs" />
|
<Compile Include="ModelsTests\HelperTest.cs" />
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Views;
|
||||||
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
|
namespace ViewModelTests
|
||||||
|
{
|
||||||
|
[TestClass]
|
||||||
|
public class ColorPicker
|
||||||
|
{
|
||||||
|
private const string ModuleName = "ColorPicker";
|
||||||
|
|
||||||
|
[TestInitialize]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
var generalSettings = new GeneralSettings();
|
||||||
|
var colorPickerSettings = new ColorPickerSettings();
|
||||||
|
|
||||||
|
SettingsUtils.SaveSettings(generalSettings.ToJsonString());
|
||||||
|
SettingsUtils.SaveSettings(colorPickerSettings.ToJsonString(), colorPickerSettings.name, ModuleName + ".json");
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCleanup]
|
||||||
|
public void CleanUp()
|
||||||
|
{
|
||||||
|
string generalSettings_file_name = string.Empty;
|
||||||
|
if (SettingsUtils.SettingsFolderExists(generalSettings_file_name))
|
||||||
|
{
|
||||||
|
DeleteFolder(generalSettings_file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SettingsUtils.SettingsFolderExists(ModuleName))
|
||||||
|
{
|
||||||
|
DeleteFolder(ModuleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void ColorPickerIsEnabledByDefault()
|
||||||
|
{
|
||||||
|
var viewModel = new ColorPickerViewModel();
|
||||||
|
|
||||||
|
ShellPage.DefaultSndMSGCallback = msg =>
|
||||||
|
{
|
||||||
|
OutGoingGeneralSettings snd = JsonSerializer.Deserialize<OutGoingGeneralSettings>(msg);
|
||||||
|
Assert.IsTrue(snd.GeneralSettings.Enabled.ColorPicker);
|
||||||
|
};
|
||||||
|
|
||||||
|
Assert.IsTrue(viewModel.IsEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void DeleteFolder(string powertoy)
|
||||||
|
{
|
||||||
|
Directory.Delete(Path.Combine(SettingsUtils.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -80,7 +80,6 @@ namespace ViewModelTests
|
|||||||
|
|
||||||
viewModel.OpenPowerLauncher = openPowerLauncher;
|
viewModel.OpenPowerLauncher = openPowerLauncher;
|
||||||
viewModel.OpenFileLocation = openFileLocation;
|
viewModel.OpenFileLocation = openFileLocation;
|
||||||
viewModel.OpenConsole = openConsole;
|
|
||||||
viewModel.CopyPathLocation = copyFileLocation;
|
viewModel.CopyPathLocation = copyFileLocation;
|
||||||
|
|
||||||
Assert.AreEqual(4, sendCallbackMock.TimesSent);
|
Assert.AreEqual(4, sendCallbackMock.TimesSent);
|
||||||
|
|||||||
130
src/modules/colorPicker/ColorPicker/ColorPicker.vcxproj
Normal file
130
src/modules/colorPicker/ColorPicker/ColorPicker.vcxproj
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<?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.200514.2\build\native\Microsoft.Windows.CppWinRT.props" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200514.2\build\native\Microsoft.Windows.CppWinRT.props')" />
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<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>15.0</VCProjectVersion>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<ProjectGuid>{655c9af2-18d3-4da6-80e4-85504a7722ba}</ProjectGuid>
|
||||||
|
<RootNamespace>ColorPicker</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>10.0.17134.0</WindowsTargetPlatformVersion>
|
||||||
|
<ProjectName>ColorPicker</ProjectName>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v142</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
<SpectreMitigation>Spectre</SpectreMitigation>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</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 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>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\$(ProjectName)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
<OutDir>$(SolutionDir)$(Platform)\$(Configuration)\modules\$(ProjectName)\</OutDir>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;EXAMPLEPOWERTOY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<SDLCheck>true</SDLCheck>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;COLORPICKER_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
<AdditionalIncludeDirectories>..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;..\..\..\..\deps\cpprestsdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
|
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||||
|
<LanguageStandard>stdcpplatest</LanguageStandard>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Windows</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(CIBuild)'!='true'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||||
|
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="pch.h" />
|
||||||
|
<ClInclude Include="trace.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="dllmain.cpp" />
|
||||||
|
<ClCompile Include="pch.cpp">
|
||||||
|
<PrecompiledHeader Condition="'$(CIBuild)'!='true'">Create</PrecompiledHeader>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="trace.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\common.vcxproj">
|
||||||
|
<Project>{74485049-c722-400f-abe5-86ac52d929b3}</Project>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
<Import Project="..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200514.2\build\native\Microsoft.Windows.CppWinRT.targets" Condition="Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200514.2\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.200514.2\build\native\Microsoft.Windows.CppWinRT.props')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200514.2\build\native\Microsoft.Windows.CppWinRT.props'))" />
|
||||||
|
<Error Condition="!Exists('..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200514.2\build\native\Microsoft.Windows.CppWinRT.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\..\packages\Microsoft.Windows.CppWinRT.2.0.200514.2\build\native\Microsoft.Windows.CppWinRT.targets'))" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<?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++;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="pch.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="trace.h">
|
||||||
|
<Filter>Source 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="trace.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
188
src/modules/colorPicker/ColorPicker/dllmain.cpp
Normal file
188
src/modules/colorPicker/ColorPicker/dllmain.cpp
Normal file
@@ -0,0 +1,188 @@
|
|||||||
|
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||||
|
#include "pch.h"
|
||||||
|
#include <common/common.h>
|
||||||
|
#include <interface/powertoy_module_interface.h>
|
||||||
|
#include "trace.h"
|
||||||
|
#include <common\settings_objects.h>
|
||||||
|
#include <common\os-detection\os-detect.h>
|
||||||
|
|
||||||
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
|
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||||
|
DWORD ul_reason_for_call,
|
||||||
|
LPVOID lpReserved
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (ul_reason_for_call)
|
||||||
|
{
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
Trace::RegisterProvider();
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
case DLL_PROCESS_DETACH:
|
||||||
|
Trace::UnregisterProvider();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModuleSettings{
|
||||||
|
} g_settings;
|
||||||
|
|
||||||
|
class ColorPicker : public PowertoyModuleIface
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
bool m_enabled = false;
|
||||||
|
|
||||||
|
std::wstring app_name;
|
||||||
|
|
||||||
|
HANDLE m_hProcess;
|
||||||
|
|
||||||
|
// Time to wait for process to close after sending WM_CLOSE signal
|
||||||
|
static const int MAX_WAIT_MILLISEC = 10000;
|
||||||
|
public:
|
||||||
|
ColorPicker()
|
||||||
|
{
|
||||||
|
app_name = L"ColorPicker";
|
||||||
|
}
|
||||||
|
|
||||||
|
~ColorPicker()
|
||||||
|
{
|
||||||
|
if (m_enabled)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
m_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the powertoy and free memory
|
||||||
|
virtual void destroy() override
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the display name of the powertoy, this will be cached by the runner
|
||||||
|
virtual const wchar_t* get_name() override
|
||||||
|
{
|
||||||
|
return app_name.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const wchar_t** get_events() override
|
||||||
|
{
|
||||||
|
static const wchar_t* events[] = { nullptr };
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool get_config(wchar_t* buffer, int* buffer_size) override
|
||||||
|
{
|
||||||
|
HINSTANCE hinstance = reinterpret_cast<HINSTANCE>(&__ImageBase);
|
||||||
|
|
||||||
|
// Create a Settings object.
|
||||||
|
PowerToysSettings::Settings settings(hinstance, get_name());
|
||||||
|
settings.set_description(L"Color picker");
|
||||||
|
// settings.set_description(GET_RESOURCE_STRING(IDS_LAUNCHER_SETTINGS_DESC));
|
||||||
|
|
||||||
|
settings.set_overview_link(L"https://aka.ms/PowerToysOverview_ColorPicker");
|
||||||
|
|
||||||
|
return settings.serialize_to_buffer(buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void call_custom_action(const wchar_t* action) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_config(const wchar_t* config) override
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Parse the input JSON string.
|
||||||
|
PowerToysSettings::PowerToyValues values =
|
||||||
|
PowerToysSettings::PowerToyValues::from_json_string(config);
|
||||||
|
|
||||||
|
// If you don't need to do any custom processing of the settings, proceed
|
||||||
|
// to persists the values calling:
|
||||||
|
values.save_to_settings_file();
|
||||||
|
// Otherwise call a custom function to process the settings before saving them to disk:
|
||||||
|
// save_settings();
|
||||||
|
}
|
||||||
|
catch (std::exception ex)
|
||||||
|
{
|
||||||
|
// Improper JSON.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void enable(){
|
||||||
|
|
||||||
|
// use only with new settings?
|
||||||
|
if (UseNewSettings())
|
||||||
|
{
|
||||||
|
unsigned long powertoys_pid = GetCurrentProcessId();
|
||||||
|
|
||||||
|
std::wstring executable_args = L"";
|
||||||
|
executable_args.append(std::to_wstring(powertoys_pid));
|
||||||
|
|
||||||
|
SHELLEXECUTEINFOW sei{ sizeof(sei) };
|
||||||
|
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||||
|
sei.lpFile = L"modules\\ColorPicker\\ColorPicker.exe";
|
||||||
|
sei.nShow = SW_SHOWNORMAL;
|
||||||
|
sei.lpParameters = executable_args.data();
|
||||||
|
ShellExecuteExW(&sei);
|
||||||
|
|
||||||
|
m_hProcess = sei.hProcess;
|
||||||
|
|
||||||
|
m_enabled = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual void disable() {
|
||||||
|
if (m_enabled)
|
||||||
|
{
|
||||||
|
terminateProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool is_enabled() override
|
||||||
|
{
|
||||||
|
return m_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL CALLBACK requestMainWindowClose(HWND nextWindow, LPARAM closePid)
|
||||||
|
{
|
||||||
|
DWORD windowPid;
|
||||||
|
GetWindowThreadProcessId(nextWindow, &windowPid);
|
||||||
|
|
||||||
|
if (windowPid == (DWORD)closePid)
|
||||||
|
::PostMessage(nextWindow, WM_CLOSE, 0, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void terminateProcess()
|
||||||
|
{
|
||||||
|
DWORD processID = GetProcessId(m_hProcess);
|
||||||
|
EnumWindows(&requestMainWindowClose, processID);
|
||||||
|
const DWORD result = WaitForSingleObject(m_hProcess, MAX_WAIT_MILLISEC);
|
||||||
|
if (result == WAIT_TIMEOUT)
|
||||||
|
{
|
||||||
|
TerminateProcess(m_hProcess, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Register helper class to handle system menu items related actions. */
|
||||||
|
virtual void register_system_menu_helper(PowertoySystemMenuIface* helper) {}
|
||||||
|
/* Handle action on system menu item. */
|
||||||
|
virtual void signal_system_menu_action(const wchar_t* name) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
|
||||||
|
{
|
||||||
|
return new ColorPicker();
|
||||||
|
}
|
||||||
|
|
||||||
4
src/modules/colorPicker/ColorPicker/packages.config
Normal file
4
src/modules/colorPicker/ColorPicker/packages.config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="Microsoft.Windows.CppWinRT" version="2.0.200514.2" targetFramework="native" />
|
||||||
|
</packages>
|
||||||
4
src/modules/colorPicker/ColorPicker/pch.cpp
Normal file
4
src/modules/colorPicker/ColorPicker/pch.cpp
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#pragma comment(lib, "windowsapp")
|
||||||
|
#pragma comment(lib, "shlwapi.lib")
|
||||||
|
|
||||||
8
src/modules/colorPicker/ColorPicker/pch.h
Normal file
8
src/modules/colorPicker/ColorPicker/pch.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <winrt/Windows.Foundation.h>
|
||||||
|
#include <winrt/Windows.Foundation.Collections.h>
|
||||||
|
#include <common/common.h>
|
||||||
|
#include <ProjectTelemetry.h>
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <Shlwapi.h>
|
||||||
29
src/modules/colorPicker/ColorPicker/trace.cpp
Normal file
29
src/modules/colorPicker/ColorPicker/trace.cpp
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
#include "pch.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
TRACELOGGING_DEFINE_PROVIDER(
|
||||||
|
g_hProvider,
|
||||||
|
"Microsoft.PowerToys",
|
||||||
|
// {38e8889b-9731-53f5-e901-e8a7c1753074}
|
||||||
|
(0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
|
||||||
|
TraceLoggingOptionProjectTelemetry());
|
||||||
|
|
||||||
|
void Trace::RegisterProvider()
|
||||||
|
{
|
||||||
|
TraceLoggingRegister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::UnregisterProvider()
|
||||||
|
{
|
||||||
|
TraceLoggingUnregister(g_hProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Trace::MyEvent()
|
||||||
|
{
|
||||||
|
TraceLoggingWrite(
|
||||||
|
g_hProvider,
|
||||||
|
"PowerToyName::Event::MyEvent",
|
||||||
|
ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
|
||||||
|
TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"),
|
||||||
|
TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
|
||||||
|
}
|
||||||
8
src/modules/colorPicker/ColorPicker/trace.h
Normal file
8
src/modules/colorPicker/ColorPicker/trace.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
class Trace
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void RegisterProvider();
|
||||||
|
static void UnregisterProvider();
|
||||||
|
static void MyEvent();
|
||||||
|
};
|
||||||
6
src/modules/colorPicker/ColorPickerUI/App.config
Normal file
6
src/modules/colorPicker/ColorPickerUI/App.config
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
78
src/modules/colorPicker/ColorPickerUI/App.manifest
Normal file
78
src/modules/colorPicker/ColorPickerUI/App.manifest
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
<?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="MyApplication.app"/>
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<!-- UAC Manifest Options
|
||||||
|
If you want to change the Windows User Account Control level replace the
|
||||||
|
requestedExecutionLevel node with one of the following.
|
||||||
|
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||||
|
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||||
|
|
||||||
|
Specifying requestedExecutionLevel element will disable file and registry virtualization.
|
||||||
|
Remove this element if your application requires this virtualization for backwards
|
||||||
|
compatibility.
|
||||||
|
-->
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- A list of the Windows versions that this application has been tested on
|
||||||
|
and is designed to work with. Uncomment the appropriate elements
|
||||||
|
and Windows will automatically select the most compatible environment. -->
|
||||||
|
|
||||||
|
<!-- Windows Vista -->
|
||||||
|
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 7 -->
|
||||||
|
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 8 -->
|
||||||
|
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 8.1 -->
|
||||||
|
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||||
|
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
|
||||||
|
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
|
||||||
|
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
|
||||||
|
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
|
||||||
|
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
|
||||||
|
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
|
||||||
|
|
||||||
|
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<windowsSettings>
|
||||||
|
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||||
|
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||||
|
PerMonitor
|
||||||
|
</dpiAwareness>
|
||||||
|
</windowsSettings>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
|
||||||
|
<!--
|
||||||
|
<dependency>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity
|
||||||
|
type="win32"
|
||||||
|
name="Microsoft.Windows.Common-Controls"
|
||||||
|
version="6.0.0.0"
|
||||||
|
processorArchitecture="*"
|
||||||
|
publicKeyToken="6595b64144ccf1df"
|
||||||
|
language="*"
|
||||||
|
/>
|
||||||
|
</dependentAssembly>
|
||||||
|
</dependency>
|
||||||
|
-->
|
||||||
|
|
||||||
|
</assembly>
|
||||||
14
src/modules/colorPicker/ColorPickerUI/App.xaml
Normal file
14
src/modules/colorPicker/ColorPickerUI/App.xaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<Application x:Class="ColorPickerUI.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:ColorPickerUI"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="Resources/Styles.xaml"/>
|
||||||
|
<ResourceDictionary Source="Resources/ViewModelViewMappings.xaml"/>
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
76
src/modules/colorPicker/ColorPickerUI/App.xaml.cs
Normal file
76
src/modules/colorPicker/ColorPickerUI/App.xaml.cs
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Windows;
|
||||||
|
using ColorPicker.Helpers;
|
||||||
|
using ColorPicker.Mouse;
|
||||||
|
using ManagedCommon;
|
||||||
|
|
||||||
|
namespace ColorPickerUI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
private Mutex _instanceMutex = null;
|
||||||
|
private static string[] _args;
|
||||||
|
private int _powerToysPid;
|
||||||
|
|
||||||
|
[STAThread]
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
_args = args;
|
||||||
|
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var application = new App();
|
||||||
|
application.InitializeComponent();
|
||||||
|
application.Run();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("Unhandled exception", ex);
|
||||||
|
CursorManager.RestoreOriginalCursors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
|
{
|
||||||
|
// allow only one instance of color picker
|
||||||
|
bool createdNew;
|
||||||
|
_instanceMutex = new Mutex(true, @"Global\ColorPicker", out createdNew);
|
||||||
|
if (!createdNew)
|
||||||
|
{
|
||||||
|
_instanceMutex = null;
|
||||||
|
Application.Current.Shutdown();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_args.Length > 0)
|
||||||
|
{
|
||||||
|
_ = int.TryParse(_args[0], out _powerToysPid);
|
||||||
|
}
|
||||||
|
|
||||||
|
RunnerHelper.WaitForPowerToysRunner(_powerToysPid, () => {
|
||||||
|
Environment.Exit(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
base.OnStartup(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnExit(ExitEventArgs e)
|
||||||
|
{
|
||||||
|
if (_instanceMutex != null)
|
||||||
|
_instanceMutex.ReleaseMutex();
|
||||||
|
|
||||||
|
CursorManager.RestoreOriginalCursors();
|
||||||
|
base.OnExit(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||||
|
{
|
||||||
|
Logger.LogError("Unhandled exception", (e.ExceptionObject is Exception) ? (e.ExceptionObject as Exception) : new Exception());
|
||||||
|
CursorManager.RestoreOriginalCursors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interactivity;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
|
||||||
|
namespace ColorPicker.Behaviors
|
||||||
|
{
|
||||||
|
public class AppearAnimationBehavior : Behavior<Window>
|
||||||
|
{
|
||||||
|
protected override void OnAttached()
|
||||||
|
{
|
||||||
|
base.OnAttached();
|
||||||
|
AssociatedObject.Loaded += AssociatedObject_Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Appear();
|
||||||
|
AssociatedObject.IsVisibleChanged += AssociatedObject_IsVisibleChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssociatedObject_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (AssociatedObject.IsVisible)
|
||||||
|
{
|
||||||
|
Appear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Appear()
|
||||||
|
{
|
||||||
|
var opacityAppear = new DoubleAnimation(0, 1.0, new Duration(TimeSpan.FromMilliseconds(250)));
|
||||||
|
opacityAppear.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
|
||||||
|
|
||||||
|
var resize = new DoubleAnimation(0, 180, new Duration(TimeSpan.FromMilliseconds(250)));
|
||||||
|
resize.EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut };
|
||||||
|
AssociatedObject.BeginAnimation(Window.OpacityProperty, opacityAppear);
|
||||||
|
AssociatedObject.BeginAnimation(Window.WidthProperty, resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Hide()
|
||||||
|
{
|
||||||
|
var opacityAppear = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(1)));
|
||||||
|
var resize = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(1)));
|
||||||
|
AssociatedObject.BeginAnimation(Window.OpacityProperty, opacityAppear);
|
||||||
|
AssociatedObject.BeginAnimation(Window.WidthProperty, resize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interactivity;
|
||||||
|
using ColorPicker.Helpers;
|
||||||
|
using ColorPicker.Mouse;
|
||||||
|
|
||||||
|
namespace ColorPicker.Behaviors
|
||||||
|
{
|
||||||
|
public class ChangeWindowPositionBehavior : Behavior<Window>
|
||||||
|
{
|
||||||
|
// color window should not get into these zones, only mouse to avoid window getting outsize of monitor
|
||||||
|
private const int MonitorRightSideDeadZone = 200;
|
||||||
|
private const int MonitorBottomSideDeadZone = 100;
|
||||||
|
|
||||||
|
private const int YOffset = 10;
|
||||||
|
private const int XOffset = 5;
|
||||||
|
|
||||||
|
private Point _lastMousePosition;
|
||||||
|
|
||||||
|
protected override void OnAttached()
|
||||||
|
{
|
||||||
|
base.OnAttached();
|
||||||
|
AssociatedObject.Loaded += AssociatedObject_Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var mouseInfoProvider = Bootstrapper.Container.GetExportedValue<IMouseInfoProvider>();
|
||||||
|
|
||||||
|
SetWindowPosition(mouseInfoProvider.CurrentPosition);
|
||||||
|
mouseInfoProvider.MousePositionChanged += (s, mousePosition) =>
|
||||||
|
{
|
||||||
|
SetWindowPosition(mousePosition);
|
||||||
|
};
|
||||||
|
|
||||||
|
AssociatedObject.IsVisibleChanged += AssociatedObject_IsVisibleChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssociatedObject_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if ((bool)e.NewValue)
|
||||||
|
{
|
||||||
|
SetWindowPosition(_lastMousePosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetWindowPosition(Point mousePosition)
|
||||||
|
{
|
||||||
|
_lastMousePosition = mousePosition;
|
||||||
|
var dpi = MonitorResolutionHelper.GetCurrentMonitorDpi();
|
||||||
|
var mousePositionScaled = new Point(mousePosition.X / dpi.DpiScaleX, mousePosition.Y / dpi.DpiScaleX);
|
||||||
|
|
||||||
|
var monitorBounds = GetBoundsOfMonitorWithMouseIn(mousePosition);
|
||||||
|
|
||||||
|
var windowLeft = mousePositionScaled.X + XOffset;
|
||||||
|
var windowTop = mousePositionScaled.Y + YOffset;
|
||||||
|
|
||||||
|
if ((windowLeft + MonitorRightSideDeadZone) > monitorBounds.Right)
|
||||||
|
{
|
||||||
|
windowLeft -= MonitorRightSideDeadZone - ((int)monitorBounds.Right - windowLeft);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((windowTop + MonitorBottomSideDeadZone / dpi.DpiScaleX) > monitorBounds.Bottom / dpi.DpiScaleX)
|
||||||
|
{
|
||||||
|
windowTop -= MonitorBottomSideDeadZone / dpi.DpiScaleX - (((int)monitorBounds.Bottom / dpi.DpiScaleX - windowTop));
|
||||||
|
}
|
||||||
|
|
||||||
|
AssociatedObject.Left = windowLeft;
|
||||||
|
AssociatedObject.Top = windowTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Rect GetBoundsOfMonitorWithMouseIn(Point mousePosition)
|
||||||
|
{
|
||||||
|
foreach (var monitor in MonitorResolutionHelper.AllMonitors)
|
||||||
|
{
|
||||||
|
if (monitor.Bounds.Contains(new Point(mousePosition.X, mousePosition.Y)))
|
||||||
|
{
|
||||||
|
return monitor.Bounds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.LogWarning("Failed to get monitor bounds for mouse position" + mousePosition.X + "," + mousePosition.Y);
|
||||||
|
return new Rect(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using ColorPicker.Helpers;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interactivity;
|
||||||
|
|
||||||
|
namespace ColorPicker.Behaviors
|
||||||
|
{
|
||||||
|
public class CloseZoomWindowBehavior : Behavior<Window>
|
||||||
|
{
|
||||||
|
private ZoomWindowHelper _zoomWindowHelper;
|
||||||
|
|
||||||
|
protected override void OnAttached()
|
||||||
|
{
|
||||||
|
base.OnAttached();
|
||||||
|
AssociatedObject.Loaded += AssociatedObject_Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown;
|
||||||
|
AssociatedObject.MouseLeftButtonDown += AssociatedObject_MouseLeftButtonDown;
|
||||||
|
_zoomWindowHelper = Bootstrapper.Container.GetExportedValue<ZoomWindowHelper>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssociatedObject_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
_zoomWindowHelper.CloseZoomWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AssociatedObject_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Key == System.Windows.Input.Key.Escape)
|
||||||
|
{
|
||||||
|
_zoomWindowHelper.CloseZoomWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interactivity;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
|
||||||
|
namespace ColorPicker.Behaviors
|
||||||
|
{
|
||||||
|
public class MoveWindowBehavior : Behavior<Window>
|
||||||
|
{
|
||||||
|
public static DependencyProperty LeftProperty = DependencyProperty.Register("Left", typeof(double), typeof(MoveWindowBehavior), new PropertyMetadata(new PropertyChangedCallback(LeftPropertyChanged)));
|
||||||
|
|
||||||
|
private static void LeftPropertyChanged(DependencyObject d,
|
||||||
|
DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var sender = ((MoveWindowBehavior)d).AssociatedObject;
|
||||||
|
var move = new DoubleAnimation(sender.Left, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.Stop);
|
||||||
|
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
|
||||||
|
sender.BeginAnimation(Window.LeftProperty, move, HandoffBehavior.SnapshotAndReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DependencyProperty TopProperty = DependencyProperty.Register("Top", typeof(double), typeof(MoveWindowBehavior), new PropertyMetadata(new PropertyChangedCallback(TopPropertyChanged)));
|
||||||
|
|
||||||
|
private static void TopPropertyChanged(DependencyObject d,
|
||||||
|
DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var sender = ((MoveWindowBehavior)d).AssociatedObject;
|
||||||
|
var move = new DoubleAnimation(sender.Top, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.Stop);
|
||||||
|
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
|
||||||
|
sender.BeginAnimation(Window.TopProperty, move, HandoffBehavior.SnapshotAndReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Left
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(LeftProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(LeftProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Top
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(TopProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(TopProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Interactivity;
|
||||||
|
using System.Windows.Media.Animation;
|
||||||
|
|
||||||
|
namespace ColorPicker.Behaviors
|
||||||
|
{
|
||||||
|
public class ResizeBehavior : Behavior<FrameworkElement>
|
||||||
|
{
|
||||||
|
public static DependencyProperty WidthProperty = DependencyProperty.Register("Width", typeof(double), typeof(ResizeBehavior), new PropertyMetadata(new PropertyChangedCallback(WidthPropertyChanged)));
|
||||||
|
|
||||||
|
private static void WidthPropertyChanged(DependencyObject d,
|
||||||
|
DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var sender = ((ResizeBehavior)d).AssociatedObject;
|
||||||
|
var move = new DoubleAnimation(sender.Width, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.Stop);
|
||||||
|
move.Completed += (s, e1) => {
|
||||||
|
sender.BeginAnimation(FrameworkElement.WidthProperty, null); sender.Width = (double)e.NewValue;
|
||||||
|
};
|
||||||
|
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
|
||||||
|
sender.BeginAnimation(FrameworkElement.WidthProperty, move, HandoffBehavior.SnapshotAndReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DependencyProperty HeightProperty = DependencyProperty.Register("Height", typeof(double), typeof(ResizeBehavior), new PropertyMetadata(new PropertyChangedCallback(HeightPropertyChanged)));
|
||||||
|
|
||||||
|
private static void HeightPropertyChanged(DependencyObject d,
|
||||||
|
DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var sender = ((ResizeBehavior)d).AssociatedObject;
|
||||||
|
var move = new DoubleAnimation(sender.Height, (double)e.NewValue, new Duration(TimeSpan.FromMilliseconds(150)), FillBehavior.Stop);
|
||||||
|
move.Completed += (s, e1) => { sender.BeginAnimation(FrameworkElement.HeightProperty, null); sender.Height = (double)e.NewValue; };
|
||||||
|
move.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
|
||||||
|
sender.BeginAnimation(FrameworkElement.HeightProperty, move, HandoffBehavior.SnapshotAndReplace);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Width
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(WidthProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(WidthProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Height
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (double)GetValue(HeightProperty);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetValue(HeightProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/modules/colorPicker/ColorPickerUI/Bootstrapper.cs
Normal file
23
src/modules/colorPicker/ColorPickerUI/Bootstrapper.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.ComponentModel.Composition.Hosting;
|
||||||
|
|
||||||
|
namespace ColorPicker
|
||||||
|
{
|
||||||
|
public static class Bootstrapper
|
||||||
|
{
|
||||||
|
public static CompositionContainer Container { get; private set; }
|
||||||
|
|
||||||
|
public static void InitializeContainer(object initPoint)
|
||||||
|
{
|
||||||
|
var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly());
|
||||||
|
Container = new CompositionContainer(catalog);
|
||||||
|
|
||||||
|
Container.SatisfyImportsOnce(initPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Dispose()
|
||||||
|
{
|
||||||
|
Container.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
186
src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj
Normal file
186
src/modules/colorPicker/ColorPickerUI/ColorPickerUI.csproj
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{BA58206B-1493-4C75-BFEA-A85768A1E156}</ProjectGuid>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<RootNamespace>ColorPicker</RootNamespace>
|
||||||
|
<AssemblyName>ColorPicker</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Deterministic>true</Deterministic>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ApplicationManifest>App.manifest</ApplicationManifest>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<OutputPath>..\..\..\..\x64\Debug\modules\ColorPicker\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||||
|
<OutputPath>..\..\..\..\x64\Release\modules\ColorPicker\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.ComponentModel.Composition" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xaml">
|
||||||
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Settings\IUserSettings.cs" />
|
||||||
|
<Compile Include="Settings\SettingItem.cs" />
|
||||||
|
<Compile Include="Settings\UserSettings.cs" />
|
||||||
|
<Compile Include="Win32Apis.cs" />
|
||||||
|
<Compile Include="ZoomWindow.xaml.cs">
|
||||||
|
<DependentUpon>ZoomWindow.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Page Include="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="Bootstrapper.cs" />
|
||||||
|
<Compile Include="ViewModelContracts\IMainViewModel.cs" />
|
||||||
|
<Compile Include="ViewModelContracts\IZoomViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\MainViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\ZoomViewModel.cs" />
|
||||||
|
<Compile Include="Views\MainView.xaml.cs">
|
||||||
|
<DependentUpon>MainView.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Views\ZoomView.xaml.cs">
|
||||||
|
<DependentUpon>ZoomView.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Page Include="MainWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="App.xaml.cs">
|
||||||
|
<DependentUpon>App.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Behaviors\AppearAnimationBehavior.cs" />
|
||||||
|
<Compile Include="Behaviors\ChangeWindowPositionBehavior.cs" />
|
||||||
|
<Compile Include="Behaviors\CloseZoomWindowBehavior.cs" />
|
||||||
|
<Compile Include="Behaviors\MoveWindowBehavior.cs" />
|
||||||
|
<Compile Include="Behaviors\ResizeBehavior.cs" />
|
||||||
|
<Compile Include="Common\RelayCommand.cs" />
|
||||||
|
<Compile Include="Common\ViewModelBase.cs" />
|
||||||
|
<Compile Include="Helpers\AppStateHandler.cs" />
|
||||||
|
<Compile Include="Helpers\Logger.cs" />
|
||||||
|
<Compile Include="Helpers\MonitorResolutionHelper.cs" />
|
||||||
|
<Compile Include="Helpers\ZoomWindowHelper.cs" />
|
||||||
|
<Compile Include="Keyboard\GlobalKeyboardHook.cs" />
|
||||||
|
<Compile Include="Keyboard\GlobalKeyboardHookEventArgs.cs" />
|
||||||
|
<Compile Include="Keyboard\KeyboardMonitor.cs" />
|
||||||
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Page Include="Resources\Styles.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Resources\ViewModelViewMappings.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Views\MainView.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Views\ZoomView.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="ZoomWindow.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Mouse\CursorManager.cs" />
|
||||||
|
<Compile Include="Mouse\IMouseInfoProvider.cs" />
|
||||||
|
<Compile Include="Mouse\MouseHook.cs" />
|
||||||
|
<Compile Include="Mouse\MouseInfoProvider.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<DependentUpon>Resources.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Properties\Settings.Designer.cs">
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
|
</Compile>
|
||||||
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
<None Include="App.manifest" />
|
||||||
|
<None Include="Properties\Settings.settings">
|
||||||
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Windows.Interactivity.WPF">
|
||||||
|
<Version>2.0.20525</Version>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="Resources\colorPicker.cur">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
<None Include="Resources\icon.ico">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj">
|
||||||
|
<Project>{4AED67B6-55FD-486F-B917-E543DEE2CB3C}</Project>
|
||||||
|
<Name>ManagedCommon</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\..\core\Microsoft.PowerToys.Settings.UI.Lib\Microsoft.PowerToys.Settings.UI.Lib.csproj">
|
||||||
|
<Project>{b1bcc8c6-46b5-4bfa-8f22-20f32d99ec6a}</Project>
|
||||||
|
<Name>Microsoft.PowerToys.Settings.UI.Lib</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
||||||
36
src/modules/colorPicker/ColorPickerUI/Common/RelayCommand.cs
Normal file
36
src/modules/colorPicker/ColorPickerUI/Common/RelayCommand.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Input;
|
||||||
|
namespace ColorPicker.Common
|
||||||
|
{
|
||||||
|
public class RelayCommand : ICommand
|
||||||
|
{
|
||||||
|
private Predicate<object> _canExecute;
|
||||||
|
private Action<object> _execute;
|
||||||
|
|
||||||
|
public RelayCommand(Action execute)
|
||||||
|
{
|
||||||
|
_canExecute = x => true;
|
||||||
|
_execute = x => { execute.Invoke(); };
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelayCommand(Action<object> execute) : this(x => true, execute)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
|
||||||
|
{
|
||||||
|
_canExecute = canExecute;
|
||||||
|
_execute = execute;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler CanExecuteChanged
|
||||||
|
{
|
||||||
|
add { CommandManager.RequerySuggested += value; }
|
||||||
|
remove { CommandManager.RequerySuggested -= value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanExecute(object parameter) => _canExecute(parameter);
|
||||||
|
|
||||||
|
public void Execute(object parameter) => _execute(parameter);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace ColorPicker.Common
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base for view models to provide property changed notifications
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ViewModelBase : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace ColorPicker.Helpers
|
||||||
|
{
|
||||||
|
[Export(typeof(AppStateHandler))]
|
||||||
|
public class AppStateHandler
|
||||||
|
{
|
||||||
|
[ImportingConstructor]
|
||||||
|
public AppStateHandler()
|
||||||
|
{
|
||||||
|
Application.Current.MainWindow.Closed += MainWindow_Closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler AppShown;
|
||||||
|
|
||||||
|
public event EventHandler AppHidden;
|
||||||
|
|
||||||
|
public event EventHandler AppClosed;
|
||||||
|
|
||||||
|
public void ShowColorPicker()
|
||||||
|
{
|
||||||
|
AppShown?.Invoke(this, EventArgs.Empty);
|
||||||
|
Application.Current.MainWindow.Opacity = 0;
|
||||||
|
Application.Current.MainWindow.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HideColorPicker()
|
||||||
|
{
|
||||||
|
Application.Current.MainWindow.Opacity = 0;
|
||||||
|
Application.Current.MainWindow.Visibility = Visibility.Collapsed;
|
||||||
|
AppHidden?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetTopMost()
|
||||||
|
{
|
||||||
|
Application.Current.MainWindow.Topmost = false;
|
||||||
|
Application.Current.MainWindow.Topmost = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainWindow_Closed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
AppClosed?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/modules/colorPicker/ColorPickerUI/Helpers/Logger.cs
Normal file
70
src/modules/colorPicker/ColorPickerUI/Helpers/Logger.cs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ColorPicker.Helpers
|
||||||
|
{
|
||||||
|
public static class Logger
|
||||||
|
{
|
||||||
|
private static string ApplicationLogPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ColorPicker");
|
||||||
|
|
||||||
|
static Logger()
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(ApplicationLogPath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(ApplicationLogPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var logFilePath = Path.Combine(ApplicationLogPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.CurrentCulture) + ".txt");
|
||||||
|
|
||||||
|
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));
|
||||||
|
|
||||||
|
Trace.AutoFlush = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogError(string message)
|
||||||
|
{
|
||||||
|
Log(message, "ERROR");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogError(string message, Exception ex)
|
||||||
|
{
|
||||||
|
Log(message + Environment.NewLine +
|
||||||
|
ex?.Message + Environment.NewLine +
|
||||||
|
"Inner exception: " + Environment.NewLine +
|
||||||
|
ex?.InnerException?.Message + Environment.NewLine +
|
||||||
|
"Stack trace: " + Environment.NewLine +
|
||||||
|
ex?.StackTrace,
|
||||||
|
"ERROR");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogWarning(string message)
|
||||||
|
{
|
||||||
|
Log(message, "WARNING");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogInfo(string message)
|
||||||
|
{
|
||||||
|
Log(message, "INFO");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Log(string message, string type)
|
||||||
|
{
|
||||||
|
Trace.WriteLine(type + ": " + DateTime.Now.TimeOfDay);
|
||||||
|
Trace.Indent();
|
||||||
|
Trace.WriteLine(GetCallerInfo());
|
||||||
|
Trace.WriteLine(message);
|
||||||
|
Trace.Unindent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetCallerInfo()
|
||||||
|
{
|
||||||
|
StackTrace stackTrace = new StackTrace();
|
||||||
|
|
||||||
|
var methodName = stackTrace.GetFrame(3)?.GetMethod();
|
||||||
|
var className = methodName?.DeclaringType.Name;
|
||||||
|
return "[Method]: " + methodName.Name + " [Class]: " + className;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using static ColorPicker.Win32Apis;
|
||||||
|
|
||||||
|
namespace ColorPicker.Helpers
|
||||||
|
{
|
||||||
|
public class MonitorResolutionHelper
|
||||||
|
{
|
||||||
|
public static readonly HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
|
||||||
|
|
||||||
|
private MonitorResolutionHelper(IntPtr monitor, IntPtr hdc)
|
||||||
|
{
|
||||||
|
var info = new MonitorInfoEx();
|
||||||
|
GetMonitorInfo(new HandleRef(null, monitor), info);
|
||||||
|
Bounds = new System.Windows.Rect(
|
||||||
|
info.rcMonitor.left,
|
||||||
|
info.rcMonitor.top,
|
||||||
|
info.rcMonitor.right - info.rcMonitor.left,
|
||||||
|
info.rcMonitor.bottom - info.rcMonitor.top);
|
||||||
|
WorkingArea = new System.Windows.Rect(
|
||||||
|
info.rcWork.left,
|
||||||
|
info.rcWork.top,
|
||||||
|
info.rcWork.right - info.rcWork.left,
|
||||||
|
info.rcWork.bottom - info.rcWork.top);
|
||||||
|
IsPrimary = (info.dwFlags & MonitorinfofPrimary) != 0;
|
||||||
|
Name = new string(info.szDevice).TrimEnd((char)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DpiScale GetCurrentMonitorDpi()
|
||||||
|
{
|
||||||
|
return VisualTreeHelper.GetDpi(Application.Current.MainWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<MonitorResolutionHelper> AllMonitors
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var closure = new MonitorEnumCallback();
|
||||||
|
var proc = new MonitorEnumProc(closure.Callback);
|
||||||
|
EnumDisplayMonitors(NullHandleRef, IntPtr.Zero, proc, IntPtr.Zero);
|
||||||
|
return closure.Monitors.Cast<MonitorResolutionHelper>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public System.Windows.Rect Bounds { get; private set; }
|
||||||
|
|
||||||
|
public System.Windows.Rect WorkingArea { get; private set; }
|
||||||
|
|
||||||
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
public bool IsPrimary { get; private set; }
|
||||||
|
|
||||||
|
public static bool HasMultipleMonitors()
|
||||||
|
{
|
||||||
|
return AllMonitors.Count() > 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MonitorEnumCallback
|
||||||
|
{
|
||||||
|
public MonitorEnumCallback()
|
||||||
|
{
|
||||||
|
Monitors = new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ArrayList Monitors { get; private set; }
|
||||||
|
|
||||||
|
public bool Callback(
|
||||||
|
IntPtr monitor,
|
||||||
|
IntPtr hdc,
|
||||||
|
IntPtr lprcMonitor,
|
||||||
|
IntPtr lparam)
|
||||||
|
{
|
||||||
|
Monitors.Add(new MonitorResolutionHelper(monitor, hdc));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
using ColorPicker.ViewModelContracts;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.IO;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
namespace ColorPicker.Helpers
|
||||||
|
{
|
||||||
|
[Export(typeof(ZoomWindowHelper))]
|
||||||
|
public class ZoomWindowHelper
|
||||||
|
{
|
||||||
|
private const int ZoomFactor = 2;
|
||||||
|
private const int BaseZoomImageSize = 50;
|
||||||
|
private const int MaxZoomLevel = 3;
|
||||||
|
private const int MinZoomLevel = 0;
|
||||||
|
|
||||||
|
private int _currentZoomLevel = 0;
|
||||||
|
private int _previousZoomLevel = 0;
|
||||||
|
|
||||||
|
private readonly IZoomViewModel _zoomViewModel;
|
||||||
|
private readonly AppStateHandler _appStateHandler;
|
||||||
|
private ZoomWindow _zoomWindow;
|
||||||
|
|
||||||
|
private double _lastLeft;
|
||||||
|
private double _lastTop;
|
||||||
|
|
||||||
|
private double _previousScaledX;
|
||||||
|
private double _previousScaledY;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public ZoomWindowHelper(IZoomViewModel zoomViewModel, AppStateHandler appStateHandler)
|
||||||
|
{
|
||||||
|
_zoomViewModel = zoomViewModel;
|
||||||
|
_appStateHandler = appStateHandler;
|
||||||
|
_appStateHandler.AppClosed += AppStateHandler_AppClosed;
|
||||||
|
_appStateHandler.AppHidden += AppStateHandler_AppClosed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Zoom(System.Windows.Point position, bool zoomIn)
|
||||||
|
{
|
||||||
|
if (zoomIn && _currentZoomLevel < MaxZoomLevel)
|
||||||
|
{
|
||||||
|
_previousZoomLevel = _currentZoomLevel;
|
||||||
|
_currentZoomLevel++;
|
||||||
|
}
|
||||||
|
else if (!zoomIn && _currentZoomLevel > MinZoomLevel)
|
||||||
|
{
|
||||||
|
_previousZoomLevel = _currentZoomLevel;
|
||||||
|
_currentZoomLevel--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetZoomImage(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseZoomWindow()
|
||||||
|
{
|
||||||
|
_currentZoomLevel = 0;
|
||||||
|
_previousZoomLevel = 0;
|
||||||
|
HideZoomWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetZoomImage(System.Windows.Point point)
|
||||||
|
{
|
||||||
|
if (_currentZoomLevel == 0)
|
||||||
|
{
|
||||||
|
HideZoomWindow();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we just started zooming, copy screen area
|
||||||
|
if (_previousZoomLevel == 0)
|
||||||
|
{
|
||||||
|
var x = (int)point.X - BaseZoomImageSize / 2;
|
||||||
|
var y = (int)point.Y - BaseZoomImageSize / 2;
|
||||||
|
var rect = new Rectangle(x, y, BaseZoomImageSize, BaseZoomImageSize);
|
||||||
|
var bmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
|
||||||
|
var g = Graphics.FromImage(bmp);
|
||||||
|
g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
|
||||||
|
|
||||||
|
var bitmapImage = BitmapToImageSource(bmp);
|
||||||
|
|
||||||
|
_zoomViewModel.ZoomArea = bitmapImage;
|
||||||
|
_zoomViewModel.ZoomFactor = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var enlarge = (_currentZoomLevel - _previousZoomLevel) > 0 ? true : false;
|
||||||
|
var currentZoomFactor = enlarge ? ZoomFactor : 1.0 / ZoomFactor;
|
||||||
|
|
||||||
|
_zoomViewModel.ZoomFactor *= currentZoomFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShowZoomWindow((int)point.X, (int)point.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
private BitmapSource BitmapToImageSource(Bitmap bitmap)
|
||||||
|
{
|
||||||
|
using (MemoryStream memory = new MemoryStream())
|
||||||
|
{
|
||||||
|
bitmap.Save(memory, ImageFormat.Bmp);
|
||||||
|
memory.Position = 0;
|
||||||
|
BitmapImage bitmapimage = new BitmapImage();
|
||||||
|
bitmapimage.BeginInit();
|
||||||
|
bitmapimage.StreamSource = memory;
|
||||||
|
bitmapimage.CacheOption = BitmapCacheOption.OnLoad;
|
||||||
|
bitmapimage.EndInit();
|
||||||
|
return bitmapimage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideZoomWindow()
|
||||||
|
{
|
||||||
|
if (_zoomWindow != null)
|
||||||
|
{
|
||||||
|
_zoomWindow.Hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowZoomWindow(int x, int y)
|
||||||
|
{
|
||||||
|
if (_zoomWindow == null)
|
||||||
|
{
|
||||||
|
_zoomWindow = new ZoomWindow();
|
||||||
|
_zoomWindow.Content = _zoomViewModel;
|
||||||
|
_zoomWindow.Loaded += ZoomWindow_Loaded;
|
||||||
|
_zoomWindow.IsVisibleChanged += ZoomWindow_IsVisibleChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we just started zooming, remember where we opened zoom window
|
||||||
|
if (_currentZoomLevel == 1 && _previousZoomLevel == 0)
|
||||||
|
{
|
||||||
|
var dpi = MonitorResolutionHelper.GetCurrentMonitorDpi();
|
||||||
|
_previousScaledX = x / dpi.DpiScaleX;
|
||||||
|
_previousScaledY = y / dpi.DpiScaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastLeft = Math.Floor(_previousScaledX - ((BaseZoomImageSize * Math.Pow(ZoomFactor, _currentZoomLevel - 1)) / 2));
|
||||||
|
_lastTop = Math.Floor(_previousScaledY - ((BaseZoomImageSize * Math.Pow(ZoomFactor, _currentZoomLevel - 1)) / 2));
|
||||||
|
|
||||||
|
var justShown = false;
|
||||||
|
if (!_zoomWindow.IsVisible)
|
||||||
|
{
|
||||||
|
_zoomWindow.Left = _lastLeft;
|
||||||
|
_zoomWindow.Top = _lastTop;
|
||||||
|
_zoomViewModel.Height = BaseZoomImageSize;
|
||||||
|
_zoomViewModel.Width = BaseZoomImageSize;
|
||||||
|
_zoomWindow.Show();
|
||||||
|
justShown = true;
|
||||||
|
// make sure color picker window is on top of just opened zoom window
|
||||||
|
AppStateHandler.SetTopMost();
|
||||||
|
}
|
||||||
|
|
||||||
|
// dirty hack - sometimes when we just show a window on a second monitor with different DPI,
|
||||||
|
// window position is not set correctly on a first time, we need to "ping" it again to make it appear on the proper location
|
||||||
|
if (justShown)
|
||||||
|
{
|
||||||
|
_zoomWindow.Left = _lastLeft + 1;
|
||||||
|
_zoomWindow.Top = _lastTop + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_zoomWindow.DesiredLeft = _lastLeft;
|
||||||
|
_zoomWindow.DesiredTop = _lastTop;
|
||||||
|
_zoomViewModel.DesiredHeight = BaseZoomImageSize * _zoomViewModel.ZoomFactor;
|
||||||
|
_zoomViewModel.DesiredWidth = BaseZoomImageSize * _zoomViewModel.ZoomFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ZoomWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
// need to set at this point again, to avoid issues moving between screens with different scaling
|
||||||
|
if ((bool)e.NewValue)
|
||||||
|
{
|
||||||
|
_zoomWindow.Left = _lastLeft;
|
||||||
|
_zoomWindow.Top = _lastTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ZoomWindow_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// need to call it again at load time, because it does was not dpi aware at the first time of Show() call
|
||||||
|
_zoomWindow.Left = _lastLeft;
|
||||||
|
_zoomWindow.Top = _lastTop;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppStateHandler_AppClosed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CloseZoomWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using static ColorPicker.Win32Apis;
|
||||||
|
|
||||||
|
namespace ColorPicker.Keyboard
|
||||||
|
{
|
||||||
|
internal class GlobalKeyboardHook : IDisposable
|
||||||
|
{
|
||||||
|
private IntPtr _windowsHookHandle;
|
||||||
|
private IntPtr _user32LibraryHandle;
|
||||||
|
private HookProc _hookProc;
|
||||||
|
|
||||||
|
public GlobalKeyboardHook()
|
||||||
|
{
|
||||||
|
_windowsHookHandle = IntPtr.Zero;
|
||||||
|
_user32LibraryHandle = IntPtr.Zero;
|
||||||
|
_hookProc = LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour.
|
||||||
|
|
||||||
|
_user32LibraryHandle = LoadLibrary("User32");
|
||||||
|
if (_user32LibraryHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
int errorCode = Marshal.GetLastWin32Error();
|
||||||
|
throw new Win32Exception(errorCode, $"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_windowsHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, _hookProc, _user32LibraryHandle, 0);
|
||||||
|
if (_windowsHookHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
int errorCode = Marshal.GetLastWin32Error();
|
||||||
|
throw new Win32Exception(errorCode, $"Failed to adjust keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal event EventHandler<GlobalKeyboardHookEventArgs> KeyboardPressed;
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
// because we can unhook only in the same thread, not in garbage collector thread
|
||||||
|
if (_windowsHookHandle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
if (!UnhookWindowsHookEx(_windowsHookHandle))
|
||||||
|
{
|
||||||
|
int errorCode = Marshal.GetLastWin32Error();
|
||||||
|
throw new Win32Exception(errorCode, $"Failed to remove keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||||
|
}
|
||||||
|
_windowsHookHandle = IntPtr.Zero;
|
||||||
|
|
||||||
|
// ReSharper disable once DelegateSubtraction
|
||||||
|
_hookProc -= LowLevelKeyboardProc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_user32LibraryHandle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
if (!FreeLibrary(_user32LibraryHandle)) // reduces reference to library by 1.
|
||||||
|
{
|
||||||
|
int errorCode = Marshal.GetLastWin32Error();
|
||||||
|
throw new Win32Exception(errorCode, $"Failed to unload library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
|
||||||
|
}
|
||||||
|
_user32LibraryHandle = IntPtr.Zero;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~GlobalKeyboardHook()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum KeyboardState
|
||||||
|
{
|
||||||
|
KeyDown = 0x0100,
|
||||||
|
KeyUp = 0x0101,
|
||||||
|
SysKeyDown = 0x0104,
|
||||||
|
SysKeyUp = 0x0105
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
bool fEatKeyStroke = false;
|
||||||
|
|
||||||
|
var wparamTyped = wParam.ToInt32();
|
||||||
|
if (Enum.IsDefined(typeof(KeyboardState), wparamTyped))
|
||||||
|
{
|
||||||
|
object o = Marshal.PtrToStructure(lParam, typeof(LowLevelKeyboardInputEvent));
|
||||||
|
LowLevelKeyboardInputEvent p = (LowLevelKeyboardInputEvent)o;
|
||||||
|
|
||||||
|
var eventArguments = new GlobalKeyboardHookEventArgs(p, (KeyboardState)wparamTyped);
|
||||||
|
|
||||||
|
EventHandler<GlobalKeyboardHookEventArgs> handler = KeyboardPressed;
|
||||||
|
handler?.Invoke(this, eventArguments);
|
||||||
|
|
||||||
|
fEatKeyStroke = eventArguments.Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fEatKeyStroke ? (IntPtr)1 : CallNextHookEx(IntPtr.Zero, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using static ColorPicker.Win32Apis;
|
||||||
|
|
||||||
|
namespace ColorPicker.Keyboard
|
||||||
|
{
|
||||||
|
internal class GlobalKeyboardHookEventArgs : HandledEventArgs
|
||||||
|
{
|
||||||
|
internal GlobalKeyboardHook.KeyboardState KeyboardState { get; private set; }
|
||||||
|
internal LowLevelKeyboardInputEvent KeyboardData { get; private set; }
|
||||||
|
|
||||||
|
internal GlobalKeyboardHookEventArgs(
|
||||||
|
LowLevelKeyboardInputEvent keyboardData,
|
||||||
|
GlobalKeyboardHook.KeyboardState keyboardState)
|
||||||
|
{
|
||||||
|
KeyboardData = keyboardData;
|
||||||
|
KeyboardState = keyboardState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using ColorPicker.Helpers;
|
||||||
|
using ColorPicker.Settings;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
|
||||||
|
|
||||||
|
namespace ColorPicker.Keyboard
|
||||||
|
{
|
||||||
|
[Export(typeof(KeyboardMonitor))]
|
||||||
|
public class KeyboardMonitor
|
||||||
|
{
|
||||||
|
private readonly AppStateHandler _appStateHandler;
|
||||||
|
private readonly IUserSettings _userSettings;
|
||||||
|
|
||||||
|
private List<string> _currentlyPressedKeys = new List<string>();
|
||||||
|
private List<string> _activationKeys = new List<string>();
|
||||||
|
private GlobalKeyboardHook _keyboardHook;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public KeyboardMonitor(AppStateHandler appStateHandler, IUserSettings userSettings)
|
||||||
|
{
|
||||||
|
_appStateHandler = appStateHandler;
|
||||||
|
_userSettings = userSettings;
|
||||||
|
_userSettings.ActivationShortcut.PropertyChanged += ActivationShortcut_PropertyChanged;
|
||||||
|
SetActivationKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
_keyboardHook = new GlobalKeyboardHook();
|
||||||
|
_keyboardHook.KeyboardPressed += Hook_KeyboardPressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetActivationKeys()
|
||||||
|
{
|
||||||
|
_activationKeys.Clear();
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(_userSettings.ActivationShortcut.Value))
|
||||||
|
{
|
||||||
|
var keys = _userSettings.ActivationShortcut.Value.Split('+');
|
||||||
|
foreach (var key in keys)
|
||||||
|
{
|
||||||
|
_activationKeys.Add(key.Trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
_activationKeys.Sort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActivationShortcut_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SetActivationKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Hook_KeyboardPressed(object sender, GlobalKeyboardHookEventArgs e)
|
||||||
|
{
|
||||||
|
var virtualCode = e.KeyboardData.VirtualCode;
|
||||||
|
var name = Helper.GetKeyName((uint)virtualCode);
|
||||||
|
|
||||||
|
// we got modifier with additional info such as "Ctrl (left)" - get rid of parenthesess
|
||||||
|
if (name.IndexOf("(", StringComparison.OrdinalIgnoreCase) > 0 && name.Length > 1)
|
||||||
|
{
|
||||||
|
name = name.Substring(0, name.IndexOf("(", StringComparison.OrdinalIgnoreCase)).Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyDown || e.KeyboardState == GlobalKeyboardHook.KeyboardState.SysKeyDown)
|
||||||
|
{
|
||||||
|
if (!_currentlyPressedKeys.Contains(name))
|
||||||
|
{
|
||||||
|
_currentlyPressedKeys.Add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (e.KeyboardState == GlobalKeyboardHook.KeyboardState.KeyUp || e.KeyboardState == GlobalKeyboardHook.KeyboardState.SysKeyUp)
|
||||||
|
{
|
||||||
|
if (_currentlyPressedKeys.Contains(name))
|
||||||
|
{
|
||||||
|
_currentlyPressedKeys.Remove(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_currentlyPressedKeys.Sort();
|
||||||
|
|
||||||
|
if (ArraysAreSame(_currentlyPressedKeys, _activationKeys))
|
||||||
|
{
|
||||||
|
_appStateHandler.ShowColorPicker();
|
||||||
|
_currentlyPressedKeys.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool ArraysAreSame(List<string> first, List<string> second)
|
||||||
|
{
|
||||||
|
if (first.Count != second.Count || (first.Count == 0 && second.Count == 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < first.Count; i++)
|
||||||
|
{
|
||||||
|
if (first[i] != second[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/modules/colorPicker/ColorPickerUI/MainWindow.xaml
Normal file
16
src/modules/colorPicker/ColorPickerUI/MainWindow.xaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<Window x:Class="ColorPicker.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:ColorPickerUI"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||||
|
xmlns:behaviors="clr-namespace:ColorPicker.Behaviors"
|
||||||
|
Title="Color Picker" Height="50" Width="180" WindowStyle="None" Opacity="0.01" ShowInTaskbar="False" ResizeMode="NoResize" Topmost="True" Background="Transparent" AllowsTransparency="True">
|
||||||
|
<e:Interaction.Behaviors>
|
||||||
|
<behaviors:ChangeWindowPositionBehavior/>
|
||||||
|
<behaviors:AppearAnimationBehavior/>
|
||||||
|
</e:Interaction.Behaviors>
|
||||||
|
<ContentControl x:Name="MainView" Content="{Binding MainViewModel}"/>
|
||||||
|
</Window>
|
||||||
31
src/modules/colorPicker/ColorPickerUI/MainWindow.xaml.cs
Normal file
31
src/modules/colorPicker/ColorPickerUI/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
using ColorPicker.ViewModelContracts;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace ColorPicker
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
Closing += MainWindow_Closing;
|
||||||
|
Bootstrapper.InitializeContainer(this);
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = this;
|
||||||
|
Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Import]
|
||||||
|
public IMainViewModel MainViewModel { get; set; }
|
||||||
|
|
||||||
|
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||||
|
{
|
||||||
|
Closing -= MainWindow_Closing;
|
||||||
|
Bootstrapper.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
src/modules/colorPicker/ColorPickerUI/Mouse/CursorManager.cs
Normal file
80
src/modules/colorPicker/ColorPickerUI/Mouse/CursorManager.cs
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
using ColorPicker.Helpers;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace ColorPicker.Mouse
|
||||||
|
{
|
||||||
|
public static class CursorManager
|
||||||
|
{
|
||||||
|
private const string CursorsRegistryPath = @"HKEY_CURRENT_USER\Control Panel\Cursors\";
|
||||||
|
private const string ArrowRegistryName = "Arrow";
|
||||||
|
private const string IBeamRegistryName = "IBeam";
|
||||||
|
private const string CrosshairRegistryName = "Crosshair";
|
||||||
|
private const string HandRegistryName = "Hand";
|
||||||
|
private const string ColorPickerCursorName = "Resources\\colorPicker.cur";
|
||||||
|
|
||||||
|
private static string _originalArrowCursorPath;
|
||||||
|
private static string _originalIBeamCursorPath;
|
||||||
|
private static string _originalCrosshairCursorPath;
|
||||||
|
private static string _originalHandCursorPath;
|
||||||
|
|
||||||
|
public static void SetColorPickerCursor()
|
||||||
|
{
|
||||||
|
BackupOriginalCursors();
|
||||||
|
|
||||||
|
var colorPickerCursorPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ColorPickerCursorName);
|
||||||
|
ChangeCursor(colorPickerCursorPath, ArrowRegistryName);
|
||||||
|
ChangeCursor(colorPickerCursorPath, IBeamRegistryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RestoreOriginalCursors()
|
||||||
|
{
|
||||||
|
ChangeCursor(_originalArrowCursorPath, ArrowRegistryName);
|
||||||
|
ChangeCursor(_originalIBeamCursorPath, IBeamRegistryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ChangeCursor(string curFile, string cursorRegistryName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(curFile != null)
|
||||||
|
{
|
||||||
|
Registry.SetValue(CursorsRegistryPath, cursorRegistryName, curFile);
|
||||||
|
Win32Apis.SystemParametersInfo(SPI_SETCURSORS, 0, new IntPtr(0), SPIF_SENDCHANGE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogInfo("Cursor file path was null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("Failed to change cursor", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BackupOriginalCursors()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_originalArrowCursorPath))
|
||||||
|
{
|
||||||
|
_originalArrowCursorPath = (string)Registry.GetValue(CursorsRegistryPath, ArrowRegistryName, string.Empty);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(_originalIBeamCursorPath))
|
||||||
|
{
|
||||||
|
_originalIBeamCursorPath = (string)Registry.GetValue(CursorsRegistryPath, IBeamRegistryName, string.Empty);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(_originalCrosshairCursorPath))
|
||||||
|
{
|
||||||
|
_originalCrosshairCursorPath = (string)Registry.GetValue(CursorsRegistryPath, CrosshairRegistryName, string.Empty);
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(_originalHandCursorPath))
|
||||||
|
{
|
||||||
|
_originalHandCursorPath = (string)Registry.GetValue(CursorsRegistryPath, HandRegistryName, string.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const int SPI_SETCURSORS = 0x0057;
|
||||||
|
const int SPIF_SENDCHANGE = 0x02;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace ColorPicker.Mouse
|
||||||
|
{
|
||||||
|
public interface IMouseInfoProvider
|
||||||
|
{
|
||||||
|
event EventHandler<Color> MouseColorChanged;
|
||||||
|
|
||||||
|
event EventHandler<System.Windows.Point> MousePositionChanged;
|
||||||
|
|
||||||
|
// position and bool indicating zoom in or zoom out
|
||||||
|
event EventHandler<Tuple<System.Windows.Point, bool>> OnMouseWheel;
|
||||||
|
|
||||||
|
event MouseUpEventHandler OnMouseDown;
|
||||||
|
|
||||||
|
System.Windows.Point CurrentPosition { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
108
src/modules/colorPicker/ColorPickerUI/Mouse/MouseHook.cs
Normal file
108
src/modules/colorPicker/ColorPickerUI/Mouse/MouseHook.cs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using static ColorPicker.Win32Apis;
|
||||||
|
|
||||||
|
namespace ColorPicker.Mouse
|
||||||
|
{
|
||||||
|
public delegate void MouseUpEventHandler(object sender, System.Drawing.Point p);
|
||||||
|
|
||||||
|
internal class MouseHook
|
||||||
|
{
|
||||||
|
private const int WH_MOUSE_LL = 14;
|
||||||
|
private const int WM_LBUTTONDOWN = 0x0201;
|
||||||
|
private const int WM_MOUSEWHEEL = 0x020A;
|
||||||
|
private const int WHEEL_DELTA = 120;
|
||||||
|
|
||||||
|
private IntPtr _mouseHookHandle;
|
||||||
|
private HookProc _mouseDelegate;
|
||||||
|
|
||||||
|
private event MouseUpEventHandler MouseDown;
|
||||||
|
public event MouseUpEventHandler OnMouseDown
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
Subscribe();
|
||||||
|
MouseDown += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
MouseDown -= value;
|
||||||
|
Unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private event MouseWheelEventHandler MouseWheel;
|
||||||
|
public event MouseWheelEventHandler OnMouseWheel
|
||||||
|
{
|
||||||
|
add
|
||||||
|
{
|
||||||
|
Subscribe();
|
||||||
|
MouseWheel += value;
|
||||||
|
}
|
||||||
|
remove
|
||||||
|
{
|
||||||
|
MouseWheel -= value;
|
||||||
|
Unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Unsubscribe()
|
||||||
|
{
|
||||||
|
if (_mouseHookHandle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
var result = UnhookWindowsHookEx(_mouseHookHandle);
|
||||||
|
_mouseHookHandle = IntPtr.Zero;
|
||||||
|
_mouseDelegate = null;
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
int errorCode = Marshal.GetLastWin32Error();
|
||||||
|
throw new Win32Exception(errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Subscribe()
|
||||||
|
{
|
||||||
|
if (_mouseHookHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
_mouseDelegate = MouseHookProc;
|
||||||
|
_mouseHookHandle = SetWindowsHookEx(WH_MOUSE_LL,
|
||||||
|
_mouseDelegate,
|
||||||
|
GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName),
|
||||||
|
0);
|
||||||
|
if (_mouseHookHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
int errorCode = Marshal.GetLastWin32Error();
|
||||||
|
throw new Win32Exception(errorCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
if (nCode >= 0)
|
||||||
|
{
|
||||||
|
MSLLHOOKSTRUCT mouseHookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
||||||
|
if (wParam.ToInt32() == WM_LBUTTONDOWN)
|
||||||
|
{
|
||||||
|
if (MouseDown != null)
|
||||||
|
{
|
||||||
|
MouseDown.Invoke(null, new System.Drawing.Point(mouseHookStruct.pt.x, mouseHookStruct.pt.y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wParam.ToInt32() == WM_MOUSEWHEEL)
|
||||||
|
{
|
||||||
|
if (MouseWheel != null)
|
||||||
|
{
|
||||||
|
MouseDevice mouseDev = InputManager.Current.PrimaryMouseDevice;
|
||||||
|
MouseWheel.Invoke(null, new MouseWheelEventArgs(mouseDev, Environment.TickCount, (int)mouseHookStruct.mouseData >> 16));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return CallNextHookEx(_mouseHookHandle, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
137
src/modules/colorPicker/ColorPickerUI/Mouse/MouseInfoProvider.cs
Normal file
137
src/modules/colorPicker/ColorPickerUI/Mouse/MouseInfoProvider.cs
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using ColorPicker.Helpers;
|
||||||
|
using ColorPicker.Settings;
|
||||||
|
using static ColorPicker.Win32Apis;
|
||||||
|
|
||||||
|
namespace ColorPicker.Mouse
|
||||||
|
{
|
||||||
|
[Export(typeof(IMouseInfoProvider))]
|
||||||
|
[PartCreationPolicy(CreationPolicy.Shared)]
|
||||||
|
public class MouseInfoProvider : IMouseInfoProvider
|
||||||
|
{
|
||||||
|
private const int MousePullInfoIntervalInMs = 10;
|
||||||
|
private readonly DispatcherTimer _timer = new DispatcherTimer();
|
||||||
|
private readonly MouseHook _mouseHook;
|
||||||
|
private readonly IUserSettings _userSettings;
|
||||||
|
private System.Windows.Point _previousMousePosition = new System.Windows.Point(-1, 1);
|
||||||
|
private Color _previousColor = Color.Transparent;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public MouseInfoProvider(AppStateHandler appStateMonitor, IUserSettings userSettings)
|
||||||
|
{
|
||||||
|
_timer.Interval = TimeSpan.FromMilliseconds(MousePullInfoIntervalInMs);
|
||||||
|
_timer.Tick += Timer_Tick;
|
||||||
|
|
||||||
|
appStateMonitor.AppShown += AppStateMonitor_AppShown;
|
||||||
|
appStateMonitor.AppClosed += AppStateMonitor_AppClosed;
|
||||||
|
appStateMonitor.AppHidden += AppStateMonitor_AppClosed;
|
||||||
|
_mouseHook = new MouseHook();
|
||||||
|
_userSettings = userSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<Color> MouseColorChanged;
|
||||||
|
|
||||||
|
public event EventHandler<System.Windows.Point> MousePositionChanged;
|
||||||
|
|
||||||
|
public event EventHandler<Tuple<System.Windows.Point, bool>> OnMouseWheel;
|
||||||
|
|
||||||
|
public event MouseUpEventHandler OnMouseDown;
|
||||||
|
|
||||||
|
public System.Windows.Point CurrentPosition
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _previousMousePosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Timer_Tick(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
UpdateMouseInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateMouseInfo()
|
||||||
|
{
|
||||||
|
var mousePosition = GetCursorPosition();
|
||||||
|
if (_previousMousePosition != mousePosition)
|
||||||
|
{
|
||||||
|
_previousMousePosition = mousePosition;
|
||||||
|
MousePositionChanged?.Invoke(this, mousePosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
var color = GetPixelColor(mousePosition);
|
||||||
|
if (_previousColor != color)
|
||||||
|
{
|
||||||
|
_previousColor = color;
|
||||||
|
MouseColorChanged?.Invoke(this, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color GetPixelColor(System.Windows.Point mousePosition)
|
||||||
|
{
|
||||||
|
var rect = new Rectangle((int)mousePosition.X, (int)mousePosition.Y, 1, 1);
|
||||||
|
var bmp = new Bitmap(rect.Width, rect.Height, PixelFormat.Format32bppArgb);
|
||||||
|
var g = Graphics.FromImage(bmp);
|
||||||
|
g.CopyFromScreen(rect.Left, rect.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
|
||||||
|
|
||||||
|
return bmp.GetPixel(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static System.Windows.Point GetCursorPosition()
|
||||||
|
{
|
||||||
|
GetCursorPos(out PointInter lpPoint);
|
||||||
|
return (System.Windows.Point)lpPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppStateMonitor_AppClosed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
_timer.Stop();
|
||||||
|
_previousMousePosition = new System.Windows.Point(-1, 1);
|
||||||
|
_mouseHook.OnMouseDown -= MouseHook_OnMouseDown;
|
||||||
|
_mouseHook.OnMouseWheel -= MouseHook_OnMouseWheel;
|
||||||
|
|
||||||
|
if (_userSettings.ChangeCursor.Value)
|
||||||
|
{
|
||||||
|
CursorManager.RestoreOriginalCursors();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AppStateMonitor_AppShown(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
UpdateMouseInfo();
|
||||||
|
if (!_timer.IsEnabled)
|
||||||
|
{
|
||||||
|
_timer.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
_mouseHook.OnMouseDown += MouseHook_OnMouseDown;
|
||||||
|
_mouseHook.OnMouseWheel += MouseHook_OnMouseWheel;
|
||||||
|
|
||||||
|
if (_userSettings.ChangeCursor.Value)
|
||||||
|
{
|
||||||
|
CursorManager.SetColorPickerCursor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MouseHook_OnMouseWheel(object sender, MouseWheelEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.Delta == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var zoomIn = e.Delta > 0;
|
||||||
|
OnMouseWheel?.Invoke(this, new Tuple<System.Windows.Point, bool>(_previousMousePosition, zoomIn));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MouseHook_OnMouseDown(object sender, Point p)
|
||||||
|
{
|
||||||
|
OnMouseDown?.Invoke(this, p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using System.Resources;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("ColorPickerUI")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("ColorPickerUI")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2020")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
//In order to begin building localizable applications, set
|
||||||
|
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||||
|
//inside a <PropertyGroup>. For example, if you are using US english
|
||||||
|
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||||
|
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||||
|
//the line below to match the UICulture setting in the project file.
|
||||||
|
|
||||||
|
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||||
|
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
|
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||||
63
src/modules/colorPicker/ColorPickerUI/Properties/Resources.Designer.cs
generated
Normal file
63
src/modules/colorPicker/ColorPickerUI/Properties/Resources.Designer.cs
generated
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ColorPicker.Properties {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
internal class Resources {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resources() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ColorPicker.Properties.Resources", typeof(Resources).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
internal static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/modules/colorPicker/ColorPickerUI/Properties/Resources.resx
Normal file
117
src/modules/colorPicker/ColorPickerUI/Properties/Resources.resx
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
</root>
|
||||||
26
src/modules/colorPicker/ColorPickerUI/Properties/Settings.Designer.cs
generated
Normal file
26
src/modules/colorPicker/ColorPickerUI/Properties/Settings.Designer.cs
generated
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ColorPicker.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")]
|
||||||
|
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||||
|
|
||||||
|
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||||
|
|
||||||
|
public static Settings Default {
|
||||||
|
get {
|
||||||
|
return defaultInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||||
|
<Profiles>
|
||||||
|
<Profile Name="(Default)" />
|
||||||
|
</Profiles>
|
||||||
|
<Settings />
|
||||||
|
</SettingsFile>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
<!--CONVERTERS-->
|
||||||
|
<BooleanToVisibilityConverter x:Key="bool2VisibilityConverter" />
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:viewModels="clr-namespace:ColorPicker.ViewModels"
|
||||||
|
xmlns:views="clr-namespace:ColorPicker.Views">
|
||||||
|
<DataTemplate DataType="{x:Type viewModels:MainViewModel}">
|
||||||
|
<views:MainView/>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<DataTemplate DataType="{x:Type viewModels:ZoomViewModel}">
|
||||||
|
<views:ZoomView/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ResourceDictionary>
|
||||||
BIN
src/modules/colorPicker/ColorPickerUI/Resources/colorPicker.cur
Normal file
BIN
src/modules/colorPicker/ColorPickerUI/Resources/colorPicker.cur
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
src/modules/colorPicker/ColorPickerUI/Resources/icon.ico
Normal file
BIN
src/modules/colorPicker/ColorPickerUI/Resources/icon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 112 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||||
|
|
||||||
|
namespace ColorPicker.Settings
|
||||||
|
{
|
||||||
|
public interface IUserSettings
|
||||||
|
{
|
||||||
|
SettingItem<string> ActivationShortcut { get; }
|
||||||
|
|
||||||
|
SettingItem<bool> ChangeCursor { get; }
|
||||||
|
|
||||||
|
SettingItem<ColorRepresentationType> CopiedColorRepresentation { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace ColorPicker.Settings
|
||||||
|
{
|
||||||
|
public sealed class SettingItem<T> : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private T _value;
|
||||||
|
|
||||||
|
public SettingItem(T startValue)
|
||||||
|
{
|
||||||
|
_value = startValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T Value
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_value = value;
|
||||||
|
OnValueChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
private void OnValueChanged()
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Lib.Utilities;
|
||||||
|
using ColorPicker.Helpers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ColorPicker.Settings
|
||||||
|
{
|
||||||
|
[Export(typeof(IUserSettings))]
|
||||||
|
public class UserSettings : IUserSettings
|
||||||
|
{
|
||||||
|
private const string ColorPickerModuleName = "ColorPicker";
|
||||||
|
private const string DefaultActivationShortcut = "Ctrl + Break";
|
||||||
|
private const int MaxNumberOfRetry = 5;
|
||||||
|
private FileSystemWatcher _watcher;
|
||||||
|
|
||||||
|
private object _loadingSettingsLock = new object();
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public UserSettings()
|
||||||
|
{
|
||||||
|
ChangeCursor = new SettingItem<bool>(true);
|
||||||
|
ActivationShortcut = new SettingItem<string>(DefaultActivationShortcut);
|
||||||
|
CopiedColorRepresentation = new SettingItem<ColorRepresentationType>(ColorRepresentationType.HEX);
|
||||||
|
|
||||||
|
LoadSettingsFromJson();
|
||||||
|
_watcher = Helper.GetFileWatcher(ColorPickerModuleName, "settings.json", LoadSettingsFromJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingItem<string> ActivationShortcut { get; private set; }
|
||||||
|
|
||||||
|
public SettingItem<bool> ChangeCursor { get; private set; }
|
||||||
|
|
||||||
|
public SettingItem<ColorRepresentationType> CopiedColorRepresentation { get; set; }
|
||||||
|
|
||||||
|
private void LoadSettingsFromJson()
|
||||||
|
{
|
||||||
|
// TODO this IO call should by Async, update GetFileWatcher helper to support async
|
||||||
|
lock (_loadingSettingsLock)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
var retry = true;
|
||||||
|
var retryCount = 0;
|
||||||
|
|
||||||
|
while (retry)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
retryCount++;
|
||||||
|
|
||||||
|
if (!SettingsUtils.SettingsExists(ColorPickerModuleName))
|
||||||
|
{
|
||||||
|
Logger.LogInfo("ColorPicker settings.json was missing, creating a new one");
|
||||||
|
var defaultColorPickerSettings = new ColorPickerSettings();
|
||||||
|
defaultColorPickerSettings.Save();
|
||||||
|
}
|
||||||
|
var settings = SettingsUtils.GetSettings<ColorPickerSettings>(ColorPickerModuleName);
|
||||||
|
if (settings != null)
|
||||||
|
{
|
||||||
|
ChangeCursor.Value = settings.properties.ChangeCursor;
|
||||||
|
ActivationShortcut.Value = settings.properties.ActivationShortcut.ToString();
|
||||||
|
CopiedColorRepresentation.Value = settings.properties.CopiedColorRepresentation;
|
||||||
|
}
|
||||||
|
|
||||||
|
retry = false;
|
||||||
|
}
|
||||||
|
catch (IOException ex)
|
||||||
|
{
|
||||||
|
if (retryCount > MaxNumberOfRetry)
|
||||||
|
{
|
||||||
|
retry = false;
|
||||||
|
}
|
||||||
|
Logger.LogError("Failed to read changed settings", ex);
|
||||||
|
Thread.Sleep(500);
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Logger.LogError("Failed to read changed settings", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace ColorPicker.ViewModelContracts
|
||||||
|
{
|
||||||
|
public interface IMainViewModel
|
||||||
|
{
|
||||||
|
string HexColor { get; }
|
||||||
|
|
||||||
|
string RgbColor { get; }
|
||||||
|
|
||||||
|
Brush ColorBrush { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
namespace ColorPicker.ViewModelContracts
|
||||||
|
{
|
||||||
|
public interface IZoomViewModel
|
||||||
|
{
|
||||||
|
BitmapSource ZoomArea { get; set; }
|
||||||
|
|
||||||
|
double ZoomFactor { get; set; }
|
||||||
|
|
||||||
|
double DesiredWidth { get; set; }
|
||||||
|
|
||||||
|
double DesiredHeight { get; set; }
|
||||||
|
|
||||||
|
double Width { get; set; }
|
||||||
|
|
||||||
|
double Height { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using ColorPicker.Common;
|
||||||
|
using ColorPicker.Helpers;
|
||||||
|
using ColorPicker.Keyboard;
|
||||||
|
using ColorPicker.Mouse;
|
||||||
|
using ColorPicker.Settings;
|
||||||
|
using ColorPicker.ViewModelContracts;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||||
|
|
||||||
|
namespace ColorPicker.ViewModels
|
||||||
|
{
|
||||||
|
[Export(typeof(IMainViewModel))]
|
||||||
|
public class MainViewModel : ViewModelBase, IMainViewModel
|
||||||
|
{
|
||||||
|
private string _hexColor;
|
||||||
|
private string _rgbColor;
|
||||||
|
private Brush _colorBrush;
|
||||||
|
private readonly ZoomWindowHelper _zoomWindowHelper;
|
||||||
|
private readonly AppStateHandler _appStateHandler;
|
||||||
|
private readonly IUserSettings _userSettings;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public MainViewModel(
|
||||||
|
IMouseInfoProvider mouseInfoProvider,
|
||||||
|
ZoomWindowHelper zoomWindowHelper,
|
||||||
|
AppStateHandler appStateHandler,
|
||||||
|
KeyboardMonitor keyboardMonitor,
|
||||||
|
IUserSettings userSettings)
|
||||||
|
{
|
||||||
|
_zoomWindowHelper = zoomWindowHelper;
|
||||||
|
_appStateHandler = appStateHandler;
|
||||||
|
_userSettings = userSettings;
|
||||||
|
|
||||||
|
mouseInfoProvider.MouseColorChanged += Mouse_ColorChanged;
|
||||||
|
mouseInfoProvider.OnMouseDown += MouseInfoProvider_OnMouseDown;
|
||||||
|
mouseInfoProvider.OnMouseWheel += MouseInfoProvider_OnMouseWheel;
|
||||||
|
|
||||||
|
keyboardMonitor.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string HexColor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _hexColor;
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_hexColor = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string RgbColor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _rgbColor;
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_rgbColor = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Brush ColorBrush
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _colorBrush;
|
||||||
|
}
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
_colorBrush = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Mouse_ColorChanged(object sender, System.Drawing.Color color)
|
||||||
|
{
|
||||||
|
HexColor = ColorToHex(color);
|
||||||
|
RgbColor = ColorToRGB(color);
|
||||||
|
ColorBrush = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MouseInfoProvider_OnMouseDown(object sender, System.Drawing.Point p)
|
||||||
|
{
|
||||||
|
string colorRepresentationToCopy = string.Empty;
|
||||||
|
|
||||||
|
switch (_userSettings.CopiedColorRepresentation.Value)
|
||||||
|
{
|
||||||
|
case ColorRepresentationType.HEX:
|
||||||
|
colorRepresentationToCopy = HexColor;
|
||||||
|
break;
|
||||||
|
case ColorRepresentationType.RGB:
|
||||||
|
colorRepresentationToCopy = RgbColor;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
CopyToClipboard(colorRepresentationToCopy);
|
||||||
|
|
||||||
|
_appStateHandler.HideColorPicker();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CopyToClipboard(string colorRepresentationToCopy)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(colorRepresentationToCopy))
|
||||||
|
{
|
||||||
|
// nasty hack - sometimes clipboard can be in use and it will raise and exception
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Clipboard.SetText(colorRepresentationToCopy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (COMException ex)
|
||||||
|
{
|
||||||
|
const uint CLIPBRD_E_CANT_OPEN = 0x800401D0;
|
||||||
|
if ((uint)ex.ErrorCode != CLIPBRD_E_CANT_OPEN)
|
||||||
|
{
|
||||||
|
Logger.LogError("Failed to set text into clipboard", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.Threading.Thread.Sleep(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MouseInfoProvider_OnMouseWheel(object sender, Tuple<Point, bool> e)
|
||||||
|
{
|
||||||
|
_zoomWindowHelper.Zoom(e.Item1, e.Item2);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ColorToHex(System.Drawing.Color c)
|
||||||
|
{
|
||||||
|
return "#" + c.R.ToString("X2", CultureInfo.InvariantCulture) + c.G.ToString("X2", CultureInfo.InvariantCulture) + c.B.ToString("X2", CultureInfo.InvariantCulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ColorToRGB(System.Drawing.Color c)
|
||||||
|
{
|
||||||
|
return "RGB(" + c.R.ToString(CultureInfo.InvariantCulture) + "," + c.G.ToString(CultureInfo.InvariantCulture) + "," + c.B.ToString(CultureInfo.InvariantCulture) + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
using ColorPicker.Common;
|
||||||
|
using ColorPicker.ViewModelContracts;
|
||||||
|
using System.ComponentModel.Composition;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
|
||||||
|
namespace ColorPicker.ViewModels
|
||||||
|
{
|
||||||
|
[Export(typeof(IZoomViewModel))]
|
||||||
|
public class ZoomViewModel : ViewModelBase, IZoomViewModel
|
||||||
|
{
|
||||||
|
private BitmapSource _zoomArea;
|
||||||
|
private double _zoomFactor = 1;
|
||||||
|
private double _desiredWidth;
|
||||||
|
private double _desiredHeight;
|
||||||
|
private double _width;
|
||||||
|
private double _height;
|
||||||
|
|
||||||
|
[ImportingConstructor]
|
||||||
|
public ZoomViewModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public BitmapSource ZoomArea
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _zoomArea;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_zoomArea = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double ZoomFactor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _zoomFactor;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_zoomFactor = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DesiredWidth
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _desiredWidth;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_desiredWidth = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DesiredHeight
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _desiredHeight;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_desiredHeight = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Width
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _width;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_width = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Height
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _height;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_height = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/modules/colorPicker/ColorPickerUI/Views/MainView.xaml
Normal file
32
src/modules/colorPicker/ColorPickerUI/Views/MainView.xaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<UserControl x:Class="ColorPicker.Views.MainView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:ColorPicker.Views"
|
||||||
|
xmlns:viewModel="clr-namespace:ColorPicker.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="50" d:DesignWidth="180"
|
||||||
|
d:DataContext="{d:DesignInstance viewModel:MainViewModel, IsDesignTimeCreatable=True}">
|
||||||
|
<Grid Background="Transparent" >
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="20"/>
|
||||||
|
<ColumnDefinition Width="50"/>
|
||||||
|
<ColumnDefinition/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition/>
|
||||||
|
<RowDefinition/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Border Grid.RowSpan="2" Grid.ColumnSpan="2" Grid.Column="1" Background="#202020" BorderThickness="1" BorderBrush="Black" />
|
||||||
|
<Border Background="{Binding ColorBrush}" BorderBrush="Black" Grid.Column="1" BorderThickness="1" Grid.RowSpan="2" x:Name="ColorBorder"/>
|
||||||
|
<TextBlock Margin="7,5,5,5" Foreground="White" Grid.Row="0" Grid.Column="2" Text="{Binding HexColor}"/>
|
||||||
|
<TextBlock Margin="7,0,0,0" Foreground="White" Grid.Row="1" Grid.Column="2" Text="{Binding RgbColor}"/>
|
||||||
|
|
||||||
|
|
||||||
|
<Border BorderBrush="#505050" Grid.Column="2" Margin="0,1,1,1" Grid.RowSpan="2" BorderThickness="3,0,3,0" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
28
src/modules/colorPicker/ColorPickerUI/Views/MainView.xaml.cs
Normal file
28
src/modules/colorPicker/ColorPickerUI/Views/MainView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace ColorPicker.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainView : UserControl
|
||||||
|
{
|
||||||
|
public MainView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/modules/colorPicker/ColorPickerUI/Views/ZoomView.xaml
Normal file
16
src/modules/colorPicker/ColorPickerUI/Views/ZoomView.xaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<UserControl x:Class="ColorPicker.Views.ZoomView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:ColorPicker.Views"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||||
|
xmlns:behaviors="clr-namespace:ColorPicker.Behaviors"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800" BorderBrush="Black" BorderThickness="2" Focusable="False">
|
||||||
|
<Image Source="{Binding ZoomArea}" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Fill" Width="{Binding Width, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}">
|
||||||
|
<e:Interaction.Behaviors>
|
||||||
|
<behaviors:ResizeBehavior Width="{Binding DesiredWidth}" Height="{Binding DesiredHeight}"/>
|
||||||
|
</e:Interaction.Behaviors>
|
||||||
|
</Image>
|
||||||
|
</UserControl>
|
||||||
28
src/modules/colorPicker/ColorPickerUI/Views/ZoomView.xaml.cs
Normal file
28
src/modules/colorPicker/ColorPickerUI/Views/ZoomView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace ColorPicker.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ZoomView.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ZoomView : UserControl
|
||||||
|
{
|
||||||
|
public ZoomView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
135
src/modules/colorPicker/ColorPickerUI/Win32Apis.cs
Normal file
135
src/modules/colorPicker/ColorPickerUI/Win32Apis.cs
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
|
namespace ColorPicker
|
||||||
|
{
|
||||||
|
public static class Win32Apis
|
||||||
|
{
|
||||||
|
public const int WH_KEYBOARD_LL = 13;
|
||||||
|
public const int VkSnapshot = 0x2c;
|
||||||
|
public const int KfAltdown = 0x2000;
|
||||||
|
public const int LlkhfAltdown = (KfAltdown >> 8);
|
||||||
|
public const int MonitorinfofPrimary = 0x00000001;
|
||||||
|
|
||||||
|
public delegate bool MonitorEnumProc(
|
||||||
|
IntPtr monitor, IntPtr hdc, IntPtr lprcMonitor, IntPtr lParam);
|
||||||
|
|
||||||
|
public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
|
||||||
|
internal static extern IntPtr LoadLibrary(string lpFileName);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||||
|
internal static extern bool FreeLibrary(IntPtr hModule);
|
||||||
|
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode,
|
||||||
|
CallingConvention = CallingConvention.StdCall)]
|
||||||
|
internal static extern IntPtr GetModuleHandle(string name);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||||
|
[ResourceExposure(ResourceScope.None)]
|
||||||
|
internal static extern bool GetMonitorInfo(
|
||||||
|
HandleRef hmonitor, [In, Out] MonitorInfoEx info);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", ExactSpelling = true)]
|
||||||
|
[ResourceExposure(ResourceScope.None)]
|
||||||
|
internal static extern bool EnumDisplayMonitors(
|
||||||
|
HandleRef hdc, IntPtr rcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
internal static extern bool GetCursorPos(out PointInter lpPoint);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto,
|
||||||
|
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||||
|
internal static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto,
|
||||||
|
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||||
|
internal static extern bool UnhookWindowsHookEx(IntPtr idHook);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Auto,
|
||||||
|
CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||||
|
internal static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
|
||||||
|
internal static extern bool SystemParametersInfo(int uiAction, int uiParam, IntPtr pvParam, int fWinIni);
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct POINT
|
||||||
|
{
|
||||||
|
public int x;
|
||||||
|
public int y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct MSLLHOOKSTRUCT
|
||||||
|
{
|
||||||
|
public POINT pt;
|
||||||
|
public uint mouseData;
|
||||||
|
public uint flags;
|
||||||
|
public uint time;
|
||||||
|
public IntPtr dwExtraInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct PointInter
|
||||||
|
{
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
public static explicit operator System.Windows.Point(PointInter point) => new System.Windows.Point(point.X, point.Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct Rect
|
||||||
|
{
|
||||||
|
public int left;
|
||||||
|
public int top;
|
||||||
|
public int right;
|
||||||
|
public int bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
|
||||||
|
internal class MonitorInfoEx
|
||||||
|
{
|
||||||
|
internal int cbSize = Marshal.SizeOf(typeof(MonitorInfoEx));
|
||||||
|
internal Rect rcMonitor = default;
|
||||||
|
internal Rect rcWork = default;
|
||||||
|
internal int dwFlags = 0;
|
||||||
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
|
||||||
|
internal char[] szDevice = new char[32];
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal struct LowLevelKeyboardInputEvent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A virtual-key code. The code must be a value in the range 1 to 254.
|
||||||
|
/// </summary>
|
||||||
|
public int VirtualCode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A hardware scan code for the key.
|
||||||
|
/// </summary>
|
||||||
|
public int HardwareScanCode;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The extended-key flag, event-injected Flags, context code, and transition-state flag. This member is specified as follows. An application can use the following values to test the keystroke Flags. Testing LLKHF_INJECTED (bit 4) will tell you whether the event was injected. If it was, then testing LLKHF_LOWER_IL_INJECTED (bit 1) will tell you whether or not the event was injected from a process running at lower integrity level.
|
||||||
|
/// </summary>
|
||||||
|
public int Flags;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time stamp stamp for this message, equivalent to what GetMessageTime would return for this message.
|
||||||
|
/// </summary>
|
||||||
|
public int TimeStamp;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Additional information associated with the message.
|
||||||
|
/// </summary>
|
||||||
|
public IntPtr AdditionalInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/modules/colorPicker/ColorPickerUI/ZoomWindow.xaml
Normal file
15
src/modules/colorPicker/ColorPickerUI/ZoomWindow.xaml
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<Window x:Class="ColorPicker.ZoomWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:ColorPicker"
|
||||||
|
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||||
|
xmlns:behaviors="clr-namespace:ColorPicker.Behaviors"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="Zoom window" WindowStyle="None" SizeToContent="WidthAndHeight" Topmost="True" ShowInTaskbar="False" ResizeMode="NoResize" Focusable="False">
|
||||||
|
<e:Interaction.Behaviors>
|
||||||
|
<behaviors:CloseZoomWindowBehavior/>
|
||||||
|
<behaviors:MoveWindowBehavior Left="{Binding DesiredLeft, Mode=TwoWay}" Top="{Binding DesiredTop}"/>
|
||||||
|
</e:Interaction.Behaviors>
|
||||||
|
</Window>
|
||||||
52
src/modules/colorPicker/ColorPickerUI/ZoomWindow.xaml.cs
Normal file
52
src/modules/colorPicker/ColorPickerUI/ZoomWindow.xaml.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace ColorPicker
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ZoomWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ZoomWindow : Window, INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
private double _left;
|
||||||
|
private double _top;
|
||||||
|
|
||||||
|
public ZoomWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = this;
|
||||||
|
}
|
||||||
|
public double DesiredLeft
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _left;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_left = value;
|
||||||
|
NotifyPropertyChanged(nameof(DesiredLeft));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double DesiredTop
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _top;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_top = value;
|
||||||
|
NotifyPropertyChanged(nameof(DesiredTop));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
private void NotifyPropertyChanged(string propertyName)
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -129,7 +129,7 @@ int runner(bool isProcessElevated)
|
|||||||
chdir_current_executable();
|
chdir_current_executable();
|
||||||
// Load Powertoys DLLs
|
// Load Powertoys DLLs
|
||||||
|
|
||||||
const std::array<std::wstring_view, 7> knownModules = {
|
const std::array<std::wstring_view, 8> knownModules = {
|
||||||
L"modules/FancyZones/fancyzones.dll",
|
L"modules/FancyZones/fancyzones.dll",
|
||||||
L"modules/FileExplorerPreview/powerpreview.dll",
|
L"modules/FileExplorerPreview/powerpreview.dll",
|
||||||
L"modules/ImageResizer/ImageResizerExt.dll",
|
L"modules/ImageResizer/ImageResizerExt.dll",
|
||||||
@@ -137,6 +137,7 @@ int runner(bool isProcessElevated)
|
|||||||
L"modules/Launcher/Microsoft.Launcher.dll",
|
L"modules/Launcher/Microsoft.Launcher.dll",
|
||||||
L"modules/PowerRename/PowerRenameExt.dll",
|
L"modules/PowerRename/PowerRenameExt.dll",
|
||||||
L"modules/ShortcutGuide/ShortcutGuide.dll",
|
L"modules/ShortcutGuide/ShortcutGuide.dll",
|
||||||
|
L"modules/ColorPicker/ColorPicker.dll",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const auto & moduleSubdir : knownModules)
|
for (const auto & moduleSubdir : knownModules)
|
||||||
|
|||||||
Reference in New Issue
Block a user