C# PostMessage CTRL+Fx not working - c#

I'm trying to simulate the CTRL+Fx key press in a window, but it's not working as spected. When my program send the key stroke, it just ignore the CTRL, so if it press CTRL+F3, the window gets only the F3 key press, here are some screenshots of the events captured with Window Detective:
Pressing CTRL+F3manually:
And this one is my program pressing CTRL+F3 using PostMessage:
As you can see, they are exactly the same, so I have no idea what to do anymore. Here is the code I'm using:
[DllImport("user32.dll", SetLastError = true)]
public static extern bool PostMessage(IntPtr hWnd, uint msg, uint wParam, uint lParam);
const int VK_CONTROL = 0x11;
const uint VK_CONTROL_LUP = 0xC01D0001;
const uint VK_CONTROL_LDOWN = 0x1D0001;
const int VK_F3 = 0x72;
const uint F3_LDOWN = 0x3D0001;
const uint F3_LUP = 0xC03D0001;
const int WM_KEYDOWN = 0x0100;
const int WM_KEYUP = 0x0101;
//Modifier
PostMessage(hWnd, WM_KEYDOWN, (uint)VK_CONTROL, VK_CONTROL_LDOWN);
//Key down
WinApi.PostMessage(hWnd, WM_KEYDOWN, (uint)VK_F3, F3_LDOWN);
//key up
WinApi.PostMessage(hWnd, WM_KEYUP, (uint)VK_F3, F3_LUP);
WinApi.PostMessage(hWnd, WM_KEYUP, (uint)VK_CONTROL, VK_CONTROL_LUP);
After a few tests I added a delay of 10 seconds after the first PostMessage (holding CTRL down) and if I press an arrow key the window detect the CTRL pressed, but if I press any other key, like F3, it just ignore it.
There is any other way to send key strokes to unfocused windows besides the PostMessage I'm using? Or there is some secret behind it that it might be ignored for some programs?
Thanks

Related

How do you perform mouse movements & clicks virtually [user32.dll]

How do you perform mouse movements & clicks virtually ?
What I mean by virtually is that, the main mouse isn't affected, so basically "creating" a second mouse that is controlled by setting x/y position (pref with user32.dll).
I have read a few similar questions here but the answer usually is with your main mouse, Example:
DllImport("user32")]
public static extern int SetCursorPos(int x, int y);
^ this moves your main mouse to x&y position on screen, what I want is to perform this action with a "virtual mouse" so my main mouse isn't moved, so basically I can keep using my computer while this "virtual mouse" does something else in another window for example.
then using this "virtual mouse" to perform clicks [virtual key codes]
I have tried this:
IntPtr MakeLParam(int x, int y) => (IntPtr)((y << 16) | (x & 0xFFFF));
var pointPtr = MakeLParam(900, 1000);//x y cords
IntPtr hWnd = ScreenCapture.FindWindow(null, ScreenCapture.GetWindowName()); //Finds Window
PostMessage(hWnd, WM_MOUSEMOVE | WM_LBUTTONDOWN | WM_LBUTTONUP, IntPtr.Zero, pointPtr);
[DllImport("User32.dll")]
public static extern Int32 PostMessage(
IntPtr hWnd, // handle to destination window
int Msg, // message
IntPtr wParam, // first message parameter
IntPtr lParam); // second message parameter
But nothing happens at all, and my guess is that WM_MOUSEMOVE is not working properly
public const int WM_KEYDOWN = 0x100;
public const int WM_KEYUP = 0x101;
public const int WM_COMMAND = 0x111;
public const int WM_LBUTTONDOWN = 0x201;
public const int WM_LBUTTONUP = 0x202;
public const int WM_LBUTTONDBLCLK = 0x203;
public const int WM_RBUTTONDOWN = 0x204;
public const int WM_RBUTTONUP = 0x205;
public const int WM_RBUTTONDBLCLK = 0x206;
public const int WM_MOUSEMOVE = 0x0200;
UPDATE, I think I solved it somewhat !
After reading more about PostMessage /SendInput, I found out that "application windows" can have layers of "application windows", so I used ispy++ to check it out, and yes the program had another layer where I wanted to click.
So to solve this I took the class name of the window where I wanted to click as well as the window name, here is an example code:
public static bool ClickTest()
{
IntPtr MakeLParam(int x, int y) => (IntPtr)((y << 16) | (x & 0xFFFF));//Just converts x&y to InPtr lParam
IntPtr WindowhWid = ScreenCapture.FindWindow(null, ScreenCapture.GetWindowName()); //Gets the window hWid
var ClasshWid = FindWindowEx(WindowhWid, IntPtr.Zero, "Classname", null); //Gets the Class hWid using WindowhWid AND the Class name (Need to find a way to get the classname using process list)
PostMessage(ClasshWid, WM_LBUTTONDOWN | WM_LBUTTONUP, 0, MakeLParam(938, 1011));//Finally sends it to the classhWid
return true;
}
Using these two functions
[DllImport("User32.dll")]
public static extern int FindWindowEx(
IntPtr hwndParent,
IntPtr hwndChildAfter,
string strClassName,
string strWindowName);
[DllImport("User32.dll")]
public static extern Int32 PostMessage(
int hWnd, // handle to destination window
int Msg, // message
int wParam, // first message parameter
IntPtr lParam); // second message parameter
Note that it won't click if the appilication window is MINIMIZED, although it will click if the window is behind another appilication window !
Also the X & Y is the screen X & Y and not the Application X & Y !
Now the question remains, why doesn't it work while the application window is minimized ?
The click doesn't go anywhere but to the application, so shouldn't it work while the application is minimized ?
It migiht not be what you're up to and what you look after, but AutoIT Dll offers plenty of automation ready to use and in the easiest way possible. Since you rely on a windows DLL then it's perfect.
If you're still on your own way to user32.dll then check Low level hook, that's what I used.
I highly recommend AutoIT dll though, it will save you ton of hair pulling hours guessing what's happening to the windows messages that do not respond properly

