В результате недостатка знаний в программировании, ни как не могу осуществить свою задумку. В интернете тоже ни чего подобного найти не получается.
В общем, нужно два макроса для Excel, управляющих мышкой: Первый макрос при запуске ждет трех кликов левой кнопкой мыши. После каждого клика записывает координаты указателя мышки в таблицу, например в ячейки a1-b1, a2-b2, a3-b3. Координаты относительно экрана, т.е. «снаружи» Excel`я. Там будут открыты окна других программ. Второй макрос проверяет три условия. При выполнении первого условия кликает мышью по координатам из ячеек a1-b1 (т.е. по кнопке в другой программе) и т.д.
p.s. Если, конечно, это вообще возможно средствами VBA
Здравствуйте, уважаемые!
В результате недостатка знаний в программировании, ни как не могу осуществить свою задумку. В интернете тоже ни чего подобного найти не получается.
В общем, нужно два макроса для Excel, управляющих мышкой: Первый макрос при запуске ждет трех кликов левой кнопкой мыши. После каждого клика записывает координаты указателя мышки в таблицу, например в ячейки a1-b1, a2-b2, a3-b3. Координаты относительно экрана, т.е. «снаружи» Excel`я. Там будут открыты окна других программ. Второй макрос проверяет три условия. При выполнении первого условия кликает мышью по координатам из ячеек a1-b1 (т.е. по кнопке в другой программе) и т.д.
p.s. Если, конечно, это вообще возможно средствами VBAFenror
AutoIt или еще что-то, но только не vba)) Однако, если на работе не дозволено запускать сторонние приложения--> [vba]
Код
Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long Private Type POINTAPI x As Long y As Long End Type Sub position() Dim vb_Stop As Boolean Dim z As POINTAPI vb_Stop = True i = 0 Do If GetAsyncKeyState(vbKeyLButton) Then If i > 0 Then GetCursorPos z: Cells(i, 1) = z.x: Cells(i, 2) = z.y: Sleep 70 i = i + 1 If i > 3 Then vb_Stop = False End If Sleep 30 DoEvents Loop While vb_Stop End Sub
[/vba] [vba]
Код
Private Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal dwData As Long, ByVal dwExtraInfo As Long) Private Const MOUSEEVENTF_LEFTDOWN = &H2 Private Const MOUSEEVENTF_LEFTUP = &H4 Private Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Public Sub MouseClick(x, y) Call SetCursorPos(x, y) mouse_event MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 End Sub Sub Click() x = Cells(1, 1) y = Cells(1, 2) Call MouseClick(x, y) End Sub
[/vba]
AutoIt или еще что-то, но только не vba)) Однако, если на работе не дозволено запускать сторонние приложения--> [vba]
Код
Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long Private Type POINTAPI x As Long y As Long End Type Sub position() Dim vb_Stop As Boolean Dim z As POINTAPI vb_Stop = True i = 0 Do If GetAsyncKeyState(vbKeyLButton) Then If i > 0 Then GetCursorPos z: Cells(i, 1) = z.x: Cells(i, 2) = z.y: Sleep 70 i = i + 1 If i > 3 Then vb_Stop = False End If Sleep 30 DoEvents Loop While vb_Stop End Sub
[/vba] [vba]
Код
Private Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal dwData As Long, ByVal dwExtraInfo As Long) Private Const MOUSEEVENTF_LEFTDOWN = &H2 Private Const MOUSEEVENTF_LEFTUP = &H4 Private Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Public Sub MouseClick(x, y) Call SetCursorPos(x, y) mouse_event MOUSEEVENTF_LEFTDOWN Or MOUSEEVENTF_LEFTUP, 0, 0, 0, 0 End Sub Sub Click() x = Cells(1, 1) y = Cells(1, 2) Call MouseClick(x, y) End Sub
по поводу первого макрос, так имхо надежнее будет: [vba]
Код
Private Type POINTAPI x As Long y As Long End Type Private Declare Function GetCursorPos Lib "user32.dll" (lpPoint As POINTAPI) As Long Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Sub clickpos() Dim i%, curpos As POINTAPI Do If GetAsyncKeyState(1) And &H8000 Then GetCursorPos curpos [A1].Offset(i) = curpos.x [A1].Offset(i, 1) = curpos.y i = i + 1 Do DoEvents Loop While GetAsyncKeyState(1) And &H8000 End If DoEvents Loop Until i = 3 End Sub
[/vba]
по поводу первого макрос, так имхо надежнее будет: [vba]
Код
Private Type POINTAPI x As Long y As Long End Type Private Declare Function GetCursorPos Lib "user32.dll" (lpPoint As POINTAPI) As Long Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Sub clickpos() Dim i%, curpos As POINTAPI Do If GetAsyncKeyState(1) And &H8000 Then GetCursorPos curpos [A1].Offset(i) = curpos.x [A1].Offset(i, 1) = curpos.y i = i + 1 Do DoEvents Loop While GetAsyncKeyState(1) And &H8000 End If DoEvents Loop Until i = 3 End Sub
и думается мне, что все-таки лучше кликать не по координатам, а по самой кнопке, отправляя сообщения в окно по hwnd. что-то типа такого: [vba]
Код
Private Declare Function GetDesktopWindow Lib "user32.dll" () As Long Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long Sub sss() Dim h As Long h = FindWindowEx(GetDesktopWindow, 0, "Button", "Start") If h <> 0 Then SendMessage h, &HF5, 0, 0 SendMessage h, &H202, 0, 0 End If End Sub
[/vba]
и думается мне, что все-таки лучше кликать не по координатам, а по самой кнопке, отправляя сообщения в окно по hwnd. что-то типа такого: [vba]
Код
Private Declare Function GetDesktopWindow Lib "user32.dll" () As Long Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long Sub sss() Dim h As Long h = FindWindowEx(GetDesktopWindow, 0, "Button", "Start") If h <> 0 Then SendMessage h, &HF5, 0, 0 SendMessage h, &H202, 0, 0 End If End Sub
Здравствуйте, уважаемые! Есть еще вопрос в продолжение темы. Задача та же, только вместо клика в заданных координатах, нужно просто подвести туда курсор мыши. Заранее благодарю.
Здравствуйте, уважаемые! Есть еще вопрос в продолжение темы. Задача та же, только вместо клика в заданных координатах, нужно просто подвести туда курсор мыши. Заранее благодарю.Fenror
Private Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long Sub Z() x = Cells(1, 1) y = Cells(1, 2) Call SetCursorPos(x, y) End Sub
[/vba]
[vba]
Код
Private Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long Sub Z() x = Cells(1, 1) y = Cells(1, 2) Call SetCursorPos(x, y) End Sub
по поводу первого макрос, так имхо надежнее будет:
Не очень хорошо разбираюсь, но хочу. Подскажи, чем твоё решение в 5-м посте надёжнее предложенного WeRiX в 3-м?
Как я вижу, WeRiX применил стандартный подход из Au3, когда события отслеживаются в цикле "Do" до наступления конкретных условий. И, перед новым витком - Sleep 30, бездействие на 30 миллисекунд. Я помню, что в Au3 данный подход снижает нагрузку на процессор, уменьшая количество обращений к нему в секунду. А у тебя цикл идёт сплошняком, вроде как без "передышек".
по поводу первого макрос, так имхо надежнее будет:
Не очень хорошо разбираюсь, но хочу. Подскажи, чем твоё решение в 5-м посте надёжнее предложенного WeRiX в 3-м?
Как я вижу, WeRiX применил стандартный подход из Au3, когда события отслеживаются в цикле "Do" до наступления конкретных условий. И, перед новым витком - Sleep 30, бездействие на 30 миллисекунд. Я помню, что в Au3 данный подход снижает нагрузку на процессор, уменьшая количество обращений к нему в секунду. А у тебя цикл идёт сплошняком, вроде как без "передышек".Rioran
Роман, Москва, voronov_rv@mail.ru Яндекс-Деньги: 41001312674279
Rioran, имхо, sleep сама по себе при малых величинах будет вносить задержки, так что принципиальной разницы, будет ли "малый слип" или "проверка на каждом фрейме" - практически нет. Ну и в примере krosav4ig есть ещё и ожидание "отщёлкивания" кнопки...
Rioran, имхо, sleep сама по себе при малых величинах будет вносить задержки, так что принципиальной разницы, будет ли "малый слип" или "проверка на каждом фрейме" - практически нет. Ну и в примере krosav4ig есть ещё и ожидание "отщёлкивания" кнопки...AndreTM
Rioran, привет. По поводу отсутствия sleep я, конечно, погорячился, ибо даже задержка в 1 мс в этом коде сводит загрузку цп (процессом excel) чуть ли не к 0, и sleep не помешает в обоих циклах. А тут
я имел в виду вложенный цикл с ожиданием отжатия кнопки.
Rioran, привет. По поводу отсутствия sleep я, конечно, погорячился, ибо даже задержка в 1 мс в этом коде сводит загрузку цп (процессом excel) чуть ли не к 0, и sleep не помешает в обоих циклах. А тут
AndreTM, идея в том, что цикл "Do" в VBА всегда крутится на максимально возможной для текущего аппарата скорости. И в 12-м посте krosav4ig подтверждает мои опасения о загрузке процессора. А задержку от одной проверки, имхо, надо бы ещё как-то отследить. Вряд ли её влияние существенно.
krosav4ig, спасибо, любопытно. А расскажи ещё по константе, как ты её используешь? Я нашёл в Win32API справочнике:
[/vba] Но что это за "абсолютное действие" и как ты его применяешь? Что за аргумент внутри функции GetAsyncKeyState, единица?
AndreTM, идея в том, что цикл "Do" в VBА всегда крутится на максимально возможной для текущего аппарата скорости. И в 12-м посте krosav4ig подтверждает мои опасения о загрузке процессора. А задержку от одной проверки, имхо, надо бы ещё как-то отследить. Вряд ли её влияние существенно.
krosav4ig, спасибо, любопытно. А расскажи ещё по константе, как ты её используешь? Я нашёл в Win32API справочнике:
Rioran, да, согласен, что sleep имеет смысл использовать. Расслабился я тут со скриптовыми языками...
Всё остальное - в материалах по GetAsyncKeyState() хорошо расписано. Функция в качестве параметра может получать один из 256 кодов "виртуальных клавиш" для проверки их состояния (MSDN). При этом физические кнопки мышки там тоже присутствуют, и 1 = VK_LBUTTON = левая клавиша мышки (независимо от системных настроек). Возвращаемое значение - 16-битный набор флагов состояния, при этом "нажата в данный момент" устанавливается в старшем бите, а "была нажата после предыдущего вызова функции" - в младшем. Поскольку среда многозадачна, на "была нажата" ориентироваться нельзя (вызвать функцию за этот промежуток могло и другое приложение), поэтому приходится ориентироваться именно на конкретное текущее состояние в момент конкретного данного вызова, то есть на состояние старшего бита. Поэтому &H8000 = 1000 0000 0000 0000 = маска для вырезания старшего бита.
Rioran, да, согласен, что sleep имеет смысл использовать. Расслабился я тут со скриптовыми языками...
Всё остальное - в материалах по GetAsyncKeyState() хорошо расписано. Функция в качестве параметра может получать один из 256 кодов "виртуальных клавиш" для проверки их состояния (MSDN). При этом физические кнопки мышки там тоже присутствуют, и 1 = VK_LBUTTON = левая клавиша мышки (независимо от системных настроек). Возвращаемое значение - 16-битный набор флагов состояния, при этом "нажата в данный момент" устанавливается в старшем бите, а "была нажата после предыдущего вызова функции" - в младшем. Поскольку среда многозадачна, на "была нажата" ориентироваться нельзя (вызвать функцию за этот промежуток могло и другое приложение), поэтому приходится ориентироваться именно на конкретное текущее состояние в момент конкретного данного вызова, то есть на состояние старшего бита. Поэтому &H8000 = 1000 0000 0000 0000 = маска для вырезания старшего бита.AndreTM
это все потому, что я страшный лентяй и не люблю объявлять константы, если они используются в коде один раз И все, что я могу добавить к исчерпывающему ответу AndreTM, это то, что если бы все-таки можно было 100% ориентироваться на младший бит, то можно было бы избавиться от вложенного цикла если отслеживать "псевдо-отжатие" [vba]
Код
Private Type POINTAPI x As Long y As Long End Type Private Declare Function GetCursorPos Lib "user32.dll" (lpPoint As POINTAPI) As Long Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Const KEY_PRESSED = &H8000 Private Const KEY_RELEASED = &H1 Private Const VK_LButton = &H1
Sub clickpos() Dim i%, curpos As POINTAPI GetAsyncKeyState VK_LButton Do If (GetAsyncKeyState(VK_LButton) And KEY_RELEASED) Then GetCursorPos curpos [A1].Offset(i) = curpos.x [A1].Offset(i, 1) = curpos.y i = i + 1 End If Sleep 30 DoEvents Loop Until i = 3 End Sub
это все потому, что я страшный лентяй и не люблю объявлять константы, если они используются в коде один раз И все, что я могу добавить к исчерпывающему ответу AndreTM, это то, что если бы все-таки можно было 100% ориентироваться на младший бит, то можно было бы избавиться от вложенного цикла если отслеживать "псевдо-отжатие" [vba]
Код
Private Type POINTAPI x As Long y As Long End Type Private Declare Function GetCursorPos Lib "user32.dll" (lpPoint As POINTAPI) As Long Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) Private Const KEY_PRESSED = &H8000 Private Const KEY_RELEASED = &H1 Private Const VK_LButton = &H1
Sub clickpos() Dim i%, curpos As POINTAPI GetAsyncKeyState VK_LButton Do If (GetAsyncKeyState(VK_LButton) And KEY_RELEASED) Then GetCursorPos curpos [A1].Offset(i) = curpos.x [A1].Offset(i, 1) = curpos.y i = i + 1 End If Sleep 30 DoEvents Loop Until i = 3 End Sub