Guía de Coordenadas PyAutoGUI: size(), Multimonitor, Corrección de DPI

Lo que PyAutoGUI vería en tu pantalla:

Resolución física
Lo que ve PyAutoGUI (sin corregir)
DPR
Offset del clic (peor caso)

pyautogui.size() devuelve las dimensiones de tu pantalla, pyautogui.position() da la ubicación actual del ratón, y pyautogui.click(960, 540) hace clic en el centro de una pantalla 1920×1080 — pero solo cuando el escalado DPI está desactivado. Si escribiste pyautogui.click(960, 540) y el clic cayó en otro sitio, o pyautogui.locateOnScreen() devuelve coordenadas erróneas, estás ante el bug de coordenadas más común de PyAutoGUI. Abajo explicamos cómo funciona pyautogui.size(), los rangos multimonitor, y la solución completa de escalado DPI.ocateOnScreen() devuelve coordenadas incorrectas. O tu captura de pantalla muestra una región equivocada. ¿Te suena?

Estos son los tres bugs clásicos de coordenadas en PyAutoGUI, y todos comparten una causa raíz: escalado DPI + coordenadas de pantalla virtual multimonitor. Abordamos los tres a continuación — con código que puedes pegar directamente en tu proyecto. Los valores de tu pantalla están detectados arriba.

Abrir herramienta gratuita de coordenadas de pantalla

Los tres bugs de coordenadas de PyAutoGUI

Los problemas de coordenadas con PyAutoGUI casi siempre caen en una de estas tres categorías:

  1. Offset del clic en pantallas con DPI alto: pyautogui.click(960, 540) no aterriza donde esperas porque PyAutoGUI usa coordenadas lógicas mientras la aplicación de destino usa coordenadas físicas. Cubierto en nuestra guía de escalado DPI.
  2. Tamaño de pantalla incorrecto: pyautogui.size() devuelve 2560×1440 en tu pantalla 4K porque Windows le está dando la resolución lógica (escalada). Tus scripts calculan centros erróneos, porcentajes erróneos, todo erróneo.
  3. Desalineación de la región de captura: pyautogui.screenshot(region=(x, y, w, h)) captura un área diferente a la que especificaste, porque las coordenadas de la región están en espacio lógico pero la captura usa el búfer de píxeles físicos.

Los tres bugs tienen la misma causa raíz: PyAutoGUI se ejecuta como un proceso no consciente del DPI en Windows por defecto. El sistema operativo le da coordenadas lógicas. La solución es siempre la misma: hacerlo consciente del DPI.

pyautogui.size() vs tu resolución real

¿Qué devuelve realmente pyautogui.size() en una pantalla 4K? Depende de tu escalado:

Resolución físicaEscalado de Windowspyautogui.size() devuelvePíxeles de diferencia
3840×2160100 %3840×2160 ✓Ninguno
3840×2160125 %3072×1728768×432 píxeles de error
3840×2160150 %2560×14401280×720 píxeles de error
3840×2160200 %1920×10801920×1080 píxeles de error
2560×1440125 %2048×1152512×288 píxeles de error
2560×1440150 %1707×960853×480 píxeles de error

Con un escalado del 150 % en 4K, PyAutoGUI cree que tu pantalla solo tiene 2560 píxeles de ancho. Cuando hace clic en lo que cree que es el centro (1280, 720), Windows traduce eso al píxel físico (1920, 1080) — que por casualidad es el centro real. Pero cualquier otra posición estará desplazada por el factor de escala.

La solución completa: configuración de PyAutoGUI consciente del DPI

Pon esto al principio de tu script — antes de importar PyAutoGUI:

import ctypes
import sys

# Corrección #1: Decir a Windows que queremos píxeles físicos reales
if sys.platform == 'win32':
    try:
        # Conciencia DPI por monitor (mejor para multimonitor)
        ctypes.windll.shcore.SetProcessDpiAwareness(2)
    except Exception:
        # Alternativa: conciencia DPI a nivel de sistema
        ctypes.windll.user32.SetProcessDPIAware()

# AHORA importamos PyAutoGUI — verá los píxeles reales
import pyautogui

# Verificar que la corrección funcionó
w, h = pyautogui.size()
print(f"Screen size: {w}×{h}")
# En una pantalla 4K al 150%, esto debería mostrar 3840×2160

