I've got this code:
[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, UIntPtr dwExtraInfo);
[Flags]
public enum MouseEventFlags
{
Move = 0x0001,
LeftDown = 0x0002,
LeftUp = 0x0004,
RightDown = 0x0008,
RightUp = 0x0010,
MiddleDown = 0x0020,
MiddleUp = 0x0040,
Absolute = 0x8000
}
public void SimMouseEvent(MouseEventFlags e, int x, int y)
{
mouse_event((uint)e, (uint)x, (uint)y, 0, UIntPtr.Zero);
}
public void SimLeftClick(int x, int y)
{
SimMouseEvent(MouseEventFlags.LeftUp | MouseEventFlags.RightUp, x, y);
}
My form looks like this:
When you click "Button" it runs this:
private void button3_Click(object sender, RoutedEventArgs e)
{
SimLeftClick(50, 50);
}
And on my Window I also have this:
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("click");
}
When I click the window it says "click" as expected, but when I click "Button" it doesn't seem to do anything.
Are the coordinates absolute, or relative? What about with multiple monitors? Do they only work on the focused application?
I would expect that 50,50 to either hit my window somewhere and trip the "click" handler or click on some random window because it missed my app completely and focus that instead... why isn't anything happening?
You handle a mouse button down message, but send a mouse button up message. A click needs to be button down followed by the same button up.
The coordinates are ignored, because you didn't pass the Move flag.
Try reading the documentation.
Fixed, with Ben's suggestions.
public void SimLeftClick(int x, int y)
{
var scr = Screen.PrimaryScreen.Bounds;
SimMouseEvent(MouseEventFlags.LeftDown | MouseEventFlags.LeftUp | MouseEventFlags.Move | MouseEventFlags.Absolute,
(int)(x / (double)scr.Width * 65535),
(int)(y / (double)scr.Height * 65535));
}
Related
I am trying to make a program (C#) which do this:
If I click my left mouse button the mouse should move to the left by a DeltaX.
The problem is that when I run the program, it simple opens the console application and nothing happens. I am not sure what I am doing wrong here.
It should keep running and checking if I click the left mouse button or not, and when I click it, the cursor should move to the left by a DeltaX.
code
using System.Data;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace Teste
{
class Program
{
static void Main(string[] args)
{
var someClass = new Up();
someClass.Update();
}
}
public class Up
{
[DllImport("user32.dll")] static extern short GetAsyncKeyState(int vKey);
[DllImport("USER32.dll")] static extern short GetKeyState(int nVirtKey);
int msShootTime = 225;
System.DateTime lastClick = System.DateTime.Now;
bool isRunning = true;
public async void Update()
{
while (true)
{
if (isRunning)
{
await Task.Delay(10);
continue;
}
int res = GetKeyState((int)1);
if (res >= 0)
{
await Task.Delay(1);
continue;
}
Move(-10, 0, true);
}
}
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
[DllImport("user32.dll")]
static extern void mouse_event(int dwFlags, int dx, int dy, uint dwData, UIntPtr dwExtraInfo);
public void Move(int xDelta, int yDelta, bool pressDown = false)
{
if (pressDown)
{
if (System.DateTime.Now.Subtract(lastClick).TotalMilliseconds < msShootTime)
{
pressDown = false;
}
else
{
lastClick = System.DateTime.Now;
}
}
mouse_event(pressDown ? (MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP) : 0x0001, xDelta, yDelta, 0, UIntPtr.Zero);
}
}
}
Some mistakes were in code, I've added some comments directly to code
class Program
{
static async Task Main(string[] args) // made Main async
{
var someClass = new Up();
await someClass.Update(); // awaiting async method, you didn't wait it and app have to exit immediately
}
public class Up
{
[DllImport("user32.dll")]
private static extern short GetAsyncKeyState(int vKey);
[DllImport("user32.dll")]
private static extern short GetKeyState(int nVirtKey);
// just copied mouse_event and Flags from one of my projects but yours worked too
[DllImport("user32.dll")]
private static extern void mouse_event(MouseFlags dwFlags, int dx, int dy, uint dwData, UIntPtr dwExtraInfo);
[Flags]
private enum MouseFlags : uint
{
MOUSEEVENTF_ABSOLUTE = 0x8000, // If set, dx and dy contain normalized absolute coordinates between 0 and 65535. The event procedure maps these coordinates onto the display surface. Coordinate (0,0) maps onto the upper-left corner of the display surface, (65535,65535) maps onto the lower-right corner.
MOUSEEVENTF_LEFTDOWN = 0x0002, // The left button is down.
MOUSEEVENTF_LEFTUP = 0x0004, // The left button is up.
MOUSEEVENTF_MIDDLEDOWN = 0x0020, // The middle button is down.
MOUSEEVENTF_MIDDLEUP = 0x0040, // The middle button is up.
MOUSEEVENTF_MOVE = 0x0001, // Movement occurred.
MOUSEEVENTF_RIGHTDOWN = 0x0008, // The right button is down.
MOUSEEVENTF_RIGHTUP = 0x0010, // The right button is up.
MOUSEEVENTF_WHEEL = 0x0800, // The wheel has been moved, if the mouse has a wheel.The amount of movement is specified in dwData
MOUSEEVENTF_XDOWN = 0x0080, // An X button was pressed.
MOUSEEVENTF_XUP = 0x0100, // An X button was released.
MOUSEEVENTF_HWHEEL = 0x01000 // The wheel button is tilted.
}
int msShootTime = 225;
DateTime lastClick = DateTime.Now;
bool isRunning = false; // it was initially true
public async Task Update() // async Task
{
while (true)
{
if (isRunning) // it was always true
{
await Task.Delay(10);
continue; // this was always executed
}
isRunning = true; // added this
int res = GetKeyState((int)1);
if (res >= 0)
{
await Task.Delay(1);
isRunning = false; // added this
continue;
}
Move(-10, 0, true);
isRunning = false; // added this
}
}
public void Move(int xDelta, int yDelta, bool pressDown = false)
{
if (pressDown)
{
if (System.DateTime.Now.Subtract(lastClick).TotalMilliseconds < msShootTime)
{
pressDown = false;
}
else
{
lastClick = System.DateTime.Now;
}
}
// updated for new Flags enum
// I'm not sure if sending both MOUSEEVENTF_LEFTDOWN and MOUSEEVENTF_LEFTUP will give any effect
// try to send it sequentially with some delay: DOWN, then UP
mouse_event(pressDown ? (MouseFlags.MOUSEEVENTF_LEFTDOWN | MouseFlags.MOUSEEVENTF_LEFTUP) : MouseFlags.MOUSEEVENTF_MOVE, xDelta, yDelta, 0, UIntPtr.Zero);
}
}
}
Note: Microsoft recommends using SendInput instead of mouse_event.
This function has been superseded. Use SendInput instead.
I have searched the internet far and wide and seen many questions like this, but I have not seen an actual answer.
I have a rich text box control with lots of text in it. It has some legal information in this control. By default the "Accept" button is disabled. I want to detect on the scroll event if the position of the v-scroll bar is at the bottom. If it is at the bottom, enable the button.
How would I detect the current v-scroll bar position?
Thank You!
EDIT
I am using WinForms (.Net 4.0)
This should get you close to what you are looking for. This class inherits from the RichTextBox and uses some pinvoking to determine the scroll position. It adds an event ScrolledToBottom which gets fired if the user scrolls using the scrollbar or uses the keyboard.
public class RTFScrolledBottom : RichTextBox {
public event EventHandler ScrolledToBottom;
private const int WM_VSCROLL = 0x115;
private const int WM_MOUSEWHEEL = 0x20A;
private const int WM_USER = 0x400;
private const int SB_VERT = 1;
private const int EM_SETSCROLLPOS = WM_USER + 222;
private const int EM_GETSCROLLPOS = WM_USER + 221;
[DllImport("user32.dll")]
private static extern bool GetScrollRange(IntPtr hWnd, int nBar, out int lpMinPos, out int lpMaxPos);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
public bool IsAtMaxScroll() {
int minScroll;
int maxScroll;
GetScrollRange(this.Handle, SB_VERT, out minScroll, out maxScroll);
Point rtfPoint = Point.Empty;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref rtfPoint);
return (rtfPoint.Y + this.ClientSize.Height >= maxScroll);
}
protected virtual void OnScrolledToBottom(EventArgs e) {
if (ScrolledToBottom != null)
ScrolledToBottom(this, e);
}
protected override void OnKeyUp(KeyEventArgs e) {
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
base.OnKeyUp(e);
}
protected override void WndProc(ref Message m) {
if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL) {
if (IsAtMaxScroll())
OnScrolledToBottom(EventArgs.Empty);
}
base.WndProc(ref m);
}
}
This is then how it can get used:
public Form1() {
InitializeComponent();
rtfScrolledBottom1.ScrolledToBottom += rtfScrolledBottom1_ScrolledToBottom;
}
private void rtfScrolledBottom1_ScrolledToBottom(object sender, EventArgs e) {
acceptButton.Enabled = true;
}
Tweak as necessary.
The following works very well in one of my solutions:
Point P = new Point(rtbDocument.Width, rtbDocument.Height);
int CharIndex = rtbDocument.GetCharIndexFromPosition(P);
if (rtbDocument.TextLength - 1 == CharIndex)
{
btnAccept.Enabled = true;
}
The question How to get scroll position for RichTextBox? could be helpful, Check out this function
richTextBox1.GetPositionFromCharIndex(0);
am trying to simulate mouse right click in my WinForm app as follow :
public const int WM_RBUTTONDOWN = 0x204;
public const int WM_RBUTTONUP = 0x205;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
public static IntPtr MakeLParam(int LoWord, int HiWord)
{
return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
}
public static void Click(int x, int y)
{
SendMessage(this.Handle, WM_RBUTTONDOWN, IntPtr.Zero, MakeLParam(x,y));
SendMessage(this.Handle, WM_RBUTTONUP, IntPtr.Zero, MakeLParam(x,y));
}
(x,y) the coords inside the app window form, but nothing happens what am missing here?
EDIT: I have also tried FindWindow(null,"Form1"); and it gives same Handle as this.Handle..
Why you dont use the Events built-in in Windows Forms??
Use de MouseDown Event of any control, example the Form:
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
}
}
The MouseDown Event take the control in a any mouse button pressed.
I have a multi-line text box that displays some values based on data it gets given, (Generally one value per line).
(For the purpose of having a tool tip popup with some 'alternative' data) I would like to get the word (or at the very least the line) that the mouse is hovering over so I can then find what alternative to display.
I have a few ideas of how to do this with calculations based on the text box and font sizes but I do not what to go down this road as the sizes and fonts may change frequently.
So... Is there any way of using the mouses position to grab specific text box text?
Here's an alternate solution. Add this MouseMove event to your TextBox:
private void txtHoverWord_MouseMove(object sender, MouseEventArgs e)
{
if (!(sender is TextBox)) return;
var targetTextBox = sender as TextBox;
if(targetTextBox.TextLength < 1) return;
var currentTextIndex = targetTextBox.GetCharIndexFromPosition(e.Location);
var wordRegex = new Regex(#"(\w+)");
var words = wordRegex.Matches(targetTextBox.Text);
if(words.Count < 1) return;
var currentWord = string.Empty;
for (var i = words.Count - 1; i >= 0; i--)
{
if (words[i].Index <= currentTextIndex)
{
currentWord = words[i].Value;
break;
}
}
if(currentWord == string.Empty) return;
toolTip.SetToolTip(targetTextBox, currentWord);
}
Use the GetCharIndexFromPosition method to map the mouse's position to an index in the whole Text. From that position, progress left and right till you have the whole word.
To get the mouse position, use the MouseHover event, so that you get it just when it's still and not every time (that would make things slow).
My solution uses a trick to achieve what you want.
When you double click inside a text area, it select the underlying word.
So using a RichTextBox (TextBox does flash on mouse events) on your form you can simulate double click when the middle mouse button is clicked (something like Babylon dictionary). If you want you can use MouseHover instead of MouseDown, too. It works.
public partial class Form3 : Form
{
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
public Form3()
{
InitializeComponent();
timer.Interval = 50;
timer.Tick += timer_Tick;
}
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
MessageBox.Show(richTextBox1.SelectedText);
// do more stuff here, e.g display your tooltip for the selected word or anything else
richTextBox1.SelectionLength = 0; // remove the highlighted color of selection
}
[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 uint MOUSEEVENTF_LEFTDOWN = 0x02;
private const uint MOUSEEVENTF_LEFTUP = 0x04;
private const uint MOUSEEVENTF_RIGHTDOWN = 0x08;
private const uint MOUSEEVENTF_RIGHTUP = 0x10;
public void DoMouseDoubleClick()
{
//Call the imported function with the cursor's current position
uint X = (uint)Cursor.Position.X;
uint Y = (uint)Cursor.Position.Y;
mouse_event(MOUSEEVENTF_LEFTDOWN, X, Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTDOWN, X, Y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, X, Y, 0, 0);
timer.Start(); // some delay is required so that mouse event reach to RichTextBox and the word get selected
}
private void richTextBox1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
DoMouseDoubleClick();
}
}
}
Hi i have a c# application and an embedded browser in it,its task is to find a link and then right click on it and click on properties!
mouse moves programmatically,so i need to find properties in righ click menu!
can you help me how to do this?
i tried pressing 'r' after right click but it didn't work on some computers!
so i need to do it by moving mouse!
here is my code for finding a link and right clicking:
int x = getXoffset(link);
int y = getYoffset(link);
webBrowser1.Document.Window.ScrollTo(x, y);
Linker.Win32.POINT p2 = new Linker.Win32.POINT();
webBrowser1.Focus();
p2.x = webBrowser1.Left + 10;
p2.y = webBrowser1.Top + 5;
Linker.Win32.ClientToScreen(this.Handle, ref p2);
Linker.Win32.SetCursorPos(p2.x, p2.y);
MouseOperations.GetCursorPosition();
MouseOperations.MouseEvent(MouseOperations.MouseEventFlags.LeftDown);
MouseOperations.MouseEvent(MouseOperations.MouseEventFlags.RightDown);
MouseOperations.MouseEvent(MouseOperations.MouseEventFlags.RightUp);
Any other idea for reaching properties on right click meny is welcomed
use this code:
[DllImport("user32.dll", SetLastError = true)]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
public static void PressKey(Keys key, bool up)
{
const int KEYEVENTF_EXTENDEDKEY = 0x1;
const int KEYEVENTF_KEYUP = 0x2;
if (up)
{
keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
}
else
{
keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
}
}
private void Form1_Load(object sender, EventArgs e)
{
webBrowser1.Navigate("http://google.com");//Your link
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//Find your link and right click(automatically by your code)
webBrowser1.Document.MouseDown += new HtmlElementEventHandler(Document_MouseDown);
}
void Document_MouseDown(object sender, HtmlElementEventArgs e)
{
if (e.MouseButtonsPressed == MouseButtons.Right)
{
Thread.Sleep(1000);
PressKey(Keys.P, true);
PressKey(Keys.P, false);
}
}