UWP Restricted Capability "inputObservation"

Ross 101 Reputation points
2019-12-13T13:30:24.91+00:00

Hi Devs,

i was looking to inputObservation restricted capability, MSDN doens't have any reference to its implementation.
Has anyone succeeded in getting keyboard input without having focus on the app?
I managed to bypass the suspended mode of the app minimized but i don't see any solution for keyboard/mouse input problem.

With Win32 apis it was easy to set up Hotkeys or use GetAsyncKeyState, but with UWP these apis are not supported and i would like to know if there's a new method.
There is only a reference in the whole UWP documentation about this "inputObservation" but i don't have any clue how to implement it.

Kind Regards,

Ros

Universal Windows Platform (UWP)
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. Roy Li - MSFT 31,826 Reputation points Microsoft Vendor
    2019-12-16T03:23:03.917+00:00

    Hello,

    Welcome to Microsoft Q&A!

    Thank you for reporting this here. There are no more documents about the inputObservation Capability. I'll confirm it with the team later.

    >>Has anyone succeeded in getting keyboard input without having focus on the app?

    Generally, UWP apps won't be able to get the input if the app is not focused. UWP apps could not get user's actions like click or keyboard input outside the app. That's why the app needs to be focused.

    >>I managed to bypass the suspended mode of the app minimized
    May I know how you do that? Are you using ExtendedExecutionForegroundSession in your app? If it is, running in the background does not mean the app is focused.

    0 comments No comments

  2. Ross 101 Reputation points
    2019-12-17T09:53:32.553+00:00

    Hi there!

    (I didn't get any notification for the answer)

    >>Generally, UWP apps won't be able to get the input if the app is not focused. UWP apps could not get user's actions like click or keyboard input outside the app. That's why the app needs to be focused.

    I understand that concept but the fact is that they added a way to do it, that restricted capability clearly refers to that. So it's wierd not having a clue about the implementation.

    May I know how you do that? Are you using ExtendedExecutionForegroundSession in your app? If it is, running in the background does not mean the app is focused.

    Nope! I had to scan through all MSDN pages to find out a solution that didn't need to use a Rescricted Capability. I found it in the last notes of a page.

    I'll write here all my static class (FROM MSDN) to unlock this functionality the quickest way.

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.Threading.Tasks;  
    using Windows.ApplicationModel.ExtendedExecution;  
    using Windows.Foundation;  
      
    namespace UWPLimitations  
    {  
      /*Info added by Rossano Montori  
     *  
     * With this class you can run your application in background without any limit.  
     *   
     * https://learn.microsoft.com/en-us/windows/uwp/launch-resume/run-minimized-with-extended-execution  
     *   
     * MSDN: "On desktop devices running Windows 10 for desktop editions (Home, Pro, Enterprise, and Education),   
     * this is the approach to use if an app needs to avoid being suspended while it is minimized"  
     *   
     * MSDN: "If the device is connected to wall power,   
     * there is no limit to the length of the extended execution time period.   
     * If the device is on battery power, the extended execution time period   
     * can run up to 10 minutes in the background."  
     *   
     * NOTE: In debug time there isn't any limitation therefore you might notice it, to verify the real time extension please "Run without debug" (CTRL + F5)  
     *   
     * MSDN: "These application lifecycle time constraints are disabled while the app is running under a debugger."  
     *   
     */  
      
        static class UWPBackgroundTimeLimit // ExtendedExecutionHelper from MSDN page  
        {  
            private static ExtendedExecutionSession session = null;  
            private static int taskCount = 0;  
      
            public static bool IsRunning  
            {  
                get  
                {  
                    if (session != null)  
                    {  
                        return true;  
                    }  
                    else  
                    {  
                        return false;  
                    }  
                }  
            }  
      
            public static async Task RequestSessionAsync(ExtendedExecutionReason reason, TypedEventHandler revoked, String description)  
            {  
                // The previous Extended Execution must be closed before a new one can be requested.         
                ClearSession();  
      
                var newSession = new ExtendedExecutionSession();  
                newSession.Reason = reason;  
                newSession.Description = description;  
                newSession.Revoked += SessionRevoked;  
      
                if (revoked != null)  
                {  
                    newSession.Revoked += revoked;  
                }  
      
                ExtendedExecutionResult result = await newSession.RequestExtensionAsync();  
      
                switch (result)  
                {  
                    case ExtendedExecutionResult.Allowed:  
                        session = newSession;  
                        break;  
                    default:  
                    case ExtendedExecutionResult.Denied:  
                        newSession.Dispose();  
                        break;  
                }  
                return result;  
            }  
      
            public static void ClearSession()  
            {  
                if (session != null)  
                {  
                    session.Dispose();  
                    session = null;  
                }  
      
                taskCount = 0;  
            }  
      
            public static Deferral GetExecutionDeferral()  
            {  
                if (session == null)  
                {  
                    throw new InvalidOperationException("No extended execution session is active");  
                }  
      
                taskCount++;  
                return new Deferral(OnTaskCompleted);  
            }  
      
            private static void OnTaskCompleted()  
            {  
                if (taskCount > 0)  
                {  
                    taskCount--;  
                }  
      
                //If there are no more running tasks than end the extended lifetime by clearing the session  
                if (taskCount == 0 && session != null)  
                {  
                    ClearSession();  
                }  
            }  
      
            private static void SessionRevoked(object sender, ExtendedExecutionRevokedEventArgs args)  
            {  
                //The session has been prematurely revoked due to system constraints, ensure the session is disposed  
                if (session != null)  
                {  
                    session.Dispose();  
                    session = null;  
                }  
      
                taskCount = 0;  
            }  
        }  
    }  
      
    

    NOTICE: In debug mode your application never goes suspended even if it is not focused! Only the release version has this limitation.

    And here is the quickest way to implement it:

    //enable on release  
      
    await UWPBackgroundTimeLimit.RequestSessionAsync(ExtendedExecutionReason.Unspecified,   
                        null, "nothing");  
      
    

    After testing this class, i can tell that the application still runs calculations after losing focus, not just when minimized. Try it out.

    I forgot, i'm targeting Windows Desktop, so "connected to power wall" it's enough to unlock the unlimited execution time.

    You don't have to create a "background task" in order to access the execution extended time. Instead use "Task.Run" or "ThreadPool.RunAsync" to initiate a task that will run despite losing focus or being minimized.