Unity, Transparent Background and Multiple Monitors - c#

I'm trying to learn a few things, but I'm kinda stuck and I don't know where to go from here. I'm either blind or just confused.
I've been looking at some scripts from here: Answers.Unity
Right now, I got the background transparency working on my main screen, but I'm wondering what I should do to make this happen on my second monitor too. Or third, if I had one. As of right now the other screens turn black. This is the code:
[SerializeField]
private Material m_Material;
[SerializeField]
private Camera mainCamera;
private bool clickThrough = true;
private bool prevClickThrough = true;
private struct MARGINS
{
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
[DllImport("user32.dll")]
private static extern IntPtr GetActiveWindow();
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, uint dwNewLong);
[DllImport("user32.dll")]
static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll", EntryPoint = "SetLayeredWindowAttributes")]
static extern int SetLayeredWindowAttributes(IntPtr hwnd, int crKey, byte bAlpha, int dwFlags);
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
private static extern int SetWindowPos(IntPtr hwnd, int hwndInsertAfter, int x, int y, int cx, int cy, int uFlags);
[DllImport("Dwmapi.dll")]
private static extern uint DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS margins);
const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_VISIBLE = 0x10000000;
const int HWND_TOPMOST = -1;
int fWidth;
int fHeight;
IntPtr hwnd;
MARGINS margins;
public bool OverUI()
{ //Use sparingly
//Set up the new Pointer Event
PointerEventData m_PointerEventData = new PointerEventData(EventSystem.current);
m_PointerEventData.position = Input.mousePosition;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(m_PointerEventData, results);
if (results.Count > 0) return true;
return false;
}
void Start()
{
fWidth = Screen.width;
fHeight = Screen.height;
margins = new MARGINS() { cxLeftWidth = -1 };
hwnd = GetActiveWindow();
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
DwmExtendFrameIntoClientArea(hwnd, ref margins);
Application.runInBackground = true;
}
void Update()
{
// If our mouse is overlapping an object
RaycastHit hit = new RaycastHit();
clickThrough = !Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition).origin,
mainCamera.ScreenPointToRay(Input.mousePosition).direction, out hit, 100,
Physics.DefaultRaycastLayers) && !OverUI();
if (clickThrough != prevClickThrough)
{
if (clickThrough)
{
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
SetWindowLong (hwnd, -20, (uint)524288 | (uint)32);//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetLayeredWindowAttributes (hwnd, 0, 255, 2);// Transparency=51=20%, LWA_ALPHA=2
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
}
else
{
SetWindowLong (hwnd, -20, ~(((uint)524288) | ((uint)32)));//GWL_EXSTYLE=-20; WS_EX_LAYERED=524288=&h80000, WS_EX_TRANSPARENT=32=0x00000020L
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, fWidth, fHeight, 32 | 64); //SWP_FRAMECHANGED = 0x0020 (32); //SWP_SHOWWINDOW = 0x0040 (64)
}
prevClickThrough = clickThrough;
}
}
void OnRenderImage(RenderTexture from, RenderTexture to)
{
Graphics.Blit(from, to, m_Material);
}
Could anyone guide me a little bit so that I can figure this out?
Edit: I've figured out a little bit.. I think.
When Unity opens, (with multiple displays), it creates two windows in the task bar. I'm guessing I need to find that other window, set it as active and then run something similar to this code again. But I'm guessing I would need to fix the pos and margins before doing so.
It's beyond my understanding of WinApi right now, but I hope someone knows a bit more about this than me.

Related

C#: Drag any window from code behind (programmatically)

