been working for a few days on a set of nodes that retrieves all sorts of interesting information about connected monitors. after fighting for a few days with some PInvoke madness, I stumbled upon MonitorDetailsReader, a nuget that already does all this magic with the help of the EDIDParser lib.
with the information provided by those libs, I managed to create a few util nodes :
GetMonitorDetails : outputs a Spread<Monitor> , containing some detailed information about each of your connected monitors
OnMonitorSetupChanged : outputs an Observable<Spread<Monitor>> when a device is added/removed from the computer. In practice, this one fires on each device add/remove (even your mouse) since I could not find a way to filter monitor only hardware change events
MonitorHelper : spawns a fullscreen Renderer on each of your monitors with some useful information about them. Press ESC to destroy the Renderers
AssignToSerialNumber : a small node that allows to place a Renderer on a specific monitor based on its serial number. For now, it does not make it fullscreen since I encountered some issues when doing that, but that’s the next thing to dig
the functionalities are there, but this has absolutely not been tested extensively : for now, I only have my laptop with a single screen plugged in.
what I’d like to dig next :
hide a renderer if the monitor it’s assigned to goes missing
… and bring it back if the monitor shows up again
make sure the other renderers don’t go all over the place when the screen setup changes
find a way to get an event only when a monitor is plugged/unplugged (and not any device as it is now)
and some questions :
i’d like to get some feedback on how the Renderer creation/disposal is handled in the MonitorHelper node. this seems to be working but I’m not sure about the disposing part
AssignToSerialNumber for now only places a windowed renderer on the screen. if you also set BorderStyle to None and Maximize the form, the windows sticks to the monitor and cannot be moved again. any leads on that?
the idea behind this lib would be to ease the development of installations with distinct content on multiple monitors without relying on Windows’ nonsensical device names
one last thing : in previous versions of these nodes, I experienced some vvvv crashes when playing with the SkiaRenderer nodes and disconnecting my second monitor. please make sure you don’t have any sensitive document open before testing that out (tho those crashes seem to be gone now)
wanna test? head over to the repo or install using
hello Seb,
nice move!
just a note the Escape key to destroy the renderers need the MouseKeyHook nuget (beta40)
side note and self questioning to minimise the number of contribs and their combinations
does the display Changer side of thing should be included to make one VL package?
i’ve recently used the DC utility https://12noon.com/?page_id=641 which is quite handy for simple setups
and if you do not have hardware EDID’s.
thanks for the feedback. Indeed, I forgot to add a dependency to MouseKeyHook, this is now fixed.
interesting question, I think it could/should be included in this plugin since it should serve as a general tool to handle multiple monitors, and not only to retrieve information about them.
for now i’d like to focus on fixing what’s already there, and then I can take a look at it. could you briefly tell me what would be your usecases for a display changer? how would you like to use it “on the field”? :)
cheers!
Seb,
the main use case i’ve in mind is to force the detected resolution by windows
let’s say i’ve 3 x 4k screens plugged directly to the GPU witout EDID emulators the native resolution of the TV’s are 38402160@50 and i want to force them to 40962160@30
additionally i know the serial number of each screen and want to make sure content 1 goes on tv1 etc…
so the process should be
1/ detect monitors resolution, refresh rate, color depth
2/ identify serial numbers
3/change/force windows display resolutions
4/set fullscreen with serial numbers matching
ok, noted, thanks! will look into that, this should definitely be part of the plugin x)
yesterday I did some tests on a more “complex” setup with the ScreenDebug thingy : a desktop computer with four screens of different resolutions. while on my laptop with a single screen everything behaves as expected, the results were totally erratic on the desktop setup.
here’s the patch that spawns the Renderers on the screens, sets their content and their size (this is the MonitorHelper node) :
here are the weird stuff I saw on the desktop setup :
Renderers were instantiated twice : for four screens, the patch spawned 8 windows
The Renderers pad was empty (0 slices), even though there were 8 windows visible. as a result, the renderers could not be destroyed in the second If since it had nothing to operate on
One of the screens was like “discarded” : the renderer was created, but its position and content were not set, like if SetSize and SetInput had no effect on only one slice (resulting in a Default Renderer lying in the middle of the main display)
After rebuilding this patch node after node to see at which point it started to fail, I realized that soon as I started introducing Process nodes (see HelperDrawer here), things started to go weird (behavior described in the previous points). Without Process nodes inside the first ForEach, Windows were correctly placed fullscreen on each monitor (without content of course, and still instantiated twice).
any hints on this issue? is this the right way create/destroy Renderers on the fly?
thanks!
seb
EDIT the exact same behavior showed up on two distinct desktop computers. for some weird reason, I noticed some monitors don’t output their serial numbers, or even report non-matching numbers (compared to the sticker behind the screen). will also investigate this further x)
Does the library directly query the monitors or obtain the EDIDs from the registry? As far as I understood the blog post that is linked in the Readme it reads from the registry.
my first attempts with all that was to use WMI (pretty interesting stuff you can find in there by the way, I’ve attached the patch if anyone’s interested), which gives more “human friendly” values than the lib does (such as the device’s friendly name).
also, wmi spits the full serial number, but the lib only gives the last four digits. after looking around, I came across MonitorInfoView by nirsoft which conveniently displays EDID informations for each monitor. looks like the EDIDParser lib rather reads the “Serial Number (Numeric)” field. my point is that the EDID seems to contain both : the full one (same as in WMI), and the “small” one that the lib gives.
did not know about Monitor Asset Manager, i like the line where they say
and unlike similar reporting utilities queries the monitor directly rather than relying on potentially dubious information stored in the registry.
damn, looks like we cannot trust the OS :-)
another one :
Moreover, end users puzzled by the way Windows treats their monitors and high-definition display devices can gain insight into exactly what Plug-and-Play means: all the information provided by the display to the system is displayed in readable format
I’ll definitely rely on this one when doing further tests with the desktop setup. thanks for sharing!
to finish with the WMI stuff, nirsoft also made SimpleWmiView that allows to quickly inspect wmi classes. pretty useful!
I’m wondering, relying on the monitor/projectors serial number is fine. But what will happen if you need to replace a projector or monitor?
Would it be possible to lock the output on the GPU?
As far as I can tell it would achieve the same and allow for replacing a monitor/projector.
I have worked in an exhibition with lots of the same model of projectors, they had extra projectors so they just replaced the projector if the bulb broke. Then they could replace the bulb when they had mare time in the workshop and use that one the next time a bulb broke.
NVIDIA’s control panel is able to show to which port of which GPU a screen is connected, so this information must be present somewhere. in theory we should be able to cross check that information with the screen’s location in the whole virtual screen, and then place the renderer to the right spot.
I have not looked in that direction yet but that’s definitely interesting, will check when i’m back in Paris x)