SEBWIN-567: Implemented keyboard activator for taskbar.

This commit is contained in:
Damian Büchel 2022-05-06 15:52:37 +02:00
parent 043187f4ec
commit aa6c765729
11 changed files with 199 additions and 79 deletions

View file

@ -303,6 +303,7 @@ namespace SafeExamBrowser.Client
context.Activators.Add(new ActionCenterKeyboardActivator(ModuleLogger(nameof(ActionCenterKeyboardActivator)), nativeMethods)); context.Activators.Add(new ActionCenterKeyboardActivator(ModuleLogger(nameof(ActionCenterKeyboardActivator)), nativeMethods));
context.Activators.Add(new ActionCenterTouchActivator(ModuleLogger(nameof(ActionCenterTouchActivator)), nativeMethods)); context.Activators.Add(new ActionCenterTouchActivator(ModuleLogger(nameof(ActionCenterTouchActivator)), nativeMethods));
context.Activators.Add(new TaskbarKeyboardActivator(ModuleLogger(nameof(TaskbarKeyboardActivator)), nativeMethods));
context.Activators.Add(new TaskviewKeyboardActivator(ModuleLogger(nameof(TaskviewKeyboardActivator)), nativeMethods)); context.Activators.Add(new TaskviewKeyboardActivator(ModuleLogger(nameof(TaskviewKeyboardActivator)), nativeMethods));
context.Activators.Add(new TerminationActivator(ModuleLogger(nameof(TerminationActivator)), nativeMethods)); context.Activators.Add(new TerminationActivator(ModuleLogger(nameof(TerminationActivator)), nativeMethods));

View file

@ -118,6 +118,12 @@ namespace SafeExamBrowser.Client.Operations
{ {
terminationActivator.Start(); terminationActivator.Start();
} }
if (Context.Settings.Taskbar.EnableTaskbar && activator is ITaskbarActivator taskbarActivator)
{
taskbar.Register(taskbarActivator);
taskbarActivator.Start();
}
} }
} }

View file

@ -87,6 +87,7 @@
<Compile Include="Shell\INotificationControl.cs" /> <Compile Include="Shell\INotificationControl.cs" />
<Compile Include="Shell\ISystemControl.cs" /> <Compile Include="Shell\ISystemControl.cs" />
<Compile Include="Shell\ITaskbar.cs" /> <Compile Include="Shell\ITaskbar.cs" />
<Compile Include="Shell\ITaskbarActivator.cs" />
<Compile Include="Shell\ITaskview.cs" /> <Compile Include="Shell\ITaskview.cs" />
<Compile Include="Shell\ITaskviewActivator.cs" /> <Compile Include="Shell\ITaskviewActivator.cs" />
<Compile Include="Shell\ITerminationActivator.cs" /> <Compile Include="Shell\ITerminationActivator.cs" />

View file

@ -57,6 +57,11 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
/// </summary> /// </summary>
void Close(); void Close();
/// <summary>
/// Puts the focus on the taskbar.
/// </summary>
void Focus(bool forward = true);
/// <summary> /// <summary>
/// Returns the absolute height of the taskbar (i.e. in physical pixels). /// Returns the absolute height of the taskbar (i.e. in physical pixels).
/// </summary> /// </summary>
@ -72,14 +77,14 @@ namespace SafeExamBrowser.UserInterface.Contracts.Shell
/// </summary> /// </summary>
void InitializeText(IText text); void InitializeText(IText text);
/// <summary>
/// Registers the specified activator for the taskbar.
/// </summary>
void Register(ITaskbarActivator activator);
/// <summary> /// <summary>
/// Shows the taskbar. /// Shows the taskbar.
/// </summary> /// </summary>
void Show(); void Show();
/// <summary>
/// Puts the focus on the taskbar.
/// </summary>
void Focus(bool forward = true);
} }
} }

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
namespace SafeExamBrowser.UserInterface.Contracts.Shell
{
/// <summary>
/// A module which can be used to activate the <see cref="ITaskbar"/>.
/// </summary>
public interface ITaskbarActivator : IActivator
{
/// <summary>
/// Fired when the taskbar should be activated (i.e. put into focus).
/// </summary>
event ActivatorEventHandler Activated;
}
}

View file

