From a8aa1a45253671f51cd8361550b2f46386ef61fc Mon Sep 17 00:00:00 2001
From: NaBian <836904362@qq.com>
Date: Tue, 14 May 2019 23:03:14 +0800
Subject: [PATCH] add ColorDropper
---
.../Controls/ColorPicker/ColorDropper.cs | 66 ++++++++++++++++++-
.../Controls/ColorPicker/ColorPicker.cs | 23 ++-----
.../Data/Args/MouseHookEventArgs.cs | 12 ++++
.../Data/Enum/MouseHookMessageType.cs | 12 ++++
.../HandyControl_Shared.projitems | 3 +
.../Tools/Hook/MouseHook.cs | 49 ++++++++++++--
.../Tools/Interop/UnsafeNativeMethods.cs | 40 +++++++++++
7 files changed, 180 insertions(+), 25 deletions(-)
create mode 100644 src/Shared/HandyControl_Shared/Data/Args/MouseHookEventArgs.cs
create mode 100644 src/Shared/HandyControl_Shared/Data/Enum/MouseHookMessageType.cs
diff --git a/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorDropper.cs b/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorDropper.cs
index 9c8d5459..4b6f48f4 100644
--- a/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorDropper.cs
+++ b/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorDropper.cs
@@ -1,9 +1,69 @@
-using System.Windows.Controls;
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using HandyControl.Data;
+using HandyControl.Tools;
+using HandyControl.Tools.Interop;
namespace HandyControl.Controls
{
- public class ColorDropper : Control
+ internal class ColorDropper : Control
{
-
+ private Cursor _dropperCursor;
+
+ private readonly ColorPicker _colorPicker;
+
+ public ColorDropper(ColorPicker colorPicker)
+ {
+ _colorPicker = colorPicker;
+ }
+
+ public void Update(bool isShow)
+ {
+ if (isShow)
+ {
+ if (_dropperCursor == null)
+ {
+ var info = Application.GetResourceStream(
+ new Uri("pack://application:,,,/HandyControl;Component/Resources/dropper.cur"));
+ if (info != null)
+ {
+ _dropperCursor = new Cursor(info.Stream);
+ }
+ }
+
+ if (_dropperCursor == null) return;
+
+ Mouse.OverrideCursor = _dropperCursor;
+ MouseHook.Start();
+ MouseHook.StatusChanged += MouseHook_StatusChanged;
+ }
+ else
+ {
+ Mouse.OverrideCursor = Cursors.Arrow;
+ }
+ }
+
+ private void MouseHook_StatusChanged(object sender, MouseHookEventArgs e)
+ {
+ if (!_colorPicker.IsMouseOver && e.Message == MouseHookMessageType.LeftButtonDown)
+ {
+ var brush = new SolidColorBrush(GetColorAt(e.Point.X, e.Point.Y));
+ _colorPicker.SelectedBrush = brush;
+ //MouseHook.Stop();
+ //MouseHook.StatusChanged -= MouseHook_StatusChanged;
+ }
+ }
+
+ public static Color GetColorAt(int x, int y)
+ {
+ var desk = UnsafeNativeMethods.GetDesktopWindow();
+ var dc = UnsafeNativeMethods.GetWindowDC(desk);
+ var a = (int)UnsafeNativeMethods.GetPixel(dc, x, y);
+ UnsafeNativeMethods.ReleaseDC(desk, dc);
+ return Color.FromArgb(255, (byte) ((a >> 0) & 0xff), (byte) ((a >> 8) & 0xff), (byte) ((a >> 16) & 0xff));
+ }
}
}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs b/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs
index ef1a39f1..695e0566 100644
--- a/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs
+++ b/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs
@@ -41,7 +41,7 @@ namespace HandyControl.Controls
#region Data
- private Cursor _dropperCursor;
+ private ColorDropper _colorDropper;
private ToggleButton _toggleButtonDropper;
@@ -696,25 +696,12 @@ namespace HandyControl.Controls
private void ToggleButtonDropper_Click(object sender, RoutedEventArgs e)
{
- if (_toggleButtonDropper.IsChecked == true)
+ if (_colorDropper == null)
{
- if (_dropperCursor == null)
- {
- var info = Application.GetResourceStream(new Uri("pack://application:,,,/HandyControl;Component/Resources/dropper.cur"));
- if (info != null)
- {
- _dropperCursor = new Cursor(info.Stream);
- }
- }
-
- if (_dropperCursor == null) return;
-
- Mouse.OverrideCursor = _dropperCursor;
- }
- else
- {
- Mouse.OverrideCursor = Cursors.Arrow;
+ _colorDropper = new ColorDropper(this);
}
+ // ReSharper disable once PossibleInvalidOperationException
+ _colorDropper.Update(_toggleButtonDropper.IsChecked.Value);
}
public void Dispose() => System.Windows.Window.GetWindow(this)?.Close();
diff --git a/src/Shared/HandyControl_Shared/Data/Args/MouseHookEventArgs.cs b/src/Shared/HandyControl_Shared/Data/Args/MouseHookEventArgs.cs
new file mode 100644
index 00000000..9c6b03fd
--- /dev/null
+++ b/src/Shared/HandyControl_Shared/Data/Args/MouseHookEventArgs.cs
@@ -0,0 +1,12 @@
+using System;
+using HandyControl.Tools.Interop;
+
+namespace HandyControl.Data
+{
+ internal class MouseHookEventArgs : EventArgs
+ {
+ public MouseHookMessageType Message { get; set; }
+
+ public NativeMethods.POINT Point { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/Data/Enum/MouseHookMessageType.cs b/src/Shared/HandyControl_Shared/Data/Enum/MouseHookMessageType.cs
new file mode 100644
index 00000000..4eeb302d
--- /dev/null
+++ b/src/Shared/HandyControl_Shared/Data/Enum/MouseHookMessageType.cs
@@ -0,0 +1,12 @@
+namespace HandyControl.Data
+{
+ public enum MouseHookMessageType
+ {
+ LeftButtonDown = 0x0201,
+ LeftButtonUp = 0x0202,
+ MouseMove = 0x0200,
+ MouseWheel = 0x020A,
+ RightButtonDown = 0x0204,
+ RightButtonUp = 0x0205
+ }
+}
\ No newline at end of file
diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems
index 57aa662b..39535ac9 100644
--- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems
+++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems
@@ -113,6 +113,7 @@
+
@@ -136,6 +137,7 @@
+
@@ -244,6 +246,7 @@
+
diff --git a/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs b/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs
index deab86c1..e7e2d0d1 100644
--- a/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs
+++ b/src/Shared/HandyControl_Shared/Tools/Hook/MouseHook.cs
@@ -1,7 +1,48 @@
-namespace HandyControl.Tools
-{
- public class MouseHook
- {
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using HandyControl.Data;
+using HandyControl.Tools.Interop;
+namespace HandyControl.Tools
+{
+ internal class MouseHook
+ {
+ public static event EventHandler StatusChanged;
+
+ private static IntPtr HookId = IntPtr.Zero;
+
+ private static readonly UnsafeNativeMethods.HookProc Proc = HookCallback;
+
+ public static void Start() => HookId = SetHook(Proc);
+
+ public static void Stop() => UnsafeNativeMethods.UnhookWindowsHookEx(HookId);
+
+ private static IntPtr SetHook(UnsafeNativeMethods.HookProc proc)
+ {
+ using (var curProcess = Process.GetCurrentProcess())
+ using (var curModule = curProcess.MainModule)
+ {
+ if (curModule != null)
+ {
+ return UnsafeNativeMethods.SetWindowsHookEx((int) UnsafeNativeMethods.HookType.WH_MOUSE_LL, proc,
+ UnsafeNativeMethods.GetModuleHandle(curModule.ModuleName), 0);
+ }
+ return IntPtr.Zero;
+ }
+ }
+
+ private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
+ {
+ if (nCode < 0) return UnsafeNativeMethods.CallNextHookEx(HookId, nCode, wParam, lParam);
+ var hookStruct = (UnsafeNativeMethods.MOUSEHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(UnsafeNativeMethods.MOUSEHOOKSTRUCT));
+ StatusChanged?.Invoke(null, new MouseHookEventArgs
+ {
+ Message = (MouseHookMessageType)wParam,
+ Point = new NativeMethods.POINT(hookStruct.pt.X, hookStruct.pt.Y)
+ });
+
+ return UnsafeNativeMethods.CallNextHookEx(HookId, nCode, wParam, lParam);
+ }
}
}
diff --git a/src/Shared/HandyControl_Shared/Tools/Interop/UnsafeNativeMethods.cs b/src/Shared/HandyControl_Shared/Tools/Interop/UnsafeNativeMethods.cs
index a88f2d1b..1c893525 100644
--- a/src/Shared/HandyControl_Shared/Tools/Interop/UnsafeNativeMethods.cs
+++ b/src/Shared/HandyControl_Shared/Tools/Interop/UnsafeNativeMethods.cs
@@ -174,5 +174,45 @@ namespace HandyControl.Tools.Interop
[DllImport(ExternDll.User32, ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ [DllImport(ExternDll.User32, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
+
+ [DllImport(ExternDll.Kernel32, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern IntPtr GetModuleHandle(string lpModuleName);
+
+ [DllImport(ExternDll.User32, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern bool UnhookWindowsHookEx(IntPtr hhk);
+
+ public enum HookType
+ {
+ WH_MOUSE_LL = 14,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct MOUSEHOOKSTRUCT
+ {
+ public NativeMethods.POINT pt;
+ public IntPtr hwnd;
+ public uint wHitTestCode;
+ public IntPtr dwExtraInfo;
+ }
+
+ public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);
+
+ [DllImport(ExternDll.User32, CharSet = CharSet.Auto, SetLastError = true)]
+ public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId);
+
+ [DllImport(ExternDll.User32, SetLastError = true)]
+ public static extern IntPtr GetDesktopWindow();
+
+ [DllImport(ExternDll.User32, SetLastError = true)]
+ public static extern IntPtr GetWindowDC(IntPtr window);
+
+ [DllImport(ExternDll.Gdi32, SetLastError = true)]
+ public static extern uint GetPixel(IntPtr dc, int x, int y);
+
+ [DllImport(ExternDll.User32, SetLastError = true)]
+ public static extern int ReleaseDC(IntPtr window, IntPtr dc);
}
}
\ No newline at end of file