Please let me elaborate what I am doing.
I am creating a screen share application. Where there are 2 apps first is a windows application (whose screen is getting shared) and the other is a browser web app (On which the user is watching the screen). The browser web app is sending client x and y coordinates of the mouse to the windows app. The windows app is using the x and y coordinates to move the mouse using the given below code.
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
public static void MoveCursorToPoint(int x, int y)
{
SetCursorPos(x, y);
}
The browser app is also sending mouse clicks and the windows app is performing the clicks using the given below code.
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
public static void DoMouseClick()
{
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
Problem/Challenge
The problem or a challenge here is to perform the drag operation. For an example how will I drag the window of any application from one place to the another place from C# code.
Many thanks for your attention.
Finally, here is the code that will do all the system mouse events. In order to perform the drag and drop operation, you will need to First Send MouseDown(Mouse Click) and keep it Clicked While Changing the Mouse Position than Send MouseUp(Release Click) something like this.
MouseHelper mh = new MouseHelper();
mh.sendMouseDown();
Cursor.Position = new Point(30, 30);
mh.sendMouseUp();
Here is the whole helper file
public class MouseHelper
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
//public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
private const uint MOUSEEVENTF_LEFTDOWN = 0x02;
private const uint MOUSEEVENTF_LEFTUP = 0x04;
private const uint MOUSEEVENTF_RIGHTDOWN = 0x08;
private const uint MOUSEEVENTF_RIGHTUP = 0x10;
public void sendMouseRightclick(Point p)
{
mouse_event((uint)MOUSEEVENTF_RIGHTDOWN | (uint)MOUSEEVENTF_RIGHTUP, (uint)p.X, (uint)p.Y, (uint)0, (uint)0);
}
public void sendMouseDoubleClick(Point p)
{
mouse_event((uint)MOUSEEVENTF_LEFTDOWN | (uint)MOUSEEVENTF_LEFTUP, (uint)p.X, (uint)p.Y, (uint)0, (uint)0);
Thread.Sleep(150);
mouse_event((uint)MOUSEEVENTF_LEFTDOWN | (uint)MOUSEEVENTF_LEFTUP, (uint)p.X, (uint)p.Y, 0, 0);
}
public void sendMouseRightDoubleClick(Point p)
{
mouse_event((uint)MOUSEEVENTF_RIGHTDOWN | (uint)MOUSEEVENTF_RIGHTUP, (uint)p.X, (uint)p.Y, 0, 0);
Thread.Sleep(150);
mouse_event((uint)MOUSEEVENTF_RIGHTDOWN | (uint)MOUSEEVENTF_RIGHTUP, (uint)p.X, (uint)p.Y, 0, 0);
}
public void sendMouseDown()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 50, 50, 0, 0);
}
public void sendMouseUp()
{
mouse_event(MOUSEEVENTF_LEFTUP, 50, 50, 0, 0);
}
}
Source The given code at this source link will give an error
Additional Information: A call to PInvoke function 'KinectHandTrackmyApping!myApp.MainWindow::mouse_event' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.
In order resolve the error I have changed
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
to this
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
The error was usage of long because long gives an exception because it's a 64-bit, uint works because it's 32-bit -- but it won't work for negative coordinates (which is a common monitor setup in Windows).

How do i use SetWindowPos to center a window?

What I want to do is to bring the handle to the front and to the center of the screen. Bring it to the front I know how to do i'm using SetForegroundWindow(IntPtr hWnd); and it's working fine. But how do I use the SetWindowPos to force to be in the center of the screen ?
IntPtr handle = process.MainWindowHandle;
if (handle != IntPtr.Zero)
{
SetWindowPos(handle, 0, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
}
Then when I call in the constructor for example to SetWindowPos what should I give it ? handle is fine I know what it should be. But all the resr 0,0,0,0,0,0 and what should be the values fro SWP_NOZORDER and SWP_NOSIZE ?
Before you can center it, first you must know how big it is. This can be accomplished with the GetWindowRect() API. After that it's simply a matter of calculating the center position taking into account the size of the screen:
public partial class Form1 : Form
{
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left; // x position of upper-left corner
public int Top; // y position of upper-left corner
public int Right; // x position of lower-right corner
public int Bottom; // y position of lower-right corner
}
private const int SWP_NOSIZE = 0x0001;
private const int SWP_NOZORDER = 0x0004;
private const int SWP_SHOWWINDOW = 0x0040;
[DllImport("user32.dll", SetLastError=true)]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);
Process process;
public Form1()
{
InitializeComponent();
process = Process.GetProcessesByName("calc").FirstOrDefault();
}
private void button1_Click(object sender, EventArgs e)
{
if (process == null)
return;
IntPtr handle = process.MainWindowHandle;
if (handle != IntPtr.Zero)
{
RECT rct;
GetWindowRect(handle, out rct);
Rectangle screen = Screen.FromHandle(handle).Bounds;
Point pt = new Point(screen.Left + screen.Width / 2 - (rct.Right - rct.Left) / 2, screen.Top + screen.Height / 2 - (rct.Bottom - rct.Top) / 2);
SetWindowPos(handle, IntPtr.Zero, pt.X, pt.Y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
}
}
}

