Быстрая эмуляция нажатия клавиш в боте для браузерки - C#
Формулировка задачи:
Пишу бота для браузерных танчиков.Прицеливание работает по принципу:через BitBlt копируется нужное окно в память, там ищутся группы пикселей определенного цвета(цвет имени врага), и если таковые найдены, нужно жать определенную кнопку(z или x) до тех пор, пока разница по абсциссе между центром имени противника и центром своих жизней(по ним определяется направление пушки), не станет меньше определенного числа(25 пикселей в данном случае). Эмуляцию нажатия клавиш реализую через PostMessage, ибо работать должно в неактивном окне. Все вроде пашет, но загвоздка в том, что пушка нередко "проезжает" цель, и начинается вертеться перед ней туда-сюда, то бишь PostMessage об отпускании клавиши не доходит вовремя. Сам алгоритм определения, когда надо остановиться, в ряд ли может быть неверным, ибо 100 раз проверен и в целом работает(то есть останавливается вовремя в тех случаях, когда пушка вертится медленнее обычного, либо просто удачно повернулась). Сообщения, которые я посылаю, полностью соответствуют аналогичным при реальном нажатии клавиш(через Spy++ проверялось). Кроме того при попытке эмулировать через keybd_event получилось ровно то же самое. Чего только не пробовал-и задержки разные, и сообщения, все то же самое. Скачал виртуальную клавиатуру-при попытке управлять с нее все работает нормально, то есть теоретически такая эмуляция возможна. Сразу скажу, что производительность при обработке изображения тут не причем, FPS достаточный, чтобы несколько кадров попало в положение, когда надо остановиться. На данный момент прога работает с гугл хромом, там проще однозначно достать хэндл нужного окна. Часть кода прилагается, желающим могу скинуть заготовку проги в личку. Жду ваших предположений, как это устранить, я пока что в тупике( но выход ищу. Заранее благодарен. Рабочие способы реализовать такое на других языках и по другим принципам тоже буду рассматривать, ибо делаю чисто ради развлечения и саморазвития, никуда не спешу. Эти куски кода миллион раз переписывались, на мелкие несуразности можете не обращать внимание, главное-указанный выше вопрос.
Листинг программы
- [DllImport("USER32.DLL", EntryPoint = "PostMessageW", SetLastError = true,
- CharSet = CharSet.Unicode, ExactSpelling = true,
- CallingConvention = CallingConvention.StdCall)]
- public static extern bool PostMessage(int hwnd, int Msg, int wParam, int lParam);
- public static bool e5 = false;
- public static bool e6 = false;
- public static bool e4 = false;
- public static bool in5 = true;
- public static bool in6 = true;
- public static bool in4 = true;
- public static System.Timers.Timer t4 = new System.Timers.Timer(60);
- public static System.Timers.Timer t5 = new System.Timers.Timer(60);
- public static System.Timers.Timer t6 = new System.Timers.Timer(60);
- public static void t4_Tick(object source, ElapsedEventArgs e)
- {
- try
- {
- if (e4)
- {
- if (!in4)
- {
- int virtual_code = MapVirtualKey(0x11, 1);
- int lp = 0x11 << 16 | 1;
- PostMessage((int)win3, WM_KEYDOWN, virtual_code, lp);
- in4 = true;
- }
- else
- {
- int virtual_code = MapVirtualKey(0x11, 1);
- int lp = 0x11 << 16 | 1 << 30 | 1;
- PostMessage((int)win3, WM_KEYDOWN, virtual_code, lp);
- }
- }
- else
- {
- if (in4)
- {
- int virtual_code = MapVirtualKey(0x11, 1);
- int lp = 1 << 31 | 1 << 30 | 0x11 << 16 | 1;
- PostMessage((int)win3, WM_KEYUP, virtual_code, lp);
- in4 = false;
- }
- }
- }
- catch { }
- }
- public static void t5_Tick(object source, ElapsedEventArgs e)
- { try
- {
- if (e5)
- {
- if (!in5)
- {
- int virtual_code = MapVirtualKey(0x2D, 1);
- int lp = 0x2D << 16 | 1;
- PostMessage((int)win3, WM_KEYDOWN, virtual_code, lp);
- in5 = true;
- }
- else
- {
- int virtual_code = MapVirtualKey(0x2D, 1);
- int lp = 0x2D << 16 | 1 << 30 | 1;
- PostMessage((int)win3, WM_KEYDOWN, virtual_code, lp);
- }
- }
- else
- {
- if (in5)
- {
- int virtual_code = MapVirtualKey(0x2D, 1);
- int lp = 1 << 31 | 1 << 30 | 0x2D << 16 | 1;
- PostMessage((int)win3, WM_KEYUP, virtual_code, lp);
- in5 = false;
- }
- }
- }
- catch { }
- }
- public static void t6_Tick(object source, ElapsedEventArgs e)
- { try
- {
- if (e6)
- {
- if (!in6)
- {
- int virtual_code = MapVirtualKey(0x2C, 1);
- int lp = 0x2C << 16 | 1;
- PostMessage((int)win3, WM_KEYDOWN, virtual_code, lp);
- in6 = true;
- }
- else
- {
- int virtual_code = MapVirtualKey(0x2C, 1);
- int lp = 0x2C << 16 | 1 << 30 | 1;
- PostMessage((int)win3, WM_KEYDOWN, virtual_code, lp);
- }
- }
- else
- {
- if (in6)
- {
- int virtual_code = MapVirtualKey(0x2C, 1);
- int lp = 1 << 31 | 1 << 30 | 0x2C << 16 | 1;
- PostMessage((int)win3, WM_KEYUP, virtual_code, lp);
- in6 = false;
- }
- }
- }
- catch { }
- }
- private void threader() {
- t4.Elapsed += new ElapsedEventHandler(t4_Tick);
- t5.Elapsed += new ElapsedEventHandler(t5_Tick);
- t6.Elapsed += new ElapsedEventHandler(t6_Tick);
- t4.Interval = 100;
- t5.Interval = 100;
- t6.Interval = 100;
- t4.Enabled = true;
- t5.Enabled = true;
- t6.Enabled = true;
- while (true)
- {
- try
- {
- mozgi();
- }
- catch { }
- }
- }
- private void mozgi()
- {
- //тут делается снимок окна и находится minraznica.X = модуль разницы абсциссы между
- //центром имени врага и центром своей пушки. Корректно, проверено. А так же
- //переменная pravo, определяющая сторону, с которой находится враг.
- //enemynamesectorREAL это массив точек цвета имени врага.
- if (enemynamesectorREAL.Count > 0 && e4)
- {
- e4 = false;
- }
- if (enemynamesectorREAL.Count > 0 && minraznica.X > 25 && (!(e5 || e6)))
- {
- if (pravo)
- {
- e5 = true;
- }
- else
- {
- e6 = true;
- }
- }
- if ((pravo && e5) || (!pravo && e6) || enemynamesectorREAL.Count == 0 || minraznica.X <= 25)
- {
- bull = false;
- }
- else { bull = true; }
- if ((minraznica.X <= 25 || bull) && (e5 || e6) && enemynamesectorREAL.Count != 0)
- {
- if (e5)
- {
- e5 = false;
- int virtual_code = MapVirtualKey(0x2D, 1);
- int lp = 1 << 31 | 0 << 30 | 0x2D << 16 | 1;
- PostMessage((int)win3, WM_KEYUP, virtual_code, lp);
- {
- notbuisy = false;
- }
- }
- if (e6)
- {
- e6 = false;
- int virtual_code = MapVirtualKey(0x2C, 1);
- int lp = 1 << 31 | 1 << 30 | 0x2C << 16 | 1;
- PostMessage((int)win3, WM_KEYUP, virtual_code, lp);
- {
- notbuisy = false;
- }
- }
- }
- }
- else { }
- if ((enemynamesectorREAL.Count == 0 && !notbuisy) || (mls == 0 && !notbuisy))
- {
- if (e5 || e6)
- {
- notbuisy = true;
- }
- else
- {
- Random rand = new Random();
- switch (rand.Next(1))
- {
- case 0:
- e5 = true;
- notbuisy = true;
- break;
- case 1:
- e6 = true;
- notbuisy = true;
- break;
- }
- }
- }
- if ((enemynamesectorREAL.Count == 0 && !e4) || (mls == 0 && !e4))
- {
- e4 = true;
- }
- //тут можно вывести обрабатываемый битмап на экран с пометками, что удобно при отладке.
- mem.Dispose();
- }
Решение задачи: «Быстрая эмуляция нажатия клавиш в боте для браузерки»
textual
Листинг программы
- BitmapData bmpData = mem.LockBits(new Rectangle(0, 0, mem.Width, mem.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- byte[] bitmapBuffer = new byte[bmpData.Stride * bmpData.Height];
- Marshal.Copy(bmpData.Scan0, bitmapBuffer, 0, bitmapBuffer.Length);
- for (int j = 0; j < (int)ypos; j++)
- {
- int strideY = bmpData.Stride * j;
- for (int i = 0; i < (int)xpos; i++)
- {
- int index = strideY + i * byteLen;
- RGBcolor x = new RGBcolor();
- x.B = bitmapBuffer[index + 0];
- x.G = bitmapBuffer[index + 1];
- x.R = bitmapBuffer[index + 2];
- if (x.R == mylife.R && x.G == mylife.G && x.B == mylife.B)
- {
- Coords coord;
- coord.X = i;
- coord.Y = j;
- if (lifeminx > i) { lifeminx = i; }
- if (lifemaxx < i) { lifemaxx = i; }
- if (lifeminy > j) { lifeminy = j; }
- if (lifemaxy < j) { lifemaxy = j; }
- mylifesector.Add(coord);
- mls++;
- }
- if ((Math.Abs(x.R - enemyname.R) < 20) && (Math.Abs(x.G - enemyname.G) < 30) && (Math.Abs(x.B - enemyname.B) < 20))
- {
- Coords coord;
- coord.X = i;
- coord.Y = j;
- enemynamesector.Add(coord);
- ens++;
- }
- if ((Math.Abs(x.R - colorpuli.R) < 20) && (Math.Abs(x.G - colorpuli.G) < 25) && (Math.Abs(x.B - colorpuli.B) < 15))
- {
- Coords coord;
- coord.X = i;
- coord.Y = j;
- colorpulisector.Add(coord);
- cps++;
- }
- }
- }
- mem.UnlockBits(bmpData);
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д