Click when mouse is in an area for some time - c#

I am trying to do something like Kinect adventures with Kinect SDK i.e. when the mouse stays in a certain area for a specific period of time, the native click event is to be fired.
The problem is that I do not get the expected results, since I get random clicking most times. I tried to check with breakpoints etc.
Most often, when my hand is not visible, the cursor goes to the corner of the screen and starts clicking. This is most probably because Math.Abs(lastX - cursorX) < threshold sets to true.
I have tried changing the threshold values to 200, but it fires a click st the start, and afterwards I am not get expected left clicks, when I hold the cursor in a certain position for some time. Any suggestions would be greatly appreciated. Here's the code:
//SkeletonFrameReadyevent
foreach (SkeletonData sd in e.SkeletonFrame.Skeletons)
{
if (sd.TrackingState == SkeletonTrackingState.Tracked)
{
// make sure both hands are tracked
if (sd.Joints[JointID.HandLeft].TrackingState == JointTrackingState.Tracked &&
sd.Joints[JointID.HandRight].TrackingState == JointTrackingState.Tracked)
{
int cursorX, cursorY;
// get the left and right hand Joints
Joint jointRight = sd.Joints[JointID.HandRight];
Joint jointLeft = sd.Joints[JointID.HandLeft];
// scale those Joints to the primary screen width and height
Joint scaledRight = jointRight.ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
Joint scaledLeft = jointLeft.ScaleTo((int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, SkeletonMaxX, SkeletonMaxY);
// figure out the cursor position based on left/right handedness
cursorX = (int)scaledRight.Position.X;
cursorY = (int)scaledRight.Position.Y;
//default false, for mouse move, set to true for mouse click
bool leftClick;
if (lastY == 0)
{
lastX = cursorX;
lastY = cursorY;
}
leftClick = false;
if (Math.Abs(lastX - cursorX) < threshold && Math.Abs(lastY - cursorY) < threshold)
{
if (Math.Abs(lastClick.Subtract(DateTime.Now).TotalSeconds) > 1)
{
//Mouse click here
leftClick = true;
}
}
//Mouse click when leftDown is true, else Mousemove
NativeMethods.SendMouseInput(cursorX, cursorY, (int)SystemParameters.PrimaryScreenWidth, (int)SystemParameters.PrimaryScreenHeight, leftClick);
return;
}
}
}
NativeMthods.cs class has this function:
public static void SendMouseInput(int positionX, int positionY, int maxX, int maxY, bool leftDown)
{
if(positionX > int.MaxValue)
throw new ArgumentOutOfRangeException("positionX");
if(positionY > int.MaxValue)
throw new ArgumentOutOfRangeException("positionY");
Input[] i = new Input[2];
// move the mouse to the position specified
i[0] = new Input();
i[0].Type = InputMouse;
i[0].MouseInput.X = (positionX * 65535) / maxX;
i[0].MouseInput.Y = (positionY * 65535) / maxY;
i[0].MouseInput.Flags = MouseEventAbsolute | MouseEventMove;
// determine if we need to send a mouse down or mouse up event
if(leftDown)
{
i[1] = new Input();
i[1].Type = InputMouse;
i[1].MouseInput.Flags = MouseEventLeftDown;
i[1].MouseInput.Flags |= MouseEventLeftUp;
}
// send it off
uint result = SendInput(2, i, Marshal.SizeOf(i[0]));
if(result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
}

Try something like this:
public class myMouseClass: IMessageFilter //Must implement IMessageFilter
{
[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);
//Constants
private const int MOUSEEVENTF_LEFTDOWN = 0x02;
private const int MOUSEEVENTF_LEFTUP = 0x04;
private const int MOUSEEVENTF_RIGHTDOWN = 0x08;
private const int MOUSEEVENTF_RIGHTUP = 0x10;
private const int WM_MOUSEMOVE = 0x0200;
private int Threshold = 20; //how far the mouse should move to reset timer
private int StartLocationX = 0; //stores starting X value
private int StartLocationY = 0; //stores starting Y value
private Timer timerHold = new Timer(); //timer to trigger mouse click
//Start Mouse monitoring by calling this. This will also set the timer.
private void StartFilterMouseEvents()
{
timerHold.Interval = 1000; //how long mouse must be in threshold.
timerHold.Tick = new EventHandler(timerHold_Tick);
Application.AddMessageFilter((IMessageFilter) this);
}
//Stop Mouse monitoring by calling this and unset the timer.
private void StopFilterMouseEvents()
{
timerHold.Stop();
timerHold -= timerHold_Tick;
Application.RemoveMessageFilter((IMessageFilter) this);
}
//This will start when Application.AddMessageFilter() is called
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE)
{
if((Cursor.Position.X > StartLocationX + 20)||(Cursor.Position.X > StartLocationX - 20))&&
((Cursor.Position.Y > StartLocationY + 20)||(Cursor.Position.Y > StartLocationY - 20))
{
timerHold.Stop(); //stops timer if running
timerHold.Start(); //starts it again with new position.
StartLocationX = Cursor.Position.X;
StartLocationY = Cursor.Position.Y;
}
}
return false;
}
//This event gets fired when the timer has not been reset for 1000ms
public void timerHold_Tick(object sender, EventArgs e)
{
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
}
}

