mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
[ColorPicker]Add option to choose what clicking individual mouse buttons does (#39025)
## Summary of the Pull Request Enables the users to choose what left, right, and middle click does when color picker is open. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] **Closes:** #39006 - [x] **Communication:** I've discussed this with core contributors already - [x] **Tests:** All pass - [x] **Localization:** All end user facing strings can be localized - [x] **Dev docs:** No need - [x] **New binaries:** None - [x] **Documentation updated:** No need ## Detailed Description of the Pull Request / Additional comments  Adds option to choose from 3 click behaviors for each standard mouse button: * **Pick color and open editor**: Copies color to clipboard, saves it to the color history and opens the editor * **Pick color and close**: Copies color to clipboard, saves it to the color history and exits * **Close**: Closes color picker without copying the color Pressing <kbd>Enter</kbd> or <kbd>Space</kbd> does what clicking the primary button would. Left and middle click actions execute on mouse down, right click on mouse up for reasons discussed previously (I can't find the conversation now) Default settings are chosen in such a way that very little or nothing changes by updating. ## Validation Steps Performed Tested: * Migrating settings from v2.0 to v2.1 (v1 to v2.1 not tested) * Settings page displays and saves settings correctly * Default settings load correctly * All three click actions do what they are supposed to * Activation behavior works as expected, doesn't affect click actions
This commit is contained in:
@@ -107,21 +107,14 @@ namespace ColorPicker.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
public void OnColorPickerMouseDown()
|
||||
public void OpenColorEditor()
|
||||
{
|
||||
if (_userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenColorPickerAndThenEditor || _userSettings.ActivationAction.Value == ColorPickerActivationAction.OpenEditor)
|
||||
lock (_colorPickerVisibilityLock)
|
||||
{
|
||||
lock (_colorPickerVisibilityLock)
|
||||
{
|
||||
HideColorPicker();
|
||||
}
|
||||
HideColorPicker();
|
||||
}
|
||||
|
||||
ShowColorPickerEditor();
|
||||
}
|
||||
else
|
||||
{
|
||||
EndUserSession();
|
||||
}
|
||||
ShowColorPickerEditor();
|
||||
}
|
||||
|
||||
public static void SetTopMost()
|
||||
|
||||
@@ -16,10 +16,12 @@ namespace ColorPicker.Mouse
|
||||
// position and bool indicating zoom in or zoom out
|
||||
event EventHandler<Tuple<System.Windows.Point, bool>> OnMouseWheel;
|
||||
|
||||
event MouseUpEventHandler OnMouseDown;
|
||||
event PrimaryMouseDownEventHandler OnPrimaryMouseDown;
|
||||
|
||||
event SecondaryMouseUpEventHandler OnSecondaryMouseUp;
|
||||
|
||||
event MiddleMouseDownEventHandler OnMiddleMouseDown;
|
||||
|
||||
System.Windows.Point CurrentPosition { get; }
|
||||
|
||||
Color CurrentColor { get; }
|
||||
|
||||
@@ -7,17 +7,18 @@ using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Input;
|
||||
|
||||
using ColorPicker.Helpers;
|
||||
using ManagedCommon;
|
||||
|
||||
using static ColorPicker.NativeMethods;
|
||||
|
||||
namespace ColorPicker.Mouse
|
||||
{
|
||||
public delegate void MouseUpEventHandler(object sender, System.Drawing.Point p);
|
||||
public delegate void PrimaryMouseDownEventHandler(object sender, IntPtr wParam);
|
||||
|
||||
public delegate void SecondaryMouseUpEventHandler(object sender, IntPtr wParam);
|
||||
|
||||
public delegate void MiddleMouseDownEventHandler(object sender, IntPtr wParam);
|
||||
|
||||
internal class MouseHook
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Interop object")]
|
||||
@@ -30,23 +31,25 @@ namespace ColorPicker.Mouse
|
||||
private const int WM_RBUTTONUP = 0x0205;
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Interop object")]
|
||||
private const int WM_RBUTTONDOWN = 0x0204;
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Interop object")]
|
||||
private const int WM_MBUTTONDOWN = 0x0207;
|
||||
|
||||
private IntPtr _mouseHookHandle;
|
||||
private HookProc _mouseDelegate;
|
||||
|
||||
private event MouseUpEventHandler MouseDown;
|
||||
private event PrimaryMouseDownEventHandler PrimaryMouseDown;
|
||||
|
||||
public event MouseUpEventHandler OnMouseDown
|
||||
public event PrimaryMouseDownEventHandler OnPrimaryMouseDown
|
||||
{
|
||||
add
|
||||
{
|
||||
Subscribe();
|
||||
MouseDown += value;
|
||||
PrimaryMouseDown += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
MouseDown -= value;
|
||||
PrimaryMouseDown -= value;
|
||||
Unsubscribe();
|
||||
}
|
||||
}
|
||||
@@ -68,6 +71,23 @@ namespace ColorPicker.Mouse
|
||||
}
|
||||
}
|
||||
|
||||
private event MiddleMouseDownEventHandler MiddleMouseDown;
|
||||
|
||||
public event MiddleMouseDownEventHandler OnMiddleMouseDown
|
||||
{
|
||||
add
|
||||
{
|
||||
Subscribe();
|
||||
MiddleMouseDown += value;
|
||||
}
|
||||
|
||||
remove
|
||||
{
|
||||
MiddleMouseDown -= value;
|
||||
Unsubscribe();
|
||||
}
|
||||
}
|
||||
|
||||
private event MouseWheelEventHandler MouseWheel;
|
||||
|
||||
public event MouseWheelEventHandler OnMouseWheel
|
||||
@@ -126,9 +146,9 @@ namespace ColorPicker.Mouse
|
||||
MSLLHOOKSTRUCT mouseHookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
||||
if (wParam.ToInt32() == WM_LBUTTONDOWN)
|
||||
{
|
||||
if (MouseDown != null)
|
||||
if (PrimaryMouseDown != null)
|
||||
{
|
||||
MouseDown.Invoke(null, new System.Drawing.Point(mouseHookStruct.pt.x, mouseHookStruct.pt.y));
|
||||
PrimaryMouseDown.Invoke(null, wParam);
|
||||
}
|
||||
|
||||
return new IntPtr(-1);
|
||||
@@ -150,6 +170,16 @@ namespace ColorPicker.Mouse
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
|
||||
if (wParam.ToInt32() == WM_MBUTTONDOWN)
|
||||
{
|
||||
if (MiddleMouseDown != null)
|
||||
{
|
||||
MiddleMouseDown.Invoke(null, wParam);
|
||||
}
|
||||
|
||||
return new IntPtr(-1);
|
||||
}
|
||||
|
||||
if (wParam.ToInt32() == WM_MOUSEWHEEL)
|
||||
{
|
||||
if (MouseWheel != null)
|
||||
|
||||
@@ -56,10 +56,12 @@ namespace ColorPicker.Mouse
|
||||
|
||||
public event EventHandler<Tuple<System.Windows.Point, bool>> OnMouseWheel;
|
||||
|
||||
public event MouseUpEventHandler OnMouseDown;
|
||||
public event PrimaryMouseDownEventHandler OnPrimaryMouseDown;
|
||||
|
||||
public event SecondaryMouseUpEventHandler OnSecondaryMouseUp;
|
||||
|
||||
public event MiddleMouseDownEventHandler OnMiddleMouseDown;
|
||||
|
||||
public System.Windows.Point CurrentPosition
|
||||
{
|
||||
get
|
||||
@@ -148,9 +150,10 @@ namespace ColorPicker.Mouse
|
||||
_timer.Start();
|
||||
}
|
||||
|
||||
_mouseHook.OnMouseDown += MouseHook_OnMouseDown;
|
||||
_mouseHook.OnPrimaryMouseDown += MouseHook_OnPrimaryMouseDown;
|
||||
_mouseHook.OnMouseWheel += MouseHook_OnMouseWheel;
|
||||
_mouseHook.OnSecondaryMouseUp += MouseHook_OnSecondaryMouseUp;
|
||||
_mouseHook.OnMiddleMouseDown += MouseHook_OnMiddleMouseDown;
|
||||
|
||||
if (_userSettings.ChangeCursor.Value)
|
||||
{
|
||||
@@ -169,10 +172,10 @@ namespace ColorPicker.Mouse
|
||||
OnMouseWheel?.Invoke(this, new Tuple<System.Windows.Point, bool>(_previousMousePosition, zoomIn));
|
||||
}
|
||||
|
||||
private void MouseHook_OnMouseDown(object sender, Point p)
|
||||
private void MouseHook_OnPrimaryMouseDown(object sender, IntPtr wParam)
|
||||
{
|
||||
DisposeHook();
|
||||
OnMouseDown?.Invoke(this, p);
|
||||
OnPrimaryMouseDown?.Invoke(this, wParam);
|
||||
}
|
||||
|
||||
private void MouseHook_OnSecondaryMouseUp(object sender, IntPtr wParam)
|
||||
@@ -181,6 +184,12 @@ namespace ColorPicker.Mouse
|
||||
OnSecondaryMouseUp?.Invoke(this, wParam);
|
||||
}
|
||||
|
||||
private void MouseHook_OnMiddleMouseDown(object sender, IntPtr wParam)
|
||||
{
|
||||
DisposeHook();
|
||||
OnMiddleMouseDown?.Invoke(this, wParam);
|
||||
}
|
||||
|
||||
private void CopiedColorRepresentation_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
_colorFormatChanged = true;
|
||||
@@ -194,9 +203,10 @@ namespace ColorPicker.Mouse
|
||||
}
|
||||
|
||||
_previousMousePosition = new System.Windows.Point(-1, 1);
|
||||
_mouseHook.OnMouseDown -= MouseHook_OnMouseDown;
|
||||
_mouseHook.OnPrimaryMouseDown -= MouseHook_OnPrimaryMouseDown;
|
||||
_mouseHook.OnMouseWheel -= MouseHook_OnMouseWheel;
|
||||
_mouseHook.OnSecondaryMouseUp -= MouseHook_OnSecondaryMouseUp;
|
||||
_mouseHook.OnMiddleMouseDown -= MouseHook_OnMiddleMouseDown;
|
||||
|
||||
if (_userSettings.ChangeCursor.Value)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,12 @@ namespace ColorPicker.Settings
|
||||
|
||||
SettingItem<ColorPickerActivationAction> ActivationAction { get; }
|
||||
|
||||
SettingItem<ColorPickerClickAction> PrimaryClickAction { get; }
|
||||
|
||||
SettingItem<ColorPickerClickAction> MiddleClickAction { get; }
|
||||
|
||||
SettingItem<ColorPickerClickAction> SecondaryClickAction { get; }
|
||||
|
||||
RangeObservableCollection<string> ColorHistory { get; }
|
||||
|
||||
SettingItem<int> ColorHistoryLimit { get; }
|
||||
|
||||
@@ -49,7 +49,10 @@ namespace ColorPicker.Settings
|
||||
ChangeCursor = new SettingItem<bool>(true);
|
||||
ActivationShortcut = new SettingItem<string>(DefaultActivationShortcut);
|
||||
CopiedColorRepresentation = new SettingItem<string>(ColorRepresentationType.HEX.ToString());
|
||||
ActivationAction = new SettingItem<ColorPickerActivationAction>(ColorPickerActivationAction.OpenEditor);
|
||||
ActivationAction = new SettingItem<ColorPickerActivationAction>(ColorPickerActivationAction.OpenColorPicker);
|
||||
PrimaryClickAction = new SettingItem<ColorPickerClickAction>(ColorPickerClickAction.PickColorThenEditor);
|
||||
MiddleClickAction = new SettingItem<ColorPickerClickAction>(ColorPickerClickAction.PickColorAndClose);
|
||||
SecondaryClickAction = new SettingItem<ColorPickerClickAction>(ColorPickerClickAction.Close);
|
||||
ColorHistoryLimit = new SettingItem<int>(20);
|
||||
ColorHistory.CollectionChanged += ColorHistory_CollectionChanged;
|
||||
ShowColorName = new SettingItem<bool>(false);
|
||||
@@ -78,6 +81,12 @@ namespace ColorPicker.Settings
|
||||
|
||||
public SettingItem<ColorPickerActivationAction> ActivationAction { get; private set; }
|
||||
|
||||
public SettingItem<ColorPickerClickAction> PrimaryClickAction { get; private set; }
|
||||
|
||||
public SettingItem<ColorPickerClickAction> MiddleClickAction { get; private set; }
|
||||
|
||||
public SettingItem<ColorPickerClickAction> SecondaryClickAction { get; private set; }
|
||||
|
||||
public RangeObservableCollection<string> ColorHistory { get; private set; } = new RangeObservableCollection<string>();
|
||||
|
||||
public SettingItem<int> ColorHistoryLimit { get; }
|
||||
@@ -121,6 +130,9 @@ namespace ColorPicker.Settings
|
||||
CopiedColorRepresentation.Value = settings.Properties.CopiedColorRepresentation;
|
||||
CopiedColorRepresentationFormat = new SettingItem<string>(string.Empty);
|
||||
ActivationAction.Value = settings.Properties.ActivationAction;
|
||||
PrimaryClickAction.Value = settings.Properties.PrimaryClickAction;
|
||||
MiddleClickAction.Value = settings.Properties.MiddleClickAction;
|
||||
SecondaryClickAction.Value = settings.Properties.SecondaryClickAction;
|
||||
ColorHistoryLimit.Value = settings.Properties.ColorHistoryLimit;
|
||||
ShowColorName.Value = settings.Properties.ShowColorName;
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ using ColorPicker.Settings;
|
||||
using ColorPicker.ViewModelContracts;
|
||||
using Common.UI;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Settings.UI.Library.Enumerations;
|
||||
using PowerToys.Interop;
|
||||
|
||||
namespace ColorPicker.ViewModels
|
||||
@@ -79,9 +80,10 @@ namespace ColorPicker.ViewModels
|
||||
{
|
||||
SetColorDetails(mouseInfoProvider.CurrentColor);
|
||||
mouseInfoProvider.MouseColorChanged += Mouse_ColorChanged;
|
||||
mouseInfoProvider.OnMouseDown += MouseInfoProvider_OnMouseDown;
|
||||
mouseInfoProvider.OnPrimaryMouseDown += MouseInfoProvider_OnPrimaryMouseDown;
|
||||
mouseInfoProvider.OnMouseWheel += MouseInfoProvider_OnMouseWheel;
|
||||
mouseInfoProvider.OnSecondaryMouseUp += MouseInfoProvider_OnSecondaryMouseUp;
|
||||
mouseInfoProvider.OnMiddleMouseDown += MouseInfoProvider_OnMiddleMouseDown;
|
||||
}
|
||||
|
||||
_userSettings.ShowColorName.PropertyChanged += (s, e) => { OnPropertyChanged(nameof(ShowColorName)); };
|
||||
@@ -113,7 +115,7 @@ namespace ColorPicker.ViewModels
|
||||
|
||||
private void AppStateHandler_EnterPressed(object sender, EventArgs e)
|
||||
{
|
||||
MouseInfoProvider_OnMouseDown(null, default(System.Drawing.Point));
|
||||
MouseInfoProvider_OnPrimaryMouseDown(null, default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,18 +169,50 @@ namespace ColorPicker.ViewModels
|
||||
SetColorDetails(color);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell the color picker that the user have press a mouse button (after release the button)
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of this event</param>
|
||||
/// <param name="p">The current <see cref="System.Drawing.Point"/> of the mouse cursor</param>
|
||||
private void MouseInfoProvider_OnMouseDown(object sender, System.Drawing.Point p)
|
||||
private void MouseInfoProvider_OnPrimaryMouseDown(object sender, IntPtr wParam)
|
||||
{
|
||||
ClipboardHelper.CopyToClipboard(ColorText);
|
||||
HandleMouseClickAction(_userSettings.PrimaryClickAction.Value);
|
||||
}
|
||||
|
||||
var color = GetColorString();
|
||||
private void MouseInfoProvider_OnMiddleMouseDown(object sender, IntPtr wParam)
|
||||
{
|
||||
HandleMouseClickAction(_userSettings.MiddleClickAction.Value);
|
||||
}
|
||||
|
||||
var oldIndex = _userSettings.ColorHistory.IndexOf(color);
|
||||
private void MouseInfoProvider_OnSecondaryMouseUp(object sender, IntPtr wParam)
|
||||
{
|
||||
HandleMouseClickAction(_userSettings.SecondaryClickAction.Value);
|
||||
}
|
||||
|
||||
private void HandleMouseClickAction(ColorPickerClickAction action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case ColorPickerClickAction.PickColorThenEditor:
|
||||
ClipboardHelper.CopyToClipboard(ColorText);
|
||||
UpdateColorHistory(GetColorString());
|
||||
|
||||
_appStateHandler.OpenColorEditor();
|
||||
|
||||
break;
|
||||
|
||||
case ColorPickerClickAction.PickColorAndClose:
|
||||
ClipboardHelper.CopyToClipboard(ColorText);
|
||||
UpdateColorHistory(GetColorString());
|
||||
|
||||
_appStateHandler.EndUserSession();
|
||||
|
||||
break;
|
||||
|
||||
case ColorPickerClickAction.Close:
|
||||
_appStateHandler.EndUserSession();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateColorHistory(string color)
|
||||
{
|
||||
int oldIndex = _userSettings.ColorHistory.IndexOf(color);
|
||||
if (oldIndex != -1)
|
||||
{
|
||||
_userSettings.ColorHistory.Move(oldIndex, 0);
|
||||
@@ -192,13 +226,6 @@ namespace ColorPicker.ViewModels
|
||||
{
|
||||
_userSettings.ColorHistory.RemoveAt(_userSettings.ColorHistory.Count - 1);
|
||||
}
|
||||
|
||||
_appStateHandler.OnColorPickerMouseDown();
|
||||
}
|
||||
|
||||
private void MouseInfoProvider_OnSecondaryMouseUp(object sender, IntPtr wParam)
|
||||
{
|
||||
_appStateHandler.EndUserSession();
|
||||
}
|
||||
|
||||
private string GetColorString()
|
||||
|
||||
Reference in New Issue
Block a user