/// <summary> /// Distinguish between touch, pen, or mouse pointer events. /// https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320(v=vs.85).aspx /// </summary> /// <param name="hookData">Hook data to check</param> /// <returns>Identified mouse event source</returns> private static EventSource GetMouseEventSource(WinApi.MSLLHOOKSTRUCT hookData) { uint extra = (uint)hookData.dwExtraInfo; bool isTouchOrPen = ((extra & 0xFFFFFF00) == 0xFF515700); if (!isTouchOrPen) { return(EventSource.Mouse); } bool isTouch = ((extra & 0x00000080) == 0x00000080); return(isTouch ? EventSource.Touch : EventSource.Pen); }
/// <summary> /// Intercepts mouse events, giving the option to change or swallow them. /// This is gives extremely bad experience if/when the app hangs (i.e. debugger break), /// as mouse events won't be processed, rendering mouse unusable until CallNextHookEx /// is called. Fortunately, the OS will fix this by probably unregistering /// the hook... /// @TODO Minimize usage or find anternative. /// </summary> /// <param name="code"></param> /// <param name="wParam"></param> /// <param name="lParam"></param> /// <returns></returns> private IntPtr HookCallback(int code, IntPtr wParam, IntPtr lParam) { if (OnMouseLeaveBoundaries != null && code >= 0 && WinApi.WM.WM_MOUSEMOVE == (WinApi.WM)wParam) { WinApi.MSLLHOOKSTRUCT hookStruct = (WinApi.MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(WinApi.MSLLHOOKSTRUCT)); var coords = new Point(hookStruct.pt.x, hookStruct.pt.y); // Boundary check var isNowInAppBoundaries = IsInAppBoundaries(coords); if (_isInAppBoundaries && !isNowInAppBoundaries) { var source = GetMouseEventSource(hookStruct); var eventArgs = new EventArgs { Source = source, Coords = coords }; OnMouseLeaveBoundaries.Invoke(null, eventArgs); } _isInAppBoundaries = isNowInAppBoundaries; } return(WinApi.CallNextHookEx(HookId, code, wParam, lParam)); }