Performance problems trying to preview video from webcam

I have a small application I wrote that simply displays a preview of webcam or my capture card. At the moment it works exactly how I want it to, with the exception that the capture card displays at a much lower framerate than I'd like it to.
Here is my relevant code:
private const int WM_CAP_DRIVER_CONNECT = 1034;
private const int WM_CAP_SET_PREVIEW = 1074;
private const int WM_CAP_SET_PREVIEWRATE = 1076;
private const int WM_CAP_SET_SCALE = 1077;
private const int WS_CHILD = 1073741824;
private const int WS_VISIBLE = 268435456;
private const short SWP_NOMOVE = 2;
private const short SWP_NOZORDER = 4;
private const short HWND_BOTTOM = 1;
private const int iDevice = 0;
private int hHwnd;
private int previewRate = 34;
private int width = 640;
private int height = 480;
[DllImport("user32.dll", EntryPoint="SendMessageA")]
public static extern int SendMessage(int hWnd, uint Msg, int wParam, int lParam);
[DllImport("user32.dll", EntryPoint="SetWindowPos")]
static extern int SetWindowPos(int hwnd, int hWndInsertAfter, int x, int y, int cx, int cy, int wFlags);
[DllImport("user32.dll")]
static extern bool DestroyWindow(int hndw);
[DllImport("avicap32.dll")]
public static extern int capCreateCaptureWindow(string lpszWindowName, int dwStyle, int X, int Y, int nWidth, int nHeight, int hwndParent, int nID);
private void OpenPreviewWindow()
{
hHwnd = capCreateCaptureWindow(iDevice.ToString(), (WS_VISIBLE | WS_CHILD), 0, 0, width, height, Handle.ToInt32(), 0);
// Connect to device
if (SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, iDevice, 0) != -1)
{
SendMessage(hHwnd, WM_CAP_SET_SCALE, 1, 0);
SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, previewRate, 0);
SendMessage(hHwnd, WM_CAP_SET_PREVIEW, 1, 0);
SetWindowPos(hHwnd, HWND_BOTTOM, 0, 0, width, height, (SWP_NOMOVE | SWP_NOZORDER));
}
else
{
DestroyWindow(hHwnd);
}
}
When I preview the capture card in an application like FMLE, it previews at 30 FPS, which is my target framerate (~34 milliseconds per frame,) however when I use my application to preview it's closer to 10-15 FPS. I should probably also note that my program will preview 30 FPS from my webcam. What could be causing the problem with the capture card, and how can I fix it?
Use DirectShow to view the webcam.
An example would be: http://www.codeproject.com/KB/audio-video/WebcamUsingDirectShowNET.aspx
or http://www.codeproject.com/KB/miscctrl/webcam_c_sharp.aspx

Directing mouse events [DllImport("user32.dll")] click, double click

