【问题标题】:How to control the mouse in Mac using Python?如何使用 Python 在 Mac 中控制鼠标?
【发布时间】:2010-09-21 19:43:06
【问题描述】:

在 OS X 上使用 Python 移动鼠标(并可能单击)的最简单方法是什么?

这只是为了快速制作原型,不一定要优雅。

【问题讨论】:

    标签: python macos mouse


    【解决方案1】:

    试试this page 的代码。它定义了几个函数,mousemovemouseclick,它们与 Apple 的 Python 和平台的 Quartz 库之间的集成挂钩。

    此代码适用于 10.6,我在 10.7 上使用它。这段代码的好处是它会生成鼠标事件,而某些解决方案不会。我用它来控制 BBC iPlayer,方法是将鼠标事件发送到 Flash 播放器中的已知按钮位置(我知道这很脆弱)。尤其需要鼠标移动事件,否则 Flash 播放器永远不会隐藏鼠标光标。 CGWarpMouseCursorPosition 之类的函数不会这样做。

    from Quartz.CoreGraphics import CGEventCreateMouseEvent
    from Quartz.CoreGraphics import CGEventPost
    from Quartz.CoreGraphics import kCGEventMouseMoved
    from Quartz.CoreGraphics import kCGEventLeftMouseDown
    from Quartz.CoreGraphics import kCGEventLeftMouseUp
    from Quartz.CoreGraphics import kCGMouseButtonLeft
    from Quartz.CoreGraphics import kCGHIDEventTap
    
    def mouseEvent(type, posx, posy):
            theEvent = CGEventCreateMouseEvent(
                        None, 
                        type, 
                        (posx,posy), 
                        kCGMouseButtonLeft)
            CGEventPost(kCGHIDEventTap, theEvent)
    
    def mousemove(posx,posy):
            mouseEvent(kCGEventMouseMoved, posx,posy);
    
    def mouseclick(posx,posy):
            # uncomment this line if you want to force the mouse 
            # to MOVE to the click location first (I found it was not necessary).
            #mouseEvent(kCGEventMouseMoved, posx,posy);
            mouseEvent(kCGEventLeftMouseDown, posx,posy);
            mouseEvent(kCGEventLeftMouseUp, posx,posy);
    

    这是上面页面的代码示例:

    ##############################################################
    #               Python OSX MouseClick
    #       (c) 2010 Alex Assouline, GeekOrgy.com
    ##############################################################
    import sys
    try:
            xclick=intsys.argv1
            yclick=intsys.argv2
            try:
                    delay=intsys.argv3
            except:
                    delay=0
    except:
            print "USAGE mouseclick [int x] [int y] [optional delay in seconds]"
            exit
    print "mouse click at ", xclick, ",", yclick," in ", delay, "seconds"
    # you only want to import the following after passing the parameters check above, because importing takes time, about 1.5s
    # (why so long!, these libs must be huge : anyone have a fix for this ?? please let me know.)
    import time
    from Quartz.CoreGraphics import CGEventCreateMouseEvent
    from Quartz.CoreGraphics import CGEventPost
    from Quartz.CoreGraphics import kCGEventMouseMoved
    from Quartz.CoreGraphics import kCGEventLeftMouseDown
    from Quartz.CoreGraphics import kCGEventLeftMouseDown
    from Quartz.CoreGraphics import kCGEventLeftMouseUp
    from Quartz.CoreGraphics import kCGMouseButtonLeft
    from Quartz.CoreGraphics import kCGHIDEventTap
    def mouseEventtype, posx, posy:
            theEvent = CGEventCreateMouseEventNone, type, posx,posy, kCGMouseButtonLeft
            CGEventPostkCGHIDEventTap, theEvent
    def mousemoveposx,posy:
            mouseEventkCGEventMouseMoved, posx,posy;
    def mouseclickposx,posy:
            #mouseEvent(kCGEventMouseMoved, posx,posy); #uncomment this line if you want to force the mouse to MOVE to the click location first (i found it was not necesary).
            mouseEventkCGEventLeftMouseDown, posx,posy;
            mouseEventkCGEventLeftMouseUp, posx,posy;
    time.sleepdelay;
    mouseclickxclick, yclick;
    print "done."
    

    【讨论】:

    【解决方案2】:

    pynput 库似乎是目前维护得最好的库。它允许您控制和监视输入设备。

    这里是控制鼠标的例子:

    from pynput.mouse import Button, Controller
    
    mouse = Controller()
    
    # Read pointer position
    print('The current pointer position is {0}'.format(
        mouse.position))
    
    # Set pointer position
    mouse.position = (10, 20)
    print('Now we have moved it to {0}'.format(
        mouse.position))
    
    # Move pointer relative to current position
    mouse.move(5, -5)
    
    # Press and release
    mouse.press(Button.left)
    mouse.release(Button.left)
    
    # Double click; this is different from pressing and releasing
    # twice on Mac OSX
    mouse.click(Button.left, 2)
    
    # Scroll two steps down
    mouse.scroll(0, 2)
    

    【讨论】:

    • 搜索了十几篇关于鼠标点击的文章,特别需要针对 Python 2.7 和 OS X 的解决方案。大部分热门文章都是 3 年前的问答。我不知道 .scroll 应该做什么,但这个答案中的其他一切都有效。这比任何其他答案(甚至 java.awt 答案)都更具可读性和复杂性。
    【解决方案3】:

    最简单的方法是使用 PyAutoGUI。

    安装:

    pip install pyautogui
    

    示例:

    • 获取鼠标位置:

      >>> pyautogui.position()
      (187, 567)
      
    • 将鼠标移动到特定位置:

      >>> pyautogui.moveTo(100,200)
      
    • 触发鼠标点击:

      >>> pyautogui.click()
      

    更多详情:PyAutoGUI

    【讨论】:

    • 是的,刚刚在 HighSierra 上查看过,它就像一个魅力。 PyAutoGUI 似乎也是跨平台的。相当不错的用户界面和示例。不管是谁做的,干得好。
    【解决方案4】:

    试试这个代码:

    #!/usr/bin/python
    
    import objc
    
    class ETMouse():    
        def setMousePosition(self, x, y):
            bndl = objc.loadBundle('CoreGraphics', globals(), 
                    '/System/Library/Frameworks/ApplicationServices.framework')
            objc.loadBundleFunctions(bndl, globals(), 
                    [('CGWarpMouseCursorPosition', 'v{CGPoint=ff}')])
            CGWarpMouseCursorPosition((x, y))
    
    if __name__ == "__main__":
        et = ETMouse()
        et.setMousePosition(200, 200)
    

    它适用于 OSX leopard 10.5.6

    【讨论】:

    • 给我错误 TypeError: a bytes-like object is required, not 'str'
    【解决方案5】:

    我翻遍了Synergy的源码,找到了产生鼠标事件的调用:

    #include <ApplicationServices/ApplicationServices.h>
    
    int to(int x, int y)
    {
        CGPoint newloc;
        CGEventRef eventRef;
        newloc.x = x;
        newloc.y = y;
    
        eventRef = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, newloc,
                                            kCGMouseButtonCenter);
        //Apparently, a bug in xcode requires this next line
        CGEventSetType(eventRef, kCGEventMouseMoved);
        CGEventPost(kCGSessionEventTap, eventRef);
        CFRelease(eventRef);
    
        return 0;
    }
    

    现在开始编写 Python 绑定!

    【讨论】:

    • 也许试试 ctypes 而不是绑定?
    • 至少在较新的 OS X 版本中,Apple 已将 Quartz 绑定包含在 OS 随附的 Python 发行版中。请参阅下面的答案。
    【解决方案6】:

    当我想这样做时,我安装了Jython 并使用了java.awt.Robot 类。如果您需要制作 CPython 脚本,这显然不合适,但是当您可以灵活选择任何东西时,它是一个不错的跨平台解决方案。

    import java.awt
    
    robot = java.awt.Robot()
    
    robot.mouseMove(x, y)
    robot.mousePress(java.awt.event.InputEvent.BUTTON1_MASK)
    robot.mouseRelease(java.awt.event.InputEvent.BUTTON1_MASK)
    

    【讨论】:

      【解决方案7】:

      最好的办法是使用AutoPy package。它使用起来非常简单,而且可以跨平台启动。

      将光标移动到位置 (200,200):

      import autopy
      autopy.mouse.move(200,200)
      

      【讨论】:

      • 我无法安装 autopy。它在 OS X 10.11 上失败,出现 9 个错误和 10 个警告。
      • 你可以使用 "xcode-select" --install 然后 "git clone git://github.com/msanders/autopy.git" 来下载和 "cd autopy && sudo python setup.py install" 来安装 autopy :) 希望对您有所帮助!
      • 不错的模块!谢谢!
      【解决方案8】:

      geekorgy.com 的 python 脚本很棒,除了我安装了更新版本的 python 后遇到了一些障碍。因此,这里有一些提示给可能正在寻找解决方案的其他人。

      如果您在 Mac OS 10.6 上安装了 Python 2.7,您有几个选项可以让 Python 从 Quartz.CoreGraphics 导入:

      A) 在终端中,在脚本路径前输入python2.6 而不是只输入python

      B)您可以通过执行以下操作安装 PyObjC

      1. http://pypi.python.org/pypi/setuptools 安装easy_install
      2. 在终端中,输入which python,然后将路径向上复制到2.7
      3. 然后输入easy_install –-prefix /Path/To/Python/Version pyobjc==2.3

        **即。 easy_install –-prefix /Library/Frameworks/Python.framework/Versions/2.7 pyobjc==2.3

      4. 在顶部的脚本类型import objc
      5. 如果第一次 easy_install 不起作用,您可能需要先安装核心:

        **即。 easy_install --prefix /Library/Frameworks/Python.framework/Versions/2.7 pyobjc-core==2.3

      C)您可以重置您的python路径到原来的Mac OS python:

      • 在终端中输入:defaults write com.apple.versioner.python Version 2.6

      ***另外,一种快速找出屏幕上 (x,y) 坐标的方法:

      1. Command+Shift+4(屏幕抓取选择)
      2. 然后光标显示坐标
      3. 然后按 Esc 退出。

      【讨论】:

        【解决方案9】:

        使用 Quartz 库中的 CoreGraphics,例如:

        from Quartz.CoreGraphics import CGEventCreate
        from Quartz.CoreGraphics import CGEventGetLocation
        ourEvent = CGEventCreate(None);
        currentpos = CGEventGetLocation(ourEvent);
        mousemove(currentpos.x,currentpos.y)
        

        来源:Tony comment at Geekorgy page.

        【讨论】:

        • 导入速度有多慢,你怎么办?我在applescript中使用它,但是每次我调用python脚本时,一切都会等待10-15秒来导入Quartz,这会让一切都变得很漫长。
        【解决方案10】:

        这是使用Quartz库的完整示例:

        #!/usr/bin/python
        import sys
        from AppKit import NSEvent
        import Quartz
        
        class Mouse():
            down = [Quartz.kCGEventLeftMouseDown, Quartz.kCGEventRightMouseDown, Quartz.kCGEventOtherMouseDown]
            up = [Quartz.kCGEventLeftMouseUp, Quartz.kCGEventRightMouseUp, Quartz.kCGEventOtherMouseUp]
            [LEFT, RIGHT, OTHER] = [0, 1, 2]
        
            def position(self):
                point = Quartz.CGEventGetLocation( Quartz.CGEventCreate(None) )
                return point.x, point.y
        
            def location(self):
                loc = NSEvent.mouseLocation()
                return loc.x, Quartz.CGDisplayPixelsHigh(0) - loc.y
        
            def move(self, x, y):
                moveEvent = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventMouseMoved, (x, y), 0)
                Quartz.CGEventPost(Quartz.kCGHIDEventTap, moveEvent)
        
            def press(self, x, y, button=1):
                event = Quartz.CGEventCreateMouseEvent(None, Mouse.down[button], (x, y), button - 1)
                Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
        
            def release(self, x, y, button=1):
                event = Quartz.CGEventCreateMouseEvent(None, Mouse.up[button], (x, y), button - 1)
                Quartz.CGEventPost(Quartz.kCGHIDEventTap, event)
        
            def click(self, button=LEFT):
                x, y = self.position()
                self.press(x, y, button)
                self.release(x, y, button)
        
            def click_pos(self, x, y, button=LEFT):
                self.move(x, y)
                self.click(button)
        
            def to_relative(self, x, y):
                curr_pos = Quartz.CGEventGetLocation( Quartz.CGEventCreate(None) )
                x += current_position.x;
                y += current_position.y;
                return [x, y]
        
            def move_rel(self, x, y):
                [x, y] = to_relative(x, y)
                moveEvent = Quartz.CGEventCreateMouseEvent(None, Quartz.kCGEventMouseMoved, Quartz.CGPointMake(x, y), 0)
                Quartz.CGEventPost(Quartz.kCGHIDEventTap, moveEvent)
        

        以上代码基于这些原始文件:Mouse.pymouseUtils.py

        这是使用上述类的演示代码:

        # DEMO
        if __name__ == '__main__':
            mouse = Mouse()
            if sys.platform == "darwin":
                print("Current mouse position: %d:%d" % mouse.position())
                print("Moving to 100:100...");
                mouse.move(100, 100)
                print("Clicking 200:200 position with using the right button...");
                mouse.click_pos(200, 200, mouse.RIGHT)
            elif sys.platform == "win32":
                print("Error: Platform not supported!")
        

        您可以将两个代码块合并到一个文件中,授予执行权限并将其作为 shell 脚本运行。

        【讨论】:

          【解决方案11】:

          最简单的方法?编译this Cocoa 应用程序并将鼠标移动传递给它。

          代码如下:

          // File:
          // click.m
          //
          // Compile with:
          // gcc -o click click.m -framework ApplicationServices -framework Foundation
          //
          // Usage:
          // ./click -x pixels -y pixels
          // At the given coordinates it will click and release.
          
          #import <Foundation/Foundation.h>
          #import <ApplicationServices/ApplicationServices.h>
          
          int main(int argc, char **argv) {
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
            NSUserDefaults *args = [NSUserDefaults standardUserDefaults];
          
          
            // grabs command line arguments -x and -y
            //
            int x = [args integerForKey:@"x"];
            int y = [args integerForKey:@"y"];
          
            // The data structure CGPoint represents a point in a two-dimensional
            // coordinate system.  Here, X and Y distance from upper left, in pixels.
            //
            CGPoint pt;
            pt.x = x;
            pt.y = y;
          
          
            // https://stackoverflow.com/questions/1483567/cgpostmouseevent-replacement-on-snow-leopard
            CGEventRef theEvent = CGEventCreateMouseEvent(NULL, kCGEventLeftMouseDown, pt, kCGMouseButtonLeft);
            CGEventSetType(theEvent, kCGEventLeftMouseDown);
            CGEventPost(kCGHIDEventTap, theEvent);
            CFRelease(theEvent);
          
            [pool release];
            return 0;
          }
          

          名为 click 的应用程序从 CGRemoteOperation.h 头文件调用 CGPostMouseEvent。它将坐标作为命令行参数,将鼠标移动到该位置,然后单击并释放鼠标按钮。

          将以上代码另存为click.m,打开终端,切换到你保存源码的文件夹。然后通过键入gcc -o click click.m -framework ApplicationServices -framework Foundation 编译程序。不要被需要编译它吓倒,因为 cmets 比代码多。这是一个非常短的程序,可以完成一项简单的任务。


          另一种方式?导入 pyobjc 以访问某些 OSX 框架并以这种方式访问​​鼠标。 (请参阅第一个示例中的代码以获取想法)。

          【讨论】:

            猜你喜欢
            • 2018-11-15
            • 2010-11-13
            • 2010-12-29
            • 2021-02-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-10-31
            • 2011-12-02
            相关资源
            最近更新 更多