WPF取色器开发

2022-03-13 09:34:56 浏览数 (1)

前言

这里全局的键盘钩子和全局鼠标钩子是为了定义快捷键。

获取鼠标坐标

代码语言:javascript复制
using System.Runtime.InteropServices;

namespace ColorPicker.Utils
{
    internal class ZPoint
    {
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern bool GetCursorPos(out POINT pt);

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }
        }
    }
}

调用方式

代码语言:javascript复制
ZPoint.POINT point;
ZPoint.GetCursorPos(out point);

获取坐标颜色

代码语言:javascript复制
using System;
using System.Drawing;
using System.Runtime.InteropServices;

namespace ColorPicker.Utils
{
    internal class ScreenColor
    {
        public static Color GetPixelColor(int x, int y)
        {
            IntPtr hdc = GetDC(IntPtr.Zero);
            uint pixel = GetPixel(hdc, x, y);
            ReleaseDC(IntPtr.Zero, hdc);
            Color color = Color.FromArgb((int)(pixel & 0x000000FF),
                         (int)(pixel & 0x0000FF00) >> 8,
                         (int)(pixel & 0x00FF0000) >> 16);
            return color;
        }

        [DllImport("user32.dll")]
        private static extern IntPtr GetDC(IntPtr hwnd);

        [DllImport("gdi32.dll")]
        private static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);

        [DllImport("user32.dll")]
        private static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
    }
}

调用方式

代码语言:javascript复制
private static bool isStart = false;        
/// <summary>
/// 上次的坐标点
/// </summary>
private ZPoint.POINT lastPoint;

/// <summary>
/// 取色
/// </summary>
private async void startTakeColor()
{
  if (!isStart)
  {
    isStart = true;
    while (isStart)
    {
      ZPoint.POINT point;
      ZPoint.GetCursorPos(out point);
      if (lastPoint.X != point.X || lastPoint.Y != point.Y)
      {
        lastPoint = point;
        System.Drawing.Color c = ScreenColor.GetPixelColor(point.X, point.Y);
        string html_color = System.Drawing.ColorTranslator.ToHtml(c);
        html_color_tb.Text = html_color;

        rgb_color_tb.Text = "RGB("   c.R   ","   c.G   ","   c.B   ")";
        color_tb.Background = (Brush)new BrushConverter().ConvertFrom(html_color);
        Clipboard.SetText(html_color);
      }
      await Task.Run(() => { Thread.Sleep(300); });
    }
  }
}

/// <summary>
/// 停止取色
/// </summary>
private void stopTakeColor()
{
  isStart = false;
}

全局键盘钩子

代码语言:javascript复制
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace ColorPicker.Utils
{
    /// <summary>
    /// 键盘全局钩子
    /// </summary>
    public class KeyboardHook
    {
        #region 常数和结构

        #region wParam对应的按钮事件

        public const int WM_KEYDOWN = 0x100;    // 键盘被按下
        public const int WM_KEYUP = 0x101;      // 键盘被松开
        public const int WM_SYSKEYDOWN = 0x104; // 键盘被按下,这个是系统键被按下,例如Alt、Ctrl等键
        public const int WM_SYSKEYUP = 0x105;   // 键盘被松开,这个是系统键被松开,例如Alt、Ctrl等键

        #endregion wParam对应的按钮事件

        public const int WH_KEYBOARD_LL = 13;

        [StructLayout(LayoutKind.Sequential)] //声明键盘钩子的封送结构类型
        public class KeyboardHookStruct

        {
            public int vkCode; //表示一个在1到254间的虚似键盘码
            public int scanCode; //表示硬件扫描码
            public int flags;
            public int time;
            public int dwExtraInfo;
        }

        #endregion 常数和结构

        #region 成员变量、委托、事件

        private static int hHook;
        private static HookProc KeyboardHookDelegate;

        // 锁
        private readonly object lockObject = new object();

        // 当前状态,是否已经启动
        private volatile bool isStart = false;

        // 键盘回调委托
        public delegate void KeyboardHandler(Int32 wParam, KeyboardHookStruct keyboardHookStruct);

        // 键盘回调事件
        private static event KeyboardHandler Handlers;

        #endregion 成员变量、委托、事件

        #region Win32的Api

        private delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

        //下一个钩挂的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention =
        CallingConvention.StdCall)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        //安装钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

        //卸下钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern bool UnhookWindowsHookEx(int idHook);

        #endregion Win32的Api

        #region 单例模式

        private static readonly object createLock = new object();
        private static volatile KeyboardHook MyKeyboard;

        private KeyboardHook()
        { }

        public static KeyboardHook GetKeyboardHook()
        {
            if (MyKeyboard == null)
            {
                lock (createLock)
                {
                    if (MyKeyboard == null)
                    {
                        MyKeyboard = new KeyboardHook();
                    }
                }
            }
            return MyKeyboard;
        }

        #endregion 单例模式

        /// <summary>
        /// 添加按键的回调函数
        /// </summary>
        /// <param name="handler">
        /// </param>
        public void AddKeyboardHandler(KeyboardHandler handler)
        {
            Handlers  = handler;
        }

        /// <summary>
        /// 删除指定按键的回调函数
        /// </summary>
        /// <param name="handler">
        /// </param>
        public void RemoveKeyboardHandler(KeyboardHandler handler)
        {
            if (Handlers != null)
            {
                Handlers -= handler;
            }
        }

        /// <summary>
        /// 安装钩子
        /// </summary>
        public void Start()
        {
            if (isStart)
            {
                return;
            }
            lock (lockObject)
            {
                if (isStart)
                {
                    return;
                }
                if (Handlers == null)
                {
                    throw new Exception("Please set handler first!Then run Start");
                }
                KeyboardHookDelegate = new HookProc(KeyboardHookProc);
                Process cProcess = Process.GetCurrentProcess();
                ProcessModule cModule = cProcess.MainModule;
                var mh = GetModuleHandle(cModule.ModuleName);
                hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookDelegate, mh, 0);
                isStart = true;
            }
        }

        /// <summary>
        /// 卸载钩子
        /// </summary>
        public void Stop()
        {
            if (!isStart)
            {
                return;
            }
            lock (lockObject)
            {
                if (!isStart)
                {
                    return;
                }
                UnhookWindowsHookEx(hHook);
                // 清除所有事件
                Handlers = null;
                isStart = false;
            }
        }

        /// <summary>
        /// 键盘的系统回调函数
        /// </summary>
        /// <param name="nCode">
        /// </param>
        /// <param name="wParam">
        /// </param>
        /// <param name="lParam">
        /// </param>
        /// <returns>
        /// </returns>
        private static int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            //如果该消息被丢弃(nCode<0)或者没有事件绑定处理程序则不会触发事件
            if ((nCode >= 0) && Handlers != null)
            {
                KeyboardHookStruct KeyDataFromHook = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
                Handlers(wParam, KeyDataFromHook);
            }
            return CallNextHookEx(hHook, nCode, wParam, lParam);
        }
    }
}

调用方式

代码语言:javascript复制
private static MainWindow mainWindow = null;
private KeyboardHook k_hook = KeyboardHook.GetKeyboardHook();

public void StartKeyboardHook()
{
  k_hook.AddKeyboardHandler(new KeyboardHook.KeyboardHandler(hookKeyboardEvent));
  k_hook.Start();
}

public void StopKeyboardHook()
{
  k_hook.Stop();
}

private static void hookKeyboardEvent(int wParam, KeyboardHook.KeyboardHookStruct keyboardHookStruct)
{
  if (keyboardHookStruct.vkCode == 164 && wParam == 0x101)
  {
    if (isStart)
    {
      mainWindow.stopTakeColor();
    }
    else
    {
      mainWindow.startTakeColor();
    }
  }
}

全局鼠标钩子

