2014-12-11 6 views
1

ну, я пишу бота, который будет использовать определенные координаты на экране, а затем имитирует 15 кликов (каждый клик с разными координатами). Я уже работал с координатами, которые я вводил вручную в код, но теперь мне нужен способ записи этих координат. То, что я хотел сделать, это: пользователи нажимают кнопку, тогда программа показывает сообщение с сообщением «щелкните правой кнопкой мыши по главному меню», пользователь щелкнет правой кнопкой мыши, и эти координаты будут записаны в массиве, тогда программа покажет вторую сообщение, требующее щелкнуть правой кнопкой мыши следующую кнопку и так ... Моя проблема в том, что я не знаю, как заставить метод ждать, пока пользователь щелкнет правой кнопкой мыши, чтобы продолжить.Сделайте способ подождать, щелкнув правой кнопкой мыши, чтобы перейти к следующему шагу (форма C#)

Я проверил свою программу, сделав событие, которое вызвало бы каждый раз я правой кнопкой мыши и показать координаты в MessageBox, используя класс UserActivityHook с содержит OnMouseActivity событие:

UserActivityHook actHook; 
    void MainFormLoad(object sender, System.EventArgs e) 
    { 
     actHook = new UserActivityHook(); 
     // crate an instance with global hooks 
     // hang on events 
     actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);   
    } 

    public void MouseMoved(object sender, MouseEventArgs e) 
    {    
     if (e.Clicks > 0) 
     { 
      if (e.Button.Equals(MouseButtons.Right)) 
      { 
       MessageBox.Show("X:" + e.X + " Y:" + e.Y); 
      } 
     } 
    } 

Я пытаюсь сделать что-то вроде:

private void button1_Click(object sender, EventArgs e) 
    { 
     RecordMacro(cords, 1);   
    } 

    public void RecordMacro(int coordinates[][], int slotnumber){ 

     MessageBox.show("Right click main menu"); 
     //saves coordinates on [0][0] and [0][1] 
     WaitForRightClickAndSaveCords(coordinates[][]); 

     MessageBox.show("Right click resupply button"); 
     //saves coordinates on [1][0] and [1][1] 
     WaitForRightClickAndSaveCords(coordinates[][]); 
     ... 
    } 

Я еще новичок и это мой первый вопрос в StackOverflow (я обычно найти ответ просматривающие здесь и нет необходимости задавать себе), поэтому я с удовольствием буду принимать любые критики.

ответ

2

Это проще всего реализовать с использованием асинхронной модели C# 5.0. Мы начнем с создания метода, который будет генерировать Task, который будет завершен, когда ваши условия будут выполнены. Он сделает это, создав TaskCompletionSource, добавив обработчик события и отметит задачу как выполненную в обработчике. Бросок в какой-то шаблонный код, чтобы убедиться, что обработчик удаляется, когда сделано, вернуть Task от источника завершения, и мы установить:

public static Task<Point> WhenRightClicked(this UserActivityHook hook) 
{ 
    var tcs = new TaskCompletionSource<Point>(); 
    MouseEventHandler handler = null; 
    handler = (s, e) => 
    { 
     if (e.Clicks > 0 && e.Button == MouseButtons.Right) 
     { 
      tcs.TrySetResult(new Point(e.X, e.Y)); 
      hook.OnMouseActivity -= handler; 
     } 
    }; 
    hook.OnMouseActivity += handler; 
    return tcs.Task; 
} 

Теперь вы можете написать:

public async void RecordMacro(int[][] coordinates, int slotnumber) 
{ 
    MessageBox.Show("Right click main menu"); 
    Point mainMenuPosition = await actHook.WhenRightClicked(); 
    MessageBox.Show("Right click resupply button"); 
    Point resupplyButtonPosition = await actHook.WhenRightClicked(); 
} 
+0

'+ 1' Мне нравится этот метод, хотя (потенциал) длина RecordMacro предлагает мне какое-то очереди, чтобы действия не были жестко закодированы. – BradleyDotNET

+0

@BradleyDotNET Я просто демонстрировал, как вызвать метод; все дело в том, что после того, как вы используете метод, он становится очень простым. Если он хочет вызвать его в цикле, он может это сделать. – Servy

+0

Ты спасатель. спасибо за ясный ответ, и да, как говорит Брэдли, я просто показывал намерение там с «неортодоксальным ручным способом сохранения координат», я думал об использовании цикла. –

0

Есть множество способов сделать эту работу, ни одна из которых вам не нужно делать дистанционно. Причина в том, что при условии, что вам удалось остановить выполнение потока с WaitForRightClick, вы блокируете поток пользовательского интерфейса!

Делая что, вы не дать пользователю возможность нажать на элемент, который вы хотите (среди многих других причин никогда блок пользовательского интерфейса резьбы).

Вы можете использовать его или использовать асинхронные методы, как предлагает Servy. Это блокирует метод (или выполняет его асинхронно) без блокировки самого потока пользовательского интерфейса.

В то время как более сложные, вы также можете поставить очередь в виде группы объектов, представляющих «ClickTarget». Затем вы прослушаете событие правой кнопки мыши и записываете связанные координаты с текущим ClickTarget, dequeue, чтобы получить следующую инструкцию, и так далее.

Полный код был бы слишком длинным для StackOverflow, но, чтобы дать вам несколько идей:

public class ClickTarget 
{ 
    Point Coordinates {get; set;} 
    String TargetName {get; set;} 
} 

Queue<ClickTarget> clickTargets; 
//Obviously you instantiate/populate this somewhere 

private void onRightClick(...) 
{ 
    ClickTarget target = clickTargets.Dequeue(); 
    target.Coordinates = clickLocation; 

    MessageBox.Show("Please click on " + clickTargets.Peek().TargetName); 
} 
+0

О, я не думал об использовании очередей. Я не использовал их с тех пор, как несколько лет назад, когда я пытался показать в графическом окружении несколько многоуровневых списков узлов. благодарю вас за ваш совет. –