sistema origen operativo objective framework macos cocoa

macos - origen - sistema operativo swift



¿Es posible activar/desactivar "no molestar" para OS X programáticamente (2)

Desafortunadamente (no es sorprendente), no hay una API pública para tratar con las preferencias de notificaciones del usuario, una de las cuales es el modo No molestar (DND).

Sin embargo, si desea proporcionar la función de activación y desactivación de DND en su aplicación, en realidad no está fuera de suerte: hay tres formas para elegir.

# 1. Ejecute este pequeño AppleScript y vea los resultados

Aquí hay un AppleScript por applehelpwriter.com/2014/12/10/… que tiene en cuenta que hacer clic en el icono del Centro de notificaciones en la barra de menú hace exactamente lo que queremos: ¡alterna el modo DND!

(* Copyright © philastokes from applehelpwriter.com *) (* Link: http://applehelpwriter.com/2014/12/10/applescript-toggle-notification-centre-yosemite *) tell application "System Events" tell application process "SystemUIServer" try (* Replace "Notification Center" with "NotificationCenter" here if you''re targeting OS X 10.10 *) if exists menu bar item "Notification Center, Do Not Disturb enabled" of menu bar 2 then key down option (* Replace "Notification Center" with "NotificationCenter" here if you''re targeting OS X 10.10 *) click menu bar item "Notification Center, Do Not Disturb enabled" of menu bar 2 key up option else key down option click menu bar item "Notification Center" of menu bar 2 key up option end if on error key up option end try end tell end tell

Tenga en cuenta que debe reemplazar el "Notification Center" por "NotificationCenter" todas partes si está orientado a OS X 10.10

Además, la ejecución de este código requiere que su aplicación tenga habilitada la Accesibilidad.

Un último paso es envolverlo en código Objctive-C / Swift:

NSString *source = ... // the AppleScript code NSAppleScript *script = [[NSAppleScript alloc] initWithSource: source]; NSDictionary *errorInfo = nil; [script executeAndReturnError: &errorInfo];

# 2. Usa la API de accesibilidad directamente

En lugar de dejar que el motor AppleScript se ocupe de las interacciones de los usuarios, podríamos hacer que ellos mismos utilicen la API de accesibilidad disponible en el sistema:

La ejecución de este código requiere que su aplicación tenga habilitada la Accesibilidad.

pid_t SystemUIServerPID = [[NSRunningApplication runningApplicationsWithBundleIdentifier: @"com.apple.systemuiserver"].firstObject processIdentifier]; assert(SystemUIServerPID != 0); AXUIElementRef target = AXUIElementCreateApplication(SystemUIServerPID); assert(target != nil); CFArrayRef attributes = nil; AXUIElementCopyAttributeNames(target, &attributes); assert([(__bridge NSArray *)attributes containsObject: @"AXExtrasMenuBar"]); CFTypeRef menubar; AXUIElementCopyAttributeValue(target, CFSTR("AXExtrasMenuBar"), &menubar); CFTypeRef children; AXUIElementCopyAttributeValue(menubar, CFSTR("AXChildren"), &children); // XXX: I hate mixing CF and Objective-C like this but it''s just a PoC code. // Anyway, I''m sorry NSArray *items = (__bridge NSArray *)children; for (id x in items) { AXUIElementRef child = (__bridge AXUIElementRef)x; CFTypeRef title; AXUIElementCopyAttributeValue(child, CFSTR("AXTitle"), &title); assert(CFGetTypeID(title) == CFStringGetTypeID()); // XXX: the proper check would be to match the whole "Notification Center" string, // but on OS X 10.10 it''s "NotificationCenter" (without the space in-between) and // I don''t feel like having two conditionals here if (CFStringHasPrefix(title, CFSTR("Notification"))) { optionKeyDown(); AXUIElementPerformAction(child, kAXPressAction); optionKeyUp(); break; } }

donde optionKeyDown() y optionKeyUp() son

#define kOptionKeyCode (58) static void optionKeyDown(void) { CGEventRef e = CGEventCreateKeyboardEvent(NULL, kOptionKeyCode, true); CGEventPost(kCGSessionEventTap, e); CFRelease(e); } static void optionKeyUp(void) { CGEventRef e = CGEventCreateKeyboardEvent(NULL, kOptionKeyCode, false); CGEventPost(kCGSessionEventTap, e); CFRelease(e); }

# 3. Vamos a pretender que somos Notifications.prefPane

Es posible que haya notado que podría habilitar el modo DND a través del panel de preferencias de Notificaciones configurando el rango del modo de 00:00 a 23:59. Y deshabilitar DND sería simplemente desmarcar la casilla de verificación.

Esto es lo que hay dentro de Notifications.prefPane:

void turnDoNotDisturbOn(void) { // The trick is to set DND time range from 00:00 (0 minutes) to 23:59 (1439 minutes), // so it will always be on CFPreferencesSetValue(CFSTR("dndStart"), (__bridge CFPropertyListRef)(@(0.0f)), CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); CFPreferencesSetValue(CFSTR("dndEnd"), (__bridge CFPropertyListRef)(@(1440.f)), CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); CFPreferencesSetValue(CFSTR("doNotDisturb"), (__bridge CFPropertyListRef)(@(YES)), CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); // Notify all the related daemons that we have changed Do Not Disturb preferences commitDoNotDisturbChanges(); } void turnDoNotDisturbOff() { CFPreferencesSetValue(CFSTR("dndStart"), NULL, CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); CFPreferencesSetValue(CFSTR("dndEnd"), NULL, CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); CFPreferencesSetValue(CFSTR("doNotDisturb"), (__bridge CFPropertyListRef)(@(NO)), CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); commitDoNotDisturbChanges(); } void commitDoNotDisturbChanges(void) { /// XXX: I''m using kCFPreferencesCurrentUser placeholder here which means that this code must /// be run under regular user''s account (not root/admin). If you''re going to run this code /// from a privileged helper, use kCFPreferencesAnyUser in order to toggle DND for all users /// or drop privileges and use kCFPreferencesCurrentUser. CFPreferencesSynchronize(CFSTR("com.apple.notificationcenterui"), kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); [[NSDistributedNotificationCenter defaultCenter] postNotificationName: @"com.apple.notificationcenterui.dndprefs_changed" object: nil userInfo: nil deliverImmediately: YES]; }

¿Es posible activar / desactivar "No molestar" para mac os x mediante programación, lo que significa por código. He hecho algunas investigaciones por google, tales como:

  1. Por secuencia de comandos Automator la programación del centro de notificación de manzanas no molesta . Por cierto, no lo hago funcionar, cuando voy a NotificationCenter, el interruptor No molestar todavía está apagado

  2. Escritura de valores predeterminados por código, equivalente programático de los comandos de escritura predeterminados, por ejemplo, cómo usar NSUserDefaults , sin embargo, cómo trabajar con args -currentHost (mencionado en el artículo en el enlace anterior)


La solución No. 2 de Dmitry fue la única que funcionó correctamente para mí.

Aquí hay una versión Swift 4 de esto:

func enableDND(){ CFPreferencesSetValue("dndStart" as CFString, CGFloat(0) as CFPropertyList, "com.apple.notificationcenterui" as CFString, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost) CFPreferencesSetValue("dndEnd" as CFString, CGFloat(1440) as CFPropertyList, "com.apple.notificationcenterui" as CFString, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost) CFPreferencesSetValue("doNotDisturb" as CFString, true as CFPropertyList, "com.apple.notificationcenterui" as CFString, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost) commitDNDChanges() } func disableDND(){ CFPreferencesSetValue("dndStart" as CFString, nil, "com.apple.notificationcenterui" as CFString, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost) CFPreferencesSetValue("dndEnd" as CFString, nil, "com.apple.notificationcenterui" as CFString, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost) CFPreferencesSetValue("doNotDisturb" as CFString, false as CFPropertyList, "com.apple.notificationcenterui" as CFString, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost) commitDNDChanges() } func commitDNDChanges(){ CFPreferencesSynchronize("com.apple.notificationcenterui" as CFString, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost) DistributedNotificationCenter.default().postNotificationName(NSNotification.Name(rawValue: "com.apple.notificationcenterui.dndprefs_changed"), object: nil, userInfo: nil, deliverImmediately: true) }