6

I have sent my user out to the browser with Application.OpenURL. And now I want to programatically bring unity back to the foreground.

Is there any way to do it without a plugin?

Thanks.

Ruzihm
  • 19,749
  • 5
  • 36
  • 48
peterept
  • 4,407
  • 23
  • 32

4 Answers4

3

Use GetActiveWindow to get the window's handle before you send the user away, then use SetForegroundWindow using that handle. Before you use SetForegroundWindow, you can try simulating an Alt keypress to bring up a menu to abide by certain limitations of SetForegroundWindow:

private IntPtr unityWindow;

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

[DllImport("user32.dll")] 
static extern bool SetForegroundWindow(IntPtr hWnd); 

[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);

const int ALT = 0xA4;
const int EXTENDEDKEY = 0x1;
const int KEYUP = 0x2;

private void SendUser() 
{
    unityWindow = GetActiveWindow();

    Application.OpenURL("http://example.com");

    StartCoroutine(RefocusWindow(30f));
}


private IEnumerator RefocusWindow(float waitSeconds) {
    // wait for new window to appear
    yield return new WaitWhile(() => unityWindow == GetActiveWindow());

    yield return new WaitForSeconds(waitSeconds);

    // Simulate alt press
    keybd_event((byte)ALT, 0x45, EXTENDEDKEY | 0, 0);

    // Simulate alt release
    keybd_event((byte)ALT, 0x45, EXTENDEDKEY | KEYUP, 0);

    SetForegroundWindow(unityWindow);
}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • I fixed the IntPtr compiler error but it still doesn't seem to work in Windows 10. It flashes down in the task bar but the window doesn't actually get focus. – glenneroo Jul 12 '19 at 18:48
  • 1
    @glenneroo There are some [limitations](https://stackoverflow.com/a/20445272/1092820) with when `SetForegroundWindow` will bring a window to the foreground vs. just flash its bar in the task bar. It seems you can try sending an alt press to bring up a menu, which allows another window (unity in this case) to take control of the foreground. I edited my answer to provide some more info. – Ruzihm Jul 12 '19 at 19:02
  • 1
    This solution works great on Windows 10 from a Windows_x64 desktop build. – Clay Fowler Feb 10 '21 at 15:32
  • @ClayFowler thank you for the feedback :) – Ruzihm Feb 10 '21 at 17:07
0

if you are using Unity3D in Windows, try below code after calling Application.OpenURL(...) :

[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

var prc = Process.GetProcessesByName("..."); //Get Unity's process, or 
var prc = Process.GetCurrentProcess();
if (prc.Length > 0) 
    SetForegroundWindow(prc[0].MainWindowHandle);
David
  • 15,894
  • 22
  • 55
  • 66
  • 2
    No luck yet. The code above always returns 0 for window handle. I changed it to EnumWindows and I do get a valid window handle. But calling SetForegroundWIndow() is having no effect. I'll keep digging. – peterept Mar 21 '15 at 00:51
0

This worked for me on Unity 5.0.1 / Windows 8.1:

using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;

public class ForeGrounder : MonoBehaviour {

    private const uint LOCK = 1;
    private const uint UNLOCK = 2;

    private IntPtr window;

    void Start() {
        LockSetForegroundWindow(LOCK);
        window = GetActiveWindow();
        StartCoroutine(Checker());
    }

    IEnumerator Checker() {
        while (true) {

            yield return new WaitForSeconds(1);
            IntPtr newWindow = GetActiveWindow();

            if (window != newWindow) {
                Debug.Log("Set to foreground");
                SwitchToThisWindow(window, true);
            }
        }
    }

    [DllImport("user32.dll")]
    static extern IntPtr GetActiveWindow();
    [DllImport("user32.dll")]
    static extern bool LockSetForegroundWindow(uint uLockCode);
    [DllImport("user32.dll")]
    static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab);
}
tteneder
  • 321
  • 2
  • 8
  • [SwitchToThisWindow](https://learn.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-switchtothiswindow) - *This function is not intended for general use. It may be altered or unavailable in subsequent versions of Windows.* – xmedeko Feb 14 '19 at 13:00
  • The problem is in `window = GetActiveWindow();` when the user switches to another app before this code is run, i.e. before the app initializes. Then the result is `0`. – xmedeko Feb 14 '19 at 18:53
0

For Mac Standalone we can try

public void OpenURLInDefaultBrowser(string URL)
    {

#if UNITY_STANDALONE_OSX

Screen.fullScreenMode = FullScreenMode.Windowed;

#endif Application.OpenURL(URL);

        StartCoroutine(ReFocusUnity());
    }

    private IEnumerator ReFocusUnity()
    {
        //You can wait for some seconds or wait for any callback you are expecting
        yield return new WaitForSeconds(5f);

#if UNITY_STANDALONE_OSX

        Screen.fullScreenMode = FullScreenMode.FullScreenWindow;

#endif }