SEBWIN-821: Implemented always on configuration for display and system.
This commit is contained in:
parent
622df39fca
commit
181346b810
15 changed files with 116 additions and 37 deletions
|
@ -45,13 +45,11 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
context.Settings = new AppSettings();
|
||||
context.Settings.Taskbar.EnableTaskbar = true;
|
||||
|
||||
displayMonitor.Setup(d => d.PreventSleepMode()).Callback(() => Assert.AreEqual(++order, 1));
|
||||
displayMonitor.Setup(d => d.InitializePrimaryDisplay(It.IsAny<int>())).Callback(() => Assert.AreEqual(++order, 2));
|
||||
displayMonitor.Setup(d => d.StartMonitoringDisplayChanges()).Callback(() => Assert.AreEqual(++order, 3));
|
||||
displayMonitor.Setup(d => d.InitializePrimaryDisplay(It.IsAny<int>())).Callback(() => Assert.AreEqual(++order, 1));
|
||||
displayMonitor.Setup(d => d.StartMonitoringDisplayChanges()).Callback(() => Assert.AreEqual(++order, 2));
|
||||
|
||||
sut.Perform();
|
||||
|
||||
displayMonitor.Verify(d => d.PreventSleepMode(), Times.Once);
|
||||
displayMonitor.Verify(d => d.InitializePrimaryDisplay(It.IsAny<int>()), Times.Once);
|
||||
displayMonitor.Verify(d => d.StartMonitoringDisplayChanges(), Times.Once);
|
||||
}
|
||||
|
@ -59,7 +57,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
[TestMethod]
|
||||
public void Perform_MustCorrectlyInitializeDisplayWithTaskbar()
|
||||
{
|
||||
int height = 25;
|
||||
var height = 25;
|
||||
|
||||
context.Settings = new AppSettings();
|
||||
context.Settings.Taskbar.EnableTaskbar = true;
|
||||
|
@ -74,7 +72,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
[TestMethod]
|
||||
public void Perform_MustCorrectlyInitializeDisplayWithoutTaskbar()
|
||||
{
|
||||
int height = 25;
|
||||
var height = 25;
|
||||
|
||||
context.Settings = new AppSettings();
|
||||
context.Settings.Taskbar.EnableTaskbar = false;
|
||||
|
|
|
@ -22,6 +22,7 @@ using SafeExamBrowser.SystemComponents.Contracts.Network;
|
|||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||
{
|
||||
|
@ -35,6 +36,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
private Mock<INotification> aboutNotification;
|
||||
private Mock<IKeyboard> keyboard;
|
||||
private Mock<INotification> logNotification;
|
||||
private Mock<INativeMethods> nativeMethods;
|
||||
private Mock<IPowerSupply> powerSupply;
|
||||
private Mock<ISystemInfo> systemInfo;
|
||||
private Mock<ITaskbar> taskbar;
|
||||
|
@ -55,6 +57,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
aboutNotification = new Mock<INotification>();
|
||||
keyboard = new Mock<IKeyboard>();
|
||||
logNotification = new Mock<INotification>();
|
||||
nativeMethods = new Mock<INativeMethods>();
|
||||
networkAdapter = new Mock<INetworkAdapter>();
|
||||
powerSupply = new Mock<IPowerSupply>();
|
||||
systemInfo = new Mock<ISystemInfo>();
|
||||
|
@ -77,6 +80,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
keyboard.Object,
|
||||
logger.Object,
|
||||
logNotification.Object,
|
||||
nativeMethods.Object,
|
||||
networkAdapter.Object,
|
||||
powerSupply.Object,
|
||||
systemInfo.Object,
|
||||
|
@ -185,6 +189,25 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
uiFactory.Verify(f => f.CreateApplicationControl(It.Is<IApplication>(a => a == application3.Object), Location.Taskbar), Times.Never);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Perform_MustInitializeAlwaysOnState()
|
||||
{
|
||||
context.Settings.Display.AlwaysOn = true;
|
||||
context.Settings.System.AlwaysOn = false;
|
||||
|
||||
sut.Perform();
|
||||
|
||||
nativeMethods.Verify(n => n.SetAlwaysOnState(true, false), Times.Once);
|
||||
nativeMethods.Reset();
|
||||
|
||||
context.Settings.Display.AlwaysOn = false;
|
||||
context.Settings.System.AlwaysOn = true;
|
||||
|
||||
sut.Perform();
|
||||
|
||||
nativeMethods.Verify(n => n.SetAlwaysOnState(false, true), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void Perform_MustInitializeClock()
|
||||
{
|
||||
|
|
|
@ -314,6 +314,7 @@ namespace SafeExamBrowser.Client
|
|||
keyboard,
|
||||
logger,
|
||||
logNotification,
|
||||
nativeMethods,
|
||||
networkAdapter,
|
||||
powerSupply,
|
||||
systemInfo,
|
||||
|
|
|
@ -17,9 +17,9 @@ namespace SafeExamBrowser.Client.Operations
|
|||
{
|
||||
internal class DisplayMonitorOperation : ClientOperation
|
||||
{
|
||||
private IDisplayMonitor displayMonitor;
|
||||
private ILogger logger;
|
||||
private ITaskbar taskbar;
|
||||
private readonly IDisplayMonitor displayMonitor;
|
||||
private readonly ILogger logger;
|
||||
private readonly ITaskbar taskbar;
|
||||
|
||||
public override event ActionRequiredEventHandler ActionRequired { add { } remove { } }
|
||||
public override event StatusChangedEventHandler StatusChanged;
|
||||
|
@ -36,7 +36,6 @@ namespace SafeExamBrowser.Client.Operations
|
|||
logger.Info("Initializing working area...");
|
||||
StatusChanged?.Invoke(TextKey.OperationStatus_InitializeWorkingArea);
|
||||
|
||||
displayMonitor.PreventSleepMode();
|
||||
displayMonitor.InitializePrimaryDisplay(Context.Settings.Taskbar.EnableTaskbar ? taskbar.GetAbsoluteHeight() : 0);
|
||||
displayMonitor.StartMonitoringDisplayChanges();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ using SafeExamBrowser.SystemComponents.Contracts.Network;
|
|||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Client.Operations
|
||||
{
|
||||
|
@ -30,6 +31,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
private readonly IKeyboard keyboard;
|
||||
private readonly ILogger logger;
|
||||
private readonly INotification logNotification;
|
||||
private readonly INativeMethods nativeMethods;
|
||||
private readonly INetworkAdapter networkAdapter;
|
||||
private readonly IPowerSupply powerSupply;
|
||||
private readonly ISystemInfo systemInfo;
|
||||
|
@ -49,6 +51,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
IKeyboard keyboard,
|
||||
ILogger logger,
|
||||
INotification logNotification,
|
||||
INativeMethods nativeMethods,
|
||||
INetworkAdapter networkAdapter,
|
||||
IPowerSupply powerSupply,
|
||||
ISystemInfo systemInfo,
|
||||
|
@ -63,6 +66,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
this.keyboard = keyboard;
|
||||
this.logger = logger;
|
||||
this.logNotification = logNotification;
|
||||
this.nativeMethods = nativeMethods;
|
||||
this.networkAdapter = networkAdapter;
|
||||
this.powerSupply = powerSupply;
|
||||
this.systemInfo = systemInfo;
|
||||
|
@ -82,6 +86,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
InitializeTaskbar();
|
||||
InitializeTaskview();
|
||||
InitializeActivators();
|
||||
InitializeAlwaysOnState();
|
||||
|
||||
return OperationResult.Success;
|
||||
}
|
||||
|
@ -150,6 +155,17 @@ namespace SafeExamBrowser.Client.Operations
|
|||
}
|
||||
}
|
||||
|
||||
private void InitializeAlwaysOnState()
|
||||
{
|
||||
var display = Context.Settings.Display.AlwaysOn;
|
||||
var system = Context.Settings.System.AlwaysOn;
|
||||
|
||||
nativeMethods.SetAlwaysOnState(display, system);
|
||||
|
||||
logger.Info($"Display(s) will {(display ? "be always on" : "use the operating system configuration and may turn off")}.");
|
||||
logger.Info($"System will {(system ? "be always on" : "use the operating system configuration and may enter sleep mode or standby")}.");
|
||||
}
|
||||
|
||||
private void InitializeTaskbar()
|
||||
{
|
||||
if (Context.Settings.Taskbar.EnableTaskbar)
|
||||
|
|
|
@ -206,6 +206,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
settings.ConfigurationMode = ConfigurationMode.Exam;
|
||||
|
||||
settings.Display.AllowedDisplays = 1;
|
||||
settings.Display.AlwaysOn = true;
|
||||
settings.Display.IgnoreError = false;
|
||||
settings.Display.InternalDisplayOnly = false;
|
||||
|
||||
|
@ -296,6 +297,8 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
|
||||
settings.SessionMode = SessionMode.Normal;
|
||||
|
||||
settings.System.AlwaysOn = true;
|
||||
|
||||
settings.Taskbar.EnableTaskbar = true;
|
||||
settings.Taskbar.ShowApplicationInfo = false;
|
||||
settings.Taskbar.ShowApplicationLog = false;
|
||||
|
|
|
@ -20,17 +20,12 @@ namespace SafeExamBrowser.Monitoring.Contracts.Display
|
|||
/// Event fired when the primary display or its settings have changed.
|
||||
/// </summary>
|
||||
event DisplayChangedEventHandler DisplayChanged;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Sets the desktop working area to accommodate to the taskbar's height and removes the configured wallpaper (if possible).
|
||||
/// </summary>
|
||||
void InitializePrimaryDisplay(int taskbarHeight);
|
||||
|
||||
/// <summary>
|
||||
/// Prevents the computer from entering sleep mode and turning its display(s) off.
|
||||
/// </summary>
|
||||
void PreventSleepMode();
|
||||
|
||||
/// <summary>
|
||||
/// Resets the desktop working area and wallpaper to their previous (initial) state.
|
||||
/// </summary>
|
||||
|
|
|
@ -26,9 +26,9 @@ namespace SafeExamBrowser.Monitoring.Display
|
|||
public class DisplayMonitor : IDisplayMonitor
|
||||
{
|
||||
private IBounds originalWorkingArea;
|
||||
private ILogger logger;
|
||||
private INativeMethods nativeMethods;
|
||||
private ISystemInfo systemInfo;
|
||||
private readonly ILogger logger;
|
||||
private readonly INativeMethods nativeMethods;
|
||||
private readonly ISystemInfo systemInfo;
|
||||
private string wallpaper;
|
||||
|
||||
public event DisplayChangedEventHandler DisplayChanged;
|
||||
|
@ -46,12 +46,6 @@ namespace SafeExamBrowser.Monitoring.Display
|
|||
InitializeWallpaper();
|
||||
}
|
||||
|
||||
public void PreventSleepMode()
|
||||
{
|
||||
nativeMethods.PreventSleepMode();
|
||||
logger.Info("Disabled sleep mode and display timeout.");
|
||||
}
|
||||
|
||||
public void ResetPrimaryDisplay()
|
||||
{
|
||||
ResetWorkingArea();
|
||||
|
|
|
@ -15,6 +15,7 @@ using SafeExamBrowser.Settings.Proctoring;
|
|||
using SafeExamBrowser.Settings.Security;
|
||||
using SafeExamBrowser.Settings.Server;
|
||||
using SafeExamBrowser.Settings.Service;
|
||||
using SafeExamBrowser.Settings.System;
|
||||
using SafeExamBrowser.Settings.SystemComponents;
|
||||
using SafeExamBrowser.Settings.UserInterface;
|
||||
|
||||
|
@ -96,6 +97,11 @@ namespace SafeExamBrowser.Settings
|
|||
/// </summary>
|
||||
public SessionMode SessionMode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All system-related settings.
|
||||
/// </summary>
|
||||
public SystemSettings System { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// All taskbar-related settings.
|
||||
/// </summary>
|
||||
|
@ -119,6 +125,7 @@ namespace SafeExamBrowser.Settings
|
|||
Security = new SecuritySettings();
|
||||
Server = new ServerSettings();
|
||||
Service = new ServiceSettings();
|
||||
System = new SystemSettings();
|
||||
Taskbar = new TaskbarSettings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,12 @@ namespace SafeExamBrowser.Settings.Monitoring
|
|||
/// </summary>
|
||||
public int AllowedDisplays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the display(s) will remain always on or not. This does not prevent the operating system from entering sleep mode or
|
||||
/// standby, see <see cref="System.SystemSettings.AlwaysOn"/>.
|
||||
/// </summary>
|
||||
public bool AlwaysOn { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether any display configuration may be allowed when the configuration can't be verified due to an error.
|
||||
/// </summary>
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
<Compile Include="Service\ServiceSettings.cs" />
|
||||
<Compile Include="AppSettings.cs" />
|
||||
<Compile Include="SystemComponents\AudioSettings.cs" />
|
||||
<Compile Include="System\SystemSettings.cs" />
|
||||
<Compile Include="UserInterface\ActionCenterSettings.cs" />
|
||||
<Compile Include="UserInterface\TaskbarSettings.cs" />
|
||||
<Compile Include="UserInterface\UserInterfaceMode.cs" />
|
||||
|
|
25
SafeExamBrowser.Settings/System/SystemSettings.cs
Normal file
25
SafeExamBrowser.Settings/System/SystemSettings.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace SafeExamBrowser.Settings.System
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines all settings related to functionality of the operating system.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SystemSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether the system will remain always on or not (i.e. potentially entering sleep mode or standby). This does not prevent the
|
||||
/// display(s) from turning off, see <see cref="Monitoring.DisplaySettings.AlwaysOn"/>.
|
||||
/// </summary>
|
||||
public bool AlwaysOn { get; set; }
|
||||
}
|
||||
}
|
|
@ -131,11 +131,6 @@ namespace SafeExamBrowser.WindowsApi.Contracts
|
|||
/// </exception>
|
||||
void PostCloseMessageToShell();
|
||||
|
||||
/// <summary>
|
||||
/// Prevents Windows from entering sleep mode and keeps all displays powered on.
|
||||
/// </summary>
|
||||
void PreventSleepMode();
|
||||
|
||||
/// <summary>
|
||||
/// Registers a keyboard hook for the given callback. Returns the identifier of the newly registered hook.
|
||||
/// </summary>
|
||||
|
@ -182,6 +177,12 @@ namespace SafeExamBrowser.WindowsApi.Contracts
|
|||
/// </summary>
|
||||
void SendCloseMessageTo(IntPtr window);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the always on state for the display and the operating system according to the given parameters, i.e. keeps all displays powered on
|
||||
/// and/or prevents Windows from entering sleep mode or standby when set to <c>true</c> respectively.
|
||||
/// </summary>
|
||||
void SetAlwaysOnState(bool display = true, bool system = true);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the wallpaper to the image located at the specified file path.
|
||||
/// </summary>
|
||||
|
|
|
@ -68,6 +68,8 @@ namespace SafeExamBrowser.WindowsApi.Desktops
|
|||
if (name?.Equals(desktop.Name, StringComparison.OrdinalIgnoreCase) != true)
|
||||
{
|
||||
logger.Warn($"Detected desktop switch to '{name}' [{handle}], trying to reactivate {desktop}...");
|
||||
|
||||
// TODO: SEBWIN-827
|
||||
desktop.Activate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -165,7 +165,7 @@ namespace SafeExamBrowser.WindowsApi
|
|||
|
||||
public uint GetProcessIdFor(IntPtr window)
|
||||
{
|
||||
User32.GetWindowThreadProcessId(window, out uint processId);
|
||||
User32.GetWindowThreadProcessId(window, out var processId);
|
||||
|
||||
return processId;
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ namespace SafeExamBrowser.WindowsApi
|
|||
public uint GetShellProcessId()
|
||||
{
|
||||
var handle = GetShellWindowHandle();
|
||||
var threadId = User32.GetWindowThreadProcessId(handle, out uint processId);
|
||||
var threadId = User32.GetWindowThreadProcessId(handle, out var processId);
|
||||
|
||||
return processId;
|
||||
}
|
||||
|
@ -276,11 +276,6 @@ namespace SafeExamBrowser.WindowsApi
|
|||
}
|
||||
}
|
||||
|
||||
public void PreventSleepMode()
|
||||
{
|
||||
Kernel32.SetThreadExecutionState(EXECUTION_STATE.CONTINUOUS | EXECUTION_STATE.DISPLAY_REQUIRED | EXECUTION_STATE.SYSTEM_REQUIRED);
|
||||
}
|
||||
|
||||
public Guid RegisterKeyboardHook(KeyboardHookCallback callback)
|
||||
{
|
||||
var hookId = default(Guid);
|
||||
|
@ -411,6 +406,19 @@ namespace SafeExamBrowser.WindowsApi
|
|||
User32.SendMessage(window, Constant.WM_SYSCOMMAND, (IntPtr) SystemCommand.CLOSE, IntPtr.Zero);
|
||||
}
|
||||
|
||||
public void SetAlwaysOnState(bool display = true, bool system = true)
|
||||
{
|
||||
if (display || system)
|
||||
{
|
||||
var state = EXECUTION_STATE.CONTINUOUS;
|
||||
|
||||
state |= display ? EXECUTION_STATE.DISPLAY_REQUIRED : 0x0;
|
||||
state |= system ? EXECUTION_STATE.SYSTEM_REQUIRED : 0x0;
|
||||
|
||||
Kernel32.SetThreadExecutionState(state);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetWallpaper(string filePath)
|
||||
{
|
||||
var success = User32.SystemParametersInfo(SPI.SETDESKWALLPAPER, 0, filePath, SPIF.NONE);
|
||||
|
|
Loading…
Reference in a new issue