@ -79,11 +79,11 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
internal BrowserWindow(IBrowserControl browserControl, BrowserSettings settings, bool isMainWindow, IText text, ILogger logger) internal BrowserWindow(IBrowserControl browserControl, BrowserSettings settings, bool isMainWindow, IText text, ILogger logger)
{ {
this.browserControl = browserControl;
this.isMainWindow = isMainWindow; this.isMainWindow = isMainWindow;
this.logger = logger;
this.settings = settings; this.settings = settings;
this.text = text; this.text = text;
this.logger = logger;
this.browserControl = browserControl;
InitializeComponent(); InitializeComponent();
InitializeBrowserWindow(browserControl); InitializeBrowserWindow(browserControl);
@ -214,12 +214,15 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
if (e.Key == Key.Tab) if (e.Key == Key.Tab)
{ {
var hasShift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; var hasShift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
if (Toolbar.IsKeyboardFocusWithin && hasShift) if (Toolbar.IsKeyboardFocusWithin && hasShift)
{ {
var firstActiveElementInToolbar = Toolbar.PredictFocus(FocusNavigationDirection.Right); var firstActiveElementInToolbar = Toolbar.PredictFocus(FocusNavigationDirection.Right);
if (firstActiveElementInToolbar is System.Windows.UIElement)
if (firstActiveElementInToolbar is UIElement)
{ {
var control = firstActiveElementInToolbar as System.Windows.UIElement; var control = firstActiveElementInToolbar as UIElement;
if (control.IsKeyboardFocusWithin) if (control.IsKeyboardFocusWithin)
{ {
this.LoseFocusRequested?.Invoke(false); this.LoseFocusRequested?.Invoke(false);
@ -257,6 +260,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{ {
var hasCtrl = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control; var hasCtrl = (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control;
var hasShift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift; var hasShift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
if (BrowserControlHost.IsFocused && hasCtrl) if (BrowserControlHost.IsFocused && hasCtrl)
{ {
if (Findbar.Visibility == Visibility.Hidden || hasShift) if (Findbar.Visibility == Visibility.Hidden || hasShift)
@ -273,6 +277,7 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
var focusedElement = FocusManager.GetFocusedElement(this); var focusedElement = FocusManager.GetFocusedElement(this);
var focusedControl = focusedElement as System.Windows.Controls.Control; var focusedControl = focusedElement as System.Windows.Controls.Control;
var prevFocusedControl = tabKeyDownFocusElement as System.Windows.Controls.Control; var prevFocusedControl = tabKeyDownFocusElement as System.Windows.Controls.Control;
if (focusedControl != null && prevFocusedControl != null) if (focusedControl != null && prevFocusedControl != null)
{ {
//var commonAncestor = focusedControl.FindCommonVisualAncestor(prevFocusedControl); //var commonAncestor = focusedControl.FindCommonVisualAncestor(prevFocusedControl);
@ -452,14 +457,14 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
var javascript = @" var javascript = @"
if (typeof __SEB_focusElement === 'undefined') { if (typeof __SEB_focusElement === 'undefined') {
__SEB_focusElement = function (forward) { __SEB_focusElement = function (forward) {
var items = [].map var items = [].map
.call(document.body.querySelectorAll(['input', 'select', 'a[href]', 'textarea', 'button', '[tabindex]']), function(el, i) { return { el, i } }) .call(document.body.querySelectorAll(['input', 'select', 'a[href]', 'textarea', 'button', '[tabindex]']), function(el, i) { return { el, i } })
.filter(function(e) { return e.el.tabIndex >= 0 && !e.el.disabled && e.el.offsetParent; }) .filter(function(e) { return e.el.tabIndex >= 0 && !e.el.disabled && e.el.offsetParent; })
.sort(function(a,b) { return a.el.tabIndex === b.el.tabIndex ? a.i - b.i : (a.el.tabIndex || 9E9) - (b.el.tabIndex || 9E9); }) .sort(function(a,b) { return a.el.tabIndex === b.el.tabIndex ? a.i - b.i : (a.el.tabIndex || 9E9) - (b.el.tabIndex || 9E9); })
var item = items[forward ? 1 : items.length - 1]; var item = items[forward ? 1 : items.length - 1];
if (item && item.focus && typeof item.focus !== 'function') if (item && item.focus && typeof item.focus !== 'function')
throw ('item.focus is not a function, ' + typeof item.focus) throw ('item.focus is not a function, ' + typeof item.focus)
setTimeout(function () { item && item.focus && item.focus(); }, 20); setTimeout(function () { item && item.focus && item.focus(); }, 20);
} }
}"; }";
this.browserControl.ExecuteJavascript(javascript, result => this.browserControl.ExecuteJavascript(javascript, result =>
@ -593,7 +598,7 @@ if (typeof __SEB_focusElement === 'undefined') {
public void FocusToolbar(bool forward) public void FocusToolbar(bool forward)
{ {
this.Dispatcher.BeginInvoke((Action)(async () => this.Dispatcher.BeginInvoke((Action) (async () =>
{ {
this.Activate(); this.Activate();
await Task.Delay(50); await Task.Delay(50);
@ -613,7 +618,7 @@ if (typeof __SEB_focusElement === 'undefined') {
public void FocusBrowser() public void FocusBrowser()
{ {
this.Dispatcher.BeginInvoke((Action)(async () => this.Dispatcher.BeginInvoke((Action) (async () =>
{ {
this.FocusToolbar(false); this.FocusToolbar(false);
await Task.Delay(100); await Task.Delay(100);
@ -630,7 +635,7 @@ if (typeof __SEB_focusElement === 'undefined') {
public void FocusAddressBar() public void FocusAddressBar()
{ {
this.Dispatcher.BeginInvoke((Action)(async () => this.Dispatcher.BeginInvoke((Action) (() =>
{ {
this.UrlTextBox.Focus(); this.UrlTextBox.Focus();
})); }));

View file

@ -20,8 +20,9 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{ {
internal partial class Taskbar : Window, ITaskbar internal partial class Taskbar : Window, ITaskbar
{ {
private readonly ILogger logger;
private bool allowClose; private bool allowClose;
private ILogger logger;
private bool isQuitButtonFocusedAtKeyDown; private bool isQuitButtonFocusedAtKeyDown;
private bool isFirstChildFocusedAtKeyDown; private bool isFirstChildFocusedAtKeyDown;
@ -82,6 +83,23 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
Dispatcher.Invoke(base.Close); Dispatcher.Invoke(base.Close);
} }
public void Focus(bool forward)
{
Dispatcher.BeginInvoke((Action) (() =>
{
Activate();
if (forward)
{
SetFocusWithin(ApplicationStackPanel.Children[0]);
}
else
{
QuitButton.Focus();
}
}));
}
public int GetAbsoluteHeight() public int GetAbsoluteHeight()
{ {
return Dispatcher.Invoke(() => return Dispatcher.Invoke(() =>
@ -121,6 +139,13 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
}); });
} }
private void InitializeTaskbar()
{
Closing += Taskbar_Closing;
Loaded += (o, args) => InitializeBounds();
QuitButton.Clicked += QuitButton_Clicked;
}
public void InitializeText(IText text) public void InitializeText(IText text)
{ {
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
@ -131,11 +156,21 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
}); });
} }
public void Register(ITaskbarActivator activator)
{
activator.Activated += Activator_Activated;
}
public new void Show() public new void Show()
{ {
Dispatcher.Invoke(base.Show); Dispatcher.Invoke(base.Show);
} }
private void Activator_Activated()
{
(this as ITaskbar).Focus(true);
}
private void QuitButton_Clicked(CancelEventArgs args) private void QuitButton_Clicked(CancelEventArgs args)
{ {
QuitButtonClicked?.Invoke(args); QuitButtonClicked?.Invoke(args);
@ -160,17 +195,10 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
} }
} }
private void InitializeTaskbar()
{
Closing += Taskbar_Closing;
Loaded += (o, args) => InitializeBounds();
QuitButton.Clicked += QuitButton_Clicked;
}
private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e) private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{ {
this.isQuitButtonFocusedAtKeyDown = this.QuitButton.IsKeyboardFocusWithin; isQuitButtonFocusedAtKeyDown = QuitButton.IsKeyboardFocusWithin;
this.isFirstChildFocusedAtKeyDown = this.ApplicationStackPanel.Children[0].IsKeyboardFocusWithin; isFirstChildFocusedAtKeyDown = ApplicationStackPanel.Children[0].IsKeyboardFocusWithin;
} }
private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e) private void Window_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
@ -178,36 +206,20 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
if (e.Key == System.Windows.Input.Key.Tab) if (e.Key == System.Windows.Input.Key.Tab)
{ {
var shift = System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.LeftShift); var shift = System.Windows.Input.Keyboard.IsKeyDown(System.Windows.Input.Key.LeftShift);
if (!shift && this.ApplicationStackPanel.Children[0].IsKeyboardFocusWithin && this.isQuitButtonFocusedAtKeyDown) if (!shift && ApplicationStackPanel.Children[0].IsKeyboardFocusWithin && isQuitButtonFocusedAtKeyDown)
{ {
this.LoseFocusRequested?.Invoke(true); LoseFocusRequested?.Invoke(true);
e.Handled = true; e.Handled = true;
} }
else if (shift && this.QuitButton.IsKeyboardFocusWithin && this.isFirstChildFocusedAtKeyDown) else if (shift && QuitButton.IsKeyboardFocusWithin && isFirstChildFocusedAtKeyDown)
{ {
this.LoseFocusRequested?.Invoke(false); LoseFocusRequested?.Invoke(false);
e.Handled = true; e.Handled = true;
} }
} }
this.isQuitButtonFocusedAtKeyDown = false; isQuitButtonFocusedAtKeyDown = false;
this.isFirstChildFocusedAtKeyDown = false; isFirstChildFocusedAtKeyDown = false;
}
void ITaskbar.Focus(bool forward)
{
this.Dispatcher.BeginInvoke((Action)(() =>
{
base.Activate();
if (forward)
{
this.SetFocusWithin(this.ApplicationStackPanel.Children[0]);
}
else
{
this.QuitButton.Focus();
}
}));
} }
private bool SetFocusWithin(UIElement uIElement) private bool SetFocusWithin(UIElement uIElement)
@ -215,15 +227,17 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
if (uIElement.Focusable) if (uIElement.Focusable)
{ {
uIElement.Focus(); uIElement.Focus();
return true; return true;
} }
if (uIElement is System.Windows.Controls.Panel) if (uIElement is System.Windows.Controls.Panel)
{ {
var panel = uIElement as System.Windows.Controls.Panel; var panel = uIElement as System.Windows.Controls.Panel;
for (var i = 0; i < panel.Children.Count; i++) for (var i = 0; i < panel.Children.Count; i++)
{ {
if (this.SetFocusWithin(panel.Children[i])) if (SetFocusWithin(panel.Children[i]))
{ {
return true; return true;
} }
@ -235,9 +249,10 @@ namespace SafeExamBrowser.UserInterface.Desktop.Windows
{ {
var control = uIElement as System.Windows.Controls.ContentControl; var control = uIElement as System.Windows.Controls.ContentControl;
var content = control.Content as UIElement; var content = control.Content as UIElement;
if (content != null) if (content != null)
{ {
return this.SetFocusWithin(content); return SetFocusWithin(content);
} }
} }

View file

@ -33,12 +33,12 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
internal partial class BrowserWindow : Window, IBrowserWindow internal partial class BrowserWindow : Window, IBrowserWindow
{ {
private readonly bool isMainWindow; private readonly bool isMainWindow;
private readonly ILogger logger;
private readonly BrowserSettings settings; private readonly BrowserSettings settings;
private readonly IText text; private readonly IText text;
private WindowClosedEventHandler closed; private WindowClosedEventHandler closed;
private WindowClosingEventHandler closing; private WindowClosingEventHandler closing;
private ILogger logger;
private WindowSettings WindowSettings private WindowSettings WindowSettings
{ {
@ -54,7 +54,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
public event ActionRequestedEventHandler DeveloperConsoleRequested; public event ActionRequestedEventHandler DeveloperConsoleRequested;
public event FindRequestedEventHandler FindRequested; public event FindRequestedEventHandler FindRequested;
public event ActionRequestedEventHandler ForwardNavigationRequested; public event ActionRequestedEventHandler ForwardNavigationRequested;
public event LoseFocusRequestedEventHandler LoseFocusRequested; public event LoseFocusRequestedEventHandler LoseFocusRequested { add { } remove { } }
public event ActionRequestedEventHandler HomeNavigationRequested; public event ActionRequestedEventHandler HomeNavigationRequested;
public event ActionRequestedEventHandler ReloadRequested; public event ActionRequestedEventHandler ReloadRequested;
public event ActionRequestedEventHandler ZoomInRequested; public event ActionRequestedEventHandler ZoomInRequested;
@ -76,9 +76,9 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
internal BrowserWindow(IBrowserControl browserControl, BrowserSettings settings, bool isMainWindow, IText text, ILogger logger) internal BrowserWindow(IBrowserControl browserControl, BrowserSettings settings, bool isMainWindow, IText text, ILogger logger)
{ {
this.isMainWindow = isMainWindow; this.isMainWindow = isMainWindow;
this.logger = logger;
this.settings = settings; this.settings = settings;
this.text = text; this.text = text;
this.logger = logger;
InitializeComponent(); InitializeComponent();
InitializeBrowserWindow(browserControl); InitializeBrowserWindow(browserControl);

View file

@ -19,8 +19,8 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
{ {
internal partial class Taskbar : Window, ITaskbar internal partial class Taskbar : Window, ITaskbar
{ {
private readonly ILogger logger;
private bool allowClose; private bool allowClose;
private ILogger logger;
public bool ShowClock public bool ShowClock
{ {
@ -32,7 +32,7 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
set { Dispatcher.Invoke(() => QuitButton.Visibility = value ? Visibility.Visible : Visibility.Collapsed); } set { Dispatcher.Invoke(() => QuitButton.Visibility = value ? Visibility.Visible : Visibility.Collapsed); }
} }
public event LoseFocusRequestedEventHandler LoseFocusRequested; public event LoseFocusRequestedEventHandler LoseFocusRequested { add { } remove { } }
public event QuitButtonClickedEventHandler QuitButtonClicked; public event QuitButtonClickedEventHandler QuitButtonClicked;
internal Taskbar(ILogger logger) internal Taskbar(ILogger logger)
@ -79,6 +79,20 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
Dispatcher.Invoke(base.Close); Dispatcher.Invoke(base.Close);
} }
public void Focus(bool fromTop)
{
Activate();
if (fromTop)
{
ApplicationStackPanel.Children[0].Focus();
}
else
{
QuitButton.Focus();
}
}
public int GetAbsoluteHeight() public int GetAbsoluteHeight()
{ {
return Dispatcher.Invoke(() => return Dispatcher.Invoke(() =>
@ -118,6 +132,13 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
}); });
} }
private void InitializeTaskbar()
{
Closing += Taskbar_Closing;
Loaded += (o, args) => InitializeBounds();
QuitButton.Clicked += QuitButton_Clicked;
}
public void InitializeText(IText text) public void InitializeText(IText text)
{ {
Dispatcher.Invoke(() => Dispatcher.Invoke(() =>
@ -126,11 +147,21 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
}); });
} }
public void Register(ITaskbarActivator activator)
{
activator.Activated += Activator_Activated;
}
public new void Show() public new void Show()
{ {
Dispatcher.Invoke(base.Show); Dispatcher.Invoke(base.Show);
} }
private void Activator_Activated()
{
(this as ITaskbar).Focus(true);
}
private void QuitButton_Clicked(CancelEventArgs args) private void QuitButton_Clicked(CancelEventArgs args)
{ {
QuitButtonClicked?.Invoke(args); QuitButtonClicked?.Invoke(args);
@ -154,25 +185,5 @@ namespace SafeExamBrowser.UserInterface.Mobile.Windows
e.Cancel = true; e.Cancel = true;
} }
} }
private void InitializeTaskbar()
{
Closing += Taskbar_Closing;
Loaded += (o, args) => InitializeBounds();
QuitButton.Clicked += QuitButton_Clicked;
}
void ITaskbar.Focus(bool fromTop)
{
base.Activate();
if (fromTop)
{
this.ApplicationStackPanel.Children[0].Focus();
}
else
{
this.QuitButton.Focus();
}
}
} }
} }

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2022 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.Windows.Input;
using SafeExamBrowser.Logging.Contracts;
using SafeExamBrowser.UserInterface.Contracts.Shell;
using SafeExamBrowser.UserInterface.Contracts.Shell.Events;
using SafeExamBrowser.WindowsApi.Contracts;
using SafeExamBrowser.WindowsApi.Contracts.Events;
namespace SafeExamBrowser.UserInterface.Shared.Activators
{
public class TaskbarKeyboardActivator : KeyboardActivator, ITaskbarActivator
{
private readonly ILogger logger;
private bool leftWindows;
public event ActivatorEventHandler Activated;
public TaskbarKeyboardActivator(ILogger logger, INativeMethods nativeMethods) : base(nativeMethods)
{
this.logger = logger;
}
protected override bool Process(Key key, KeyModifier modifier, KeyState state)
{
var changed = false;
var pressed = state == KeyState.Pressed;
if (key == Key.LWin)
{
changed = leftWindows != pressed;
leftWindows = pressed;
}
if (leftWindows && changed)
{
logger.Debug("Detected activation sequence for taskbar.");
Activated?.Invoke();
return true;
}
return false;
}
}
}

View file

@ -66,6 +66,7 @@
<Compile Include="Activators\ActionCenterKeyboardActivator.cs" /> <Compile Include="Activators\ActionCenterKeyboardActivator.cs" />
<Compile Include="Activators\ActionCenterTouchActivator.cs" /> <Compile Include="Activators\ActionCenterTouchActivator.cs" />
<Compile Include="Activators\KeyboardActivator.cs" /> <Compile Include="Activators\KeyboardActivator.cs" />
<Compile Include="Activators\TaskbarKeyboardActivator.cs" />
<Compile Include="Activators\TaskviewKeyboardActivator.cs" /> <Compile Include="Activators\TaskviewKeyboardActivator.cs" />
<Compile Include="Activators\TerminationActivator.cs" /> <Compile Include="Activators\TerminationActivator.cs" />
<Compile Include="Activators\TouchActivator.cs" /> <Compile Include="Activators\TouchActivator.cs" />