Related

Why does my application just stop and does not keep running?

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.

How to cancel left mouse down without click on C#?

I'm try to wrote app, that will send right click, when user take long press left mouse button.
I found https://github.com/gmamaladze/globalmousekeyhook project and hook events with it.
When I hook left up, then send right click with mouse event, first fire left click, than right click fire.
Is any method to cancel first left mouse down?
using Gma.System.MouseKeyHook;
using System;
using System.Windows.Forms;
namespace MouseRClick
{
class ClassRightClick
{
// API
[System.Runtime.InteropServices.DllImport("user32.dll")]
public static extern void mouse_event(int dwFlags, int dx, int dy, int cButtons, int dwExtraInfo);
public const int MOUSEEVENTF_LEFTDOWN = 0x02;
public const int MOUSEEVENTF_LEFTUP = 0x04;
public const int MOUSEEVENTF_RIGHTDOWN = 0x08;
public const int MOUSEEVENTF_RIGHTUP = 0x10;
// Hook module
private IKeyboardMouseEvents _hook;
private bool _rclick_activated = false;
private int _down_cursor_x;
private int _down_cursor_y;
private Timer timer;
public ClassRightClick(int delay)
{
timer = new Timer();
timer.Interval = delay;
timer.Tick += timer_Tick;
}
public void Subscribe()
{
_hook = Hook.GlobalEvents();
_hook.MouseDownExt += onMouseDown;
_hook.MouseUpExt += onMouseUp;
}
public void Unsubscribe()
{
_hook.MouseDownExt -= onMouseDown;
_hook.MouseUpExt -= onMouseUp;
//It is recommened to dispose it
_hook.Dispose();
}
private void onMouseDown(object sender, MouseEventExtArgs e)
{
if (e.Button == MouseButtons.Left)
{
_down_cursor_x = e.Location.X;
_down_cursor_y = e.Location.Y;
_rclick_activated = false;
timer.Enabled = true;
}
}
private void onMouseUp(object sender, MouseEventExtArgs e)
{
if (e.Button == MouseButtons.Left)
{
timer.Enabled = false;
Unsubscribe();
if (_rclick_activated)
{
mouse_event(MOUSEEVENTF_RIGHTDOWN, _down_cursor_x, _down_cursor_y, 0, 0);
mouse_event(MOUSEEVENTF_RIGHTUP, _down_cursor_x, _down_cursor_y, 0, 0);
e.Handled = true;
}
_rclick_activated = false;
Subscribe();
}
}
private void timer_Tick(object sender, EventArgs e)
{
_rclick_activated = true;
}
}
}
Actually, you cannot do this. Problem is, left mouse click is already fired by the time you dispatch the right-mouse click. You can't just go back in time.
I'm try to wrote app, that will send right click, when user take long
press left mouse button.
You can start record the time when receive left mouse button down message by starting a timer. If the timer timeout a WM_TIMER message will be sent out and you can set the _rclick_activated to true to indicate the left button pressed long enough. When handle the left mouse button up message check the _rclick_activated, if it is true send right mouse button down event. After receive right mouse button down message send right mouse button up event.
The following code is Windows desktop API C++ implement as a simple example. You can use as a reference.
// Mouse hook
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0) // do not process the message
return CallNextHookEx(NULL, nCode,
wParam, lParam);
if (WM_LBUTTONDOWN == wParam)
{
OutputDebugString(L"\n Left button down \n");
_rclick_activated = false;
SetTimer(m_windowHandle, // handle to main window
IDT_TIMER1, // timer identifier
2000, // 2-second interval
(TIMERPROC)NULL); // no timer callback
}
else if (WM_LBUTTONUP == wParam)
{
OutputDebugString(L"\n Left button up \n");
if (_rclick_activated)
{
MOUSEINPUT mouseData = {};
mouseData.dx = GET_X_LPARAM(lParam);
mouseData.dy = GET_Y_LPARAM(lParam);
mouseData.dwFlags = MOUSEEVENTF_RIGHTDOWN;
INPUT inputData = {};
inputData.type = INPUT_MOUSE;
inputData.mi = mouseData;
UINT result = SendInput(1, &inputData, sizeof(INPUT));
if (result == 1)
{
OutputDebugString(L"\n successfully insert right button down \n");
}
}
}
else if (WM_RBUTTONDOWN == wParam)
{
OutputDebugString(L"\n Right button down \n");
if (_rclick_activated)
{
MOUSEINPUT mouseData = {};
mouseData.dx = GET_X_LPARAM(lParam);
mouseData.dy = GET_Y_LPARAM(lParam);
mouseData.dwFlags = MOUSEEVENTF_RIGHTUP;
INPUT inputData = {};
inputData.type = INPUT_MOUSE;
inputData.mi = mouseData;
UINT result = SendInput(1, &inputData, sizeof(INPUT));
if (result == 1)
{
OutputDebugString(L"\n successfully insert right button up \n");
}
_rclick_activated = false;
}
}
else if (WM_RBUTTONUP == wParam)
{
OutputDebugString(L"\n Right button up \n");
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
//...
// Rigister mouse hook
HHOOK m_msgHook = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL, GetCurrentThreadId());
//...
//...
case WM_TIMER:
// process the 2-second timer
_rclick_activated = true;
KillTimer(hWnd, IDT_TIMER1);
return 0;
//...

