1 (изменено: sapmortimer, 2017-05-14 18:42:21)

Тема: AHK | BF2: Выбор пункта контекстного меню в игре

Аве, друзья!
С AHK знаком достаточно давно, но с перемещениями мыши ранее не игрался, поэтому возникла одна проблема.
Суть: нужно, чтобы при нажатии на кнопку мыши (дополнительную - XButton1) нажималась правая кнопка мыши, курсор смещался чуть ниже и правее (пока не высчитал координаты) и нажималась левая кнопка мыши через некоторый промежуток времени.
Я создал нечто подобное:

CoordMode, Mouse, Window
XButton1::
  Send {Click, right}
  MouseMove, 2, 5, 20, R
  Sleep, 200
  Send {Click}
Return

Проблема в том, что нажатия мыши срабатывают через раз, а перемещение курсора происходит хаотично - каждый раз в новое место.
Пробовал заменять на "CoordMode, Mouse, Screen", а "Send {Click}" на "MouseClick" - толку немного.
Более наглядно можно посмотреть здесь:
https://youtu.be/PG3z6zvGpIk
Спасибо за внимание!

2

Re: AHK | BF2: Выбор пункта контекстного меню в игре

Пробовал заменять на "CoordMode, Mouse, Screen", а "Send {Click}" на "MouseClick"

Зачем? Смещение у вас все равно относительное - R, a Send {Click}, Click и MouseClick одно и тоже.
Я бы попробывал SendMode Play, уменьшение скорости перемещения курсора и BlockInput.

3

Re: AHK | BF2: Выбор пункта контекстного меню в игре

sapmortimer
Небольшой пример кода, думаю тебе поможет.

CoordMode, Mouse, Screen  ;|Window|Client]
  SetMouseDelay, 10
  MouseGetPos, xPos, yPos
  ; The first number is the X-coordinate and the second is the Y (relative to the screen).
  ;DllCall("SetCursorPos", int, 100, int, 400)
  xPos  := xPos + 5
  MouseMove, xPos,yPos,50
  ;Sleep 50
Return

Как я понял у тебя полноэкранное приложение/игра по этому лучше использовать CoordMode, Mouse, Screen , а не CoordMode, Mouse, Window, но из видио это не ясно...

"На каждое действие есть равная ему противодействующая критика." Постулат Харриссона
OS Windows 7 x64
AutoHotkey v1.1.32.00 - November 24, 2019
Click to Download

4

Re: AHK | BF2: Выбор пункта контекстного меню в игре

Indomito пишет:

Как я понял у тебя полноэкранное приложение/игра по этому лучше использовать CoordMode, Mouse, Screen , а не CoordMode, Mouse, Window, но из видио это не ясно...

Сейчас полечим видео. Выложил необработанное с дохлым звуком.
Новая ссылка: https://youtu.be/PG3z6zvGpIk

sapmortimer пишет:

Пробовал заменять на "CoordMode, Mouse, Screen"

Не помогло.

5

Re: AHK | BF2: Выбор пункта контекстного меню в игре

stealzy пишет:

Я бы попробывал SendMode Play, уменьшение скорости перемещения курсора и BlockInput.

Скорость крутил, но дело в том, что он берет исходную точку черте-знает-откуда и отталкивается уже от нее.
Наглядно вот здесь: https://youtu.be/PG3z6zvGpIk

6

Re: AHK | BF2: Выбор пункта контекстного меню в игре

Скорость крутил, по остальным двум пунктам что?
Такой код как работает:

XButton1::MouseMove 30, 30, 2, R

7 (изменено: sapmortimer, 2017-05-16 08:00:23)

Re: AHK | BF2: Выбор пункта контекстного меню в игре

stealzy, так же, как и на видео

8 (изменено: sapmortimer, 2017-05-14 21:01:57)

Re: AHK | BF2: Выбор пункта контекстного меню в игре

