Отслеживание цвета пикселя на экране

Рейтинг: 0Ответов: 1Опубликовано: 26.07.2023

У меня есть код, который представлен ниже. Помогите сделать так, что бы отслеживание цвета происходила самостоятельно в определённой области, без нажатия на мышь. Если что то будет не понятно постараюсь объяснить.

using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using Gma.System.MouseKeyHook;

public class ColorTracker : Form
{
    private const int VK_A = 0x41;
    private const int VK_D = 0x44;
    private const int KEY_DOWN = 0x8000;

    private int tolerance = 5;
    private Color targetColorMin = Color.FromArgb(0, 255, 0);
    private Color targetColorMax = Color.FromArgb(255, 255, 255);
    private bool scriptActivated = false;
    private Button startStopButton;
    private IKeyboardMouseEvents globalHook;

    [DllImport("user32.dll")]
    private static extern short GetAsyncKeyState(int vKey);

    public ColorTracker()
    {
        SetupUI();

        // Инициализация глобальных хуков
        globalHook = Hook.GlobalEvents();

        // Подписываемся на события перемещения мыши и ввода с клавиатуры
        globalHook.MouseDownExt += GlobalHookMouseDownExt;
        globalHook.KeyPress += GlobalHookKeyPress;
    }

    private void SetupUI()
    {
        startStopButton = new Button();
        startStopButton.Text = "Запустить";
        startStopButton.Click += StartStopButton_Click;

        this.Controls.Add(startStopButton);
    }

    private void StartStopButton_Click(object sender, EventArgs e)
    {
        scriptActivated = !scriptActivated;
        startStopButton.Text = scriptActivated ? "Остановить" : "Запустить";
    }

    private void GlobalHookMouseDownExt(object sender, MouseEventExtArgs e)
    {
        // При нажатии мыши проверяем цвет в текущей позиции курсора
        if (scriptActivated)
        {
            Color pixelColor = GetPixelColor(e.X, e.Y);

            if (IsColorInRange(pixelColor, targetColorMin, targetColorMax))
            {
                // Делаем что-то на основе совпадения цвета
                // Например:
                if (IsColorCloseToWhite(pixelColor))
                {
                    SendKeys.SendWait("d");
                }
                else
                {
                    SendKeys.SendWait("a");
                }
            }
        }
    }

    private void GlobalHookKeyPress(object sender, KeyPressEventArgs e)
    {
        // При нажатии клавиши можно обработать это глобально, если необходимо
        // Например, можно остановить скрипт при нажатии определенной клавиши
        if (e.KeyChar == 'x')
        {
            scriptActivated = false;
            startStopButton.Text = "Запустить";
        }
    }

    private Color GetPixelColor(int x, int y)
    {
        using (Bitmap bmp = new Bitmap(1, 1))
        {
            using (Graphics g = Graphics.FromImage(bmp))
            {
                g.CopyFromScreen(new Point(x, y), Point.Empty, new Size(1, 1));
            }
            return bmp.GetPixel(0, 0);
        }
    }

    private bool IsColorInRange(Color color, Color min, Color max)
    {
        return color.R >= min.R - tolerance && color.R <= max.R + tolerance
            && color.G >= min.G - tolerance && color.G <= max.G + tolerance
            && color.B >= min.B - tolerance && color.B <= max.B + tolerance;
    }

    private bool IsColorCloseToWhite(Color color)
    {
        return color.R >= 230 && color.G >= 230 && color.B >= 230;
    }

    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new ColorTracker());
    }
}

Ответы

▲ 0Принят

Можно по тыку мышкой запустить цикл, скажем раз в секунду.

private bool isWorking;

private async void GlobalHookMouseDownExt(object sender, MouseEventExtArgs e)
{
    if (isWorking)
    {
        isWorking = false;
        return;
    }
    if (!scriptActivated)
        return;
    isWorking = true;

    while (isWorking && scriptActivated)
    {
        Color pixelColor = GetPixelColor(e.Location);

        if (IsColorInRange(pixelColor, targetColorMin, targetColorMax))
        {
            if (IsColorCloseToWhite(pixelColor))
            {
                SendKeys.SendWait("d");
            }
            else
            {
                SendKeys.SendWait("a");
            }
        }
        await Task.Delay(1000); // пауза 1 секунда
    }
    isWorking = false;
}

То есть нажал на мышь, начало работать раз в секунду. Нажал еще раз - прекратило.

По-хорошему, сюда бы CancellationToken прикрутить для верности, пример здесь, это позволит прерывать Delay немедленно. Но вы уж сами решайте, как лучше.

И взятие цвета можно слегка оптимизировать

private readonly Bitmap bufferBmp = new Bitmap(1, 1);

private Color GetPixelColor(Point location)
{
    using (Graphics g = Graphics.FromImage(bufferBmp))
    {
        g.CopyFromScreen(location, Point.Empty, bufferBmp.Size);
    }
    return bufferBmp.GetPixel(0, 0);
}

Незачем создавать новый битмап на каждый пиксель, это ресурсозатратное занятие.