I'm currently writing a program that holds down a mouse button when initially clicked, and continues to hold it until the user presses the mouse button for a second time.
The program works by detecting input globally using a MouseHookListener and then uses an input simulator to hold down the mouse button that has been pressed.
The program is able to hold down the mouse as intended, but there is an issue with the original mouse click that signals the program to simulate the button being held; it still gets carried out. I know that the MouseHookListener uses low level hooks to operate, but it's HookCallBack() method can't be overridden due to it being protected.
Is there any way to block out the original mouse input? Or is there a way to make the original input held in until the mouse is clicked once more?
This is the code I've produced, thus far (note - the mListener is being activated in a forum else where):
public MouseHold()
{
mListener = new MouseHookListener(new GlobalHooker());
mListener.MouseClick += mListener_MouseClick;
}
private bool isDown;
private int count = 0;
private InputSimulator sim = new InputSimulator();
public MouseHookListener mListener;
private void mListener_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (isDown)
{
isDown = false;
Console.Out.WriteLine(count);
}
else
{
Console.Out.WriteLine(count);
isDown = true;
sim.Mouse.LeftButtonDown();
}
}
}
I am the author of the library you mentioned https://github.com/gmamaladze/globalmousekeyhook.
To enable your usecase I have extended the library by one more event. Please note that the construction of listener has also slightly changed in the new version.
I beleave that with the example below you are able to accomplish your scenario without involving InputSimulator library.
How it works?
First mouse down set the flag m_SupressNextUp - down is fired.
Mouse button up which follows previous down is supressed and set the flag m_SupressNextDown
Second down is supressed too and reset the flag m_SupressNextUp
Second up is fired and reset m_SupressNextDown
System is returned to initial state.
internal class Sample
{
private IKeyboardMouseEvents m_GlobalHook;
private bool m_SupressNextUp;
private bool m_SupressNextDown;
public void Subscribe()
{
m_GlobalHook = Hook.GlobalEvents();
m_GlobalHook.MouseDownExt += GlobalHookMouseDownExt;
m_GlobalHook.MouseUpExt += GlobalHook_MouseUpExt;
}
void GlobalHook_MouseUpExt(object sender, MouseEventExtArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (m_SupressNextUp)
{
Console.WriteLine(#"First mouse up supress.");
e.Handled = true;
m_SupressNextDown = true;
}
else
{
Console.WriteLine(#"Second mouse up - make it heppen.");
m_SupressNextDown = false;
}
}
}
private void GlobalHookMouseDownExt(object sender, MouseEventExtArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (m_SupressNextDown)
{
Console.WriteLine(#"Second mouse down supress.");
e.Handled = true;
m_SupressNextUp = false;
}
else
{
Console.WriteLine(#"First mouse down - make it heppen.");
m_SupressNextUp = true;
}
}
}
public void Unsubscribe()
{
m_GlobalHook.MouseDownExt -= GlobalHookMouseDownExt;
m_GlobalHook.MouseUpExt -= GlobalHook_MouseUpExt;
m_GlobalHook.Dispose();
}
}
after reviewing the documentation for the input simulator I am guessing you need to reverse the mouse down input.
the source code for the input simulator has a mouse up method
private void mListener_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
if (isDown)
{
isDown = false;
Console.Out.WriteLine(count);
sim.Mouse.LeftButtonUp(); //maybe try this
}
else
{
Console.Out.WriteLine(count);
isDown = true;
sim.Mouse.LeftButtonDown();
}
}
}
Related
I have a borderless, transparent Window with only one Button.
My fancy button looks like this
The expected behaviour is:
When I click and drag the Button, the Button must follow the cursor.
When I only click on the Button, the MouseDown, PreviewMouseDown events or Command binding should raise.
At first I tried to call the DragMove() on PreviewMouseDown event, but that blocks the click events. Now my idea is: I set a 100ms delay after mouse down. If the time passed, than the button wil be dragging, otherwise it was just a click.
Code
private bool _dragging;
private Point startpos;
CancellationTokenSource cancellation;
private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (_dragging && e.LeftButton == MouseButtonState.Pressed)
{
var currentpos = e.GetPosition(this);
Left += currentpos.X - startpos.X;
Top += currentpos.Y - startpos.Y;
}
}
private async void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton != MouseButton.Left)
return;
_dragging = false;
startpos = e.GetPosition(this);
cancellation?.Cancel();
cancellation = new CancellationTokenSource();
await Task.Delay(100, cancellation.Token).ContinueWith(task =>
{
_dragging = !task.IsCanceled;
});
}
private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (_dragging)
{
_dragging = false;
e.Handled = true;
}
cancellation?.Cancel();
}
Basically it works, but has some bugs:
When I hold down the mouse button for longer time and release, then the click won't work, because after 100ms the dragging will be active.
After I dragged the button, and click anywhere outside the Button and Window control, the PreviewMouseDown and PreviewMouseUp events are raised. I don't know why??
Does somebody have any better solution?
For your first problem:
You must handle the case when your button is pushed down but not moved. I think a better way to do this (instead of the 100ms delay) would be to specify a minimum threshold of movement above which the dragging will start.
You could do it like this:
private const double _dragThreshold = 1.0;
private bool _dragging;
private Point startpos;
CancellationTokenSource cancellation;
private void Button_PreviewMouseMove(object sender, MouseEventArgs e)
{
var currentpos = e.GetPosition(this);
var delta = currentpos - startpos;
if ((delta.Length > _dragThreshold || _dragging) && e.LeftButton == MouseButtonState.Pressed)
{
_dragging = true;
Left += currentpos.X - startpos.X;
Top += currentpos.Y - startpos.Y;
}
}
private async void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton != MouseButton.Left)
return;
_dragging = false;
startpos = e.GetPosition(this);
cancellation?.Cancel();
cancellation = new CancellationTokenSource();
}
For your second problem: the button will capture the mouse on the mouse down event.
You need to release the captured mouse with the ReleaseMouseCapture method when you are done with your drag.
private void Button_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
if (_dragging)
{
_dragging = false;
e.Handled = true;
var button = sender as Button;
button.ReleaseMouseCapture();
}
cancellation?.Cancel();
}
I have a program where I want to move a Graphic with the keyboard keys. I originally had a function to move the graphic whenever pressed a button, but I abandoned that method to get around the keyboard repeat delay. Instead, I decided I would use a timer, which I would enable upon the KeyPess event, and disable on the KeyUp event. At first, I used 4 different timers for each different direction, and although it worked I noticed my program had begun to freeze quite often. I decided to use a single timer for all movements, and use if statements to determine the direction. Now, it seems that my Graphic doesn't move at all, even though all I did was copy and paste code.
enum Direction
{
Left, Right, Up, Down
}
private Direction _objectDirection;
int _x = 100, _y = 100;
private void Form1_Paint(object sender, PaintEventArgs e)
{
Picture.MakeTransparent(Color.Transparent);
e.Graphics.DrawImage(Picture, _x, _y);
}
void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.W)
{
if (timerAnimation.Enabled == false)
{
AnimationMaxFrame = 3;
timerAnimation.Enabled = true;
}
_objectDirection = Direction.Up;
timerMovement.Enabled = true;
}
//The rest of this code is omitted to save space, it is repeated 4 times with the only
//changes being the key pressed, and the object direction.
Invalidate();
}
void Form1_KeyUp(object sender, KeyEventArgs e)
{
timerAnimation.Enabled = false;
timerMovement.Enabled = false;
Picture = Idle;
this.Refresh();
}
private void timerMovement_Tick(object sender, EventArgs e)
{
if (_objectDirection == Direction.Up)
{
if (_y > 24)
{ _y = _y - 2; }
else
{ timerMovement.Enabled = false; }
//This if statement is to ensure that the object doesn't leave the form.
//I have tried removing them already, they're not the problem.
}
//Again, this is shortened to save space, it is repeated for each direction.
Invalidate();
}
What is preventing my graphic from moving, and is there a better way to do this? There is still a lot of functionality I want to add to this, but it's already freezing.
Not sure you are making a game with WinForms, but to the point...
You need to handle key pressed events, when a key pressed event fires set a boolean flag in your code depending on if the event was a press or release. Then in your update code check the flag and do your movement accordingly.
It would be something like this (example code):
bool moveup = false;
void KeyPressed(object sender, KeyEventArgs e)
{
// check for keys that trigger starting of movement
if (e.KeyCode == Keys.W) moveup = true;
}
void KeyReleased(object sender, EventEventArgs e)
{
// check for keys that trigger stopping of movement
if (e.KeyCode == Keys.W) moveup = false;
}
void TimerTick(obect sender, EventArgs e)
{
if (moveup)
{
// move your object
}
}
I like to write a small Application to paste/insert some text at my current cursor position.
For Example: I am in Word: Here I like to press CTRL+ALT+1 and it will insert some text at my pointer position. Or I have an open Internet-Explorer window, Notepad, Adobe, ..., or any other application
I started with listening the shortcuts with a global Keyboard hook library.
And the event for the hotkeys is working fine for me. But now I got stuck because I found no way to paste/insert the text at the position from my cursor. I tried using SendMessage/PostMessage, or SendKeys.
The problem with SendMessage is that I was not able to get every window and SendKeys is fired multiple times if you are using it togheter with the Keyboard hook library...
Any ideas how I could continue?
Code for the Hotkeys:
namespace Developper_Dashboard
{
public partial class Form1 : Form
{
globalKeyboardHook gkh = new globalKeyboardHook();
private bool IsADown = false;
private bool IsBDown = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// Hide the MainForm
this.Opacity = 0;
// Listening Keys
gkh.HookedKeys.Add(Keys.LControlKey);
gkh.HookedKeys.Add(Keys.LMenu);
gkh.HookedKeys.Add(Keys.NumPad1);
gkh.KeyDown += new KeyEventHandler(gkh_KeyDown);
gkh.KeyUp += new KeyEventHandler(gkh_KeyUp);
}
void gkh_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LControlKey)
{
IsADown = false;
}
if (e.KeyCode == Keys.LMenu)
{
IsBDown = false;
}
if (!IsADown | !IsBDown)
{
this.Opacity = 0;
}
//e.Handled = true;
}
void gkh_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LControlKey)
{
IsADown = true;
}
if (e.KeyCode == Keys.LMenu)
{
IsBDown = true;
}
if (IsADown && IsBDown)
{
this.Opacity = 1;
}
if (IsADown && IsBDown && e.KeyCode == Keys.NumPad1)
{
// Here the code for paste/insert...?
}
}
}
}
I want to be able to use the space key to modify the behavior of the mouse while it is held down. Without knowing better I am imagining it involves some kind of coordination between two (or three) event handler - mousemove, keydown, and keyup. But I am wondering if there is some way to handle it entirely within one event handler - mousemove.
Example code to give an idea of what I hope to be able to do...
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (Keyboard.KeyDown == Keys.Space)
{
/* Do modified behavour for left mouse being held down while
space is also held down */
}
else
{
// Do normal behavour for left mouse being held down
}
}
}
Is something like this possible or will I have to save the state of the space key to a class variable using keydown event handler and check it with the mouse move handler?
IT could be done using Control.ModifierKeys & Control.MouseButtons. But only works for kays like shift, ctrl and alt.
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if ((Control.ModifierKeys & Keys.Shift) != 0)
{
if ((Control.MouseButtons & MouseButtons.Left) != 0)
{ // here you go
}
}
}
You should set a variable in your KeyDown-Event and check it in your MouseEvent:
bool buttonpressed = false;
private void KeyDown_Event(object s, System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyCode == KeyCode.Space)
buttonpressed = true;
else
buttonpressed = false;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (buttonPressed)
{
/* Do modified behavour for left mouse being held down while
space is also held down */
}
else
{
// Do normal behavour for left mouse being held down
}
}
}
I'd have a variable that tracks when Keys.Space is in the Pressed state, then trigger it with KeyUp and KeyDown events
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
// Check if Key.Space pressed
if(SpacePressed) {
// Do something
}
}
private void KeyPressed_Event(object sender, KeyEventArgs e) {
// Check if Key.Space pressed
if(e.Key == Key.Space) {
SpacePressed = true;
}
}
private void KeyRelease_Event(object sender, KeyEventArgs e) {
// Check if Key.Space pressed
if(e.Key == Key.Space) {
SpacePressed = false;
}
}
You could use PInvoke to call GetKeyState in User32.dll.
Looking for some help on a problem Im having
sorry if this question has already been asked, I can not find anything similar.
The idea is when a picturebox is clicked changed the image to ON.
If the picture box is held for more than 2 seconds to open a new form and leave the picturebox as OFF.
However if the picturebox is clicked ON and then held for 2 seconds and then returns i need the picturebox state to remain ON.
Here is what I have tried so far.
I believe for this to work correctly I need to stop MouseUp event from occuring.
Is there a way I can stop MouseUp when Tick occurs?
Is there a easier / better way to do this?
Any help would be appreciated.
private void time_HoldDownInternal_Tick(object sender, EventArgs e)
{
time_HoldDownInternal.Enabled = false;
time_HoldDownInternal.Interval = 1000;
form1show.Visible = true;
}
private void pb_pictureBoxTest_MouseDown(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = true;
time_HoldDownInternal.Enabled = true;
}
private void pb_pictureBoxTest_MouseUp(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = false;
//MessageBox.Show("mouse up");
time_HoldDownInternal.Enabled = false;
time_HoldDownInternal.Interval = 1000;
}
private void pb_pictureBoxTest_Click(object sender, EventArgs e)
{
if (mainMenuVariables.mousedown == true)
{
if (mainMenuVariables.pictureBox == false)
{
mainMenuVariables.pictureBox = true;
pb_pictureBoxTest.Image = new Bitmap(mainMenuVariables.pictureBoxOn);
return;
}
if (mainMenuVariables.pictureBox == true)
{
mainMenuVariables.pictureBox = false;
pb_pictureBoxTest.Image = new Bitmap(mainMenuVariables.pictureBoxOff);
return;
}
}
if (mainMenuVariables.mousedown == false)
{
//nothing
}
}
Rather than starting a timer, just record the current time on mouse down. Then in mouse up, check if it has been 2 seconds. e.g:
private void pb_pictureBoxTest_MouseDown(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = true;
mainMenuVariables.mousedowntime = DateTime.Now;
}
private void pb_pictureBoxTest_MouseUp(object sender, MouseEventArgs e)
{
mainMenuVariables.mousedown = false;
var clickDuration = DateTime.Now - mainMenuVariables.mousedowntime;
if ( clickDuration > TimeSpan.FromSeconds(2))
{
// Do 'hold' logic (e.g. open dialog, etc)
}
else
{
// Do normal click logic (e.g. toggle 'On'/'Off' image)
}
}