简体   繁体   中英

Global low-level mouse hook doesn't get called when UWP desktop app is out of focus

I'm creating a desktop UWP app and I need to set a global low level mouse hook to detect and change the position of it when it is moved to certain locations of the screen.

It works fine while my app's window is in focus and the values get logged correctly to the output window(meaning that the hook is working correctly).

This UWP app isn't going to be on the store and will only be used on a Windows 10 desktop (1903+).

I've tried calling SetWindowsHookEx on a different thread (which didn't do anything). Tried also passing a thread ID when calling SetWindowsHookEx to no avail. Also tried using the following restricted capabilities to prevent the app to suspend when not on focus: extendedExecutionUnconstrained and extendedBackgroundTaskTime along with the PreventFromSuspending method shown here . Another thing I tried was to set uiAccess to true on the app manifest, which also didn't work.

The global hook is supposed to work even when the app isn't in the foreground, but instead it just works when it has the active window focus.

#region Structures

[StructLayout(LayoutKind.Sequential)]
/* MSLLHOOKSTRUCT */
public struct NativeMouseLowLevelHook
{
    public override string ToString()
    {
        return $"{nameof(Point)}: {Point}, {nameof(MouseData)}: {MouseData}, {nameof(Flags)}: {Flags}";
    }

    public NativePoint Point;
    public int MouseData;
    public int Flags;
    public int Time;
    public UIntPtr ExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
public class NativePoint
{
    public override string ToString()
    {
        return $"{nameof(X)}: {X}, {nameof(Y)}: {Y}";
    }

    public int X;
    public int Y;
}

#endregion
#region Hook

public class ManagedMouseHook : SafeHandleZeroOrMinusOneIsInvalid
{
    public static List<ManagedMouseHook> KnownHooks { get; set; } = new List<ManagedMouseHook>();

    public HookProc HookImpl { get; set; }

    public ManagedMouseHook() : base(true)
    {
        Hook();
    }

    private void Hook()
    {
        HookImpl = NativeHookCallback;
        KnownHooks.Add(this);
        using (var curProcess = Process.GetCurrentProcess())
        using (var curModule = curProcess.MainModule)
        {
            DoHook(curModule);
        }
    }

    private void DoHook(ProcessModule curModule)
    {
        SetHandle(SetWindowsHookEx(14 /*WH_MOUSE_LL*/, HookImpl, GetModuleHandle(curModule.ModuleName), 0));
    }

    private bool UnHook()
    {
        var result = UnhookWindowsHookEx(DangerousGetHandle());
        KnownHooks.Remove(this);
        HookImpl = null;
        return result;
    }

    /* LowLevelMouseProc */
    private IntPtr NativeHookCallback(int code, IntPtr wparam, IntPtr lparam)
    {
        if (code >= 0)
        {
            var info = (NativeMouseLowLevelHook) Marshal.PtrToStructure(lparam,
                typeof(NativeMouseLowLevelHook));

            Debug.WriteLine(info); //Output example: Point: X: 408, Y: 535, MouseData: 0, Flags: 0
            return new IntPtr(-1);
        }

        return CallNextHookEx(IntPtr.Zero, code, wparam, lparam);
    }

    protected override bool ReleaseHandle()
    {
        return UnHook();
    }
}

#endregion
#region Interop

public delegate IntPtr HookProc(int code, IntPtr wParam, IntPtr lParam);

[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int hookType, HookProc lpfn, IntPtr hMod, ulong dwThreadId);

[DllImport("user32.dll", SetLastError = true)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);

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

[DllImport("user32.dll")]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam,
    IntPtr lParam);

#endregion

Then, to start using it:

public ManagedMouseHook MouseHook { get; set; }
MouseHook/*property*/ = new ManagedMouseHook();

And to unhook:

MouseHook/*property*/.Close();

UWP apps are running in the sandbox, so that doesn't sound strange. If you think a bit it is a security problem if the app can receive such an input and as 'Security' is listed as No.1 characteristic of the UWP this behavior is expected.

我在评论的帮助下决定,最好的方法是使用我的 UWP 应用程序作为前端,并使用 win32 应用程序来实现挂钩功能本身。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM