如何在macOS 10.14上重置HIDIdleTime [英] How to reset HIDIdleTime on macOS 10.14
问题描述
在过去的几天里,我一直在尝试编写一个可重置IORegistry
> IOHIDSystem
> HIDIdleTime
条目的应用程序.最终目标将是防止读取此值的其他应用程序将用户标记为空闲(这不仅与电源管理有关,还与防止睡眠有关).假设已禁用沙箱,并且该应用程序具有所有必需的权限(如辅助功能访问权限).
这是我尝试执行的操作(到目前为止未成功):
尝试1-移动鼠标光标以模拟活动:
变体1:
let mouseCursorPosition = CGPoint(x: Int.random(in: 0...500), y: Int.random(in: 0...500))
CGWarpMouseCursorPosition(mouseCursorPosition)
变体2:
CGDisplayMoveCursorToPoint(CGMainDisplayID(), mouseCursorPosition)
变体3(单独使用CGEvent
或与上述2个变体之一一起使用):
let moveEvent = CGEvent(mouseEventSource: nil, mouseType:
CGEventType.mouseMoved, mouseCursorPosition: mouseCursorPosition,
mouseButton: CGMouseButton.left)
moveEvent?.post(tap: CGEventTapLocation.cghidEventTap)
变体4(使用IOHIDSetMouseLocation
/IOHIDPostEvent
):
func moveCursor() {
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"))
if (service == 0) { return }
var connect:io_connect_t = 0
let result = IOServiceOpen(service, mach_task_self_, UInt32(kIOHIDParamConnectType), &connect)
IOObjectRelease(service)
if (result == kIOReturnSuccess) {
let cursorX = Int16.random(in: 0...100)
let cursorY = Int16.random(in: 0...100)
IOHIDSetMouseLocation(connect, Int32(cursorX), Int32(cursorY))
let cursorLocation:IOGPoint = IOGPoint(x: cursorX, y: cursorY)
var event:NXEventData = NXEventData()
IOHIDPostEvent(connect, UInt32(NX_MOUSEMOVED), cursorLocation, &event, 0, 0, 0)
}
}
注意::我后来了解到,从macOS 10.12开始, 虽然这似乎可行(上面的函数返回 任何建议都将不胜感激.如果可能的话,我试图避免编写自己的虚拟驱动程序(尽管我愿意挂接到现有的驱动程序上,并尽可能模拟事件). 问题是注册表属性不是普通属性,但是每次查询属性时都会动态生成(请参见_idleTimeSerializerCallback href ="https://opensource.apple.com/source/IOHIDFamily/IOHIDFamily-1090.260.23/IOHIDSystem/IOHIDSystem.cpp.auto.html" rel ="nofollow noreferrer">源). 我不会讲Swift,但是下面的一些C代码正是这样做的: 它以非根用户身份在High Sierra上对我有效,尚未在其他地方进行过测试.我确实运行了非标准的系统配置,因此,如果在外部方法上出现错误消息 For the past couple of days I've been trying to write an application that would reset the Here are my attempts at doing this (unsuccessful so far): Attempt 1 - move the mouse cursor to simulate activity: Variant 1: Variant 2: Variant 3 (using Variant 4 (using NOTE: I've later learned that starting with macOS 10.12, Attempt 2 - overwrite the value directly in the While this seems to work (the function above returns Any suggestions are greatly appreciated. If at all possible, I'm trying to avoid writing my own virtual driver (although I'm open to hooking into an existing one and simulating events if at all possible). The thing is that the registry property isn't a normal property, but is generated on the fly every time properties are queried (see I don't speak Swift, but here is some C code that does precisely that: It works for me on High Sierra as non-root, haven't tested it elsewhere. I do run a non-standard system configuration though, so if you get an error saying 这篇关于如何在macOS 10.14上重置HIDIdleTime的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!IOHIDPostEvent
不会重置HIDIdleTime
(来源:true
),但是该值随后被系统覆盖,从而跟踪内存中的实际空闲时间. Apple从IOHIDSystem
此脚本来轻松监控系统空闲时间并测试解决方案.
长话短说,您需要强制重置lastUndimEvent
,这可以通过IOHIDParamUserClient
的外部方法6进行.
// clang -o t t.c -Wall -O3 -framework CoreFoundation -framework IOKit
#include <stdio.h>
#include <stdint.h>
#include <mach/mach.h>
#include <CoreFoundation/CoreFoundation.h>
extern const mach_port_t kIOMasterPortDefault;
typedef mach_port_t io_object_t;
typedef io_object_t io_service_t;
typedef io_object_t io_connect_t;
kern_return_t IOObjectRelease(io_object_t object);
CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;
io_service_t IOServiceGetMatchingService(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
kern_return_t IOServiceOpen(io_service_t service, task_t task, uint32_t type, io_connect_t *client);
kern_return_t IOServiceClose(io_connect_t client);
kern_return_t IOConnectCallScalarMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt);
const uint32_t kIOHIDParamConnectType = 1;
const uint32_t kIOHIDActivityUserIdle = 3;
const uint32_t kIOHIDActivityReport = 0;
const uint32_t kIOHIDParam_extSetStateForSelector = 6;
#define LOG(str, args...) do { fprintf(stderr, str "\n", ##args); } while(0)
int hid_reset(void)
{
int retval = -1;
kern_return_t ret = 0;
io_service_t service = MACH_PORT_NULL;
io_connect_t client = MACH_PORT_NULL;
service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"));
LOG("service: %x", service);
if(!MACH_PORT_VALID(service)) goto out;
ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &client);
LOG("client: %x, %s", client, mach_error_string(ret));
if(ret != KERN_SUCCESS || !MACH_PORT_VALID(client)) goto out;
uint64_t in[] = { kIOHIDActivityUserIdle, kIOHIDActivityReport };
ret = IOConnectCallScalarMethod(client, kIOHIDParam_extSetStateForSelector, in, 2, NULL, NULL);
LOG("extSetStateForSelector: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS) goto out;
retval = 0;
out:;
if(MACH_PORT_VALID(client)) IOServiceClose(client);
if(MACH_PORT_VALID(service)) IOObjectRelease(service);
return retval;
}
int main(void)
{
return hid_reset();
}
(iokit/common) not permitted
,则很可能是您击中了mac_iokit_check_hid_control
,并且可能需要其他权利,可访问性清除之类的东西./p>IORegistry
> IOHIDSystem
> HIDIdleTime
entry. The end goal would be to prevent other applications that read this value from marking the user as idle (it's not only about power management or preventing sleep). Assume that sandboxing is disabled and the application has all necessary permissions (such as accessibility access).let mouseCursorPosition = CGPoint(x: Int.random(in: 0...500), y: Int.random(in: 0...500))
CGWarpMouseCursorPosition(mouseCursorPosition)
CGDisplayMoveCursorToPoint(CGMainDisplayID(), mouseCursorPosition)
CGEvent
by itself or together with one of the 2 variants above):let moveEvent = CGEvent(mouseEventSource: nil, mouseType:
CGEventType.mouseMoved, mouseCursorPosition: mouseCursorPosition,
mouseButton: CGMouseButton.left)
moveEvent?.post(tap: CGEventTapLocation.cghidEventTap)
IOHIDSetMouseLocation
/ IOHIDPostEvent
):func moveCursor() {
let service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"))
if (service == 0) { return }
var connect:io_connect_t = 0
let result = IOServiceOpen(service, mach_task_self_, UInt32(kIOHIDParamConnectType), &connect)
IOObjectRelease(service)
if (result == kIOReturnSuccess) {
let cursorX = Int16.random(in: 0...100)
let cursorY = Int16.random(in: 0...100)
IOHIDSetMouseLocation(connect, Int32(cursorX), Int32(cursorY))
let cursorLocation:IOGPoint = IOGPoint(x: cursorX, y: cursorY)
var event:NXEventData = NXEventData()
IOHIDPostEvent(connect, UInt32(NX_MOUSEMOVED), cursorLocation, &event, 0, 0, 0)
}
}
IOHIDPostEvent
doesn't reset HIDIdleTime
(source: https://github.com/tekezo/Karabiner-Elements/issues/385). Also tried simulating keypresses without success.IORegistry
func overwriteValue() -> Bool {
var iterator: io_iterator_t = 0
defer { IOObjectRelease(iterator) }
guard IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"), &iterator) == kIOReturnSuccess else { return false }
let entry: io_registry_entry_t = IOIteratorNext(iterator)
defer { IOObjectRelease(entry) }
guard entry != 0 else { return false }
var value:NSInteger = 0;
var convertedValue:CFNumber = CFNumberCreate(kCFAllocatorDefault, CFNumberType.nsIntegerType, &value);
let result = IORegistryEntrySetCFProperty(entry, "HIDIdleTime" as CFString, convertedValue)
if (result != kIOReturnSuccess) { return false }
return true
}
true
), the value is then overwritten by the system, which keeps track of the actual idle time in memory. Got a bit of insight into this from the source code release by Apple for IOHIDSystem
here. Currently using this script to easily monitor system idle time and test solutions._idleTimeSerializerCallback
in the source).
Long story short, you need to force lastUndimEvent
to be reset, which you can do with external method 6 of an IOHIDParamUserClient
.// clang -o t t.c -Wall -O3 -framework CoreFoundation -framework IOKit
#include <stdio.h>
#include <stdint.h>
#include <mach/mach.h>
#include <CoreFoundation/CoreFoundation.h>
extern const mach_port_t kIOMasterPortDefault;
typedef mach_port_t io_object_t;
typedef io_object_t io_service_t;
typedef io_object_t io_connect_t;
kern_return_t IOObjectRelease(io_object_t object);
CFMutableDictionaryRef IOServiceMatching(const char *name) CF_RETURNS_RETAINED;
io_service_t IOServiceGetMatchingService(mach_port_t master, CFDictionaryRef matching CF_RELEASES_ARGUMENT);
kern_return_t IOServiceOpen(io_service_t service, task_t task, uint32_t type, io_connect_t *client);
kern_return_t IOServiceClose(io_connect_t client);
kern_return_t IOConnectCallScalarMethod(io_connect_t client, uint32_t selector, const uint64_t *in, uint32_t inCnt, uint64_t *out, uint32_t *outCnt);
const uint32_t kIOHIDParamConnectType = 1;
const uint32_t kIOHIDActivityUserIdle = 3;
const uint32_t kIOHIDActivityReport = 0;
const uint32_t kIOHIDParam_extSetStateForSelector = 6;
#define LOG(str, args...) do { fprintf(stderr, str "\n", ##args); } while(0)
int hid_reset(void)
{
int retval = -1;
kern_return_t ret = 0;
io_service_t service = MACH_PORT_NULL;
io_connect_t client = MACH_PORT_NULL;
service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOHIDSystem"));
LOG("service: %x", service);
if(!MACH_PORT_VALID(service)) goto out;
ret = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &client);
LOG("client: %x, %s", client, mach_error_string(ret));
if(ret != KERN_SUCCESS || !MACH_PORT_VALID(client)) goto out;
uint64_t in[] = { kIOHIDActivityUserIdle, kIOHIDActivityReport };
ret = IOConnectCallScalarMethod(client, kIOHIDParam_extSetStateForSelector, in, 2, NULL, NULL);
LOG("extSetStateForSelector: %s", mach_error_string(ret));
if(ret != KERN_SUCCESS) goto out;
retval = 0;
out:;
if(MACH_PORT_VALID(client)) IOServiceClose(client);
if(MACH_PORT_VALID(service)) IOObjectRelease(service);
return retval;
}
int main(void)
{
return hid_reset();
}
(iokit/common) not permitted
on the external method, it's likely you're hitting mac_iokit_check_hid_control
and might need additional entitlements, accessibility clearance, or something like that.