Что нового

[Diablo II] Отправка нажатия клавиши в активное окно, не через Send

ava

нуб
Сообщения
10
Репутация
0
Здравствуйте, форумчане.
Прошу прощения, за вопрос по набившей оскомину теме, однако Поиск не дает понимания.

Предисловие: я решил вспомнить старые времена и поиграть в Diablo II. Однако классика или LoD, уже не интересны, решил попробовать мод. Нашел для себя подходящий, даже с сервером живым. Однако пока играю в Single.

Завязка: в моде очень много крафта. Членом сообщества много версий назад была написана утилита, с функцией кликера и OCR. Кликер, уже фактически не работает, однако OCR - изумительный, скорость работы особенно радует. Я решил написать свой кликер, который использует эту утилиту, для распознавания текста.
EDIT: В связи с вопросами в личку, а также убедившись, что это скорее согласуется с правилами раздела, чем противоречит им, дополняю пост.
Ссылка на игру: http://us.blizzard.com/en-us/games/d2/
Что важнее ссылка на мод: http://www.medianxl.com/
Ссылка на утилиту: http://grig.vlexofree.com/mxl/d2clicker.html

Суть: Утилита висит как неактивное окно, можно даже свернуть. У неё есть хоткеи. По хоткею "\" (BackSlash), утилита сканирует изображение, и выдирает текст (свойства предмета), а дальше сравнивает с тем, что написано в ее конфиге и выдает прямо в окне Диабло строчку, совпало или нет. Мне остается только проверить эту строчку по одному пикселю(черный или белый). К сожалению, эта программа не ловит нажатия клавиши большинством методов. На данный момент у меня работает только Send. А от него хотелось бы уйти, в надежде на то, что в дальнейшем, смогу сделать кликер с возможностью минимизации.

Для теста, я максимально упростил функцию, вот что получилось:
Код:
Global $fActive = False
Global $hWndDi2

Opt("WinTitleMatchMode", 2)		
Opt("SendKeyDownDelay",5) 		;or 0 ;or 200 ;or even 2000

HotKeySet("{NUMPAD7}", "_Start")                             ;bind start/break/finish buttons for script
HotKeySet("{NUMPAD8}", "_Break")
HotKeySet("{NUMPAD5}", "_Terminate")

Func _Start()
	$hWndDi2 = WinGetHandle("[CLASS:Diablo II]")
	;$hWndDi2 = WinGetHandle("Diablo II")
	;MsgBox(0,"",$hWndDi2)
;~ 	DllOpen("WinIo.dll") 
;~ 	DllCall("WinIo.dll", "bool", "InitializeWinIo")
	$fActive = True
EndFunc

Func _Break()
;~ 	DllCall("WinIo.dll", "none", "ShutdownWinIo")
;~ 	DllClose("WinIo.dll")
	$fActive = False
EndFunc

Func _Terminate() 
        _Break()
	Exit 0
EndFunc   

While 1
	If $fActive Then
		;ControlSend("Diablo II","","","{|}")
		;ControlSend($hWndDi2,"","","{|}")
		;ControlSend("Diablo II","",$hWndDi2,"{|}")
		;DllCall("user32.dll", "long", "PostMessage", "HWND", $hWndDi2, "int", 0x0100, "int", 0xDC,"int", 0)
		If WinActive($hwndDi2) Then
			Send("{\}")
		EndIf
