是否可以以编程方式打开/关闭mac os x的“请勿打扰”,即通过代码进行。我已经通过Google做过一些研究,例如:

  • 通过自动脚本applescripting notification center scheduling do not disturb
    顺便说一句,我不起作用,当我杀死所有NotificationCenter时,请勿打扰开关仍处于关闭状态
  • 通过代码programmatic equivalent of defaults write command e.g. how to use NSUserDefaults编写默认值,但是如何使用args -currentHost(在上面的链接中的文章中提到)
  • 最佳答案

    遗憾的是(目前还不足为奇),没有用于处理用户通知首选项的公共(public)API,其中之一是请勿打扰模式(DND)。

    但是,如果您想提供在应用程序中打开和关闭DND的功能,那么您实际上并不会走运:您可以通过三种方式进行选择。

    #1运行此微小的AppleScript并查看结果

    这是philastokes编写的AppleScript,它考虑到在菜单栏中的通知中心图标上单击选项即可完成我们想要的操作:它会切换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
    



    最后一步是将其包装到Objctive-C / Swift代码中:
    NSString *source  = ... // the AppleScript code
    NSAppleScript *script = [[NSAppleScript alloc] initWithSource: source];
    NSDictionary *errorInfo = nil;
    [script executeAndReturnError: &errorInfo];
    

    #2。直接使用辅助功能API

    不用让AppleScript引擎处理用户交互,我们可以使用系统中可用的Accessibility API使他们成为我们自己:


    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;
        }
    }
    
    optionKeyDown()optionKeyUp()在哪里
    #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。假设我们是Notifications.prefPane

    您可能已经注意到,可以通过在“通知”首选项 Pane 中将DND模式设置为00:00到23:59来启用DND模式。禁用DND只是取消选中该复选框。

    这是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];
    }
    

    关于macos - 是否可以以编程方式打开/关闭OS X的 “do not disturb”,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25210120/

    10-10 20:30