Implemented basic mouse interception.

This commit is contained in:
dbuechel 2017-08-04 15:20:33 +02:00
parent a79f0c6d77
commit 0807b5f5f9
23 changed files with 452 additions and 61 deletions

View file

@ -63,6 +63,7 @@
<Compile Include="Bounds.cs" />
<Compile Include="Settings\BrowserSettings.cs" />
<Compile Include="Settings\KeyboardSettings.cs" />
<Compile Include="Settings\MouseSettings.cs" />
<Compile Include="Settings\SettingsImpl.cs" />
<Compile Include="WorkingArea.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2017 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.Contracts.Configuration.Settings;
namespace SafeExamBrowser.Configuration.Settings
{
public class MouseSettings : IMouseSettings
{
public bool AllowMiddleButton => false;
public bool AllowRightButton => false;
}
}

View file

@ -25,6 +25,7 @@ namespace SafeExamBrowser.Configuration
{
Browser = new BrowserSettings(this);
Keyboard = new KeyboardSettings();
Mouse = new MouseSettings();
}
public string AppDataFolderName => "SafeExamBrowser";
@ -38,6 +39,8 @@ namespace SafeExamBrowser.Configuration
public IKeyboardSettings Keyboard { get; private set; }
public IMouseSettings Mouse { get; private set; }
public string LogFolderPath
{
get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), AppDataFolderName, "Logs"); }

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2017 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.Contracts.Configuration.Settings
{
public interface IMouseSettings
{
/// <summary>
/// Determines whether the user may use the middle mouse button.
/// </summary>
bool AllowMiddleButton { get; }
/// <summary>
/// Determines whether the user may use the right mouse button.
/// </summary>
bool AllowRightButton { get; }
}
}

View file

@ -30,6 +30,11 @@ namespace SafeExamBrowser.Contracts.Configuration.Settings
/// </summary>
IKeyboardSettings Keyboard { get; }
/// <summary>
/// All mouse-related settings.
/// </summary>
IMouseSettings Mouse { get; }
/// <summary>
/// The path where the log files are to be stored.
/// </summary>

View file

@ -10,5 +10,9 @@ namespace SafeExamBrowser.Contracts.Monitoring
{
public interface IMouseInterceptor
{
/// <summary>
/// Returns <c>true</c> if the given button should be blocked, otherwise <c>false</c>.
/// </summary>
bool Block(MouseButton button, KeyState state);
}
}

View file

