Toggling Focus Assist mode in Win 10 Programmatically
Asked Answered
B

4

17

There are a few unanswered questions to this pretty much everywhere I've looked so I suppose I should add mine to the tally.

I am looking to toggle Focus Assist mode in Win 10 programmatically and have thus far been unsuccessful with finding much documentation on this in both official and unofficial channels.

If I am not able to toggle focus assist programmatically, I will need to essentially emulate the same behavior meaning, that I will need to intercept and squelch incoming notifications until it is turned off and then display notifications that were silenced during this period.

It seems the only path available right now is to write some c++ using reversed WNF information and then pray it won't break in an update. Before I go down that rabbit hole I figured I'd see if anyone has done this or maybe can point me to a resource I haven't considered.

The notification listener is great and gives me access to said notifications to fulfills my secondary requirement but it does not allow me to silence them as they come in since it runs in parallel with vs interrupts the flow of the notification.

For folks that ask this question in the future, I've found these helpful:

Bombe answered 2/4, 2019 at 14:16 Comment(1)
The kind thing to do would've been to free the code and save others from having to pay consultants.Yablon
A
7

I am looking to toggle Focus Assist mode in Win 10 programmatically and have thus far been unsuccessful

Currently, UWP does not provide such api to switch Focus Assist mode programmatically . If you do want this feature, please feel free to ask for this feature on UserVoice.

Autochthon answered 3/4, 2019 at 8:20 Comment(1)
Thank you, I appreciate the help and getting this posted in UserVoice.Bombe
S
9

You can toggle the mode using WNF mechanism.

Generate binary content of the file "0" = 00 00 00 00 (hex) and file "1" = 02 00 00 00 (hex)

For example, in git bash

echo -n -e "\x00\x00\x00\x00" > 0
echo -n -e "\x02\x00\x00\x00" > 1

Clone repository: https://github.com/ionescu007/wnfun

pip install Pywin32
pip install hexdump

Turn on the Priority mode

python WnfDump.py -w WNF_SHEL_QUIET_MOMENT_SHELL_MODE_CHANGED 1

Turn off Focus Assist

python WnfDump.py -w WNF_SHEL_QUIET_MOMENT_SHELL_MODE_CHANGED 0

If you find a way to turn on the "Alarms only" mode, let me know.

You can use the same technique C++ as well.

EDIT: Actually, the command activates mode that is set for the "full screen mode" and the file content 01 00 00 00, would activate the "game mode". If both are turned off, the command will have no effect.

Sanborne answered 26/6, 2020 at 20:45 Comment(3)
Great answer! I tried using the included .exe but unsuccessful so far: github.com/ionescu007/wnfun/issues/2Passant
Thank you! Please make sure you configured the automatic rules in the focus assist settings (check the edit sections)Sanborne
Yes I did and it works when using the .py like you describe, but not with the .exe see issue linkPassant
A
7

I am looking to toggle Focus Assist mode in Win 10 programmatically and have thus far been unsuccessful

Currently, UWP does not provide such api to switch Focus Assist mode programmatically . If you do want this feature, please feel free to ask for this feature on UserVoice.

Autochthon answered 3/4, 2019 at 8:20 Comment(1)
Thank you, I appreciate the help and getting this posted in UserVoice.Bombe
P
4

Like Pavel Henrykhsen answer says, there is one programmatic, albeit undocumented and unsupported way of doing it. Here is an implementation, albeit written in Rust.

The relevant function is the ZwUpdateWnfStateData from the ntdll.dll. In this case, the relevant arguments are

  1. The ID of the state, which I managed to find at https://github.com/googleprojectzero/sandbox-attacksurface-analysis-tools/blob/80d7fcc8df9c3160c814c60f5121ae46c560a1b5/NtApiDotNet/NtWnfWellKnownNames.cs#L865
  2. A buffer with the values [0x02, 0x00, 0x00, 0x00]
  3. The length of the buffer

All arguments after that can be safely ignored.

// Pseudo-code
ZwUpdateWnfStateData(
            0xd83063ea3bf5075UL,
            new byte[] {0x02, 0x00, 0x00, 0x00},
            4,
            0,
            0,
            0,
            0,
        );

This does seem to rely on the "when I'm using an app in full-screen" setting being turned on in the focus mode settings.

Also, if one attempts to use this to enable focus mode, I recommend first disabling focus mode (pass new byte[] {0x00, 0x00, 0x00, 0x00} instead). Then, after a few milliseconds, one can safely enable focus mode.

