You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使LowLevelKeyboardProc/LowLevelMouseProc仅对聚焦应用生效而非全局?

Make LowLevelMouseProc Only Active for Target Focused Application

Got it, let's tweak your code so that your mouse hook only blocks clicks when your target app is the focused (foreground) window—no more global blocking! Here's how to do it step by step:

Core Idea

The solution boils down to three key steps:

  • Define your target application (by process name or PID)
  • In your hook callback, check if the current foreground window belongs to the target process
  • Only intercept mouse events if the target app is active; otherwise, let the event pass through normally

Modified Implementation

We'll add new WinAPI calls to get the foreground window and its associated process ID, then update your MouseHook class to include a target process identifier and logic to validate the active window before blocking events. Here's the updated code with comments highlighting changes:

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace GlobalLowLevelHooks
{
    public class MouseHook
    {
        public bool enabled = false;
        // Add this property to set your target app's process name (e.g., "notepad.exe")
        public string TargetProcessName { get; set; }

        public delegate IntPtr MouseHookHandler(int nCode, IntPtr wParam, IntPtr lParam);
        public MouseHookHandler hookHandler;
        public delegate void MouseHookCallback(MSLLHOOKSTRUCT mouseStruct);

        #region Events
        public event MouseHookCallback LeftButtonDown;
        public event MouseHookCallback LeftButtonUp;
        public event MouseHookCallback RightButtonDown;
        public event MouseHookCallback RightButtonUp;
        public event MouseHookCallback MouseMove;
        public event MouseHookCallback MouseWheel;
        public event MouseHookCallback DoubleClick;
        public event MouseHookCallback MiddleButtonDown;
        public event MouseHookCallback MiddleButtonUp;
        #endregion

        public IntPtr hookID = IntPtr.Zero;

        public void Enable()
        {
            hookHandler = HookFunc;
            hookID = SetHook(hookHandler);
            enabled = true;
        }

        public void Disable()
        {
            if (hookID == IntPtr.Zero) return;
            UnhookWindowsHookEx(hookID);
            hookID = IntPtr.Zero;
            enabled = false;
        }

        ~MouseHook()
        {
            Disable(); // Fixed typo here—was Enable(), should clean up the hook instead
        }

        private IntPtr SetHook(MouseHookHandler proc)
        {
            using (ProcessModule module = Process.GetCurrentProcess().MainModule)
                return SetWindowsHookEx(WH_MOUSE_LL, proc, GetModuleHandle(module.ModuleName), 0);
        }

        private IntPtr HookFunc(int nCode, IntPtr wParam, IntPtr lParam)
        {
            // Only process events if hook is valid and target is set
            if (nCode >= 0 && !string.IsNullOrEmpty(TargetProcessName))
            {
                // Check if the focused window belongs to our target app
                if (IsTargetAppActive())
                {
                    // Block mouse clicks only when target is active
                    MouseMessages message = (MouseMessages)wParam;
                    if (message is MouseMessages.WM_LBUTTONDOWN 
                        or MouseMessages.WM_RBUTTONDOWN 
                        or MouseMessages.WM_MBUTTONDOWN 
                        or MouseMessages.WM_LBUTTONDBLCLK)
                    {
                        return (IntPtr)1; // Block the event from reaching the app
                    }
                }
            }
            // Pass event through if target isn't active or hook is invalid
            return CallNextHookEx(hookID, nCode, wParam, lParam);
        }

        // Helper method to verify if target app is in focus
        private bool IsTargetAppActive()
        {
            IntPtr foregroundWindow = GetForegroundWindow();
            if (foregroundWindow == IntPtr.Zero) return false;

            GetWindowThreadProcessId(foregroundWindow, out uint processId);
            if (processId == 0) return false;

            try
            {
                using (Process process = Process.GetProcessById((int)processId))
                {
                    // Match process name (ignore .exe extension case)
                    return process.ProcessName.Equals(
                        TargetProcessName.TrimEnd('.', 'e', 'x', 'e'), 
                        StringComparison.OrdinalIgnoreCase);
                }
            }
            catch (ArgumentException)
            {
                // Process might have exited since we checked
                return false;
            }
        }

        #region WinAPI
        private const int WH_MOUSE_LL = 14;

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201,
            WM_LBUTTONUP = 0x0202,
            WM_MOUSEMOVE = 0x0200,
            WM_MOUSEWHEEL = 0x020A,
            WM_RBUTTONDOWN = 0x0204,
            WM_RBUTTONUP = 0x0205,
            WM_LBUTTONDBLCLK = 0x0203,
            WM_MBUTTONDOWN = 0x0207,
            WM_MBUTTONUP = 0x0208
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int x;
            public int y;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct MSLLHOOKSTRUCT
        {
            public POINT pt;
            public uint mouseData;
            public uint flags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, MouseHookHandler lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

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

        // Added WinAPI functions to get foreground window and its process ID
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
        #endregion
    }
}

Key Changes Breakdown

  1. TargetProcessName Property: Lets you specify which app to target (e.g., "notepad.exe" or just "notepad"—the helper method handles both formats).
  2. IsTargetAppActive() Helper: Uses GetForegroundWindow() to grab the current focused window, then GetWindowThreadProcessId() to get its PID, and checks if the process name matches your target.
  3. Hook Logic Update: Only blocks mouse events if the target app is active. If not, it calls CallNextHookEx to let the event proceed to whatever app is focused.
  4. Fixed Destructor: Changed Enable() to Disable() in the finalizer to properly clean up the hook when the object is disposed.

How to Use It

Initialize the hook and set your target before enabling it:

var mouseHook = new MouseHook();
mouseHook.TargetProcessName = "your-target-app.exe"; // Replace with your app's process name
mouseHook.Enable();

Quick Notes

  • If you need to target a specific instance of an app (instead of all instances), swap the TargetProcessName property for a TargetProcessId property and adjust the IsTargetAppActive() method to compare PIDs directly.
  • Low-level hooks run in your app's context, so make sure your app stays running for the hook to work.

内容的提问来源于stack exchange,提问作者Mark Aven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:53:23