Avatar of AlHal2
AlHal2
Flag for United Kingdom of Great Britain and Northern Ireland asked on

Click, Double Click and Triple Click

How does C# distinguish between two single click events and a double click event?
Suppose I have a key and I want it to display "1" in the textbox if pressed once; "2" in the textbox if pressed twice and "3" if pressed three times.
If the gap between key presses is more than a second reset counter to zero.
C#

Avatar of undefined
Last Comment
AlHal2

8/22/2022 - Mon
SOLUTION
it_saige

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
Russ Suter

It's determined by the operating system. There's an option in the Mouse Properties control panel that lets you adjust the double click speed.
Mouse Control PanelThe OS will always send a click event message on a single click. If another click is registered before the interval has elapsed (and that click is within a given distance from the first click) it will send an double click message as well. If the second click is registered after the time has elapsed then you just get another single click event.

As it_saige suggested above, you can hook into the windows messaging system and create your own handler to simulate a double-click event using timing other than what the operating system uses.
AndyAinscow

In addition it is considered really bad practice to modify system settings without asking the user first - so adjusting the double click interval in the operating system by your app should not be an option.

The op system does not recognise a triple click, that is something you have to do yourself.

A simple alternative to that above is for your app to have the same handler for a double click as for a single click and you track the interval between mouse click events yourself and act appropriately.
AlHal2

ASKER
Hi IT_Saige,

I've no doubt that your hook will work.  The only problem is my difficulty understanding it.
Why do you need to call DLLs?
Perhaps the complexity is due to the requestor asking about co-ordinates.  Do you have a version which just does what I need?
The code below doesn't work properly with an old mobile keypad.  I'm trying to see if it's a simple bug in my code or if I'm missing something more fundamental.

public Button clickedButton1 = null;
        public Button clickedButton2 = null;
        public Button clickedButton3 = null;
        public Button clickedButton4 = null;
        public DateTime clickTime1 = new DateTime(2011,1,1,1,1,1,1);
        public DateTime clickTime2 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
        public DateTime clickTime3 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
        public DateTime clickTime4 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
        TimeSpan timeDiff1;
        TimeSpan timeDiff2;
        TimeSpan timeDiff3;
        TimeSpan timeDiff1Now;
        TimeSpan timeDiff2Now;
        public string LetterToDisplay = "";
        public int cmdAbcPressed = 0;
        public int cmdDefPressed = 0;
private void ProcessButton(object sender, EventArgs e)
        {

            clickedButton4 = clickedButton3;
            clickTime4 = clickTime3;
            clickedButton3 = clickedButton2;
            clickTime3 = clickTime2;
            clickedButton2 = clickedButton1;
            clickTime2 = clickTime1;
            clickedButton1 = sender as Button;
            clickTime1 = DateTime.Now;

            timeDiff1 = clickTime1-clickTime2;
            timeDiff2 = clickTime2 - clickTime3;
            timeDiff3 = clickTime3 - clickTime4;

            timeDiff1Now = DateTime.Now-clickTime2;
            timeDiff2Now = DateTime.Now - clickTime3;
            //MessageBox.Show(clickedButton1.Name + " clicked at " + clickTime1);
        }

        private void cmdAbc_Click(object sender, EventArgs e)
        {
            //string LetterToDisplay = "";
            cmdAbcPressed += 1;
            cmdDefPressed = 0;
            //if (LetterToDisplay!="")
            //{
            //    DisplayText(LetterToDisplay);
            //}
            ProcessButton(sender,e);
            if (clickedButton2 == null)
            {
                LetterToDisplay = "a";
            }
            else if(clickedButton2 != clickedButton1)
            {
                LetterToDisplay = "a";
            }
            else if  (timeDiff1.TotalMilliseconds > 500)
                //else if (((clickTime1 - clickTime2).Milliseconds > 500))
            {
                LetterToDisplay = "a";
            }
            else
            {
                if (clickedButton3 == null)
                {
                    LetterToDisplay = "b";
                }
                else if (clickedButton3 != clickedButton2)
                {
                    LetterToDisplay = "b";
                }
                else if (timeDiff2.TotalMilliseconds > 500)
                //else if (((clickTime2 - clickTime3).Milliseconds > 500))

                {
                    LetterToDisplay = "b";
                }
                else
                {
                    LetterToDisplay = "c";
                }
            }
  
            DisplayText(LetterToDisplay);
            txtDebug.Text = txtDebug.Text + (timeDiff1.TotalMilliseconds + " | " + timeDiff2.TotalMilliseconds + " | " + clickTime1 + " | " + clickTime2 + " | " + clickTime3 + " | " + clickTime4 + (char)13 + (char)10);
            if (clickedButton3 != null)
            {
                if ((timeDiff2Now).TotalMilliseconds > 500)
                {
                    clickedButton1 = null;
                    clickedButton2 = null;
                    clickedButton3 = null;
                    clickTime3 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
                    clickTime2 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
                    clickTime1 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
                }
            }
            if (clickedButton2 != null)
            {
                if ((timeDiff1Now).TotalMilliseconds > 500)
                {
                    clickedButton1 = null;
                    clickedButton2 = null;
                    clickTime2 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
                    clickTime1 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
                }
            }
            if (clickedButton1 != null)
            {
                if ((DateTime.Now - clickTime1).TotalMilliseconds > 500)
                {
                    clickedButton1 = null;
                    clickTime1 = new DateTime(2011, 1, 1, 1, 1, 1, 1);
                }
            }

        }

