Это проблема, которая меня раздражала, поэтому я взглянул на исходный код 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
Я понимаю, что этот ответ немного запоздал, но я искал ответы на эту проблему и видел ваш вопрос; Когда я решил проблему, я решил поделиться своими знаниями.