Another way to make the mouse click? - c#

I am making an AI and want it to function as a player. I use some code to make the mouse click and this works. Then I made some code to make the mouse click on random places but then it stopped working.
I changed
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
to
private const int MOUSEEVENTF_LEFTDOWN = 0x0002;
private const int MOUSEEVENTF_LEFTUP = 0x0004;
but it did not seem to change anything except the location it pressed on.
I also made it wait 0,5 sec between mouseDown and mouseUp but it still did not work when I ran rndPlay();, when I tried to do just press1(); it did work.
public static void MoveTo(int x, int y)
{
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, x, y, 0, 0);
}
public static void LeftClick()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, System.Windows.Forms.Control.MousePosition.X, System.Windows.Forms.Control.MousePosition.Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, System.Windows.Forms.Control.MousePosition.X, System.Windows.Forms.Control.MousePosition.Y, 0, 0);
}
public static void LeftMouseClick(int x, int y)
{
MoveTo(x, y);
LeftClick();
}
public static void press1()
{
LeftMouseClick(28000, 25000);
last2Moves("1");
}
public static void press2()
{
LeftMouseClick(33000, 25000);
last2Moves("2");
}
//etc
public static void rndPlay()
{
for (int r = 0; moveSucces != true && r < 10000; r++)
{
Random rndP = new Random();
int rndPress = rndP.Next(1, 10);
if (rndPress == 1)
{
press1();
}
if (rndPress == 2)
{
press2();
}
//etc
}
}
When I run rndPlay(); I see the mouse move but it does not seem to click. Is there another way to make the mouse click in a location that would work better/faster?

Apart from using very large values for X and Y your code seems ok.
I whipped up a small example using a textbox to show when and where the mouse was clicked, connected to a simple Forms timer to simulate clicks.
public partial class Form1 : Form
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
private const int MouseLeftDown = 0x02;
private const int MouseLeftUp = 0x04;
private readonly Timer _timer = new Timer();
public Form1()
{
InitializeComponent();
_timer.Interval = 1000;
_timer.Tick += (s, a) => mouse_event(MouseLeftDown | MouseLeftUp, (uint)MousePosition.X, (uint)MousePosition.Y, 0, 0);
_timer.Enabled = true;
_textBox.Click += (s, a) => _textBox.AppendText($"Clicked at {PointToClient(MousePosition)}\n");
}
}

Related

Is there a way I can use PictureBox MouseMove event but still move around on the whole screen?

