SEBWIN-106: Implemented basic popup and reload handling, revised browser control implementation and added mouse button interception for navigation (auxiliary) keys. Also finally implemented a custom template for small scrollbars in scrollviewers.
This commit is contained in:
parent
91c2417930
commit
f949a19f32
40 changed files with 454 additions and 158 deletions
|
@ -11,12 +11,14 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
|
using SafeExamBrowser.Browser.Events;
|
||||||
using SafeExamBrowser.Contracts.Browser;
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
using SafeExamBrowser.Contracts.Core;
|
using SafeExamBrowser.Contracts.Core;
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
using SafeExamBrowser.Contracts.I18n;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
|
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
|
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
|
||||||
|
|
||||||
|
@ -29,6 +31,7 @@ namespace SafeExamBrowser.Browser
|
||||||
private AppConfig appConfig;
|
private AppConfig appConfig;
|
||||||
private IApplicationButton button;
|
private IApplicationButton button;
|
||||||
private IList<IApplicationInstance> instances;
|
private IList<IApplicationInstance> instances;
|
||||||
|
private IMessageBox messageBox;
|
||||||
private IModuleLogger logger;
|
private IModuleLogger logger;
|
||||||
private BrowserSettings settings;
|
private BrowserSettings settings;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
@ -39,6 +42,7 @@ namespace SafeExamBrowser.Browser
|
||||||
public BrowserApplicationController(
|
public BrowserApplicationController(
|
||||||
AppConfig appConfig,
|
AppConfig appConfig,
|
||||||
BrowserSettings settings,
|
BrowserSettings settings,
|
||||||
|
IMessageBox messageBox,
|
||||||
IModuleLogger logger,
|
IModuleLogger logger,
|
||||||
IText text,
|
IText text,
|
||||||
IUserInterfaceFactory uiFactory)
|
IUserInterfaceFactory uiFactory)
|
||||||
|
@ -46,6 +50,7 @@ namespace SafeExamBrowser.Browser
|
||||||
this.appConfig = appConfig;
|
this.appConfig = appConfig;
|
||||||
this.instances = new List<IApplicationInstance>();
|
this.instances = new List<IApplicationInstance>();
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
|
this.messageBox = messageBox;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.uiFactory = uiFactory;
|
this.uiFactory = uiFactory;
|
||||||
|
@ -56,7 +61,7 @@ namespace SafeExamBrowser.Browser
|
||||||
var cefSettings = InitializeCefSettings();
|
var cefSettings = InitializeCefSettings();
|
||||||
var success = Cef.Initialize(cefSettings, true, null);
|
var success = Cef.Initialize(cefSettings, true, null);
|
||||||
|
|
||||||
logger.Info("Initialized CEF.");
|
logger.Info("Initialized browser engine.");
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
|
@ -87,18 +92,20 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
Cef.Shutdown();
|
Cef.Shutdown();
|
||||||
|
|
||||||
logger.Info("Terminated CEF.");
|
logger.Info("Terminated browser engine.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateNewInstance()
|
private void CreateNewInstance(BrowserSettings custom = null)
|
||||||
{
|
{
|
||||||
var id = new BrowserInstanceIdentifier(++instanceIdCounter);
|
var id = new BrowserInstanceIdentifier(++instanceIdCounter);
|
||||||
var isMainInstance = instances.Count == 0;
|
var isMainInstance = instances.Count == 0;
|
||||||
var instanceLogger = logger.CloneFor($"BrowserInstance {id}");
|
var instanceLogger = logger.CloneFor($"BrowserInstance {id}");
|
||||||
var instance = new BrowserApplicationInstance(appConfig, settings, id, isMainInstance, instanceLogger, text, uiFactory);
|
var instanceSettings = custom ?? settings;
|
||||||
|
var instance = new BrowserApplicationInstance(appConfig, instanceSettings, id, isMainInstance, messageBox, instanceLogger, text, uiFactory);
|
||||||
|
|
||||||
instance.Initialize();
|
instance.Initialize();
|
||||||
instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
instance.ConfigurationDownloadRequested += (fileName, args) => ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||||
|
instance.PopupRequested += Instance_PopupRequested;
|
||||||
instance.Terminated += Instance_Terminated;
|
instance.Terminated += Instance_Terminated;
|
||||||
|
|
||||||
button.RegisterInstance(instance);
|
button.RegisterInstance(instance);
|
||||||
|
@ -120,9 +127,10 @@ namespace SafeExamBrowser.Browser
|
||||||
UserAgent = settings.UseCustomUserAgent ? settings.CustomUserAgent : string.Empty
|
UserAgent = settings.UseCustomUserAgent ? settings.CustomUserAgent : string.Empty
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.Debug($"CEF cache path is '{cefSettings.CachePath}'.");
|
logger.Debug($"Browser cache path: {cefSettings.CachePath}");
|
||||||
logger.Debug($"CEF log file is '{cefSettings.LogFile}'.");
|
logger.Debug($"Browser log file: {cefSettings.LogFile}");
|
||||||
logger.Debug($"CEF log severity is '{cefSettings.LogSeverity}'.");
|
logger.Debug($"Browser log severity: {cefSettings.LogSeverity}");
|
||||||
|
logger.Debug($"Browser engine version: Chromium {Cef.ChromiumVersion}, CEF {Cef.CefVersion}, CefSharp {Cef.CefSharpVersion}");
|
||||||
|
|
||||||
return cefSettings;
|
return cefSettings;
|
||||||
}
|
}
|
||||||
|
@ -139,6 +147,27 @@ namespace SafeExamBrowser.Browser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Instance_PopupRequested(PopupRequestedEventArgs args)
|
||||||
|
{
|
||||||
|
var popupSettings = new BrowserSettings
|
||||||
|
{
|
||||||
|
AllowAddressBar = false,
|
||||||
|
AllowBackwardNavigation = false,
|
||||||
|
AllowConfigurationDownloads = settings.AllowConfigurationDownloads,
|
||||||
|
AllowDeveloperConsole = settings.AllowDeveloperConsole,
|
||||||
|
AllowDownloads = settings.AllowDownloads,
|
||||||
|
AllowForwardNavigation = false,
|
||||||
|
AllowPageZoom = settings.AllowPageZoom,
|
||||||
|
AllowPopups = settings.AllowPopups,
|
||||||
|
AllowReloading = settings.AllowReloading,
|
||||||
|
ShowReloadWarning = settings.ShowReloadWarning,
|
||||||
|
StartUrl = args.Url
|
||||||
|
};
|
||||||
|
|
||||||
|
logger.Info($"Received request to create new instance for '{args.Url}'...");
|
||||||
|
CreateNewInstance(popupSettings);
|
||||||
|
}
|
||||||
|
|
||||||
private void Instance_Terminated(InstanceIdentifier id)
|
private void Instance_Terminated(InstanceIdentifier id)
|
||||||
{
|
{
|
||||||
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
||||||
|
|
|
@ -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 SafeExamBrowser.Browser.Events;
|
||||||
using SafeExamBrowser.Browser.Handlers;
|
using SafeExamBrowser.Browser.Handlers;
|
||||||
using SafeExamBrowser.Contracts.Browser;
|
using SafeExamBrowser.Contracts.Browser;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
@ -16,6 +17,7 @@ using SafeExamBrowser.Contracts.I18n;
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
using SafeExamBrowser.Contracts.Logging;
|
||||||
using SafeExamBrowser.Contracts.UserInterface;
|
using SafeExamBrowser.Contracts.UserInterface;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Browser;
|
using SafeExamBrowser.Contracts.UserInterface.Browser;
|
||||||
|
using SafeExamBrowser.Contracts.UserInterface.MessageBox;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
using SafeExamBrowser.Contracts.UserInterface.Windows;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser
|
namespace SafeExamBrowser.Browser
|
||||||
|
@ -26,6 +28,7 @@ namespace SafeExamBrowser.Browser
|
||||||
private IBrowserControl control;
|
private IBrowserControl control;
|
||||||
private IBrowserWindow window;
|
private IBrowserWindow window;
|
||||||
private bool isMainInstance;
|
private bool isMainInstance;
|
||||||
|
private IMessageBox messageBox;
|
||||||
private IModuleLogger logger;
|
private IModuleLogger logger;
|
||||||
private BrowserSettings settings;
|
private BrowserSettings settings;
|
||||||
private IText text;
|
private IText text;
|
||||||
|
@ -36,14 +39,16 @@ namespace SafeExamBrowser.Browser
|
||||||
public IWindow Window { get { return window; } }
|
public IWindow Window { get { return window; } }
|
||||||
|
|
||||||
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
public event DownloadRequestedEventHandler ConfigurationDownloadRequested;
|
||||||
public event NameChangedEventHandler NameChanged;
|
|
||||||
public event InstanceTerminatedEventHandler Terminated;
|
public event InstanceTerminatedEventHandler Terminated;
|
||||||
|
public event NameChangedEventHandler NameChanged;
|
||||||
|
public event PopupRequestedEventHandler PopupRequested;
|
||||||
|
|
||||||
public BrowserApplicationInstance(
|
public BrowserApplicationInstance(
|
||||||
AppConfig appConfig,
|
AppConfig appConfig,
|
||||||
BrowserSettings settings,
|
BrowserSettings settings,
|
||||||
InstanceIdentifier id,
|
InstanceIdentifier id,
|
||||||
bool isMainInstance,
|
bool isMainInstance,
|
||||||
|
IMessageBox messageBox,
|
||||||
IModuleLogger logger,
|
IModuleLogger logger,
|
||||||
IText text,
|
IText text,
|
||||||
IUserInterfaceFactory uiFactory)
|
IUserInterfaceFactory uiFactory)
|
||||||
|
@ -51,6 +56,7 @@ namespace SafeExamBrowser.Browser
|
||||||
this.appConfig = appConfig;
|
this.appConfig = appConfig;
|
||||||
this.Id = id;
|
this.Id = id;
|
||||||
this.isMainInstance = isMainInstance;
|
this.isMainInstance = isMainInstance;
|
||||||
|
this.messageBox = messageBox;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.settings = settings;
|
this.settings = settings;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
@ -59,13 +65,18 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
internal void Initialize()
|
internal void Initialize()
|
||||||
{
|
{
|
||||||
var controlLogger = logger.CloneFor($"{nameof(BrowserControl)} {Id}");
|
var contextMenuHandler = new ContextMenuHandler(settings, text);
|
||||||
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} {Id}");
|
var downloadLogger = logger.CloneFor($"{nameof(DownloadHandler)} {Id}");
|
||||||
var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger);
|
var downloadHandler = new DownloadHandler(appConfig, settings, downloadLogger);
|
||||||
|
var keyboardHandler = new KeyboardHandler();
|
||||||
|
var lifeSpanHandler = new LifeSpanHandler();
|
||||||
|
var requestHandler = new RequestHandler(appConfig);
|
||||||
|
|
||||||
downloadHandler.ConfigurationDownloadRequested += DownloadHandler_ConfigurationDownloadRequested;
|
downloadHandler.ConfigurationDownloadRequested += DownloadHandler_ConfigurationDownloadRequested;
|
||||||
|
keyboardHandler.ReloadRequested += KeyboardHandler_ReloadRequested;
|
||||||
|
lifeSpanHandler.PopupRequested += LifeSpanHandler_PopupRequested;
|
||||||
|
|
||||||
control = new BrowserControl(appConfig, settings, downloadHandler, controlLogger, text);
|
control = new BrowserControl(contextMenuHandler, downloadHandler, keyboardHandler, lifeSpanHandler, requestHandler, settings.StartUrl);
|
||||||
control.AddressChanged += Control_AddressChanged;
|
control.AddressChanged += Control_AddressChanged;
|
||||||
control.LoadingStateChanged += Control_LoadingStateChanged;
|
control.LoadingStateChanged += Control_LoadingStateChanged;
|
||||||
control.TitleChanged += Control_TitleChanged;
|
control.TitleChanged += Control_TitleChanged;
|
||||||
|
@ -84,8 +95,36 @@ namespace SafeExamBrowser.Browser
|
||||||
logger.Debug("Initialized browser window.");
|
logger.Debug("Initialized browser window.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void HandleReloadRequest()
|
||||||
|
{
|
||||||
|
if (settings.AllowReloading && settings.ShowReloadWarning)
|
||||||
|
{
|
||||||
|
var result = messageBox.Show(TextKey.MessageBox_ReloadConfirmation, TextKey.MessageBox_ReloadConfirmationTitle, MessageBoxAction.YesNo, MessageBoxIcon.Question, window);
|
||||||
|
|
||||||
|
if (result == MessageBoxResult.Yes)
|
||||||
|
{
|
||||||
|
logger.Debug("The user confirmed reloading the current page...");
|
||||||
|
control.Reload();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Debug("The user aborted reloading the current page.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (settings.AllowReloading)
|
||||||
|
{
|
||||||
|
logger.Debug("Reloading current page...");
|
||||||
|
control.Reload();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Debug("Blocked reload attempt, as the user is not allowed to reload web pages.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Control_AddressChanged(string address)
|
private void Control_AddressChanged(string address)
|
||||||
{
|
{
|
||||||
|
logger.Debug($"Navigated to '{address}'.");
|
||||||
window.UpdateAddress(address);
|
window.UpdateAddress(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +145,6 @@ namespace SafeExamBrowser.Browser
|
||||||
{
|
{
|
||||||
args.BrowserWindow = window;
|
args.BrowserWindow = window;
|
||||||
logger.Debug($"Forwarding download request for configuration file '{fileName}'.");
|
logger.Debug($"Forwarding download request for configuration file '{fileName}'.");
|
||||||
|
|
||||||
ConfigurationDownloadRequested?.Invoke(fileName, args);
|
ConfigurationDownloadRequested?.Invoke(fileName, args);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -115,6 +153,24 @@ namespace SafeExamBrowser.Browser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void KeyboardHandler_ReloadRequested()
|
||||||
|
{
|
||||||
|
HandleReloadRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LifeSpanHandler_PopupRequested(PopupRequestedEventArgs args)
|
||||||
|
{
|
||||||
|
if (settings.AllowPopups)
|
||||||
|
{
|
||||||
|
logger.Debug($"Forwarding request to open new window for '{args.Url}'...");
|
||||||
|
PopupRequested?.Invoke(args);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger.Debug($"Blocked attempt to open new window for '{args.Url}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void Window_AddressChanged(string address)
|
private void Window_AddressChanged(string address)
|
||||||
{
|
{
|
||||||
logger.Debug($"The user requested to navigate to '{address}'.");
|
logger.Debug($"The user requested to navigate to '{address}'.");
|
||||||
|
@ -123,19 +179,18 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
private void Window_ReloadRequested()
|
private void Window_ReloadRequested()
|
||||||
{
|
{
|
||||||
logger.Debug($"The user requested to reload the current page.");
|
HandleReloadRequest();
|
||||||
control.Reload();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_BackwardNavigationRequested()
|
private void Window_BackwardNavigationRequested()
|
||||||
{
|
{
|
||||||
logger.Debug($"The user requested to navigate backwards.");
|
logger.Debug($"Navigating forwards...");
|
||||||
control.NavigateBackwards();
|
control.NavigateBackwards();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_ForwardNavigationRequested()
|
private void Window_ForwardNavigationRequested()
|
||||||
{
|
{
|
||||||
logger.Debug($"The user requested to navigate forwards.");
|
logger.Debug($"Navigating backwards...");
|
||||||
control.NavigateForwards();
|
control.NavigateForwards();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,27 +6,20 @@
|
||||||
* 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;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using CefSharp.WinForms;
|
using CefSharp.WinForms;
|
||||||
using SafeExamBrowser.Browser.Handlers;
|
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
|
||||||
using SafeExamBrowser.Contracts.I18n;
|
|
||||||
using SafeExamBrowser.Contracts.Logging;
|
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Browser;
|
using SafeExamBrowser.Contracts.UserInterface.Browser;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Browser.Events;
|
using SafeExamBrowser.Contracts.UserInterface.Browser.Events;
|
||||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
|
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser
|
namespace SafeExamBrowser.Browser
|
||||||
{
|
{
|
||||||
internal class BrowserControl : ChromiumWebBrowser, IBrowserControl
|
internal class BrowserControl : ChromiumWebBrowser, IBrowserControl
|
||||||
{
|
{
|
||||||
private AppConfig appConfig;
|
private IContextMenuHandler contextMenuHandler;
|
||||||
private BrowserSettings settings;
|
|
||||||
private IDownloadHandler downloadHandler;
|
private IDownloadHandler downloadHandler;
|
||||||
private ILogger logger;
|
private IKeyboardHandler keyboardHandler;
|
||||||
private IText text;
|
private ILifeSpanHandler lifeSpanHandler;
|
||||||
|
private IRequestHandler requestHandler;
|
||||||
|
|
||||||
private AddressChangedEventHandler addressChanged;
|
private AddressChangedEventHandler addressChanged;
|
||||||
private LoadingStateChangedEventHandler loadingStateChanged;
|
private LoadingStateChangedEventHandler loadingStateChanged;
|
||||||
|
@ -51,30 +44,31 @@ namespace SafeExamBrowser.Browser
|
||||||
}
|
}
|
||||||
|
|
||||||
public BrowserControl(
|
public BrowserControl(
|
||||||
AppConfig appConfig,
|
IContextMenuHandler contextMenuHandler,
|
||||||
BrowserSettings settings,
|
|
||||||
IDownloadHandler downloadHandler,
|
IDownloadHandler downloadHandler,
|
||||||
ILogger logger,
|
IKeyboardHandler keyboardHandler,
|
||||||
IText text) : base(settings.StartUrl)
|
ILifeSpanHandler lifeSpanHandler,
|
||||||
|
IRequestHandler requestHandler,
|
||||||
|
string url) : base(url)
|
||||||
{
|
{
|
||||||
this.appConfig = appConfig;
|
this.contextMenuHandler = contextMenuHandler;
|
||||||
this.downloadHandler = downloadHandler;
|
this.downloadHandler = downloadHandler;
|
||||||
this.logger = logger;
|
this.keyboardHandler = keyboardHandler;
|
||||||
this.settings = settings;
|
this.lifeSpanHandler = lifeSpanHandler;
|
||||||
this.text = text;
|
this.requestHandler = requestHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
AddressChanged += BrowserControl_AddressChanged;
|
AddressChanged += (o, args) => addressChanged?.Invoke(args.Address);
|
||||||
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
|
LoadingStateChanged += (o, args) => loadingStateChanged?.Invoke(args.IsLoading);
|
||||||
MouseWheel += BrowserControl_MouseWheel;
|
|
||||||
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
|
TitleChanged += (o, args) => titleChanged?.Invoke(args.Title);
|
||||||
|
|
||||||
DownloadHandler = downloadHandler;
|
DownloadHandler = downloadHandler;
|
||||||
KeyboardHandler = new KeyboardHandler(settings);
|
KeyboardHandler = keyboardHandler;
|
||||||
MenuHandler = new ContextMenuHandler(settings, text);
|
LifeSpanHandler = lifeSpanHandler;
|
||||||
RequestHandler = new RequestHandler(appConfig);
|
MenuHandler = contextMenuHandler;
|
||||||
|
RequestHandler = requestHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void NavigateBackwards()
|
public void NavigateBackwards()
|
||||||
|
@ -89,37 +83,12 @@ namespace SafeExamBrowser.Browser
|
||||||
|
|
||||||
public void NavigateTo(string address)
|
public void NavigateTo(string address)
|
||||||
{
|
{
|
||||||
if (!String.IsNullOrWhiteSpace(address))
|
Load(address);
|
||||||
{
|
|
||||||
Load(address);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reload()
|
public void Reload()
|
||||||
{
|
{
|
||||||
GetBrowser().Reload();
|
GetBrowser().Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BrowserControl_AddressChanged(object sender, AddressChangedEventArgs args)
|
|
||||||
{
|
|
||||||
logger.Debug($"Navigated to '{args.Address}'.");
|
|
||||||
addressChanged?.Invoke(args.Address);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BrowserControl_MouseWheel(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (settings.AllowPageZoom && ModifierKeys == Keys.Control)
|
|
||||||
{
|
|
||||||
var browser = GetBrowser();
|
|
||||||
|
|
||||||
browser.GetZoomLevelAsync().ContinueWith(task =>
|
|
||||||
{
|
|
||||||
if (task.IsCompleted)
|
|
||||||
{
|
|
||||||
browser.SetZoomLevel(task.Result + e.Delta * 0.1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
15
SafeExamBrowser.Browser/Events/PopupRequestedEventArgs.cs
Normal file
15
SafeExamBrowser.Browser/Events/PopupRequestedEventArgs.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Events
|
||||||
|
{
|
||||||
|
internal class PopupRequestedEventArgs
|
||||||
|
{
|
||||||
|
public string Url { get; set; }
|
||||||
|
}
|
||||||
|
}
|
12
SafeExamBrowser.Browser/Events/PopupRequestedEventHandler.cs
Normal file
12
SafeExamBrowser.Browser/Events/PopupRequestedEventHandler.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Events
|
||||||
|
{
|
||||||
|
internal delegate void PopupRequestedEventHandler(PopupRequestedEventArgs args);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Events
|
||||||
|
{
|
||||||
|
internal delegate void ReloadRequestedEventHandler();
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
|
||||||
namespace SafeExamBrowser.Browser.Handlers
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
{
|
{
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IContextMenuHandler.htm.
|
/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_IContextMenuHandler.htm.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal class ContextMenuHandler : IContextMenuHandler
|
internal class ContextMenuHandler : IContextMenuHandler
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@ using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.Browser
|
||||||
namespace SafeExamBrowser.Browser.Handlers
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
{
|
{
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IDownloadHandler.htm.
|
/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_IDownloadHandler.htm.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal class DownloadHandler : IDownloadHandler
|
internal class DownloadHandler : IDownloadHandler
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,21 +8,16 @@
|
||||||
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CefSharp;
|
using CefSharp;
|
||||||
using BrowserSettings = SafeExamBrowser.Contracts.Configuration.Settings.BrowserSettings;
|
using SafeExamBrowser.Browser.Events;
|
||||||
|
|
||||||
namespace SafeExamBrowser.Browser.Handlers
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
{
|
{
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_IKeyboardHandler.htm.
|
/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_IKeyboardHandler.htm.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal class KeyboardHandler : IKeyboardHandler
|
internal class KeyboardHandler : IKeyboardHandler
|
||||||
{
|
{
|
||||||
private BrowserSettings settings;
|
public event ReloadRequestedEventHandler ReloadRequested;
|
||||||
|
|
||||||
public KeyboardHandler(BrowserSettings settings)
|
|
||||||
{
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
|
public bool OnKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey)
|
||||||
{
|
{
|
||||||
|
@ -31,9 +26,9 @@ namespace SafeExamBrowser.Browser.Handlers
|
||||||
|
|
||||||
public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
|
public bool OnPreKeyEvent(IWebBrowser browserControl, IBrowser browser, KeyType type, int windowsKeyCode, int nativeKeyCode, CefEventFlags modifiers, bool isSystemKey, ref bool isKeyboardShortcut)
|
||||||
{
|
{
|
||||||
if (settings.AllowReloading && type == KeyType.KeyUp && windowsKeyCode == (int) Keys.F5)
|
if (type == KeyType.KeyUp && windowsKeyCode == (int) Keys.F5)
|
||||||
{
|
{
|
||||||
browserControl.Reload();
|
ReloadRequested?.Invoke();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
44
SafeExamBrowser.Browser/Handlers/LifeSpanHandler.cs
Normal file
44
SafeExamBrowser.Browser/Handlers/LifeSpanHandler.cs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* 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 CefSharp;
|
||||||
|
using SafeExamBrowser.Browser.Events;
|
||||||
|
|
||||||
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
|
{
|
||||||
|
/// <remarks>
|
||||||
|
/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_ILifeSpanHandler.htm.
|
||||||
|
/// </remarks>
|
||||||
|
internal class LifeSpanHandler : ILifeSpanHandler
|
||||||
|
{
|
||||||
|
public event PopupRequestedEventHandler PopupRequested;
|
||||||
|
|
||||||
|
public bool DoClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnAfterCreated(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnBeforeClose(IWebBrowser chromiumWebBrowser, IBrowser browser)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
|
||||||
|
{
|
||||||
|
var args = new PopupRequestedEventArgs { Url = targetUrl };
|
||||||
|
|
||||||
|
newBrowser = default(IWebBrowser);
|
||||||
|
PopupRequested?.Invoke(args);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,7 @@ using SafeExamBrowser.Contracts.Configuration;
|
||||||
namespace SafeExamBrowser.Browser.Handlers
|
namespace SafeExamBrowser.Browser.Handlers
|
||||||
{
|
{
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// See https://cefsharp.github.io/api/63.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
|
/// See https://cefsharp.github.io/api/67.0.0/html/T_CefSharp_Handler_DefaultRequestHandler.htm.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
internal class RequestHandler : DefaultRequestHandler
|
internal class RequestHandler : DefaultRequestHandler
|
||||||
{
|
{
|
||||||
|
|
|
@ -66,6 +66,9 @@
|
||||||
<Compile Include="BrowserApplicationInfo.cs" />
|
<Compile Include="BrowserApplicationInfo.cs" />
|
||||||
<Compile Include="BrowserApplicationInstance.cs" />
|
<Compile Include="BrowserApplicationInstance.cs" />
|
||||||
<Compile Include="BrowserInstanceIdentifier.cs" />
|
<Compile Include="BrowserInstanceIdentifier.cs" />
|
||||||
|
<Compile Include="Events\PopupRequestedEventArgs.cs" />
|
||||||
|
<Compile Include="Events\PopupRequestedEventHandler.cs" />
|
||||||
|
<Compile Include="Events\ReloadRequestedEventHandler.cs" />
|
||||||
<Compile Include="Handlers\ContextMenuHandler.cs" />
|
<Compile Include="Handlers\ContextMenuHandler.cs" />
|
||||||
<Compile Include="BrowserControl.cs">
|
<Compile Include="BrowserControl.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
|
@ -73,6 +76,7 @@
|
||||||
<Compile Include="BrowserIconResource.cs" />
|
<Compile Include="BrowserIconResource.cs" />
|
||||||
<Compile Include="Handlers\DownloadHandler.cs" />
|
<Compile Include="Handlers\DownloadHandler.cs" />
|
||||||
<Compile Include="Handlers\KeyboardHandler.cs" />
|
<Compile Include="Handlers\KeyboardHandler.cs" />
|
||||||
|
<Compile Include="Handlers\LifeSpanHandler.cs" />
|
||||||
<Compile Include="Handlers\RequestHandler.cs" />
|
<Compile Include="Handlers\RequestHandler.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -171,7 +171,7 @@ namespace SafeExamBrowser.Client
|
||||||
private IOperation BuildBrowserOperation()
|
private IOperation BuildBrowserOperation()
|
||||||
{
|
{
|
||||||
var moduleLogger = new ModuleLogger(logger, "BrowserController");
|
var moduleLogger = new ModuleLogger(logger, "BrowserController");
|
||||||
var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, moduleLogger, text, uiFactory);
|
var browserController = new BrowserApplicationController(configuration.AppConfig, configuration.Settings.Browser, messageBox, moduleLogger, text, uiFactory);
|
||||||
var browserInfo = new BrowserApplicationInfo();
|
var browserInfo = new BrowserApplicationInfo();
|
||||||
var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
|
var operation = new BrowserOperation(browserController, browserInfo, logger, Taskbar, uiFactory);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,39 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
{
|
{
|
||||||
internal partial class DataMapper
|
internal partial class DataMapper
|
||||||
{
|
{
|
||||||
|
private void MapAllowNavigation(Settings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is bool allow)
|
||||||
|
{
|
||||||
|
settings.Browser.AllowBackwardNavigation = allow;
|
||||||
|
settings.Browser.AllowForwardNavigation = allow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapAllowPageZoom(Settings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is bool allow)
|
||||||
|
{
|
||||||
|
settings.Browser.AllowPageZoom = allow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapAllowPopups(Settings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is bool block)
|
||||||
|
{
|
||||||
|
settings.Browser.AllowPopups = !block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MapAllowReload(Settings settings, object value)
|
||||||
|
{
|
||||||
|
if (value is bool allow)
|
||||||
|
{
|
||||||
|
settings.Browser.AllowReloading = allow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void MapMainWindowMode(Settings settings, object value)
|
private void MapMainWindowMode(Settings settings, object value)
|
||||||
{
|
{
|
||||||
const int FULLSCREEN = 1;
|
const int FULLSCREEN = 1;
|
||||||
|
@ -23,11 +56,11 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MapPageZoom(Settings settings, object value)
|
private void MapShowReloadWarning(Settings settings, object value)
|
||||||
{
|
{
|
||||||
if (value is bool enabled)
|
if (value is bool show)
|
||||||
{
|
{
|
||||||
settings.Browser.AllowPageZoom = enabled;
|
settings.Browser.ShowReloadWarning = show;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,24 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
{
|
{
|
||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case Keys.Browser.EnablePageZoom:
|
case Keys.Browser.AllowNavigation:
|
||||||
MapPageZoom(settings, value);
|
MapAllowNavigation(settings, value);
|
||||||
|
break;
|
||||||
|
case Keys.Browser.AllowPageZoom:
|
||||||
|
MapAllowPageZoom(settings, value);
|
||||||
|
break;
|
||||||
|
case Keys.Browser.AllowPopups:
|
||||||
|
MapAllowPopups(settings, value);
|
||||||
|
break;
|
||||||
|
case Keys.Browser.AllowReload:
|
||||||
|
MapAllowReload(settings, value);
|
||||||
break;
|
break;
|
||||||
case Keys.Browser.MainWindowMode:
|
case Keys.Browser.MainWindowMode:
|
||||||
MapMainWindowMode(settings, value);
|
MapMainWindowMode(settings, value);
|
||||||
break;
|
break;
|
||||||
|
case Keys.Browser.ShowReloadWarning:
|
||||||
|
MapShowReloadWarning(settings, value);
|
||||||
|
break;
|
||||||
case Keys.ConfigurationFile.ConfigurationPurpose:
|
case Keys.ConfigurationFile.ConfigurationPurpose:
|
||||||
MapConfigurationMode(settings, value);
|
MapConfigurationMode(settings, value);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,10 +20,14 @@ namespace SafeExamBrowser.Configuration.ConfigurationData
|
||||||
|
|
||||||
internal static class Browser
|
internal static class Browser
|
||||||
{
|
{
|
||||||
|
internal const string AllowNavigation = "allowBrowsingBackForward";
|
||||||
|
internal const string AllowPageZoom = "enableZoomPage";
|
||||||
|
internal const string AllowPopups = "blockPopUpWindows";
|
||||||
|
internal const string AllowReload = "browserWindowAllowReload";
|
||||||
internal const string CustomUserAgentDesktop = "browserUserAgentWinDesktopModeCustom";
|
internal const string CustomUserAgentDesktop = "browserUserAgentWinDesktopModeCustom";
|
||||||
internal const string CustomUserAgentMobile = "browserUserAgentWinTouchModeCustom";
|
internal const string CustomUserAgentMobile = "browserUserAgentWinTouchModeCustom";
|
||||||
internal const string EnablePageZoom = "enableZoomPage";
|
|
||||||
internal const string MainWindowMode = "browserViewMode";
|
internal const string MainWindowMode = "browserViewMode";
|
||||||
|
internal const string ShowReloadWarning = "showReloadWarning";
|
||||||
internal const string UserAgentModeDesktop = "browserUserAgentWinDesktopMode";
|
internal const string UserAgentModeDesktop = "browserUserAgentWinDesktopMode";
|
||||||
internal const string UserAgentModeMobile = "browserUserAgentWinTouchMode";
|
internal const string UserAgentModeMobile = "browserUserAgentWinTouchMode";
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,42 +17,47 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
|
||||||
public class BrowserSettings
|
public class BrowserSettings
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to change the URL of a browser window.
|
/// Determines whether the user will be allowed to change the URL of a browser window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowAddressBar { get; set; }
|
public bool AllowAddressBar { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to navigate backwards in a browser window.
|
/// Determines whether the user will be allowed to navigate backwards in a browser window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowBackwardNavigation { get; set; }
|
public bool AllowBackwardNavigation { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to download configuration files.
|
/// Determines whether the user will be allowed to download configuration files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowConfigurationDownloads { get; set; }
|
public bool AllowConfigurationDownloads { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to open the developer console of a browser window.
|
/// Determines whether the user will be allowed to open the developer console of a browser window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowDeveloperConsole { get; set; }
|
public bool AllowDeveloperConsole { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to download files (excluding configuration files).
|
/// Determines whether the user will be allowed to download files (excluding configuration files).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowDownloads { get; set; }
|
public bool AllowDownloads { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to navigate forwards in a browser window.
|
/// Determines whether the user will be allowed to navigate forwards in a browser window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowForwardNavigation { get; set; }
|
public bool AllowForwardNavigation { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to zoom webpages.
|
/// Determines whether the user will be allowed to zoom webpages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowPageZoom { get; set; }
|
public bool AllowPageZoom { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the user should be allowed to reload webpages.
|
/// Determines whether popup windows will be opened or not.
|
||||||
|
/// </summary>
|
||||||
|
public bool AllowPopups { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the user will be allowed to reload webpages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool AllowReloading { get; set; }
|
public bool AllowReloading { get; set; }
|
||||||
|
|
||||||
|
@ -62,17 +67,22 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
|
||||||
public string CustomUserAgent { get; set; }
|
public string CustomUserAgent { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the main browser window should be rendered in fullscreen mode, i.e. without window frame.
|
/// Determines whether the main browser window will be rendered in fullscreen mode, i.e. without window frame.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool FullScreenMode { get; set; }
|
public bool FullScreenMode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The start URL with which a new browser window should be loaded.
|
/// Determines whether the user will need to confirm every reload attempt.
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowReloadWarning { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The start URL with which a new browser window will be loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string StartUrl { get; set; }
|
public string StartUrl { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether a custom user agent should be used for all requests, see <see cref="CustomUserAgent"/>.
|
/// Determines whether a custom user agent will be used for all requests, see <see cref="CustomUserAgent"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseCustomUserAgent { get; set; }
|
public bool UseCustomUserAgent { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace SafeExamBrowser.Contracts.I18n
|
||||||
MessageBox_ReconfigurationErrorTitle,
|
MessageBox_ReconfigurationErrorTitle,
|
||||||
MessageBox_ReconfigurationQuestion,
|
MessageBox_ReconfigurationQuestion,
|
||||||
MessageBox_ReconfigurationQuestionTitle,
|
MessageBox_ReconfigurationQuestionTitle,
|
||||||
|
MessageBox_ReloadConfirmation,
|
||||||
|
MessageBox_ReloadConfirmationTitle,
|
||||||
MessageBox_ShutdownError,
|
MessageBox_ShutdownError,
|
||||||
MessageBox_ShutdownErrorTitle,
|
MessageBox_ShutdownErrorTitle,
|
||||||
MessageBox_SingleInstance,
|
MessageBox_SingleInstance,
|
||||||
|
|
|
@ -13,7 +13,7 @@ namespace SafeExamBrowser.Contracts.Monitoring
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum KeyState
|
public enum KeyState
|
||||||
{
|
{
|
||||||
None = 0,
|
Unknown = 0,
|
||||||
Pressed,
|
Pressed,
|
||||||
Released
|
Released
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ namespace SafeExamBrowser.Contracts.Monitoring
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum MouseButton
|
public enum MouseButton
|
||||||
{
|
{
|
||||||
None = 0,
|
Unknown = 0,
|
||||||
|
Auxiliary,
|
||||||
Left,
|
Left,
|
||||||
Middle,
|
Middle,
|
||||||
Right
|
Right
|
||||||
|
|
|
@ -84,6 +84,12 @@
|
||||||
<Entry key="MessageBox_ReconfigurationQuestionTitle">
|
<Entry key="MessageBox_ReconfigurationQuestionTitle">
|
||||||
Configuration Detected
|
Configuration Detected
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry key="MessageBox_ReloadConfirmation">
|
||||||
|
Would you like to reload the current page?
|
||||||
|
</Entry>
|
||||||
|
<Entry key="MessageBox_ReloadConfirmationTitle">
|
||||||
|
Reload?
|
||||||
|
</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 application log for more information...
|
||||||
</Entry>
|
</Entry>
|
||||||
|
|
|
@ -27,6 +27,7 @@ namespace SafeExamBrowser.Monitoring.Mouse
|
||||||
{
|
{
|
||||||
var block = false;
|
var block = false;
|
||||||
|
|
||||||
|
block |= button == MouseButton.Auxiliary;
|
||||||
block |= button == MouseButton.Middle && !settings.AllowMiddleButton;
|
block |= button == MouseButton.Middle && !settings.AllowMiddleButton;
|
||||||
block |= button == MouseButton.Right && !settings.AllowRightButton;
|
block |= button == MouseButton.Right && !settings.AllowRightButton;
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
xmlns:fa="http://schemas.fontawesome.io/icons/"
|
||||||
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop"
|
||||||
mc:Ignorable="d" Title="BrowserWindow" Background="#FFF0F0F0" Height="500" Width="750" MinHeight="250" MinWidth="250"
|
mc:Ignorable="d" Title="BrowserWindow" Background="#FFF0F0F0" Height="500" Width="750" MinHeight="250" MinWidth="250" Icon=".\Images\SafeExamBrowser.ico">
|
||||||
WindowState="Maximized" Icon=".\Images\SafeExamBrowser.ico">
|
|
||||||
<Window.Resources>
|
<Window.Resources>
|
||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
|
|
@ -153,12 +153,26 @@ namespace SafeExamBrowser.UserInterface.Desktop
|
||||||
|
|
||||||
private void ApplySettings()
|
private void ApplySettings()
|
||||||
{
|
{
|
||||||
if (IsMainWindow && settings.FullScreenMode)
|
if (IsMainWindow)
|
||||||
{
|
{
|
||||||
MaxHeight = SystemParameters.WorkArea.Height;
|
if (settings.FullScreenMode)
|
||||||
ResizeMode = ResizeMode.NoResize;
|
{
|
||||||
WindowState = WindowState.Maximized;
|
MaxHeight = SystemParameters.WorkArea.Height;
|
||||||
WindowStyle = WindowStyle.None;
|
ResizeMode = ResizeMode.NoResize;
|
||||||
|
WindowState = WindowState.Maximized;
|
||||||
|
WindowStyle = WindowStyle.None;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WindowState = WindowState.Maximized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Top = 0;
|
||||||
|
Left = SystemParameters.WorkArea.Width / 2;
|
||||||
|
Height = SystemParameters.WorkArea.Height;
|
||||||
|
Width = SystemParameters.WorkArea.Width / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
UrlTextBox.IsEnabled = settings.AllowAddressBar;
|
UrlTextBox.IsEnabled = settings.AllowAddressBar;
|
||||||
|
|
|
@ -11,17 +11,17 @@
|
||||||
<ResourceDictionary.MergedDictionaries>
|
<ResourceDictionary.MergedDictionaries>
|
||||||
<ResourceDictionary Source="../Templates/Buttons.xaml" />
|
<ResourceDictionary Source="../Templates/Buttons.xaml" />
|
||||||
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
<ResourceDictionary Source="../Templates/Colors.xaml" />
|
||||||
|
<ResourceDictionary Source="../Templates/ScrollViewers.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Popup x:Name="InstancePopup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
<Popup x:Name="InstancePopup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
||||||
<ScrollViewer x:Name="InstanceScrollViewer" Background="{StaticResource BackgroundBrush}" VerticalScrollBarVisibility="Auto">
|
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
|
||||||
<ScrollViewer.Resources>
|
<ScrollViewer x:Name="InstanceScrollViewer" MaxHeight="400" VerticalScrollBarVisibility="Auto" Template="{StaticResource SmallBarScrollViewer}">
|
||||||
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
|
<StackPanel x:Name="InstanceStackPanel" />
|
||||||
</ScrollViewer.Resources>
|
</ScrollViewer>
|
||||||
<StackPanel x:Name="InstanceStackPanel" />
|
</Border>
|
||||||
</ScrollViewer>
|
|
||||||
</Popup>
|
</Popup>
|
||||||
<Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Click="Button_Click" Padding="4" Template="{StaticResource TaskbarButton}" Width="50" />
|
<Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Click="Button_Click" Padding="4" Template="{StaticResource TaskbarButton}" Width="50" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -6,13 +6,16 @@
|
||||||
* 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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using SafeExamBrowser.Contracts.Core;
|
using System.Windows.Threading;
|
||||||
using SafeExamBrowser.Contracts.Configuration;
|
using SafeExamBrowser.Contracts.Configuration;
|
||||||
|
using SafeExamBrowser.Contracts.Core;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
using SafeExamBrowser.Contracts.UserInterface.Taskbar;
|
||||||
using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events;
|
using SafeExamBrowser.Contracts.UserInterface.Taskbar.Events;
|
||||||
using SafeExamBrowser.UserInterface.Desktop.Utilities;
|
using SafeExamBrowser.UserInterface.Desktop.Utilities;
|
||||||
|
@ -36,13 +39,16 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
|
||||||
|
|
||||||
public void RegisterInstance(IApplicationInstance instance)
|
public void RegisterInstance(IApplicationInstance instance)
|
||||||
{
|
{
|
||||||
var instanceButton = new ApplicationInstanceButton(instance, info);
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
var instanceButton = new ApplicationInstanceButton(instance, info);
|
||||||
|
|
||||||
instanceButton.Clicked += (id) => Clicked?.Invoke(id);
|
instanceButton.Clicked += (id) => Clicked?.Invoke(id);
|
||||||
instance.Terminated += (id) => Instance_OnTerminated(id, instanceButton);
|
instance.Terminated += (id) => Instance_OnTerminated(id, instanceButton);
|
||||||
|
|
||||||
instances.Add(instance);
|
instances.Add(instance);
|
||||||
InstanceStackPanel.Children.Add(instanceButton);
|
InstanceStackPanel.Children.Add(instanceButton);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeApplicationButton()
|
private void InitializeApplicationButton()
|
||||||
|
@ -53,13 +59,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
|
||||||
Button.Content = IconResourceLoader.Load(info.IconResource);
|
Button.Content = IconResourceLoader.Load(info.IconResource);
|
||||||
|
|
||||||
Button.MouseEnter += (o, args) => InstancePopup.IsOpen = instances.Count > 1;
|
Button.MouseEnter += (o, args) => InstancePopup.IsOpen = instances.Count > 1;
|
||||||
Button.MouseLeave += (o, args) => InstancePopup.IsOpen = InstancePopup.IsMouseOver;
|
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = InstancePopup.IsMouseOver));
|
||||||
InstancePopup.MouseLeave += (o, args) => InstancePopup.IsOpen = IsMouseOver;
|
InstancePopup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => InstancePopup.IsOpen = IsMouseOver));
|
||||||
|
|
||||||
InstancePopup.Opened += (o, args) =>
|
InstancePopup.Opened += (o, args) =>
|
||||||
{
|
{
|
||||||
Background = Brushes.LightBlue;
|
Background = Brushes.LightGray;
|
||||||
Button.Background = Brushes.LightBlue;
|
Button.Background = Brushes.LightGray;
|
||||||
};
|
};
|
||||||
|
|
||||||
InstancePopup.Closed += (o, args) =>
|
InstancePopup.Closed += (o, args) =>
|
||||||
|
@ -67,14 +73,6 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
|
||||||
Background = originalBrush;
|
Background = originalBrush;
|
||||||
Button.Background = originalBrush;
|
Button.Background = originalBrush;
|
||||||
};
|
};
|
||||||
|
|
||||||
InstanceStackPanel.SizeChanged += (o, args) =>
|
|
||||||
{
|
|
||||||
if (instances.Count > 9)
|
|
||||||
{
|
|
||||||
InstanceScrollViewer.MaxHeight = InstanceScrollViewer.ActualHeight;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Button_Click(object sender, RoutedEventArgs e)
|
private void Button_Click(object sender, RoutedEventArgs e)
|
||||||
|
@ -91,8 +89,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
|
||||||
|
|
||||||
private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton)
|
private void Instance_OnTerminated(InstanceIdentifier id, ApplicationInstanceButton instanceButton)
|
||||||
{
|
{
|
||||||
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
Dispatcher.BeginInvoke(new Action(() =>
|
||||||
InstanceStackPanel.Children.Remove(instanceButton);
|
{
|
||||||
|
instances.Remove(instances.FirstOrDefault(i => i.Id == id));
|
||||||
|
InstanceStackPanel.Children.Remove(instanceButton);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Button x:Name="Button" Background="{StaticResource BackgroundBrush}" Click="Button_Click" Height="25" Template="{StaticResource TaskbarButton}">
|
<Button x:Name="Button" Background="Transparent" Click="Button_Click" Height="40" Padding="10" Template="{StaticResource TaskbarButton}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<ContentControl x:Name="Icon" HorizontalAlignment="Left" />
|
<ContentControl x:Name="Icon" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,10,0" />
|
||||||
<TextBlock x:Name="Text" Padding="5,0,5,0" HorizontalAlignment="Left" VerticalAlignment="Center" />
|
<TextBlock x:Name="Text" HorizontalAlignment="Left" VerticalAlignment="Center" Padding="5" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Button x:Name="Button" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
|
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
||||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.5,0.5,0.5,0">
|
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
|
||||||
<ScrollViewer x:Name="LayoutsScrollViewer" Background="{StaticResource BackgroundBrush}" MaxHeight="250" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer x:Name="LayoutsScrollViewer" MaxHeight="250" VerticalScrollBarVisibility="Auto">
|
||||||
<ScrollViewer.Resources>
|
<ScrollViewer.Resources>
|
||||||
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
|
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
|
||||||
</ScrollViewer.Resources>
|
</ScrollViewer.Resources>
|
||||||
|
@ -28,7 +28,11 @@
|
||||||
</Popup>
|
</Popup>
|
||||||
<Button x:Name="Button" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40">
|
<Button x:Name="Button" Background="Transparent" Template="{StaticResource TaskbarButton}" Padding="5" Width="40">
|
||||||
<Grid>
|
<Grid>
|
||||||
<fa:ImageAwesome Panel.ZIndex="1" Foreground="LightGray" Icon="KeyboardOutline" VerticalAlignment="Center" />
|
<fa:ImageAwesome Panel.ZIndex="1" Foreground="LightGray" Icon="KeyboardOutline" VerticalAlignment="Center">
|
||||||
|
<fa:ImageAwesome.Effect>
|
||||||
|
<DropShadowEffect Color="White" BlurRadius="5" Direction="0" Opacity="1" ShadowDepth="0" />
|
||||||
|
</fa:ImageAwesome.Effect>
|
||||||
|
</fa:ImageAwesome>
|
||||||
<Viewbox Panel.ZIndex="2" Stretch="Uniform">
|
<Viewbox Panel.ZIndex="2" Stretch="Uniform">
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TextBlock x:Name="LayoutCultureCode" FontWeight="Bold" TextAlignment="Center" Text="ENG">
|
<TextBlock x:Name="LayoutCultureCode" FontWeight="Bold" TextAlignment="Center" Text="ENG">
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using SafeExamBrowser.Contracts.SystemComponents;
|
using SafeExamBrowser.Contracts.SystemComponents;
|
||||||
|
@ -62,13 +63,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
|
||||||
var originalBrush = Button.Background;
|
var originalBrush = Button.Background;
|
||||||
|
|
||||||
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
||||||
Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver;
|
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
|
||||||
Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver;
|
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
|
||||||
|
|
||||||
Popup.Opened += (o, args) =>
|
Popup.Opened += (o, args) =>
|
||||||
{
|
{
|
||||||
Background = Brushes.LightBlue;
|
Background = Brushes.LightGray;
|
||||||
Button.Background = Brushes.LightBlue;
|
Button.Background = Brushes.LightGray;
|
||||||
};
|
};
|
||||||
|
|
||||||
Popup.Closed += (o, args) =>
|
Popup.Closed += (o, args) =>
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
||||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.5,0.5,0.5,0" MaxWidth="250" Padding="20,10,20,20">
|
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
|
||||||
<Grid>
|
<Grid MaxWidth="250" Margin="20,10,20,20">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Button x:Name="Button" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
|
<Button x:Name="Button" Background="Transparent" Height="40" Padding="10,0" Template="{StaticResource TaskbarButton}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
<Popup x:Name="Popup" IsOpen="False" Placement="Top" PlacementTarget="{Binding ElementName=Button}">
|
||||||
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.5,0.5,0.5,0">
|
<Border Background="LightGray" BorderBrush="Gray" BorderThickness="0.75,0.75,0.75,0">
|
||||||
<ScrollViewer Background="{StaticResource BackgroundBrush}" MaxHeight="250" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer MaxHeight="250" VerticalScrollBarVisibility="Auto">
|
||||||
<ScrollViewer.Resources>
|
<ScrollViewer.Resources>
|
||||||
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
|
<s:Double x:Key="{x:Static SystemParameters.VerticalScrollBarWidthKey}">5</s:Double>
|
||||||
</ScrollViewer.Resources>
|
</ScrollViewer.Resources>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
@ -114,13 +115,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Controls
|
||||||
|
|
||||||
SignalStrengthIcon.Child = GetIcon(0);
|
SignalStrengthIcon.Child = GetIcon(0);
|
||||||
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
Button.Click += (o, args) => Popup.IsOpen = !Popup.IsOpen;
|
||||||
Button.MouseLeave += (o, args) => Popup.IsOpen = Popup.IsMouseOver;
|
Button.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = Popup.IsMouseOver));
|
||||||
Popup.MouseLeave += (o, args) => Popup.IsOpen = IsMouseOver;
|
Popup.MouseLeave += (o, args) => Task.Delay(250).ContinueWith(_ => Dispatcher.Invoke(() => Popup.IsOpen = IsMouseOver));
|
||||||
|
|
||||||
Popup.Opened += (o, args) =>
|
Popup.Opened += (o, args) =>
|
||||||
{
|
{
|
||||||
Background = Brushes.LightBlue;
|
Background = Brushes.LightGray;
|
||||||
Button.Background = Brushes.LightBlue;
|
Button.Background = Brushes.LightGray;
|
||||||
};
|
};
|
||||||
|
|
||||||
Popup.Closed += (o, args) =>
|
Popup.Closed += (o, args) =>
|
||||||
|
|
|
@ -162,6 +162,10 @@
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Templates\ScrollViewers.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Resource Include="Images\Battery.xaml">
|
<Resource Include="Images\Battery.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|
|
@ -8,6 +8,13 @@
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Taskbar" Background="#FFF0F0F0" Height="40" Width="750" WindowStyle="None" Topmost="True" Visibility="Visible"
|
Title="Taskbar" Background="#FFF0F0F0" Height="40" Width="750" WindowStyle="None" Topmost="True" Visibility="Visible"
|
||||||
ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico">
|
ResizeMode="NoResize" Icon="./Images/SafeExamBrowser.ico">
|
||||||
|
<Window.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="./Templates/ScrollViewers.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Window.Resources>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
|
@ -16,10 +23,8 @@
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="40" />
|
<ColumnDefinition Width="40" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<ScrollViewer Grid.Column="0" x:Name="ApplicationScrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
|
<ScrollViewer Grid.Column="0" x:Name="ApplicationScrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto"
|
||||||
<ScrollViewer.Resources>
|
Template="{StaticResource SmallBarScrollViewer}">
|
||||||
<s:Double x:Key="{x:Static SystemParameters.HorizontalScrollBarHeightKey}">5</s:Double>
|
|
||||||
</ScrollViewer.Resources>
|
|
||||||
<StackPanel x:Name="ApplicationStackPanel" Orientation="Horizontal" />
|
<StackPanel x:Name="ApplicationStackPanel" Orientation="Horizontal" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
<StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
<StackPanel Grid.Column="1" x:Name="NotificationStackPanel" Orientation="Horizontal" VerticalAlignment="Stretch" />
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:SafeExamBrowser.UserInterface.Desktop.Templates">
|
||||||
|
<ControlTemplate x:Key="Thumb" TargetType="{x:Type Thumb}">
|
||||||
|
<Border Background="DarkGray" Height="Auto" Width="Auto" />
|
||||||
|
</ControlTemplate>
|
||||||
|
<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||||
|
<Track Name="PART_Track" Height="Auto" IsDirectionReversed="True" Width="10">
|
||||||
|
<Track.Thumb>
|
||||||
|
<Thumb Template="{StaticResource Thumb}" Focusable="False" Margin="2.5" OverridesDefaultStyle="True" SnapsToDevicePixels="True" />
|
||||||
|
</Track.Thumb>
|
||||||
|
</Track>
|
||||||
|
</ControlTemplate>
|
||||||
|
<ControlTemplate x:Key="HorizontalScrollBar" TargetType="{x:Type ScrollBar}">
|
||||||
|
<Track Name="PART_Track" Height="10" IsDirectionReversed="False" Width="Auto">
|
||||||
|
<Track.Thumb>
|
||||||
|
<Thumb Template="{StaticResource Thumb}" Focusable="False" Margin="2.5" OverridesDefaultStyle="True" SnapsToDevicePixels="True" />
|
||||||
|
</Track.Thumb>
|
||||||
|
</Track>
|
||||||
|
</ControlTemplate>
|
||||||
|
<ControlTemplate x:Key="SmallBarScrollViewer" TargetType="{x:Type ScrollViewer}">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<ScrollContentPresenter Grid.Column="0" Grid.Row="0" />
|
||||||
|
<ScrollBar Name="PART_VerticalScrollBar" Grid.Column="1" Grid.Row="0" OverridesDefaultStyle="True" Value="{TemplateBinding VerticalOffset}"
|
||||||
|
Maximum="{TemplateBinding ScrollableHeight}" Template="{StaticResource VerticalScrollBar}"
|
||||||
|
ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
|
||||||
|
<ScrollBar Name="PART_HorizontalScrollBar" Grid.Column="0" Grid.Row="1" OverridesDefaultStyle="True" Orientation="Horizontal"
|
||||||
|
Value="{TemplateBinding HorizontalOffset}" Maximum="{TemplateBinding ScrollableWidth}" Template="{StaticResource HorizontalScrollBar}"
|
||||||
|
ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
</ResourceDictionary>
|
|
@ -184,5 +184,23 @@ namespace SafeExamBrowser.WindowsApi.Constants
|
||||||
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms646287(v=vs.85).aspx
|
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms646287(v=vs.85).aspx
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal const int WM_SYSKEYUP = 0x105;
|
internal const int WM_SYSKEYUP = 0x105;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Posted when the user presses the first or second X button while the cursor is in the client area of a window. If the mouse is
|
||||||
|
/// not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has
|
||||||
|
/// captured the mouse.
|
||||||
|
///
|
||||||
|
/// See https://docs.microsoft.com/de-de/windows/desktop/inputdev/wm-xbuttondown.
|
||||||
|
/// </summary>
|
||||||
|
internal const int WM_XBUTTONDOWN = 0x20B;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Posted when the user releases the first or second X button while the cursor is in the client area of a window. If the mouse is
|
||||||
|
/// not captured, the message is posted to the window beneath the cursor. Otherwise, the message is posted to the window that has
|
||||||
|
/// captured the mouse.
|
||||||
|
///
|
||||||
|
/// See https://docs.microsoft.com/de-de/windows/desktop/inputdev/wm-xbuttonup.
|
||||||
|
/// </summary>
|
||||||
|
internal const int WM_XBUTTONUP = 0x20C;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ namespace SafeExamBrowser.WindowsApi.Monitoring
|
||||||
case Constant.WM_SYSKEYUP:
|
case Constant.WM_SYSKEYUP:
|
||||||
return KeyState.Released;
|
return KeyState.Released;
|
||||||
default:
|
default:
|
||||||
return KeyState.None;
|
return KeyState.Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,8 +82,11 @@ namespace SafeExamBrowser.WindowsApi.Monitoring
|
||||||
case Constant.WM_RBUTTONDOWN:
|
case Constant.WM_RBUTTONDOWN:
|
||||||
case Constant.WM_RBUTTONUP:
|
case Constant.WM_RBUTTONUP:
|
||||||
return MouseButton.Right;
|
return MouseButton.Right;
|
||||||
|
case Constant.WM_XBUTTONDOWN:
|
||||||
|
case Constant.WM_XBUTTONUP:
|
||||||
|
return MouseButton.Auxiliary;
|
||||||
default:
|
default:
|
||||||
return MouseButton.None;
|
return MouseButton.Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,13 +97,15 @@ namespace SafeExamBrowser.WindowsApi.Monitoring
|
||||||
case Constant.WM_LBUTTONDOWN:
|
case Constant.WM_LBUTTONDOWN:
|
||||||
case Constant.WM_MBUTTONDOWN:
|
case Constant.WM_MBUTTONDOWN:
|
||||||
case Constant.WM_RBUTTONDOWN:
|
case Constant.WM_RBUTTONDOWN:
|
||||||
|
case Constant.WM_XBUTTONDOWN:
|
||||||
return KeyState.Pressed;
|
return KeyState.Pressed;
|
||||||
case Constant.WM_LBUTTONUP:
|
case Constant.WM_LBUTTONUP:
|
||||||
case Constant.WM_MBUTTONUP:
|
case Constant.WM_MBUTTONUP:
|
||||||
case Constant.WM_RBUTTONUP:
|
case Constant.WM_RBUTTONUP:
|
||||||
|
case Constant.WM_XBUTTONUP:
|
||||||
return KeyState.Released;
|
return KeyState.Released;
|
||||||
default:
|
default:
|
||||||
return KeyState.None;
|
return KeyState.Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue