Pyautogui прокрутки тонкой настройки? - PullRequest
0 голосов
/ 28 августа 2018

Значение 1 суммы прокрутки Пятогуи слишком мало, 2 слишком велико для конкретной задачи, которую я хочу выполнить. Есть ли способ прокрутки между ними? Я попробовал 1.5, но это не сработало.

Я работаю на OSX 10.13 и, конечно, могу использовать прокрутку с большей точностью, чем та, что делает pyautogui при использовании трекпада.

1 Ответ

0 голосов
/ 21 января 2019

Это проблема, которая меня раздражала, поэтому я взглянул на исходный код pyautogui и смог ее решить. Это, вероятно, будет довольно длинный ответ; Я постараюсь объяснить каждый шаг в деталях. Обратите внимание, что это работает только для Mac. (прокрутите вниз, если хотите получить ответ, а не объяснение)

Во-первых, вот исходный код функции прокрутки:

def _scroll(clicks, x=None, y=None):
    _vscroll(clicks, x, y)

def _vscroll(clicks, x=None, y=None):
    _moveTo(x, y)
    clicks = int(clicks)
    for _ in range(abs(clicks) // 10):
        scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
            None, # no source
            Quartz.kCGScrollEventUnitLine, # units
            1, # wheelCount (number of dimensions)
            10 if clicks >= 0 else -10) # vertical movement
        Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)

    scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
        None, # no source
        Quartz.kCGScrollEventUnitLine, # units
        1, # wheelCount (number of dimensions)
        clicks % 10 if clicks >= 0 else -1 * (-clicks % 10)) # vertical movement
    Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)

Давайте разберемся с этим:

1.

def _scroll(clicks, x=None, y=None):
_vscroll(clicks, x, y)

Это просто оболочка для функции _vscroll, достаточно простая.

2.

Главное, что нужно понять, это то, что pyautogui для Mac использует Quartz Core Graphics, и все, что он делает, это предоставляет более простую, более читаемую оболочку для кода Quartz.

С помощью функции прокрутки она создает событие прокрутки :

scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent

А потом отправив :

Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)

Не обращайте внимания на детали публикации, мы не будем ничего менять.

Мне кажется, что этот код повторяется, и я понятия не имею, почему какой-либо код после цикла for включен. Я удалил это из моего исходного кода, и все работает; Если кто-то знает, почему этот код включен, пожалуйста, прокомментируйте ниже и исправьте меня.

3.

Итак, у нас остался следующий код (игнорируя мышь moveTo, которая не имеет ничего общего с самой прокруткой):

clicks = int(clicks)
for _ in range(abs(clicks) // 10):
    scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
        None, # no source
        Quartz.kCGScrollEventUnitLine, # units
        1, # wheelCount (number of dimensions)
        10 if clicks >= 0 else -10) # vertical movement

    Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)

Формат CGEventCreateScrollWheelEvent следующий:

Quartz.CGEventCreateScrollWheelEvent(source, units, wheelCount, scroll distance)

source в этом случае - None, не беспокойтесь об этом, и мы имеем дело только с 1 колесом, поэтому wheelCount - это 1.

Таким образом, исходный код выполняет прокрутку на расстояние ±10 Quartz.kCGScrollEventUnitLine, что является единицами компьютеров для одной «прокрутки». Он повторяет это в цикле for столько раз, сколько вы укажете, потому что система может выдавать ошибку, если слишком много единиц прокрутки отправляются одновременно.

Следовательно, минимальная прокрутка на pyautogui - это одна итерация этого цикла, который отправляет один компьютерный блок. Проблема в том, что эти единицы слишком велики для точной прокрутки.

РЕШЕНИЕ

Нам нужно изменить минимальное значение, которое мы можем отправить. В настоящее время это 1 Quartz.kCGScrollEventUnitLine, но мы можем изменить их на базовые единицы, заменив их на ноль. Я также не вижу необходимости делить слово на пол clicks (in range(abs(clicks) // 10)), а затем отправлять 10 единицы прокрутки.

Мы можем изменить эти две части и удалить ненужные повторения:

def _scroll(clicks, x=None, y=None):
    _vscroll(clicks, x, y)

def _vscroll(clicks, x=None, y=None):
    _moveTo(x, y)
    clicks = int(clicks)
    for _ in range(abs(clicks)):  # <------------------------------------
        scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(
            None, # no source
            0, # units  <------------------------------------------------
            1, # wheelCount (number of dimensions)
            1 if clicks >= 0 else -1) # vertical movement <--------------
        Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)

Если вам неудобно редактировать сам исходный код, вы можете напрямую использовать эти функции в своем коде, пропуская необходимость в pyautogui. Просто установите pyobjc (что будет в любом случае, если вы используете pyautogui), удалите _moveTo(x, y) и аргументы ключевого слова и используйте следующие операции импорта:

from Quartz.CoreGraphics import CGEventCreateScrollWheelEvent, CGEventPost, kCGHIDEventTap

Я понимаю, что этот ответ немного запоздал, но я искал ответы на эту проблему и видел ваш вопрос; Когда я решил проблему, я решил поделиться своими знаниями.

...