如何在 PC 上检测用户 activity/input(或缺少用户)?
How to detect user activity/input (or lack thereof) on a PC?
最近,我一直在寻找一种完全自动化我的备份系统的方法,它使用了一个名为“AOMEI Backupper Standard”的第三方程序。我试图让计算机执行的自动序列包括:
- 每天中午前一点启动 PC 并在中午初始化一组两个增量备份,这将 运行 顺序进行直到完成。这两个备份执行的总时间目前约为 2 小时 55 分钟(我有很多数据要读取,即使是条带卷),但随着我将来积累更多数据,这个时间可能会增加。
- 完成时,PC 需要验证某人是否在某个时间段(比如 1 小时)内使用计算机的时间很长(比如 5 分钟或更长时间,以忽略快速使用或随机干扰)在第二次备份完成之前。或者,不是验证是否使用超过 5 分钟,PC 可以简单地检测任何超过 1 分钟的使用(以消除键盘或鼠标被轻推或轻微移动的随机错误),然后可能有另一个脚本如果用户希望 PC 在 1 小时的时间段内忽略他们之前的使用情况,则用于重置使用标志。
- 如果那个时间段内没有重要用户activity,那么PC必须在第二次备份结束时自动休眠(如果我不在[=45],这就完成了自动化过程=] 电脑)。否则,如果 PC 检测到此用户 activity,它必须中止休眠,这样它就不会在我使用它时突然断电,或者如果我最近一直在使用它。
我可以使用批处理文件处理计时开始的设置,方法是将前一次完成两个备份所用的时间加上中午,然后减去 1 小时。这将允许计时周期的开始相对于中午变得更晚,因为总备份时间随着存储的数据的增加而增加。
因此,我正在寻找一种方法,通过检查鼠标 and/or 键盘输入或其他方式来检测该时间段内 PC 上的用户 activity。此检测方法还需要考虑是否设置了“ES_DISPLAY_REQUIRED”标志或类似标志,以便在没有用户的情况下用于观看电影的 PC 不会被视为空闲长时间输入。
除了直接检查 M&K 之外,我对检测的一个想法是以某种方式利用 Windows 空闲 flag/state,但修改它以忽略资源消耗作为确定空闲状态的一个因素。这是因为在备份期间,CPU 和 IO 百分比空闲时间很容易低于 Microsoft 设置的 80% 阈值(有关详细信息,请参阅 Microsoft this page for Windows 8 (虽然我假设这也适用于 Windows 10 个系统,这是我目前用作我的 OS 的系统),因此即使没有鼠标或键盘,系统也永远不会“空闲” input/user 在此期间在场。
理想情况下,我希望能够使用批处理 file/Windows 命令行 (cmd) 进行此检测,但我明白这对于此类任务来说可能是不可能的。因此,如果您对 integrate/work 与 Windows 配合良好并且能够完成此任务的其他编程语言有任何建议,我将很高兴听到他们的建议(我对 [=] 有一些基本经验51=] 和 JavaScript,以及中等水平的 Visual BASIC 和命令 Line/Batch 文件经验)。对不起,如果这有点太冗长,但我想避免对我的问题造成任何混淆。
提前感谢您的宝贵时间。
编辑 #1:我将标题概括为远离我最初选择的仅使用批处理文件,并且我为 C# 添加了一个标签,据我所知类似于 VB,可用于 Windows.
中的任务
编辑 #2:经过更多研究后,我意识到 PowerShell 可能是另一个比批处理文件更强大的选项,因为它具有更先进的功能功能比cmd。现在,我将尝试做一些研究来学习 PowerShell 并查看相关问题,例如 this one,因为看起来我想要实现的目标可以在没有大量复杂代码的情况下使用这种语言来完成。
编辑#3:由于我不知道哪种语言可以解决我的问题,所以我对多种语言的概括似乎没有受到赞赏,所以我现在 re-focusing 这个问题只适用于 PowerShell。这是因为这个问题显然“与 C# 无关”,现在我几乎可以肯定它不能使用 cmd 来完成,因为根本没有用于检测鼠标或键盘输入的命令。
从 this answer 开始,您可以在 PowerShell 中非常简单地执行此操作。首先你添加一个类型来访问 Win32_UserInput class 然后你可以阅读想法时间。
当空闲时间满足您的要求时,只需触发您的操作即可。
Add-Type @' using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace PInvoke.Win32 { public static class UserInput { [DllImport("user32.dll", SetLastError=false)] private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); [StructLayout(LayoutKind.Sequential)] private struct LASTINPUTINFO { public uint cbSize; public int dwTime; } public static DateTime LastInput { get { DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount); DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks); return lastInput; } } public static TimeSpan IdleTime { get { return DateTime.UtcNow.Subtract(LastInput); } } public static int LastInputTicks { get { LASTINPUTINFO lii = new LASTINPUTINFO(); lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO)); GetLastInputInfo(ref lii); return lii.dwTime; } } } } '@
以及用法示例:
for ( $i = 0; $i -lt 10; $i++ ) { Write-Host ("Last input " + [PInvoke.Win32.UserInput]::LastInput) Write-Host ("Idle for " + [PInvoke.Win32.UserInput]::IdleTime) Start-Sleep -Seconds (Get-Random -Minimum 1 -Maximum 5) }
P.S。上面的人类可读形式的代码:
Add-Type @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace PInvoke.Win32 {
public static class UserInput {
[DllImport("user32.dll", SetLastError=false)]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO {
public uint cbSize;
public int dwTime;
}
public static DateTime LastInput {
get {
DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount);
DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks);
return lastInput;
}
}
public static TimeSpan IdleTime {
get {
return DateTime.UtcNow.Subtract(LastInput);
}
}
public static int LastInputTicks {
get {
LASTINPUTINFO lii = new LASTINPUTINFO();
lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
GetLastInputInfo(ref lii);
return lii.dwTime;
}
}
}
}
'@
ForEach ($i in 0..9) {
Write-Host ("Last input " + [PInvoke.Win32.UserInput]::LastInput)
Write-Host ("Idle for " + [PInvoke.Win32.UserInput]::IdleTime)
Start-Sleep -Seconds (Get-Random -Minimum 1 -Maximum 5)
}
最近,我一直在寻找一种完全自动化我的备份系统的方法,它使用了一个名为“AOMEI Backupper Standard”的第三方程序。我试图让计算机执行的自动序列包括:
- 每天中午前一点启动 PC 并在中午初始化一组两个增量备份,这将 运行 顺序进行直到完成。这两个备份执行的总时间目前约为 2 小时 55 分钟(我有很多数据要读取,即使是条带卷),但随着我将来积累更多数据,这个时间可能会增加。
- 完成时,PC 需要验证某人是否在某个时间段(比如 1 小时)内使用计算机的时间很长(比如 5 分钟或更长时间,以忽略快速使用或随机干扰)在第二次备份完成之前。或者,不是验证是否使用超过 5 分钟,PC 可以简单地检测任何超过 1 分钟的使用(以消除键盘或鼠标被轻推或轻微移动的随机错误),然后可能有另一个脚本如果用户希望 PC 在 1 小时的时间段内忽略他们之前的使用情况,则用于重置使用标志。
- 如果那个时间段内没有重要用户activity,那么PC必须在第二次备份结束时自动休眠(如果我不在[=45],这就完成了自动化过程=] 电脑)。否则,如果 PC 检测到此用户 activity,它必须中止休眠,这样它就不会在我使用它时突然断电,或者如果我最近一直在使用它。
我可以使用批处理文件处理计时开始的设置,方法是将前一次完成两个备份所用的时间加上中午,然后减去 1 小时。这将允许计时周期的开始相对于中午变得更晚,因为总备份时间随着存储的数据的增加而增加。
因此,我正在寻找一种方法,通过检查鼠标 and/or 键盘输入或其他方式来检测该时间段内 PC 上的用户 activity。此检测方法还需要考虑是否设置了“ES_DISPLAY_REQUIRED”标志或类似标志,以便在没有用户的情况下用于观看电影的 PC 不会被视为空闲长时间输入。
除了直接检查 M&K 之外,我对检测的一个想法是以某种方式利用 Windows 空闲 flag/state,但修改它以忽略资源消耗作为确定空闲状态的一个因素。这是因为在备份期间,CPU 和 IO 百分比空闲时间很容易低于 Microsoft 设置的 80% 阈值(有关详细信息,请参阅 Microsoft this page for Windows 8 (虽然我假设这也适用于 Windows 10 个系统,这是我目前用作我的 OS 的系统),因此即使没有鼠标或键盘,系统也永远不会“空闲” input/user 在此期间在场。
理想情况下,我希望能够使用批处理 file/Windows 命令行 (cmd) 进行此检测,但我明白这对于此类任务来说可能是不可能的。因此,如果您对 integrate/work 与 Windows 配合良好并且能够完成此任务的其他编程语言有任何建议,我将很高兴听到他们的建议(我对 [=] 有一些基本经验51=] 和 JavaScript,以及中等水平的 Visual BASIC 和命令 Line/Batch 文件经验)。对不起,如果这有点太冗长,但我想避免对我的问题造成任何混淆。
提前感谢您的宝贵时间。
编辑 #1:我将标题概括为远离我最初选择的仅使用批处理文件,并且我为 C# 添加了一个标签,据我所知类似于 VB,可用于 Windows.
中的任务编辑 #2:经过更多研究后,我意识到 PowerShell 可能是另一个比批处理文件更强大的选项,因为它具有更先进的功能功能比cmd。现在,我将尝试做一些研究来学习 PowerShell 并查看相关问题,例如 this one,因为看起来我想要实现的目标可以在没有大量复杂代码的情况下使用这种语言来完成。
编辑#3:由于我不知道哪种语言可以解决我的问题,所以我对多种语言的概括似乎没有受到赞赏,所以我现在 re-focusing 这个问题只适用于 PowerShell。这是因为这个问题显然“与 C# 无关”,现在我几乎可以肯定它不能使用 cmd 来完成,因为根本没有用于检测鼠标或键盘输入的命令。
从 this answer 开始,您可以在 PowerShell 中非常简单地执行此操作。首先你添加一个类型来访问 Win32_UserInput class 然后你可以阅读想法时间。
当空闲时间满足您的要求时,只需触发您的操作即可。
Add-Type @' using System; using System.Diagnostics; using System.Runtime.InteropServices; namespace PInvoke.Win32 { public static class UserInput { [DllImport("user32.dll", SetLastError=false)] private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); [StructLayout(LayoutKind.Sequential)] private struct LASTINPUTINFO { public uint cbSize; public int dwTime; } public static DateTime LastInput { get { DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount); DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks); return lastInput; } } public static TimeSpan IdleTime { get { return DateTime.UtcNow.Subtract(LastInput); } } public static int LastInputTicks { get { LASTINPUTINFO lii = new LASTINPUTINFO(); lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO)); GetLastInputInfo(ref lii); return lii.dwTime; } } } } '@
以及用法示例:
for ( $i = 0; $i -lt 10; $i++ ) { Write-Host ("Last input " + [PInvoke.Win32.UserInput]::LastInput) Write-Host ("Idle for " + [PInvoke.Win32.UserInput]::IdleTime) Start-Sleep -Seconds (Get-Random -Minimum 1 -Maximum 5) }
P.S。上面的人类可读形式的代码:
Add-Type @'
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace PInvoke.Win32 {
public static class UserInput {
[DllImport("user32.dll", SetLastError=false)]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO {
public uint cbSize;
public int dwTime;
}
public static DateTime LastInput {
get {
DateTime bootTime = DateTime.UtcNow.AddMilliseconds(-Environment.TickCount);
DateTime lastInput = bootTime.AddMilliseconds(LastInputTicks);
return lastInput;
}
}
public static TimeSpan IdleTime {
get {
return DateTime.UtcNow.Subtract(LastInput);
}
}
public static int LastInputTicks {
get {
LASTINPUTINFO lii = new LASTINPUTINFO();
lii.cbSize = (uint)Marshal.SizeOf(typeof(LASTINPUTINFO));
GetLastInputInfo(ref lii);
return lii.dwTime;
}
}
}
}
'@
ForEach ($i in 0..9) {
Write-Host ("Last input " + [PInvoke.Win32.UserInput]::LastInput)
Write-Host ("Idle for " + [PInvoke.Win32.UserInput]::IdleTime)
Start-Sleep -Seconds (Get-Random -Minimum 1 -Maximum 5)
}