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.MessageBox;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client.UnitTests
|
namespace SafeExamBrowser.Client.UnitTests
|
||||||
|
@ -170,11 +171,9 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
RequestId = Guid.NewGuid()
|
RequestId = Guid.NewGuid()
|
||||||
};
|
};
|
||||||
var dialog = new Mock<IPasswordDialog>();
|
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);
|
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(result);
|
||||||
result.SetupGet(r => r.Password).Returns("blubb");
|
|
||||||
result.SetupGet(r => r.Success).Returns(true);
|
|
||||||
uiFactory.Setup(f => f.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(dialog.Object);
|
uiFactory.Setup(f => f.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(dialog.Object);
|
||||||
|
|
||||||
sut.TryStart();
|
sut.TryStart();
|
||||||
|
@ -182,8 +181,8 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
|
|
||||||
runtimeProxy.Verify(p => p.SubmitPassword(
|
runtimeProxy.Verify(p => p.SubmitPassword(
|
||||||
It.Is<Guid>(g => g == args.RequestId),
|
It.Is<Guid>(g => g == args.RequestId),
|
||||||
It.Is<bool>(b => b == result.Object.Success),
|
It.Is<bool>(b => b == result.Success),
|
||||||
It.Is<string>(s => s == result.Object.Password)), Times.Once);
|
It.Is<string>(s => s == result.Password)), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -461,14 +460,11 @@ namespace SafeExamBrowser.Client.UnitTests
|
||||||
{
|
{
|
||||||
var args = new System.ComponentModel.CancelEventArgs();
|
var args = new System.ComponentModel.CancelEventArgs();
|
||||||
var dialog = new Mock<IPasswordDialog>();
|
var dialog = new Mock<IPasswordDialog>();
|
||||||
var dialogResult = new Mock<IPasswordDialogResult>();
|
var dialogResult = new PasswordDialogResult { Password = "blobb", Success = true };
|
||||||
var password = "blobb";
|
|
||||||
|
|
||||||
settings.QuitPasswordHash = "1234";
|
settings.QuitPasswordHash = "1234";
|
||||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult.Object);
|
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult);
|
||||||
dialogResult.SetupGet(r => r.Password).Returns(password);
|
hashAlgorithm.Setup(h => h.GenerateHashFor(It.Is<string>(s => s == dialogResult.Password))).Returns(settings.QuitPasswordHash);
|
||||||
dialogResult.SetupGet(r => r.Success).Returns(true);
|
|
||||||
hashAlgorithm.Setup(h => h.GenerateHashFor(It.Is<string>(s => s == password))).Returns(settings.QuitPasswordHash);
|
|
||||||
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
|
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
|
||||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<TextKey>(), It.IsAny<TextKey>())).Returns(dialog.Object);
|
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 args = new System.ComponentModel.CancelEventArgs();
|
||||||
var dialog = new Mock<IPasswordDialog>();
|
var dialog = new Mock<IPasswordDialog>();
|
||||||
var dialogResult = new Mock<IPasswordDialogResult>();
|
var dialogResult = new PasswordDialogResult { Success = false };
|
||||||
|
|
||||||
settings.QuitPasswordHash = "1234";
|
settings.QuitPasswordHash = "1234";
|
||||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult.Object);
|
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult);
|
||||||
dialogResult.SetupGet(r => r.Success).Returns(false);
|
|
||||||
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
|
runtimeProxy.Setup(r => r.RequestShutdown()).Returns(new CommunicationResult(true));
|
||||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<TextKey>(), It.IsAny<TextKey>())).Returns(dialog.Object);
|
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 args = new System.ComponentModel.CancelEventArgs();
|
||||||
var dialog = new Mock<IPasswordDialog>();
|
var dialog = new Mock<IPasswordDialog>();
|
||||||
var dialogResult = new Mock<IPasswordDialogResult>();
|
var dialogResult = new PasswordDialogResult { Password = "blobb", Success = true };
|
||||||
|
|
||||||
settings.QuitPasswordHash = "1234";
|
settings.QuitPasswordHash = "1234";
|
||||||
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult.Object);
|
dialog.Setup(d => d.Show(It.IsAny<IWindow>())).Returns(dialogResult);
|
||||||
dialogResult.SetupGet(r => r.Password).Returns("blobb");
|
|
||||||
dialogResult.SetupGet(r => r.Success).Returns(true);
|
|
||||||
hashAlgorithm.Setup(h => h.GenerateHashFor(It.IsAny<string>())).Returns("9876");
|
hashAlgorithm.Setup(h => h.GenerateHashFor(It.IsAny<string>())).Returns("9876");
|
||||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<TextKey>(), It.IsAny<TextKey>())).Returns(dialog.Object);
|
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
|
public class ShellOperationTests
|
||||||
{
|
{
|
||||||
private Mock<IActionCenter> actionCenter;
|
private Mock<IActionCenter> actionCenter;
|
||||||
private List<IActionCenterActivator> activators;
|
|
||||||
private Mock<IAudio> audio;
|
private Mock<IAudio> audio;
|
||||||
private ClientContext context;
|
private ClientContext context;
|
||||||
private Mock<ILogger> logger;
|
private Mock<ILogger> logger;
|
||||||
|
@ -52,7 +51,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
actionCenter = new Mock<IActionCenter>();
|
actionCenter = new Mock<IActionCenter>();
|
||||||
activators = new List<IActionCenterActivator>();
|
|
||||||
audio = new Mock<IAudio>();
|
audio = new Mock<IAudio>();
|
||||||
context = new ClientContext();
|
context = new ClientContext();
|
||||||
logger = new Mock<ILogger>();
|
logger = new Mock<ILogger>();
|
||||||
|
@ -77,7 +75,6 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
sut = new ShellOperation(
|
sut = new ShellOperation(
|
||||||
actionCenter.Object,
|
actionCenter.Object,
|
||||||
activators,
|
|
||||||
audio.Object,
|
audio.Object,
|
||||||
aboutInfo.Object,
|
aboutInfo.Object,
|
||||||
aboutController.Object,
|
aboutController.Object,
|
||||||
|
@ -109,7 +106,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
foreach (var activator in activatorMocks)
|
foreach (var activator in activatorMocks)
|
||||||
{
|
{
|
||||||
activators.Add(activator.Object);
|
context.Activators.Add(activator.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
sut.Perform();
|
sut.Perform();
|
||||||
|
@ -272,7 +269,7 @@ namespace SafeExamBrowser.Client.UnitTests.Operations
|
||||||
|
|
||||||
foreach (var activator in activatorMocks)
|
foreach (var activator in activatorMocks)
|
||||||
{
|
{
|
||||||
activators.Add(activator.Object);
|
context.Activators.Add(activator.Object);
|
||||||
}
|
}
|
||||||
|
|
||||||
sut.Revert();
|
sut.Revert();
|
||||||
|
|
|
@ -7,10 +7,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using SafeExamBrowser.Browser.Contracts;
|
using SafeExamBrowser.Browser.Contracts;
|
||||||
using SafeExamBrowser.Communication.Contracts.Hosts;
|
using SafeExamBrowser.Communication.Contracts.Hosts;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.Settings;
|
using SafeExamBrowser.Settings;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client
|
namespace SafeExamBrowser.Client
|
||||||
{
|
{
|
||||||
|
@ -19,6 +21,11 @@ namespace SafeExamBrowser.Client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class ClientContext
|
internal class ClientContext
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// All activators for the action center.
|
||||||
|
/// </summary>
|
||||||
|
internal IList<IActionCenterActivator> Activators { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The global application configuration.
|
/// The global application configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -43,5 +50,10 @@ namespace SafeExamBrowser.Client
|
||||||
/// The settings for the current session.
|
/// The settings for the current session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal AppSettings Settings { get; set; }
|
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.MessageBox;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Client
|
namespace SafeExamBrowser.Client
|
||||||
|
@ -235,9 +236,60 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
private void ApplicationMonitor_TerminationFailed(IEnumerable<RunningApplication> applications)
|
private void ApplicationMonitor_TerminationFailed(IEnumerable<RunningApplication> applications)
|
||||||
{
|
{
|
||||||
// foreach actionCenterActivator -> Pause
|
var applicationList = string.Join(Environment.NewLine, applications.Select(a => $"- {a.Name}"));
|
||||||
// TODO: Show lock screen!
|
var message = $"{text.Get(TextKey.LockScreen_Message)}{Environment.NewLine}{Environment.NewLine}{applicationList}";
|
||||||
// foreach actionCenterActivator -> Resume
|
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)
|
private void Browser_ConfigurationDownloadRequested(string fileName, DownloadEventArgs args)
|
||||||
|
@ -409,16 +461,16 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
private void Shell_QuitButtonClicked(System.ComponentModel.CancelEventArgs args)
|
private void Shell_QuitButtonClicked(System.ComponentModel.CancelEventArgs args)
|
||||||
{
|
{
|
||||||
terminationActivator.Pause();
|
PauseActivators();
|
||||||
args.Cancel = !TryInitiateShutdown();
|
args.Cancel = !TryInitiateShutdown();
|
||||||
terminationActivator.Resume();
|
ResumeActivators();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TerminationActivator_Activated()
|
private void TerminationActivator_Activated()
|
||||||
{
|
{
|
||||||
terminationActivator.Pause();
|
PauseActivators();
|
||||||
TryInitiateShutdown();
|
TryInitiateShutdown();
|
||||||
terminationActivator.Resume();
|
ResumeActivators();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AskForAutomaticApplicationTermination(ApplicationTerminationEventArgs args)
|
private void AskForAutomaticApplicationTermination(ApplicationTerminationEventArgs args)
|
||||||
|
@ -442,10 +494,33 @@ namespace SafeExamBrowser.Client
|
||||||
messageBox.Show(message, title, icon: MessageBoxIcon.Error, parent: splashScreen);
|
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()
|
private bool TryInitiateShutdown()
|
||||||
{
|
{
|
||||||
var hasQuitPassword = !String.IsNullOrEmpty(Settings.QuitPasswordHash);
|
var hasQuitPassword = !string.IsNullOrEmpty(Settings.QuitPasswordHash);
|
||||||
var requestShutdown = false;
|
var requestShutdown = false;
|
||||||
|
var succes = false;
|
||||||
|
|
||||||
if (hasQuitPassword)
|
if (hasQuitPassword)
|
||||||
{
|
{
|
||||||
|
@ -458,20 +533,10 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
if (requestShutdown)
|
if (requestShutdown)
|
||||||
{
|
{
|
||||||
var communication = runtime.RequestShutdown();
|
succes = TryRequestShutdown();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return succes;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool TryConfirmShutdown()
|
private bool TryConfirmShutdown()
|
||||||
|
@ -512,5 +577,18 @@ namespace SafeExamBrowser.Client
|
||||||
|
|
||||||
return false;
|
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 logController = new LogNotificationController(logger, uiFactory);
|
||||||
var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
var powerSupply = new PowerSupply(ModuleLogger(nameof(PowerSupply)));
|
||||||
var wirelessAdapter = new WirelessAdapter(ModuleLogger(nameof(WirelessAdapter)));
|
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(
|
var operation = new ShellOperation(
|
||||||
actionCenter,
|
actionCenter,
|
||||||
activators,
|
|
||||||
audio,
|
audio,
|
||||||
aboutInfo,
|
aboutInfo,
|
||||||
aboutController,
|
aboutController,
|
||||||
|
@ -267,6 +261,9 @@ namespace SafeExamBrowser.Client
|
||||||
uiFactory,
|
uiFactory,
|
||||||
wirelessAdapter);
|
wirelessAdapter);
|
||||||
|
|
||||||
|
context.Activators.Add(new KeyboardActivator(ModuleLogger(nameof(KeyboardActivator))));
|
||||||
|
context.Activators.Add(new TouchActivator(ModuleLogger(nameof(TouchActivator))));
|
||||||
|
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using SafeExamBrowser.Client.Contracts;
|
using SafeExamBrowser.Client.Contracts;
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
|
@ -26,7 +25,6 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
internal class ShellOperation : ClientOperation
|
internal class ShellOperation : ClientOperation
|
||||||
{
|
{
|
||||||
private IActionCenter actionCenter;
|
private IActionCenter actionCenter;
|
||||||
private IEnumerable<IActionCenterActivator> activators;
|
|
||||||
private IAudio audio;
|
private IAudio audio;
|
||||||
private INotificationInfo aboutInfo;
|
private INotificationInfo aboutInfo;
|
||||||
private INotificationController aboutController;
|
private INotificationController aboutController;
|
||||||
|
@ -47,7 +45,6 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
|
|
||||||
public ShellOperation(
|
public ShellOperation(
|
||||||
IActionCenter actionCenter,
|
IActionCenter actionCenter,
|
||||||
IEnumerable<IActionCenterActivator> activators,
|
|
||||||
IAudio audio,
|
IAudio audio,
|
||||||
INotificationInfo aboutInfo,
|
INotificationInfo aboutInfo,
|
||||||
INotificationController aboutController,
|
INotificationController aboutController,
|
||||||
|
@ -67,7 +64,6 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
this.aboutInfo = aboutInfo;
|
this.aboutInfo = aboutInfo;
|
||||||
this.aboutController = aboutController;
|
this.aboutController = aboutController;
|
||||||
this.actionCenter = actionCenter;
|
this.actionCenter = actionCenter;
|
||||||
this.activators = activators;
|
|
||||||
this.audio = audio;
|
this.audio = audio;
|
||||||
this.keyboard = keyboard;
|
this.keyboard = keyboard;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
@ -113,7 +109,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
|
|
||||||
if (Context.Settings.ActionCenter.EnableActionCenter)
|
if (Context.Settings.ActionCenter.EnableActionCenter)
|
||||||
{
|
{
|
||||||
foreach (var activator in activators)
|
foreach (var activator in Context.Activators)
|
||||||
{
|
{
|
||||||
actionCenter.Register(activator);
|
actionCenter.Register(activator);
|
||||||
activator.Start();
|
activator.Start();
|
||||||
|
@ -283,7 +279,7 @@ namespace SafeExamBrowser.Client.Operations
|
||||||
|
|
||||||
if (Context.Settings.ActionCenter.EnableActionCenter)
|
if (Context.Settings.ActionCenter.EnableActionCenter)
|
||||||
{
|
{
|
||||||
foreach (var activator in activators)
|
foreach (var activator in Context.Activators)
|
||||||
{
|
{
|
||||||
activator.Stop();
|
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);
|
MapApplicationLogAccess(rawData, settings);
|
||||||
|
MapRequestFilter(rawData, settings);
|
||||||
MapKioskMode(rawData, settings);
|
MapKioskMode(rawData, settings);
|
||||||
MapUserAgentMode(rawData, settings);
|
MapUserAgentMode(rawData, settings);
|
||||||
}
|
}
|
||||||
|
@ -95,12 +96,6 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
case Keys.Browser.AdditionalWindow.ShowReloadWarning:
|
case Keys.Browser.AdditionalWindow.ShowReloadWarning:
|
||||||
MapShowReloadWarningAdditionalWindow(settings, value);
|
MapShowReloadWarningAdditionalWindow(settings, value);
|
||||||
break;
|
break;
|
||||||
case Keys.Browser.Filter.EnableContentRequestFilter:
|
|
||||||
MapEnableContentRequestFilter(settings, value);
|
|
||||||
break;
|
|
||||||
case Keys.Browser.Filter.EnableMainRequestFilter:
|
|
||||||
MapEnableMainRequestFilter(settings, value);
|
|
||||||
break;
|
|
||||||
case Keys.Browser.Filter.UrlFilterRules:
|
case Keys.Browser.Filter.UrlFilterRules:
|
||||||
MapUrlFilterRules(settings, value);
|
MapUrlFilterRules(settings, value);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,6 +21,11 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
BrowserWindow_DeveloperConsoleMenuItem,
|
BrowserWindow_DeveloperConsoleMenuItem,
|
||||||
BrowserWindow_ZoomMenuItem,
|
BrowserWindow_ZoomMenuItem,
|
||||||
Build,
|
Build,
|
||||||
|
LockScreen_AllowOption,
|
||||||
|
LockScreen_Message,
|
||||||
|
LockScreen_TerminateOption,
|
||||||
|
LockScreen_Title,
|
||||||
|
LockScreen_UnlockButton,
|
||||||
LogWindow_Title,
|
LogWindow_Title,
|
||||||
MessageBox_ApplicationAutoTerminationDataLossWarning,
|
MessageBox_ApplicationAutoTerminationDataLossWarning,
|
||||||
MessageBox_ApplicationAutoTerminationQuestion,
|
MessageBox_ApplicationAutoTerminationQuestion,
|
||||||
|
@ -44,6 +49,8 @@ namespace SafeExamBrowser.I18n.Contracts
|
||||||
MessageBox_InvalidPasswordErrorTitle,
|
MessageBox_InvalidPasswordErrorTitle,
|
||||||
MessageBox_InvalidQuitPassword,
|
MessageBox_InvalidQuitPassword,
|
||||||
MessageBox_InvalidQuitPasswordTitle,
|
MessageBox_InvalidQuitPasswordTitle,
|
||||||
|
MessageBox_InvalidUnlockPassword,
|
||||||
|
MessageBox_InvalidUnlockPasswordTitle,
|
||||||
MessageBox_NoButton,
|
MessageBox_NoButton,
|
||||||
MessageBox_NotSupportedConfigurationResource,
|
MessageBox_NotSupportedConfigurationResource,
|
||||||
MessageBox_NotSupportedConfigurationResourceTitle,
|
MessageBox_NotSupportedConfigurationResourceTitle,
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
Back to previous page
|
Back to previous page
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="Browser_BlockedPageMessage">
|
<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>
|
||||||
<Entry key="Browser_BlockedPageTitle">
|
<Entry key="Browser_BlockedPageTitle">
|
||||||
Page Blocked
|
Page Blocked
|
||||||
|
@ -21,6 +21,21 @@
|
||||||
<Entry key="Build">
|
<Entry key="Build">
|
||||||
Build
|
Build
|
||||||
</Entry>
|
</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">
|
<Entry key="LogWindow_Title">
|
||||||
Application Log
|
Application Log
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -34,7 +49,7 @@
|
||||||
IMPORTANT: Any unsaved application data might be lost!
|
IMPORTANT: Any unsaved application data might be lost!
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ApplicationError">
|
<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>
|
||||||
<Entry key="MessageBox_ApplicationErrorTitle">
|
<Entry key="MessageBox_ApplicationErrorTitle">
|
||||||
Application Error
|
Application Error
|
||||||
|
@ -46,7 +61,7 @@
|
||||||
Automatic Termination Failed
|
Automatic Termination Failed
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_BrowserNavigationBlocked">
|
<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>
|
||||||
<Entry key="MessageBox_BrowserNavigationBlockedTitle">
|
<Entry key="MessageBox_BrowserNavigationBlockedTitle">
|
||||||
Page Blocked
|
Page Blocked
|
||||||
|
@ -55,19 +70,19 @@
|
||||||
Cancel
|
Cancel
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ClientConfigurationError">
|
<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>
|
||||||
<Entry key="MessageBox_ClientConfigurationErrorTitle">
|
<Entry key="MessageBox_ClientConfigurationErrorTitle">
|
||||||
Client Configuration Error
|
Client Configuration Error
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ClientConfigurationQuestion">
|
<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>
|
||||||
<Entry key="MessageBox_ClientConfigurationQuestionTitle">
|
<Entry key="MessageBox_ClientConfigurationQuestionTitle">
|
||||||
Configuration Successful
|
Configuration Successful
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ConfigurationDownloadError">
|
<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>
|
||||||
<Entry key="MessageBox_ConfigurationDownloadErrorTitle">
|
<Entry key="MessageBox_ConfigurationDownloadErrorTitle">
|
||||||
Download Error
|
Download Error
|
||||||
|
@ -79,17 +94,23 @@
|
||||||
Configuration Error
|
Configuration Error
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_InvalidPasswordError">
|
<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>
|
||||||
<Entry key="MessageBox_InvalidPasswordErrorTitle">
|
<Entry key="MessageBox_InvalidPasswordErrorTitle">
|
||||||
Invalid Password
|
Invalid Password
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_InvalidQuitPassword">
|
<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>
|
||||||
<Entry key="MessageBox_InvalidQuitPasswordTitle">
|
<Entry key="MessageBox_InvalidQuitPasswordTitle">
|
||||||
Invalid Quit Password
|
Invalid Quit Password
|
||||||
</Entry>
|
</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">
|
<Entry key="MessageBox_NoButton">
|
||||||
No
|
No
|
||||||
</Entry>
|
</Entry>
|
||||||
|
@ -103,7 +124,7 @@
|
||||||
OK
|
OK
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_Quit">
|
<Entry key="MessageBox_Quit">
|
||||||
Do you want to quit the application?
|
Do you want to quit SEB?
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_QuitTitle">
|
<Entry key="MessageBox_QuitTitle">
|
||||||
Quit?
|
Quit?
|
||||||
|
@ -115,7 +136,7 @@
|
||||||
Quit Error
|
Quit Error
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ReconfigurationDenied">
|
<Entry key="MessageBox_ReconfigurationDenied">
|
||||||
You are not allowed to reconfigure the application.
|
You are not allowed to reconfigure SEB.
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ReconfigurationDeniedTitle">
|
<Entry key="MessageBox_ReconfigurationDeniedTitle">
|
||||||
Reconfiguration Denied
|
Reconfiguration Denied
|
||||||
|
@ -133,37 +154,37 @@
|
||||||
Reload?
|
Reload?
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ServiceUnavailableError">
|
<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>
|
||||||
<Entry key="MessageBox_ServiceUnavailableErrorTitle">
|
<Entry key="MessageBox_ServiceUnavailableErrorTitle">
|
||||||
Service Unavailable
|
Service Unavailable
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ServiceUnavailableWarning">
|
<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>
|
||||||
<Entry key="MessageBox_ServiceUnavailableWarningTitle">
|
<Entry key="MessageBox_ServiceUnavailableWarningTitle">
|
||||||
Service Unavailable
|
Service Unavailable
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_SessionStartError">
|
<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>
|
||||||
<Entry key="MessageBox_SessionStartErrorTitle">
|
<Entry key="MessageBox_SessionStartErrorTitle">
|
||||||
Session Start Error
|
Session Start Error
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_ShutdownError">
|
<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>
|
||||||
<Entry key="MessageBox_ShutdownErrorTitle">
|
<Entry key="MessageBox_ShutdownErrorTitle">
|
||||||
Shutdown Error
|
Shutdown Error
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_StartupError">
|
<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>
|
||||||
<Entry key="MessageBox_StartupErrorTitle">
|
<Entry key="MessageBox_StartupErrorTitle">
|
||||||
Startup Error
|
Startup Error
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="MessageBox_UnexpectedConfigurationError">
|
<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>
|
||||||
<Entry key="MessageBox_UnexpectedConfigurationErrorTitle">
|
<Entry key="MessageBox_UnexpectedConfigurationErrorTitle">
|
||||||
Configuration Error
|
Configuration Error
|
||||||
|
@ -196,7 +217,7 @@
|
||||||
Initializing browser
|
Initializing browser
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeConfiguration">
|
<Entry key="OperationStatus_InitializeConfiguration">
|
||||||
Initializing application configuration
|
Initializing configuration
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="OperationStatus_InitializeKioskMode">
|
<Entry key="OperationStatus_InitializeKioskMode">
|
||||||
Initializing kiosk mode
|
Initializing kiosk mode
|
||||||
|
@ -283,19 +304,19 @@
|
||||||
Settings Password Required
|
Settings Password Required
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="PasswordDialog_QuitPasswordRequired">
|
<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>
|
||||||
<Entry key="PasswordDialog_QuitPasswordRequiredTitle">
|
<Entry key="PasswordDialog_QuitPasswordRequiredTitle">
|
||||||
Quit Password Required
|
Quit Password Required
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="PasswordDialog_SettingsPasswordRequired">
|
<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>
|
||||||
<Entry key="PasswordDialog_SettingsPasswordRequiredTitle">
|
<Entry key="PasswordDialog_SettingsPasswordRequiredTitle">
|
||||||
Settings Password Required
|
Settings Password Required
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="RuntimeWindow_ApplicationRunning">
|
<Entry key="RuntimeWindow_ApplicationRunning">
|
||||||
The application is running.
|
SEB is running.
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry key="Shell_QuitButton">
|
<Entry key="Shell_QuitButton">
|
||||||
Terminate Session
|
Terminate Session
|
||||||
|
|
|
@ -14,16 +14,17 @@ using SafeExamBrowser.Communication.Contracts.Events;
|
||||||
using SafeExamBrowser.Communication.Contracts.Hosts;
|
using SafeExamBrowser.Communication.Contracts.Hosts;
|
||||||
using SafeExamBrowser.Communication.Contracts.Proxies;
|
using SafeExamBrowser.Communication.Contracts.Proxies;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.Settings;
|
|
||||||
using SafeExamBrowser.Settings.Service;
|
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel;
|
using SafeExamBrowser.Core.Contracts.OperationModel;
|
||||||
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
using SafeExamBrowser.Core.Contracts.OperationModel.Events;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
using SafeExamBrowser.Runtime.Operations.Events;
|
using SafeExamBrowser.Runtime.Operations.Events;
|
||||||
|
using SafeExamBrowser.Settings;
|
||||||
|
using SafeExamBrowser.Settings.Service;
|
||||||
using SafeExamBrowser.UserInterface.Contracts;
|
using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
using SafeExamBrowser.UserInterface.Contracts.MessageBox;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
using SafeExamBrowser.WindowsApi.Contracts;
|
using SafeExamBrowser.WindowsApi.Contracts;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Runtime.UnitTests
|
namespace SafeExamBrowser.Runtime.UnitTests
|
||||||
|
@ -219,14 +220,11 @@ namespace SafeExamBrowser.Runtime.UnitTests
|
||||||
public void Operations_MustRequestPasswordViaDialogOnDefaultDesktop()
|
public void Operations_MustRequestPasswordViaDialogOnDefaultDesktop()
|
||||||
{
|
{
|
||||||
var args = new PasswordRequiredEventArgs();
|
var args = new PasswordRequiredEventArgs();
|
||||||
var password = "test1234";
|
|
||||||
var passwordDialog = new Mock<IPasswordDialog>();
|
var passwordDialog = new Mock<IPasswordDialog>();
|
||||||
var result = new Mock<IPasswordDialogResult>();
|
var result = new PasswordDialogResult { Password = "test1234", Success = true };
|
||||||
|
|
||||||
currentSettings.KioskMode = KioskMode.DisableExplorerShell;
|
currentSettings.KioskMode = KioskMode.DisableExplorerShell;
|
||||||
passwordDialog.Setup(p => p.Show(It.IsAny<IWindow>())).Returns(result.Object);
|
passwordDialog.Setup(p => p.Show(It.IsAny<IWindow>())).Returns(result);
|
||||||
result.SetupGet(r => r.Password).Returns(password);
|
|
||||||
result.SetupGet(r => r.Success).Returns(true);
|
|
||||||
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(passwordDialog.Object);
|
uiFactory.Setup(u => u.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>())).Returns(passwordDialog.Object);
|
||||||
|
|
||||||
sut.TryStart();
|
sut.TryStart();
|
||||||
|
@ -237,7 +235,7 @@ namespace SafeExamBrowser.Runtime.UnitTests
|
||||||
uiFactory.Verify(u => u.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
uiFactory.Verify(u => u.CreatePasswordDialog(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
|
||||||
|
|
||||||
Assert.AreEqual(true, args.Success);
|
Assert.AreEqual(true, args.Success);
|
||||||
Assert.AreEqual(password, args.Password);
|
Assert.AreEqual(result.Password, args.Password);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -6,12 +6,13 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using SafeExamBrowser.Applications.Contracts;
|
using SafeExamBrowser.Applications.Contracts;
|
||||||
using SafeExamBrowser.Client.Contracts;
|
using SafeExamBrowser.Client.Contracts;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.Settings.Browser;
|
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Settings.Browser;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||||
|
@ -19,6 +20,7 @@ using SafeExamBrowser.SystemComponents.Contracts.WirelessNetwork;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Contracts
|
namespace SafeExamBrowser.UserInterface.Contracts
|
||||||
{
|
{
|
||||||
|
@ -52,6 +54,11 @@ namespace SafeExamBrowser.UserInterface.Contracts
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ISystemControl CreateKeyboardLayoutControl(IKeyboard keyboard, Location location);
|
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>
|
/// <summary>
|
||||||
/// Creates a new log window which runs on its own thread.
|
/// Creates a new log window which runs on its own thread.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -75,9 +75,12 @@
|
||||||
<Compile Include="Shell\ISystemControl.cs" />
|
<Compile Include="Shell\ISystemControl.cs" />
|
||||||
<Compile Include="Shell\ITaskbar.cs" />
|
<Compile Include="Shell\ITaskbar.cs" />
|
||||||
<Compile Include="Shell\Location.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\Events\WindowClosingEventHandler.cs" />
|
||||||
|
<Compile Include="Windows\ILockScreen.cs" />
|
||||||
<Compile Include="Windows\IPasswordDialog.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\IRuntimeWindow.cs" />
|
||||||
<Compile Include="Windows\ISplashScreen.cs" />
|
<Compile Include="Windows\ISplashScreen.cs" />
|
||||||
<Compile Include="Windows\IWindow.cs" />
|
<Compile Include="Windows\IWindow.cs" />
|
||||||
|
|
|
@ -30,6 +30,16 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event ActivatorEventHandler Toggled;
|
event ActivatorEventHandler Toggled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Temporarily stops processing all user input.
|
||||||
|
/// </summary>
|
||||||
|
void Pause();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resumes processing user input.
|
||||||
|
/// </summary>
|
||||||
|
void Resume();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Starts monitoring user input events.
|
/// Starts monitoring user input events.
|
||||||
/// </summary>
|
/// </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/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
namespace SafeExamBrowser.UserInterface.Contracts.Windows.Data
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the user interaction result of an <see cref="IPasswordDialog"/>.
|
/// Defines the user interaction result of an <see cref="IPasswordDialog"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IPasswordDialogResult
|
public class PasswordDialogResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The password entered by the user, or <c>null</c> if the interaction was unsuccessful.
|
/// The password entered by the user, or <c>null</c> if the interaction was unsuccessful.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Password { get; }
|
public string Password { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Indicates whether the user confirmed the dialog or not.
|
/// Indicates whether the user confirmed the dialog or not.
|
||||||
/// </summary>
|
/// </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/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -16,6 +18,6 @@ namespace SafeExamBrowser.UserInterface.Contracts.Windows
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
|
/// Shows the dialog as topmost window. If a parent window is specified, the dialog is rendered modally for the given parent.
|
||||||
/// </summary>
|
/// </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 System.Windows.Input;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Desktop
|
namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
|
@ -38,7 +39,7 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
Dispatcher.Invoke(Activate);
|
Dispatcher.Invoke(Activate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPasswordDialogResult Show(IWindow parent = null)
|
public PasswordDialogResult Show(IWindow parent = null)
|
||||||
{
|
{
|
||||||
return Dispatcher.Invoke(() =>
|
return Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
@ -96,11 +97,5 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PasswordDialogResult : IPasswordDialogResult
|
|
||||||
{
|
|
||||||
public string Password { get; set; }
|
|
||||||
public bool Success { get; set; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,7 @@
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xaml">
|
<Reference Include="System.Xaml">
|
||||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||||
|
@ -140,6 +141,9 @@
|
||||||
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
||||||
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="LockScreen.xaml.cs">
|
||||||
|
<DependentUpon>LockScreen.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="LogWindow.xaml.cs">
|
<Compile Include="LogWindow.xaml.cs">
|
||||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -306,6 +310,10 @@
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Resource>
|
</Resource>
|
||||||
|
<Page Include="LockScreen.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Templates\ScrollViewers.xaml">
|
<Page Include="Templates\ScrollViewers.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
@ -13,9 +14,9 @@ using FontAwesome.WPF;
|
||||||
using SafeExamBrowser.Applications.Contracts;
|
using SafeExamBrowser.Applications.Contracts;
|
||||||
using SafeExamBrowser.Client.Contracts;
|
using SafeExamBrowser.Client.Contracts;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.Settings.Browser;
|
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Settings.Browser;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||||
|
@ -24,6 +25,7 @@ using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
using SafeExamBrowser.UserInterface.Desktop.Controls;
|
using SafeExamBrowser.UserInterface.Desktop.Controls;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Desktop
|
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)
|
public IWindow CreateLogWindow(ILogger logger)
|
||||||
{
|
{
|
||||||
LogWindow logWindow = null;
|
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 System.Windows.Input;
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Mobile
|
namespace SafeExamBrowser.UserInterface.Mobile
|
||||||
|
@ -38,7 +39,7 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
||||||
Dispatcher.Invoke(Activate);
|
Dispatcher.Invoke(Activate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPasswordDialogResult Show(IWindow parent = null)
|
public PasswordDialogResult Show(IWindow parent = null)
|
||||||
{
|
{
|
||||||
return Dispatcher.Invoke(() =>
|
return Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
|
@ -115,11 +116,5 @@ namespace SafeExamBrowser.UserInterface.Mobile
|
||||||
Dispatcher.InvokeAsync(InitializeBounds);
|
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">
|
<Compile Include="Controls\TaskbarWirelessNetworkControl.xaml.cs">
|
||||||
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
<DependentUpon>TaskbarWirelessNetworkControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="LockScreen.xaml.cs">
|
||||||
|
<DependentUpon>LockScreen.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="LogWindow.xaml.cs">
|
<Compile Include="LogWindow.xaml.cs">
|
||||||
<DependentUpon>LogWindow.xaml</DependentUpon>
|
<DependentUpon>LogWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -425,6 +428,10 @@
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="LockScreen.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
<Page Include="LogWindow.xaml">
|
<Page Include="LogWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
@ -13,9 +14,9 @@ using FontAwesome.WPF;
|
||||||
using SafeExamBrowser.Applications.Contracts;
|
using SafeExamBrowser.Applications.Contracts;
|
||||||
using SafeExamBrowser.Client.Contracts;
|
using SafeExamBrowser.Client.Contracts;
|
||||||
using SafeExamBrowser.Configuration.Contracts;
|
using SafeExamBrowser.Configuration.Contracts;
|
||||||
using SafeExamBrowser.Settings.Browser;
|
|
||||||
using SafeExamBrowser.I18n.Contracts;
|
using SafeExamBrowser.I18n.Contracts;
|
||||||
using SafeExamBrowser.Logging.Contracts;
|
using SafeExamBrowser.Logging.Contracts;
|
||||||
|
using SafeExamBrowser.Settings.Browser;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
using SafeExamBrowser.SystemComponents.Contracts.Audio;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
using SafeExamBrowser.SystemComponents.Contracts.Keyboard;
|
||||||
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
using SafeExamBrowser.SystemComponents.Contracts.PowerSupply;
|
||||||
|
@ -24,6 +25,7 @@ using SafeExamBrowser.UserInterface.Contracts;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
using SafeExamBrowser.UserInterface.Contracts.Browser;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
using SafeExamBrowser.UserInterface.Contracts.Shell;
|
||||||
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
using SafeExamBrowser.UserInterface.Contracts.Windows;
|
||||||
|
using SafeExamBrowser.UserInterface.Contracts.Windows.Data;
|
||||||
using SafeExamBrowser.UserInterface.Mobile.Controls;
|
using SafeExamBrowser.UserInterface.Mobile.Controls;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Mobile
|
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)
|
public IWindow CreateLogWindow(ILogger logger)
|
||||||
{
|
{
|
||||||
LogWindow logWindow = null;
|
LogWindow logWindow = null;
|
||||||
|
|
|
@ -12,31 +12,52 @@ using System.Windows.Media;
|
||||||
|
|
||||||
namespace SafeExamBrowser.UserInterface.Shared.Utilities
|
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
|
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)
|
public static Vector TransformToPhysical(this Visual visual, double x, double y)
|
||||||
{
|
{
|
||||||
Matrix transformToDevice;
|
var matrix = default(Matrix);
|
||||||
var source = PresentationSource.FromVisual(visual);
|
var source = PresentationSource.FromVisual(visual);
|
||||||
|
|
||||||
if (source != null)
|
if (source != null)
|
||||||
{
|
{
|
||||||
transformToDevice = source.CompositionTarget.TransformToDevice;
|
matrix = source.CompositionTarget.TransformToDevice;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
using (var newSource = new HwndSource(new HwndSourceParameters()))
|
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
|
public class KeyboardActivator : IActionCenterActivator
|
||||||
{
|
{
|
||||||
private bool A, LeftWindows;
|
private bool A, LeftWindows, paused;
|
||||||
private IntPtr handle;
|
private IntPtr handle;
|
||||||
private HookDelegate hookDelegate;
|
private HookDelegate hookDelegate;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
@ -34,6 +34,18 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
A = false;
|
||||||
|
LeftWindows = false;
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
var hookReadyEvent = new AutoResetEvent(false);
|
var hookReadyEvent = new AutoResetEvent(false);
|
||||||
|
@ -72,7 +84,7 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
|
|
||||||
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
|
private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
|
||||||
{
|
{
|
||||||
if (nCode >= 0)
|
if (nCode >= 0 && !paused)
|
||||||
{
|
{
|
||||||
var changed = false;
|
var changed = false;
|
||||||
var keyData = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
|
var keyData = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
{
|
{
|
||||||
private HookDelegate hookDelegate;
|
private HookDelegate hookDelegate;
|
||||||
private IntPtr handle;
|
private IntPtr handle;
|
||||||
private bool isDown;
|
private bool isDown, paused;
|
||||||
private ILogger logger;
|
private ILogger logger;
|
||||||
|
|
||||||
public event ActivatorEventHandler Activated;
|
public event ActivatorEventHandler Activated;
|
||||||
|
@ -35,6 +35,17 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Pause()
|
||||||
|
{
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Resume()
|
||||||
|
{
|
||||||
|
isDown = false;
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
var hookReadyEvent = new AutoResetEvent(false);
|
var hookReadyEvent = new AutoResetEvent(false);
|
||||||
|
@ -73,7 +84,7 @@ namespace SafeExamBrowser.WindowsApi
|
||||||
|
|
||||||
private IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
|
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 message = wParam.ToInt32();
|
||||||
var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
|
||||||
|
|
Loading…
Reference in a new issue