Счетчик задержки мыши

Я пытаюсь сделать систему, которая сначала записывает, когда вы нажимаете, а потом выдает список задержек между двумя нажатиями мыши из записи, это очень сложно объяснить, но, возможно, вы поймете, когда посмотрите на код. Текущий код таков:

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

Ошибок не выдает, но номера списка задержек намного меньше, чем должны быть. Интервал таймера составляет 1 мс, поэтому, если вы нажмете, отпустите (1 секунду) нажмите снова, значение в списке должно быть 1000, теперь значения такие, как 1, 1, 4, 2, и это почти невозможно нажать на это быстрый. Что не так с моим кодом?


c#
person Community    schedule 30.01.2018    source источник
comment
Если вы хотите измерить время между двумя событиями, было бы гораздо точнее запомнить DateTime start = DateTime.Now;, а затем, когда вы остановитесь, получить TimeSpan elapsed = DateTime.Now - start;.   -  person Blorgbeard    schedule 30.01.2018
comment
Но этот текущий код тоже должен работать? Я не вижу никаких ошибок.   -  person    schedule 30.01.2018
comment
Вы устанавливаете mouseBool и stopbool в true в одном и том же месте. Если таймер запущен, он увеличит recDelay, а затем сразу же добавит его в список. Я подозреваю, что использование DateTime упростило бы ваш код и облегчило бы его отладку.   -  person Blorgbeard    schedule 30.01.2018
comment
recToggle просто делает, когда вы нажимаете кнопку, он сначала запускает таймер, а когда вы нажимаете снова, он останавливается. Таймер проверяет, является ли значение stopbool истинным, и если оно истинно, то делает его ложным.   -  person    schedule 30.01.2018
comment
Хорошо .. Я предлагаю вам немного отладить. Добавьте несколько операторов Console.WriteLine или несколько точек останова.   -  person Blorgbeard    schedule 30.01.2018


Ответы (1)


Проблема, с которой вы сталкиваетесь, заключается в том, что System.Windows.Forms.Timer не очень точен (Самый точный таймер в . NET?). Несмотря на то, что вы установили тик каждые 1 мс, на самом деле между тиками требуется гораздо больше времени. В качестве теста я запустил его в своей системе, распечатывая на каждом тике:

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

Вы можете видеть, что между тиками проходит более 1 мс. Иногда это 60 мс, иногда 40 мс, иногда 12 мс.

Лучше использовать Секундомер или с помощью DateTime, как упомянул Блоргберд.

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

См. также: Почему таймеры .NET ограничены разрешением 15 мс?

Чтобы преобразовать список TimeSpans в ints:

List<int> int_list = new List<int>();
foreach (TimeSpan delay in list)
{
  int_list.Add((int)delay.TotalMilliseconds);
}
person gunnerone    schedule 30.01.2018
comment
У него есть некоторые ошибки, например, в foreach он говорит, что не может преобразовать int в временной интервал, и я не могу это исправить. Это сказано в списке. Добавить (ts) то же самое, но я исправил это, но не могу исправить foreach - person ; 31.01.2018
comment
Проверьте определение списка. Я изменил тип списка по сравнению с тем, который у вас был изначально, вместо List<int> list теперь List<TimeSpan> list. - person gunnerone; 31.01.2018
comment
Теперь он работает, но я получил еще одну ошибку. Мне нужно преобразовать этот список временных интервалов в список int, возможно ли это? - person ; 31.01.2018
comment
Проверьте мое последнее редактирование, я добавил пример для обратного преобразования. Когда вы вызываете .TotalMilliseconds для TimeSpan, он возвращает двойное значение. - person gunnerone; 31.01.2018