Puma answered 9/10, 2021 at 13:11 Comment(4)
Hello Stefnotch, I am also looking for a similar solution and to me looks like your solution is a good fit, thanks for all your hard work and research. One question though i have is - you mentioned that This does seem to rely on the "when I'm using an app in full-screen" setting being turned on in the focus mode settings. so what does that mean? My app will never be in full-screen mode? Though I will try your scripts soon.Jaf
@MP Windows 10 has some "focus assist" settings. If you check them out, you'll see some "Automatic rules", namely "During these times", "When I'm duplicating my display", "When I'm playing a game" and finally "When I'm using an app in full-screen mode". My solution apparently relies on the "When I'm using an app in full-screen mode" rule being turned on. It works without having to put any app into full-screen mode though :)Puma
Stefnotch, looks like it is working without having the app in the fullscreen mode. Thanks for your support man!!Jaf
Awesome, glad to hear that you got it to work! Pretty please do upvote answers that you found useful ;)Puma
Y
1

Given that the question is tagged with C#, I took the information supplied by @Pavel Henrykhsen and @Stefnotch and formulated a solution in C#.

    using System.Runtime.InteropServices;

    while(true)
    {

        var focusAssistMode = Console.ReadLine() == "on" ? FocusAssistMode.Fullscreen : FocusAssistMode.Off;

        var result = FocusAssistHelper.SetFocusAssistMode(focusAssistMode);

        if (result == 0)
        {
            Console.WriteLine("Success");
        }
        else
        {
            Console.WriteLine($"Failed with error code {result}");
        };

    }

    public static class FocusAssistHelper
    {

        [DllImport("ntdll.dll", SetLastError = true)]
        static extern int ZwUpdateWnfStateData(
            ref ulong StateName,
            IntPtr Buffer,
            int Length,
            Guid TypeId,
            IntPtr ExplicitScope,
            uint MatchingChangeStamp,
            bool CheckStamp
        );

        [DllImport("ntdll.dll", SetLastError = true)]
        static extern int ZwQueryWnfStateData(
            ref ulong StateName,
            Guid TypeId,
            IntPtr ExplicitScope,
            out uint ChangeStamp,
            IntPtr Buffer,
            ref int BufferSize
        );

        const ulong WNF_SHEL_QUIET_MOMENT_SHELL_MODE_CHANGED = 0xd83063ea3bf5075UL;

        public static int GetFocusAssistMode(out FocusAssistMode mode)
        {

            var stateName = WNF_SHEL_QUIET_MOMENT_SHELL_MODE_CHANGED;

            int bufferSize = 4;
            var bufferPtr = Marshal.AllocHGlobal(bufferSize);
    
            var result = ZwQueryWnfStateData(ref stateName, Guid.Empty, IntPtr.Zero, out _, bufferPtr, ref bufferSize);

            if (result == 0)
            {

                var modeAsByteArray = new byte[bufferSize];

                Marshal.Copy(bufferPtr, modeAsByteArray, 0, modeAsByteArray.Length);

                mode = (FocusAssistMode)BitConverter.ToUInt32(modeAsByteArray);

            }
            else
            {
                mode = FocusAssistMode.Off;
            }

            return result;

        }

        public static int SetFocusAssistMode(FocusAssistMode mode)
        {

            var stateName = WNF_SHEL_QUIET_MOMENT_SHELL_MODE_CHANGED;

            var modeAsByteArray = BitConverter.GetBytes((uint)mode);

            var bufferPtr = Marshal.AllocHGlobal(modeAsByteArray.Length);

            try
            {

                Marshal.Copy(modeAsByteArray, 0, bufferPtr, modeAsByteArray.Length);

                return ZwUpdateWnfStateData(ref stateName, bufferPtr, modeAsByteArray.Length, Guid.Empty, IntPtr.Zero, 0, false);

            }
            finally
            {
                Marshal.FreeHGlobal(bufferPtr);
            }

        }

    }

    public enum FocusAssistMode : uint
    {
        Off = 0,
        Game = 1,
        Fullscreen = 2,
    }

Notes:

  • Tested in Windows 10 22H2 19045.3803.
  • Under Windows Focus Assist settings, either When I'm duplicating my display or When I'm playing a game must be set to On, depending on which mode you intend to activate programmatically.
  • It seems like Windows keeps track of which process/app was responsible for activating Focus Assist. If it wasn't your app, you cannot turn it off (please let me know if you find a workaround).
  • In order to turn Focus Assist on, you sometimes need to issue a command to turn it off first (even though it is already off). For best results, always turn off then on.
Yablon answered 6/1 at 0:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.