Send keys to unfocused window

im frustrated, i´ve been trying almost for 2 weeks to make a bot for a game that runs on the background on my PC.
Basically i want a bot that presses 1 and TAB every 5 seconds on a game that is in the background and doesnt have focus. I already spoke with a guy that achieved it but he said that as it wasnt easy he wouldnt tell me how he did it, he only said that it has to do with the process pipe and that i should focus on the events that activate a window.
And he sent me this link:
https://www.pinvoke.net/default.aspx/Constants.WM.
Any help would be appreciated.
This is my latest try that worked in the background but only for notepad:
static class Program
{
const UInt32 WM_KEYDOWN = 0x0100;
const UInt32 WM_KEYUP = 0x0101;
const int VK_D1 = 0x0031;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
[STAThread]
static void Main()
{
while (true)
{
IntPtr hwnd = (IntPtr)1517968;
PostMessage(hwnd, WM_KEYDOWN, VK_D1, 0);
Console.WriteLine(hwnd);
PostMessage(hwnd, WM_KEYUP, VK_D1, 0);
Thread.Sleep(5000);
}
}
}

Making Background Transparent

I am trying to make a makeshift onscreen keyboard for Windows 10 and need the background to be transparent, to make it more convenient for the user (the keys are already transparent). I, however, have no idea how to make the background transparent.
Any help would be greatly appreciated.
I believe that I am essentially looking for an updated version of the code in this thread show below:
using System;
using System.Runtime.InteropServices;
using UnityEngine;
public class TransparentWindow : MonoBehaviour
{
[SerializeField]
private Material m_Material;
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;
void Start()
{
// You really don't want to enable this in the editor, but it works there..
int fWidth = Screen.width;
int fHeight = Screen.height;
var margins = new MARGINS() { cxLeftWidth = -1 };
var hwnd = GetActiveWindow();
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_VISIBLE);
// Transparent windows with click through
SetWindowLong(hwnd, -20, 524288 | 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)
DwmExtendFrameIntoClientArea(hwnd, ref margins);
}
void OnRenderImage(RenderTexture from, RenderTexture to)
{
Graphics.Blit(from, to, m_Material);
}
}
The code given did not work, so I assume that it is outdated. I have no idea how to update it myself, since it is a bit out of my skill set. When I upload the code to Unity, it just says that there are errors in the code and that it is not a valid script. When I open the script, however, no errors appear.
I expect to be able to have a relatively good view of whatever is behind my keyboard, like my desktop, but I actually just see a black plane.
Update:
So apparently the error message was caused by my script not having the same name as my class. I spent over 4 hours yesterday trying to fix that error message, and this naming incident was the cause :(. Thanks Ruzihm. Anyway, now that the error message is gone, when I run or build the program, my transparent window material just comes up: a dark pink. I then changed my Unity version back to 2018.2.16f1, with no success. Then I removed the #if !Unity Editor line to get the transparency to work perfectly in the editor, but not when I build it. Note, click through does work when I build it and when I run it in the editor.
As discovered in the comments, the problem was fixed when the camera's clear flags were set to solid color and the pink transparent window material was replaced a with white transparent material.

"Place" a WinForm directly on the desktop

So I want to have something similar to an desktop overlay. So the thing is I tried to draw to the desktop wallpaper directly but this will get redrawn and from what I read there is really no good way around this. So I tried to go with a broderless completely transparent WinForm with text on it.
The Problem I have with is that hitting Windows+D will hide the application and I didn't found a way to prevent this or bring it up again. Also I read that setting the form as a Child of the Desktop can cause problems aswell.
What I did so far was setting the position of the Form directly above the Desktop:
[DllImport("user32.dll")]
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;
const UInt32 SWP_NOACTIVATE = 0x0010;
//By calling SetWindowPos(Handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); it will move to the very back of all windows.
What I want in the end is a Win Form that is always ontop of the Desktop but under every other window.
You should run a thread which in fraction of time ( such as 100ms) call BringWindowToTop api and bring your window aplication to top, it will solve to Win+D issue.
[DllImport("user32.dll", SetLastError=true)]
static extern bool BringWindowToTop(IntPtr hWnd);
[DllImport("user32.dll", SetLastError=true)]
static extern bool BringWindowToTop(HandleRef hWnd);

How to simulate a key that is being pressed/hold in the background application

I would like to simulate a key that is being pressed for few seconds and then it was released.
You all know the effect of holding key for a moment ;)
I tried something like this:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool PostMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
...
const uint WM_KEYDOWN = 0x0100;
const uint WM_KEYUP = 0x0101;
intKeyCode = 'a';
...
PostMessage(windowPointer, WM_KEYDOWN, (IntPtr)(intKeyCode - 0x020), IntPtr.Zero);
Thread.Sleep(5000); // Sleep for 5 sec
PostMessage(windowPointer, WM_KEYUP, (IntPtr)(intKeyCode - 0x020), IntPtr.Zero);
Result is easy to predict. It shows only two letters instead of typing it few times for first 5 seconds.
Does anyone tried something like this?

Categories

Resources