使用 WPF 进行全局事件监控

问题描述 投票:0回答:1

我想在这件事上寻求帮助:在WPF中,我想监视keydown、mousedown和mousewheel事件,即使窗口当前不是活动的。我在WPF中使用c#。我尝试了在互联网上找到的很多东西,但没有一个起作用,假设没有关于这个主题的任何材料。我尝试的最后一个是:

namespace GlobalInputEvents
{
    public partial class MainWindow : Window
    {
        private LowLevelKeyboardListener _keyboardListener;

        public MainWindow()
        {
            InitializeComponent();

            _keyboardListener = new LowLevelKeyboardListener();
            _keyboardListener.OnKeyPressed += GlobalKeyDownHandler;
            _keyboardListener.HookKeyboard();

            this.Loaded += (sender, e) =>
            {
                // Az egér események kezelése
                this.PreviewMouseDown += GlobalMouseDownHandler;
                this.PreviewMouseWheel += GlobalMouseWheelHandler;
            };
        }

        private void GlobalKeyDownHandler(object sender, KeyEventArgs e)
        {
            MessageBox.Show("A billentyűt megnyomták a háttérben is! Billentyű: " + e.Key);
        }

        private void GlobalMouseDownHandler(object sender, MouseButtonEventArgs e)
        {
            MessageBox.Show("Az egérgombot lenyomták a háttérben is! Gomb: " + e.ChangedButton);
        }

        private void GlobalMouseWheelHandler(object sender, MouseWheelEventArgs e)
        {
            MessageBox.Show("Az egér görgőjét használták a háttérben is! Görgetés: " + e.Delta);
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            _keyboardListener.UnHookKeyboard();
        }
    }
}

namespace GlobalInputEvents
{
    public class LowLevelKeyboardListener
    {
        private const int WH_KEYBOARD_LL = 13;
        private const int WM_KEYDOWN = 0x0100;

        private readonly LowLevelKeyboardProc _proc;
        private IntPtr _hookID = IntPtr.Zero;

        public event EventHandler<KeyEventArgs> OnKeyPressed;

        public LowLevelKeyboardListener()
        {
            _proc = HookCallback;
        }

        public void HookKeyboard()
        {
            _hookID = SetHook(_proc);
        }

        public void UnHookKeyboard()
        {
            UnhookWindowsHookEx(_hookID);
        }

        private IntPtr SetHook(LowLevelKeyboardProc proc)
        {
            using (var curProcess = System.Diagnostics.Process.GetCurrentProcess())
            using (var curModule = curProcess.MainModule)
            {
                return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
            }
        }

        private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
            {
                int vkCode = Marshal.ReadInt32(lParam);
                OnKeyPressed?.Invoke(this, new KeyEventArgs(KeyInterop.KeyFromVirtualKey(vkCode)));
            }
            return CallNextHookEx(_hookID, nCode, wParam, lParam);
        }

        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

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

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private 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);
    }
}
c# wpf event-handling monitoring global
1个回答
0
投票

你做的一切都是对的,但是你得到的窗口句柄是错误的,在WPF中有一个类提供窗口指针来处理操作系统事件:

WindowInteropHelper
所以要解决这个问题你需要

  1. 在MainWindow构造函数中调用
    new WindowInteropHelper(this).Handle
    之前获取指向wpf窗口的指针
    HookKeyboard
  2. IntPtr hwnd
    方法中添加参数
    HookKeyboard
  3. 使用步骤 2 中的 hwnd 调用
    SetWindowsHookEx
  4. 删除
using (var curProcess = System.Diagnostics.Process.GetCurrentProcess())
using (var curModule = curProcess.MainModule)
© www.soinside.com 2019 - 2024. All rights reserved.