;		wSend("\")
		Sleep(500)
	Else
		Sleep(100)
	EndIf
WEnd


;got this from http://autoit-script.ru/index.php/topic,14307.msg91374.html#msg91374
;should check more here http://www.autoitscript.com/forum/topic/121084-io-port-functions-x64-parallel-port-io-keyboard-etc-restore-pc-speaker-beep/
Func wSend($Param1, $Param2 = 300, $Param3="no param")
local $wkey[2]
$wkey[0] = "0x2B"		;got table of codes here: http://stanislavs.org/helppc/make_codes.html
$wkey[1] = "0xAB"

DllCall("WinIo.dll", "bool", "SetPortVal", "word", 0x64, "dword", 0xD2,  "byte", 1) ; cmd byte
sleep(30)
DllCall("WinIo.dll", "bool", "SetPortVal", "word", 0x60, "dword", $wkey[0] , "byte", 1) ; +key
Sleep($Param2)
DllCall("WinIo.dll", "bool", "SetPortVal", "word", 0x64, "dword", 0xD2,  "byte", 1) ; cmd byte
sleep(30)
DllCall("WinIo.dll", "bool", "SetPortVal", "word", 0x60, "dword", $wkey[1], "byte", 1) ; -key
Sleep(Random(30,40))

EndFunc


Учитывая, что AutoIt я использую впервые, думаю вы убедились, что поиск был изучен -)
Все что закоментировано - испробовано. И все не работает. То есть сама Диабла нажатие воспринимает отлично, и в чате видно, и если хоткеи назначать все работает, вплоть до ESC. А вот утилита игнорирует все кроме Send()
Вариант с IO-port я пока, если честно только попробовал, он не сработал вообще никак. Может быть чего-то не доделал, но по-крайней мере не ругается.

Я бы, может даже пропустил это пока мимо головы, но у меня такое ощущение, что в процессе написания самого бота, был момент, когда я как раз тестировал проверку функции считывания, и она работала на ControlSend(), а потом дописав все остальное и причесав, я это испортил. Писал на дропбоксе, так что отчасти даже были сохранены предыдущие версии, в том числе и те, где как раз тестировал, но они тоже не сработали. Может быть это и глюк.

В любом случае, у меня вопрос к знатокам тонкостей, может у вас есть какие-то идеи?

Заключение: зависит целиком от вас :IL_AutoIt_1:
 

Belfigor

Модератор
Локальный модератор
Сообщения
3,608
Репутация
941
Re: [Мышь, клавиатура] Отправка нажатия клавиши в активное окно, не через Send

Предупреждение За нарушение правил форума (пункт Б.5):
Имя темы должно нести смысловую нагрузку (отражать суть вопроса/проблемы)
Правильно сформулированное название темы привлекает больше внимания, и шансы получить конкретный ответ увеличиваются.


Данные правила могут пополняться локальными правилами раздела.
Как правильно называть темы

"[Мышь, клавиатура] Отправка нажатия клавиши в активное окно, не через Send" - это неприемлемое название темы, переименуйте тему иначе она будет закрыта, а вам возможно будет выдан бан на несколько дней.

С уважением, ваш Модератор.
 
Автор
A

ava

нуб
Сообщения
10
Репутация
0
Странно, вроде бы специально постарался отразить смысловую нагрузку, а также избежать использования слов, упомянутых в http://autoit-script.ru/index.php/topic,1734.0.html
Быть может вы поможете мне, если считаете мой вариант неудачным?

P.S. На всякий случай заменил [Мышь, клавиатура] на [Diablo II], может вы это имели в виду.
 

_ToBe_

Осваивающий
Сообщения
142
Репутация
35
Ну, если MouseClick и ControlSend не справляются, могу посоветовать лишь это:


Код:
Func _MClickPlus($Window, $Button = "left", $X = "", $Y = "", $Clicks = 1)
	Local $MK_LBUTTON	   =  0x0001
	Local $WM_LBUTTONDOWN   =  0x0201
	Local $WM_LBUTTONUP	 =  0x0202

	Local $MK_RBUTTON	   =  0x0002
	Local $WM_RBUTTONDOWN   =  0x0204
	Local $WM_RBUTTONUP	 =  0x0205

	Local $WM_MOUSEMOVE	 =  0x0200

	Local $i				= 0

	Select
	Case $Button = "left"
	   $Button	 =  $MK_LBUTTON
	   $ButtonDown =  $WM_LBUTTONDOWN
	   $ButtonUp   =  $WM_LBUTTONUP
	Case $Button = "right"
	   $Button	 =  $MK_RBUTTON
	   $ButtonDown =  $WM_RBUTTONDOWN
	   $ButtonUp   =  $WM_RBUTTONUP
	EndSelect

	If $X = "" OR $Y = "" Then
	   $MouseCoord = MouseGetPos()
	   $X = $MouseCoord[0]
	   $Y = $MouseCoord[1]
	EndIf

	For $i = 1 to $Clicks
	   DllCall("user32.dll", "int", "SendMessage", _
		  "hwnd",  WinGetHandle( $Window ), _
		  "int",   $WM_MOUSEMOVE, _
		  "int",   0, _
		  "long",  _MakeLong($X, $Y))

	   DllCall("user32.dll", "int", "SendMessage", _
		  "hwnd",  WinGetHandle( $Window ), _
		  "int",   $ButtonDown, _
		  "int",   $Button, _
		  "long",  _MakeLong($X, $Y))

	   DllCall("user32.dll", "int", "SendMessage", _
		  "hwnd",  WinGetHandle( $Window ), _
		  "int",   $ButtonUp, _
		  "int",   $Button, _
		  "long",  _MakeLong($X, $Y))
	Next
 EndFunc

 Func _MakeLong($LoWord,$HiWord)
	Return BitOR($HiWord * 0x10000, BitAND($LoWord, 0xFFFF))