¿Por qué SetProcessDpiAwareness(2) en vez de SetProcessDPIAware()?

LlamadaNivelMultimonitorUsar cuando
SetProcessDPIAware()SistemaUsa el DPI del monitor principal para todosSolo con un monitor
SetProcessDpiAwareness(2)Por monitorCada monitor reporta su resolución física realCualquier configuración (recomendado)

Si tienes una pantalla de portátil 4K al 150 % y un monitor externo de 1080p al 100 %, SetProcessDpiAwareness(2) asegura que PyAutoGUI vea 3840×2160 en la pantalla del portátil y 1920×1080 en el externo — los valores reales de cada pantalla. Para más detalles sobre cómo funcionan las coordenadas entre monitores diferentes, consulta nuestra guía de coordenadas multimonitor.

Corregir los offsets en la región de captura de pantalla

El problema de la región de captura es traicionero. Sin la corrección DPI, el parámetro region usa coordenadas lógicas — así que ocurre esto (el ejemplo asume un escalado del 150 % en una pantalla 4K; tu DPR detectado puede variar):

# SIN la corrección (escalado al 150 % en 4K):
# Quieres capturar los 960×540 píxeles de la esquina superior izquierda
img = pyautogui.screenshot(region=(0, 0, 960, 540))
# Pero en realidad captura la zona lógica superior izquierda de 960×540
# que se mapea a píxeles físicos (0, 0, 1440, 810) — mucho más de lo que querías

# CON SetProcessDpiAwareness(2):
# Ahora la región usa píxeles físicos correctamente
img = pyautogui.screenshot(region=(0, 0, 960, 540))
# Captura exactamente los 960×540 píxeles físicos de la esquina superior izquierda ✓

Importante: Tras activar la conciencia DPI, pyautogui.screenshot() devuelve una imagen a la resolución física completa. En una pantalla 4K, es una imagen de 3840×2160, no de 2560×1440. Si estabas recortando capturas antes de la corrección, necesitas actualizar tus coordenadas de recorte a píxeles físicos.

Multimonitor: coordenadas de pantalla virtual explicadas

En una configuración multimonitor, PyAutoGUI trabaja con una única pantalla virtual que abarca todos tus monitores. El monitor principal empieza en (0, 0). Los demás se extienden desde ahí:

# Comprueba el tamaño de tu pantalla virtual
import ctypes
import pyautogui

# Tras la corrección DPI:
print(pyautogui.size())   # Tamaño del monitor principal
x, y = pyautogui.position()
print(f"Current mouse position: ({x}, {y})")
# Valores negativos significan que estás en un monitor a la izquierda/arriba

Para los cálculos completos de coordenadas para obtener el centro, los offsets y las posiciones de los bordes de cualquier monitor, consulta nuestra guía de coordenadas multimonitor.

Por qué locateOnScreen() devuelve coordenadas incorrectas

pyautogui.locateOnScreen('button.png') es una de las funciones más útiles de PyAutoGUI — y una de las que más falla en pantallas con DPI alto. El problema (el ejemplo asume un escalado del 150 % en una pantalla 4K):

  1. Haces una captura de pantalla de un botón en tu pantalla 4K (la imagen es de 3840×2160 píxeles físicos)
  2. Recortas el botón y lo guardas como button.png
  3. locateOnScreen() hace una captura — pero sin conciencia DPI, Windows devuelve una imagen de tamaño lógico (2560×1440) que ha sido remuestreada y difuminada por el sistema operativo (virtualización DPI). Los píxeles ya no coinciden exactamente con tu imagen de referencia.
  4. Intenta encontrar tu botón nítido recortado a 4K dentro de esta captura borrosa y reducida — y falla o devuelve coordenadas incorrectas

La solución: Tras llamar a SetProcessDpiAwareness(2), las capturas internas de PyAutoGUI obtienen píxeles físicos en crudo sin remuestreo del SO. Tu imagen de referencia y la captura de búsqueda están ahora a la misma resolución y nitidez, así que locateOnScreen() funciona correctamente.

Consejo: Crea siempre tus imágenes de referencia después de activar la conciencia DPI. Si las capturaste antes de la corrección, están a resolución lógica y no coincidirán con las capturas de píxeles físicos.