Open in new window

Experts Exchange has (a) saved my job multiple times, (b) saved me hours, days, and even weeks of work, and often (c) makes me look like a superhero! This place is MAGIC!
Walt Forbes
ASKER CERTIFIED SOLUTION
Russ Suter

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
AlHal2

ASKER
I've put Saige's solution into program.cs in a windows form application.
I want to put two buttons onto Form1 and check their click, double click and triple click events.  Also, I need to see if the user has pressed button 2 after a single or double click of button 1.
What do I put in form1.cs?
Russ Suter

AlHal2,

Where are you on this issue? Do you still need help?
AlHal2

ASKER
I realised I could use key presses instead of mouse clicks and came up with this code.  It seems to work, but let me know what you think.


using System;

using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.IO;
namespace 
{
    public partial class Form1 : Form
    {
        public DateTime FirstClickTime = new DateTime(2011, 1, 1, 1, 1, 1, 1);
        public DateTime SecondClickTime = new DateTime(2011, 1, 1, 1, 1, 1, 1);
        public DateTime ThirdClickTime = new DateTime(2011, 1, 1, 1, 1, 1, 1);
        public DateTime FourthClickTime = new DateTime(2011, 1, 1, 1, 1, 1, 1);
        TimeSpan timeDiff1;
        TimeSpan timeDiff2;
        TimeSpan timeDiff3;
        TimeSpan timeDiff1Now;
        public string FirstKey = "";
        public string SecondKey = "";
        public string ThirdKey = "";
        public string FourthKey = "";
        public DateTime StartTime;
        public DateTime EndTime;
        public int Keystrokes = 0;
        public int TimeTaken = 0;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            StartTime = DateTime.Now;
            using (StreamWriter sw = new StreamWriter(@"D:\OneDrive\Documents\Tests\OldMobileKeyboard\MobKeyboard4\Results.txt", false))
            {
                sw.WriteLine("Started at " + StartTime);
            }
        }
        private void textBox1_KeyUp(object sender, KeyEventArgs e)
        {
            textBox1.Text = Regex.Replace(textBox1.Text, @"[\d-]", "");
            textBox1.Text = textBox1.Text.Replace("?", "");
        }
        private string ReturnKeys(string KeyPressed)
        {
            
            string OutputKey = "";
            switch (KeyPressed)
            {
                case "2":
                    OutputKey = "abc";
                    break;

                case "3":
                    OutputKey = "def";
                    break;
                case "4":
                    OutputKey = "ghi";
                    break;
                case "5":
                    OutputKey = "jkl";
                    break;
                case "6":
                    OutputKey = "mno";
                    break;
                case "7":
                    OutputKey = "pqrs";
                    break;
                case "8":
                    OutputKey = "tuv";
                    break;
                case "9":
                    OutputKey = "wxyz";
                    break;
                case "0":
                    OutputKey = " ";
                    break;
                case "#":
                    OutputKey = "#";
                    break;
                case "*":
                    OutputKey = "*";
                    break;

                default:
                    OutputKey = "???";
                    MessageBox.Show("Please enter one of the following keys: 234567890*#");
                    break;
            }
                    return OutputKey;
            
        }