EndFunc
 
Автор
A

ava

нуб
Сообщения
10
Репутация
0
_ToBe_, спасибо за ответ, но мне кажется вы не очень внимательно прочитали код.
Насколько я понимаю, то что вы предлагаете использовать уже было мною опробовано:
Код:
;DllCall("user32.dll", "long", "PostMessage", "HWND", $hWndDi2, "int", 0x0100, "int", 0xDC,"int", 0)


Это работает, но только для целевого окна, утилита не видит этих нажатий. А для целевого окна (Диабло 2), у меня вообще, что угодно работает.

Мне кажется тут вопрос именно в механике разных способов, я видел что похожие моменты уже были, когда сторонней утилитой выступал геймгард какой-нибудь. Возможно, понимание именно отличия реализации команд Send() и ControlSend() смогло бы мне помочь.

З.Ы. Бельфигор, не могли бы вы прокомментировать, достаточны ли были внесенные мной в название темы изменения, чтобы не нарушать правила.
З.З.Ы. Может быть этот вопрос вообще лучше было бы переместить в раздел для новичков? Просто, с одной стороны, это вроде как имеет непосредственное отношение к ботам для игр. С другой стороны, уровень моих знаний скорее для раздела новичков... =)
 

bugaj

Знающий
Сообщения
140
Репутация
11
"Послать в неактивное окно" можно только PostMessage, который по идее использует ту же Апи функцию, что и Send в итоге. Может защита запрещает в игру слать сообщения от мышки. Полагаю других способов послать что либо в неактивное окно нет.
 
Автор
A

ava

нуб
Сообщения
10
Репутация
0
bugaj, спасибо за ответ.
Вынужден повториться, в саму игру нажатие клавиши (речь пока не о мышке), прекрасно доходит разными способами. В том числе и PostMessage, библиотеки user32.dll, работает. Но стороннее приложение, запущенное в фоновом режиме, которое, каким-то образом, читает Input игры не реагирует ни на что, кроме Send. И что еще важно, я пока работаю с активным окном.

Есть подозрение, что оно работает с памятью процесса игры, так как оно вполне определенно подхватывает конкретное окно игры. При этом, если запускать игру через модменеджер, то надо пользоваться отдельным exe-шником, для этого предназначенным. Может быть это даст какую-то подсказку.
 

nowost

Знающий
Сообщения
178
Репутация
17
т.е другими словами нужен бот для бота ? :shok:
 
Автор
A

ava

нуб
Сообщения
10
Репутация
0
почти верно, бота, использующего сторонюю утилиту в качестве OCR
 

bugaj

Знающий
Сообщения
140
Репутация
11
ничего не понимаю :stars:

$hWndDi2 = WinGetHandle("[CLASS:Diablo II]") - это хендл окна диабло


If WinActive($hwndDi2) Then - делается активным окно диабло
Send("{\}") - хотя вообще это глобальный посыл, т.е. не только в окно диаблы.

это видимо "Посыл" в окно диабло, я не вижу в этом скрипте ничего, что пыталось бы отослать сообщение куда либо еще. Очевидно, если нужно отправлять сообщения другому окну, то и нужно тогда хендл получать другого окна.

