Search Unity

  1. Looking for a job or to hire someone for a project? Check out the re-opened job forums.
    Dismiss Notice
  2. The Burst compiler has its own forum section now.
    Dismiss Notice
  3. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Switch Monitor at runtime

Discussion in 'Scripting' started by InvincibleCat, Oct 23, 2017.

  1. InvincibleCat

    InvincibleCat

    Joined:
    Dec 23, 2014
    Posts:
    73
    Hey!

    I have the option the change which monitor you want to use at runtime from a video setting menu on PC.
    It worked fine so far. I am using this method to do so:
    Code (CSharp):
    1.     public IEnumerator ChangeMonitorAsync()
    2.     {
    3.         if (Monitor >= Display.displays.Length)
    4.         {
    5.             Monitor = 0;
    6.         }
    7.         PlayerPrefs.SetInt("UnitySelectMonitor", Monitor);
    8.         Screen.SetResolution(800, 600, FullScreen);
    9.         yield return null;
    10.         Resolution = Screen.resolutions.Length - 1;
    11.         Apply();
    12.     }
    Since I updated to Unity 2017.1 it does not work anymore. I have to restart the game to apply the changes.

    It seems that it is a known issue but it says won't fix...
    https://issuetracker.unity3d.com/is...ntime-with-unityselectmonitor-no-longer-works

    Any clue?

    Thanks,
    -Tim
     
    deus0 likes this.
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,512
  3. InvincibleCat

    InvincibleCat

    Joined:
    Dec 23, 2014
    Posts:
    73
    Unfortunately this won't work as it adds a new display (a secondary one). It does not change the main display!
     
    futurlab_xbox likes this.
  4. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,512
    Yeah you're right. Seems like they need a Deactivate method to counter. My guess is they won't fix it because something is slated to support the functionality properly (not setting magic strings in PlayerPrefs)
     
  5. InvincibleCat

    InvincibleCat

    Joined:
    Dec 23, 2014
    Posts:
    73
    Maybe... it is kind of annoying though since it broke my game...
    Last resort for me would be to tell the user to restart the game then
     
  6. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    The reason I marked it as won't fix was because it was relying on an undocumented internal implementation detail (setting the UnitySelectMonitor player pref) of the engine. It broke by accident as the whole windowing manager was rewritten to fix some serious design flaws related to multi-monitor setups. Since this wasn't a documented or supported feature, it was never noticed when the build was tested. And I have no idea how this was discovered to achieve wanted effect in the first place... Furthermore, "fixing" this to behave like it did before would make moving the window across monitors and entering/leaving fullscreen on a particular monitor broken.

    We don't have any APIs to manipulate window position in Unity, but you can P/Invoke into MoveWindow function instead and manipulate the window position with it.
     
    Joe-Censored likes this.
  7. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,520
    What is the recommended and supported Unity API to switch monitors in Unity 2017 while the game is running?
     
    JimmyCushnie likes this.
  8. InvincibleCat

    InvincibleCat

    Joined:
    Dec 23, 2014
    Posts:
    73
    I understand. In the meantime I just change it so a restart is required.
     
  9. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    Use the Win32 function I mentioned.
     
  10. InvincibleCat

    InvincibleCat

    Joined:
    Dec 23, 2014
    Posts:
    73
    But how can we get the window position then?
     
  11. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    You can use EnumDisplayMonitors function to find coordinates of all monitors in the virtual desktop space.
     
  12. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    5,520
    This functionality is needed in the majority of Desktop games. Games often provide an option to select the monitor in which the game is running via an options screen of the game, as shown in the screenshot below.

    video options.jpg

    Do you think it would be beneficial if a multi platform game engine supports such functionality?

    Having support for that allows game developers to write code for switching monitors once and it works across all platforms, such as Windows, OS X and Linux, versus everyone needs to implement it from scratch and has to deal with platform specifics.
     
    Last edited: Jan 29, 2020
    deus0 and DaDonik like this.
  13. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    Yes, I definitely believe so. ScreenManager improvements in general are in my team (desktop team) roadmap. Being realistic though, we don't support that today, so I mentioned that API as a way to solve your issues now, rather than at some unspecified time in the future.
     
    Peter77 likes this.
  14. HarryCodder

    HarryCodder

    Joined:
    Feb 20, 2015
    Posts:
    72
    Hi @Tautvydas-Zilys

    Do you have any news on progress on this feature ?
    Thanks in advance.
     
    deus0 and Tom60chat like this.
  15. Hyp-X

    Hyp-X

    Joined:
    Jun 24, 2015
    Posts:
    383
    Is there any improvement for this?
    Thanks in advance.
     
    deus0 and SuperNeon like this.
  16. markv12

    markv12

    Joined:
    Dec 31, 2013
    Posts:
    33
    With the release of 2019.3 the resolution dialogue has been removed meaning this feature is needed more than ever.
    Now there is no way to specify which screen your app runs on besides changing your main display in Windows.
     
  17. JimmyCushnie

    JimmyCushnie

    Joined:
    Jun 7, 2017
    Posts:
    192
    @markv12 The user can use OS hotkeys to switch monitors, or switch the application to windowed mode and drag the window over to a different monitor before going back to fullscreen. However, this solution is far from ideal; in particular, Display.main does not update, so we cannot get an updated list of supported resolutions to present to the user. I hope @Tautvydas-Zilys and the rest of the desktop team get around to adding this functionality soon.

    The Win32 API mentioned in this thread does not work on Mac or Linux, so it's not an option for cross-platform games.
     
  18. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    Screen.resolutions should update. They did last time I checked...
     
  19. VoodooDetective

    VoodooDetective

    Joined:
    Oct 11, 2019
    Posts:
    143
    @Tautvydas-Zilys is there a roadmap we could follow? It's pretty rough on multi-monitor users to have to go out of fullscreen, drag, and go back into fullscreen every time they play.

    Trying to figure out how much time to put into this. If there's a feature upcoming in the next year, I'll hold off. Otherwise, I'll have to do the cross-platform code myself through p/invoke which will take lots of time and testing.
     
    JimmyCushnie likes this.
  20. JimmyCushnie

    JimmyCushnie

    Joined:
    Jun 7, 2017
    Posts:
    192
    I really, really wish Unity was open source. There are so many tiny issues like this... with open source, we could fix them ourselves, and Unity would be better for everyone.
     
    deus0 likes this.
  21. Holy-Manfred

    Holy-Manfred

    Joined:
    Nov 30, 2013
    Posts:
    13
    Since it has been almost three years since the question has been asked: Is there any progress on this?
    Code (CSharp):
    1. PlayerPrefs.SetInt("UnitySelectMonitor", Monitor);
    still works but requires a restart, which is not ideal.
    @Tautvydas-Zilys Could you provide a bit of information and let us know if this is something that will ever get addressed?
     
    deus0 and futurlab_xbox like this.
  22. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    This is on my team's backlog... I am trying to make it happen.
     
  23. talecrafter

    talecrafter

    Joined:
    Mar 26, 2013
    Posts:
    34
    Oh, this is cool to hear.

    And I don't want to hijack this, but if the code that has to be touched for making switching monitors possible is also the part where it's responsible that we can activate more displays but not deactivate them, a fix for that would be most welcome too.
     
    deus0 and futurlab_xbox like this.
  24. cfloutier

    cfloutier

    Joined:
    Jul 30, 2009
    Posts:
    34
    yes most wanted since the dialog box disapeared in version 2019.3...;
    It's hard to ask for the user to restart the application
     
  25. chadfranklin47

    chadfranklin47

    Joined:
    Aug 11, 2015
    Posts:
    121
    A very desired feature
     
  26. Weightless

    Weightless

    Joined:
    Sep 7, 2017
    Posts:
    13
    yeah would be nice to see this
     
  27. Weightless

    Weightless

    Joined:
    Sep 7, 2017
    Posts:
    13
    Alright so for anyone interested I made this work in 2019.3 using the stuff recommended by Tautvydas-Zilys

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Runtime.InteropServices;
    5. using UnityEngine;
    6.  
    7. public class DisplayChanger : MonoBehaviour
    8. {
    9.     //cycles through the connected displays by calling the ChangeDisplayClicked() method
    10.     //does not work with windowed mode
    11.  
    12.     List<DisplayInfo> myDisplays = new List<DisplayInfo>();
    13.     List<MyMonitor> myMonitors = new List<MyMonitor>();
    14.     int monitorNumber = 0;
    15.  
    16.     [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)]
    17.     internal static extern void MoveWindow(IntPtr hwnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    18.  
    19.     [DllImport("user32.dll")]
    20.     private static extern IntPtr GetActiveWindow();
    21.  
    22.     [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)]
    23.     internal static extern bool GetWindowRect(IntPtr hWnd, ref RECT rect);
    24.  
    25.     [DllImport("user32.dll")]
    26.     static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);
    27.  
    28.     delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
    29.  
    30.     [StructLayout(LayoutKind.Sequential)]
    31.     public struct RECT
    32.     {
    33.         public int left;
    34.         public int top;
    35.         public int right;
    36.         public int bottom;
    37.     }
    38.  
    39.     public class DisplayInfo
    40.     {
    41.         public string Availability { get; set; }
    42.         public string ScreenHeight { get; set; }
    43.         public string ScreenWidth { get; set; }
    44.         public RECT MonitorArea { get; set; }
    45.         public RECT WorkArea { get; set; }
    46.     }
    47.  
    48.     public class DisplayInfoCollection : List<DisplayInfo>
    49.     {
    50.     }
    51.  
    52.     [DllImport("User32.dll", CharSet = CharSet.Auto)]
    53.     public static extern bool GetMonitorInfo(IntPtr hmonitor, [In, Out] MONITORINFOEX info);
    54.     [DllImport("User32.dll", ExactSpelling = true)]
    55.     public static extern IntPtr MonitorFromPoint(POINTSTRUCT pt, int flags);
    56.  
    57.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 4)]
    58.     public class MONITORINFOEX
    59.     {
    60.         public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
    61.         public RECT rcMonitor = new RECT();
    62.         public RECT rcWork = new RECT();
    63.         public int dwFlags = 0;
    64.         [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    65.         public char[] szDevice = new char[32];
    66.     }
    67.  
    68.     [StructLayout(LayoutKind.Sequential)]
    69.     public struct POINTSTRUCT
    70.     {
    71.         public int x;
    72.         public int y;
    73.         public POINTSTRUCT(int x, int y)
    74.         {
    75.             this.x = x;
    76.             this.y = y;
    77.         }
    78.     }
    79.  
    80.     public DisplayInfoCollection GetDisplays()
    81.     {
    82.         DisplayInfoCollection col = new DisplayInfoCollection();
    83.  
    84.         EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
    85.             delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
    86.             {
    87.                 MONITORINFOEX mi = new MONITORINFOEX();
    88.                 mi.cbSize = (int)Marshal.SizeOf(mi);
    89.                 bool success = GetMonitorInfo(hMonitor, mi);
    90.                 if (success)
    91.                 {
    92.                     DisplayInfo di = new DisplayInfo();
    93.                     di.ScreenWidth = (mi.rcMonitor.right - mi.rcMonitor.left).ToString();
    94.                     di.ScreenHeight = (mi.rcMonitor.bottom - mi.rcMonitor.top).ToString();
    95.                     di.MonitorArea = mi.rcMonitor;
    96.                     di.WorkArea = mi.rcWork;
    97.                     di.Availability = mi.dwFlags.ToString();
    98.                     col.Add(di);
    99.                 }
    100.                 return true;
    101.             }, IntPtr.Zero);
    102.         return col;
    103.     }
    104.  
    105.     public class MyMonitor
    106.     {
    107.         public int targetX;
    108.         public int monitorNumber;
    109.         public int height;
    110.         public int width;
    111.  
    112.         public MyMonitor(int targetX, int monitorNumber, int height, int width)
    113.         {
    114.             this.targetX = targetX;
    115.             this.monitorNumber = monitorNumber;
    116.             this.height = height;
    117.             this.width = width;
    118.         }
    119.     }
    120.  
    121.     private void Start()
    122.     {
    123.         myDisplays = GetDisplays();
    124.         for (int i = 0; i < myDisplays.Count; i++)
    125.         {
    126.             myMonitors.Add(new MyMonitor(myDisplays[i].WorkArea.left, i, Convert.ToInt32(myDisplays[i].ScreenHeight), Convert.ToInt32(myDisplays[i].ScreenWidth)));
    127.         }
    128.     }
    129.  
    130.     public void ChangeDisplayClicked()
    131.     {
    132.         if (monitorNumber < myDisplays.Count)
    133.         {
    134.             StartCoroutine(MyMoveWindow(myMonitors[monitorNumber].height, myMonitors[monitorNumber].width, myMonitors[monitorNumber].targetX));
    135.             monitorNumber++;
    136.         }
    137.         else if (monitorNumber >= myDisplays.Count)
    138.         {
    139.             monitorNumber = 0;
    140.             StartCoroutine(MyMoveWindow(myMonitors[monitorNumber].height, myMonitors[monitorNumber].width, myMonitors[monitorNumber].targetX));
    141.         }
    142.     }
    143.  
    144.     public IEnumerator MyMoveWindow(int newHeight, int newWidth, int targetX)
    145.     {
    146.         IntPtr hwnd;
    147.         RECT Rect = new RECT();
    148.         yield return new WaitForSeconds(2);
    149.         hwnd = GetActiveWindow();
    150.         GetWindowRect(hwnd, ref Rect);
    151.         MoveWindow(hwnd, targetX, Rect.top, newWidth, newHeight, true);
    152.     }
    153. }
    154.  
     
    deus0, Jelvand, futurlab_xbox and 2 others like this.
  28. Hyp-X

    Hyp-X

    Joined:
    Jun 24, 2015
    Posts:
    383
    Does this work with Exclusive fullscreen?
    I'm not gonna implement this just to find out it doesn't.
     
    deus0 likes this.
  29. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    You need to switch to fullscreen window mode before moving the window, and switch back to exclusive fullscreen after moving it.
     
    Munchy2007 likes this.
  30. holyfot

    holyfot

    Joined:
    Dec 16, 2016
    Posts:
    41
    Me and many others have the issue of the game freezing when you try to: Screen.SetResolution(x, y, FullScreenMode.ExclusiveFullScreen, refreshRate);

    If you just use true/false instead of FullScreenMode it doesn't freeze, the FullScreenMode seems to actually use the hardware to set the screen mode, while true/false is kind of a soft mode.
     
  31. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    Can we have a bug report on it? I've heard of such issues happening in the wild before but we haven't been able to narrow it down or reproduce it ourselves. Even a crash dump from a frozen state would help.
     
  32. Jelvand

    Jelvand

    Joined:
    Oct 4, 2019
    Posts:
    2
    Hi, sorry to necro this, but since I still haven't found any support for doing this with Unity APIs, I've resorted to the above method, which works great in Mono.
    However, for IL2CPP I have problems.
    The first one was fairly easy to fix: The delegate needs to be a static function, and cannot be supplied anonymously like in the above code, and the static function implementing the delegate must have the MonoPInvokeCallback attribute with the type of the delegate declaration you need to do.

    After that I ran into another problem. The call to the GetMonitorInfo fails, and the structs provided to it remain unfilled (I've checked). The handles provided to the callback, and subsequently to the failing function, seem to be legit (at least they're not 0), and the callback is in fact called as many times as the number of monitors. I've tried to call the direct functions that the GetMonitorInfo aliases to (GetMonitorInfoA, GetMonitorInfoW) without any change in luck.
    Does anyone have any idea why this call would fail just for IL2CPP builds, and what I could possibly do about it?
     
  33. Tautvydas-Zilys

    Tautvydas-Zilys

    Unity Technologies

    Joined:
    Jul 25, 2013
    Posts:
    8,191
    Looks like you ran into an IL2CPP marshaling bug. It seems like IL2CPP isn't picking up the CharSet property from the StructLayout attribute on MONITORINFOEX when marshaling the szDevice field. Can you report a bug on it?

    In the mean time, you can work around like this:

    Code (csharp):
    1.     [DllImport("User32.dll", CharSet = CharSet.Unicode)]
    2.     public static extern bool GetMonitorInfo(IntPtr hmonitor, [In, Out] MONITORINFOEX info);
    3.     [DllImport("User32.dll", ExactSpelling = true)]
    4.     public static extern IntPtr MonitorFromPoint(POINTSTRUCT pt, int flags);
    5.  
    6.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
    7.     public class MONITORINFOEX
    8.     {
    9.         public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
    10.         public RECT rcMonitor = new RECT();
    11.         public RECT rcWork = new RECT();
    12.         public int dwFlags = 0;
    13.         [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U2, SizeConst = 32)]
    14.         public char[] szDevice = new char[32];
    15.     }
     
  34. Jelvand

    Jelvand

    Joined:
    Oct 4, 2019
    Posts:
    2
    Thanks Tautvydas-Zilus, worked like a charm. I'll look into posting a bug report.
     
  35. deus0

    deus0

    Joined:
    May 12, 2015
    Posts:
    122
    Hi does this work around work for linux/mac?
    Is there any progress for monitor support with unity?
     
    Last edited: Dec 31, 2020
  36. piede828

    piede828

    Joined:
    Dec 12, 2017
    Posts:
    4
    would something like this work if I want to set a camera to display on a monitor that has been connected after the application has started? right now, the build can only detect monitors that are connecting before launch but I need to be able to detected newly connected monitors at runtime? thanks!
     
    deus0 likes this.
  37. BKinAK

    BKinAK

    Joined:
    Mar 6, 2014
    Posts:
    2
    I found that above code only moves a window's targetX and not targetY, if you have a monitor above or below the others in real world space then the switch fails. Here is an updated version that also sets targetY to support this scenario:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using System.Runtime.InteropServices;
    5. using UnityEngine;
    6.  
    7. public class DisplayChanger : MonoBehaviour
    8. {
    9.     //cycles through the connected displays by calling the ChangeDisplayClicked() method
    10.     //does not work with windowed mode
    11.  
    12.     List<DisplayInfo> myDisplays = new List<DisplayInfo>();
    13.     List<MyMonitor> myMonitors = new List<MyMonitor>();
    14.     int monitorNumber = 0;
    15.  
    16.     [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)]
    17.     internal static extern void MoveWindow(IntPtr hwnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
    18.  
    19.     [DllImport("user32.dll")]
    20.     private static extern IntPtr GetActiveWindow();
    21.  
    22.     [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, ExactSpelling = true, SetLastError = true)]
    23.     internal static extern bool GetWindowRect(IntPtr hWnd, ref RECT rect);
    24.  
    25.     [DllImport("user32.dll")]
    26.     static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);
    27.  
    28.     delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
    29.  
    30.     [StructLayout(LayoutKind.Sequential)]
    31.     public struct RECT
    32.     {
    33.         public int left;
    34.         public int top;
    35.         public int right;
    36.         public int bottom;
    37.     }
    38.  
    39.     public class DisplayInfo
    40.     {
    41.         public string Availability { get; set; }
    42.         public string ScreenHeight { get; set; }
    43.         public string ScreenWidth { get; set; }
    44.         public RECT MonitorArea { get; set; }
    45.         public RECT WorkArea { get; set; }
    46.     }
    47.  
    48.     public class DisplayInfoCollection : List<DisplayInfo>
    49.     {
    50.     }
    51.  
    52.     [DllImport("User32.dll", CharSet = CharSet.Unicode)]
    53.     public static extern bool GetMonitorInfo(IntPtr hmonitor, [In, Out] MONITORINFOEX info);
    54.     [DllImport("User32.dll", ExactSpelling = true)]
    55.     public static extern IntPtr MonitorFromPoint(POINTSTRUCT pt, int flags);
    56.  
    57.     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
    58.     public class MONITORINFOEX
    59.     {
    60.         public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
    61.         public RECT rcMonitor = new RECT();
    62.         public RECT rcWork = new RECT();
    63.         public int dwFlags = 0;
    64.         [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U2, SizeConst = 32)]
    65.         public char[] szDevice = new char[32];
    66.     }
    67.  
    68.     [StructLayout(LayoutKind.Sequential)]
    69.     public struct POINTSTRUCT
    70.     {
    71.         public int x;
    72.         public int y;
    73.         public POINTSTRUCT(int x, int y)
    74.         {
    75.             this.x = x;
    76.             this.y = y;
    77.         }
    78.     }
    79.  
    80.     public DisplayInfoCollection GetDisplays()
    81.     {
    82.         DisplayInfoCollection col = new DisplayInfoCollection();
    83.  
    84.         EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
    85.             delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
    86.             {
    87.                 MONITORINFOEX mi = new MONITORINFOEX();
    88.                 mi.cbSize = (int)Marshal.SizeOf(mi);
    89.                 bool success = GetMonitorInfo(hMonitor, mi);
    90.                 if (success)
    91.                 {
    92.                     DisplayInfo di = new DisplayInfo();
    93.                     di.ScreenWidth = (mi.rcMonitor.right - mi.rcMonitor.left).ToString();
    94.                     di.ScreenHeight = (mi.rcMonitor.bottom - mi.rcMonitor.top).ToString();
    95.                     di.MonitorArea = mi.rcMonitor;
    96.                     di.WorkArea = mi.rcWork;
    97.                     di.Availability = mi.dwFlags.ToString();
    98.                     col.Add(di);
    99.                 }
    100.                 return true;
    101.             }, IntPtr.Zero);
    102.         return col;
    103.     }
    104.  
    105.     public class MyMonitor
    106.     {
    107.         public int targetX;
    108.         public int targetY;
    109.         public int monitorNumber;
    110.         public int height;
    111.         public int width;
    112.  
    113.         public MyMonitor(int targetX, int targetY, int monitorNumber, int height, int width)
    114.         {
    115.             this.targetX = targetX;
    116.             this.targetY = targetY;
    117.             this.monitorNumber = monitorNumber;
    118.             this.height = height;
    119.             this.width = width;
    120.         }
    121.     }
    122.  
    123.     private void Start()
    124.     {
    125.         myDisplays = GetDisplays();
    126.         for (int i = 0; i < myDisplays.Count; i++)
    127.         {
    128.             myMonitors.Add(new MyMonitor(myDisplays[i].WorkArea.left, myDisplays[i].WorkArea.top ,i, Convert.ToInt32(myDisplays[i].ScreenHeight), Convert.ToInt32(myDisplays[i].ScreenWidth)));
    129.         }
    130.     }
    131.  
    132.     public void ChangeDisplayClicked()
    133.     {
    134.         if (monitorNumber < myDisplays.Count)
    135.         {
    136.             StartCoroutine(MyMoveWindow(myMonitors[monitorNumber].height, myMonitors[monitorNumber].width, myMonitors[monitorNumber].targetX, myMonitors[monitorNumber].targetY));
    137.             monitorNumber++;
    138.         }
    139.         else if (monitorNumber >= myDisplays.Count)
    140.         {
    141.             monitorNumber = 0;
    142.             StartCoroutine(MyMoveWindow(myMonitors[monitorNumber].height, myMonitors[monitorNumber].width, myMonitors[monitorNumber].targetX, myMonitors[monitorNumber].targetY));
    143.         }
    144.     }
    145.  
    146.     public IEnumerator MyMoveWindow(int newHeight, int newWidth, int targetX, int targetY)
    147.     {
    148.         IntPtr hwnd;
    149.         RECT Rect = new RECT();
    150.         yield return new WaitForSeconds(2);
    151.         hwnd = GetActiveWindow();
    152.         GetWindowRect(hwnd, ref Rect);
    153.         MoveWindow(hwnd, targetX, targetY, newWidth, newHeight, true);
    154.     }
    155. }
    156.  
     
    Munchy2007 likes this.
unityunity