        private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
        {
            
            try
            {
                using (StreamWriter sw = new StreamWriter(@"D:\OneDrive\Documents\Tests\OldMobileKeyboard\MobKeyboard4\Results.txt", true))
                {
                Keystrokes += 1;
                textBox1.Text = Regex.Replace(textBox1.Text, @"[\d-]", "");
                textBox1.Text = textBox1.Text.Replace("?", "");
                FourthKey = ThirdKey;
                FourthClickTime = ThirdClickTime;
                ThirdKey = SecondKey;
                ThirdClickTime = SecondClickTime;
                SecondKey = FirstKey;
                SecondClickTime = FirstClickTime;
                FirstKey = e.KeyChar.ToString();
                FirstClickTime = DateTime.Now;
                string LetterToDisplay = "";
                timeDiff1Now = DateTime.Now - FirstClickTime;
                timeDiff1 = FirstClickTime - SecondClickTime;
                timeDiff2 = SecondClickTime - ThirdClickTime;
                timeDiff3 = ThirdClickTime - FourthClickTime;
                int NumberOfClicks = 0;
                
                    switch (FirstKey)
                    {
                        case ("2"):
                        case ("3"):
                        case ("4"):
                        case ("5"):
                        case ("6"):
                        case ("7"):
                        case ("8"):
                        case ("9"):
                        case ("0"):
                        case ("*"):
                        case ("#"):
                            break;
                        default:
                            e.Handled = true;
                            break;
                    }
                if (FirstKey != SecondKey)
                {
 
                        LetterToDisplay = ReturnKeys(FirstKey).Substring(0, 1);
                        NumberOfClicks = 1;
                        TimeTaken += 500;

                }
                else if (FirstKey == SecondKey && timeDiff1.TotalMilliseconds >= 500)
                {
                    LetterToDisplay = ReturnKeys(FirstKey).Substring(0, 1);
                    NumberOfClicks = 1;
                    TimeTaken += 500;
                    }
                else if (SecondKey == ThirdKey && timeDiff2.TotalMilliseconds < 500 && ThirdKey == FourthKey && timeDiff3.TotalMilliseconds >= 500)
                {
                    LetterToDisplay = ReturnKeys(SecondKey).Substring(2, 1);
                    NumberOfClicks = 3;
                    TimeTaken += 500;
                    }
                else if (SecondKey == ThirdKey && timeDiff2.TotalMilliseconds < 500 && ThirdKey == FourthKey && timeDiff3.TotalMilliseconds < 500)
                {
                    LetterToDisplay = ReturnKeys(SecondKey).Substring(3, 1);
                    NumberOfClicks = 4;
                    TimeTaken += 100;
                    }
                else if (FirstKey == SecondKey && timeDiff1.TotalMilliseconds < 500 && SecondKey != ThirdKey)
                {
                    LetterToDisplay = ReturnKeys(FirstKey).Substring(1, 1);
                    NumberOfClicks = 2;
                    TimeTaken += 100;
                }
                else if (FirstKey == SecondKey && timeDiff1.TotalMilliseconds < 500 && SecondKey == ThirdKey && timeDiff2.TotalMilliseconds >= 500)
                {
                    LetterToDisplay = ReturnKeys(FirstKey).Substring(1, 1);
                    NumberOfClicks =2;
                    TimeTaken += 100;
                }
                else if (FirstKey == SecondKey && timeDiff1.TotalMilliseconds < 500 && SecondKey == ThirdKey && timeDiff2.TotalMilliseconds < 500)
                {
                    LetterToDisplay = ReturnKeys(FirstKey).Substring(2, 1);
                    NumberOfClicks = 3;
                    TimeTaken += 100;
                }
                else
                {
                    LetterToDisplay = ReturnKeys(FirstKey).Substring(0, 1);
                    NumberOfClicks = 1;
                    TimeTaken += 500;
                }

                if (NumberOfClicks >1)
                {
                    textBox1.Text = textBox1.Text.Remove(textBox1.Text.Length -  1,  1);
                }
                
                textBox1.Text = textBox1.Text + LetterToDisplay;
                sw.WriteLine(e.KeyChar);
                textBox1.Text= Regex.Replace(textBox1.Text, @"[\d-]", "");
                textBox1.Text = textBox1.Text.Replace("?", "");
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message.ToString());
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            EndTime = DateTime.Now;
            using (StreamWriter sw = new StreamWriter(@"D:\OneDrive\Documents\Tests\OldMobileKeyboard\MobKeyboard4\Results.txt", true))
            {
                sw.WriteLine("Ended at   " + EndTime);
                sw.WriteLine("Duration" + (EndTime - StartTime));
                sw.WriteLine("Minimum Duration " + TimeTaken +" milliseconds");
                sw.WriteLine("keystrokes " + (Keystrokes));
                sw.WriteLine("To make this more configurable I would put each key in a cross reference file with the chracters assigned to it.");
            }
            Environment.Exit(0);
        }
    }
}

Open in new window

⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
Russ Suter

I'm not sure what you're trying to accomplish here but it's a completely different problem than your initial question. May I suggest that if you require assistance with the code immediately above that you open a new question. As for the original question about single, double, and triple clicking, both it_saige and myself offered viable solutions.
AlHal2

ASKER
Thanks all.