pynput - ¿Cómo controlar el mouse en Mac usando Python?
python keyboard (11)
¿Cuál sería la forma más fácil de mover el mouse (y posiblemente hacer clic) usando Python en OS X?
Esto es solo para prototipos rápidos, no tiene que ser elegante.
¿La forma más fácil? Compila this aplicación Cocoa y pásale los movimientos de tu mouse.
Aquí está el código:
// 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://.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;
}
Aplicación llamada clic que invoca CGPostMouseEvent desde el archivo de encabezado CGRemoteOperation.h. Toma coordenadas como argumentos de línea de comandos, mueve el mouse a esa posición, luego hace clic y suelta el botón del mouse.
Guarde el código anterior como click.m, abra Terminal y cambie a la carpeta donde guardó el código fuente. Luego, compile el programa escribiendo
gcc -o click click.m -framework ApplicationServices -framework Foundation
. No se deje intimidar por la necesidad de compilar esto ya que hay más comentarios que código. Es un programa muy corto que realiza una tarea simple.
¿De otra manera? Importe pyobjc para acceder a algunos de los marcos OSX y acceda al mouse de esa forma. (vea el código del primer ejemplo para ideas).
Aquí está el ejemplo completo usando la biblioteca de 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)
El código anterior se basa en estos archivos originales: Mouse.py
mouseUtils.py
.
Aquí está el código de demostración que usa la clase anterior:
# 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!")
Puede combinar ambos bloques de código en un archivo, otorgar permiso de ejecución y ejecutarlo como un script de shell.
Busqué en el código fuente de Synergy para encontrar la llamada que genera eventos de mouse:
#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;
}
¡Ahora para escribir enlaces de Python!
Cuando quise hacerlo, instalé Jython y usé la clase java.awt.Robot
. Si necesita hacer un script CPython, esto obviamente no es adecuado, pero cuando tiene la flexibilidad de elegir cualquier cosa, es una buena solución multiplataforma.
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)
El script de python de geekorgy.com es excelente, salvo que encontré algunos inconvenientes desde que instalé una versión más nueva de python. Aquí hay algunos consejos para otros que pueden estar buscando una solución.
Si instaló Python 2.7 en su Mac OS 10.6, tiene algunas opciones para que Python pueda importar desde Quartz.CoreGraphics:
A) En la terminal, escribe python2.6
lugar de solo python
antes de la ruta al script
B) Puede instalar PyObjC haciendo lo siguiente:
- Instala easy_install desde http://pypi.python.org/pypi/setuptools
- En la terminal, escribe
which python
y copia la ruta hasta2.7
Luego escriba
easy_install –-prefix /Path/To/Python/Version pyobjc==2.3
**es decir.
easy_install –-prefix /Library/Frameworks/Python.framework/Versions/2.7 pyobjc==2.3
- Dentro del script escriba
import objc
en la parte superior Si easy_install no funciona la primera vez, es posible que deba instalar primero el núcleo:
**es decir.
easy_install --prefix /Library/Frameworks/Python.framework/Versions/2.7 pyobjc-core==2.3
C) Puede restablecer su ruta de Python a la python original de Mac OS:
- En la terminal, escriba:
defaults write com.apple.versioner.python Version 2.6
*** También, una forma rápida de descubrir las coordenadas (x, y) en la pantalla:
- Presione
Command+Shift+4
(selección de captura de pantalla) - El cursor muestra las coordenadas
- Luego presiona Esc para salir de ella.
La biblioteca pynput
parece ser la mejor biblioteca mantenida actualmente. Le permite controlar y controlar los dispositivos de entrada.
Aquí está el ejemplo para controlar el mouse:
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)
La forma más fácil es usar PyAutoGUI.
Ejemplo:
Para obtener la posición del mouse:
>>> pyautogui.position() (187, 567)
Para mover el mouse a una posición específica:
>>> pyautogui.moveTo(100,200)
Para activar un clic del mouse:
>>> pyautogui.click()
Más detalles: PyAutoGUI
Solo prueba este código:
#!/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)
funciona en OSX leopard 10.5.6
Su mejor opción es usar el paquete AutoPy . Es extremadamente simple de usar y multiplataforma para arrancar.
Para mover el cursor a la posición (200,200):
import autopy
autopy.mouse.move(200,200)
Utilice CoreGraphics
desde la biblioteca de Quartz, por ejemplo:
from Quartz.CoreGraphics import CGEventCreate
from Quartz.CoreGraphics import CGEventGetLocation
ourEvent = CGEventCreate(None);
currentpos = CGEventGetLocation(ourEvent);
mousemove(currentpos.x,currentpos.y)
Fuente: Tony comenta en la página de Geekorgy .
Prueba el código en esta página . Define un par de funciones, mousemove
y mouseclick
, que mouseclick
la integración de Apple entre Python y las bibliotecas de Quartz de la plataforma.
Este código funciona en 10.6, y lo estoy usando en 10.7. Lo bueno de este código es que genera eventos de mouse, que algunas soluciones no. Lo uso para controlar BBC iPlayer enviando eventos de mouse a posiciones de botón conocidas en su reproductor Flash (muy frágil, lo sé). Los eventos de movimiento del mouse, en particular, son necesarios ya que de lo contrario, el reproductor de Flash nunca oculta el cursor del mouse. Funciones como CGWarpMouseCursorPosition
no harán esto.
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 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);
Aquí está el ejemplo de código de la página anterior:
##############################################################
# 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."