【问题标题】:Objective C: Get notifications about a user's idle state目标 C:获取有关用户空闲状态的通知
【发布时间】:2011-01-10 03:59:11
【问题描述】:

我的可可应用程序运行后台任务,我想在用户空闲时停止(没有键盘/鼠标输入),然后在用户再次活跃时恢复。有没有办法注册空闲状态通知?

【问题讨论】:

    标签: objective-c time python-idle


    【解决方案1】:

    如果您无法链接到 Carbon(即您想编译 x86_64 位二进制文​​件),您可以在计时器中包装此函数(以秒为单位返回当前空闲时间,分辨率为双精度 - CFTimeInterval):

    #include <IOKit/IOKitLib.h>
    
    CFTimeInterval CFDateGetIdleTimeInterval() {
        mach_port_t port;
        io_iterator_t iter;
        CFTypeRef value = kCFNull;
        uint64_t idle = 0;
        CFMutableDictionaryRef properties = NULL;
        io_registry_entry_t entry;
    
        IOMasterPort(MACH_PORT_NULL, &port);
        IOServiceGetMatchingServices(port, IOServiceMatching("IOHIDSystem"), &iter);
        if (iter) {
            if ((entry = IOIteratorNext(iter))) {
                if (IORegistryEntryCreateCFProperties(entry, &properties, kCFAllocatorDefault, 0) == KERN_SUCCESS && properties) {
                    if (CFDictionaryGetValueIfPresent(properties, CFSTR("HIDIdleTime"), &value)) {
                        if (CFGetTypeID(value) == CFDataGetTypeID()) {
                            CFDataGetBytes(value, CFRangeMake(0, sizeof(idle)), (UInt8 *) &idle);
                        } else if (CFGetTypeID(value) == CFNumberGetTypeID()) {
                            CFNumberGetValue(value, kCFNumberSInt64Type, &idle);
                        }
                    }
                    CFRelease(properties);
                }
                IOObjectRelease(entry);
            }
            IOObjectRelease(iter);
        }
    
        return idle / 1000000000.0;
    }
    

    您需要将您的代码链接到IOKit.framework

    【讨论】:

    • 小编辑,entry = IOIteratorNext(tier) 应该是entry = IOIteratorNext(iter)。
    • 请注意,HIDIdleTime 不是很可靠,并且在某些 Mac 上由于未知原因它总是返回零(可能某些连接的设备会重置空闲时间计数)。
    【解决方案2】:

    有一个 Carbon API 会在称为 EventLoopIdleTimer 的特定持续时间后没有用户事件时发送通知。 Uli Kusterer 为 here (look for UKIdleTimer) 编写了一个 Cocoa 包装器。

    如果您想要更低级别的东西,您可以结合使用计时器和 CoreGraphics 函数 CGEventSourceSecondsSinceLastEventType(在 &lt;CoreGraphics/CGEventSource.h&gt; 中提供)来实现您想要的行为。

    【讨论】:

    • 是否可以在 iOS 上做同样的事情?
    • 这些 API 在 iOS 上均不可用。我也不知道有没有等价物。
    • 不要在启动守护进程中使用 CGEventSourceSecondsSinceLastEventType。
    • HIDIdleTime:这个函数在某些机器上总是返回零,原因不明(可能与连接的设备有关)。
    【解决方案3】:

    Apple 的Technical Q&A QA1340 Registering and unregistering for sleep and wake notifications 可能正是您想要的。

    如果您需要比 NSWorkspaceWillSleepNotification 更多的控制权(清单 1),请使用 I/O Kit 并注册以接收电源通知(清单 3)。

    【讨论】:

    • 依赖睡眠/唤醒通知的问题是,如果用户将他们的睡眠设置设置为“从不”,他们将永远不会被发送。我想将空闲时间计为没有键盘/鼠标活动的时间。
    • 抱歉,您的意思是当应用程序进入理想睡眠时。 kperryua 的 CGEventSourceSecondsSinceLastEventType 解决方案对于监控自上次用户输入以来的时间是正确的。
    【解决方案4】:

    我使用了不同的方法。 子类化 UIApplication 我重写了 sendEvent 方法过滤触摸(实际上你可以过滤任何类型的事件、加速、触摸等)。 使用共享变量和后台计时器,我管理了“空闲”。 每次用户触摸屏幕时,都会使用当前时间间隔(当前时间)设置变量。 计时器触发方法检查自上次触摸以来经过的时间,如果大于阈值(在我的情况下约为 90 秒),您可以发布自己的通知。

    我使用这种简单的方法创建了一组自定义应用程序,这些应用程序在闲置一段时间后会自动调用“屏幕保护程序”应用程序。

    没有什么聪明的,它只是做这项工作。

    希望对您有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-23
      • 2012-11-05
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      • 2010-12-15
      • 2018-10-09
      • 1970-01-01
      相关资源
      最近更新 更多