Richtextbox convert a line number to scroll bar position

I'm able now to synchronize my two RichTextBox using this potion of code:
private const int SB_HORZ = 0x0;
private const int SB_VERT = 0x1;
private const int WM_HSCROLL = 0x114;
private const int WM_VSCROLL = 0x115;
private const int SB_THUMBPOSITION = 4;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetScrollPos(int hWnd, int nBar);
[DllImport("user32.dll")]
private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
[DllImport("user32.dll")]
private static extern bool PostMessageA(IntPtr hWnd, int nBar, int wParam, int lParam);
internal int HScrollPos
{
private get { return GetScrollPos((int)this.Handle, SB_HORZ); }
set
{
SetScrollPos((IntPtr)this.Handle, SB_HORZ, value, true);
PostMessageA((IntPtr)this.Handle, WM_HSCROLL, SB_THUMBPOSITION + 0x10000 * value, 0);
}
}
internal int VScrollPos
{
get { return GetScrollPos((int)this.Handle, SB_VERT); }
set
{
SetScrollPos((IntPtr)this.Handle, SB_VERT, value, true);
PostMessageA((IntPtr)this.Handle, WM_VSCROLL, SB_THUMBPOSITION + 0x10000 * value, 0);
}
}
I can synchronize the RichTextBoxes while key down ,up and Vscroll event.
Indeed this is not my goal, I want to synchronize my RichTextBoxes basing on the content,
What do I need:
Get the current line form non-selected RichTextBox.
Set Scroll bar position using line number in the other RichTextBox (without losing the focus from the current one).
Get line number using scroll bar position.
Note: you are welcome to ask if you need any more details.
Thanks in advance.
From what I understand, you need to synchronize scrolling on 2 RichTextBoxes based on the line number. Leave me a comment if I misunderstood it.
RichTextBox extended :
public class RichTextBoxEx : RichTextBox
{
// combination of multiple events that may cause focus(caret) to change
public event EventHandler FocusChanged;
public RichTextBoxEx()
{
this.KeyPress += (s, e) => RaiseFocusChanged();
this.KeyDown += (s, e) => RaiseFocusChanged();
this.KeyUp += (s, e) => RaiseFocusChanged();
this.MouseClick += (s, e) => RaiseFocusChanged();
}
private void RaiseFocusChanged()
{
var focusChanged = FocusChanged;
if (focusChanged != null)
{
focusChanged(this, null);
}
}
public int GetFirstSelectedLine()
{
var index = GetFirstCharIndexOfCurrentLine();
return GetLineFromCharIndex(index);
}
public int GetFirstVisibleLine()
{
var index = GetCharIndexFromPosition(new Point(1, 1));
return GetLineFromCharIndex(index);
}
public void ScrollToLine(int line)
{
if (line < 0)
throw new ArgumentOutOfRangeException("line cannot be less than 0");
// save the current selection to be restored later
var selection = new { SelectionStart, SelectionLength };
// select that line and scroll it to
Select(GetFirstCharIndexFromLine(line) + 1, 0);
ScrollToCaret();
// restore selection
Select(selection.SelectionStart, selection.SelectionLength);
}
}
Usage :
void Main()
{
var mainScreenArea = Screen.PrimaryScreen.WorkingArea;
var rich1 = new RichTextBoxEx() { Width = mainScreenArea.Width / 2 - 10, Dock = DockStyle.Left };
var rich2 = new RichTextBoxEx() { Width = mainScreenArea.Width / 2 - 10, Dock = DockStyle.Right };
rich1.LoadFile(__RTF_FILE_0__);
rich2.LoadFile(__RTF_FILE_1__);
// pick one :
// synchronize by focus
rich1.FocusChanged += (s, e) => rich2.ScrollToLine(rich1.GetFirstSelectedLine());
// synchronize by viewbox
// rich1.VScroll += (s, e) => rich2.ScrollToLine(rich1.GetFirstVisibleLine());
var form = new Form();
form.Controls.Add(rich1);
form.Controls.Add(rich2);
form.WindowState = FormWindowState.Maximized;
form.ShowDialog()
}