Протестировал ещё и заметил вот что: в экране загрузки курсор нормально выполняет команды, но в режиме игры (особенно заметно при открытой карте) курсор лихорадочно дергается в рандомное направление и пропускает нажатие клавиш ЛКМ и ПКМ.
Такое чувство, будто игра неадекватно воспринимает эмуляцию движения и нажатия клавиш мыши
UPD: в оконном режиме не лучше

9

Re: AHK | BF2: Выбор пункта контекстного меню в игре

Игра перехватывает мышиный ввод на низком уровне.
Берешь библиотеку LLMouse, вместо примера в верхней части вставляешь:

XButton1::LLMouse.Move(30, 30)

10 (изменено: sapmortimer, 2017-05-16 07:59:45)

Re: AHK | BF2: Выбор пункта контекстного меню в игре

stealzy, оч сложна, можно объяснить, как для дебила?
Мне ведь еще нужно задать нажатие на ПКМ, слип, движение мыши, слип, ЛКМ
Я так понял, должно получиться это:

+ открыть спойлер
; =========== Sample script ============================================================
#SingleInstance,Force

XButton1::
  MouseClick, right
  Sleep, 100
  LLMouse.Move(30, 30)
  Sleep, 200
  MouseClick
  Sleep, 100
  LLMouse.Move(-30, -30)
Return

; =======================================================================================
; LLMouse - A library to send Low Level Mouse input

; Note that many functions have time and rate parameters.
; These all work the same way:
; times	- How many times to send the requested action. Optional, default is 1
; rate	- The rate (in ms) to send the action at. Optional, default rate varies
; Note that if you use a value for rate of less than 10, special code will kick in.
; QPX is used for rates of <10ms as the AHK Sleep command does not support sleeps this short
; More CPU will be used in this mode.
class LLMouse {
	static MOUSEEVENTF_MOVE := 0x1
	static MOUSEEVENTF_WHEEL := 0x800
	
	; ======================= Functions for the user to call ============================
	; Move the mouse
	; All values are Signed Integers (Whole numbers, Positive or Negative)
	; x		- How much to move in the x axis. + is right, - is left
	; y		- How much to move in the y axis. + is down, - is up
	Move(x, y, times := 1, rate := 1){
		this._MouseEvent(times, rate, this.MOUSEEVENTF_MOVE, x, y)
	}
	
	; Move the wheel
	; dir	- Which direction to move the wheel. 1 is up, -1 is down
	Wheel(dir, times := 1, rate := 10){
		static WHEEL_DELTA := 120
		this._MouseEvent(times, rate, this.MOUSEEVENTF_WHEEL, , , dir * WHEEL_DELTA)
	}
	
	; ============ Internal functions not intended to be called by end-users ============
	_MouseEvent(times, rate, dwFlags := 0, dx := 0, dy := 0, dwData := 0){
		Loop % times {
			DllCall("mouse_event", uint, dwFlags, int, dx ,int, dy, uint, dwData, int, 0)
			if (A_Index != times){	; Do not delay after last send, or if rate is 0
				if (rate >= 10){
					Sleep % rate
				} else {
					this._Delay(rate * 0.001)
				}
			}
		}
	}
	
	_Delay( D=0.001 ) { ; High Resolution Delay ( High CPU Usage ) by SKAN | CD: 13/Jun/2009
		Static F ; www.autohotkey.com/forum/viewtopic.php?t=52083 | LM: 13/Jun/2009
		Critical
		F ? F : DllCall( "QueryPerformanceFrequency", Int64P,F )
		DllCall( "QueryPerformanceCounter", Int64P,pTick ), cTick := pTick
		While( ( (Tick:=(pTick-cTick)/F)) <D ) {
			DllCall( "QueryPerformanceCounter", Int64P,pTick )
			Sleep -1
		}
		Return Round( Tick,3 )
	}
}

Но нажатия клавиш все равно пропускаются (что логично).
Есть такая же low-level штука для нажатий клавиш мыши?

11 (изменено: Ядрён, 2017-05-15 00:23:24)

Re: AHK | BF2: Выбор пункта контекстного меню в игре

Доброго времени суток. Попробуйте так, sapmortimer.

x := 10

y := 30

XButton1::

