Click here to Skip to main content
13,869,161 members
Click here to Skip to main content

Stats

737K views
30K downloads
281 bookmarked
Posted 14 Sep 2010
Licenced CPOL

PVS.AVPlayer - MCI Audio and Video Library

, 7 Aug 2018
Windows Media Control Interface (MCI) library with many added features
PVS.AVPlayer
PVS.AVPlayer .NET 2.0
PVS.AVPlayer.XML
PVS.AVPlayer .NET 3.0
PVS.AVPlayer.XML
PVS.AVPlayer .NET 3.5
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.0
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.5
PVS.AVPlayer .NET 4.5.1
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.5.2
PVS.AVPlayer.XML
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.6
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.6.1
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.6.2
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.7
PVS.AVPlayer .NET 4.7.1
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer .NET 4.7.2
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer.dll
PVS.AVPlayer.XML
PVS.AVPlayer All Source Code
AVPlayerExample
AVPlayerExample
AVPlayerExample.csproj.user
bin
Debug
PVS.AVPlayer.XML
Release
Dialogs
Display Overlays
obj
Debug
Release
x86
Debug
Release
Properties
Resources
Crystal Italic1.ttf
WingDings3a.ttf
Voice Recorder
FolderView
FolderView
bin
Debug
PVS.AVPlayer.XML
Release
FolderView.csproj.user
obj
Release
x86
Debug
Release
Properties
Resources
Crystal Italic1.ttf
PVS.AVPlayer
AVPlayerExample.csproj.user
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Custom Items
Native Methods
Bob.png
Crystal Italic1.ttf
Dial Green 2.png
Dial Green 4.png
Dial Green.png
Dial Red 2.png
Dial Red.png
media7.ico
media7a.ico
Media8.ico
Media8a.ico
VU Meter.png
WingDings3a.ttf
Sound Recorder
Various
About Dialog
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Custom Items
FolderView.csproj.user
Debug
Bob.png
Crystal Italic1.ttf
media7a.ico
media7b.ico
Media8a.ico
Media8b.ico
Subtitles Overlay
Various
How To (C#)
PVSAVPlayerHowTo
bin
Debug
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Release
obj
Debug
Release
Properties
How To (VB.NET)
PVSAVPlayerHowToVB
bin
Debug
PVS.AVPlayer.dll
PVS.AVPlayer.XML
Release
My Project
Application.myapp
obj
Debug
Release
PVSAVPlayerHowTo.vbproj.user
PVS.AVPlayer Examples
AVPlayerExample.ex_
FolderView.ex_
AVPlayerExample.exe
FolderView.exe
PVS.AVPlayer.dll
/****************************************************************

    PVS.AVPlayer - Version 0.91
    August 2018, The Netherlands
    © Copyright 2018 PVS The Netherlands - Free to Use

    ****************

    For use with Microsoft .NET Framework version 2.0 or higher and any CPU.
    Created with Microsoft Visual Studio.

    Articles on CodeProject with information on the use of the PVS.AVPlayer library:
    About the Player: http://www.codeproject.com/Articles/109714/PVS-AVPlayer-MCI-Audio-and-Video-Library
    About the Sound Recorder: http://www.codeproject.com/Articles/1116698/PVS-AVPlayer-MCI-Sound-Recorder

    ****************

    The PVS.AVPlayer library source code is divided into 10 files:

     1. Player.cs            - Player source code
     2. MouseEvents.cs       - extension source code of Player.cs, provides player display mouse events
     3. PeakMeter.cs         - extension source code of Player.cs, provides player audio peak level values
     4. DisplayClones.cs     - extension source code of Player.cs, provides player multiple video displays 
     5. Subtitles.cs         - extension source code of Player.cs, provides player SubRip (.srt) subtitles
     6. Signals.cs           - extension source code of Player.cs, provides player media position signaling
     7. CursorHide.cs        - extension source code of Player.cs, hides the mouse cursor during inactivity
     8. Recorder.cs          - Sound Recorder source code
     9. PlayerRecorder.cs    - code used by both Player.cs (and its extension files) and Recorder.cs
    10. Infolabel.cs         - Info Label (custom ToolTip) source code

    Required references:
    System
    System.Drawing
    System.Windows.Forms

    ****************

    This file: MouseEvents.cs

    Player Class
    Extension to file 'Player.cs'.

    ****************

    About Media Control Interface (MCI)
    - for information about MCI, please see https://msdn.microsoft.com/en-us/library/vs/alm/dd757151(v=vs.85).aspx
    - you can find many articles about mci on the internet, search examples: 'c# mci', 'vb mci', 'mcisendstring'
      or the subject of your question.
    - the PVS.AVPlayer library also provides 'direct access' to MCI (e.g. 'Mci.MciSendString').

    ****************

    Thanks!

    Many thanks to Microsoft (Windows, .NET Framework, Visual Studio Express, etc.), all the people
    writing about programming on the internet (a great source for ideas and solving problems),
    the websites publishing those or other writings about programming, the people responding
    to the PVS.AVPlayer articles with comments and suggestions and, of course, CodeProject:
    thank you Deeksha, Smitha and Sean Ewington for the beautiful articles and all!

    Menu Monitor based on code by nicholas at:
    stackoverflow.com/questions/35613926/detect-if-a-contextmenustrip-is-displayed-or-intercepting-key-events

    Special thanks to Sean Ewington of CodeProject who also took care of publishing the many code
    updates and changes in the PVS.AVPlayer articles in a friendly, fast, and highly competent manner.
    Thank you very much, Sean!

    Peter Vegter
    August 2018, The Netherlands

    ****************************************************************/

#region Usings

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

#endregion

namespace PVS.AVPlayer
{
    // This section provides player mouse events on MCI video display windows (that is normally not possible) by using a message filter.
    // Maybe it's a bit much, but it's needed to handle both the display overlay mechanism and the non-accessible MCI video window.

    // The events are for the entire display (combining the display control, the display overlay and the MCI video window).
    // Other display events (like MouseEnter and MouseLeave) can be set as usually with the display control itself.
    // To add an event handler, the display control (e.g. a panel) must already be on a form, otherwise it's ignored.


    public partial class Player
    {
        /*
            This section provides player mouse events on MCI video display windows (that is normally not possible) by using a message filter.
            Maybe it's a bit much, but it's needed to handle both the display overlay mechanism and the non-accessible MCI video window.

            The events are for the entire display (combining the display control, the display overlay and the MCI video window).
            Other display events (like MouseEnter and MouseLeave) can be set as usually with the display control itself.
            To add an event handler, the display control (e.g. a panel) must already be on a form, otherwise it's ignored.
        */

        // ******************************** Mouse Events - Event Declarations

        #region Mouse Events - Event Declarations

        internal event EventHandler<MediaMouseEventArgs> MediaMouseMove
        {
            add { MF_AddEvent(MediaMouseEventFlags.MouseMove, value); }
            remove { MF_Unsubscribe(this, MediaMouseEventFlags.MouseMove, value); }
        }
        internal event EventHandler<MediaMouseEventArgs> MediaMouseDown
        {
            add { MF_AddEvent(MediaMouseEventFlags.MouseDown, value); }
            remove { MF_Unsubscribe(this, MediaMouseEventFlags.MouseDown, value); }
        }
        internal event EventHandler<MediaMouseEventArgs> MediaMouseUp
        {
            add { MF_AddEvent(MediaMouseEventFlags.MouseUp, value); }
            remove { MF_Unsubscribe(this, MediaMouseEventFlags.MouseUp, value); }
        }
        internal event EventHandler<MediaMouseEventArgs> MediaMouseClick
        {
            add { MF_AddEvent(MediaMouseEventFlags.MouseClick, value); } // this is maybe not right - should be a combination of MouseUp followed by MouseDown (?)
            remove { MF_Unsubscribe(this, MediaMouseEventFlags.MouseClick, value); }
        }
        internal event EventHandler<MediaMouseEventArgs> MediaMouseDoubleClick
        {
            add { MF_AddEvent(MediaMouseEventFlags.MouseDoubleClick, value); }
            remove { MF_Unsubscribe(this, MediaMouseEventFlags.MouseDoubleClick, value); }
        }
        internal event EventHandler<MediaMouseEventArgs> MediaMouseWheel
        {
            add { MF_AddEvent(MediaMouseEventFlags.MouseWheel, value); }
            remove { MF_Unsubscribe(this, MediaMouseEventFlags.MouseWheel, value); }
        }

        // Subscribes eventhandlers to the MessageFilter event processor
        private void MF_AddEvent(MediaMouseEventFlags eventType, EventHandler<MediaMouseEventArgs> callBack)
        {
            _lastError = Global.MCIERR_NO_WINDOW;
            if (_hasDisplay)
            {
                Form form = _display.FindForm();
                if (form != null)
                {
                    _lastError = Global.MCIERR_NO_ERROR;
                    MF_Subscribe(this, _display, form, eventType, callBack);
                }
            }
        }

        #endregion


        // ******************************** Mouse Events - Fields / also contains the Message Filter MF_MessageFilter

        #region Mouse Events - Fields / also contains the Message Filter MF_MessageFilter

        #region Windows Message Codes

        private const int WM_MOUSEMOVE = 0x0200;
        private const int WM_LBUTTONDOWN = 0x0201;
        private const int WM_LBUTTONUP = 0x0202;
        private const int WM_LBUTTONDBLCLK = 0x0203;
        private const int WM_RBUTTONDOWN = 0x0204;
        private const int WM_RBUTTONUP = 0x0205;
        private const int WM_RBUTTONDBLCLK = 0x0206;
        private const int WM_MBUTTONDOWN = 0x0207;
        private const int WM_MBUTTONUP = 0x0208;
        private const int WM_MBUTTONDBLCLK = 0x0209;
        private const int WM_MOUSEWHEEL = 0x020A;

        #endregion

        [Flags]
        private enum MediaMouseEventFlags
        {
            MouseMove = 1,
            MouseDown = 2,
            MouseUp = 4,
            MouseClick = 8,
            MouseDoubleClick = 16,
            MouseWheel = 32
        }

        private sealed class MF_Client
        {
            internal Player Player;
            internal Control Display;
            internal Form Form;
            internal MediaMouseEventFlags EventType;
            internal EventHandler<MediaMouseEventArgs> CallBack;
            internal bool Obsolete;

            internal MF_Client(Player player, Control display, Form form, MediaMouseEventFlags eventType, EventHandler<MediaMouseEventArgs> callBack)
            {
                Player = player;
                Display = display;
                Form = form;
                EventType = eventType;
                CallBack = callBack;
            }
        }

        private sealed class MF_MessageFilter : IMessageFilter
        {
            internal Point mf_MousePosition;
            internal MediaMouseEventArgs mf_MouseEventArgs;
            internal bool mf_MouseUpPending;
            internal Player mf_MouseUpPendingPlayer;
            internal MouseButtons mf_MouseUpPendingButton;
            private int mf_HandledIndex;
            private bool mf_Busy;

            // constructor
            public MF_MessageFilter()
            {
                mf_MouseEventArgs = new MediaMouseEventArgs();
            }

            public bool PreFilterMessage(ref Message m)
            {
                bool mf_Handled = false;

                if (!mf_Busy && !mf_Ignore)
                {
                    mf_Busy = true;
                    if (mf_Clients.Count > 0 && Form.ActiveForm != null) // application in foreground
                    {
                        mf_MousePosition = Control.MousePosition;
                        //mf_MousePosition.X = unchecked((short)((long)m.LParam));
                        //mf_MousePosition.Y = unchecked((short)((long)m.LParam >> 16));
                        mf_MouseEventArgs._clicks = 1;
                        mf_MouseEventArgs._delta = 0;
                        switch (m.Msg)
                        {
                            case (WM_MOUSEMOVE):
                                mf_MouseEventArgs._button = MouseButtons.None;
                                mf_MouseEventArgs._clicks = 0;
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseMove);
                                break;

                            case (WM_LBUTTONDOWN):
                                mf_MouseEventArgs._button = MouseButtons.Left;
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseDown);
                                if (mf_Handled)
                                {
                                    mf_MouseUpPendingPlayer = mf_Clients[mf_HandledIndex].Player;
                                    mf_MouseUpPendingButton = MouseButtons.Left;
                                    mf_MouseUpPending = true;
                                }
                                else
                                {
                                    mf_Handled = true;
                                    mf_MouseUpPending = false;
                                }
                                break;
                            case (WM_LBUTTONUP):
                                if (mf_MouseUpPending)
                                {
                                    if (MF_CallBackMouseUpPlayer(mf_MouseUpPendingPlayer, mf_MouseUpPendingButton))
                                    {
                                        mf_Handled = true;
                                    }
                                    mf_MouseUpPending = false;
                                }
                                if (!mf_Handled)
                                {
                                    mf_MouseEventArgs._button = MouseButtons.Left;
                                    mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseUp | MediaMouseEventFlags.MouseClick);
                                }
                                break;
                            case (WM_LBUTTONDBLCLK):
                                mf_MouseUpPending = false;
                                mf_MouseEventArgs._button = MouseButtons.Left;
                                ++mf_MouseEventArgs._clicks;
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseDoubleClick);
                                break;

                            case (WM_MBUTTONDOWN):
                                mf_MouseEventArgs._button = MouseButtons.Middle;
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseDown);
                                if (mf_Handled)
                                {
                                    mf_MouseUpPendingPlayer = mf_Clients[mf_HandledIndex].Player;
                                    mf_MouseUpPendingButton = MouseButtons.Middle;
                                    mf_MouseUpPending = true;
                                }
                                else mf_MouseUpPending = false;
                                break;
                            case (WM_MBUTTONUP):
                                if (mf_MouseUpPending)
                                {
                                    if (MF_CallBackMouseUpPlayer(mf_MouseUpPendingPlayer, mf_MouseUpPendingButton))
                                    {
                                        mf_Handled = true;
                                    }
                                    mf_MouseUpPending = false;
                                }
                                if (!mf_Handled)
                                {
                                    mf_MouseEventArgs._button = MouseButtons.Middle;
                                    mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseUp | MediaMouseEventFlags.MouseClick);
                                }
                                break;
                            case (WM_MBUTTONDBLCLK):
                                mf_MouseUpPending = false;
                                mf_MouseEventArgs._button = MouseButtons.Middle;
                                ++mf_MouseEventArgs._clicks;
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseDoubleClick);
                                break;

                            case (WM_RBUTTONDOWN):
                                mf_MouseEventArgs._button = MouseButtons.Right;
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseDown);
                                if (mf_Handled)
                                {
                                    mf_MouseUpPendingPlayer = mf_Clients[mf_HandledIndex].Player;
                                    mf_MouseUpPendingButton = MouseButtons.Left;
                                    mf_MouseUpPending = true;
                                }
                                else mf_MouseUpPending = false;
                                break;
                            case (WM_RBUTTONUP):
                                if (mf_MouseUpPending)
                                {
                                    if (MF_CallBackMouseUpPlayer(mf_MouseUpPendingPlayer, mf_MouseUpPendingButton))
                                    {
                                        mf_Handled = true;
                                    }
                                    mf_MouseUpPending = false;
                                }
                                if (!mf_Handled)
                                {
                                    mf_MouseEventArgs._button = MouseButtons.Right;
                                    mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseUp | MediaMouseEventFlags.MouseClick);
                                }
                                break;
                            case (WM_RBUTTONDBLCLK):
                                mf_MouseUpPending = false;
                                mf_MouseEventArgs._button = MouseButtons.Right;
                                ++mf_MouseEventArgs._clicks;
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseDoubleClick);
                                break;

                            case (WM_MOUSEWHEEL):
                                mf_MouseEventArgs._button = MouseButtons.None;
                                mf_MouseEventArgs._clicks = 0;
                                mf_MouseEventArgs._delta = unchecked((short)((long)m.WParam >> 16));
                                mf_Handled = RaiseEvents(MediaMouseEventFlags.MouseWheel);
                                break;
                        }
                    }
                    mf_Busy = false;
                }
                //return mf_Handled;
                return false;
            }

            private bool RaiseEvents(MediaMouseEventFlags mouseEvent)
            {
                Form activeForm = Form.ActiveForm; // already checked (above PreFilterMessage) app is in foreground
                Form overlay;
                bool overlayActive;
                bool doIt = false;
                bool obsolete = false;

                for (int i = 0; i < mf_Clients.Count; i++)
                {
                    if (!mf_Clients[i].Obsolete)
                    {
                        try
                        {
                            if (mf_Clients[i].Player._overlay != null && mf_Clients[i].Player._overlay == activeForm)
                            {
                                overlay = mf_Clients[i].Player._overlay;
                                overlayActive = true;
                            }
                            else
                            {
                                overlay = null;
                                overlayActive = false;
                            }

                            doIt = false;
                            //if (((mf_Clients[i].Form == activeForm || (mf_Clients[i].Form.IsMdiChild && mf_Clients[i].Form.ContainsFocus)) || overlayActive)
                            if ((mf_Clients[i].Form.ContainsFocus || overlayActive)
                                && (mf_Clients[i].EventType & mouseEvent) != 0
                                && ((mf_MouseUpPending && mouseEvent == MediaMouseEventFlags.MouseMove) || mf_Clients[i].Display.ClientRectangle.Contains(mf_Clients[i].Display.PointToClient(mf_MousePosition))))
                            {

                                doIt = true;
                                // TODO mousepending + mousemove doit - skip tests

                                if (overlayActive)
                                {
                                    if (overlay.ContextMenuStrip != null && (overlay.ContextMenuStrip.Visible || mf_MouseEventArgs._button == MouseButtons.Right))
                                    {
                                        doIt = false;
                                    }
                                    else if (overlay.Controls.Count > 0)
                                    {
                                        Point pos = overlay.PointToClient(mf_MousePosition);
                                        for (int j = 0; j < overlay.Controls.Count; j++)
                                        {
                                            if (overlay.Controls[j].Bounds.Contains(pos))
                                            {
                                                doIt = false;
                                                break;
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    if (mf_Clients[i].Display.ContextMenuStrip != null) // check display contextmenu - 3 layers deep
                                    {
                                        if (mf_Clients[i].Display.ContextMenuStrip.Visible || (mf_MouseEventArgs._button == MouseButtons.Right))
                                            doIt = false;
                                    }
                                    else if ((mf_Clients[i].Display).Parent != null)
                                    {
                                        if ((mf_Clients[i].Display).Parent.ContextMenuStrip != null)
                                        {
                                            if ((mf_Clients[i].Display).Parent.ContextMenuStrip.Visible || (mf_MouseEventArgs._button == MouseButtons.Right))
                                                doIt = false;
                                        }
                                        else if (((mf_Clients[i].Display).Parent).Parent != null && ((mf_Clients[i].Display).Parent).Parent.ContextMenuStrip != null)
                                        {
                                            if (((mf_Clients[i].Display).Parent).Parent.ContextMenuStrip.Visible || (mf_MouseEventArgs._button == MouseButtons.Right))
                                                doIt = false;
                                        }
                                    }
                                }

                                if (doIt)
                                {
                                    mf_HandledIndex = i;
                                    mf_MouseEventArgs._location = mf_MousePosition;
                                    mf_Clients[i].CallBack(mf_Clients[i].Display, mf_MouseEventArgs);
                                }
                                break;
                            }
                        }
                        catch
                        {
                            // flag remove client(s)
                            mf_Clients[i].Obsolete = obsolete = true;
                            for (int x = i + 1; x < mf_Clients.Count; x++)
                            {
                                if (mf_Clients[x].Player == mf_Clients[i].Player) mf_Clients[x].Obsolete = true;
                            }
                        }
                    }
                }
                if (obsolete)
                {
                    MF_UnsubscribeObsoletes();
                }
                return doIt;
            }
        }

        private static bool             mf_Active;
        private static bool             mf_HasMouseDown;
        private static int              mf_MouseDownCount;
        private static List<MF_Client>  mf_Clients;
        private static MF_MessageFilter mf_MessageFilter;

        // menu monitor
        private static bool             mf_HasMenuMonitor;
        private static bool             mf_Ignore;
        private static SafeNativeMethods.WinEventDelegate mf_MenuMonitorCallback;
        private static IntPtr           mf_MenuMonitorHook;

        #endregion


        // ******************************** Mouse Events - Message Filter Clients Subscribe / Unsubscribe

        #region Mouse Events - Message Filter Clients Subscribe / Unsubscribe

        private static void MF_Subscribe(Player player, Control display, Form form, MediaMouseEventFlags eventType, EventHandler<MediaMouseEventArgs> callBack)
        {
            bool exists = false;

            if (mf_Clients == null) mf_Clients = new List<MF_Client>(32);
            else
            {
                for (int i = mf_Clients.Count - 1; i >= 0; i--)
                {
                    if (mf_Clients[i].Player == player && mf_Clients[i].EventType == eventType && mf_Clients[i].CallBack == callBack)
                    {
                        exists = true;
                        break;
                    }
                }
            }

            if (!exists)
            {
                MF_Client client = new MF_Client(player, display, form, eventType, callBack);
                mf_Clients.Add(client);

                if (eventType == MediaMouseEventFlags.MouseDown)
                {
                    mf_HasMouseDown = true;
                    mf_MouseDownCount++;
                }
                if (!mf_Active) MF_SetMessageFilter();
            }
        }

        private static void MF_Unsubscribe(Player player, MediaMouseEventFlags eventType, EventHandler<MediaMouseEventArgs> callBack)
        {
            if (mf_Clients != null && mf_Clients.Count > 0)
            {
                for (int i = mf_Clients.Count - 1; i >= 0; i--)
                {
                    if (mf_Clients[i].Player == player && mf_Clients[i].EventType == eventType && mf_Clients[i].CallBack == callBack)
                    {
                        if (mf_Clients[i].EventType == MediaMouseEventFlags.MouseDown)
                        {
                            if (--mf_MouseDownCount == 0) mf_HasMouseDown = false;
                        }
                        mf_Clients.RemoveAt(i);
                        if (mf_Clients.Count == 0) MF_RemoveMessageFilter();
                        break;
                    }
                }
            }
        }

        private static void MF_UnsubscribePlayer(Player player)
        {
            if (mf_Clients != null && mf_Clients.Count > 0)
            {
                for (int i = mf_Clients.Count - 1; i >= 0; i--)
                {
                    if (mf_Clients[i].Player == player)
                    {
                        if (mf_Clients[i].EventType == MediaMouseEventFlags.MouseDown)
                        {
                            if (--mf_MouseDownCount == 0) mf_HasMouseDown = false;
                        }
                        mf_Clients.RemoveAt(i);
                    }
                }
                if (mf_Clients.Count == 0) MF_RemoveMessageFilter();
            }
        }

        private static void MF_UnsubscribeObsoletes()
        {
            if (mf_Clients != null && mf_Clients.Count > 0)
            {
                for (int i = mf_Clients.Count - 1; i >= 0; i--)
                {
                    if (mf_Clients[i].Obsolete)
                    {
                        if (mf_Clients[i].EventType == MediaMouseEventFlags.MouseDown)
                        {
                            if (--mf_MouseDownCount == 0) mf_HasMouseDown = false;
                        }
                        mf_Clients.RemoveAt(i);
                    }
                }
                if (mf_Clients.Count == 0) MF_RemoveMessageFilter();
            }
        }

        #endregion


        // ******************************** Mouse Events - Change Display / MouseUp Callback

        #region Mouse Events - Change Display / MouseUp Callback

        private static void MF_ChangeDisplay(Control oldDisplay, Control newDisplay)
        {
            if (mf_Clients != null && mf_Clients.Count > 0)
            {
                for (int i = mf_Clients.Count - 1; i >= 0; i--)
                {
                    if (mf_Clients[i].Display == oldDisplay) mf_Clients[i].Display = newDisplay;
                }
            }
        }

        private static bool MF_CallBackMouseUpPlayer(Player player, MouseButtons button)
        {
            bool handled = false;
            for (int i = 0; i < mf_Clients.Count; i++)
            {
                if (mf_Clients[i].Player == player && mf_Clients[i].EventType == MediaMouseEventFlags.MouseUp)
                {
                    mf_MessageFilter.mf_MouseEventArgs._location = Control.MousePosition;
                    mf_MessageFilter.mf_MouseEventArgs._button = button;
                    mf_MessageFilter.mf_MouseEventArgs._clicks = 1;
                    mf_MessageFilter.mf_MouseEventArgs._delta = 0;
                    mf_Clients[i].CallBack(mf_Clients[i].Display, mf_MessageFilter.mf_MouseEventArgs);

                    handled = true;
                    break;
                }
            }
            return handled;
        }

        #endregion


        // ******************************** Mouse Events - Set MessageFilter / Remove MessageFilter

        #region Mouse Events - Set MessageFilter / Remove MessageFilter

        private static void MF_SetMessageFilter()
        {
            if (!mf_Active)
            {
                if (mf_MessageFilter == null) mf_MessageFilter = new MF_MessageFilter();
                Application.AddMessageFilter(mf_MessageFilter);
                MF_StartMenuMonitor();
                mf_Active = true;
            }
        }

        private static void MF_RemoveMessageFilter()
        {
            if (mf_Active)
            {
                Application.RemoveMessageFilter(mf_MessageFilter);
                mf_MessageFilter.mf_MouseUpPending = false;
                if (!ch_Active) MF_StopMenuMonitor();
                mf_Active = false;
            }
        }

        #endregion


        // ******************************** Mouse Events - Menu Monitor Start / Stop / Callback

        #region Mouse Events - Menu Monitor Start / Stop / Callback

        // Menu Monitor is used to prevent mouseclicks from 'falling through' certain pop-up (contextmenu (strip)) menus
        // when the above Message Filter is used.

        private static void MF_StartMenuMonitor()
        {
            if (!mf_HasMenuMonitor)
            {
                mf_MenuMonitorCallback = new SafeNativeMethods.WinEventDelegate(MF_MenuMonitorCallback);
                mf_MenuMonitorHook = SafeNativeMethods.SetWinEventHook(
                    SafeNativeMethods.EVENT_SYSTEM_MENUSTART,
                    SafeNativeMethods.EVENT_SYSTEM_MENUPOPUPEND,
                    IntPtr.Zero,
                    mf_MenuMonitorCallback,
                    (uint)Process.GetCurrentProcess().Id,
                    0,
                    SafeNativeMethods.WINEVENT_OUTOFCONTEXT);
                mf_Ignore = false;
                mf_HasMenuMonitor = true;
            }
        }

        private static void MF_StopMenuMonitor()
        {
            if (mf_HasMenuMonitor)
            {
                SafeNativeMethods.UnhookWinEvent(mf_MenuMonitorHook);
                mf_MenuMonitorCallback = null;
                mf_Ignore = false;
                mf_HasMenuMonitor = false;
            }
        }

        private static void MF_MenuMonitorCallback(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
        {
            mf_Ignore = (eventType == SafeNativeMethods.EVENT_SYSTEM_MENUPOPUPSTART || eventType == SafeNativeMethods.EVENT_SYSTEM_MENUSTART);
            if (mf_Ignore && ch_Active && !ch_Disabled && !ch_Busy && ch_Hidden)
            {
                // cursor hide menu opened
                ch_Moved = DateTime.Now;
                Cursor.Show();
                ch_Hidden = false;
                ch_Timer.Start();

                if (MediaCursorHideChanged != null)
                {
                    ch_EventArgs._reason = CursorChangedReason.MenuOpened;
                    CH_RaiseEvent(Form.ActiveForm);
                }
            }
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Peter Vegter
United States United States
No Biography provided

You may also be interested in...

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web05 | 2.8.190214.1 | Last Updated 7 Aug 2018
Article Copyright 2010 by Peter Vegter
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid