Descartar las notificaciones de MacOS Big Sur con el teclado

Durante mucho tiempo he usado un Applescript activado desde un atajo de teclado para descartar notificaciones en MacOS. Funcionó simulando un clic en el botón "cerrar" de cada ventana abierta del Centro de notificaciones.

Desde la actualización a Big Sur (actualmente 11.0.1), las notificaciones ya no tienen un botón de cierre. En su lugar, cuando pasa el mouse sobre ellos, aparecerá un botón "X". Para una persona que tiene dificultad para hacer clic con precisión (tengo un ligero temblor en la mano), usar el mouse/panel táctil es difícil.

¿Alguien tiene sugerencias sobre cómo restaurar esa funcionalidad para poder mantener mis manos en el teclado?

Mi configuración

Estoy usando Automator para probar esto.

En Preferencias del Sistema > Notificaciones , seleccioné Automator :

  • Permitir notificaciones es verdadero.
  • Estilo de alerta de Automator: es Alertas .
  • La agrupación de notificaciones es automática .

Pruebas

  • Abrí Automator y creé un nuevo flujo de trabajo.
  • Agregué tres instancias de la acción Mostrar notificación .
  • Les di Título: valores de test 1, test 2y test 3.
  • Y Subtítulo: valores de subtitle 1, subtitle 2y subtitle 3.
  • Y Mensaje: valores de message 1, message 2y message 3.
  • Ejecuté el flujo de trabajo usando ⌘+R .
  • En la esquina superior derecha de mi pantalla, veo una notificación de Automator apilada sobre otras dos. Solo la notificación test 3es completamente visible y tiene la anotación "2 notificaciones más" en la parte inferior.

Guión de @AndrewJanian

  • Una vez más, ¡gracias, Andrew, por proporcionarnos el guión!
  • Agregué la línea #!/usr/bin/osascriptal inicio del script y la guardé como andrew.applescript.
  • Hice el archivo ejecutable. ( chmod 755 andrew.applescript).
  • Lo ejecuté en una ventana de terminal ( ./andrew.applescript)
  • El resultado de correr es:
    • las notificaciones agrupadas se desagrupan (así que veo test 3, test 2y test 1se apilan de arriba a abajo en el área de notificación
    • el terminal muestra el siguiente error
      ./andrew.applescript:370:377: execution error: System Events got an error: Can’t get action "Name:Clear All
      Target:0x60000116ff20
      Selector:_internal_handleCustomActionWithUiAction:" of group 1 of UI element 1 of scroll area 1 of window "Notification Center" of application process "NotificationCenter". (-1728)
      

Intentaré jugar con él para ver si puedo hacerlo funcionar con modificaciones.

Nota: si vuelvo a ejecutar el script, comenzando desde el estado desagrupado:

  • descarta la notificación superior ( test 3)
  • y muestra lo siguiente en la terminal:
    action Name:Close
    Target:0x60000116ff20
    Selector:_internal_handleCustomActionWithUiAction: of group 1 of UI element 1 of scroll area 1 of window Notification Center of application process NotificationCenter
    
Si la notificación está configurada en tipo Banner, se descartará automáticamente después de un tiempo, no se necesita interacción.
Gracias, @AivarPaalberg. Realmente quiero que las notificaciones permanezcan hasta que las descarte. Solo quiero poder descartarlos sin usar el mouse. [En lugar del antiguo botón 'Cerrar', ahora hay un pequeño botón X para hacer clic; es casi como si quisieran hacerlo tan pequeño como el botón "cerrar" para anuncios móviles. :-)
Puede descartar las notificaciones sin apuntar a las pequeñas Xsi tiene un panel táctil. Mientras se desplaza sobre cualquier lugar sobre la notificación, deslice dos dedos de izquierda a derecha para descartarla. Desde la perspectiva de la productividad, personalmente no creo que las notificaciones en el escritorio y la interacción inmediata con ellas sea un buen flujo de trabajo.
Gracias, @AivarPaalberg. Eso ciertamente ayuda, pero estoy de acuerdo en que no es ideal tener que mover el cursor del mouse hacia esa esquina solo para descartar las notificaciones. Prefiero mi antiguo flujo de trabajo de ejecutar un comando (bueno, presionar una combinación de teclas) para hacer que desaparezcan mientras mantengo mi atención en lo que se interrumpió.
Y la cruz es realmente muy pequeña. Tan pequeño que acabo de notarlo... Hay un problema con la interfaz de usuario aquí, Apple.

Respuestas (10)

Actualizar

Estoy publicando una versión más robusta que evolucionó desde mi publicación inicial. Esto parece hacer un trabajo razonable al cerrar todas las ventanas, pero a veces es lento de ejecutar. Como dije en los comentarios, no sé mucho sobre AppleScript, por lo que quizás alguien que sepa lo que está haciendo pueda decirnos cómo mejorar el rendimiento.

activate application "NotificationCenter"
tell application "System Events"
    tell process "Notification Center"
        repeat
            
            try
                set theWindow to group 1 of UI element 1 of scroll area 1 of window "Notification Center"
            on error
                exit repeat
            end try
            
            try
                set theActions to actions of theWindow
                
                # Try to close the whole group first. If that fails, close individual windows.
                repeat with theAction in theActions
                    if description of theAction is "Clear All" then
                        set closed to true
                        tell theWindow
                            perform theAction
                        end tell
                        exit repeat
                    end if
                end repeat
                
                repeat with theAction in theActions
                    if description of theAction is "Close" then
                        set closed to true
                        tell theWindow
                            perform theAction
                        end tell
                        exit repeat
                    end if
                end repeat
                
            end try
        end repeat
    end tell
end tell

Original

Sí, gracias por publicar el guión, @AndrewJanian.

Recibí un error similar al de @ColinFraizer cuando lo usé tal cual. Creo que el problema es la repetición interna de las acciones: intenta acceder a las acciones en algunos casos después de cerrar la ventana. Un ajuste menor soluciona este problema para mí:

activate application "NotificationCenter"
tell application "System Events"
    tell process "Notification Center"
        set theWindow to group 1 of UI element 1 of scroll area 1 of window "Notification Center"
        # click theWindow
        set theActions to actions of theWindow
        repeat with theAction in theActions
            if description of theAction is "Close" then
                tell theWindow
                    perform theAction
                end tell
                exit repeat
            end if
        end repeat
    end tell
end tell
¿Funciona en Big Sur? Recibo un error en Eventos del sistema: No se puede obtener el proceso "Centro de notificaciones" aquí.
Cuando ejecuto esta secuencia de comandos en el Editor de secuencias de comandos en macOS Big Sur 11.2, descarta solo la notificación superior, pero no todas las notificaciones.
@AmadeuCavalcanteFilho Sí, lo ejecuto en Big Sur. Soy un novato total de AppleScript, así que me temo que no sé qué está causando ese error en particular.
@Empleado ¡Sí! Actualizaré la publicación para agregar una versión más reciente que he convertido en una forma más robusta. La versión actualizada hace un trabajo bastante razonable al borrar todas las notificaciones, aunque parece lento. No sé nada sobre cómo escribir un buen AppleScript, así que quizás alguien que sepa lo que está haciendo pueda mejorar esto.
@AmadeuCavalcanteFilho el nombre del proceso varía dependiendo de dónde esté registrada su computadora portátil. Para mí es "Centro de notificaciones"
Esto ya no me funciona desde que instalé MacOS Ventura. ¿Alguna sugerencia?
@incandescentman Tengo el mismo problema después de actualizar. Parece que la forma de acceder a la ventana ha cambiado, pero intente reemplazar la set theWindowlínea existente conset theWindow to group 1 of UI element 1 of scroll area 1 of UI element 1 of window "Notification Center"
@lunzwell Wow, eso funcionó, ¡gracias!
Sigo recibiendo el error de índice no válido con la edición de @lunz. Monterey OS con idioma configurado en inglés de EE. UU.

Tengo un AppleScript que funciona. Encontré los elementos usando UIBrowser . La advertencia es que la notificación debe tener una acción "Cerrar". Todas las notificaciones que he encontrado tienen esa acción.

activate application "NotificationCenter"
tell application "System Events"
    tell process "Notification Center"
        set theWindow to group 1 of UI element 1 of scroll area 1 of window "Notification Center"
        click theWindow
        set theActions to actions of theWindow
        repeat with theAction in theActions
            if description of theAction is "Close" then
                tell theWindow
                    perform theAction
                end tell
            end if
        end repeat
    end tell
end tell
Gracias, @Andrew. Lamentablemente, esto no funciona para mí en Big Sur. Me encantaría explicar más, pero el comentario tiene caracteres limitados y no me permite agregar saltos de línea, lo que lo hace muy molesto. Voy a editar mi pregunta para dar el contexto.

Encontré una acción de JavaScript de Automator que funciona:

function run(input, parameters) {

  const notNull = (val) => {
    return val !== null && val !== undefined;
  }

  const appName = "";
  const verbose = true;

  const CLEAR_ALL_ACTION = "Clear All";
  const CLOSE_ACTION = "Close";

  const hasAppName = notNull(appName) && appName !== "";
  const appNameForLog = hasAppName ? (" " + appName) : "";

  const log = (message, ...optionalParams) => {
    console.log("[close_notifications] " + message, optionalParams);
  }

  const logVerbose = (message) => {
    if (verbose) {
      log(message);
    }
  }

  const findCloseAction = (group, closedCount) => {
    try {
      let clearAllAction;
      let closeAction;
      for (let action of group.actions()) {
        if (action.description() === CLEAR_ALL_ACTION) {
          clearAllAction = action;
          break;
        } else if (action.description() === CLOSE_ACTION) {
          closeAction = action;
        }
      }
      if (notNull(clearAllAction)) {
        return clearAllAction;
      } else if (notNull(closeAction)) {
        return closeAction;
      }
    } catch (err) {
      logVerbose(`${closedCount}: Caught error while searching for close action, window is probably closed.`);
      logVerbose(err);
      return null;
    }
    log("No close action found for notification");
    return null;
  }

  const notificationGroupMatches = (group) => {
    if (!hasAppName) {
      return true;
    }

    logVerbose(`Checking UI elements of group...`);
    try {
      for (let elem of group.uiElements()) {
        if (hasAppName && elem.role() === "AXStaticText" && elem.value().toLowerCase() === appName.toLowerCase()) {
          return true;
        }
      }
    } catch (err) {
      logVerbose(`Caught error while checking window, window is probably closed.`);
      logVerbose(err);
    }
    return false;
  }

  const closeNextGroup = (groups, closedCount) => {
    for (let group of groups) {
      if (notificationGroupMatches(group)) {
        logVerbose(`${closedCount}: FIND_CLOSE_ACTION`);
        let closeAction = findCloseAction(group, closedCount);

        if (notNull(closeAction)) {
          logVerbose(`${closedCount}: CLOSING`);
          try {
            closeAction.perform();
            logVerbose(`${closedCount}: CLOSE_PERFORMED`);
            return [true, 1];
          } catch (err) {
            logVerbose(`${closedCount}: Caught error while performing close action, window is probably closed.`);
            logVerbose(err);
          }
        }
        return [true, 0];
      }
    }
    return false;
  }

  const getNotificationCenter = () => {
    let systemEvents = Application("System Events");
    return systemEvents.processes.byName("NotificationCenter");
  }

  const getNotificationCenterGroups = () => {
    return getNotificationCenter().windows[0].uiElements[0].uiElements[0].uiElements();
  }

  let notificationCenter = getNotificationCenter();
  if (notificationCenter.windows.length <= 0) {
    return input;
  }

  let groupsCount = getNotificationCenterGroups().filter(group => notificationGroupMatches(group)).length;

  if (groupsCount > 0) {
    logVerbose(`Closing ${groupsCount}${appNameForLog} notification group${(groupsCount > 1 ? "s" : "")}`);

    let closedCount = 0;
    let maybeMore = true;
    while (maybeMore) {
      let closeResult = closeNextGroup(getNotificationCenterGroups(), closedCount);
      maybeMore = closeResult[0];
      if (maybeMore) {
        closedCount = closedCount + closeResult[1];
      }
    }
  } else {
    throw Error(`No${appNameForLog} notifications found...`);
  }

  return input;
}
¿Cómo lo ejecutas? todavía en el editor de applescript?

Esto también me ha estado molestando, pero hoy logré que algo parecido funcionara.

Primero instalé clickclick , una herramienta de línea de comandos que te permite simular el movimiento del mouse y los clics. Está disponible a través de Homebrew con brew install cliclick.

Luego descubrí las coordenadas de la hora en la parte superior derecha, que cuando se hace clic, abre el centro de notificaciones. Esto tomó un poco de experimentación.

Luego descubrí las coordenadas del botón de cerrar que aparece al pasar el mouse. De nuevo, esto requirió un poco de experimentación.

Luego escribí un script que usa cliclicky estas coordenadas para abrir el Centro de notificaciones, mueva el mouse sobre donde aparece el botón "borrar", duerme durante 500 milisegundos para darle tiempo a que aparezca y luego haga clic en él. ¡Funcionó!

export PATH=/usr/local/bin:$PATH # make sure cliclick binary is on the path
cliclick c:1900,10               # click on the time to open Notification Center
cliclick -w 500 m:1570,45 c:.    # move mouse over the close button, wait for it to appear, then click it

Luego traté de hacer que esto funcionara como un servicio de Automator. Lo hice ejecutar desde Automator, pero aunque el script funcionó allí, se negó a funcionar cuando lo asigné a un atajo de teclado. Golpeé mi cabeza contra una pared de ladrillos probando diferentes permisos, etc. hasta que me rendí.

Probé la aplicación HotKey, pero obtuve el mismo resultado.

Eventualmente, pensé en probar un flujo de trabajo de Alfred, para poder abrir Alfred con Cmd+Space y luego escribir "Borrar notificaciones" para borrarlas. Mucho más detallado que un atajo de teclado pero... ¡funcionó! Y no se necesita ratón. Mi mejor suposición de por qué es que cuando Alfred ejecuta el script, siempre se ejecuta desde Alfred , y Alfred ya tiene los permisos necesarios para mover el mouse y hacer clic en cosas, pero cuando intento adjuntar un servicio de Automator a un atajo de teclado , ese servicio se ejecuta con los permisos que tenga la aplicación actualmente enfocada.

Esto se siente como una solución terriblemente frágil (¿qué sucede cuando no estoy usando mi monitor externo?) y parece una tontería que no haya una forma integrada de hacer esto, pero al menos funciona.

TL; DR una combinación de un script usando cliclicky un flujo de trabajo Alfred para ejecutarlo.

Esto es genial, pero está codificado para las dimensiones de su monitor. Es mejor si mueve el mouse hacia el extremo superior derecho y luego usa cantidades negativas para llegar a las posiciones requeridas.

He probado la mayoría de las soluciones que se ofrecen aquí, pero ninguna ha funcionado tan bien como quisiera. Desde entonces, he intentado usar Keysmith y estoy muy contento con los resultados.

Keysmith ofrece un atajo existente para esto. Se parece a esto:

Captura de pantalla de un atajo de Keysmith para cerrar la notificación

Esto le da la posibilidad de presionar ⌘ escpara cerrar las notificaciones (desde cualquier aplicación).

El único problema que tuve fue que una vez que se cerraron las notificaciones, la ventana activa de la aplicación actual perdió el foco. Afortunadamente, puede agregar un paso adicional en el atajo de Keysmith para recuperar el foco de la ventana activa: ⌃F4. Eso se ve así en Keysmith:

Captura de pantalla de un atajo de Keysmith para cerrar notificaciones.  El atajo es: en el Centro de notificaciones, "Haga clic en Cerrar" y luego "Presione ⌃F4"

Genial aplicación, gracias por la recomendación.
Esto no funciona en Big Sur para cerrar todo si hay un grupo, solo funciona en una sola notificación. El error de Keysmith dice algo así como "no se puede encontrar el elemento".
Esto tampoco funciona en Monterrey para cerrar todo si hay un grupo, solo funciona en una sola notificación. Keysmith da un error.

Gracias @lunzwell. Agregué una rutina de error.

on run
    try
        activate application "NotificationCenter"
        tell application "System Events"
            tell process "Mitteilungszentrale"
                set theWindow to group 1 of UI element 1 of scroll area 1 of window "Notification Center"
                # click theWindow
                set theActions to actions of theWindow
                repeat with theAction in theActions
                    if description of theAction is "Schließen" then
                        tell theWindow
                            perform theAction
                        end tell
                        exit repeat
                    end if
                end repeat
            end tell
        end tell
    on error e
        display dialog e
        activate
    end try
end run

Sin embargo, me pregunto si hay una manera de evitar un mensaje de error cuando se ejecuta accidentalmente el script sin notificaciones en la pantalla.

También tradujiste el guión al alemán. :D
Sí, lo siento. Me olvide de eso. Necesitaba hacer eso para poder trabajar en mi máquina. Sería genial si eso no fuera necesario.

Hice algunas mejoras en este script:

  1. Agregué manejo de errores (una trampa más estrecha, en inglés) /ht @ Ptujec
  2. Llamo recursivamente a esta función después de un retraso (porque descubrí que para algunas notificaciones, las cerraba, todas desaparecían, pero luego todas las demás que no estaban en la parte superior de la pila reaparecían unos segundos más tarde)
  3. Agregué soporte para el "Clear All"botón (descubrí que a veces tenía que usar esto en lugar de "Close")

Mi script completo está en mis archivos de puntos en GitHub aquí y lo tengo expuesto a través de Alfred Workflow aquí .

#!/usr/bin/osascript
# via:
# https://apple.stackexchange.com/questions/408019/dismiss-macos-big-sur-notifications-with-keyboard

# define a function we can call recursively
on dismiss_notification_center(n)
    log "dismiss_notification_center: " & n
    set performedAction to false
    activate application "NotificationCenter"
    tell application "System Events"
        tell process "Notification Center"
            try
                # when there are no notifications, this may result in:
                # 'System Events got an error: Can’t get window "Notification Center" of process "Notification Center".'
                # This is our recursion base case.
                set theWindow to group 1 of UI element 1 of scroll area 1 of window "Notification Center"
            on error e
                # log the error to the console:
                log quoted form of e
                return
            end try
            # log theWindow

            set theActions to actions of theWindow
            repeat with theAction in theActions
                # log theAction
                # log description of theAction
                if description of theAction is in {"Close", "Clear All"} then
                    tell theWindow
                        perform theAction
                        set performedAction to true
                    end tell
                    exit repeat
                end if
            end repeat
        end tell
    end tell
    # log "performedAction: " & performedAction
    if performedAction
        # for some reason, the loop doesn't close them all when grouped, so
        # we need to recurse. But, first we have to sleep to allow notif to re-appear:
        do shell script "/bin/sleep 3" # min sleep time that worked for me, and sometimes reminders take even longer
        dismiss_notification_center(n + 1)
    end if
end dismiss_notification_center

# first call to recursive function:
dismiss_notification_center(0)

También obtuve un script de trabajo a través de clickclick. Aquí está mi versión del script que uso. He unido un montón de bibliotecas de usuario que usé. Lo tengo asignado al control de voz creado a través de Automator en lugar de un atajo de teclado.

Todavía falla cuando la notificación se niega a mostrar el botón de cerrar sin importar cuánto muevas el puntero encima.

activate application "NotificationCenter"
delay 0.1
tell application "System Events" to tell process "Notification Center"
    if (count of windows) is 0 then return 
    
    set theGroup to first group of UI element 1 of scroll area 1 of window "Notification Center"        
    tell theGroup
        if my isStacked(theGroup) then
            click theGroup
            delay 1
        end if
        
        my dismissNotification(theGroup)
    end tell
end tell

on isStacked(nextGroup)
    tell application "System Events" to tell process "Notification Center"          
        get help of nextGroup is "Activate to expand"
    end tell
end isStacked

to dismissNotification(theNotification)
    script CloseButtonClicker
        -- pointer's saveCurrentPosition()
        movePointer at theNotification
        delay 0.1
        tell application "System Events"
            try
                click button "Close" of theNotification
                return true
            end try
            delay 0.1
        end tell
        -- pointer's restorePosition()
    end script  
    exec on CloseButtonClicker for 3 by 0.4  -- Retry on failure up to 3x. Optional.
end dismissNotification

to movePointer at theUi
    set coord to getCoord at theUi
    set formattedCoord to formatCoordinates(item 1 of coord, item 2 of coord)

    set clickCommand to "/usr/local/bin/cliclick -e 1 m:" & formattedCoord
    do shell script clickCommand
end movePointer

to formatCoordinates(x, y)
    if x is less than 0 then set x to "=" & x
    if y is less than 0 then set y to "=" & y

    return x & "," & y as text
end formatCoordinates

to exec on scriptObj by sleep : 1 for ntimes : 1000
    repeat ntimes times
        try
            set handlerResult to run of scriptObj
            if handlerResult is not missing value then return         handlerResult
        end try 
        delay sleep
    end repeat
    return missing value
end exec

¿Alguien había considerado simplemente usar:

pkill NotificationCenter

El proceso reaparece después de hacer esto. Lo uso para borrar todas las notificaciones que recibo con una unidad externa.

Las notificaciones regresan casi de inmediato; Probablemente estés en una versión antigua de macOS.

Esta respuesta sugiere que en Big Sur en su versión actual no hay una forma satisfactoria de descartar notificaciones con un teclado. En cambio, esta respuesta explica formas alternativas de descartarlos que no se mencionan en ninguna otra parte de este hilo.

Deslizar dos dedos hacia la derecha en el grupo de notificaciones funciona en Big Sur con el panel táctil de la Macbook (no estoy seguro acerca de Yosemite). También funciona con clic izquierdo y arrastrar hacia la derecha. Supongo que esto también funcionaría con un Apple Magic Mouse o Magic Trackpad. Personalmente, creo que deslizar dos dedos y hacer clic con el botón izquierdo y arrastrar es más fácil de hacer que hacer clic en el ícono X y luego hacer clic en Borrar todo. Me resulta muy difícil coordinar el doble clic en un área tan pequeña.

Esto no "borra" todas las notificaciones de forma permanente. Todavía se mostrarán si abre la barra lateral de notificaciones. También mostrarán si llega otro mensaje; en lugar de ver 1 notificación, mostrará N + 1 notificaciones disponibles.

Esta idea se anotó en un comentario en otra respuesta: Descartar las notificaciones de MacOS Big Sur con el teclado .

La razón por la que sugiero que no existe una forma satisfactoria de descartar notificaciones con un teclado es: un script automatizado es notablemente lento para una gran cantidad de notificaciones, la solución Keysmith no funcionó en Big Sur (error), pkill/killall NotificationCenter no funcionó descartar las notificaciones (lo que significa que un atajo de teclado no ayudaría). No probé la solución clickclick, me preocupaba perder demasiado tiempo tratando de hacer que funcionara y que experimentaría los mismos retrasos que un script automatizado.

Este hilo es similar a ¿Cómo borro todas las notificaciones de OS X con 1 clic? .

La pregunta pregunta cómo hacerlo con el teclado. Su primer párrafo es todo sobre el mouse y el trackpad.
Sí, gracias por notarlo. Lo modifiqué para que el descargo de responsabilidad de la respuesta aparezca como el primer párrafo en lugar de más adelante en la respuesta.