Быстрая эмуляция нажатия клавиш в боте для браузерки - 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);
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д