Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually



  • In Windows 10, the only way to arrange displays is with this user interface:
    7734bdc4-4d06-4c38-8fd7-e0a12aaa8b13-image.png
    You click and drag and it snaps and shoves the displays around seemingly at random with no real intention of actually getting your displays aligned in any useful manner. As a result, you'll always have weird misalignments like this:
    7c150dfd-e9b9-4b3b-92a5-3aa5d5478ab8-image.png
    I did a lot of googling and I guess my google-fu is terrible because I could find maybe only a few people complaining about this and no solutions. Not even AMD's driver software would allow me to do anything about it, it just opens Windows 10's interface.

    So, I did what any programmer would do, and coded my own (lazy) solution:

    #include <cassert>
    #include <Windows.h>
    
    int main()
    {
    	DISPLAY_DEVICEW info0 {sizeof(DISPLAY_DEVICEW)};
    	DISPLAY_DEVICEW info1 {sizeof(DISPLAY_DEVICEW)};
    	DISPLAY_DEVICEW info2 {sizeof(DISPLAY_DEVICEW)};
    	DISPLAY_DEVICEW info3 {sizeof(DISPLAY_DEVICEW)};
    
    	{
    		auto const result0 = EnumDisplayDevicesW(NULL, 0, &info0, EDD_GET_DEVICE_INTERFACE_NAME);
    		assert(result0 != 0);
    
    		auto const result1 = EnumDisplayDevicesW(NULL, 1, &info1, EDD_GET_DEVICE_INTERFACE_NAME);
    		assert(result1 != 0);
    
    		auto const result2 = EnumDisplayDevicesW(NULL, 2, &info2, EDD_GET_DEVICE_INTERFACE_NAME);
    		assert(result2 != 0);
    
    		auto const result3 = EnumDisplayDevicesW(NULL, 3, &info3, EDD_GET_DEVICE_INTERFACE_NAME);
    		assert(result3 != 0);
    	}
    
    	DEVMODEW mode0 {{}, {}, {}, sizeof(DEVMODEW), 0};
    	DEVMODEW mode1 {{}, {}, {}, sizeof(DEVMODEW), 0};
    	DEVMODEW mode2 {{}, {}, {}, sizeof(DEVMODEW), 0};
    	DEVMODEW mode3 {{}, {}, {}, sizeof(DEVMODEW), 0};
    
    	{
    		auto const result0 = EnumDisplaySettingsExW(info0.DeviceName, ENUM_CURRENT_SETTINGS, &mode0, EDS_RAWMODE);
    		assert(result0 != 0);
    
    		auto const result1 = EnumDisplaySettingsExW(info1.DeviceName, ENUM_CURRENT_SETTINGS, &mode1, EDS_RAWMODE);
    		assert(result1 != 0);
    
    		auto const result2 = EnumDisplaySettingsExW(info2.DeviceName, ENUM_CURRENT_SETTINGS, &mode2, EDS_RAWMODE);
    		assert(result2 != 0);
    
    		auto const result3 = EnumDisplaySettingsExW(info3.DeviceName, ENUM_CURRENT_SETTINGS, &mode3, EDS_RAWMODE);
    		assert(result3 != 0);
    	}
    
    	mode0.dmFields = DM_POSITION;
    	mode0.dmPosition.x = 0;
    	mode0.dmPosition.y = 0;
    
    	mode1.dmFields = DM_POSITION;
    	mode1.dmPosition.x = 1920;
    	mode1.dmPosition.y = 0;
    
    	mode2.dmFields = DM_POSITION;
    	mode2.dmPosition.x = 1920;
    	mode2.dmPosition.y = -1080;
    
    	mode3.dmFields = DM_POSITION;
    	mode3.dmPosition.x = 0;
    	mode3.dmPosition.y = -1080;
    
    	{
    		auto const result0 = ChangeDisplaySettingsExW(info0.DeviceName, &mode0, NULL, CDS_GLOBAL|CDS_UPDATEREGISTRY, NULL);
    		assert(result0 == DISP_CHANGE_SUCCESSFUL);
    
    		auto const result1 = ChangeDisplaySettingsExW(info1.DeviceName, &mode1, NULL, CDS_GLOBAL|CDS_UPDATEREGISTRY, NULL);
    		assert(result1 == DISP_CHANGE_SUCCESSFUL);
    
    		auto const result2 = ChangeDisplaySettingsExW(info2.DeviceName, &mode2, NULL, CDS_GLOBAL|CDS_UPDATEREGISTRY, NULL);
    		assert(result2 == DISP_CHANGE_SUCCESSFUL);
    
    		auto const result3 = ChangeDisplaySettingsExW(info3.DeviceName, &mode3, NULL, CDS_GLOBAL|CDS_UPDATEREGISTRY, NULL);
    		assert(result3 == DISP_CHANGE_SUCCESSFUL);
    	}
    
    	return 0;
    }
    

    I just stepped through in the debugger, figured out what values I needed to use, and then ran it to completion. After some display stuttering, success!
    7efdf39d-b5f1-4fd6-a29c-06d1cf19b9fb-image.png
    Pixel perfect alignment. Here's hoping this helps someone else...

    Documentation links (that might be invalid soon knowing Microsoft):
    \https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-enumdisplaydevicesw
    \https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-_display_devicew
    \https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-enumdisplaysettingsexw
    \https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/ns-wingdi-_devicemodew
    \https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-changedisplaysettingsexw


  • Notification Spam Recipient

    @LB_ said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    You click and drag and it snaps and shoves the displays around seemingly at random with no real intention of actually getting your displays aligned in any useful manner. As a result, you'll always have weird misalignments like this:
    7c150dfd-e9b9-4b3b-92a5-3aa5d5478ab8-image.png

    Ah, so 1 and 2 were aligned, but since Windows doesn't support multiple alignment edges 4 (which should have been aligned next) wasn't snapped and 3 necessarily couldn't snap either.



  • @LB_ said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    I did a lot of googling and I guess my google-fu is terrible because I could find maybe only a few people complaining about this and no solutions.

    It's a niche of a niche: few people have more than one monitor, much less more than two, and the snapping works well enough.

    My anecdote: the last time I had a problem with how the monitors positioned themselves was when I was using a laptop running XP docked-but-open with the dock connected to a CRT. It had more to do with the difference in resolutions and where I could put things on my desk than the UI, though.



  • Do the corners still capture the mouse pointer and make it so that you can't go diagonally across?

    Absolute worst feature of Windows 10, and I wish I could turn it off.

    I normally set my monitors adjacent by 1 corner, not by an edge (I like being able to move windows side-to-side off the screen without having it show up on the other one). On Windows 10 it's virtually impossible to get the mouse pointer over to the other screen because the corners capture it, so I ended up having to leave some overlap:

    8542cbb1-b692-47e9-9ae7-380feb3a8794-image.png

    The two corners still capture the mouse if I don't hit the edge far enough away from the corner to make the mouse go across it. :angry:



  • You could probably also have gotten away with modifying the registry by hand and then restarting Explorer, FWIW.



  • @anotherusername said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    Do the corners still capture the mouse pointer and make it so that you can't go diagonally across?
    Absolute worst feature of Windows 10, and I wish I could turn it off.

    Yes, and when you have the displays configured like I do, the boundaries between screens are impassible unless you are moving the cursor fast enough, so sometimes you get stuck when you mean to cross, and other times you cross when you don't mean to.

    @anotherusername said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    You could probably also have gotten away with modifying the registry by hand and then restarting Explorer, FWIW.

    I looked up how to do that but nothing I was finding was matching up with what I could actually see in the registry. I never actually found where it stores the offsets.


  • Java Dev

    @anotherusername said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    Do the corners still capture the mouse pointer and make it so that you can't go diagonally across?

    I don't know about corners, having only two monitors side-by-side. But in windows 10, if you are dragging a window, you need to take a run up and move quickly if you want to get over the monitor edge. No amount of moving slowly will pass the cursor over the monitor boundary if you're moving slowly.


  • Banned

    @LB_ said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    So, I did what any programmer would do, and coded my own (lazy) solution:

    I did the same thing on Ubuntu at work, for similar reasons. Although it's a bit easier there, as all you have to do is run xrandr command.


  • BINNED

    @PleegWat Are you aware of + shift + /?
    Moves a window across screens without changing its relative position nor size.



  • @LB_ said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    I looked up how to do that but nothing I was finding was matching up with what I could actually see in the registry. I never actually found where it stores the offsets.

    Windows 7 and onward, it should be in:

    HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\GraphicsDrivers\Configuration\

    Inside each configuration folder, there should be one or more logical displays (this means an area that Windows will render things to). Inside each logical display will be one or more physical displays (one if you've extended the desktop, two if it's cloning it). The logical displays will have Position.cx and Position.cy values, which store the respective offsets. They are signed integers, but RegEdit displays them as unsigned values... you should just be able to use 0,0 for the upper-left window, and avoid worrying about negative numbers; that doesn't have to be the "primary" monitor's position or anything special like that.

    As far as finding which configuration is the active one... that, I guess you kind of just have to figure out; each configuration will include the monitor IDs (which you probably won't recognize, but the hardware ids consist of a 3-letter manufacturer code followed by 4 numbers; you could look in Device Manager under Monitors and check the "Hardware ids" property for each installed monitor). Those hardware IDs will each have some extra hex digits and underscores tacked on at the end, and they will be concatenated with + if the displays are extended or * if they're cloned. At the end of the configuration key, there's also some kind of UID component that's concatenated after a ^. It might be pretty tough to programmatically determine what the active configuration path is (or should be).



  • @kazitor said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    @PleegWat Are you aware of + shift + /?
    Moves a window across screens without changing its relative position nor size.

    One of my displays is 4k and set to 200% scaling. When I use that shortcut now with maximized windows, they often become un-maximized and larger than the display and you have to fiddle around with dragging them about until the maximize button works again. It's very strange and buggy whether the app supports it or not. Also it doesn't matter what display is primary, the mere act of having a 4k display connected causes many applications to behave weirdly no matter what display they are on.

    @anotherusername said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    @LB_ said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    I looked up how to do that but nothing I was finding was matching up with what I could actually see in the registry. I never actually found where it stores the offsets.

    Windows 7 and onward, it should be in:

    HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\GraphicsDrivers\Configuration\

    Inside each configuration folder, there should be one or more logical displays (this means an area that Windows will render things to). Inside each logical display will be one or more physical displays (one if you've extended the desktop, two if it's cloning it). The logical displays will have Position.cx and Position.cy values, which store the respective offsets. They are signed integers, but RegEdit displays them as unsigned values... you should just be able to use 0,0 for the upper-left window, and avoid worrying about negative numbers; that doesn't have to be the "primary" monitor's position or anything special like that.

    As far as finding which configuration is the active one... that, I guess you kind of just have to figure out; each configuration will include the monitor IDs (which you probably won't recognize, but the hardware ids consist of a 3-letter manufacturer code followed by 4 numbers; you could look in Device Manager under Monitors and check the "Hardware ids" property for each installed monitor). Those hardware IDs will each have some extra hex digits and underscores tacked on at the end, and they will be concatenated with + if the displays are extended or * if they're cloned. At the end of the configuration key, there's also some kind of UID component that's concatenated after a ^. It might be pretty tough to programmatically determine what the active configuration path is (or should be).

    Ah, thanks! I'll just...
    c84a6925-26bf-40f9-b15b-3e4d372b3495-image.png
    ...uh, I'll just keep that in mind.



  • @LB_ said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    Ah, thanks! I'll just...

    ...uh, I'll just keep that in mind.

    ...yeah.

    Well, let me help you make sense of it.

    You have 4 displays, which Windows identifies as: (these aren't the hardware IDs, but they contain the hardware ID, plus some extra stuff at the end whose meaning I don't know)

    • AUS28B155456_29_07E2_9F
    • VSC5A37VKV184400212_2C_07E2_D7
    • VSCDE2ETVT152401550_18_07DF_52
    • VSCDE2ETVT153801258_26_07DF_3A

    I'll just call those displays 1-4. For curiosity's sake, one of them has a manufacturer code AUS, and the other 3 are VSC. I don't know what those correspond to, but it doesn't matter (edit: VSC is ViewSonic). The hardware IDs are AUS28B1, VSC5A37, and VSCDE2E... I think. Two of the monitors are the same exact model, and it's probably using the serial number or something like that to uniquely identify them in the remaining hex digits.

    You can ignore the devices that start with "MSNIL" or "NOEDID"*. (Or "SIMULATED"... but you doesn't appear to have one of those. Strange. That's the configuration that Windows applies when you don't have any active monitor connected, typically when it's going to sleep... maybe you don't have sleep enabled?) Each configuration also has a ^ followed by a bunch of hex digits at the end... it's some type of UID; ignore it.

    So your configurations are, respectively:

    3d7f7b5d-57a6-4d77-805f-c015df8745f3-image.png

    The configuration with all 4 displays connected is going to be the one that I labeled "Display 2 + 1 + 4 + 3". If you expand it, you'll see 4 logical displays, numbered 00-03. Each will have a Position.cx and Position.cy which represent the display's upper-left corner in the extended desktop area.

    As far as why there are so many different configurations... either that's an artifact of Windows polling the attached displays and adding them one by one, or it's because some of the monitors were turned off at some point in the past, and Windows remembers everything.

    * "NOEDID" is the default profile that Windows will use for monitors that don't provide EDID information to report their supported display modes. So technically you've got configurations for "unknown display" and "unknown display + display 2" in there as well.


  • Notification Spam Recipient

    @LB_ said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    the mere act of having a 4k display connected causes many applications to behave weirdly no matter what display they are on.

    O have mine set to 100 percent scaling. Works fine. :trollface:



  • @anotherusername Next time someone tell me that Windows is easier than Linux, I'll point him to this thread :rolleyes:


  • BINNED

    @TimeBandit said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    @anotherusername Next time someone tell me that Windows is easier than Linux, I'll point him to this thread :rolleyes:

    I hate to be the one to engage you on this, but at least Windows consistently manages to set a single screen's resolution.
    I remember back when I had to manually edit xorg.conf after every. single. update. just to get the screen's native resolution, instead of putting it at 800x600 or some shit like that.



  • @topspin said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    I remember back when I had to manually edit xorg.conf

    15 years ago? 🤷♂



  • @TimeBandit I recently installed various Linux distros in a Hyper-V VM. Guess how you have to change the screen resolution in all of them.

    If you guessed xorg.conf: wrong. It's actually /etc/default/grub.

    But that one might be Microsoft's fault.


  • Notification Spam Recipient

    @anonymous234 said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    @TimeBandit I recently installed various Linux distros in a Hyper-V VM. Guess how you have to change the screen resolution in all of them.

    If you guessed xorg.conf: wrong. It's actually /etc/default/grub.

    But that one might be Microsoft's fault.

    In bhyve you necessarily set the resolution in the VM launch parameters, and it cannot be changed by the guest, and must be booted via UEFI or you get nothing.


  • Banned

    @Tsaukpaetra Next time someone tell me that *NIX is easier than Windows...


  • BINNED

    Next time someone tells me computers are easy…

    oh who am I kidding; nobody would ever say that


  • Considered Harmful

    @kazitor said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    Next time someone tells me computers are easy…

    oh who am I kidding; nobody would ever say that

    They're easy if they're all you know.


  • Notification Spam Recipient

    @Gribnit said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    @kazitor said in Windows 10 display arranging sucks, so I fixed it by setting the pixel positions manually:

    Next time someone tells me computers are easy…

    oh who am I kidding; nobody would ever say that

    They're easy if they're all you know.

    I know many computers. :giggity:



  • During development today my primary monitor was top left and my Visual Studio 2019 window was maximized bottom right. It informed me there was an update, so I clicked "View Details" and it opened Visual Studio Installer. After an apparent internal disagreement about where the window should appear, it decided to be an enlightened centrist.

    wtf-vs-installer.png

    It's a lot more :wtf: in person, where each quarter of the window is on a different monitor with 10cm gaps between.



  • I just registered to say thank you for this nifty solution. I may be the only other person on this planet with the same problem but thank you thank you thank you.

    I took the liberty to up the ante and create my own version with a multistep setup where you can use a regular text file to actually run this. The code is anything but beautiful but it does what I made it for.



  • @Stefan-Misch Wow, I am really glad to have been able to help inspire you to create that! My original code kept needing tweaks as I discovered that monitor entries Windows would enumerate were sometimes disconnected or unused entries, your tool seems quite handy for avoiding that issue. Great work!



  • I just got two LG 27GL83A-B 27 and the issue I am having is when I turn them off and then back on everything that was on the right side is now on the left side. I cannot figure out the Regedit thing or how to use the program that Stefan created. Below is my reg entries. I need to set it to 5120x1440 as each monitor is set to 2560x1440

    b5b3ce7a-78a6-499c-b1b9-14d20d3ec99a-image.png



  • @Jeffrey-Hatley Did you try to switch their cables around? This sounds like Windows can't tell them apart, so it's just placing them in the order it found them. So, in theory, if you switch the ports around, the discovery order should also get changed.


Log in to reply