I am making a PictureBox move in the direction of the mouse, but it only works inside the PictureBox. The PictureBoxis 200x200 so it makes a glitchy thing, which I'm guessing is because the space is too tight. I also have a function that makes the PictureBoxfollow the mouse. Is there a way that I can move my mouse around the screen meanwhile the PictureBoxrotates in the direction of the mouse?
private float _angle;
private void Spiller_MouseMove(object sender, MouseEventArgs e)
{
(float centerX, float centerY) = GetCenter(spiller.ClientRectangle);
_angle = (float)(Math.Atan2(e.Y - centerY, e.X - centerX) * 180.0 / Math.PI);
spiller.Invalidate();
}
private void Spiller_Paint(object sender, PaintEventArgs e)
{
Bitmap image = Resource1.spillerr;
float scale = (float)spiller.Width / image.Width;
(float centerX, float centerY) = GetCenter(e.ClipRectangle);
e.Graphics.TranslateTransform(centerX, centerY);
e.Graphics.RotateTransform(_angle);
e.Graphics.TranslateTransform(-centerX, -centerY);
e.Graphics.ScaleTransform(scale, scale);
e.Graphics.DrawImage(image, 0, 0);
}
private static (float, float) GetCenter(Rectangle rect)
{
float centerX = (rect.Left + rect.Right) * 0.5f;
float centerY = (rect.Top + rect.Bottom) * 0.5f;
return (centerX, centerY);
}
You can create sudo-active graphics by using a Timer component that has a small interval (16ms ~= 60fps). And calling Invalidate every tick of the timer.
To reduce the flickering of the control that is being constantly refreshed, you'll likely want to set its style as follows:
class CustomPictureBox : PictureBox
{
public CustomPictureBox() {
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
}
}
// change the type of spiller in Form1.designer.cs
private System.Windows.Forms.PictureBox spiller;
// becomes
private CustomPictureBox spiller;
// and
spiller = new System.Windows.Forms.PictureBox();
// becomes
spiller = new CustomPictureBox();
Global mouse position on the screen can be obtained in the paint routine via Control.MousePosition.
A way is with a WH_MOUSE_LL hook .
I just tested on Windows 10 by adapting your sample in VS 2015, it works fine without any flickering, and just needs ScreenToClient to convert screen coordinates into picture coordinates
Main declarations :
public const int WH_MIN = (-1);
public const int WH_MSGFILTER = (-1);
public const int WH_JOURNALRECORD = 0;
public const int WH_JOURNALPLAYBACK = 1;
public const int WH_KEYBOARD = 2;
public const int WH_GETMESSAGE = 3;
public const int WH_CALLWNDPROC = 4;
public const int WH_CBT = 5;
public const int WH_SYSMSGFILTER = 6;
public const int WH_MOUSE = 7;
public const int WH_HARDWARE = 8;
public const int WH_DEBUG = 9;
public const int WH_SHELL = 10;
public const int WH_FOREGROUNDIDLE = 11;
public const int WH_CALLWNDPROCRET = 12;
public const int WH_KEYBOARD_LL = 13;
public const int WH_MOUSE_LL = 14;
public const int WH_MAX = 14;
public const int WH_MINHOOK = WH_MIN;
public const int WH_MAXHOOK = WH_MAX;
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct MSLLHOOKSTRUCT
{
public System.Drawing.Point pt;
public int mouseData;
public int flags;
public int time;
public uint dwExtraInfo;
}
[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct KBDLLHOOKSTRUCT
{
public int vkCode;
public int scanCode;
public int flags;
public int time;
public uint dwExtraInfo;
}
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("User32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public int x;
public int y;
public POINT(int X, int Y)
{
this.x = X;
this.y = Y;
}
}
[DllImport("User32.dll", SetLastError = true)]
public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);

Positioning window form to be bottommost