Любая функция по работе с клавой и мышью использует одну и туже функцию WinAPI, т.е. фактически везде программная эмуляция клавы и мыши делается одной и той же функцией, в какую бы обертку это не было бы завернуто.
 

nowost

Знающий
Сообщения
178
Репутация
17
глянул это кликекр в дизасме, он юзает user32.dll и ставит хуки по всей видимости на дьяблу 2, и опять же d2hotkeyshook.dll в папке с кликером какбы намекает.
 

bugaj

Знающий
Сообщения
140
Репутация
11
месье знает толк в извращениях :smile: в скрипте стоит защита от программной эмуляции нажатий Хоткеев наверное :D

вот http://autoit-script.ru/index.php/topic,14307.msg90310.html#msg90310 топик по эмуляции "другим способом", там про мышь, но вроде про клаву там в dll тоже есть.
 
Автор
A

ava

нуб
Сообщения
10
Репутация
0
Спасибо за ответы.
Бугай, там просто в комментариях, варианты которые я пробовал, чтобы было видно сразу, что уже делал, а что нет. И без комментариев - Send(), как работающий.

Кстати,
Send("{\}") - хотя вообще это глобальный посыл, т.е. не только в окно диаблы.
вот если это факт, то видимо именно с этим и связано то, что на утилиту работает только он. А есть какой-то более подробный источник?

А ссылочку которую вы мне дали, я уже пробовал, она как раз единственная пока вообще никак не заработала. Хотя драйвера установились, ошибок нет. Думаю просто недоразобрался еще, может надо какие-то дополнительные телодвижения совершить, но в любом случае схоронил.

новость, поправьте, если не правильно читаю ник, если я правильно понял, вы подтвердили мое предположение по поводу мониторинга памяти программы. Так?
 

lirikmel

Продвинутый
Сообщения
226
Репутация
84
Если утилита ждет слеш почему бы неотправить именно ей эту клавишу а не окну дьяблы ?
 

bugaj

Знающий
Сообщения
140
Репутация
11
гуглить mouseEvent или keybEvent(вот тут я не уверен с названием), SendMessage, Hook WinApi. - как это работает

я не думаю, что он лезет в диабло и там чего то хукает, потому что это содомия уже какая то, проще хукнуть Win Api функцию, пока она до диабло еще не дошла, но там есть свойство указывающее кому адресовано сообщение. Возможно хук завязан на очень конкретную Api функцию, и соответственно вариант с dll он тогда будет просто игнорировать. А при неактивном окне диабло, он все равно ловит Send???

В общем гадать тут можно долго, что конкретно делает ОЦР, причем мне совсем неясно нафига ставить Hook. у меня в программе стоит условие выходить по esc. Так она выходит даже когда я нажимаю esc в полноэкранном приложении, без всяких хуков.

можно заняться хакерством и поснифить эту утилиту, посмотреть что она там делает. Но в этом я не мастер.


Добавлено:
Сообщение автоматически объединено:

Если утилита ждет слеш почему бы неотправить именно ей эту клавишу а не окну дьяблы ?

есть опасения, что утилита не ждет чтобы ей что то прислали, она перехватывает нажатия клавиш, причем тут могут быть ньюансы. Т.е. может все подряд, может те которые идут в диабло, может.....
 
Автор
A

ava

нуб
Сообщения
10
Репутация
0
Спасибо за ответы.
Утилита после запуска повисате консолькой такого вида:
2013-11-13_220128.png
Думаю очевидны проблемы с Send непосредственно ей -)
 

_ToBe_

Осваивающий
Сообщения
142
Репутация
35
А напиши свою читалку текста из дьяблы ;D
 
Автор
A

ava

нуб
Сообщения
10
Репутация
0
_ToBe_, как ни странно, но я видимо это и сделаю. Не по необходимости, так как вариант с сендом, пусть даже и в активном окне, у меня отлично работает, и вполне неплохо крафтит, пока я не у компьютера. Но просто стало интересно, да и AutoIt понравился, а изучение языка, исходя из моей практики лучше всего происходит на выполнении конкретных задач.
 
Верх