如何在UWP中检查用户是否处于空闲状态?

4

我想要创建一个函数,如果用户闲置一段时间,则会超时并导航到主页面。经过一番调研,我发现 ThreadPoolTimer 应该满足我的需求。测试后,我决定使用 10 秒的间隔。

    timer =ThreadPoolTimer.CreatePeriodicTimer(Timer_Tick,TimeSpan.FromSeconds(10));

这就是我遇到的问题。在不逐个检查PointerPressed,PointerExited等情况下,我无法找到在UWP上检查用户输入的方法。因此,我进行了更多的研究,并找到了一段代码块,据说可以给出一个布尔值来判断用户是否处于空闲状态。

    public static uint GetIdleTime()
    {
        LASTINPUTINFO lastInPut = new LASTINPUTINFO();
        lastInPut.cbSize = (uint)Marshal.SizeOf(lastInPut);
        GetLastInputInfo(ref lastInPut);

        return ((uint)Environment.TickCount - lastInPut.dwTime);
    }

    public static bool IsUserIdle()
    {
        uint idleTime = (uint)Environment.TickCount - GetLastInputEventTickCount();
       if (idleTime > 0)
       {
           idleTime = (idleTime / 1000);
       }
       else
       {
           idleTime = 0;
       }
       //user is idle for 10 sec
       bool b = (idleTime >= 10);
       return b;
    }

    private static uint GetLastInputEventTickCount()
    {
        LASTINPUTINFO lii = new LASTINPUTINFO();
        lii.cbSize = (uint)Marshal.SizeOf(lii);
        lii.dwTime = 0;
        uint p = GetLastInputInfo(ref lii) ? lii.dwTime : 0;
        return p;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct LASTINPUTINFO
    {
        public static readonly int SizeOf = Marshal.SizeOf<LASTINPUTINFO>();
        [MarshalAs(UnmanagedType.U4)]
        public UInt32 cbSize;
        [MarshalAs(UnmanagedType.U4)]
        public UInt32 dwTime;
    }

    [DllImport("user32.dll")]
    private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);

我会尽力进行翻译,请核对以下内容是否符合您的需求:

然后我在tick函数中调用该函数,并使用条件语句:如果IsUserIdle()等于true,则导航到主页面。

    public static void Timer_Tick(object sender)
    {
       if (IsUserIdle() == true)
       {
           Frame.Navigate(typeof(MainPage));
       }                                        
    }

但是当我启动它时什么也没有发生,我设置了几个断点后发现即使在10秒的不活动时间后IsUserIdle()从来没有返回过一个真值。我完全陷入困境,所以任何帮助都将不胜感激。


抱歉,我打字太快了。原始代码应该是 bool b = (idleTime >= 10); @gravity - Calvin Carter
1个回答

10

GetLastInputInfo 不支持 Windows 应用商店应用:

最低客户端支持版本:Windows 2000 Professional [仅适用于桌面应用程序]

我不知道是否存在内在的 UWP API 可以检测用户是否空闲,但是肯定可以自己编写一种机制来进行检测。

我无法找到在 UWP 上检查用户输入的方法,而不必分别检查 PointerPressed、PointerExited 等方法。

这种方法有什么不好?以下是我的尝试:

App.xaml.cs

public sealed partial class App : Application
{
    public static new App Current => (App)Application.Current;

    public event EventHandler IsIdleChanged;

    private DispatcherTimer idleTimer;

    private bool isIdle;
    public bool IsIdle
    {
        get
        {
            return isIdle;
        }

        private set
        {
            if (isIdle != value)
            {
                isIdle = value;
                IsIdleChanged?.Invoke(this, EventArgs.Empty);
            }
        }
    }

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        idleTimer = new DispatcherTimer();
        idleTimer.Interval = TimeSpan.FromSeconds(10);  // 10s idle delay
        idleTimer.Tick += onIdleTimerTick;
        Window.Current.CoreWindow.PointerMoved += onCoreWindowPointerMoved;
    }

    private void onIdleTimerTick(object sender, object e)
    {
        idleTimer.Stop();
        IsIdle = true;
    }

    private void onCoreWindowPointerMoved(CoreWindow sender, PointerEventArgs args)
    {
        idleTimer.Stop();
        idleTimer.Start();
        IsIdle = false;
    }
}

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        App.Current.IsIdleChanged += onIsIdleChanged;
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        App.Current.IsIdleChanged -= onIsIdleChanged;
    }

    private void onIsIdleChanged(object sender, EventArgs e)
    {
        System.Diagnostics.Debug.WriteLine($"IsIdle: {App.Current.IsIdle}");
    }
}

当指针在应用程序窗口内静止不动10秒时,将检测到空闲状态。这对于仅支持触摸的应用程序(如移动应用程序)也适用,因为当窗口被点击时,PointerMoved事件也会被激发。


“那种方法有什么不好的?” - 简而言之:它不能提供有效结果。它只能记录调用进程的输入事件,不能区分用户输入和自动化产生的事件。这种方法既会产生误报又会漏报,并且无法确定用户是否处于空闲状态。 - IInspectable
很遗憾,我不知道有其他选择。对于大多数场景来说,这已经足够了。 - Decade Moon
我通过使用调度计时器和tick函数而不是线程池计时器,实际上解决了我的初始问题。在调试时它完美地工作,但现在当我尝试在发布模式下运行它时,我会收到一个System.TypeLoad Exception,其中提到程序集中未解析的P/Invoke方法'GetLastInputInfo!user32.dll',因为它在UWP应用程序中不可用。请使用另一个API或使用[DllImport(ExactSpelling=true)]来表明您理解使用非UWP应用程序API的影响。@IInspectable - Calvin Carter
1
报告。建议的答案在UWP Windows IOT上非常稳定。已点赞。 - Zen Of Kursat
如果我创建了一个后台进程并且应用程序在后台运行,那么我仍然可以检查用户是否处于空闲状态吗? - Ali123
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接