2

As I mentioned in this question, I am trying to implement a feature in my app whereby placing a cursor over some point for a while (say 3-5 seconds) triggers a double-click event. Based on the answers provided in that thread, I wrote the following. This code is not working as expected. Can someone please help?

    #region Timer Mouse Double Click event

    timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);

    //Here, the timer for Timer click event will start when mouse hovers over an area
    private void form_MouseHover(object sender, System.EventArgs e)
    {
        timer.Start();
    }

    private void form_MouseLeave(object sender, System.EventArgs e)
    {
        timer.Stop();
    }

    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        timer.Stop();
        DoubleClickEvent();
    }

    //This method allows the user to click a file/folder by hovering/keeping still the mouse for specified time
    void DoubleClickEvent()
    {

        DoClickMouse(0x2);      // Left mouse button down
        DoClickMouse(0x4);      // Left mouse button up
    }

    static void DoClickMouse(int mouseButton)
    {
        var input = new INPUT()
        {
            dwType = 0, // Mouse input
            mi = new MOUSEINPUT() { dwFlags = mouseButton }
        };

        if (SendInput(1, input, Marshal.SizeOf(input)) == 0)
        {
            throw new Exception();
        }
    }
    [StructLayout(LayoutKind.Sequential)]
    struct MOUSEINPUT
    {
        int dx;
        int dy;
        int mouseData;
        public int dwFlags;
        int time;
        IntPtr dwExtraInfo;
    }
    struct INPUT
    {
        public uint dwType;
        public MOUSEINPUT mi;
    }
    [DllImport("user32.dll", SetLastError = true)]
    static extern uint SendInput(uint cInputs, INPUT input, int size);

    #endregion
Community
  • 1
  • 1
ykombinator
  • 2,724
  • 7
  • 25
  • 46

4 Answers4

2

At first glance if your expecting a double click your are only doing a single click.

Down then up is one mouse click, shouldn't you do.

void DoubleClickEvent()
{
    DoClickMouse(0x2);      // Left mouse button down
    DoClickMouse(0x4);      // Left mouse button up        
    DoClickMouse(0x2);      // Left mouse button down
    DoClickMouse(0x4);      // Left mouse button up
}
Matt
  • 1,436
  • 12
  • 24
1

I hope it's not bad etiquette to provide two answers, however this is very different from my previous answer I felt editing for improvements wasn't correct.

By the looks of it you only have an event handler on the form, once you hover over a control on your form that will trigger your MouseLeave event of the form.

What you need is to add an event handler to every control on your form, something like this should do it.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {

        this.MouseHover += new EventHandler(MouseHoverEvent);
        this.MouseLeave +=new EventHandler(MouseLeaveEvent);
        timer1.Tick += new EventHandler(timer1_Tick);

        foreach (Control item in this.Controls)
        {
            item.MouseHover += new EventHandler(MouseHoverEvent);
            item.MouseLeave += new EventHandler(MouseLeaveEvent);
        }

    }

    void timer1_Tick(object sender, EventArgs e)
    {
        timer1.Stop();
        DoubleClickEvent();
    }

    void MouseLeaveEvent(object sender, EventArgs e)
    {
        timer1.Stop();
    }

    void MouseHoverEvent(object sender, EventArgs e)
    {
        timer1.Start();
    }
}
Matt
  • 1,436
  • 12
  • 24
0

Basic Idea: I use MouseAdapter so that I don't have to override everything under the sun.

my MouseAdapter object has a MouseTimer which extends a swing Timer, and an ActionListener with an overridden anonymous actionPerformed method.

I may have over thought/ or under thought when to start and stop the timer object. Basically all it does is print out when it is single clicked or when it is double clicked.

package mouseUtils;

import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.Timer;

/**
 *
 * @author jcpartri
 */
public class MyMouseAdapter extends MouseAdapter{
     private Integer mouseDoubleClickInterval = (int)     
     Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
     private MouseEvent event = null;
     private ActionListener taskPerformer = new ActionListener(){
      @Override
      public void actionPerformed(ActionEvent e){
           if(event.getClickCount() == 2){
                //mouseDoubleClicked(event);
                mouseTimer.stop();
           }
           if(event.getClickCount() == 1){
                //mouseSingleClicked(event);
                mouseTimer.stop();

           }
     }
 };

Class MouseTimer is a child of class Timer. When the Timer fires after a delay, there is a check to see if there was a single or double click within that timespan.

private MouseTimer mouseTimer = new  

MouseTimer(getMouseDoubleClickInterval(),taskPerformer);

 //The DebugClock helps me to see how long a process that I have programmed takes from 
start to finish.
     private DebugClock clock = new DebugClock();

 //Constructors
 public MyMouseAdapter(){
      super();
 }


@Override
public void mouseClicked(MouseEvent e){ 
     event = e;
     if(e.getClickCount() == 1){
          mouseTimer.setInitialDelay(mouseDoubleClickInterval);
          mouseTimer.start();
     }
     mouseTimer.setNumOfClicks();
}

public void mouseSingleClicked(MouseEvent e){
     p("Mouse was SingleClicked!!!\n");
}
public void mouseDoubleClicked(MouseEvent e){
     p("Mouse was DoubleClicked!!!\n");
}
@Override
public void mouseMoved(MouseEvent e){
     event = e;
     mouseTimer.resetNumOfClicks();
     mouseTimer.stop();
}

//Setters and Getters for MouseAdapter
public Integer getMouseDoubleClickInterval(){
      return this.mouseDoubleClickInterval;
}



    //Timer Classes
    private class MouseTimer extends Timer{

     //Constructors
     public MouseTimer(int delay, ActionListener taskPerformer){
          super(delay,taskPerformer);
     }

     //Instance variables
     private int numOfClicks = 0;


      //Setters and Getters
      public int getNumOfClicks(){
           return this.numOfClicks;
      }
      public void setNumOfClicks(){
           this.numOfClicks++;
      }
      public void resetNumOfClicks(){
           this.numOfClicks = 0;
      }
    }
    //Basic Printing Classes
    private void p(String message){
     System.out.print(message);
    }
}

class DebugClock{
     private long startTime = 0;
     private long endTime = 0;

     //Setters and Getters
     public long getStartTime(){
          return this.startTime;
     }
     public void setStartTime(long start){
          this.startTime = start;
     }
     public long getEndTime(){
          return this.endTime;
     }
     public void setEndTime(long end){
          this.endTime = end;
     }

     //Constructors
     public DebugClock(){

     }

     //Methods
     public float getTimeInMilliSeconds(){
          float seconds = (this.endTime - this.startTime);
          return seconds;
     }
}
Prashant Kumar
  • 20,069
  • 14
  • 47
  • 63
john p
  • 132
  • 1
  • 4
0

It might be better to write this code as a single call to SendInput passing all the mouse downs and ups in one array. If you do this, SendInput guarantees that no other keys get in between the sequence. For example if a user has Alt + N keys held in theory it could sneak in - and change the auto-clicker clicking Yes to instead trigger a No (with a Alt + N keys held).

That being said however, I think the answer to our question is here: SendInput doesn't perform click mouse button unless I move cursor

Community
  • 1
  • 1
Jeremy Thompson
  • 61,933
  • 36
  • 195
  • 321