14

我编写了一个 C 程序/LaunchDaemon 来检查我的 MacBook 是否在家(连接到我的 WLAN)。如果是这样,它会禁用我的密码保护;如果没有,它会启用它。

简单的。但问题是,当我将 MacBook 带到其他任何地方并且密码保护被禁用时,它会在没有密码保护的情况下唤醒。

我对此的解决方法是:每次在它进入睡眠之前启用密码保护

问题:有什么方法可以知道我的 Mac 何时准备睡觉?我可以让我的程序听一些中断吗?

4

2 回答 2

7

您可以使用 I/O Kit 来完成,查看 Apple 的 QA1340:Registering and unregistering for sleep and wake notifications。您可能还想分析SleepWatcher实用程序源或根据您的需要使用/集成。从主页:

SleepWatcher 2.2(与 Mac OS X 10.5 到 10.8 一起运行,包括源代码)是用于 Mac OS X 的命令行工具(守护程序),用于监控 Mac 的睡眠、唤醒和空闲状态。它可用于在 Mac 或 Mac 的显示器进入睡眠模式或唤醒时、在没有用户交互的给定时间后或当用户在休息后恢复活动或 Mac 的电源时执行 Unix 命令笔记本连接或分离。它还可以使 Mac 进入睡眠模式或检索自上次用户活动以来的时间。要从该软件中受益,需要对 Unix 命令行有一点了解。

于 2012-11-23T18:43:25.333 回答
1

我附在我的 C 文件的内容下面,beforesleep.c当收到“将睡眠”通知时,它执行一些命令行命令(在我的情况下是 shell 命令和 AppleScript 脚本)。

你可以把你的代码放在哪里:

为了在 mac 进入休眠状态时运行您的代码,只需将system(...)调用替换为您希望运行的代码即可。

就我而言,我使用system()as 它允许我运行以字符串形式传递的 shell 命令,但如果您更喜欢只运行 C 代码,则可以将 C 代码放在那里。

如何构建它

为了构建这个文件,我运行:

gcc -framework IOKit -framework Cocoa beforesleep.c

评论

如果您要使用此代码,请确保它始终在后台运行。例如,我有一个 Cron 作业,它确保此代码始终运行,并再次启动它,以防它因任何原因意外被杀死(尽管到目前为止它从未发生在我身上)。如果你有足够的经验,你可以找到更聪明的方法来确保这一点。

更多信息

有关其工作原理的更多详细信息,请参阅此链接(已由 sidyll 建议)。

代码模板

#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
 
#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_init.h>
 
#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/IOMessage.h>
 
io_connect_t  root_port; // a reference to the Root Power Domain IOService
 
void
MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument )
{
    switch ( messageType )
    {
 
        
        case kIOMessageCanSystemSleep:
            IOAllowPowerChange( root_port, (long)messageArgument );
            break;
 
        case kIOMessageSystemWillSleep:
            system("/Users/andrea/bin/mylogger.sh");
            system("osascript /Users/andrea/bin/pause_clockwork.scpt");
 
            IOAllowPowerChange( root_port, (long)messageArgument );
            break;
 
        case kIOMessageSystemWillPowerOn:
            //System has started the wake up process...
            break;
 
        case kIOMessageSystemHasPoweredOn:
            //System has finished waking up...
        break;
 
        default:
            break;
 
    }
}
 
 
int main( int argc, char **argv )
{
    
    // notification port allocated by IORegisterForSystemPower
    IONotificationPortRef  notifyPortRef;
 
    // notifier object, used to deregister later
    io_object_t            notifierObject;
   // this parameter is passed to the callback
    void*                  refCon;
 
    // register to receive system sleep notifications
 
    root_port = IORegisterForSystemPower( refCon, &notifyPortRef, MySleepCallBack, &notifierObject );
    if ( root_port == 0 )
    {
        printf("IORegisterForSystemPower failed\n");
        return 1;
    }
 
    // add the notification port to the application runloop
    CFRunLoopAddSource( CFRunLoopGetCurrent(),
            IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes );
 
    /* Start the run loop to receive sleep notifications. Don't call CFRunLoopRun if this code
        is running on the main thread of a Cocoa or Carbon application. Cocoa and Carbon
        manage the main thread's run loop for you as part of their event handling
        mechanisms.
    */
    CFRunLoopRun();
 
    //Not reached, CFRunLoopRun doesn't return in this case.
    return (0);
}
于 2021-03-18T07:48:37.267 回答