代码语言:javascript复制
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace ColorPicker.Utils
{
    /// <summary>
    /// 鼠标全局钩子
    /// </summary>
    public class MouseHook
    {
        private const int WM_MOUSEMOVE = 0x200;
        private const int WM_LBUTTONDOWN = 0x201;
        private const int WM_RBUTTONDOWN = 0x204;
        private const int WM_MBUTTONDOWN = 0x207;
        private const int WM_LBUTTONUP = 0x202;
        private const int WM_RBUTTONUP = 0x205;
        private const int WM_MBUTTONUP = 0x208;
        private const int WM_LBUTTONDBLCLK = 0x203;
        private const int WM_RBUTTONDBLCLK = 0x206;
        private const int WM_MBUTTONDBLCLK = 0x209;

        /// <summary>
        /// 点
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public class POINT
        {
            public int x;
            public int y;
        }

        /// <summary>
        /// 钩子结构体
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public class MouseHookStruct
        {
            public POINT pt;
            public int hWnd;
            public int wHitTestCode;
            public int dwExtraInfo;
        }

        public const int WH_MOUSE_LL = 14; // mouse hook constant

        // 装置钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);

        // 卸下钩子的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);

        // 下一个钩挂的函数
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

        // 键盘回调委托
        public delegate void MouseHandler(object sender, MouseEventArgs e, int downup);

        // 键盘回调事件
        private static event MouseHandler Handlers;

        // 钩子回调函数
        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

        // 声明鼠标钩子事件类型
        private HookProc _mouseHookProcedure;

        private static int _hMouseHook = 0; // 鼠标钩子句柄

        /// <summary>
        /// 构造函数
        /// </summary>
        public MouseHook()
        {
        }

        /// <summary>
        /// 析构函数
        /// </summary>
        ~MouseHook()
        {
            Stop();
        }

        /// <summary>
        /// 启动全局钩子
        /// </summary>
        public void Start()
        {
            // 安装鼠标钩子
            if (_hMouseHook == 0)
            {
                if (Handlers == null)
                {
                    throw new Exception("Please set handler first!Then run Start");
                }
                // 生成一个HookProc的实例.
                _mouseHookProcedure = new HookProc(MouseHookProc);

                _hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, _mouseHookProcedure, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]), 0);

                //假设装置失败停止钩子
                if (_hMouseHook == 0)
                {
                    Stop();
                    throw new Exception("SetWindowsHookEx failed.");
                }
            }
        }

        /// <summary>
        /// 停止全局钩子
        /// </summary>
        public void Stop()
        {
            bool retMouse = true;

            if (_hMouseHook != 0)
            {
                retMouse = UnhookWindowsHookEx(_hMouseHook);
                _hMouseHook = 0;
            }

            // 假设卸下钩子失败
            if (!(retMouse))
                throw new Exception("UnhookWindowsHookEx failed.");
        }

        /// <summary>
        /// 添加按键的回调函数
        /// </summary>
        /// <param name="handler">
        /// </param>
        public void AddMouseHandler(MouseHandler handler)
        {
            Handlers  = handler;
        }

        /// <summary>
        /// 鼠标钩子回调函数
        /// </summary>
        private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            // 假设正常执行而且用户要监听鼠标的消息
            if ((nCode >= 0) && (Handlers != null))
            {
                MouseButtons button = MouseButtons.None;
                int clickCount = 0;
                int downup = 0;//0 down 1 up

                switch (wParam)
                {
                    case WM_LBUTTONDOWN:
                        button = MouseButtons.Left;
                        clickCount = 1;

                        break;

                    case WM_LBUTTONUP:
                        button = MouseButtons.Left;
                        clickCount = 1;
                        downup = 1;
                        break;

                    case WM_LBUTTONDBLCLK:
                        button = MouseButtons.Left;
                        clickCount = 2;
                        break;

                    case WM_RBUTTONDOWN:
                        button = MouseButtons.Right;
                        clickCount = 1;

                        break;

                    case WM_RBUTTONUP:
                        button = MouseButtons.Right;
                        clickCount = 1;
                        downup = 1;
                        break;

                    case WM_RBUTTONDBLCLK:
                        button = MouseButtons.Right;
                        clickCount = 2;
                        break;
                }

                // 从回调函数中得到鼠标的信息
                MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
                MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);

                Handlers(this, e, downup);
            }

            // 启动下一次钩子
            return CallNextHookEx(_hMouseHook, nCode, wParam, lParam);
        }
    }
}

调用方式

代码语言:javascript复制
private static MainWindow mainWindow = null;
private MouseHook m_hook = new MouseHook();

public void StartMouseHook()
{
  m_hook.AddMouseHandler(new MouseHook.MouseHandler(hookMouseEvent));
  m_hook.Start();
}

public void StopMouseHook()
{
  m_hook.Stop();
}

private static void hookMouseEvent(object sender, System.Windows.Forms.MouseEventArgs e, int downup)
{
  if (e.Button == System.Windows.Forms.MouseButtons.Left && downup == 1)
  {
    mainWindow.stopTakeColor();
  }
}

0 人点赞