SEBWIN-313: Implemented lock screen mechanism for blacklisted processes.
This commit is contained in:
parent
de6cb5e75c
commit
b6dbe6451d
32 changed files with 837 additions and 177 deletions
|
@ -28,6 +28,7 @@ using SafeExamBrowser.UserInterface.Contracts;
|
|||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Client.UnitTests
|
||||
|
@ -170,11 +171,9 @@ namespace SafeExamBrowser.Client.UnitTests
|
|||
RequestId = Guid.NewGuid()
|
||||
};
|
||||
var dialog = new Mock<IPasswordDialog>();
|
||||
var result = new Mock<IPasswordDialogResult>();
|
||||
var result = new PasswordDialogResult { Password = "blubb", Success = true };
|
||||
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(result.Object);
|
||||
result.SetupGet(r => r.Password).Returns("blubb");
|
||||
result.SetupGet(r => r.Success).Returns(true);
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(result);
|
||||
uiFactory.Setup(f => f.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(dialog.Object);
|
||||
|
||||
sut.TryStart();
|
||||
|
@ -182,8 +181,8 @@ namespace SafeExamBrowser.Client.UnitTests
|
|||
|
||||
runtimeProxy.Verify(p => p.SubmitPassword(
|
||||
It.Is<Guid>(g => g == args.RequestId),
|
||||
It.Is<bool>(b => b == result.Object.Success),
|
||||
It.Is<string>(s => s == result.Object.Password)), Times.Once);
|
||||
It.Is<bool>(b => b == result.Success),
|
||||
It.Is<string>(s => s == result.Password)), Times.Once);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
@ -461,14 +460,11 @@ namespace SafeExamBrowser.Client.UnitTests
|
|||
{
|
||||
var args = new System.ComponentModel.CancelEventArgs();
|
||||
var dialog = new Mock<IPasswordDialog>();
|
||||
var dialogResult = new Mock<IPasswordDialogResult>();
|
||||
var password = "blobb";
|
||||
var dialogResult = new PasswordDialogResult { Password = "blobb", Success = true };
|
||||
|
||||
settings.QuitPasswordHash = "1234";
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult.Object);
|
||||
dialogResult.SetupGet(r => r.Password).Returns(password);
|
||||
dialogResult.SetupGet(r => r.Success).Returns(true);
|
||||
hashAlgorithm.Setup(h => h.GenerateHashFor(It.Is<string>(s => s == password))).Returns(settings.QuitPasswordHash);
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult);
|
||||
hashAlgorithm.Setup(h => h.GenerateHashFor(It.Is<string>(s => s == dialogResult.Password))).Returns(settings.QuitPasswordHash);
|
||||
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
|
||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<TextKey>(), It.IsAny<TextKey>())).Returns(dialog.Object);
|
||||
|
||||
|
@ -486,11 +482,10 @@ namespace SafeExamBrowser.Client.UnitTests
|
|||
{
|
||||
var args = new System.ComponentModel.CancelEventArgs();
|
||||
var dialog = new Mock<IPasswordDialog>();
|
||||
var dialogResult = new Mock<IPasswordDialogResult>();
|
||||
var dialogResult = new PasswordDialogResult { Success = false };
|
||||
|
||||
settings.QuitPasswordHash = "1234";
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult.Object);
|
||||
dialogResult.SetupGet(r => r.Success).Returns(false);
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult);
|
||||
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
|
||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<TextKey>(), It.IsAny<TextKey>())).Returns(dialog.Object);
|
||||
|
||||
|
@ -508,12 +503,10 @@ namespace SafeExamBrowser.Client.UnitTests
|
|||
{
|
||||
var args = new System.ComponentModel.CancelEventArgs();
|
||||
var dialog = new Mock<IPasswordDialog>();
|
||||
var dialogResult = new Mock<IPasswordDialogResult>();
|
||||
var dialogResult = new PasswordDialogResult { Password = "blobb", Success = true };
|
||||
|
||||
settings.QuitPasswordHash = "1234";
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult.Object);
|
||||
dialogResult.SetupGet(r => r.Password).Returns("blobb");
|
||||
dialogResult.SetupGet(r => r.Success).Returns(true);
|
||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult);
|
||||
hashAlgorithm.Setup(h => h.GenerateHashFor(It.IsAny<string>())).Returns("9876");
|
||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<TextKey>(), It.IsAny<TextKey>())).Returns(dialog.Object);
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
public class ShellOperationTests
|
||||
{
|
||||
private Mock<IActionCenter> actionCenter;
|
||||
private List<IActionCenterActivator> activators;
|
||||
private Mock<IAudio> audio;
|
||||
private ClientContext context;
|
||||
private Mock<ILogger> logger;
|
||||
|
@ -52,7 +51,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
public void Initialize()
|
||||
{
|
||||
actionCenter = new Mock<IActionCenter>();
|
||||
activators = new List<IActionCenterActivator>();
|
||||
audio = new Mock<IAudio>();
|
||||
context = new ClientContext();
|
||||
logger = new Mock<ILogger>();
|
||||
|
@ -77,7 +75,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
|
||||
sut = new ShellOperation(
|
||||
actionCenter.Object,
|
||||
activators,
|
||||
audio.Object,
|
||||
aboutInfo.Object,
|
||||
aboutController.Object,
|
||||
|
@ -109,7 +106,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
|
||||
foreach (var activator in activatorMocks)
|
||||
{
|
||||
activators.Add(activator.Object);
|
||||
context.Activators.Add(activator.Object);
|
||||
}
|
||||
|
||||
sut.Perform();
|
||||
|
@ -272,7 +269,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
|||
|
||||
foreach (var activator in activatorMocks)
|
||||
{
|
||||
activators.Add(activator.Object);
|
||||
context.Activators.Add(activator.Object);
|
||||
}
|
||||
|
||||
sut.Revert();
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Browser.Contracts;
|
||||
using SafeExamBrowser.Communication.Contracts.Hosts;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
|
||||
namespace SafeExamBrowser.Client
|
||||
{
|
||||
|
@ -19,6 +21,11 @@ namespace SafeExamBrowser.Client
|
|||
/// </summary>
|
||||
internal class ClientContext
|
||||
{
|
||||
/// <summary>
|
||||
/// All activators for the action center.
|
||||
/// </summary>
|
||||
internal IList<IActionCenterActivator> Activators { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The global application configuration.
|
||||
/// </summary>
|
||||
|
@ -43,5 +50,10 @@ namespace SafeExamBrowser.Client
|
|||
/// The settings for the current session.
|
||||
/// </summary>
|
||||
internal AppSettings Settings { get; set; }
|
||||
|
||||
internal ClientContext()
|
||||
{
|
||||
Activators = new List<IActionCenterActivator>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ using SafeExamBrowser.UserInterface.Contracts;
|
|||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Client
|
||||
|
@ -235,9 +236,60 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
private void ApplicationMonitor_TerminationFailed(IEnumerable<RunningApplication> applications)
|
||||
{
|
||||
// foreach actionCenterActivator -> Pause
|
||||
// TODO: Show lock screen!
|
||||
// foreach actionCenterActivator -> Resume
|
||||
var applicationList = string.Join(Environment.NewLine, applications.Select(a => $"- {a.Name}"));
|
||||
var message = $"{text.Get(TextKey.LockScreen_Message)}{Environment.NewLine}{Environment.NewLine}{applicationList}";
|
||||
var title = text.Get(TextKey.LockScreen_Title);
|
||||
var hasQuitPassword = !string.IsNullOrEmpty(Settings.QuitPasswordHash);
|
||||
var allowOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_AllowOption) };
|
||||
var terminateOption = new LockScreenOption { Text = text.Get(TextKey.LockScreen_TerminateOption) };
|
||||
var lockScreen = uiFactory.CreateLockScreen(message, title, new [] { allowOption, terminateOption });
|
||||
var result = default(LockScreenResult);
|
||||
|
||||
logger.Warn("Showing lock screen due to failed termination of blacklisted application(s)!");
|
||||
PauseActivators();
|
||||
lockScreen.Show();
|
||||
|
||||
for (var unlocked = false; !unlocked;)
|
||||
{
|
||||
result = lockScreen.WaitForResult();
|
||||
|
||||
if (hasQuitPassword)
|
||||
{
|
||||
var passwordHash = hashAlgorithm.GenerateHashFor(result.Password);
|
||||
var isCorrect = Settings.QuitPasswordHash.Equals(passwordHash, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (isCorrect)
|
||||
{
|
||||
logger.Info("The user entered the correct unlock password.");
|
||||
unlocked = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Info("The user entered the wrong unlock password.");
|
||||
messageBox.Show(TextKey.MessageBox_InvalidUnlockPassword, TextKey.MessageBox_InvalidUnlockPasswordTitle, icon: MessageBoxIcon.Warning, parent: lockScreen);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Warn($"No unlock password is defined, allowing user to resume session!");
|
||||
unlocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
lockScreen.Close();
|
||||
ResumeActivators();
|
||||
logger.Info("Closed lock screen.");
|
||||
|
||||
if (result.OptionId == allowOption.Id)
|
||||
{
|
||||
logger.Info($"The blacklisted application(s) {string.Join(", ", applications.Select(a => $"'{a.Name}'"))} will be temporarily allowed.");
|
||||
}
|
||||
else if (result.OptionId == terminateOption.Id)
|
||||
{
|
||||
logger.Info("Initiating shutdown request...");
|
||||
|
||||
TryRequestShutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void Browser_ConfigurationDownloadRequested(string fileName, DownloadEventArgs args)
|
||||
|
@ -409,16 +461,16 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
private void Shell_QuitButtonClicked(System.ComponentModel.CancelEventArgs args)
|
||||
{
|
||||
terminationActivator.Pause();
|
||||
PauseActivators();
|
||||
args.Cancel = !TryInitiateShutdown();
|
||||
terminationActivator.Resume();
|
||||
ResumeActivators();
|
||||
}
|
||||
|
||||
private void TerminationActivator_Activated()
|
||||
{
|
||||
terminationActivator.Pause();
|
||||
PauseActivators();
|
||||
TryInitiateShutdown();
|
||||
terminationActivator.Resume();
|
||||
ResumeActivators();
|
||||
}
|
||||
|
||||
private void AskForAutomaticApplicationTermination(ApplicationTerminationEventArgs args)
|
||||
|
@ -442,10 +494,33 @@ namespace SafeExamBrowser.Client
|
|||
messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: splashScreen);
|
||||
}
|
||||
|
||||
private void PauseActivators()
|
||||
{
|
||||
// TODO: Same for task view activator!
|
||||
terminationActivator.Pause();
|
||||
|
||||
foreach (var activator in context.Activators)
|
||||
{
|
||||
activator.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
private void ResumeActivators()
|
||||
{
|
||||
// TODO: Same for task view activator!
|
||||
terminationActivator.Resume();
|
||||
|
||||
foreach (var activator in context.Activators)
|
||||
{
|
||||
activator.Resume();
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryInitiateShutdown()
|
||||
{
|
||||
var hasQuitPassword = !String.IsNullOrEmpty(Settings.QuitPasswordHash);
|
||||
var hasQuitPassword = !string.IsNullOrEmpty(Settings.QuitPasswordHash);
|
||||
var requestShutdown = false;
|
||||
var succes = false;
|
||||
|
||||
if (hasQuitPassword)
|
||||
{
|
||||
|
@ -458,20 +533,10 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
if (requestShutdown)
|
||||
{
|
||||
var communication = runtime.RequestShutdown();
|
||||
|
||||
if (communication.Success)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.Error("Failed to communicate shutdown request to the runtime!");
|
||||
messageBox.Show(TextKey.MessageBox_QuitError, TextKey.MessageBox_QuitErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
succes = TryRequestShutdown();
|
||||
}
|
||||
|
||||
return false;
|
||||
return succes;
|
||||
}
|
||||
|
||||
private bool TryConfirmShutdown()
|
||||
|
@ -512,5 +577,18 @@ namespace SafeExamBrowser.Client
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryRequestShutdown()
|
||||
{
|
||||
var communication = runtime.RequestShutdown();
|
||||
|
||||
if (!communication.Success)
|
||||
{
|
||||
logger.Error("Failed to communicate shutdown request to the runtime!");
|
||||
messageBox.Show(TextKey.MessageBox_QuitError, TextKey.MessageBox_QuitErrorTitle, icon: MessageBoxIcon.Error);
|
||||
}
|
||||
|
||||
return communication.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,14 +243,8 @@ namespace SafeExamBrowser.Client
|
|||
var logController = new LogNotificationController(logger, uiFactory);
|
||||
var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
||||
var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
|
||||
var activators = new IActionCenterActivator[]
|
||||
{
|
||||
new KeyboardActivator(ModuleLogger(nameof(KeyboardActivator))),
|
||||
new TouchActivator(ModuleLogger(nameof(TouchActivator)))
|
||||
};
|
||||
var operation = new ShellOperation(
|
||||
actionCenter,
|
||||
activators,
|
||||
audio,
|
||||
aboutInfo,
|
||||
aboutController,
|
||||
|
@ -267,6 +261,9 @@ namespace SafeExamBrowser.Client
|
|||
uiFactory,
|
||||
wirelessAdapter);
|
||||
|
||||
context.Activators.Add(new KeyboardActivator(ModuleLogger(nameof(KeyboardActivator))));
|
||||
context.Activators.Add(new TouchActivator(ModuleLogger(nameof(TouchActivator))));
|
||||
|
||||
return operation;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Client.Contracts;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||
|
@ -26,7 +25,6 @@ namespace SafeExamBrowser.Client.Operations
|
|||
internal class ShellOperation : ClientOperation
|
||||
{
|
||||
private IActionCenter actionCenter;
|
||||
private IEnumerable<IActionCenterActivator> activators;
|
||||
private IAudio audio;
|
||||
private INotificationInfo aboutInfo;
|
||||
private INotificationController aboutController;
|
||||
|
@ -47,7 +45,6 @@ namespace SafeExamBrowser.Client.Operations
|
|||
|
||||
public ShellOperation(
|
||||
IActionCenter actionCenter,
|
||||
IEnumerable<IActionCenterActivator> activators,
|
||||
IAudio audio,
|
||||
INotificationInfo aboutInfo,
|
||||
INotificationController aboutController,
|
||||
|
@ -67,7 +64,6 @@ namespace SafeExamBrowser.Client.Operations
|
|||
this.aboutInfo = aboutInfo;
|
||||
this.aboutController = aboutController;
|
||||
this.actionCenter = actionCenter;
|
||||
this.activators = activators;
|
||||
this.audio = audio;
|
||||
this.keyboard = keyboard;
|
||||
this.logger = logger;
|
||||
|
@ -113,7 +109,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
|
||||
if (Context.Settings.ActionCenter.EnableActionCenter)
|
||||
{
|
||||
foreach (var activator in activators)
|
||||
foreach (var activator in Context.Activators)
|
||||
{
|
||||
actionCenter.Register(activator);
|
||||
activator.Start();
|
||||
|
@ -283,7 +279,7 @@ namespace SafeExamBrowser.Client.Operations
|
|||
|
||||
if (Context.Settings.ActionCenter.EnableActionCenter)
|
||||
{
|
||||
foreach (var activator in activators)
|
||||
foreach (var activator in Context.Activators)
|
||||
{
|
||||
activator.Stop();
|
||||
}
|
||||
|
|
|
@ -106,19 +106,57 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
}
|
||||
}
|
||||
|
||||
private void MapEnableContentRequestFilter(AppSettings settings, object value)
|
||||
private void MapMainWindowMode(AppSettings settings, object value)
|
||||
{
|
||||
if (value is bool process)
|
||||
const int FULLSCREEN = 1;
|
||||
|
||||
if (value is int mode)
|
||||
{
|
||||
settings.Browser.Filter.ProcessContentRequests = process;
|
||||
settings.Browser.MainWindow.FullScreenMode = mode == FULLSCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
private void MapEnableMainRequestFilter(AppSettings settings, object value)
|
||||
private void MapRequestFilter(IDictionary<string, object> rawData, AppSettings settings)
|
||||
{
|
||||
if (value is bool process)
|
||||
var processMainRequests = rawData.TryGetValue(Keys.Browser.Filter.EnableMainRequestFilter, out var value) && value as bool? == true;
|
||||
var processContentRequests = rawData.TryGetValue(Keys.Browser.UserAgentModeMobile, out value) && value as bool? == true;
|
||||
|
||||
settings.Browser.Filter.ProcessMainRequests = processMainRequests;
|
||||
settings.Browser.Filter.ProcessContentRequests = processMainRequests && processContentRequests;
|
||||
}
|
||||
|
||||
private void MapShowReloadWarning(AppSettings settings, object value)
|
||||
{
|
||||
if (value is bool show)
|
||||
{
|
||||
settings.Browser.Filter.ProcessMainRequests = process;
|
||||
settings.Browser.MainWindow.ShowReloadWarning = show;
|
||||
}
|
||||
}
|
||||
|
||||
private void MapShowReloadWarningAdditionalWindow(AppSettings settings, object value)
|
||||
{
|
||||
if (value is bool show)
|
||||
{
|
||||
settings.Browser.AdditionalWindow.ShowReloadWarning = show;
|
||||
}
|
||||
}
|
||||
|
||||
private void MapUserAgentMode(IDictionary<string, object> rawData, AppSettings settings)
|
||||
{
|
||||
const int DEFAULT = 0;
|
||||
|
||||
var useCustomForDesktop = rawData.TryGetValue(Keys.Browser.UserAgentModeDesktop, out var value) && value as int? != DEFAULT;
|
||||
var useCustomForMobile = rawData.TryGetValue(Keys.Browser.UserAgentModeMobile, out value) && value as int? != DEFAULT;
|
||||
|
||||
if (settings.UserInterfaceMode == UserInterfaceMode.Desktop && useCustomForDesktop)
|
||||
{
|
||||
settings.Browser.UseCustomUserAgent = true;
|
||||
settings.Browser.CustomUserAgent = rawData[Keys.Browser.CustomUserAgentDesktop] as string;
|
||||
}
|
||||
else if (settings.UserInterfaceMode == UserInterfaceMode.Mobile && useCustomForMobile)
|
||||
{
|
||||
settings.Browser.UseCustomUserAgent = true;
|
||||
settings.Browser.CustomUserAgent = rawData[Keys.Browser.CustomUserAgentMobile] as string;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,50 +197,5 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void MapMainWindowMode(AppSettings settings, object value)
|
||||
{
|
||||
const int FULLSCREEN = 1;
|
||||
|
||||
if (value is int mode)
|
||||
{
|
||||
settings.Browser.MainWindow.FullScreenMode = mode == FULLSCREEN;
|
||||
}
|
||||
}
|
||||
|
||||
private void MapShowReloadWarning(AppSettings settings, object value)
|
||||
{
|
||||
if (value is bool show)
|
||||
{
|
||||
settings.Browser.MainWindow.ShowReloadWarning = show;
|
||||
}
|
||||
}
|
||||
|
||||
private void MapShowReloadWarningAdditionalWindow(AppSettings settings, object value)
|
||||
{
|
||||
if (value is bool show)
|
||||
{
|
||||
settings.Browser.AdditionalWindow.ShowReloadWarning = show;
|
||||
}
|
||||
}
|
||||
|
||||
private void MapUserAgentMode(IDictionary<string, object> rawData, AppSettings settings)
|
||||
{
|
||||
const int DEFAULT = 0;
|
||||
|
||||
var useCustomForDesktop = rawData.TryGetValue(Keys.Browser.UserAgentModeDesktop, out var value) && value as int? != DEFAULT;
|
||||
var useCustomForMobile = rawData.TryGetValue(Keys.Browser.UserAgentModeMobile, out value) && value as int? != DEFAULT;
|
||||
|
||||
if (settings.UserInterfaceMode == UserInterfaceMode.Desktop && useCustomForDesktop)
|
||||
{
|
||||
settings.Browser.UseCustomUserAgent = true;
|
||||
settings.Browser.CustomUserAgent = rawData[Keys.Browser.CustomUserAgentDesktop] as string;
|
||||
}
|
||||
else if (settings.UserInterfaceMode == UserInterfaceMode.Mobile && useCustomForMobile)
|
||||
{
|
||||
settings.Browser.UseCustomUserAgent = true;
|
||||
settings.Browser.CustomUserAgent = rawData[Keys.Browser.CustomUserAgentMobile] as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
}
|
||||
|
||||
MapApplicationLogAccess(rawData, settings);
|
||||
MapRequestFilter(rawData, settings);
|
||||
MapKioskMode(rawData, settings);
|
||||
MapUserAgentMode(rawData, settings);
|
||||
}
|
||||
|
@ -95,12 +96,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
|||
case Keys.Browser.AdditionalWindow.ShowReloadWarning:
|
||||
MapShowReloadWarningAdditionalWindow(settings, value);
|
||||
break;
|
||||
case Keys.Browser.Filter.EnableContentRequestFilter:
|
||||
MapEnableContentRequestFilter(settings, value);
|
||||
break;
|
||||
case Keys.Browser.Filter.EnableMainRequestFilter:
|
||||
MapEnableMainRequestFilter(settings, value);
|
||||
break;
|
||||
case Keys.Browser.Filter.UrlFilterRules:
|
||||
MapUrlFilterRules(settings, value);
|
||||
break;
|
||||
|
|
|
@ -21,6 +21,11 @@ namespace SafeExamBrowser.I18n.Contracts
|
|||
BrowserWindow_DeveloperConsoleMenuItem,
|
||||
BrowserWindow_ZoomMenuItem,
|
||||
Build,
|
||||
LockScreen_AllowOption,
|
||||
LockScreen_Message,
|
||||
LockScreen_TerminateOption,
|
||||
LockScreen_Title,
|
||||
LockScreen_UnlockButton,
|
||||
LogWindow_Title,
|
||||
MessageBox_ApplicationAutoTerminationDataLossWarning,
|
||||
MessageBox_ApplicationAutoTerminationQuestion,
|
||||
|
@ -44,6 +49,8 @@ namespace SafeExamBrowser.I18n.Contracts
|
|||
MessageBox_InvalidPasswordErrorTitle,
|
||||
MessageBox_InvalidQuitPassword,
|
||||
MessageBox_InvalidQuitPasswordTitle,
|
||||
MessageBox_InvalidUnlockPassword,
|
||||
MessageBox_InvalidUnlockPasswordTitle,
|
||||
MessageBox_NoButton,
|
||||
MessageBox_NotSupportedConfigurationResource,
|
||||
MessageBox_NotSupportedConfigurationResourceTitle,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
Back to previous page
|
||||
</Entry>
|
||||
<Entry key="Browser_BlockedPageMessage">
|
||||
Access to this page is not allowed according to the application configuration.
|
||||
Access to this page is not allowed according to the current configuration.
|
||||
</Entry>
|
||||
<Entry key="Browser_BlockedPageTitle">
|
||||
Page Blocked
|
||||
|
@ -21,6 +21,21 @@
|
|||
<Entry key="Build">
|
||||
Build
|
||||
</Entry>
|
||||
<Entry key="LockScreen_AllowOption">
|
||||
Temporarily allow the blacklisted applications. This applies only to the currently running instances and session!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_Message">
|
||||
The blacklisted applications listed below were started and could not be automatically terminated! In order to unlock SEB, please select one of the available options and enter the correct unlock password.
|
||||
</Entry>
|
||||
<Entry key="LockScreen_TerminateOption">
|
||||
Terminate Safe Exam Browser. WARNING: There will be no possibility to save data or perform any further actions, the shutdown will be initiated immediately!
|
||||
</Entry>
|
||||
<Entry key="LockScreen_Title">
|
||||
SEB LOCKED
|
||||
</Entry>
|
||||
<Entry key="LockScreen_UnlockButton">
|
||||
Unlock
|
||||
</Entry>
|
||||
<Entry key="LogWindow_Title">
|
||||
Application Log
|
||||
</Entry>
|
||||
|
@ -34,7 +49,7 @@
|
|||
IMPORTANT: Any unsaved application data might be lost!
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ApplicationError">
|
||||
An unrecoverable error has occurred! Please consult the application log for more information. The application will now shut down...
|
||||
An unrecoverable error has occurred! Please consult the log files for more information. SEB will now shut down...
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ApplicationErrorTitle">
|
||||
Application Error
|
||||
|
@ -46,7 +61,7 @@
|
|||
Automatic Termination Failed
|
||||
</Entry>
|
||||
<Entry key="MessageBox_BrowserNavigationBlocked">
|
||||
Access to "%%URL%%" is not allowed according to the application configuration.
|
||||
Access to "%%URL%%" is not allowed according to the current configuration.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_BrowserNavigationBlockedTitle">
|
||||
Page Blocked
|
||||
|
@ -55,19 +70,19 @@
|
|||
Cancel
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ClientConfigurationError">
|
||||
The local client configuration has failed! Please consult the application log for more information. The application will now shut down...
|
||||
The local client configuration has failed! Please consult the log files for more information. SEB will now shut down...
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ClientConfigurationErrorTitle">
|
||||
Client Configuration Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ClientConfigurationQuestion">
|
||||
The client configuration has been saved and will be used when you start the application the next time. Do you want to quit for now?
|
||||
The client configuration has been saved and will be used when you start SEB the next time. Do you want to quit for now?
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ClientConfigurationQuestionTitle">
|
||||
Configuration Successful
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ConfigurationDownloadError">
|
||||
Failed to download the new application configuration. Please try again or contact technical support.
|
||||
Failed to download the new configuration. Please try again or contact technical support.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ConfigurationDownloadErrorTitle">
|
||||
Download Error
|
||||
|
@ -79,17 +94,23 @@
|
|||
Configuration Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_InvalidPasswordError">
|
||||
You failed to enter the correct password within 5 attempts. The application will now terminate...
|
||||
You failed to enter the correct password within 5 attempts. SEB will now terminate...
|
||||
</Entry>
|
||||
<Entry key="MessageBox_InvalidPasswordErrorTitle">
|
||||
Invalid Password
|
||||
</Entry>
|
||||
<Entry key="MessageBox_InvalidQuitPassword">
|
||||
The application can only be terminated by entering the correct quit password.
|
||||
SEB can only be terminated by entering the correct quit password.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_InvalidQuitPasswordTitle">
|
||||
Invalid Quit Password
|
||||
</Entry>
|
||||
<Entry key="MessageBox_InvalidUnlockPassword">
|
||||
SEB can only be unlocked by entering the correct password.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_InvalidUnlockPasswordTitle">
|
||||
Invalid Unlock Password
|
||||
</Entry>
|
||||
<Entry key="MessageBox_NoButton">
|
||||
No
|
||||
</Entry>
|
||||
|
@ -103,7 +124,7 @@
|
|||
OK
|
||||
</Entry>
|
||||
<Entry key="MessageBox_Quit">
|
||||
Do you want to quit the application?
|
||||
Do you want to quit SEB?
|
||||
</Entry>
|
||||
<Entry key="MessageBox_QuitTitle">
|
||||
Quit?
|
||||
|
@ -115,7 +136,7 @@
|
|||
Quit Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigurationDenied">
|
||||
You are not allowed to reconfigure the application.
|
||||
You are not allowed to reconfigure SEB.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ReconfigurationDeniedTitle">
|
||||
Reconfiguration Denied
|
||||
|
@ -133,37 +154,37 @@
|
|||
Reload?
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ServiceUnavailableError">
|
||||
Failed to initialize the SEB service! The application will now terminate since the service is configured to be mandatory.
|
||||
Failed to initialize the SEB service! SEB will now terminate since the service is configured to be mandatory.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ServiceUnavailableErrorTitle">
|
||||
Service Unavailable
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ServiceUnavailableWarning">
|
||||
Failed to initialize the SEB service. The application will continue initialization since the service is configured to be optional.
|
||||
Failed to initialize the SEB service. SEB will continue initialization since the service is configured to be optional.
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ServiceUnavailableWarningTitle">
|
||||
Service Unavailable
|
||||
</Entry>
|
||||
<Entry key="MessageBox_SessionStartError">
|
||||
The application failed to start a new session! Please consult the application log for more information...
|
||||
SEB failed to start a new session! Please consult the log files for more information...
|
||||
</Entry>
|
||||
<Entry key="MessageBox_SessionStartErrorTitle">
|
||||
Session Start Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ShutdownError">
|
||||
An unexpected error occurred during the shutdown procedure! Please consult the application log for more information...
|
||||
An unexpected error occurred during the shutdown procedure! Please consult the log files for more information...
|
||||
</Entry>
|
||||
<Entry key="MessageBox_ShutdownErrorTitle">
|
||||
Shutdown Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_StartupError">
|
||||
An unexpected error occurred during the startup procedure! Please consult the application log for more information...
|
||||
An unexpected error occurred during the startup procedure! Please consult the log files for more information...
|
||||
</Entry>
|
||||
<Entry key="MessageBox_StartupErrorTitle">
|
||||
Startup Error
|
||||
</Entry>
|
||||
<Entry key="MessageBox_UnexpectedConfigurationError">
|
||||
An unexpected error occurred while trying to load configuration resource "%%URI%%"! Please consult the application log for more information...
|
||||
An unexpected error occurred while trying to load configuration resource "%%URI%%"! Please consult the log files for more information...
|
||||
</Entry>
|
||||
<Entry key="MessageBox_UnexpectedConfigurationErrorTitle">
|
||||
Configuration Error
|
||||
|
@ -196,7 +217,7 @@
|
|||
Initializing browser
|
||||
</Entry>
|
||||
<Entry key="OperationStatus_InitializeConfiguration">
|
||||
Initializing application configuration
|
||||
Initializing configuration
|
||||
</Entry>
|
||||
<Entry key="OperationStatus_InitializeKioskMode">
|
||||
Initializing kiosk mode
|
||||
|
@ -283,19 +304,19 @@
|
|||
Settings Password Required
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_QuitPasswordRequired">
|
||||
Please enter the quit password in order to terminate the application:
|
||||
Please enter the quit password in order to terminate SEB:
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_QuitPasswordRequiredTitle">
|
||||
Quit Password Required
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_SettingsPasswordRequired">
|
||||
Please enter the settings password for the selected application configuration:
|
||||
Please enter the settings password for the selected configuration:
|
||||
</Entry>
|
||||
<Entry key="PasswordDialog_SettingsPasswordRequiredTitle">
|
||||
Settings Password Required
|
||||
</Entry>
|
||||
<Entry key="RuntimeWindow_ApplicationRunning">
|
||||
The application is running.
|
||||
SEB is running.
|
||||
</Entry>
|
||||
<Entry key="Shell_QuitButton">
|
||||
Terminate Session
|
||||
|
|
|
@ -14,16 +14,17 @@ using SafeExamBrowser.Communication.Contracts.Events;
|
|||
using SafeExamBrowser.Communication.Contracts.Hosts;
|
||||
using SafeExamBrowser.Communication.Contracts.Proxies;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.Settings.Service;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Runtime.Operations.Events;
|
||||
using SafeExamBrowser.Settings;
|
||||
using SafeExamBrowser.Settings.Service;
|
||||
using SafeExamBrowser.UserInterface.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.WindowsApi.Contracts;
|
||||
|
||||
namespace SafeExamBrowser.Runtime.UnitTests
|
||||
|
@ -219,14 +220,11 @@ namespace SafeExamBrowser.Runtime.UnitTests
|
|||
public void Operations_MustRequestPasswordViaDialogOnDefaultDesktop()
|
||||
{
|
||||
var args = new PasswordRequiredEventArgs();
|
||||
var password = "test1234";
|
||||
var passwordDialog = new Mock<IPasswordDialog>();
|
||||
var result = new Mock<IPasswordDialogResult>();
|
||||
var result = new PasswordDialogResult { Password = "test1234", Success = true };
|
||||
|
||||
currentSettings.KioskMode = KioskMode.DisableExplorerShell;
|
||||
passwordDialog.Setup(p => p.Show(It.IsAny<IWindow>())).Returns(result.Object);
|
||||
result.SetupGet(r => r.Password).Returns(password);
|
||||
result.SetupGet(r => r.Success).Returns(true);
|
||||
passwordDialog.Setup(p => p.Show(It.IsAny<IWindow>())).Returns(result);
|
||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(passwordDialog.Object);
|
||||
|
||||
sut.TryStart();
|
||||
|
@ -237,7 +235,7 @@ namespace SafeExamBrowser.Runtime.UnitTests
|
|||
uiFactory.Verify(u => u.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||
|
||||
Assert.AreEqual(true, args.Success);
|
||||
Assert.AreEqual(password, args.Password);
|
||||
Assert.AreEqual(result.Password, args.Password);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
|
|
|
@ -6,12 +6,13 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Client.Contracts;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
|
@ -19,6 +20,7 @@ using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
|
|||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Contracts
|
||||
{
|
||||
|
@ -52,6 +54,11 @@ namespace SafeExamBrowser.UserInterface.Contracts
|
|||
/// </summary>
|
||||
ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a lock screen with the given message, title and options.
|
||||
/// </summary>
|
||||
ILockScreen CreateLockScreen(string message, string title, IEnumerable<LockScreenOption> options);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new log window which runs on its own thread.
|
||||
/// </summary>
|
||||
|
|
|
@ -75,9 +75,12 @@
|
|||
<Compile Include="Shell\ISystemControl.cs" />
|
||||
<Compile Include="Shell\ITaskbar.cs" />
|
||||
<Compile Include="Shell\Location.cs" />
|
||||
<Compile Include="Windows\Data\LockScreenOption.cs" />
|
||||
<Compile Include="Windows\Data\LockScreenResult.cs" />
|
||||
<Compile Include="Windows\Events\WindowClosingEventHandler.cs" />
|
||||
<Compile Include="Windows\ILockScreen.cs" />
|
||||
<Compile Include="Windows\IPasswordDialog.cs" />
|
||||
<Compile Include="Windows\IPasswordDialogResult.cs" />
|
||||
<Compile Include="Windows\Data\PasswordDialogResult.cs" />
|
||||
<Compile Include="Windows\IRuntimeWindow.cs" />
|
||||
<Compile Include="Windows\ISplashScreen.cs" />
|
||||
<Compile Include="Windows\IWindow.cs" />
|
||||
|
|
|
@ -30,6 +30,16 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
|||
/// </summary>
|
||||
event ActivatorEventHandler Toggled;
|
||||
|
||||
/// <summary>
|
||||
/// Temporarily stops processing all user input.
|
||||
/// </summary>
|
||||
void Pause();
|
||||
|
||||
/// <summary>
|
||||
/// Resumes processing user input.
|
||||
/// </summary>
|
||||
void Resume();
|
||||
|
||||
/// <summary>
|
||||
/// Starts monitoring user input events.
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2019 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.UserInterface.Contracts.Windows.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines an option for the user to select on the <see cref="ILockScreen"/>.
|
||||
/// </summary>
|
||||
public class LockScreenOption
|
||||
{
|
||||
/// <summary>
|
||||
/// The unique identifier for this option.
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The text to be displayed to the user.
|
||||
/// </summary>
|
||||
public string Text { get; set; }
|
||||
|
||||
public LockScreenOption()
|
||||
{
|
||||
Id = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2019 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.UserInterface.Contracts.Windows.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the result of a lock screen interaction by the user.
|
||||
/// </summary>
|
||||
public class LockScreenResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The identifier of the option selected by the user, if available.
|
||||
/// </summary>
|
||||
public Guid? OptionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The password entered by the user.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
}
|
||||
}
|
|
@ -6,21 +6,21 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the user interaction result of an <see cref="IPasswordDialog"/>.
|
||||
/// </summary>
|
||||
public interface IPasswordDialogResult
|
||||
public class PasswordDialogResult
|
||||
{
|
||||
/// <summary>
|
||||
/// The password entered by the user, or <c>null</c> if the interaction was unsuccessful.
|
||||
/// </summary>
|
||||
string Password { get; }
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the user confirmed the dialog or not.
|
||||
/// </summary>
|
||||
bool Success { get; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2019 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 SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the functionality of a lock screen which covers all active displays and prevents the user from continuing their work.
|
||||
/// </summary>
|
||||
public interface ILockScreen : IWindow
|
||||
{
|
||||
/// <summary>
|
||||
/// Waits for the user to provide the required input to unlock the application.
|
||||
/// </summary>
|
||||
LockScreenResult WaitForResult();
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -16,6 +18,6 @@ namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
|||
/// <summary>
|
||||
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
|
||||
/// </summary>
|
||||
IPasswordDialogResult Show(IWindow parent = null);
|
||||
PasswordDialogResult Show(IWindow parent = null);
|
||||
}
|
||||
}
|
||||
|
|
34
SafeExamBrowser.UserInterface.Desktop/LockScreen.xaml
Normal file
34
SafeExamBrowser.UserInterface.Desktop/LockScreen.xaml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<Window x:Class="SafeExamBrowser.UserInterface.Desktop.LockScreen"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
|
||||
mc:Ignorable="d" d:DesignWidth="1500" ResizeMode="NoResize" Topmost="True" WindowState="Maximized" WindowStyle="None">
|
||||
<Grid Background="Red">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="1" Orientation="Vertical">
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Margin="0,10">
|
||||
<Image Height="75" Margin="0,0,20,0" Source="./Images/SafeExamBrowser.ico" />
|
||||
<TextBlock Name="Heading" Foreground="White" FontSize="50" FontWeight="ExtraBold" TextAlignment="Center" Text="SEB LOCKED" />
|
||||
</StackPanel>
|
||||
<TextBlock Name="Message" Foreground="White" FontSize="16" FontWeight="DemiBold" Margin="0,10" Padding="5" TextWrapping="Wrap" />
|
||||
<StackPanel Name="Options" Margin="0,10" Orientation="Vertical" />
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Margin="0,10">
|
||||
<PasswordBox Name="Password" Margin="10,5" MinWidth="250" Padding="5" />
|
||||
<Button Name="Button" Cursor="Hand" Margin="10,5" MinWidth="75" Padding="5" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
168
SafeExamBrowser.UserInterface.Desktop/LockScreen.xaml.cs
Normal file
168
SafeExamBrowser.UserInterface.Desktop/LockScreen.xaml.cs
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2019 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
using Screen = System.Windows.Forms.Screen;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop
|
||||
{
|
||||
public partial class LockScreen : Window, ILockScreen
|
||||
{
|
||||
private AutoResetEvent autoResetEvent;
|
||||
private IList<Window> windows;
|
||||
private IText text;
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { throw new NotImplementedException(); }
|
||||
remove { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public LockScreen(string message, string title, IText text, IEnumerable<LockScreenOption> options)
|
||||
{
|
||||
this.autoResetEvent = new AutoResetEvent(false);
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeLockWindow(message, title, options);
|
||||
}
|
||||
|
||||
public void BringToForeground()
|
||||
{
|
||||
Dispatcher.Invoke(Activate);
|
||||
}
|
||||
|
||||
public new void Close()
|
||||
{
|
||||
Dispatcher.Invoke(CloseAll);
|
||||
}
|
||||
|
||||
public new void Show()
|
||||
{
|
||||
Dispatcher.Invoke(ShowAll);
|
||||
}
|
||||
|
||||
public LockScreenResult WaitForResult()
|
||||
{
|
||||
var result = new LockScreenResult();
|
||||
|
||||
autoResetEvent.WaitOne();
|
||||
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
result.Password = Password.Password;
|
||||
|
||||
foreach (var child in Options.Children)
|
||||
{
|
||||
if (child is RadioButton option && option.IsChecked == true)
|
||||
{
|
||||
result.OptionId = option.Tag as Guid?;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void InitializeLockWindow(string message, string title, IEnumerable<LockScreenOption> options)
|
||||
{
|
||||
windows = new List<Window>();
|
||||
|
||||
Button.Content = text.Get(TextKey.LockScreen_UnlockButton);
|
||||
Button.Click += Button_Click;
|
||||
Heading.Text = title;
|
||||
Message.Text = message;
|
||||
Password.KeyUp += Password_KeyUp;
|
||||
|
||||
foreach (var option in options)
|
||||
{
|
||||
Options.Children.Add(new RadioButton
|
||||
{
|
||||
Content = new TextBlock { Text = option.Text, TextWrapping = TextWrapping.Wrap },
|
||||
Cursor = Cursors.Hand,
|
||||
FontSize = Message.FontSize,
|
||||
Foreground = Message.Foreground,
|
||||
IsChecked = options.First() == option,
|
||||
Margin = new Thickness(2.5),
|
||||
Tag = option.Id,
|
||||
VerticalContentAlignment = VerticalAlignment.Center
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseAll()
|
||||
{
|
||||
foreach (var window in windows)
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
|
||||
base.Close();
|
||||
}
|
||||
|
||||
private void ShowAll()
|
||||
{
|
||||
foreach (var screen in Screen.AllScreens)
|
||||
{
|
||||
if (!screen.Primary)
|
||||
{
|
||||
ShowLockWindowOn(screen);
|
||||
}
|
||||
}
|
||||
|
||||
base.Show();
|
||||
}
|
||||
|
||||
private void ShowLockWindowOn(Screen screen)
|
||||
{
|
||||
var window = new Window();
|
||||
var position = this.TransformFromPhysical(screen.Bounds.X, screen.Bounds.Y);
|
||||
var size = this.TransformFromPhysical(screen.Bounds.Width, screen.Bounds.Height);
|
||||
|
||||
window.Background = Brushes.Red;
|
||||
window.Topmost = true;
|
||||
window.Left = position.X;
|
||||
window.Top = position.Y;
|
||||
window.Width = size.X;
|
||||
window.Height = size.Y;
|
||||
window.ResizeMode = ResizeMode.NoResize;
|
||||
window.WindowStyle = WindowStyle.None;
|
||||
|
||||
window.Show();
|
||||
windows.Add(window);
|
||||
|
||||
// The window can only be maximized after it was shown on its screen, otherwise it is rendered on the primary screen!
|
||||
window.WindowState = WindowState.Maximized;
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
autoResetEvent.Set();
|
||||
}
|
||||
|
||||
private void Password_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
autoResetEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using System.Windows;
|
|||
using System.Windows.Input;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop
|
||||
|
@ -38,7 +39,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
|||
Dispatcher.Invoke(Activate);
|
||||
}
|
||||
|
||||
public IPasswordDialogResult Show(IWindow parent = null)
|
||||
public PasswordDialogResult Show(IWindow parent = null)
|
||||
{
|
||||
return Dispatcher.Invoke(() =>
|
||||
{
|
||||
|
@ -96,11 +97,5 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
|||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private class PasswordDialogResult : IPasswordDialogResult
|
||||
{
|
||||
public string Password { get; set; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@
|
|||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
|
@ -140,6 +141,9 @@
|
|||
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
||||
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LockScreen.xaml.cs">
|
||||
<DependentUpon>LockScreen.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LogWindow.xaml.cs">
|
||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -306,6 +310,10 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Resource>
|
||||
<Page Include="LockScreen.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Templates\ScrollViewers.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
@ -13,9 +14,9 @@ using FontAwesome.WPF;
|
|||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Client.Contracts;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
|
@ -24,6 +25,7 @@ using SafeExamBrowser.UserInterface.Contracts;
|
|||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Desktop.Controls;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Desktop
|
||||
|
@ -85,6 +87,11 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
|||
}
|
||||
}
|
||||
|
||||
public ILockScreen CreateLockScreen(string message, string title, IEnumerable<LockScreenOption> options)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new LockScreen(message, title, text, options));
|
||||
}
|
||||
|
||||
public IWindow CreateLogWindow(ILogger logger)
|
||||
{
|
||||
LogWindow logWindow = null;
|
||||
|
|
34
SafeExamBrowser.UserInterface.Mobile/LockScreen.xaml
Normal file
34
SafeExamBrowser.UserInterface.Mobile/LockScreen.xaml
Normal file
|
@ -0,0 +1,34 @@
|
|||
<Window x:Class="SafeExamBrowser.UserInterface.Mobile.LockScreen"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Mobile"
|
||||
mc:Ignorable="d" d:DesignWidth="1500" FontSize="16" ResizeMode="NoResize" Topmost="True" WindowState="Maximized" WindowStyle="None">
|
||||
<Grid Background="Red">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="1">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="2*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="1" Orientation="Vertical">
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Margin="0,10">
|
||||
<Image Height="100" Margin="0,0,20,0" Source="./Images/SafeExamBrowser.ico" />
|
||||
<TextBlock Name="Heading" Foreground="White" FontSize="75" FontWeight="ExtraBold" TextAlignment="Center" Text="SEB LOCKED" />
|
||||
</StackPanel>
|
||||
<TextBlock Name="Message" Foreground="White" FontSize="24" FontWeight="DemiBold" Margin="0,10" Padding="5" TextWrapping="Wrap" />
|
||||
<StackPanel Name="Options" Margin="0,10" Orientation="Vertical" />
|
||||
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Margin="0,10">
|
||||
<PasswordBox Name="Password" Margin="10,5" MinWidth="500" Padding="12" />
|
||||
<Button Name="Button" Cursor="Hand" Margin="10,5" MinWidth="125" Padding="12" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Window>
|
168
SafeExamBrowser.UserInterface.Mobile/LockScreen.xaml.cs
Normal file
168
SafeExamBrowser.UserInterface.Mobile/LockScreen.xaml.cs
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (c) 2019 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||
using SafeExamBrowser.UserInterface.Shared.Utilities;
|
||||
using Screen = System.Windows.Forms.Screen;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Mobile
|
||||
{
|
||||
public partial class LockScreen : Window, ILockScreen
|
||||
{
|
||||
private AutoResetEvent autoResetEvent;
|
||||
private IList<Window> windows;
|
||||
private IText text;
|
||||
|
||||
event WindowClosingEventHandler IWindow.Closing
|
||||
{
|
||||
add { throw new NotImplementedException(); }
|
||||
remove { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
public LockScreen(string message, string title, IText text, IEnumerable<LockScreenOption> options)
|
||||
{
|
||||
this.autoResetEvent = new AutoResetEvent(false);
|
||||
this.text = text;
|
||||
|
||||
InitializeComponent();
|
||||
InitializeLockWindow(message, title, options);
|
||||
}
|
||||
|
||||
public void BringToForeground()
|
||||
{
|
||||
Dispatcher.Invoke(Activate);
|
||||
}
|
||||
|
||||
public new void Close()
|
||||
{
|
||||
Dispatcher.Invoke(CloseAll);
|
||||
}
|
||||
|
||||
public new void Show()
|
||||
{
|
||||
Dispatcher.Invoke(ShowAll);
|
||||
}
|
||||
|
||||
public LockScreenResult WaitForResult()
|
||||
{
|
||||
var result = new LockScreenResult();
|
||||
|
||||
autoResetEvent.WaitOne();
|
||||
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
result.Password = Password.Password;
|
||||
|
||||
foreach (var child in Options.Children)
|
||||
{
|
||||
if (child is RadioButton option && option.IsChecked == true)
|
||||
{
|
||||
result.OptionId = option.Tag as Guid?;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void InitializeLockWindow(string message, string title, IEnumerable<LockScreenOption> options)
|
||||
{
|
||||
windows = new List<Window>();
|
||||
|
||||
Button.Content = text.Get(TextKey.LockScreen_UnlockButton);
|
||||
Button.Click += Button_Click;
|
||||
Heading.Text = title;
|
||||
Message.Text = message;
|
||||
Password.KeyUp += Password_KeyUp;
|
||||
|
||||
foreach (var option in options)
|
||||
{
|
||||
Options.Children.Add(new RadioButton
|
||||
{
|
||||
Content = new TextBlock { Text = option.Text, TextWrapping = TextWrapping.Wrap },
|
||||
Cursor = Cursors.Hand,
|
||||
FontSize = Message.FontSize,
|
||||
Foreground = Message.Foreground,
|
||||
IsChecked = options.First() == option,
|
||||
Margin = new Thickness(5),
|
||||
Tag = option.Id,
|
||||
VerticalContentAlignment = VerticalAlignment.Center
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseAll()
|
||||
{
|
||||
foreach (var window in windows)
|
||||
{
|
||||
window.Close();
|
||||
}
|
||||
|
||||
base.Close();
|
||||
}
|
||||
|
||||
private void ShowAll()
|
||||
{
|
||||
foreach (var screen in Screen.AllScreens)
|
||||
{
|
||||
if (!screen.Primary)
|
||||
{
|
||||
ShowLockWindowOn(screen);
|
||||
}
|
||||
}
|
||||
|
||||
base.Show();
|
||||
}
|
||||
|
||||
private void ShowLockWindowOn(Screen screen)
|
||||
{
|
||||
var window = new Window();
|
||||
var position = this.TransformFromPhysical(screen.Bounds.X, screen.Bounds.Y);
|
||||
var size = this.TransformFromPhysical(screen.Bounds.Width, screen.Bounds.Height);
|
||||
|
||||
window.Background = Brushes.Red;
|
||||
window.Topmost = true;
|
||||
window.Left = position.X;
|
||||
window.Top = position.Y;
|
||||
window.Width = size.X;
|
||||
window.Height = size.Y;
|
||||
window.ResizeMode = ResizeMode.NoResize;
|
||||
window.WindowStyle = WindowStyle.None;
|
||||
|
||||
window.Show();
|
||||
windows.Add(window);
|
||||
|
||||
// The window can only be maximized after it was shown on its screen, otherwise it is rendered on the primary screen!
|
||||
window.WindowState = WindowState.Maximized;
|
||||
}
|
||||
|
||||
private void Button_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
autoResetEvent.Set();
|
||||
}
|
||||
|
||||
private void Password_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
{
|
||||
autoResetEvent.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using System.Windows;
|
|||
using System.Windows.Input;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Mobile
|
||||
|
@ -38,7 +39,7 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
|||
Dispatcher.Invoke(Activate);
|
||||
}
|
||||
|
||||
public IPasswordDialogResult Show(IWindow parent = null)
|
||||
public PasswordDialogResult Show(IWindow parent = null)
|
||||
{
|
||||
return Dispatcher.Invoke(() =>
|
||||
{
|
||||
|
@ -115,11 +116,5 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
|||
Dispatcher.InvokeAsync(InitializeBounds);
|
||||
}
|
||||
}
|
||||
|
||||
private class PasswordDialogResult : IPasswordDialogResult
|
||||
{
|
||||
public string Password { get; set; }
|
||||
public bool Success { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,6 +142,9 @@
|
|||
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
||||
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LockScreen.xaml.cs">
|
||||
<DependentUpon>LockScreen.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="LogWindow.xaml.cs">
|
||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -425,6 +428,10 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="LockScreen.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="LogWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
@ -13,9 +14,9 @@ using FontAwesome.WPF;
|
|||
using SafeExamBrowser.Applications.Contracts;
|
||||
using SafeExamBrowser.Client.Contracts;
|
||||
using SafeExamBrowser.Configuration.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.I18n.Contracts;
|
||||
using SafeExamBrowser.Logging.Contracts;
|
||||
using SafeExamBrowser.Settings.Browser;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||
|
@ -24,6 +25,7 @@ using SafeExamBrowser.UserInterface.Contracts;
|
|||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||
using SafeExamBrowser.UserInterface.Mobile.Controls;
|
||||
|
||||
namespace SafeExamBrowser.UserInterface.Mobile
|
||||
|
@ -85,6 +87,11 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
|||
}
|
||||
}
|
||||
|
||||
public ILockScreen CreateLockScreen(string message, string title, IEnumerable<LockScreenOption> options)
|
||||
{
|
||||
return Application.Current.Dispatcher.Invoke(() => new LockScreen(message, title, text, options));
|
||||
}
|
||||
|
||||
public IWindow CreateLogWindow(ILogger logger)
|
||||
{
|
||||
LogWindow logWindow = null;
|
||||
|
|
|
@ -12,31 +12,52 @@ using System.Windows.Media;
|
|||
|
||||
namespace SafeExamBrowser.UserInterface.Shared.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// WPF works with device-independent pixels. These methods are required to transform
|
||||
/// such values to their absolute, device-specific pixel values and vice versa.
|
||||
///
|
||||
/// Source: https://stackoverflow.com/questions/3286175/how-do-i-convert-a-wpf-size-to-physical-pixels
|
||||
/// </summary>
|
||||
public static class VisualExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// WPF works with device-independent pixels. This method is required to
|
||||
/// transform such values to their absolute, device-specific pixel value.
|
||||
/// Source: https://stackoverflow.com/questions/3286175/how-do-i-convert-a-wpf-size-to-physical-pixels
|
||||
/// </summary>
|
||||
public static Vector TransformToPhysical(this Visual visual, double x, double y)
|
||||
{
|
||||
Matrix transformToDevice;
|
||||
var matrix = default(Matrix);
|
||||
var source = PresentationSource.FromVisual(visual);
|
||||
|
||||
if (source != null)
|
||||
{
|
||||
transformToDevice = source.CompositionTarget.TransformToDevice;
|
||||
matrix = source.CompositionTarget.TransformToDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var newSource = new HwndSource(new HwndSourceParameters()))
|
||||
{
|
||||
transformToDevice = newSource.CompositionTarget.TransformToDevice;
|
||||
matrix = newSource.CompositionTarget.TransformToDevice;
|
||||
}
|
||||
}
|
||||
|
||||
return transformToDevice.Transform(new Vector(x, y));
|
||||
return matrix.Transform(new Vector(x, y));
|
||||
}
|
||||
|
||||
public static Vector TransformFromPhysical(this Visual visual, double x, double y)
|
||||
{
|
||||
var matrix = default(Matrix);
|
||||
var source = PresentationSource.FromVisual(visual);
|
||||
|
||||
if (source != null)
|
||||
{
|
||||
matrix = source.CompositionTarget.TransformFromDevice;
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var newSource = new HwndSource(new HwndSourceParameters()))
|
||||
{
|
||||
matrix = newSource.CompositionTarget.TransformFromDevice;
|
||||
}
|
||||
}
|
||||
|
||||
return matrix.Transform(new Vector(x, y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace SafeExamBrowser.WindowsApi
|
|||
{
|
||||
public class KeyboardActivator : IActionCenterActivator
|
||||
{
|
||||
private bool A, LeftWindows;
|
||||
private bool A, LeftWindows, paused;
|
||||
private IntPtr handle;
|
||||
private HookDelegate hookDelegate;
|
||||
private ILogger logger;
|
||||
|
@ -34,6 +34,18 @@ namespace SafeExamBrowser.WindowsApi
|
|||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
paused = true;
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
A = false;
|
||||
LeftWindows = false;
|
||||
paused = false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
var hookReadyEvent = new AutoResetEvent(false);
|
||||
|
@ -72,7 +84,7 @@ namespace SafeExamBrowser.WindowsApi
|
|||
|
||||
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (nCode >= 0)
|
||||
if (nCode >= 0 && !paused)
|
||||
{
|
||||
var changed = false;
|
||||
var keyData = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
|
||||
|
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.WindowsApi
|
|||
{
|
||||
private HookDelegate hookDelegate;
|
||||
private IntPtr handle;
|
||||
private bool isDown;
|
||||
private bool isDown, paused;
|
||||
private ILogger logger;
|
||||
|
||||
public event ActivatorEventHandler Activated;
|
||||
|
@ -35,6 +35,17 @@ namespace SafeExamBrowser.WindowsApi
|
|||
this.logger = logger;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
paused = true;
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
isDown = false;
|
||||
paused = false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
var hookReadyEvent = new AutoResetEvent(false);
|
||||
|
@ -73,7 +84,7 @@ namespace SafeExamBrowser.WindowsApi
|
|||
|
||||
private IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||
{
|
||||
if (nCode >= 0 && !Ignore(wParam.ToInt32()))
|
||||
if (nCode >= 0 && !paused && !Ignore(wParam.ToInt32()))
|
||||
{
|
||||
var message = wParam.ToInt32();
|
||||
var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
||||
|
|
Loading…
Reference in a new issue