DllCall("mouse_event", UInt, 0x0008, Int, 0, Int, 0, UInt, 0, Int, 0) ; нажать правую кнопку мыши
      
DllCall("mouse_event", UInt, 0x0010, Int, 0, Int, 0, UInt, 0, Int, 0) ; отпустить правую кнопку мыши

DllCall("mouse_event", uint, 1, int, x, int, y, uint, 0, int, 0) ; координаты по оси "x" "y" относительно курсора

DllCall("Sleep", UInt, 400) ; задержка

DllCall("mouse_event", UInt, 0x02, Int, 0, Int, 0, UInt, 0, Int, 0) ; нажать левую кнопку мыши
      
DllCall("mouse_event", UInt, 0x04, Int, 0, Int, 0, UInt, 0, Int, 0) ; отпустить левую кнопку мыши

Return
OS: Win11x64, AutoHotkey v1.1.25.01 (Unicode 64-bit).

12 (изменено: sapmortimer, 2017-05-15 13:42:28)

Re: AHK | BF2: Выбор пункта контекстного меню в игре

stealzy забыл уточнить: у меня Win 8.1, а SendInpit/Event так же реагирует через раз.

Применил старый метод с МТА:SA:

Send {click, down}
  Sleep, 20
  Send {click, up}

Работает безотказно, но есть существенный минус: скорость ниже.

UPD: Тут возник один казус: при вызове контекстного меню ближе к нижней границе карты, контекстное меню "поднимается" чуть выше курсора (при вызове меню, курсор встаёт не у верхнего левого угла, а ниже или вообще у нижнего угла) и скрипт промахивается.

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

+ открыть спойлер

Спасибо, возьму на вооружение

Ядрён пишет:

Доброго времени суток. Попробуйте так, sapmortimer.

x := 10

y := 30

XButton1::

DllCall("mouse_event", UInt, 0x0008, Int, 0, Int, 0, UInt, 0, Int, 0) ; нажать правую кнопку мыши
      
DllCall("mouse_event", UInt, 0x0010, Int, 0, Int, 0, UInt, 0, Int, 0) ; отпустить правую кнопку мыши

DllCall("mouse_event", uint, 1, int, x, int, y, uint, 0, int, 0) ; координаты по оси "x" "y" относительно курсора

DllCall("Sleep", UInt, 400) ; задержка

DllCall("mouse_event", UInt, 0x02, Int, 0, Int, 0, UInt, 0, Int, 0) ; нажать левую кнопку мыши
      
DllCall("mouse_event", UInt, 0x04, Int, 0, Int, 0, UInt, 0, Int, 0) ; отпустить левую кнопку мыши

Return

13 (изменено: sapmortimer, 2017-05-16 07:58:43)

Re: AHK | BF2: Выбор пункта контекстного меню в игре

stealzy, SendPlay не работает на платформах win8 и win8.1

sapmortimer пишет:

а SendInpit/Event так же реагирует через раз.

14 (изменено: stealzy, 2017-05-16 15:53:26)

Re: AHK | BF2: Выбор пункта контекстного меню в игре

Самого себя цитировать тоже не стоило.
Методом тыка находите граничное значение координаты у, при котором меню показывается сверху от курсора:

~RButton::
	MouseGetPos x, y
	ToolTip % y ; если не виден поверх игры, замените на msgbox
	Return

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

15

Re: AHK | BF2: Выбор пункта контекстного меню в игре

stealzy приношу извинения, что не отвечал, был на сутках и только сейчас еду домой.
Насколько я понял, Ваш код определяет положение курсора и выводит данные о нем в виде окна с текстом.
Этим скриптом я определяю нижний "порог", при котором курсор встаёт на нужный угол.
Далее, мне нужно будет сделать так, чтобы перенос курсора по оси Y изменялся при пересечении этого "порога" на некую переменную, которая зависит о того, насколько сильно курсор "зашел" за этот "порог".

Решение,конечно, отличное, но я никогда не работал с переменными в AHK (не осилил). Я всегда использовал только статичные значения.
Тем более, я так понял, что придётся использовать if, а им пользоваться я не умею