Mouse wheel scrolling Toolstrip menu items

I have some menus that contain many menuitems. Mouse wheel doesn't scroll them. I have to use the keyboard arrows or click the arrows at top and bottom.
Is it possible to use the mouse wheel to scroll toolstrip menu items?
Thanks
You can enable it application wide with this class:
public class DropDownMenuScrollWheelHandler : System.Windows.Forms.IMessageFilter
{
private static DropDownMenuScrollWheelHandler Instance;
public static void Enable(bool enabled)
{
if (enabled)
{
if (Instance == null)
{
Instance = new DropDownMenuScrollWheelHandler();
Application.AddMessageFilter(Instance);
}
}
else
{
if (Instance != null)
{
Application.RemoveMessageFilter(Instance);
Instance = null;
}
}
}
private IntPtr activeHwnd;
private ToolStripDropDown activeMenu;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x200 && activeHwnd != m.HWnd) // WM_MOUSEMOVE
{
activeHwnd = m.HWnd;
this.activeMenu = Control.FromHandle(m.HWnd) as ToolStripDropDown;
}
else if (m.Msg == 0x20A && this.activeMenu != null) // WM_MOUSEWHEEL
{
int delta = (short)(ushort)(((uint)(ulong)m.WParam) >> 16);
handleDelta(this.activeMenu, delta);
return true;
}
return false;
}
private static readonly Action<ToolStrip, int> ScrollInternal
= (Action<ToolStrip, int>)Delegate.CreateDelegate(typeof(Action<ToolStrip, int>),
typeof(ToolStrip).GetMethod("ScrollInternal",
System.Reflection.BindingFlags.NonPublic
| System.Reflection.BindingFlags.Instance));
private void handleDelta(ToolStripDropDown ts, int delta)
{
if (ts.Items.Count == 0)
return;
var firstItem = ts.Items[0];
var lastItem = ts.Items[ts.Items.Count - 1];
if (lastItem.Bounds.Bottom < ts.Height && firstItem.Bounds.Top > 0)
return;
delta = delta / -4;
if (delta < 0 && firstItem.Bounds.Top - delta > 9)
{
delta = firstItem.Bounds.Top - 9;
}
else if (delta > 0 && delta > lastItem.Bounds.Bottom - ts.Height + 9)
{
delta = lastItem.Bounds.Bottom - owner.Height + 9;
}
if (delta != 0)
ScrollInternal(ts, delta);
}
}
A working solution:
Register for MouseWheel event of your form and DropDownClosed event of your root MenuStripItem (here, rootItem) in the Load event of the form
this.MouseWheel += Form3_MouseWheel;
rootItem.DropDownOpened += rootItem_DropDownOpened;
rootItem.DropDownClosed += rootItem_DropDownClosed;
Add the code for Keyboard class which simulate key presses
public static class Keyboard
{
[DllImport("user32.dll")]
static extern uint keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo);
const byte VK_UP = 0x26; // Arrow Up key
const byte VK_DOWN = 0x28; // Arrow Down key
const int KEYEVENTF_EXTENDEDKEY = 0x0001; //Key down flag, the key is going to be pressed
const int KEYEVENTF_KEYUP = 0x0002; //Key up flag, the key is going to be released
public static void KeyDown()
{
keybd_event(VK_DOWN, 0, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_DOWN, 0, KEYEVENTF_KEYUP, 0);
}
public static void KeyUp()
{
keybd_event(VK_UP, 0, KEYEVENTF_EXTENDEDKEY, 0);
keybd_event(VK_UP, 0, KEYEVENTF_KEYUP, 0);
}
}
Add the code for DropDownOpened, DropDownClosed, MouseWheel events:
bool IsMenuStripOpen = false;
void rootItem_DropDownOpened(object sender, EventArgs e)
{
IsMenuStripOpen = true;
}
void rootItem_DropDownClosed(object sender, EventArgs e)
{
IsMenuStripOpen = false;
}
void Form3_MouseWheel(object sender, MouseEventArgs e)
{
if (IsMenuStripOpen)
{
if (e.Delta > 0)
{
Keyboard.KeyUp();
}
else
{
Keyboard.KeyDown();
}
}
}
This is very simply using a submenu (ToolStripMenuItem) of the context menu :
Assuming using a form1 (or UserControl) and a contextMenuStrip1 :
private void form1_Load( object sender , EventArgs e )
{
//this.MouseWheel -= When_MouseWheel;
this.MouseWheel += When_MouseWheel;
}
void When_MouseWheel( object sender , MouseEventArgs e )
{
if ( this.contextMenuStrip1.IsDropDown ) {
//this.Focus();
if ( e.Delta > 0 ) SendKeys.SendWait( "{UP}" );
else SendKeys.SendWait( "{DOWN}" );
}
}
I modified Mohsen Afshin's answer to click the up/down arrows instead of sending up/down key presses. My application had a ContextMenuStrip called menu. Here's the code.
In the initialization:
menu.VisibleChanged += (s, e) =>
{
if (menu.Visible)
{
MouseWheel += ScrollMenu;
menu.MouseWheel += ScrollMenu;
}
else
{
MouseWheel -= ScrollMenu;
menu.MouseWheel -= ScrollMenu;
}
};
The ScrollMenu function:
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint cButtons, uint dwExtraInfo);
private void ScrollMenu(object sender, MouseEventArgs e)
{
Point origin = Cursor.Position;
int clicks;
if (e.Delta < 0)
{
Cursor.Position = menu.PointToScreen(new Point(menu.DisplayRectangle.Left + 5, menu.DisplayRectangle.Bottom + 5));
clicks = e.Delta / -40;
}
else
{
Cursor.Position = menu.PointToScreen(new Point(menu.DisplayRectangle.Left + 5, menu.DisplayRectangle.Top - 5));
clicks = e.Delta / 40;
}
for (int i = 0; i < clicks; i++)
mouse_event(0x0006, 0, 0, 0, 0);//Left mouse button up and down on cursor position
Cursor.Position = origin;
}
I was having trouble getting the mouse_event function to click a specific location, so I moved the cursor, clicked, and then moved the cursor back. It doesn't seem the cleanest, but it works.

How to get specific text value from a textbox based upon the mouse position

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();
}
}
}

Categories

Resources