AutoHotkey, булева переменная не работает должным образом - PullRequest
1 голос
/ 09 февраля 2020

Я написал программу Autohotkey для переключения масштабирования на уровне Windows встроенной лупы. Это очень просто. Когда вы перемещаете мышь в верхний левый угол, она увеличивается, а в следующий раз вы переходите в верхний левый угол. Ниже мой код. Проблема в том, что он всегда увеличивается. Я не знаю, в чем проблема. Кто-нибудь может помочь взглянуть?

; Timer to check mouse position
SetTimer, CheckMouse, 300

#Persistent
#SingleInstance force

WinGetPos,,,Xmax,Ymax,ahk_class Progman  ; get desktop size

T = 4   ; adjust tolerance value if desired

Xmax := Xmax - T   ; allow tolerance to mouse corner activation position
Ymax := Ymax - T

CheckMouse:                   ; check mouse position
CoordMode, Mouse, Screen
MouseGetPos, MouseX, MouseY

GetKeyState, SState, Shift
GetKeyState, AState, Alt
GetKeyState, CState, Control

zoom_toggle := True

if (MouseY < T and MouseX < T and CState = "U" and AState = "U" and SState = "U")
{
    if(zoom_toggle)
    {
        Send #{+}
        zoom_toggle := False
    }
    else
    {
        Send #{-}
        zoom_toggle := True
    }
}

Return

1 Ответ

2 голосов
/ 09 февраля 2020

Несколько вещей, которые нужно исправить / улучшить.
Я начну с реальной проблемы, а затем go с того, что вы должны / могли бы улучшить.

Так что реальная проблема, каждый раз, когда вы запустив таймер, вы установите для переменной zoom_toggle значение true. Так что да, не сильно помогает попытка сделать какие-либо переключатели, когда значение каждый раз сбрасывается.
Переместите определение в верхнюю часть скрипта, или из-за того, как простит ахк, вы могли бы фактически полностью пропустить объявление переменной , Таким образом, когда он используется впервые, он создается со значением по умолчанию none , которое оценивается как false.

А теперь с другими исправлениями / улучшениями.
Расположение вашего # директивы.
Хорошей / обычной практикой является определение этих типов #directives в самом верху вашего скрипта.

Использование WinGetPos для получения ширины / высоты экрана.
Вы можете использовать A_ScreenWidth и A_ScreenHeight переменных, чтобы легко получить ширину и высоту экрана.

Отсутствует return, что должно закончить секция автозапуска .
Когда вы запускаете скрипт в первый раз, ничто не мешает выполнению кода полностью перейти к метке обратного вызова вашего таймера.
Ничего плохого не получится это в вашем случае, но для дальнейшего использования, вы не хотите, чтобы это произошло. Используйте return, чтобы остановить выполнение кода и завершить раздел автозапуска.

Код избыточности
Нет необходимости устанавливать CoordMode при каждом запуске таймера. Переместите эту команду в верхнюю часть вашего скрипта.
В вашей команде send нет необходимости заключать - в { }. Это делается только для экранирования символов, которые имеют особое значение в команде отправки, а - не имеет ни одного. В особых случаях вы можете даже столкнуться с нежелательным поведением при этом. Подробнее об этом в документации .
Почему создаются Xmax и Ymax? Они ничего не делают для нас?

Использование Send вместо SendInput
SendInput быстрее и надежнее. Почти всегда должен использоваться над Send.
. Вы можете указать SendMode, Input в верхней части скрипта, чтобы превратить все команды Send в SendInput. Лично я предпочитаю просто писать SendInput.

Устаревший код
Технически нет ничего плохого в использовании унаследованного кода, но это определенно не рекомендуется. Совместимость с будущими версиями AHK также отсутствует. Синтаксис выражений - это то, что всегда должно использоваться в наши дни.
Используйте устаревшую команду GetKeyState().
Используйте не устаревшие операторы (&& , ||, et c) вместо прежних AND, OR, et c. Всегда используйте := вместо =. Устаревшее назначение никогда не используется.
Использование метки также довольно унаследовано. Должен заменить на функцию, но тогда я должен убедиться, что вы также понимаете области действия функции. Если хотите, я могу.

Вот ваш пересмотренный код:

#Persistent
#SingleInstance, Force
CoordMode, Mouse, Screen ;move this to the top, needs to be executed only once

; Timer to check mouse position
SetTimer, CheckMouse, 1000

T := 4   ; adjust tolerance value if desired
Xmax := A_ScreenWidth - T   ; allow tolerance to mouse corner activation position
Ymax := A_ScreenHeight - T
;not sure why we're creating these two variables though, they're doing absolutely nothing for us?

return ;end auto-execute section

CheckMouse:                   ; check mouse position
    MouseGetPos, MouseX, MouseY
    SState := GetKeyState("Shift", "P")
    AState := GetKeyState("Alt", "P")
    CState := GetKeyState("Control", "P") 
    ;returns true/false (1/0)
    ;true meaning the key is down

    if (MouseY < T && MouseX < T && !SState && !AState && !CState)
    {
        ;I skipped definin the zoom_toggle variable so it's created for us
        ;with the default value of nothing, which evaluates to false
        ;had to flip around the if statement to account for this as well
        if(!zoom_toggle) 
        {
            SendInput, #{+}
            zoom_toggle := true
        }
        else
        {
            SendInput, #-
            zoom_toggle := false
        }
    }
return ;ends the label

Чтобы закончить, я хотел бы сказать, что это не очень хорошая реализация. Чтобы сделать его хотя бы пригодным для использования, измените таймер, чтобы он работал медленнее. Я сделал это 1se c в этом пересмотренном коде.
Если вы хотите улучшить его, я могу упомянуть супер простой способ - заставить его запускать код только один раз, пока мышь находится в этой области. Добавление еще одного переключателя на то, вышла ли мышь из этого региона, сделает это.
Также, если бы у вас был второй монитор, который находится слева от вашего основного монитора в Windows, все было бы довольно плохо, ха-ха.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...