private bool mh_MouseDownEvent(object sender, APIMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                int padding = (int)(GetTouchAccuracy() * 0.5f);

                Win32Api.Rect lbpos = GetLioranBoardWindowLocation();

                if (lbpos.Top == 0 && lbpos.Bottom == 0 && lbpos.Left == 0 && lbpos.Right == 0)
                {
                    // The get Rectangle failed.  Likely because lioranboard is closed.
                    LioranBoardWindowHandle = IntPtr.Zero;
                }

                var outputX = e.X;
                var outputY = e.Y;


                string hashstr = string.Format("LD:({0},{1})", outputX, outputY);
                Debug.WriteLine(string.Format("Checking for Ignore Hash {0}", hashstr));
                if (!ignoreSet.Contains(hashstr))
                {
                    Debug.WriteLine(string.Format("Checking for Ignore Hash {0}", hashstr));
                    // We need location and placement because location returns the actual position (Aero snap included),
                    // GetWindowPlacement returns the minimized/maximized state but often returns the non-snapped dimensions

                    var placement = GetLBWindowPlacement();

                    if (LioranBoardWindowHandle != IntPtr.Zero && (e.X >= lbpos.Left && e.X < lbpos.Right) && (e.Y >= lbpos.Top && e.Y < lbpos.Bottom) &&
                        (placement.showCmd == Win32Api.ShowWindowCommands.Normal || placement.showCmd == Win32Api.ShowWindowCommands.Maximized))
                    {
                        ignoreSet.Add(hashstr);
                        Debug.WriteLine(string.Format("Added Ignore Hash {0}", hashstr));
                        // We are drawing a square in a hashtable the size of the padding around the touch point.
                        // We need this to dedupe our touch..   since we will also receive our own mouse click message.
                        // We also need this to disambiguate our touch from a drag.
                        for (int x = (-1 * padding); x < padding; x++)
                        {
                            for (int y = (-1 * padding); y < padding; y++)
                            {
                                string subhashstr = string.Format("LD:({0},{1})", outputX + x, outputY + y);
                                padSet.Add(subhashstr);
                                ignoreSet.Add(subhashstr);
                            }
                        }
                        richTextBox1.Text = string.Format("Setting release pad square:{0},{1}", e.X, e.Y);
                        return(false);
                    }
                }
            }
            if (e.Button == MouseButtons.Right)
            {
                //richTextBox1.AppendText("Right Button Press\n");
            }
            return(true);
        }
        /// <summary>
        /// Uses the Windows API to get the window positions in desktop space based on the position of the primary monitor as zero.
        /// We use this for filtering on clicks only over the Lioranboard window.
        /// </summary>
        /// <returns></returns>
        private Win32Api.Rect GetLioranBoardWindowLocation()
        {
            Win32Api.Rect rect = new Win32Api.Rect();

            if (!(LioranBoardWindowHandle == IntPtr.Zero))
            {
                Win32Api.GetWindowRect(LioranBoardWindowHandle, ref rect);
            }

            return(rect);
        }
        private bool mh_MouseUpEvent(object sender, APIMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                var outputX = e.X; //pointGlobal.x;
                var outputY = e.Y; //pointGlobal.y;

                string hashdown = string.Format("LD:({0},{1})", outputX, outputY);
                string hashup   = string.Format("LU:({0},{1})", outputX, outputY);
                richTextBox1.Text = string.Format("({0},{1})Left Button Release\n", outputX, outputY);
                Debug.WriteLine(string.Format("({0},{1})Left Button Release\n", outputX, outputY));

                // Don't trigger ourselves with our own generated mouse messages.
                Debug.WriteLine(string.Format("Checking for Ignore Hash {0}", hashup));
                if (!ignoreSet.Contains(hashup))
                {
                    Debug.WriteLine(string.Format("Ignore Hash {0} Not found", hashup));
                    ignoreSet.Add(hashup);
                    int padding = (int)(GetTouchAccuracy() * 0.5f);
                    // We are drawing a square in a hashtable the size of the padding around the touch point.
                    // We need this to dedupe our touch..   since we will also receive our own mouse click message.
                    // We also need this to disambiguate our touch from a drag.
                    for (int x = (-1 * padding); x < padding; x++)
                    {
                        for (int y = (-1 * padding); y < padding; y++)
                        {
                            string subhashstr = string.Format("LU:({0},{1})", outputX + x, outputY + y);
                            ignoreSet.Add(subhashstr);
                        }
                    }
                    // Only trigger a click if the touch release position is within the padding square
                    if (padSet.Contains(hashdown))
                    {
                        Win32Api.Rect lbpos = GetLioranBoardWindowLocation();
                        if (lbpos.Top == 0 && lbpos.Bottom == 0 && lbpos.Left == 0 && lbpos.Right == 0)
                        {
                            // The get Rectangle failed.  Likely because lioranboard is closed.
                            LioranBoardWindowHandle = IntPtr.Zero;
                        }
                        var placement = GetLBWindowPlacement();

                        // Filter clicks and releases to only over-top of the Lioranboard window.
                        if ((e.X >= lbpos.Left && e.X < lbpos.Right) && (e.Y >= lbpos.Top && e.Y < lbpos.Bottom) &&
                            (placement.showCmd == Win32Api.ShowWindowCommands.Normal || placement.showCmd == Win32Api.ShowWindowCommands.Maximized) && evtthd != null && evtthd.Running)
                        {
                            richTextBox1.Text = string.Format("Triggering Delayed Click: {0},{1}", e.X, e.Y);


                            evtthd.PostLeftClick(GetDelayMS());

                            return(false);
                        }
                    }
                }
                else
                {
                    Debug.WriteLine(string.Format("Removing Ignore Hash {0}", hashup));
                    ignoreSet.Remove(hashup);
                }
            }
            if (e.Button == MouseButtons.Right)
            {
                // richTextBox1.Text = "Right Button Release\n";
            }
            return(true);
        }