michel-pi / GameOverlay.Net

Draw hardware accelerated graphics using our Direct2D1 renderer and create transparent click-through windows.
MIT License
426 stars 83 forks source link

Draw over full screen programs does not work #71

Closed razfazz closed 3 years ago

razfazz commented 3 years ago

First I want to thank you for this amazing peace of code. I tried to draw an overlay over the windows media player in fullscreen mode. Unfortunately the overlay disappears as soon as i switch to full screen mode in the Windows Media Player.

Is it possible to overlay also full screen applications like the Windows Media Player? Thank you for help in advance!

michel-pi commented 3 years ago

Whenever the focus of the target window changes do this:

WindowHelper.EnableBlurBehind(windowsMediaPlayer);
overlay.Recreate()
mentorfloat commented 3 years ago

I attempted this with League of Legends FullScreen but it didn't work.

WindowHelper.EnableBlurBehind(leagueclient);
overlayinstance.Myoverlay.Recreate();

My setup:

Mygfx = new Graphics()
            {
                MeasureFPS = false,
                PerPrimitiveAntiAliasing = true,
                TextAntiAliasing = true,
                WindowHandle = MainWindow.leagueclient
            };

            Myoverlay = new StickyWindow(MainWindow.leagueclient, Mygfx)
            {
                FPS = 30,
                IsTopmost = true,
                IsVisible = true,
                AttachToClientArea = true
            };

Only worked in Borderless. Fantastic repo too by the way.

razfazz commented 3 years ago

Thank you very much for the quick answer, but unfortunately it did not work for me.

      [DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

  private void TimerThatTicksEverySecond(object sender, EventArgs e)
        {
            IntPtr handle = GetForegroundWindow();

            if (handle != _window.Handle)
            {
                WindowHelper.EnableBlurBehind(handle);
                _window.Recreate();
            }

        }
michel-pi commented 3 years ago

I attempted this with League of Legends FullScreen but it didn't work.

WindowHelper.EnableBlurBehind(leagueclient);
overlayinstance.Myoverlay.Recreate();

My setup:

Mygfx = new Graphics()
          {
              MeasureFPS = false,
              PerPrimitiveAntiAliasing = true,
              TextAntiAliasing = true,
              WindowHandle = MainWindow.leagueclient
          };

          Myoverlay = new StickyWindow(MainWindow.leagueclient, Mygfx)
          {
              FPS = 30,
              IsTopmost = true,
              IsVisible = true,
              AttachToClientArea = true
          };

Only worked in Borderless. Fantastic repo too by the way.

The window handle used to draw should be the one of the overlay not the league client.

Thank you very much for the quick answer, but unfortunately it did not work for me.

      [DllImport("user32.dll")]
        static extern IntPtr GetForegroundWindow();

  private void TimerThatTicksEverySecond(object sender, EventArgs e)
        {
            IntPtr handle = GetForegroundWindow();

            if (handle != _window.Handle)
            {
                WindowHelper.EnableBlurBehind(handle);
                _window.Recreate();
            }

        }

The WindowHelper class implements GetForegroundWindow for you. You could use that.

It works but you need to be exact on the timing. Please follow these steps exactly and maybe try debugging the issue with a hotkey or delay performing the wizardry.

I added the OverlayWindow and Graphics recreate methods so you can create the Overlay just when the game is Full-screen again and after you called WindowHelper.EnableBlurBehind(gameWindowHandle);.

If you are using the GraphicsWindow or StickyWindow then the event https://github.com/michel-pi/GameOverlay.Net/blob/master/source/Tests/GraphicsWindowTest.cs#L81 will be called again. You need to recreate every resource besides fonts and images if I remember correctly. https://github.com/michel-pi/GameOverlay.Net/blob/master/source/Tests/GraphicsWindowTest.cs#L92

If you don't handle recreation correctly you may also run into problems when not using the "Full-screen" bypass.

mentorfloat commented 3 years ago

The window handle used to draw should be the one of the overlay not the league client.

I updated WindowHandle to IntPtr.Zero like your example, but it didn't make a difference to me.

private void TestWMPlayerFull()
{
    DispatcherTimer timer = new DispatcherTimer
    {
        Interval = new TimeSpan(0, 0, 1)
    };

    timer.Tick += (sender, EventArgs) =>
    {
            if (WindowHelper.GetForegroundWindow() != overlayinstance.Myoverlaywin.Handle)
            {
                WindowHelper.EnableBlurBehind(wmplayer_handle);
                overlayinstance.Myoverlaywin.Recreate();
            }
    };
    timer.Start();
}

@smedasn I tested with Windows Media Player. The above simple check worked in Fullscreen videos, but sometimes when I hovered my mouse or clicked on some buttons (play, pause, right-click, etc), the overlay stopped rendering until I exit fullscreen and reenter fullscreen. This behaviour occurs randomly.

@michel-pi I wonder if it is because of the way I am checking and calling EnableBlurBehind? And if this issue will lead to solving League of Legends Fullscreen render. Somehow the above didn't work for League in Fullscreen at all but as soon as I switched the setting to 'Windowed' or 'Borderless', the overlay showed.

michel-pi commented 3 years ago

Can you provide a complete example solution? I can not reproduce your error otherwise.

I have the media player and league installed.

mentorfloat commented 3 years ago

Can you provide a complete example solution?

I created a bare-bones version. It renders a simple line of text at the top left corner if successful.

https://github.com/mentorfloat/FullscreenOverlay

Running this will return the exact occurrences described in my earlier post.

michel-pi commented 3 years ago

Your problem is the timing on your window creation. I use a hotkey in my projects since I did not find a truly reliable way to detect the changes.

Note: I used Thread.Sleep(10000); to get into the game window.

The tricky part is that you need to figure out when the game actually starts drawing again. There is a short time when the game window is black when it is already foreground. It will not work when you activate it there.

razfazz commented 3 years ago

Thanks for your answers and help. I wonder if we can perhaps make a universal, solid implementation that always works.

My idea was the following, but unfortunately I couldn't find an appropriate event that would trigger at the right moment.

private void OnLostTopMostVisibility(object sender, EventArgs e)
{
     //Code to bring Overlay back to top
}

Do you guys think this could be possible?

michel-pi commented 3 years ago

Of course, it's possible and my plan was to implement this. But my time and resources are very limited, so I decided not to.

I would suggest you to use a hotkey which a user can press to toggle it to full-screen again after tabbing out.

razfazz commented 3 years ago

This is perfectly understandable. Thanks for your help

michel-pi commented 3 years ago

No problem

marcoscavaleiro commented 7 months ago

Hello, @michel-pi and @mentorfloat i know this very old... but i'm trying to do an overlay for Iracing and i'm with the same issue.. i have a .net console application where i read the telemetry and display it. if the game is in full screen the overlay dont appear.. i tried the mentorfloat approach but didnt work (even with the win11 media player)

michel-pi commented 6 months ago

I am not planning to update this anymore. I do not have Windows 11 and the used renderer discontinued support