How to detect duplicated monitors as separate screens - c#

Using the answer in this question I can get the "screen" count. However, this doesn't seem to work with monitors that are set to "duplicate" (one monitor is reported instead of 2). My application prompts a user to switch from VGA to HDMI (this is on a device with both output ports), and then puts a "can you see this?" prompt on screen to verify that both video ports are working.
I am trying to detect that the switch has happened before showing the prompt, but due to the above mentioned problem the code does not see the monitor count decrement, then increment (that is how I am detecting the switch).
How can I detect the video device switch if everything is set to duplicate? The existing code works if the monitors are set to "extend". There is an internal video device that is always present as well (not trying to test this one).

See This question and use the provided (and fixed in the answer) wrapper for QueryDisplayConfig.
change the signature of the import to have out DisplayConfigTopologyId topology as the last parameter.
Use the QueryDisplayFlags.DatabaseCurrent for the display flags, otherwise you'll get status 87 (invalid parameter)
After calling QueryDisplayFlags the topology will be Clone, Extend etc.
call the method...
var status = CCDWrapper.QueryDisplayConfig(
CCDWrapper.QueryDisplayFlags.DatabaseCurrent,
ref numPathArrayElements, pathInfoArray, ref numModeInfoArrayElements,
modeInfoArray, out currentTopologyId);
In my tests numPathArrayElements always came back as the number of monitors currently In Use. If I changed it to "Show Only Screen 1", It said 1 screen, topology internal. "Show Only Screen 2" came back with 1 screen external. "Cloned" showed 2 screens.

James Barrass' answer didn't work for me. I ended up going with the answer here: link
Here's the code:
public static int GetScreenCount()
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_PnPEntity where service =\"monitor\"");
return searcher.Get().Count;
}

Related

Unity Android: NoClassDefFoundError: Can't create Notifications

Edit
I found out, that the requirements for showing a notification consist of setting a content-title, a context-text and a small icon. The last of which I do not do. Unfortunately, I don't know, how to provide a small icon especially in unity.
Original Question
I'm currently trying to show a notification from a unity-instance via android. I want to show the notification, when the user enters a specific gps-area. Thus, the script should run, when the app is paused. That's why I want to use the android-functionality.
With this code, I currently try to show the notification manually:
public void createNotification(){
NotificationManagerCompat nManager = NotificationManagerCompat.from(curContext);
NotificationCompat.Builder builder = new NotificationCompat.Builder(curContext, CHANNEL_ID)
.setContentTitle("Stuff")
.setContentText("MoreStuff")
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
nManager.notify(1551, builder.build());
}
The context is stored in a static variable and is set, when calling the method.
The function is called in C# with:
PluginInstance.Call("createNotification");
The PluginInstance works, the function can be called, but I get the error:
AndroidJavaException: java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/core/app/NotificationManagerCompat
I found the solution for my problem: I used the Unity Android Jar-Resolver in which I provided the *Dependencies.xml (Where the * presents the Name of my project). In the *Dependenices.xml I specified: <androidPackage spec="androidx.appcompat:appcompat:1.1.0"> and run through the steps, provided in the Tutorial of the Resolver.
Afterwards, multiple dependencies appeared in my /Assets/Plugin/Android-Folder, which were successfully transferred to the app, when building it.

The new Input System doesn't trigger anything anymore

This post is shamelessly a copy/paste from my post on the Unity Forums : https://forum.unity.com/threads/input-system-doesnt-trigger-anything-anymore.717386/, but Stack Overflow seems more active
TL;DR : InputSystem worked some days ago, don't trigger anything anymore, halp.
I tried the new Input System some days ago, and that's really neat ! I did a lot of stuff, trying to understand the best way to use it, and, in the end, I had a character jumping and moving everywhere, that was cool ! Then, I merged my code in our develop branch and went to bed.
Today, I want to continue my code, but my character doesn't move anymore, Actions are not triggered (even if inputs are detected in debugger) and I really don't know why. Either the code merge overwrote some important settings (I know what you're thinking and yes, the "Active Input Handling" is set on "Both" and I tried only running the preview) or I did something important during my little tests and I didn't realize.
So I decided to try to reproduce my steps on a fresh new project, maybe you guys can help me figure what do I do wrong ?
1/ Create a new 2D project (via the Hub)
2/ Install the latest Package (version 0.9.0)
3/ Click Yes on that message prompt to activate the new Input management in the settings
4/ Restart Unity Editor since it didn't restart even if the message said it would and check the project settings (yes, it's on "Both", and yes, my Scripting Runtime Version is 4.0)
5/ Create a new GameObject and add a PlayerInput on it
6/ Click on "Open Input Settings" and create an "InputSettings" asset
7/ Click on "Create Actions..." to create my ActionMap asset
8/ Create a "TestAction" on my "Player" ActionMap and set it to the key "t"
9/ Create a new Script "TestScript" that contains a OnTestAction() method (that only logs "test") and enables the test map/action (just to be sure) :
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.PlayerInput;
public class TestScript : MonoBehaviour
{
void Start()
{
InputActionMap playerActionMap = GetComponent<PlayerInput>().actions.GetActionMap("Player");
playerActionMap.Enable();
playerActionMap.GetAction("TestAction").Enable(); //Just to be sure
}
public void OnTestAction()
{
Debug.Log("test");
}
}
10/ Pressing "Play" and spamming "T" like a madman to try to display a debug (note that, in the debugger, a User is created, my "t" presses are detected, my TestAction exists and is mapped on the "t" key but no debug is displayed
It's probably a silly problem, but it's driving me crazy, what do I do wrong ? It's even more infuriating that it worked some days ago !
Additional information :
- Switching the Input Management from "Both" to "New Input System (preview) does nothing
- Checking in Update() is my action is enabled returns "True" every frame
- Checking in Update() is my action is triggered returns "False" every frame
- Using action.started/triggered/performed does nothing (I tried also switching to UnityEvent or C# events for this) :
public class TestScript : MonoBehaviour
{
InputAction a;
void Start()
{
InputActionMap playerActionMap = GetComponent<PlayerInput>().actions.GetActionMap("Player");
playerActionMap.Enable();
a = playerActionMap.GetAction("TestAction");
a.Enable(); //Just to be sure
a.started += OnTriggeredTestAction;
a.performed += OnTriggeredTestAction;
a.canceled += OnTriggeredTestAction;
}
public void OnTestAction()
{
Debug.Log("test");
}
public void OnTriggeredTestAction(InputAction.CallbackContext ctx)
{
Debug.Log("test triggered");
}
}
Injecting directly the InputActionReference of my TestAction and using it does nothing
Forcing "Default Control Scheme" and "Default Action Map" does nothing
Using BroadcastMessage or UnityEvents doesn't work
You probably tried to import a new input system package for multiple input devices compatibility. These types of errors are due to conflict between old and new input system packages and are probably resolved in the latest updates.
To resolve this issue, Go to Edit -> Project Settings->Player->Under Other Settings under Configuration is the option Active Input Handling. Select Both. Unity will restart. Now your problem should be solved. You will be able to use old input system packages and the new ones also simultaneously.
Check for rogue users in the input debugger
I was having very similar symptoms (Input System would randomly just stop sending callbacks). When I opened up the input debugger, it was registering the key presses, but the callbacks were never being called in my script.
Restarting Unity didn't help.
Rebooting didn't help.
I also discovered in the input debugger that there were 2 "users" in the input system and (by process of disabling Game Objects in the scene one at a time) discovered that I had accidentally attached another copy of my Input Action Asset to a different Game Object in the scene and that Unity was registering this other object as a 2nd player or "user", which was assigned all the input action bindings I was trying to capture.
The rogue Action Asset was essentially intercepting the actions, preventing the callbacks from being called on the intended script. I don't know if that's your particular issue, but maybe it will help someone else who (like me) has spent hours pouring through forums, looking for a solution to this elusive problem.
An easy way to tell if you have the same problem is to open the input debugger and see if the desired actions are actually mapped to the user of interest.
Screen clip of input debugger:
For me, there was an unexpected User #1 and only one of the users (not the intended one) actually had keys bound to the desired actions
Posting just incase others run into this issue, as this solved my problem. Make sure to call Enable() for it to start routing events.
//Create a and set the reference
private InputControls _inputMapping;
private void Awake() => _inputMapping = new InputControls();
//Route and Un-route events
private void OnEnable() => _inputMapping.Enable();
private void OnDisable() => _inputMapping.Disable();
I don't know if this will work for you but it worked for me and I was having the same issue.
I had created 2 control schemes. Mobile and Pc. Mobile required touch screen and PC required keyboard and Mouse. Doing this made my Mobile input event stop firing. So adding the Gamepad to my Mobile Control scheme allowed the events to fire again.
TLDR. Check your control scheme make sure it allows for the inputs your binding to.
I had a similar problem, reproduced with exactly the steps described in the question.
In my case, I forgot to set control schemes.
The problem was fixed after adding them.
To do so:
Open your Input Action Asset.
Select a control scheme, in the upper left corner. (say, Keyboard) (if you haven't added a control scheme to begin with, your problem may be different than mine)
Go Right Click > Edit Control Scheme.
EditControlScehme Screen Img
Click on the plus sign to add a control scheme to the list.
Add control scheme to the list Screen Img
Select the control scheme you want to add. (in this case, Keyboard)
Select control scheme Screen Img
Should look like this:
Added control scheme Screen Img
You're all set. Save everything and the problem should be fixed.
Play your game and it should work.
As of at least Unity 2020.1.2 and Input System 1.0.0 the input system will randomly stop working correctly. The only fix I'm aware of is restarting Unity.

How can I change the Paperspace background using .NET in AutoCAD

I've asked this question over in the Autodesk Forums, and no one seems to have any answer. I'm hoping someone here might.
I'm simply trying to programatically change the Paperspace(Layout Tab) background color. Also the Command Prompt Text("Command:" to "User decides").
This is being coded to run for Autocad and Bricscad. The Bricscad system variables are:
BKGCOLORPS
CMDLNTEXT
I think the background color is located in:
...DocumentManager.MdiActiveDocument.Editor.Document.GraphicsManager but I'm still not figuring out how to get/set it.
The Command Prompt Text, I don't even know where to start.
Edit: got somewhere. Here's the layout background anyways. Still waiting on a support request for the command line prompt.
Had to add the Autodesk.AutoCAD.Interop.dll reference on top of the 3 standard ones(accoremgd/acdbmgd/acmgd).
AcP.AcadPreferences acBkgColor = (AcP.AcadPreferences)AcAp.Application.Preferences;
if (acBkgColor.Display.GraphicsWinLayoutBackgrndColor == 0) { cbxPsBackground.Checked = true; }

.NET - Capturing cursor bitmap at specific coordinates

DISCLAIMER
This question is somewhat similar to another on StackOverflow, C# - Capturing the Mouse cursor image - but with a slightly different requirement.
BACKGROUND
I am writing a scriptable automation client that scraps data from 3 legacy Win32 systems.
Two of these systems may indicate the presence of finished tasks via a change in cursor bitmap when the cursor is hovered over some specific areas. No other hints (color change, status message) are offered.
My own code is derived from the original post mentioned on the disclaimer.
REQUIREMENTS
While I an able to capture the cursor bitmaps by programatically moving the cursor to a specific coordinate and capturing it via CURSORINFO, the idea was to allow an interactive user to continue using the computer. As it is, the forced positioning disrupts the process.
QUESTION
Is there a way to capture the cursor bitmap by parametrized position (e.g., request the CURSORINFO as if the focus was in window W at coordinates X, Y)?
A solution fulfilling the specifics of this question was implemented using the information provided by Hans Passant, so all credit must go to him.
The current setup is as shown:
It runs on a machine with two displays. Not shown in the picture is a small application that is actually responsible for the event monitoring and data scraping - it runs minimized and unattended.
Solution
Obtain the Window handle for the application to be tested (in this case, I cycled through all processes returned by Process.GetProcesses():
IntPtr _probeHwnd;
var _procs = Process.GetProcesses();
foreach (var item in _procs)
{
if (item.MainWindowTitle == "WinApp#1")
{
_probeHwnd= item.MainWindowHandle;
break;
}
}
With the window handle for the target application, we are now able to craft specific messages and send to it via SendMessage.
In order to pass coordinates to SendMessage we need to serialize both X and Y coordinates into a single long value:
public int MakeLong(short lowPart, short highPart)
{
return (int)(((ushort)lowPart) | (uint)(highPart << 16));
}
Knowing the specific coordinates we want to probe (_probeX,_probeY), now we can issue a WM_NCHITTEST message:
SendMessage(_probeHwnd, WM_NCHITTEST, NULL, (LPARAM)MakeLong(_probeX, _probeY));
We need GetCursorInfo to obtain the Bitmap:
Win32Stuff.CURSORINFO ci = new Win32Stuff.CURSORINFO();
Win32Stuff.GetCursorInfo(ci);
Check if the return flag from GetCursorInfo indicates that the cursor is showing (pco.flags == CURSOR_SHOWING):
Use CopyIcon in order to obtain a valid handle for the cursor bitmap:
IntPtr hicon = default(IntPtr);
hicon = Win32Stuff.CopyIcon(ci.hCursor);
Use GetIconInfo to extract the information from the handler:
Win32Stuff.ICONINFO icInfo = default(Win32Stuff.ICONINFO);
Win32Stuff.GetIconInfo(hicon, icInfo);
Use the System.Drawing.Icon class to obtain a manageable copy using Icon.FromHandle, passing the value returned by CopyIcon;
Icon ic = Icon.FromHandle(hicon);
Extract the bitmap via Icon.ToBitmap method.
Bitmap bmp = ic.ToBitmap();
Limitations
This solution was tested on two different OSes: Windows XP and Windows 8. It only worked on Windows XP. On Windows 8 the cursor would flicker and return to the 'correct' format immediately, and the the captured CURSORINFO reflected that.
The test point areas must be visible (i.e., application must not be minimized, and test points can't be under an overlapping window. Tested window may be partially overlapped, though - and it doesn't need to have focus.)
When WM_NCHITTEST is issued, the current physical cursor over WebApp changes to whatever cursor bitmap is set by the probed application. CURSORINFO contains the cursor bitmap set by the probed application, but the coordinates always indicate the 'physical' location.

Why is Process.MainWindowTitle always empty for all but one window?

When accessing Process.MainWindowTitle as follows...
Process[] processes = Process.GetProcessesByName( "iexplore" );
...and then loop over the resulting array, I always end up with the MainWindowTitle being empty for all but one item in the array. In my case I've got two Internet Explorer windows open, one with a single tab and one with two tabs in it.
Running my code I always get the MainWindowTitle for the window and tab that I had last active - all the others remain empty. The strange thing is that the process ID in which the MainWindowTitle is filled is always the same - if I activate the other IE window or tab before running my code, the process ID is always the same:
if ( !processes.Any() )
{
MessageBox.Show( "TODO - No matching process found" );
return;
}
if ( processes.Count() > 1 )
{
foreach ( Process currentProcess in processes )
{
// More than one matching process found
checkedListBox1.Items.Add( currentProcess.Id + " - " + currentProcess.MainWindowTitle + " - " + currentProcess.ProcessName );
}
return;
}
Output could therefore be for the first run like:
4824 - - iexplore
3208 - - iexplore
4864 - Google - Windows Internet Explorer - iexplore
Next run (with the other IE window selected beforehand):
4824 - - iexplore
3208 - - iexplore
4864 - id Software - Windows Internet Explorer - iexplore
I've read about this post, but I didn't get any further with my problem (and it seems to go into a somewhat different direction anyway).
Why do I always only get one non-empty MainWindowTitle?
Remember that internet explorer uses a hosting model - one iexplore.exe instance hosts the internet explorer frame, the other iexplore.exe instances just display the contents of tabs.
The only IE instance with a top level window is the iexplore.exe process which hosts the frame.
This article discusses the multi-process architecture of various web browsers. As I understand it, browsers are moving to a multi-process model - that way a failure in one web page won't affect other pages. This article goes into more detail about IE's multi-process model.
One option to make this happen reliabely (see comments above) is to implement a BHO - esp. the DWebBrowserEvents2::WindowStateChanged Event is usefull in this scenario.
BHOs are implementations of a bunch of COM interfaces and get loaded into the browser process/each tab... best way to implement them is in C++ IMO.
But it is certainly possible to do so in .NET (although not recommended):
http://www.codeproject.com/Articles/350432/BHO-Development-using-managed-code
http://www.codeguru.com/csharp/.net/net_general/comcom/article.php/c19613/Build-a-Managed-BHO-and-Plug-into-the-Browser.htm
AddIn-Express for IE (commercial library for .NET-based BHOs)
I had the same problem. With Teamviewer Host, we have the QuickConnect Button on some Application. In my case WinWord. If you remove or disable the QuickConnect, the MainWindowTitle will be enhanced

Categories