I want every time you start my window form, he set at the bottom of the screen (above the taskbar)
public void goBottomWindow(Form targetForm)
{
targetForm.WindowState = FormWindowState.Maximized;
targetForm.FormBorderStyle = FormBorderStyle.None;
targetForm.TopMost = true;
WinApi.SetWinFullScreen(targetForm.Handle);
}
public class WinApi
{
[DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
public static extern int GetSystemMetrics(int which);
[DllImport("user32.dll")]
public static extern void
SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter,
int X, int Y, int width, int height, uint flags);
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
private static IntPtr HWND_TOP = IntPtr.Zero;
private const int SWP_SHOWWINDOW = 64; // 0x0040
public static int ScreenX
{
get { return GetSystemMetrics(SM_CXSCREEN); }
}
public static int ScreenY
{
get {return 60;}
}
public static void SetWinFullScreen(IntPtr hwnd)
{
SetWindowPos(hwnd, HWND_TOP, 0, 0, ScreenX, ScreenY, SWP_SHOWWINDOW);
}
}
Using this code, it leaves my window form at the top of the screen .... but what I need is the form window positioned below.
It is possible to do this?
Sorry, my English is very bad :(
Why targetForm.WindowState = FormWindowState.Maximized; ?
isn't FormWindowState.Normal better for you?
Just fetch the dimension of your desktop/screen
var rect = Screen.PrimaryScreen.WorkingArea;
targetForm.Witdh = rect.Width;
targetForm.Top = rect.Height - targetForm.Height;
I saw that in your first lines it says targetForm.TopMost = true;
That means that your form will be TOPMOST, if you want your form to be BottomMost, you should change that to false;
Hope this helps! - CCB

How to simulate a mouse click on a started process

I am trying to open an application through C# using Process.Start() and then simulate a mouse click on the application.
When I run the application, the mouse click occurs in the left top corner, which is not what I want.
public partial class Form1 : Form
{
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, int dx, int dy,
int dwData, int dwExtraInfo);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
private const int MOUSEEVENTF_ABSOLUTE = 0x8000;
private const int MOUSEEVENTF_LEFTDOWN = 0x0002;
private const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
private const int MOUSEEVENTF_MIDDLEUP = 0x0040;
private const int MOUSEEVENTF_MOVE = 0x0001;
private const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
private const int MOUSEEVENTF_RIGHTUP = 0x0010;
private const int MOUSEEVENTF_WHEEL = 0x0800;
private const int MOUSEEVENTF_XDOWN = 0x0080;
private const int MOUSEEVENTF_XUP = 0x0100;
private void button1_Click(object sender, EventArgs e)
{
new Thread(() =>
{
AddTextToListBox1(label1);
}).Start();
new Thread(() =>
{
// AddTextToListBox2(label2);
}).Start();
}
private void AddTextToListBox1(Label label)
{
if (label1.InvokeRequired)
{
stringDelegate sd = new stringDelegate(AddTextToListBox1);
this.Invoke(sd, new object[] { label1 });
}
else
{
label1.Text = this.ToString()+"Hi";
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "C://xyz//xyz.exe";
p.Start();
IntPtr hwnd = p.MainWindowHandle;
}
}
private void AddTextToListBox2(Label label)
{
if (label1.InvokeRequired)
{
stringDelegate sd = new stringDelegate(AddTextToListBox2);
this.Invoke(sd, new object[] { label1 });
}
else
{
label2.Text = "done";
Thread.Sleep(6000);
int X = 579;
int Y = 637;
mouse_event(MOUSEEVENTF_ABSOLUTE| MOUSEEVENTF_MOVE, X, Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
}
}
I think mouse_event will only raise event in current app because it doesn't take hwnd on params. My experience in this area is really low, but I've done some research. Look at SendMessage function.
MSDN article:
Sends the specified message to a window or windows.
The SendMessage function calls the window procedure for the specified window
and does not return until the window procedure has processed the message.
You can send many messages with it, including mouse events

Send mouse & keyboard events

I'm developing an app that have to send some keys or mouse events to the active window.
I'm using this class:
Mouse
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Mouse
{
public static class VirtualMouse
{
// import the necessary API function so .NET can
// marshall parameters appropriately
[DllImport("user32.dll")]
static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
// constants for the mouse_input() API function
private const int MOUSEEVENTF_MOVE = 0x0001;
private const int MOUSEEVENTF_LEFTDOWN = 0x0002;
private const int MOUSEEVENTF_LEFTUP = 0x0004;
private const int MOUSEEVENTF_RIGHTDOWN = 0x0008;
private const int MOUSEEVENTF_RIGHTUP = 0x0010;
private const int MOUSEEVENTF_MIDDLEDOWN = 0x0020;
private const int MOUSEEVENTF_MIDDLEUP = 0x0040;
private const int MOUSEEVENTF_ABSOLUTE = 0x8000;
// simulates movement of the mouse. parameters specify changes
// in relative position. positive values indicate movement
// right or down
public static void Move(int xDelta, int yDelta)
{
mouse_event(MOUSEEVENTF_MOVE, xDelta, yDelta, 0, 0);
}
// simulates movement of the mouse. parameters specify an
// absolute location, with the top left corner being the
// origin
public static void MoveTo(int x, int y)
{
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, x, y, 0, 0);
}
// simulates a click-and-release action of the left mouse
// button at its current position
public static void LeftClick()
{
mouse_event(MOUSEEVENTF_LEFTDOWN, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
}
public static void RightClick()
{
mouse_event(MOUSEEVENTF_RIGHTDOWN, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
mouse_event(MOUSEEVENTF_RIGHTUP, Control.MousePosition.X, Control.MousePosition.Y, 0, 0);
}
}
}
Keyboard
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Mouse
{
public static class VirtualKeyboard
{
[DllImport("user32.dll")] static extern uint keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
public static void KeyDown(System.Windows.Forms.Keys key)
{
keybd_event((byte)key, 0, 0, 0);
}
public static void KeyUp(System.Windows.Forms.Keys key)
{
keybd_event((byte)key, 0, 0x7F, 0);
}
}
}
this is my testing code:
private void button1_Click(object sender, EventArgs e)
{
Thread.Sleep(2000);
VirtualMouse.Move(100, 100);
VirtualMouse.RightClick();
VirtualKeyboard.KeyDown(System.Windows.Forms.Keys.A);
VirtualKeyboard.KeyUp(System.Windows.Forms.Keys.A);
}
Mouse moves, but doesn't send click. Any idea?
How can I make a key continue pressed for some time? I tried using thread.sleep between KeyDown and KeyUp and it's not working.
There is an open source project on CodePlex (Microsoft's open source website)
Windows Input Simulator (C# SendInput Wrapper - Simulate Keyboard and Mouse)
http://inputsimulator.codeplex.com/
It has examples and real simple to use.
Your definitions should be Uint32:
private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x02;
private const UInt32 MOUSEEVENTF_ABSOLUTE = 0x8000;
private const UInt32 MOUSEEVENTF_LEFTUP = 0x04;
private const UInt32 MOUSEEVENTF_RIGHTDOWN = 0x08;
private const UInt32 MOUSEEVENTF_RIGHTUP = 0x10;

Control another application using C#

I need to control other application by simulating mouse movement and keyboard input. How do I accomplish this in C#? Is it even possible?
Have you looked at White TestStack?
Sample code:
Application application = Application.Launch("foo.exe");
Window window = application.GetWindow("bar", InitializeOption.NoCache);
Button button = window.Get<Button>("save");
button.Click();
I don't think it can get better than that. The library is created by ThoughtWorks.
See "To send a keystroke to a different application" on this page:
http://msdn.microsoft.com/en-us/library/ms171548.aspx
You can use p/invoke, I stole the following code for mouse clicks in random spots on a button with a known handle:
[Flags]
public enum MouseEventFlags
{
LEFTDOWN = 0x00000002,
LEFTUP = 0x00000004,
MIDDLEDOWN = 0x00000020,
MIDDLEUP = 0x00000040,
MOVE = 0x00000001,
ABSOLUTE = 0x00008000,
RIGHTDOWN = 0x00000008,
RIGHTUP = 0x00000010
}
[StructLayout(LayoutKind.Sequential)]
public struct Rectangle
{
public int X;
public int Y;
public int Width;
public int Height;
}
private static void Click(IntPtr Handle)
{
lock (typeof(MouseAction))
{
Rectangle buttonDesign;
GetWindowRect(Handle, out buttonDesign);
Random r = new Random();
int curX = 10 + buttonDesign.X + r.Next(100 - 20);
int curY = 10 + buttonDesign.Y + r.Next(60 - 20);
SetCursorPos(curX, curY);
//Mouse Right Down and Mouse Right Up
mouse_event((uint)MouseEventFlags.LEFTDOWN, curX, curY, 0, 0);
mouse_event((uint)MouseEventFlags.LEFTUP, curX, curY, 0, 0);
}
}
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
[DllImport("user32.dll")]
private static extern void mouse_event(
long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
[DllImport("user32.dll")]
static extern bool GetWindowRect(IntPtr hWnd, out Rectangle rect);
you can use AutoIT, it's freeware, and it has a dll version that you can import into C# (DllImport). It allows you to click on controls, write strings to edit boxes, make combobox selections etc on another application from C#.
Use the SendMessage Native Win32 API. DllImport this method from the User32.dll. You can use this API to send both keyboard & mouse messages
I tried to do the same: to use the mouse i used this class
(you need to add using System.Runtime.InteropServices;)
public class MouseClick1 //public is important here**
{
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint 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 int CoordX { get; set; }
public int CoordY { get; set; }
public void Click1()
{
Cursor.Position = new Point(CoordX, CoordY);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
}
and after on your form1 (presuming the name is form1) you can
public partial class form1 : Form
{
MouseClick1 button1 = new MouseClick1();
MouseClick1 button2 = new MouseClick1();
[...]
public void Simulate_button1and2_Click(object sender, EventArgs e)
{
button1.CoordX = 1652; //random coordinates
button1.CoordY = 225;
button2.CoordX = 1650;
button2.CoordY = 250;
button1.Click1();
button1.Click2();
}
}
To have the coordinates on your pointer, I use a timer and a label:
private void timer1_Tick(object sender, EventArgs e)
{
Coord.Text = Cursor.Position.X.ToString() + " : " + Cursor.Position.Y.ToString(); //Premet d'avoir les coord en direct
}
Work fine with me.

Categories