- Бот для DirectX-аркады. Часть №1: устанавливаем контакт
- Введение
- Отступление
- Эмуляция мыши
- Перенос игры на виртуальную машину
- Перехват изображения
- Зацикливаем игровой процесс
- Резюме
- Повышаем эффективность работы из дома, или как шевелить мышкой на Pi Zero
- Про трекпоинт и эмуляцию мыши
- Много рассуждений
- Мало настроек
Бот для DirectX-аркады. Часть №1: устанавливаем контакт
Введение
В данном цикле статей я собираюсь показать, что, во-первых: «не так страшен черт, как его малюют», а во-вторых: позже собираюсь ответить и на вопрос: «зачем это надо?».
Сейчас начнем с простого. С установления взаимосвязи между игрой и программой-игроком (ботом). В качестве подопытного кролика берется широкоизвестная игра Zuma.
Всякое взаимодействие складывается из двух процессов: отправки данных «им» и получения данных от «них». В Zuma всё управление делается мышой, а обратную связь игра выдает с помощью изображения. Соответственно, перво-наперво необходимо научиться программно эмулировать поведение мыши и получать изображение от игры.
Основная цель этой статьи: получить программу, которая самостоятельно раз за разом заходит в игровой процесс, там что-то делает, а при game over-е начинает всё заново. Далее этот каркас будет развиваться в направлении, чтобы бот всё дальше и всё дольше продержался в игре до game over-а.
Решаемые вспомогательные подзадачи: эмуляция мыши, перенаправление мыши на виртуальную машину, захват изображения.
Отступление
При разработке кода для данного цикла статей используется подход: как можно быстрее получить результат за минимум усилий. Такой подход позволяет поддерживать мотивацию на высоком уровне, и не дает опустить руки при виде неподъемности задачи. Из-за этого:
— во-первых, многие малозначимые (с точки зрения текущего результата) моменты будут быстро пробегаться, оставляя в коде «костыли и подпорки». И только на следующих итерациях эти моменты будут отдельно разбираться, и «костыли» будут заменяться на полноценный код.
— во-вторых, стиль кода больше «хакерский», чем классический C#-ный. В коде будет много лямд, анонимных данных, трюков, авторского произвола и полное отсутствие комментариев.
Эмуляция мыши
Windows поддерживает 2 штатных способа эмуляции мыши с помощью 4 различных функций WinApi.
Первый способ: посылка программе своих window-сообщений (WM_MOUSEMOVE, WM_LBUTTONDOWN и т.д.) с помощью функций SendMessage или PostMessage.
Для DirectX-игр (как в нашем случае) такой способ не подходит, потому что такие программы для опроса мыши используют DirectInput, который опрашивает мышь напрямую, игнорируя windows-сообщения.
Второй способ: прямая эмуляция поведения мыши с помощью функций mouse_event или SendInput. Этот способ подходит для любых программ, в том числе и для полноэкранных DirectX-игр. Функция mouse_event попроще, но она считается устаревшей, SendInput — современнее, но более громоздкая. Остановимся на mouse_event.
WinApi-функции из C# вызываются с помощью технологии PInvoke. PInvoke-описание для большинства распространных WinApi-функций можно взять на сайте PInvoke.net. Функция mouse_event не является исключением.
Координаты мыши
Функция mouse_event имеет специфическую особенность: координаты мыши задаются в mickey, а не в пикселях. Перерасчет mickey в пиксели (и обратно) зависит от разрешения основного используемого монитора. (0,0) соответствует левому верхнему углу монитора, а (65535, 65535) нижнему правому, что дает формулы для пересчета mickey в пиксели и обратно: mickey_point = pixel_point * (65536, 65536) / screen_size и pixel_point = mickey_point * screen_size / (65536, 65536) .
Основные операции
Суммируя всё вышеперечисленное, получаем следующие операции для управления мышью.
Передвижение курсора мыши в точку (x,y):
Клик левой кнопкой мыши:
Клик правой кнопкой мыши:
Проблема: эксклюзивность ввода
При эмуляции мыши через функцию mouse_event присутствует серьезное неудобство: mouse_event имитирует мышь для всей ОС сразу, а не для отдельного приложения. Из этого следует, что пока бот запущен и играется, то невозможна другая работа за компом: отладка бота, активный просмотр состояния бота, чтение интернета и т.д. Но есть выход: виртуальная машина!
Перенос игры на виртуальную машину
Перенос игры на виртуалку решает следующие проблемы:
— во-первых, упрощается взаимодействие с играми, которые не поддерживают оконный режим и работают только в полноэкранной режиме,
— во-вторых, ввод мыши подменяется только на виртуалке, а на основной машине продолжает работать в нормальной режиме, позволяя пользователю компьютера заниматься своими делами.
Бота, в отличии от самой игры, удобнее запускать на основной машине. Это позволяет перезапускать бота напрямую из Visual Studio, там же его отлаживать, есть куда выводить внутреннее состояние бота и т.д.
Развертывание виртуальной машины (в данном случае использовалась Oracle VirtualBox), установка гостевой ОС и перенос игры делается штатным образом за исключением одного момента: для бота необходима возможность установки связи по сети между хостовой ОС и гостевой ОС. Это делается множеством способов. Один из способов, прокинуть с помощью VirtualBox конкретный порт из гостевой ОС в хостовую. Другой способ, настроить режим Bridged Adapter, тогда виртуалка для всей сети будет выглядеть как обычный компьютер, и гостевая ОС будет получать свой ip-адрес через dhcp от роутера. По этому адресу и будет происходит доступ из хостовой ОС в гостевую. (автором, в данном случае, использовался вариант с bridged adapter)
Прокси
Для работы прокси достаточно его скопировать на виртуальную машину и запустить. Прокси ждет сообщения на порту 7001 и выводит лог своей работы на консоль. Для завершения работы прокси достаточно закрыть консольное окно.
Клиент
Подключение к прокси еще проще, чем код самого прокси.
Перехват изображения
Изображение проще всего захватывать напрямую с экрана. В .net-е для этого есть готовая функция Graphics.CopyFromScreen. На этом способе и остановимся подробнее.
Во-первых, на выходе хочется получить Bitmap, а не Graphics — это решается с помощью вспомогательной функции:
Во-вторых, необходимо знать какую часть экрана надо захватывать. Можно, конечно, захватывать всегда одну и ту же часть экрана, а игру руками располагать в этой части экрана, но это не спортивно не удобно. Тем более автоматизация этого процесса делается минимальными усилиями. В этом нам опять поможет WinApi и PInvoke, а конкретнее две функции: FindWindow и GetWindowRect. FindWindow позволяет по заголовку окна получить handle окна, а GetWindowRect по handle-у возвращает позицию и размер окна на экране.
Pinvoke-описание обеих функций есть на сайте pinvoke.net: FindWindow и GetWindowRect.
И код захвата изображения окна виртуальной машины получается следующим:
Слабое место
Существенным недостатком данного подхода является то, что захватываемое окно, во-первых: обязано целиком располагаться на экране, а во-вторых: обязано располагаться поверх всех остальных окон. Это неудобство нивелируется с помощью двух (и более) мониторов :), тогда окно виртуальной машины располагается на вспомогательном мониторе, ни кому не мешая, оставаясь поверх остальных окон. Также данная проблема полностью решается с помощью ранее расмотренного способа: переноса функции (захват экрана) внутрь виртуальной машины. Для этого достаточно добавить соответствующую функцию в InputProxy.
Зацикливаем игровой процесс
Наконец-то, приступаем непосредственно к решению поставленной на сегодня задаче: зацикливанию игрового процесса — все необходимые подзадачи решены. Игровой процесс в Zuma крутится вокруг трех окон: main, mission и action. Main-окно содержит основное меню, позволяя выбрать вид игры, mission-окно предлагает выбрать миссию, а в action-окне происходит сам игровой процесс.
Бот определяет текущее окно самым простым способом: по значению цвета в нескольких ключевых точках. Точки выбираются вручную: методом «пристального всматривания».
Основной цикл бота:
В игровой фазе бот постоянно кликает, выпуская шарики в одну точку. На такой простой (скорее даже тупой) тактике бот в первой миссии набирает 1000-2000 очков, и иногда даже полностью набирает полоску Zuma.
Резюме
Поставленная цель выполнена: каркас бота написан — игровой процесс зациклен.
Следующие цели: подключить OpenCV, распознать положение и цвет шаров.
Изображение для привлечение внимания. (Оранжевым показаны области, которые следующая версия бота распознала как шары)
Источник
Повышаем эффективность работы из дома, или как шевелить мышкой на Pi Zero
Работа из дома – это не только благо, но и серьезный вызов для эффективных менеджеров, которые до сих пор меряют производительность ИТ отдела в трудочасах. Основным индикатором твоей трудонадёжности частенько выступает бодро-зеленый статус в корпоративном мессенджере. Некоторые идут ещё дальше и деплоят средства измерения “digital experience” сотрудников дабы считать, сколько времени они провели в Word’е, браузере или среде разработки.
Есть несколько способов, как можно противостоять этому безобразию:
Программный. Я перепробовал различные скрипты и тулзы, эмулирующие действия пользователя – ничего не работает. Компьютер всё равно засыпает/мессенджер ставит статус “Away”
Работает, но печатать что-либо разумное не выйдет.
3. Гибридный, на нём и остановимся поподробнее
Изготовить эмулятор USB HID устройства можно на любой Ардуине с ATmega32U4. Там есть поддержка USB. Но зачем использовать Ардуину, если за те же деньги есть Raspberry Pi Zero (W)? Pi0 можно превратить в USB клавиатуру, мышь и сетевую карту одновременно, при этом управлять всем добром через SSH, ни в чём себе не отказывая.
Давайте посмотрим, как это можно сделать.
Вначале нужно достать Pi Zero (W), установить туда ОС и настроить SSH
Источник
Про трекпоинт и эмуляцию мыши
Много рассуждений
В предыдущей статье про настройку док-станций, я упоминал как тяжко, в свое время, мне было пользоваться лаптопами «потребительского» сегмента. Отсутствие docking-port’a и необходимость каждый раз по приходу домой или на работу подключать кучу кабелей — все это неприятно и раздражало, но что действительно вызывало страдания, так это отсутствие трекпоинта: той самой «красной пимпочки», которую можно встретить на лаптопах от IBM/Lenovo (синяя или серая в случае HP и DELL). Подробней можно почитать на той же Википедии.
Зачем он нужен? Когда большая часть операций производится с клавиатуры, будь то написание кода, либо работа в командной оболочке, необходимость переместить руку на мышь дабы переместить графический курсор и что-нибудь там кликнуть не вызывает особой радости.
Особую нелюбовь к использованию мыши создает привычка работать на достаточном удалении от монитора (до двух метров), расположив клавиатуру на коленях. Здесь на помощь и приходит замечательный мини-джойстик: для манипуляций графическим курсором, всей кисти нет нужды покидать пределы home row, требуется переместить лишь указательный палец правой или левой руки, а клавиши находятся под большими пальцами. Для наглядности, приведу старый ролик от IBM:
Проблема в том, что на данный момент найти приличную клавиатуру, оснащенную таким устройством становится все тяжелее: серийно их производит только Unicomp, при этом сами клавиатуры весьма громоздкие, с классической 104-key раскладкой.
Существуют модели от Lenovo, в основном ориентированные на использование в серверной стойке (то есть, большую часть времени, валяющиеся там, подключенные к консоли) с довольно низким качеством материалов (дешевый, быстро вытирающийся пластик, хлипкие ножки), плюс все эти клавиатуры мембранные.
Из трех клавиатур производства IBM/Lenovo, самые теплые чувства вызывает модель Space Saver 2: достаточно тяжелая, шероховатый пластик, прочные ножки и резиновые вставки, которые не отклеились за, приблизительно, восемь лет эксплуатации. Недостаток у данной клавиатуры ровно один: она тоже мембранная со всеми вытекающими.
Весьма удобных при использовании в Unix-среде так-называемых 60% клавиатур с трекпоинтом буквально единицы: Tex Yoda и Guru-board, да и те, скорее, являются кастомами, нежели серийно производимыми.
В общем, тяжко нынче любителям трекпоинта: выбор очень мал. Придется либо искать model M раритеты от IBM, либо приобретать Unicomp, либо довольствоваться ножничными мембранками от Lenovo (кстати, тоже весьма не дешевыми).
Таким образом и родилась мысль, что неплохо бы это самый трекпоинт эмулировать. То есть управлять перемещениями графического курсора с клавиатуры.
Мало настроек
Сразу вспомнилось, что в X-системе нужный функционал когда-то имелся: для управления графическим курсором можно использовать нампад (активация по Shift+Numlock).
Правда, клавиатурами с нампадом я давным-давно не пользуюсь, да и опять же туда-сюда дергать кисть — это не дело. Посему, способ этот не годится. Мы пойдем другим путем.
Есть такая утилита: xdotool, позволяющая эмулировать нажатия клавиш и движения мыши. Годится она не только для имитации движений мыши, но и для автоматизации каких-либо мышинно-клавиатурных действий.
И так, сценарий прост: забиндить вызов xdotool с нужными параметрами на хоткеи, либо ввести дополнительный режим клавиатуры.
Так как я пользуюсь оконным менеджером i3, покажу на его примере. Создавать режимы клавиатуры, которые могут использоваться как для кейчейнов, так и модифицированного ввода, в этом WM одно удовольствие:
Для того, чтобы передвинуть курсор мыши, на заданную позицию относительно текущего местоположения, нужно выполнить следующую команду:
Для эмуляции клика:
Где 1 — левая кнопка, 2 — средняя, 3 — правая.
А конфиг для i3 будет выглядеть так:
Думаю, что конфиг в излишних комментариях не нуждается: все, вроде бы, довольно очевидно.
К сожалению, реализовать ускорение курсора навскидку не удалось.
Для тех, кто пользуется другими оконными менеджерами или DE, могу порекомендовать утилиту xbindkeys.
Трекпоинт, безусловно, гораздо удобнее, но это все-таки лучше, чем каждый раз тянуться за мышью.
У кого-то может возникнуть вопрос: если работаем за лаптопом, то почему бы не использовать тачпад? Во-первых, лично мне использовать его тяжело, вплоть до возникновения болевых ощущений: без отрыва пальцев от home row, управление производится большим пальцем сильной руки, вывернутым под тупым углом. В таком положении палец довольно быстро начинает болеть. Если тыкать указательным пальцем, то опять возникает проблема переноса кисти и в этом случае куда проще и логичнее взяться уже, в конце концов, за мышь. Также жутко раздражали ложные срабатывания при наборе текста, отключаться при наборе тачпады научились не так давно, да и то не все.
На этом пока все. Такое решение вполне сгодится как временная мера. А в качестве постоянной, планирую восстановить IBM SpaceSaver 2 и переделать ее в механику.
Источник