SetWindowsHookEx с WH_MOUSE_LL замедляет мышь на несколько секунд - PullRequest
3 голосов
/ 12 июля 2010

Я использую следующий код для получения сообщений мыши о текущем процессе.

using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
    return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}

По какой-то причине, когда этот код запускается, мышь замедляется на несколько секунд, а затем возвращается в нормальное состояние.

Есть идеи?
Спасибо

РЕДАКТИРОВАТЬ - метод крюка

private static IntPtr mouseEvent(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
    {
        MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));     
        LastLeftClick = new ClickInfo { Time = DateTime.Now, X = hookStruct.pt.x, Y = hookStruct.pt.y };
    }
    return CallNextHookEx(hookID, nCode, wParam, lParam);
}

public class ClickInfo
{
    public int X { get; set; }
    public int Y { get; set; }
    public DateTime Time { get; set; }
}

Ответы [ 6 ]

2 голосов
/ 21 октября 2011

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

SetHook
LongRunningStartupProcess
Мышь не реагирует, пока здесь

Во время запуска лучше всего направить крючок на нить, чтобы это произошло в конце процесса запуска. Dispatcher.CurrentDispatcher.BeginInvoke(new Action(SetHook));

DispatchSetHook
LongRunningStartupProcess
SetHook (обратный вызов)
Мышь становится отзывчивой

В приложении по-прежнему сохраняются проблемы с управлением, чтобы основной поток не выполнял никаких длительных процессов, поскольку это также блокирует мышь. В этом легко убедиться, установив зацепку, а затем выполнить Thread.Sleep в главном потоке.

2 голосов
/ 20 июля 2010

У меня была та же проблема (только это проект c ++, а не c #), и я решил ее, изменив ловушку с WH_MOUSE_LL на WH_MOUSE (с низкого уровня на нормальный уровень). Для сообщений WM_LBUTTONUP и WM_RBUTTONUP это работает нормально.

Меня удивляет то, что код с WH_MOUSE_LL работал хорошо, когда я его писал (без зависания мыши и т. Д.) Похоже, что какое-то обновление безопасности для Windows изменило поведение ловушек мыши, и ранее прекрасный код стал проблема.

2 голосов
/ 12 июля 2010

Как выглядит ваша подключаемая процедура?

Если ваш процесс имеет только один поток пользовательского интерфейса, используйте вместо этого фильтр сообщений: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx

1 голос
/ 24 февраля 2011

Когда вы получаете событие ловушки, выключите книгу, затем сделайте свою работу, и, если действительно необходимо, установите крючок обратно.

Это предотвратит отставание мыши.

Оставайтесь на связи только тогда, когда вам действительно нужно.

1 голос
/ 20 июля 2010

Ваш крюк проц стоит дорого; вам просто нужно выяснить, почему и как это исправить.

Несмотря на то, что код выглядит очень минимальным, я подозреваю, что некоторые начальные затраты на взаимодействие с C # вызывают задержки, возможно, из-за JIT или подкачки.

Если вы измените код для выполнения максимально возможной обработки этого потока, проблема должна исчезнуть. как разработчик C ++ я даже беспокоюсь о Marshal.PtrToStructure, так как низкоуровневые хуки очень чувствительны, и я не могу сказать, что эта операция гарантированно будет настолько дешевой, что не будет мешать движению мыши.

В прошлом я довольно часто использовал низкоуровневые хуки для мыши (в C ++), и у меня никогда не было проблем, если сама процедура хука не стоит дорого. В C ++ я стараюсь не делать ничего, кроме PostMessage для HWND, который выполняет остальную часть обработки.

0 голосов
/ 06 сентября 2018

Прошу прощения, что по прошествии такого долгого времени продолжаю, но я решил проблему, создав отдельный поток, который обрабатывает ловушку (я не добавил все в код, поскольку он также переводит сообщения, но основная идея должна быть ясной ):

    public Form1()
    {
        InitializeComponent();

        Thread thread = new Thread(HookThread);
        thread.IsBackground = true;
        thread.Start();
    }

    private void HookThread()
    {
        _hookControl = new Control();
        IntPtr handle = _hookControl.Handle;

        _hookProc = new HookProc(HookFunction);
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            _hook = SetWindowsHookEx(HookType.WH_MOUSE_LL, _hookProc, GetModuleHandle(curModule.ModuleName), 0);// (uint)AppDomain.GetCurrentThreadId());
        }

        Application.Run();

        UnhookWindowsHookEx(_hook);
        _hook = IntPtr.Zero;
    }

    private IntPtr HookFunction(int code, IntPtr wParam, IntPtr lParam)
    {
        if (code < 0)
        {
            //you need to call CallNextHookEx without further processing
            //and return the value returned by CallNextHookEx
            return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
        }

        int msg = wParam.ToInt32();
        string messages = string.Join(", ", _messageMapping.Where(t => t.Item1 == msg).Select(t => t.Item2));
        if (string.IsNullOrWhiteSpace(messages))
            messages = msg.ToString();
        Trace.WriteLine($"Messages: { messages }");

        //return the value returned by CallNextHookEx
        return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
    }

Вы можете прервать поток из любого другого потока, вызвав BeginInvoke для созданного _hookControl:

        _hookControl.BeginInvoke(((Action)(() => Application.ExitThread())));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...