I tried
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
and it works pretty fine to move the cursor to the desired point. I have never tried such kind of a DLL import before but it works :). However I want more what else can I extract?
Mainly I want to make double click, click or use wheel options without any mouse input, just the code how can I do that? and how can I check what else is included in user32dll?
Thanx
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, UIntPtr dwExtraInfo);
private const uint MOUSEEVENTF_LEFTDOWN = 0x02;
private const uint MOUSEEVENTF_LEFTUP = 0x04;
private const uint MOUSEEVENTF_RIGHTDOWN = 0x08;
private const uint MOUSEEVENTF_RIGHTUP = 0x10;
You should Import and Define these Constant's to work with Mouse using Win32API
Use method's below to do Mouse Operation's
void sendMouseRightclick(Point p)
{
mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, p.X, p.Y, 0, 0);
}
void sendMouseDoubleClick(Point p)
{
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, p.X, p.Y, 0, 0);
Thread.Sleep(150);
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, p.X, p.Y, 0, 0);
}
void sendMouseRightDoubleClick(Point p)
{
mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, p.X, p.Y, 0, 0);
Thread.Sleep(150);
mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, p.X, p.Y, 0, 0);
}
void sendMouseDown()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, 50, 50, 0, 0);
}
void sendMouseUp()
{
mouse_event(MOUSEEVENTF_LEFTUP, 50, 50, 0, 0);
}
If you want to do a Mouse Drag you should First Send MouseDown(Mouse Click) and keep it Clicked While Changing the Mouse Position than Send MouseUp(Release Click) something like this .
sendMouseDown();
Cursor.Position = new Point(30,30);
sendMouseUp();
Using long type raises an "PInvoke" error.
We should use int type:
[DllImport("user32.dll")]
static extern void mouse_event(int dwFlags, int dx, int dy,
int dwData, int dwExtraInfo);
[Flags]
public enum MouseEventFlags
{
LEFTDOWN = 0x00000002,
LEFTUP = 0x00000004,
MIDDLEDOWN = 0x00000020,
MIDDLEUP = 0x00000040,
MOVE = 0x00000001,
ABSOLUTE = 0x00008000,
RIGHTDOWN = 0x00000008,
RIGHTUP = 0x00000010
}
public static void LeftClick(int x, int y)
{
Cursor.Position = new System.Drawing.Point(x, y);
mouse_event((int)(MouseEventFlags.LEFTDOWN), 0, 0, 0, 0);
mouse_event((int)(MouseEventFlags.LEFTUP), 0, 0, 0, 0);
}
source: http://www.pinvoke.net/default.aspx/user32.mouse_event
Take a look at pinvoke.net for a listing of the available APIs. Code examples and the import statements are included. You can also expand the selection on the left to see the available APIs for each DLL.

Simulating mouse move in Math Input Panel (Windows 7)

I would like to compare my application for handwritten mathematical symbols recognition with the Math Input Panel (MIP) contained in Windows 7. I have a library of recorded mouse strokes representing different mathematical formulas and I need to send them to the MIP to measure its performance.
I tried to simulate mouse move but it's not working.
Here are constants and imported methods that I use:
const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
static extern void mouse_event(UInt32 dwFlags, UInt32 dx, UInt32 dy, UInt32 dwData, UIntPtr dwExtraInfo);
And that's the code itself:
IntPtr windowHandle = FindWindow("MathInput_Window", "");
SetForegroundWindow(windowHandle);
Cursor.Position = new Point(600, 700);
mouse_event(MOUSEEVENTF_LEFTDOWN, 600, 700, 0, UIntPtr.Zero);
for (int x = 600; x <= 650; x++)
{
Cursor.Position = new Point(x, 700);
}
for (int y = 700; y <= 750; y++)
{
Cursor.Position = new Point(650, y);
}
mouse_event(MOUSEEVENTF_LEFTUP, 650, 750, 0, UIntPtr.Zero);
But the only thing i get is a single dot at the position [600,700]. The funny thing is that when I use MSPaint instead of MIP everything is working perfectly.
Does anyone have some idea how it could be solved?
I have already solved the problem using the following function:
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
I call it to control both mouse button clicks and mouse moves and it works perfectly.

Categories