【问题标题】:Last Instance of User Interaction on MacMac 上用户交互的最后一个实例
【发布时间】:2012-01-23 20:31:37
【问题描述】:

我正在尝试检测用户与给定 Mac 交互的最后一个实例(最好在某种可比较的数据结构中,例如自纪元以来的秒数。)

这种交互应该包括打字、鼠标移动、应用交互等。但是,我不打算确定计算机是锁定还是屏幕保护,因为这些状态取决于用户的偏好。

【问题讨论】:

    标签: macos cocoa user-interaction


    【解决方案1】:

    使用IOKit 框架。看看RHSystemIdleTimer

    #import <Cocoa/Cocoa.h>
    
    @interface RHSystemIdleTimer : NSObject {
        NSTimer *idleTimer, *continuingIdleTimer;
        id delegate;
        NSTimeInterval timeInterval;
    @private
        mach_port_t masterPort;
        io_iterator_t iter;
        io_registry_entry_t curObj; 
    }
    - (id)initSystemIdleTimerWithTimeInterval:(NSTimeInterval)ti;
    - (int)systemIdleTime;
    - (id)delegate;
    - (void)setDelegate:(id)receiver;
    - (void)invalidate;
    @end
    
    @interface RHSystemIdleTimer(Delegates)
    -(void)timerBeginsIdling:(id)sender;
    -(void)timerContinuesIdling:(id)sender;
    -(void)timerFinishedIdling:(id)sender;
    @end
    
    #import "RHSystemIdleTimer.h"
    
    @interface RHSystemIdleTimer(Private)
    - (void)checkIdleStatus;
    - (void)checkIfStillIdle;
    @end
    
    @implementation RHSystemIdleTimer
    
    #pragma mark Initilization/Dealloc
    
    - (id)initSystemIdleTimerWithTimeInterval:(NSTimeInterval)ti
    {
        self = [super init];
        if(self) {
    
            IOMasterPort(MACH_PORT_NULL, &masterPort);
    
            /* Get IOHIDSystem */
            IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOHIDSystem"), &iter);
            if (iter == 0) {
                NSLog(@"Error accessing IOHIDSystem\n");
            }
            else {
                curObj = IOIteratorNext(iter);
    
                if (curObj == 0) {
                    NSLog(@"Iterator's empty!\n");
                }
            }
    
            timeInterval = ti;              
            idleTimer = [NSTimer scheduledTimerWithTimeInterval:ti
                                                         target:self
                                                       selector:@selector(checkIdleStatus)
                                                       userInfo:nil
                                                        repeats:NO];
        }
        return self;
    }
    
    - (void) dealloc {
        IOObjectRelease(curObj);
        IOObjectRelease(iter);
        [super dealloc];
    }
    
    #pragma mark Accessors
    
    - (id)delegate
    {
        return delegate;
    }
    
    - (void)setDelegate:(id)receiver
    {
        delegate = receiver;
    }
    
    #pragma mark Private Methods
    
    - (void)checkIdleStatus
    {
        double idleTime = [self systemIdleTime];
        double timeLeft = timeInterval - idleTime;
        if(timeLeft <= 0) {
    
            if([delegate respondsToSelector:@selector(timerBeginsIdling:)]) {
                [delegate timerBeginsIdling:self];          
            }
    
            [NSTimer scheduledTimerWithTimeInterval:1.0
                                             target:self
                                           selector:@selector(checkIfStillIdle)
                                           userInfo:nil
                                            repeats:NO];
    
            if([delegate respondsToSelector:@selector(timerContinuesIdling:)]) {
                continuingIdleTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval
                                                                       target:delegate
                                                                     selector:@selector(timerContinuesIdling:)
                                                                     userInfo:nil
                                                                      repeats:YES];
            }       
        }
        else {
            idleTimer = [NSTimer scheduledTimerWithTimeInterval:timeLeft
                                                         target:self
                                                       selector:@selector(checkIdleStatus)
                                                       userInfo:nil
                                                        repeats:NO];
        }
    }
    
    - (void)checkIfStillIdle
    {
        double idleTime = [self systemIdleTime];
        if(idleTime <= 1.0) {
            [continuingIdleTimer invalidate];
    
            if([delegate respondsToSelector:@selector(timerFinishedIdling:)]) {
                [delegate timerFinishedIdling:self];            
            }
    
            // reset; start checking for system idle time again
            idleTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval
                                             target:self
                                           selector:@selector(checkIdleStatus)
                                           userInfo:nil
                                            repeats:NO];
        }
        else {
            [NSTimer scheduledTimerWithTimeInterval:1.0
                                             target:self
                                           selector:@selector(checkIfStillIdle)
                                           userInfo:nil
                                            repeats:NO];
        }
    }
    
    #pragma mark Public Methods
    
    - (void)invalidate
    {
        [idleTimer invalidate]; 
    }
    
    - (int)systemIdleTime
    {       
        CFMutableDictionaryRef properties = 0;
        CFTypeRef obj;
    
        if (IORegistryEntryCreateCFProperties(curObj, &properties, kCFAllocatorDefault, 0) == KERN_SUCCESS && properties != NULL) {
            obj = CFDictionaryGetValue(properties, CFSTR("HIDIdleTime"));
            CFRetain(obj);
        } else {
            NSLog(@"Couldn't grab properties of system\n");
            obj = NULL;
        }
    
        uint64_t tHandle = 0;
        if (obj) {
            CFTypeID type = CFGetTypeID(obj);
    
            if (type == CFDataGetTypeID()) {
                CFDataGetBytes((CFDataRef) obj, CFRangeMake(0, sizeof(tHandle)), (UInt8*) &tHandle);
            }
            else if (type == CFNumberGetTypeID()) {
                CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt64Type, &tHandle);
            }
            else {
                NSLog(@"%d: unsupported type\n", (int)type);
            }
    
            CFRelease(obj);
    
            tHandle >>= 30; // essentially divides by 10^9 (nanoseconds)
        }
        else {
            NSLog(@"Can't find idle time\n");
        }
    
        CFRelease((CFTypeRef)properties);       
        return tHandle;
    }
    
    @end  
    

    【讨论】:

      【解决方案2】:

      您可以使用此函数获取自上次事件以来的秒数:

      CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType);
      

      这会返回一个CFTimeInterval,它是一个double

      【讨论】:

      • 不要在启动守护进程中使用 CGEventSourceSecondsSinceLastEventType。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-24
      • 2018-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多