Pyautogui滚动微调?

Rap*_*ber 2 python scroll pyautogui

pyautogui 滚动量值 1 太小,2 对于我想要执行的特定任务来说太大。有没有办法在中间滚动?我尝试了1.5,但没有成功。

我使用的是 OSX 10.13,当使用触控板时,我肯定可以比 pyautogui 所做的更精确地滚动。

heg*_*ash 7

这是一个一直困扰我的问题,所以我查看了 pyautogui 源代码并能够解决该问题。这可能是一个很长的答案;我将尝试详细解释每一步。请注意,这仅适用于 Mac。(如果您想要答案而不是解释,请滚动到底部)

\n\n

首先,这是滚动函数的源代码:

\n\n
def _scroll(clicks, x=None, y=None):\n    _vscroll(clicks, x, y)\n\ndef _vscroll(clicks, x=None, y=None):\n    _moveTo(x, y)\n    clicks = int(clicks)\n    for _ in range(abs(clicks) // 10):\n        scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(\n            None, # no source\n            Quartz.kCGScrollEventUnitLine, # units\n            1, # wheelCount (number of dimensions)\n            10 if clicks >= 0 else -10) # vertical movement\n        Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)\n\n    scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(\n        None, # no source\n        Quartz.kCGScrollEventUnitLine, # units\n        1, # wheelCount (number of dimensions)\n        clicks % 10 if clicks >= 0 else -1 * (-clicks % 10)) # vertical movement\n    Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)\n
Run Code Online (Sandbox Code Playgroud)\n\n

让我们来分解一下:

\n\n

1.

\n\n
def _scroll(clicks, x=None, y=None):\n_vscroll(clicks, x, y)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这只是_vscroll函数的包装,很简单。

\n\n

2.

\n\n

要认识到的主要事情是,针对 Mac 的 pyautogui 使用 Quartz Core Graphics,它所做的只是为 Quartz 代码提供一个更简单、更易读的包装器。

\n\n

使用滚动函数,它所做的是创建一个滚动事件

\n\n

scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent

\n\n

然后发布它

\n\n

Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)

\n\n

忽略发布的细节,我们不会更改任何内容。

\n\n

对我来说,这段代码似乎在重复,而且我不知道为什么for包含循环之后的任何代码。我从源代码中删除了它,一切正常;如果有人知道为什么包含此代码,请在下面评论并纠正我。

\n\n

3.

\n\n

所以我们留下了以下代码(忽略鼠标moveTo,它与滚动本身无关):

\n\n
clicks = int(clicks)\nfor _ in range(abs(clicks) // 10):\n    scrollWheelEvent = Quartz.CGEventCreateScrollWheelEvent(\n        None, # no source\n        Quartz.kCGScrollEventUnitLine, # units\n        1, # wheelCount (number of dimensions)\n        10 if clicks >= 0 else -10) # vertical movement\n\n    Quartz.CGEventPost(Quartz.kCGHIDEventTap, scrollWheelEvent)\n
Run Code Online (Sandbox Code Playgroud)\n\n

a的格式CGEventCreateScrollWheelEvent如下:

\n\n

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

\n\n

在本source例中是None,不用担心,我们只处理 1 个轮子,wheelCount所以1

\n\n

因此,源代码正在执行的操作是滚动 的距离\xc2\xb110 Quartz.kCGScrollEventUnitLine,这是一次“滚动”的计算机单位。无论您指定多少次,它都会在循环中重复此操作for,因为如果一次发送太多滚动单元,系统可能会出现错误。

\n\n

因此,在 pyautogui 上可以滚动的最小次数是该循环的一次迭代,它发送一个计算机单元。问题是这些单位对于精细滚动来说太大了。

\n\n

解决方案

\n\n

我们需要更改可以发送的最小值。目前它是 1 Quartz.kCGScrollEventUnitLine,但我们可以通过用零替换它们来将它们更改为基本单位。我还认为不需要地板划分clicks( in range(abs(clicks) // 10)) 然后发送10滚动单元。

\n\n

我们可以更改这两部分,并删除不必要的重复:

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

如果您不愿意编辑源代码本身,您可以直接在代码中使用这些函数,无需使用 pyautogui。只需pyobjc安装(如果您使用 pyautogui,无论如何您都会拥有),删除_moveTo(x, y)关键字参数,并使用以下导入:

\n\n

from Quartz.CoreGraphics import CGEventCreateScrollWheelEvent, CGEventPost, kCGHIDEventTap

\n\n

我意识到这个答案有点晚了,但我来寻找这个问题的答案并看到了你的问题;当我解决这个问题时,我想我应该分享知识。

\n