Не срабатывал ControlClick в игру, на которую писал бота. При поиске решений наткнулся на эту старую тему и исходя из здесь написанного разобрался в ситуации, хочу этим поделится и хочу еще кое-что уточнить.
В MSDN нашел описание функций PostMessage и SendMessage. Они обе отправляют сообщение по указанному дескриптору окна. Разница в том, что PostMessage помещает сообщение в очередь и сразу возвращается, а SendMessage отправляет сообщение и ждет, пока целевое окно это сообщение обработает. Как вариант сообщением может быть команда о нажатии кнопки мыши или перемещении.
В либе WinAPI.au3 есть _WinAPI_PostMessage, которая работает в фоновых окнах:
; #FUNCTION# ====================================================================================================================
; Author ........: Paul Campbell (PaulIA)
; Modified.......: jpm
; ===============================================================================================================================
Func _WinAPI_PostMessage($hWnd, $iMsg, $wParam, $lParam)
Local $aResult = DllCall("user32.dll", "bool", "PostMessage", "hwnd", $hWnd, "uint", $iMsg, "wparam", $wParam, "lparam", $lParam)
If @error Then Return SetError(@error, @extended, False)
Return $aResult[0]
EndFunc ;==>_WinAPI_PostMessage
Теперь посмотрим на UDF MouseClickPlus. Как уже написал Yashied, там лишние WinGetHandle, настройка привязки координат мыши и надо понимать какой именно Handle нам нужен: окна или контрола. Если не ошибаюсь по памяти, то и объявление локальных переменных типа Local $LBDown = 0x0201 там лишнее, они уже есть в WindowsConstants.au3. Но главное что есть в этой MouseClickPlus - это DllCall, который из user32.dll вызывает функцию SendMessage.
Поэтому у меня возникло мнение, что эта MouseClickPlus просто ниочем, _WinAPI_PostMessage делает ту же работу, только сразу возвращается к программе после вызова. А если в вызове ее dll поменять PostMessage на SendMessage, то наверняка будет делать абсолютно то же самое.
В другой теме видел вопрос о SendInput для эмуляции нажатия мышки. Из того что прочитал:
SendInput симулирует события нажатия мышки/клавиатуры на более низком уровне. Если воспользоваться функциями GetKeyState или GetAsyncKeyState, то нажатие через SendInput должно отобразится как и реальное нажатие пользователя. Для сравнения фейково нажатая кнопка через SendMessage там не отображается. От реального нажатия SendInput отличается тем, что не выставляет какого-то флага. Также
SendInput как и реальная клавиатура и мышь
может работать только с активным окном.
Теперь к возникшим вопросам.
1) Нашел в AutoIt функцию _SendMessage:
; #FUNCTION# ====================================================================================================================
; Author ........: Valik
; Modified.......: Gary Frost (GaryFrost) aka gafrost
; ===============================================================================================================================
Func _SendMessage($hWnd, $iMsg, $wParam = 0, $lParam = 0, $iReturn = 0, $wParamType = "wparam", $lParamType = "lparam", $sReturnType = "lresult")
Local $aResult = DllCall("user32.dll", $sReturnType, "SendMessageW", "hwnd", $hWnd, "uint", $iMsg, $wParamType, $wParam, $lParamType, $lParam)
If @error Then Return SetError(@error, @extended, "")
If $iReturn >= 0 And $iReturn <= 4 Then Return $aResult[$iReturn]
Return $aResult
EndFunc ;==>_SendMessage
У меня она работает только в активном окне почему-то. Но в ней используется не SendMessage, а SendMessageW. В MSDN пишет, что "Unicode and ANSI names - SendMessageW (Unicode) and SendMessageA (ANSI)". Пожалуйста, тыкните где можно почитать что это или обьясните.
2) Второй вопрос. В нескольких примерах перед кликом мышкой видел:
_WinAPI_PostMessage($hWnd, $WM_SETCURSOR, $hWnd, _WinAPI_MakeLong($HTCLIENT, $WM_LBUTTONDOWN))
или прямо в этой теме
DllCall('user32.dll', 'int', 'SendMessage', 'hwnd', $hWnd, 'int', 0x0200, 'int', 0, 'dword', _WinAPI_MakeLong($X, $Y)) ;MOUSEMOVE
Я понимаю зачем перемещать курсор при реализации например mousedrag. Но зачем его перемещать перед обычным кликом в фоновом окне? Вроде и без этого работает. Может это делается для большей схожести с работой человека, типа маскировка от антикликеров?))
3) Насколько я понял, ControlClick это реализация функции из 2-х команд, причем между ними нет паузы ($Sleep = 0):
Func MouseLeftClick3($hWnd, $X, $Y, $Sleep)
_WinAPI_PostMessage($hWnd, $WM_LBUTTONDOWN, 0, _WinAPI_MakeLong($X, $Y))
Sleep($Sleep)
_WinAPI_PostMessage($hWnd, $WM_LBUTTONUP, 0, _WinAPI_MakeLong($X, $Y))
EndFunc
потому что в таком виде в этой игре у меня не кликает, а кликает только если дать между командами слип хоть 1 мс. Но как посмотреть реализацию команд ControlClick, MouseClick и т.д., которых я не нашел в папке AutoIT3\Include\ и они не включаются в проект через #include?