I want to make a mouse macroer. Which can both do simulated mouse events, or using my computers own cursor on screen.
The macro shall be created by typing in methods in the IDE. These methods shall then execute mouse events on a certain .exe´s window. By using coordinates.
For example this is my goal of a method executing a simulated or not simulated mouse left click on a certain .exe´s window:
Psuedo code:
//Following method left clicks with the offset (x, y)
//from the windows top left corner. If the bool isSimulated
//is set to true the click will be simulated else the computers
//own mouse cursor will be moved and execute the mouse event.
LeftMouseClickOnWindow(x, y, isSimulated);
To chrisp the problem even more, simulated mouse clicks should function while the window is minimized or when unfocused.
I am wondering what the best approach to create this kind of util is.
Is user32.dll´s functions a good approach?
Is it easier to do it in C++ rather than C#?
Any advices, sources, example codes and comments is warmly appreciated!
Both C++ and C# are great. AutoHotKey can do the job, but I'm like you - I love to write my own stuff. Another option is AutoIt, and you can use its dll in your C# project... but then you have to make sure that it's installed on every system... not a luxury that I've encountered often.
Here's something to play around with. Hopefully it'll get you going... note that it's C#. Before you run this code, make sure that you don't have anything important open where your mouse is at... this will move 20 times in a diagonal to the lower right and perform a click every time it moves. You don't want this to close your stuff accidentally. So, just minimize it all, prior to running this.
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleApplication
{
class Program
{
[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 void DoMouseStuff()
{
Cursor.Current = new Cursor(Cursor.Current.Handle);
var point = new Point(Cursor.Position.X, Cursor.Position.Y);
for (int i = 0; i < 20; i++, point.X += 10, point.Y += 10)
{
Cursor.Position = point;
Program.mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, (uint)Cursor.Position.X, (uint)Cursor.Position.Y, 0, 0);
System.Threading.Thread.Sleep(100);
}
}
static void Main(string[] args)
{
var prog = new Program();
prog.DoMouseStuff();
}
}
}
You'll need to set references for System.Windows.Forms & System.Drawing, if you don't have those set already. I made it as a console app, so, setting for me was required. As you notice, I included System.Threading.Thread.Sleep(100);... this is so that you can see what's going on. So, I'm basically slowing down the whole thing. It moves and it clicks every time it moves (which is approximately once every 100 milliseconds).
Familiarize yourself with the Cursor and user32.dll.
Last, but not least, here's MSDN documentation on mouse & keyboard simulation: http://msdn.microsoft.com/en-us/library/ms171548.aspx
Related
I have created a small C# console app to move the pointer around the screen, in the hope that this would prevent the screen from sleeping / locking after a few minutes. Unfortunately the screen still goes to sleep after a few minutes.
Does anyone know if it's actually possible to write something in C# which will act like user input (either mouse or keyboard), and prevent the screen from sleeping / locking automatically?
Here is what I have, which I thought might do the trick.
class Program
{
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
static Random rnd = new Random();
static void Main(string[] args)
{
Rectangle screenRes = Screen.PrimaryScreen.Bounds;
int widtMax = screenRes.Width;
int heighMax = screenRes.Height;
int w;
int h;
do
{
while (!Console.KeyAvailable)
{
w = rnd.Next(1, widtMax);
h = rnd.Next(1, heighMax);
SetCursorPos(w, h);
System.Threading.Thread.Sleep(1000);
}
} while (Console.ReadKey(true).Key != ConsoleKey.Escape);
}
}
You can make use of SetThreadExecutionState
Enables an application to inform the system that it is in use, thereby
preventing the system from entering sleep or turning off the display
while the application is running.
Remarks
Calling SetThreadExecutionState without ES_CONTINUOUS simply resets
the idle timer; to keep the display or system in the working state,
the thread must call SetThreadExecutionState periodically.
To run properly on a power-managed computer, applications such as fax
servers, answering machines, backup agents, and network management
applications must use both ES_SYSTEM_REQUIRED and ES_CONTINUOUS when
they process events. Multimedia applications, such as video players
and presentation applications, must use ES_DISPLAY_REQUIRED when they
display video for long periods of time without user input.
Applications such as word processors, spreadsheets, browsers, and
games do not need to call SetThreadExecutionState.
DllImport
[DllImport("kernel32.dll", CharSet = CharSet.Auto,SetLastError = true)]
static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
Enums
[FlagsAttribute]
public enum EXECUTION_STATE :uint
{
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
// Legacy flag, should not be used.
// ES_USER_PRESENT = 0x00000004
}
Usage
void PreventSleep ()
{
// Prevent Idle-to-Sleep (monitor not affected) (see note above)
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_AWAYMODE_REQUIRED);
}
UPDATE 02/08/2021:
In case anyone is looking for a complete example, here is a project I found on github that has implemented this: https://github.com/pedrolcl/screensaver-disabler
I'm busy making a application where i can use the Leap as a mouse. I'm making a WPF application with C# and XAML.
I allready can move the cursor, but i have problems making a function to activate the left mouse button.
Can someone help me with this problem? I need to activate buttons created in XAML.
Another solution could be a function that activates a button when de Leap cursor is on the button for like 3 seconds. I can't find any examples on the Internet. Does someone have a simple basic program or example for me? Please help!
Here is a link to the application i allready have. Maybe it helps
https://www.dropbox.com/sh/kp51hdbhcacaky7/pdinDQpA-6
About the "mouse over button" thing - u can try this solution (worked for me):
create hover event for buttons (mouse entered / leave)
create a bool flag for like "isHovered" (true if hovered, false if not)
start a DispacherTimer, set it's Tick (3 sec?)
on Tick do mouse click (previous answer)
hope it halped :)
try this:
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int 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()
{
Point mousePoint = GetMousePosition();
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, (int)mousePoint.X, (int)mousePoint.Y, 0, 0);
}
I'm working on an Windows Form Application in C#, Framework 4 (32 bit).
I have a list that holds coords of the mouse, and I can capture them. So far so good.
But at some point, I want to go to those coords and left mouse click on it.
This is how it looks like right now:
for (int i = 0; i < coordsX.Count; i++)
{
Cursor.Position = new Point(coordsX[i], coordsY[i]);
Application.DoEvents();
Clicking.SendClick();
}
And the Clicking class:
class Clicking
{
private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
private static extern void mouse_event(
UInt32 dwFlags, // motion and click options
UInt32 dx, // horizontal position or change
UInt32 dy, // vertical position or change
UInt32 dwData, // wheel movement
IntPtr dwExtraInfo // application-defined information
);
// public static void SendClick(Point location)
public static void SendClick()
{
// Cursor.Position = location;
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, new System.IntPtr());
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, new System.IntPtr());
}
}
But I'm getting this error:
Could not load type 'program.Clicking' from assembly 'program, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because the method 'mouse_event' has no implementation (no RVA).
And i realy don't understand what the problem is... Do you guys know what the problem is? or do you know an better way to do what i'm trying to do?
Have you included the following line?
[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData,
UIntPtr dwExtraInfo);
This will import the function mouse_event from the user32 dll, which is what you are trying to use within your program. Currently your program does not know about this method within the DLL untill you specify wher it comes from.
The website PInvoke.net user32 Mouse Event is quite handy for the basics on this sort of thing.
The answer to Directing mouse events [DllImport(“user32.dll”)] click, double click will be of great help to your understanding as well.
The flags are what commands you want to send into the mouse_input function, in that example you can see that he is sending both mouse down and mouse up in the same line, this is fine because the mouse_event function will split those flags up and execute them consecutively.
Also note that this method has been superseded by the SendInput command, a good example of SendInput and SetMousePos can be found At this Blog
I guess you are missing the following line
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
I am using sendkeys in C# .NET. I have letters, arrow keys and enter working. I cant figure out how to send a right click for the context menu. I know i can press a key on my keyboard to do it but i have no idea how to send the msg. How do i? i googled and saw
new MenuItem().PerformClick();
as a solution however i didnt see any affect. The keys are being sent to another application.
You can wrap the user32.dll, I got the general idea from here
EDIT:
I added in posX and posY, which would be the mouse coordinates.
using System;
using System.Runtime.InteropServices;
namespace WinApi
{
public class Mouse
{
[DllImport("user32.dll")]
private static extern void mouse_event(UInt32 dwFlags,UInt32 dx,UInt32 dy,UInt32 dwData,IntPtr dwExtraInfo);
private const UInt32 MouseEventRightDown = 0x0008;
private const UInt32 MouseEventRightUp = 0x0010;
public static void SendRightClick(UInt32 posX, UInt32 posY)
{
mouse_event(MouseEventRightDown, posX, posY, 0, new System.IntPtr());
mouse_event(MouseEventRightUp, posX, posY, 0, new System.IntPtr());
}
}
}
Assuming you are referring to the key positioned a few places right of the spacebar, which performs the same operation as the right mouse button in some situations, {MENU} may be the special key you want to send. It is not implemented in some SendKeys variations, and I am unsure of the latest version of C#.NET.
You cannot send mouse input using the .NET SendKeys class. At least, not that I know of nor that's documented. The best way to do this is to switch to the WinAPI and use the SendInput method. You can use this in .NET using DllImport for the function (in "user32.dll") and StructLayout for the structures.
Then you will want to call it like this:
INPUT pressRight;
pressRight.type = MOUSE; // = 0
pressRight.mi.dx = 0;
pressRight.mi.dy = 0;
pressRight.mi.mouseData = 0;
pressRight.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN; // = 8
pressRight.mi.time = 0;
pressRight.mi.dwExtraInfo = IntPtr.Zero;
INPUT releaseRight = pressRight;
releaseRight.mi.dwFlags = MOUSEEVENTF_RIGHTUP; // = 10
INPUT[] inputs = new INPUT[2];
inputs[0] = pressRight;
inputs[1] = releaseRight;
SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT)));
The {MENU} key is not always avialable, as noted by #Sparr. However, shift-F10 brings up the context menu in most Windows applications. So SendKeys.SendWait("+{F10}"); should work.
There must be a better way than a constrained numeric updown control.
The easiest way to enter numbers (especially non-integer numbers) in Windows Mobile (or in a regular Windows application) is to just have a text box that the users type into, and then validate that they've entered a proper number.
The problem with this approach in Windows Mobile is that the default SIP (Soft Input Panel aka little pop-up keyboard) looks like this:
alt text http://img510.imageshack.us/img510/6210/sipreg.jpg
On a real Windows Mobile device, the SIP looks even smaller than this, and it is a gigantic pain in the keister to hit the little number keys at the top correctly. What you want to use for this purpose is the Numeric mode, which you get by clicking the "123" button in the upper left corner, and looks like this:
alt text http://img16.imageshack.us/img16/6128/sipnum.jpg
The problem with this is that there is no (simple) way programatically to make this mode of the SIP appear instead of the regular keyboard. To get the SIP to appear in numeric mode, add a reference to your project to Microsoft.WindowsCE.Forms, and then add this code as a class named "SIPHandler" (you will have to change the namespace to your project's namespace):
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
using Microsoft.WindowsCE.Forms;
namespace DeviceApplication1
{
/// <summary>
/// Handles showing and hiding of Soft Input Panel (SIP). Better to use these
/// methods than having an InputControl on a form. InputControls behave oddly
/// if you have multiple forms open.
/// </summary>
public class SIPHandler
{
public static void ShowSIP()
{
SipShowIM(1);
}
public static void ShowSIPNumeric()
{
SipShowIM(1);
SetKeyboardToNumeric();
}
public static void ShowSIPRegular()
{
SipShowIM(1);
SetKeyboardToRegular();
}
public static void HideSIP()
{
SipShowIM(0);
}
private static void SetKeyboardToRegular()
{
// Find the SIP window
IntPtr hWnd = FindWindow("SipWndClass", null);
// Go one level below as the actual SIP window is a child
hWnd = GetWindow(hWnd, GW_CHILD);
// Obtain its context and get a color sample
// The premise here is that the numeric mode is controlled by a virtual button in the top left corner
// Whenever the numeric mode is active, the button background will be of COLOR_WINDOW_TEXT
IntPtr hDC = GetDC(hWnd);
int pixel = GetPixel(hDC, 2, 2);
// Notice that we cannot simply compare the color to the system color as the system color is 24 bit (or palette)
// and the real color is dithered to 15-16 bits for most devices, so white (0xff, 0xff, 0xff) becomes
// almost white (oxf8, 0xfc, 0xf8)
// ken's hack: here we only want to simulate the click if the keyboard is in numeric mode, in
// which case the back color will be WindowText
//int clrText = (SystemColors.Window.R) | (SystemColors.Window.G << 8) | (SystemColors.Window.B << 16);
int clrText = (SystemColors.WindowText.R) | (SystemColors.WindowText.G << 8) | (SystemColors.WindowText.B << 16);
SetPixel(hDC, 2, 2, clrText);
int pixelNew = GetPixel(hDC, 2, 2);
// Restore the original pixel
SetPixel(hDC, 2, 2, pixel);
if (pixel == pixelNew)
{
// Simulate stylus click
Message msg = Message.Create(hWnd, WM_LBUTTONDOWN, new IntPtr(1), new IntPtr(0x00090009));
MessageWindow.SendMessage(ref msg);
msg = Message.Create(hWnd, WM_LBUTTONUP, new IntPtr(0), new IntPtr(0x00090009));
MessageWindow.SendMessage(ref msg);
}
// Free resources
ReleaseDC(hWnd, hDC);
}
private static void SetKeyboardToNumeric()
{
// Find the SIP window
IntPtr hWnd = FindWindow("SipWndClass", null);
// Go one level below as the actual SIP window is a child
hWnd = GetWindow(hWnd, GW_CHILD);
// Obtain its context and get a color sample
// The premise here is that the numeric mode is controlled by a virtual button in the top left corner
// Whenever the numeric mode is active, the button background will be of COLOR_WINDOW_TEXT
IntPtr hDC = GetDC(hWnd);
int pixel = GetPixel(hDC, 2, 2);
// Notice that we cannot simply compare the color to the system color as the system color is 24 bit (or palette)
// and the real color is dithered to 15-16 bits for most devices, so white (0xff, 0xff, 0xff) becomes
// almost white (oxf8, 0xfc, 0xf8)
int clrText = (SystemColors.Window.R) | (SystemColors.Window.G << 8) | (SystemColors.Window.B << 16);
SetPixel(hDC, 2, 2, clrText);
int pixelNew = GetPixel(hDC, 2, 2);
// Restore the original pixel
SetPixel(hDC, 2, 2, pixel);
if (pixel == pixelNew)
{
// Simulate stylus click
Message msg = Message.Create(hWnd, WM_LBUTTONDOWN, new IntPtr(1), new IntPtr(0x00090009));
MessageWindow.SendMessage(ref msg);
msg = Message.Create(hWnd, WM_LBUTTONUP, new IntPtr(0), new IntPtr(0x00090009));
MessageWindow.SendMessage(ref msg);
}
// Free resources
ReleaseDC(hWnd, hDC);
}
[DllImport("coredll.dll")]
private extern static bool SipShowIM(int dwFlag);
[DllImport("coredll.dll")]
private extern static IntPtr FindWindow(string wndClass, string caption);
[DllImport("coredll.dll")]
private extern static IntPtr GetWindow(IntPtr hWnd, int nType);
[DllImport("coredll.dll")]
private extern static int GetPixel(IntPtr hdc, int nXPos, int nYPos);
[DllImport("coredll.dll")]
private extern static void SetPixel(IntPtr hdc, int nXPos, int nYPos, int clr);
[DllImport("coredll.dll")]
private extern static IntPtr GetDC(IntPtr hWnd);
[DllImport("coredll.dll")]
private extern static void ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("coredll.dll")]
private static extern bool SipSetCurrentIM(byte[] clsid);
const int WM_LBUTTONDOWN = 0x0201;
const int WM_LBUTTONUP = 0x0202;
const int GW_CHILD = 5;
}
}
Sorry about the length. To pop the SIP up in numeric mode, you just use this line:
SIPHandler.ShowSIPNumeric();
or to make it appear in regular keyboard mode:
SIPHandler.ShowSIPRegular();
And to hide it again:
SIPHandler.HideSIP();
The basic trick behind this code is to sort of "peek" the color in the upper left corner to determine whether the SIP is already in regular keyboard or numeric mode, and then to simulate a mouse click (if necessary) in the same corner to ensure that the SIP is in the mode desired.
Note: this is "borrowed" web code, but I no longer know where I got it from. If anyone on SO knows where this hack came from, please let me know and I'll be happy to attribute it to the original author.
Update: well, after 2 seconds of Googling, I've found that the proximate source of this code was Daniel Moth:
http://www.danielmoth.com/Blog/InputPanelEx.cs
... who credits Alex Feinman with the original:
http://www.alexfeinman.com/download.asp?doc=IMSwitch.zip
Thanks, guys! This code actually brought me to tears once (I was chopping onions at the time, but that couldn't have been it).
The MaskedTextBox might be of use. Failing that, I recommend using an ordinary TextBox with an OnTextChange event handler that checks to make sure the value entered is actually a number. Any non-numerical characters, and you can bang out a message box, or simply remove those characters completely, depending on your needs.
The NumericUpDown controls are slow to use sometimes, but they have intrinsic data validation which in some cases is quite useful. If the control is one the user is not going to use often, consider using it. Otherwise the MaskedTextBox or TextBox is the way to go.
Another approach to this problem is to use a multi-level ContextMenu, where the first layer of options covers ranges of numbers, and the second layers let the users pick specific values, like this:
alt text http://img19.imageshack.us/img19/6329/dropdowns.jpg
You can create the full menu structure ahead of time (kind of a pain) or just load the structure dynamically depending on the range of values and the resolutions required. You can do this with hundreds of menu items in much less than a second, even on Windows Mobile devices.
This approach also works very well for entering monetary values.