Практическое применение mouse_event

Все когда-то хоть один раз, да требуется. Так и у меня. О функции имитирующей нажатие кнопок мыши (клики) я собственно и не задумывался , пока какой-то один веселый парень не нафлудил на моем сайте бесплатных программ. В итоге нужно было удалить более 400 новостей различного вареза. Конечно если бы он выкладывал новости там где они должны быть, то я бы заметил. Но вот ведь хитрец! Он заливал их в каталог статей, а туда я захожу очень редко. Нет конечно этот варез был не активирован и вроде бы наплевать, но размер сайта все-таки ограничен... Судя по всему он это делал специально для таких нужд приспособленной программой для заливки новостей. Когда я начал чистить вручную , то понял что это будет довольно гиморно. Приходилось в админке кликать по удалению новости и потом потверждать. После 10-15 удалений новостей, я начал задумываться об автоматизации этой задачи. Поискал что-то готовое , но все какое-то навороченное, кучу времени надо на изучение. Решил сделать свою. В уме сразу ожила функция keybd_event для имитации нажатия клавиш. Раз есть для клавиш, значит должна быть и для мыши. Залез в интернет и тут же натолкнулся на функцию Mouse_Event. То что нужно!

Ее определение:

mouse_event(
    DWORD dwFlags,
    DWORD dx,
    DWORD dy,
    DWORD dwData,
    ULONG_PTR dwExtraInfo
)
  • dwFlags - Флаг(и), могут быть: 
    • MOUSEEVENTF_ABSOLUTE - устанавливает, что параметры  dx и dy содержат абсолютные координаты. Если флажок не установлен, то параметры dx и dy содержит относительные координаты.
    • MOUSEEVENTF_MOVE - устанавливает, что произошло перемещение.
    • MOUSEEVENTF_LEFTDOWN - устанавливает, что нажата левая кнопка.
    • MOUSEEVENTF_LEFTUP - устанавливает, что отпущена левая кнопка.
    • MOUSEEVENTF_RIGHTDOWN - устанавливает, что нажата правая кнопка.
    • MOUSEEVENTF_RIGHTUP - устанавливает, что отпущена правая кнопка.
    • MOUSEEVENTF_MIDDLEDOWN - устанавливает, что нажата средняя кнопка.
    • MOUSEEVENTF_MIDDLEUP - устанавливает, что отпущена средняя кнопка.
    • MOUSEEVENTF_WHEEL - Windows NT/2000/XP: устанавливает, что переместилось колесико, если мышь имеет колесико. Величина перемещения определяется в параметре dwData.
    • MOUSEEVENTF_XDOWN - Windows 2000/XP: устанавливает, что была нажата X-кнопка.
    • MOUSEEVENTF_XUP - Windows 2000/XP: устанавливает, что была отпущена X-кнопка.
  • dx,dy - кординаты мыши
  • dwData - величина перемещения колесика, один щелчок колесика содержит величину - 120.
  • dwExtraInfo - дополнительное значение, связанное с событием мыши, для получения следует вызвать функцию GetMessageExtraInfo.

Данная функция способна кликать и двигать мышью. Но если первое делается очень просто, то для определения координат для параметров функции, нужно заниматься преобразованием их в другую систему координат, что для моих задач было просто не нужно. Есть способы гораздо проще: функция SetCursorPos вполне сгодится для перемещения мыши. В итоге получалась такая схема в цикле:

  1. перемещаемся на нужную кнопку
  2. создаем имитацию нажатия на левую кнопку мыши
  3. ждем 200 мс
  4. создаем имитацию отпускания левой кнопки мыши
  5. перемещаемся на место где покажется окно с кнопкой потверждения
  6. ждем 2000 мс (все-таки появляется не сразу)
  7. повторяем пукнты 2,3,4

Для того, чтобы это смотрелось очевидным я написал похожий код:

#INCLUDE "windows.bi"

Dim msg As MSG
Dim As WNDCLASSEX wc
Dim As String NameClass="MyClass"
Dim As HINSTANCE Hinst=GetModuleHandle(0)

Sub cur(I As Any Ptr)
    
    For i As Integer = 1 To 5
        
        SetCursorPos(565,423) ' помещаем курсор на кнопку
        
        mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0) 'нажимаем
        Sleep(200) ' пауза между нажатиями
        mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0)' отпускаем
        
        SetCursorPos(660,555)' помещаем курсор на другую кнопку
        Sleep(2000) ' ждем пока появится окно потверждения
        
        mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0) 'нажимаем
        Sleep(200)' пауза между нажатиями
        mouse_event(MOUSEEVENTF_LEFTUP,0,0,0,0)' отпускаем
        
        Sleep(1000)     
        
    Next

End Sub

Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    
    Select Case msg
        Case WM_CREATE
            
            CreateWindowEx(0,"Button","OK",_
                WS_VISIBLE Or WS_CHILD,10,10,100,30,_
                hwnd,Cast(HMENU,1),0,0)     
                        
        Case WM_COMMAND
            
            If Loword(wParam) = 1 Then
                MessageBox(0,"","",0)
            Endif
            
        Case WM_DESTROY
            
            PostQuitMessage(0)
            
    End Select
    
    Return DefWindowProc(hwnd,msg,wparam,lparam)
    
End Function

With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_WINLOGO)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With

If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif

CreateWindowEx(0,NameClass,"",_
        WS_VISIBLE Or WS_OVERLAPPEDWINDOW,_
        GetSystemMetrics(SM_CXSCREEN)\2-150,_
        GetSystemMetrics(SM_CYSCREEN)\2-150,_
        300,300,0,0,Hinst,0)
        
Threadcreate(@cur)

While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend

Вот таким простым способом я легко удалил весь флуд с сайта, а заодно познакомился еще с одной великолепной API функцией.