@ -0,0 +1,18 @@
/*
* Copyright (c) 2017 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.Contracts.Monitoring
{
public enum MouseButton
{
None = 0,
Left,
Middle,
Right
}
}

View file

@ -68,6 +68,7 @@
<Compile Include="Configuration\INotificationInfo.cs" />
<Compile Include="Configuration\Settings\IBrowserSettings.cs" />
<Compile Include="Configuration\Settings\IKeyboardSettings.cs" />
<Compile Include="Configuration\Settings\IMouseSettings.cs" />
<Compile Include="Configuration\Settings\ISettings.cs" />
<Compile Include="Behaviour\IShutdownController.cs" />
<Compile Include="Behaviour\IStartupController.cs" />
@ -87,6 +88,7 @@
<Compile Include="Monitoring\IWindowMonitor.cs" />
<Compile Include="Monitoring\KeyModifier.cs" />
<Compile Include="Monitoring\KeyState.cs" />
<Compile Include="Monitoring\MouseButton.cs" />
<Compile Include="UserInterface\IBrowserControl.cs" />
<Compile Include="UserInterface\IBrowserWindow.cs" />
<Compile Include="UserInterface\IMessageBox.cs" />

View file

@ -14,6 +14,30 @@ namespace SafeExamBrowser.Contracts.WindowsApi
{
public interface INativeMethods
{
/// <summary>
/// Deregisters the system hook for the given keyboard interceptor.
/// </summary>
/// <exception cref="System.ComponentModel.Win32Exception">
/// If the hook for the given interceptor could not be successfully removed.
/// </exception>
void DeregisterKeyboardHook(IKeyboardInterceptor interceptor);
/// <summary>
/// Deregisters the system hook for the given mouse interceptor.
/// </summary>
/// <exception cref="System.ComponentModel.Win32Exception">
/// If the hook for the given interceptor could not be successfully removed.
/// </exception>
void DeregisterMouseHook(IMouseInterceptor interceptor);
/// <summary>
/// Deregisters a previously registered system event.
/// </summary>
/// <exception cref="System.ComponentModel.Win32Exception">
/// If the event hook could not be successfully removed.
/// </exception>
void DeregisterSystemEvent(IntPtr handle);
/// <summary>
/// Retrieves a collection of handles to all currently open (i.e. visible) windows.
/// </summary>
@ -76,6 +100,11 @@ namespace SafeExamBrowser.Contracts.WindowsApi
/// </summary>
void RegisterKeyboardHook(IKeyboardInterceptor interceptor);
/// <summary>
/// Registers a system hook for the given mouse interceptor.
/// </summary>
void RegisterMouseHook(IMouseInterceptor interceptor);
/// <summary>
/// Registers a system event which will invoke the specified callback when the foreground window has changed.
/// Returns a handle to the newly registered Windows event hook.
@ -105,21 +134,5 @@ namespace SafeExamBrowser.Contracts.WindowsApi
/// If the working area could not be set.
/// </exception>
void SetWorkingArea(IBounds bounds);
/// <summary>
/// Unregisters the system hook for the given keyboard interceptor.
/// </summary>
/// <exception cref="System.ComponentModel.Win32Exception">
/// If the hook for the given interceptor could not be successfully removed.
/// </exception>
void UnregisterKeyboardHook(IKeyboardInterceptor interceptor);
/// <summary>
/// Unregisters a previously registered system event.
/// </summary>
/// <exception cref="System.ComponentModel.Win32Exception">
/// If the event hook could not be successfully removed.
/// </exception>
void UnregisterSystemEvent(IntPtr handle);
}
}

View file

@ -18,14 +18,20 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
{
private IKeyboardInterceptor keyboardInterceptor;
private ILogger logger;
private IMouseInterceptor mouseInterceptor;
private INativeMethods nativeMethods;
public ISplashScreen SplashScreen { private get; set; }
public DeviceInterceptionOperation(IKeyboardInterceptor keyboardInterceptor, ILogger logger, INativeMethods nativeMethods)
public DeviceInterceptionOperation(
IKeyboardInterceptor keyboardInterceptor,
ILogger logger,
IMouseInterceptor mouseInterceptor,
INativeMethods nativeMethods)
{
this.keyboardInterceptor = keyboardInterceptor;
this.logger = logger;
this.mouseInterceptor = mouseInterceptor;
this.nativeMethods = nativeMethods;
}
@ -34,13 +40,15 @@ namespace SafeExamBrowser.Core.Behaviour.Operations
logger.Info("Starting keyboard and mouse interception...");
nativeMethods.RegisterKeyboardHook(keyboardInterceptor);
nativeMethods.RegisterMouseHook(mouseInterceptor);
}
public void Revert()
{
logger.Info("Stopping keyboard and mouse interception...");
nativeMethods.UnregisterKeyboardHook(keyboardInterceptor);
nativeMethods.DeregisterMouseHook(mouseInterceptor);
nativeMethods.DeregisterKeyboardHook(keyboardInterceptor);
}
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2017 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.Contracts.Configuration.Settings;
using SafeExamBrowser.Contracts.Logging;
using SafeExamBrowser.Contracts.Monitoring;
namespace SafeExamBrowser.Monitoring.Mouse
{
public class MouseInterceptor : IMouseInterceptor
{
private ILogger logger;
private IMouseSettings settings;
public MouseInterceptor(ILogger logger, IMouseSettings settings)
{
this.logger = logger;
this.settings = settings;
}
public bool Block(MouseButton button, KeyState state)
{
var block = false;
block |= !settings.AllowMiddleButton && button == MouseButton.Middle;
block |= !settings.AllowRightButton && button == MouseButton.Right;
if (block)
{
logger.Info($"Blocked {button.ToString().ToLower()} mouse button when {state.ToString().ToLower()}.");
}
return block;
}
}
}

View file

@ -61,6 +61,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Keyboard\KeyboardInterceptor.cs" />
<Compile Include="Mouse\MouseInterceptor.cs" />
<Compile Include="Processes\ProcessMonitor.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Windows\WindowMonitor.cs" />
@ -71,8 +72,6 @@
<Name>SafeExamBrowser.Contracts</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Mouse\" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View file

@ -102,13 +102,13 @@ namespace SafeExamBrowser.Monitoring.Windows
{
if (captureStartHookHandle != IntPtr.Zero)
{
nativeMethods.UnregisterSystemEvent(captureStartHookHandle);
nativeMethods.DeregisterSystemEvent(captureStartHookHandle);
logger.Info($"Unregistered system capture start event with handle = {captureStartHookHandle}.");
}
if (foregroundHookHandle != IntPtr.Zero)
{
nativeMethods.UnregisterSystemEvent(foregroundHookHandle);
nativeMethods.DeregisterSystemEvent(foregroundHookHandle);
logger.Info($"Unregistered system foreground event with handle = {foregroundHookHandle}.");
}
}

View file

@ -65,6 +65,77 @@ namespace SafeExamBrowser.WindowsApi.Constants
/// </summary>
internal const int WM_KEYUP = 0x101;
/// <summary>
/// Posted when the user presses the left mouse 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://msdn.microsoft.com/en-us/library/windows/desktop/ms645607(v=vs.85).aspx.
/// </summary>
internal const int WM_LBUTTONDOWN = 0x201;
/// <summary>
/// Posted when the user releases the left mouse 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://msdn.microsoft.com/en-us/library/windows/desktop/ms645608(v=vs.85).aspx.
/// </summary>
internal const int WM_LBUTTONUP = 0x202;
/// <summary>
/// Posted when the user presses the middle mouse 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://msdn.microsoft.com/en-us/library/windows/desktop/ms645610(v=vs.85).aspx.
/// </summary>
internal const int WM_MBUTTONDOWN = 0x207;
/// <summary>
/// Posted when the user releases the middle mouse 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://msdn.microsoft.com/en-us/library/windows/desktop/ms645611(v=vs.85).aspx.
/// </summary>
internal const int WM_MBUTTONUP = 0x208;
/// <summary>
/// Posted to a window when the cursor moves. If the mouse is not captured, the message is posted to the window that contains the
/// cursor. Otherwise, the message is posted to the window that has captured the mouse.
///
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms645616(v=vs.85).aspx.
/// </summary>
internal const int WM_MOUSEMOVE = 0x200;
/// <summary>
/// Sent to the focus window when the mouse wheel is rotated. The DefWindowProc function propagates the message to the window's
/// parent. There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until i
/// finds a window that processes it.
///
/// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms645617(v=vs.85).aspx.
/// </summary>
internal const int WM_MOUSEWHEEL = 0x20A;
/// <summary>
/// Posted when the user presses the right mouse 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://msdn.microsoft.com/en-us/library/windows/desktop/ms646242(v=vs.85).aspx.
/// </summary>
internal const int WM_RBUTTONDOWN = 0x204;
/// <summary>
/// Posted when the user releases the right mouse 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://msdn.microsoft.com/en-us/library/windows/desktop/ms646243(v=vs.85).aspx.
/// </summary>
internal const int WM_RBUTTONUP = 0x205;
/// <summary>
/// A window receives this message when the user chooses a command from the Window menu (formerly known as the system or control
/// menu) or when the user chooses the maximize button, minimize button, restore button, or close button.

View file

@ -54,9 +54,9 @@ namespace SafeExamBrowser.WindowsApi.Monitoring
{
if (nCode >= 0)
{
var state = GetState(wParam.ToInt32());
var keyData = (KBDLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
var modifier = GetModifiers(keyData, wParam.ToInt32());
var state = GetState(wParam.ToInt32());
if (Interceptor.Block((int) keyData.KeyCode, modifier, state))
{

View file

@ -0,0 +1,104 @@
/*
* Copyright (c) 2017 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.Runtime.InteropServices;
using SafeExamBrowser.Contracts.Monitoring;
using SafeExamBrowser.WindowsApi.Constants;
using SafeExamBrowser.WindowsApi.Types;
namespace SafeExamBrowser.WindowsApi.Monitoring
{
internal class MouseHook
{
private HookProc hookProc;
internal IntPtr Handle { get; private set; }
internal IMouseInterceptor Interceptor { get; private set; }
internal MouseHook(IMouseInterceptor interceptor)
{
Interceptor = interceptor;
}
internal void Attach()
{
var module = Kernel32.GetModuleHandle(null);
// IMORTANT:
// Ensures that the hook delegate does not get garbage collected prematurely, as it will be passed to unmanaged code.
// Not doing so will result in a <c>CallbackOnCollectedDelegate</c> error and subsequent application crash!
hookProc = new HookProc(LowLevelMouseProc);
Handle = User32.SetWindowsHookEx(HookType.WH_MOUSE_LL, hookProc, module, 0);
}
internal bool Detach()
{
return User32.UnhookWindowsHookEx(Handle);
}
private IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && !Ignore(wParam.ToInt32()))
{
var mouseData = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
var button = GetButton(wParam.ToInt32());
var state = GetState(wParam.ToInt32());
if (Interceptor.Block(button, state))
{
return (IntPtr) 1;
}
}
return User32.CallNextHookEx(Handle, nCode, wParam, lParam);
}
private bool Ignore(int wParam)
{
// For performance reasons, ignore mouse movement and wheel rotation...
return wParam == Constant.WM_MOUSEMOVE || wParam == Constant.WM_MOUSEWHEEL;
}
private MouseButton GetButton(int wParam)
{
switch (wParam)
{
case Constant.WM_LBUTTONDOWN:
case Constant.WM_LBUTTONUP:
return MouseButton.Left;
case Constant.WM_MBUTTONDOWN:
case Constant.WM_MBUTTONUP:
return MouseButton.Middle;
case Constant.WM_RBUTTONDOWN:
case Constant.WM_RBUTTONUP:
return MouseButton.Right;
default:
return MouseButton.None;
}
}
private KeyState GetState(int wParam)
{
switch (wParam)
{
case Constant.WM_LBUTTONDOWN:
case Constant.WM_MBUTTONDOWN:
case Constant.WM_RBUTTONDOWN:
return KeyState.Pressed;
case Constant.WM_LBUTTONUP:
case Constant.WM_MBUTTONUP:
case Constant.WM_RBUTTONUP:
return KeyState.Released;
default:
return KeyState.None;
}
}
}
}

View file

@ -25,6 +25,7 @@ namespace SafeExamBrowser.WindowsApi
{
private ConcurrentDictionary<IntPtr, EventProc> EventDelegates = new ConcurrentDictionary<IntPtr, EventProc>();
private ConcurrentDictionary<IntPtr, KeyboardHook> KeyboardHooks = new ConcurrentDictionary<IntPtr, KeyboardHook>();
private ConcurrentDictionary<IntPtr, MouseHook> MouseHooks = new ConcurrentDictionary<IntPtr, MouseHook>();
/// <summary>
/// Upon finalization, unregister all active system events and hooks...
@ -40,6 +41,57 @@ namespace SafeExamBrowser.WindowsApi
{
User32.UnhookWindowsHookEx(handle);
}
foreach (var handle in MouseHooks.Keys)
{
User32.UnhookWindowsHookEx(handle);
}
}
public void DeregisterKeyboardHook(IKeyboardInterceptor interceptor)
{
var hook = KeyboardHooks.Values.FirstOrDefault(h => h.Interceptor == interceptor);
if (hook != null)
{
var success = hook.Detach();
if (!success)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
KeyboardHooks.TryRemove(hook.Handle, out KeyboardHook h);
}
}
public void DeregisterMouseHook(IMouseInterceptor interceptor)
{
var hook = MouseHooks.Values.FirstOrDefault(h => h.Interceptor == interceptor);
if (hook != null)
{
var success = hook.Detach();
if (!success)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
MouseHooks.TryRemove(hook.Handle, out MouseHook h);
}
}
public void DeregisterSystemEvent(IntPtr handle)
{
var success = User32.UnhookWinEvent(handle);
if (!success)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
EventDelegates.TryRemove(handle, out EventProc d);
}
public IEnumerable<IntPtr> GetOpenWindows()
@ -147,6 +199,15 @@ namespace SafeExamBrowser.WindowsApi
KeyboardHooks[hook.Handle] = hook;
}
public void RegisterMouseHook(IMouseInterceptor interceptor)
{
var hook = new MouseHook(interceptor);
hook.Attach();
MouseHooks[hook.Handle] = hook;
}
public IntPtr RegisterSystemForegroundEvent(Action<IntPtr> callback)
{
EventProc eventProc = (IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime) =>
@ -201,34 +262,5 @@ namespace SafeExamBrowser.WindowsApi
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
public void UnregisterKeyboardHook(IKeyboardInterceptor interceptor)
{
var hook = KeyboardHooks.Values.FirstOrDefault(h => h.Interceptor == interceptor);
if (hook != null)
{
var success = hook.Detach();
if (!success)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
KeyboardHooks.TryRemove(hook.Handle, out KeyboardHook h);
}
}
public void UnregisterSystemEvent(IntPtr handle)
{
var success = User32.UnhookWinEvent(handle);
if (!success)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
EventDelegates.TryRemove(handle, out EventProc d);
}
}
}

View file

@ -60,6 +60,7 @@
<ItemGroup>
<Compile Include="Constants\Constant.cs" />
<Compile Include="Constants\HookType.cs" />
<Compile Include="Monitoring\MouseHook.cs" />
<Compile Include="Types\Bounds.cs" />
<Compile Include="Types\KBDLLHOOKSTRUCT.cs" />
<Compile Include="Types\KBDLLHOOKSTRUCTFlags.cs" />
@ -71,6 +72,8 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Constants\SPI.cs" />
<Compile Include="Constants\SPIF.cs" />
<Compile Include="Types\MSLLHOOKSTRUCT.cs" />
<Compile Include="Types\POINT.cs" />
<Compile Include="Types\RECT.cs" />
<Compile Include="User32.cs" />
</ItemGroup>

View file

@ -15,17 +15,17 @@ namespace SafeExamBrowser.WindowsApi.Types
/// See http://www.pinvoke.net/default.aspx/Structures/KBDLLHOOKSTRUCT.html.
/// </remarks>
[StructLayout(LayoutKind.Sequential)]
public struct KBDLLHOOKSTRUCT
internal struct KBDLLHOOKSTRUCT
{
/// <summary>
/// A virtual-key code. The code must be a value in the range 1 to 254.
/// </summary>
public uint KeyCode;
internal uint KeyCode;
/// <summary>
/// A hardware scan code for the key.
/// </summary>
public uint ScanCode;
internal uint ScanCode;
/// <summary>
/// The extended-key flag, event-injected flags, context code, and transition-state flag. This member is specified as follows. An
@ -33,16 +33,16 @@ namespace SafeExamBrowser.WindowsApi.Types
/// event was injected. If it was, then testing LLKHF_LOWER_IL_INJECTED (bit 1) will tell you whether or not the event was injected
/// from a process running at lower integrity level.
/// </summary>
public KBDLLHOOKSTRUCTFlags Flags;
internal KBDLLHOOKSTRUCTFlags Flags;
/// <summary>
/// The time stamp for this message, equivalent to what <c>GetMessageTime</c> would return for this message.
/// </summary>
public uint Time;
internal uint Time;
/// <summary>
/// Additional information associated with the message.
/// </summary>
public IntPtr DwExtraInfo;
internal IntPtr DwExtraInfo;
}
}

View file

@ -11,7 +11,7 @@ namespace SafeExamBrowser.WindowsApi.Types
/// <remarks>
/// See http://www.pinvoke.net/default.aspx/Structures/KBDLLHOOKSTRUCT.html.
/// </remarks>
public enum KBDLLHOOKSTRUCTFlags
internal enum KBDLLHOOKSTRUCTFlags
{
/// <summary>
/// Test the extended-key flag.

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2017 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.Runtime.InteropServices;
namespace SafeExamBrowser.WindowsApi.Types
{
[StructLayout(LayoutKind.Sequential)]
internal struct MSLLHOOKSTRUCT
{
internal POINT Point;
internal int MouseData;
internal int Flags;
internal int Time;
internal UIntPtr DwExtraInfo;
}
}

View file

@ -0,0 +1,19 @@
/*
* Copyright (c) 2017 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.Runtime.InteropServices;
namespace SafeExamBrowser.WindowsApi.Types
{
[StructLayout(LayoutKind.Sequential)]
internal struct POINT
{
internal int X;
internal int Y;
}
}

View file

@ -22,6 +22,7 @@ using SafeExamBrowser.Core.Behaviour.Operations;
using SafeExamBrowser.Core.I18n;
using SafeExamBrowser.Core.Logging;
using SafeExamBrowser.Monitoring.Keyboard;
using SafeExamBrowser.Monitoring.Mouse;
using SafeExamBrowser.Monitoring.Processes;
using SafeExamBrowser.Monitoring.Windows;
using SafeExamBrowser.UserInterface;
@ -35,6 +36,7 @@ namespace SafeExamBrowser
private IApplicationInfo browserInfo;
private IKeyboardInterceptor keyboardInterceptor;
private ILogger logger;
private IMouseInterceptor mouseInterceptor;
private INativeMethods nativeMethods;
private IProcessMonitor processMonitor;
private IRuntimeController runtimeController;
@ -65,6 +67,7 @@ namespace SafeExamBrowser
text = new Text(textResource);
browserController = new BrowserApplicationController(settings, text, uiFactory);
keyboardInterceptor = new KeyboardInterceptor(settings.Keyboard, new ModuleLogger(logger, typeof(KeyboardInterceptor)));
mouseInterceptor = new MouseInterceptor(new ModuleLogger(logger, typeof(MouseInterceptor)), settings.Mouse);
processMonitor = new ProcessMonitor(new ModuleLogger(logger, typeof(ProcessMonitor)), nativeMethods);
windowMonitor = new WindowMonitor(new ModuleLogger(logger, typeof(WindowMonitor)), nativeMethods);
workingArea = new WorkingArea(new ModuleLogger(logger, typeof(WorkingArea)), nativeMethods);
@ -74,7 +77,7 @@ namespace SafeExamBrowser
StartupController = new StartupController(logger, settings, text, uiFactory);
StartupOperations = new Queue<IOperation>();
StartupOperations.Enqueue(new DeviceInterceptionOperation(keyboardInterceptor, logger, nativeMethods));
StartupOperations.Enqueue(new DeviceInterceptionOperation(keyboardInterceptor, logger, mouseInterceptor, nativeMethods));
StartupOperations.Enqueue(new WindowMonitorOperation(logger, windowMonitor));
StartupOperations.Enqueue(new ProcessMonitorOperation(logger, processMonitor));
StartupOperations.Enqueue(new WorkingAreaOperation(logger, Taskbar, workingArea));