AutoHotKey WinActive возвращает неправильное значение при изменении фокуса окна - PullRequest
0 голосов
/ 18 января 2020

В моем скрипте AutoHotKey я использую #IfWinActive, чтобы определить, находится ли окно Roblox в фокусе, а затем нажимать цифровую кнопку 1 при каждом щелчке левой кнопкой мыши, например:

#IfWinActive, Roblox
    LButton::
        MouseClick, Left
        SendInput, {1}
    return
#IfWinActive

Отлично работает, кроме случаев, когда я щелкаю из окна Roblox обратно в другое окно. Он все еще запускает этот код при первом щелчке, в результате чего он набирает число 1 в Блокноте (или в любом другом окне, на которое я переключаю фокус).

Я подумал, что когда я нажимаю на Блокнот, фокус все еще в окне Roblox, поэтому код все еще срабатывает. Поэтому я попытался изменить код так:

#IfWinActive, Roblox
    LButton::
        Sleep, 100
        if WinActive("Roblox")
        {
            MouseClick, Left
            SendInput, {1}
        }
    return
#IfWinActive

Предполагая, что к моменту окончания Sleep фокус переместится в окно Блокнота, и If WinActive("Roblox") вернет false, но все равно вернет true и набирает 1 в Блокноте.

Я также пытался использовать StartTimer и метку, думая, что, возможно, Sleep не был асинхронным, но с той же проблемой.

Кто-нибудь знает, как обойти эту проблему? Заранее спасибо!

Ответы [ 2 ]

2 голосов
/ 19 января 2020

Основная проблема в этом случае заключается в том, что горячая клавиша срабатывает сразу после нажатия LButton, а окно Roblox все еще активно.

Единственное решение, которое я вижу, - это нажать горячую клавишу при отпускании LButton. используя префикс тильды (~) , чтобы AHK не блокировал события нажатия клавиш / вверх:

#IfWinActive, Roblox

    ~LButton Up:: SendInput, 1

#IfWinActive
1 голос
/ 19 января 2020

Есть несколько способов достичь этого. TL; DR для решения, проверьте желтую часть этого поста.
Сначала я рассмотрю проблемы в вашем коде:

  1. Использование MouseClick свыше Click. Технически нет ничего плохого, но говорят, что Click более надежен в некоторых ситуациях и проще в использовании. Также выглядит чище.
  2. Упаковка 1 в {} здесь не нужна и здесь ничего не делает. В некоторых случаях вы можете даже сделать нежелательное поведение, делая это. В команде send {} используется для экранирования ключей, которые имеют особое значение, или для определения ключей, которые вы не можете просто ввести. Подробнее об этом из документации .
  3. Имея несколько плохих WinTitle , с которыми вы подходите. Опять же, ничего технически не так, но сейчас вы подходите к любому окну, которое начинается со слова Roblox. Не должно быть слишком сложно случайно найти неправильное окно.
    Быстрое и очень эффективное решение будет соответствовать имени процесса вашего окна Roblox.
    Итак #IfWinActive, ahk_exe Roblox.exe или в операторе if if (WinActive("ahk_exe Roblox.exe")) (если предположить, что это имя процесса, я понятия не имею)
    Поскольку абсолютно безошибочный способ может соответствовать hwnd окна Roblox. Однако, это может быть немного излишним, и вы не могли бы действительно использовать его с #IfWinActive. Пример, который я напишу ниже, будет использовать это, хотя.

Однако, проблем 1 и 2 можно полностью избежать, если использовать этот аккуратный способ переназначения ключа (переназначение почти то, что вы здесь делаете).
~LButton::1
Хорошо, так почему это работает?
key::key - это всего лишь синтаксис, позволяющий легко выполнить базовый c переназначение и с помощью ~ мы указываем, что горячая клавиша не срабатывает при ее срабатывании.


Классно, но теперь перейдем к реальной проблеме, с которой вы столкнулись.
Итак, что пошло не так со спящей штукой? Ну, так как вы используете горячую клавишу, все, что вы на самом деле делаете, это нажимаете горячую клавишу, ожидаете 100 мс, а затем проверяете, активен ли Roblox. Ну, да, он все еще будет активен, поскольку ничего не было сделано, чтобы переключить фокус с него.
Если бы вы не использовали левое нажатие, это сработало бы, , но это определенно не хорошо идея. Вы не хотите спать внутри утверждения горячей клавиши. У AHK нет истинной многопоточности, и если вы не укажете более высокую #MaxThreadsPerHotkey для своей горячей клавиши, все последующие нажатия горячей клавиши будут полностью игнорироваться для этих 100 мс.
Так что да, с указанием большее количество потоков, которые могут работать для этой горячей клавиши, могло бы заставить это решение работать, но это все еще плохая практика. Мы можем придумать что-нибудь получше.

С таймерами вы можете избежать сна в выражении горячих клавиш. Звучит так, как будто вы уже опробовали таймеры, но я не могу быть уверен, что он работал правильно, поскольку код не был предоставлен, поэтому я go за него:

#IfWinActive, ahk_exe Roblox.exe
~LButton::SetTimer, OurTimersCallbackLabel, -100 ;-100 specifies that it runs ONCE after 100ms has passed
#IfWinActive

OurTimersCallbackLabel:
    if (WinActive("ahk_exe Roblox.exe"))
        SendInput, 1
return

И Теперь перейдем к реальному решению, в котором @ user3419297, кажется, победил меня, так же, как я пишу эту строку текста.

Использование события up вашей LButton press в качестве горячей клавиши.

#IfWinActive, ahk_exe Roblox.exe
~LButton Up::SendInput, 1
#IfWinActive

Таким образом, событие down уже переключило фокус окна, и наша горячая клавиша даже не сработает.
Обратите внимание, что здесь мы, к сожалению, не можем использовать key::key способ переназначения, который я описал выше .


Бонус:

Вот кое-что, что можно использовать, если нежелательно событие up нажатия нашей клавиши, или переключение окна активного окна задерживается.

RobloxHwnd := WinExist("ahk_exe Roblox.exe")

#If, RobloxUnderMouse()
~LButton::1
#If

RobloxUnderMouse()
{
    global RobloxHwnd ;specify that we're using the variable defined outside of this function scope
    ;could've also ran the code to get Roblox's hwnd here every time, but that would be wasteful

    MouseGetPos, , , HwndUnderMouse ;we don't need the first two parameters
    return RobloxHwnd == HwndUnderMouse ;are they the same hwnd? (return true or false)
}

Здесь мы сначала сохраняем hwnd нашего Roblox в переменной RobloxHwnd.
Обратите внимание, что Roblox должен быть запущен, прежде чем мы запустим этот скрипт, и если вы перезапустите robox, скрипт потребуется также перезапустить.
Так что было бы неплохо добавить какой-либо способ обновления значения этой переменной на лету, возможно, с помощью некоторой горячей клавиши.

Затем, используя #If, мы оцениваем выражение (в нашем случае, запускаем функцию и вычисляем ее возвращаемое значение) каждый раз, когда пытаемся запустить горячую клавишу. Если выражение имеет значение true, мы запускаем горячую клавишу.
Использование #If на самом деле не рекомендуется, и рекомендуется избегать использования, если это вообще возможно. Тем не менее, вы не столкнетесь с какими-либо проблемами в таком небольшом скрипте, поэтому использование #If будет очень удобным здесь.
Если бы у вас был скрипт большего размера, в котором часто выполняется много кода, вы бы быть может столкнуться с проблемами.

...