--- name: cdp_click_xy kind: function lang: py domain: browser version: "1.0.0" purity: impure signature: "def cdp_click_xy(x: int, y: int, *, port: int = 9222, target_url_substr: str = '', move_first: bool = True, timeout_s: float = 10.0) -> dict" description: "Hace un click izquierdo de raton REAL en coordenadas (x, y) del viewport de una pestana de un Chrome con remote debugging, via CDP Input.dispatchMouseEvent (mouseMoved opcional + mousePressed + mouseReleased). Primitiva de input CDP reutilizable: necesaria cuando element.click() de JavaScript NO dispara los handlers de React de SPAs (WhatsApp Web): abrir un chat de la lista o un resultado de busqueda requiere un click de raton sintetico real. El caller resuelve las coordenadas con cdp_eval (getBoundingClientRect -> centro) y las pasa aqui." tags: [cdp, browser, automation, python, navegator] uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: ["json", "time", "urllib.request", "websocket"] params_schema: params: - name: x desc: "Coordenada X en CSS px del viewport donde hacer click. Normalmente el centro del elemento (getBoundingClientRect via cdp_eval)." - name: y desc: "Coordenada Y en CSS px del viewport donde hacer click. Normalmente el centro del elemento (getBoundingClientRect via cdp_eval)." - name: port desc: "Puerto de remote debugging de Chrome. Default 9222." - name: target_url_substr desc: "Substring que debe contener la URL del target (pestana). Si vacio, usa el primer target de tipo 'page'." - name: move_first desc: "Si True, emite un mouseMoved a (x, y) antes del click para que la SPA registre el hover. Default True." - name: timeout_s desc: "Timeout en segundos para la conexion WebSocket. Default 10.0." output: "dict {ok: bool, error: str, x: int, y: int}. ok=True si los eventos de raton (mouseMoved opcional, mousePressed, mouseReleased) se emitieron sin error; x/y son eco de los argumentos. Nunca lanza: errores de red/conexion/transport se devuelven en 'error' con ok=False." tested: true tests: ["test_golden_click_emite_movido_pressed_released_left", "test_edge_move_first_false_omite_mousemoved", "test_error_create_connection_lanza_ok_false"] test_file_path: "python/functions/browser/cdp_click_xy_test.py" file_path: "python/functions/browser/cdp_click_xy.py" --- ## Ejemplo ```python import sys, os, json sys.path.insert(0, os.path.join("python", "functions")) from browser.cdp_eval import cdp_eval from browser.cdp_click_xy import cdp_click_xy # Requiere un Chrome lanzado con --remote-debugging-port=9222 # y una pestana de WhatsApp Web abierta. # Localizar el row de un chat por nombre exacto y abrirlo con click REAL. r = cdp_eval(r'''(() => { const row = [...document.querySelectorAll('#side [role="row"]')] .find(x => /^NOTAS WASAP\b/.test(x.innerText.replace(/\s+/g,' ').trim())); if(!row) return null; const b = row.getBoundingClientRect(); return JSON.stringify({x: Math.round(b.x+b.width/2), y: Math.round(b.y+b.height/2)}); })()''', target_url_substr="whatsapp") c = json.loads(r["value"]) res = cdp_click_xy(c["x"], c["y"], target_url_substr="whatsapp") # abre el chat print(res["ok"], res["error"]) ``` O directo por CLI: `python3 python/functions/browser/cdp_click_xy.py 100 200 "whatsapp"`. ## Cuando usarla Cuando necesites **clickar un elemento** y `element.click()` de JavaScript NO dispara sus handlers (SPAs React como WhatsApp Web): **abrir un chat de la lista**, abrir un **resultado de busqueda**, pulsar un boton que React renderiza con listeners propios. Resuelve primero las coordenadas del elemento con `cdp_eval_py_browser` (`getBoundingClientRect` -> centro) y pasa `x, y` aqui. Es la primitiva de input de raton sobre la que se construyen funciones `whatsapp_*_py_browser` y cualquier script que opere una pestana existente via CDP. Para teclas usa `cdp_press_key_py_browser`; para escribir texto, `cdp_type_chars_py_browser`. ## Gotchas - **Coordenadas en CSS px del viewport**: `getBoundingClientRect()` ya las devuelve en ese sistema, por eso encaja directo. No uses `pageX/pageY` ni coords absolutas de documento. - **El elemento debe estar VISIBLE en el viewport**: si esta fuera de pantalla por scroll, las coords del rect son invalidas (negativas o fuera de rango) y el click cae en el lugar equivocado. Haz scroll al elemento primero (via `cdp_eval` con `scrollIntoView`) y vuelve a leer el rect. - Es un **click izquierdo simple** (clickCount=1, button=left). No hace doble click, click derecho ni drag. - `move_first=True` (default) emite un `mouseMoved` previo para que la SPA registre el hover; algunas UIs solo muestran/activan controles tras hover. Ponlo en False si no lo necesitas. - Requiere un Chrome lanzado con `--remote-debugging-port=9222` (o el puerto que pases). Sin remote debugging, `GET /json` falla y devuelve `ok=False`. - Nunca lanza: errores de red, conexion WS o transport se reportan en el campo `error` con `ok=False`.