Script listo para usar

Copia y pega esto en tu proyecto. Gestiona la conciencia DPI, la detección multimonitor y te da funciones auxiliares para clics independientes de la resolución:

"""
Configuración de PyAutoGUI consciente del DPI — coloca esto al principio de cualquier script.
Funciona en Windows, macOS y Linux. Compatible con multimonitor.

CRÍTICO: La conciencia DPI DEBE configurarse antes de importar pyautogui,
de lo contrario cachea la resolución lógica en la importación.
"""
import ctypes
import sys

# --- Configurar conciencia DPI ANTES de importar pyautogui ---
if sys.platform == 'win32':
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(2)
    except Exception:
        try:
            ctypes.windll.user32.SetProcessDPIAware()
        except Exception:
            pass

# AHORA es seguro importar pyautogui
import pyautogui

def get_screen_info():
    """Devuelve información útil de la pantalla."""
    w, h = pyautogui.size()
    return {
        'width': w,
        'height': h,
        'center': (w // 2, h // 2),
        'total_pixels': w * h,
    }

def click_relative(x_pct, y_pct):
    """Hace clic en un porcentaje del tamaño de pantalla (0.0 a 1.0).
    Independiente de la resolución — funciona en cualquier pantalla."""
    w, h = pyautogui.size()
    pyautogui.click(int(w * x_pct), int(h * y_pct))

# --- Uso ---
info = get_screen_info()
print(f"Primary screen: {info['width']}×{info['height']}")
print(f"Center: {info['center']}")

# Ejemplo: hacer clic en el centro de la pantalla
click_relative(0.5, 0.5)

Preguntas frecuentes

¿Esta corrección funciona en macOS y Linux?

SetProcessDpiAwareness() solo existe en Windows. En macOS, PyAutoGUI gestiona bastante bien el escalado Retina por su cuenta. En Linux depende de tu servidor gráfico (X11 vs Wayland). La función setup_dpi_awareness() anterior se puede llamar desde cualquier plataforma sin riesgo — simplemente no hace nada en sistemas que no sean Windows.

¿Por qué mi script funciona en IDLE pero no cuando lo ejecuto directamente?

Algunos IDEs — incluido IDLE — ya son conscientes del DPI. Si ejecutas tu script dentro de uno, hereda ese contexto. Ejecuta el mismo script desde la línea de comandos o el Programador de tareas y se inicia como un proceso no consciente del DPI. Siempre llama a SetProcessDpiAwareness(2) independientemente de cómo lo lances.

¿Puedo usar esto con PyAutoGUI + OpenCV juntos?

Sí. Tras activar la conciencia DPI, pyautogui.screenshot() devuelve una imagen PIL a resolución completa. Puedes convertirla a un array de NumPy para procesarla con OpenCV. Las coordenadas de cv2.matchTemplate() coincidirán con el espacio de coordenadas de píxeles físicos de PyAutoGUI.

¿Qué pasa si SetProcessDpiAwareness(2) lanza un error?

Puede fallar si tu proceso ya ha sido marcado como no consciente del DPI (por ejemplo, si Python fue lanzado por un proceso padre que no es consciente del DPI). La alternativa es SetProcessDPIAware(). Si incluso esa falla, probablemente estás en un contexto donde la conciencia DPI se hereda del proceso padre — revisa la configuración de tu lanzador de Python o terminal.

¿Cómo obtengo mis coordenadas de ratón para verificar la corrección?

Ejecuta print(pyautogui.position()) después de llamar a setup_dpi_awareness(). Mueve el ratón a la esquina inferior derecha de tu pantalla — debería mostrar algo cercano a (width-1, height-1) donde width/height son la resolución física. O usa nuestra herramienta online de coordenadas de pantalla para ver tu posición en tiempo real.

Relacionado: Necesitas encontrar coordenadas antes de tu script PyAutoGUI? Ve nuestra guia de coordenadas de pixel con metodos para PowerShell, xdotool y DevTools.

Relacionado: Capturar una secuencia de clics? Nuestro detector registra coordenadas para scripts PyAutoGUI.

Abrir rastreador de coordenadas en vivo Guía de escalado DPI y coordenadas