0

I'm trying to make the system, which first records when you click, and then it gives a list of delays between two mouse downs from the record, it is very hard to explain but maybe you will understand when you look at the code. Current code is this:

    bool  recToggle = false;
    public static bool stopbool = false;
    public static bool mouseBool = false;
    int recDelay = 0;

    private void button1_Click(object sender, EventArgs e)
    {
        if (recToggle)
        {
            button1.Text = "Start Recording";
            //REC IS OFF!
            //MessageBox.Show(list.Count.ToString()); //show how many items
            //list.ForEach(Console.WriteLine); //print the list
            recTimer.Stop();
            recToggle = false;
        }
        else
        {
            button1.Text = "Stop Recording";
            //REC IS ON!
            recTimer.Start();
            recToggle = true;
        }
    }

    private void recTimer_Tick(object sender, EventArgs e)
    {
        recTimer.Interval = 1;
        if (mouseBool)
        {
            recDelay = recDelay + 1;
        }
        if (stopbool)
        {
            stopbool = false;
            list.Add(recDelay);
            recDelay = 0;
        }
    }

    public List<int> list = new List<int>();

    //hook is working but I didnt put whole code here to make this bit smaller

    public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
    {
        if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
        {
             //mouse down
             if (mouseBool)
             {
                 mouseBool = false;
             }
             else
             {
                 mouseBool = true;
                 stopbool = true;
             }                 
        }

        if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
        {
             //mouse up
        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);
    }

It doesn't give any errors, but the delay list numbers are much less than they should be. Timer interval is 1ms, so if you press down, release (1 second) press down again, the value in the list should be 1000, now the values are like 1, 1, 4, 2, and that is almost impossible to click that fast. What is wrong with my code?

  • If you want to measure the time between two events, it would be far more accurate to remember `DateTime start = DateTime.Now;` and then when you stop, get `TimeSpan elapsed = DateTime.Now - start;`. – Blorgbeard Jan 30 '18 at 17:54
  • But that current code should work too? I don't see any mistakes. –  Jan 30 '18 at 17:56
  • You set `mouseBool` and `stopbool` to true in the same place. If the timer's running, it's going to increment `recDelay` and then add it to the list immediately. Using `DateTime` would simplify your code and make it easier to debug as well, I suspect. – Blorgbeard Jan 30 '18 at 18:01
  • recToggle is just making when you click the button it first starts timer and when you click again it stops. Timer checks is stopbool is true, and if it is true it makes it false. –  Jan 30 '18 at 18:08
  • Ok.. I suggest you do some debugging. Add some `Console.WriteLine` statements or some breakpoints. – Blorgbeard Jan 30 '18 at 18:15

1 Answers1

1

The issue you're running into is that the System.Windows.Forms.Timer isn't very accurate (Most accurate timer in .NET?). Even though you have it set to tick every 1 ms, it's actually taking much longer between ticks. As a test I ran it on my system printing out at each tick:

11.8543 11.8603 11.8803 11.8923 11.9073 11.9273 11.9433 11.9553 11.9703 11.9863 12.0023 12.0223 12.0323

You can see there is way more than 1 ms between ticks. Sometimes it's 60 ms, sometimes 40 ms, sometimes 12 ms.

You'd be much better off using a Stopwatch or using DateTime as Blorgbeard mentioned.

static bool recToggle = false;
static bool mouseBool = false;
static DateTime start = DateTime.Now;
static List<TimeSpan> list = new List<TimeSpan>();

private static IntPtr HookCallback(
    int nCode, IntPtr wParam, IntPtr lParam)
{
  if (nCode >= 0 && MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
  {
    //mouse down
    if (mouseBool && recToggle)
    {
      mouseBool = false;
      start = DateTime.Now;
    }
    else if (!mouseBool && recToggle)
    {
      mouseBool = true;

      TimeSpan ts = DateTime.Now.Subtract(start);
      list.Add(ts);
    }
  }

  if (nCode >= 0 && MouseMessages.WM_LBUTTONUP == (MouseMessages)wParam)
  {
    //mouse up
  }
  return CallNextHookEx(_hookID, nCode, wParam, lParam);
}

private void button1_Click(object sender, EventArgs e)
{
  if (recToggle)
  {
    button1.Text = "Start Recording";
    //REC IS OFF!
    string s = string.Empty;
    foreach (TimeSpan delay in list)
    {
      s += delay.TotalMilliseconds.ToString() + " ";
    }
    MessageBox.Show(s); //show how many items
    list.Clear();
    recToggle = false;
  }
  else
  {
    button1.Text = "Stop Recording";
    list.Clear();
    //REC IS ON!
    recToggle = true;
    start = DateTime.Now;
  }
}

See also: Why are .NET timers limited to 15 ms resolution?

To convert the list of TimeSpans to ints:

List<int> int_list = new List<int>();
foreach (TimeSpan delay in list)
{
  int_list.Add((int)delay.TotalMilliseconds);
}
gunnerone
  • 3,566
  • 2
  • 14
  • 18
  • It has some errors like in the foreach it says can't convert int to timespan and I can't fix it. It said on the list.Add(ts) the same but I fixed it but can't fix on foreach –  Jan 31 '18 at 18:10
  • Check your list definition. I changed the type of the list from what you originally had, instead of it being `List list`, it's now `List list`. – gunnerone Jan 31 '18 at 18:12
  • Now it is working, but I got one error more. I need to convert that timespan list into int list, is it possible? –  Jan 31 '18 at 18:38
  • Checkout my last edit, I added an example for converting back. When you call .TotalMilliseconds on a TimeSpan it returns a double. – gunnerone Jan 31 '18 at 19:00