fix(tracker): en macOS medir inactividad sin permiso de Accesibilidad
El sensor leia el teclado/mouse global con device_query para saber si hubo entrada. En macOS eso exige el permiso de Accesibilidad y, como la app va sin firma estable, macOS nunca lo retiene: el dialogo «... quiere controlar este ordenador» reaparecia en cada arranque aunque ya se hubiera concedido. Solo hace falta saber SI hubo entrada, no cual. macOS lo da con CGEventSourceSecondsSinceLastEventType (segundos desde la ultima entrada HID), de solo lectura y sin pedir ningun permiso. Windows/Linux siguen con device_query (ahi no piden permiso), ahora como dependencia solo de esas plataformas. Verificado: cargo check OK (4.5s); prueba aislada de la API devuelve los segundos de inactividad en vivo sin ningun dialogo de permiso. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Este commit está contenido en:
@@ -34,10 +34,16 @@ serde_json = "1"
|
|||||||
# ureq: subir los lotes a /api/tracker (bloqueante, corre en su propio hilo).
|
# ureq: subir los lotes a /api/tracker (bloqueante, corre en su propio hilo).
|
||||||
# gethostname: el nombre del equipo, que bautiza al device en el servidor.
|
# gethostname: el nombre del equipo, que bautiza al device en el servidor.
|
||||||
active-win-pos-rs = "0.11"
|
active-win-pos-rs = "0.11"
|
||||||
device_query = "4"
|
|
||||||
ureq = { version = "2", features = ["json"] }
|
ureq = { version = "2", features = ["json"] }
|
||||||
gethostname = "0.5"
|
gethostname = "0.5"
|
||||||
|
|
||||||
|
# device_query solo en Windows/Linux: la huella de entrada (posición del mouse + cuántas teclas
|
||||||
|
# hay presionadas). En macOS NO se usa —leer el teclado global dispara el permiso de
|
||||||
|
# Accesibilidad y el diálogo «… quiere controlar este ordenador»— y se sustituye por
|
||||||
|
# CGEventSourceSecondsSinceLastEventType (idle_seconds_macos en tracker.rs), que no pide permiso.
|
||||||
|
[target.'cfg(not(target_os = "macos"))'.dependencies]
|
||||||
|
device_query = "4"
|
||||||
|
|
||||||
# ── Excepción del video (Windows) ──
|
# ── Excepción del video (Windows) ──
|
||||||
# Para saber si «hay un video reproduciéndose» sin espiar el navegador: se mira el MEDIDOR de
|
# Para saber si «hay un video reproduciéndose» sin espiar el navegador: se mira el MEDIDOR de
|
||||||
# la salida de audio por defecto (WASAPI, IAudioMeterInformation). Si al frente hay un navegador
|
# la salida de audio por defecto (WASAPI, IAudioMeterInformation). Si al frente hay un navegador
|
||||||
|
|||||||
@@ -102,6 +102,22 @@ struct MenuState<R: Runtime>(Mutex<MenuUi<R>>);
|
|||||||
fn ahora_seg() -> u64 {
|
fn ahora_seg() -> u64 {
|
||||||
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0)
|
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_secs()).unwrap_or(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Segundos desde la última entrada del usuario (teclado/mouse/trackpad), preguntados al
|
||||||
|
// subsistema HID de macOS. CGEventSourceSecondsSinceLastEventType es de solo LECTURA y NO
|
||||||
|
// exige permiso de Accesibilidad ni de Monitorización de entrada (lo usan el salvapantallas y
|
||||||
|
// `ioreg HIDIdleTime`). Con esto el sensor sabe si hubo actividad SIN el diálogo «… quiere
|
||||||
|
// controlar este ordenador» que salía al leer el teclado global con device_query.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn idle_seconds_macos() -> f64 {
|
||||||
|
const HID_SYSTEM_STATE: i32 = 1; // kCGEventSourceStateHIDSystemState
|
||||||
|
const ANY_INPUT_EVENT: u32 = 0xFFFF_FFFF; // kCGAnyInputEventType
|
||||||
|
#[link(name = "CoreGraphics", kind = "framework")]
|
||||||
|
extern "C" {
|
||||||
|
fn CGEventSourceSecondsSinceLastEventType(state_id: i32, event_type: u32) -> f64;
|
||||||
|
}
|
||||||
|
unsafe { CGEventSourceSecondsSinceLastEventType(HID_SYSTEM_STATE, ANY_INPUT_EVENT) }
|
||||||
|
}
|
||||||
fn ahora_ms() -> u64 {
|
fn ahora_ms() -> u64 {
|
||||||
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as u64).unwrap_or(0)
|
SystemTime::now().duration_since(UNIX_EPOCH).map(|d| d.as_millis() as u64).unwrap_or(0)
|
||||||
}
|
}
|
||||||
@@ -427,8 +443,10 @@ pub fn iniciar<R: Runtime>(app: &AppHandle<R>) {
|
|||||||
let _ = CoInitializeEx(None, COINIT_MULTITHREADED);
|
let _ = CoInitializeEx(None, COINIT_MULTITHREADED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
let device_state = device_query::DeviceState::new();
|
let device_state = device_query::DeviceState::new();
|
||||||
let mut ultimo_input = ahora_seg();
|
let mut ultimo_input = ahora_seg();
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
let mut huella_anterior: (i32, i32, usize) = (0, 0, 0);
|
let mut huella_anterior: (i32, i32, usize) = (0, 0, 0);
|
||||||
let mut acumulado: HashMap<(String, String), Bloque> = HashMap::new();
|
let mut acumulado: HashMap<(String, String), Bloque> = HashMap::new();
|
||||||
let mut ocios_pendientes: Vec<Ocio> = Vec::new();
|
let mut ocios_pendientes: Vec<Ocio> = Vec::new();
|
||||||
@@ -504,14 +522,27 @@ pub fn iniciar<R: Runtime>(app: &AppHandle<R>) {
|
|||||||
}
|
}
|
||||||
tic_previo = ahora;
|
tic_previo = ahora;
|
||||||
|
|
||||||
// ¿Hubo entrada desde el último tic? Solo se compara una huella (posición del
|
// ¿Hubo entrada desde el último tic? Solo interesa el HECHO de que hubo entrada,
|
||||||
// mouse + cuántas teclas hay presionadas): nunca se registra QUÉ se tecleó.
|
// nunca QUÉ se tecleó ni dónde.
|
||||||
use device_query::DeviceQuery;
|
//
|
||||||
let mouse = device_state.get_mouse();
|
// macOS: se pregunta al sistema cuántos segundos lleva SIN entrada (HID). Esa API
|
||||||
let teclas = device_state.get_keys().len();
|
// NO exige permiso de Accesibilidad ni de Monitorización de entrada, así que ya no
|
||||||
let huella = (mouse.coords.0, mouse.coords.1, teclas);
|
// aparece el diálogo «… quiere controlar este ordenador». Inactividad < 1 tic =
|
||||||
let hubo_input = huella != huella_anterior || teclas > 0;
|
// hubo entrada. Aquí `device_state`/`huella_anterior` no existen.
|
||||||
huella_anterior = huella;
|
#[cfg(target_os = "macos")]
|
||||||
|
let hubo_input = idle_seconds_macos() < (TICK_SEG as f64) + 1.0;
|
||||||
|
// Windows/Linux: huella de entrada con device_query (posición del mouse + cuántas
|
||||||
|
// teclas hay presionadas). Leer esto ahí no pide permiso especial.
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
let hubo_input = {
|
||||||
|
use device_query::DeviceQuery;
|
||||||
|
let mouse = device_state.get_mouse();
|
||||||
|
let teclas = device_state.get_keys().len();
|
||||||
|
let huella = (mouse.coords.0, mouse.coords.1, teclas);
|
||||||
|
let cambio = huella != huella_anterior || teclas > 0;
|
||||||
|
huella_anterior = huella;
|
||||||
|
cambio
|
||||||
|
};
|
||||||
if hubo_input {
|
if hubo_input {
|
||||||
ultimo_input = ahora;
|
ultimo_input = ahora;
|
||||||
}
|
}
|
||||||
|
|||||||
Referencia en una nueva incidencia
Block a user